diff --git a/.codeclimate.yml b/.codeclimate.yml deleted file mode 100644 index 37ffdfd22d..0000000000 --- a/.codeclimate.yml +++ /dev/null @@ -1,16 +0,0 @@ -engines: - phpcodesniffer: - enabled: true - phpmd: - enabled: true - duplication: - enabled: true - config: - languages: - - php -ratings: - paths: - - src/**/* - - tests/** -exclude_paths: -- vendor/**/* diff --git a/.github/auto_assign.yml b/.github/auto_assign.yml new file mode 100644 index 0000000000..ae99d1af81 --- /dev/null +++ b/.github/auto_assign.yml @@ -0,0 +1,17 @@ +# Set to true to add reviewers to pull requests +addReviewers: true + +# Set to true to add assignees to pull requests +addAssignees: true + +# A list of reviewers to be added to pull requests (GitHub user name) +reviewers: + - Progi1984 + +# A list of keywords to be skipped the process that add reviewers if pull requests include it +skipKeywords: + - WIP + +# A number of reviewers added to the pull request +# Set 0 to add all the reviewers (default: 0) +numberOfReviewers: 0 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..3245e4a36c --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: +- package-ecosystem: composer + directory: "/" + schedule: + interval: monthly + time: "11:00" + open-pull-requests-limit: 10 + assignees: + - Progi1984 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000000..fcc83844ae --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,50 @@ +name: Deploy + +on: + push: + branches: + - develop + pull_request: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + ### MkDocs + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.x + - name: Install Python Dependencies + run: pip install mkdocs-material autolink-references-mkdocs-plugin + - name: Build documentation + run: mkdocs build --site-dir public + ### PHPUnit + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: mbstring, intl, gd, xml, dom, json, fileinfo, curl, zip, iconv + coverage: xdebug + - name: Create directory public/coverage + run: mkdir ./public/coverage + - name: Create directory public/coverage + run: mkdir ./public/docs + - name: Install PHP Dependencies + run: composer install --ansi --prefer-dist --no-interaction --no-progress + - name: Install PhpDocumentor + run: wget https://phpdoc.org/phpDocumentor.phar && chmod +x phpDocumentor.phar + - name: Build Coverage Report + run: XDEBUG_MODE=coverage ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./public/coverage + - name: Build Documentation + run: ./phpDocumentor.phar -d ./src -t ./public/docs + + ### Deploy + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: github.ref == 'refs/heads/develop' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000000..9b259c42c4 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,95 @@ +name: PHPPresentation +on: [push, pull_request] +jobs: + php-cs-fixer: + name: PHP CS Fixer + runs-on: ubuntu-latest + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: mbstring, intl, gd, xml, dom, json, fileinfo, curl, zip, iconv + - uses: actions/checkout@v2 + + - name: Validate composer config + run: composer validate --strict + + - name: Composer Install + run: composer global require friendsofphp/php-cs-fixer + + - name: Add environment path + run: export PATH="$PATH:$HOME/.composer/vendor/bin" + + - name: Run PHPCSFixer + run: php-cs-fixer fix --dry-run --diff + + phpmd: + name: PHP Mess Detector + runs-on: ubuntu-latest + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + extensions: gd, xml, zip + - uses: actions/checkout@v2 + + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress + + - name: Run phpmd + run: ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist + + phpstan: + name: PHP Static Analysis + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + - uses: actions/checkout@v2 + + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress + + - name: Run phpstan + run: ./vendor/bin/phpstan analyse -c phpstan.neon.dist + + phpunit: + name: PHPUnit + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + coverage: xdebug + + - uses: actions/checkout@v2 + + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress + + - name: Run phpunit + run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml + + - name: Upload coverage results to Coveralls + if: matrix.php == '7.3' + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar + chmod +x php-coveralls.phar + php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv diff --git a/.gitignore b/.gitignore index 2e0a455edc..afe22ddd18 100644 --- a/.gitignore +++ b/.gitignore @@ -6,16 +6,11 @@ Thumbs.db Desktop.ini -### IDE Jetbrains PhpStorm -.idea -### IDE Eclipse -*.settings -*.project -*.buildpath - ### Continuous Integration build/ phpunit.xml +.php-cs-fixer.cache +.phpunit.result.cache composer.phar vendor /batch_CI.bat diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000000..532c34a425 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,44 @@ +setUsingCache(true) + ->setRiskyAllowed(true) + ->setRules([ + '@Symfony' => true, + 'array_indentation' => true, + 'cast_spaces' => [ + 'space' => 'single', + ], + 'combine_consecutive_issets' => true, + 'concat_space' => [ + 'spacing' => 'one', + ], + 'error_suppression' => [ + 'mute_deprecation_error' => false, + 'noise_remaining_usages' => false, + 'noise_remaining_usages_exclude' => [], + ], + 'function_to_constant' => false, + 'method_chaining_indentation' => true, + 'no_alias_functions' => false, + 'no_superfluous_phpdoc_tags' => false, + 'non_printable_character' => [ + 'use_escape_sequences_in_strings' => true, + ], + 'phpdoc_align' => [ + 'align' => 'left', + ], + 'phpdoc_summary' => false, + 'protected_to_private' => false, + 'self_accessor' => false, + 'yoda_style' => false, + 'single_line_throw' => false, + 'no_alias_language_construct_call' => false, + ]) + ->getFinder() + ->in(__DIR__) + ->exclude('vendor'); + +return $config; \ No newline at end of file diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 6d188bee8f..0000000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,24 +0,0 @@ -filter: - excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*' ] - -before_commands: - - "composer install --prefer-source --dev" - -tools: - php_code_sniffer: - enabled: true - config: - standard: PSR2 - php_mess_detector: - enabled: true - config: - ruleset: phpmd.xml.dist - external_code_coverage: - enabled: true - timeout: 900 - php_cpd: true - # php_sim: # Temporarily disabled to allow focus on things other than duplicates - # min_mass: 40 - php_pdepend: true - php_analyzer: true - sensiolabs_security_checker: true \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a990503629..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,66 +0,0 @@ -sudo: false -language: php - -php: - - 5.3 - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - - hhvm - -matrix: - allow_failures: - - php: 7.1 - - php: hhvm - -env: - global: - - secure: "LtlUOzC8FtqgbqUTmU7EU281NSCb58UFdvnz8lelNIDltBdP4eayN/TsgNIePB4jXg2d2R56ZA6j/grhE/md6jdUkulV355H3GrH/hIZmmQ+F9+87agnwLzb9+MJbqXoiE7VvjY3zGIO09G897SUfsfu6JWEcscYFlsH6KcXM6M=" - -addons: - apt: - packages: - - graphviz - code_climate: - repo_token: 9d5714bfd25acc27c449c2d71cfb444351a3b91c59ed1a5dc3a50732d2bf45f0 - -before_script: - ## Composer - - composer self-update - - composer install --prefer-source - ## PHPDocumentor - - mkdir -p build/docs - - mkdir -p build/coverage - -script: - ## PHP_CodeSniffer - - ./vendor/bin/phpcs src/ tests/ --standard=PSR2 -n - ## PHP Copy/Paste Detector - # - ./vendor/bin/phpcpd src/ - ## PHP Mess Detector - - ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist - ## PHPUnit - - ./vendor/bin/phpunit -c ./ --coverage-text --coverage-html ./build/coverage - ## PHPLOC - - ./vendor/bin/phploc src/ - ## PHPDocumentor - - ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --template="responsive-twig" - -after_script: - ## PHPDocumentor - - bash .travis_shell_after_success.sh - ## Scrutinizer - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml - ## CodeClimate - - ./vendor/bin/test-reporter - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/0dbc70ac93ba40880eef - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false diff --git a/.travis_shell_after_success.sh b/.travis_shell_after_success.sh deleted file mode 100644 index d3138a2485..0000000000 --- a/.travis_shell_after_success.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -echo "--DEBUG--" -echo "TRAVIS_REPO_SLUG: $TRAVIS_REPO_SLUG" -echo "TRAVIS_PHP_VERSION: $TRAVIS_PHP_VERSION" -echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST" - -if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPPresentation" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.5" ]; then - - echo -e "Publishing PHPDoc...\n" - - cp -R build/docs $HOME/docs-latest - cp -R build/coverage $HOME/coverage-latest - - cd $HOME - git config --global user.email "travis@travis-ci.org" - git config --global user.name "travis-ci" - git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/PHPOffice/PHPPresentation gh-pages > /dev/null - - cd gh-pages - echo "--DEBUG : Suppression" - git rm -rf ./docs/$TRAVIS_BRANCH - - echo "--DEBUG : Dossier" - mkdir -p docs/$TRAVIS_BRANCH - mkdir -p coverage/$TRAVIS_BRANCH - - echo "--DEBUG : Copie" - cp -Rf $HOME/docs-latest/* ./docs/$TRAVIS_BRANCH/ - cp -Rf $HOME/coverage-latest/* ./coverage/$TRAVIS_BRANCH/ - - echo "--DEBUG : Git" - git add -f . - git commit -m "PHPDocumentor (Travis Build: $TRAVIS_BUILD_NUMBER - Branch: $TRAVIS_BRANCH)" - git push -fq origin gh-pages > /dev/null - - echo -e "Published PHPDoc to gh-pages.\n" - -fi diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 4f2b08b5b1..0000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,254 +0,0 @@ -# Changelog - -## 0.9.0 - 2017-07-05 - -### Bugfix -- PowerPoint2007 Writer : Margins in table cell - @Progi1984 GH-347 - -### Changes -- PowerPoint2007 Writer : Write percentage values with a trailing percent sign instead of formatted as 1000th of a percent to comply with the standard - @k42b3 GH-307 - -### Features -- PowerPoint2007 Writer : Implemented XSD validation test case according to the ECMA/ISO standard - @k42b3 GH-307 -- PowerPoint2007 Writer : Implement visibility for axis - @kw-pr @Progi1984 GH-356 -- PowerPoint2007 Writer : Implement gap width in Bar(3D) Charts - @Progi1984 GH-358 - -## 0.8.0 - 2017-04-03 - -### Bugfix -- PowerPoint2007 Writer : Fixed the marker on line chart when symbol is none - @Napryc GH-211 -- PowerPoint2007 Writer : Fixed the format value in Pie Chart - @Napryc GH-212 -- PowerPoint2007 Writer : The presentation need repairs on Mac @jrking4 GH-266 GH-276 -- PowerPoint2007 Writer : Fix for PowerPoint2007 Writer (Need repair) @Progi1984 GH-266 GH-274 GH-276 GH-282 GH-302 -- PowerPoint2007 Writer : Fixed the axis title in bar chart - @pgee70 GH-267 -- PowerPoint2007 Writer : Fixed the label position in bar chart - @pgee70 GH-268 -- PowerPoint2007 Writer : Support of margins in cell in table - @carlosafonso @Progi1984 GH-273 GH-315 -- Fixed the corruption of file when an addExternalSlide is called - @Progi1984 GH-240 - -### Changes -- Misc : Added two methods for setting Border & Fill in Legend - @Progi1984 GH-265 - -### Features -- ODPresentation Writer : Show/Hide Value / Name / Series Name in Chart - @Progi1984 GH-272 -- ODPresentation Writer : Axis Bounds in Chart - @Progi1984 GH-269 -- PowerPoint97 Reader : Support of Slide Note - @Progi1984 GH-226 -- PowerPoint2007 Reader : Support of Shape Table - @Progi1984 GH-240 -- PowerPoint2007 Reader : Support of Slide Note - @Progi1984 GH-226 -- PowerPoint2007 Reader : Support text direction in Alignment for Table - @Progi1984 GH-218 -- PowerPoint2007 Writer : Implement character spacing - @jvanoostrom GH-301 -- PowerPoint2007 Writer : Axis Bounds in Chart - @Progi1984 GH-269 -- PowerPoint2007 Writer : Implement Legend Key in Series for Chart - @Progi1984 GH-319 -- PowerPoint2007 Writer : Support text direction in Alignment for Table - @SeregPie GH-218 -- PowerPoint2007 Writer : Support tick mark & unit in Axis for Chart - @Faab GH-218 -- PowerPoint2007 Writer : Support separator in Series for Chart - @jphchaput GH-218 -- PowerPoint2007 Writer : Add support for Outline in Axis - @Progi1984 GH-255 -- PowerPoint2007 Writer : Support autoscale for Chart - @Progi1984 GH-293 - -## 0.7.0 - 2016-09-12 - -### Bugfix -- Fixed the image project - @mvargasmoran GH-177 -- PowerPoint2007 Writer : Bugfix for printing slide notes - @JewrassicPark @Progi1984 GH-179 - -### Changes -- PhpOffice\PhpPresentation\Writer\ODPresentation : Move to Design Pattern Decorator - @Progi1984 -- PhpOffice\PhpPresentation\Writer\PowerPoint2007 : Move to Design Pattern Decorator - @Progi1984 -- PhpOffice\PhpPresentation\Shape\Type\AbstracType\getData has been deprecated for PhpOffice\PhpPresentation\Shape\Type\AbstracType\getSeries - @Progi1984 GH-169 -- PhpOffice\PhpPresentation\Shape\Type\AbstracType\setData has been deprecated for PhpOffice\PhpPresentation\Shape\Type\AbstracType\setSeries - @Progi1984 GH-169 -- Added documentation for chart series (font, outline, marker) - @Progi1984 GH-169 -- Internal Structure for Drawing Shape - @Progi1984 GH-192 -- Documentation about manual installation - @danielbair GH-254 - -### Features -- ODPresentation & PowerPoint2007 Writer : Add support for Comment - @Progi1984 GH-116 -- ODPresentation & PowerPoint2007 Writer : Thumbnail of the presentation - @Progi1984 GH-125 -- ODPresentation & PowerPoint2007 Writer : Add support for Gridlines in Chart - @Progi1984 GH-129 -- ODPresentation & PowerPoint2007 Writer : Support for images in base 64 - @Progi1984 GH-168 -- ODPresentation & PowerPoint2007 Writer : Marker of Series in Line & Scatter chart is customizable - @Progi1984 GH-169 -- ODPresentation & PowerPoint2007 Writer : Outline of Series in Line & Scatter chart is customizable - @Progi1984 GH-169 -- ODPresentation & PowerPoint2007 & Serialized Writer : Support for Zip Adapter - @Progi1984 GH-176 -- ODPresentation & PowerPoint2007 Writer : language property to TextElement - @skrajewski & @Progi1984 GH-180 -- ODPresentation & PowerPoint2007 Writer : Add Font Support For Chart Axis - @jrking4 GH-186 -- ODPresentation & PowerPoint2007 Writer : Support for video - @Progi1984 GH-123 -- ODPresentation & PowerPoint2007 Writer : Support for Visibility for slides - @Progi1984 -- PowerPoint2007 Reader : Layout Management - @vincentKool @Progi1984 GH-161 -- PowerPoint2007 Reader : Slide size - @loverslcn @Progi1984 GH-246 -- PowerPoint2007 Reader : Bullet Color - @Progi1984 GH-257 -- PowerPoint2007 Reader : Line Spacing - @Progi1984 GH-257 -- PowerPoint2007 Writer : Presentation with predefined View Type - @Progi1984 GH-120 -- PowerPoint2007 Writer : Implement alpha channel to Fills - @Dayjo GH-203 / @Progi1984 GH-215 -- PowerPoint2007 Writer : Implement Animations - @JewrassicPark GH-214 / @Progi1984 GH-217 -- PowerPoint2007 Writer : Layout Management - @vincentKool @Progi1984 GH-161 -- PowerPoint2007 Writer : Bullet Color - @piotrbelina GH-249 -- PowerPoint2007 Writer : Line Spacing - @piotrbelina GH-249 - -## 0.6.0 - 2016-01-24 - -### Bugfix -- Documentation : Fixes in the rename of PHPPowerPoint - @Progi1984 GH-127 -- ODPresentation : Exclude SVM files for reader - @Progi1984 GH-141 -- PowerPoint2007 Writer : Bugfix for opening PPTX on Mac - @thsteinmetz GH-89 - -### Changes -- PhpOffice\PhpPresentation\getProperties has been deprecated for PhpOffice\PhpPresentation\getDocumentProperties - @Progi1984 GH-154 -- PhpOffice\PhpPresentation\setProperties has been deprecated for PhpOffice\PhpPresentation\setDocumentProperties - @Progi1984 GH-154 -- PhpOffice\PhpPowerpoint\Style\Alignment::setLevel can now be defined great than 8 - @Progi1984 GH-141 - -### Features -- ODPresentation Reader/Writer : Name of the slide - @Progi1984 GH-121 -- ODPresentation Reader/Writer : Slide Background Color or Image - @Progi1984 GH-152 -- PowerPoint2007 Reader : Support for Layout Name - @Progi1984 GH-144 -- PowerPoint2007 Reader/Writer : Mark as final - @Progi1984 GH-118 -- PowerPoint2007 Reader/Writer : Set default zoom value for presentation - @Progi1984 GH-122 -- PowerPoint2007 Reader/Writer : Slide Background Color or Image - @Progi1984 GH-152 -- PowerPoint2007 Reader/Writer : Add Properties for allowing loop continuously until 'Esc' - @Progi1984 GH-154 - -## 0.5.0 - 2015-10-08 - -### Features -- PowerPoint2007 Reader : Initial Commit - @Progi1984 GH-44 -- ODPresentation Reader : Initial Commit - @Progi1984 GH-113 - -### Bugfix -- Fixed the sample in Readme.md - @Progi1984 GH-114 - -### Changes -- PhpOffice\PhpPowerpoint becomes PhpOffice\PhpPresentation - @Progi1984 GH-25 -- PhpOffice\PhpPowerpoint\Style\Font::setStriketrough has been removed : Use setStrikethrough - @Progi1984 -- PhpOffice\PhpPowerpoint\AbstractShape::getSlide has been removed - @Progi1984 -- PhpOffice\PhpPowerpoint\AbstractShape::setSlide has been removed - @Progi1984 -- PhpOffice\PhpPowerpoint\DocumentLayout::getLayoutXmilli has been removed : getCX(DocumentLayout::UNIT_MILLIMETER) - @Progi1984 -- PhpOffice\PhpPowerpoint\DocumentLayout::getLayoutYmilli has been removed : getCY(DocumentLayout::UNIT_MILLIMETER) - @Progi1984 -- PhpOffice\PhpPowerpoint\DocumentLayout::setLayoutXmilli has been removed : setCX(DocumentLayout::UNIT_MILLIMETER) - @Progi1984 -- PhpOffice\PhpPowerpoint\DocumentLayout::setLayoutYmilli has been removed : setCY(DocumentLayout::UNIT_MILLIMETER) - @Progi1984 -- Update the dependence PhpOffice\Common to 0.2.* - @Progi1984 -- Migrated Travis CI to legacy - @Progi1984 GH-115 - -## 0.4.0 - 2015-07-07 - -### Features -- Added support for grouping shapes together in a Group - @Pr0phet GH-68 -- Added support for calculating the offset and extent on a Slide. - @Pr0phet GH-68 -- Added support for Horizontal bar chart - @rdoepke @Progi1984 GH-58 -- Added support for hyperlink on picture (ODPresentation & PowerPoint2007) - @Progi1984 GH-49 -- Added support for hyperlink on richtext (PowerPoint2007) - @JewrassicPark GH-49 -- Added support for notes slide (ODPresentation & PowerPoint2007) - @Progi1984 @JewrassicPark GH-63 -- Added option for explosion in Pie3D Chart (ODPresentation & PowerPoint2007) - @Progi1984 GH-76 -- ODPresentation Writer : Support for fill in RichText - @Progi1984 GH-79 -- ODPresentation Writer : Support for border style in RichText - @Progi1984 GH-79 -- ODPresentation Writer : Support for Area Chart - @Progi1984 GH-82 -- PowerPoint2007 Writer : Support for Area Chart - @Progi1984 GH-82 -- ODPresentation Writer : Support for Bar Chart - @Progi1984 GH-82 -- PowerPoint2007 Writer : Support for Bar Chart - @Progi1984 GH-82 -- Added units in DocumentLayout - @Progi1984 GH-87 -- Added support for transitions between slides - @Progi1984 -- ODPresentation Writer : Support for Pie Chart & Stack Percent Bar Charts - @jrking4 GH-108 -- PowerPoint2007 Writer : Support for Pie Chart & Stack Percent Bar Charts - @jrking4 GH-108 - -### Bugfix -- PSR-0 via composer broken - @Progi1984 GH-51 -- ODPresentation Writer : Title in Legend in chart doesn't displayed - @Progi1984 GH-79 -- ODPresentation Writer : Segments in Pie3D Chart are now in clockwise order, as in PowerPoint2007 Writer - @Progi1984 GH-79 -- ODPresentation Writer : Axis in Line Chart have not tick marks displayed, as in PowerPoint2007 Writer - @Progi1984 GH-79 -- ODPresentation Writer : Shadow don't work for RichTextShapes - @Progi1984 GH-81 -- PowerPoint2007 Writer : Fill don't work for RichTextShapes - @Progi1984 GH-61 -- PowerPoint2007 Writer : Border don't work for RichTextShapes - @Progi1984 GH-61 -- PowerPoint2007 Writer : Hyperlink in table doesn't work - @Progi1984 GH-70 -- PowerPoint2007 Writer : AutoFitNormal works with options (fontScale & lineSpacingReduction) - @Progi1984 @desigennaro GH-71 -- PowerPoint2007 Writer : Shadow don't work for RichTextShapes - @Progi1984 GH-81 -- PowerPoint2007 Writer : Visibility of the Title doesn't work - @Progi1984 GH-107 -- Refactor findLayoutIndex to findLayoutId where it assumes the slideLayout order was sorted. IMPROVED: unit tests - @kenliau GH-95 - -### Miscellaneous -- Improved the sample 04-Table for having a Text Run in a Cell - @Progi1984 GH-84 -- Improved the sample 04-Table for having two links in a Cell - @Progi1984 GH-93 -- Improved the documentation about Table Shapes and cell width - @Progi1984 GH-104 -- Some parts of code shared between PHPOffice projects have been moved to PhpOffice/Common - @Progi1984 -- Refactored the PowerPoint97 Reader for managing the group shape and improving evolutions - @Progi1984 GH-110 -- Added a sample (12) for PowerPoint97 Reader with tree of the PhpPowerPoint object - @Progi1984 GH-110 - -## 0.3.0 - 2014-09-22 - -### Features -- PowerPoint97 Reader : Implement Basic Reader - @Progi1984 GH-15 GH-14 GH-4 -- ODPresentation Writer : Ability to set auto shrink text - @Progi1984 GH-28 -- Make package PSR-4 compliant. Autoload classes by composer out of the box - @Djuki GH-41 - -### Bugfix -- PowerPoint2007 Writer : Powerpoint Repair Error in Office 2010 - @Progi1984 GH-39 -- PowerPoint2007 Writer : BUG: Repair Error / Wrong anchor if you don't set vertical alignment different to VERTICAL_BASE - @fregge GH-42 -- PowerPoint2007 Writer : Keynote incompatibility - @catrane CP#237322 / @Progi1984 GH-46 - -### Miscellaneous -- QA : Move AbstractType for Chart - @Progi1984 -- QA : Unit Tests - @Progi1984 - -## 0.2.0 - 2014-07-22 - -### Features - -- Provide fluent interfaces where possible - @maartenba CP- 815 -- Use existing presentation template when writing PPTX file - @maartenba CP-1034 -- Implement bullet and numeric lists - @maartenba CP-1093 -- getProperties: setCompany feature request - @maartenba CP-1173 -- New shape type: table - @maartenba CP-1375 -- Use of CDATA text when writing text - @maartenba CP-2804 -- Possibility to set borders on tables and table cells - @maartenba CP-1378 -- Access to additional properties of Text Boxes - @maartenba CP-4921 -- Applied patch 7010 - @maartenba CP-7010 -- Applied patch 7020 - @maartenba CP-7020 -- Add a hyperlink to an image or textbox - @maartenba CP-1196 -- PowerPoint Charts - @maartenba CP-4953 -- Editing chart data - @maartenba CP-5580 -- Solid Fill support - @maartenba CP-5461 -- Applied patch 8375 - @maartenba CP-8375 -- Implement autoloader - @MarkBaker -- ODPresentation Writer : Implement Basic Writer - @Progi1984 GH-1 -- ODPresentation Writer : Implement Support of Charts - @Progi1984 GH-33 -- ODPresentation Writer : Implement Support of Lines - @Progi1984 GH-30 -- ODPresentation Writer : Implement Support of Tables - @Progi1984 GH-31 -- PowerPoint2007 Writer : Implement Support of Fill - @Progi1984 GH-32 - -### Bugfix - -- Allow solid color fill - @MarkBaker -- Table width setting Office 2007 - @maartenba CP-3910 -- Bullet characters in Master Slide Layouts of template file become corrupted - @maartenba CP-4598 -- Generated files cannot be opened in Office 08 for Mac OSX - @maartenba CP-3424 -- Table Cell Borders Not Displaying Correctly - @maartenba CP-2541 -- Multiple Master Slides are not supported - @maartenba CP-4597 -- Images in Layouts other than first Master Slide within Template file causes corrupted PPTX - @maartenba CP-4596 -- Fixed A3 and A4 formats dimensions - @delphiki GH-16 -- Fixed custom document layout - @delphiki GH-18 -- Filename parameter is required for IWriter::save method - @sapfeer0k GH-19 -- DocumentLayout: Fix incorrect variable assignment - @kaiesh GH-6 -- Hyperlink: Wrong input parameter object type in setHyperlink - @nynka GH-23 -- ODPresentation Writer: ODP writer is locale sensitive in the wrong places - @Progi1984 GH-21 -- ODPresentation Writer: Display InMemory Image - @Progi1984 GH-29 -- PowerPoint2007 Writer: Bar3D doesn't display - @Progi1984 GH-32 -- PowerPoint2007 Writer: Changed PowerPoint2007 writer attributes to protected - @delphiki GH-20 -- PowerPoint2007 Writer: Scatter chart with numerical X values not working well - @Progi1984 GH-3 -- Shape RichText: Support of Vertical Alignment in PowerPoint2007 - @Progi1984 GH-35 - - -### Miscellaneous - -- Rename PHPPowerpoint.php to PHPPowerPoint.php - @maartenba CP-1165 -- Create build script using Phing - @maartenba CP-5270 -- QA: Prepare `.travis.yml` and `phpcs.xml` for Travis build passing - @Progi1984 @ivanlanin -- QA: Initiate unit tests - @Progi1984 @ivanlanin -- QA: Cleanup source code for PSR dan PHPDoc compatibility - @ivanlanin -- QA: Unit Tests - @Progi1984 & @ivanlanin -- Doc: Initiate documentation - @ivanlanin -- Doc: Move to [Read The Docs](http://phppowerpoint.readthedocs.org) - @Progi1984 -- Refactor: Change PHPPowerPoint_Shape_Shadow to PHPPowerPoint_Style_Shadow because it's a style, not a shape - @ivanlanin -- Refactor: Change PHPPowerPoint_SlideIterator to PHPPowerPoint_Slide_Iterator - @ivanlanin - -## 0.1.0 - -- Create a Presentation object -- Add one or more Slide objects -- Add one or more Shapes to Slide objects -- Text Shapes -- Image Shapes -- Export Presentation object to PowerPoint 2007 OpenXML format diff --git a/README.md b/README.md index 47b633fb14..fa3bebe852 100644 --- a/README.md +++ b/README.md @@ -1,150 +1,149 @@ -# ![PHPPresentation](https://raw.githubusercontent.com/mvargasmoran/PHPPresentation/develop/docs/images/PHPPresentationLogo.png "PHPPresentation") - -[![Latest Stable Version](https://poser.pugx.org/phpoffice/phppresentation/v/stable.png)](https://packagist.org/packages/phpoffice/phppresentation) -[![Code Climate](https://codeclimate.com/github/PHPOffice/PHPPresentation/badges/gpa.svg)](https://codeclimate.com/github/PHPOffice/PHPPresentation) -[![Test Coverage](https://codeclimate.com/github/PHPOffice/PHPPresentation/badges/coverage.svg)](https://codeclimate.com/github/PHPOffice/PHPPresentation/coverage) -[![Total Downloads](https://poser.pugx.org/phpoffice/phppresentation/downloads.png)](https://packagist.org/packages/phpoffice/phppresentation) -[![License](https://poser.pugx.org/phpoffice/phppresentation/license.png)](https://packagist.org/packages/phpoffice/phppresentation) -[![BountySource](https://img.shields.io/bountysource/team/phpoffice/activity.svg)](https://www.bountysource.com/teams/phpoffice) -[![Join the chat at https://gitter.im/PHPOffice/PHPPresentation](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPPresentation) - -Branch Master : [![Build Status](https://travis-ci.org/PHPOffice/PHPPresentation.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPPresentation) [![Documentation Status](https://readthedocs.org/projects/phppresentation/badge/?version=master)](http://phppresentation.readthedocs.io/en/latest/?badge=master) -Branch Develop : [![Build Status](https://travis-ci.org/PHPOffice/PHPPresentation.svg?branch=develop)](https://travis-ci.org/PHPOffice/PHPPresentation) [![Documentation Status](https://readthedocs.org/projects/phppresentation/badge/?version=develop)](http://phppresentation.readthedocs.io/en/latest/?badge=develop) - -PHPPresentation is a library written in pure PHP that provides a set of classes to write to different presentation file formats, i.e. Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML) or OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF). - -PHPPresentation is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPPresentation/blob/develop/COPYING.LESSER). PHPPresentation is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPPresentation) and [unit testing](http://phpoffice.github.io/PHPPresentation/coverage/develop/). You can learn more about PHPPresentation by reading the [Developers' Documentation](http://phppresentation.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPPresentation/docs/develop/). - -Read more about PHPPresentation: - -- [Features](#features) -- [Requirements](#requirements) -- [Installation](#installation) -- [Getting started](#getting-started) -- [Contributing](#contributing) -- [Developers' Documentation](http://phppresentation.readthedocs.org/) -- [API Documentation](http://phpoffice.github.io/PHPPresentation/docs/master/) - -### Features - -- Create an in-memory presentation representation -- Set presentation meta data (author, title, description, etc) -- Add slides from scratch or from existing one -- Supports different fonts and font styles -- Supports different formatting, styles, fills, gradients -- Supports hyperlinks and rich-text strings -- Add images with different styles (positioning, rotation, shadow) -- Set printing options (header, footer, page margins, paper size, orientation) -- Set transitions between slides -- Output to different file formats: PowerPoint 2007 (.pptx), OpenDocument Presentation (.odp), Serialized Presentation) -- ... and lots of other things! - -### Requirements - -PHPPresentation requires the following: - -- PHP 5.3+ -- [Zip extension](http://php.net/manual/en/book.zip.php) -- [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) -- [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write DOCX and ODT) -- [GD](http://php.net/manual/en/book.image.php) - -### Installation - -#### Composer method - -It is recommended that you install the PHPPresentation library [through composer](http://getcomposer.org/). To do so, add -the following lines to your ``composer.json``. - -```json -{ - "require": { - "phpoffice/phppresentation": "dev-master" - } -} -``` - -#### Manual download method - -Alternatively, you can download the latest release from the [releases page](https://github.com/PHPOffice/PHPPresentation/releases). -In this case, you will have to register the autoloader. -(Register autoloading is required only if you do not use composer in your project.) - -```php -require_once 'path/to/PhpPresentation/src/PhpPresentation/Autoloader.php'; -\PhpOffice\PhpPresentation\Autoloader::register(); -``` - -You will also need to download the latest PHPOffice/Common release from its [releases page](https://github.com/PHPOffice/Common/releases). -And you will also have to register its autoloader, too. - -```php -require_once 'path/to/PhpOffice/Common/src/Common/Autoloader.php'; -\PhpOffice\Common\Autoloader::register(); -``` - -## Getting started - -The following is a basic usage example of the PHPPresentation library. - -```php -// with your own install -require_once 'src/PhpPresentation/Autoloader.php'; -\PhpOffice\PhpPresentation\Autoloader::register(); -require_once 'src/Common/Autoloader.php'; -\PhpOffice\Common\Autoloader::register(); - -// with Composer -require_once 'vendor/autoload.php'; - -use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\IOFactory; -use PhpOffice\PhpPresentation\Style\Color; -use PhpOffice\PhpPresentation\Style\Alignment; - -$objPHPPowerPoint = new PhpPresentation(); - -// Create slide -$currentSlide = $objPHPPowerPoint->getActiveSlide(); - -// Create a shape (drawing) -$shape = $currentSlide->createDrawingShape(); -$shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); -$shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - -// Create a shape (text) -$shape = $currentSlide->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); -$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); -$textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); -$textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor( new Color( 'FFE06B20' ) ); - -$oWriterPPTX = IOFactory::createWriter($objPHPPowerPoint, 'PowerPoint2007'); -$oWriterPPTX->save(__DIR__ . "/sample.pptx"); -$oWriterODP = IOFactory::createWriter($objPHPPowerPoint, 'ODPresentation'); -$oWriterODP->save(__DIR__ . "/sample.odp"); -``` - -More examples are provided in the [samples folder](samples/). You can also read the [Developers' Documentation](http://phppresentation.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPPresentation/docs/master/) for more detail. - - -## Contributing - -We welcome everyone to contribute to PHPPresentation. Below are some of the things that you can do to contribute: - -- Read [our contributing guide](https://github.com/PHPOffice/PHPPresentation/blob/master/CONTRIBUTING.md) -- [Fork us](https://github.com/PHPOffice/PHPPresentation/fork) and [request a pull](https://github.com/PHPOffice/PHPPresentation/pulls) to the [develop](https://github.com/PHPOffice/PHPPresentation/tree/develop) branch -- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPPresentation/issues) to GitHub -- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter +# ![PHPPresentation](https://raw.githubusercontent.com/mvargasmoran/PHPPresentation/develop/docs/images/PHPPresentationLogo.png "PHPPresentation") + +[![Latest Stable Version](https://poser.pugx.org/phpoffice/phppresentation/v/stable.png)](https://packagist.org/packages/phpoffice/phppresentation) +[![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPPresentation/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPPresentation?branch=develop) +[![Total Downloads](https://poser.pugx.org/phpoffice/phppresentation/downloads.png)](https://packagist.org/packages/phpoffice/phppresentation) +[![License](https://poser.pugx.org/phpoffice/phppresentation/license.png)](https://packagist.org/packages/phpoffice/phppresentation) +[![BountySource](https://img.shields.io/bountysource/team/phpoffice/activity.svg)](https://www.bountysource.com/teams/phpoffice) +[![Join the chat at https://gitter.im/PHPOffice/PHPPresentation](https://img.shields.io/badge/Gitter-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPPresentation) + +Branch Master : [![PHPPresentation](https://github.com/PHPOffice/PHPPresentation/actions/workflows/php.yml/badge.svg?branch=master)](https://github.com/PHPOffice/PHPPresentation/actions/workflows/php.yml) + +Branch Develop : [![PHPPresentation](https://github.com/PHPOffice/PHPPresentation/actions/workflows/php.yml/badge.svg?branch=develop)](https://github.com/PHPOffice/PHPPresentation/actions/workflows/php.yml) + +PHPPresentation is a library written in pure PHP that provides a set of classes to write to different presentation file formats, i.e. Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML) or OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF). + +PHPPresentation is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPPresentation/blob/develop/COPYING.LESSER). PHPPresentation is aimed to be a high quality software product by incorporating [continuous integration](https://github.com/PHPOffice/PHPPresentation/actions/workflows/php.yml) and [unit testing](https://coveralls.io/github/PHPOffice/PHPPresentation). You can learn more about PHPPresentation by reading the [Developers' Documentation](https://phpoffice.github.io/PHPPresentation) and the [API Documentation](https://phpoffice.github.io/PHPPresentation/docs/). + +Read more about PHPPresentation: + +- [Features](#features) +- [Requirements](#requirements) +- [Installation](#installation) +- [Getting started](#getting-started) +- [Contributing](#contributing) +- [Developers' Documentation](https://phpoffice.github.io/PHPPresentation/) +- [API Documentation](https://phpoffice.github.io/PHPPresentation/docs/) + +### Features + +- Create an in-memory presentation representation +- Set presentation meta data (author, title, description, etc) +- Add slides from scratch or from existing one +- Supports different fonts and font styles +- Supports different formatting, styles, fills, gradients +- Supports hyperlinks and rich-text strings +- Add images with different styles (positioning, rotation, shadow) +- Set printing options (header, footer, page margins, paper size, orientation) +- Set transitions between slides +- Output to different file formats: PowerPoint 2007 (.pptx), OpenDocument Presentation (.odp), Serialized Presentation) +- ... and lots of other things! + +### Requirements + +PHPPresentation requires the following: + +- PHP 7.1+ +- [ZIP Extension](http://php.net/manual/en/book.zip.php) +- [XML Parser Extension](http://www.php.net/manual/en/xml.installation.php) +- [XMLWriter Extension](http://php.net/manual/en/book.xmlwriter.php) (optional, used to write DOCX and ODT) +- [GD Extension](http://php.net/manual/en/book.image.php) + +### Installation + +#### Composer method + +It is recommended that you install the PHPPresentation library [through composer](http://getcomposer.org/). To do so, add +the following lines to your ``composer.json``. + +```json +{ + "require": { + "phpoffice/phppresentation": "dev-master" + } +} +``` + +#### Manual download method + +Alternatively, you can download the latest release from the [releases page](https://github.com/PHPOffice/PHPPresentation/releases). +In this case, you will have to register the autoloader. +(Register autoloading is required only if you do not use composer in your project.) + +```php +require_once 'path/to/PhpPresentation/src/PhpPresentation/Autoloader.php'; +\PhpOffice\PhpPresentation\Autoloader::register(); +``` + +You will also need to download the latest PHPOffice/Common release from its [releases page](https://github.com/PHPOffice/Common/releases). +And you will also have to register its autoloader, too. + +```php +require_once 'path/to/PhpOffice/Common/src/Common/Autoloader.php'; +\PhpOffice\Common\Autoloader::register(); +``` + +## Getting started + +The following is a basic usage example of the PHPPresentation library. + +```php +// with your own install +require_once 'src/PhpPresentation/Autoloader.php'; +\PhpOffice\PhpPresentation\Autoloader::register(); +require_once 'src/Common/Autoloader.php'; +\PhpOffice\Common\Autoloader::register(); + +// with Composer +require_once 'vendor/autoload.php'; + +use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\IOFactory; +use PhpOffice\PhpPresentation\Style\Color; +use PhpOffice\PhpPresentation\Style\Alignment; + +$objPHPPowerPoint = new PhpPresentation(); + +// Create slide +$currentSlide = $objPHPPowerPoint->getActiveSlide(); + +// Create a shape (drawing) +$shape = $currentSlide->createDrawingShape(); +$shape->setName('PHPPresentation logo') + ->setDescription('PHPPresentation logo') + ->setPath('./resources/phppowerpoint_logo.gif') + ->setHeight(36) + ->setOffsetX(10) + ->setOffsetY(10); +$shape->getShadow()->setVisible(true) + ->setDirection(45) + ->setDistance(10); + +// Create a shape (text) +$shape = $currentSlide->createRichTextShape() + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(170) + ->setOffsetY(180); +$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); +$textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); +$textRun->getFont()->setBold(true) + ->setSize(60) + ->setColor( new Color( 'FFE06B20' ) ); + +$oWriterPPTX = IOFactory::createWriter($objPHPPowerPoint, 'PowerPoint2007'); +$oWriterPPTX->save(__DIR__ . "/sample.pptx"); +$oWriterODP = IOFactory::createWriter($objPHPPowerPoint, 'ODPresentation'); +$oWriterODP->save(__DIR__ . "/sample.odp"); +``` + +More examples are provided in the [samples folder](samples/). You can also read the [Developers' Documentation](https://phpoffice.github.io/PHPPresentation/) and the [API Documentation](https://phpoffice.github.io/PHPPresentation/docs/) for more detail. + +## Contributing + +We welcome everyone to contribute to PHPPresentation. Below are some of the things that you can do to contribute: + +- Read [our contributing guide](https://github.com/PHPOffice/PHPPresentation/blob/master/CONTRIBUTING.md) +- [Fork us](https://github.com/PHPOffice/PHPPresentation/fork) and [request a pull](https://github.com/PHPOffice/PHPPresentation/pulls) to the [develop](https://github.com/PHPOffice/PHPPresentation/tree/develop) branch +- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPPresentation/issues) to GitHub +- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter diff --git a/composer.json b/composer.json index 17b29fea00..ab4a5dd19f 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "keywords": ["PHP","PowerPoint","LibreOffice","pptx","ppt","odp","presentations"], "homepage": "http://phpoffice.github.io", "type": "library", - "license": "LGPL", + "license": "LGPL-3.0-only", "authors": [ { "name": "Mark Baker" @@ -19,23 +19,19 @@ } ], "require": { - "php": ">=5.3.0", + "php": "^7.1|^8.0", "ext-xml": "*", "ext-zip": "*", - "phpoffice/common": "0.2.*" + "phpoffice/common": "^1", + "phpoffice/phpspreadsheet": "^1.9.0" }, "require-dev": { - "phpunit/phpunit": "3.7.*", - "phpdocumentor/phpdocumentor":"2.*", - "twig/twig":"1.27", + "phpunit/phpunit": ">=7.0", "phpmd/phpmd": "2.*", - "sebastian/phpcpd": "2.*", - "phploc/phploc": "2.*", - "squizlabs/php_codesniffer": "2.*", - "codeclimate/php-test-reporter": "dev-master" + "phpstan/phpstan": "^0.12.88" }, "suggest": { - "ext-gd2": "Required to add images" + "ext-gd": "Required to add images" }, "autoload": { "psr-4": { diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 5631b06028..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,153 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PhpWord.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PhpWord.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/PhpWord" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PhpWord" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/changes/0.1.0.md b/docs/changes/0.1.0.md new file mode 100644 index 0000000000..ebe5e9abf5 --- /dev/null +++ b/docs/changes/0.1.0.md @@ -0,0 +1,8 @@ +# 0.1.0 + +- Create a Presentation object +- Add one or more Slide objects +- Add one or more Shapes to Slide objects +- Text Shapes +- Image Shapes +- Export Presentation object to PowerPoint 2007 OpenXML format \ No newline at end of file diff --git a/docs/changes/0.2.0.md b/docs/changes/0.2.0.md new file mode 100644 index 0000000000..664a920ca8 --- /dev/null +++ b/docs/changes/0.2.0.md @@ -0,0 +1,59 @@ +# 0.2.0 - 2014-07-22 + +## Features + +- Provide fluent interfaces where possible - [@maartenba](https://github.com/maartenba) CP-815 +- Use existing presentation template when writing PPTX file - [@maartenba](https://github.com/maartenba) CP-1034 +- Implement bullet and numeric lists - [@maartenba](https://github.com/maartenba) CP-1093 +- getProperties: setCompany feature request - [@maartenba](https://github.com/maartenba) CP-1173 +- New shape type: table - [@maartenba](https://github.com/maartenba) CP-1375 +- Use of CDATA text when writing text - [@maartenba](https://github.com/maartenba) CP-2804 +- Possibility to set borders on tables and table cells - [@maartenba](https://github.com/maartenba) CP-1378 +- Access to additional properties of Text Boxes - [@maartenba](https://github.com/maartenba) CP-4921 +- Applied patch 7010 - [@maartenba](https://github.com/maartenba) CP-7010 +- Applied patch 7020 - [@maartenba](https://github.com/maartenba) CP-7020 +- Add a hyperlink to an image or textbox - [@maartenba](https://github.com/maartenba) CP-1196 +- PowerPoint Charts - [@maartenba](https://github.com/maartenba) CP-4953 +- Editing chart data - [@maartenba](https://github.com/maartenba) CP-5580 +- Solid Fill support - [@maartenba](https://github.com/maartenba) CP-5461 +- Applied patch 8375 - [@maartenba](https://github.com/maartenba) CP-8375 +- Implement autoloader - [@MarkBaker](https://github.com/MarkBaker) +- ODPresentation Writer : Implement Basic Writer - [@Progi1984](https://github.com/Progi1984) GH-1 +- ODPresentation Writer : Implement Support of Charts - [@Progi1984](https://github.com/Progi1984) GH-33 +- ODPresentation Writer : Implement Support of Lines - [@Progi1984](https://github.com/Progi1984) GH-30 +- ODPresentation Writer : Implement Support of Tables - [@Progi1984](https://github.com/Progi1984) GH-31 +- PowerPoint2007 Writer : Implement Support of Fill - [@Progi1984](https://github.com/Progi1984) GH-32 + +## Bugfix + +- Allow solid color fill - [@MarkBaker](https://github.com/MarkBaker) +- Table width setting Office 2007 - [@maartenba](https://github.com/maartenba) CP-3910 +- Bullet characters in Master Slide Layouts of template file become corrupted - [@maartenba](https://github.com/maartenba) CP-4598 +- Generated files cannot be opened in Office 08 for Mac OSX - [@maartenba](https://github.com/maartenba) CP-3424 +- Table Cell Borders Not Displaying Correctly - [@maartenba](https://github.com/maartenba) CP-2541 +- Multiple Master Slides are not supported - [@maartenba](https://github.com/maartenba) CP-4597 +- Images in Layouts other than first Master Slide within Template file causes corrupted PPTX - [@maartenba](https://github.com/maartenba) CP-4596 +- Fixed A3 and A4 formats dimensions - [@delphiki](https://github.com/delphiki) GH-16 +- Fixed custom document layout - [@delphiki](https://github.com/delphiki) GH-18 +- Filename parameter is required for IWriter::save method - [@sapfeer0k](https://github.com/sapfeer0k) GH-19 +- DocumentLayout: Fix incorrect variable assignment - [@kaiesh](https://github.com/kaiesh) GH-6 +- Hyperlink: Wrong input parameter object type in setHyperlink - [@nynka](https://github.com/nynka) GH-23 +- ODPresentation Writer: ODP writer is locale sensitive in the wrong places - [@Progi1984](https://github.com/Progi1984) GH-21 +- ODPresentation Writer: Display InMemory Image - [@Progi1984](https://github.com/Progi1984) GH-29 +- PowerPoint2007 Writer: Bar3D doesn't display - [@Progi1984](https://github.com/Progi1984) GH-32 +- PowerPoint2007 Writer: Changed PowerPoint2007 writer attributes to protected - [@delphiki](https://github.com/delphiki) GH-20 +- PowerPoint2007 Writer: Scatter chart with numerical X values not working well - [@Progi1984](https://github.com/Progi1984) GH-3 +- Shape RichText: Support of Vertical Alignment in PowerPoint2007 - [@Progi1984](https://github.com/Progi1984) GH-35 + +## Miscellaneous + +- Rename PHPPowerpoint.php to PHPPowerPoint.php - [@maartenba](https://github.com/maartenba) CP-1165 +- Create build script using Phing - [@maartenba](https://github.com/maartenba) CP-5270 +- QA: Prepare `.travis.yml` and `phpcs.xml` for Travis build passing - [@Progi1984](https://github.com/Progi1984) [@ivanlanin](https://github.com/ivanlanin) +- QA: Initiate unit tests - [@Progi1984](https://github.com/Progi1984) [@ivanlanin](https://github.com/ivanlanin) +- QA: Cleanup source code for PSR dan PHPDoc compatibility - [@ivanlanin](https://github.com/ivanlanin) +- QA: Unit Tests - [@Progi1984](https://github.com/Progi1984) & [@ivanlanin](https://github.com/ivanlanin) +- Doc: Initiate documentation - [@ivanlanin](https://github.com/ivanlanin) +- Doc: Move to [Read The Docs](http://phppowerpoint.readthedocs.org) - [@Progi1984](https://github.com/Progi1984) +- Refactor: Change PHPPowerPoint_Shape_Shadow to PHPPowerPoint_Style_Shadow because it's a style, not a shape - [@ivanlanin](https://github.com/ivanlanin) +- Refactor: Change PHPPowerPoint_SlideIterator to PHPPowerPoint_Slide_Iterator - [@ivanlanin](https://github.com/ivanlanin) diff --git a/docs/changes/0.3.0.md b/docs/changes/0.3.0.md new file mode 100644 index 0000000000..995ecda0a9 --- /dev/null +++ b/docs/changes/0.3.0.md @@ -0,0 +1,15 @@ +# 0.3.0 - 2014-09-22 + +## Features +- PowerPoint97 Reader : Implement Basic Reader - [@Progi1984](https://github.com/Progi1984) GH-15 GH-14 GH-4 +- ODPresentation Writer : Ability to set auto shrink text - [@Progi1984](https://github.com/Progi1984) GH-28 +- Make package PSR-4 compliant. Autoload classes by composer out of the box - [@Djuki](https://github.com/Djuki) GH-41 + +## Bugfix +- PowerPoint2007 Writer : Powerpoint Repair Error in Office 2010 - [@Progi1984](https://github.com/Progi1984) GH-39 +- PowerPoint2007 Writer : BUG: Repair Error / Wrong anchor if you don't set vertical alignment different to VERTICAL_BASE - [@fregge](https://github.com/fregge) GH-42 +- PowerPoint2007 Writer : Keynote incompatibility - [@catrane](https://github.com/catrane) CP#237322 / [@Progi1984](https://github.com/Progi1984) GH-46 + +## Miscellaneous +- QA : Move AbstractType for Chart - [@Progi1984](https://github.com/Progi1984) +- QA : Unit Tests - [@Progi1984](https://github.com/Progi1984) \ No newline at end of file diff --git a/docs/changes/0.4.0.md b/docs/changes/0.4.0.md new file mode 100644 index 0000000000..b2742ed111 --- /dev/null +++ b/docs/changes/0.4.0.md @@ -0,0 +1,42 @@ +# 0.4.0 - 2015-07-07 + +## Features +- Added support for grouping shapes together in a Group - [@Pr0phet](https://github.com/Pr0phet) GH-68 +- Added support for calculating the offset and extent on a Slide. - [@Pr0phet](https://github.com/Pr0phet) GH-68 +- Added support for Horizontal bar chart - [@rdoepke](https://github.com/rdoepke) [@Progi1984](https://github.com/Progi1984) GH-58 +- Added support for hyperlink on picture (ODPresentation & PowerPoint2007) - [@Progi1984](https://github.com/Progi1984) GH-49 +- Added support for hyperlink on richtext (PowerPoint2007) - [@JewrassicPark](https://github.com/JewrassicPark) GH-49 +- Added support for notes slide (ODPresentation & PowerPoint2007) - [@Progi1984](https://github.com/Progi1984) [@JewrassicPark](https://github.com/JewrassicPark) GH-63 +- Added option for explosion in Pie3D Chart (ODPresentation & PowerPoint2007) - [@Progi1984](https://github.com/Progi1984) GH-76 +- ODPresentation Writer : Support for fill in RichText - [@Progi1984](https://github.com/Progi1984) GH-79 +- ODPresentation Writer : Support for border style in RichText - [@Progi1984](https://github.com/Progi1984) GH-79 +- ODPresentation Writer : Support for Area Chart - [@Progi1984](https://github.com/Progi1984) GH-82 +- PowerPoint2007 Writer : Support for Area Chart - [@Progi1984](https://github.com/Progi1984) GH-82 +- ODPresentation Writer : Support for Bar Chart - [@Progi1984](https://github.com/Progi1984) GH-82 +- PowerPoint2007 Writer : Support for Bar Chart - [@Progi1984](https://github.com/Progi1984) GH-82 +- Added units in DocumentLayout - [@Progi1984](https://github.com/Progi1984) GH-87 +- Added support for transitions between slides - [@Progi1984](https://github.com/Progi1984) +- ODPresentation Writer : Support for Pie Chart & Stack Percent Bar Charts - [@jrking4](https://github.com/jrking4) GH-108 +- PowerPoint2007 Writer : Support for Pie Chart & Stack Percent Bar Charts - [@jrking4](https://github.com/jrking4) GH-108 + +## Bugfix +- PSR-0 via composer broken - [@Progi1984](https://github.com/Progi1984) GH-51 +- ODPresentation Writer : Title in Legend in chart doesn't displayed - [@Progi1984](https://github.com/Progi1984) GH-79 +- ODPresentation Writer : Segments in Pie3D Chart are now in clockwise order, as in PowerPoint2007 Writer - [@Progi1984](https://github.com/Progi1984) GH-79 +- ODPresentation Writer : Axis in Line Chart have not tick marks displayed, as in PowerPoint2007 Writer - [@Progi1984](https://github.com/Progi1984) GH-79 +- ODPresentation Writer : Shadow don't work for RichTextShapes - [@Progi1984](https://github.com/Progi1984) GH-81 +- PowerPoint2007 Writer : Fill don't work for RichTextShapes - [@Progi1984](https://github.com/Progi1984) GH-61 +- PowerPoint2007 Writer : Border don't work for RichTextShapes - [@Progi1984](https://github.com/Progi1984) GH-61 +- PowerPoint2007 Writer : Hyperlink in table doesn't work - [@Progi1984](https://github.com/Progi1984) GH-70 +- PowerPoint2007 Writer : AutoFitNormal works with options (fontScale & lineSpacingReduction) - [@Progi1984](https://github.com/Progi1984) [@desigennaro](https://github.com/desigennaro) GH-71 +- PowerPoint2007 Writer : Shadow don't work for RichTextShapes - [@Progi1984](https://github.com/Progi1984) GH-81 +- PowerPoint2007 Writer : Visibility of the Title doesn't work - [@Progi1984](https://github.com/Progi1984) GH-107 +- Refactor findLayoutIndex to findLayoutId where it assumes the slideLayout order was sorted. IMPROVED: unit tests - [@kenliau](https://github.com/kenliau) GH-95 + +## Miscellaneous +- Improved the sample 04-Table for having a Text Run in a Cell - [@Progi1984](https://github.com/Progi1984) GH-84 +- Improved the sample 04-Table for having two links in a Cell - [@Progi1984](https://github.com/Progi1984) GH-93 +- Improved the documentation about Table Shapes and cell width - [@Progi1984](https://github.com/Progi1984) GH-104 +- Some parts of code shared between PHPOffice projects have been moved to PhpOffice/Common - [@Progi1984](https://github.com/Progi1984) +- Refactored the PowerPoint97 Reader for managing the group shape and improving evolutions - [@Progi1984](https://github.com/Progi1984) GH-110 +- Added a sample (12) for PowerPoint97 Reader with tree of the PhpPowerPoint object - [@Progi1984](https://github.com/Progi1984) GH-110 \ No newline at end of file diff --git a/docs/changes/0.5.0.md b/docs/changes/0.5.0.md new file mode 100644 index 0000000000..51c4be8e81 --- /dev/null +++ b/docs/changes/0.5.0.md @@ -0,0 +1,20 @@ +# 0.5.0 - 2015-10-08 + +## Features +- PowerPoint2007 Reader : Initial Commit - [@Progi1984](https://github.com/Progi1984) GH-44 +- ODPresentation Reader : Initial Commit - [@Progi1984](https://github.com/Progi1984) GH-113 + +## Bugfix +- Fixed the sample in Readme.md - [@Progi1984](https://github.com/Progi1984) GH-114 + +## Changes +- PhpOffice\PhpPowerpoint becomes PhpOffice\PhpPresentation - [@Progi1984](https://github.com/Progi1984) GH-25 +- PhpOffice\PhpPowerpoint\Style\Font::setStriketrough has been removed : Use setStrikethrough - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPowerpoint\AbstractShape::getSlide has been removed - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPowerpoint\AbstractShape::setSlide has been removed - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPowerpoint\DocumentLayout::getLayoutXmilli has been removed : getCX(DocumentLayout::UNIT_MILLIMETER) - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPowerpoint\DocumentLayout::getLayoutYmilli has been removed : getCY(DocumentLayout::UNIT_MILLIMETER) - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPowerpoint\DocumentLayout::setLayoutXmilli has been removed : setCX(DocumentLayout::UNIT_MILLIMETER) - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPowerpoint\DocumentLayout::setLayoutYmilli has been removed : setCY(DocumentLayout::UNIT_MILLIMETER) - [@Progi1984](https://github.com/Progi1984) +- Update the dependence PhpOffice\Common to 0.2.* - [@Progi1984](https://github.com/Progi1984) +- Migrated Travis CI to legacy - [@Progi1984](https://github.com/Progi1984) GH-115 \ No newline at end of file diff --git a/docs/changes/0.6.0.md b/docs/changes/0.6.0.md new file mode 100644 index 0000000000..7e11fce7cb --- /dev/null +++ b/docs/changes/0.6.0.md @@ -0,0 +1,20 @@ +# 0.6.0 - 2016-01-24 + +## Bugfix +- Documentation : Fixes in the rename of PHPPowerPoint - [@Progi1984](https://github.com/Progi1984) GH-127 +- ODPresentation : Exclude SVM files for reader - [@Progi1984](https://github.com/Progi1984) GH-141 +- PowerPoint2007 Writer : Bugfix for opening PPTX on Mac - [@thsteinmetz](https://github.com/thsteinmetz) GH-89 + +## Changes +- PhpOffice\PhpPresentation\getProperties has been deprecated for PhpOffice\PhpPresentation\getDocumentProperties - [@Progi1984](https://github.com/Progi1984) GH-154 +- PhpOffice\PhpPresentation\setProperties has been deprecated for PhpOffice\PhpPresentation\setDocumentProperties - [@Progi1984](https://github.com/Progi1984) GH-154 +- PhpOffice\PhpPowerpoint\Style\Alignment::setLevel can now be defined great than 8 - [@Progi1984](https://github.com/Progi1984) GH-141 + +## Features +- ODPresentation Reader/Writer : Name of the slide - [@Progi1984](https://github.com/Progi1984) GH-121 +- ODPresentation Reader/Writer : Slide Background Color or Image - [@Progi1984](https://github.com/Progi1984) GH-152 +- PowerPoint2007 Reader : Support for Layout Name - [@Progi1984](https://github.com/Progi1984) GH-144 +- PowerPoint2007 Reader/Writer : Mark as final - [@Progi1984](https://github.com/Progi1984) GH-118 +- PowerPoint2007 Reader/Writer : Set default zoom value for presentation - [@Progi1984](https://github.com/Progi1984) GH-122 +- PowerPoint2007 Reader/Writer : Slide Background Color or Image - [@Progi1984](https://github.com/Progi1984) GH-152 +- PowerPoint2007 Reader/Writer : Add Properties for allowing loop continuously until 'Esc' - [@Progi1984](https://github.com/Progi1984) GH-154 \ No newline at end of file diff --git a/docs/changes/0.7.0.md b/docs/changes/0.7.0.md new file mode 100644 index 0000000000..730e6e0d97 --- /dev/null +++ b/docs/changes/0.7.0.md @@ -0,0 +1,37 @@ +# 0.7.0 - 2016-09-12 + +## Bugfix +- Fixed the image project - [@mvargasmoran](https://github.com/mvargasmoran) GH-177 +- PowerPoint2007 Writer : Bugfix for printing slide notes - [@JewrassicPark](https://github.com/JewrassicPark) [@Progi1984](https://github.com/Progi1984) GH-179 + +## Changes +- PhpOffice\PhpPresentation\Writer\ODPresentation : Move to Design Pattern Decorator - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPresentation\Writer\PowerPoint2007 : Move to Design Pattern Decorator - [@Progi1984](https://github.com/Progi1984) +- PhpOffice\PhpPresentation\Shape\Type\AbstracType\getData has been deprecated for PhpOffice\PhpPresentation\Shape\Type\AbstracType\getSeries - [@Progi1984](https://github.com/Progi1984) GH-169 +- PhpOffice\PhpPresentation\Shape\Type\AbstracType\setData has been deprecated for PhpOffice\PhpPresentation\Shape\Type\AbstracType\setSeries - [@Progi1984](https://github.com/Progi1984) GH-169 +- Added documentation for chart series (font, outline, marker) - [@Progi1984](https://github.com/Progi1984) GH-169 +- Internal Structure for Drawing Shape - [@Progi1984](https://github.com/Progi1984) GH-192 +- Documentation about manual installation - [@danielbair](https://github.com/danielbair) GH-254 + +## Features +- ODPresentation & PowerPoint2007 Writer : Add support for Comment - [@Progi1984](https://github.com/Progi1984) GH-116 +- ODPresentation & PowerPoint2007 Writer : Thumbnail of the presentation - [@Progi1984](https://github.com/Progi1984) GH-125 +- ODPresentation & PowerPoint2007 Writer : Add support for Gridlines in Chart - [@Progi1984](https://github.com/Progi1984) GH-129 +- ODPresentation & PowerPoint2007 Writer : Support for images in base 64 - [@Progi1984](https://github.com/Progi1984) GH-168 +- ODPresentation & PowerPoint2007 Writer : Marker of Series in Line & Scatter chart is customizable - [@Progi1984](https://github.com/Progi1984) GH-169 +- ODPresentation & PowerPoint2007 Writer : Outline of Series in Line & Scatter chart is customizable - [@Progi1984](https://github.com/Progi1984) GH-169 +- ODPresentation & PowerPoint2007 & Serialized Writer : Support for Zip Adapter - [@Progi1984](https://github.com/Progi1984) GH-176 +- ODPresentation & PowerPoint2007 Writer : language property to TextElement - [@skrajewski](https://github.com/skrajewski) & [@Progi1984](https://github.com/Progi1984) GH-180 +- ODPresentation & PowerPoint2007 Writer : Add Font Support For Chart Axis - [@jrking4](https://github.com/jrking4) GH-186 +- ODPresentation & PowerPoint2007 Writer : Support for video - [@Progi1984](https://github.com/Progi1984) GH-123 +- ODPresentation & PowerPoint2007 Writer : Support for Visibility for slides - [@Progi1984](https://github.com/Progi1984) +- PowerPoint2007 Reader : Layout Management - [@vincentKool](https://github.com/vincentKool) [@Progi1984](https://github.com/Progi1984) GH-161 +- PowerPoint2007 Reader : Slide size - [@loverslcn](https://github.com/loverslcn) [@Progi1984](https://github.com/Progi1984) GH-246 +- PowerPoint2007 Reader : Bullet Color - [@Progi1984](https://github.com/Progi1984) GH-257 +- PowerPoint2007 Reader : Line Spacing - [@Progi1984](https://github.com/Progi1984) GH-257 +- PowerPoint2007 Writer : Presentation with predefined View Type - [@Progi1984](https://github.com/Progi1984) GH-120 +- PowerPoint2007 Writer : Implement alpha channel to Fills - [@Dayjo](https://github.com/Dayjo) GH-203 / [@Progi1984](https://github.com/Progi1984) GH-215 +- PowerPoint2007 Writer : Implement Animations - [@JewrassicPark](https://github.com/JewrassicPark) GH-214 / [@Progi1984](https://github.com/Progi1984) GH-217 +- PowerPoint2007 Writer : Layout Management - [@vincentKool](https://github.com/vincentKool) [@Progi1984](https://github.com/Progi1984) GH-161 +- PowerPoint2007 Writer : Bullet Color - [@piotrbelina](https://github.com/piotrbelina) GH-249 +- PowerPoint2007 Writer : Line Spacing - [@piotrbelina](https://github.com/piotrbelina) GH-249 \ No newline at end of file diff --git a/docs/changes/0.8.0.md b/docs/changes/0.8.0.md new file mode 100644 index 0000000000..fe7ed9059c --- /dev/null +++ b/docs/changes/0.8.0.md @@ -0,0 +1,30 @@ +# 0.8.0 - 2017-04-03 + +## Bugfix +- PowerPoint2007 Writer : Fixed the marker on line chart when symbol is none - [@Napryc](https://github.com/Napryc) GH-211 +- PowerPoint2007 Writer : Fixed the format value in Pie Chart - [@Napryc](https://github.com/Napryc) GH-212 +- PowerPoint2007 Writer : The presentation need repairs on Mac [@jrking4](https://github.com/jrking4) GH-266 GH-276 +- PowerPoint2007 Writer : Fix for PowerPoint2007 Writer (Need repair) [@Progi1984](https://github.com/Progi1984) GH-266 GH-274 GH-276 GH-282 GH-302 +- PowerPoint2007 Writer : Fixed the axis title in bar chart - [@pgee70](https://github.com/pgee70) GH-267 +- PowerPoint2007 Writer : Fixed the label position in bar chart - [@pgee70](https://github.com/pgee70) GH-268 +- PowerPoint2007 Writer : Support of margins in cell in table - [@carlosafonso](https://github.com/carlosafonso) [@Progi1984](https://github.com/Progi1984) GH-273 GH-315 +- Fixed the corruption of file when an addExternalSlide is called - [@Progi1984](https://github.com/Progi1984) GH-240 + +## Changes +- Misc : Added two methods for setting Border & Fill in Legend - [@Progi1984](https://github.com/Progi1984) GH-265 + +## Features +- ODPresentation Writer : Show/Hide Value / Name / Series Name in Chart - [@Progi1984](https://github.com/Progi1984) GH-272 +- ODPresentation Writer : Axis Bounds in Chart - [@Progi1984](https://github.com/Progi1984) GH-269 +- PowerPoint97 Reader : Support of Slide Note - [@Progi1984](https://github.com/Progi1984) GH-226 +- PowerPoint2007 Reader : Support of Shape Table - [@Progi1984](https://github.com/Progi1984) GH-240 +- PowerPoint2007 Reader : Support of Slide Note - [@Progi1984](https://github.com/Progi1984) GH-226 +- PowerPoint2007 Reader : Support text direction in Alignment for Table - [@Progi1984](https://github.com/Progi1984) GH-218 +- PowerPoint2007 Writer : Implement character spacing - [@jvanoostrom](https://github.com/jvanoostrom) GH-301 +- PowerPoint2007 Writer : Axis Bounds in Chart - [@Progi1984](https://github.com/Progi1984) GH-269 +- PowerPoint2007 Writer : Implement Legend Key in Series for Chart - [@Progi1984](https://github.com/Progi1984) GH-319 +- PowerPoint2007 Writer : Support text direction in Alignment for Table - [@SeregPie](https://github.com/SeregPie) GH-218 +- PowerPoint2007 Writer : Support tick mark & unit in Axis for Chart - [@Faab](https://github.com/Faab) GH-218 +- PowerPoint2007 Writer : Support separator in Series for Chart - [@jphchaput](https://github.com/jphchaput) GH-218 +- PowerPoint2007 Writer : Add support for Outline in Axis - [@Progi1984](https://github.com/Progi1984) GH-255 +- PowerPoint2007 Writer : Support autoscale for Chart - [@Progi1984](https://github.com/Progi1984) GH-293 \ No newline at end of file diff --git a/docs/changes/0.9.0.md b/docs/changes/0.9.0.md new file mode 100644 index 0000000000..7fa49d7bc8 --- /dev/null +++ b/docs/changes/0.9.0.md @@ -0,0 +1,12 @@ +# 0.9.0 - 2017-07-05 + +## Bugfix +- PowerPoint2007 Writer : Margins in table cell - [@Progi1984](https://github.com/Progi1984) GH-347 + +## Changes +- PowerPoint2007 Writer : Write percentage values with a trailing percent sign instead of formatted as 1000th of a percent to comply with the standard - [@k42b3](https://github.com/k42b3) GH-307 + +## Features +- PowerPoint2007 Writer : Implemented XSD validation test case according to the ECMA/ISO standard - [@k42b3](https://github.com/k42b3) GH-307 +- PowerPoint2007 Writer : Implement visibility for axis - [@kw-pr](https://github.com/kw-pr) [@Progi1984](https://github.com/Progi1984) GH-356 +- PowerPoint2007 Writer : Implement gap width in Bar(3D) Charts - [@Progi1984](https://github.com/Progi1984) GH-358 \ No newline at end of file diff --git a/docs/changes/1.0.0.md b/docs/changes/1.0.0.md new file mode 100644 index 0000000000..c23af1e93b --- /dev/null +++ b/docs/changes/1.0.0.md @@ -0,0 +1,110 @@ +# 1.0.0 - WIP + +## Bugfix +- PowerPoint2007 Writer : Text is subscripted when set superscript to false - [[@qmachard]](https://github.com/qmachard])(https://github.com/qmachard) GH-360 +- Core : Defining width & height of a shape don't return any error if width & height were equal to 0 - [[@surger]](https://github.com/surger])(https://github.com/surger) GH-555 +- ODPresentation Writer : Display axis title depending the visibility - [[@Progi1984]](https://github.com/Progi1984])(https://github.com/Progi1984) GH-410 + +## Changes +- Dropped support for HHVM - [@sunspikes](https://github.com/sunspikes) GH-556 +- PHP 7.1 is now supported - [@Progi1984](https://github.com/Progi1984) GH-355 +- Added support PHP 7.4 to 8.0 & Removed support PHP < 7.1 - [@Progi1984](https://github.com/Progi1984) GH-636 +- Added support for PHP 8.1 - [@Progi1984](https://github.com/Progi1984) GH-661 +- Removed deprecated methods/classes - [@Progi1984](https://github.com/Progi1984) GH-650 +- Migrated use of PHPExcel to PhpSpreadsheet - [@Progi1984](https://github.com/Progi1984) GH-652 +- PhpOffice\PhpPresentation\Style\Color : Define only the transparency - [@Progi1984](https://github.com/Progi1984) GH-370 +- PowerPoint2007 Reader : Background Color based on SchemeColor - [@Progi1984](https://github.com/Progi1984) GH-397 +- PowerPoint2007 Reader : Support for hyperlinks under pictures - [@ulziibuyan](https://github.com/ulziibuyan) +- PowerPoint2007 Reader : Load images in their initial format (and not by default in PNG) - [@polidog](https://github.com/polidog) GH-553 + +## Features +- Support for bar overlap in 2D bar charts - [@mindline](https://github.com/mindline-analytics) GH-667 + - PowerPoint2007 Writer +- Support for the position of Legend in ODPresentation Writer - [@Progi1984](https://github.com/Progi1984) GH-355 +- Support for DoughnutChart - [@Progi1984](https://github.com/Progi1984) GH-355 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for fill for transparent image - [@Progi1984](https://github.com/Progi1984) & [@JewrassicPark](https://github.com/JewrassicPark) GH-370 + - ODPresentation Reader + - ODPresentation Writer + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for Slideshow Type (Fullscreen/Window/Kiosk mode) - [@zmip](https://github.com/zmip) GH-588 & [@Progi1986](https://github.com/Progi1986) GH-656 + - ODPresentation Reader + - ODPresentation Writer + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for RTL in Alignment & Font Format (Latin/East Asian/Complex Script) - [@amirakbari](https://github.com/amirakbari) GH-629 & [@Progi1986](https://github.com/Progi1986) GH-657 + - ODPresentation Reader + - ODPresentation Writer + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for Border & Fill for Chart's Marker in PowerPoint2007 Writer - [@ksmeeks0001](https://github.com/ksmeeks0001) GH-627 & [@Progi1986](https://github.com/Progi1986) GH-658 +- Support for rotation for axis label - [@Progi1986](https://github.com/Progi1986) GH-410 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for managing missing values in Chart - [@TonisOrmisson](https://github.com/TonisOrmisson) GH-581 & [@Progi1986](https://github.com/Progi1986) GH-659 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for defining ticks label position for Axis in Chart - [@Web](https://github.com/Web)-Mobiledev GH-591 & [@Progi1986](https://github.com/Progi1986) GH-660 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for interval unit for Chart's Axis - [@Progi1984](https://github.com/Progi1984) GH-546 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for line smooth for line and scatter chart - [@ksmeeks0001](https://github.com/ksmeeks0001) GH-626 & [@Progi1984](https://github.com/Progi1984) GH-662 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for column spacing for RichText - [@zoff83](https://github.com/zoff83) GH-617 & [@Progi1984](https://github.com/Progi1984) GH-663 + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for line spacing mode & spacing before/after for Paragraph - [@zoff83](https://github.com/zoff83) GH-617 & [@Progi1984](https://github.com/Progi1984) GH-663 + - ODPresentation Reader + - ODPresentation Writer + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for custom document properties - [@Progi1984](https://github.com/Progi1984) GH-313 + - ODPresentation Reader + - ODPresentation Writer + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for RadarChart - [@Progi1984](https://github.com/Progi1984) GH-253 + - ODPresentation Writer + - PowerPoint2007 Writer +- Support for Drawing (SVG format) - [@Aggiekev](https://github.com/Aggiekev) GH-531 & [@Progi1984](https://github.com/Progi1984) GH-666 + - ODPresentation Reader + - ODPresentation Writer + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Support for Geometric form/AutoShape - [@Progi1984](https://github.com/Progi1984) GH-545 + - PowerPoint2007 Writer + +## Project Management +- Migrated from Travis CI to Github Actions - [@Progi1984](https://github.com/Progi1984) GH-635 +- Enabled PHPStan - [@Progi1984](https://github.com/Progi1984) GH-639 +- Enabled PHPCSFixer - [@Progi1984](https://github.com/Progi1984) GH-637 / GH-640 +- Added link to Coveralls - [@Progi1984](https://github.com/Progi1984) GH-648 +- Migrated from ReadTheDocs to MkDocs & Github Actions - [@Progi1984](https://github.com/Progi1984) GH-647 +- Added Changelog to MkDocs - [@Progi1984](https://github.com/Progi1984) GH-649 + +## BC Breaks +* Classes have been strict typed +* `PhpOffice\PhpPresentation\PhpPresentation` + * Removed method `getProperties()` (replaced by `getDocumentProperties()`) + * Removed method `getZoom()` (replaced by `getPresentationProperties()->getZoom()`) + * Removed method `isMarkedAsFinal()` (replaced by `getPresentationProperties()->isMarkedAsFinal()`) + * Removed method `markAsFinal($state)` (replaced by `getPresentationProperties()->markAsFinal($state)`) + * Removed method `setProperties($value)` (replaced by `setDocumentProperties()`) + * Removed method `setZoom($zoom)` (replaced by `getPresentationProperties()->setZoom($zoom)`) +* `PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType` + * Removed method `getData()` (replaced by `getSeries()`) + * Removed method `setData($value)` (replaced by `setSeries($value)`) +* `PhpOffice\PhpPresentation\Writer\PowerPoint2007` + * Removed method `getLayoutPack()` + * Removed method `setLayoutPack($pValue)` +* `PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\AbstractLayoutPack` + * Removed class +* `PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\PackDefault` + * Removed class +* `PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\TemplateBased` + * Removed class diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index ffb127fe0d..0000000000 --- a/docs/conf.py +++ /dev/null @@ -1,290 +0,0 @@ -# -*- coding: utf-8 -*- -# -# PhpPresentation documentation build configuration file, created by -# sphinx-quickstart on Fri Mar 14 23:09:26 2014. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = 'PhpPresentation' -copyright = u'2014, PHPPresentation Contributors' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '0.12.0' -# The full version, including alpha/beta/rc tags. -release = version - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PhpPresentation' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'PhpPresentation.tex', u'PhpPresentation Documentation', - u'The PhpPresentation Team', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'PhpPresentation', u'PhpPresentation Documentation', - [u'The PhpPresentation Team'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'PhpPresentation', u'PhpPresentation Documentation', - u'The PhpPresentation Team', 'PhpPresentation', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# -- Options for Epub output --------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = u'PhpPresentation' -epub_author = u'The PhpPresentation Team' -epub_publisher = u'The PhpPresentation Team' -epub_copyright = copyright - -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -#epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - -# Allow duplicate toc entries. -#epub_tocdup = True - -# Highlight PHP without starting ) \ No newline at end of file diff --git a/docs/credits.rst b/docs/credits.rst deleted file mode 100644 index 85987b7508..0000000000 --- a/docs/credits.rst +++ /dev/null @@ -1,8 +0,0 @@ -.. _credits: - -Credits -======= - - Images from chart page come from the `LibreOffice Core `. - - Some definitions come from the `Office Open XML `. \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000000..c770cee346 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,32 @@ +# Frequently asked questions + +## Is this the same with PHPPowerPoint that I found in CodePlex? + +No. This one is much better with tons of new features that you can’t find in PHPPowerPoint 0.1. The development in CodePlex is halted and switched to GitHub to allow more participation from the crowd. The more the merrier, right? + +## I’ve been running PHPPowerPoint from CodePlex flawlessly, but I can’t use the latest PHPPresentation from GitHub. Why? + +PHPPresentation requires **PHP 5.3+** since **v0.2**, while PHPPowerPoint **v0.1** from CodePlex can run with **PHP 5.2**. + +There’s a lot of new features that we can get from **PHP 5.3** and it’s been around since 2009! You should upgrade your PHP version to use PHPPresentation **v0.2+**. + +## Why am I getting a class not found error? + +If you have followed the instructions for either adding this package to your `composer.json` or registering the autoloader, then perhaps you forgot to include a `use` statement for the class(es) you are trying to access. + +Here's an example that allows you to refer to the `MemoryDrawing` class without having to specify the full class name in your code: + +``` php +`__, PowerPoint is a `trademark `__. -For avoiding any problems with Microsoft, we decide to change the name to a more logic name, with our panel of readers/writers. \ No newline at end of file diff --git a/docs/general.rst b/docs/general.rst deleted file mode 100644 index d24c884e73..0000000000 --- a/docs/general.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. _general: - -General usage -============= - -Basic example -------------- - -The following is a basic example of the PHPPresentation library. More examples -are provided in the `samples -folder `__. - -.. code-block:: php - - require_once 'src/PhpPresentation/Autoloader.php'; - \PhpOffice\PhpPresentation\Autoloader::register(); - - $objPHPPresentation = new PhpPresentation(); - - // Create slide - $currentSlide = $objPHPPresentation->getActiveSlide(); - - // Create a shape (drawing) - $shape = $currentSlide->createDrawingShape(); - $shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppresentation_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); - $shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - - // Create a shape (text) - $shape = $currentSlide->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); - $shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); - $textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); - $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor( new Color( 'FFE06B20' ) ); - - $oWriterPPTX = IOFactory::createWriter($objPHPPresentation, 'PowerPoint2007'); - $oWriterPPTX->save(__DIR__ . "/sample.pptx"); - $oWriterODP = IOFactory::createWriter($objPHPPresentation, 'ODPresentation'); - $oWriterODP->save(__DIR__ . "/sample.odp"); - -Document information --------------------- - -You can set the document information such as title, creator, and company -name. Use the following functions : - -.. code-block:: php - - $properties = $objPHPPresentation->getProperties(); - $properties->setCreator('My name'); - $properties->setCompany('My factory'); - $properties->setTitle('My title'); - $properties->setDescription('My description'); - $properties->setCategory('My category'); - $properties->setLastModifiedBy('My name'); - $properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); - $properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); - $properties->setSubject('My subject'); - $properties->setKeywords('my, key, word'); - - -Presentation Properties ------------------------ - -You can define some properties which are relative to the presentation, like the zoom or the thumbnail. - -Comments -```````` - -You can define if the presentation display or not the comments with the method ``setCommentVisible``. - -.. code-block:: php - - $oPresentation = new PhpPresentation(); - $oProperties = $oPresentation->getPresentationProperties(); - // Get the display for comment - var_export($oProperties->isCommentVisible()); - // Output : false - // Enable the display for comment - $oProperties->setCommentVisible(true); - // Get the display for comment - var_export($oProperties->isCommentVisible()); - // Output : true - -Last View -````````` - -You can define the last view of the presentation with the method ``setLastView``. - -.. code-block:: php - - $oPresentation = new PhpPresentation(); - $oProperties = $oPresentation->getPresentationProperties(); - // Get the last view of the presentation - echo $oProperties->getZoom(); - // Output : PresentationProperties::VIEW_SLIDE - // Set the last view of the presentation - $oProperties->setLastView(PresentationProperties::VIEW_NOTES); - // Get the last view of the presentation - echo $oProperties->getZoom(); - // Output : PresentationProperties::VIEW_NOTES - -Thumbnail -````````` - -You can define the thumbnail of the presentation with the method ``setThumbnailPath``. - -.. code-block:: php - - $oPresentation = new PhpPresentation(); - $oProperties = $oPresentation->getPresentationProperties(); - // Set path of the thumbnail - $oProperties->setThumbnailPath(__DIR__.'\resources\phppowerpoint_logo.gif'); - // Get path of the thumbnail - echo $oProperties->getThumbnailPath(); - -Zoom -```` - -You can define the zoom of the presentation with the method ``setZoom``. - -.. code-block:: php - - $oPresentation = new PhpPresentation(); - $oProperties = $oPresentation->getPresentationProperties(); - // Get zoom of the presentation - echo $oProperties->getZoom(); - // Output : 1 - // Set zoom of the presentation (3 = 300%) - $oProperties->setZoom(3); - // Get zoom of the presentation - echo $oProperties->getZoom(); - // Output : 3 diff --git a/docs/images/chart_bar_overlap.png b/docs/images/chart_bar_overlap.png new file mode 100644 index 0000000000..4c79419cb3 Binary files /dev/null and b/docs/images/chart_bar_overlap.png differ diff --git a/docs/images/libreoffice_chart_displayblankas.png b/docs/images/libreoffice_chart_displayblankas.png new file mode 100644 index 0000000000..c37331d778 Binary files /dev/null and b/docs/images/libreoffice_chart_displayblankas.png differ diff --git a/docs/images/presentation_slideshow_type.png b/docs/images/presentation_slideshow_type.png new file mode 100644 index 0000000000..22b5ae85ae Binary files /dev/null and b/docs/images/presentation_slideshow_type.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000000..f6f6fa65d2 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,107 @@ +# + +![PHPPresentation](images/PHPPresentationLogo.png) + +PHPPresentation is a library written in pure PHP that provides a set of +classes to write to different presentation file formats, i.e. +[Microsoft Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) +(`.pptx`) and OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (`.odp`). + +PHPPresentation is an open source project licensed under the terms of [LGPL +version 3](https://github.com/PHPOffice/PHPPresentation/blob/develop/COPYING.LESSER). +PHPPresentation is aimed to be a high quality software product by incorporating +[continuous integration and unit testing](https://github.com/PHPOffice/PHPPresentation/actions/workflows/php.yml). +You can learn more about PHPPresentation by reading this Developers' +Documentation. + + +## Features + +- Create an in-memory presentation representation +- Set presentation meta data (author, title, description, etc) +- Add slides from scratch or from existing one +- Supports different fonts and font styles +- Supports different formatting, styles, fills, gradients +- Supports hyperlinks and rich-text strings +- Add images with different styles (positioning, rotation, shadow) +- Set printing options (header, footer, page margins, paper size, orientation) +- Input from different file formats: + - PowerPoint 97 (.ppt) + - PowerPoint 2007 (.pptx) + - OpenDocument Presentation (.odp) + - Serialized Spreadsheet +- Output to different file formats: + - PowerPoint 2007 (.pptx) + - OpenDocument Presentation (.odp) + - Serialized Spreadsheet +- ... and lots of other things! + +## File formats + +Below are the supported features for each file formats. + + +### Writers + +| Features | | HTML | ODP | PDF | PPTX | +|---------------------------|----------------------|-------|-------|-------|-------| +| **Document** | Mark as final | | | | :material-check: | +| **Document Properties** | Standard | | :material-check: | | :material-check: | +| | Custom | | :material-check: | | :material-check: | +| **Slides** | | | :material-check: | | :material-check: | +| | Name | | :material-check: | | | +| **Element Shape** | AutoShape | | | | :material-check: | +| | Image | | :material-check: | | :material-check: | +| | Hyperlink | | :material-check: | | :material-check: | +| | Line | | :material-check: | | :material-check: | +| | MemoryImage | | :material-check: | | :material-check: | +| | RichText | | :material-check: | | :material-check: | +| | Table | | :material-check: | | :material-check: | +| | Text | | :material-check: | | :material-check: | +| **Charts** | Area | | :material-check: | | :material-check: | +| | Bar | | :material-check: | | :material-check: | +| | Bar3D | | :material-check: | | :material-check: | +| | Doughnut | | :material-check: | | :material-check: | +| | Line | | :material-check: | | :material-check: | +| | Pie | | :material-check: | | :material-check: | +| | Pie3D | | :material-check: | | :material-check: | +| | Radar | | :material-check: | | :material-check: | +| | Scatter | | :material-check: | | :material-check: | + + +### Readers + +| Features | | ODP | PPT | PPTX | +|---------------------------|----------------------|-------|-------|-------| +| **Document** | Mark as final | | | :material-check: | +| **Document Properties** | Standard | :material-check: | | :material-check: | +| | Custom | :material-check: | | :material-check: | +| **Slides** | | :material-check: | | :material-check: | +| | Name | | | | +| **Element Shape** | AutoShape | | | | +| | Image | :material-check: | :material-check: | :material-check: | +| | Hyperlink | :material-check: | :material-check: | :material-check: | +| | RichText | :material-check: | :material-check: | :material-check: | +| | Table | | | | +| | Text | :material-check: | :material-check: | :material-check: | +| **Charts** | Area | | | | +| | Bar | | | | +| | Bar3D | | | | +| | Doughnut | | | | +| | Line | | | | +| | Pie | | | | +| | Pie3D | | | | +| | Radar | | | | +| | Scatter | | | | + + +## Contributing + +We welcome everyone to contribute to PHPPresentation. Below are some of the things that you can do to contribute: + +- Read [our contributing guide](https://github.com/PHPOffice/PHPPresentation/blob/master/CONTRIBUTING.md) +- [Fork us](https://github.com/PHPOffice/PHPPresentation/fork) and [request a pull](https://github.com/PHPOffice/PHPPresentation/pulls) to the [develop](https://github.com/PHPOffice/PHPPresentation/tree/develop) branch +- Submit [bug reports or feature requests](https://github.com/PHPOffice/PHPPresentation/issues) to GitHub +- Follow [@PHPOffice](https://twitter.com/PHPOffice) on Twitter diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index d88c933c42..0000000000 --- a/docs/index.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. PHPPresentation documentation master file, created by - sphinx-quickstart on Fri Mar 14 23:09:26 2014. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to PHPPresentation's documentation -========================================== - -|PHPPresentation| - -PHPPresentation is a library written in pure PHP that provides a set of classes to write to different presentation file formats, i.e. OpenXML (.pptx) and OpenDocument (.odp). PHPPresentation is an open source project licensed under LGPL. - -.. toctree:: - :maxdepth: 2 - - intro - installing - general - slides - shapes - styles - writers - readers - recipes - faq - credits - references - -.. _slidesdocs: - -.. toctree:: - :maxdepth: 2 - :caption: Slides - - slides_animation - -.. _shapesdocs: - -.. toctree:: - :maxdepth: 2 - :caption: Shapes - - shapes_chart - shapes_comment - shapes_drawing - shapes_media - shapes_richtext - shapes_table - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - -.. |PHPPresentation| image:: images/phppowerpoint_logo.gif diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000000..b8b1a0846b --- /dev/null +++ b/docs/install.md @@ -0,0 +1,54 @@ +# Installation + +## Requirements + +Mandatory: + +- PHP 5.3+ +- PHP [ZIP extension](http://php.net/manual/en/book.zip.php) +- PHP [XML Parser extension](http://www.php.net/manual/en/xml.installation.php) + +Optional: + +- PHP [XMLWriter extension](http://php.net/manual/en/book.xmlwriter.php) + + +## Installation + +There are two ways to install PHPPresentation, i.e. via [Composer](http://getcomposer.org) or manually by downloading the library. + +### Using Composer + +To install via Composer, add the following lines to your `composer.json`: + +``` json +{ + "require": { + "phpoffice/phppresentation": "dev-master" + } +} +``` + + +### Using manual install +To install manually: + +* [download PHPOffice\PHPPresentation package from GitHub](https://github.com/PHPOffice/PHPPresentation/archive/master.zip) +* [download PHPOffice\Common package from GitHub](https://github.com/PHPOffice/Common/archive/master.zip) +* extract the package and put the contents to your machine. + + +``` php +`__ extension -- PHP `XML - Parser `__ - extension - -Optional PHP extensions: - -- `XMLWriter `__ - -Installation ------------- - -There are two ways to install PHPPresentation, i.e. via -`Composer `__ or manually by downloading the -library. - -Using Composer -~~~~~~~~~~~~~~ - -To install via Composer, add the following lines to your -``composer.json``: - -.. code-block:: json - - { - "require": { - "phpoffice/phppresentation": "dev-master" - } - } - -Manual install -~~~~~~~~~~~~~~ - -To install manually, `download PHPOffice\PHPPresentation package from -GitHub `__ -and `download PHPOffice\Common package from -GitHub `__. -Extract the package and put the contents to your machine. - -.. code-block:: php - - require_once 'path/to/PhpPresentation/src/PhpPresentation/Autoloader.php'; - \PhpOffice\PhpPresentation\Autoloader::register(); - - require_once 'path/to/PhpOffice/Common/src/Common/Autoloader.php'; - \PhpOffice\Common\Autoloader::register(); - -Using samples -------------- - -After installation, you can browse and use the samples that we've -provided, either by command line or using browser. If you can access -your PHPPresentation library folder using browser, point your browser to the -``samples`` folder, e.g. ``http://localhost/PhpPresentation/samples/``. diff --git a/docs/intro.rst b/docs/intro.rst deleted file mode 100644 index 74b5bca5bf..0000000000 --- a/docs/intro.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. _intro: - -Introduction -============ - -PHPPresentation is a library written in pure PHP that provides a set of -classes to write to different presentation file formats, i.e. Microsoft -`Office Open XML ` -(.pptx) and OASIS `Open Document Format for Office Applications -`__ (.odp). - -PHPPresentation is an open source project licensed under the terms of `LGPL -version 3 `__. -PHPPresentation is aimed to be a high quality software product by incorporating -`continuous integration `__ and -`unit testing `__. -You can learn more about PHPPresentation by reading this Developers' -Documentation and the `API Documentation `__. - -Features --------- - -- Create an in-memory presentation representation -- Set presentation meta data (author, title, description, etc) -- Add slides from scratch or from existing one -- Supports different fonts and font styles -- Supports different formatting, styles, fills, gradients -- Supports hyperlinks and rich-text strings -- Add images with different styles (positioning, rotation, shadow) -- Set printing options (header, footer, page margins, paper size, orientation) -- Output to different file formats: PowerPoint 2007 (.pptx), OpenDocument Presentation (.odp), Serialized Spreadsheet) -- ... and lots of other things! - -File formats ------------- - -Below are the supported features for each file formats. - -Writers -~~~~~~~ - -+---------------------------+----------------------+--------+-------+-------+-------+ -| Features | | PPTX | ODP | HTML | PDF | -+===========================+======================+========+=======+=======+=======+ -| **Document** | Mark as final | ✓ | | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| **Document Properties** | Standard | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Custom | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| **Slides** | | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Name | | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| **Element Shape** | Image | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Hyperlink | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Line | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | MemoryImage | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | RichText | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Table | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Text | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| **Charts** | Bar3D | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Line | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Pie3D | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ -| | Scatter | ✓ | ✓ | | | -+---------------------------+----------------------+--------+-------+-------+-------+ - -Readers -~~~~~~~ -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| Features | | PPTX | ODP | HTML | PDF | PPT | -+===========================+======================+========+=======+=======+=======+=======+ -| **Document** | Mark as final | ✓ | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Document Properties** | Standard | ✓ | ✓ | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Custom | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Slides** | | ✓ | ✓ | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Name | | ✓ | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Element Shape** | Image | ✓ | ✓ | | | ✓ | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Hyperlink | ✓ | ✓ | | | ✓ | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | RichText | ✓ | ✓ | | | ✓ | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Table | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Text | ✓ | ✓ | | | ✓ | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| **Charts** | Bar3D | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Line | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Pie3D | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ -| | Scatter | | | | | | -+---------------------------+----------------------+--------+-------+-------+-------+-------+ - -Contributing ------------- - -We welcome everyone to contribute to PHPPresentation. Below are some of the -things that you can do to contribute: - -- Read `our contributing - guide `__ -- `Fork us `__ and `request - a pull `__ to the - `develop `__ - branch -- Submit `bug reports or feature - requests `__ to GitHub -- Follow `@PHPOffice `__ on Twitter diff --git a/docs/readers.rst b/docs/readers.rst deleted file mode 100644 index 5078761d37..0000000000 --- a/docs/readers.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. _writersreaders: - -Readers -======= - -ODPresentation --------------- - -The name of the reader is ``ODPresentation``. - -.. code-block:: php - - $oReader = IOFactory::createReader('ODPresentation'); - $oReader->load(__DIR__ . '/sample.odp'); - -PowerPoint97 ------------- - -The name of the reader is ``PowerPoint97``. - -.. code-block:: php - - $oReader = IOFactory::createReader('PowerPoint97'); - $oReader->load(__DIR__ . '/sample.ppt'); - -PowerPoint2007 --------------- - -The name of the reader is ``PowerPoint2007``. - -.. code-block:: php - - $oReader = IOFactory::createReader('PowerPoint2007'); - $oReader->load(__DIR__ . '/sample.pptx'); - -Serialized ----------- - -The name of the reader is ``Serialized``. - -.. code-block:: php - - $oReader = IOFactory::createReader('Serialized'); - $oReader->load(__DIR__ . '/sample.phppt'); diff --git a/docs/recipes.rst b/docs/recipes.rst deleted file mode 100644 index ec2c604e82..0000000000 --- a/docs/recipes.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. _recipes: - -Recipes -======= - -How to define the zoom of a presentation ? ------------------------------------------- - -You must define the zoom of your presentation with the method ``setZoom()`` - -.. code-block:: php - - // Default - $zoom = $oPHPPresentation->getZoom(); - // $zoom = 1 - - // Without parameter - $oPHPPresentation->setZoom(); - $zoom = $oPHPPresentation->getZoom(); - // $zoom = true - - // Parameter = false - $oPHPPresentation->setZoom(2.8); - $zoom = $oPHPPresentation->getZoom(); - // $zoom = 2.8 - -How to mark a presentation as final ? -------------------------------------- - -You must define your presentation as it with the method ``markAsFinal()`` - -.. code-block:: php - - // Default - $state = $oPHPPresentation->isMarkedAsFinal(); - // $state = false - - // Without parameter - $oPHPPresentation->markAsFinal(); - $state = $oPHPPresentation->isMarkedAsFinal(); - // $state = true - - // Parameter = false - $oPHPPresentation->markAsFinal(false); - $state = $oPHPPresentation->isMarkedAsFinal(); - // $state = false - - // Parameter = true - $oPHPPresentation->markAsFinal(true); - $state = $oPHPPresentation->isMarkedAsFinal(); - // $state = true diff --git a/docs/references.rst b/docs/references.rst deleted file mode 100644 index bea9c0cc40..0000000000 --- a/docs/references.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. _references: - -References -========== - -OpenXML ---------------------- - -Known as "ISO/IEC 29500, Third edition, 2012-09-01" - -ISO : - -- `Part 1: Fundamentals and Markup Language Reference - `__ -- `Part 2: Open Packaging Conventions - `__ -- `Part 3: Markup Compatibility and Extensibility - `__ -- `Part 4: Transitional Migration Features - `__ - -MSDN : - -- `PowerPoint Viewer `__ -- `DocumentFormat.OpenXml.Presentation Namespace on - MSDN `__ -- `Open XML SDK 2.5 with Validator `__ - -OpenDocument ---------------------- - -- `Oasis OpenDocument Standard Version - 1.2 `__ - - -PowerPoint 97 ---------------- - -- `[MS-PPT]: PowerPoint (.ppt) Binary File Format `__ -- `OffVis : Microsoft Tool for reading PPT files `__ \ No newline at end of file diff --git a/docs/shapes_chart.rst b/docs/shapes_chart.rst deleted file mode 100644 index f5994bd3de..0000000000 --- a/docs/shapes_chart.rst +++ /dev/null @@ -1,247 +0,0 @@ -.. _shapes_chart: - -Charts -====== - -To create a chart, use `createChartShape` method of Slide. - -Example: - -.. code-block:: php - - $chartShape = $slide->createChartShape(); - -Parts ------ - -Axis -^^^^ - -You can define gridlines (minor and major) for each axis (X & Y). -For each gridline, you can custom the width (in points), the fill type and the fill color. - -.. code-block:: php - - use \PhpOffice\PhpPresentation\Shape\Chart\Gridlines; - - $oLine = new Line(); - - $oGridLines = new Gridlines(); - $oGridLines->getOutline()->setWidth(10); - $oGridLines->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); - - $oShape = $oSlide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - $oShape->getPlotArea()->getAxisX()->setMajorGridlines($oGridLines); - -For Axis, you can define the min & max bounds with `setMinBounds` & `setMaxBounds` methods. -For resetting them, you pass null as parameter to these methods. - -.. code-block:: php - - use \PhpOffice\PhpPresentation\Shape\Chart\Gridlines; - - $oLine = new Line(); - - $oShape = $oSlide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - $oShape->getPlotArea()->getAxisX()->setMinBounds(0); - $oShape->getPlotArea()->getAxisX()->setMaxBounds(200); - -You can define outline for each axis (X & Y). - -.. code-block:: php - - $oLine = new Line(); - - $oShape = $oSlide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - $oShape->getPlotArea()->getAxisX()->getOutline()->setWidth(10); - $oShape->getPlotArea()->getAxisX()->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); - -For Axis Y, you can define tick mark with `setMinorTickMark` & `setMajorTickMark` methods. -For resetting them, you pass Axis::TICK_MARK_NONE as parameter to these methods. - -.. code-block:: php - - use \PhpOffice\PhpPresentation\Shape\Chart\Axis; - - $oLine = new Line(); - - $oShape = $oSlide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - $oShape->getPlotArea()->getAxisY()->setMinorTickMark(Axis::TICK_MARK_NONE); - $oShape->getPlotArea()->getAxisY()->setMajorTickMark(Axis::TICK_MARK_INSIDE); - -For Axis Y, you can define unit with `setMinorUnit` & `setMajorUnit` methods. -For resetting them, you pass null as parameter to these methods. - -.. code-block:: php - - use \PhpOffice\PhpPresentation\Shape\Chart\Axis; - - $oLine = new Line(); - - $oShape = $oSlide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - $oShape->getPlotArea()->getAxisY()->setMinorUnit(null); - $oShape->getPlotArea()->getAxisY()->setMajorUnit(0.05); - -You can define visibility for each axis (X & Y). - -.. code-block:: php - - $oLine = new Line(); - - $oShape = $oSlide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - $oShape->getPlotArea()->getAxisX()->setIsVisible(false); - -Title -^^^^^ - -By default, the title of a chart is displayed. -For hiding it, you define its visibility to false. - -.. code-block:: php - - $oLine = new Line(); - $oShape = $slide->createChartShape(); - $oShape->getPlotArea()->setType($oLine); - // Hide the title - $oShape->getTitle()->setVisible(false); - -Series -^^^^^^ - -You can custom the font of a serie. - -.. code-block:: php - $oSeries = new Series('Downloads', $seriesData); - // Define the size - $oSeries->getFont()->setSize(25); - -You can custom the marker of a serie, for Line & Scatter charts. - -.. code-block:: php - use \PhpOffice\PhpPresentation\Shape\Chart\Marker; - - $oSeries = new Series('Downloads', $seriesData); - $oMarker = $oSeries->getMarker(); - $oMarker->setSymbol(Marker::SYMBOL_DASH)->setSize(10); - -You can custom the line of a serie, for Line & Scatter charts. - -.. code-block:: php - use \PhpOffice\PhpPresentation\Style\Outline; - - $oOutline = new Outline(); - // Define the color - $oOutline->getFill()->setFillType(Fill::FILL_SOLID); - $oOutline->getFill()->setStartColor(new Color(Color::COLOR_YELLOW)); - // Define the width (in points) - $oOutline->setWidth(2); - - $oSeries = new Series('Downloads', $seriesData); - $oSeries->setOutline($oOutline); - -You can define the position of the data label. -Each position is described in `MSDN `_ - -.. code-block:: php - - $oSeries = new Series('Downloads', $seriesData); - $oSeries->setLabelPosition(Series::LABEL_INSIDEEND); - -You can define if some informations are displayed. - -.. code-block:: php - - $oSeries = new Series('Downloads', $seriesData); - $oSeries->setSeparator(';'); - $oSeries->setShowCategoryName(true); - $oSeries->setShowLeaderLines(true); - $oSeries->setShowLegendKey(true); - $oSeries->setShowPercentage(true); - $oSeries->setShowSeriesName(true); - $oSeries->setShowValue(true); - -View3D -^^^^^^ - -For enabling the autoscale for a shape, you must reset the height percent. - -.. code-block:: php - - $oShape->getView3D()->setHeightPercent(null); - -Types ------ - -Area -^^^^ - -TODO - -Bar & Bar3D -^^^^^^^^^^^ - -Gap Width -""""""""" - -You can define the gap width between bar or columns clusters. It is defined in percent. -The default value is 150%. The value must be defined between 0 and 500. - -.. code-block:: php - - $oBarChart = new Bar(); - $oBarChart->setGapWidthPercent(250); - -Stacking -"""""""" - -You can stack multiples series in a same chart. After adding multiples series, you can define the bar grouping with `setBarGrouping` method of AbstractTypeBar. - -.. code-block:: php - - $oBarChart = new Bar(); - $oBarChart->addSeries($oSeries1); - $oBarChart->addSeries($oSeries2); - $oBarChart->addSeries($oSeries3); - $oBarChart->setBarGrouping(Bar::GROUPING_CLUSTERED); - // OR - $oBarChart->setBarGrouping(Bar::GROUPING_STACKED); - // OR - $oBarChart->setBarGrouping(Bar::GROUPING_PERCENTSTACKED); - -- Bar::GROUPING_CLUSTERED -.. image:: images/chart_columns_52x60.png - :width: 120px - :alt: Bar::GROUPING_CLUSTERED - -- Bar::GROUPING_STACKED -.. image:: images/chart_columnstack_52x60.png - :width: 120px - :alt: Bar::GROUPING_STACKED - -- Bar::GROUPING_PERCENTSTACKED -.. image:: images/chart_columnpercent_52x60.png - :width: 120px - :alt: Bar::GROUPING_PERCENTSTACKED - - -Line -^^^^ - -TODO - -Pie & Pie3D -^^^^^^^^^^^ - -TODO - -Scatter -^^^^^^^ - -TODO - diff --git a/docs/shapes_comment.rst b/docs/shapes_comment.rst deleted file mode 100644 index 6ad217b474..0000000000 --- a/docs/shapes_comment.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. _shapes_comment: - -Comments -======== - -To create a comment, create an object `Comment`. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Comment; - - $oComment = new Comment(); - $oSlide->addShape($oComment); - -You can define text and date with setters. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Comment; - - $oComment = new Comment(); - $oComment->setText('Text of the Comment'); - $oComment->setDate(time()); - $oSlide->addShape($oComment); - - -Author ------- - -For a comment, you can define the author. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Comment; - use PhpOffice\PhpPresentation\Shape\Comment\Author; - - $oAuthor = new Author(); - $oComment = new Comment(); - $oComment->setAuthor($oAuthor); - $oSlide->addShape($oComment); - -You can define name and initials with setters. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Comment; - use PhpOffice\PhpPresentation\Shape\Comment\Author; - - $oAuthor = new Author(); - $oAuthor->setName('Name of the author'); - $oAuthor->setInitals('Nota'); - $oComment = new Comment(); - $oComment->setAuthor($oAuthor); - $oSlide->addShape($oComment); \ No newline at end of file diff --git a/docs/shapes_drawing.rst b/docs/shapes_drawing.rst deleted file mode 100644 index 7777951f7c..0000000000 --- a/docs/shapes_drawing.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. _shapes_drawing: - -Drawing -======= - -To create a drawing, you have four sources : File, GD, Base64 and ZipFile. - -File ----- - -To create a drawing, use `createDrawingShape` method of slide. - -.. code-block:: php - - $oShape = $oSlide->createDrawingShape(); - $oShape->setName('Unique name') - ->setDescription('Description of the drawing') - ->setPath('/path/to/drawing.filename'); - -It's an alias for : - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Drawing\File; - - $oShape = new File(); - $oShape->setName('Unique name') - ->setDescription('Description of the drawing') - ->setPath('/path/to/drawing.filename'); - $oSlide->addShape($oShape); - -GD --- - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Drawing\Gd; - - $gdImage = @imagecreatetruecolor($width, $height); - - $oShape = new Gd(); - $oShape->setName('Sample image') - ->setDescription('Sample image') - ->setImageResource($gdImage) - ->setRenderingFunction(Drawing\Gd::RENDERING_JPEG) - ->setMimeType(Drawing\Gd::MIMETYPE_DEFAULT); - $oSlide->addShape($oShape); - - -Base64 ------- - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Drawing\Base64; - - $oShape = new Base64(); - $oShape->setName('Sample image') - ->setDescription('Sample image') - ->setImageResource($gdImage) - ->setData('data:image/jpeg;base64,..........'); - $oSlide->addShape($oShape); - -ZipFile -------- - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Drawing\ZipFile; - - $oShape = new ZipFile(); - $oShape->setName('Sample image') - ->setDescription('Sample image') - ->setPath('zip://myzipfile.zip#path/in/zip/img.ext') - $oSlide->addShape($oShape); diff --git a/docs/shapes_media.rst b/docs/shapes_media.rst deleted file mode 100644 index ba3fddec10..0000000000 --- a/docs/shapes_media.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _shapes_table: - -Media -===== - -To create a video, create an object `Media`. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Media; - - $oMedia = new Media(); - $oMedia->setPath('file.wmv'); - // $oMedia->setPath('file.ogv'); - $oSlide->addShape($oMedia); - -You can define text and date with setters. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Media; - - $oMedia = new Media(); - $oMedia->setName('Name of the Media'); - $oSlide->addShape($oMedia); - - -Quirks ------- - -For Windows readers, the prefered file format is WMV. -For Linux readers, the prefered file format is OGV. \ No newline at end of file diff --git a/docs/shapes_richtext.rst b/docs/shapes_richtext.rst deleted file mode 100644 index e8987cb64b..0000000000 --- a/docs/shapes_richtext.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. _shapes_richtext: - -RichText -======== - -Rich text shapes contain paragraphs of texts. To create a rich text shape, use ``createRichTextShape`` method of slide. - -Below are the properties that you can set for a rich text shape. - -- ``wrap`` -- ``autoFit`` -- ``fontScale`` : font scale (in percentage) when autoFit = RichText::AUTOFIT_NORMAL -- ``lnSpcReduction`` : line spacing reduction (in percentage) when autoFit = RichText::AUTOFIT_NORMAL -- ``horizontalOverflow`` -- ``verticalOverflow`` -- ``upright`` -- ``vertical`` -- ``columns`` -- ``bottomInset`` in pixels -- ``leftInset`` in pixels -- ``rightInset`` in pixels -- ``topInset`` in pixels -- ``autoShrinkHorizontal`` (boolean) -- ``autoShrinkVertical`` (boolean) - -Properties that can be set for each paragraphs are as follow. - -- ``alignment`` see *[Alignment](#alignment)* -- ``bulletStyle`` see *[Bullet](#bullet)* -- ``lineSpacing`` see *[LineSpacing](#linespacing)* -- ``font`` see *[Font](#font)* - - -Bullet ------- - -For a paragraph, you can define the bullet style. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; - use PhpOffice\PhpPresentation\Style\Bullet; - - $oParagraph = new Paragraph(); - $oParagraph->getBulletStyle(); - -With the bullet style, you can define the char, the font, the color and the type. - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; - use PhpOffice\PhpPresentation\Style\Bullet; - use PhpOffice\PhpPresentation\Style\Color; - - $oParagraph = new Paragraph(); - $oParagraph->getBulletStyle()->setBulletChar('-'); - $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); - $oParagraph->getBulletStyle()->setBulletColor(new Color(Color::COLOR_RED)); - - -LineSpacing ------------ - -For a paragraph, you can define the line spacing. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; - - $oParagraph = new Paragraph(); - $oParagraph->setLineSpacing(200); - $iLineSpacing = $oParagraph->getLineSpacing(); - - -Run ---- - -For a run, you can define the language. - -Example: - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\RichText\Run; - - $oRun = new Run(); - $oRun->setLanguage('fr-FR'); \ No newline at end of file diff --git a/docs/shapes_table.rst b/docs/shapes_table.rst deleted file mode 100644 index 32be173f4e..0000000000 --- a/docs/shapes_table.rst +++ /dev/null @@ -1,96 +0,0 @@ -.. _shapes_table: - -Tables -====== - -To create a table, use `createTableShape` method of slide. - -Example: - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - -Rows -------- - -A row is a child of a table. For creating a row, use `createRow` method of a Table shape. - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - $row = $tableShape->createRow(); - -Cells -------- -A cell is a child of a row. - -You can access cell objects with `nextCell` method of a Row object. - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - $row = $tableShape->createRow(); - // Get the first cell - $cellA1 = $row->nextCell(); - // Get the second cell - $cellA2 = $row->nextCell(); - -You can access cell object directly. - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - $row = $tableShape->createRow(); - // Get the first cell - $cellA1 = $row->getCell(0); - // Get the second cell - $cellA2 = $row->getCell(1); - - -Define margins of a cell -~~~~~~~~~~~~~~~~~~~~~~~~ -Margins of cells are defined by margins of the first paragraph of cell. -Margins of cells are defined in pixels. - -For defining margins of cell, you can use the `setMargin*` method of a Alignment object of the active paragraph of a Cell object. - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - $row = $tableShape->createRow(); - $cellA1 = $row->nextCell(); - $cellA1->getActiveParagraph()->getAlignment() - ->setMarginBottom(20) - ->setMarginLeft(40) - ->setMarginRight(60) - ->setMarginTop(80); - - -Define the text direction of a cell -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For defining the text direction of cell, you can use the `setTextDirection` method of the `getAlignment` method of a Cell object. -The width is in pixels. - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - $row = $tableShape->createRow(); - $cellA1 = $row->nextCell(); - $cellA1->getAlignment()->setTextDirection(\PhpOffice\PhpPresentation\Style\Alignment::TEXT_DIRECTION_VERTICAL_270); - - -Define the width of a cell -~~~~~~~~~~~~~~~~~~~~~~~~~~ -The width of cells are defined by the width of cell of the first row. -If not defined, all cells widths are calculated from the width of the shape and the number of columns. - -For defining the width of cell, you can use the `setWidth` method of a Cell object. -The width is in pixels. - -.. code-block:: php - - $tableShape = $slide->createTableShape($columns); - $row = $tableShape->createRow(); - $cellA1 = $row->nextCell(); - $cellA1->setWidth(100); \ No newline at end of file diff --git a/docs/slides.rst b/docs/slides.rst deleted file mode 100644 index c1a5e4b681..0000000000 --- a/docs/slides.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _slides: - -Slides -====== - -Slides are pages in a presentation. Slides are stored as a zero based array in ``PHPPresentation`` object. Use ``createSlide`` to create a new slide and retrieve the slide for other operation such as creating shapes for that slide. - -Name ----- - -By default, a slide has not a name. -You can define it with the method ``setName``. - -.. code-block:: php - - $oSlide = $oPHPPresentation->createSlide(); - $oSlide->setName('Title of the slide'); - -Visibility ----------- - -By default, a slide is visible. -You can define it with the method ``setIsVisible``. - -.. code-block:: php - - $oSlide = $oPHPPresentation->createSlide(); - $oSlide->setIsVisible(false); - var_dump($oSlide->isVisible()); \ No newline at end of file diff --git a/docs/slides_animation.rst b/docs/slides_animation.rst deleted file mode 100644 index 662aac38ca..0000000000 --- a/docs/slides_animation.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _slides_animation: - -Animation -========= - -You can create multiples animations in a slide. - -.. code-block:: php - - use PhpOffice\PhpPresentation\Slide\Animation; - - $oAnimation1 = new Animation(); - $oAnimation1->addShape($oDrawing); - $oSlide->addAnimation($oAnimation1); - - $oAnimation2 = new Animation(); - $oAnimation2->addShape($oRichText); - $oSlide->addAnimation($oAnimation2); - diff --git a/docs/slides_layout.rst b/docs/slides_layout.rst deleted file mode 100644 index 7a43144afa..0000000000 --- a/docs/slides_layout.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. _slides_layout: - -Slides Layout -============= - -A slide is a hierarchy of three components : -- The master slide upon which the slide is based : it specifies such properties as the font styles for the title, body, and footer, placeholder positions for text and objects, bullets styles, and background ; -- The slide layout which is applied to the the slide : it permits to override what is specified in the master slide ; -- The slide itself : it contains content and formatting that is not already specified by the master slide and the slide layout - -Placeholders permit to link these three components together in order that the override is possible. - -Master slides -------------- - -You can access to all master slides with the method ``getAllMasterSlides`` or create one with ``createMasterSlide``. - -.. code-block:: php - - $arraySlideMasters = $oPHPPresentation->getAllMasterSlides(); - $oMasterSlide = $oPHPPresentation->createMasterSlide(); - -Slides Layout -------------- - -You can access to all slide layout from a master with the method ``getAllSlideLayouts`` or create one with ``createSlideLayout``. - -.. code-block:: php - - $arraySlideLayouts = $oMasterSlide->getAllSlideLayouts(); - $oSlideLayout = $oMasterSlide->createSlideLayout(); - -Placeholders ------------- - -For each master slide or slide layout, you can add any shape like on a slide. - -.. code-block:: php - - $oShape = $oMasterSlide->createChartShape(); - $oShape = $oSlideLayout->createTableShape(); - -You can define a shape as a placeholder for each level with the method ``setPlaceHolder``. -A shape defined in each level will have an override for its formatting in each level. - -.. code-block:: php - - use PhpOffice\PhpPresentation\Shape\Placeholder; - $oShape->setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_TITLE)); - diff --git a/docs/styles.rst b/docs/styles.rst deleted file mode 100644 index 7278401629..0000000000 --- a/docs/styles.rst +++ /dev/null @@ -1,106 +0,0 @@ -.. _styles: - -Styles -====== - -Fill ----- - -Use this style to define fill of a shape as example below. - -.. code-block:: php - - $shape->getFill() - ->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setRotation(270) - ->setStartColor(new Color('FFCCCCCC')) - ->setEndColor(new Color('FFFFFFFF')); - -Properties: - -- ``fillType`` -- ``rotation`` -- ``startColor`` -- ``endColor`` - -Border ------- - -Use this style to define border of a shape as example below. - -.. code-block:: php - - $shape->getBorder() - ->setLineStyle(Border::LINE_SINGLE) - ->setLineWidth(4) - ->getColor()->setARGB('FFC00000'); - -Properties: - -- ``lineWidth`` -- ``lineStyle`` -- ``dashStyle`` -- ``color`` - -Shadow ------- - -Use this style to define shadow of a shape as example below. - -.. code-block:: php - - $shape->getShadow() - ->setVisible(true) - ->setDirection(45) - ->setDistance(10); - -Properties: - -- ``visible`` -- ``blurRadius`` -- ``distance`` -- ``direction`` -- ``alignment`` -- ``color`` -- ``alpha`` - -Alignment ---------- - -- ``horizontal`` -- ``vertical`` -- ``level`` -- ``indent`` -- ``marginLeft`` -- ``marginRight`` - -Font ----- - -- ``name`` -- ``bold`` -- ``italic`` -- ``superScript`` -- ``subScript`` -- ``underline`` -- ``strikethrough`` -- ``color`` - -Bullet ------- - -- ``bulletType`` -- ``bulletFont`` -- ``bulletChar`` -- ``bulletNumericStyle`` -- ``bulletNumericStartAt`` - -Color ------ - -Colors can be applied to different objects, e.g. font or border. - -.. code-block:: php - - $textRun = $shape->createTextRun('Text'); - $textRun->getFont()->setColor(new Color('C00000')); diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md new file mode 100644 index 0000000000..76e6edc39b --- /dev/null +++ b/docs/usage/introduction.md @@ -0,0 +1,2 @@ +# General + diff --git a/docs/usage/presentation.md b/docs/usage/presentation.md new file mode 100644 index 0000000000..03080aa1c2 --- /dev/null +++ b/docs/usage/presentation.md @@ -0,0 +1,236 @@ +# Presentation + +## Basic code + +The following is a basic example of the PHPPresentation library. More examples are provided in the [samples folder](https://github.com/PHPOffice/PHPPresentation/tree/master/samples/). + +``` php +getActiveSlide(); + +// Create a shape (drawing) +$shape = $currentSlide->createDrawingShape(); +$shape->setName('PHPPresentation logo') + ->setDescription('PHPPresentation logo') + ->setPath('./resources/phppresentation_logo.gif') + ->setHeight(36) + ->setOffsetX(10) + ->setOffsetY(10); +$shape->getShadow()->setVisible(true) + ->setDirection(45) + ->setDistance(10); + +// Create a shape (text) +$shape = $currentSlide->createRichTextShape() + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(170) + ->setOffsetY(180); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); +$textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); +$textRun->getFont()->setBold(true) + ->setSize(60) + ->setColor(new Color('FFE06B20')); + +$writerPPTX = IOFactory::createWriter($presentation, 'PowerPoint2007'); +$writerPPTX->save(__DIR__ . '/sample.pptx'); +$writerODP = IOFactory::createWriter($presentation, 'ODPresentation'); +$writerODP->save(__DIR__ . '/sample.odp'); + +``` + +## Document information + +You can set the document information such as title, creator, and company name. Use the following functions: + +``` php +getProperties(); + +$properties->setCreator('My name'); +$properties->setCompany('My factory'); +$properties->setTitle('My title'); +$properties->setDescription('My description'); +$properties->setCategory('My category'); +$properties->setLastModifiedBy('My name'); +$properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); +$properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); +$properties->setSubject('My subject'); +$properties->setKeywords('my, key, word'); +``` + +### Custom Properties + +You can add custom properties with the method `setCustomProperty`. + +Multiple types are available: +* `DocumentProperties::PROPERTY_TYPE_STRING` for string value, +* `DocumentProperties::PROPERTY_TYPE_BOOLEAN` for boolean value, +* `DocumentProperties::PROPERTY_TYPE_FLOAT` for float value, +* `DocumentProperties::PROPERTY_TYPE_INTEGER` for integer value, +* `DocumentProperties::PROPERTY_TYPE_DATE` for date value, +* `DocumentProperties::PROPERTY_TYPE_UNKNOWN` for unknown type value. + + +``` php +getProperties(); + +// Set the custom property +$properties->setCustomProperty('propertyName', 'propertyValue', DocumentProperties::PROPERTY_TYPE_STRING); + +// Check if a custom property exists +$properties->isCustomPropertySet('unknown'); // return `false` +$properties->isCustomPropertySet('propertyName'); // return `true` + +// Return all custom properties +$properties->getCustomProperties(); // return `['propertyName']` + +// Return value from a custom property +$properties->getCustomPropertyValue('unknown'); // return `null` if not set +$properties->getCustomPropertyValue('propertyName'); // return `propertyValue` + +// Return type from a custom property +$properties->getCustomPropertyType('unknown'); // return `null` if not set +$properties->getCustomPropertyType('propertyName'); // return `DocumentProperties::PROPERTY_TYPE_STRING` +``` + +## Presentation Properties + +You can define some properties which are relative to the presentation, like the zoom or the thumbnail. + +### Comments + +You can define if the presentation display or not the comments with the method `setCommentVisible`. + +``` php +getPresentationProperties(); +// Get the display for comment +var_export($properties->isCommentVisible()); +// Output : false +// Enable the display for comment +$properties->setCommentVisible(true); +// Get the display for comment +var_export($properties->isCommentVisible()); +// Output : true +``` + +### Last View + +You can define the last view of the presentation with the method `setLastView`. + +``` php +getPresentationProperties(); +// Get the last view of the presentation +echo $properties->getZoom(); +// Output : PresentationProperties::VIEW_SLIDE +// Set the last view of the presentation +$properties->setLastView(PresentationProperties::VIEW_NOTES); +// Get the last view of the presentation +echo $properties->getZoom(); +// Output : PresentationProperties::VIEW_NOTES +``` + +### Mark as final + +You must define your presentation as final with the method `markAsFinal()` + +``` php +isMarkedAsFinal(); +// $state = false + +// Without parameter +$presentation->markAsFinal(); +$state = $presentation->isMarkedAsFinal(); +// $state = true + +// Parameter = false +$presentation->markAsFinal(false); +$state = $presentation->isMarkedAsFinal(); +// $state = false + +// Parameter = true +$presentation->markAsFinal(true); +$state = $presentation->isMarkedAsFinal(); +// $state = true +``` + +### Slideshow type + +You can define the type of slideshow you can with the method `setSlideshowType`. + +![Slideshow type](../images/presentation_slideshow_type.png) + +Differents types are available: + +* `PresentationProperties::SLIDESHOW_TYPE_PRESENT` for **Presented by a speaker** +* `PresentationProperties::SLIDESHOW_TYPE_BROWSE` for **Browsed by an individual** +* `PresentationProperties::SLIDESHOW_TYPE_KIOSK` for **Browsed at a kiosk** + +``` php +getPresentationProperties(); +// Set type of slideshow +$properties->setSlideshowType(PresentationProperties::SLIDESHOW_TYPE_PRESENT); +// Get type of slideshow +echo $properties->getSlideshowType(); +``` + +### Thumbnail + +You can define the thumbnail of the presentation with the method `setThumbnailPath`. + +``` php +getPresentationProperties(); +// Set path of the thumbnail +$properties->setThumbnailPath(__DIR__.'\resources\phppowerpoint_logo.gif'); +// Get path of the thumbnail +echo $properties->getThumbnailPath(); +``` + +### Zoom + +You can define the zoom of the presentation with the method `setZoom`. + +``` php +getPresentationProperties(); +// Get zoom of the presentation +echo $properties->getZoom(); +// Output : 1 +// Set zoom of the presentation (3 = 300%) +$properties->setZoom(3); +// Get zoom of the presentation +echo $properties->getZoom(); +// Output : 3 +``` diff --git a/docs/usage/readers.md b/docs/usage/readers.md new file mode 100644 index 0000000000..ed4c531485 --- /dev/null +++ b/docs/usage/readers.md @@ -0,0 +1,41 @@ +# Readers + +## ODPresentation +The name of the reader is `ODPresentation`. + +``` php +load(__DIR__ . '/sample.odp'); +``` + +## PowerPoint97 +The name of the reader is `PowerPoint97`. + +``` php +load(__DIR__ . '/sample.ppt'); +``` + +## PowerPoint2007 +The name of the reader is `PowerPoint2007`. + +``` php +load(__DIR__ . '/sample.pptx'); +``` + +## Serialized +The name of the reader is `Serialized`. + +``` php +load(__DIR__ . '/sample.phppt'); +``` diff --git a/docs/usage/shapes/autoshape.md b/docs/usage/shapes/autoshape.md new file mode 100644 index 0000000000..d196bb7777 --- /dev/null +++ b/docs/usage/shapes/autoshape.md @@ -0,0 +1,31 @@ +# AutoShape + +!!! warning + Available only on the PowerPoint2007 Writer + +To create a geometric form, create an object `AutoShape` and add it to slide. + +``` php +addShape($shape) +``` + +## Text + +You can define text of the geometric form with `setText` method. + +``` php +setText('ABC'); +// Return the text +$shape->getText(); +``` \ No newline at end of file diff --git a/docs/usage/shapes/chart.md b/docs/usage/shapes/chart.md new file mode 100644 index 0000000000..388d88309e --- /dev/null +++ b/docs/usage/shapes/chart.md @@ -0,0 +1,434 @@ +# Charts + +To create a chart, use `createChartShape` method of Slide. + +``` php +createChartShape(); +``` + +## Customization + +### Manage how blank values are displayed + +You can define how blank values are displayed with the method `setDisplayBlankAs`. + +![Slideshow type](../../images/libreoffice_chart_displayblankas.png) + +Differents types are available: + +* `Chart::BLANKAS_GAP` for **Leave a gap** +* `Chart::BLANKAS_ZERO` for **Assume zero** (default) +* `Chart::BLANKAS_SPAN` for **Continue line** + +``` php +setDisplayBlankAs(Chart::BLANKAS_GAP); +// Get the behavior +echo $chart->getDisplayBlankAs(); +``` + +## Parts + +### Axis + +#### Title + +You can define title for each axis (X & Y) with `setTitle` method. +You can apply a rotation with the `setTitleRotation` method with an expected paremeter in degrees. + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); + +$shape->getPlotArea()->getAxisX()->setTitle('Axis X'); +$shape->getPlotArea()->getAxisX()->setTitleRotation(45); +``` + +#### Gridlines + +You can define gridlines (minor and major) for each axis (X & Y). +For each gridline, you can custom the width (in points), the fill type and the fill color. + +``` php +getOutline()->setWidth(10); +$gridlines->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); + +$shape = $slide->createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisX()->setMajorGridlines($gridlines); +``` + +#### Bounds (Min & Max) + +For Axis, you can define the min & max bounds with `setMinBounds` & `setMaxBounds` methods. +For resetting them, you pass null as parameter to these methods. + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisX()->setMinBounds(0); +$shape->getPlotArea()->getAxisX()->setMaxBounds(200); +``` + +#### Outline + +You can define outline for each axis (X & Y). + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisX()->getOutline()->setWidth(10); +$shape->getPlotArea()->getAxisX()->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); +``` +#### Tick Label Position + +You can define the tick label position with the `setTickLabelPosition` method. +For resetting it, you pass `Axis::TICK_LABEL_POSITION_NEXT_TO` as parameter to this method. + +Differents types are available: + +* `Axis::TICK_LABEL_POSITION_HIGH`: **Labels are at the high end of the perpendicular axis** +* `Axis::TICK_LABEL_POSITION_LOW`: **Labels are at the low end of the perpendicular axis** +* `Axis::TICK_LABEL_POSITION_NEXT_TO`: **Labels are next to the axis** (default) + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisY()->setTickLabelPosition(Axis::TICK_LABEL_POSITION_LOW); +``` +#### Tick Marks + +For Axis Y, you can define tick mark with `setMinorTickMark` & `setMajorTickMark` methods. +For resetting them, you pass `Axis::TICK_MARK_NONE` as parameter to these methods. + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisY()->setMinorTickMark(Axis::TICK_MARK_NONE); +$shape->getPlotArea()->getAxisY()->setMajorTickMark(Axis::TICK_MARK_INSIDE); +``` + +#### Unit + +For Axis Y, you can define unit with `setMinorUnit` & `setMajorUnit` methods. +For resetting them, you pass null as parameter to these methods. + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisY()->setMinorUnit(null); +$shape->getPlotArea()->getAxisY()->setMajorUnit(0.05); +``` +#### Visibility + +You can define visibility for each axis (X & Y). + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +$shape->getPlotArea()->getAxisX()->setIsVisible(false); +``` + +### Title + +By default, the title of a chart is displayed. +For hiding it, you define its visibility to false. + +``` php +createChartShape(); +$shape->getPlotArea()->setType($line); +// Hide the title +$shape->getTitle()->setVisible(false); +``` + +### Series + +#### Display Informations +You can define if some informations are displayed. + +``` php +setSeparator(';'); +$series->setShowCategoryName(true); +$series->setShowLeaderLines(true); +$series->setShowLegendKey(true); +$series->setShowPercentage(true); +$series->setShowSeriesName(true); +$series->setShowValue(true); +``` + +#### Font +You can custom the font of a serie. + +``` php +getFont()->setSize(25); +``` + +#### Label Position +You can define the position of the data label. +Each position is described in [MSDN](https://msdn.microsoft.com/en-us/library/mt459417(v=office.12).aspx). + +``` php +setLabelPosition(Series::LABEL_INSIDEEND); +``` + +#### Marker +You can custom the marker of a serie, for Line & Scatter charts. + +##### Customize the border + +!!! warning + Available only on the PowerPoint2007 Writer + +``` php +getMarker(); +$marker->getBorder()->setLineStyle(Border::LINE_SINGLE); +``` + +##### Customize the fill + +!!! warning + Available only on the PowerPoint2007 Writer + +``` php +getMarker(); +$marker->getFill()->setFillType(Fill::FILL_SOLID); +``` + +##### Customize the symbol + +``` php +getMarker(); +$marker->setSymbol(Marker::SYMBOL_DASH)->setSize(10); +``` + +#### Outline +You can custom the line of a serie, for Line & Scatter charts. + +``` php +getFill()->setFillType(Fill::FILL_SOLID); +$outline->getFill()->setStartColor(new Color(Color::COLOR_YELLOW)); +// Define the width (in points) +$outline->setWidth(2); + +$series = new Series('Downloads', $seriesData); +$series->setOutline($outline); +``` + +### View3D + +For enabling the autoscale for a shape, you must reset the height percent. + +``` php +getView3D()->setHeightPercent(null); +``` + +## Types + +### Area + +TODO + +### Bar & Bar3D + +#### Gap Width + +You can define the gap width between bar or columns clusters. It is relatively defined as percentage of a bars width. +The default value is 150%. The value must be defined between 0 and 500. + +```php +setGapWidthPercent(250); +``` + +#### Overlap + +You can define the bar overlap within bar or column clusters. It is relatively defined as percentage of a bars width. +The default value is `100%` for stacked and `0%` for grouped bar charts. The value must be defined between `-100` and `100`. + +When setting the bar grouping type, the default overlap values will be set. Any change to the overlap must be made after setting the bar grouping type through `setBarGrouping`. + +```php +$barChart = new Bar(); +// will set the overlap to the default value for grouped bars: 0 +$barChart->setBarGrouping(Bar::GROUPING_CLUSTERED); + +// a positive value will result in an overlapping +$barChart->setOverlapWidthPercent(25); + +// a negative value will result in a gap +$barChart->setOverlapWidthPercent(-25); +``` + +![Bar Overlap](../../images/chart_bar_overlap.png) + +#### Stacking + +You can stack multiples series in a same chart. After adding multiples series, you can define the bar grouping with `setBarGrouping` method of AbstractTypeBar. + +``` php +addSeries($series1); +$barChart->addSeries($series2); +$barChart->addSeries($series3); +$barChart->setBarGrouping(Bar::GROUPING_CLUSTERED); +// OR +$barChart->setBarGrouping(Bar::GROUPING_STACKED); +// OR +$barChart->setBarGrouping(Bar::GROUPING_PERCENTSTACKED); +``` + +| | Type | Constant | +| --------------------------------------------------------------------------- | ------------ | ---------------------------- | +| ![Bar::GROUPING_CLUSTERED](../../images/chart_columns_52x60.png) | Grouped Bars | Bar::GROUPING_CLUSTERED | +| ![Bar::GROUPING_STACKED](../../images/chart_columnstack_52x60.png) | Stacked Bars | Bar::GROUPING_STACKED | +| ![Bar::GROUPING_PERCENTSTACKED](../../images/chart_columnpercent_52x60.png) | Stacked Bars 100% | Bar::GROUPING_PERCENTSTACKED | + +### Line + +#### Smooth line + +You can enable or disable the smooth line with `setIsSmooth` method from `AbstractTypeLine`. +By default, smooth line is disabled. + +``` php +setIsSmooth(true); +// Disable the smooth line +$chart->setIsSmooth(false); +// Get status of smooth line +$chart->isSmooth(); +``` + +### Pie & Pie3D + +TODO + +### Radar + +You can create a Radar Chart. + +``` php +createChartShape(); +$shape->getPlotArea()->setType($radarChart); +``` + +### Scatter + +#### Smooth line + +You can enable or disable the smooth line with `setIsSmooth` method from `AbstractTypeLine`. +By default, smooth line is disabled. + +``` php +setIsSmooth(true); +// Disable the smooth line +$chart->setIsSmooth(false); +// Get status of smooth line +$chart->isSmooth(); +``` diff --git a/docs/usage/shapes/comment.md b/docs/usage/shapes/comment.md new file mode 100644 index 0000000000..93480e7004 --- /dev/null +++ b/docs/usage/shapes/comment.md @@ -0,0 +1,63 @@ +# Comments + +To create a comment, create an object `Comment`. + +``` php +addShape($comment); +``` + +You can define text and date with setters. + +Example: + +``` php +setText('Text of the Comment'); +$comment->setDate(time()); +$slide->addShape($comment); +``` + +## Author + +For a comment, you can define the author. + +Example: + +``` php +setAuthor($author); +$slide->addShape($comment); +``` + +You can define name and initials with setters. + +Example: + +``` php +setName('Name of the author'); +$author->setInitals('Nota'); +$comment = new Comment(); +$comment->setAuthor($author); +$slide->addShape($comment); +``` \ No newline at end of file diff --git a/docs/usage/shapes/drawing.md b/docs/usage/shapes/drawing.md new file mode 100644 index 0000000000..56749ed828 --- /dev/null +++ b/docs/usage/shapes/drawing.md @@ -0,0 +1,89 @@ +# Drawing + +To create a drawing, you have multiples sources : + +- Base64 +- File +- GD +- ZipFile + +You can add multiples formats of image : + +- GIF +- JPEG +- PNG +- SVG + +## File + +To create a drawing, use `createDrawingShape` method of slide. + +``` php +createDrawingShape(); +$shape->setName('Unique name') + ->setDescription('Description of the drawing') + ->setPath('/path/to/drawing.filename'); +``` + +It's an alias for : + +``` php +setName('Unique name') + ->setDescription('Description of the drawing') + ->setPath('/path/to/drawing.filename'); +$slide->addShape($shape); +``` + +## Base64 + +``` php +setName('Sample image') + ->setDescription('Sample image') + ->setImageResource($gdImage) + ->setData('data:image/jpeg;base64,..........'); +$slide->addShape($shape); +``` + +## GD + +``` php +setName('Sample image') + ->setDescription('Sample image') + ->setImageResource($gdImage) + ->setRenderingFunction(Drawing\Gd::RENDERING_JPEG) + ->setMimeType(Drawing\Gd::MIMETYPE_DEFAULT); +$slide->addShape($shape); +``` + +## ZipFile + +``` php +setName('Sample image') + ->setDescription('Sample image') + ->setPath('zip://myzipfile.zip#path/in/zip/img.ext') +$slide->addShape($shape); +``` diff --git a/docs/shapes.rst b/docs/usage/shapes/introduction.md similarity index 88% rename from docs/shapes.rst rename to docs/usage/shapes/introduction.md index dd21ab97da..81a30f6ad4 100644 --- a/docs/shapes.rst +++ b/docs/usage/shapes/introduction.md @@ -1,7 +1,4 @@ -.. _shapes: - -Shapes -====== +# Shapes Shapes are objects that can be added to a slide. There are five types of shapes that can be used, i.e. [rich text](#rich-text), [line](#line), [chart](#chart), [drawing](#drawing), and [table](#table). Read the corresponding section of this manual for detail information of each shape. @@ -19,15 +16,15 @@ Every shapes have common properties that you can set by using fluent interface. Example: -.. code-block:: php - - $richtext = $slide->createRichTextShape() +``` php +createRichTextShape() ->setHeight(300) ->setWidth(600) ->setOffsetX(170) ->setOffsetY(180); +``` -Line ----- +## Line To create a line, use `createLineShape` method of slide. diff --git a/docs/usage/shapes/media.md b/docs/usage/shapes/media.md new file mode 100644 index 0000000000..ec9e158c10 --- /dev/null +++ b/docs/usage/shapes/media.md @@ -0,0 +1,35 @@ +# Media + +To create a video, create an object `Media`. + +Example: + +``` php +setPath('file.wmv'); +// $media->setPath('file.ogv'); +$slide->addShape($media); +``` + +You can define text and date with setters. + +Example: + +``` php +setName('Name of the Media'); +$slide->addShape($media); +``` + +## Quirks + +For Windows readers, the prefered file format is WMV. +For Linux readers, the prefered file format is OGV. \ No newline at end of file diff --git a/docs/usage/shapes/richtext.md b/docs/usage/shapes/richtext.md new file mode 100644 index 0000000000..e44f358e39 --- /dev/null +++ b/docs/usage/shapes/richtext.md @@ -0,0 +1,136 @@ +# RichText + +Rich text shapes contain paragraphs of texts. To create a rich text shape, use `createRichTextShape` method of slide. + +Each rich text can contain multiples paragraphs. +Each paragraph can contain: +- a `TextElement` +- a `BreakElement` +- a `Run` + +Below are the properties that you can set for a rich text shape. + +- `wrap` +- `autoFit` +- `fontScale` : font scale (in percentage) when autoFit = `RichText::AUTOFIT_NORMAL` +- `lnSpcReduction` : line spacing reduction (in percentage) when autoFit = `RichText::AUTOFIT_NORMAL` +- `horizontalOverflow` +- `verticalOverflow` +- `upright` +- `vertical` +- `columns` +- `bottomInset` in pixels +- `leftInset` in pixels +- `rightInset` in pixels +- `topInset` in pixels +- `autoShrinkHorizontal` (boolean) +- `autoShrinkVertical` (boolean) +- `columnSpacing` see *Column Spacing* + +Properties that can be set for each paragraphs are as follow. + +- `alignment` +- `bulletStyle` see *[Bullet](#bullet)* +- `lineSpacing` see *Line Spacing* +- `font` + +## Column Spacing + +For a paragraph, you can define the column spacing. + +Example: + +``` php +setColumnSpacing(200); +$columnSpacing = $richText->getColumnSpacing(); +``` + +## Paragraph +### Bullet + +For a paragraph, you can define the bullet style. + +Example: + +``` php +getBulletStyle(); +``` + +With the bullet style, you can define the char, the font, the color and the type. + +``` php +getBulletStyle()->setBulletChar('-'); +$paragraph->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); +$paragraph->getBulletStyle()->setBulletColor(new Color(Color::COLOR_RED)); +``` + +### Line Spacing + +For a paragraph, you can define the line spacing. +By default, mode is in percent (`Paragraph::LINE_SPACING_MODE_PERCENT`), but you can use the point mode (`Paragraph::LINE_SPACING_MODE_POINT`). + +Example: + +``` php +setLineSpacing(200); +$lineSpacing = $paragraph->getLineSpacing(); + +$paragraph->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT); +$lineSpacingMode = $paragraph->getLineSpacingMode(); +``` + +### Spacing + +For a paragraph, you can define the spacing before and after the paragraph in point +Example: + +``` php +setSpacingAfter(12); +$spacingAfter = $paragraph->getSpacingAfter(); + +$paragraph->setSpacingBefore(34); +$spacingBefore = $paragraph->getSpacingBefore(); +``` + +## Run + +For a run, you can define the language. + +Example: + +``` php +setLanguage('fr-FR'); +``` \ No newline at end of file diff --git a/docs/usage/shapes/table.md b/docs/usage/shapes/table.md new file mode 100644 index 0000000000..8fd53db038 --- /dev/null +++ b/docs/usage/shapes/table.md @@ -0,0 +1,99 @@ +# Tables +To create a table, use `createTableShape` method of slide. + +Example: + +``` php +createTableShape($columns); +``` + +## Rows +A row is a child of a table. For creating a row, use `createRow` method of a Table shape. + +``` php +createTableShape($columns); +$row = $tableShape->createRow(); +``` + +## Cells +A cell is a child of a row. + +You can access cell objects with `nextCell` method of a Row object. + +``` php +createTableShape($columns); +$row = $tableShape->createRow(); +// Get the first cell +$cellA1 = $row->nextCell(); +// Get the second cell +$cellA2 = $row->nextCell(); +``` + +You can access cell object directly. + +``` php +createTableShape($columns); +$row = $tableShape->createRow(); +// Get the first cell +$cellA1 = $row->getCell(0); +// Get the second cell +$cellA2 = $row->getCell(1); +``` + +### Define margins +Margins of cells are defined by margins of the first paragraph of cell. +Margins of cells are defined in pixels. + +For defining margins of cell, you can use the `setMargin*` method of a Alignment object of the active paragraph of a Cell object. + +``` php +createTableShape($columns); +$row = $tableShape->createRow(); +$cellA1 = $row->nextCell(); +$cellA1->getActiveParagraph()->getAlignment() + ->setMarginBottom(20) + ->setMarginLeft(40) + ->setMarginRight(60) + ->setMarginTop(80); +``` + +### Define the text direction +For defining the text direction of cell, you can use the `setTextDirection` method of the `getAlignment` method of a Cell object. +The width is in pixels. + +``` php +createTableShape($columns); +$row = $tableShape->createRow(); +$cellA1 = $row->nextCell(); +$cellA1->getAlignment()->setTextDirection(Alignment::TEXT_DIRECTION_VERTICAL_270); +``` + +### Define the width +The width of cells are defined by the width of cell of the first row. +If not defined, all cells widths are calculated from the width of the shape and the number of columns. + +For defining the width of cell, you can use the `setWidth` method of a Cell object. +The width is in pixels. + +``` php +createTableShape($columns); +$row = $tableShape->createRow(); +$cellA1 = $row->nextCell(); +$cellA1->setWidth(100); +``` \ No newline at end of file diff --git a/docs/usage/slides/animation.md b/docs/usage/slides/animation.md new file mode 100644 index 0000000000..4177564015 --- /dev/null +++ b/docs/usage/slides/animation.md @@ -0,0 +1,19 @@ +# Animations + + +You can create multiples animations in a slide. + + +``` php +addShape($drawing); +$slide->addAnimation($animation1); + +$animation2 = new Animation(); +$animation2->addShape($richtext); +$slide->addAnimation($animation2); + +``` \ No newline at end of file diff --git a/docs/usage/slides/introduction.md b/docs/usage/slides/introduction.md new file mode 100644 index 0000000000..3166122026 --- /dev/null +++ b/docs/usage/slides/introduction.md @@ -0,0 +1,29 @@ +# Introduction + +Slides are pages in a presentation. Slides are stored as a zero based array in `PHPPresentation` object. Use the method `createSlide` to create a new slide and retrieve the slide for other operation such as creating shapes for that slide. + +## Name + +By default, a slide has not a name. +You can define it with the method `setName`. + +``` php +createSlide(); +$slide->setName('Title of the slide'); +``` + +## Visibility + +By default, a slide is visible. +You can define it with the method `setIsVisible`. + + +``` php +createSlide(); +$slide->setIsVisible(false); +var_dump($slide->isVisible()); +``` \ No newline at end of file diff --git a/docs/usage/slides/layout.md b/docs/usage/slides/layout.md new file mode 100644 index 0000000000..68f7f0cb12 --- /dev/null +++ b/docs/usage/slides/layout.md @@ -0,0 +1,54 @@ +# Slides Layout + +A slide is a hierarchy of three components: + +- The master slide upon which the slide is based : it specifies such properties as the font styles for the title, body, and footer, placeholder positions for text and objects, bullets styles, and background; +- The slide layout which is applied to the the slide : it permits to override what is specified in the master slide; +- The slide itself: it contains content and formatting that is not already specified by the master slide and the slide layout. + +Placeholders permit to link these three components together in order that the override is possible. + +## Master slides + +You can access to all master slides with the method `getAllMasterSlides` or create one with `createMasterSlide`. + +``` php +getAllMasterSlides(); +$masterSlide = $presentation->createMasterSlide(); +``` + +## Slides Layout + +You can access to all slide layout from a master with the method `getAllSlideLayouts` or create one with `createSlideLayout`. + + +``` php +getAllSlideLayouts(); +$slideLayout = $masterSlide->createSlideLayout(); +``` + +## Placeholders + +For each master slide or slide layout, you can add any shape like on a slide. + +``` php +createChartShape(); +$shape = $slideLayout->createTableShape(); +``` + +You can define a shape as a placeholder for each level with the method `setPlaceHolder`. +A shape defined in each level will have an override for its formatting in each level. + + +``` php +setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_TITLE)); +``` diff --git a/docs/usage/styles.md b/docs/usage/styles.md new file mode 100644 index 0000000000..ba21479853 --- /dev/null +++ b/docs/usage/styles.md @@ -0,0 +1,143 @@ +# Styles + +## Fill + +Use this style to define fill of a shape as example below. + +``` php +getFill() + ->setFillType(Fill::FILL_GRADIENT_LINEAR) + ->setRotation(270) + ->setStartColor(new Color('FFCCCCCC')) + ->setEndColor(new Color('FFFFFFFF')); +``` + +Properties: + +- `fillType` +- `rotation` +- `startColor` +- `endColor` + +## Border + +Use this style to define border of a shape as example below. + +``` php +getBorder() + ->setLineStyle(Border::LINE_SINGLE) + ->setLineWidth(4) + ->getColor()->setARGB('FFC00000'); +``` + +Properties: + +- `lineWidth` +- `lineStyle` +- `dashStyle` +- `color` + +## Shadow + +Use this style to define shadow of a shape as example below. + +``` php +getShadow() + ->setVisible(true) + ->setDirection(45) + ->setDistance(10); +``` + +Properties: + +- `visible` +- `blurRadius` +- `distance` +- `direction` +- `alignment` +- `color` +- `alpha` + +## Alignment + +- `horizontal` +- `vertical` +- `level` +- `indent` +- `marginLeft` +- `marginRight` + +### RTL / LTR + +You can define if the alignment is RTL or LTR. + +``` php +setIsRTL(true); +// Set alignment to LTR +$alignment->setIsRTL(false); +// Is the alignment RTL? +echo $alignment->isRTL(); +``` + +## Font + +- `name` +- `bold` +- `italic` +- `superScript` +- `subScript` +- `underline` +- `strikethrough` +- `color` + +### Format + +Some formats are available : + +* `Font::FORMAT_LATIN` +* `Font::FORMAT_EAST_ASIAN` +* `Font::FORMAT_COMPLEX_SCRIPT` + +``` php +setFormat(Font::FORMAT_EAST_ASIAN); +// Get format of font +echo $font->getFormat(); +``` +## Bullet + +- `bulletType` +- `bulletFont` +- `bulletChar` +- `bulletNumericStyle` +- `bulletNumericStartAt` + +## Color + +Colors can be applied to different objects, e.g. font or border. + +``` php +createTextRun('Text'); +$textRun->getFont()->setColor(new Color('C00000')); +``` diff --git a/docs/usage/writers.md b/docs/usage/writers.md new file mode 100644 index 0000000000..7546cd1f4b --- /dev/null +++ b/docs/usage/writers.md @@ -0,0 +1,57 @@ +# Writers + +## ODPresentation +The name of the writer is `ODPresentation`. + +``` php +save(__DIR__ . '/sample.pptx'); +``` + +## PowerPoint2007 +The name of the writer is `PowerPoint2007`. + +``` php +save(__DIR__ . '/sample.pptx'); +``` + +You can change the ZIP Adapter for the writer. By default, the ZIP Adapter is `ZipArchiveAdapter`. + +``` php +setZipAdapter(new PclZipAdapter()); +$writer->save(__DIR__ . '/sample.pptx'); +``` + +## Serialized +The name of the writer is `Serialized`. + +``` php +save(__DIR__ . '/sample.phppt'); +``` + +You can change the ZIP Adapter for the writer. By default, the ZIP Adapter is `ZipArchiveAdapter`. + +``` php +setZipAdapter(new PclZipAdapter()); +$writer->save(__DIR__ . '/sample.phppt'); +``` diff --git a/docs/writers.rst b/docs/writers.rst deleted file mode 100644 index e1105290e3..0000000000 --- a/docs/writers.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. _writersreaders: - -Writers -======= - - -ODPresentation --------------- - -The name of the writer is ``ODPresentation``. - -.. code-block:: php - - $oWriter = IOFactory::createWriter($oPhpPresentation, 'PowerPoint2007'); - $oWriter->save(__DIR__ . '/sample.pptx'); - -PowerPoint2007 --------------- - -The name of the writer is ``PowerPoint2007``. - -.. code-block:: php - - $oWriter = IOFactory::createWriter($oPhpPresentation, 'PowerPoint2007'); - $oWriter->save(__DIR__ . '/sample.pptx'); - -You can change the ZIP Adapter for the writer. By default, the ZIP Adapter is ZipArchiveAdapter. - -.. code-block:: php - - use PhpOffice\Common\Adapter\Zip\PclZipAdapter; - use PhpOffice\Common\Adapter\Zip\ZipArchiveAdapter; - - $oWriter = IOFactory::createWriter($oPhpPresentation, 'PowerPoint2007'); - $oWriter->setZipAdapter(PclZipAdapter); - $oWriter->save(__DIR__ . '/sample.pptx'); - -Serialized ----------- - -The name of the writer is ``Serialized``. - -.. code-block:: php - - $oWriter = IOFactory::createWriter($oPhpPresentation, 'Serialized'); - $oWriter->save(__DIR__ . '/sample.phppt'); - -You can change the ZIP Adapter for the writer. By default, the ZIP Adapter is ZipArchiveAdapter. - -.. code-block:: php - - use PhpOffice\Common\Adapter\Zip\PclZipAdapter; - use PhpOffice\Common\Adapter\Zip\ZipArchiveAdapter; - - $oWriter = IOFactory::createWriter($oPhpPresentation, 'Serialized'); - $oWriter->setZipAdapter(PclZipAdapter); - $oWriter->save(__DIR__ . '/sample.phppt'); - diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000000..c60fad741d --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,83 @@ +site_name: PHPPresentation +site_url: https://phpoffice.github.io/PHPPresentation +repo_url: https://github.com/PHPOffice/PHPPresentation +repo_name: PHPOffice/PHPPresentation +edit_uri: edit/develop/docs/ + +## Theme +theme: + name: material + palette: + primary: orange + features: + - search.highlight + - search.suggest + +## Plugins +plugins: + - search + - autolink_references: + autolinks: + - reference_prefix: GP- + target_url: https://github.com/ + - reference_prefix: GH- + target_url: https://github.com/PHPOffice/PHPPresentation/issues/ + - reference_prefix: CP- + target_url: https://archive.codeplex.com/?p=phppowerpoint& + +## Config +extra: + generator: false +markdown_extensions: + ## Syntax highlighting + - pymdownx.highlight + - pymdownx.superfences + ## Support for emojis + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + ## Support for call-outs + - admonition + - pymdownx.details +use_directory_urls: false + +## Navigation +nav: + - Introduction: 'index.md' + - Install: 'install.md' + - Usage: + - Introduction: 'usage/introduction.md' + - Presentation: 'usage/presentation.md' + - Slides: + - Introduction: 'usage/slides/introduction.md' + - Animations: 'usage/slides/animation.md' + - Layouts: 'usage/slides/layout.md' + - Shapes: + - Introduction: 'usage/shapes/introduction.md' + - AutoShape: 'usage/shapes/autoshape.md' + - Chart: 'usage/shapes/chart.md' + - Comment: 'usage/shapes/comment.md' + - Drawing: 'usage/shapes/drawing.md' + - Media: 'usage/shapes/media.md' + - Richtext: 'usage/shapes/richtext.md' + - Table: 'usage/shapes/table.md' + - Styles: 'usage/styles.md' + - Readers: 'usage/readers.md' + - Writers: 'usage/writers.md' + - FAQ: 'faq.md' + - Credits: 'credits.md' + - Releases: + - '1.0.0 (WIP)': 'changes/1.0.0.md' + - '0.9.0': 'changes/0.9.0.md' + - '0.8.0': 'changes/0.8.0.md' + - '0.7.0': 'changes/0.7.0.md' + - '0.6.0': 'changes/0.6.0.md' + - '0.5.0': 'changes/0.5.0.md' + - '0.4.0': 'changes/0.4.0.md' + - '0.3.0': 'changes/0.3.0.md' + - '0.2.0': 'changes/0.2.0.md' + - '0.1.0': 'changes/0.1.0.md' + - Developers: + - 'Coveralls': 'https://coveralls.io/github/PHPOffice/PHPPresentation' + - 'Code Coverage': 'coverage/index.html' + - 'PHPDoc': 'docs/index.html' diff --git a/phpmd.xml.dist b/phpmd.xml.dist index a7143e92f8..2499a06587 100644 --- a/phpmd.xml.dist +++ b/phpmd.xml.dist @@ -6,12 +6,18 @@ xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"> + + + + + + @@ -20,7 +26,7 @@ - + @@ -31,4 +37,4 @@ - \ No newline at end of file + diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000000..0ab30292c2 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,26 @@ +parameters: + level: 6 + bootstrapFiles: + - tests/bootstrap.php + paths: + - src + - tests + reportUnmatchedIgnoredErrors: false + ignoreErrors: + ## Relative to Common + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:angleToDegrees\(\) expects int, string given\.#' + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:centimetersToPixels\(\) expects int, string given\.#' + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:degreesToAngle\(\) expects int, float given\.#' + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:emuToPixels\(\) expects int, float given\.#' + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:emuToPixels\(\) expects int, string given\.#' + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:pixelsToCentimeters\(\) expects int, float given\.#' + - '#^Parameter \#1 \$pValue of static method PhpOffice\\Common\\Drawing\:\:pixelsToEmu\(\) expects int, float given\.#' + ## PHP 8.0 & GdImage + - '#^Parameter \#1 \$value of method PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd::setImageResource\(\) expects resource\|null, GdImage\|false given\.#' + - '#^Parameter \#1 \$image of function imagesx expects GdImage, resource given\.#' + - '#^Parameter \#1 \$image of function imagesy expects GdImage, resource given\.#' + - '#^Parameter \#1 \$image of function imagealphablending expects GdImage, resource given\.#' + - '#^Parameter \#1 \$image of function imagesavealpha expects GdImage, resource given\.#' + + ## Remove after remove ArrayObject + treatPhpDocTypesAsCertain: false diff --git a/phpunit.xml.dist b/phpunit.xml.dist index c22a3a0501..a9f7e2189e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,8 +6,7 @@ convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" - stopOnFailure="false" - syntaxCheck="false"> + stopOnFailure="false"> ./tests/PhpPresentation @@ -19,7 +18,7 @@ - + - \ No newline at end of file + diff --git a/samples/Sample_01_Complex.php b/samples/Sample_01_Complex.php index ec492a85c8..7f45bbaefa 100644 --- a/samples/Sample_01_Complex.php +++ b/samples/Sample_01_Complex.php @@ -7,38 +7,38 @@ include_once 'Sample_Header.php'; -$colorBlack = new Color( 'FF000000' ); +$colorBlack = new Color('FF000000'); // Create new PHPPresentation object -echo date('H:i:s') . ' Create new PHPPresentation object'.EOL; +echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 02 Title') - ->setSubject('Sample 02 Subject') - ->setDescription('Sample 02 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 02 Title') + ->setSubject('Sample 02 Subject') + ->setDescription('Sample 02 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Remove first slide -echo date('H:i:s') . ' Remove first slide'.EOL; +echo date('H:i:s') . ' Remove first slide' . EOL; $objPHPPresentation->removeSlideByIndex(0); // Create templated slide -echo date('H:i:s') . ' Create templated slide'.EOL; +echo date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // local function // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape(); $shape->setHeight(200); $shape->setWidth(600); $shape->setOffsetX(10); $shape->setOffsetY(400); -$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_LEFT ); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); $textRun = $shape->createTextRun('Introduction to'); $textRun->getFont()->setBold(true); @@ -52,37 +52,36 @@ $textRun->getFont()->setSize(60); $textRun->getFont()->setColor($colorBlack); - // Create templated slide -echo date('H:i:s') . ' Create templated slide'.EOL; +echo date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // local function // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape(); $shape->setHeight(100) - ->setWidth(930) - ->setOffsetX(10) - ->setOffsetY(50); + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(50); $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); $textRun = $shape->createTextRun('What is PHPPresentation?'); $textRun->getFont()->setBold(true) - ->setSize(48) - ->setColor($colorBlack); + ->setSize(48) + ->setColor($colorBlack); // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape() - ->setHeight(600) - ->setWidth(930) - ->setOffsetX(10) - ->setOffsetY(130); + ->setHeight(600) + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(130); $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT) - ->setMarginLeft(25) - ->setIndent(-25); + ->setMarginLeft(25) + ->setIndent(-25); $shape->getActiveParagraph()->getFont()->setSize(36) - ->setColor($colorBlack); + ->setColor($colorBlack); $shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); $shape->createTextRun('A class library'); @@ -90,100 +89,98 @@ $shape->createParagraph()->createTextRun('Representing a presentation'); $shape->createParagraph()->createTextRun('Supports writing to different file formats'); - // Create templated slide -echo date('H:i:s') . ' Create templated slide'.EOL; +echo date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // local function // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape() - ->setHeight(100) - ->setWidth(930) - ->setOffsetX(10) - ->setOffsetY(50); -$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT ); + ->setHeight(100) + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(50); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); $textRun = $shape->createTextRun('What\'s the point?'); $textRun->getFont()->setBold(true) - ->setSize(48) - ->setColor($colorBlack); + ->setSize(48) + ->setColor($colorBlack); // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape(); $shape->setHeight(600) - ->setWidth(930) - ->setOffsetX(10) - ->setOffsetY(130); + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(130); $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT) - ->setMarginLeft(25) - ->setIndent(-25); + ->setMarginLeft(25) + ->setIndent(-25); $shape->getActiveParagraph()->getFont()->setSize(36) - ->setColor($colorBlack); + ->setColor($colorBlack); $shape->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); $shape->createTextRun('Generate slide decks'); $shape->createParagraph()->getAlignment()->setLevel(1) - ->setMarginLeft(75) - ->setIndent(-25); + ->setMarginLeft(75) + ->setIndent(-25); $shape->createTextRun('Represent business data'); $shape->createParagraph()->createTextRun('Show a family slide show'); $shape->createParagraph()->createTextRun('...'); $shape->createParagraph()->getAlignment()->setLevel(0) - ->setMarginLeft(25) - ->setIndent(-25); + ->setMarginLeft(25) + ->setIndent(-25); $shape->createTextRun('Export these to different formats'); $shape->createParagraph()->getAlignment()->setLevel(1) - ->setMarginLeft(75) - ->setIndent(-25); + ->setMarginLeft(75) + ->setIndent(-25); $shape->createTextRun('PHPPresentation 2007'); $shape->createParagraph()->createTextRun('Serialized'); $shape->createParagraph()->createTextRun('... (more to come) ...'); - // Create templated slide -echo date('H:i:s') . ' Create templated slide'.EOL; +echo date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // local function // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape(); $shape->setHeight(100) - ->setWidth(930) - ->setOffsetX(10) - ->setOffsetY(50); -$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_LEFT ); + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(50); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); $textRun = $shape->createTextRun('Need more info?'); $textRun->getFont()->setBold(true) - ->setSize(48) - ->setColor($colorBlack); + ->setSize(48) + ->setColor($colorBlack); // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape(); $shape->setHeight(600) - ->setWidth(930) - ->setOffsetX(10) - ->setOffsetY(130); -$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_LEFT ); + ->setWidth(930) + ->setOffsetX(10) + ->setOffsetY(130); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT); $textRun = $shape->createTextRun('Check the project site on GitHub:'); $textRun->getFont()->setSize(36) - ->setColor($colorBlack); + ->setColor($colorBlack); $shape->createBreak(); $textRun = $shape->createTextRun('https://github.com/PHPOffice/PHPPresentation/'); $textRun->getFont()->setSize(32) - ->setColor($colorBlack); + ->setColor($colorBlack); $textRun->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/') - ->setTooltip('PHPPresentation'); + ->setTooltip('PHPPresentation'); // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_01_Simple.php b/samples/Sample_01_Simple.php index e7ebd0b9a5..7066137827 100644 --- a/samples/Sample_01_Simple.php +++ b/samples/Sample_01_Simple.php @@ -5,6 +5,7 @@ use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Color; +use PhpOffice\PhpPresentation\Style\Font; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; @@ -29,7 +30,7 @@ $shape = $currentSlide->createDrawingShape(); $shape->setName('PHPPresentation logo') ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') + ->setPath(__DIR__ . '/resources/phppowerpoint_logo.gif') ->setHeight(36) ->setOffsetX(10) ->setOffsetY(10); @@ -44,13 +45,32 @@ ->setHeight(300) ->setWidth(600) ->setOffsetX(170) - ->setOffsetY(180); -$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + ->setOffsetY(100); +$shape->getActiveParagraph()->getAlignment() + ->setHorizontal(Alignment::HORIZONTAL_CENTER); $textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); $textRun->getFont()->setBold(true) ->setSize(60) ->setColor(new Color('FFE06B20')); +// Create a shape (text) +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; +$shape = $currentSlide->createRichTextShape() + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(170) + ->setOffsetY(550); +$shape->getActiveParagraph()->getAlignment() + ->setHorizontal(Alignment::HORIZONTAL_RIGHT) + ->setIsRTL(true); +$textRun = $shape->createTextRun('تست فونت فارسی'); +$textRun->getFont() + ->setBold(true) + ->setSize(60) + ->setColor(new Color('FFE06B20')) + ->setFormat(Font::FORMAT_COMPLEX_SCRIPT) + ->setName('B Nazanin'); + // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/samples/Sample_02_Serialized.php b/samples/Sample_02_Serialized.php index 5a5159f86c..b2101c440e 100644 --- a/samples/Sample_02_Serialized.php +++ b/samples/Sample_02_Serialized.php @@ -2,67 +2,67 @@ include_once 'Sample_Header.php'; +use PhpOffice\PhpPresentation\IOFactory; use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Color; -use PhpOffice\PhpPresentation\IOFactory; // Create new PHPPresentation object -echo date('H:i:s') . ' Create new PHPPresentation object'.EOL; +echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 03 Title') - ->setSubject('Sample 03 Subject') - ->setDescription('Sample 03 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 02 Title') + ->setSubject('Sample 02 Subject') + ->setDescription('Sample 02 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = $objPHPPresentation->getActiveSlide(); // Create a shape (drawing) -echo date('H:i:s') . ' Create a shape (drawing)'.EOL; +echo date('H:i:s') . ' Create a shape (drawing)' . EOL; $shape = $currentSlide->createDrawingShape(); $shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); + ->setDescription('PHPPresentation logo') + ->setPath('./resources/phppowerpoint_logo.gif') + ->setHeight(36) + ->setOffsetX(10) + ->setOffsetY(10); $shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); + ->setDirection(45) + ->setDistance(10); // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); -$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(170) + ->setOffsetY(180); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor( new Color( 'FFE06B20' ) ); + ->setSize(60) + ->setColor(new Color('FFE06B20')); // Save serialized file $basename = basename(__FILE__, '.php'); -echo date('H:i:s') . ' Write to serialized format'.EOL; +echo date('H:i:s') . ' Write to serialized format' . EOL; $objWriter = IOFactory::createWriter($objPHPPresentation, 'Serialized'); -$objWriter->save('results/'.basename(__FILE__, '.php').'.phppt'); +$objWriter->save('results/' . basename(__FILE__, '.php') . '.phppt'); // Read from serialized file -echo date('H:i:s') . ' Read from serialized format'.EOL; -$objPHPPresentationLoaded = IOFactory::load('results/'.basename(__FILE__, '.php').'.phppt'); +echo date('H:i:s') . ' Read from serialized format' . EOL; +$objPHPPresentationLoaded = IOFactory::load('results/' . basename(__FILE__, '.php') . '.phppt'); // Save file echo write($objPHPPresentationLoaded, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_03_Image.php b/samples/Sample_03_Image.php index ea1ad2afe4..8c6e0e847c 100644 --- a/samples/Sample_03_Image.php +++ b/samples/Sample_03_Image.php @@ -4,62 +4,64 @@ use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Shape\Drawing; -use PhpOffice\PhpPresentation\Shape\Media; +use PhpOffice\PhpPresentation\Style\Color; +use PhpOffice\PhpPresentation\Style\Fill; // Create new PHPPresentation object -echo date('H:i:s') . ' Create new PHPPresentation object'.EOL; +echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = $objPHPPresentation->getActiveSlide(); // Generate an image -echo date('H:i:s') . ' Generate an image'.EOL; -$gdImage = @imagecreatetruecolor(140, 20) or die('Cannot Initialize new GD image stream'); +echo date('H:i:s') . ' Generate an image' . EOL; +$gdImage = @imagecreatetruecolor(140, 20) or exit('Cannot Initialize new GD image stream'); $textColor = imagecolorallocate($gdImage, 255, 255, 255); -imagestring($gdImage, 1, 5, 5, 'Created with PHPPresentation', $textColor); +imagestring($gdImage, 1, 5, 5, 'Created with PHPPresentation', $textColor); // Add a generated drawing to the slide -echo date('H:i:s') . ' Add a drawing to the slide'.EOL; +echo date('H:i:s') . ' Add a drawing to the slide' . EOL; $shape = new Drawing\Gd(); -$shape->setName('Sample image') - ->setDescription('Sample image') - ->setImageResource($gdImage) - ->setRenderingFunction(Drawing\Gd::RENDERING_JPEG) - ->setMimeType(Drawing\Gd::MIMETYPE_DEFAULT) - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); +$shape->setName('Image GD') + ->setDescription('Image GD') + ->setImageResource($gdImage) + ->setMimeType(Drawing\Gd::MIMETYPE_DEFAULT) + ->setHeight(36) + ->setOffsetX(10) + ->setOffsetY(10); $currentSlide->addShape($shape); // Add a file drawing (GIF) to the slide $shape = new Drawing\File(); -$shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') +$shape->setName('Image File') + ->setDescription('Image File') + ->setPath(__DIR__ . '/resources/phppowerpoint_logo.gif') ->setHeight(36) ->setOffsetX(10) ->setOffsetY(100); $currentSlide->addShape($shape); // Add a file drawing (Zip) to the slide -$shape = new Drawing\ZipFile(); -$shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('zip://./resources/Sample_12.pptx#ppt/media/phppowerpoint_logo1.gif') - ->setResizeProportional(false) - ->setHeight(36) - ->setWidth(36) - ->setOffsetX(10) - ->setOffsetY(150); -$currentSlide->addShape($shape); +if (file_exists(__DIR__ . '/resources/Sample_12.pptx')) { + $shape = new Drawing\ZipFile(); + $shape->setName('Image ZipFile') + ->setDescription('Image ZipFile') + ->setPath('zip://' . __DIR__ . '/resources/Sample_12.pptx#ppt/media/phppowerpoint_logo1.gif') + ->setResizeProportional(false) + ->setHeight(36) + ->setWidth(36) + ->setOffsetX(10) + ->setOffsetY(150); + $currentSlide->addShape($shape); +} // Add a file drawing (JPEG) to the slide $shape = new Drawing\Base64(); -$shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setData('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI1TXRUr2tkR2apmmSIRSyshbjkWyEkMT5n4I0upJBXLeaf5kvkTnP3pxTfMl8ic5p/idF/uIb34VXf7SlgACxKwAA8PQAAAAD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgXG4tpsqWBWur5m/wBmhci/pHcSeXvmEkjY2q5y2RD1EuTwZe4YXo66jS4Xh09Pe5HZVFKxyaDETU3LUv7qNX4y7SsZh2nt70rKPfH1EC6cbXuTJXJszOd/6iplfhRMr2v9TB00LHYVdmbsFRZb2lc1tNWOZHcURXSwMavUpnq5eLLj4y3OhjkbI1HNXJTJQADMAAAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+PdoMc7kRVP0+J0zgk77VMJFwsVTJllciKUdZXrUSNdGr42omWWkRHSPevVvc7kzXM69DL878CdQWN1dG56TozRXLW3P3ny6erfM5XyO1PpVNJRxIkcS6fepWNTNyJmau22dKNkm/73Mq5ZZt2FJW2daKRjN+R2lx6OWRY8Hanug7yLzmq56L1M5Jo5Lsa4kn4QZ7FPDlnWKufeXnOtFSPptPTl3zSy+w+kUfEJKrC5IrNXrdPlrqcJV0MNOipzUVydLL8yUAC2KsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVvtQ2lxvYZ3IqtjcjlRO841RSX+ypWuZcY1e6ppGKsUbcsnrtyU0eIROlpnMaZtWyne71jLhc5qqNrmtfo5I7bqRE9xD4iuju7Io0ZcnMpapPjxLtbyfhkp+uvFK9qspJWTVDtUcaZ9U7iQ+ZpSysXlo1csiifTzOet29fYcrJ+0Gq8R/pYbUz1gs7kqUvVW2SGtmYrZINWi3Jck7+xqL9poT6TwyF0NM1r0zLu1mtbsiIAAWJ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFIc/XGn8LfWSZv1En1VKmnXKpiXkenrOU/wBR1WCNKe3nZ38FLKgju7Hsaup+Sy/Ud6igttwWkziSNHb45NarsNAqx1EL2teio5FTNq5la2wxMejt+fqXPYhwqHTzMerkcw711sStka5ZVZoplszPqgoW0CPTftPTy2plsPmvrZqV7Uig3xFTWuvUUlbXurXxudG1uhxIe5qYyPjjditmak5Tw79o9Vll3in4QS/QM8qkmku8lRpZxNTRy2KblA2pWoalN5+dvct9e4wnnpnRqkuh8gA+sHFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE61WqW7TvhikYxWN0s3FrwKre2IPxM4bux4iZcWKyqdFFOr8mMbn1SZFdVvnj8qNcvAniRjslKfgVXdsQ/iOBVd2xD+JtSDeq2S22iprImtc+FmkiO2KVbuIzol7/AAJ3RxtRVUzHAqu7Zg/EcCq3tiD8SpttjqsW3aW4XCKSmp6iPTbJFlkrkyTLXn3/ACEOy4ZZdbXcahj5lnpVVsUbcsnrlqRTR/GqtbWbre3s9hXc9VVMMet7Z629hcs3MaCetfVXClpKlz06pV0s1XUifghT3XCtjttdBJSW2GKRiaSObnqVC/wXdK+Csbh2qpmxJTxufr+NrXS1+cRsR/K4/AvrIqWbtHEoZVXXFdOl0Tb6my2RHxYm3T70KcAHcEIAAAAAAAAAAAAAAAAAAAAAKljK7Fd5qMO2Wp6BraRm/vnl+KrUyRUTLNc83pxcR+YSwlSbqVDPdbrUTUktLJ0O1lLloq3JHZrpZ6+qPXcO2SDDliprRTyySxUzVa18mWkuaquvLwlFU16vTDHl3m6yG2bjy/4LMdfxNS+c/wDKRaKqnobzPhmue6evoWZyzp8R+xdXHscnkPbMzBbsNluV+wlS0tro5KudlcyRWRprRqMkTPyqnlNSGqkjde9yV8aOSxSApemlbJvcttp21NupkRK+oTPKny25/YWtNVQVlO2oppEkifnouTYuS5HRsmY9VRq6FerFbmp1ABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH45uk1WrxpkRXW+JGOVNLNE1ayWfirkiquxDTqKOnqc5WopJHK9nmqQqGumo5WwaLUSR6Z6aa+Q0pkq6RjqmOdjs1jTNOTNDvFiCtci5pFq/unzKsgZFM5ka3ROp2VLIi03MXpqmxpFTNCpks9viy3ype3PZpSNT3ETp7WckfkINwuU9Q6NXozVnlkhrNatzNHMndhal17y66TW/th/npzHKCnZT56CqulynCmrkejt+c1vITDveC0NIxOfE7EvfqmqfE5etqHv8lW4fDqAAdKVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPuGaSnmbNE7RkYubV5D4B4qXSwN1hy/dMUSklR7qiONXPkXLJ2vveFDvirsYr/FKeemxornDiC3T22ueyB0qJGxGbVT7czn+IUKta50ei/A2eYr2KzrYyiYvmpcM0lut6ywVMDurkyarVbr1a/Ch9pJc8GV1OktWj4Kh2/SRxJnpJ9qEy/YC6Bo2SWxairlWTJzF0dTcl1+XIp6HCV1mrYYqihnjhe9Ee9MupTjU5BzZ2uRFTNLWKZzalrka5FulrW0QvsOXGO77oFVXwscxk1Pqa/LNMkanuPnEfyuPwL6y/smD6Sx1/RkFTNI/QVmi/LLXlyJ3igxH8rj8C+stOHMe2vhx6rjX4FkxkjIvzNVVV95TgA7wxAAAAAAAAAAAAAAAABGra+noIkfPK2PTXRZpfvO5DxVREuoRLkkrb3e4LFTRzzxSSNe/QRGZcmZD0d0P+E181fzG/wFg3pVI7ENXv8ADcrhBo1NK/LRiXNF1cfEnGVc3EWI38vU2WQLfyjvubYNrcF2eqoq2ognfNUb610OeSJoonGichb1mJKejq5Kd8EjnMXJVTLLYWdXTtq6WSncqtbImSqm1D8oqVlFSR07HK5I0yRV2lMzAiXdmSypKq2Ytu/X2WP2rZNJSyMp36Eqp1Ll4lINuuKrULbZ9J9TC3N8mrRX/wAzQtMz8PEciJZUM1jVXI5FKikwjYaC3VtvpbcyKmrs+iI0e5UkzTLl9R5PVtbad0u4YeoE3i10sLXQ06a0YqsY5da69rlXbxnuB5RunWaHDdVUY3ppZJa2rljgfDJlvaJoZZplrz6hOPjJKeTlyI4ye27VQ/AV09zVlJCyFGyV9VGi01PrzlfkmTU+1T6t9fK9yUNzjbS3WNqrNS6840z1eVqtX7TpeezHgvmV2BbX6E8AExiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVGtVztiIV9TW5rlC7qVbr1EmqmYyN8bl6pzVyKk5Lj3EnxryIXJ321TuLGkgRfLch+O+IvgOVPsd4T8ne5FyRcj9p9i+E463knUNiVlE5y9bHY4VHxmnY4VO1p43Ui4fnUNTx+RIJ9NW/G396Jsy1FVC9X5568jsbdJWTUcmKNfZ0Xx95oVdKiOWJ+qF4fpzhnjmz0F2d4+z6hHIyVuJi3Q5xzVatlP0AEhiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADpBNJTzNmidovYubV5DmAqX1Bu8O35LgxlJJvjqlkave9WojV15cXhTiL08oRytXNqqngU3FixGytbvVW6KKVXI2NqZ5uKCso1YqvZobsU1/JUvzz/ABH8rj8C+s9APP8AEfyuPwL6yrp//wDRg/8A7+QqPNKcAHZmkAAAAAAAAAAAAAD5kdoRudyIqgH0TcPYCqblc5a/EK0tbapG6dHTo9yPifmmSrkicWfGu0z+EsIU26ba5b1cqyoo5YJ1pWx0qojVajWuzXSRdfVr5D1yx2qKxWWltcMsksdMzQa+TLSd4cjn6us5yYW6G9FFhzUngArTYAAAAAABAvNjtuIKJKK60ramnR6P0HOVNaZ5LqVOUngAweFNz2aguE1biLoWtkp5kfbHRSPVadqKupdSa/i8uwxl9/bdef5eP/lRHt5Q4rwlRYstiUVTNLTfpWyb7Bkj1yRUyzVNmslZIrZEeudjFzUVtkPNLVe6a8PqG07JWLTP0X74iJmuvZkq8hYEXdTpmUOIsI0sCaLY36CqmpXZOjTNciUX9HULO1cXQ0ZY8C5H6ADeIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsuHyn+lCKaenpoJo9KSJj1Rcs1Q69A0na0fmny7izv++l8TqaSmc6BqovQxkjHSTsjbtcuSHSsoqi3PayVzc3pn1Kk3EEcdPXRbyxI+oRep1a8yrmqJqhUdNK6RU2K5c8jUbmiHUU8doWtXND531/zlJdHb6i4te6Nzco9ukpBOsNTPAjkilcxHbdFcszK2xPy2pmxERT7pv3vsO5Y4bp4Z4599ia/JW5Zps2l10BR9rR+aQPdmUdZTK+dzkUobZ8aT7CwJFTTwwaKwxtZnnnoptI59G4Ct+Hs9vzU5CvYrKhzV7vkAAXZpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+4pXwStljdovYubV5FPgHipdAbnDl9SujZRzb4+qa1znPVE0V18ypxGexH8rj8C+s5WJVS4L4tfcdcQfKYfqL6zj3Oazj0cLU0RV96KTOero8ynAB2JCAAAAAAAAAAAAD8VqOaqLsXUfoAK6hr6rBFdFV0kyw4ehXfayjhRHPleqaOaaX9H7ybD1qzXenvlkprtTNkZBUx74xsqIjkTv5KvrPNXIjkyciKnIpUR3abAl3feKVOi1uD0p1glcqMjRVRc0y8BR1tIjUWRntNyGW/kqeyW25Q3SB00LXtRrtFUflnsz4vCTCruFA9tSlyptJ0sLcmwpsdt5youUl3ucLI1t7o0a7Szbxmk2FJF8lbJ39P5MH1D4ks9t17uv8GsPwpbdiSnqInOrHxwOR2pM9qcouWI6anga6kfHO9XZK3PYnKYdnlxYLZmfa4MGPFkWlXUso6WSokRytjTNUbtFHVMraWOpjRyNempHbTIy3GtrahlzSm/R0+pyIvU/b5S+or/QyUkbp5o4ZFTWzk1kslM5jdLr8u4iirWSSKl7J0v17y2BXS3qkWJyUs7JpsuojRfjLxISqGWaekZLURb1I7PSZyazXVjkS6m22VjnYWrc7lLirFNDhC0pc7hFUSwrKkWjTta52aoq8apyF0fL42SN0ZGNenI5MzAkPFWRXC+VaXC/1Da7e5N9oOJYGqueS5Imv4vLsLQiXzDdTgy9Qtt6S18F0mV875Ey6HTSTZl3nL5CWdJRKxYvISxXzXxZqAAbxCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdIXOSRiI5U6pCwlekUT5FTNGNVSpkfvUT5Nugiuy8BRVtwfVSI5NJqI3LLSzzON/wBRwRuc1+Ky7W19p1HAmySXbbyd9j6u1wbcahsjGKzRblrUgH6frU0ntbszXI5dreiHZpZje4/D8LRbK5EVd/TUnzSsNqoo56a3Nba5rU1ZBU35Lr2LS0XaO2tkR8bn6eWxeTM1h58T6K5vptPT0pNLLLqthrxwskkRHuwpvqYVcTsKvjbddty+VznbXKvhPwA+rNRESyIfMVVV1AAMjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrD1xXxa+464g+UQ/UX1nKxdcV8WvuOuIPlEP1F9ZxUv9TM/s+imf7CoAB2pgAAAAAAAAAAAAAAAfhGr7dTXGJrKiJJFjXSjzVU0XcS6iSDFURUsp6i2Kda3dMX/AP6iDyJ/0zeYExol5f0gq+iJrtQw6VXUK1qRPXPLNuS58afuoZsrbzZWXeBkaVD6ZzXaWnFtXVlkVc3Dm4bx6m0yoW/lHqlXh6ifSvbTU7GSqnUuVy5IpBtmGHxVCur0ili0dTWuXb+B5vasQXzc/p32+2W6S8xTu350squzYuzRTLwZ/aLviS+Y+pWWq52p9ohikSoSeLSzVyIrdFc+LqlX7DRTtSKsWf33kbqamcqSWTL70PRMG36xYts9VLa6Kohpmy73IyoREVy5IvE5dWWR81uFaiSse6lWCOFfitVy5p+B5teMNx3aoZKlZNTaDdHRiyRF155kyhx1iPCtFHY6KwLcaekRWsqX6ecma6Werw5fYSOjqaZyubmih0VPO1EcmnsPS7Ph5KNVkq2RySo5HMcxy9SfeK8VUOELS253CGolhWVIsqdrVdmqKvGqJlqPM6vdDxNf6WWz1OHOg4a1qwvqGaecSO1aX2EC0YXZa6xah1dNUorFboS6018Zg2nnqHYnErEip24WHslbe6agw/Le5WSupoqfohWtRNPR0c9meWf2nnF23UkxVRpb8IyVluuCPSRZqqNiM3tM801K7XmqcXEZyHCDYbiyr6Y1D0bJp70vxV17Nuw0DYo2Lm1jUXvITRcNcq3kWwfUJbySNb5sRzI/hFcmVzky3lWp8Tl/dTvEwAuY42xtRjdDVc5XLdQACQxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVXrpJk497d6jNqx6bWuTwoadZGNXJzmp4VK+4Oa6ZqtVF6niOW/1DCx0aTYs25W8ToOD8QdTXjw3vmU+ivIW9kRUhl+shFLC2/q3/AFvcUnAnXrm+35G9xTiKzUysw20+ZNKi9pm+LVxL7i3K+5/HZ4FOq44tqF6+HzQouFzcmqa+19fkUuS8ihGOXY1V8CEwnW1zW75pORM8tq+E4ehiSpqGxOWyLfP2XOql406NiuRnxLAHyj2v+K5F8Cn0fUEcipdDhAADIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuK+LX3HXEHyiH6i+s5WLrivi19x1xB8oh+ovrOKl/qZn9n0Uz/YVAAO1MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWlDSy0tMlzpolqJX5s3rLUicv4GjXVnZIuZhvmbNLT89+C9irBtaWenq2Zx725zctNrf3V5DvvbPmN8hVpx1q/s+P+DZXh6otlceZ10Mj50VrHL1KbEI3Q030TvIeqb3H8xvkG9s+Y3yHPVLIKiZ0q3uven8G4xrmNRqKeWdDzfRO8hNoGOYx6Paqa+M2d+vdusFDJNVT08UqxPdBHK5G765qbE+1U8p5PYLtJjfdIgnnYlJvkLm6ES5omixeUmomRUsnPYiqqIvVP4MJWLImBy2ubAhXCJ8jo1Y1XZZ7DZ0NX0O51LWRMhZFlHBI/VvuWrmLbe2fMb5DfquKR1sCxKxUv39/gYNoXQPvc8q6Gn+id5B0NP9E7yHqu9x/Mb5D83tnzG+Qo+yU//wCvh/BseXun37Tze3xPjc/Tarc0TLMmm7c2JjVc5rUROPI8o3R8fU0kMlltXQtXTVUDXPqYpM1Y7TXVq7zU8p0FBXtpoUhYy6J3999jTmpsTleri8P0qsMqrsN0Kqqqu98fhLQ6djsbUduVbkstgADMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuC+LX3HXEHyiH6i+s5WLrgvi19x1xB8oh+ovrOLl/qZn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAayw9aY/C71mTNZYutMfhd6ym4z+nTx/k3KL0vsOFVRy2yXom35QwZrJVJnmrkTXqzz4s+Q+OFlv+bL5pZXTrVV+Jf6jzs4aaRYV8nqdXTQtqEVZNUNlwsoPmy+aOFlB82XzTGgg7XIbf4fD3+8wWN8R3G+32oiq6lZaakqZm0rFja3QYrtmpNepqbc9hO3Kez2j8XL7CmavXXuu/mH+0ppdyns+pPFy+wp0a+j9hy65Se09zraCGuY3fI9J8euNc1TJSsZenWtOh7s90lQvVIsbUy0eLkL4xeK+u6eKb7yondgTG3UtqVqTO5btC44WW75s3mpzjhZbvmzeanOYwGn2uTuLL8Ph7/edN0PHFXR26m6SVD6d8j3NlV0THaTctmtFPGjb48+RUvjF9RiC8o3K+FHKc/XRpHOrE0Q9cwv2NUPi/eWpVYX7GqHxfvLU7iH0bfBDn3+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuC+LX3HXEHyiH6i+s5WLrgvi19x1xB8oh+ovrOLl/qZn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAayxdaY/C71mTNZYetMfhd6ym4z+nTx/k3KL0vsJF061VfiX+o87Nzf7pb6C3TxVlfTUz5oX722aZrFfq4kVdZ5501tvdCm9M3nOFqmOVUsh1/Dnta111JQIvTW290Kb0zecdNbb3QpvTN5zT5cnqr7iz5sfrJ7zzW9de67+Yf7Sml3Kez6k8XL7CmevkUjLpUTujckU8z3RPVOpeme1F401oaDcp7PqTxcvsKdQvo/YcY70ntPfjGYs67p4pvvNk97Y2Oe9yNa1M3OVckRDz/E17tFTdEfBdaKVm9omkyoYqcffKipaqx5IW1AqJNmvQhAi9Nbd3QpfTN5x01t3dCl9M3nK7lSeqvuLzmR+snvM/jz5DS+MX1GINvi5UudLAygc2rcxyuekC6eimW1cthiDoaFLQIinMcRzqFVNMvkeuYX7GqHxfvLUqsL9jVD4v3lqdzD6Nvghzb/ADlAAJTEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrF1wXxa+464g+UQ/UX1nKxdcF8WvuOuIPlEP1F9Zxcv9TM/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaHgwztpfM/wBxwZZ20vmf7lb+K0nrfBTZ7JNsZ4Gg4Ms7ad5n+44MM7ad5n+55+KUnrfBT3skuxny3kxDRYZwvFX16SuiWbe8omo5c1zXjVOQi3+nt9ht1RUVF0gZOyB8kMEr2sWZWpnotzXNdeSauUw9vw8/HTUudbcJbbSS56LVRXRo5vU6lVUTPaV/Eq2nmhREd12XvNmlp5WvXLoZLEmJrjiWt3yuqVmjhc/eEWNrVa1V2dSiZ7E2lNmeuJuI0rkzbfpF8FOn5j9+A+m7uy/d0/MVaSsQn5blPIgeufAhTd3Zfu6fmHwIU3d2X7un5j3nMHLcYGguFPcYOg7qjp5GNSKiyTRSNVTLXllyN257C+3PLbPat0ikpqhWq9IpF6lc01sUv37i1JAx0smIXxsjTSc90CIjUTjVdLUUMlFE27phm1XBLgr274lxp1Rz9mat6lV5MtpruVG3VmnXu7/8dTZb5dmv16Lv3L/PQud0HdIkSV1rsdRNTyQSywVmnCxUfl1OrPP+9yHlJ6rTbkNLXN03Yies6ojpmLCiuY5dqL1W3PPad/gQp+70n3ZPzEjJI0TJSB7H3zQ8jB658CEHd6T7sn5h8CEHd6T7sn5iTnM3MOW48uoLlVW6RzqaXQ3xNF/UouafahZ3K2UtXRvuloi3qihTQekjl0ldn31XiVDffAhT93pPuyfmK+8YKtuCqd9W7EUdRUQtSRlvk0WOmRV0dmkq8vEuwic5qriZr8/v4E7L4cD9Pl99dywwv2NUPi/eWpBstSlZZ6aoSJsSPZnoN2ITjtYPRNvshQyWxrbcAAmMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXBfFr7jriD5RD9RfWcrF1wXxa+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsqC4Q17HrCqrva6Ls0y1kwyeKVWnqoEhVYkVqqqM1Z6yj6JqPp5POU+XOqcC4VS52zKHmtR7VsinpBV37EFBhq3JX3FXpCsiR9Q3SXNc+L7DF9E1H08nnKZzHM0r7C1r5HOTf26lVV4lM4ahJJEZbUxmoVijV+LQy+KMUXDE1Yj62dJY4HPSDKNGqjVXjy8CHrO5rRQV+53Rw1DVcxJZFyRctemp4Ue+7lHYDR+Ml9tS0namCxTwuVH3QuaWtnt86U1yf+ucjadGpnkmeWv8AAuSHdWtW2VL1RNJkLlavGmowXRM/00nnKVT5eTkuZbw0/abuTI9JB5t0TP8ATSeco6Jn+mk85TDtibE/4avrfAgbou6K5sjrTZKhzVYs9NXI+FMl2NTRVf6thmdyrs+o/Fy+wpnL4qrfa9VXNVqH6/6lNFuVdn1H4uX2FLuyJHkUDlXme09nqqGahmWptqNZvjldUq5c8026s/CpPoq+C4Qb9BpaOlkuaZEkxuJnOp7roQuWNu9pqYuScZUPXkpiTQtImdoXAuu5sQeb9FVH08nnKOiqj6eTzlIu2J6ptfhrvWNdibFFBhejjmrnSN35VbFoM0uqRMz+fr7iC44krmVlzlbLMyNI2uaxG9SiqvF31U0+P5ZJKGkSSRz8pF+MufEYUt6RyPjx7lNVxrFIsd9D1zDHY3Q+K95alVhjsbofFe8tTtofRN8EKF/nKAATGIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZWLrgvi19x1xB8oh+ovrOVi64L4tfcdcQfKIfqL6zi5f6nZ/b9FM/2FQADtDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAssYfKqf6i+szposYfKqf6i+szp8iqPSKfSKP0DT9M9jfrCnjm+pTQmext1hTxzfUplSenb4is/Tv8Dz4993KOwKj8ZL7angR77uUdgVH4yX21Ojn805KLzjT3TrVV+Jf6jzw9DunWqr8S/1HnhQ1mqHRcM81wABpFoeWXvr7XfzD/aU0W5V2fUfi5fYUzt76+138w/2lNFuVdn1H4uX2FOtX0fsOJd6T2nv5i8V9d08W33m0MZivrunim+8par0Zb0HpikABWF+ZXHnyGl8YvqMQbfHnyGl8YvqMQdJQfp09pynEv1LvZ8j1zDHY3Q+K95alVhjsbofFe8tTuYfRN8EObf5ygAExiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWVi64L4tfcdcQfKIfqL6zlYuuC+LX3HXEHyiH6i+s4uX+p2f2/RTP9hUAA7QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPNbjug4guE+nNVtcjc0Z+hamrPwEThjeu2W+ibzETg9e+49f92fzDg9e+49f92fzHDrDEuatQvUqJmpZHKS+GN67Zb6NvMdIcQdMXLBfpHS0uWkjWMRF0uLZkV/B699x6/wC7P5hwevfcev8Auz+Y85EXRLGXaZurlXuXQ/Lra5ra+N0jURk+boslz6n/AMU9u3KOwGk8ZL7anldtp7pHFLTXKz1jo5k0EqaiJ2VMmSortabE27U2FjUXa6UmGIsL2amq5t4m35K+je7q0XNVbotT+987iMFVV8h2plhan5jNNti5xzunSOmbR4fqXMYiSR1SSQprXZqVftMRwxvPbKejbzEV1gvj3K51pr1VVzVVp36/wPng9eu5Fd92fzEnJiXVLkbZ5W+aqoTOGF67Zb6NvMOGF67Zb6NvMROD167j1/3Z/MOD167j133Z/MeciH1U9xl2mf1195PqaKG9U61luaqzxMWSuV65ZuVM9SeFHbCx3Kuz6j8XL7ClPR2u/wBHMjm2m4KxXIr2JA9EeicS6jSWyrdZLyzEaW1Y6mJFZ0q/VvVFTR0s8s+PP4vEYKqsTCui6GWFJfKTJU17+9PvNT1TFmK6HC9C11W6RslQ16QaDNLqkTj8qHiNZjzEFfPv1TVMe/LRzSFqe4/L2zEd+uE9ZLbrm6KaZ80UTmSSNiRy55NXLZxauQruD967j133Z/MZthZazsyPmvR12qqEvhfee2GeibzDhfee2GeibzETg9e+5Fd92fzDg9e+5Fd92fzDs8PqoZdpqPXX3lhBeorrpRX1zpGtT9CjG6OTl5ciquVrqbTUNhqUaj3N0k0Vz1ZqnuOnB699x6/7s/mLqlprjLRSUNztdTFvrtdwqYnfoU1ZJ1SbM05U2nluVm3Tb+DJHc7yX+d0X6L9NjZYY7G6DxXvLQhWWnZS2elgjmSZjGZJI3Y4mnaQLeJqpshQyIqPVF3P0AExgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWVi64f0L7jriD5RD9RfWcrF1w/oX3HXEHyiH6i+s4uX+p2f2/RTP9hUAA7QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN6i6SIqcZ+mcmrZMNv3qRXVu/9Wiudo6CcnGfHDH/2H+d/2nzPnsTJ2SnXpSSuzYl0NMDM8Mf/AGH+d/2mV3RMV1M+G2spWy0cnRDV3yKdUXLJdWpEMo5o5HI1FMJKWaNquc3JCFj7dL6IbJa7JJnDJHLBWJLDr19TqXzi43OKCZME0tdQInRbpJGqr11aOmv+x4s5yucrnKqqq5qqrtPe9ynsCpPGS+2pvTxpy7GlDIqPuae33CKua9rM9OLJr9WWsmaipuVBvaJXQSbylMiyPjY3LfcteSqng5OMruGX/sP87/tNDmozJ5vpAsucSf4NNknINXIZrhknc/8Azv8AtHDJO5/+d/2nnaY9z3sU/q/I+8X4uosK0Sb+57ampjk6G0WaSabUTLP7XIeXYSuNTjDdHpqi6q10j4XtVY26OprFyM5im41VwxDXunnlextVKscb5FckaK5dSZ7OLyFzuU9n9H4uX2FLLltSNfArcbkenceyw1c1ql3itySnc7e6XQTNck5fsyLo4VFPHURq17WqqIui5Uz0V5UKB90fh53QUiOrHL1e+Ofo7eLLXyFcq8vXQsEZz/N840wMxwx/9h/nf9o4Y/8AsP8AO/7THtEW5l2Go9U0j3pGxz12NRVU8Vx7ukOvTXW6zyZ22eBqTJJFk5Xo5V1LyZI0sd0vFNXU26jbSOmolSV2ksU6ppJlsXLI8rLCmRr240NCdHxuwO1PXcMdjVD4otCqwx2NUPii1O4h9G3wQoX+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuH9C+464g+UQ/UX1nKxdcP6F9x1xB8oh+ovrOLl/qdn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyxf8qp/qKZ00WL/lVP8AUUzp8in9Kp9Ho/QNBnsbdYU8c31KaEz2NusKeOb6lM6T07RW/pn+B5+e+7lHYDSeMl9tTwI993KOwGk8ZL7anQz+acnF5xp7r1orPEv9R54eh3XrRWeJf6jzwoqvVDouGea4AA0i0PLL118rv5h/tKaPcp7P6LxcvsKZy9dfK7+Yf7Smj3Kez+i8XL7CnWL6P2HEr6T2nvxjMVdd08WnvNmYzFXXdPFp7ynqvRlxw/0/sKQAFWXxlcefIaXxi+oxBt8efIaXxi+oxB0lB+nacpxL9S72fI9cwx2NUPiy1KrDHY1Q+LLU7qH0bfBDm3+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuH9C+464g+UQ/UX1nKxdcP6F9x1xB8oh+ovrOLl/qdn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACuxLj3D1bVR7xVvdvSK12cLk15+ApeGFl7Zf6J3MecqquVVVVVV2qoPnz6CJ63W51EfEpo2IxETI9G4YWXtl/oncxBu9fT4moegLW9ZZ0ekmi5NHUmeetfCYc6wVM9LJvlPM+J+WWkx2ShtBHGuJirdD13EpJEwSIll2PhzVjerHanNXJT3vco7AqTxkvtqeSyxU+IKR08LYqJ9HGuk3JFWdcvs16u/tN5hnFUGENzOjnlhSom6IexaffUY9M3OXPYvJ+JK92Ntuprcvlre903Ndi7FNpsFG6luM7o5KqF6RI2NXZ6suLZtQ844X2Xtl/onGIu94rrxVumrKuonRHOWNs0rn72irnkmewgGD6KOS2K5LDXSQ3Rlj0bhhZe2H+idzDhhZe2H+idzHnOYzIvw2HvJvxafZC1v1HNFWurXtyhrZHywrn8Zqrns4tSoXm5T2fUfi5fYUqLVdWuY+irY+iUlRI4XyrmkG1M0z2cXJsNHgOgbZt0Ol3ypY+Bscmc/wAVmti6szaV1kVjtTUcxF/MZp17j2+aZlPC+aRcmRtVzl7yJmeWX/HmHq+4JNT1b3M0ETNYXJr8hU7oW6DUXKsdbbbJUUbaOaWKSSCpXRqG56P7uWrVnx7Tzwi7K2RtnmUdU6F+Jh6NwvsvbL/RO5hwvsvbL/RO5jzkEf4ZDuptfi1Rsn37TZ3uojxPTsitKrM6BVfIjk0ck+0xh3pauekeroZpI9LU7QcqZpyF3X09PeqJ9zpI4qRYU3voViJnIue3Vly8nETxt5CIz9prSOWqVX/u6/48Dd4Y7GqHxRaFXhlFbhyia5FRUj1oqFodvD6Nvghzz/OUAAlMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXD+hfcdcQfKIfqL6zlYuuH9C+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3+CPCn0NV6dR8EeFPoar06mmt90bUxv35iwKxdH9I743f1kzoqm+nj85D52kyql0U6R0OFbKhjfgjwp9DVenUfBHhT6Gq9Opsuiqb6ePzkKTFeLabDFoS4b0lXnKke9slRq60Vc9i8h6kj1WyKYrGiJdUMTijDOCsHQb7pVUdwdE+SiRXOe1ZGp1OerZmqEHDuGrdiK2x3/ELZN7mVzNOJ+j1TVyTUneQwd3vFbeKt01ZV1E6I5yxtmlc/e0VdiZ7OLyHte5fBFUbntGyaJkjd8lXRe3NPjqSyscjbouZjDImLCqeTt99Tmzcmwm9iObHV5Kmafp15j6+CPCv0VV6deYuo3z2aqSGZ0tUypkTRdmuUKZ5d/Vr/AALjomD6aPziBs7l62JnwI1cs0Mb8EeFfoqr068w+CPCv0VV6deY2XRMH00fnIOiYPpo/OQy5rtyPl9xiKncrwhSUstTMyrbHCxXvXflXJETNeIw8ENsveIWYbw+sktplYr0STNr9JEVy6176HbdFx5VXK4OtlA+pomUUs8E6xVCo2oTNG60TLV1K6lz2lfuU9n1H4uX2FNhWKrFVxg2TC/yf+e43Vu3M8I1aOgVlV0TCiJMm+rkjti8XKik34I8K/RVXpl5jR3G2ucrZ6R/QzmuV8u9pksvHkuX2+U7UF0jrIFklZ0M5Fy0JHazUSV6LhcpsOiYqY2Jl8jLfBHhX6Kq9Oo+CPCv0VV6dTZdFU/08fnIOiqf6ePzkJOY7cj5abGN+CLCv0VV6dTL4tsuEMFoqUT6ll5SJstM16ue3JXK3Xqy2I422NMaQYWoIZWwdFrUudGm9yo1WatuxTwGtuFbcpkmr6yeqla3RR88ivcibcs14ta+UnjRXpdy5ETnYFyTM9ZsVTJWWSlqZlRZJGZrkmSFgVWGOxqh8WWp2sCWiaibIUkiqr1VdwACYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/U7P7fopn+wqAAdoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlHLh/e275JLp5dVki7fIdqijtzrS6so9NU0kRFcvfMy747vCpoqTsSd4z3nCUfEqqStSNzsr/U6us4fBDS8xqZ2+hVgA7s5QuLBoolU9zEfoMRclTwkfhS3ubD5f9jvYv1Nd4rnMwcFx6aSKrVGLb/hDrODQRSwqr0v9qaDhS3ubD5f9iXbL6yvr46ZaCJmnnrRc9iKvJ3jKFnhzr9Tf1eypSsqplciK4tZaKBsblRvRTtcURLhOiIiJvi7PCRiVcuuNR4xSKfUIfRN8EOAf5yg0N4usdrqGRJRxyaTc811cfgM8WGL+uEPi/epzv8AqKR0bGK1ba/QuuDRsklVr0un/J+8KW9zYvL/ALDhS3ubF5f9jPA47tc/rKdV2Gn9Q1dylZVWCmqkhbG6SRNTf6ikLafsSovGfmKk+h8FVXUbVU4fiLUbUORAXFneyC31s7omyb0iORHfaU5aUHWS5/U5yTiyq2jeqfeZhQoi1DUU+OFDe5sPl/2I1Vc0uStVKZkOh81duf8A+CoJFL+99hyHBKiV9cxrnXTP5KdTxWlhjpHOa3PL5odwAfQjiwADwAAAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALHGPyun+ovrM6aLGPyun+ovrM6fIqj0in0ej9A0Gfxt1gTxzfUpoDP426wp49vqUzpPTtPa39O/wPPz37co7AaPxkvtqeAnv25R2A0fjJfbU6GfzTkotTTXXrVV+Jd6jzw9DuvWqr8S71HnhRVmqHRcM81wABpFoeWXrr5XfzD/AGlNHuU9n1H4uX2FM5euvld/MP8AaU0e5T2fUfi5fYU61fR+w4h3pF8T34xeK+vCeKb7zaGLxX14TxTfeUtV6MueH+m9hSgArC+Mtjz5DS+MX1GHNxjz5DS+MX1GHOkoP06HKcS/Uu9nyPXMMdjVD4v3lqVWGOxqh8X7y1O6h9G3wQ5t/nKAASmIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZWLrh/QvuOuIPlEP1F9ZysXXD+hfcdcQfKIfqL6zi5f6nZ/b9FM/2FQADtDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgu+O7wqaKk7EneM9551VYfvD6uZ7L7OxjnuVGortSZ7PjGwwxclstiS3V6OuLkkc5ZJHbc+LJcz5rC+GmqubjvZdPadvOk9TT8tI7Za3TY/QT5cS26KJ8nSWJ2i1Vy6nX+BDsuNrXeKJalthjiRHq3RVWr/pOnT/UMCtV2FbIc/wDg9Qjkb1UtLGqNp69yrk1ItarsTUpjemtt7oUvpm85pK6/JLCsNFTMpmStc2VEanVoqeDw+UxXBCy9rv8ASu5zmeIVdPVzrIt0/wCC/oaaqpY8KIntLLprbe6FN6ZvOW2F7hRT4ipY4ayCR66eTWyoqr1C8R55abFQVV+uNJNG50VOuUaI5Uy1mntNkobJc4bjQxKyoh0tByuVyJmitXUveVTVfHTwuS6rfXobDZKmdi2allumq+BsLhRVTrhO5tNM5qvVUVI1yXWRugaztSf0anzwnun0zfRt5ikrsc3+HFVFQsq2JBNHm9u9N1r1XHl3kOig/wBQOVMLWaJ8iim4M5nlOdqtveXvQNZ2pP6NT6xrWUtPc4Gz1MMLlhzRJJEaqpmvKfHCa6/Tt9GhQ36ihxLVR1N0asskbNBqtXRyTNV4vCVtfxVlcjWyJa2xY0fDZqR2JqovifPTS3d0KX0zecdNLd3QpfTN5zJYpsVBaqCKWkjcxzpNFc3qurIu+CFl7Xf6V3OVroqZrEequz8OhvNmqnPcxGtuluq9T0KPOtwjROpf06K/NFi6pFTquQgdAVnak3o15iHarnVWe2w2+iejKeFFRjVajskVc9q+E/briy8U1sqZ4qhqPjjVzV3tq5Ll4C7ouNpTsSFjb+JUVXCJJXLK5bEzoCs7Um9GpOgY+ksNzfUsdA3e885E0URMl5TO4fxle6+y09TUVDHSv0tJUiamxypyd4lV95rrlQT0NVKj4J2Kx6I1EzRdusyrOOc5joHtt4dynlLwiRqtmaveU/Ta3dv03pm85Ot1VTVSSLT1EU2jlpb29HZeQoOB9l7Xf6VxywCxI33Rjfitlaif4iLgcUK1aOYq5b+Ck3F5p0p8EiJZdu5UNgADvTkQAAAADwAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALHGPyun+ovrM6eZVOJL1VTK+S7Vr9a6KPqHOyTk1qcund17o1XpXHzaThyvcrsR2MHFGxxoxW6HqRn8bdYU8c31KY3p3de6NV6VxJoL/NFUaVx3y4Q5fqpn6Tc+XJcxHQOiej73sZScSZMxY7Wv1Kg9+3KOwGj8ZL7ani12tPQu9zQyNmZMivVI2/q05F8p7LuX1ENNufUb55WRN32VNJ7kRPjrym9K5HsuhVIx0b7ONXdetVX4l/qPOzM443Q6y8VrIbbLVW+On3yORIalUbNmuWa5Zcnf2mS6dXXujVelcaktC6Wy3sb1NXtgRUVLnqYPLOnV17o1XpXDp1de6NV6VxD+Fu9Y2/xhnqqfl66+V38w/1qaTco7PqPxcvsKQHMgxDRaTUjpJ6KPORy5K6pcqbeJc829/4xZblkb4t0GkbIxzF3uXU5Mv3FLNHXYreqFNIyz0cminvZi8V9d08U33nTHOOKfDVGyKFiVM1Qkkf6KdGuhciZZrlmvH+B4jLiC8zO05rtWyO2aT6hzl/FTTdTLMy17G1BVNp5MSpc9QB5Z06undGq9M4dOrp3RqvTOIfwt3rG/8AjDPU+JqsefIaXxi+ow5dW6+uSR6XJrq9rkyYkz9LQXlTPMj3azutkyNZMlSxWaSyRp1Ka8sjep28lEiX/krKp3Pcszfb3HpWGOxqh8X7y1KrDHY1Q+L95ancQ+jb4Ic6/wA5QACUxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/AFOz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABm58UWaKokikrNF7Hq1U3p65Ki+A58LLH29/lP5iwltlvdM9zqCmVXKqqqxNzzz8BmnUdImOo6foWHeVj/V6CaPxV4j5crKaSR+uV16HfLJVRsZm3OyaL/JY1GKrK+mlY2szVzFRP0T9uXgKvC99tlutSwVdTvcm+udloOXVknIhpXWq3cVBTehbzBLXbe51L6FvMRpLTJGrLLZfAzWGpWRH4m3TuUp67GlFDvaUMa1iuVUdkrmaPJtbrz1+Q+ExZXdwJ/PX8pxxVSU1NPbeh6eKHSlXS3tiNz2chrDN/IZG1yMve+q/wYRpUySPaslrW0TfxMLQXKvorrWV3Sed/RS56GtNHXnty1ljLi+sgjWSWxTMYm1zpFRE/wAJqSnxZ2M1f9HttPEnimkRHR62TVQ6nmgicrZNLroniV7MXVkjUcywzOaqZoqSKqL/AIStqbnX1F8prp0nnb0O3R3vWult49Hv8hrLJ1ko/Et9RNPOfFE9zWx7pqpl2aaVjVdJsuiGa4WV/wDD8/nr+U5w4zqahFdBZZJETUqtlVf9JqTNYF61z+N9yHrXQLG5/L0t1XqYvbUNlazma36J0Ky+3OvvVLHB0nnh0H6Wet2er6qFlwrr/wCH5/SL+U04MFqolajVjyTvUlSklRyuSXNe5DLNxnUumdC2ySOkbrViSrmn2aJzrsRXCtoZqbpDOzfWK3S0lXLP+k72zs6ufifyGmJJHwwubaPoi6qQxMnma68nVU0QxtqvVfa7bFRJZJ5d7z6vNW55qq7NHvkh+MqmJ7Y5LJK17/itWVUVfB1JqjN3/sjsnjPeh7HJDPJnHrddV8RLFPTxJhkySyaJ4Hzwrr/4fn89fyknAkc7OmMk0D4Vkka5Eeip84vSRS/vfYWXA6hi1jWNZa9+vcppcXpn9mV733t3J1VCQADvzjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADzr4L8Zdx/8Aiofzj4L8Zdx/+Kh/Of0BHI2VukxzV5clzyPo4HnuL5YkQ/n34L8Zdx/+Kh/OPgvxl3H/AOKh/Of0EfE08NOzTnlZEzPLSe5Gpn9o57jzloeHUWD8XWSjqlrLW2G3vZnVy79E5WRIi6SoiOVdmfEoWlvl+sceHsP0jKu0xSLNE9zmskV2vS1uVNWarxH7jjdDq75P0JQLPRQRpJDM1s2bZ0XVryRNWSL5TabnVu6JwBSSU0iU9SskmcyN1qmmuoPxNTmIme331JY3Nf8Alu06Lt/g87+DHGPcj/iYfzj4MMYr/wDtH/Ew/nPc7dcuiEdFNGsT4lRiK9fj99CxPG1KuS6GL6fA6yn89/BfjLuP/wATD+c/fgvxl3H/AOJh/Of0GD3nu2MeU0/n+Hc1xrBMyVln6pjkcmdTDtT+ssUfdLJfG1MsDGYmY3qKZyo6PQVMs80XLPRz/eN3jzHUGG6RtNTs6Inq2TR6cM6IsDkRERVTXrzd3th51ue1M173QqSW6SvrXujkRXTrpKuTFy2nqo56Y9vv3GTHoxcGqLr97nKpwDjS8Vc1zfaWq6se6dVbURImb10tSaeracvgvxl3H/4mH857S509ln6pX1EFQ/RYxNSQoi/bq1p5C3a9j0zY5HJyopG2pcvQzfTI3O90P5/+C/GXcf8A4mH84+C/GXcf/iYfzH9BZAz7Q4i5SH8+/BfjLuP/AMTD+YmxYVxJZLRNFerclNaNLTqZkmjc5uxEy0XKu1E4lPbqusgoYFlnlZGmS5I9yN0lTi1ng2M8f1mJ6jRplnoqJ0LY5KVJtJj3I5V0l2cqeQyu6XJT1F5S3Q2tlSmbZ6ZtG9X06M/RudnmqE0q8L9jVD4r3qWh20CWianchRyLd6r3n6ACYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/U7P7fopn+wqAAdoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGPqarFjauZIaGF0Wm7QXSbrTPV+8Va0mKFu7bn0AzfkboommzLZl842MlXTJI5FqIk6pdr0Pjoul7Zh89D5e+oc2R1o069Dvm0rXMbikXK3VDOvrcXMY577fAjWpmq6TdnnFRw2ufzIPNXnNpV1dMtHOnREWaxu2PTkPKTZpGsmRcbES3caNc6SnVqMkVb95ZXW+1d33nf8AQbvKqrdBFTblzEfppX9uz+kUigsmsa1LImRUule52JVzL+wwV97mlj6azwb01HZ5q7PX4ULmTB9XNGrJb7K9i7WujVUX/EUmFbtS2mpnkqlcjZGIiaKZ8ZpuGdn+fL6NStqXVLZfyky8ELikbSOiRZlz8VIrMIVkbEYy/TNampESNck/xFbVWyvpr5TWzpxO7ohmlvmtNHbxaXe5S84Z2f58vo1KWtv1DPieiuDHP3iGPReujr/e4vtQxhdVKq406L0TUynbRtRuB3VOq6depY8FK/8AiCfzF/MfEWDamBqthvUkaLrVGxKmf+ImcM7P8+b0Y4Z2b583oyHHXbfBCfl8P9ZPev8AJR32219lpY5um88+m/Ry1ty/xKUXTOv7cn9IpfYov1DdaKKGlc9XNfpLpMy1ZGXLSmRyxosiZlNVqxsqpEvk+J2bWVLZnTNqJEkdqV6OXNftOnTOv7cn9IpFBsK1DVxO3NfabHX3S2RVnTueLfM+o0Vdlkqpt0u8SH4NqpXtkkvcr3s+K5YlVW+DqjnYcTW232aCkqHyJJHpZ5MzTW5V95YcM7P8+X0ZTSOq0euFMr7IX0TKJ0bcbs7JfNf5I/BSv/iCf0a/mJOBJJ39MWTzyTLHI1qK9yr84/OGdn+kl9GfOAHpKt0e34rpWqn+It+CLOtT+anw7lK3iqU6RJyVvvnc2AAO1ObAAAAAPAAAegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtrhM/DcqRUOStn6t2+JnrInCu48kPmf7nfF/yun+opnj5NK9zHq1q2Q+h08MckSOel1UuuFdx5IfM/wBzKbot7q7hhpsM+96KVDHdS3LiUsTPY36wp45vqUzpZXrM1FUwq6eJsDlRudjz5D37co7AqTxkvtqeAoe/blPYFSeMl9tS+n805mLzi/vFFHJD0cue+0jXSR8iqmvX5DPcK7lyQ+Z/uam7daavxL/UeelHUucxyYVtc6ChYyRq40vYueFdy/8Ak+Z/uOFdy/8Ak+Z/uUgNTnSbm/2aD1UPL8QyunxHcpn5aUlVK5cuVXKpodyns+o/Fy+wpm7118rv5h/tKaPcp7PqPxcvsKdSvo/Ycgqfme098e1HscxdjkVDLVtdLh2o6BotFY1aj85EzXNf/wAGqUxmK+vCeKb7ynqVVrcSalxRIj5MDtD94V3Hkh8z/ccK7jyQ+Z/uUgK/nyesW/ZofVQpN0y8VVzt1Eyo0ERkrlTRTLiPOTcY7+Q0vjF9RhzoKJyugRVOa4gxrKhUalky+R65hjsaofFe8tSqwx2NUPiveWp3MPo2+CHOv85QACUxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/U7P7fopn+wqAAdoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGTqcHWueqlme6fSkerlyenGvgKF2H6JuK2WzOXeHR6Xxuq+LntLmpxjFBVSxLQTLvb3Nzz25KUbr812JWXXoOXQazR0OPZkfOkSqxvxLvbTXodi9aNWMwomqXyXTqXnAi0ctR6ROYy2JLZBarklPTK9WaCO6pc1NHw2h7nz+UzN/urLxXpUxxOjRGI3JVzFIlVzPzdDCtdRrF+Ta/tKsAFmU5p8D08M9ZVJPCyREjTJHtRctZd4poqWHD1S+KmhY5NDJzWIip1SGXw266pUTdKmsdJopp6WWzPvlzXU+K7hRyUs8MKxyZaWTmIupc+XvFVOxe0o7GiIlsrl3TvTsiswKqqi52Lmz0FG+z0jnUkDnLE1VVY0VVJnS6h7Sp/RN5jO00eLaWmjgjhh0I2o1uas2eU4y3bE0FwioJGQpUSpmxuTdaa+P7DVdDI96q2RN9TcbURxsaj416JoajpdQ9pU/om8xncFUtNPbZnTU8UipLkivYi8R008YfQweVnOQ7bb8UWmF0NLBEjXO0l0nNXX5TJjFSNzVkS626mL5EWVj0iWyXv5O5rOl1B2lT+iQ8lNhcLvia1wtlq2Qsa5ckVEauv7DHm7QxPYiq51799yu4jMyRWo1tlS/S2wABYFWeh4XoqWbDtK+Wmhe5dPNzo0VV6tSHfaSmjxBaGR08TGPkXSa1iIjtabUIllfiRLTD0BFE6m6rQV2jn8Zc9vfzPqqoMUVlXT1UtPGslMuceTm8/eKZGq2dzlels+p0CyI6ma1I1vl02sarpdQ9pU/om8xNt9PBAkiQwxx5qmeg1EzMpvmMfoIfK3nLLB11rLkla2s0dKF7Wpoply5+o3uCwyJWtdjRUS/W/RSDitRGtM5uBUVbapbqaUAHenIAAAAAHgAAPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWWL/ldP9RTPFTft02iuNU3Qt8zN6zauk9NesquHdL2nL5yHyyakndIqo072mradkSNc7M1ZnsbdYU8c31KRuHdL2pL5yHKpukWLYelsKdDORd805F1auL8T2CmlikR70siHs9VDNE6NjrquhjD37cp7AqPxkvtqeCzQuhldG791VTPLae9blPYFR+Ml9tS5n8w5yPzjT3XrTV+Jd6jzwvcc43o8OQspH0z6l1bFIiOjemTMsk1+U844d0vakvnIVVRTyyWViXLqiqYYkcj3WNUDK8OqTtWTzv9hw6pO1ZPO/2NXsdR6pYdvpvXMreuvld/MP8AaU0e5T2e0fi5fYUp79QPbKy4te17a9XTaDdsaLkuS+Uudyns+o/Fy+wp0KOR0d0OXe1Wy2U98UxmK+vCeKb7zWVlXHRUss8jmokbHORFXLSyTPJDx68bpdFc61KhlvmjTQRui56LylZNE+RnkJcsKOVkUuJ62QuwZbh3S9qS+cg4d0vakvnIaPYqj1S47fS+uMefIaXxi+ow5sKyrjxdFvMCpTLTZyKsi56XeMg5qtXJyKnhLqjRWRYHaoc/XrjmWRvmroet4Y7GqHxXvLUqsL9jVD4r3lqdzD6Nvghzj/OUAAlMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXD+hfcdcQfKIfqL6zlYuuH9C+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAf8dfCfJnqyx319XNJHensY56q1qKupM9hULFfEvbbV03lSRzdLT0ly2Zny19K173WkTqvU+gNq3sY3FGudk6Gzq/kc/i3eo8kNy7D9+citdfXKipkqZuMrd7VJaKxKaSRsiq1HZtQ3aBI2XajrqpW8SWSRGvVioiEAAFmU5p8EVENPWVSzSsiRY0yV7kTPWbHpjQ9u0/pW85hMLWmlu1TPHVI5UjYipouy4y2v8Ahm22+yz1VOyRJGaOWb801uRPeU1VHC+owuVbrY6CjlnjpsTWoqJfrmaXpjQ9uU/pW85nblV0z8a2+Vs8axsiyV6PTJPjcZ923CdrqrZTTytk05I0c7J/GpJ4GWf5kvpFIGdmhc7NeqaGw/tU7WrhToupb9MKHt2D0recdMKHt2D0jecqOBlo+ZL6QpsMWChu1DLNVNermyaKaLstWRg2Gnc1XYlsnduZunqWvRitS69+xMxrVU01thbDURyKkuaox6LxLyGKPQ+Bln+ZL6RTzwtaJ8aswRrp9Sm4jHKkiSSIiX27gADeK09CwvW0sOHqWOWphY9NPNrpERU6tS26Y0PblP6VvOZqw4Zttxs0FVUMk3yTS0sn5Jqcqe4jXawUFHebbSwtekdS7KRFdnxoULoYJJnJiW916HTMmqIoGrhS1k6mu6Y0PblP6VvOVOA1R0l2VFzRZm5f4j94GWf5kvpC4sVnpLS2dtKjkSRUVdJ2ezMs+BOhZVo1iqt7/JTQ4uyofBjeiIibLvYtgAd6ckAAAAAeAAA9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4cD+k+BmGO4NB6BD94GYY7g0HoEOG57S75S7n81g/pPgXhjuDQegQcC8MdwaD0KHnPae8pTw9lXTYhgSGufvVVCze6RkSKiSOVNSLnmm1E5DWW/Gq4LwNT2yBYHXmKdVkppo3OajHK5c9JuSZ604+MtMdzYVwxTJT01ipei6qGTeKiBrUWB6Jk13Lmiqi/YQ8HWmhqcOQ3270cVxWVz41SVmk7NHZIuvkRCJyoxt7eT9/A2UTnLb9/z/z8LHllRO6pqJZ3oiOler3ImzNVzOZ/SMWEMLSsa5thoNaIuW8t1H3wLwx3BoPQIS89prLCqH81g/pTgVhnuDQegQcCsM9waD0CHvPaOUp/P1mu77bv0GTN5q9FkzlRVVrdaKqfYqmowktusOKoL4k70s0THtdUvRVVHK1U+KiaW1U4j0+4YawlbqGeqmsVvyhidJo701Fdopnkh5la56PFuNobfbqNKG2yxqvQi5aCOa1VzyTVtRCJy3u5iePf/kmYqWRj18O7/G5W45xpUYprVgVtOtHSTydCyRsc1z2KuSK7SXkROJDKH9A2zDmGJlfSy2Cj3ymyY6R8Lf0ipqVU8hZcC8MdwaD0CGTKhityQwfA5rrKfzYD+k+BmGO4NB6BBwMwx3BoPQIZdobsYcpdz+bWuVrkcm1FzNHLUQYnh05XZXX9XT08SKjHNTXmqrq43cabD2/gXhjuDQegQwW6BW4bw+j7ZbbJTxV0sDZYaynRqb1m5Uy1a88mr5TxXI/zdTNn5aKjs0XX732Jdgp5aSxUkE7dCRkeTm5ouS/YWBW4cmkqMP0csz1e90etyrrXWWR2tPflNvsnyKOS2NbbgAExgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWVi64f0L7jriD5RD9RfWcrF1w/oX3HXEHyiH6i+s4uX+p2f2/RTP9hUAA7QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2pamnpZt8qYd9ZllokE8yQROkdohJFGsr0Y3VTiC4prraqmpjgbbWosjkaiqiaiJd42RXOZkbUa1MskTwIaNFxSKserWJobNVQyUyIryEAC1NIAvaue322kpHTUDZFmZnmiJxInOROnlp7l+o56T/UFPG5WuRboW0fCKiRqObopiajFNminkjfWZOY5Wqm9v25+Azrr1b1xjHcEqP7M2PJX6DtuiqbMsz0l7MIyPc9+GqVXOXNVWNutfIfddYcN1OHZK2msdJA7SRqKkSZprOURaa73NVc0Uv39rXA16IllS33cyPCux9vf5T+YyGKK+muN0Sakk3yNI0bnoqmv7TaVVmtjaSZW0ECKkblRdBNWoqMI22iq7OslRSxSP31U0nNzXLUeU7oIkWZqLll06klTHUTKkDlTPPr0MhS26trtPoOjnqNDLS3qNX6OezPLwKSOD967kV33Z/Me14LpKa3pcH0kEcKrG3PQTLPLPI/OFN0+fH5hsrxFiIi21NFOGSK5Wouh5XYY71ZJ5ZOD9dPvjUblvT25f4VJ92r7zdLZLRcGq6LfMuq0HrlkqLs0e8eicKbn8+PzCbZ7/X1t0hp5nM0H6WeTcv3VU1+008kqOVuZs9mqoolZi8mynl1JiC40NHFSOsFSroWoxVVVaurvaJ9OxnUNlbCtlkSRyZoxZVzX7NE212T/AOLVXjVMbc+zq2+K/ORtdBK9yKzS66qTvSeOJipJrZNE6jhVX/w/P56/lIdilvdlpZIODdfPpv0s96e3/SpsjXX+8Vduq444FYjXMzXSbnxnkc0OB12WTLqonhqEkZhkuudsk7jzLp9e/wCE6/zX/kMdwevfcev+7P5j2nhRcvnR+YOFFy+dH5hJFVwRXwNtchmoqua3Mci2+9jxOSx3eFulLa6yNOV0Dk9xydbq2NiufSTNamtVVi5Ie93mpkq8M0c8uWm+XNcky4nGOvXWSs8S71E68QXmI1G62+JAzhqLG56u0v8AAzFkxDV0NohporRLUNZpZSNeqI7Nyr81eUVlbdbpcaOtisNX/Y3ZqxrXO0tfKjdWwvcJ9jVJ/X7bjc4enfTWq5Tx/Gjajk8imvzomzu8jO653XvNl0M3ZWrzMvJysncefdP71/Cld5H/AJC9w7UXG5MndUWaqo9BWoiPa7qtvK1C84U3P58fmDhTc/nx+YS0tbTU0qSsZmniYz0dZPGsb35L4fwfHQlT2tL5inFUVq5KmS8il1Y75W19xbBOrFZoqupuRV1ny2fxjvWdjw3ifbsXk2sc3W0K0ioiqcT9RFcuSa1U/DtSfLYPGN9ZbOWyKpXpmtj86Fqe15fMUdC1KJmtPL5ilrfL5W0FwWGBWIzRRdbcysXE1ykRWK6PJ2peoOU/6k8vCrC/bwR7mY0ccAAdac+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaamuz6ZrmXZWUzs/0SZL1TeXjO3T619uM8i8xSYx+V0/1FM6fK31Do3YdTvIqOOZiSLlfY3vT+19uM8i8xQYzxwljsaVdpkp56hZms0JWuVNFUXNdSpyIUJn8a9YU8c31KZ09S58qNVNTCooGRxOeirkYSomdU1Ek70RHSvV6omzNVzPedynsBo/GSe2p4Ce/blPYDR+Mk9tS4n80oYvOLR9NPZZ98o275Tyv06l8ip1CJtyyy4s+UmcILX223zXHa69aavxLvUp54U0siwrZpd08LalFV+qfE3vCC1duN81w4QWrtxvmuMECLtb9kNn8Nj3Uxe6FiqrxFen0szIEp7dUTR07omqivYrkTN2arryanIdNyns/o/Fy+wpm7117rfHv9pTSblPZ9R+Ll9hToF9Hlsc0vpLd57fc7bHXtje5Xo+BVcxGqmte+cKe8pDHoXZ0dNUZ56CIuziXjLUxuK+u6eKb7ypmXlpjQtqVvOXlu0NF0/tfbjPIvMOn9r7cZ5F5jBA1O2P2N/8Oi3Ussf47kstsgW0Ppp3VD1ZLvrHLk3Li1oeGG3x58ipfGL6jEF5SOxxI7coq2NIplYmh65hfsaofF+9S1KrC/Y1Q+L96lqdvD6Nvghz7/OUAAlMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXD+hfcdcQfKIfqL6zlYuuH9C+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVR+rTwnU41TmtizcqJr4yu4p+il8FN3h/wCrj8T6tPXal8YhZ3vrtP8A0+yhVWiWPpvSokjVVZU4y2vTHLdp+pX93i/uocx/pv0rvD+C84/nht96lcD73t/zHeQaD/mO8h2103OXspPxN8jtni3eppnjQYoe1tHbNJyN/Ru2r3mmc36L6RvnHymt/UOPodAqdmafZa3CWsh3PpX0ELZp0mTJjti9UmfGhT79F9IzzkNFD1eC36HVfpf3df7yGMF0cq26HtV5SNRF6oecSXDFcsTo1tMKI5FRVRf+4iWpMTWikWmgtbHsVyuzeqZ/g4229yfRv8h+71J9G/yEiVVkw8tLGHY7uRyyuv7DvgCpu1Sy6rc6VlNowt3tGfvZ6WfGuzJPKRDQYdzhpblLIita2HNc07zjCcMLL2w/0buYPa+VrVYzfQxhfHDI9r37ar3F2WeHevtN/V7KmR4YWXth/o3cxdYQxJa7hiijpaeZzpX6eiisVNjHL7jCOnlR6KrV9xJLUwLG5Eemi9SsxFYbtUYhr5or5NCx87nNjRXZNTPZtKd+Erk+obUPvT3TMTJsio5XIneXM9LuGH7jPcJ5Y4mq171VF00I3Bi6fQt89CdZ6lFyT4Gs2GjVqYl+KmD4O3r+Ip/K7nPRsX9cIfF+8i8GLp9C3z0OGP77QWq600VXI5rnw6SZMVdWaoeKs8rFRyZ+ATs0UrVY7LO+ZABScMLL2w/0TuYcMLL2w/0TuY1+zzeovuN7tdP66e81mJqKprsC26GkrX0kiVCOV7M81TJ+rUqcv4GHkwvdpY3RyX+V7HJkrXaSoqeU9Ipo3X7Btvkt6b41zlcmfU6s3JxkXgzdfoG+kQ2nSVEdmtTpsaDGUsmJXu6r1PP4cK3WnibFDfZI427GtRyIn2Zm0wbbqy34fvSVdwfWLI1uirlXqckdyqTODN1+gb6RCWylmsuHLtNXN3tiRK/NF0tSIuewNlqHrZ6ZeB5JHSsbdi55de8zwzKPhhZe2X+idzH5wwsvbD/RO5jU7NN6i+4sO1weunvNrhbry36jj4rPls/jHesrsEYht1xxEynpZXPkWNy5KxU2eE0FRY6+Sple2JFa56qi6Scp1XAHJBj5q4fE5njTkme1Y8/AqjtSfLYPGN9ZM6QXD6JvnodKex18dTG90SI1r0VV0k5TppKunVq+WnvKJsMl0yIWKevLvqNKdvx08J0xviC227ET6epmc2RImqqIxV2lFDiyzySsY2oernORE/RuPmqwSrNdGrqd3HUwpAiK5L23NQAD6sfPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxxj8qp/qKZ40OMfldN9RTPHyOo9Kp9Ho/QNBnsbdYU8c31KaEz2NusKeOb6lMqT07Tyt/Tv8Dz89+3KewKj8ZJ7angJ79uU9gVH4yT21Ohn805SLzjT3TrVV+Jf6lPOz0S6daqvxL/AFKedlHWaodDwzzXAAGiW1zyu9de63+Yf7Smj3Kuz6j8XL7CmcvXXut/mH+tTR7lXZ9R+Ll9hTrf/r9hxC+k9p7+YzFfXhPFN95szGYr68J4pvvKaq9GXFB6b2FIACrL+6GVx58ipfGL6jEG3x58ipfGL6jEHSUH6dPb8zk+JfqXez5HrmF+xqh8X7y1KrC/Y1Q+L95andQ+jb4Ic2/zlAAJTEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrF1w/oX3HXEHyiL6i+s5WLrh/QvuOuIPlEX1F9Zxcv9Ts/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAACuvtshu1vSnqHPaxHo7qFRFzyUsStv8AdIrTbkqZmOe1ZEbk3brReY0eIY+yyYNbG1R4O0M5ml8yotmFqC1XOmuFPJOstNIkjEe5FRVRc9eo2vC24fRweavOee8Orf2vP+HOOHVv7Wn/AA5z54sdc7W/wOxR3Dk0t8TVXXdFvFDdbfSR09E5lVJovV7HKqa02dV3y54WXH6On8xec8kuuIqauulBVxwyI2lfpOR2Wa60XV5C44d0Ha0/4Er4qnlsw69SGN9HzH4rWytrsaPFMDcXdC9Mc2dC6e97x1Pxss888/moYzEOGKG1WtaqB8yvR6Jk9yKmv7Cw4d0Ha0/4Fbf8UUt2ti0sMEjXK9HZuyy1GUCViPajr29gnWhWN2C17ZalhSYNtk9HDM6WpRz2I5cnplrTwGxw9XS4ataW6iRr4Uer85tbs18GRiqTGlFBSQwup5lWNiNVUy4kO3Dmg7Wn/DnI5G1rlXW3sJGLw5ES9r+038+MbjFA+RsVNmxqqmbXcnhK7D26Dd7tbVqZ4KNj98VuUbHInFyuUxs+NqGWCSNKefNzVTPVxp4Svw/ialtNuWmmhke7TV2bcsteRk2Kp5TrpndCNz6PnNsqYbLfU9Lrr9W3BrWSPSNqIqK2JVRHIvLr1lJ0qtvaFL6FvMZmrxnLM6JttgyVVydvqJrVdmWvwknorF/c6Dzm/mIOz1CZuciX3WxspUU3mxsuibJc42SipJMS3WKSlhdGxV0GOYio3XxJxGnpqSlop21FLTRQTM+LJGxGubqy1KhkaWkxRSV1RWx0May1K5v0nsy9okVd1xTQ0zqipooGRMy0nZtXLNcuJ3fJpo3yP8iROnUigljijXHGvVfNNr0yru3Kj0rucz1yvl3jxjb4G3WtbC+LN0aVD9FfjbUzyK2C44sqYWTQ0MDo3pm1c2pmnnEWekxRPdIbi+gj36Fui1EkZllr/vd8xhidG52N6aKmp7PKyRrcEa6ovmm96YV3btR6VSHWQRXGVslbG2qe1NFrpk01ROTNTN9F4w7nw+e38xGob5iW5ROlo6WCRjV0VXNEyX7XEKU0vnI9Mu8mWqhvZY1z/wDyfeNKKkprdC6CmiicsuSqxiNXZ3jRdKbb2hTeibzGWulJii7wshqaCPRY7STRexP9RN6Lxh3Pg85n5id7HLG1qSJdL38ohZIxJXuWNbLa3kmrp6mopIGwU08kMTPixxuVrU8CIR7vdblHaKuSOvqWPbE5WubM5FT8TJx3zEs1dJQx0kDqiJM3s1Jkmrjzy40OtU7F1XTSU8lBCjJG6Kqj2Z5ecRtp5GPRXPTfUzdURPY5Gxr1TzS/wzeLpUWCmlnuVXLI7Tzc+dzlXq141Us5qupqYXwz1M0sb0ycx71VHJyKhire3FltomUkFBEsceeWlIzPWufzu+Ki+YmpamGmmpYGyzrlG3NF0l+xx6+B75FVj0zVepjHPFHG1HxrkiftNJ0qtvc+m9E3mM5hSipJ5rkk1LDIjJURumxFyTqth36Lxh3Pg89v5iDbqPFFsdO6ChjVZ3aTtJ7F16/73fM2MekbmrIl1tbMxkkY6VjkjWyXv5JsKWmgoZkmo4I6eVEy04mIx2XhQndMq7tyo9KpiKy8Ynt8Cz1VJBHGiomlqXX9inWOuxdLEyVlBArHojmrpN1p5xAtNLbEsie82Eqob4UjW/8AaWLL5d+HMlN00rd4SLNI+iH6OeinFnkaDpjXdu1HpXc5gko8UJdlufQMe/K3RVNNmWWWXziZJXYtiifLJb4GsYiucuk3Uif1E0sSvw4XpkiJqQQytZixxrmqr5vQ0dXTQV06z1kEdRKqIivmaj3ZeFTMYoo6alqrWsFPFFpTLnvbEbnrbyH5R3jE1wgSelo4JI1XLSzRPW451dHiW6VNKtXQxtbBIjs2Pbyp/e7xnTRvinbjemXS/wBDCplZNAqRxrdf/wA/U9BAB9MOIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEHvWSRz12uXNT5PR/gUvfdOg/x/lPz4Fb33SoP8f5TieYzcucDtjzrMm2q6zWmrWpgYx7larcnpqNz8Ct67p0H+P8o+BW9d06Dyv/ACnivjVLKetR7VumplLjbIKqJKq1K+o0Wq+qXPJGLt40Tv8ALsPVdz+8W+x7m1FV3KpSngWaRmmrVXWr3ZJqTvGZbuaXywUFTXS3KldSRRrLVQMV2cjGoqq3ZtyzIdBYrpjKjbR2qujpbXmskdLKq6LXJqVdSLxqprq79rly3+hs4cSY2Jn1T6oUeMcXVmKq6NallOkdKr2Quha5NJqrtXNV5E5DOHo/wK3zulQ+V/MPgVvndGh8r+Y2EkYiWRTWwvPOMxmej/ArfO6ND5X8w+BW+d0aHyv5j3ms3PMDtjNQVlNfKNlLcHpFLSRpHRpFmm+KqZdVt+a3k2ltubUdRQbotJBUxLFIkci6Kr/cUsGbjN9ika9tzoWuauaLm/UvkOFVSXCx3pLV0W3p8jdNtezPJGqmzWnJmmw11cjb4dPl/jc2mpzbI7zk+Pd47Gnx9ujRW5i2+zS01TMrpYKxkkb84stWrWmvPPl2Hi56P8Ed/uf9vkutE99V+mc56vzVXa1Vep75+/Ape+6dB5X8xKx0bUyU13Neq5oebg9H+BS9906Dyv8Ayj4FL33ToPK/8pnzWbmOB2xiLTd5rTJIsLGOSVui7TRVyTvEq62iBrFq7S6SooWNyklf+67PZsTiVvFxmt+BS9906Dyv/KfVRgC7YVtU9bcK+mqLbD1c1NErs35qicacuXkInOai4mLn8/voTszTBJp07v8AG5Z4X7GqHxfvLUhWaSCa0U0lLEsULmdQzkQmnaQZxNXuQo5MnqneAATkYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK293uCx00c88T5GyP0URmXJnxmLntYmJ2h6iKq2Qm1NTDSU76iofoRsTNzuQq+F1h7oM8x3MUEdFe5JEZX3NaimX9ZGux6chK6SWztRvlU5io/1FG1yctLmu+qgZle/gclxJipPi2ukVvEuS6088+eEeK+5dL+P5y12agUn47V7mt+JO9RDlbsUujZImIFiopVVFja1q9Un4lrRX613GfeKSrbLJlpaKNVNX2oU9Rb6WsVHVELXq3ZmVLmxMuElFaP7HWMRFWZM/i5Iqp6i0pePuWzZG6aqbMVUyXKyovXZDfAyVsu9XaayKjus8lY+skayFzcsma8tflQ1p01NVR1LMcak+Vrot0AANoAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuH9C+464g+UQ/UX1nKxdcP6F9x1xB8oh+ovrOLl/qdn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAcan9V9p2Ky/01dVW9I6CpSnlSRFV68mvUV/EmotHIirbI3KFbVLFRL5kO89Y63xLiPhLsapP6/bcVsthxHPE6KS8RuY9MnNVV1p5D5p8O4hpYWwwXaOONvxWtVck4+Q+e8uPk8vmJrf4HY8yXnczlLa1um9zWAw9cmIaCtpaWS6q59U7RarV2a0TX5Sw6T4m7tJ5V5iNaRERFWRMyVKtyqrUjW6eB9YT66XrxzfW80xkKfDN8pJJH09zjjdKucipn1S6+931ON0hxFaaNaqW66bEcjcm7df2E0sTZ5btkTOxBDM+nhs+Ncr7bm1Uy7/2gR+J/wBKnOG24lmgjmbeUykajkTNdWaZ8h8cGb4tWlZ0zi6IRMkkzXPLyHkUbI8SLImaKhlNJJKjbRrkqL0NeDKS2rE0UT5FvLVRiKurPmItqjxDdqNamK7aDUcrcnbdX2ESUrcOLmJYl7Y5HI1Y1uvgTcZKiTWxVX/1Xf6TQ9F03bEPnoUEeGamuVenda+o0P1O9uyyz+Nxd5D74E2n51R56cxm7kKxrHP0vom5gztCSOkazzrarsXnRdN2xD56FRimogkw7VNZNG5V0NSPRV+O0obXh+iq73X0cqyb3TrkzJ2vblrLWqwpY6GmfU1EtQyJmWk7SzyzXLiTvmSQwQytu5b5LoYrNPNC7yURM019hZ2aqpmWaka6ojaqRNzRXoTejKXtmLz05zzu8xWOOGNbVUSSvV3Vo9F1J9qIVGZsfh7ZVV91S/cai8TdDaPCi22U9b6Mpe2YvPTnM3gmaKK2TpJIxirLq0nInEhiMzW09swlV1DIIKyofI9cmt6pM1+1odSMhjc1VXPu2PWVr6iVr0REw7rrc13RdL2xF56Doul7Yi89DF4mw/Q2iiimpVlVzpNFdN2erLwFzwItPzqjz05jTWCnRqOV62XuN5tRUuerEYl0t13I9umhTG9xesrEasWpyuTJfimj6Lpu2YfPQpeBFp+dUeenMRbnhG2UdtqKiJ02nGxXJpPRU9Rm/s8zmpiXomhhH2mBjlVqaqupo+i6btmHz0M9fp4X4hszmysVGyZqqOTVrQjWLC1uuVmgq53Tb5JpZ6L0RNTlTk7xY8CLR86p89OY9YlPBIvlLdLpp7A5amoiSzEstl19pddF0vbMXnoOi6XtmLz0KXgRafnVPpE5ikw/h6iuclY2oWTKCRGt0XZatfMRtgp3NVyPWydxm6oqGvRisS69+xc4vnhksLmxzMcu+N1NcilpbqqmS2UrVqIkyhZtenIhW8CbTy1HpE5hwJtPLUekTmMldTLGkeJclvoeI2qSVZMKZpbUuui6btmHz0I9wqqZ1sqmpURKqwv2PTkUybcP0TsVvtirLvCM0vjdV8XPaXXAi0ctR6ROYLFBGrVVy76Bs9TKjkRiZXTU+cITwx2FrXzRtXfHanORC9bV02m1OiItqfvoUnAi0ctR6ROYqL3YqOz1VvdSrJnJNk7TdnsVO93yRrIJ5/Jct1XYidJUU1PZzUsibno4APp5wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt6Sqhq41WKRr9H42XEpIRDKYgkfaaiNlA7odsiK5yM41z2lT06uXbch8vdUoxcLkzO0bQrImNi5Lueg5EO53Sgs9L0VcallNCrkZpvXVmvF+CmK6dXLtyQzOPblWVWHkjnnfIzf2rory5KZxVDZHo22pjNQyRsV6qmRm8a4uqMV10SzRQsZSK9kTos+raqprXNe8h6bud2+O5bnFHBI9zESaR2bdvx3Hhp77uU9gVH4yX21LOdqYLFVC9yPxJqXlDcZIndD3BrYF0kZBntk4uYtSDdqeF1HLUujRZoI3Pieu1q5Z5/ghj+ndy7bkKt0vKydmWjKftHlMy3N+Dz/p3cu25B07uXbchj2tuxL+GybocN0PdCit0S2u1vpqt8zZ6esa7POFUyb5dbvIYjcpX/wDX9F4uX2FM7fXulv8AXyPdm51TI5y8qq5czRblPZ/ReLl9hS4woka2KRb48z2SWlmtFU+pomLMlU9Vm0tjEzz1eVS1p6mCqj3yCRJG55ZodHNR7Va5M0VMlMhe6ia1V/Q9A9aeLQR2izZmVblSFL9CzjatQuH925sPtPz7TAdO7n25IOndz7ckIu2M2U2Pw2TdDX3m+W6xUyTXCqjp0fmken+85E2H8+YqxPVYsucdfVwRQvjhSFGxZ5KiK5c9a/3lNJuiV9XWUFIlRO6RGyKqIvFqMAWtKqPYj0KmqY6KRY1PXcMdjND4v3loVeGOxmh8X7y0O3h9G3wQoX+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAArb5eI7NSskkY9++u0G6GWpcjB72sbidoeolz5vN5Zb4nRQujkrlajooHZ5v1/7L5CioKN3RMlynRW1NUmcjOJF7x9UlDMj0qLlKlVVsXJsq56m8n4r5SepwPFeKuqlwM80raqqv+XHp1Xf/AABQFYACpxJVTUltSSnkVjt8RM05MlJI2LI9Gp1JYYllejE6ku69aqnxannJr7LLVXW1VcU0yve7qWq7izKWOwTyXWS3pKxHxtRyu4tiL7y4pMMONjlzQv6HDT443rmmfsyNoyJs9vSF2aJJForlyKhztFctik6AqEbFbo0VW1D9quXXl6yTEzQia3arURD5npoapm9zsR7c88lNSir30kuJuhUQ1KxOVFzappGua9qOauaOTNFQ/TJWy7VFnrI6G4yyVPRcrWU+WWUSZ5a/KhrT6LS1MdTHjYpb5KiKmaKAAbQAAPAAAegAAAAAAAAAAAAAAAAAAsrF1w/oX3HXEHyiL6i+s5WLrh/QvuOuIPlEX1F9Zxcv9Ts/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAACHc6unoqZJamVsTNJEzXlJhEuVJT1tMkNTE2Vmki5LylfxPD2OTFpY3KDF2pmHW5UcIbT29H+I4Q2jt6P8AEiXexWuC01UkdHG17YlVqpxKR8N2W21dgpp6ikZJI7SzcvH1SofOuXTcvmZ2vbodrzKrm8vyb2v1Id8ulDUXu1Tw1LHxwy5yKn7qaSGg4Q2jt+L8Rwes/aMf4jg9Z+0Y/wAT18lM5rWrfLwDIqpj3PTDn4jhDaO34vxKbFV3t9ZZXQ09UyR6vaui3kOGHLXQ1VxusU9M17YZUSNF/dTN3Mhf8HrT2jF+JmqU9PL1ungRotTUwr5qIt06+BwoL9amW+mY+tjRzYmoqZ7FyQkcIbR29F5T84PWntGL8Sgfa6FMax0aUzd4WLNWcWeipg1lPKrl8rqvQzfJUxI1Fw5qidS7qr/aXUkzUro1VWKiJy6iowndqCis6xVNSyN++uXJeTJC84P2jufF+I4P2jtCL8QklMjFZ5WfgerFVLIj/Jy8epDr8W0FLve8Z1Wnnnva/F2HHhd/9KqvIQsS26koKi3dCwNi05V0tHjyy5zYB6U7I2uw3vfVdjxnaZJHtV9rW0S+viYW33eSiu9bXPt87mVK5o1E+LrzId+xFJdpNGFZYoNBGuiV2pyouefq8hurncqS3U+lVy72kiK1vUqua5d5DyosaRWzOWXBbYq67HA1IUfdF1++8AAsSpB9xTSQStlierHtXNHNXJUPgAF5W3iW7Wenod6llqIXK58m3Pbzmj4X/wD0qq/8+wz2ErlSWyumlrJt6a6PRRdFVzXNORD0QpqxzI3IxzLp4211OgoGyytV7ZLLki5X00MymNY3SLG23VCvTa3jT7DjccTOrKCembbKlrpWK1FVNn4HW2dnVz8V+U0xBI6GFzbM6IuqmxG2ona68nVU0Qx9mxA62WqGjfbal7o9LNyJqXNyr7yW7GkcbmsdbahHO2Iq61/A0pm8Q9kll8Z70Eb4Z5M2a3XVfESMnp40wyZJZNE8D94X/wD0qqKmx3eW1vqnPt9RJv70cmSbNvObkESVMTWq1I8l7yVaWZzkesmadydTNPxmyJulJbKhjeVdR9cMEVEVLXU6zrjPsfd4xpa27rZSeIZ6iReQkSPwarupgnaFmWPmaJfRDHtu8jcSuuvS+o0FZo6GWvZkW3DHUqra6lMv/OQ0ZHuPWyq8S/1KeLPDIqIrO7U9SmmiRytk3XRCiZjNkjdKO2VDm8qL/sVt2ukl5qqBGUE8W9TZrpJnnmqcxc4L7H2+McaBu1PCSJLFBUWazNF3IuVNUU93yZKl9EJwAPqBwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZYw+VU/1F9ZnTQ4w+VU/1F9ZnuI+RVHpVPpFH6BoM9jbrCnjm+pTQmext1hTxzfUpnSenaeVn6d/gefnv25R2BUnjJPbU8BPftyjsCpPGSe2p0U/mHJxecae69aavxL/Uednol1601fiX+o87KGs1Q6LhvmuAANItDyu9de63x7/WppNyrs/ovqS+wpm7117rfHv9amk3Kez+i+pL7CnW/wD1+w4lfSe09+MZivrwnim+82ZjMV9eE8U33lNVejLjh/pvYUgAKsvjK48+Q0vjF9RiDb48+Q0vjF9RiDpKD9Ont+ZyvEv1LvZ8j1zC/Y1Q+L96lqVWF+xqh8X71LU7mH0bfBDmn+coABMYgAAAAAAAAAAAAAAAAAAAAAAAAArb3eoLNAx0zZXLMqsZvaIuS9/NTB72sTE7Q9RLnzeL1Hb4nwwOjkrlajooFzzfr/8AyUdDRu6KluczVZU1SZyM4mr3j9pKGd8jaq6SNqayNcmSpqybycXKvlJ5wPFeKuqnYI/NK2qqkX8uPTqv30AAKArAAAAVGJKWestyR08avdviLknJkpbn4SRyLG9HJ0JYZViej06FJhijqKOnmbURLGquTLMvABLIsj1evUTSrNIr16gAEZEc54UqIHwuVUR7Vaqp3yNaa91hmS3TtYy2xoqpUP2q5deXlUmHOppoauHeZ2abM88iwoa6SkkxN06m5TVKxLZfNU0jJGSxtkjdpMembV5UPpFzMlbrtPZaptJcppJ46p7Y6RsaIu9Ii5ZLnlyt5dhrUPotLVR1MeNilxkqI5Fuin4ADbAAAAAAAAAAAAAAAAAAAAABZWLrh/QvuOuIPlEX1F9ZysXXD+hfcdcQfKIvqL6zi5f6nZ/b9FM/2FQADtDAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZf6mupbe2SgpkqJd8RFYvJkusszjU/q/tK/iSolHIqpfI26FL1LEvbMw9XcMSVlLLTvtCNbKxWroour8T4ttViG20EdHHZ0e2PPJzkXNc1VeXvmxB857UmHDy0sdv2RcWPmrfToZGbE98p5YoZrXEySZco2rn1S+Xvnfp1ibuK3yLzn7iPshsnjf9TTTEkkkbWNdy0zIo45HyPasq5W22MRbXYgttTVTx2pXLVORzkci6ss9mvvkupxJfqOLfai1RxR55aTkXnNYUOM+x9/jGnrJ2zSojmJmJKd0EKqyRcr7ERl8xHJGkjLMxzXJmi5LrTykFeEK3pt0W1qsrW6Ojlq2Zcprrd1spfEs9SEkw7S1jlRsabGfZXSNRXSLv0Mu694lY1XOsrEaiZquS85ypcSX6ti32mtUcseeWk1F2+U09b8hn8W71FJgnrEvjnepDNHxrEr+WmVjF0ciStj5i2VF2Ic9BesSKxauJlAtMubM0Xqs/t4svxO3B+/93XeVS7r7tRWve+jJt63zPR6lVzyyz2J30IfCyydu/wCU/mMUmqFTyGZeB6sNM1y8x/ldc7GGu09clXJR1lW+o3h6tzcuaZ94ryXdp46m61U8LtKOSVXNXLLNCIX7Mmoc1It3rmAAZEYAAAN3wfv/AHed5XGEPSeFtj7e/wAp/MV9a6VMPLS+vS5Z8PbCuLmutp1tuVTcKXaOpfUsvCJM9MnSJpZqnh+wVlpv1HRy1Lr49yRNVyoiu1lrwssfbv8AlP5iJdMS2eptdTDFV6T3xq1qb29M18hpslqnPTE3LwLF8dG1i4X5/wB3+SDbLffbnb46yO9SMbJnk1XLmmSqnuOkuFbxPLHLLd9OSJc2Odmqt8B94exDaqGx09NU1W9ys0tJu9uXLNyrxIWfCyx9vf5T+Y9kkqWvVGNyvsYxx0j42q9+dkv5XUr+kGIO7rvKpXWqC93V9Q2O8SRrTv0V0nLr28xoOFlj7e/yn8xRYbvVvt81e6qqNBJpEVnUOXNNfInfMmOqFjcqtzytkYSNpklYjX5Le/ld2RKqMLXmrj3ue8pKzPPRdpKh9Nw7fmNa1l8VrWpkiIrtSFjwssfb3+U/mHCyxdvf5T+Yh5tXpg/9SflUV74//b/Jn2wXx18dakvEmm1ulp6S5bMywfh6/ParH3xXNcmSoulrQhNvduTGL7gtR/ZljyR+g7bo5bMsy+4WWPt5PRP/ACk8rqhuHC3onTqQQtpnYsb+q28roVVPhe80ke9U943pm3RbmiEevjvVnqqPfbtLKk0uWTXKmxU5y94V2Pt7/Kf+UpL/AHigudVbko5993ubquocmWapyonIe0z6h8zUkbl4HlUymZAqxPz/ALj0IAH0k4sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwt43Tblc6pHuo6VrY82t0dLWme3aQOHdf2rT/wCLnMuDhVpYVW6tOgbWTtSzXZGn4d1/atP/AIuc/Uv0eIP7FdXR0sCdWj2Z5qqcWvPlMuDzssSZtSy7mXbZ1ye66bEuvoJqGRN8icxkmaxq795OU9y3KOwGk8ZL7ankNBXw3SNaK5NfUVL0SKjdsSNV1a8uLPLl2GikxfUYUwhDhyhmmhusE+m+eNrVjVjs3ZIq689acQVXOTA7U8VjW/mM800uOt0uK3q2is7qStSVsjJ89LONdSZalTv+QwHDuv7Vp/8AFzmallfNK+WRdJ73K5y8qqfJktNE7zkuYsqZWeY6xpeHNw+hh8ijhzcPoYfIpmshkY9kg9VDPt1T66l7dKBle1K+3q6okkR01W1uyFV15e15C03Kez+i+pL7CmbttxmoJFa2RyQSqiTMRE6tuvV5FU12Hqu3WO9xYsihey2Qo6NYWJnKrlRW5oirltXlCqrEwL7P4/g8wpL5bdU1T6/yewX2/wBBYKPfq2qihe9rt5SRV6tyJs9R4vct0u53Kq3+SjpGOyyyajvepVYqxVXYluMr5qmSSjZPI6ljka1FjY5dSau9km1ShPUp2K2z0uYJO9jrsWxp+Hdf2rT/AOLnHDuv7Vp/8XOZgHnZIPVQk7dU+upp+m0OJE3m6PZStiTSj3vPq3cmvMz9XRVNDKkdTC6J6ppIjuQ4IqouabTRU1VHf4OhKtHS3SV2jDO/U1rU15av6uLjPcPJ83zfl99TzF2jJ3nb7938G6wv2NUPi/eWpAslLJQ2alpZVar42ZKrdhPOzhVFiaqbIUMiKj1RdwACcwAAAAAAAAAAAAAAAAAAAAAABWXu8RWmnZppJpzqrI1YiLouy2rmYPe1jVc7Q9RLnxer0lvifDSrHLcMkWOndnm5M9f4Zr9hS0FFoVE1wlRWz1XVSs4mqq56j9o6GZZG1dykbUVrM0bKmrqeTk41J6nAcV4q6qdgZ5pWVVUi/lx6dV3/AMAAFCVoAAAAAAAAAAAAAAAAAB8SxpNC+JVVEe1Wrl3yJaax2H5UoJmsZbUzd0TJt0l4iccqmmhq4d6nYj2Z55KWFDXSUkmJunU26apWJbL5po45GSxtljcjmPRHNVONFPoyduu81mqkpbnLJNHUvbHSNjRFSJEXLJdnK3l2GsPo1LVR1MeNilzkqIqZooABtAAA8AAB6AAAAAAAAAAAACysXXD+hfcdcQfKIvqL6zlYuuH9C+464g+URfUX1nFy/wBTs/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAACtv1riu9vSmme9jUkR2bfAvOWRXX26QWmgSpqGvcxZEbkxEVc8l5V7xo8Qx9lkwa2NmjwdoZzNL5mRuGDaKkt89SyeZXRMVyIuWSnGyYUpLlaYKyWaVr5NLNG5ZanKnuJVxxhbqu3VFPHHUI+RitRXNTL1nCx4qt9ts8FJNHOskelmrGoqa3KvL3zhP+85P/6v3aHVf9jz+mG3frcmcBrf2xP+A4DUHbE/4cx98N7Vl+rqfMTnHDi1/RVXmN5yC/EO/wCBsf8Axvd8SksuHaa5VdfDNLI1KZ6Narcteau2+QuOAtB2xP8AgVNkxFR22tuE0zJlbUvRzNFqKqIiu26++hc8OLX9FVeY3nNiftnMXl6ew16bsPLTmWvnvufHASg7Yn/Ap3YdpkxO2177JvTmaWlqz2Zl3w5tX0VV5jecpnYio1xSy6aE28tZo5aKaWzLlES1nlY9ltpqeT9h8nBbVL66dS24C2/tif8ADmHAW39sT+VD74cWr6Kq8xv5hw4tX0VV5jfzEH/yHf8AA2f/AI3u+JTXrD9LaJqJInvkSeXJ2nlxZc5ruktq7nweYhmbrXSYldTutFLLJ0I5XSaaIm3LLj7yk7pnivuTB/5/UZyJM9jUV9nZ3zt4EUToGSPVrLtW1rJfxIeMqCjpKOndTU0cSueqKrG5Z6jIFzfb3XXFUpK2CKJ0D1zRmeeflUpiypmPZEiPW6lTWPY+ZVYlk9wABsGqAAAD1LpJa+0IPMQ8tN30zxZ3Ig8v/cV1c17sOF1teti14c+NuLG2+nS+5Gt9uopcY19M+mjWJkebWK3UnxeL7TQ9JbV3Pg8wzMEeJKe7z3NtrYss7dFzVVNFNmzqu8S5bziiCJ80tqgaxiZuXkTzjWmZI9UwvTROvU3YZIo2uxxrqq+b0LvpLau58HmFBe7dRQ360wx0sbI5ZFR7UbkjkzTafVNfMS1tO2oprZBJE/PRcmevJcvnEasbiWtraWrktbGvpVzYjV1Ls29V3jyKOWN/lvTr1E8sMkfkRr0/b3mm6SWvtCDzB0ktfaEHmFP0zxZ3Ig8v/cRqXEeIa1ZEprdTyLEuT8kXUvnEXInVL8xP/InWopkWyxr/AOJ3xZbaGlsjpYKSKN+m1NJrclLKgs9tfb6Z76GFznRNVVVia1yKO5rie60a0s1rjaxVRc2Lr1f1EiCuxTBBHC20QqkbUairtXJPrEqskWJGpIl7+sQtki5yu5a2sn7S86SWztCDzEI9fZray31Dm0MDXNicqKjNaLkU3CPEK1y0PS6n6IRM1jyXPLb846zV2KZ4JIXWmFGyNVqqm3JU+sYJDO1yK56f+RIs9O5qo2Nf/E+sKWyhqrI2Welilesjk0nNzLxlmtjXtc2ggRUVFRdBDM2xcTWqjSlhtcbmIqrm9devwOO0uIr9R1EDKygghbM9Goqoq560z2OJXRyyTXY9LX3ImTQxwIkka3RPVN4AD6WcOAAAAAAAAAAAAAAAD8VzWpm5UTwldd7xFbo1ibI3oyRirBE5FXTXiM1LLdr+zoS70kdPTounpQ6lVU8KryldV8QhpvOXPYKrWpdy2NbW3CGjopqnSSTemK7Ra7WuXEZvh/B3MqPOQi02GKGlqY543zaUbs0zcmXqLjJDnaj/AFG66cpMjVfXQs81MXwIPwgU6L1tqPOQvrVeIbnQsqtHedJVTQe5M0yXIr8k5CsrcO0VwqnVEzpUc7L4rkRNSeAxg/1E/F+amX33HjK6Jy2cmH4mxbIx/wARyOy25LmfRgaGons2+Mw7Eysa9U37fs+pVNmWtOVTS2S+rWo2lr97huGtXQMRdScXLxd86Ok4lDUWRFs7Y3EwuzRf59xcgAsjwAAAAAAAAAAAAAAA3CUtKqZpTRa/7iH70JTdrReYhS9M5rH+jubnTrJrj3rJdFqcWvI+uF1D9DP5G85805zE85bHWdmkXNqXTcuOhKbteLzEHQlN2vF5iFPwtofop/I3nM1jzGs1Nh9slnlmpanf2ppq1q9TkuacfeM2SMe5Gopi+CVjVcrckIOPseW6kppLZaYqOs6KilhnkTNHQqqaPJt1r5DrueUDo8IU11hg6Lne+RixuRMkTSXX+B47LK+aV8si6T3uVzl5VU973KewKk+vL7am3NEnLsasMqo9VNLSdAVbF3uOBz2ZabUYnUryHfoOl7Wi8xCsq6OW3vSqoXNhgbnJUt2q9E16s+9nybTlwwofoKjzU5zS5uHJ5uchX5xJdC56Epe1ovMQdCUva0XmIU/C+h+gqPI3nHC+h+gqPI3nHaI/WHZZvUU/cRXiy4donS1nQscz43up43sRN9c1Nmzvp5TyqwXFcbbo1PJPCykbJC5u9xa2posXlKLGl/r71fqqOqqXzU9NUzJTMc1E3tiu2au8jfIWG5T2fUf1JPYU3+WiRrfY0eY5Hpbop7FRvhpHLSVtJDBHHlHBI5qZy5auYtuhabteLzEPitoYaxiLJGjnR5rGqrsUqW3l9nToa6K+af42lGiKmS7E4ivx8vJ2hvYObmxM9i66Epu14vMQdCU3a8XmIU3C+h+hn81OccLqH6GfyJzjnx+sOyz+opbupqVjVc6CJERM16hDyfdCx3QTQyWezx0lTTVMDVdVR6nMdpLmifY1PKWW6LjarhttKlnnmpXPkckqq1vVNy2cZ46b0CI9Md7mnPiY7AqWU9cwwulhuhVfoveWpVYW7GqHxfvUtTuIPRt8EKF/nKAASmIAAAAAAAAAAAAAAAAAAAKu+XqG0RRtkSVZKhHNjViIuS9/Ne+hg97Y24nLkeolz8vF7Zb2Ohp9CavyRY6dV1uTPX+Ga/YUlFQvSplr5lXfaldJ0btjFVeI/aShmWRlVcpG1FazNElTPU3iTi5VJ5wPFeKuqnYGeaVlVVX/AC49Oq7/AOAACgK0AFTUYjoqardTSNm02rkuTUy9ZJHG+TJqXJYonyrZiXIeKLq+mb0E2NMpY0dpZ601/wCx9YZur6tnQaxoiQsz0s81XWV2MeuMHifep9YO+W1Hi/eWqxM7He3f7S7WGPsGK2dr+014AKY58AAAAAA/AfM0qQwvlcmaMarly7xAoL9S3KdYYUkRyJn1TUQkbE9zVciZISthkc1XtTJDN3K/TTXKGXe2t6FeuSIup2tNvkNTaa11wt7KlzEarlXUneXIwNX8rl+uptMMdYofC72lLWtiY2FtkLriMMbKdqtTQtwAUxQHOaJs0T41/eaqZ8mZGtNc+wyNoZ2olAiq51U9diqmzykw5VNNDVwrDOzTYvFmqFhQV0lHJibp1NumqViWy+apo4pWTRMljcjmPajmuTjRdin0ZOiu81iqFguEj5qWZUjpGRtRd7RNWvPLiVOXYa0+i0lVHVRo9il1kqYk0UAA2zwAAAAAAAAAHWmp0q6hkDnaKPXLNOI5Ey09dKf65BU+hf4L8iSJVSRqpuW9NL0qf0JVRtZSRpkyof8Avrty9fkLhGMciKjW6+8c6qkp62NI6iJJGouaIq8ZTpc5rL+jubnTOk1x73kuiicXEfPcax6rkdRgSbzU8rbf76l6jEbsaieBD90UXa1FKThZb/mTeaOFlv8AmTeaec+PXEedkm9RS60G/Mb5DzTH+6HR01NJbLUlNWJVQywzvRyo6FVTR96+QlY7xtNTYeSSzyz0lTv7U01a1epyXNOPvHissj5pXSyO0nvcrnLyqpu09npjRboakyOjXAqWU9QwS5XYYgVVVV037frKX5n8D9i8H13+0poDtqf0LfBCik89QACcwAAAAAAAAAAAAAAAAAAAAABxqmtdD1TUVM+M7FZfoK+ot6Mt1QyCbfEVXO5Ml7yldxJL0ciXtkbdC7DUsW18xvMX0bPIfu8RfRs8hlaqlxTR0stQ+6xKyJquXRTWqJydSfFvixPcqKOriusbWSZ5I5NepVT5vePnfZVw4uYljt+2eVh5S38EJGIWMbiGy6LETOZM8k/vNNLvUX0TPIZKfDuIaqeGee4wPkhXONy59Svm94kdLcV914fJ/wBpJJG1zGNSRMrkMcj2yPcsS526JsaXeYvomeQocYxsbYHq1jUXfG7EKq3PxLcqiqhiubWupXI1+miZLnns6nvEmrsGI66BYam5QSRqueiq/wDaI4OTKivemR7JULPCqMjXPLoaC3RRrbaXONv6ln7qciEneYvom+RDNMtOKY42xsu0CNaiNanIif0kLTxIl4ba+mbEmc3S0sk0UTLPkMFp8blVsibmfauW1EdGu2iGtq4Yug5v0bf1buJOQpMFsY6xrpMav6Z21O8hzdasVORWOu0CoqZL3/8ACcaTD+I6CHeaW408ceeeiiquvzTNsbUiczmJdVQjdI9Zmv5S2RF6J1NV+ii+azPwJmN+i+kb5xhb7QXRklG261jKjTkVrND91NWfEneLrgPavpKrz28xG6nia1HPfrslyVtVM9ytZHputjIXzXfK3Jc/0zvWQDR4lw/R2enhkpnyqsjlRdNyL7jOF9C9r40VuhzdRG6OVUfqAASkAAAAPXt9i+kb5yHkJv8AgPavparz28xWcQbGuHG62vS+xb8MdK3Hy230623L/fYvpG+chCvUsa2Wsye1f0TuPvGUo8O0dRiWrtr3zJDAzSaqOTSVep2rl31LjgPa/panz05jR5MEL2q5+y6Flz6iZjkaxOqaknCksbcN0qOe1F6vav8AfcW+/wAX0jPOQz3Ae1fS1PnpzFTdMOUVFdrdSRvmVlU7J6ucmabNmrvjlQTyKqP1uuntCTVFPEiOYmVk19huN/i+kZ5xmcISMbNctJyJ+lTavhOnAe1/S1Pnt5j94D2v6Wp89vMG9naxzMetumwf2p0jX4E8m/Xc0O/RfSN84/N+i+kb5yGMxBhihtdrdVQSTK9Ho3J7kVNf2E6kwXbJqOGV8tTpSRtcuT0yzVM+Qx7PBgR+PLwM+01CvVnLS6Z6iN7OH0rtNMt625/3UNMk8X0rPKZ7gNa/parz28xxq8GW2CjmmZLUq6ONzkzemWaJ4DORKeVWpj0RE0I4+0xI5cCZqq6mn36L6VnlMzi57HVNr0XI79Muxe+0g4ewxQ3W1pVVD5ker1TJjkRNX2FtDgq1xTMkbLU5tcipm9vMSQsgp50u/NF2MJnVFTTqiMREXvNgAD6ccIAAAAAAAAAAAACtvd7is1K2d0SzqsiM0GLrTUq5/gfN5vMdvjWGJzHVz2aUELkXq/8AzwlHRUjpKp90qmLHWVCZSMRepTweTlKbifE2UjbJm4xkkbE3E73biloZ5ZEqLjN0VM1c4nO2sTkLAA+eyzPmdiet1KKWV8rsTgACIiBV4iqZqW0vlgerHo5qZp4TjfrzPanw7zHG/fEXPTz4suc41D6m+YZR7IUWV7/it1Jqd3zdhhVqskd5qqWEFOrVZM+2FVKKyVtTHdIWMmcjZpWpInztZsK2ge9y1FFL0PVrq35NuXIZCyUFTLc4pI4lVsErVkXNNWs3htVsnLla6NbKbnEZOXK10a5/ep3sN7bcElppGuZLSo1j3vVP0i60zTyfiXJkrhb2VboqhNLfqZVfEiLqV2pdfkQsrLfVq0bS3BY4rgqqu8savxdufH6zrOFcVZVNwPycSRTNmbdNeqF2AC9JAAAAAAAAAAAACxxh8qpvqL6zPGhxh8qpvqL6zPHyKo9Kp9Io/QNBnsbdYk8c31KaEz2NusSeOb6lM6T07fEVn6d/gefnvu5T2BUfjJfbU8CPfdynsCo/GS+2p0M/mnJRamnuvWir8S/1Hnh6HdetFX4l/qPPCirNUOj4b5rgADSLM8rvXXuu/mH+0ppNyns+o/qSewpm7117rv5h/tKaTcp7PqP6knsKdavo/YcQvpPae+mNxX13/wD6m+82RjcV9d08U33lNV+iLjh/pvYUgAKsvzK48+Q0vjF9RiDb48+Q0vjF9RiDpKD9OhynEv1K+z5HrmFuxqh8X71LUqsLdjVD4v3qWp3UPo2+CHNv85QACUxAAAAAAAAAAAAAAAABU329R2qOKHKTf6pHNhc1qKjXJlrXPwpykb5GxtVzlyQ9RLn7eby23xPjpd7nrUy0afS6pU8BSUNDozTV0rnLJVrvjo3bI1Vc1RPKfVLQyunStuL2z1yat9bqTLiTJMk/AmqcDxXirqp2BnmlZVVSKnLj06rv/g/QAUJWgAAAwN47IZ/GJ6kN8V81kt1RUOqJKfSkcuarpuT3m5STthcquN+hqGU7lV3VCRW0bK6lfTu1aaImllrTXmKOkZR0scDdegmWlltO4U1sbsOHoanMdhwXyP0AGBGAAAAAARrh1tqfFO9RlMJddXeLU2UkbZY3RvTNrkVFTvEWktFDRS77TwaD8ss9Jy+tTchnayFzF1U34KlkcD411U+ay1RVlXT1CrorA7NERNutOYmoiN1ImR+5A1le5yIiroajpHORGquSAAGBGAAAfEsbZY1Y5EXNMs8thEtNZLYamOhlTSoXKr5KqVctBctSeVET7Sccqmmiq4HQTt0o37UzVOPPiLChrpKSTE3TqbdNUrCtl0U0cU0c8TZYno9j0za5q5oqH2ZGku0tinSnrXukpJVSOkjiYmcaJyquS8acprT6JSVcdVGj2FzdFTE3RQADcAAB4AAD0Al2nrpT/XIhLtPXSn+uQVHoX+C/Izj89DZKZTGHymn+ovrNWplMYfKaf6i+s+c1PolOuofTp7TOgAqToDP426xJ45vqU8+PQMbdYk8c31KefnRcP9AcvxX9R7EPUcD9i8H13+0poDP4H7F4Prv9pTQHdU/oW+CHMyeeoABOYAAAAAAAAAAAAAAAAAAAAAAiXGpgpaZJaiVsTNJEzcuSZksg3ehprjRpBVxb5Gj0dlpKmvXyFfxLD2OTFpY3KDF2lmHW5R3e726W0VUcdbC97olRrUfrVSNhq60FNh+mhnq4o5G6ebXOyVOrVSXwTsfaX+a/nHBOx9o/5r+c+d8ym5fL8q179DtOXV83meTpbqSunlq7fh88dPLV2/D55mb3ZLdSXm2U8FPoRVEmjI3TcuaaSJxr3y94JWPtL/Nfzh8VM1rXKrs/A9ZNVPc5qI3LxKfDdxo6e43V81THG2WVqsVzstLW7Z5TQdO7X2/B55G4J2PtL/NfzlTiaw2y3Wh1RS029yI9qaWm5dX2qZu7PUS9br4ETUqqaHRqol16+Jf9O7X29D55n33CjXG7KnomPed7yV+lq+KvGWNFhizS0MEr6PN742ucu+v1qqeE7cE7H2l/mv5zFj6aJXJ5XVOhm9lVKjVs3JUXqSundr7fp/PHTu19vweeQajC1ljppXto8laxVRd9fty8JVYXsVtuVqWeqpt8k3xW56bk1ZJyKeJFTKxX3dZPAyWaqSRGWbdfEYtudJNJQOp5mTb29znaDs8vikvhzb+15/InOXVvtNDa986Cg3rfMtPq3Ozyzy2r31Jh46aDCjMCqid9tT1tPUYlkxoir3X08Tz/ABJiGmvNPDHBFIxY3Kq6eRniwv3X6t8e71leX0LGsjRG6HNVEj3yqr1uoABKQAAAA3fDqg7Xn/Awh7CVnEHRtw4231622LjhbJXY+W62nS+5gaTEdNT4jqrk6GRY52aKNTLNPi8xccOrf2vP5E5zTEG99ZK3xLjR50MrmorNk1LHkVELHK2TddCn4dW/tefyJzlTc8SU1bdLfVxwyo2ldm5FyzXZs8hpcJdjVJ/X7bi4PebDDIqNZpdNfYeJDUTxIrpNbLp7dzL8OqDtaf8AAcOqDtef8DUGXwf8ounjk/1HjOzuY5+DS3U9f2psjWczzr9Nitv+KKW62x1LDDKxyvR2bsstROpca0MFJDC6nmV0cbWqqZcSZGrBitRDgRnLy8f8GaUs+NX8zP8At/yZnh1b+15/w5zjV41op6SaFtPMivYrUVcuNMjrH2fyeJ/0oaYzkdBErVwaoi6kcSVMyORZNFVNDEWHFFLaralLLDK9yOV2bcstZaw42oZJo40pp+qcicXL4TRGWxvG+ZtBFGmb5Hua1O+uiZRSQTzpdma95HMyopqdVR+SdxuT9MnaUulltfSOKla696ayMpJNebV155oqJszXaSLzRPwalur4WqtbeXZ1scy5tjfqVUZlllkr12quxDuHcZpmvjZfN+2fQ4vlLc0gALghAAAAAABXXu8w2OibVTxvka6RI8mZZ5qir7j4vN5Zbo1hhex1c9ulBE5F6v8A88JSUVK99W+6VLVjrKhuUjE+Kng8icZT8S4mykbZM3GEkjIkxP8AcflJRTSPSouMvRM6LnG9drW8hPP0/D55LM+Z2N63Uo5ZXSuxOP0AEREAAAZXGWt9J4He4s8MdY4frO9pS2P02nVF4Uitobj6nFTpDbTqcYKWCmVywsRunty4zsAayqq5qaqqqrdQQq2ifIqz0bkgrNjZuNE4/wACaDOOR0bkc1czKOR0bsTTvYL0lwSSie1/RFGxrZZHZZPdsVU+1FLkyNwoGVKxTdUstMunEibFdtTPyFpZL66sRtLcN7huCqq7wxq/F5eP1nf8K4q2qbgfk75l5FK2ZuJNdi6ABekgAAAAAAAAB84pxJZKmrh3i60sug1UdoyouS5lH07tfb8HpEPLXuV71e5c1cuan4fPH8Oje7EqqdVFxOSNiMRqHqfTu19vwekQqMTTxXa1pTW6RtVMkiO0Il0ly168kMGSaG4VVunWakl3qRUyz0UXV9p4zh7Y3I9q5oZP4m6Vqse3JdtSMqK1VRUyVNqKe+7lPYFR+Ml9tTyKpoKa70j6y1R730OxX1W+OXNy5Z6ta8i8h6RgvENFhncwoq+vSVYlqHx/om6S5q5y8veNl78be80uWsbs9NzX4ivNtttvmhrq6CnknhekbZHoiv1cXlPO+ndr7fg88wmJMTXLElZvldUrNHE5+8IsbW6LVXZ1KJnsTaU5DJQtksrlNiCvdBdGoep9O7X2/B546d2vt+DzzywEX4ZHupsfjEvqoWN8glZdJ6h0bkhqJXvieqanpnnmnLtQ0G5T2fUf1JPYUq6C4QXKBKK7I6d7GpFRZJopGqplryyz2N257C/3PLdPa90ijpp1bppFIvUrmmtim5i8lWO1sV72ZpI3Rfh99D3J72RxukkcjWNTNzl4k5TzrEmI7LVXRJKe6UsrN7RNJsiKnGVm6FujyNlda7HUzU8sEssFZpwsVH5dTqVc+R3IeUkC0qSts5bEsVUsD8TUuep9OrZ2/T+kQdOrZ2/T+kQ8sBF+GR7qbf4vJ6qG1xU9t3pIWW5yVTo3K56RLpK1MtqmKJdvuNVbpHOppNDfE0X9Si5p9pZ3K2UlXSPuloi3mjhTRe2Ry6Suz4s1XlQ2ompAiRrp0X+foaczu0qsqed1T+Pqb7C3Y1Q+L96lqVWFuxqh8X71LU7eH0bfBDnn+coABKYgAAAAAAAAAAAAAq73eY7XHHD1aVFUjmwK1qKiOTLJVz76oRvkaxqudoh6iXPy83ptvhfHTb3PWplo0+l1SovHl4CmoaNWSz1kqqslW7fHMdsjVc1VE8v4H5SUcz5m11yc2WvTNN9TVq2JqTV+BPOA4txVap2BnmlZV1SKnLj06rv/AIAAKIrQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnLE2VitciLmmWzYRbTVy2CoZQSppULnK+SqlXJI1VNSeVE8pNOdRTxVlO6CZulG/amapx58Rv0NdJSSYm6dTbpqhYlsuhoopY5omyxPR7Hpm1zVzRUPoyVHdprBOsVfI59AuUdLHGxFVnhXb+KmuPo1JVR1UeNhc3RUu3QAA2wAAeAEy09dKf65DJlp66U/1yGo9C/wX5GcfnobIwGKMSWSpqot5utLJoNVHaMiLkuZE3Q90Z9re61WSeanuVPO3fnuhY5is0VXJNLPjVvEeNvcr3K5y5qq5qcL2VJWWdkdBHUrDJialz1Lp3a+34PPQdO7X2/B56HlgIvwyLdTc/F5fVQ3mJqiG7WtKa3SNqpt8R2hEukuSZ68jBqitVUVMlTaikihr6m3T7/SS73IqZZ6KLq+0uaq3014pnVdqjVnQ0auqlkVeqXLPVrXkXkNmNqU6YOm/8/Q1ZnrVrj/dt/H1NhgfsXg+u/2lNAZ/A/YvB9d/tKaA7an9C3wQ52Tz1AAJzAAAAAAAAAAAAAAAAAAAAAAFZf6qro7ektFSrUy74iaCZ7Ml16izONV+rTwlfxJUSjkVUvkblA1XVLERbZmMlxHfIo3SyWRWMYmblXSyQ+YMTXqpibNBZ98jdsc3NUXiLy99ZKzxLiNhLsapf6/bcfPccXJ5nLTWx2WCbn8vmrpfpuUFfPfK+uo6t1nla6kdpIiNXqtaLr8hY9PsQ9wH+RxpgRrVNVERY0yJUo3tVVSVbr4GSgxVdql0jILRvjolyejc1Vq9/wAike61l9u1EtLJZpWNVyLmjVXYTsKddLz41vreaYmlljgls2NMrEMMMlRDd8i5323MrBer/BTxwpY5HJGxGoqo7iTI+eFd26K6F6UJv+We969LLwGtMxJ+0GPxP+hTGOSKTEqxpkiqJo5YkbaRc1ROh8y3q/yxOjWxPRHNVF1O4yHaKm+2ijWmjs0sjdNXZuaqbf8A8G1BglUxGq3lpZSbsj8SO5q3TwMPc71fnuga6KS3aTtFOLTzy9XvLHpNibu23yrzH5jORsc1sV65IkrlXwJolvwhtHb8X4k7pHcpjomJnfpc1WxsWZ7ZZFyt1t0MTfrHV23RqauoZM6d65q3PPMpTXYxudFXUlOylqGSua9VVG8WoyJaUznuiRX6lNVsjZMqRrdAADYNUAAAG76TYn7tt8q8xhD1DhFaO3o/xK+tfI3DgbfXpcteHMidi5jradbbmZgbiGovE9sbdlSSBuk56r1K7O93ydLYMRzxOilvDHsemTmqq608hHoLrQxYvr6p9QxIJI8mP4lXqeZTQcIrT2/F+JqzPmYqYGdE6dTcgjgejsb+q/u6FLBh7EFJC2Cnu0ccbdjUVck4+Qi1rMQ0NfS0cl20nVS5NVqrknh1d80nCC09vxfiUN7ulBUX61TxVLHRwvVZHJsbrQQyTPf5bN+h7NFAyPyH7fu7yR0nxN3ab5V5jhTYZvtGsi090jjWRc35Z618hecILR2/F+I4Q2jt+L8SHnVOmD/1JuRSa4//AGM9dIcRWmiWqlu2m1HImTV16/sJMFsxJPTxzNvLUSRqORFz408B+Ypu9vrbM6GnqmSPV7V0WllQ3+1R0FPG+tjRzImtci56lyJldLyUdgzvsQoyDnK3GtrJ+4quDF96LWr6aRb+qZb5rzy8h0ntmJYKeSZ15aqRtVyoirxJ4C44Q2jt+L8ThXX61SW+oYytjVzonIia9a5EbZqhzkRzP/UlWGla1VR//sUtqhxFdqNKqK76DVcqZOXXq+wmR4avVVX0j6y5RzJFM1yIqrq1pnxHPCt3t9HZWw1FUyORHuXJS/pL/anVcLW1saqsjURNfKezSzse5GMyTuIY4qeSBFe/NU9Y9EW0W910S6LSx9Go3RSb95EyyyM9j7DVTfoKKop5oo229z5no/PNyalyTL6preI/TkIKqSGVsrVzbocmiqeStr6qpoX4uiney00rt6lo1+O9y5NzTi2vbx8RfUVWyuooaqNqtbMxHojtqZkvdEraaow7WWOGZr7lO2N0VMnxnIkjVVfI1fIVljhkp7HRwytVkjIWo5q8S5H1f/T9fUVrHySpZFXL4dSOREsTwAdNmQArb3e4LHSxzzxSSNkfoIjMs88s+M+bzeGW6J0ULo5K5Wo6KB21+v8A2XyFHQ0arUyXOduhUVKZyM4mr3in4nxRlIyyZuMJJGRNxO9wo7fOj0mucyVVSxeokXaichYAHz2WZ8rsT1upRyyuldicAAREQAAAAAAAAAAAAAAAIVbRPeq1FG9IKzUjZuNE4/wJoJI5HRORzVzJI5HRuxNO9gvSXBZKF6P6Jo2NbNI7LJ7tiqnhVC5Mlcbc2uSN+bkfAukxE41/8Qs7JfXVqJT3BsdNXOcujA3PNWomefr8h33C+Ktqm4H5OLyKZszbpr1QugAXpIAAMwAAMwUnwVYc/iWTyNHwVYc/iV/kaSwfLvxGU7r8Ji3MdiHBtDbMQW22W64PrG1q5KqImbVzyNFT7llmWBvRt6lpqjXpxua1Fbybe9kv2kOp/aDhzx7fbNfiPr9U/wBPsobMlVI2JsidTVioonTOh26+7+SiTc9sNqjdWR4ke7eE3xY10Ua/R15LrI8OEKTEbui5bnLTW5+eirMt60k1auLPad7r1orPEP8AZUl4V/ZXRfzD/bcYNme9iz3zTIlkp2RPbT6o74EX4LcOfxD+Cc4+C3Df8RfgnOSAQfiMpN+ExbqVtw3M7BSW6pqYsQOkfDE97WZN6pURVRClwngaC/W9tbWVUtLTq5zVlRqaKZd9TS3DrZVeJf6iTgn9ln/+l3tIbTKqR8Ln9UNSWijinbHriIablmHG60xLJnxamajnUYeooZUsVvujqmqVNNszFTfuVU1d4n8ZXYd/a5S/y7vYUjinfUOwqtrZk0tMyjbjTO+WfedW7l9jkaj6rEMrJ3JnI1yNza7jz17cz9+CvDn8SP8AI0s7j1zqvHP9akcjXiEqLYzbwuJyIt9SJ8FeHP4kf5GmYuWDqSHGlNYrfVvq454t802oirnk5cv8Jsiss/7XbV4mT/lyGxT1kkrlauymvVUMdOxHpnmh1h3K7GsTFqL9LDNl1catb1K8h9uwNYbDA6vbiF8zYdaxPRqNdnq1lvdeu9X41TPYo7HavwN9pCHtcj3cpeuRsdgiYznN6Je3xNTZYKeop45JXtp6RzM4pU1Nd4PxLPoKz91I/KhS0X7NrD9RPeQjafxarpl5TX3RDXj4bT1TecqWvsafoKzd1I/KhX39bda7HV11LXRzzQR6TI9JOqUqCtxF1grPF+8yj45WOejVd1MpeDU7GK5OiF7hiVbvboK64J0JDMxVR/7qrnlln9i+QvOgbN3VZ5UKKz/stsv13e08ins/GKyKRWo+5FTcLp6iNH2sTXzwTXee326RtXJCmkqMXNctWvV4ULlKK0ZdVc2IvGmaavxMfufftTu38kvtRE6X9a/6ymUvFayJGrjviS/QQ8Ppp3OZhthy8TR9A2juq3yoOgbP3Wb5UMyCD8drfWNj8DpznUXR640lsVBG2qibGj0kauar1KKvrNS2htOgm+XNrH5dU3NNSmJwn+1x/wDLL7CFrVfKpfrr6zZn4vWMRrkdqhqU/DYJXPjVPNXUs7w602yhWpbc43LpI3JzkTaVFnwnSLJUVtxuEjG1Ktkp1lRMslzXqc+LWn4FBjPrA7xjTaXHscsH8o32GGtNW1FRBjkddNuhm7h1Nzeyq3JU16/eR98HbJ3ab/hPzg7Ze7af4SmBU81vqnv/AE3QbH1iqlt1jsUtfRV7KqZjmokWaa81RPedbJaIq+ghq7jO6jZPCySNXJqdpJnqzM7i/scn+sz2kNjL2FYd/kYv+Ww2kRiwczDmimmvBKJtRycGSp3nRMPWRE68N8qFJDSU9Xc56OiqEqEgflIrNei3PLNeQ+syJuddlWJfFr7SmMLGzouVrGc/BaGmsuC98s7/AMmj4O2Xu2n+EcHbL3bT/CU4IOa31UNj/pqh2Ljg7Ze7af4TLUiyV2KrhaKRizQ0etJma9JM0TNfKWJF3O+z6/fyq+002adrJsSK22RqVPBKKnwuRl7qaLg7ZO7af4StvdFZ7VTRzNu7H6b9HJypyHAzWOetcHjfcpHDhmejMNrk03AaGCNZMN7dDb0eHqZWO6Z1jqKTPqWPREzTl1kjg9ZO7af4Tti/rjD4v3mfMHubG5W4b2Mov9P0MzEkw2v0Lng7ZO7aeVpn8ZsocOWiKsoK1tZI+dI3MVU1IrXLnq8CeU7mdxx1jj/mG+y4lp3MklRqt1I6n/T9FFE56N0Nhb7BTyQadyq3UblyVjXIiaSZbdZM4O2Xu17J94k+LQ+IKQjkVsblbhuSRcAoZmJJhtc+KCkguVVI2lqN+ghkRs0jNaMTPav2IpdJhyyonXpF80z+5j1rxV4U9TySSTsbA7Da5FT8GoapFXl4bbX/AJLjg7Zu7Kf4T84O2buyn+EpwQc1vqIbH/TVDsVtiWW9XS5UzI13ihnRiys19SquTSXk1NNUuHrIq9ecu9m0z+5h+sxf4Wf/AHSQbNS1kL8m6mpScEop2rdlrHW8Udqt8tLFT3Jkr6hytRqqmarqyRPKTqXD9DvP/wAQrVpZs/1b0yXLlMZf+yPDv82ntsNzirr076jfUYuY1sSS216GbeDULplp+Xp1zv8AM/OD1k7sp+A4PWTuyn4FODX5jfVNj/puh2IeLehbC+3tt9SlYtXKrHJ83Zls8JfUmHaLev8A4hXOpJs/1b0TZymLxP1ws38z72m8xV13/wD6095tPaxIWyYTVbwSiWodBh2zONRhqwyRO0rw1cmqqfFKjB9CxKNUZWvqaRZl3yqVc0jXRTVn5PKfs/6iT6q+o+dzf9mdz/nnezET0dRIxjpIlw226k7uF0lK9sTWXR3jl93NV0DaF/8A3VnlQ/OgbP3WZ5UMyCX8erfWNz8EpzTdAWjuszyoZbCF0nxJA+pnp0ggjl0JJGa0bqRc1VfCfZw3MOwK8/zH+lpsxcXrJY3ritaxpz8NghkY218V/oa7oGz91WeVCkxCyic5lrorjpT1bcmLG7q88+LIilSn7RsO/XX3kUXFqyoVY1fbJSafhlPTM5iJfxJDNzC0TNSS44gnjqna5GSI1XIvfzXPYfvwV4b/AIlk81he4g6+VPhT1IVppLXytXDsbDeGRPajr2uRPgrw5/Er/IwzeIcG0NtxBbbbbq91Y2tXJVREzaueWSGwKSo/aBh3x7PbQmp6ySV+Fe8gqaCOCPmJnoS6fcrs28s6NvUtNUfvxOa1Fbyfhkp3+D2wWuN9ZHiN6pAm+LEuijX6OvJdewvcR9fqn+n2UKG7daKz+Xk9lSLtsiv5a72Jk4fHg5qLbK9i4sMVNVQxyo5kVAueU7MtDPPYXPQVm7qx+VDO4S/ZPS+Pf7anI2n8Tq6VUiY/JCCKggrEWZyWVdjT9BWbuqzyoR7hDaqW21NTFco3vhhfI1madUqJmiFAR7j1sq/Ev9R43jlYrkTEZu4LTIiqTMJVkt+oW11ZH0LTq9zVlT4rctiZqaPoKzd1Y/KhmcE/srd/NO9pD5JajjFZDIrUfcgpeGU9RGj1S3Qsa2ejZeI7bQ1DKmaRmk1jVzcu1V1eBFUtIqK2rEzoivbFLoppsVUza7jQxFm/a9afFSf8p5e3HrnV+Pf7SnsnFayNrX473TuEXD6aWR0WG2HruX3QNm7qR+VB0FZu6jPKhlwQfjtb6xtfglMfl6ufQuMKGyW3RrI6mFHq9q5qjuq1eRqeU0lPQ29IWpV1rYZ8urjcqIrV5DD0v7VbH4tfVIaO9deqr6/uNmbi1YxjXo/VDTh4bTvkfEqaLqT7my0UNvlqUuUarGialcnLkR7SyCsjbUVMqQ0sjc45v3XeBTLYn7HavwJ60NDQ/s2sXi095inFax0Sy49OmRm7h9MyZIMN79epc9A2fuszyoOgbP3WZ5UM0CD8drPWNj8Epi1vy2612OrrqavjnmhjVzI8/jKRMMyreLbBX17eg4JmKqSfuqqLllmpR4h6w1niy6s37LbL9d3tPNlvFqx0CyY80U1H8Op46hIrXuhe9AWXuq3ytMvfqOnvNbJZKCtV8sStkzhXNypo8n9R9IQsFftarv5T3RkcfFKuqxMc+yW7iSfh9PSIkiJfOx2+Da0PjRs2KahFVMnsVW6l5Azc0skbdFmKZ2t4karURCZVfKpvGL6zkV/b5dLG5+FxrniU5fBvZv4sqPK0y0+GnrjOWw0NzqKqJkaPSVq5qvUoq7F75riBhT9rTv5V3sIbFPVPmVzVyyNaqo2U7WvRb5naDczsrI0V+JpoZXJ+kbk1FReRSLd8D2e10S1LcVzOycjclVE2/aXNd8un8Y71mbxl2Pv8Ywjjq5HyIxeuRLJQRxxrIi6Z2J1u3Pqeoi32tv1XSxva10LlyykReNM/s8pJ+DKxb5vnCqbT+d1OZfXDsaw//Jt9hhUnj6ySJys1PYqGOdiSaX6HH4N7N/F1R5UKrE+DLfZMPVVxpMSz1M0OhoxKqdVm9EXZ3lzLsp8WdjVX/R7bRFXPfI1qpqp5Nw5jI3ORy5IpKwxhy3Ulujrb9RSXBlZFG+Dfk1MzTNctfHmnkQuugME/w3H5P9z8r66lo8GYXSombHvlFEjc+P8ARsIZ5PUTRvVEXIypaWnnjRypn4kC0WaxYhv1xo6K2RwNolVyo/YqZ5ZJkpedA4J/hmPyf7lVua9mGI/qf6lJB7UyPhVMC6mNNFHUYkenm6WyJvQOCf4Zj8n+46BwT/DMfk/3IQNbts+5t/h9PsUFiw5QX/HV3pKalhipom6cUT88mpm1OLwms6AwT/DTPJ/uVe5t+0W+eIX2mikraauYslLM2VrVyVW8Sm5Uyyss5q6pmaFJBDK5zHpouRHxS7CFuoYZIMPpG50mSq1OLLwl4uFsNWRd4uVmhqpH9U1zE2Jsy1qYzHXWuDxvuU9Fxf8AL4fFe8xdK9IElutzNIWdoWnt5Px95W9AYI/huPyf7joDBH8Nx+T/AHIQNXtk+5ufh1NsU+PaXDkWHmutNnbSVG/tRZET93Jc02+AvqLC+HbTQU77paIat1TE17Fai6tWvavfMxjbrEnjm+pTaYhq6eCiscMszWyTUyJG1f3lyabvNkdTo9FzzNBaeJtVyreSqHDoDBH8Nx+T/cpMO2awX+SuqYbZGynt0iLKx+1zda5Jr5GqTjhuY9a8U+FPU8jglfM1yuXQzqYY6dWoxPO1vmWvQGCf4cZ/59o6AwT/AA4z/wA+0hA1u2zbm3+HU+xN6AwT/Dkf/n2mTwdhyhvF2vsklLE6mop2ubG7PUxXPXJPsaX5G3NHtjXF73rk1iMcq8iJvpuU00krHo5djRqqeKBzFYmty26AwT/DTPJ/uUuIFwrQ1FvbRWNKeWabRRzU480yXb3yTTVcFZDvtPKkjM8tJChxT1xsv8z72kUM0ssqRyLkT1FLDDCssaZp7UPTem/Sf+yVyPqJk6pXs2ZLs2jhZSdrTfgVuKevLvFtKY0n4WOVqNTLuQkjoYJGI9zc1L2ouGH6q5MuM9oV9Wxui2Vcs0TX3++pl8e3xjYLeloY+ie+dUkcmXVJlsJZm8Y/Ft/8wnuLCiq5klbGjrJshDWUEEcDnomafyejf2WyKtNcadKmV3Vo5vE1dWWvwKfL73ZUjdlbXpkirsTnIuMa2lixBBSPmak8sCOazjVM3cylNL+qf9VfUYvraqN2HGtjKGjppY+YqJfuP3DkNuxDTriaelSRlHKsCtk+OuSIuri/fL3o3DvchfInOZ/c2/Zpc/553sxHUxrHLHLZM/HMipaSCrZjlYl9NELvozDncdfw5x0ZhzuOvkTnKQGrz3bJ7jY/CKL1EIWA6d1xoK251qpPBS1Ko5jvjK3JFyTymp6Ow53Id5E5zNbnk0VPgO/TTPRkbKhVc5eLqWnanniqoGzQvR7HbFTjNurvHJ5KZeBo0NDSzx+WxLp3Ifd2udpmv1utdHQugfVuSNF1ZZquWa6y80LPak6Crrek9RF8eRuxc9acfIqGHqP2g4d/mGe0hsMSdfqn+j2EMZERsTZU1Ukjo6d87oHMTCncl+nX2kjo7Dvchfw5x0dh3uQv4c5Rg1uc/u9xt/g9F/tldiisgnxLYaK0xLRx1M6RytXLJ+b2onrU1u92m0/2Out6VE7NbpG7Fz1ptUwtx7N8M/z0f/MYa3EtbTLiiajSZvRCNaqx8fxUNyS/IZIiZ59CvjoqXtL4XMTD4IdbjcsPxWyqkbaVa5kL3IqImaKiL3yJh1lDWWeK/wA1MklG9XM3p3xs0XL3FXdutFZ4h/sqT8JfsnpvHv8A+YphGiPhWRUzQklo6eKZsTWJZ2uSFx0Zh3uQv4c46Mw73IX8OcowavPf3e43Pwii9QsrpXWJtorFgtaxypA9WP1dS7RXJdvKVGBqdJ8OMvVzRtVE2V7HMX4y8Sd7jPi5da6rxL/ZU6YSqYaTclfNUSJHGlU7Ny/WQ3YvzIXKqZouRoTUNLDOxqMSy65IaHo/Dvcf8E5zPTS2i447pKG32/oeqliXe5FTU3JrlX8EU+o5GSsbJG7SY9Ec1U40Ur7N+161eKk/5UhjSuV8iouVk6ZE1RRU9KxJIWJe9tENp0daqL+zVFC6WaLqXvTLJypx7R04sncx/wCHOVN1661XjVIgXiFU1VRHr7zabw6mc1HK3U0PTiydzH/hzmUutfLcd0O12+2SPpaaeDqo12K5NPXq7yJ5CUVVF+1ax+Ld6nmxS1tTI9Wueui9TUrKKCGNHsbndDbpW2y3/wBjqaF000Wp70yyVfKQrxf7PTWmomZbpGOazNFTLV+JAu1ZTTYiraaOZrpo39WzjQp8Q9YKv6hElbVcxI1etr/Am7HTclZUbna/tLEAFWW5QXKV8OOLBJHGsj2zNVGJ+91ewk32HFDsa1t1p7DWzwytY1rGtcrdTGpty5UOdT+0LDn8w32zeXm93Gku08EFRoRt0ck0Grl1KLxoW6SJHAxXJdFS1iidE+WqekeSot7+xDA1EmJJqaWKsw5VUlM9itlnc12UTVTW5dWxE1mos9LBR7nNJDTVKVEaVDspE4+qccr1frnUWK4Qy1Okx9LI1yaDdaK1e8ccKfsrof5l/tuMbsdTuWNLIZKkraljZVuu5+AAqi7I1x62VXiX+pSstKXat3KZLfbrfPMrqnSa+FFVdT0VdSFncetlV4l/qUn7n9VNR7mW/U79CRKl+S5Iv7ycpZ0i4YXO2Up69uOZrd0sZyndi2Cmih4K1z97YjdJWO15JlnsLPB9LJJjynrrii0Nekb06Ckbk7LQXJdev8C+4R3btr/LbzFBZ6qas3Y6aad+m/odyZ5ImyNeQlhfFI5cCWUhqY54405rsSaf5LS49c6vxz/WpGJNx651fjn+tSMVLvOUu4/MTwBS0c0lPup2yWGFZnthflGnH+jeXRWWX9r1p8TJ/wAqQ3KHN7k7lNDiOUSKu6EWpp8V0+JrnXR4frqiOplcrU0XaKJnnq1HxX9PKyikguliqLbRvy3yqkaujHr480Tj1beM3twv1zguE8UdTosY9Uamg3UnkM7i+93GqwtXQTVGnG9rUVNBqZ9UnIhsc6J8iIrfK0ua3IqWRKqO8m17d22hc7zFT4Ds0MMyTRsTJsifvbSrJtF+zexfVT3kI06xLSqb3D7LAioCuxD1grPF+8sSuxD1grPF+8ih9K3xQnn9C7wU4TxXq6bltnobdbamTep9NJIUVVcn6Tk8J8tnxY1qJwSrdSZfFd+U1eHK6ooNzOzS00mg9Vcirki6s38p9cJLv23/AJbeYsqiaJrsEjblNSwzubjhdh6e4q9zuk0cZVtbVPWCvlpHJNROTJ8XVs2+ROLjOsv61/1lI2BqiWr3WLxPO/SkfRKqrllnriJMv61/1lIK3RngbPD745L6/wDOZzABXlsU1iqJqbdRfLBAs7+h8tBPqIRKWlxZb6ytfwdrqlJ5Vemk12Sa12au+WmEv2uO/ll9hDUT4hujJ5Gtqcka9UT9G3mLiSRrI2o9LoqIc+yOSSd6xLZUVfiYS5R3W4UiwXm1TWil0kVamVq6KLxJry2m9vDWR2Kxxxv02tpkRrvnJosyUymPrxX1uGXw1E+mzfWLloNT1Iai5djmH/5NvsMI5FatMqsyTb3E0SSNq2tlzXf2KVAAKsuikxf2OT/WZ7SEi/xX+6YXwyy32mqeylpmdVCjl000GZZ5cuRHxf2OT/WZ7SG3huFVQYNw8tLLvauoYs+pRc/0beXwlrTP5dPjXov0KSsYslVgTVU/kxfROLP4RrPNdzFzufUccN0vNS+bRqpoM56VUydC7PWi+osuEd27b/y28xS4AmfPi/FMsi6T3xq5y5ZZrpKZwOiejuWlrGFS2dmHnOxXXLuO4AKcvgU+Eampp8a3zoWldUPkp3N0W7U1t1lwRdzpVbugX1U4qZfaab9F+/wKviKojWXS+f0KK00+LrZSOgdhqvnVXq7Scx2exEy2d4XSnuFxgZFfaGWywtdmyadq5Pd83Xlxa/sN3wju3bX+W3mMhujXStuFnpmVU2+NbPpImiia9FeRDYimhllTC2zl6mvJDUQwricitTobrF/XGLxfvKAv8X9cYvF+8oCuqPSqWlH6BoM7jjrFH/MN9lxojO456xM/mG+y4ko/1DTCu/TPLXGMeI7jcbTV0VlrHspoUzbG1yo7Xnr1ELonFv8ACdZ5rvynoV6udZQMo20s29o6FFVNFF4k5UKrhJdu2/8ALbzG1JNCi4ZG3VCvggqFbiidhRehBwBR09LZMQOhqkmkkaiysRP1a5O1evyHM4bmblfbcVucuaq7NV+x53Iq5LPRLk/DXI5rlRLH4ADQLQpsFT1rGYugoqN9Q6duh1GebVylRPWRLXBi620aU7sNV0+Squm5js/UX+5a90VRi2Ri5OY6NUXkX9KXPCS7dtf5beYu6iWNi4ZEui2+Rz1LFK/yolsqX+KmObTVldfLXJfKWSzugqWLTtmb+vXSbmiZ5bMm+cbbFXXp31G+oyGK7jV3DEmGeipd83ur6nqUTLN8eezwGvxV16d9RvqNefCtO1zdNtjZpsSVTmv85EzXfQpgAVhcGbxW5W1tociZqlRmicutpbYtixLVYvhulLY6ySKOBGb2xrlaq9UnJ3yrxR1ws38ynraek4hvFfQ3LeqafQZoIuWg1fWhbxyNjpmudmmafEopo3S1bmsyXJb+CHn7p8VKxyPwnVsaqa3aLtScuw0WDqOmodz+5RUtW2qYtUrle1Ni6Mer8E8p2nxFdlp5EWq/cX/028ngKvc3/ZpdP553sxHjFjfE9Y0tb4iVszJY0mXFdcu46gAqS9PwocHPuMu57eaG30M1Q+eVUR8WeaLk3VkngL4+NyqaSmwRd5onaMjKjNq5Z5dS0sqJbRvXa31KjiKXkjTe6fIoqBMW0VFHTLheul3tFTTcx2a68+Qn2WnqarGNqqbxA+1VEMn6GCVMllTlTPI03CS7dtf4G8xnqyvqa/dJw4+ql3xzXKidSicfeJYpIpJPIbZc8yGeKoii/MddqdPkX1/6+VP1k9SFcWN/6+VP1k9SFcVknnr4lzD6JvggKC4yPhxxYJI498e2Zqoz53VJqL8pKj9oOHPHs9tDZovTexTU4hlAq96fM632HFLsa1t1p7BWzxStY1rGtcrdTGpqXLlQ4zyYknp5Iq3DlVSUz2K2aoex2UTFTW5dWxE1/Yb693q4Ud3mggqNGNujkmg1cupReNCjvV/uc9jr4ZKnNklNI1yb21M0Vq942OdC56Nc3NMrmm2CpbGrmu8lc7EmyU0FJubQQ01Q2ojSZ2UicfVqQDphH9lFL49/tqczWrU/Nspt8OVFhuiWzBHuPWyq8S/1KSCPcetlV4l/qU1o/PTxN5/mqVVpS7Vu5RJb7dQTzOdU6SPhRVXU5FXYftNJiynpYoOCla/e2I3SVrteSZZ7DRYAqZqPcx36nfoPSpciLki/vJyk3hHdu2k9EzmLaomia5WSJfO5Q0kMz244Vw9CgwrSyz4/t9dco3W+ua2RG0UjcnObvb+q15LxrxcRa3HrnV+Pf7SlVQVc9buyWiaofpv3h6Z5ImrepOQtbj1zq/HP9pSCrty2KmhtUN+e9Hapr395GABWlsUiyyQbpVnlhhWaRsS5MTavxz8uMGKYsW3C4x2CunineuizRdops1pqO9J+1Wx+LX1PNndb7cqa5zww1OixrskTQavrQuVkbHC1XJdFS1ig5b5Kh/LWyot7mBrVvlbRyU90sdRbqNyJvtVI1dGNM9SrmiceSfabVsMdPgSzwwzJNGxqI2RNjtpSYwvlxqsLVsM9Rpxva1HN0Gpn1SciFpb/ANm9i8XzkSqx1O5zEsmxIiSNqmNlzXfu2IIAKsuyuxD1hrPFnCeK9XTcts9DbrbUyb1NppJCiqrk/ScnhO+IesNZ4s0OHK6poNzKzSU0m9ucrmquii6tJ/KWtK/BBi2X6FLXMx1CM3T6mWbUYsaxG8E6zUnzXflLXAdIq43lrqxVpbhJTOSWhenVRp1OSr4URF2cZb8I7t23/ls5ikwnUzVe7DXzzv05HUmt2SJnk2NOIzp3xPcvLSy2+0I6ps8bEWZ2JL+5dybVfK5vrr6zkdar5XN9dfWcioXUvW6ICnsVRNTbqL5YKdZ3pTqmgn1ULggYT/a47+Wd7KG7Q5vd4KV3El/Laq+sn1KxlLiuhu9ymbh2vqGVM7ntzjdk3qnLq1d/8D5uUd2r6RYL1ap7RSK5FWpmYuii8Sa0Tab2qxBdI6uZjanJrXuRE0G7M/AZXHt4rq3DL4aifTZvrFy0UTj7yGy2aGSVPJs7c1VgqYoVu7yU6GsvDGR2Oxxxv02NpkRrvnJos1lKW1x7G8P/AMm32GFSaFT6VSxovQN++p+FPizsaq/6PbaXBT4s7Gqv+j22mNP6ZnihJU+gf4L8i1qsMXfGWF8Px0280SW+lj0HzaX6XNjclTJP7v4nz8HeNP4hovIv5S5m7DMOfyUf/LYVpvzVWBysc29t/wDgqoKNZGJI1ytvt3e064AZT01+vVA6PO4U7NCqnReplcjtap9veQ4Ebc27L8R/U/1KSSKuSytJ+HKq47/eoABXlqVeCYaybH15SinbC9IlVVdxppNO9HuW4qt8ax0l8oomOXNURHbfNOu5t+0W9/y6+00klxNNykTK90T4FBBTrUPfZ1sKr8VKPEOH6/DVLFU4nqornTSyaEccOaK1+WeexOJFN1i/rhB4r3nnWO+tcHjfcp6Li/rhB4r3kUzkfTo+1rksDVZV8tVvbr10KAAFYXRn8bdYk8c31KaK74Hv+Iaaz1UV0pmOpYEWNZM825o1eJO8Z3G3WJPHN9Sm6vnW2z/yrfZaW0T+XTI/a5TVEfNq1jva6J8DP/B5jP8AiCj8i/lJeA5KJ1nxDFSwLHLEiMncv77kR+tPxORH3MetWKfCnqeexSJKxy2tbYhqIXwOaiuxX3JAAKgvwVWA7fcLnJimloalkG+q2N+nsXS31E4vCWpw3Mf1mLv6P/ulhReY/wBnzKriN0WP2nKk3McW0MG8017oo4889FNL8pFuVkq8N19udiaojuXRE6Npt5zTe3IqZqupOVPIW5nMUdcrL/NJ62k0NQk0uFW2v16kE9K6niV6Pvbp0N1inry7xbSnLnFPXl3i2lMV03pFLan9C3wBm8Z56FAibd/1fgaQzeMvi2/+Y5iWi/UNIeIfpnffU1WJMA4ivd7gukV1pWSwQpG1z880yVy8Tcv3iE/c/wAYsjc6S/0bmNaquREXWnH+6aPFqr01Zl9CnrUoZdcT8/mr6jZfVYXYFbexpRUbns5iPtfon/JLwbNQT7n9xfb6d0ESVaorXLnm7Rj17V4siMctzb9mlz/nnezEdSKvRGy2Qn4a5XRKq7gAGiWRVYIstxvuELxQ0VVHDHPUKxzX55KuSd4l025ni+jgbBBfaNkbPitRHav8J13Nuwq+fzK+y06l1Uz8p+G1755nPUlMs7MSOw2yy95Agtc2HsY2amv8rLhWTzNWnlhzRIuq49nHrNHiTr9U/wBHsIY+f9oOHf5hntIbDEnX6p/o9hDXqVR0DXIlr/5NqkRW1LmKt7Jr7irABWluZ68Ne7F+HmxO0ZFq2Ix3IumzJTR3nc7xJcMQyXiC70kUsjUbpOR2eSIifNy4jPXLs3w1/Ox/8xhtcTde5fqt9lC2STlU7HWvqnxKJ0POq3svbRfgZ6swPiigoqituF6paijp4nSzxNRUV8aJm5qdSmtUzQurLLSTbmsD6GB0MKzuyY5dnVqU116z1viH+ypOwl+yil8e/wBtRjSWBzkSx6sboahjFdivnmcwAVJeEe5da6rxL/ZUi4Yw3dMSbmq0NLWwxQyVCroSZ5Zo5F4k7xKuXWuq8S/2VJOCf2Wf/wCp3tIWdKuGBztluVFcmKdjN0sRotzfGMMTIo7/AETWMajWpkupE/pPqwUDrHui2+23hzay6OY+RlTHnooxY36stXIvFxncrLN+1+0+Jk/5UhLBOkzlTDbK+RBU0zqePFjv0spfXbrtVeMUhky7ddqrxikMqn+cpdx+Y3wBSaM790qzNp5EjlWNdFy8Wp5dlVR/tVsXi19Tzbok/MXwU0uJLaFF70LKt3NsTy3yrudNd6SN9S7Nyqjs8vNIdzwbiO022evu92p6uhgbpTQsRUc9vInUp6y9vPXiq8YUGIesFZ9QmSpRZEYre6/U1exubEsiP77dN9ybBU09SirTzxzI3UqxuR2XkOhzrMJVNQ5q4FbDQUyJlUNnerlc/iVNLS4igxHbsaYWt7K6419MsUkqRIkSNcukqKvzU+apH2HGt43JYmXiSMykaqL1LPDNG3E1SuJHv6HfZJkVsKJpJLl1W3VlsLm4Vi19dJVKzQV+XU555ZIie4k1FvpcNUzKW0RdDRV0enUN0lfprlt6pVy+wrTCrkS/LbohnQxrZZn5q4i3TrTW/wAvJ7KlNYb/AH9mEae10OGautp45HPbUxRvc1yq5VVNTVTjy2lzdOtFb/LyeypZYKraih3MKKWmk0H7/ImeSL++7lJ6VWpTuVyXS5r1yOdUsRi2UrIrlSSaDFqoGzOyRYt8TSR3Jly8RLOsuH8J1DZH0FtfHd5EVYJnyyaLZ1TqXKmkqZaWS7PsK7gTuh90aHyp+Qw7KyTOJ3vJUr3R5TMVPAjXivWGqorbvebbk9YFfn8TNWtzy4/jGjjoW4VsrsNsk6IZp77vyporrXPLLXycpRYJt/TypvLr+1Kqrsb2LTPaugkb835r1OWlrY3bnsLWrq562dZqh+m9UyzyRPUJv+3iSJNV1MYF7VOsv7U0OJmluVZad0SKsoLfJcJ2QqjYI0VXOzYqKupFXV4DSldh39rtN/Lv/wCWp5QZSLfZTPinoU8UP1l6rZ6uea9WySzJK5XR9FZxo9VXNURXImeWomwzw1DNOCaOVueWkxyOT8C3ujbTeq6eDElO+sippHJTNa5WaGvJfiqmexNpTVWELrPLpYKfBQ2zLJYp3qrt8416pHLsy4zJYYpVvGtl26EbamaBqJK27d0OjnaLHOy2JmRsJ0iXHe8dK/QkonugSkyzR+bdHPS4v1nJxFNf6HGGGkpXXSvp3xVUu9okSNVe/wDuoba4UVPh1jrNao+h6CREldDmrs3Z7c3Zr+6nGZJEtKxzlzVcksYOmSskaxuSJmt/vxIVVOtTVyzq3RWRyuy5ClxR2OVf1U9pC1KrFHY5WfVb7SGjCt5mr3p8yznREgcibL8iPQYixHJhe32+mwnW1EFM3qKiOORzZE18jcvxLSO40M0iRxVkD3rsa2RFVfxL2y11TQbndjfTSaDnMRFXRRdWvlKyfC+GpYXMwzblpbuvyaaWZ6tavHmjnKmzPiUsahsMkiouS/MqKWSeGJHImJvysfJVV8q3C9UmHFTQbcU0Vm2qzWvFx7OUkcC90PuhQ+Vv5D9wJDFebNV4huDN+udvm0aafPR3tMkX4qZNXau1FMY6TlLzHqiomxJNXpM3lxoqKu5dTRdJ7RBhtF31tC7VMqZK7PNdnF8bl4iAdaiolqpnTTO0pH61dkiZ+Q5FdLIr3q5S1hiSJiNQzdovNwsmPblU220S3SZ8GgsMSOVWt6hdLqUXjRE+0s6a7VC74t5pFtEiuzZHU5xq9OVEciajvufftQu38ivtRF1Vw2O+y75iakkrJoVVkLmuczRbydSqZlrNylYxsmyZlHAs7ZZHRZ56b5qV0Usc8aSRSNkYuxzVzRT4q5uhqOadE0t6jc/LlyTM+KnB+IZp3PwrNTUlnX5PDK/NzfnZq5HL8bSXaVFVb8S2jENntV+qoJqe51DYnsiy6piua1yKqNRUzR3Ea7aFXORWuRU+htu4m1rVRWqjvqXWEqNFjjx3p/pJUdB0JlqTJdHPS+zkJEj98kc/LLScqk+408Vk0rJbmbzQR5ObDnpZKuteqXNdq8pXEFVJifhTRMjYoYlazG7znZlDjPsff4xpJ4SYhq7dbIZMLVkNJSwtb0Vvb9FWaKdWq6OSJkme0i4z7H3+MabyarfDhmyU6uXoepomMnbl8Zmg1FTPi1Kuw3IVYlL5aXS5pVKSLWpy1stv5MzFcKOeRI4ayCR67GskRVJB+1WGLFNAseEaDoO7Kv6KaaV7mon72pyuTZnxFZV4U3QKKjnqprhRb3BG6R+WjnkiZr+4Q9ja/OJ2XeTfiCx5TMVF7jnJBwlxC3Cr3dDtmZvi1CdUqaKaWWj9nKaSsnWKhpbPlmltYlOkmfx0aiNzy4vildg6nimww3FUjc7wyV0TanNUybnllo/F2KvEdpJHTSPkeubnqrnL31PKleUxIU9vie0iLPItQ7wTuPgzNhvVzs2J72tss010dPmx7IWuVWJnt1IppiNubvVmLsSOauSpHmnnGdBby77HnFLq1ltyPSXVyQ5XaHpXUZ6oKhdB2jxLk7JctvkLBj2SMR8bmuY5M0c1c0UmTUeG74/ovEdE+rrctBJGvczJibEya5E414islwbi+WVz7FV0kFscqrSxyORXMj/dRc2quzvqeLTxTZxLZdlHa5YMp23706nxda1bdbZqtGaaxonU55Z68ibhmg6UUyYtbJvkl4h0XU6pkkWa56l4/i8iFFT2y8x41t+GsTTxVVPWN05IoskRzcnZdUiIqa28Rqbh/Yk6UU/6OipF0YYtuinhXWv2qZqzssS+svVNiNJErZkt5qaopBMzjrrVD433KaYzOOutUHjvcprUfp2m7X/pnF3XYnv1zrYprhhart1MxujJPKyRGMTlVVaiIdIa6jqH6EFVDK7LPJj0VTYYnqI3Tx2+tRX2+eP9PEiZK5PDtT7FMrWYWts8TWYIpW0Nx085JKiRzmrFkuadUrkzz0eLiNmVkMr1stnfA0YJ54I0VUxN+R+lVBQJja+1OG5JVpGUjOiN+a3TV2WimWWrL4/LxHzdcOY7s9sqLjU3CjWGnZpvRmiq5d7qC8w7TRUWFaHE9O3Qu9cjo6iozz025rq0V6lPiN2JxHsVP2e8r1vbbcxmq0qrQx3S++xKulwWtdE1Y9DeGaG3PPvkA/XLmqqvGfhWOcrlupdMYjG4WmXwpfbtamXqmtlhqLo2qfoyPha5d6+MibGry/gXFNdWpCnTRrbdVZrpU07tB7U4tTsl1pr2ErcskfDRYmljXRex7XNXv5PLCa3YVvMi11+t8lVXyanytke1FRNSamuRNmXEXNSkLnI2TLvOfo1nY1XR5psRWqjmo5q5ouxSvvdydabctW2JJcnImiq5bTq7BeOtJVo66iZTKv6FqqmaM4k+JyZESzWqurMbuwxip8dZE2FZXxxrotVckVvVNRq8Zrx0K4rqqKhtycTbgVGoqL0L6x2xMK26WtZKtQt/ibK5qt0d51KuSbc/1ne2Ecl108iubR6X6CkVY4W5fFampEz2rqRNpENSolWSRV6G7SQpFGm66mYxZNJTXWyTxRLNJFOr2xpteqOYqJ9pd1WIr1cbn0VdcO1NqplaiOmna5rGrlq1uaia11FXfuyPDn82ntsPQsSvpqqufa7tG6e2Oa1z4W9SqrtRc0yXaicZvosfZWJImt/ZmVj0l7a9Y9U+OSZGYgrKaqVUp6iKVW7d7ejsvIdj4q8JsqEbwEhZb5E+VLUSOdpp+7lpaX97k2lNe7FjmwWia6VtwpFgg0dLe9FXa3I1NWhyqhAlFjW8bkt3mx+JIxLStVFJNstiYxvNVE+XoXpI9JGq1unvuvZxZfF/EvrpcHXKr6IdHoLoo3LPM+bVTxWrDdBdaJm9Vt2ga6slzV2+rlnsXUm1diIRTCqdhtE3RDOhar1Wd2qnxN+ok+ovqM1hG/XqiwvV2y24dqbjDNUK91RCx7kY7JvU6mr81PKaWb9RJ9RfUfe5fPJS7ndynhdoyMrnK12WeXURk1ErUikVyXTL6kPEUcssSNWy5/Qgw3SBIW9GyRUdR/6kE0iNfGvIqLkqE4ky2jBtylWsu1rlnrpuqmkSV7dJ3LkjkRPsQqeBW6H3RofKn5DDsscucTveSdtkhynavdbqR79d3WWkjmbCkqvfo5K7I0VHZ24ItdRZY5lrG1q76sit0FbqRMsteewoMJ2d99xVcbDitG1qUESuRrHKxEfpNTNFboqupS6q62prpEkqZd8c1MkXJE1fYZSp2aLAmq6mEK9sn5n7W9FI5nLzWVFvxfZ6ykpHVc8ObmQMRVWRc9iZIqmj4yp//kbD31yKh9N7FNjiP6dfZ8zu++3OsuM1VebNPZ4ZPiyVKOYxXaupRXIiZ5Iq/YpKgqaepRVp545kTasbkdl5DQX5aC6XKa3X6J1Vb4Xo+KJqq3Rflki5tVF2K7j4ygrMJ1E72rgVIaGmRMqhtRIqq5/EqaWlxEr4oZnLgWztuhrx1E9O1OY27dzoQcO0SYjrn4hfJvDrHOmjCiaSS5dVt4tnfKzEVsxrhm2pX19wpVhWRI/0SNcua5/3U5DYrRU1gtcEdsj3htxgbLUpmrt8cqJr6rPLbxZGbYezNWRy3XpYwfUJWPbEzJOtzjcKxbhWyVTmIxX5dSi55ZIie4qrr1prP5eT2VJZEuvWms/l5PZUr41vKiruWr2o2JUTYqLBiC/R4PhtVDhirrKdsjnJUxRvcjuqVVTU1U720tornSOaxktTDHOup8LpE0mO42qm3NF1Ftgernoty+mlp36D9+emeSL++vKc5rDhKsbJNDbXpdpkVzJnSyI3fl2Oy0sstLXsy7xaVCQPkwuyUpKN88UWJiYm/I4lVea50NTRW1I80uT1gWTPXHmrW55cfxvwJPArdE7oUPlb+Q+ME0CXyovLr+1tXV2R7FpntVWpG/N+apo5I7Wxu3PYRRUasdjeqKibE83EWyMwMRUVdy8ZQtwrZVw2x61DdPfd+VNFda55Za+TlIZ1qqqatnWaok035ZZ5InqORoSyLI9XKWVPCkMaMQzM9xq7VuhUNbQ0ElfURQu0KeNFVz82vRdiKupFVdnEWkd5rpquea9WySzpK9Xx9FZsR+a60TSRM8tXlPmz/tdtPiZP+VIae6stN6rZoMSU76yGmlelOjVVmhr1/FVM9ibS0k5SwsbJtqVDFmSpkdFnZdNyohnhqGacErJW55aTHI5PwPp7tBiu5EzOVXhC6TzaeCnQUNsyyWKd6q7fONc3I5cssuMob/QYvwylK66V1O+Kql3tEhRq+HPqUNdKFXLdjksbK8Ta1LPaqKW+E6Tp2rcbOkWKS2TLA2lRM0emimvS4v1nJxFpW1K1lZJUK3R3xc8s88ibcaCmwyjrRZ4+hqGZN+ki0lfpPVcs83ZqmpqcfEVakdXIiuwN0QloYlRvNf5ylVijscq/A32kOFBiLEcmF6C302FK2ogp29RURxyKkia9epvvO+KOxyr8DfaQ1Vmrqmg3OrJJTSb250aIq6KLq18psU7mNpnK9Lpf+DVrGvdVtRi2W31UoY7jQSvRkdbTve5ckakrVVSSfc+GMKyQPZh+2Op7qqf2WWSaRWtf383Kn4KV/ArdE7fofK38hEtG1+cTsu8m7e6PKZiovd/kjV0i3C90mHFTQZcE0Vm26G3i49nKaSWLpNZ4MNtVZWUK6p11K7PNdnF8blKXAdPFeLLVYhrm79dLfNo00+at3tNFF+KnUrtXahYTzyVMzppn6b3bVyyPaj8mNIU16mNN/wBzKs66Jp3HMzVDdq+zbolbVW21y3KdYEZvESOVclazXqRf/FNKQ8Fftbrf5T/TGY8Pykd4fwZcU9E3x+inKnu9U+SV96oHWdznZxNqs41enHlpImeWryk+KWOaNJIpGyMdscxc0X7Szr4rLfal/CWmfWOp3K2DRc5miirr+KqZ7E25lNU4PxDNO6TCs1NSWdfk8Mr83N+dmrkcvxtJdpksEU3o1suymKVU0CWmbdN0Purn6Go56hG6SxRufly5JmfuE6NFjjx3pfpJUdB0JlqTXo56X2Z7CkqrfiS04itFqv1VDNT3OoZE9kWXVMVzWuRVRqKmaO4jY3GmisqrZLc3eKCLJzYc1dkq611rmu1eUz5fZY1cuq9UI1lStmRieamaopAmk32eSTLLTcrsvCZ7GfY+/wAY31l8UOM+x9/jG+s1Kb07fEsatLU7/AlriTENZbrZDJharhpaSFreit7foqzRb1aro5ImTc9pMiuFFO9I4auCR67GskRVU009U+HDVkp3O/s1RRMZUNy+OzQaipnxalXYUVVhexSwLHhGh6Du6r+hlmle5qJ+9qcrk2Z8RuzMhlkVNHfMrKeWeGJFtib8j5KqoZ0+xBDhVy7yytYrlqE6pWaKK/4vH8TLbxnWfCO6DT08k8lxodCNqudlo55ImfzCVgmnirMNPxVUM07xSzuiiqc1TRaui3LRTqV1PdtTjMY6bk3keqLbbcymrUqESKNFRV3LOsmWKjo7QmtlsZ0Okn0miiNzy4vikM+pJHSyOkeub3uVzl5VU4T1ENJC6eokSONu1y8XEV73LI+/VS2jY2KNE6IZ7DtvxHcMV3mPDlxhopUVd+WXY5uls+K4mV9VU4NmS3Yhm6Kq5G782SmTSboKqoiLno682rxE7cvljnxXiCaJyOY+LNrk400i7orw+iidH0PDNm7S0pUzVO8XFRJG2zJUyt7SipmTOc98K539nUqqWoZV0sdRGioyVqOajtuREv8AUS0lkqZ4HaEjETRcnFrQn1OB8O3eokuFRe6mnmqXLJJDGrUaxV2omrYVNFZKCxbqNmoaCtkraaSNZHLLkvVKkiZak5EQ14qWNXYmvv1sbEtdKjFa5lul+80Fkp4rfha3X2kYkVyr48qmoTWsm1daLq4k2IRydedV1qGJqaj9ScSEE06iTHIqlhSQ8uJN1MxjvrVB433KX1zsWNbdE68X29UlXS0jdKWOJV03N5ETQROPlM1jaup5KaOlZKizRy5uYm1NR6liaodS3emlaiO0Y/iu2LrXaWDXJHStxpkVcjVkrVwLmYW1Yjo7xUOgpo5kcxmmqvaiJlmicvfLYm3KKjxbTNt9ye23wxvSVJadERyuRFTLXnqycvkM/esBYet1lrKulv1XLPDC58cbnNycqJs1IQdngkW7HW7jYWrqIUtIy/eh9WGmhv8Aj+ps10YlTQRwb42FdSI7JmvNMl41LmsqJZZEhe/NkCqyNvzUTi/A+MNJluW2uZERJFkkRX5a1/SycZxMKt2G0SdPiZ0DeYrp16r7gZrB9pxRdHXduHrpT0cW+o2obMq9XnpZfuu75f1VZT0UW+1MqRszyzXlPncvejrVilzHalycip9V5LQ3ax7rbEHE7K5jb5lXWXZ2Fql1ovb31NbDk58lOmkxUcmaZKuS7F5C6hlbUQRzMz0ZGo5M9uvWWtJfH0lO2FKWCTL96RualXLgDDddM+slvtVFJUOWR8bFbkxV1qiathjhp5s0XCvUl5lVT5OTEnQqMUVlRQ2d01NIsciPamkiJsNPFR09ksdBU22JKeW6UzX1jk1767RRc1z2fHdsy2lBhS1Udq3V1ttLUvrKVlMrmvlyXSzai8hb1qqtbOmepJHZJya1Mp0SnhwIt79SOB3aqjG5LYehxMvjBsr57W2ByNlWZUY5eJ2bclNQZXENZTVF3tUUMzXviqkR7U/dXSbzENCirOip95G1xFUSmci93zQvrrasW2Bi3zEl2pq2liya9kCqr1z1Jkisam1U4zhar9SXh0jaZsrViRFdvjUTb4FXkNnfat9Hf99RjZNGNOofraurkKq52+3YvbHHc6jpalMqqxaZEbp57c80XZl+JNIsErla7J25qRJUwMRzfKbrbqQyDhCjp8R4lvFLd40qoaJNOnY5VTe10ss9WX4kLFOCrHZsPVVwob3VVFRFoaEb3Nydm9EXYnIqqauBGtwHYpGtRHup2aTk2r1KbTNkbadjpGriMJJ3VT2wqmEjVVXPWyJJUSLI9EyRVRNhFl/VP+qvqOhEr62mooFdUzNjR6Kjc+Ncirbdzt1LpcLGbIU2CLJi+7YdqEsd2pqShWpVskUyqiufotVV+IvFo8fEdajEUNinfarmss1ZSroSyRNRWuXvKuXqQu9zZVbuaXNUVU/trvZjLiC/Pgp2RdB08mimWk9uaqXNVJDzMMqHP0Uc/Lxwr3WKopMWV1TQWlk1LKsUizNbmiJsyXmLb4N8LfxJW+c38pxwDbqW37pt0t1PO6rpYKN29vlyVV6qLXycakUNLGjsSOxW6WJ566RWK1WK2/W5e1lHT2CmZR2uJKanq4kkmY1VVHOXVnr8CFafUrlWV2a59Up8ldLIsj1cpawRJFGjTM3yKsnxXZ4rdM2Gre9EhkfsY/S1KupfUXF2oMS4aRbzie5wVsEjki0afW/SVNS5K1qZZN5SqbWU1bugWBaaZsiNqmI7LiXSQ9Autc+ixHUyJGyVMmpoSa0+K0tFe2OnY2RuS/5KdGukq3uidmn+DKWm8U14ikkpmyIka5Lpoie8nne5WW04vkZPc611tdTpoMbTIjUei681zRTKYywjZsP2VtZbLxU1UyzNZoPcmWSouvUichrtpoZV8h9r9DZWtmhS0kd7dS2wNTQ3uO73C5M6IqbXI19HIq5LEvVLmmW3W1Nuewsp6marlWad+m9drizu7WxWy1b21GadMmlo6s9SbSnIqyS78KZIhLQRWZzFW6qRbr1nrfEP9lSuwrh7Gt3wrD0qvFLBbnPdoQSquaKjlz2MXjz4yVfK6lpbZURTzNY+WF6MRf3lyLbCDlbuUUqtXJd/f7amzSqrKZzlTqata1JKpjEXP5GdZiikp6xLbUNmdVRybxI9rU0Vei6Kqi57M+8XxZrdkqqRaCangZHLHvLpUb1TUVMlXPlKf4NsL/xJW+c38pHy6eXNrsJLz6qHKRuLwKu91ErLnaKRr1SGrqUimb89qq1FT8VNXc6WKyOdZ7cxKehyR+8prTSXWq5rrKHc7pIae7YrpWPWeKlzZDJJrXJHPRF8OpCaqq5c1VVXvipTkxpEnvPKRe0TOmd7tvux+GaqKe6VW6HQw2WqZS17oV3qWT4reocq56l/dzTYaRzka1XOXJqJmq8hTYdrKet3WrTLTStlZvUiZp4qQx4ffmKvcZ8UVOSid6He5w3zCLkrcUV0VcyrcrWdDa1R21VXNrTtarrT3eldUU7Xoxr1Zk9MlzyRfeaOe4voLvVqkbJkc9UylTNE18RXXLD9nxbUtr7lXvt00bEiSOnyRrmoqrpa025uVPsM3ciZVv5LiNnaadqL5zfjmR5VVsT1TiQ44EgjuOGKnEdW3fbrRVLo4KldSsbos1ZJq/fdxcZQ4twza8OpQS2y61FW6afRe17k1J9iHoOKkSO5sZGiMasSLk1Mk2qZ4Ep4lc1b36kfNdVztY5MNum5TySvnkdLK7Se7WqlXiHrBWfULLIpsTV1LDaainkma2WSPqWca6zQgRXSttuWlQqNhdfZfkfDLvi2NFRmE7m3PkhlT/Sfk1FiHFkfQFws1xoIo131JJIJFRVTVlrRPnfgbLhNdPpmejQcJrp9Mz0aG4lRTtzY2yletNVuye5FT77it3Rb5LZq610kNH0S+WDUmlkuaassslM7HdsSTMR8WEq6Ri7HNhkVF+1Gkm+VU13x9h1la5Ho6VrV0URurSTkNlXXKqs9a+gonoyCLLRarUXLNM11r31UkfyUa2RzL3IYkqcSwsfZW+6x5pc6PEl8qaZk9iuVBAi6Mr1gk0Uaqpmq5ompDSsmrrLg+CzW63y3OSKZX/omKrlRVVVXRRF2ZlpdcTXTpTWfpm/qH/uJ81T4wpWTLgqlveknR0sz43SZalbpLxbOJD3mYo7sSzE1Q95To5LSLeR2imaS54pbkrcI3BFRc9UEn5Tp07xh/C919HL+U13Ca6fTM9Gh+8J7p9Mz0aEPOpPU+ZOsFd66fD+CHhC0VNhtGIblUxzNkqqdJ1jljVmSo2Rypr27THUmJrvcERaLD01Si7N5Rz/U02V1xFcprNWxvlboup5EVNBPmqQtz+NtHgJLrB1NU2oe1HLrTLNE2bCfFHLGsjkvY1lZLBKjGrhxbZ5+0oKiuxTNBJEmEbkzTardJKeXVn/SdMF2qtst1hvVwiqI6mNHt6HqI1Y7JUyRdevj5DZ8Jrp9Mz0aFHQ3WrvW6VDba56PpnxKqtRqN2MVU1oYsla9qsp0wqZSRPY5JKtcSae34EC4XXEclxqZIMJ10sT5XOZIyGRUcmepUXR1nJl5xaxMmYTubU70Mqf6TZz3yvo6iSlgka2KByxsTQRcmouSHPhLdPpm+jQi5tMmrMyVIaxU8l+X33GQ6X3/ABXNFFcbTX0DKZ6SNdJDIqOXPvohbboOIam34rjoKagWpe+na9Ea5c11u4kTvF1wlun0zfRoZhsjr1uuWxK5d80oHNXLqdSRyKmwmifFLdiJkiXRCCaOeC0jlzvZVTX3aEJt2xNIxHMwlXua7Y5sUiov+Era62Ygv1yiWss1wt1No6L3up36Ddq5rmiJtPS6m9V1vqZKOnlRsULlYxFai5IhT4lxRdm4fq1SdvxU/cT5yGLJoWutG2ztCSSCoe3FI+7NfYRquuuFDhi32m3Wma4upFyXemOc5U168kRctpUtueKWuRzcIXFqpxpBJ+U11nqZKTCFsu8SolXVs/SvVM0XbxbE2IdOE11+nTzG8xg58bFtM27tzJjJpEvTLZm33cyHTzGP8LXX0cv5TQWe1S4O3P7097ZJFRyyo2RmhnqRPcT+E11+nTzG8xU4pv8AcarDVfBNMjo3xZOTQRDJk8KuRjEsi695jJTVCNV71RVTNO4zNJiG917UdR4dqalqpmiwtc/NOXU0+6uqxTUUssCYTuTN8ardJKeTV3/imswsiWrANruVImhUTI5j3LrRU0nLs+xCZwmuv0zPRoevdTxPsrM0PGJVzsxNkyUy+BaOpw1XPutUyZaqeB0MlPOxWOZm5FzXPX+6nFxkeS54nWRypg+4KiuVUVIJNf8AhLnDNbPiDdCudDcn77BHTLK1qIjcnIsacXeVS6diO5xOVjZm5JqTqEEj0R2KdLouncgiY5Uw0y4VTzu9fu5jWXnFzGo1uFLoiJyRSp/pJNrtl7xDf7bX3O211B0uqY3tSaF/Vppoq63ImXxTT8Jrr9M3zEHCe6/Tt8xDBKiBubGqima0tU/J7kVPvuM/jnElVSYyqbfS25alzWMXqXLmvUouxEKvpnifJF4IXDJdn6GT8pPtKJe91yXo9N80qbNcup2MTLYaeXENyhlfEyZqNY5WomgmpEJZezss5zNUuRQ9qfdjH2VuXQ80mst8vl0dJcLdX22nc3bLA/QRUTvoiazX3q73VLdbKO3WOor0pId6e6Brn5ZI1EVcmrlnkvkPjGGKLsyxOck7c98b/wCmnKaJtTLaLLa6qjcjJa6mbJOqpnpLotXj2fGU8dIjmo+35aZWPWxKx6sv+aud/v29DENumK2Lm3CNyavegk/KfTrji2tRaSXDd0jZOm9uesUqo1Has/imx4T3X6dvmIOE91+mb5iEXPpU0YTLT1q6vT79hXSQS4M3LZmujfK6OoRcpGrGq6T0MtT36/VjEfS4Zq52qiLnEx7kyXYuppcY7vlfW4VqIJ5GuY57FVEaifvIaG3vWy4Us1RQ/o5KqjiWVV16XUNXj2bVJldE6PmvbfOxro2aKXkMdhvmm3xMFcpsU19DJSphe5Qq/Lq2wSKqZKi/N7xbYPpKjDDKqpfFJNVVlPoPgkYrHNdty5c89Ww1HCa6/Tt9G3mKXCNbPfMT3xte/fEpEV8WSI3J2l3jxsiPYrYEsiZqZvjVj0fUrivkn3kUnTHFP8IXH0En5Tol6xe1Mm4VuiJyJFL+U2HCW6fTt8xvMOEt0+nb5jeYi5tL6hMsFcv/ANny/go8M2m7XbFNBfrlQ1lDJSqse9Twv6pNFdek5E+d+BX4jxNWx4tuNDSWx1SsMqp1Cqqr38kQ1vCa6fTt8xvMZrB0LLtuh36WrTSckKyatWvSaTxujnRUtdE0Q1pGTU6tcq2vkqoV/TPFP8H3D7vL+UqUw7ebzcZpbpSVtthd1Td/gejc+RM0Q9K4S3X6dvo28xm8b4pu0dtgc2due+/Rt5F7xjFNGq4YW2cpnLBMiY6h12pqhKxPfr1XVsUlBh+prGJHkroGveiLmurNGlOy7YrjdpMwncmrypDIn+k39zqJMPztp7cqRxvbpuRU0s12cZD4TXT6ZvmIRcyFuUjbqSpFUPS8LrM6IY18+Kb0xbbU4fudPDUdQ6V0Mio3v62mgv00mD9zS0wrC6Z8dTvWT00F174ufGWXCa6fTN8xDJ7o13rLhh6GKokRzW1TXIiNRNei5PeTRSQvekaJkvQgmhqI2LK5UunX7yIcN7xHUN0oMLVszeWOORyfg0i3ZcV3SkSBML3SBUcjtNtPKq+yel1kz7BDTR25d7bNGj3o7qs1yTlIvCa6/Tt9GhhzaeJ2bM0JOVVTsu2TyV9hnsMwz4Ys1xhhikq566P9XkqORyNXqURM1Vc1Kzplij+ELj6CT8peYFqprxDfKytdvk1A9HwORMtFeqXYm3YhccJbp9M3zEEjmsd/3CYlPImuen/aLhTr95mP6d4w4sL3T0Uv5S9wTZ7jNipuIrjSVVJLJE5joZonJlqRE1r4OQs+Et0+mb5iDhLdPpm+Yhj2mBvmJYzWkqXpaRUVPvYxNbii4TXyvp6OzyVO81L2folc5fjKiakTjyPrplij+ELj6GX8pY7ndPHV3DFNZMmlNDI2Vi55ZOzkXPLwoaThLdPpmejQlm7PE6zmEUDqqZvkP08Dzu02G6TXhLjdaasod4qGzRR1ELmo/qs1RFdlsyTymkxHe77V3V0tFhyrq4lY1Ekhje9vlRp84kxHc5rzY6Z8zVjnqNB6IxNaK5ie81dxrZ7JVrR0Dt7hREdoqmete+p4+TEiSPS7F0QRRK1VijW0iar3fdjBsu+LI897wnc257coZU/0iVcTYijW1VlhuVHBP8aZ8Mio3R6pNSoibURPtNlwluf0yeYg4S3T6dPMQj59MmbW2UmWmq185yKn33FTi6vlwrhbD1E2n6Iekax5O6lc0RvFkZ6O74jnZpw4UrZW7NJkT3J+DSTjm41NzrLKyqej2tqVREyRNqtzN1cquexVa0lvckcOij8lTS1r4SVyw4Elc29zXjSobIsDHWt06Hl92jxTdmRx8G7nSoxyqrm08n5UNLauicN4SrbVQ00lxlmm31qMaukqropkjURfm5l5Pia67y/9M34q/wDpoV2AaqWuwlWXqodpVtNVOZG/JERE0WcWz95THmI+P8pLNTVNzJY1jf8Anrd7vNXb7yKDplij+ELl6CT8h06eYx/he6+il/Ka/hLdPpmejQcJrp9Mz0aEaT0qfsJ1grvXT4fwRtz+yVsF7q71XQTwS1sHVRTROboLpJqzXwGJpMVXSv1UVhkqdeX6LSdr+xDf8Jrp9Mz0aGd3LqeNuFbjcUT+0U9R+jdns6lOL7Sdjo5mOcqXwms5s1PIiI7Di2zz9viVvTPFH8H3D0En5SPhay3KjvUF3udPV00lLMj44amJzNNO8ruY3nCW6fTt9GhR1t7r7jjWy0FTKjoKhytkajUTNPCYxysddlO2yqZywyNs+qXE1Pr7iLe7xiCovFRNS4YraiFypoyRxvc12pNio0hsu+LY0yZhO5tTvQyp/pNzXXastNW+ho5EZBFqa1Wo5UzTPapw4T3X6dno0IubTp5zM+viS8qrcnkP8nond06GMmpsRYpi6X19luNDEi74kkkMioqpxa0TlLzH15msUtmoYqTol76VETWqLmmSbMi34T3X6dno0Mpfaua8Y8w6ytdposjW6k0dSv7xNE+KVeWiZbEE0U8Kc1ypffr/AARY7riSViSR4SrnsXY5kMiov2o0gXKjxLeqmnZNYrlQwIujI9aeTRRqqmarmiJkiHptwuVVZ619BRPRkEWWi1Wo5UzTNda99VKu64muqWisVJmZ7w//ANNPmqYRzQsfZrLO0M3wVMjLufduvs1K2GorLLg2OzW+gluUscquTemqrlRXKvxURdmZU9MsUouaYQuXoJPymmwnVTLgmnvul/blkcxX5alTSVNmzYTOE11+mZ6NDxzmMdadt3bmUbZHtvSrhbt3/EyPTvGH8LXX0Uv5TR4Rs9TYrPiK5VMczZKunSdY5Y1YqKjZHKmvb8Yl8Jbp9Mz0aES7YiuUtnrY3ytVrqeRFTQT5qhtRDezEtfXvPH0tQrbvVFtp3fAx1Jie717UdRYemqUXZvKPfn5EO8tfiqSJ7OCNybpNVNVPLq/wl/gCNtHgFt1gTRqm1D2o7amWaJs2Fxwmun0zPRoZyLTxPwqwxi7XOzEyT5GHwbaK+0XinvVwjqYqmnc9Ep6mJzHKisVuevXl1S8XETLhdcRyXGpkgwpXSxPlc5kjIZFRyKupUXR1k6G7Vl43Srfbq2RJKeaJ2m1Go3PJj3JrTvohoJr5X0c8lLBI1sUD1jYitRckRckEr0vjmS7V07hFGvo4Fs5NV3MYy8YtjbkzClzanIkMv5R0vv+K5oorjabhQMpnpI10kD1Ry599ENhwlun0zPRoOEt0+mb6NCLtFO3NjbKSrS1T8nuRU++4qN0i/1FtxTTUNNR9EvkpGvREVc16p+rLLvGfZdcTyMR7MKV72rsc2CRUX/CWFVK+97q1m6OXT0oVYuWrUm+LxGtrLxW22sloqWVGwwu0WIrUXJPCpNLyGoj3Mvcgg7SqrEx9lb7rHmddbMQX25RLWWa4W6mVui97qeTQTaua5oiciGrq6+4UOFqC0221TXF1KqNzha5zlTXryRFyO+JcUXZuH6pUnZ8VP8A00+chYWepkpcI2y7wqjaurZlK5UzRdvFsTYh4smNmJE/LTJUCRKx+F6/mrmi/f8ABkUumKmrm3CFyRU40glT/SdOneMP4Wuvo5fymu4TXb6dno2n7wmuv07PRt5iLnUvqE/IrvXT79hX2i1y4O3Pr057ZJF0llRsjNDPU1PcZGkxDe65qOo8PVNSipmiwtc/NPsaafFN+uNVhmvglmarHxZORGInGSsLIlswDarlSpoVMqOa5y6800ncX2ITYo5I+a9MVl+9DXwTQy8lq4b5pbP5mRq6rFNVSS0/BO5M3xqt0kp5NX+Em4Ht9Xh6vS8VscyVb4nxvp52Kxzc1TJVz17ERdnGa3hLdfp2ejQpbFcKi/bo9bb7g9JIG02mjURG60azLWnhPGSI9qsp0w9VMpInRuSSrXEmiePwKqe6YmdUSOZhG4Pa56q1yQSZKmf1T8becXMbotwpdETkSKVP9JspMR3KGV8TJmo1jlaiaCbEPjhPdfp2+YhFzqVP2fMm5Nav7/v3GatdsveIMQW2vuVtrqDpfUxvak0L8nppoq63ImXxTrjjElTSYyqaCmty1L2sYvUuXNUVqLsRDQcJ7r9M3zEM1aES97rknR6b5pU2vLqdjEy2E0b4prstdES6Ia8zJqe0irZVWyqn8aEBLniZ7UVuEbgqLrRUhkVF/wAJXVFmvl9uencbbX2ynVutZYHozNNm1EQ9Klv1wpZpKeOVqRxOVjU0E2IuSGfxhim6ssL1bO1F3xv/AKbeXwGMcsSOwxNs5ciSSGdW4pnXYmaofV7u11S3Wyjt1jqLglJDvT3QNc/LJGoirki5Z5L5CnbdMVsXNuErki8qQSflNslTLabJa6qjVGS11M2SdVTPSdotXj2fGU5cJrp9M3zEI1fExbTNu7qZtjnemKndZnRPvvMi664uqUWB+GboxsvUK5YpdSL/AEmgipJcG7ldw0mOlcydr0SRqsVdJ8bSdwmuv0zfMQosa32vrMJVtPPK1Y36GaIxE2PapmyaFzkY1LIpHJT1DWLI9UVW5ou1ittVLinGDXOtu82xsDUcrqhXZTI7Zo9QuzL8UJdTuaY2rad1PUXi2viflpNWR6Z5Ln9GXkdJDR4Ssc0KOa+opInSLpLrXQbzqRd8f893lDqhsL8KMTIyZTPqWY1kXMjWa0y4X3yCmcyKrczeZ5GKrmuVPDxZ94+Pg+x/3ct3nu/6Z9bnCrLi7ESSLpJoLln9ZSVv0nz3eUSPWB13+Vi36HkcfaEwxrhw5ZdSH8H2Pu7lu893/TLrDOBbnQXSnuN6mpaqrgeuhLE93Uty1Jloom1V8pB36T6R3lG/SfSO8pGtY3oy3hkSpw+TrJfxzM5fp75cMcXeioa9IWQSqqI9EyRNSci8pbfB7j7u3b/Pd/0z63OUR+6Je0eml+hXb9ZpM3x/z3eU2J5mxW8hFumxrU8D5sTUeqYV3UpX7nVxt1TJXYhko6xJ+pTeXvz0uX4reJC3uFlxdimVtVbrrTQsiTe3JOqoue3VkxeUzWOpZOlkHVu/W8veU9ExX1FdCjF0f0f7urjMXSLhSddNuhm2JEetMnna4uu/3mZX4Psf93Lf57v+mfcO55jN8zGXC70E1K5cpY0e/qm8afq0JW+SfPd5Rvj/AJ7vKQ9tYv7EJuwSf7q/ftOmNoJ8K7m9JSUTkgdDVI39GukmTle7j8JnrThfGd6p1mpbzRtaiIqpKqouvwMU5Y4e5bE1Fcq/p27V7ym5vCrHbLRodTnToi5as9TTY5qclJcKL45mryHJOsOJUvnlknuMpWbmONa+Heaq7W2SPPS0Ve9Nf2Rky2W6e1UlRarU9lNPVt3l7s1VqvyVqKuaKuWa8hJ3x/z3eUibmjlfbsUK5dJWuzRV4tTzFsjp2rh8lG9NzN8SUrkx+Ursrr0Pn4Pce927d5z/APpj4Pce927d5z/+mTN+k+e7yjfZPnu8pF2xn+2nuJ+wS/7q/H+S2wlguts9ybcrq+mnrUa5j5oXuXNF1JqVE4u8efZ4hvWJbnTUVxjiSKscxN9RETW9yJsavIavfZPnu8pE3MkR0uLVVEVdJmvk/Wk8MrZGuW2m+ZrVELoXNu7XLLI+Pg+x53at3nO/6ZFgwBW2OsWsvklJVSSv043Qveqo9FzVV1JyoXO+yfPd5TOYplk6Y2bq3ZdE8vfaYR1HOXlMTDfqhJLSrA3nSOxInRfcXtdh3GGJKjphQXekjhcmijZVVHZp4GKR/g+x73ct3nu/6ZpMSucy7uRiq1NBupFKjfZPpHeUj7S2PyFYi26kiUj5UxteqIvTYj0+5ziyeZsd2uVBU0bv1kTXvzdxp+4nHku07bo8lXh/DFkoqGbeNB29dTrTU1OVD73yT6R3lMxjNznNt+k5Vyn418BJBO2WVG4bfL3EVRSvihV+O6p7/eTrdhHG10gdNT3qjRrXaKo9VRdicjF5T6rdzDGFc1nR11t0sca6WSyPT1RmwxWqx3SNGLopvKam6uNShmlk3l/6R3xV4zztfLdbCl07jJtGszMWNbL0XM/KS31jLZLY7BNHRrVP0k01XR0tWaquSrsaR/g9x93ct3nu/wCmdtzhyrucXN6r1SVrsncadTGSN8f9I/zg+TszlY5MS7qI4+1txxrgTSyEH4Psfd3Ld57v+manB2D6qw1rrhcHwS1ssLo5ZonuXS6pFTaicTU4ik3x/wBI7zhvj/pHecRrWNXRlvAk7A+1lkv45mQtEWJ8RVkrKK5xR/plYm+plr+xqmh+D7Hvdy3+e7/pnXc1T/8ARV7f+8lUuS/0tJO+yZfHd5TYqJmwvVuBF9hrUsD6iPEj1T2qVNuwRUYWq457i6mlq0eksMkD3LoKnhROPvE+swvjS/VL7nRXijjgny0WyuVHJkmiueTF40UqKiRzt0DDyK9VRZ2Zoq7eqQ1+IVVl7qGtcqImjqRck+Khg+RW2ndni6bGbIkcq0zMlb+5Ov3coPg/x93dt/nu/wCmdqXc3xLUSaF8r6Gspss0jbI/PS4l+InfO+m/57/OGm/57/OIlrGroxEJ0oJP9xV8Tjun1FfQ1lgt9vqd4dLG6LZqzzaibUIFDgzHFfTNqIb1RIxyqiI9zkXV4GKRLppOxthnNVX+2x7V/wDmMNriR7o71K1qqiaLdSeA2HSo2JsmFFuascD1mdCj1S3X/HtMnVbmWKJXx1d3uFvqaem6t7WyPzVu1UTqE4k5Syjtl0q7U2xWCpio0R2+NSVV0U15rryVeM43WSTpPW9W79Q/j/uqTcJKvwV00mfV7+/quP46mHMdJHzNEb06KZ8pIX8pc3P69UIHwfY+7u2/z3f9MfB9j3u7b/Pd/wBMm79J893lG/SfPd5SPtrfUQl/D5f91fj/ACWtswzJhiwXiqkWHouaicsksTnLpPRqqq60TjU89w9QYrxK1i0V1gj01cib9q2eBqmjuUsnSyr6t36l/H/dUkYH6ncuVyal6Jdr4/jITslR0Svtpvma8kLo5msxedtkQ3bnWO3sVjr3bVa5MlTTd/0znaMKTYPrI5Kl0LrlHm5k8DnKjWuRW5dUid/i4yz3yT57vKVVoe5265amuVXIsMmpdf8A6UhgyZZ0WNiYeuRJJB2a0si4+mfeS58HY3uk76+mvVEyGpXfGNe5yORF5cozn8H2Pe7lv893/TLi6SObdapEc5ESRdSLlxkTfX/Pf5xH2tqLZWISpQyOTEkipf73Pig3Ob9LPnfq2hrY2Kjo2tkfm13moRd0ysufDait9vqd436jautNWenJ3uRCbvr/AJ7/ADlKelVX7q1j0uq/Rrt8DyaCZJXKmHp7Pca9TTuhYj1dfP2+87U2Bcc1VMyeO90CMemaaTnZ/wDLOVTuZ4iWoZX3muoKqCBOra2R+kreROoQ0d5e9t3qEa5URH7MyhxDI/pBWdW79Xy98wbVeVga1EXS5ItG7BzHPVU1sufeTwR+mND27T+laOmND27T+laVvLfspb42blXVvbHj/Dz3uRrWztzVVyROqQtb/iWnfjquonPhZAxrFSdZUycug3V+PLxFDWzUVRjSyadTC6DfmpK5JEyamkm1eI1d0tO5xPcpZKqRsszstJ0dWqoupMti8hcJG10LWyJlb4lC+Rzal7otb/CxT3C4UU9tqYYayCSWSF7WMZIiq5VRURERNq5lvhqCam3MaOKeJ8b0qHqrXtyVOqcV1wtu59RW+pqrY5W10ML5KZVqHO/SImbdSrr15EyzX+nq9zylWtr6ZKvf3aTFka12Wk7LUYrGjIXIzNDLnLJUMdIll+APwj9MKHt2n9K3nHTCh7dp/St5yq5btlLzGzdBcetlV4l/qUj2K8xWncfkkRY5Jm1S/oVfkq5vQXCvolt1SjauByrE5ERJE16lP3BtLhaqwHoX2ePSWd2lH0Rov2plqRcyypW/lKjkyvn4FPXORZmq1c7Lbx6CmvVBNTRSvraZjnsRzmLM3Nqqmw/cLMdU7qFLWwNWWm3l7d+Z1TM9BdWaaiV0k3L+/wDenc5HsNztNo3Q4KC1VcUFlSJzlWWRMkerFz6pe/lxk0ULGOVYvjsQT1EkkaNmSyb95bXHrnVeOf61Ix+XC5291yqVbXUzkWV6oqSty2r3yP0xoe3af0recqXMfiXJS8je3AmaaEkqrXIyHdZtckr2sYkMmbnLkifo5Cb0xoe3af0recqKOW3VG6bblqamHoTeno+RZURqfo35dV4cjbomuR7suimlxFzFiTPqhYVWJaefFF0pZXQQxwzORkrpkyfr4iJfqymrLLUU9JURTzvREZHG9HOdrTYiF5W2fc1lrZnzuR8jnqrnNqnZKveycVV6pMD2q0VFdYl0blCiLAqzq/Jc0RdSrkupVNnkQ40c299ulzTSpmSNWOS7d+tv+DRUsT4dzyxxyMcx7W5K1yZKm3iIBIZfaOqwPaHVFxpVqcs5Gb61HN1LtTiK/pjQ9u0/pW85p1TXrKuRv0DmJAllJBW4h6xVfi1JXTGh7dp/St5yuv8AXUb7JVtZVwPcseSNbIiqpFCx3MbkuqE87m8p2fRfkS5L/Hadyayvj3ueVJ9B0WnkqIqyLn+CeU+m3a3qxF6PpUzTWm/N1fidbHSYOqsBW1t7niWTNVfG2pyci6Tss0Rc01H10k3MO/8Ae3fmLOaGKRfLyW/QpaaomibaNLp379T53PYpH7o1zrWsV1NLRuRkyJmxy6Uexdi7F8hLm/Wu8KkTBd5ttDjuvt9PWwwWaGld0Ms0iImelGuWku3a7jP2W5UG+u/ttPt+lbzmvWMdZqWNuge3G9d/nnc7Aj9MaHt2n9K3nHTGh7dp/St5yv5b9lLXG3ci4Zmig3WHvlkbGxKZeqcuSfEQ50eJqetrq5tS+CmSKZUYrpU6tM116yPY322o3S3vramFtMtOq74sqI3PQTLqsy9msu5msz1euk7SXNUq1yz84uHRsfG1smyHPtlkjme6LPNbp8jP4mniuVodT0MrKqZXtXe4XI9ypy5Ibm6NVmHbAxyK1zaRqKipkqdQwx+Io8JWO1OrMMP0Lgj0amc2+dSu3Uqqaa63q31FlsyrcaV0vQyLIiStza5WszzTPVxkUseGBWszT4k0UuOqa6RLL8OpBBG6ZUHbtP6Vo6ZUHbtP6VpWYH+qpdY27oVuMOx2b6zPaQtr9iOG2YRwrFEsUyyUsbZP0iJveUbNv/nEUeK6ulnsEzIamGR6ub1LZEVfjIaOOhwRV4Ys3Taojkl6EjVWx1WStcrG6WaIurWWlO38iz0yvn7ikrHqlTijXO2XvUh9Nbd3QpfTN5z73O4ZkxFiGp3p28TQqscmXUvTS4l4z66RbmPKv3p35j8wXfKKC+Xyh6Nhht0Easo0lka3NqKuSIq7dXfJI4WsReWt763I56h8tua21tDuCN0yoe3Kf0recdMqHtyn9K3nKflv2Uv+YzckldgSphpcc3+SaVkadCuy03Ima6TdRI6ZUPblP6VvOVeD0tNRja7uuVTAynWFdFz5UYjlzTYuZv0TXJjy6FZxFzFazPr9D7tGJaW4UjpqmSClej1akbpUzyyTXryIGK3sulBFFb3Nq5GyaSsgXTVEy25IaPpJuYd/7078xS4mfhrD9FFUYTk0KqSTQlzk3zqMlXYqrx5GyyGJsmKLXonQ1X1MzosEyZdV6m+xd1wi8V71KEs8U3e2TV8TorjSSIketWztXjXvlH0xoe3af0recrZmP5i5KWlI9vJbmSTN456xx/zDfZcXfTKh7dp/St5zP4zq6aezRshqIpHb+i5MejlyydyElIxyTtuhjXOatO5EU1WM8SQUlxs9Kx0MscsKacqSplHry1kPppbu6FL6ZvOWlytuAKtlK64VEUsiRJlvdXs8OTiB0j3MeX/i3fmNt0ET83KqL1sV0NTPGmGNLt6XP3c3p54bTiZ8sL42yZOYrmqiOTJ+zlOpwwPiCF9sxBBWV9PHGxNCmbI9rFVuTtnLxHz0yoe3Kf0qEFa16vS6Gxw1zEa6y5d5IBH6Y0PbtP6VB0xoe3af0qGjgfspaY27oR9z6tgoY8YyTSMaqNRWtc/R08kl1IcLTiKlr6NJ6manpX6SpvbpUz/E/MAssc9TiPpvUQsjc5uhpTozTRd80staZ8RadI9y/v8A3p3OXU8THraTLS1vA52nmkiziz1v78ijuSpccQ2J9AqVTYKtFlWDq9BFezLPLZsXyG5xP14d9RpjrlUYfsF7syYWmSOKpqUStV0mmmijm6Otc8tSvNNiS626W7OdFcKR7dBNbZ2r7zXqGKkCNbmnTf2m1Syo6pV7slVM9iCCP0xoO3af0recdMaDt2n9K3nK3lv2UuMbN0KTFKolfZlVUROiePwtNHjDEsEeMoaFHQ7xJTo51RvqZNXqubl4zK4nqaSorbVo1ET2pP1ei9FyTNvkNpebXueVFaj62eOaXRRNKOrVUy+xS2jYiwNbImWfzKKZ7m1TnR65e62ZUS3S3uieiV9Mq5bN9bzk7c9pqik3ObnHUwyQvWscqI9qoqpoxkeSzbmbInvjVdNrVVv9qdt8p0wdiOKqwHcOmVfTsqeiVRrHvaxyt0Y9icevM8SJGROSPNF1D53SysWRLKi5H2CN0xoe3af0recdMqDt2n9K3nKrlv2Uvcbd0JJVYFukVs3N77K50bpWzK5sTn5K7qWkzpjQdu0/pW85B3PIcO1GFbgy+TxNzny3t0+g5zdFNiZ69ZY0bXIx902+pU8Qcivjsu+m+Vj7t1+oquhinnqqeCR6LnG6VM26z5pP7dj+xT0i9EQwyfpJIuqazwqmwsekm5jyO+9O/MRIayxWLGVnp8P1DIaCd+lVrJLpIip/ecurUTRwxsfij1NeWolfFgmSybmgxB16qPCnqQrjvfLpbpbxUOjr6ZzVVMlbM1UXUnfIHTCh7cg9K3nKuRj8a5LqXUMjeW3PohIKSreyPHuHXvcjWpO3NzlyROqQs+mFD27B6RvOUddNQ1ONLFp1MS0++tSR++IiNTS414jZomOSW6p0U1OIOasC59U+ZfX/ABLTuxzXULnwtgY1itnWVMnLoNXL8fwIlwuFFPbamGGsgklkhe1jGSI5XKqakRE2qXF0tO5vNcJZKqVssy5aTo6tdFdSci8hW19u3PaK31NVbHK2ugifJTL0Qrv0iIqt1KuvXkbPIhVyOzRfqaTamdrFZa7d+ti0wxTy025dTxTxujek782vTJU6tSOfdjxBT1W55AtbcKbotZnaTHSNa7LSXLqfAROmND27B6VvOatY16y3sbnD3MSGyLlfqSCPcetlX4l/sqOmND27B6VvOR7hcKJ1tqWtq4FVYXoiJI3XqXvmvGx2NMlN2R7cC5n5Y71FadyB8qLHJM2qX9EsmSqivQ+qe9UE1LFK+spo3SMRysWZubVVNh+YNpcLVOA0ZfaiJHLO7Si6I0HKmaZasyX0j3MOVfvTvzFtPFHI5ceS92xRU08sTU5SXTv3IWHmuq91K2VlM1ZqdjJGumZ1TEXen6s01caF3cOuVV45/rUp7RcbRZ90SgoLNVRw2Z0b3yLJIioj9B/7y7NjeMnV90oHXGpcldTqizPyVJWqi6175r1bHIxqIl06G1RPasz3Lkq6+J+gj9MaHtyD0rR0xoe3IPStK7lv2UtsbdyBTSMh3UrJJI9GNbGubnLkiankq44kp5sX3KkldDFFE9dGZZUyfsKtJLfPuiWl1RUxdCrGu+P3xEamp+1c9XEaSvtG5tLXTPqHo+VXdU5lUuSr9ji4wNdE1siZW+JQcxzJ3uizW/ssUN9q6WsstRT0tTFPNIiIyOJ6Oc7WmxENVSwyQbndkjlY5j2t1tcmSpqUzt6pMD2q0z1thdlcokRYFWdX680RdSqvFmXcd9pKvA1pWe4Uq1OjnKzfWo5q69qcRg6PBArWZp8bmbZVkqWukSy/CxHBH6Y0PblP6VvOOmND25T+lbzlVgfspeY2boRsQ9YazxfvOkl/jtG5LZXxLHNNv2g+LfMlRFWRdfkTykS/19HJY6tjKqBznR5IiSIqqWFipMH1WAra29VETpM1V8banRejtJ2WaIuaai0pW/kqj0yv9ClrXf8AcIrFztl43ObLtb3MRej6XNU1pvzdX4n7gaKSXdMq62NivpZKVUbO3Wxy5MTU7ZtRfId+ke5j3/vTuc5YUvFstmP6m3UVZDBZIadd4WWRETSVGqvVL/eV3GZxQsjVVjW+XXYiqKh8rEbKltrbk2p+VS/XX1nI+Ki5UC1MqpW065vXZK3lOXTGh7dg9K3nKlWPvopfNeyyZkgrsMzRQbrL3zSNjb0MqaTlyT4iEnpjQ9uU/pW85V2OS21G6W51ZUwpSugX9IsqNbnoJlrzNyia9HOy6KV3EXMWNt16p9SSzEtPV3i5xVDoadsFQ5rHOlT9Imk7Xr8CeUhYmnhuVndT0MrKqZXtVI4XI92XLkhoKiz7mclTK6V+b1equVKpclXP6xT4hZhCx2p1Zhh+VwR6NRVlV/Urt1Kqm0kMXMR7NduhqLUzcpY5Ey362+RsLox0eHbAxyK1zaRqKipkqLoMKcn3W9UFTZLM5bjSOl6HRZEbM3NHK1meaZ6io6YUHbtP6VvOV9S16yrkWVE5qQNz3+ZIKfFnY3Vf0e20sOmFD27T+lbzlTiispZcPVLIqmGRy6GTWyIqr1aHkDHc1uXVPmZ1Lm8l+fRfkTcXXx9DhHCLaSqRMqViTNYqOXVHHqXk4yv4c2r6Kp8xvOaOPFdhwthqyq1kVXPVUkazNY5JFjc1jc80z6nW5fIcfhbtPcz/AC0LV8TZPPZfwKSKeSL0b0t3nbc3oJG3a63bTZvFdDpxt/eRFXPWfhnsMY6t1rxNerlWMnbDX5rEyJqLo5uz5dQ4bWnkqPRpzmvVwSuVLJc2qGphZixLa5oQZ7htaeSo9GnOOG1p5Kj0ac5p9kn9VSy7bT+uhOwTcobXj28zTNe5HRK1EYibdJpn7PjJsFO9tzdPNKrs2uYxuzL7CZhLGFqsuLLlc62Od1PVRq1iMjRy56SLrTPvGi+Fu0dym+iQt3RXSz23yT2FA2ZWvV0TrLddV12yMvXVcWMIko7fnE+Fd8cs6ZJls4s+U9Nxb8vh8X7zzbGuOaPEltgpqSl6HfFLpq5Go3NMlTL8S8v26RYrlVRyQMq9FrMl0o0Tj8JBPA/k4WJlsbEFS3tCPkVL9V6dxNBnuG1p+bUeYnOOG1p+bUeYnOV3ZJ/VUtu2U/rofuN+sTfHN9SkzGGKkj4P7w6ZkEUOU7NFvVomjs/EzuJMSUN1tiU9MkqPSRHdW1ETLJe/3zZt3VbFBQ0kMdFLI6KFrX75CmpURE1ayzhie2JEe3e6FPUTMdOrmOzystzP8ObX9DU+YnOafAFrmt9mv80rmK2qYkjEaq5omi7b5SN8LVn7m/5SFBhHG1ts1NfWVyVCuuDlWFI2o5E1O25qmW1DJsGFq8tqp9TCSoV6pzVRdrdPE0gM9w2tPzajzE5xw2tPzajzE5yq7JP6pd9spvXQ0JS4LuzLXDi9FR++Ss/RuYiLoqiS69fhOHDa0/NqPMTnOeB8aWrDtRe5q6KaTo1zHQtbGjtmnt16vjIb1LBKxr7pbQra6ohkVllvqRbVjOGGjRlxWeafSXNzWNyy4uNCSk0eLrjRdAKsfQUzXyb+mWaKqbMs+Q0PwtWjuZ/loZzFeOKK/VFsfTUzqdtJPpyaLUTSTNvMbDYG48TG2X4e41nVL+Xgkcjm/H3noOKOvC/UaU5W3rdFslwuCzwsqtDRROqjRF9ZX8N7T82o8xOcrZKWdXqqNLaCrgbE1FehojM4zXRjoFXinz9R14b2n5tR5ic5TYhxFQ3RtIlOkqbzLpO02omryklJTTMmRzm2QiraqF8DmtciqaXHOLdHF9HNG+ZtElMm+x6Lc1XSf/tx8RXuxpbJEVjYqnNyZJ1Cc5p6zdcsO+p0Nb5JGaOtZImouflIsu6zaZInsS2Jm5qp+qQ3HQNdbGxbleyokYipG9ETZSwwbaprRuf3KnnfG9zqpXorFVUyVsacad4jGcwlja2WXB9baq3ol1TPULIxWMRW6OixNuf91T64bWn5tR6NOc1qunmfJdEubdBUQMjVFW2fU0IM9w2tPzaj0ac44bWn5tR6NOc1eyT+ob/bKf10PvDN5S27n9+gjSRKiSZXRvaiZN1NT3EK341pI6GOOtSokqETq3NY3JdfhJeBsc2nDVmrqesgllmmnWSNEjRzcskTXr7xd/C3aO5ieiQt5okeqo9tyggmdGl43Im9yosmWJMW2q40btCKjqGaaS6nLrRdWWfIbDEfX2p/p9lDC3bHNFccW2e6MhfBT0T0WVrGIiqmlnqTjLK7boNlrrnNUxNqtB+jlnGmepqJy941qiB6xo1iZbG1S1LEnV0i5216LoWgM9w3tPzan0ac44b2n5tT6NOc0eyT+qW3baf10P28Stgxdh2Z6KrYqpj1y25JI1TpifF2hjioke+boHe25RaLc89FO/y98p6zEtvqMR2ava2beaKoZJKitTNWo9qrlr7ym1qt1yxb+u8W58jOJ0kTc/WWjInJC1r23yXL2lJLM1ahzo3Z3TPpoZmTFdBc4n2+COdJapqwsV7UREV2pM9ezWbSyW6W17msFLM9jntmcqqzPLW9eUoLruoWuvtFbRx27e5Kinkia7e0TRVzVRF/EhWPHVqt+B4bPUpUuqmSucqtYityVyrtz7546BUiVsbVTuPUqMUzXSql06l6DP8ADa08lR6NOccNrTyVHo05ys7JP6ql12yn9dC3uXWur8S/2VKigvy0G5LJTU7pI6lKnNHoiZImmhxrMY2ueinhYk+lJG5qZsTLNU8JMwdugWjDuFEt9RTSy1SSud+rRWZKvLmWFNDIyNUc3qVVbPFJI1Wr0XropCpcb0DKWJtQypdKjER6oxut2Wtdpb4PZ07x5QX2lXRpoUkjVsmp6rvbk2Jmn7ycZL+Fu09zG+iQoUx1b5N0WhxA6GSGjghcx8cbEzzVj0zyzy2uQlZA1HKrGqimvJUvczDI5HJ3Guu3Xaq8a71kQpq/HlnqK+eZjanRe9VTONOcj8NrT82o8xOcqnUk+JVwqXMdZToxEV6aGhKToplFul2apkRVayJVVG7f3zjw2tPzajzE5yDDiq2x43tt4eyZaWlaqPTQTS2O2Jn/AHkNqkp5mPVVS2SmrXVMD4kRHIuaEu5YvSHGFzfUundSK/8ARRo1ubdn/m0+KjEdFe6d9spmTNmqU0GLI1Eai9/JTSz7rlm3529W5zmZ6lfEma/iVd/3S7ddbHV0MNBvUk7NFr0jRMja5DVci4FvuaSVEjWq3EmHbrY//9k=', false) +$shape->setName('Image Base64') + ->setDescription('Image Base64') + ->setData(file_get_contents(__DIR__ . '/resources/base64.txt')) ->setResizeProportional(false) ->setHeight(36) ->setWidth(36) @@ -67,20 +69,33 @@ ->setOffsetY(200); $currentSlide->addShape($shape); -// Add a video to the slide -$shape = new Media(); -$shape->setName('Video') - ->setDescription('Video') - ->setPath(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? './resources/sintel_trailer-480p.wmv' : './resources/sintel_trailer-480p.ogv') - ->setResizeProportional(false) - ->setHeight(90) - ->setWidth(90) +// Add a file drawing (PNG transparent) to the slide +$fill = new Fill(); +$fill->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKRED)); + +$shape = new Drawing\File(); +$shape->setName('Image File PNG') + ->setDescription('Image File PNG') + ->setPath(__DIR__ . '/resources/logo_ubuntu_transparent.png') + ->setHeight(100) + ->setOffsetX(10) + ->setOffsetY(250) + ->setFill($fill); +$currentSlide->addShape($shape); + +// Add a file drawing (SVG) to the slide +$shape = new Drawing\File(); +$shape->setName('Image File SVG') + ->setDescription('Image File SVG') + ->setPath(__DIR__ . '/resources/tiger.svg') + ->setHeight(100) + ->setWidth(100) ->setOffsetX(10) - ->setOffsetY(300); + ->setOffsetY(360); $currentSlide->addShape($shape); // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_03_Video.php b/samples/Sample_03_Video.php new file mode 100644 index 0000000000..3998f750ce --- /dev/null +++ b/samples/Sample_03_Video.php @@ -0,0 +1,32 @@ +getActiveSlide(); + +// Add a video to the slide +$shape = new Media(); +$shape->setName('Video') + ->setDescription('Video') + ->setPath('WIN' === strtoupper(substr(PHP_OS, 0, 3)) ? './resources/sintel_trailer-480p.wmv' : './resources/sintel_trailer-480p.ogv') + ->setResizeProportional(false) + ->setHeight(90) + ->setWidth(90) + ->setOffsetX(10) + ->setOffsetY(300); +$currentSlide->addShape($shape); + +// Save file +echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_04_Table.php b/samples/Sample_04_Table.php index 6cc6f3bff3..0dce634c6f 100644 --- a/samples/Sample_04_Table.php +++ b/samples/Sample_04_Table.php @@ -8,29 +8,29 @@ use PhpOffice\PhpPresentation\Style\Fill; // Create new PHPPresentation object -echo date('H:i:s') . ' Create new PHPPresentation object'.EOL; +echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 06 Title') - ->setSubject('Sample 06 Subject') - ->setDescription('Sample 06 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 06 Title') + ->setSubject('Sample 06 Subject') + ->setDescription('Sample 06 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Remove first slide -echo date('H:i:s') . ' Remove first slide'.EOL; +echo date('H:i:s') . ' Remove first slide' . EOL; $objPHPPresentation->removeSlideByIndex(0); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // Create a shape (table) -echo date('H:i:s') . ' Create a shape (table)'.EOL; +echo date('H:i:s') . ' Create a shape (table)' . EOL; $shape = $currentSlide->createTableShape(3); $shape->setHeight(200); $shape->setWidth(600); @@ -38,29 +38,29 @@ $shape->setOffsetY(300); // Add row -echo date('H:i:s') . ' Add row'.EOL; +echo date('H:i:s') . ' Add row' . EOL; $row = $shape->createRow(); $row->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setRotation(90) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFFFFFFF')); + ->setRotation(90) + ->setStartColor(new Color('FFE06B20')) + ->setEndColor(new Color('FFFFFFFF')); $cell = $row->nextCell(); $cell->setColSpan(3); $cell->createTextRun('Title row')->getFont()->setBold(true)->setSize(16); $cell->getBorders()->getBottom()->setLineWidth(4) - ->setLineStyle(Border::LINE_SINGLE) - ->setDashStyle(Border::DASH_DASH); + ->setLineStyle(Border::LINE_SINGLE) + ->setDashStyle(Border::DASH_DASH); $cell->getActiveParagraph()->getAlignment() - ->setMarginLeft(10); + ->setMarginLeft(10); // Add row -echo date('H:i:s') . ' Add row'.EOL; +echo date('H:i:s') . ' Add row' . EOL; $row = $shape->createRow(); $row->setHeight(20); $row->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setRotation(90) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFFFFFFF')); + ->setRotation(90) + ->setStartColor(new Color('FFE06B20')) + ->setEndColor(new Color('FFFFFFFF')); $oCell = $row->nextCell(); $oCell->createTextRun('R1C1')->getFont()->setBold(true); $oCell->getActiveParagraph()->getAlignment()->setMarginLeft(20); @@ -71,37 +71,37 @@ foreach ($row->getCells() as $cell) { $cell->getBorders()->getTop()->setLineWidth(4) - ->setLineStyle(Border::LINE_SINGLE) - ->setDashStyle(Border::DASH_DASH); + ->setLineStyle(Border::LINE_SINGLE) + ->setDashStyle(Border::DASH_DASH); } // Add row -echo date('H:i:s') . ' Add row'.EOL; +echo date('H:i:s') . ' Add row' . EOL; $row = $shape->createRow(); $row->getFill()->setFillType(Fill::FILL_SOLID) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFE06B20')); + ->setStartColor(new Color('FFE06B20')) + ->setEndColor(new Color('FFE06B20')); $oCell = $row->nextCell(); $oCell->createTextRun('R2C1'); $oCell->getActiveParagraph()->getAlignment() - ->setMarginLeft(30) - ->setTextDirection(\PhpOffice\PhpPresentation\Style\Alignment::TEXT_DIRECTION_VERTICAL_270); + ->setMarginLeft(30) + ->setTextDirection(\PhpOffice\PhpPresentation\Style\Alignment::TEXT_DIRECTION_VERTICAL_270); $oCell = $row->nextCell(); $oCell->createTextRun('R2C2'); $oCell->getActiveParagraph()->getAlignment() - ->setMarginBottom(10) - ->setMarginTop(20) - ->setMarginRight(30) - ->setMarginLeft(40); + ->setMarginBottom(10) + ->setMarginTop(20) + ->setMarginRight(30) + ->setMarginLeft(40); $oCell = $row->nextCell(); $oCell->createTextRun('R2C3'); // Add row -echo date('H:i:s') . ' Add row'.EOL; +echo date('H:i:s') . ' Add row' . EOL; $row = $shape->createRow(); $row->getFill()->setFillType(Fill::FILL_SOLID) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFE06B20')); + ->setStartColor(new Color('FFE06B20')) + ->setEndColor(new Color('FFE06B20')); $oCell = $row->nextCell(); $oCell->createTextRun('R3C1'); $oCell->getActiveParagraph()->getAlignment()->setMarginLeft(40); @@ -111,11 +111,11 @@ $oCell->createTextRun('R3C3'); // Add row -echo date('H:i:s') . ' Add row'.EOL; +echo date('H:i:s') . ' Add row' . EOL; $row = $shape->createRow(); $row->getFill()->setFillType(Fill::FILL_SOLID) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFE06B20')); + ->setStartColor(new Color('FFE06B20')) + ->setEndColor(new Color('FFE06B20')); $cellC1 = $row->nextCell(); $textRunC1 = $cellC1->createTextRun('Link'); $textRunC1->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/')->setTooltip('PHPPresentation'); @@ -140,5 +140,5 @@ // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; -} \ No newline at end of file + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_05_Chart.php b/samples/Sample_05_Chart.php index bb28ec65c0..9169b1f43b 100644 --- a/samples/Sample_05_Chart.php +++ b/samples/Sample_05_Chart.php @@ -3,35 +3,40 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\Shape\Chart\Gridlines; +use PhpOffice\PhpPresentation\Shape\Chart\Legend; +use PhpOffice\PhpPresentation\Shape\Chart\Marker; +use PhpOffice\PhpPresentation\Shape\Chart\Series; use PhpOffice\PhpPresentation\Shape\Chart\Type\Area; use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar; use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Line; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut; use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie; use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar; use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter; -use PhpOffice\PhpPresentation\Shape\Chart\Series; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Shadow; -function fnSlide_Area(PhpPresentation $objPHPPresentation) { +function fnSlide_Area(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Generate sample data for chart echo date('H:i:s') . ' Generate sample data for chart' . EOL; - $seriesData = array( + $seriesData = [ 'Monday' => 12, 'Tuesday' => 15, 'Wednesday' => 13, 'Thursday' => 17, 'Friday' => 14, 'Saturday' => 9, - 'Sunday' => 7 - ); + 'Sunday' => 7, + ]; // Create templated slide echo EOL . date('H:i:s') . ' Create templated slide' . EOL; @@ -66,21 +71,22 @@ function fnSlide_Area(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_Bar(PhpPresentation $objPHPPresentation) { +function fnSlide_Bar(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // Generate sample data for first chart - echo date('H:i:s') . ' Generate sample data for chart'.EOL; - $series1Data = array('Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293); - $series2Data = array('Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379); + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $series1Data = ['Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293]; + $series2Data = ['Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379]; // Create a bar chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a bar chart (that should be inserted in a chart shape)'.EOL; + echo date('H:i:s') . ' Create a bar chart (that should be inserted in a chart shape)' . EOL; $barChart = new Bar(); $barChart->setGapWidthPercent(158); $series1 = new Series('2009', $series1Data); @@ -97,7 +103,7 @@ function fnSlide_Bar(PhpPresentation $objPHPPresentation) { $barChart->addSeries($series2); // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Monthly Downloads') ->setResizeProportional(false) @@ -119,21 +125,22 @@ function fnSlide_Bar(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_BarHorizontal(PhpPresentation $objPHPPresentation) { +function fnSlide_BarHorizontal(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Create a bar chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a horizontal bar chart (that should be inserted in a chart shape) '.EOL; + echo date('H:i:s') . ' Create a horizontal bar chart (that should be inserted in a chart shape) ' . EOL; $barChartHorz = clone $objPHPPresentation->getSlide(1)->getShapeCollection()->offsetGet(1)->getPlotArea()->getType(); $barChartHorz->setBarDirection(Bar3D::DIRECTION_HORIZONTAL); // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Monthly Downloads') ->setResizeProportional(false) @@ -154,160 +161,163 @@ function fnSlide_BarHorizontal(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_BarStacked(PhpPresentation $objPHPPresentation) { +function fnSlide_BarStacked(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Create templated slide - echo EOL . date( 'H:i:s' ) . ' Create templated slide' . EOL; - $currentSlide = createTemplatedSlide( $objPHPPresentation ); + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; + $currentSlide = createTemplatedSlide($objPHPPresentation); // Generate sample data for first chart - echo date( 'H:i:s' ) . ' Generate sample data for chart' . EOL; - $series1Data = array('Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293); - $series2Data = array('Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379); - $series3Data = array('Jan' => 233, 'Feb' => 146, 'Mar' => 238, 'Apr' => 175, 'May' => 108, 'Jun' => 257, 'Jul' => 199, 'Aug' => 201, 'Sep' => 88, 'Oct' => 147, 'Nov' => 287, 'Dec' => 105); + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $series1Data = ['Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293]; + $series2Data = ['Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379]; + $series3Data = ['Jan' => 233, 'Feb' => 146, 'Mar' => 238, 'Apr' => 175, 'May' => 108, 'Jun' => 257, 'Jul' => 199, 'Aug' => 201, 'Sep' => 88, 'Oct' => 147, 'Nov' => 287, 'Dec' => 105]; // Create a bar chart (that should be inserted in a shape) - echo date( 'H:i:s' ) . ' Create a stacked bar chart (that should be inserted in a chart shape)' . EOL; + echo date('H:i:s') . ' Create a stacked bar chart (that should be inserted in a chart shape)' . EOL; $StackedBarChart = new Bar(); - $series1 = new Series( '2009', $series1Data ); - $series1->setShowSeriesName( false ); - $series1->getFill()->setFillType( Fill::FILL_SOLID )->setStartColor( new Color( 'FF4F81BD' ) ); - $series1->getFont()->getColor()->setRGB( '00FF00' ); - $series1->setShowValue( true ); - $series1->setShowPercentage( false ); - $series2 = new Series( '2010', $series2Data ); - $series2->setShowSeriesName( false ); - $series2->getFont()->getColor()->setRGB( 'FF0000' ); - $series2->getFill()->setFillType( Fill::FILL_SOLID )->setStartColor( new Color( 'FFC0504D' ) ); - $series2->setShowValue( true ); - $series2->setShowPercentage( false ); - $series3 = new Series( '2011', $series3Data ); - $series3->setShowSeriesName( false ); - $series3->getFont()->getColor()->setRGB( 'FF0000' ); - $series3->getFill()->setFillType( Fill::FILL_SOLID )->setStartColor( new Color( 'FF804DC0' ) ); - $series3->setShowValue( true ); - $series3->setShowPercentage( false ); - $StackedBarChart->addSeries( $series1 ); - $StackedBarChart->addSeries( $series2 ); - $StackedBarChart->addSeries( $series3 ); - $StackedBarChart->setBarGrouping( Bar::GROUPING_STACKED ); + $series1 = new Series('2009', $series1Data); + $series1->setShowSeriesName(false); + $series1->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4F81BD')); + $series1->getFont()->getColor()->setRGB('00FF00'); + $series1->setShowValue(true); + $series1->setShowPercentage(false); + $series2 = new Series('2010', $series2Data); + $series2->setShowSeriesName(false); + $series2->getFont()->getColor()->setRGB('FF0000'); + $series2->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFC0504D')); + $series2->setShowValue(true); + $series2->setShowPercentage(false); + $series3 = new Series('2011', $series3Data); + $series3->setShowSeriesName(false); + $series3->getFont()->getColor()->setRGB('FF0000'); + $series3->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF804DC0')); + $series3->setShowValue(true); + $series3->setShowPercentage(false); + $StackedBarChart->addSeries($series1); + $StackedBarChart->addSeries($series2); + $StackedBarChart->addSeries($series3); + $StackedBarChart->setBarGrouping(Bar::GROUPING_STACKED); // Create a shape (chart) - echo date( 'H:i:s' ) . ' Create a shape (chart)' . EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); - $shape->setName( 'PHPPresentation Monthly Downloads' ) - ->setResizeProportional( false ) - ->setHeight( 550 ) - ->setWidth( 700 ) - ->setOffsetX( 120 ) - ->setOffsetY( 80 ); - $shape->setShadow( $oShadow ); - $shape->setFill( $oFill ); - $shape->getBorder()->setLineStyle( Border::LINE_SINGLE ); - $shape->getTitle()->setText( 'PHPPresentation Monthly Downloads' ); - $shape->getTitle()->getFont()->setItalic( true ); - $shape->getTitle()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_RIGHT ); - $shape->getPlotArea()->getAxisX()->setTitle( 'Month' ); - $shape->getPlotArea()->getAxisY()->setTitle( 'Downloads' ); - $shape->getPlotArea()->setType( $StackedBarChart ); - $shape->getLegend()->getBorder()->setLineStyle( Border::LINE_SINGLE ); - $shape->getLegend()->getFont()->setItalic( true ); + $shape->setName('PHPPresentation Monthly Downloads') + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); + $shape->setShadow($oShadow); + $shape->setFill($oFill); + $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getTitle()->setText('PHPPresentation Monthly Downloads'); + $shape->getTitle()->getFont()->setItalic(true); + $shape->getTitle()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); + $shape->getPlotArea()->getAxisX()->setTitle('Month'); + $shape->getPlotArea()->getAxisY()->setTitle('Downloads'); + $shape->getPlotArea()->setType($StackedBarChart); + $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_BarPercentStacked(PhpPresentation $objPHPPresentation) { +function fnSlide_BarPercentStacked(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Create templated slide - echo EOL . date( 'H:i:s' ) . ' Create templated slide' . EOL; - $currentSlide = createTemplatedSlide( $objPHPPresentation ); + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; + $currentSlide = createTemplatedSlide($objPHPPresentation); // Generate sample data for first chart - echo date( 'H:i:s' ) . ' Generate sample data for chart' . EOL; - $series1Data = array('Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293); + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $series1Data = ['Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293]; $Series1Sum = array_sum($series1Data); foreach ($series1Data as $CatName => $Value) { - $series1Data[$CatName]= round($Value / $Series1Sum, 2); + $series1Data[$CatName] = round($Value / $Series1Sum, 2); } - $series2Data = array('Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379); + $series2Data = ['Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379]; $Series2Sum = array_sum($series2Data); foreach ($series2Data as $CatName => $Value) { $series2Data[$CatName] = round($Value / $Series2Sum, 2); } - $series3Data = array('Jan' => 233, 'Feb' => 146, 'Mar' => 238, 'Apr' => 175, 'May' => 108, 'Jun' => 257, 'Jul' => 199, 'Aug' => 201, 'Sep' => 88, 'Oct' => 147, 'Nov' => 287, 'Dec' => 105); - $Series3Sum = array_sum( $series3Data ); + $series3Data = ['Jan' => 233, 'Feb' => 146, 'Mar' => 238, 'Apr' => 175, 'May' => 108, 'Jun' => 257, 'Jul' => 199, 'Aug' => 201, 'Sep' => 88, 'Oct' => 147, 'Nov' => 287, 'Dec' => 105]; + $Series3Sum = array_sum($series3Data); foreach ($series3Data as $CatName => $Value) { - $series3Data[$CatName] = round($Value / $Series3Sum,2); + $series3Data[$CatName] = round($Value / $Series3Sum, 2); } // Create a bar chart (that should be inserted in a shape) - echo date( 'H:i:s' ) . ' Create a percent stacked horizontal bar chart (that should be inserted in a chart shape)' . EOL; + echo date('H:i:s') . ' Create a percent stacked horizontal bar chart (that should be inserted in a chart shape)' . EOL; $PercentStackedBarChartHoriz = new Bar(); - $series1 = new Series( '2009', $series1Data ); - $series1->setShowSeriesName( false ); - $series1->getFill()->setFillType( Fill::FILL_SOLID )->setStartColor( new Color( 'FF4F81BD' ) ); - $series1->getFont()->getColor()->setRGB( '00FF00' ); - $series1->setShowValue( true ); - $series1->setShowPercentage( false ); + $series1 = new Series('2009', $series1Data); + $series1->setShowSeriesName(false); + $series1->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4F81BD')); + $series1->getFont()->getColor()->setRGB('00FF00'); + $series1->setShowValue(true); + $series1->setShowPercentage(false); // Set Data Label Format For Chart To Display Percent - $series1->setDlblNumFormat( '#%' ); - $series2 = new Series( '2010', $series2Data ); - $series2->setShowSeriesName( false ); - $series2->getFont()->getColor()->setRGB( 'FF0000' ); - $series2->getFill()->setFillType( Fill::FILL_SOLID )->setStartColor( new Color( 'FFC0504D' ) ); - $series2->setShowValue( true ); - $series2->setShowPercentage( false ); - $series2->setDlblNumFormat( '#%' ); - $series3 = new Series( '2011', $series3Data ); - $series3->setShowSeriesName( false ); - $series3->getFont()->getColor()->setRGB( 'FF0000' ); - $series3->getFill()->setFillType( Fill::FILL_SOLID )->setStartColor( new Color( 'FF804DC0' ) ); - $series3->setShowValue( true ); - $series3->setShowPercentage( false ); - $series3->setDlblNumFormat( '#%' ); - $PercentStackedBarChartHoriz->addSeries( $series1 ); - $PercentStackedBarChartHoriz->addSeries( $series2 ); - $PercentStackedBarChartHoriz->addSeries( $series3 ); - $PercentStackedBarChartHoriz->setBarGrouping( Bar::GROUPING_PERCENTSTACKED ); - $PercentStackedBarChartHoriz->setBarDirection( Bar3D::DIRECTION_HORIZONTAL ); + $series1->setDlblNumFormat('#%'); + $series2 = new Series('2010', $series2Data); + $series2->setShowSeriesName(false); + $series2->getFont()->getColor()->setRGB('FF0000'); + $series2->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFC0504D')); + $series2->setShowValue(true); + $series2->setShowPercentage(false); + $series2->setDlblNumFormat('#%'); + $series3 = new Series('2011', $series3Data); + $series3->setShowSeriesName(false); + $series3->getFont()->getColor()->setRGB('FF0000'); + $series3->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF804DC0')); + $series3->setShowValue(true); + $series3->setShowPercentage(false); + $series3->setDlblNumFormat('#%'); + $PercentStackedBarChartHoriz->addSeries($series1); + $PercentStackedBarChartHoriz->addSeries($series2); + $PercentStackedBarChartHoriz->addSeries($series3); + $PercentStackedBarChartHoriz->setBarGrouping(Bar::GROUPING_PERCENTSTACKED); + $PercentStackedBarChartHoriz->setBarDirection(Bar3D::DIRECTION_HORIZONTAL); // Create a shape (chart) - echo date( 'H:i:s' ) . ' Create a shape (chart)' . EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); - $shape->setName( 'PHPPresentation Monthly Downloads' ) - ->setResizeProportional( false ) - ->setHeight( 550 ) - ->setWidth( 700 ) - ->setOffsetX( 120 ) - ->setOffsetY( 80 ); - $shape->setShadow( $oShadow ); - $shape->setFill( $oFill ); - $shape->getBorder()->setLineStyle( Border::LINE_SINGLE ); - $shape->getTitle()->setText( 'PHPPresentation Monthly Downloads' ); - $shape->getTitle()->getFont()->setItalic( true ); - $shape->getTitle()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_RIGHT ); - $shape->getPlotArea()->getAxisX()->setTitle( 'Month' ); - $shape->getPlotArea()->getAxisY()->setTitle( 'Downloads' ); - $shape->getPlotArea()->setType( $PercentStackedBarChartHoriz ); - $shape->getLegend()->getBorder()->setLineStyle( Border::LINE_SINGLE ); - $shape->getLegend()->getFont()->setItalic( true ); + $shape->setName('PHPPresentation Monthly Downloads') + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); + $shape->setShadow($oShadow); + $shape->setFill($oFill); + $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getTitle()->setText('PHPPresentation Monthly Downloads'); + $shape->getTitle()->getFont()->setItalic(true); + $shape->getTitle()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); + $shape->getPlotArea()->getAxisX()->setTitle('Month'); + $shape->getPlotArea()->getAxisY()->setTitle('Downloads'); + $shape->getPlotArea()->setType($PercentStackedBarChartHoriz); + $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_Bar3D(PhpPresentation $objPHPPresentation) { +function fnSlide_Bar3D(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // Generate sample data for first chart - echo date('H:i:s') . ' Generate sample data for chart'.EOL; - $series1Data = array('Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293); - $series2Data = array('Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379); + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $series1Data = ['Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293]; + $series2Data = ['Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379]; // Create a bar chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a bar chart (that should be inserted in a chart shape)'.EOL; + echo date('H:i:s') . ' Create a bar chart (that should be inserted in a chart shape)' . EOL; $bar3DChart = new Bar3D(); $series1 = new Series('2009', $series1Data); $series1->setShowSeriesName(true); @@ -322,7 +332,7 @@ function fnSlide_Bar3D(PhpPresentation $objPHPPresentation) { $bar3DChart->addSeries($series2); // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Monthly Downloads') ->setResizeProportional(false) @@ -346,28 +356,29 @@ function fnSlide_Bar3D(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_Bar3DHorizontal(PhpPresentation $objPHPPresentation) { +function fnSlide_Bar3DHorizontal(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; - + // Create a bar chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a horizontal bar chart (that should be inserted in a chart shape) '.EOL; + echo date('H:i:s') . ' Create a horizontal bar chart (that should be inserted in a chart shape) ' . EOL; $bar3DChartHorz = clone $objPHPPresentation->getSlide(5)->getShapeCollection()->offsetGet(1)->getPlotArea()->getType(); $bar3DChartHorz->setBarDirection(Bar3D::DIRECTION_HORIZONTAL); - + // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); - + // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Monthly Downloads') - ->setResizeProportional(false) - ->setHeight(550) - ->setWidth(700) - ->setOffsetX(120) - ->setOffsetY(80); + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); $shape->setShadow($oShadow); $shape->setFill($oFill); $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); @@ -384,20 +395,76 @@ function fnSlide_Bar3DHorizontal(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_Pie3D(PhpPresentation $objPHPPresentation) { +function fnSlide_Doughnut(PhpPresentation $objPHPPresentation) +{ + global $oFill; + global $oShadow; + + // Create templated slide + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; + $currentSlide = createTemplatedSlide($objPHPPresentation); + + // Generate sample data for second chart + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $seriesData = ['Monday' => 18, 'Tuesday' => 23, 'Wednesday' => 14, 'Thursday' => 12, 'Friday' => 20, 'Saturday' => 8, 'Sunday' => 10]; + + // Create a doughnut chart (that should be inserted in a shape) + echo date('H:i:s') . ' Create a non-3D Doughnut chart (that should be inserted in a chart shape)' . EOL; + $doughnutChart = new Doughnut(); + $doughnutChart->setHoleSize(43); + $series = new Series('Downloads', $seriesData); + $series->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF7CB5EC')); + $series->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF434348')); + $series->getDataPointFill(2)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF90ED7D')); + $series->getDataPointFill(3)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFF7A35C')); + $series->getDataPointFill(4)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF8085E9')); + $series->getDataPointFill(5)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFF15C80')); + $series->getDataPointFill(6)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFE4D354')); + $series->setShowPercentage(true); + $series->setShowValue(false); + $series->setShowSeriesName(false); + $series->setShowCategoryName(true); + $series->setDlblNumFormat('%d'); + $series->setSeparator(' > '); + $series->getFont()->getColor()->setRGB('FFFF00'); + $series->getFont()->setBold(true); + $doughnutChart->addSeries($series); + + // Create a shape (chart) + echo date('H:i:s') . ' Create a shape (chart)' . EOL; + $shape = $currentSlide->createChartShape(); + $shape->setName('PHPPresentation Daily Downloads') + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); + $shape->setShadow($oShadow); + $shape->setFill($oFill); + $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getTitle()->setText('PHPPresentation Daily Downloads'); + $shape->getTitle()->getFont()->setItalic(true); + $shape->getPlotArea()->setType($doughnutChart); + $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getLegend()->getFont()->setItalic(true); + $shape->getLegend()->setPosition(Legend::POSITION_LEFT); +} + +function fnSlide_Pie3D(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; - + // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); - + // Generate sample data for second chart - echo date('H:i:s') . ' Generate sample data for chart'.EOL; - $seriesData = array('Monday' => 12, 'Tuesday' => 15, 'Wednesday' => 13, 'Thursday' => 17, 'Friday' => 14, 'Saturday' => 9, 'Sunday' => 7); - + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $seriesData = ['Monday' => 12, 'Tuesday' => 15, 'Wednesday' => 13, 'Thursday' => 17, 'Friday' => 14, 'Saturday' => 9, 'Sunday' => 7]; + // Create a pie chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a pie chart (that should be inserted in a chart shape)'.EOL; + echo date('H:i:s') . ' Create a pie chart (that should be inserted in a chart shape)' . EOL; $pie3DChart = new Pie3D(); $pie3DChart->setExplosion(20); $series = new Series('Downloads', $seriesData); @@ -412,14 +479,14 @@ function fnSlide_Pie3D(PhpPresentation $objPHPPresentation) { $pie3DChart->addSeries($series); // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Daily Downloads') - ->setResizeProportional(false) - ->setHeight(550) - ->setWidth(700) - ->setOffsetX(120) - ->setOffsetY(80); + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); $shape->setShadow($oShadow); $shape->setFill($oFill); $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); @@ -432,20 +499,21 @@ function fnSlide_Pie3D(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_Pie(PhpPresentation $objPHPPresentation) { +function fnSlide_Pie(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // Generate sample data for second chart - echo date('H:i:s') . ' Generate sample data for chart'.EOL; - $seriesData = array('Monday' => 18, 'Tuesday' => 23, 'Wednesday' => 14, 'Thursday' => 12, 'Friday' => 20, 'Saturday' => 8, 'Sunday' => 10); + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $seriesData = ['Monday' => 18, 'Tuesday' => 23, 'Wednesday' => 14, 'Thursday' => 12, 'Friday' => 20, 'Saturday' => 8, 'Sunday' => 10]; // Create a pie chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a non-3D pie chart (that should be inserted in a chart shape)'.EOL; + echo date('H:i:s') . ' Create a non-3D pie chart (that should be inserted in a chart shape)' . EOL; $pieChart = new Pie(); $pieChart->setExplosion(15); $series = new Series('Downloads', $seriesData); @@ -456,22 +524,22 @@ function fnSlide_Pie(PhpPresentation $objPHPPresentation) { $series->getDataPointFill(4)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF8085E9')); $series->getDataPointFill(5)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFF15C80')); $series->getDataPointFill(6)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFE4D354')); - $series->setShowPercentage( true ); - $series->setShowValue( false ); - $series->setShowSeriesName( false ); - $series->setShowCategoryName( true ); + $series->setShowPercentage(true); + $series->setShowValue(false); + $series->setShowSeriesName(false); + $series->setShowCategoryName(true); $series->setDlblNumFormat('%d'); $pieChart->addSeries($series); // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Daily Downloads') - ->setResizeProportional(false) - ->setHeight(550) - ->setWidth(700) - ->setOffsetX(120) - ->setOffsetY(80); + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); $shape->setShadow($oShadow); $shape->setFill($oFill); $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); @@ -482,29 +550,93 @@ function fnSlide_Pie(PhpPresentation $objPHPPresentation) { $shape->getLegend()->getFont()->setItalic(true); } -function fnSlide_Scatter(PhpPresentation $objPHPPresentation) { +function fnSlide_Radar(PhpPresentation $objPHPPresentation) +{ global $oFill; global $oShadow; - + // Create templated slide - echo EOL.date('H:i:s') . ' Create templated slide'.EOL; + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // local function - + // Generate sample data for fourth chart - echo date('H:i:s') . ' Generate sample data for chart'.EOL; - $seriesData = array('Monday' => 0.1, 'Tuesday' => 0.33333, 'Wednesday' => 0.4444, 'Thursday' => 0.5, 'Friday' => 0.4666, 'Saturday' => 0.3666, 'Sunday' => 0.1666); - + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $seriesData = ['Monday' => 0.1, 'Tuesday' => 0.33333, 'Wednesday' => 0.4444, 'Thursday' => 0.5, 'Friday' => 0.4666, 'Saturday' => 0.3666, 'Sunday' => 0.1666]; + // Create a scatter chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a scatter chart (that should be inserted in a chart shape)'.EOL; + echo date('H:i:s') . ' Create a radar chart (that should be inserted in a chart shape)' . EOL; + $oChart = new Radar(); + $series = new Series('Downloads', $seriesData); + $series->setShowSeriesName(true); + $series->getMarker()->setSymbol(Marker::SYMBOL_DASH); + $series->getMarker()->setSize(10); + $oChart->addSeries($series); + + // Create a shape (chart) + echo date('H:i:s') . ' Create a shape (chart)' . EOL; + $shape = $currentSlide->createChartShape(); + $shape->setName('PHPPresentation Daily Download Distribution') + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80); + $shape->setShadow($oShadow); + $shape->setFill($oFill); + $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getTitle()->setText('PHPPresentation Daily Downloads'); + $shape->getTitle()->getFont()->setItalic(true); + $shape->getPlotArea()->setType($oChart); + $shape->getView3D()->setRotationX(30); + $shape->getView3D()->setPerspective(30); + $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); + $shape->getLegend()->getFont()->setItalic(true); + + $oGridlines = new Gridlines(); + $oGridlines->getOutline() + ->setWidth(1) + ->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color(Color::COLOR_RED)); // FF0000 + $shape->getPlotArea()->getAxisY() + ->setMajorGridlines($oGridlines) + ->getOutline() + ->setWidth(2) + ->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color(Color::COLOR_BLUE)); // 0000FF +} + +function fnSlide_Scatter(PhpPresentation $objPHPPresentation) +{ + global $oFill; + global $oShadow; + + // Create templated slide + echo EOL . date('H:i:s') . ' Create templated slide' . EOL; + $currentSlide = createTemplatedSlide($objPHPPresentation); // local function + + // Generate sample data for fourth chart + echo date('H:i:s') . ' Generate sample data for chart' . EOL; + $seriesData = ['Monday' => 0.1, 'Tuesday' => 0.33333, 'Wednesday' => 0.4444, 'Thursday' => 0.5, 'Friday' => 0.4666, 'Saturday' => 0.3666, 'Sunday' => 0.1666]; + + // Create a scatter chart (that should be inserted in a shape) + echo date('H:i:s') . ' Create a scatter chart (that should be inserted in a chart shape)' . EOL; $lineChart = new Scatter(); + $lineChart->setIsSmooth(true); $series = new Series('Downloads', $seriesData); $series->setShowSeriesName(true); - $series->getMarker()->setSymbol(\PhpOffice\PhpPresentation\Shape\Chart\Marker::SYMBOL_DASH); + $series->getMarker()->setSymbol(Marker::SYMBOL_CIRCLE); + $series->getMarker()->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color('FF6F3510')) + ->setEndColor(new Color('FF6F3510')); + $series->getMarker()->getBorder()->getColor()->setRGB('FF0000'); $series->getMarker()->setSize(10); $lineChart->addSeries($series); - + // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; + echo date('H:i:s') . ' Create a shape (chart)' . EOL; $shape = $currentSlide->createChartShape(); $shape->setName('PHPPresentation Daily Download Distribution') ->setResizeProportional(false) @@ -525,21 +657,21 @@ function fnSlide_Scatter(PhpPresentation $objPHPPresentation) { } // Create new PHPPresentation object -echo date('H:i:s') . ' Create new PHPPresentation object'.EOL; +echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 07 Title') - ->setSubject('Sample 07 Subject') - ->setDescription('Sample 07 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 07 Title') + ->setSubject('Sample 07 Subject') + ->setDescription('Sample 07 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Remove first slide -echo date('H:i:s') . ' Remove first slide'.EOL; +echo date('H:i:s') . ' Remove first slide' . EOL; $objPHPPresentation->removeSlideByIndex(0); // Set Style @@ -563,10 +695,14 @@ function fnSlide_Scatter(PhpPresentation $objPHPPresentation) { fnSlide_Bar3DHorizontal($objPHPPresentation); +fnSlide_Doughnut($objPHPPresentation); + fnSlide_Pie3D($objPHPPresentation); fnSlide_Pie($objPHPPresentation); +fnSlide_Radar($objPHPPresentation); + fnSlide_Scatter($objPHPPresentation); // Save file diff --git a/samples/Sample_05_Chart_Line.php b/samples/Sample_05_Chart_Line.php index d9f1529b0d..f87aad8c31 100644 --- a/samples/Sample_05_Chart_Line.php +++ b/samples/Sample_05_Chart_Line.php @@ -3,11 +3,15 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Line; +use PhpOffice\PhpPresentation\Shape\Chart; +use PhpOffice\PhpPresentation\Shape\Chart\Gridlines; +use PhpOffice\PhpPresentation\Shape\Chart\Marker; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Line; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Fill; +use PhpOffice\PhpPresentation\Style\Outline; use PhpOffice\PhpPresentation\Style\Shadow; // Create new PHPPresentation object @@ -31,15 +35,22 @@ // Generate sample data for chart echo date('H:i:s') . ' Generate sample data for chart' . EOL; -$seriesData = array( - 'Monday' => 12, - 'Tuesday' => 15, - 'Wednesday' => 13, - 'Thursday' => 17, - 'Friday' => 14, - 'Saturday' => 9, - 'Sunday' => 7 -); +$seriesData = [ + 'Monday 01' => 12, + 'Tuesday 02' => 15, + 'Wednesday 03' => 13, + 'Thursday 04' => 17, + 'Friday 05' => 14, + 'Saturday 06' => 9, + 'Sunday 07' => 7, + 'Monday 08' => 8, + 'Tuesday 09' => 8, + 'Wednesday 10' => 15, + 'Thursday 11' => 16, + 'Friday 12' => 14, + 'Saturday 13' => 14, + 'Sunday 14' => 13, +]; // Create templated slide echo EOL . date('H:i:s') . ' Create templated slide' . EOL; @@ -67,13 +78,15 @@ $shape->getView3D()->setPerspective(30); $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); $shape->getLegend()->getFont()->setItalic(true); +$shape->getPlotArea()->getAxisX()->setMajorUnit(3); +$shape->getPlotArea()->getAxisY()->setMajorUnit(5); // Create templated slide echo EOL . date('H:i:s') . ' Create templated slide' . EOL; $currentSlide = createTemplatedSlide($objPHPPresentation); // Create a line chart (that should be inserted in a shape) -$oOutline = new \PhpOffice\PhpPresentation\Style\Outline(); +$oOutline = new Outline(); $oOutline->getFill()->setFillType(Fill::FILL_SOLID); $oOutline->getFill()->setStartColor(new Color(Color::COLOR_YELLOW)); $oOutline->setWidth(2); @@ -82,7 +95,7 @@ $lineChart1 = clone $lineChart; $series1 = $lineChart1->getSeries(); $series1[0]->setOutline($oOutline); -$series1[0]->getMarker()->setSymbol(\PhpOffice\PhpPresentation\Shape\Chart\Marker::SYMBOL_DIAMOND); +$series1[0]->getMarker()->setSymbol(Marker::SYMBOL_DIAMOND); $series1[0]->getMarker()->setSize(7); $lineChart1->setSeries($series1); @@ -106,7 +119,7 @@ $lineChart2 = clone $lineChart; $series2 = $lineChart2->getSeries(); $series2[0]->getFont()->setSize(25); -$series2[0]->getMarker()->setSymbol(\PhpOffice\PhpPresentation\Shape\Chart\Marker::SYMBOL_TRIANGLE); +$series2[0]->getMarker()->setSymbol(Marker::SYMBOL_TRIANGLE); $series2[0]->getMarker()->setSize(10); $lineChart2->setSeries($series2); @@ -129,11 +142,11 @@ echo date('H:i:s') . ' Create a line chart (that should be inserted in a chart shape)' . EOL; $lineChart3 = clone $lineChart; -$oGridLines1 = new \PhpOffice\PhpPresentation\Shape\Chart\Gridlines(); +$oGridLines1 = new Gridlines(); $oGridLines1->getOutline()->setWidth(10); $oGridLines1->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); -$oGridLines2 = new \PhpOffice\PhpPresentation\Shape\Chart\Gridlines(); +$oGridLines2 = new Gridlines(); $oGridLines2->getOutline()->setWidth(1); $oGridLines2->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKGREEN)); @@ -156,12 +169,12 @@ echo date('H:i:s') . ' Create a line chart (that should be inserted in a chart shape)' . EOL; $lineChart4 = clone $lineChart; -$oOutlineAxisX = new \PhpOffice\PhpPresentation\Style\Outline(); +$oOutlineAxisX = new Outline(); $oOutlineAxisX->setWidth(2); $oOutlineAxisX->getFill()->setFillType(Fill::FILL_SOLID); $oOutlineAxisX->getFill()->getStartColor()->setRGB('012345'); -$oOutlineAxisY = new \PhpOffice\PhpPresentation\Style\Outline(); +$oOutlineAxisY = new Outline(); $oOutlineAxisY->setWidth(5); $oOutlineAxisY->getFill()->setFillType(Fill::FILL_SOLID); $oOutlineAxisY->getFill()->getStartColor()->setRGB('ABCDEF'); @@ -174,7 +187,9 @@ $shape4->getTitle()->setText('Chart with Outline on Axis'); $shape4->getPlotArea()->setType($lineChart4); $shape4->getPlotArea()->getAxisX()->setOutline($oOutlineAxisX); +$shape4->getPlotArea()->getAxisX()->setTitleRotation(45); $shape4->getPlotArea()->getAxisY()->setOutline($oOutlineAxisY); +$shape4->getPlotArea()->getAxisY()->setTitleRotation(135); $currentSlide->addShape($shape4); // Create templated slide @@ -188,6 +203,26 @@ $shape5->getPlotArea()->getAxisY()->setMinBounds(5); $shape5->getPlotArea()->getAxisY()->setMaxBounds(20); $currentSlide->addShape($shape5); + +// Create templated slide +echo EOL . date('H:i:s') . ' Create templated slide #6' . EOL; +$currentSlide = createTemplatedSlide($objPHPPresentation); + +// Create a shape (chart) +echo date('H:i:s') . ' Create a shape (chart6)' . EOL; +echo date('H:i:s') . ' Feature : DisplayBlankAs' . EOL; +$shape6 = clone $shape; +$lineChart6 = clone $lineChart; +$series6 = clone $series; +$seriesData6 = $seriesData; +$seriesData6['Thursday'] = null; + +$series6->setValues($seriesData6); +$lineChart6->setSeries([$series6]); +$shape6->getPlotArea()->setType($lineChart6); +$shape6->setDisplayBlankAs(Chart::BLANKAS_GAP); +$currentSlide->addShape($shape6); + // Save file echo EOL . write($objPHPPresentation, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_05_Chart_with_PHPExcel.php b/samples/Sample_05_Chart_with_PHPExcel.php deleted file mode 100644 index e10a4eda43..0000000000 --- a/samples/Sample_05_Chart_with_PHPExcel.php +++ /dev/null @@ -1,122 +0,0 @@ -PHPExcel has not been loaded. Include PHPExcel.php in your script, e.g. require_once \'PHPExcel.php\'.'); -} else { - // Create new PHPPresentation object - echo date('H:i:s') . ' Create new PHPPresentation object'.EOL; - $objPHPPresentation = new PhpPresentation(); - - // Set properties - echo date('H:i:s') . ' Set properties'.EOL; - $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 08 Title') - ->setSubject('Sample 08 Subject') - ->setDescription('Sample 08 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); - - // Remove first slide - echo date('H:i:s') . ' Remove first slide'.EOL; - $objPHPPresentation->removeSlideByIndex(0); - - // Create templated slide - echo date('H:i:s') . ' Create templated slide'.EOL; - $currentSlide = createTemplatedSlide($objPHPPresentation); // local function - - // Generate sample data for first chart - echo date('H:i:s') . ' Generate sample data for first chart'.EOL; - $series1Data = array('Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293); - $series2Data = array('Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379); - - // Create a bar chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a bar chart (that should be inserted in a chart shape)'.EOL; - $bar3DChart = new Bar3D(); - $bar3DChart->addSeries( new Series('2009', $series1Data) ); - $bar3DChart->addSeries( new Series('2010', $series2Data) ); - - // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; - $shape = $currentSlide->createChartShape(); - $shape->setName('PHPPresentation Monthly Downloads') - ->setResizeProportional(false) - ->setHeight(550) - ->setWidth(700) - ->setOffsetX(120) - ->setOffsetY(80) - ->setIncludeSpreadsheet(true); - $shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - $shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setStartColor(new Color('FFCCCCCC')) - ->setEndColor(new Color('FFFFFFFF')) - ->setRotation(270); - $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); - $shape->getTitle()->setText('PHPPresentation Monthly Downloads'); - $shape->getTitle()->getFont()->setItalic(true); - $shape->getPlotArea()->getAxisX()->setTitle('Month'); - $shape->getPlotArea()->getAxisY()->setTitle('Downloads'); - $shape->getPlotArea()->setType($bar3DChart); - $shape->getView3D()->setRightAngleAxes(true); - $shape->getView3D()->setRotationX(20); - $shape->getView3D()->setRotationY(20); - $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); - $shape->getLegend()->getFont()->setItalic(true); - - // Create templated slide - echo date('H:i:s') . ' Create templated slide'.EOL; - $currentSlide = createTemplatedSlide($objPHPPresentation); // local function - - // Generate sample data for second chart - echo date('H:i:s') . ' Generate sample data for second chart'.EOL; - $seriesData = array('Monday' => 12, 'Tuesday' => 15, 'Wednesday' => 13, 'Thursday' => 17, 'Friday' => 14, 'Saturday' => 9, 'Sunday' => 7); - - // Create a pie chart (that should be inserted in a shape) - echo date('H:i:s') . ' Create a pie chart (that should be inserted in a chart shape)'.EOL; - $pie3DChart = new Pie3D(); - $pie3DChart->addSeries( new Series('Downloads', $seriesData) ); - - // Create a shape (chart) - echo date('H:i:s') . ' Create a shape (chart)'.EOL; - $shape = $currentSlide->createChartShape(); - $shape->setName('PHPPresentation Daily Downloads') - ->setResizeProportional(false) - ->setHeight(550) - ->setWidth(700) - ->setOffsetX(120) - ->setOffsetY(80) - ->setIncludeSpreadsheet(true); - $shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - $shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setStartColor(new Color('FFCCCCCC')) - ->setEndColor(new Color('FFFFFFFF')) - ->setRotation(270); - $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); - $shape->getTitle()->setText('PHPPresentation Daily Downloads'); - $shape->getTitle()->getFont()->setItalic(true); - $shape->getPlotArea()->setType($pie3DChart); - $shape->getView3D()->setRotationX(30); - $shape->getView3D()->setPerspective(30); - $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); - $shape->getLegend()->getFont()->setItalic(true); - - // Save file - echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); -} -if (!CLI) { - include_once 'Sample_Footer.php'; -} diff --git a/samples/Sample_05_Chart_with_PhpSpreadsheet.php b/samples/Sample_05_Chart_with_PhpSpreadsheet.php new file mode 100644 index 0000000000..bdbf79e75c --- /dev/null +++ b/samples/Sample_05_Chart_with_PhpSpreadsheet.php @@ -0,0 +1,119 @@ +getDocumentProperties()->setCreator('PHPOffice') + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 08 Title') + ->setSubject('Sample 08 Subject') + ->setDescription('Sample 08 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); + +// Remove first slide +echo date('H:i:s') . ' Remove first slide' . EOL; +$objPHPPresentation->removeSlideByIndex(0); + +// Create templated slide +echo date('H:i:s') . ' Create templated slide' . EOL; +$currentSlide = createTemplatedSlide($objPHPPresentation); // local function + +// Generate sample data for first chart +echo date('H:i:s') . ' Generate sample data for first chart' . EOL; +$series1Data = ['Jan' => 133, 'Feb' => 99, 'Mar' => 191, 'Apr' => 205, 'May' => 167, 'Jun' => 201, 'Jul' => 240, 'Aug' => 226, 'Sep' => 255, 'Oct' => 264, 'Nov' => 283, 'Dec' => 293]; +$series2Data = ['Jan' => 266, 'Feb' => 198, 'Mar' => 271, 'Apr' => 305, 'May' => 267, 'Jun' => 301, 'Jul' => 340, 'Aug' => 326, 'Sep' => 344, 'Oct' => 364, 'Nov' => 383, 'Dec' => 379]; + +// Create a bar chart (that should be inserted in a shape) +echo date('H:i:s') . ' Create a bar chart (that should be inserted in a chart shape)' . EOL; +$bar3DChart = new Bar3D(); +$bar3DChart->addSeries(new Series('2009', $series1Data)); +$bar3DChart->addSeries(new Series('2010', $series2Data)); + +// Create a shape (chart) +echo date('H:i:s') . ' Create a shape (chart)' . EOL; +$shape = $currentSlide->createChartShape(); +$shape->setName('PHPPresentation Monthly Downloads') + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80) + ->setIncludeSpreadsheet(true); +$shape->getShadow()->setVisible(true) + ->setDirection(45) + ->setDistance(10); +$shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) + ->setStartColor(new Color('FFCCCCCC')) + ->setEndColor(new Color('FFFFFFFF')) + ->setRotation(270); +$shape->getBorder()->setLineStyle(Border::LINE_SINGLE); +$shape->getTitle()->setText('PHPPresentation Monthly Downloads'); +$shape->getTitle()->getFont()->setItalic(true); +$shape->getPlotArea()->getAxisX()->setTitle('Month'); +$shape->getPlotArea()->getAxisY()->setTitle('Downloads'); +$shape->getPlotArea()->setType($bar3DChart); +$shape->getView3D()->setRightAngleAxes(true); +$shape->getView3D()->setRotationX(20); +$shape->getView3D()->setRotationY(20); +$shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); +$shape->getLegend()->getFont()->setItalic(true); + +// Create templated slide +echo date('H:i:s') . ' Create templated slide' . EOL; +$currentSlide = createTemplatedSlide($objPHPPresentation); // local function + +// Generate sample data for second chart +echo date('H:i:s') . ' Generate sample data for second chart' . EOL; +$seriesData = ['Monday' => 12, 'Tuesday' => 15, 'Wednesday' => 13, 'Thursday' => 17, 'Friday' => 14, 'Saturday' => 9, 'Sunday' => 7]; + +// Create a pie chart (that should be inserted in a shape) +echo date('H:i:s') . ' Create a pie chart (that should be inserted in a chart shape)' . EOL; +$pie3DChart = new Pie3D(); +$pie3DChart->addSeries(new Series('Downloads', $seriesData)); + +// Create a shape (chart) +echo date('H:i:s') . ' Create a shape (chart)' . EOL; +$shape = $currentSlide->createChartShape(); +$shape->setName('PHPPresentation Daily Downloads') + ->setResizeProportional(false) + ->setHeight(550) + ->setWidth(700) + ->setOffsetX(120) + ->setOffsetY(80) + ->setIncludeSpreadsheet(true); +$shape->getShadow()->setVisible(true) + ->setDirection(45) + ->setDistance(10); +$shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) + ->setStartColor(new Color('FFCCCCCC')) + ->setEndColor(new Color('FFFFFFFF')) + ->setRotation(270); +$shape->getBorder()->setLineStyle(Border::LINE_SINGLE); +$shape->getTitle()->setText('PHPPresentation Daily Downloads'); +$shape->getTitle()->getFont()->setItalic(true); +$shape->getPlotArea()->setType($pie3DChart); +$shape->getView3D()->setRotationX(30); +$shape->getView3D()->setPerspective(30); +$shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); +$shape->getLegend()->getFont()->setItalic(true); + +// Save file +echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); + +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_06_Fill.php b/samples/Sample_06_Fill.php index 563f00baff..e917a34f90 100644 --- a/samples/Sample_06_Fill.php +++ b/samples/Sample_06_Fill.php @@ -12,57 +12,56 @@ $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 01 Title') - ->setSubject('Sample 01 Subject') - ->setDescription('Sample 01 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 01 Title') + ->setSubject('Sample 01 Subject') + ->setDescription('Sample 01 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = $objPHPPresentation->getActiveSlide(); - -for($inc = 1 ; $inc <= 4 ; $inc++){ +for ($inc = 1; $inc <= 4; ++$inc) { // Create a shape (text) - echo date('H:i:s') . ' Create a shape (rich text)'.EOL; + echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentSlide->createRichTextShape() - ->setHeight(200) - ->setWidth(300); - if($inc == 1 || $inc == 3){ + ->setHeight(200) + ->setWidth(300); + if (1 == $inc || 3 == $inc) { $shape->setOffsetX(10); } else { $shape->setOffsetX(320); } - if($inc == 1 || $inc == 2){ + if (1 == $inc || 2 == $inc) { $shape->setOffsetY(10); } else { $shape->setOffsetY(220); } - $shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); - + $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + switch ($inc) { - case 1 : + case 1: $shape->getFill()->setFillType(Fill::FILL_NONE); break; - case 2 : - $shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR)->setRotation(90)->setStartColor(new Color( 'FF4672A8' ))->setEndColor(new Color( 'FF000000' )); + case 2: + $shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF000000')); break; - case 3 : - $shape->getFill()->setFillType(Fill::FILL_GRADIENT_PATH)->setRotation(90)->setStartColor(new Color( 'FF4672A8' ))->setEndColor(new Color( 'FF000000' )); + case 3: + $shape->getFill()->setFillType(Fill::FILL_GRADIENT_PATH)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF000000')); break; - case 4 : - $shape->getFill()->setFillType(Fill::FILL_SOLID)->setRotation(90)->setStartColor(new Color( 'FF4672A8' ))->setEndColor(new Color( 'FF4672A8' )); + case 4: + $shape->getFill()->setFillType(Fill::FILL_SOLID)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF4672A8')); break; } - + $textRun = $shape->createTextRun('Use PHPPresentation!'); $textRun->getFont()->setBold(true) - ->setSize(30) - ->setColor( new Color('FFE06B20') ); + ->setSize(30) + ->setColor(new Color('FFE06B20')); } // Save file diff --git a/samples/Sample_07_Border.php b/samples/Sample_07_Border.php index a6402fd58a..24816fedda 100644 --- a/samples/Sample_07_Border.php +++ b/samples/Sample_07_Border.php @@ -4,9 +4,8 @@ use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Style\Alignment; -use PhpOffice\PhpPresentation\Style\Color; -use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Border; +use PhpOffice\PhpPresentation\Style\Color; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; @@ -20,44 +19,43 @@ echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = $objPHPPresentation->getActiveSlide(); - -for ($inc = 1; $inc <= 4; $inc++) { - // Create a shape (text) - echo date('H:i:s') . ' Create a shape (rich text)' . EOL; - $shape = $currentSlide->createRichTextShape()->setHeight(200)->setWidth(300); - if ($inc == 1 || $inc == 3) { - $shape->setOffsetX(10); - } else { - $shape->setOffsetX(320); - } - if ($inc == 1 || $inc == 2) { - $shape->setOffsetY(10); - } else { - $shape->setOffsetY(220); - } - $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - - switch ($inc) { - case 1: - $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_SOLID)->setLineStyle(Border::LINE_DOUBLE); - break; - case 2: - $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_DASH)->setLineStyle(Border::LINE_SINGLE); - break; - case 3: - $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_DOT)->setLineStyle(Border::LINE_THICKTHIN); - break; - case 4: - $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_LARGEDASHDOT)->setLineStyle(Border::LINE_THINTHICK); - break; - } - - $textRun = $shape->createTextRun('Use PHPPresentation!'); - $textRun->getFont()->setBold(true)->setSize(30)->setColor(new Color('FFE06B20')); +for ($inc = 1; $inc <= 4; ++$inc) { + // Create a shape (text) + echo date('H:i:s') . ' Create a shape (rich text)' . EOL; + $shape = $currentSlide->createRichTextShape()->setHeight(200)->setWidth(300); + if (1 == $inc || 3 == $inc) { + $shape->setOffsetX(10); + } else { + $shape->setOffsetX(320); + } + if (1 == $inc || 2 == $inc) { + $shape->setOffsetY(10); + } else { + $shape->setOffsetY(220); + } + $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); + + switch ($inc) { + case 1: + $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_SOLID)->setLineStyle(Border::LINE_DOUBLE); + break; + case 2: + $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_DASH)->setLineStyle(Border::LINE_SINGLE); + break; + case 3: + $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_DOT)->setLineStyle(Border::LINE_THICKTHIN); + break; + case 4: + $shape->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_LARGEDASHDOT)->setLineStyle(Border::LINE_THINTHICK); + break; + } + + $textRun = $shape->createTextRun('Use PHPPresentation!'); + $textRun->getFont()->setBold(true)->setSize(30)->setColor(new Color('FFE06B20')); } // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_08_Group.php b/samples/Sample_08_Group.php index 55b35f4c33..b87b50b7b5 100644 --- a/samples/Sample_08_Group.php +++ b/samples/Sample_08_Group.php @@ -11,47 +11,47 @@ $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 01 Title') - ->setSubject('Sample 01 Subject') - ->setDescription('Sample 01 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 01 Title') + ->setSubject('Sample 01 Subject') + ->setDescription('Sample 01 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentGroup = $objPHPPresentation->getActiveSlide()->createGroup(); // Create a shape (drawing) -echo date('H:i:s') . ' Create a shape (drawing)'.EOL; +echo date('H:i:s') . ' Create a shape (drawing)' . EOL; $shape = $currentGroup->createDrawingShape(); $shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); + ->setDescription('PHPPresentation logo') + ->setPath('./resources/phppowerpoint_logo.gif') + ->setHeight(36) + ->setOffsetX(10) + ->setOffsetY(10); $shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); + ->setDirection(45) + ->setDistance(10); // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shape = $currentGroup->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); -$shape->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(170) + ->setOffsetY(180); +$shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor( new Color( 'FFE06B20' ) ); + ->setSize(60) + ->setColor(new Color('FFE06B20')); // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_09_SlideNote.php b/samples/Sample_09_SlideNote.php index 0462dc0c0c..8a597dfa08 100644 --- a/samples/Sample_09_SlideNote.php +++ b/samples/Sample_09_SlideNote.php @@ -5,8 +5,6 @@ use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Color; -use PhpOffice\PhpPresentation\Style\Fill; -use PhpOffice\PhpPresentation\Style\Border; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; diff --git a/samples/Sample_10_Transition.php b/samples/Sample_10_Transition.php index 9a760fc97e..58dcbab34b 100644 --- a/samples/Sample_10_Transition.php +++ b/samples/Sample_10_Transition.php @@ -3,54 +3,54 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\Slide\Transition; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Color; -use PhpOffice\PhpPresentation\Slide\Transition; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Set properties -echo date('H:i:s') . ' Set properties'.EOL; +echo date('H:i:s') . ' Set properties' . EOL; $objPHPPresentation->getDocumentProperties()->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 10 Title') - ->setSubject('Sample 10 Subject') - ->setDescription('Sample 10 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 10 Title') + ->setSubject('Sample 10 Subject') + ->setDescription('Sample 10 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $slide0 = $objPHPPresentation->getActiveSlide(); // Create a shape (drawing) -echo date('H:i:s') . ' Create a shape (drawing)'.EOL; +echo date('H:i:s') . ' Create a shape (drawing)' . EOL; $shapeDrawing = $slide0->createDrawingShape(); $shapeDrawing->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); + ->setDescription('PHPPresentation logo') + ->setPath('./resources/phppowerpoint_logo.gif') + ->setHeight(36) + ->setOffsetX(10) + ->setOffsetY(10); $shapeDrawing->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); + ->setDirection(45) + ->setDistance(10); $shapeDrawing->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/')->setTooltip('PHPPresentation'); // Create a shape (text) -echo date('H:i:s') . ' Create a shape (rich text)'.EOL; +echo date('H:i:s') . ' Create a shape (rich text)' . EOL; $shapeRichText = $slide0->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); -$shapeRichText->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); + ->setHeight(300) + ->setWidth(600) + ->setOffsetX(170) + ->setOffsetY(180); +$shapeRichText->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $textRun = $shapeRichText->createTextRun('Thank you for using PHPPresentation!'); $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor( new Color( 'FFE06B20' ) ); + ->setSize(60) + ->setColor(new Color('FFE06B20')); $oTransition = new Transition(); $oTransition->setManualTrigger(false); @@ -59,7 +59,7 @@ $slide0->setTransition($oTransition); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $slide1 = $objPHPPresentation->createSlide(); $slide1->addShape(clone $shapeDrawing); $slide1->addShape(clone $shapeRichText); @@ -67,5 +67,5 @@ // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_12_Reader_ODPresentation.php b/samples/Sample_12_Reader_ODPresentation.php index acb582956b..3948e6e3a2 100644 --- a/samples/Sample_12_Reader_ODPresentation.php +++ b/samples/Sample_12_Reader_ODPresentation.php @@ -5,8 +5,6 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\IOFactory; -use PhpOffice\PhpPresentation\Slide; -use PhpOffice\PhpPresentation\Shape\RichText; $pptReader = IOFactory::createReader('ODPresentation'); $oPHPPresentation = $pptReader->load('resources/Sample_12.odp'); @@ -14,5 +12,5 @@ $oTree = new PhpPptTree($oPHPPresentation); echo $oTree->display(); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_12_Reader_PowerPoint2007.php b/samples/Sample_12_Reader_PowerPoint2007.php index 0093615477..97636393ed 100644 --- a/samples/Sample_12_Reader_PowerPoint2007.php +++ b/samples/Sample_12_Reader_PowerPoint2007.php @@ -5,8 +5,6 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\IOFactory; -use PhpOffice\PhpPresentation\Slide; -use PhpOffice\PhpPresentation\Shape\RichText; $pptReader = IOFactory::createReader('PowerPoint2007'); $oPHPPresentation = $pptReader->load('resources/Sample_12.pptx'); @@ -14,5 +12,5 @@ $oTree = new PhpPptTree($oPHPPresentation); echo $oTree->display(); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_12_Reader_PowerPoint97.php b/samples/Sample_12_Reader_PowerPoint97.php index bcc780ce7d..6ecf748587 100644 --- a/samples/Sample_12_Reader_PowerPoint97.php +++ b/samples/Sample_12_Reader_PowerPoint97.php @@ -5,8 +5,6 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\IOFactory; -use PhpOffice\PhpPresentation\Slide; -use PhpOffice\PhpPresentation\Shape\RichText; $pptReader = IOFactory::createReader('PowerPoint97'); $oPHPPresentation = $pptReader->load('resources/Sample_12.ppt'); @@ -14,5 +12,5 @@ $oTree = new PhpPptTree($oPHPPresentation); echo $oTree->display(); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_13_MarkAsFinal.php b/samples/Sample_13_MarkAsFinal.php index 0556ff0d16..f8670eba5a 100644 --- a/samples/Sample_13_MarkAsFinal.php +++ b/samples/Sample_13_MarkAsFinal.php @@ -3,18 +3,16 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Style\Alignment; -use PhpOffice\PhpPresentation\Style\Color; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Mark the document as final -$objPHPPresentation->markAsFinal(true); +$objPHPPresentation->getPresentationProperties()->markAsFinal(true); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = $objPHPPresentation->getActiveSlide(); $currentSlide->addShape(clone $oShapeDrawing); $currentSlide->addShape(clone $oShapeRichText); @@ -22,5 +20,5 @@ // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_14_Zoom.php b/samples/Sample_14_Zoom.php index 9b76917792..a134c2210f 100644 --- a/samples/Sample_14_Zoom.php +++ b/samples/Sample_14_Zoom.php @@ -3,8 +3,6 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Style\Alignment; -use PhpOffice\PhpPresentation\Style\Color; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; @@ -14,7 +12,7 @@ $objPHPPresentation->getPresentationProperties()->setZoom(3); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $currentSlide = $objPHPPresentation->getActiveSlide(); $currentSlide->addShape(clone $oShapeDrawing); $currentSlide->addShape(clone $oShapeRichText); @@ -22,5 +20,5 @@ // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_15_Background.php b/samples/Sample_15_Background.php index 7d7c054220..8c78d2d501 100644 --- a/samples/Sample_15_Background.php +++ b/samples/Sample_15_Background.php @@ -4,15 +4,15 @@ use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Slide\Background\Color; +use PhpOffice\PhpPresentation\Slide\Background\Image; use PhpOffice\PhpPresentation\Style\Color as StyleColor; -use \PhpOffice\PhpPresentation\Slide\Background\Image; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $oSlide1 = $objPHPPresentation->getActiveSlide(); $oSlide1->addShape(clone $oShapeDrawing); $oSlide1->addShape(clone $oShapeRichText); @@ -23,7 +23,7 @@ $oSlide1->setBackground($oBkgColor); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $oSlide2 = $objPHPPresentation->createSlide(); $oSlide2->addShape(clone $oShapeDrawing); $oSlide2->addShape(clone $oShapeRichText); @@ -39,5 +39,5 @@ // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_16_Thumbnail.php b/samples/Sample_16_Thumbnail.php index 15c33fbe84..884deb9315 100644 --- a/samples/Sample_16_Thumbnail.php +++ b/samples/Sample_16_Thumbnail.php @@ -3,19 +3,16 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Slide\Background\Color; -use PhpOffice\PhpPresentation\Style\Color as StyleColor; -use \PhpOffice\PhpPresentation\Slide\Background\Image; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Set Thumbnail -$objPHPPresentation->getPresentationProperties()->setThumbnailPath(__DIR__.'\resources\phppowerpoint_logo.gif'); +$objPHPPresentation->getPresentationProperties()->setThumbnailPath(__DIR__ . '\resources\phppowerpoint_logo.gif'); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $oSlide1 = $objPHPPresentation->getActiveSlide(); $oSlide1->addShape(clone $oShapeDrawing); $oSlide1->addShape(clone $oShapeRichText); @@ -23,5 +20,5 @@ // Save file echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); if (!CLI) { - include_once 'Sample_Footer.php'; + include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_17_Comment.php b/samples/Sample_17_Comment.php index 727d72bc6d..c9fa849269 100644 --- a/samples/Sample_17_Comment.php +++ b/samples/Sample_17_Comment.php @@ -3,16 +3,13 @@ include_once 'Sample_Header.php'; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Slide\Background\Color; -use PhpOffice\PhpPresentation\Style\Color as StyleColor; -use \PhpOffice\PhpPresentation\Slide\Background\Image; // Create new PHPPresentation object echo date('H:i:s') . ' Create new PHPPresentation object' . EOL; $objPHPPresentation = new PhpPresentation(); // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $oSlide1 = $objPHPPresentation->getActiveSlide(); $oSlide1->addShape(clone $oShapeDrawing); $oSlide1->addShape(clone $oShapeRichText); @@ -22,7 +19,7 @@ $oAuthor->setInitials('P'); // Add Comment 1 -echo date('H:i:s') . ' Add Comment 1'.EOL; +echo date('H:i:s') . ' Add Comment 1' . EOL; $oComment1 = new \PhpOffice\PhpPresentation\Shape\Comment(); $oComment1->setText('Text A'); $oComment1->setOffsetX(10); @@ -32,7 +29,7 @@ $oSlide1->addShape($oComment1); // Add Comment -echo date('H:i:s') . ' Add Comment 2'.EOL; +echo date('H:i:s') . ' Add Comment 2' . EOL; $oComment2 = new \PhpOffice\PhpPresentation\Shape\Comment(); $oComment2->setText('Text B'); $oComment2->setOffsetX(170); diff --git a/samples/Sample_18_Animation.php b/samples/Sample_18_Animation.php index 9f46eca86b..f632cb49cf 100644 --- a/samples/Sample_18_Animation.php +++ b/samples/Sample_18_Animation.php @@ -13,7 +13,7 @@ $oRichText1 = clone $oShapeRichText; // Create slide -echo date('H:i:s') . ' Create slide'.EOL; +echo date('H:i:s') . ' Create slide' . EOL; $oSlide1 = $objPHPPresentation->getActiveSlide(); $oSlide1->addShape($oDrawing1); $oSlide1->addShape($oRichText1); diff --git a/samples/Sample_19_SlideMaster.php b/samples/Sample_19_SlideMaster.php index 3fe68add2e..ef1ac4b52b 100644 --- a/samples/Sample_19_SlideMaster.php +++ b/samples/Sample_19_SlideMaster.php @@ -1,4 +1,5 @@ getDocumentProperties()->setCreator('PHPOffice') + ->setLastModifiedBy('PHPPresentation Team') + ->setTitle('Sample 21 AutoShape') + ->setSubject('Sample 21 Subject') + ->setDescription('Sample 21 Description') + ->setKeywords('office 2007 openxml libreoffice odt php') + ->setCategory('Sample Category'); + +// Create slide +echo date('H:i:s') . ' Create slide' . EOL; +$currentSlide = $objPHPPresentation->getActiveSlide(); + +$autoShape = new AutoShape(); +$autoShape->setType(AutoShape::TYPE_PENTAGON) + ->setText('Step 1') + ->setOffsetX(93) + ->setOffsetY(30) + ->setWidthAndHeight(175, 100); +$autoShape->getOutline() + ->setWidth(0) + ->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color(Color::COLOR_BLACK)); +$autoShape->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color('804F81BD')); +$currentSlide->addShape($autoShape); + +for ($inc = 1; $inc < 5; ++$inc) { + $autoShape = new AutoShape(); + $autoShape->setType(AutoShape::TYPE_CHEVRON) + ->setText('Step ' . ($inc + 1)) + ->setOffsetX(93 + $inc * 100) + ->setOffsetY(30) + ->setWidthAndHeight(175, 100); + $autoShape->getOutline() + ->setWidth($inc) + ->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color(Color::COLOR_BLACK)); + $autoShape->getFill() + ->setFillType(Fill::FILL_SOLID) + ->setStartColor(new Color('FF4F81BD')); + $currentSlide->addShape($autoShape); +} + +// Save file +echo write($objPHPPresentation, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_Footer.php b/samples/Sample_Footer.php index 4aeadf9027..3667c4bcf5 100644 --- a/samples/Sample_Footer.php +++ b/samples/Sample_Footer.php @@ -1,6 +1,6 @@ diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index e83c2515ff..308451e193 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -1,18 +1,18 @@ 'pptx', 'ODPresentation' => 'odp'); +$writers = ['PowerPoint2007' => 'pptx', 'ODPresentation' => 'odp']; // Return to the caller script when runs by CLI if (CLI) { @@ -60,38 +74,46 @@ ->setWidth(600) ->setOffsetX(170) ->setOffsetY(180); -$oShapeRichText->getActiveParagraph()->getAlignment()->setHorizontal( Alignment::HORIZONTAL_CENTER ); +$oShapeRichText->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $textRun = $oShapeRichText->createTextRun('Thank you for using PHPPresentation!'); $textRun->getFont()->setBold(true) ->setSize(60) - ->setColor( new Color( 'FFE06B20' ) ); - - + ->setColor(new Color('FFE06B20')); // Populate samples -$files = ''; +$files = []; if ($handle = opendir('.')) { while (false !== ($file = readdir($handle))) { if (preg_match('/^Sample_\d+_/', $file)) { $name = str_replace('_', ' ', preg_replace('/(Sample_|\.php)/', '', $file)); - $files .= "
  • {$name}
  • "; + $group = substr($name, 0, 1); + if (!isset($files[$group])) { + $files[$group] = []; + } + $files[$group][$name] = "
  • {$name}
  • "; } } closedir($handle); + + foreach ($files as $group => $a) { + natsort($files[$group]); + } + ksort($files); } /** - * Write documents + * Write documents. * * @param \PhpOffice\PhpPresentation\PhpPresentation $phpPresentation * @param string $filename * @param array $writers + * * @return string */ function write($phpPresentation, $filename, $writers) { $result = ''; - + // Write documents foreach ($writers as $writer => $extension) { $result .= date('H:i:s') . " Write to {$writer} format"; @@ -111,9 +133,10 @@ function write($phpPresentation, $filename, $writers) } /** - * Get ending notes + * Get ending notes. * * @param array $writers + * * @return string */ function getEndingNotes($writers) @@ -122,8 +145,8 @@ function getEndingNotes($writers) // Do not show execution time for index if (!IS_INDEX) { - $result .= date('H:i:s') . " Done writing file(s)" . EOL; - $result .= date('H:i:s') . " Peak memory usage: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MB" . EOL; + $result .= date('H:i:s') . ' Done writing file(s)' . EOL; + $result .= date('H:i:s') . ' Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . ' MB' . EOL; } // Return @@ -150,21 +173,22 @@ function getEndingNotes($writers) } /** - * Creates a templated slide + * Creates a templated slide. * * @param PHPPresentation $objPHPPresentation + * * @return \PhpOffice\PhpPresentation\Slide */ function createTemplatedSlide(PhpOffice\PhpPresentation\PhpPresentation $objPHPPresentation) { // Create slide $slide = $objPHPPresentation->createSlide(); - + // Add logo $shape = $slide->createDrawingShape(); $shape->setName('PHPPresentation logo') ->setDescription('PHPPresentation logo') - ->setPath('./resources/phppowerpoint_logo.gif') + ->setPath(__DIR__ . '/resources/phppowerpoint_logo.gif') ->setHeight(36) ->setOffsetX(10) ->setOffsetY(10); @@ -176,7 +200,8 @@ function createTemplatedSlide(PhpOffice\PhpPresentation\PhpPresentation $objPHPP return $slide; } -class PhpPptTree { +class PhpPptTree +{ protected $oPhpPresentation; protected $htmlOutput; @@ -218,9 +243,9 @@ protected function displayPhpPresentation(PhpPresentation $oPHPPpt) foreach ($oPHPPpt->getAllSlides() as $oSlide) { $this->append('
  • Slide'); $this->append('
      '); - $this->append('
    • Info "Slide"
    • '); + $this->append('
    • Info "Slide"
    • '); foreach ($oSlide->getShapeCollection() as $oShape) { - if($oShape instanceof Group) { + if ($oShape instanceof Group) { $this->append('
    • Shape "Group"'); $this->append('
        '); // $this->append('
      • Info "Group"
      • '); @@ -242,16 +267,16 @@ protected function displayPhpPresentation(PhpPresentation $oPHPPpt) protected function displayShape(AbstractShape $shape) { - if($shape instanceof Drawing\Gd) { - $this->append('
      • Shape "Drawing\Gd"
      • '); - } elseif($shape instanceof Drawing\File) { - $this->append('
      • Shape "Drawing\File"
      • '); - } elseif($shape instanceof Drawing\Base64) { - $this->append('
      • Shape "Drawing\Base64"
      • '); - } elseif($shape instanceof Drawing\Zip) { - $this->append('
      • Shape "Drawing\Zip"
      • '); - } elseif($shape instanceof RichText) { - $this->append('
      • Shape "RichText"
      • '); + if ($shape instanceof Drawing\Gd) { + $this->append('
      • Shape "Drawing\Gd"
      • '); + } elseif ($shape instanceof Drawing\File) { + $this->append('
      • Shape "Drawing\File"
      • '); + } elseif ($shape instanceof Drawing\Base64) { + $this->append('
      • Shape "Drawing\Base64"
      • '); + } elseif ($shape instanceof Drawing\ZipFile) { + $this->append('
      • Shape "Drawing\Zip"
      • '); + } elseif ($shape instanceof RichText) { + $this->append('
      • Shape "RichText"
      • '); } else { var_dump($shape); } @@ -261,41 +286,41 @@ protected function displayPhpPresentationInfo(PhpPresentation $oPHPPpt) { $this->append('
        '); $this->append('
        '); - $this->append('
        Number of slides
        '.$oPHPPpt->getSlideCount().'
        '); - $this->append('
        Document Layout Name
        '.(empty($oPHPPpt->getLayout()->getDocumentLayout()) ? 'Custom' : $oPHPPpt->getLayout()->getDocumentLayout()).'
        '); - $this->append('
        Document Layout Height
        '.$oPHPPpt->getLayout()->getCY(DocumentLayout::UNIT_MILLIMETER).' mm
        '); - $this->append('
        Document Layout Width
        '.$oPHPPpt->getLayout()->getCX(DocumentLayout::UNIT_MILLIMETER).' mm
        '); - $this->append('
        Properties : Category
        '.$oPHPPpt->getDocumentProperties()->getCategory().'
        '); - $this->append('
        Properties : Company
        '.$oPHPPpt->getDocumentProperties()->getCompany().'
        '); - $this->append('
        Properties : Created
        '.$oPHPPpt->getDocumentProperties()->getCreated().'
        '); - $this->append('
        Properties : Creator
        '.$oPHPPpt->getDocumentProperties()->getCreator().'
        '); - $this->append('
        Properties : Description
        '.$oPHPPpt->getDocumentProperties()->getDescription().'
        '); - $this->append('
        Properties : Keywords
        '.$oPHPPpt->getDocumentProperties()->getKeywords().'
        '); - $this->append('
        Properties : Last Modified By
        '.$oPHPPpt->getDocumentProperties()->getLastModifiedBy().'
        '); - $this->append('
        Properties : Modified
        '.$oPHPPpt->getDocumentProperties()->getModified().'
        '); - $this->append('
        Properties : Subject
        '.$oPHPPpt->getDocumentProperties()->getSubject().'
        '); - $this->append('
        Properties : Title
        '.$oPHPPpt->getDocumentProperties()->getTitle().'
        '); + $this->append('
        Number of slides
        ' . $oPHPPpt->getSlideCount() . '
        '); + $this->append('
        Document Layout Name
        ' . (empty($oPHPPpt->getLayout()->getDocumentLayout()) ? 'Custom' : $oPHPPpt->getLayout()->getDocumentLayout()) . '
        '); + $this->append('
        Document Layout Height
        ' . $oPHPPpt->getLayout()->getCY(DocumentLayout::UNIT_MILLIMETER) . ' mm
        '); + $this->append('
        Document Layout Width
        ' . $oPHPPpt->getLayout()->getCX(DocumentLayout::UNIT_MILLIMETER) . ' mm
        '); + $this->append('
        Properties : Category
        ' . $oPHPPpt->getDocumentProperties()->getCategory() . '
        '); + $this->append('
        Properties : Company
        ' . $oPHPPpt->getDocumentProperties()->getCompany() . '
        '); + $this->append('
        Properties : Created
        ' . $oPHPPpt->getDocumentProperties()->getCreated() . '
        '); + $this->append('
        Properties : Creator
        ' . $oPHPPpt->getDocumentProperties()->getCreator() . '
        '); + $this->append('
        Properties : Description
        ' . $oPHPPpt->getDocumentProperties()->getDescription() . '
        '); + $this->append('
        Properties : Keywords
        ' . $oPHPPpt->getDocumentProperties()->getKeywords() . '
        '); + $this->append('
        Properties : Last Modified By
        ' . $oPHPPpt->getDocumentProperties()->getLastModifiedBy() . '
        '); + $this->append('
        Properties : Modified
        ' . $oPHPPpt->getDocumentProperties()->getModified() . '
        '); + $this->append('
        Properties : Subject
        ' . $oPHPPpt->getDocumentProperties()->getSubject() . '
        '); + $this->append('
        Properties : Title
        ' . $oPHPPpt->getDocumentProperties()->getTitle() . '
        '); $this->append('
        '); $this->append('
        '); foreach ($oPHPPpt->getAllSlides() as $oSlide) { - $this->append('
        '); + $this->append('
        '); $this->append('
        '); - $this->append('
        HashCode
        '.$oSlide->getHashCode().'
        '); - $this->append('
        Slide Layout
        Layout::'.$this->getConstantName('\PhpOffice\PhpPresentation\Slide\Layout', $oSlide->getSlideLayout()).'
        '); - - $this->append('
        Offset X
        '.$oSlide->getOffsetX().'
        '); - $this->append('
        Offset Y
        '.$oSlide->getOffsetY().'
        '); - $this->append('
        Extent X
        '.$oSlide->getExtentX().'
        '); - $this->append('
        Extent Y
        '.$oSlide->getExtentY().'
        '); + $this->append('
        HashCode
        ' . $oSlide->getHashCode() . '
        '); + $this->append('
        Slide Layout
        Layout::' . $this->getConstantName('\PhpOffice\PhpPresentation\Slide\Layout', $oSlide->getSlideLayout()) . '
        '); + + $this->append('
        Offset X
        ' . $oSlide->getOffsetX() . '
        '); + $this->append('
        Offset Y
        ' . $oSlide->getOffsetY() . '
        '); + $this->append('
        Extent X
        ' . $oSlide->getExtentX() . '
        '); + $this->append('
        Extent Y
        ' . $oSlide->getExtentY() . '
        '); $oBkg = $oSlide->getBackground(); if ($oBkg instanceof Slide\AbstractBackground) { if ($oBkg instanceof Slide\Background\Color) { - $this->append('
        Background Color
        #'.$oBkg->getColor()->getRGB().'
        '); + $this->append('
        Background Color
        #' . $oBkg->getColor()->getRGB() . '
        '); } if ($oBkg instanceof Slide\Background\Image) { $sBkgImgContents = file_get_contents($oBkg->getPath()); - $this->append('
        Background Image
        '); + $this->append('
        Background Image
        '); } } $oNote = $oSlide->getNote(); @@ -312,7 +337,7 @@ protected function displayPhpPresentationInfo(PhpPresentation $oPHPPpt) $this->append('
        '); foreach ($oSlide->getShapeCollection() as $oShape) { - if($oShape instanceof Group) { + if ($oShape instanceof Group) { foreach ($oShape->getShapeCollection() as $oShapeChild) { $this->displayShapeInfo($oShapeChild); } @@ -325,82 +350,101 @@ protected function displayPhpPresentationInfo(PhpPresentation $oPHPPpt) protected function displayShapeInfo(AbstractShape $oShape) { - $this->append('
        '); + $this->append('
        '); $this->append('
        '); - $this->append('
        HashCode
        '.$oShape->getHashCode().'
        '); - $this->append('
        Offset X
        '.$oShape->getOffsetX().'
        '); - $this->append('
        Offset Y
        '.$oShape->getOffsetY().'
        '); - $this->append('
        Height
        '.$oShape->getHeight().'
        '); - $this->append('
        Width
        '.$oShape->getWidth().'
        '); - $this->append('
        Rotation
        '.$oShape->getRotation().'°
        '); - $this->append('
        Hyperlink
        '.ucfirst(var_export($oShape->hasHyperlink(), true)).'
        '); - $this->append('
        Fill
        @Todo
        '); + $this->append('
        HashCode
        ' . $oShape->getHashCode() . '
        '); + $this->append('
        Offset X
        ' . $oShape->getOffsetX() . '
        '); + $this->append('
        Offset Y
        ' . $oShape->getOffsetY() . '
        '); + $this->append('
        Height
        ' . $oShape->getHeight() . '
        '); + $this->append('
        Width
        ' . $oShape->getWidth() . '
        '); + $this->append('
        Rotation
        ' . $oShape->getRotation() . '°
        '); + $this->append('
        Hyperlink
        ' . ucfirst(var_export($oShape->hasHyperlink(), true)) . '
        '); + $this->append('
        Fill
        '); + if (is_null($oShape->getFill())) { + $this->append('
        None
        '); + } else { + switch ($oShape->getFill()->getFillType()) { + case \PhpOffice\PhpPresentation\Style\Fill::FILL_NONE: + $this->append('
        None
        '); + break; + case \PhpOffice\PhpPresentation\Style\Fill::FILL_SOLID: + $this->append('
        Solid ('); + $this->append('Color : #' . $oShape->getFill()->getStartColor()->getRGB()); + $this->append(' - Alpha : ' . $oShape->getFill()->getStartColor()->getAlpha() . '%'); + $this->append(')
        '); + break; + } + } $this->append('
        Border
        @Todo
        '); $this->append('
        IsPlaceholder
        ' . ($oShape->isPlaceholder() ? 'true' : 'false') . '
        '); - if($oShape instanceof Drawing\Gd) { - $this->append('
        Name
        '.$oShape->getName().'
        '); - $this->append('
        Description
        '.$oShape->getDescription().'
        '); + if ($oShape instanceof Drawing\Gd) { + $this->append('
        Name
        ' . $oShape->getName() . '
        '); + $this->append('
        Description
        ' . $oShape->getDescription() . '
        '); ob_start(); call_user_func($oShape->getRenderingFunction(), $oShape->getImageResource()); $sShapeImgContents = ob_get_contents(); ob_end_clean(); - $this->append('
        Mime-Type
        '.$oShape->getMimeType().'
        '); - $this->append('
        Image
        '); - } elseif($oShape instanceof Drawing) { - $this->append('
        Name
        '.$oShape->getName().'
        '); - $this->append('
        Description
        '.$oShape->getDescription().'
        '); - } elseif($oShape instanceof RichText) { - $this->append('
        # of paragraphs
        '.count($oShape->getParagraphs()).'
        '); - $this->append('
        Inset (T / R / B / L)
        '.$oShape->getInsetTop().'px / '.$oShape->getInsetRight().'px / '.$oShape->getInsetBottom().'px / '.$oShape->getInsetLeft().'px
        '); + $this->append('
        Mime-Type
        ' . $oShape->getMimeType() . '
        '); + $this->append('
        Image
        '); + if ($oShape->hasHyperlink()) { + $this->append('
        Hyperlink URL
        ' . $oShape->getHyperlink()->getUrl() . '
        '); + $this->append('
        Hyperlink Tooltip
        ' . $oShape->getHyperlink()->getTooltip() . '
        '); + } + } elseif ($oShape instanceof Drawing\AbstractDrawingAdapter) { + $this->append('
        Name
        ' . $oShape->getName() . '
        '); + $this->append('
        Description
        ' . $oShape->getDescription() . '
        '); + } elseif ($oShape instanceof RichText) { + $this->append('
        # of paragraphs
        ' . count($oShape->getParagraphs()) . '
        '); + $this->append('
        Inset (T / R / B / L)
        ' . $oShape->getInsetTop() . 'px / ' . $oShape->getInsetRight() . 'px / ' . $oShape->getInsetBottom() . 'px / ' . $oShape->getInsetLeft() . 'px
        '); $this->append('
        Text
        '); $this->append('
        '); foreach ($oShape->getParagraphs() as $oParagraph) { $this->append('Paragraph
        '); - $this->append('
        Alignment Horizontal
        Alignment::'.$this->getConstantName('\PhpOffice\PhpPresentation\Style\Alignment', $oParagraph->getAlignment()->getHorizontal()).'
        '); - $this->append('
        Alignment Vertical
        Alignment::'.$this->getConstantName('\PhpOffice\PhpPresentation\Style\Alignment', $oParagraph->getAlignment()->getVertical()).'
        '); - $this->append('
        Alignment Margin (L / R)
        '.$oParagraph->getAlignment()->getMarginLeft().' px / '.$oParagraph->getAlignment()->getMarginRight().'px
        '); - $this->append('
        Alignment Indent
        '.$oParagraph->getAlignment()->getIndent().' px
        '); - $this->append('
        Alignment Level
        '.$oParagraph->getAlignment()->getLevel().'
        '); - $this->append('
        Bullet Style
        Bullet::'.$this->getConstantName('\PhpOffice\PhpPresentation\Style\Bullet', $oParagraph->getBulletStyle()->getBulletType()).'
        '); - if ($oParagraph->getBulletStyle()->getBulletType() != Bullet::TYPE_NONE) { + $this->append('
        Alignment Horizontal
        Alignment::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Alignment', $oParagraph->getAlignment()->getHorizontal()) . '
        '); + $this->append('
        Alignment Vertical
        Alignment::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Alignment', $oParagraph->getAlignment()->getVertical()) . '
        '); + $this->append('
        Alignment Margin (L / R)
        ' . $oParagraph->getAlignment()->getMarginLeft() . ' px / ' . $oParagraph->getAlignment()->getMarginRight() . 'px
        '); + $this->append('
        Alignment Indent
        ' . $oParagraph->getAlignment()->getIndent() . ' px
        '); + $this->append('
        Alignment Level
        ' . $oParagraph->getAlignment()->getLevel() . '
        '); + $this->append('
        Bullet Style
        Bullet::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Bullet', $oParagraph->getBulletStyle()->getBulletType()) . '
        '); + if (Bullet::TYPE_NONE != $oParagraph->getBulletStyle()->getBulletType()) { $this->append('
        Bullet Font
        ' . $oParagraph->getBulletStyle()->getBulletFont() . '
        '); $this->append('
        Bullet Color
        ' . $oParagraph->getBulletStyle()->getBulletColor()->getARGB() . '
        '); } - if ($oParagraph->getBulletStyle()->getBulletType() == Bullet::TYPE_BULLET) { - $this->append('
        Bullet Char
        '.$oParagraph->getBulletStyle()->getBulletChar().'
        '); + if (Bullet::TYPE_BULLET == $oParagraph->getBulletStyle()->getBulletType()) { + $this->append('
        Bullet Char
        ' . $oParagraph->getBulletStyle()->getBulletChar() . '
        '); } - if ($oParagraph->getBulletStyle()->getBulletType() == Bullet::TYPE_NUMERIC) { - $this->append('
        Bullet Start At
        '.$oParagraph->getBulletStyle()->getBulletNumericStartAt().'
        '); - $this->append('
        Bullet Style
        '.$oParagraph->getBulletStyle()->getBulletNumericStyle().'
        '); + if (Bullet::TYPE_NUMERIC == $oParagraph->getBulletStyle()->getBulletType()) { + $this->append('
        Bullet Start At
        ' . $oParagraph->getBulletStyle()->getBulletNumericStartAt() . '
        '); + $this->append('
        Bullet Style
        ' . $oParagraph->getBulletStyle()->getBulletNumericStyle() . '
        '); } - $this->append('
        Line Spacing
        '.$oParagraph->getLineSpacing().'
        '); + $this->append('
        Line Spacing
        ' . $oParagraph->getLineSpacing() . '
        '); $this->append('
        RichText
        '); foreach ($oParagraph->getRichTextElements() as $oRichText) { - if($oRichText instanceof BreakElement) { + if ($oRichText instanceof BreakElement) { $this->append('
        Break
        '); } else { if ($oRichText instanceof TextElement) { - $this->append('
        TextElement
        '); + $this->append('
        TextElement
        '); } else { - $this->append('
        Run
        '); + $this->append('
        Run
        '); } - $this->append('
        '.$oRichText->getText()); + $this->append('
        ' . $oRichText->getText()); $this->append('
        '); - $this->append('
        Font Name
        '.$oRichText->getFont()->getName().'
        '); - $this->append('
        Font Size
        '.$oRichText->getFont()->getSize().'
        '); - $this->append('
        Font Color
        #'.$oRichText->getFont()->getColor()->getARGB().'
        '); + $this->append('
        Font Name
        ' . $oRichText->getFont()->getName() . '
        '); + $this->append('
        Font Size
        ' . $oRichText->getFont()->getSize() . '
        '); + $this->append('
        Font Color
        #' . $oRichText->getFont()->getColor()->getARGB() . '
        '); $this->append('
        Font Transform
        '); - $this->append('Bold : '.($oRichText->getFont()->isBold() ? 'Y' : 'N').' - '); - $this->append('Italic : '.($oRichText->getFont()->isItalic() ? 'Y' : 'N').' - '); - $this->append('Underline : Underline::'.$this->getConstantName('\PhpOffice\PhpPresentation\Style\Font', $oRichText->getFont()->getUnderline()).' - '); - $this->append('Strikethrough : '.($oRichText->getFont()->isStrikethrough() ? 'Y' : 'N').' - '); - $this->append('SubScript : '.($oRichText->getFont()->isSubScript() ? 'Y' : 'N').' - '); - $this->append('SuperScript : '.($oRichText->getFont()->isSuperScript() ? 'Y' : 'N')); + $this->append('Bold : ' . ($oRichText->getFont()->isBold() ? 'Y' : 'N') . ' - '); + $this->append('Italic : ' . ($oRichText->getFont()->isItalic() ? 'Y' : 'N') . ' - '); + $this->append('Underline : Underline::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Font', $oRichText->getFont()->getUnderline()) . ' - '); + $this->append('Strikethrough : ' . ($oRichText->getFont()->isStrikethrough() ? 'Y' : 'N') . ' - '); + $this->append('SubScript : ' . ($oRichText->getFont()->isSubScript() ? 'Y' : 'N') . ' - '); + $this->append('SuperScript : ' . ($oRichText->getFont()->isSuperScript() ? 'Y' : 'N')); $this->append('
        '); if ($oRichText instanceof TextElement) { if ($oRichText->hasHyperlink()) { - $this->append('
        Hyperlink URL
        '.$oRichText->getHyperlink()->getUrl().'
        '); - $this->append('
        Hyperlink Tooltip
        '.$oRichText->getHyperlink()->getTooltip().'
        '); + $this->append('
        Hyperlink URL
        ' . $oRichText->getHyperlink()->getUrl() . '
        '); + $this->append('
        Hyperlink Tooltip
        ' . $oRichText->getHyperlink()->getTooltip() . '
        '); } } $this->append('
        '); @@ -416,19 +460,21 @@ protected function displayShapeInfo(AbstractShape $oShape) $this->append('
        '); $this->append('
        '); } - - protected function getConstantName($class, $search, $startWith = '') { + + protected function getConstantName($class, $search, $startWith = '') + { $fooClass = new ReflectionClass($class); $constants = $fooClass->getConstants(); $constName = null; - foreach ($constants as $key => $value ) { + foreach ($constants as $key => $value) { if ($value == $search) { - if (empty($startWith) || (!empty($startWith) && strpos($key, $startWith) === 0)) { + if (empty($startWith) || (!empty($startWith) && 0 === strpos($key, $startWith))) { $constName = $key; } break; } } + return $constName; } } @@ -456,17 +502,19 @@ protected function getConstantName($class, $search, $startWith = '') {
        - \ No newline at end of file + array('PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')), - 'xml' => array('PHP extension XML', extension_loaded('xml')), - 'zip' => array('PHP extension ZipArchive (optional)', extension_loaded('zip')), - 'gd' => array('PHP extension GD (optional)', extension_loaded('gd')), - 'xmlw' => array('PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')), - 'xsl' => array('PHP extension XSL (optional)', extension_loaded('xsl')), -); +$requirements = [ + 'php' => ['PHP 5.3.0', version_compare(phpversion(), '5.3.0', '>=')], + 'xml' => ['PHP extension XML', extension_loaded('xml')], + 'zip' => ['PHP extension ZipArchive (optional)', extension_loaded('zip')], + 'gd' => ['PHP extension GD (optional)', extension_loaded('gd')], + 'xmlw' => ['PHP extension XMLWriter (optional)', extension_loaded('xmlwriter')], + 'xsl' => ['PHP extension XSL (optional)', extension_loaded('xsl')], +]; if (!CLI) { -?> + ?>

        Welcome to PHPPresentation, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Office Open XML (.pptx) and Open Document Format (.odp).

         

        Fork us on Github! - Read the Docs + Read the Docs

        Requirement check:"; - echo "
          "; + echo '

          Requirement check:

          '; + echo '
            '; foreach ($requirements as $key => $value) { list($label, $result) = $value; $status = $result ? 'passed' : 'failed'; echo "
          • {$label} ... {$status}
          • "; } - echo "
          "; + echo '
        '; include_once 'Sample_Footer.php'; } else { echo 'Requirement check:' . PHP_EOL; @@ -37,4 +37,4 @@ $status = $result ? '32m passed' : '31m failed'; echo "{$label} ... \033[{$status}\033[0m" . PHP_EOL; } -} \ No newline at end of file +} diff --git a/samples/resources/base64.txt b/samples/resources/base64.txt new file mode 100644 index 0000000000..28f3c3fcce --- /dev/null +++ b/samples/resources/base64.txt @@ -0,0 +1 @@ +data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI1TXRUr2tkR2apmmSIRSyshbjkWyEkMT5n4I0upJBXLeaf5kvkTnP3pxTfMl8ic5p/idF/uIb34VXf7SlgACxKwAA8PQAAAAD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgXG4tpsqWBWur5m/wBmhci/pHcSeXvmEkjY2q5y2RD1EuTwZe4YXo66jS4Xh09Pe5HZVFKxyaDETU3LUv7qNX4y7SsZh2nt70rKPfH1EC6cbXuTJXJszOd/6iplfhRMr2v9TB00LHYVdmbsFRZb2lc1tNWOZHcURXSwMavUpnq5eLLj4y3OhjkbI1HNXJTJQADMAAAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB+PdoMc7kRVP0+J0zgk77VMJFwsVTJllciKUdZXrUSNdGr42omWWkRHSPevVvc7kzXM69DL878CdQWN1dG56TozRXLW3P3ny6erfM5XyO1PpVNJRxIkcS6fepWNTNyJmau22dKNkm/73Mq5ZZt2FJW2daKRjN+R2lx6OWRY8Hanug7yLzmq56L1M5Jo5Lsa4kn4QZ7FPDlnWKufeXnOtFSPptPTl3zSy+w+kUfEJKrC5IrNXrdPlrqcJV0MNOipzUVydLL8yUAC2KsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGVvtQ2lxvYZ3IqtjcjlRO841RSX+ypWuZcY1e6ppGKsUbcsnrtyU0eIROlpnMaZtWyne71jLhc5qqNrmtfo5I7bqRE9xD4iuju7Io0ZcnMpapPjxLtbyfhkp+uvFK9qspJWTVDtUcaZ9U7iQ+ZpSysXlo1csiifTzOet29fYcrJ+0Gq8R/pYbUz1gs7kqUvVW2SGtmYrZINWi3Jck7+xqL9poT6TwyF0NM1r0zLu1mtbsiIAAWJ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFIc/XGn8LfWSZv1En1VKmnXKpiXkenrOU/wBR1WCNKe3nZ38FLKgju7Hsaup+Sy/Ud6igttwWkziSNHb45NarsNAqx1EL2teio5FTNq5la2wxMejt+fqXPYhwqHTzMerkcw711sStka5ZVZoplszPqgoW0CPTftPTy2plsPmvrZqV7Uig3xFTWuvUUlbXurXxudG1uhxIe5qYyPjjditmak5Tw79o9Vll3in4QS/QM8qkmku8lRpZxNTRy2KblA2pWoalN5+dvct9e4wnnpnRqkuh8gA+sHFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE61WqW7TvhikYxWN0s3FrwKre2IPxM4bux4iZcWKyqdFFOr8mMbn1SZFdVvnj8qNcvAniRjslKfgVXdsQ/iOBVd2xD+JtSDeq2S22iprImtc+FmkiO2KVbuIzol7/AAJ3RxtRVUzHAqu7Zg/EcCq3tiD8SpttjqsW3aW4XCKSmp6iPTbJFlkrkyTLXn3/ACEOy4ZZdbXcahj5lnpVVsUbcsnrlqRTR/GqtbWbre3s9hXc9VVMMet7Z629hcs3MaCetfVXClpKlz06pV0s1XUifghT3XCtjttdBJSW2GKRiaSObnqVC/wXdK+Csbh2qpmxJTxufr+NrXS1+cRsR/K4/AvrIqWbtHEoZVXXFdOl0Tb6my2RHxYm3T70KcAHcEIAAAAAAAAAAAAAAAAAAAAAKljK7Fd5qMO2Wp6BraRm/vnl+KrUyRUTLNc83pxcR+YSwlSbqVDPdbrUTUktLJ0O1lLloq3JHZrpZ6+qPXcO2SDDliprRTyySxUzVa18mWkuaquvLwlFU16vTDHl3m6yG2bjy/4LMdfxNS+c/wDKRaKqnobzPhmue6evoWZyzp8R+xdXHscnkPbMzBbsNluV+wlS0tro5KudlcyRWRprRqMkTPyqnlNSGqkjde9yV8aOSxSApemlbJvcttp21NupkRK+oTPKny25/YWtNVQVlO2oppEkifnouTYuS5HRsmY9VRq6FerFbmp1ABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH45uk1WrxpkRXW+JGOVNLNE1ayWfirkiquxDTqKOnqc5WopJHK9nmqQqGumo5WwaLUSR6Z6aa+Q0pkq6RjqmOdjs1jTNOTNDvFiCtci5pFq/unzKsgZFM5ka3ROp2VLIi03MXpqmxpFTNCpks9viy3ype3PZpSNT3ETp7WckfkINwuU9Q6NXozVnlkhrNatzNHMndhal17y66TW/th/npzHKCnZT56CqulynCmrkejt+c1vITDveC0NIxOfE7EvfqmqfE5etqHv8lW4fDqAAdKVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPuGaSnmbNE7RkYubV5D4B4qXSwN1hy/dMUSklR7qiONXPkXLJ2vveFDvirsYr/FKeemxornDiC3T22ueyB0qJGxGbVT7czn+IUKta50ei/A2eYr2KzrYyiYvmpcM0lut6ywVMDurkyarVbr1a/Ch9pJc8GV1OktWj4Kh2/SRxJnpJ9qEy/YC6Bo2SWxairlWTJzF0dTcl1+XIp6HCV1mrYYqihnjhe9Ee9MupTjU5BzZ2uRFTNLWKZzalrka5FulrW0QvsOXGO77oFVXwscxk1Pqa/LNMkanuPnEfyuPwL6y/smD6Sx1/RkFTNI/QVmi/LLXlyJ3igxH8rj8C+stOHMe2vhx6rjX4FkxkjIvzNVVV95TgA7wxAAAAAAAAAAAAAAAABGra+noIkfPK2PTXRZpfvO5DxVREuoRLkkrb3e4LFTRzzxSSNe/QRGZcmZD0d0P+E181fzG/wFg3pVI7ENXv8ADcrhBo1NK/LRiXNF1cfEnGVc3EWI38vU2WQLfyjvubYNrcF2eqoq2ognfNUb610OeSJoonGichb1mJKejq5Kd8EjnMXJVTLLYWdXTtq6WSncqtbImSqm1D8oqVlFSR07HK5I0yRV2lMzAiXdmSypKq2Ytu/X2WP2rZNJSyMp36Eqp1Ll4lINuuKrULbZ9J9TC3N8mrRX/wAzQtMz8PEciJZUM1jVXI5FKikwjYaC3VtvpbcyKmrs+iI0e5UkzTLl9R5PVtbad0u4YeoE3i10sLXQ06a0YqsY5da69rlXbxnuB5RunWaHDdVUY3ppZJa2rljgfDJlvaJoZZplrz6hOPjJKeTlyI4ye27VQ/AV09zVlJCyFGyV9VGi01PrzlfkmTU+1T6t9fK9yUNzjbS3WNqrNS6840z1eVqtX7TpeezHgvmV2BbX6E8AExiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVGtVztiIV9TW5rlC7qVbr1EmqmYyN8bl6pzVyKk5Lj3EnxryIXJ321TuLGkgRfLch+O+IvgOVPsd4T8ne5FyRcj9p9i+E463knUNiVlE5y9bHY4VHxmnY4VO1p43Ui4fnUNTx+RIJ9NW/G396Jsy1FVC9X5568jsbdJWTUcmKNfZ0Xx95oVdKiOWJ+qF4fpzhnjmz0F2d4+z6hHIyVuJi3Q5xzVatlP0AEhiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADpBNJTzNmidovYubV5DmAqX1Bu8O35LgxlJJvjqlkave9WojV15cXhTiL08oRytXNqqngU3FixGytbvVW6KKVXI2NqZ5uKCso1YqvZobsU1/JUvzz/ABH8rj8C+s9APP8AEfyuPwL6yrp//wDRg/8A7+QqPNKcAHZmkAAAAAAAAAAAAAD5kdoRudyIqgH0TcPYCqblc5a/EK0tbapG6dHTo9yPifmmSrkicWfGu0z+EsIU26ba5b1cqyoo5YJ1pWx0qojVajWuzXSRdfVr5D1yx2qKxWWltcMsksdMzQa+TLSd4cjn6us5yYW6G9FFhzUngArTYAAAAAABAvNjtuIKJKK60ramnR6P0HOVNaZ5LqVOUngAweFNz2aguE1biLoWtkp5kfbHRSPVadqKupdSa/i8uwxl9/bdef5eP/lRHt5Q4rwlRYstiUVTNLTfpWyb7Bkj1yRUyzVNmslZIrZEeudjFzUVtkPNLVe6a8PqG07JWLTP0X74iJmuvZkq8hYEXdTpmUOIsI0sCaLY36CqmpXZOjTNciUX9HULO1cXQ0ZY8C5H6ADeIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsuHyn+lCKaenpoJo9KSJj1Rcs1Q69A0na0fmny7izv++l8TqaSmc6BqovQxkjHSTsjbtcuSHSsoqi3PayVzc3pn1Kk3EEcdPXRbyxI+oRep1a8yrmqJqhUdNK6RU2K5c8jUbmiHUU8doWtXND531/zlJdHb6i4te6Nzco9ukpBOsNTPAjkilcxHbdFcszK2xPy2pmxERT7pv3vsO5Y4bp4Z4599ia/JW5Zps2l10BR9rR+aQPdmUdZTK+dzkUobZ8aT7CwJFTTwwaKwxtZnnnoptI59G4Ct+Hs9vzU5CvYrKhzV7vkAAXZpAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+4pXwStljdovYubV5FPgHipdAbnDl9SujZRzb4+qa1znPVE0V18ypxGexH8rj8C+s5WJVS4L4tfcdcQfKYfqL6zj3Oazj0cLU0RV96KTOero8ynAB2JCAAAAAAAAAAAAD8VqOaqLsXUfoAK6hr6rBFdFV0kyw4ehXfayjhRHPleqaOaaX9H7ybD1qzXenvlkprtTNkZBUx74xsqIjkTv5KvrPNXIjkyciKnIpUR3abAl3feKVOi1uD0p1glcqMjRVRc0y8BR1tIjUWRntNyGW/kqeyW25Q3SB00LXtRrtFUflnsz4vCTCruFA9tSlyptJ0sLcmwpsdt5youUl3ucLI1t7o0a7Szbxmk2FJF8lbJ39P5MH1D4ks9t17uv8GsPwpbdiSnqInOrHxwOR2pM9qcouWI6anga6kfHO9XZK3PYnKYdnlxYLZmfa4MGPFkWlXUso6WSokRytjTNUbtFHVMraWOpjRyNempHbTIy3GtrahlzSm/R0+pyIvU/b5S+or/QyUkbp5o4ZFTWzk1kslM5jdLr8u4iirWSSKl7J0v17y2BXS3qkWJyUs7JpsuojRfjLxISqGWaekZLURb1I7PSZyazXVjkS6m22VjnYWrc7lLirFNDhC0pc7hFUSwrKkWjTta52aoq8apyF0fL42SN0ZGNenI5MzAkPFWRXC+VaXC/1Da7e5N9oOJYGqueS5Imv4vLsLQiXzDdTgy9Qtt6S18F0mV875Ey6HTSTZl3nL5CWdJRKxYvISxXzXxZqAAbxCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdIXOSRiI5U6pCwlekUT5FTNGNVSpkfvUT5Nugiuy8BRVtwfVSI5NJqI3LLSzzON/wBRwRuc1+Ky7W19p1HAmySXbbyd9j6u1wbcahsjGKzRblrUgH6frU0ntbszXI5dreiHZpZje4/D8LRbK5EVd/TUnzSsNqoo56a3Nba5rU1ZBU35Lr2LS0XaO2tkR8bn6eWxeTM1h58T6K5vptPT0pNLLLqthrxwskkRHuwpvqYVcTsKvjbddty+VznbXKvhPwA+rNRESyIfMVVV1AAMjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrD1xXxa+464g+UQ/UX1nKxdcV8WvuOuIPlEP1F9ZxUv9TM/s+imf7CoAB2pgAAAAAAAAAAAAAAAfhGr7dTXGJrKiJJFjXSjzVU0XcS6iSDFURUsp6i2Kda3dMX/AP6iDyJ/0zeYExol5f0gq+iJrtQw6VXUK1qRPXPLNuS58afuoZsrbzZWXeBkaVD6ZzXaWnFtXVlkVc3Dm4bx6m0yoW/lHqlXh6ifSvbTU7GSqnUuVy5IpBtmGHxVCur0ili0dTWuXb+B5vasQXzc/p32+2W6S8xTu350squzYuzRTLwZ/aLviS+Y+pWWq52p9ohikSoSeLSzVyIrdFc+LqlX7DRTtSKsWf33kbqamcqSWTL70PRMG36xYts9VLa6Kohpmy73IyoREVy5IvE5dWWR81uFaiSse6lWCOFfitVy5p+B5teMNx3aoZKlZNTaDdHRiyRF155kyhx1iPCtFHY6KwLcaekRWsqX6ecma6Werw5fYSOjqaZyubmih0VPO1EcmnsPS7Ph5KNVkq2RySo5HMcxy9SfeK8VUOELS253CGolhWVIsqdrVdmqKvGqJlqPM6vdDxNf6WWz1OHOg4a1qwvqGaecSO1aX2EC0YXZa6xah1dNUorFboS6018Zg2nnqHYnErEip24WHslbe6agw/Le5WSupoqfohWtRNPR0c9meWf2nnF23UkxVRpb8IyVluuCPSRZqqNiM3tM801K7XmqcXEZyHCDYbiyr6Y1D0bJp70vxV17Nuw0DYo2Lm1jUXvITRcNcq3kWwfUJbySNb5sRzI/hFcmVzky3lWp8Tl/dTvEwAuY42xtRjdDVc5XLdQACQxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVXrpJk497d6jNqx6bWuTwoadZGNXJzmp4VK+4Oa6ZqtVF6niOW/1DCx0aTYs25W8ToOD8QdTXjw3vmU+ivIW9kRUhl+shFLC2/q3/AFvcUnAnXrm+35G9xTiKzUysw20+ZNKi9pm+LVxL7i3K+5/HZ4FOq44tqF6+HzQouFzcmqa+19fkUuS8ihGOXY1V8CEwnW1zW75pORM8tq+E4ehiSpqGxOWyLfP2XOql406NiuRnxLAHyj2v+K5F8Cn0fUEcipdDhAADIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuK+LX3HXEHyiH6i+s5WLrivi19x1xB8oh+ovrOKl/qZn9n0Uz/YVAAO1MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWlDSy0tMlzpolqJX5s3rLUicv4GjXVnZIuZhvmbNLT89+C9irBtaWenq2Zx725zctNrf3V5DvvbPmN8hVpx1q/s+P+DZXh6otlceZ10Mj50VrHL1KbEI3Q030TvIeqb3H8xvkG9s+Y3yHPVLIKiZ0q3uven8G4xrmNRqKeWdDzfRO8hNoGOYx6Paqa+M2d+vdusFDJNVT08UqxPdBHK5G765qbE+1U8p5PYLtJjfdIgnnYlJvkLm6ES5omixeUmomRUsnPYiqqIvVP4MJWLImBy2ubAhXCJ8jo1Y1XZZ7DZ0NX0O51LWRMhZFlHBI/VvuWrmLbe2fMb5DfquKR1sCxKxUv39/gYNoXQPvc8q6Gn+id5B0NP9E7yHqu9x/Mb5D83tnzG+Qo+yU//wCvh/BseXun37Tze3xPjc/Tarc0TLMmm7c2JjVc5rUROPI8o3R8fU0kMlltXQtXTVUDXPqYpM1Y7TXVq7zU8p0FBXtpoUhYy6J3999jTmpsTleri8P0qsMqrsN0Kqqqu98fhLQ6djsbUduVbkstgADMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuC+LX3HXEHyiH6i+s5WLrgvi19x1xB8oh+ovrOLl/qZn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAayw9aY/C71mTNZYutMfhd6ym4z+nTx/k3KL0vsOFVRy2yXom35QwZrJVJnmrkTXqzz4s+Q+OFlv+bL5pZXTrVV+Jf6jzs4aaRYV8nqdXTQtqEVZNUNlwsoPmy+aOFlB82XzTGgg7XIbf4fD3+8wWN8R3G+32oiq6lZaakqZm0rFja3QYrtmpNepqbc9hO3Kez2j8XL7CmavXXuu/mH+0ppdyns+pPFy+wp0a+j9hy65Se09zraCGuY3fI9J8euNc1TJSsZenWtOh7s90lQvVIsbUy0eLkL4xeK+u6eKb7yondgTG3UtqVqTO5btC44WW75s3mpzjhZbvmzeanOYwGn2uTuLL8Ph7/edN0PHFXR26m6SVD6d8j3NlV0THaTctmtFPGjb48+RUvjF9RiC8o3K+FHKc/XRpHOrE0Q9cwv2NUPi/eWpVYX7GqHxfvLU7iH0bfBDn3+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuC+LX3HXEHyiH6i+s5WLrgvi19x1xB8oh+ovrOLl/qZn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAayxdaY/C71mTNZYetMfhd6ym4z+nTx/k3KL0vsJF061VfiX+o87Nzf7pb6C3TxVlfTUz5oX722aZrFfq4kVdZ5501tvdCm9M3nOFqmOVUsh1/Dnta111JQIvTW290Kb0zecdNbb3QpvTN5zT5cnqr7iz5sfrJ7zzW9de67+Yf7Sml3Kez6k8XL7CmevkUjLpUTujckU8z3RPVOpeme1F401oaDcp7PqTxcvsKdQvo/YcY70ntPfjGYs67p4pvvNk97Y2Oe9yNa1M3OVckRDz/E17tFTdEfBdaKVm9omkyoYqcffKipaqx5IW1AqJNmvQhAi9Nbd3QpfTN5x01t3dCl9M3nK7lSeqvuLzmR+snvM/jz5DS+MX1GINvi5UudLAygc2rcxyuekC6eimW1cthiDoaFLQIinMcRzqFVNMvkeuYX7GqHxfvLUqsL9jVD4v3lqdzD6Nvghzb/ADlAAJTEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrF1wXxa+464g+UQ/UX1nKxdcF8WvuOuIPlEP1F9Zxcv9TM/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaHgwztpfM/wBxwZZ20vmf7lb+K0nrfBTZ7JNsZ4Gg4Ms7ad5n+44MM7ad5n+55+KUnrfBT3skuxny3kxDRYZwvFX16SuiWbe8omo5c1zXjVOQi3+nt9ht1RUVF0gZOyB8kMEr2sWZWpnotzXNdeSauUw9vw8/HTUudbcJbbSS56LVRXRo5vU6lVUTPaV/Eq2nmhREd12XvNmlp5WvXLoZLEmJrjiWt3yuqVmjhc/eEWNrVa1V2dSiZ7E2lNmeuJuI0rkzbfpF8FOn5j9+A+m7uy/d0/MVaSsQn5blPIgeufAhTd3Zfu6fmHwIU3d2X7un5j3nMHLcYGguFPcYOg7qjp5GNSKiyTRSNVTLXllyN257C+3PLbPat0ikpqhWq9IpF6lc01sUv37i1JAx0smIXxsjTSc90CIjUTjVdLUUMlFE27phm1XBLgr274lxp1Rz9mat6lV5MtpruVG3VmnXu7/8dTZb5dmv16Lv3L/PQud0HdIkSV1rsdRNTyQSywVmnCxUfl1OrPP+9yHlJ6rTbkNLXN03Yies6ojpmLCiuY5dqL1W3PPad/gQp+70n3ZPzEjJI0TJSB7H3zQ8jB658CEHd6T7sn5h8CEHd6T7sn5iTnM3MOW48uoLlVW6RzqaXQ3xNF/UouafahZ3K2UtXRvuloi3qihTQekjl0ldn31XiVDffAhT93pPuyfmK+8YKtuCqd9W7EUdRUQtSRlvk0WOmRV0dmkq8vEuwic5qriZr8/v4E7L4cD9Pl99dywwv2NUPi/eWpBstSlZZ6aoSJsSPZnoN2ITjtYPRNvshQyWxrbcAAmMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXBfFr7jriD5RD9RfWcrF1wXxa+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsqC4Q17HrCqrva6Ls0y1kwyeKVWnqoEhVYkVqqqM1Z6yj6JqPp5POU+XOqcC4VS52zKHmtR7VsinpBV37EFBhq3JX3FXpCsiR9Q3SXNc+L7DF9E1H08nnKZzHM0r7C1r5HOTf26lVV4lM4ahJJEZbUxmoVijV+LQy+KMUXDE1Yj62dJY4HPSDKNGqjVXjy8CHrO5rRQV+53Rw1DVcxJZFyRctemp4Ue+7lHYDR+Ml9tS0namCxTwuVH3QuaWtnt86U1yf+ucjadGpnkmeWv8AAuSHdWtW2VL1RNJkLlavGmowXRM/00nnKVT5eTkuZbw0/abuTI9JB5t0TP8ATSeco6Jn+mk85TDtibE/4avrfAgbou6K5sjrTZKhzVYs9NXI+FMl2NTRVf6thmdyrs+o/Fy+wpnL4qrfa9VXNVqH6/6lNFuVdn1H4uX2FLuyJHkUDlXme09nqqGahmWptqNZvjldUq5c8026s/CpPoq+C4Qb9BpaOlkuaZEkxuJnOp7roQuWNu9pqYuScZUPXkpiTQtImdoXAuu5sQeb9FVH08nnKOiqj6eTzlIu2J6ptfhrvWNdibFFBhejjmrnSN35VbFoM0uqRMz+fr7iC44krmVlzlbLMyNI2uaxG9SiqvF31U0+P5ZJKGkSSRz8pF+MufEYUt6RyPjx7lNVxrFIsd9D1zDHY3Q+K95alVhjsbofFe8tTtofRN8EKF/nKAATGIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZWLrgvi19x1xB8oh+ovrOVi64L4tfcdcQfKIfqL6zi5f6nZ/b9FM/2FQADtDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAssYfKqf6i+szposYfKqf6i+szp8iqPSKfSKP0DT9M9jfrCnjm+pTQmext1hTxzfUplSenb4is/Tv8Dz4993KOwKj8ZL7angR77uUdgVH4yX21Ojn805KLzjT3TrVV+Jf6jzw9DunWqr8S/1HnhQ1mqHRcM81wABpFoeWXvr7XfzD/aU0W5V2fUfi5fYUzt76+138w/2lNFuVdn1H4uX2FOtX0fsOJd6T2nv5i8V9d08W33m0MZivrunim+8par0Zb0HpikABWF+ZXHnyGl8YvqMQbfHnyGl8YvqMQdJQfp09pynEv1LvZ8j1zDHY3Q+K95alVhjsbofFe8tTuYfRN8EObf5ygAExiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWVi64L4tfcdcQfKIfqL6zlYuuC+LX3HXEHyiH6i+s4uX+p2f2/RTP9hUAA7QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPNbjug4guE+nNVtcjc0Z+hamrPwEThjeu2W+ibzETg9e+49f92fzDg9e+49f92fzHDrDEuatQvUqJmpZHKS+GN67Zb6NvMdIcQdMXLBfpHS0uWkjWMRF0uLZkV/B699x6/wC7P5hwevfcev8Auz+Y85EXRLGXaZurlXuXQ/Lra5ra+N0jURk+boslz6n/AMU9u3KOwGk8ZL7anldtp7pHFLTXKz1jo5k0EqaiJ2VMmSortabE27U2FjUXa6UmGIsL2amq5t4m35K+je7q0XNVbotT+987iMFVV8h2plhan5jNNti5xzunSOmbR4fqXMYiSR1SSQprXZqVftMRwxvPbKejbzEV1gvj3K51pr1VVzVVp36/wPng9eu5Fd92fzEnJiXVLkbZ5W+aqoTOGF67Zb6NvMOGF67Zb6NvMROD167j1/3Z/MOD167j133Z/MeciH1U9xl2mf1195PqaKG9U61luaqzxMWSuV65ZuVM9SeFHbCx3Kuz6j8XL7ClPR2u/wBHMjm2m4KxXIr2JA9EeicS6jSWyrdZLyzEaW1Y6mJFZ0q/VvVFTR0s8s+PP4vEYKqsTCui6GWFJfKTJU17+9PvNT1TFmK6HC9C11W6RslQ16QaDNLqkTj8qHiNZjzEFfPv1TVMe/LRzSFqe4/L2zEd+uE9ZLbrm6KaZ80UTmSSNiRy55NXLZxauQruD967j133Z/MZthZazsyPmvR12qqEvhfee2GeibzDhfee2GeibzETg9e+5Fd92fzDg9e+5Fd92fzDs8PqoZdpqPXX3lhBeorrpRX1zpGtT9CjG6OTl5ciquVrqbTUNhqUaj3N0k0Vz1ZqnuOnB699x6/7s/mLqlprjLRSUNztdTFvrtdwqYnfoU1ZJ1SbM05U2nluVm3Tb+DJHc7yX+d0X6L9NjZYY7G6DxXvLQhWWnZS2elgjmSZjGZJI3Y4mnaQLeJqpshQyIqPVF3P0AExgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWVi64f0L7jriD5RD9RfWcrF1w/oX3HXEHyiH6i+s4uX+p2f2/RTP9hUAA7QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN6i6SIqcZ+mcmrZMNv3qRXVu/9Wiudo6CcnGfHDH/2H+d/2nzPnsTJ2SnXpSSuzYl0NMDM8Mf/AGH+d/2mV3RMV1M+G2spWy0cnRDV3yKdUXLJdWpEMo5o5HI1FMJKWaNquc3JCFj7dL6IbJa7JJnDJHLBWJLDr19TqXzi43OKCZME0tdQInRbpJGqr11aOmv+x4s5yucrnKqqq5qqrtPe9ynsCpPGS+2pvTxpy7GlDIqPuae33CKua9rM9OLJr9WWsmaipuVBvaJXQSbylMiyPjY3LfcteSqng5OMruGX/sP87/tNDmozJ5vpAsucSf4NNknINXIZrhknc/8Azv8AtHDJO5/+d/2nnaY9z3sU/q/I+8X4uosK0Sb+57ampjk6G0WaSabUTLP7XIeXYSuNTjDdHpqi6q10j4XtVY26OprFyM5im41VwxDXunnlextVKscb5FckaK5dSZ7OLyFzuU9n9H4uX2FLLltSNfArcbkenceyw1c1ql3itySnc7e6XQTNck5fsyLo4VFPHURq17WqqIui5Uz0V5UKB90fh53QUiOrHL1e+Ofo7eLLXyFcq8vXQsEZz/N840wMxwx/9h/nf9o4Y/8AsP8AO/7THtEW5l2Go9U0j3pGxz12NRVU8Vx7ukOvTXW6zyZ22eBqTJJFk5Xo5V1LyZI0sd0vFNXU26jbSOmolSV2ksU6ppJlsXLI8rLCmRr240NCdHxuwO1PXcMdjVD4otCqwx2NUPii1O4h9G3wQoX+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuH9C+464g+UQ/UX1nKxdcP6F9x1xB8oh+ovrOLl/qdn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACyxf8qp/qKZ00WL/lVP8AUUzp8in9Kp9Ho/QNBnsbdYU8c31KaEz2NusKeOb6lM6T07RW/pn+B5+e+7lHYDSeMl9tTwI993KOwGk8ZL7anQz+acnF5xp7r1orPEv9R54eh3XrRWeJf6jzwoqvVDouGea4AA0i0PLL118rv5h/tKaPcp7P6LxcvsKZy9dfK7+Yf7Smj3Kez+i8XL7CnWL6P2HEr6T2nvxjMVdd08WnvNmYzFXXdPFp7ynqvRlxw/0/sKQAFWXxlcefIaXxi+oxBt8efIaXxi+oxB0lB+nacpxL9S72fI9cwx2NUPiy1KrDHY1Q+LLU7qH0bfBDm3+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuH9C+464g+UQ/UX1nKxdcP6F9x1xB8oh+ovrOLl/qdn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACuxLj3D1bVR7xVvdvSK12cLk15+ApeGFl7Zf6J3MecqquVVVVVV2qoPnz6CJ63W51EfEpo2IxETI9G4YWXtl/oncxBu9fT4moegLW9ZZ0ekmi5NHUmeetfCYc6wVM9LJvlPM+J+WWkx2ShtBHGuJirdD13EpJEwSIll2PhzVjerHanNXJT3vco7AqTxkvtqeSyxU+IKR08LYqJ9HGuk3JFWdcvs16u/tN5hnFUGENzOjnlhSom6IexaffUY9M3OXPYvJ+JK92Ntuprcvlre903Ndi7FNpsFG6luM7o5KqF6RI2NXZ6suLZtQ844X2Xtl/onGIu94rrxVumrKuonRHOWNs0rn72irnkmewgGD6KOS2K5LDXSQ3Rlj0bhhZe2H+idzDhhZe2H+idzHnOYzIvw2HvJvxafZC1v1HNFWurXtyhrZHywrn8Zqrns4tSoXm5T2fUfi5fYUqLVdWuY+irY+iUlRI4XyrmkG1M0z2cXJsNHgOgbZt0Ol3ypY+Bscmc/wAVmti6szaV1kVjtTUcxF/MZp17j2+aZlPC+aRcmRtVzl7yJmeWX/HmHq+4JNT1b3M0ETNYXJr8hU7oW6DUXKsdbbbJUUbaOaWKSSCpXRqG56P7uWrVnx7Tzwi7K2RtnmUdU6F+Jh6NwvsvbL/RO5hwvsvbL/RO5jzkEf4ZDuptfi1Rsn37TZ3uojxPTsitKrM6BVfIjk0ck+0xh3pauekeroZpI9LU7QcqZpyF3X09PeqJ9zpI4qRYU3voViJnIue3Vly8nETxt5CIz9prSOWqVX/u6/48Dd4Y7GqHxRaFXhlFbhyia5FRUj1oqFodvD6Nvghzz/OUAAlMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXD+hfcdcQfKIfqL6zlYuuH9C+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3+CPCn0NV6dR8EeFPoar06mmt90bUxv35iwKxdH9I743f1kzoqm+nj85D52kyql0U6R0OFbKhjfgjwp9DVenUfBHhT6Gq9Opsuiqb6ePzkKTFeLabDFoS4b0lXnKke9slRq60Vc9i8h6kj1WyKYrGiJdUMTijDOCsHQb7pVUdwdE+SiRXOe1ZGp1OerZmqEHDuGrdiK2x3/ELZN7mVzNOJ+j1TVyTUneQwd3vFbeKt01ZV1E6I5yxtmlc/e0VdiZ7OLyHte5fBFUbntGyaJkjd8lXRe3NPjqSyscjbouZjDImLCqeTt99Tmzcmwm9iObHV5Kmafp15j6+CPCv0VV6deYuo3z2aqSGZ0tUypkTRdmuUKZ5d/Vr/AALjomD6aPziBs7l62JnwI1cs0Mb8EeFfoqr068w+CPCv0VV6deY2XRMH00fnIOiYPpo/OQy5rtyPl9xiKncrwhSUstTMyrbHCxXvXflXJETNeIw8ENsveIWYbw+sktplYr0STNr9JEVy6176HbdFx5VXK4OtlA+pomUUs8E6xVCo2oTNG60TLV1K6lz2lfuU9n1H4uX2FNhWKrFVxg2TC/yf+e43Vu3M8I1aOgVlV0TCiJMm+rkjti8XKik34I8K/RVXpl5jR3G2ucrZ6R/QzmuV8u9pksvHkuX2+U7UF0jrIFklZ0M5Fy0JHazUSV6LhcpsOiYqY2Jl8jLfBHhX6Kq9Oo+CPCv0VV6dTZdFU/08fnIOiqf6ePzkJOY7cj5abGN+CLCv0VV6dTL4tsuEMFoqUT6ll5SJstM16ue3JXK3Xqy2I422NMaQYWoIZWwdFrUudGm9yo1WatuxTwGtuFbcpkmr6yeqla3RR88ivcibcs14ta+UnjRXpdy5ETnYFyTM9ZsVTJWWSlqZlRZJGZrkmSFgVWGOxqh8WWp2sCWiaibIUkiqr1VdwACYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/U7P7fopn+wqAAdoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFlHLh/e275JLp5dVki7fIdqijtzrS6so9NU0kRFcvfMy747vCpoqTsSd4z3nCUfEqqStSNzsr/U6us4fBDS8xqZ2+hVgA7s5QuLBoolU9zEfoMRclTwkfhS3ubD5f9jvYv1Nd4rnMwcFx6aSKrVGLb/hDrODQRSwqr0v9qaDhS3ubD5f9iXbL6yvr46ZaCJmnnrRc9iKvJ3jKFnhzr9Tf1eypSsqplciK4tZaKBsblRvRTtcURLhOiIiJvi7PCRiVcuuNR4xSKfUIfRN8EOAf5yg0N4usdrqGRJRxyaTc811cfgM8WGL+uEPi/epzv8AqKR0bGK1ba/QuuDRsklVr0un/J+8KW9zYvL/ALDhS3ubF5f9jPA47tc/rKdV2Gn9Q1dylZVWCmqkhbG6SRNTf6ikLafsSovGfmKk+h8FVXUbVU4fiLUbUORAXFneyC31s7omyb0iORHfaU5aUHWS5/U5yTiyq2jeqfeZhQoi1DUU+OFDe5sPl/2I1Vc0uStVKZkOh81duf8A+CoJFL+99hyHBKiV9cxrnXTP5KdTxWlhjpHOa3PL5odwAfQjiwADwAAAAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALHGPyun+ovrM6aLGPyun+ovrM6fIqj0in0ej9A0Gfxt1gTxzfUpoDP426wp49vqUzpPTtPa39O/wPPz37co7AaPxkvtqeAnv25R2A0fjJfbU6GfzTkotTTXXrVV+Jd6jzw9DuvWqr8S71HnhRVmqHRcM81wABpFoeWXrr5XfzD/AGlNHuU9n1H4uX2FM5euvld/MP8AaU0e5T2fUfi5fYU61fR+w4h3pF8T34xeK+vCeKb7zaGLxX14TxTfeUtV6MueH+m9hSgArC+Mtjz5DS+MX1GHNxjz5DS+MX1GHOkoP06HKcS/Uu9nyPXMMdjVD4v3lqVWGOxqh8X7y1O6h9G3wQ5t/nKAASmIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZWLrh/QvuOuIPlEP1F9ZysXXD+hfcdcQfKIfqL6zi5f6nZ/b9FM/2FQADtDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgu+O7wqaKk7EneM9551VYfvD6uZ7L7OxjnuVGortSZ7PjGwwxclstiS3V6OuLkkc5ZJHbc+LJcz5rC+GmqubjvZdPadvOk9TT8tI7Za3TY/QT5cS26KJ8nSWJ2i1Vy6nX+BDsuNrXeKJalthjiRHq3RVWr/pOnT/UMCtV2FbIc/wDg9Qjkb1UtLGqNp69yrk1ItarsTUpjemtt7oUvpm85pK6/JLCsNFTMpmStc2VEanVoqeDw+UxXBCy9rv8ASu5zmeIVdPVzrIt0/wCC/oaaqpY8KIntLLprbe6FN6ZvOW2F7hRT4ipY4ayCR66eTWyoqr1C8R55abFQVV+uNJNG50VOuUaI5Uy1mntNkobJc4bjQxKyoh0tByuVyJmitXUveVTVfHTwuS6rfXobDZKmdi2allumq+BsLhRVTrhO5tNM5qvVUVI1yXWRugaztSf0anzwnun0zfRt5ikrsc3+HFVFQsq2JBNHm9u9N1r1XHl3kOig/wBQOVMLWaJ8iim4M5nlOdqtveXvQNZ2pP6NT6xrWUtPc4Gz1MMLlhzRJJEaqpmvKfHCa6/Tt9GhQ36ihxLVR1N0asskbNBqtXRyTNV4vCVtfxVlcjWyJa2xY0fDZqR2JqovifPTS3d0KX0zecdNLd3QpfTN5zJYpsVBaqCKWkjcxzpNFc3qurIu+CFl7Xf6V3OVroqZrEequz8OhvNmqnPcxGtuluq9T0KPOtwjROpf06K/NFi6pFTquQgdAVnak3o15iHarnVWe2w2+iejKeFFRjVajskVc9q+E/briy8U1sqZ4qhqPjjVzV3tq5Ll4C7ouNpTsSFjb+JUVXCJJXLK5bEzoCs7Um9GpOgY+ksNzfUsdA3e885E0URMl5TO4fxle6+y09TUVDHSv0tJUiamxypyd4lV95rrlQT0NVKj4J2Kx6I1EzRdusyrOOc5joHtt4dynlLwiRqtmaveU/Ta3dv03pm85Ot1VTVSSLT1EU2jlpb29HZeQoOB9l7Xf6VxywCxI33Rjfitlaif4iLgcUK1aOYq5b+Ck3F5p0p8EiJZdu5UNgADvTkQAAAADwAAHoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALHGPyun+ovrM6eZVOJL1VTK+S7Vr9a6KPqHOyTk1qcund17o1XpXHzaThyvcrsR2MHFGxxoxW6HqRn8bdYU8c31KY3p3de6NV6VxJoL/NFUaVx3y4Q5fqpn6Tc+XJcxHQOiej73sZScSZMxY7Wv1Kg9+3KOwGj8ZL7ani12tPQu9zQyNmZMivVI2/q05F8p7LuX1ENNufUb55WRN32VNJ7kRPjrym9K5HsuhVIx0b7ONXdetVX4l/qPOzM443Q6y8VrIbbLVW+On3yORIalUbNmuWa5Zcnf2mS6dXXujVelcaktC6Wy3sb1NXtgRUVLnqYPLOnV17o1XpXDp1de6NV6VxD+Fu9Y2/xhnqqfl66+V38w/1qaTco7PqPxcvsKQHMgxDRaTUjpJ6KPORy5K6pcqbeJc829/4xZblkb4t0GkbIxzF3uXU5Mv3FLNHXYreqFNIyz0cminvZi8V9d08U33nTHOOKfDVGyKFiVM1Qkkf6KdGuhciZZrlmvH+B4jLiC8zO05rtWyO2aT6hzl/FTTdTLMy17G1BVNp5MSpc9QB5Z06undGq9M4dOrp3RqvTOIfwt3rG/8AjDPU+JqsefIaXxi+ow5dW6+uSR6XJrq9rkyYkz9LQXlTPMj3azutkyNZMlSxWaSyRp1Ka8sjep28lEiX/krKp3Pcszfb3HpWGOxqh8X7y1KrDHY1Q+L95ancQ+jb4Ic6/wA5QACUxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/AFOz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABm58UWaKokikrNF7Hq1U3p65Ki+A58LLH29/lP5iwltlvdM9zqCmVXKqqqxNzzz8BmnUdImOo6foWHeVj/V6CaPxV4j5crKaSR+uV16HfLJVRsZm3OyaL/JY1GKrK+mlY2szVzFRP0T9uXgKvC99tlutSwVdTvcm+udloOXVknIhpXWq3cVBTehbzBLXbe51L6FvMRpLTJGrLLZfAzWGpWRH4m3TuUp67GlFDvaUMa1iuVUdkrmaPJtbrz1+Q+ExZXdwJ/PX8pxxVSU1NPbeh6eKHSlXS3tiNz2chrDN/IZG1yMve+q/wYRpUySPaslrW0TfxMLQXKvorrWV3Sed/RS56GtNHXnty1ljLi+sgjWSWxTMYm1zpFRE/wAJqSnxZ2M1f9HttPEnimkRHR62TVQ6nmgicrZNLroniV7MXVkjUcywzOaqZoqSKqL/AIStqbnX1F8prp0nnb0O3R3vWult49Hv8hrLJ1ko/Et9RNPOfFE9zWx7pqpl2aaVjVdJsuiGa4WV/wDD8/nr+U5w4zqahFdBZZJETUqtlVf9JqTNYF61z+N9yHrXQLG5/L0t1XqYvbUNlazma36J0Ky+3OvvVLHB0nnh0H6Wet2er6qFlwrr/wCH5/SL+U04MFqolajVjyTvUlSklRyuSXNe5DLNxnUumdC2ySOkbrViSrmn2aJzrsRXCtoZqbpDOzfWK3S0lXLP+k72zs6ufifyGmJJHwwubaPoi6qQxMnma68nVU0QxtqvVfa7bFRJZJ5d7z6vNW55qq7NHvkh+MqmJ7Y5LJK17/itWVUVfB1JqjN3/sjsnjPeh7HJDPJnHrddV8RLFPTxJhkySyaJ4Hzwrr/4fn89fyknAkc7OmMk0D4Vkka5Eeip84vSRS/vfYWXA6hi1jWNZa9+vcppcXpn9mV733t3J1VCQADvzjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADzr4L8Zdx/8Aiofzj4L8Zdx/+Kh/Of0BHI2VukxzV5clzyPo4HnuL5YkQ/n34L8Zdx/+Kh/OPgvxl3H/AOKh/Of0EfE08NOzTnlZEzPLSe5Gpn9o57jzloeHUWD8XWSjqlrLW2G3vZnVy79E5WRIi6SoiOVdmfEoWlvl+sceHsP0jKu0xSLNE9zmskV2vS1uVNWarxH7jjdDq75P0JQLPRQRpJDM1s2bZ0XVryRNWSL5TabnVu6JwBSSU0iU9SskmcyN1qmmuoPxNTmIme331JY3Nf8Alu06Lt/g87+DHGPcj/iYfzj4MMYr/wDtH/Ew/nPc7dcuiEdFNGsT4lRiK9fj99CxPG1KuS6GL6fA6yn89/BfjLuP/wATD+c/fgvxl3H/AOJh/Of0GD3nu2MeU0/n+Hc1xrBMyVln6pjkcmdTDtT+ssUfdLJfG1MsDGYmY3qKZyo6PQVMs80XLPRz/eN3jzHUGG6RtNTs6Inq2TR6cM6IsDkRERVTXrzd3th51ue1M173QqSW6SvrXujkRXTrpKuTFy2nqo56Y9vv3GTHoxcGqLr97nKpwDjS8Vc1zfaWq6se6dVbURImb10tSaeracvgvxl3H/4mH857S509ln6pX1EFQ/RYxNSQoi/bq1p5C3a9j0zY5HJyopG2pcvQzfTI3O90P5/+C/GXcf8A4mH84+C/GXcf/iYfzH9BZAz7Q4i5SH8+/BfjLuP/AMTD+YmxYVxJZLRNFerclNaNLTqZkmjc5uxEy0XKu1E4lPbqusgoYFlnlZGmS5I9yN0lTi1ng2M8f1mJ6jRplnoqJ0LY5KVJtJj3I5V0l2cqeQyu6XJT1F5S3Q2tlSmbZ6ZtG9X06M/RudnmqE0q8L9jVD4r3qWh20CWianchRyLd6r3n6ACYwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/U7P7fopn+wqAAdoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGPqarFjauZIaGF0Wm7QXSbrTPV+8Va0mKFu7bn0AzfkboommzLZl842MlXTJI5FqIk6pdr0Pjoul7Zh89D5e+oc2R1o069Dvm0rXMbikXK3VDOvrcXMY577fAjWpmq6TdnnFRw2ufzIPNXnNpV1dMtHOnREWaxu2PTkPKTZpGsmRcbES3caNc6SnVqMkVb95ZXW+1d33nf8AQbvKqrdBFTblzEfppX9uz+kUigsmsa1LImRUule52JVzL+wwV97mlj6azwb01HZ5q7PX4ULmTB9XNGrJb7K9i7WujVUX/EUmFbtS2mpnkqlcjZGIiaKZ8ZpuGdn+fL6NStqXVLZfyky8ELikbSOiRZlz8VIrMIVkbEYy/TNampESNck/xFbVWyvpr5TWzpxO7ohmlvmtNHbxaXe5S84Z2f58vo1KWtv1DPieiuDHP3iGPReujr/e4vtQxhdVKq406L0TUynbRtRuB3VOq6depY8FK/8AiCfzF/MfEWDamBqthvUkaLrVGxKmf+ImcM7P8+b0Y4Z2b583oyHHXbfBCfl8P9ZPev8AJR32219lpY5um88+m/Ry1ty/xKUXTOv7cn9IpfYov1DdaKKGlc9XNfpLpMy1ZGXLSmRyxosiZlNVqxsqpEvk+J2bWVLZnTNqJEkdqV6OXNftOnTOv7cn9IpFBsK1DVxO3NfabHX3S2RVnTueLfM+o0Vdlkqpt0u8SH4NqpXtkkvcr3s+K5YlVW+DqjnYcTW232aCkqHyJJHpZ5MzTW5V95YcM7P8+X0ZTSOq0euFMr7IX0TKJ0bcbs7JfNf5I/BSv/iCf0a/mJOBJJ39MWTzyTLHI1qK9yr84/OGdn+kl9GfOAHpKt0e34rpWqn+It+CLOtT+anw7lK3iqU6RJyVvvnc2AAO1ObAAAAAPAAAegAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtrhM/DcqRUOStn6t2+JnrInCu48kPmf7nfF/yun+opnj5NK9zHq1q2Q+h08MckSOel1UuuFdx5IfM/wBzKbot7q7hhpsM+96KVDHdS3LiUsTPY36wp45vqUzpZXrM1FUwq6eJsDlRudjz5D37co7AqTxkvtqeAoe/blPYFSeMl9tS+n805mLzi/vFFHJD0cue+0jXSR8iqmvX5DPcK7lyQ+Z/uam7daavxL/UeelHUucxyYVtc6ChYyRq40vYueFdy/8Ak+Z/uOFdy/8Ak+Z/uUgNTnSbm/2aD1UPL8QyunxHcpn5aUlVK5cuVXKpodyns+o/Fy+wpm7118rv5h/tKaPcp7PqPxcvsKdSvo/Ycgqfme098e1HscxdjkVDLVtdLh2o6BotFY1aj85EzXNf/wAGqUxmK+vCeKb7ynqVVrcSalxRIj5MDtD94V3Hkh8z/ccK7jyQ+Z/uUgK/nyesW/ZofVQpN0y8VVzt1Eyo0ERkrlTRTLiPOTcY7+Q0vjF9RhzoKJyugRVOa4gxrKhUalky+R65hjsaofFe8tSqwx2NUPiveWp3MPo2+CHOv85QACUxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALKxdcP6F9x1xB8oh+ovrOVi64f0L7jriD5RD9RfWcXL/U7P7fopn+wqAAdoYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGTqcHWueqlme6fSkerlyenGvgKF2H6JuK2WzOXeHR6Xxuq+LntLmpxjFBVSxLQTLvb3Nzz25KUbr812JWXXoOXQazR0OPZkfOkSqxvxLvbTXodi9aNWMwomqXyXTqXnAi0ctR6ROYy2JLZBarklPTK9WaCO6pc1NHw2h7nz+UzN/urLxXpUxxOjRGI3JVzFIlVzPzdDCtdRrF+Ta/tKsAFmU5p8D08M9ZVJPCyREjTJHtRctZd4poqWHD1S+KmhY5NDJzWIip1SGXw266pUTdKmsdJopp6WWzPvlzXU+K7hRyUs8MKxyZaWTmIupc+XvFVOxe0o7GiIlsrl3TvTsiswKqqi52Lmz0FG+z0jnUkDnLE1VVY0VVJnS6h7Sp/RN5jO00eLaWmjgjhh0I2o1uas2eU4y3bE0FwioJGQpUSpmxuTdaa+P7DVdDI96q2RN9TcbURxsaj416JoajpdQ9pU/om8xncFUtNPbZnTU8UipLkivYi8R008YfQweVnOQ7bb8UWmF0NLBEjXO0l0nNXX5TJjFSNzVkS626mL5EWVj0iWyXv5O5rOl1B2lT+iQ8lNhcLvia1wtlq2Qsa5ckVEauv7DHm7QxPYiq51799yu4jMyRWo1tlS/S2wABYFWeh4XoqWbDtK+Wmhe5dPNzo0VV6tSHfaSmjxBaGR08TGPkXSa1iIjtabUIllfiRLTD0BFE6m6rQV2jn8Zc9vfzPqqoMUVlXT1UtPGslMuceTm8/eKZGq2dzlels+p0CyI6ma1I1vl02sarpdQ9pU/om8xNt9PBAkiQwxx5qmeg1EzMpvmMfoIfK3nLLB11rLkla2s0dKF7Wpoply5+o3uCwyJWtdjRUS/W/RSDitRGtM5uBUVbapbqaUAHenIAAAAAHgAAPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWWL/ldP9RTPFTft02iuNU3Qt8zN6zauk9NesquHdL2nL5yHyyakndIqo072mradkSNc7M1ZnsbdYU8c31KRuHdL2pL5yHKpukWLYelsKdDORd805F1auL8T2CmlikR70siHs9VDNE6NjrquhjD37cp7AqPxkvtqeCzQuhldG791VTPLae9blPYFR+Ml9tS5n8w5yPzjT3XrTV+Jd6jzwvcc43o8OQspH0z6l1bFIiOjemTMsk1+U844d0vakvnIVVRTyyWViXLqiqYYkcj3WNUDK8OqTtWTzv9hw6pO1ZPO/2NXsdR6pYdvpvXMreuvld/MP8AaU0e5T2e0fi5fYUp79QPbKy4te17a9XTaDdsaLkuS+Uudyns+o/Fy+wp0KOR0d0OXe1Wy2U98UxmK+vCeKb7zWVlXHRUss8jmokbHORFXLSyTPJDx68bpdFc61KhlvmjTQRui56LylZNE+RnkJcsKOVkUuJ62QuwZbh3S9qS+cg4d0vakvnIaPYqj1S47fS+uMefIaXxi+ow5sKyrjxdFvMCpTLTZyKsi56XeMg5qtXJyKnhLqjRWRYHaoc/XrjmWRvmroet4Y7GqHxXvLUqsL9jVD4r3lqdzD6Nvghzj/OUAAlMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXD+hfcdcQfKIfqL6zlYuuH9C+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAf8dfCfJnqyx319XNJHensY56q1qKupM9hULFfEvbbV03lSRzdLT0ly2Zny19K173WkTqvU+gNq3sY3FGudk6Gzq/kc/i3eo8kNy7D9+citdfXKipkqZuMrd7VJaKxKaSRsiq1HZtQ3aBI2XajrqpW8SWSRGvVioiEAAFmU5p8EVENPWVSzSsiRY0yV7kTPWbHpjQ9u0/pW85hMLWmlu1TPHVI5UjYipouy4y2v8Ahm22+yz1VOyRJGaOWb801uRPeU1VHC+owuVbrY6CjlnjpsTWoqJfrmaXpjQ9uU/pW85nblV0z8a2+Vs8axsiyV6PTJPjcZ923CdrqrZTTytk05I0c7J/GpJ4GWf5kvpFIGdmhc7NeqaGw/tU7WrhToupb9MKHt2D0recdMKHt2D0jecqOBlo+ZL6QpsMWChu1DLNVNermyaKaLstWRg2Gnc1XYlsnduZunqWvRitS69+xMxrVU01thbDURyKkuaox6LxLyGKPQ+Bln+ZL6RTzwtaJ8aswRrp9Sm4jHKkiSSIiX27gADeK09CwvW0sOHqWOWphY9NPNrpERU6tS26Y0PblP6VvOZqw4Zttxs0FVUMk3yTS0sn5Jqcqe4jXawUFHebbSwtekdS7KRFdnxoULoYJJnJiW916HTMmqIoGrhS1k6mu6Y0PblP6VvOVOA1R0l2VFzRZm5f4j94GWf5kvpC4sVnpLS2dtKjkSRUVdJ2ezMs+BOhZVo1iqt7/JTQ4uyofBjeiIibLvYtgAd6ckAAAAAeAAA9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4cD+k+BmGO4NB6BD94GYY7g0HoEOG57S75S7n81g/pPgXhjuDQegQcC8MdwaD0KHnPae8pTw9lXTYhgSGufvVVCze6RkSKiSOVNSLnmm1E5DWW/Gq4LwNT2yBYHXmKdVkppo3OajHK5c9JuSZ604+MtMdzYVwxTJT01ipei6qGTeKiBrUWB6Jk13Lmiqi/YQ8HWmhqcOQ3270cVxWVz41SVmk7NHZIuvkRCJyoxt7eT9/A2UTnLb9/z/z8LHllRO6pqJZ3oiOler3ImzNVzOZ/SMWEMLSsa5thoNaIuW8t1H3wLwx3BoPQIS89prLCqH81g/pTgVhnuDQegQcCsM9waD0CHvPaOUp/P1mu77bv0GTN5q9FkzlRVVrdaKqfYqmowktusOKoL4k70s0THtdUvRVVHK1U+KiaW1U4j0+4YawlbqGeqmsVvyhidJo701Fdopnkh5la56PFuNobfbqNKG2yxqvQi5aCOa1VzyTVtRCJy3u5iePf/kmYqWRj18O7/G5W45xpUYprVgVtOtHSTydCyRsc1z2KuSK7SXkROJDKH9A2zDmGJlfSy2Cj3ymyY6R8Lf0ipqVU8hZcC8MdwaD0CGTKhityQwfA5rrKfzYD+k+BmGO4NB6BBwMwx3BoPQIZdobsYcpdz+bWuVrkcm1FzNHLUQYnh05XZXX9XT08SKjHNTXmqrq43cabD2/gXhjuDQegQwW6BW4bw+j7ZbbJTxV0sDZYaynRqb1m5Uy1a88mr5TxXI/zdTNn5aKjs0XX732Jdgp5aSxUkE7dCRkeTm5ouS/YWBW4cmkqMP0csz1e90etyrrXWWR2tPflNvsnyKOS2NbbgAExgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWVi64f0L7jriD5RD9RfWcrF1w/oX3HXEHyiH6i+s4uX+p2f2/RTP9hUAA7QwAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2pamnpZt8qYd9ZllokE8yQROkdohJFGsr0Y3VTiC4prraqmpjgbbWosjkaiqiaiJd42RXOZkbUa1MskTwIaNFxSKserWJobNVQyUyIryEAC1NIAvaue322kpHTUDZFmZnmiJxInOROnlp7l+o56T/UFPG5WuRboW0fCKiRqObopiajFNminkjfWZOY5Wqm9v25+Azrr1b1xjHcEqP7M2PJX6DtuiqbMsz0l7MIyPc9+GqVXOXNVWNutfIfddYcN1OHZK2msdJA7SRqKkSZprOURaa73NVc0Uv39rXA16IllS33cyPCux9vf5T+YyGKK+muN0Sakk3yNI0bnoqmv7TaVVmtjaSZW0ECKkblRdBNWoqMI22iq7OslRSxSP31U0nNzXLUeU7oIkWZqLll06klTHUTKkDlTPPr0MhS26trtPoOjnqNDLS3qNX6OezPLwKSOD967kV33Z/Me14LpKa3pcH0kEcKrG3PQTLPLPI/OFN0+fH5hsrxFiIi21NFOGSK5Wouh5XYY71ZJ5ZOD9dPvjUblvT25f4VJ92r7zdLZLRcGq6LfMuq0HrlkqLs0e8eicKbn8+PzCbZ7/X1t0hp5nM0H6WeTcv3VU1+008kqOVuZs9mqoolZi8mynl1JiC40NHFSOsFSroWoxVVVaurvaJ9OxnUNlbCtlkSRyZoxZVzX7NE212T/AOLVXjVMbc+zq2+K/ORtdBK9yKzS66qTvSeOJipJrZNE6jhVX/w/P56/lIdilvdlpZIODdfPpv0s96e3/SpsjXX+8Vduq444FYjXMzXSbnxnkc0OB12WTLqonhqEkZhkuudsk7jzLp9e/wCE6/zX/kMdwevfcev+7P5j2nhRcvnR+YOFFy+dH5hJFVwRXwNtchmoqua3Mci2+9jxOSx3eFulLa6yNOV0Dk9xydbq2NiufSTNamtVVi5Ie93mpkq8M0c8uWm+XNcky4nGOvXWSs8S71E68QXmI1G62+JAzhqLG56u0v8AAzFkxDV0NohporRLUNZpZSNeqI7Nyr81eUVlbdbpcaOtisNX/Y3ZqxrXO0tfKjdWwvcJ9jVJ/X7bjc4enfTWq5Tx/Gjajk8imvzomzu8jO653XvNl0M3ZWrzMvJysncefdP71/Cld5H/AJC9w7UXG5MndUWaqo9BWoiPa7qtvK1C84U3P58fmDhTc/nx+YS0tbTU0qSsZmniYz0dZPGsb35L4fwfHQlT2tL5inFUVq5KmS8il1Y75W19xbBOrFZoqupuRV1ny2fxjvWdjw3ifbsXk2sc3W0K0ioiqcT9RFcuSa1U/DtSfLYPGN9ZbOWyKpXpmtj86Fqe15fMUdC1KJmtPL5ilrfL5W0FwWGBWIzRRdbcysXE1ykRWK6PJ2peoOU/6k8vCrC/bwR7mY0ccAAdac+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaamuz6ZrmXZWUzs/0SZL1TeXjO3T619uM8i8xSYx+V0/1FM6fK31Do3YdTvIqOOZiSLlfY3vT+19uM8i8xQYzxwljsaVdpkp56hZms0JWuVNFUXNdSpyIUJn8a9YU8c31KZ09S58qNVNTCooGRxOeirkYSomdU1Ek70RHSvV6omzNVzPedynsBo/GSe2p4Ce/blPYDR+Mk9tS4n80oYvOLR9NPZZ98o275Tyv06l8ip1CJtyyy4s+UmcILX223zXHa69aavxLvUp54U0siwrZpd08LalFV+qfE3vCC1duN81w4QWrtxvmuMECLtb9kNn8Nj3Uxe6FiqrxFen0szIEp7dUTR07omqivYrkTN2arryanIdNyns/o/Fy+wpm7117rfHv9pTSblPZ9R+Ll9hToF9Hlsc0vpLd57fc7bHXtje5Xo+BVcxGqmte+cKe8pDHoXZ0dNUZ56CIuziXjLUxuK+u6eKb7ypmXlpjQtqVvOXlu0NF0/tfbjPIvMOn9r7cZ5F5jBA1O2P2N/8Oi3Ussf47kstsgW0Ppp3VD1ZLvrHLk3Li1oeGG3x58ipfGL6jEF5SOxxI7coq2NIplYmh65hfsaofF+9S1KrC/Y1Q+L96lqdvD6Nvghz7/OUAAlMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACysXXD+hfcdcQfKIfqL6zlYuuH9C+464g+UQ/UX1nFy/1Oz+36KZ/sKgAHaGAAAAAAAAAAAAAAAAAAAAAAAAAAAAOVR+rTwnU41TmtizcqJr4yu4p+il8FN3h/wCrj8T6tPXal8YhZ3vrtP8A0+yhVWiWPpvSokjVVZU4y2vTHLdp+pX93i/uocx/pv0rvD+C84/nht96lcD73t/zHeQaD/mO8h2103OXspPxN8jtni3eppnjQYoe1tHbNJyN/Ru2r3mmc36L6RvnHymt/UOPodAqdmafZa3CWsh3PpX0ELZp0mTJjti9UmfGhT79F9IzzkNFD1eC36HVfpf3df7yGMF0cq26HtV5SNRF6oecSXDFcsTo1tMKI5FRVRf+4iWpMTWikWmgtbHsVyuzeqZ/g4229yfRv8h+71J9G/yEiVVkw8tLGHY7uRyyuv7DvgCpu1Sy6rc6VlNowt3tGfvZ6WfGuzJPKRDQYdzhpblLIita2HNc07zjCcMLL2w/0buYPa+VrVYzfQxhfHDI9r37ar3F2WeHevtN/V7KmR4YWXth/o3cxdYQxJa7hiijpaeZzpX6eiisVNjHL7jCOnlR6KrV9xJLUwLG5Eemi9SsxFYbtUYhr5or5NCx87nNjRXZNTPZtKd+Erk+obUPvT3TMTJsio5XIneXM9LuGH7jPcJ5Y4mq171VF00I3Bi6fQt89CdZ6lFyT4Gs2GjVqYl+KmD4O3r+Ip/K7nPRsX9cIfF+8i8GLp9C3z0OGP77QWq600VXI5rnw6SZMVdWaoeKs8rFRyZ+ATs0UrVY7LO+ZABScMLL2w/0TuYcMLL2w/0TuY1+zzeovuN7tdP66e81mJqKprsC26GkrX0kiVCOV7M81TJ+rUqcv4GHkwvdpY3RyX+V7HJkrXaSoqeU9Ipo3X7Btvkt6b41zlcmfU6s3JxkXgzdfoG+kQ2nSVEdmtTpsaDGUsmJXu6r1PP4cK3WnibFDfZI427GtRyIn2Zm0wbbqy34fvSVdwfWLI1uirlXqckdyqTODN1+gb6RCWylmsuHLtNXN3tiRK/NF0tSIuewNlqHrZ6ZeB5JHSsbdi55de8zwzKPhhZe2X+idzH5wwsvbD/RO5jU7NN6i+4sO1weunvNrhbry36jj4rPls/jHesrsEYht1xxEynpZXPkWNy5KxU2eE0FRY6+Sple2JFa56qi6Scp1XAHJBj5q4fE5njTkme1Y8/AqjtSfLYPGN9ZM6QXD6JvnodKex18dTG90SI1r0VV0k5TppKunVq+WnvKJsMl0yIWKevLvqNKdvx08J0xviC227ET6epmc2RImqqIxV2lFDiyzySsY2oernORE/RuPmqwSrNdGrqd3HUwpAiK5L23NQAD6sfPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxxj8qp/qKZ40OMfldN9RTPHyOo9Kp9Ho/QNBnsbdYU8c31KaEz2NusKeOb6lMqT07Tyt/Tv8Dz89+3KewKj8ZJ7angJ79uU9gVH4yT21Ohn805SLzjT3TrVV+Jf6lPOz0S6daqvxL/AFKedlHWaodDwzzXAAGiW1zyu9de63+Yf7Smj3Kuz6j8XL7CmcvXXut/mH+tTR7lXZ9R+Ll9hTrf/r9hxC+k9p7+YzFfXhPFN95szGYr68J4pvvKaq9GXFB6b2FIACrL+6GVx58ipfGL6jEG3x58ipfGL6jEHSUH6dPb8zk+JfqXez5HrmF+xqh8X7y1KrC/Y1Q+L95andQ+jb4Ic2/zlAAJTEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrF1w/oX3HXEHyiL6i+s5WLrh/QvuOuIPlEX1F9Zxcv9Ts/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAACuvtshu1vSnqHPaxHo7qFRFzyUsStv8AdIrTbkqZmOe1ZEbk3brReY0eIY+yyYNbG1R4O0M5ml8yotmFqC1XOmuFPJOstNIkjEe5FRVRc9eo2vC24fRweavOee8Orf2vP+HOOHVv7Wn/AA5z54sdc7W/wOxR3Dk0t8TVXXdFvFDdbfSR09E5lVJovV7HKqa02dV3y54WXH6On8xec8kuuIqauulBVxwyI2lfpOR2Wa60XV5C44d0Ha0/4Er4qnlsw69SGN9HzH4rWytrsaPFMDcXdC9Mc2dC6e97x1Pxss888/moYzEOGKG1WtaqB8yvR6Jk9yKmv7Cw4d0Ha0/4Fbf8UUt2ti0sMEjXK9HZuyy1GUCViPajr29gnWhWN2C17ZalhSYNtk9HDM6WpRz2I5cnplrTwGxw9XS4ataW6iRr4Uer85tbs18GRiqTGlFBSQwup5lWNiNVUy4kO3Dmg7Wn/DnI5G1rlXW3sJGLw5ES9r+038+MbjFA+RsVNmxqqmbXcnhK7D26Dd7tbVqZ4KNj98VuUbHInFyuUxs+NqGWCSNKefNzVTPVxp4Svw/ialtNuWmmhke7TV2bcsteRk2Kp5TrpndCNz6PnNsqYbLfU9Lrr9W3BrWSPSNqIqK2JVRHIvLr1lJ0qtvaFL6FvMZmrxnLM6JttgyVVydvqJrVdmWvwknorF/c6Dzm/mIOz1CZuciX3WxspUU3mxsuibJc42SipJMS3WKSlhdGxV0GOYio3XxJxGnpqSlop21FLTRQTM+LJGxGubqy1KhkaWkxRSV1RWx0May1K5v0nsy9okVd1xTQ0zqipooGRMy0nZtXLNcuJ3fJpo3yP8iROnUigljijXHGvVfNNr0yru3Kj0rucz1yvl3jxjb4G3WtbC+LN0aVD9FfjbUzyK2C44sqYWTQ0MDo3pm1c2pmnnEWekxRPdIbi+gj36Fui1EkZllr/vd8xhidG52N6aKmp7PKyRrcEa6ovmm96YV3btR6VSHWQRXGVslbG2qe1NFrpk01ROTNTN9F4w7nw+e38xGob5iW5ROlo6WCRjV0VXNEyX7XEKU0vnI9Mu8mWqhvZY1z/wDyfeNKKkprdC6CmiicsuSqxiNXZ3jRdKbb2hTeibzGWulJii7wshqaCPRY7STRexP9RN6Lxh3Pg85n5id7HLG1qSJdL38ohZIxJXuWNbLa3kmrp6mopIGwU08kMTPixxuVrU8CIR7vdblHaKuSOvqWPbE5WubM5FT8TJx3zEs1dJQx0kDqiJM3s1Jkmrjzy40OtU7F1XTSU8lBCjJG6Kqj2Z5ecRtp5GPRXPTfUzdURPY5Gxr1TzS/wzeLpUWCmlnuVXLI7Tzc+dzlXq141Us5qupqYXwz1M0sb0ycx71VHJyKhire3FltomUkFBEsceeWlIzPWufzu+Ki+YmpamGmmpYGyzrlG3NF0l+xx6+B75FVj0zVepjHPFHG1HxrkiftNJ0qtvc+m9E3mM5hSipJ5rkk1LDIjJURumxFyTqth36Lxh3Pg89v5iDbqPFFsdO6ChjVZ3aTtJ7F16/73fM2MekbmrIl1tbMxkkY6VjkjWyXv5JsKWmgoZkmo4I6eVEy04mIx2XhQndMq7tyo9KpiKy8Ynt8Cz1VJBHGiomlqXX9inWOuxdLEyVlBArHojmrpN1p5xAtNLbEsie82Eqob4UjW/8AaWLL5d+HMlN00rd4SLNI+iH6OeinFnkaDpjXdu1HpXc5gko8UJdlufQMe/K3RVNNmWWWXziZJXYtiifLJb4GsYiucuk3Uif1E0sSvw4XpkiJqQQytZixxrmqr5vQ0dXTQV06z1kEdRKqIivmaj3ZeFTMYoo6alqrWsFPFFpTLnvbEbnrbyH5R3jE1wgSelo4JI1XLSzRPW451dHiW6VNKtXQxtbBIjs2Pbyp/e7xnTRvinbjemXS/wBDCplZNAqRxrdf/wA/U9BAB9MOIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPEHvWSRz12uXNT5PR/gUvfdOg/x/lPz4Fb33SoP8f5TieYzcucDtjzrMm2q6zWmrWpgYx7larcnpqNz8Ct67p0H+P8o+BW9d06Dyv/ACnivjVLKetR7VumplLjbIKqJKq1K+o0Wq+qXPJGLt40Tv8ALsPVdz+8W+x7m1FV3KpSngWaRmmrVXWr3ZJqTvGZbuaXywUFTXS3KldSRRrLVQMV2cjGoqq3ZtyzIdBYrpjKjbR2qujpbXmskdLKq6LXJqVdSLxqprq79rly3+hs4cSY2Jn1T6oUeMcXVmKq6NallOkdKr2Quha5NJqrtXNV5E5DOHo/wK3zulQ+V/MPgVvndGh8r+Y2EkYiWRTWwvPOMxmej/ArfO6ND5X8w+BW+d0aHyv5j3ms3PMDtjNQVlNfKNlLcHpFLSRpHRpFmm+KqZdVt+a3k2ltubUdRQbotJBUxLFIkci6Kr/cUsGbjN9ika9tzoWuauaLm/UvkOFVSXCx3pLV0W3p8jdNtezPJGqmzWnJmmw11cjb4dPl/jc2mpzbI7zk+Pd47Gnx9ujRW5i2+zS01TMrpYKxkkb84stWrWmvPPl2Hi56P8Ed/uf9vkutE99V+mc56vzVXa1Vep75+/Ape+6dB5X8xKx0bUyU13Neq5oebg9H+BS9906Dyv8Ayj4FL33ToPK/8pnzWbmOB2xiLTd5rTJIsLGOSVui7TRVyTvEq62iBrFq7S6SooWNyklf+67PZsTiVvFxmt+BS9906Dyv/KfVRgC7YVtU9bcK+mqLbD1c1NErs35qicacuXkInOai4mLn8/voTszTBJp07v8AG5Z4X7GqHxfvLUhWaSCa0U0lLEsULmdQzkQmnaQZxNXuQo5MnqneAATkYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK293uCx00c88T5GyP0URmXJnxmLntYmJ2h6iKq2Qm1NTDSU76iofoRsTNzuQq+F1h7oM8x3MUEdFe5JEZX3NaimX9ZGux6chK6SWztRvlU5io/1FG1yctLmu+qgZle/gclxJipPi2ukVvEuS6088+eEeK+5dL+P5y12agUn47V7mt+JO9RDlbsUujZImIFiopVVFja1q9Un4lrRX613GfeKSrbLJlpaKNVNX2oU9Rb6WsVHVELXq3ZmVLmxMuElFaP7HWMRFWZM/i5Iqp6i0pePuWzZG6aqbMVUyXKyovXZDfAyVsu9XaayKjus8lY+skayFzcsma8tflQ1p01NVR1LMcak+Vrot0AANoAAAAAAAAAAAAAAAAAAAAAAAAAAAFlYuuH9C+464g+UQ/UX1nKxdcP6F9x1xB8oh+ovrOLl/qdn9v0Uz/YVAAO0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAcan9V9p2Ky/01dVW9I6CpSnlSRFV68mvUV/EmotHIirbI3KFbVLFRL5kO89Y63xLiPhLsapP6/bcVsthxHPE6KS8RuY9MnNVV1p5D5p8O4hpYWwwXaOONvxWtVck4+Q+e8uPk8vmJrf4HY8yXnczlLa1um9zWAw9cmIaCtpaWS6q59U7RarV2a0TX5Sw6T4m7tJ5V5iNaRERFWRMyVKtyqrUjW6eB9YT66XrxzfW80xkKfDN8pJJH09zjjdKucipn1S6+931ON0hxFaaNaqW66bEcjcm7df2E0sTZ5btkTOxBDM+nhs+Ncr7bm1Uy7/2gR+J/wBKnOG24lmgjmbeUykajkTNdWaZ8h8cGb4tWlZ0zi6IRMkkzXPLyHkUbI8SLImaKhlNJJKjbRrkqL0NeDKS2rE0UT5FvLVRiKurPmItqjxDdqNamK7aDUcrcnbdX2ESUrcOLmJYl7Y5HI1Y1uvgTcZKiTWxVX/1Xf6TQ9F03bEPnoUEeGamuVenda+o0P1O9uyyz+Nxd5D74E2n51R56cxm7kKxrHP0vom5gztCSOkazzrarsXnRdN2xD56FRimogkw7VNZNG5V0NSPRV+O0obXh+iq73X0cqyb3TrkzJ2vblrLWqwpY6GmfU1EtQyJmWk7SzyzXLiTvmSQwQytu5b5LoYrNPNC7yURM019hZ2aqpmWaka6ojaqRNzRXoTejKXtmLz05zzu8xWOOGNbVUSSvV3Vo9F1J9qIVGZsfh7ZVV91S/cai8TdDaPCi22U9b6Mpe2YvPTnM3gmaKK2TpJIxirLq0nInEhiMzW09swlV1DIIKyofI9cmt6pM1+1odSMhjc1VXPu2PWVr6iVr0REw7rrc13RdL2xF56Doul7Yi89DF4mw/Q2iiimpVlVzpNFdN2erLwFzwItPzqjz05jTWCnRqOV62XuN5tRUuerEYl0t13I9umhTG9xesrEasWpyuTJfimj6Lpu2YfPQpeBFp+dUeenMRbnhG2UdtqKiJ02nGxXJpPRU9Rm/s8zmpiXomhhH2mBjlVqaqupo+i6btmHz0M9fp4X4hszmysVGyZqqOTVrQjWLC1uuVmgq53Tb5JpZ6L0RNTlTk7xY8CLR86p89OY9YlPBIvlLdLpp7A5amoiSzEstl19pddF0vbMXnoOi6XtmLz0KXgRafnVPpE5ikw/h6iuclY2oWTKCRGt0XZatfMRtgp3NVyPWydxm6oqGvRisS69+xc4vnhksLmxzMcu+N1NcilpbqqmS2UrVqIkyhZtenIhW8CbTy1HpE5hwJtPLUekTmMldTLGkeJclvoeI2qSVZMKZpbUuui6btmHz0I9wqqZ1sqmpURKqwv2PTkUybcP0TsVvtirLvCM0vjdV8XPaXXAi0ctR6ROYLFBGrVVy76Bs9TKjkRiZXTU+cITwx2FrXzRtXfHanORC9bV02m1OiItqfvoUnAi0ctR6ROYqL3YqOz1VvdSrJnJNk7TdnsVO93yRrIJ5/Jct1XYidJUU1PZzUsibno4APp5wgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt6Sqhq41WKRr9H42XEpIRDKYgkfaaiNlA7odsiK5yM41z2lT06uXbch8vdUoxcLkzO0bQrImNi5Lueg5EO53Sgs9L0VcallNCrkZpvXVmvF+CmK6dXLtyQzOPblWVWHkjnnfIzf2rory5KZxVDZHo22pjNQyRsV6qmRm8a4uqMV10SzRQsZSK9kTos+raqprXNe8h6bud2+O5bnFHBI9zESaR2bdvx3Hhp77uU9gVH4yX21LOdqYLFVC9yPxJqXlDcZIndD3BrYF0kZBntk4uYtSDdqeF1HLUujRZoI3Pieu1q5Z5/ghj+ndy7bkKt0vKydmWjKftHlMy3N+Dz/p3cu25B07uXbchj2tuxL+GybocN0PdCit0S2u1vpqt8zZ6esa7POFUyb5dbvIYjcpX/wDX9F4uX2FM7fXulv8AXyPdm51TI5y8qq5czRblPZ/ReLl9hS4woka2KRb48z2SWlmtFU+pomLMlU9Vm0tjEzz1eVS1p6mCqj3yCRJG55ZodHNR7Va5M0VMlMhe6ia1V/Q9A9aeLQR2izZmVblSFL9CzjatQuH925sPtPz7TAdO7n25IOndz7ckIu2M2U2Pw2TdDX3m+W6xUyTXCqjp0fmken+85E2H8+YqxPVYsucdfVwRQvjhSFGxZ5KiK5c9a/3lNJuiV9XWUFIlRO6RGyKqIvFqMAWtKqPYj0KmqY6KRY1PXcMdjND4v3loVeGOxmh8X7y0O3h9G3wQoX+coABKYgAAAAAAAAAAAAAAAAAAAAAAAAAAAArb5eI7NSskkY9++u0G6GWpcjB72sbidoeolz5vN5Zb4nRQujkrlajooHZ5v1/7L5CioKN3RMlynRW1NUmcjOJF7x9UlDMj0qLlKlVVsXJsq56m8n4r5SepwPFeKuqlwM80raqqv+XHp1Xf/AABQFYACpxJVTUltSSnkVjt8RM05MlJI2LI9Gp1JYYllejE6ku69aqnxannJr7LLVXW1VcU0yve7qWq7izKWOwTyXWS3pKxHxtRyu4tiL7y4pMMONjlzQv6HDT443rmmfsyNoyJs9vSF2aJJForlyKhztFctik6AqEbFbo0VW1D9quXXl6yTEzQia3arURD5npoapm9zsR7c88lNSir30kuJuhUQ1KxOVFzappGua9qOauaOTNFQ/TJWy7VFnrI6G4yyVPRcrWU+WWUSZ5a/KhrT6LS1MdTHjYpb5KiKmaKAAbQAAPAAAegAAAAAAAAAAAAAAAAAAsrF1w/oX3HXEHyiL6i+s5WLrh/QvuOuIPlEX1F9Zxcv9Ts/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAACHc6unoqZJamVsTNJEzXlJhEuVJT1tMkNTE2Vmki5LylfxPD2OTFpY3KDF2pmHW5UcIbT29H+I4Q2jt6P8AEiXexWuC01UkdHG17YlVqpxKR8N2W21dgpp6ikZJI7SzcvH1SofOuXTcvmZ2vbodrzKrm8vyb2v1Id8ulDUXu1Tw1LHxwy5yKn7qaSGg4Q2jt+L8Rwes/aMf4jg9Z+0Y/wAT18lM5rWrfLwDIqpj3PTDn4jhDaO34vxKbFV3t9ZZXQ09UyR6vaui3kOGHLXQ1VxusU9M17YZUSNF/dTN3Mhf8HrT2jF+JmqU9PL1ungRotTUwr5qIt06+BwoL9amW+mY+tjRzYmoqZ7FyQkcIbR29F5T84PWntGL8Sgfa6FMax0aUzd4WLNWcWeipg1lPKrl8rqvQzfJUxI1Fw5qidS7qr/aXUkzUro1VWKiJy6iowndqCis6xVNSyN++uXJeTJC84P2jufF+I4P2jtCL8QklMjFZ5WfgerFVLIj/Jy8epDr8W0FLve8Z1Wnnnva/F2HHhd/9KqvIQsS26koKi3dCwNi05V0tHjyy5zYB6U7I2uw3vfVdjxnaZJHtV9rW0S+viYW33eSiu9bXPt87mVK5o1E+LrzId+xFJdpNGFZYoNBGuiV2pyouefq8hurncqS3U+lVy72kiK1vUqua5d5DyosaRWzOWXBbYq67HA1IUfdF1++8AAsSpB9xTSQStlierHtXNHNXJUPgAF5W3iW7Wenod6llqIXK58m3Pbzmj4X/wD0qq/8+wz2ErlSWyumlrJt6a6PRRdFVzXNORD0QpqxzI3IxzLp4211OgoGyytV7ZLLki5X00MymNY3SLG23VCvTa3jT7DjccTOrKCembbKlrpWK1FVNn4HW2dnVz8V+U0xBI6GFzbM6IuqmxG2ona68nVU0Qx9mxA62WqGjfbal7o9LNyJqXNyr7yW7GkcbmsdbahHO2Iq61/A0pm8Q9kll8Z70Eb4Z5M2a3XVfESMnp40wyZJZNE8D94X/wD0qqKmx3eW1vqnPt9RJv70cmSbNvObkESVMTWq1I8l7yVaWZzkesmadydTNPxmyJulJbKhjeVdR9cMEVEVLXU6zrjPsfd4xpa27rZSeIZ6iReQkSPwarupgnaFmWPmaJfRDHtu8jcSuuvS+o0FZo6GWvZkW3DHUqra6lMv/OQ0ZHuPWyq8S/1KeLPDIqIrO7U9SmmiRytk3XRCiZjNkjdKO2VDm8qL/sVt2ukl5qqBGUE8W9TZrpJnnmqcxc4L7H2+McaBu1PCSJLFBUWazNF3IuVNUU93yZKl9EJwAPqBwYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABZYw+VU/1F9ZnTQ4w+VU/1F9ZnuI+RVHpVPpFH6BoM9jbrCnjm+pTQmext1hTxzfUpnSenaeVn6d/gefnv25R2BUnjJPbU8BPftyjsCpPGSe2p0U/mHJxecae69aavxL/Uednol1601fiX+o87KGs1Q6LhvmuAANItDyu9de63x7/WppNyrs/ovqS+wpm7117rfHv9amk3Kez+i+pL7CnW/wD1+w4lfSe09+MZivrwnim+82ZjMV9eE8U33lNVejLjh/pvYUgAKsvjK48+Q0vjF9RiDb48+Q0vjF9RiDpKD9Ont+ZyvEv1LvZ8j1zC/Y1Q+L96lqVWF+xqh8X71LU7mH0bfBDmn+coABMYgAAAAAAAAAAAAAAAAAAAAAAAAArb3eoLNAx0zZXLMqsZvaIuS9/NTB72sTE7Q9RLnzeL1Hb4nwwOjkrlajooFzzfr/8AyUdDRu6KluczVZU1SZyM4mr3j9pKGd8jaq6SNqayNcmSpqybycXKvlJ5wPFeKuqnYI/NK2qqkX8uPTqv30AAKArAAAAVGJKWestyR08avdviLknJkpbn4SRyLG9HJ0JYZViej06FJhijqKOnmbURLGquTLMvABLIsj1evUTSrNIr16gAEZEc54UqIHwuVUR7Vaqp3yNaa91hmS3TtYy2xoqpUP2q5deXlUmHOppoauHeZ2abM88iwoa6SkkxN06m5TVKxLZfNU0jJGSxtkjdpMembV5UPpFzMlbrtPZaptJcppJ46p7Y6RsaIu9Ii5ZLnlyt5dhrUPotLVR1MeNilxkqI5Fuin4ADbAAAAAAAAAAAAAAAAAAAAABZWLrh/QvuOuIPlEX1F9ZysXXD+hfcdcQfKIvqL6zi5f6nZ/b9FM/2FQADtDAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZf6mupbe2SgpkqJd8RFYvJkusszjU/q/tK/iSolHIqpfI26FL1LEvbMw9XcMSVlLLTvtCNbKxWroour8T4ttViG20EdHHZ0e2PPJzkXNc1VeXvmxB857UmHDy0sdv2RcWPmrfToZGbE98p5YoZrXEySZco2rn1S+Xvnfp1ibuK3yLzn7iPshsnjf9TTTEkkkbWNdy0zIo45HyPasq5W22MRbXYgttTVTx2pXLVORzkci6ss9mvvkupxJfqOLfai1RxR55aTkXnNYUOM+x9/jGnrJ2zSojmJmJKd0EKqyRcr7ERl8xHJGkjLMxzXJmi5LrTykFeEK3pt0W1qsrW6Ojlq2Zcprrd1spfEs9SEkw7S1jlRsabGfZXSNRXSLv0Mu694lY1XOsrEaiZquS85ypcSX6ti32mtUcseeWk1F2+U09b8hn8W71FJgnrEvjnepDNHxrEr+WmVjF0ciStj5i2VF2Ic9BesSKxauJlAtMubM0Xqs/t4svxO3B+/93XeVS7r7tRWve+jJt63zPR6lVzyyz2J30IfCyydu/wCU/mMUmqFTyGZeB6sNM1y8x/ldc7GGu09clXJR1lW+o3h6tzcuaZ94ryXdp46m61U8LtKOSVXNXLLNCIX7Mmoc1It3rmAAZEYAAAN3wfv/AHed5XGEPSeFtj7e/wAp/MV9a6VMPLS+vS5Z8PbCuLmutp1tuVTcKXaOpfUsvCJM9MnSJpZqnh+wVlpv1HRy1Lr49yRNVyoiu1lrwssfbv8AlP5iJdMS2eptdTDFV6T3xq1qb29M18hpslqnPTE3LwLF8dG1i4X5/wB3+SDbLffbnb46yO9SMbJnk1XLmmSqnuOkuFbxPLHLLd9OSJc2Odmqt8B94exDaqGx09NU1W9ys0tJu9uXLNyrxIWfCyx9vf5T+Y9kkqWvVGNyvsYxx0j42q9+dkv5XUr+kGIO7rvKpXWqC93V9Q2O8SRrTv0V0nLr28xoOFlj7e/yn8xRYbvVvt81e6qqNBJpEVnUOXNNfInfMmOqFjcqtzytkYSNpklYjX5Le/ld2RKqMLXmrj3ue8pKzPPRdpKh9Nw7fmNa1l8VrWpkiIrtSFjwssfb3+U/mHCyxdvf5T+Yh5tXpg/9SflUV74//b/Jn2wXx18dakvEmm1ulp6S5bMywfh6/ParH3xXNcmSoulrQhNvduTGL7gtR/ZljyR+g7bo5bMsy+4WWPt5PRP/ACk8rqhuHC3onTqQQtpnYsb+q28roVVPhe80ke9U943pm3RbmiEevjvVnqqPfbtLKk0uWTXKmxU5y94V2Pt7/Kf+UpL/AHigudVbko5993ubquocmWapyonIe0z6h8zUkbl4HlUymZAqxPz/ALj0IAH0k4sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwt43Tblc6pHuo6VrY82t0dLWme3aQOHdf2rT/wCLnMuDhVpYVW6tOgbWTtSzXZGn4d1/atP/AIuc/Uv0eIP7FdXR0sCdWj2Z5qqcWvPlMuDzssSZtSy7mXbZ1ye66bEuvoJqGRN8icxkmaxq795OU9y3KOwGk8ZL7ankNBXw3SNaK5NfUVL0SKjdsSNV1a8uLPLl2GikxfUYUwhDhyhmmhusE+m+eNrVjVjs3ZIq689acQVXOTA7U8VjW/mM800uOt0uK3q2is7qStSVsjJ89LONdSZalTv+QwHDuv7Vp/8AFzmallfNK+WRdJ73K5y8qqfJktNE7zkuYsqZWeY6xpeHNw+hh8ijhzcPoYfIpmshkY9kg9VDPt1T66l7dKBle1K+3q6okkR01W1uyFV15e15C03Kez+i+pL7CmbttxmoJFa2RyQSqiTMRE6tuvV5FU12Hqu3WO9xYsihey2Qo6NYWJnKrlRW5oirltXlCqrEwL7P4/g8wpL5bdU1T6/yewX2/wBBYKPfq2qihe9rt5SRV6tyJs9R4vct0u53Kq3+SjpGOyyyajvepVYqxVXYluMr5qmSSjZPI6ljka1FjY5dSau9km1ShPUp2K2z0uYJO9jrsWxp+Hdf2rT/AOLnHDuv7Vp/8XOZgHnZIPVQk7dU+upp+m0OJE3m6PZStiTSj3vPq3cmvMz9XRVNDKkdTC6J6ppIjuQ4IqouabTRU1VHf4OhKtHS3SV2jDO/U1rU15av6uLjPcPJ83zfl99TzF2jJ3nb7938G6wv2NUPi/eWpAslLJQ2alpZVar42ZKrdhPOzhVFiaqbIUMiKj1RdwACcwAAAAAAAAAAAAAAAAAAAAAABWXu8RWmnZppJpzqrI1YiLouy2rmYPe1jVc7Q9RLnxer0lvifDSrHLcMkWOndnm5M9f4Zr9hS0FFoVE1wlRWz1XVSs4mqq56j9o6GZZG1dykbUVrM0bKmrqeTk41J6nAcV4q6qdgZ5pWVVUi/lx6dV3/AMAAFCVoAAAAAAAAAAAAAAAAAB8SxpNC+JVVEe1Wrl3yJaax2H5UoJmsZbUzd0TJt0l4iccqmmhq4d6nYj2Z55KWFDXSUkmJunU26apWJbL5po45GSxtljcjmPRHNVONFPoyduu81mqkpbnLJNHUvbHSNjRFSJEXLJdnK3l2GsPo1LVR1MeNilzkqIqZooABtAAA8AAB6AAAAAAAAAAAACysXXD+hfcdcQfKIvqL6zlYuuH9C+464g+URfUX1nFy/wBTs/t+imf7CoAB2hgAAAAAAAAAAAAAAAAAAAAAAAAAAACtv1riu9vSmme9jUkR2bfAvOWRXX26QWmgSpqGvcxZEbkxEVc8l5V7xo8Qx9lkwa2NmjwdoZzNL5mRuGDaKkt89SyeZXRMVyIuWSnGyYUpLlaYKyWaVr5NLNG5ZanKnuJVxxhbqu3VFPHHUI+RitRXNTL1nCx4qt9ts8FJNHOskelmrGoqa3KvL3zhP+85P/6v3aHVf9jz+mG3frcmcBrf2xP+A4DUHbE/4cx98N7Vl+rqfMTnHDi1/RVXmN5yC/EO/wCBsf8Axvd8SksuHaa5VdfDNLI1KZ6Narcteau2+QuOAtB2xP8AgVNkxFR22tuE0zJlbUvRzNFqKqIiu26++hc8OLX9FVeY3nNiftnMXl6ew16bsPLTmWvnvufHASg7Yn/Ap3YdpkxO2177JvTmaWlqz2Zl3w5tX0VV5jecpnYio1xSy6aE28tZo5aKaWzLlES1nlY9ltpqeT9h8nBbVL66dS24C2/tif8ADmHAW39sT+VD74cWr6Kq8xv5hw4tX0VV5jfzEH/yHf8AA2f/AI3u+JTXrD9LaJqJInvkSeXJ2nlxZc5ruktq7nweYhmbrXSYldTutFLLJ0I5XSaaIm3LLj7yk7pnivuTB/5/UZyJM9jUV9nZ3zt4EUToGSPVrLtW1rJfxIeMqCjpKOndTU0cSueqKrG5Z6jIFzfb3XXFUpK2CKJ0D1zRmeeflUpiypmPZEiPW6lTWPY+ZVYlk9wABsGqAAAD1LpJa+0IPMQ8tN30zxZ3Ig8v/cV1c17sOF1teti14c+NuLG2+nS+5Gt9uopcY19M+mjWJkebWK3UnxeL7TQ9JbV3Pg8wzMEeJKe7z3NtrYss7dFzVVNFNmzqu8S5bziiCJ80tqgaxiZuXkTzjWmZI9UwvTROvU3YZIo2uxxrqq+b0LvpLau58HmFBe7dRQ360wx0sbI5ZFR7UbkjkzTafVNfMS1tO2oprZBJE/PRcmevJcvnEasbiWtraWrktbGvpVzYjV1Ls29V3jyKOWN/lvTr1E8sMkfkRr0/b3mm6SWvtCDzB0ktfaEHmFP0zxZ3Ig8v/cRqXEeIa1ZEprdTyLEuT8kXUvnEXInVL8xP/InWopkWyxr/AOJ3xZbaGlsjpYKSKN+m1NJrclLKgs9tfb6Z76GFznRNVVVia1yKO5rie60a0s1rjaxVRc2Lr1f1EiCuxTBBHC20QqkbUairtXJPrEqskWJGpIl7+sQtki5yu5a2sn7S86SWztCDzEI9fZray31Dm0MDXNicqKjNaLkU3CPEK1y0PS6n6IRM1jyXPLb846zV2KZ4JIXWmFGyNVqqm3JU+sYJDO1yK56f+RIs9O5qo2Nf/E+sKWyhqrI2Welilesjk0nNzLxlmtjXtc2ggRUVFRdBDM2xcTWqjSlhtcbmIqrm9devwOO0uIr9R1EDKygghbM9Goqoq560z2OJXRyyTXY9LX3ImTQxwIkka3RPVN4AD6WcOAAAAAAAAAAAAAAAD8VzWpm5UTwldd7xFbo1ibI3oyRirBE5FXTXiM1LLdr+zoS70kdPTounpQ6lVU8KryldV8QhpvOXPYKrWpdy2NbW3CGjopqnSSTemK7Ra7WuXEZvh/B3MqPOQi02GKGlqY543zaUbs0zcmXqLjJDnaj/AFG66cpMjVfXQs81MXwIPwgU6L1tqPOQvrVeIbnQsqtHedJVTQe5M0yXIr8k5CsrcO0VwqnVEzpUc7L4rkRNSeAxg/1E/F+amX33HjK6Jy2cmH4mxbIx/wARyOy25LmfRgaGons2+Mw7Eysa9U37fs+pVNmWtOVTS2S+rWo2lr97huGtXQMRdScXLxd86Ok4lDUWRFs7Y3EwuzRf59xcgAsjwAAAAAAAAAAAAAAA3CUtKqZpTRa/7iH70JTdrReYhS9M5rH+jubnTrJrj3rJdFqcWvI+uF1D9DP5G85805zE85bHWdmkXNqXTcuOhKbteLzEHQlN2vF5iFPwtofop/I3nM1jzGs1Nh9slnlmpanf2ppq1q9TkuacfeM2SMe5Gopi+CVjVcrckIOPseW6kppLZaYqOs6KilhnkTNHQqqaPJt1r5DrueUDo8IU11hg6Lne+RixuRMkTSXX+B47LK+aV8si6T3uVzl5VU973KewKk+vL7am3NEnLsasMqo9VNLSdAVbF3uOBz2ZabUYnUryHfoOl7Wi8xCsq6OW3vSqoXNhgbnJUt2q9E16s+9nybTlwwofoKjzU5zS5uHJ5uchX5xJdC56Epe1ovMQdCUva0XmIU/C+h+gqPI3nHC+h+gqPI3nHaI/WHZZvUU/cRXiy4donS1nQscz43up43sRN9c1Nmzvp5TyqwXFcbbo1PJPCykbJC5u9xa2posXlKLGl/r71fqqOqqXzU9NUzJTMc1E3tiu2au8jfIWG5T2fUf1JPYU3+WiRrfY0eY5Hpbop7FRvhpHLSVtJDBHHlHBI5qZy5auYtuhabteLzEPitoYaxiLJGjnR5rGqrsUqW3l9nToa6K+af42lGiKmS7E4ivx8vJ2hvYObmxM9i66Epu14vMQdCU3a8XmIU3C+h+hn81OccLqH6GfyJzjnx+sOyz+opbupqVjVc6CJERM16hDyfdCx3QTQyWezx0lTTVMDVdVR6nMdpLmifY1PKWW6LjarhttKlnnmpXPkckqq1vVNy2cZ46b0CI9Md7mnPiY7AqWU9cwwulhuhVfoveWpVYW7GqHxfvUtTuIPRt8EKF/nKAASmIAAAAAAAAAAAAAAAAAAAKu+XqG0RRtkSVZKhHNjViIuS9/Ne+hg97Y24nLkeolz8vF7Zb2Ohp9CavyRY6dV1uTPX+Ga/YUlFQvSplr5lXfaldJ0btjFVeI/aShmWRlVcpG1FazNElTPU3iTi5VJ5wPFeKuqnYGeaVlVVX/AC49Oq7/AOAACgK0AFTUYjoqardTSNm02rkuTUy9ZJHG+TJqXJYonyrZiXIeKLq+mb0E2NMpY0dpZ601/wCx9YZur6tnQaxoiQsz0s81XWV2MeuMHifep9YO+W1Hi/eWqxM7He3f7S7WGPsGK2dr+014AKY58AAAAAA/AfM0qQwvlcmaMarly7xAoL9S3KdYYUkRyJn1TUQkbE9zVciZISthkc1XtTJDN3K/TTXKGXe2t6FeuSIup2tNvkNTaa11wt7KlzEarlXUneXIwNX8rl+uptMMdYofC72lLWtiY2FtkLriMMbKdqtTQtwAUxQHOaJs0T41/eaqZ8mZGtNc+wyNoZ2olAiq51U9diqmzykw5VNNDVwrDOzTYvFmqFhQV0lHJibp1NumqViWy+apo4pWTRMljcjmPajmuTjRdin0ZOiu81iqFguEj5qWZUjpGRtRd7RNWvPLiVOXYa0+i0lVHVRo9il1kqYk0UAA2zwAAAAAAAAAHWmp0q6hkDnaKPXLNOI5Ey09dKf65BU+hf4L8iSJVSRqpuW9NL0qf0JVRtZSRpkyof8Avrty9fkLhGMciKjW6+8c6qkp62NI6iJJGouaIq8ZTpc5rL+jubnTOk1x73kuiicXEfPcax6rkdRgSbzU8rbf76l6jEbsaieBD90UXa1FKThZb/mTeaOFlv8AmTeaec+PXEedkm9RS60G/Mb5DzTH+6HR01NJbLUlNWJVQywzvRyo6FVTR96+QlY7xtNTYeSSzyz0lTv7U01a1epyXNOPvHissj5pXSyO0nvcrnLyqpu09npjRboakyOjXAqWU9QwS5XYYgVVVV037frKX5n8D9i8H13+0poDtqf0LfBCik89QACcwAAAAAAAAAAAAAAAAAAAAABxqmtdD1TUVM+M7FZfoK+ot6Mt1QyCbfEVXO5Ml7yldxJL0ciXtkbdC7DUsW18xvMX0bPIfu8RfRs8hlaqlxTR0stQ+6xKyJquXRTWqJydSfFvixPcqKOriusbWSZ5I5NepVT5vePnfZVw4uYljt+2eVh5S38EJGIWMbiGy6LETOZM8k/vNNLvUX0TPIZKfDuIaqeGee4wPkhXONy59Svm94kdLcV914fJ/wBpJJG1zGNSRMrkMcj2yPcsS526JsaXeYvomeQocYxsbYHq1jUXfG7EKq3PxLcqiqhiubWupXI1+miZLnns6nvEmrsGI66BYam5QSRqueiq/wDaI4OTKivemR7JULPCqMjXPLoaC3RRrbaXONv6ln7qciEneYvom+RDNMtOKY42xsu0CNaiNanIif0kLTxIl4ba+mbEmc3S0sk0UTLPkMFp8blVsibmfauW1EdGu2iGtq4Yug5v0bf1buJOQpMFsY6xrpMav6Z21O8hzdasVORWOu0CoqZL3/8ACcaTD+I6CHeaW408ceeeiiquvzTNsbUiczmJdVQjdI9Zmv5S2RF6J1NV+ii+azPwJmN+i+kb5xhb7QXRklG261jKjTkVrND91NWfEneLrgPavpKrz28xG6nia1HPfrslyVtVM9ytZHputjIXzXfK3Jc/0zvWQDR4lw/R2enhkpnyqsjlRdNyL7jOF9C9r40VuhzdRG6OVUfqAASkAAAAPXt9i+kb5yHkJv8AgPavparz28xWcQbGuHG62vS+xb8MdK3Hy230623L/fYvpG+chCvUsa2Wsye1f0TuPvGUo8O0dRiWrtr3zJDAzSaqOTSVep2rl31LjgPa/panz05jR5MEL2q5+y6Flz6iZjkaxOqaknCksbcN0qOe1F6vav8AfcW+/wAX0jPOQz3Ae1fS1PnpzFTdMOUVFdrdSRvmVlU7J6ucmabNmrvjlQTyKqP1uuntCTVFPEiOYmVk19huN/i+kZ5xmcISMbNctJyJ+lTavhOnAe1/S1Pnt5j94D2v6Wp89vMG9naxzMetumwf2p0jX4E8m/Xc0O/RfSN84/N+i+kb5yGMxBhihtdrdVQSTK9Ho3J7kVNf2E6kwXbJqOGV8tTpSRtcuT0yzVM+Qx7PBgR+PLwM+01CvVnLS6Z6iN7OH0rtNMt625/3UNMk8X0rPKZ7gNa/parz28xxq8GW2CjmmZLUq6ONzkzemWaJ4DORKeVWpj0RE0I4+0xI5cCZqq6mn36L6VnlMzi57HVNr0XI79Muxe+0g4ewxQ3W1pVVD5ker1TJjkRNX2FtDgq1xTMkbLU5tcipm9vMSQsgp50u/NF2MJnVFTTqiMREXvNgAD6ccIAAAAAAAAAAAACtvd7is1K2d0SzqsiM0GLrTUq5/gfN5vMdvjWGJzHVz2aUELkXq/8AzwlHRUjpKp90qmLHWVCZSMRepTweTlKbifE2UjbJm4xkkbE3E73biloZ5ZEqLjN0VM1c4nO2sTkLAA+eyzPmdiet1KKWV8rsTgACIiBV4iqZqW0vlgerHo5qZp4TjfrzPanw7zHG/fEXPTz4suc41D6m+YZR7IUWV7/it1Jqd3zdhhVqskd5qqWEFOrVZM+2FVKKyVtTHdIWMmcjZpWpInztZsK2ge9y1FFL0PVrq35NuXIZCyUFTLc4pI4lVsErVkXNNWs3htVsnLla6NbKbnEZOXK10a5/ep3sN7bcElppGuZLSo1j3vVP0i60zTyfiXJkrhb2VboqhNLfqZVfEiLqV2pdfkQsrLfVq0bS3BY4rgqqu8savxdufH6zrOFcVZVNwPycSRTNmbdNeqF2AC9JAAAAAAAAAAAACxxh8qpvqL6zPGhxh8qpvqL6zPHyKo9Kp9Io/QNBnsbdYk8c31KaEz2NusSeOb6lM6T07fEVn6d/gefnvu5T2BUfjJfbU8CPfdynsCo/GS+2p0M/mnJRamnuvWir8S/1Hnh6HdetFX4l/qPPCirNUOj4b5rgADSLM8rvXXuu/mH+0ppNyns+o/qSewpm7117rv5h/tKaTcp7PqP6knsKdavo/YcQvpPae+mNxX13/wD6m+82RjcV9d08U33lNV+iLjh/pvYUgAKsvzK48+Q0vjF9RiDb48+Q0vjF9RiDpKD9OhynEv1K+z5HrmFuxqh8X71LUqsLdjVD4v3qWp3UPo2+CHNv85QACUxAAAAAAAAAAAAAAAABU329R2qOKHKTf6pHNhc1qKjXJlrXPwpykb5GxtVzlyQ9RLn7eby23xPjpd7nrUy0afS6pU8BSUNDozTV0rnLJVrvjo3bI1Vc1RPKfVLQyunStuL2z1yat9bqTLiTJMk/AmqcDxXirqp2BnmlZVVSKnLj06rv/g/QAUJWgAAAwN47IZ/GJ6kN8V81kt1RUOqJKfSkcuarpuT3m5STthcquN+hqGU7lV3VCRW0bK6lfTu1aaImllrTXmKOkZR0scDdegmWlltO4U1sbsOHoanMdhwXyP0AGBGAAAAAARrh1tqfFO9RlMJddXeLU2UkbZY3RvTNrkVFTvEWktFDRS77TwaD8ss9Jy+tTchnayFzF1U34KlkcD411U+ay1RVlXT1CrorA7NERNutOYmoiN1ImR+5A1le5yIiroajpHORGquSAAGBGAAAfEsbZY1Y5EXNMs8thEtNZLYamOhlTSoXKr5KqVctBctSeVET7Sccqmmiq4HQTt0o37UzVOPPiLChrpKSTE3TqbdNUrCtl0U0cU0c8TZYno9j0za5q5oqH2ZGku0tinSnrXukpJVSOkjiYmcaJyquS8acprT6JSVcdVGj2FzdFTE3RQADcAAB4AAD0Al2nrpT/XIhLtPXSn+uQVHoX+C/Izj89DZKZTGHymn+ovrNWplMYfKaf6i+s+c1PolOuofTp7TOgAqToDP426xJ45vqU8+PQMbdYk8c31KefnRcP9AcvxX9R7EPUcD9i8H13+0poDP4H7F4Prv9pTQHdU/oW+CHMyeeoABOYAAAAAAAAAAAAAAAAAAAAAAiXGpgpaZJaiVsTNJEzcuSZksg3ehprjRpBVxb5Gj0dlpKmvXyFfxLD2OTFpY3KDF2lmHW5R3e726W0VUcdbC97olRrUfrVSNhq60FNh+mhnq4o5G6ebXOyVOrVSXwTsfaX+a/nHBOx9o/5r+c+d8ym5fL8q179DtOXV83meTpbqSunlq7fh88dPLV2/D55mb3ZLdSXm2U8FPoRVEmjI3TcuaaSJxr3y94JWPtL/Nfzh8VM1rXKrs/A9ZNVPc5qI3LxKfDdxo6e43V81THG2WVqsVzstLW7Z5TQdO7X2/B55G4J2PtL/NfzlTiaw2y3Wh1RS029yI9qaWm5dX2qZu7PUS9br4ETUqqaHRqol16+Jf9O7X29D55n33CjXG7KnomPed7yV+lq+KvGWNFhizS0MEr6PN742ucu+v1qqeE7cE7H2l/mv5zFj6aJXJ5XVOhm9lVKjVs3JUXqSundr7fp/PHTu19vweeQajC1ljppXto8laxVRd9fty8JVYXsVtuVqWeqpt8k3xW56bk1ZJyKeJFTKxX3dZPAyWaqSRGWbdfEYtudJNJQOp5mTb29znaDs8vikvhzb+15/InOXVvtNDa986Cg3rfMtPq3Ozyzy2r31Jh46aDCjMCqid9tT1tPUYlkxoir3X08Tz/ABJiGmvNPDHBFIxY3Kq6eRniwv3X6t8e71leX0LGsjRG6HNVEj3yqr1uoABKQAAAA3fDqg7Xn/Awh7CVnEHRtw4231622LjhbJXY+W62nS+5gaTEdNT4jqrk6GRY52aKNTLNPi8xccOrf2vP5E5zTEG99ZK3xLjR50MrmorNk1LHkVELHK2TddCn4dW/tefyJzlTc8SU1bdLfVxwyo2ldm5FyzXZs8hpcJdjVJ/X7bi4PebDDIqNZpdNfYeJDUTxIrpNbLp7dzL8OqDtaf8AAcOqDtef8DUGXwf8ounjk/1HjOzuY5+DS3U9f2psjWczzr9Nitv+KKW62x1LDDKxyvR2bsstROpca0MFJDC6nmV0cbWqqZcSZGrBitRDgRnLy8f8GaUs+NX8zP8At/yZnh1b+15/w5zjV41op6SaFtPMivYrUVcuNMjrH2fyeJ/0oaYzkdBErVwaoi6kcSVMyORZNFVNDEWHFFLaralLLDK9yOV2bcstZaw42oZJo40pp+qcicXL4TRGWxvG+ZtBFGmb5Hua1O+uiZRSQTzpdma95HMyopqdVR+SdxuT9MnaUulltfSOKla696ayMpJNebV155oqJszXaSLzRPwalur4WqtbeXZ1scy5tjfqVUZlllkr12quxDuHcZpmvjZfN+2fQ4vlLc0gALghAAAAAABXXu8w2OibVTxvka6RI8mZZ5qir7j4vN5Zbo1hhex1c9ulBE5F6v8A88JSUVK99W+6VLVjrKhuUjE+Kng8icZT8S4mykbZM3GEkjIkxP8AcflJRTSPSouMvRM6LnG9drW8hPP0/D55LM+Z2N63Uo5ZXSuxOP0AEREAAAZXGWt9J4He4s8MdY4frO9pS2P02nVF4Uitobj6nFTpDbTqcYKWCmVywsRunty4zsAayqq5qaqqqrdQQq2ifIqz0bkgrNjZuNE4/wACaDOOR0bkc1czKOR0bsTTvYL0lwSSie1/RFGxrZZHZZPdsVU+1FLkyNwoGVKxTdUstMunEibFdtTPyFpZL66sRtLcN7huCqq7wxq/F5eP1nf8K4q2qbgfk75l5FK2ZuJNdi6ABekgAAAAAAAAB84pxJZKmrh3i60sug1UdoyouS5lH07tfb8HpEPLXuV71e5c1cuan4fPH8Oje7EqqdVFxOSNiMRqHqfTu19vwekQqMTTxXa1pTW6RtVMkiO0Il0ly168kMGSaG4VVunWakl3qRUyz0UXV9p4zh7Y3I9q5oZP4m6Vqse3JdtSMqK1VRUyVNqKe+7lPYFR+Ml9tTyKpoKa70j6y1R730OxX1W+OXNy5Z6ta8i8h6RgvENFhncwoq+vSVYlqHx/om6S5q5y8veNl78be80uWsbs9NzX4ivNtttvmhrq6CnknhekbZHoiv1cXlPO+ndr7fg88wmJMTXLElZvldUrNHE5+8IsbW6LVXZ1KJnsTaU5DJQtksrlNiCvdBdGoep9O7X2/B546d2vt+DzzywEX4ZHupsfjEvqoWN8glZdJ6h0bkhqJXvieqanpnnmnLtQ0G5T2fUf1JPYUq6C4QXKBKK7I6d7GpFRZJopGqplryyz2N257C/3PLdPa90ijpp1bppFIvUrmmtim5i8lWO1sV72ZpI3Rfh99D3J72RxukkcjWNTNzl4k5TzrEmI7LVXRJKe6UsrN7RNJsiKnGVm6FujyNlda7HUzU8sEssFZpwsVH5dTqVc+R3IeUkC0qSts5bEsVUsD8TUuep9OrZ2/T+kQdOrZ2/T+kQ8sBF+GR7qbf4vJ6qG1xU9t3pIWW5yVTo3K56RLpK1MtqmKJdvuNVbpHOppNDfE0X9Si5p9pZ3K2UlXSPuloi3mjhTRe2Ry6Suz4s1XlQ2ompAiRrp0X+foaczu0qsqed1T+Pqb7C3Y1Q+L96lqVWFuxqh8X71LU7eH0bfBDnn+coABKYgAAAAAAAAAAAAAq73eY7XHHD1aVFUjmwK1qKiOTLJVz76oRvkaxqudoh6iXPy83ptvhfHTb3PWplo0+l1SovHl4CmoaNWSz1kqqslW7fHMdsjVc1VE8v4H5SUcz5m11yc2WvTNN9TVq2JqTV+BPOA4txVap2BnmlZV1SKnLj06rv/AIAAKIrQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADnLE2VitciLmmWzYRbTVy2CoZQSppULnK+SqlXJI1VNSeVE8pNOdRTxVlO6CZulG/amapx58Rv0NdJSSYm6dTbpqhYlsuhoopY5omyxPR7Hpm1zVzRUPoyVHdprBOsVfI59AuUdLHGxFVnhXb+KmuPo1JVR1UeNhc3RUu3QAA2wAAeAEy09dKf65DJlp66U/1yGo9C/wX5GcfnobIwGKMSWSpqot5utLJoNVHaMiLkuZE3Q90Z9re61WSeanuVPO3fnuhY5is0VXJNLPjVvEeNvcr3K5y5qq5qcL2VJWWdkdBHUrDJialz1Lp3a+34PPQdO7X2/B56HlgIvwyLdTc/F5fVQ3mJqiG7WtKa3SNqpt8R2hEukuSZ68jBqitVUVMlTaikihr6m3T7/SS73IqZZ6KLq+0uaq3014pnVdqjVnQ0auqlkVeqXLPVrXkXkNmNqU6YOm/8/Q1ZnrVrj/dt/H1NhgfsXg+u/2lNAZ/A/YvB9d/tKaA7an9C3wQ52Tz1AAJzAAAAAAAAAAAAAAAAAAAAAAFZf6qro7ektFSrUy74iaCZ7Ml16izONV+rTwlfxJUSjkVUvkblA1XVLERbZmMlxHfIo3SyWRWMYmblXSyQ+YMTXqpibNBZ98jdsc3NUXiLy99ZKzxLiNhLsapf6/bcfPccXJ5nLTWx2WCbn8vmrpfpuUFfPfK+uo6t1nla6kdpIiNXqtaLr8hY9PsQ9wH+RxpgRrVNVERY0yJUo3tVVSVbr4GSgxVdql0jILRvjolyejc1Vq9/wAike61l9u1EtLJZpWNVyLmjVXYTsKddLz41vreaYmlljgls2NMrEMMMlRDd8i5323MrBer/BTxwpY5HJGxGoqo7iTI+eFd26K6F6UJv+We969LLwGtMxJ+0GPxP+hTGOSKTEqxpkiqJo5YkbaRc1ROh8y3q/yxOjWxPRHNVF1O4yHaKm+2ijWmjs0sjdNXZuaqbf8A8G1BglUxGq3lpZSbsj8SO5q3TwMPc71fnuga6KS3aTtFOLTzy9XvLHpNibu23yrzH5jORsc1sV65IkrlXwJolvwhtHb8X4k7pHcpjomJnfpc1WxsWZ7ZZFyt1t0MTfrHV23RqauoZM6d65q3PPMpTXYxudFXUlOylqGSua9VVG8WoyJaUznuiRX6lNVsjZMqRrdAADYNUAAAG76TYn7tt8q8xhD1DhFaO3o/xK+tfI3DgbfXpcteHMidi5jradbbmZgbiGovE9sbdlSSBuk56r1K7O93ydLYMRzxOilvDHsemTmqq608hHoLrQxYvr6p9QxIJI8mP4lXqeZTQcIrT2/F+JqzPmYqYGdE6dTcgjgejsb+q/u6FLBh7EFJC2Cnu0ccbdjUVck4+Qi1rMQ0NfS0cl20nVS5NVqrknh1d80nCC09vxfiUN7ulBUX61TxVLHRwvVZHJsbrQQyTPf5bN+h7NFAyPyH7fu7yR0nxN3ab5V5jhTYZvtGsi090jjWRc35Z618hecILR2/F+I4Q2jt+L8SHnVOmD/1JuRSa4//AGM9dIcRWmiWqlu2m1HImTV16/sJMFsxJPTxzNvLUSRqORFz408B+Ypu9vrbM6GnqmSPV7V0WllQ3+1R0FPG+tjRzImtci56lyJldLyUdgzvsQoyDnK3GtrJ+4quDF96LWr6aRb+qZb5rzy8h0ntmJYKeSZ15aqRtVyoirxJ4C44Q2jt+L8ThXX61SW+oYytjVzonIia9a5EbZqhzkRzP/UlWGla1VR//sUtqhxFdqNKqK76DVcqZOXXq+wmR4avVVX0j6y5RzJFM1yIqrq1pnxHPCt3t9HZWw1FUyORHuXJS/pL/anVcLW1saqsjURNfKezSzse5GMyTuIY4qeSBFe/NU9Y9EW0W910S6LSx9Go3RSb95EyyyM9j7DVTfoKKop5oo229z5no/PNyalyTL6preI/TkIKqSGVsrVzbocmiqeStr6qpoX4uiney00rt6lo1+O9y5NzTi2vbx8RfUVWyuooaqNqtbMxHojtqZkvdEraaow7WWOGZr7lO2N0VMnxnIkjVVfI1fIVljhkp7HRwytVkjIWo5q8S5H1f/T9fUVrHySpZFXL4dSOREsTwAdNmQArb3e4LHSxzzxSSNkfoIjMs88s+M+bzeGW6J0ULo5K5Wo6KB21+v8A2XyFHQ0arUyXOduhUVKZyM4mr3in4nxRlIyyZuMJJGRNxO9wo7fOj0mucyVVSxeokXaichYAHz2WZ8rsT1upRyyuldicAAREQAAAAAAAAAAAAAAAIVbRPeq1FG9IKzUjZuNE4/wJoJI5HRORzVzJI5HRuxNO9gvSXBZKF6P6Jo2NbNI7LJ7tiqnhVC5Mlcbc2uSN+bkfAukxE41/8Qs7JfXVqJT3BsdNXOcujA3PNWomefr8h33C+Ktqm4H5OLyKZszbpr1QugAXpIAAMwAAMwUnwVYc/iWTyNHwVYc/iV/kaSwfLvxGU7r8Ji3MdiHBtDbMQW22W64PrG1q5KqImbVzyNFT7llmWBvRt6lpqjXpxua1Fbybe9kv2kOp/aDhzx7fbNfiPr9U/wBPsobMlVI2JsidTVioonTOh26+7+SiTc9sNqjdWR4ke7eE3xY10Ua/R15LrI8OEKTEbui5bnLTW5+eirMt60k1auLPad7r1orPEP8AZUl4V/ZXRfzD/bcYNme9iz3zTIlkp2RPbT6o74EX4LcOfxD+Cc4+C3Df8RfgnOSAQfiMpN+ExbqVtw3M7BSW6pqYsQOkfDE97WZN6pURVRClwngaC/W9tbWVUtLTq5zVlRqaKZd9TS3DrZVeJf6iTgn9ln/+l3tIbTKqR8Ln9UNSWijinbHriIablmHG60xLJnxamajnUYeooZUsVvujqmqVNNszFTfuVU1d4n8ZXYd/a5S/y7vYUjinfUOwqtrZk0tMyjbjTO+WfedW7l9jkaj6rEMrJ3JnI1yNza7jz17cz9+CvDn8SP8AI0s7j1zqvHP9akcjXiEqLYzbwuJyIt9SJ8FeHP4kf5GmYuWDqSHGlNYrfVvq454t802oirnk5cv8Jsiss/7XbV4mT/lyGxT1kkrlauymvVUMdOxHpnmh1h3K7GsTFqL9LDNl1catb1K8h9uwNYbDA6vbiF8zYdaxPRqNdnq1lvdeu9X41TPYo7HavwN9pCHtcj3cpeuRsdgiYznN6Je3xNTZYKeop45JXtp6RzM4pU1Nd4PxLPoKz91I/KhS0X7NrD9RPeQjafxarpl5TX3RDXj4bT1TecqWvsafoKzd1I/KhX39bda7HV11LXRzzQR6TI9JOqUqCtxF1grPF+8yj45WOejVd1MpeDU7GK5OiF7hiVbvboK64J0JDMxVR/7qrnlln9i+QvOgbN3VZ5UKKz/stsv13e08ins/GKyKRWo+5FTcLp6iNH2sTXzwTXee326RtXJCmkqMXNctWvV4ULlKK0ZdVc2IvGmaavxMfufftTu38kvtRE6X9a/6ymUvFayJGrjviS/QQ8Ppp3OZhthy8TR9A2juq3yoOgbP3Wb5UMyCD8drfWNj8DpznUXR640lsVBG2qibGj0kauar1KKvrNS2htOgm+XNrH5dU3NNSmJwn+1x/wDLL7CFrVfKpfrr6zZn4vWMRrkdqhqU/DYJXPjVPNXUs7w602yhWpbc43LpI3JzkTaVFnwnSLJUVtxuEjG1Ktkp1lRMslzXqc+LWn4FBjPrA7xjTaXHscsH8o32GGtNW1FRBjkddNuhm7h1Nzeyq3JU16/eR98HbJ3ab/hPzg7Ze7af4SmBU81vqnv/AE3QbH1iqlt1jsUtfRV7KqZjmokWaa81RPedbJaIq+ghq7jO6jZPCySNXJqdpJnqzM7i/scn+sz2kNjL2FYd/kYv+Ww2kRiwczDmimmvBKJtRycGSp3nRMPWRE68N8qFJDSU9Xc56OiqEqEgflIrNei3PLNeQ+syJuddlWJfFr7SmMLGzouVrGc/BaGmsuC98s7/AMmj4O2Xu2n+EcHbL3bT/CU4IOa31UNj/pqh2Ljg7Ze7af4TLUiyV2KrhaKRizQ0etJma9JM0TNfKWJF3O+z6/fyq+002adrJsSK22RqVPBKKnwuRl7qaLg7ZO7af4StvdFZ7VTRzNu7H6b9HJypyHAzWOetcHjfcpHDhmejMNrk03AaGCNZMN7dDb0eHqZWO6Z1jqKTPqWPREzTl1kjg9ZO7af4Tti/rjD4v3mfMHubG5W4b2Mov9P0MzEkw2v0Lng7ZO7aeVpn8ZsocOWiKsoK1tZI+dI3MVU1IrXLnq8CeU7mdxx1jj/mG+y4lp3MklRqt1I6n/T9FFE56N0Nhb7BTyQadyq3UblyVjXIiaSZbdZM4O2Xu17J94k+LQ+IKQjkVsblbhuSRcAoZmJJhtc+KCkguVVI2lqN+ghkRs0jNaMTPav2IpdJhyyonXpF80z+5j1rxV4U9TySSTsbA7Da5FT8GoapFXl4bbX/AJLjg7Zu7Kf4T84O2buyn+EpwQc1vqIbH/TVDsVtiWW9XS5UzI13ihnRiys19SquTSXk1NNUuHrIq9ecu9m0z+5h+sxf4Wf/AHSQbNS1kL8m6mpScEop2rdlrHW8Udqt8tLFT3Jkr6hytRqqmarqyRPKTqXD9DvP/wAQrVpZs/1b0yXLlMZf+yPDv82ntsNzirr076jfUYuY1sSS216GbeDULplp+Xp1zv8AM/OD1k7sp+A4PWTuyn4FODX5jfVNj/puh2IeLehbC+3tt9SlYtXKrHJ83Zls8JfUmHaLev8A4hXOpJs/1b0TZymLxP1ws38z72m8xV13/wD6095tPaxIWyYTVbwSiWodBh2zONRhqwyRO0rw1cmqqfFKjB9CxKNUZWvqaRZl3yqVc0jXRTVn5PKfs/6iT6q+o+dzf9mdz/nnezET0dRIxjpIlw226k7uF0lK9sTWXR3jl93NV0DaF/8A3VnlQ/OgbP3WZ5UMyCX8erfWNz8EpzTdAWjuszyoZbCF0nxJA+pnp0ggjl0JJGa0bqRc1VfCfZw3MOwK8/zH+lpsxcXrJY3ritaxpz8NghkY218V/oa7oGz91WeVCkxCyic5lrorjpT1bcmLG7q88+LIilSn7RsO/XX3kUXFqyoVY1fbJSafhlPTM5iJfxJDNzC0TNSS44gnjqna5GSI1XIvfzXPYfvwV4b/AIlk81he4g6+VPhT1IVppLXytXDsbDeGRPajr2uRPgrw5/Er/IwzeIcG0NtxBbbbbq91Y2tXJVREzaueWSGwKSo/aBh3x7PbQmp6ySV+Fe8gqaCOCPmJnoS6fcrs28s6NvUtNUfvxOa1Fbyfhkp3+D2wWuN9ZHiN6pAm+LEuijX6OvJdewvcR9fqn+n2UKG7daKz+Xk9lSLtsiv5a72Jk4fHg5qLbK9i4sMVNVQxyo5kVAueU7MtDPPYXPQVm7qx+VDO4S/ZPS+Pf7anI2n8Tq6VUiY/JCCKggrEWZyWVdjT9BWbuqzyoR7hDaqW21NTFco3vhhfI1madUqJmiFAR7j1sq/Ev9R43jlYrkTEZu4LTIiqTMJVkt+oW11ZH0LTq9zVlT4rctiZqaPoKzd1Y/KhmcE/srd/NO9pD5JajjFZDIrUfcgpeGU9RGj1S3Qsa2ejZeI7bQ1DKmaRmk1jVzcu1V1eBFUtIqK2rEzoivbFLoppsVUza7jQxFm/a9afFSf8p5e3HrnV+Pf7SnsnFayNrX473TuEXD6aWR0WG2HruX3QNm7qR+VB0FZu6jPKhlwQfjtb6xtfglMfl6ufQuMKGyW3RrI6mFHq9q5qjuq1eRqeU0lPQ29IWpV1rYZ8urjcqIrV5DD0v7VbH4tfVIaO9deqr6/uNmbi1YxjXo/VDTh4bTvkfEqaLqT7my0UNvlqUuUarGialcnLkR7SyCsjbUVMqQ0sjc45v3XeBTLYn7HavwJ60NDQ/s2sXi095inFax0Sy49OmRm7h9MyZIMN79epc9A2fuszyoOgbP3WZ5UM0CD8drPWNj8Epi1vy2612OrrqavjnmhjVzI8/jKRMMyreLbBX17eg4JmKqSfuqqLllmpR4h6w1niy6s37LbL9d3tPNlvFqx0CyY80U1H8Op46hIrXuhe9AWXuq3ytMvfqOnvNbJZKCtV8sStkzhXNypo8n9R9IQsFftarv5T3RkcfFKuqxMc+yW7iSfh9PSIkiJfOx2+Da0PjRs2KahFVMnsVW6l5Azc0skbdFmKZ2t4karURCZVfKpvGL6zkV/b5dLG5+FxrniU5fBvZv4sqPK0y0+GnrjOWw0NzqKqJkaPSVq5qvUoq7F75riBhT9rTv5V3sIbFPVPmVzVyyNaqo2U7WvRb5naDczsrI0V+JpoZXJ+kbk1FReRSLd8D2e10S1LcVzOycjclVE2/aXNd8un8Y71mbxl2Pv8Ywjjq5HyIxeuRLJQRxxrIi6Z2J1u3Pqeoi32tv1XSxva10LlyykReNM/s8pJ+DKxb5vnCqbT+d1OZfXDsaw//Jt9hhUnj6ySJys1PYqGOdiSaX6HH4N7N/F1R5UKrE+DLfZMPVVxpMSz1M0OhoxKqdVm9EXZ3lzLsp8WdjVX/R7bRFXPfI1qpqp5Nw5jI3ORy5IpKwxhy3Ulujrb9RSXBlZFG+Dfk1MzTNctfHmnkQuugME/w3H5P9z8r66lo8GYXSombHvlFEjc+P8ARsIZ5PUTRvVEXIypaWnnjRypn4kC0WaxYhv1xo6K2RwNolVyo/YqZ5ZJkpedA4J/hmPyf7lVua9mGI/qf6lJB7UyPhVMC6mNNFHUYkenm6WyJvQOCf4Zj8n+46BwT/DMfk/3IQNbts+5t/h9PsUFiw5QX/HV3pKalhipom6cUT88mpm1OLwms6AwT/DTPJ/uVe5t+0W+eIX2mikraauYslLM2VrVyVW8Sm5Uyyss5q6pmaFJBDK5zHpouRHxS7CFuoYZIMPpG50mSq1OLLwl4uFsNWRd4uVmhqpH9U1zE2Jsy1qYzHXWuDxvuU9Fxf8AL4fFe8xdK9IElutzNIWdoWnt5Px95W9AYI/huPyf7joDBH8Nx+T/AHIQNXtk+5ufh1NsU+PaXDkWHmutNnbSVG/tRZET93Jc02+AvqLC+HbTQU77paIat1TE17Fai6tWvavfMxjbrEnjm+pTaYhq6eCiscMszWyTUyJG1f3lyabvNkdTo9FzzNBaeJtVyreSqHDoDBH8Nx+T/cpMO2awX+SuqYbZGynt0iLKx+1zda5Jr5GqTjhuY9a8U+FPU8jglfM1yuXQzqYY6dWoxPO1vmWvQGCf4cZ/59o6AwT/AA4z/wA+0hA1u2zbm3+HU+xN6AwT/Dkf/n2mTwdhyhvF2vsklLE6mop2ubG7PUxXPXJPsaX5G3NHtjXF73rk1iMcq8iJvpuU00krHo5djRqqeKBzFYmty26AwT/DTPJ/uUuIFwrQ1FvbRWNKeWabRRzU480yXb3yTTVcFZDvtPKkjM8tJChxT1xsv8z72kUM0ssqRyLkT1FLDDCssaZp7UPTem/Sf+yVyPqJk6pXs2ZLs2jhZSdrTfgVuKevLvFtKY0n4WOVqNTLuQkjoYJGI9zc1L2ouGH6q5MuM9oV9Wxui2Vcs0TX3++pl8e3xjYLeloY+ie+dUkcmXVJlsJZm8Y/Ft/8wnuLCiq5klbGjrJshDWUEEcDnomafyejf2WyKtNcadKmV3Vo5vE1dWWvwKfL73ZUjdlbXpkirsTnIuMa2lixBBSPmak8sCOazjVM3cylNL+qf9VfUYvraqN2HGtjKGjppY+YqJfuP3DkNuxDTriaelSRlHKsCtk+OuSIuri/fL3o3DvchfInOZ/c2/Zpc/553sxHUxrHLHLZM/HMipaSCrZjlYl9NELvozDncdfw5x0ZhzuOvkTnKQGrz3bJ7jY/CKL1EIWA6d1xoK251qpPBS1Ko5jvjK3JFyTymp6Ow53Id5E5zNbnk0VPgO/TTPRkbKhVc5eLqWnanniqoGzQvR7HbFTjNurvHJ5KZeBo0NDSzx+WxLp3Ifd2udpmv1utdHQugfVuSNF1ZZquWa6y80LPak6Crrek9RF8eRuxc9acfIqGHqP2g4d/mGe0hsMSdfqn+j2EMZERsTZU1Ukjo6d87oHMTCncl+nX2kjo7Dvchfw5x0dh3uQv4c5Rg1uc/u9xt/g9F/tldiisgnxLYaK0xLRx1M6RytXLJ+b2onrU1u92m0/2Out6VE7NbpG7Fz1ptUwtx7N8M/z0f/MYa3EtbTLiiajSZvRCNaqx8fxUNyS/IZIiZ59CvjoqXtL4XMTD4IdbjcsPxWyqkbaVa5kL3IqImaKiL3yJh1lDWWeK/wA1MklG9XM3p3xs0XL3FXdutFZ4h/sqT8JfsnpvHv8A+YphGiPhWRUzQklo6eKZsTWJZ2uSFx0Zh3uQv4c46Mw73IX8OcowavPf3e43Pwii9QsrpXWJtorFgtaxypA9WP1dS7RXJdvKVGBqdJ8OMvVzRtVE2V7HMX4y8Sd7jPi5da6rxL/ZU6YSqYaTclfNUSJHGlU7Ny/WQ3YvzIXKqZouRoTUNLDOxqMSy65IaHo/Dvcf8E5zPTS2i447pKG32/oeqliXe5FTU3JrlX8EU+o5GSsbJG7SY9Ec1U40Ur7N+161eKk/5UhjSuV8iouVk6ZE1RRU9KxJIWJe9tENp0daqL+zVFC6WaLqXvTLJypx7R04sncx/wCHOVN1661XjVIgXiFU1VRHr7zabw6mc1HK3U0PTiydzH/hzmUutfLcd0O12+2SPpaaeDqo12K5NPXq7yJ5CUVVF+1ax+Ld6nmxS1tTI9Wueui9TUrKKCGNHsbndDbpW2y3/wBjqaF000Wp70yyVfKQrxf7PTWmomZbpGOazNFTLV+JAu1ZTTYiraaOZrpo39WzjQp8Q9YKv6hElbVcxI1etr/Am7HTclZUbna/tLEAFWW5QXKV8OOLBJHGsj2zNVGJ+91ewk32HFDsa1t1p7DWzwytY1rGtcrdTGpty5UOdT+0LDn8w32zeXm93Gku08EFRoRt0ck0Grl1KLxoW6SJHAxXJdFS1iidE+WqekeSot7+xDA1EmJJqaWKsw5VUlM9itlnc12UTVTW5dWxE1mos9LBR7nNJDTVKVEaVDspE4+qccr1frnUWK4Qy1Okx9LI1yaDdaK1e8ccKfsrof5l/tuMbsdTuWNLIZKkraljZVuu5+AAqi7I1x62VXiX+pSstKXat3KZLfbrfPMrqnSa+FFVdT0VdSFncetlV4l/qUn7n9VNR7mW/U79CRKl+S5Iv7ycpZ0i4YXO2Up69uOZrd0sZyndi2Cmih4K1z97YjdJWO15JlnsLPB9LJJjynrrii0Nekb06Ckbk7LQXJdev8C+4R3btr/LbzFBZ6qas3Y6aad+m/odyZ5ImyNeQlhfFI5cCWUhqY54405rsSaf5LS49c6vxz/WpGJNx651fjn+tSMVLvOUu4/MTwBS0c0lPup2yWGFZnthflGnH+jeXRWWX9r1p8TJ/wAqQ3KHN7k7lNDiOUSKu6EWpp8V0+JrnXR4frqiOplcrU0XaKJnnq1HxX9PKyikguliqLbRvy3yqkaujHr480Tj1beM3twv1zguE8UdTosY9Uamg3UnkM7i+93GqwtXQTVGnG9rUVNBqZ9UnIhsc6J8iIrfK0ua3IqWRKqO8m17d22hc7zFT4Ds0MMyTRsTJsifvbSrJtF+zexfVT3kI06xLSqb3D7LAioCuxD1grPF+8sSuxD1grPF+8ih9K3xQnn9C7wU4TxXq6bltnobdbamTep9NJIUVVcn6Tk8J8tnxY1qJwSrdSZfFd+U1eHK6ooNzOzS00mg9Vcirki6s38p9cJLv23/AJbeYsqiaJrsEjblNSwzubjhdh6e4q9zuk0cZVtbVPWCvlpHJNROTJ8XVs2+ROLjOsv61/1lI2BqiWr3WLxPO/SkfRKqrllnriJMv61/1lIK3RngbPD745L6/wDOZzABXlsU1iqJqbdRfLBAs7+h8tBPqIRKWlxZb6ytfwdrqlJ5Vemk12Sa12au+WmEv2uO/ll9hDUT4hujJ5Gtqcka9UT9G3mLiSRrI2o9LoqIc+yOSSd6xLZUVfiYS5R3W4UiwXm1TWil0kVamVq6KLxJry2m9vDWR2Kxxxv02tpkRrvnJosyUymPrxX1uGXw1E+mzfWLloNT1Iai5djmH/5NvsMI5FatMqsyTb3E0SSNq2tlzXf2KVAAKsuikxf2OT/WZ7SEi/xX+6YXwyy32mqeylpmdVCjl000GZZ5cuRHxf2OT/WZ7SG3huFVQYNw8tLLvauoYs+pRc/0beXwlrTP5dPjXov0KSsYslVgTVU/kxfROLP4RrPNdzFzufUccN0vNS+bRqpoM56VUydC7PWi+osuEd27b/y28xS4AmfPi/FMsi6T3xq5y5ZZrpKZwOiejuWlrGFS2dmHnOxXXLuO4AKcvgU+Eampp8a3zoWldUPkp3N0W7U1t1lwRdzpVbugX1U4qZfaab9F+/wKviKojWXS+f0KK00+LrZSOgdhqvnVXq7Scx2exEy2d4XSnuFxgZFfaGWywtdmyadq5Pd83Xlxa/sN3wju3bX+W3mMhujXStuFnpmVU2+NbPpImiia9FeRDYimhllTC2zl6mvJDUQwricitTobrF/XGLxfvKAv8X9cYvF+8oCuqPSqWlH6BoM7jjrFH/MN9lxojO456xM/mG+y4ko/1DTCu/TPLXGMeI7jcbTV0VlrHspoUzbG1yo7Xnr1ELonFv8ACdZ5rvynoV6udZQMo20s29o6FFVNFF4k5UKrhJdu2/8ALbzG1JNCi4ZG3VCvggqFbiidhRehBwBR09LZMQOhqkmkkaiysRP1a5O1evyHM4bmblfbcVucuaq7NV+x53Iq5LPRLk/DXI5rlRLH4ADQLQpsFT1rGYugoqN9Q6duh1GebVylRPWRLXBi620aU7sNV0+Squm5js/UX+5a90VRi2Ri5OY6NUXkX9KXPCS7dtf5beYu6iWNi4ZEui2+Rz1LFK/yolsqX+KmObTVldfLXJfKWSzugqWLTtmb+vXSbmiZ5bMm+cbbFXXp31G+oyGK7jV3DEmGeipd83ur6nqUTLN8eezwGvxV16d9RvqNefCtO1zdNtjZpsSVTmv85EzXfQpgAVhcGbxW5W1tociZqlRmicutpbYtixLVYvhulLY6ySKOBGb2xrlaq9UnJ3yrxR1ws38ynraek4hvFfQ3LeqafQZoIuWg1fWhbxyNjpmudmmafEopo3S1bmsyXJb+CHn7p8VKxyPwnVsaqa3aLtScuw0WDqOmodz+5RUtW2qYtUrle1Ni6Mer8E8p2nxFdlp5EWq/cX/028ngKvc3/ZpdP553sxHjFjfE9Y0tb4iVszJY0mXFdcu46gAqS9PwocHPuMu57eaG30M1Q+eVUR8WeaLk3VkngL4+NyqaSmwRd5onaMjKjNq5Z5dS0sqJbRvXa31KjiKXkjTe6fIoqBMW0VFHTLheul3tFTTcx2a68+Qn2WnqarGNqqbxA+1VEMn6GCVMllTlTPI03CS7dtf4G8xnqyvqa/dJw4+ql3xzXKidSicfeJYpIpJPIbZc8yGeKoii/MddqdPkX1/6+VP1k9SFcWN/6+VP1k9SFcVknnr4lzD6JvggKC4yPhxxYJI498e2Zqoz53VJqL8pKj9oOHPHs9tDZovTexTU4hlAq96fM632HFLsa1t1p7BWzxStY1rGtcrdTGpqXLlQ4zyYknp5Iq3DlVSUz2K2aoex2UTFTW5dWxE1/Yb693q4Ud3mggqNGNujkmg1cupReNCjvV/uc9jr4ZKnNklNI1yb21M0Vq942OdC56Nc3NMrmm2CpbGrmu8lc7EmyU0FJubQQ01Q2ojSZ2UicfVqQDphH9lFL49/tqczWrU/Nspt8OVFhuiWzBHuPWyq8S/1KSCPcetlV4l/qU1o/PTxN5/mqVVpS7Vu5RJb7dQTzOdU6SPhRVXU5FXYftNJiynpYoOCla/e2I3SVrteSZZ7DRYAqZqPcx36nfoPSpciLki/vJyk3hHdu2k9EzmLaomia5WSJfO5Q0kMz244Vw9CgwrSyz4/t9dco3W+ua2RG0UjcnObvb+q15LxrxcRa3HrnV+Pf7SlVQVc9buyWiaofpv3h6Z5ImrepOQtbj1zq/HP9pSCrty2KmhtUN+e9Hapr395GABWlsUiyyQbpVnlhhWaRsS5MTavxz8uMGKYsW3C4x2CunineuizRdops1pqO9J+1Wx+LX1PNndb7cqa5zww1OixrskTQavrQuVkbHC1XJdFS1ig5b5Kh/LWyot7mBrVvlbRyU90sdRbqNyJvtVI1dGNM9SrmiceSfabVsMdPgSzwwzJNGxqI2RNjtpSYwvlxqsLVsM9Rpxva1HN0Gpn1SciFpb/ANm9i8XzkSqx1O5zEsmxIiSNqmNlzXfu2IIAKsuyuxD1hrPFnCeK9XTcts9DbrbUyb1NppJCiqrk/ScnhO+IesNZ4s0OHK6poNzKzSU0m9ucrmquii6tJ/KWtK/BBi2X6FLXMx1CM3T6mWbUYsaxG8E6zUnzXflLXAdIq43lrqxVpbhJTOSWhenVRp1OSr4URF2cZb8I7t23/ls5ikwnUzVe7DXzzv05HUmt2SJnk2NOIzp3xPcvLSy2+0I6ps8bEWZ2JL+5dybVfK5vrr6zkdar5XN9dfWcioXUvW6ICnsVRNTbqL5YKdZ3pTqmgn1ULggYT/a47+Wd7KG7Q5vd4KV3El/Laq+sn1KxlLiuhu9ymbh2vqGVM7ntzjdk3qnLq1d/8D5uUd2r6RYL1ap7RSK5FWpmYuii8Sa0Tab2qxBdI6uZjanJrXuRE0G7M/AZXHt4rq3DL4aifTZvrFy0UTj7yGy2aGSVPJs7c1VgqYoVu7yU6GsvDGR2Oxxxv02NpkRrvnJos1lKW1x7G8P/AMm32GFSaFT6VSxovQN++p+FPizsaq/6PbaXBT4s7Gqv+j22mNP6ZnihJU+gf4L8i1qsMXfGWF8Px0280SW+lj0HzaX6XNjclTJP7v4nz8HeNP4hovIv5S5m7DMOfyUf/LYVpvzVWBysc29t/wDgqoKNZGJI1ytvt3e064AZT01+vVA6PO4U7NCqnReplcjtap9veQ4Ebc27L8R/U/1KSSKuSytJ+HKq47/eoABXlqVeCYaybH15SinbC9IlVVdxppNO9HuW4qt8ax0l8oomOXNURHbfNOu5t+0W9/y6+00klxNNykTK90T4FBBTrUPfZ1sKr8VKPEOH6/DVLFU4nqornTSyaEccOaK1+WeexOJFN1i/rhB4r3nnWO+tcHjfcp6Li/rhB4r3kUzkfTo+1rksDVZV8tVvbr10KAAFYXRn8bdYk8c31KaK74Hv+Iaaz1UV0pmOpYEWNZM825o1eJO8Z3G3WJPHN9Sm6vnW2z/yrfZaW0T+XTI/a5TVEfNq1jva6J8DP/B5jP8AiCj8i/lJeA5KJ1nxDFSwLHLEiMncv77kR+tPxORH3MetWKfCnqeexSJKxy2tbYhqIXwOaiuxX3JAAKgvwVWA7fcLnJimloalkG+q2N+nsXS31E4vCWpw3Mf1mLv6P/ulhReY/wBnzKriN0WP2nKk3McW0MG8017oo4889FNL8pFuVkq8N19udiaojuXRE6Npt5zTe3IqZqupOVPIW5nMUdcrL/NJ62k0NQk0uFW2v16kE9K6niV6Pvbp0N1inry7xbSnLnFPXl3i2lMV03pFLan9C3wBm8Z56FAibd/1fgaQzeMvi2/+Y5iWi/UNIeIfpnffU1WJMA4ivd7gukV1pWSwQpG1z880yVy8Tcv3iE/c/wAYsjc6S/0bmNaquREXWnH+6aPFqr01Zl9CnrUoZdcT8/mr6jZfVYXYFbexpRUbns5iPtfon/JLwbNQT7n9xfb6d0ESVaorXLnm7Rj17V4siMctzb9mlz/nnezEdSKvRGy2Qn4a5XRKq7gAGiWRVYIstxvuELxQ0VVHDHPUKxzX55KuSd4l025ni+jgbBBfaNkbPitRHav8J13Nuwq+fzK+y06l1Uz8p+G1755nPUlMs7MSOw2yy95Agtc2HsY2amv8rLhWTzNWnlhzRIuq49nHrNHiTr9U/wBHsIY+f9oOHf5hntIbDEnX6p/o9hDXqVR0DXIlr/5NqkRW1LmKt7Jr7irABWluZ68Ne7F+HmxO0ZFq2Ix3IumzJTR3nc7xJcMQyXiC70kUsjUbpOR2eSIifNy4jPXLs3w1/Ox/8xhtcTde5fqt9lC2STlU7HWvqnxKJ0POq3svbRfgZ6swPiigoqituF6paijp4nSzxNRUV8aJm5qdSmtUzQurLLSTbmsD6GB0MKzuyY5dnVqU116z1viH+ypOwl+yil8e/wBtRjSWBzkSx6sboahjFdivnmcwAVJeEe5da6rxL/ZUi4Yw3dMSbmq0NLWwxQyVCroSZ5Zo5F4k7xKuXWuq8S/2VJOCf2Wf/wCp3tIWdKuGBztluVFcmKdjN0sRotzfGMMTIo7/AETWMajWpkupE/pPqwUDrHui2+23hzay6OY+RlTHnooxY36stXIvFxncrLN+1+0+Jk/5UhLBOkzlTDbK+RBU0zqePFjv0spfXbrtVeMUhky7ddqrxikMqn+cpdx+Y3wBSaM790qzNp5EjlWNdFy8Wp5dlVR/tVsXi19Tzbok/MXwU0uJLaFF70LKt3NsTy3yrudNd6SN9S7Nyqjs8vNIdzwbiO022evu92p6uhgbpTQsRUc9vInUp6y9vPXiq8YUGIesFZ9QmSpRZEYre6/U1exubEsiP77dN9ybBU09SirTzxzI3UqxuR2XkOhzrMJVNQ5q4FbDQUyJlUNnerlc/iVNLS4igxHbsaYWt7K6419MsUkqRIkSNcukqKvzU+apH2HGt43JYmXiSMykaqL1LPDNG3E1SuJHv6HfZJkVsKJpJLl1W3VlsLm4Vi19dJVKzQV+XU555ZIie4k1FvpcNUzKW0RdDRV0enUN0lfprlt6pVy+wrTCrkS/LbohnQxrZZn5q4i3TrTW/wAvJ7KlNYb/AH9mEae10OGautp45HPbUxRvc1yq5VVNTVTjy2lzdOtFb/LyeypZYKraih3MKKWmk0H7/ImeSL++7lJ6VWpTuVyXS5r1yOdUsRi2UrIrlSSaDFqoGzOyRYt8TSR3Jly8RLOsuH8J1DZH0FtfHd5EVYJnyyaLZ1TqXKmkqZaWS7PsK7gTuh90aHyp+Qw7KyTOJ3vJUr3R5TMVPAjXivWGqorbvebbk9YFfn8TNWtzy4/jGjjoW4VsrsNsk6IZp77vyporrXPLLXycpRYJt/TypvLr+1Kqrsb2LTPaugkb835r1OWlrY3bnsLWrq562dZqh+m9UyzyRPUJv+3iSJNV1MYF7VOsv7U0OJmluVZad0SKsoLfJcJ2QqjYI0VXOzYqKupFXV4DSldh39rtN/Lv/wCWp5QZSLfZTPinoU8UP1l6rZ6uea9WySzJK5XR9FZxo9VXNURXImeWomwzw1DNOCaOVueWkxyOT8C3ujbTeq6eDElO+sippHJTNa5WaGvJfiqmexNpTVWELrPLpYKfBQ2zLJYp3qrt8416pHLsy4zJYYpVvGtl26EbamaBqJK27d0OjnaLHOy2JmRsJ0iXHe8dK/QkonugSkyzR+bdHPS4v1nJxFNf6HGGGkpXXSvp3xVUu9okSNVe/wDuoba4UVPh1jrNao+h6CREldDmrs3Z7c3Zr+6nGZJEtKxzlzVcksYOmSskaxuSJmt/vxIVVOtTVyzq3RWRyuy5ClxR2OVf1U9pC1KrFHY5WfVb7SGjCt5mr3p8yznREgcibL8iPQYixHJhe32+mwnW1EFM3qKiOORzZE18jcvxLSO40M0iRxVkD3rsa2RFVfxL2y11TQbndjfTSaDnMRFXRRdWvlKyfC+GpYXMwzblpbuvyaaWZ6tavHmjnKmzPiUsahsMkiouS/MqKWSeGJHImJvysfJVV8q3C9UmHFTQbcU0Vm2qzWvFx7OUkcC90PuhQ+Vv5D9wJDFebNV4huDN+udvm0aafPR3tMkX4qZNXau1FMY6TlLzHqiomxJNXpM3lxoqKu5dTRdJ7RBhtF31tC7VMqZK7PNdnF8bl4iAdaiolqpnTTO0pH61dkiZ+Q5FdLIr3q5S1hiSJiNQzdovNwsmPblU220S3SZ8GgsMSOVWt6hdLqUXjRE+0s6a7VC74t5pFtEiuzZHU5xq9OVEciajvufftQu38ivtRF1Vw2O+y75iakkrJoVVkLmuczRbydSqZlrNylYxsmyZlHAs7ZZHRZ56b5qV0Usc8aSRSNkYuxzVzRT4q5uhqOadE0t6jc/LlyTM+KnB+IZp3PwrNTUlnX5PDK/NzfnZq5HL8bSXaVFVb8S2jENntV+qoJqe51DYnsiy6piua1yKqNRUzR3Ea7aFXORWuRU+htu4m1rVRWqjvqXWEqNFjjx3p/pJUdB0JlqTJdHPS+zkJEj98kc/LLScqk+408Vk0rJbmbzQR5ObDnpZKuteqXNdq8pXEFVJifhTRMjYoYlazG7znZlDjPsff4xpJ4SYhq7dbIZMLVkNJSwtb0Vvb9FWaKdWq6OSJkme0i4z7H3+MabyarfDhmyU6uXoepomMnbl8Zmg1FTPi1Kuw3IVYlL5aXS5pVKSLWpy1stv5MzFcKOeRI4ayCR67GskRVJB+1WGLFNAseEaDoO7Kv6KaaV7mon72pyuTZnxFZV4U3QKKjnqprhRb3BG6R+WjnkiZr+4Q9ja/OJ2XeTfiCx5TMVF7jnJBwlxC3Cr3dDtmZvi1CdUqaKaWWj9nKaSsnWKhpbPlmltYlOkmfx0aiNzy4vildg6nimww3FUjc7wyV0TanNUybnllo/F2KvEdpJHTSPkeubnqrnL31PKleUxIU9vie0iLPItQ7wTuPgzNhvVzs2J72tss010dPmx7IWuVWJnt1IppiNubvVmLsSOauSpHmnnGdBby77HnFLq1ltyPSXVyQ5XaHpXUZ6oKhdB2jxLk7JctvkLBj2SMR8bmuY5M0c1c0UmTUeG74/ovEdE+rrctBJGvczJibEya5E414islwbi+WVz7FV0kFscqrSxyORXMj/dRc2quzvqeLTxTZxLZdlHa5YMp23706nxda1bdbZqtGaaxonU55Z68ibhmg6UUyYtbJvkl4h0XU6pkkWa56l4/i8iFFT2y8x41t+GsTTxVVPWN05IoskRzcnZdUiIqa28Rqbh/Yk6UU/6OipF0YYtuinhXWv2qZqzssS+svVNiNJErZkt5qaopBMzjrrVD433KaYzOOutUHjvcprUfp2m7X/pnF3XYnv1zrYprhhart1MxujJPKyRGMTlVVaiIdIa6jqH6EFVDK7LPJj0VTYYnqI3Tx2+tRX2+eP9PEiZK5PDtT7FMrWYWts8TWYIpW0Nx085JKiRzmrFkuadUrkzz0eLiNmVkMr1stnfA0YJ54I0VUxN+R+lVBQJja+1OG5JVpGUjOiN+a3TV2WimWWrL4/LxHzdcOY7s9sqLjU3CjWGnZpvRmiq5d7qC8w7TRUWFaHE9O3Qu9cjo6iozz025rq0V6lPiN2JxHsVP2e8r1vbbcxmq0qrQx3S++xKulwWtdE1Y9DeGaG3PPvkA/XLmqqvGfhWOcrlupdMYjG4WmXwpfbtamXqmtlhqLo2qfoyPha5d6+MibGry/gXFNdWpCnTRrbdVZrpU07tB7U4tTsl1pr2ErcskfDRYmljXRex7XNXv5PLCa3YVvMi11+t8lVXyanytke1FRNSamuRNmXEXNSkLnI2TLvOfo1nY1XR5psRWqjmo5q5ouxSvvdydabctW2JJcnImiq5bTq7BeOtJVo66iZTKv6FqqmaM4k+JyZESzWqurMbuwxip8dZE2FZXxxrotVckVvVNRq8Zrx0K4rqqKhtycTbgVGoqL0L6x2xMK26WtZKtQt/ibK5qt0d51KuSbc/1ne2Ecl108iubR6X6CkVY4W5fFampEz2rqRNpENSolWSRV6G7SQpFGm66mYxZNJTXWyTxRLNJFOr2xpteqOYqJ9pd1WIr1cbn0VdcO1NqplaiOmna5rGrlq1uaia11FXfuyPDn82ntsPQsSvpqqufa7tG6e2Oa1z4W9SqrtRc0yXaicZvosfZWJImt/ZmVj0l7a9Y9U+OSZGYgrKaqVUp6iKVW7d7ejsvIdj4q8JsqEbwEhZb5E+VLUSOdpp+7lpaX97k2lNe7FjmwWia6VtwpFgg0dLe9FXa3I1NWhyqhAlFjW8bkt3mx+JIxLStVFJNstiYxvNVE+XoXpI9JGq1unvuvZxZfF/EvrpcHXKr6IdHoLoo3LPM+bVTxWrDdBdaJm9Vt2ga6slzV2+rlnsXUm1diIRTCqdhtE3RDOhar1Wd2qnxN+ok+ovqM1hG/XqiwvV2y24dqbjDNUK91RCx7kY7JvU6mr81PKaWb9RJ9RfUfe5fPJS7ndynhdoyMrnK12WeXURk1ErUikVyXTL6kPEUcssSNWy5/Qgw3SBIW9GyRUdR/6kE0iNfGvIqLkqE4ky2jBtylWsu1rlnrpuqmkSV7dJ3LkjkRPsQqeBW6H3RofKn5DDsscucTveSdtkhynavdbqR79d3WWkjmbCkqvfo5K7I0VHZ24ItdRZY5lrG1q76sit0FbqRMsteewoMJ2d99xVcbDitG1qUESuRrHKxEfpNTNFboqupS6q62prpEkqZd8c1MkXJE1fYZSp2aLAmq6mEK9sn5n7W9FI5nLzWVFvxfZ6ykpHVc8ObmQMRVWRc9iZIqmj4yp//kbD31yKh9N7FNjiP6dfZ8zu++3OsuM1VebNPZ4ZPiyVKOYxXaupRXIiZ5Iq/YpKgqaepRVp545kTasbkdl5DQX5aC6XKa3X6J1Vb4Xo+KJqq3Rflki5tVF2K7j4ygrMJ1E72rgVIaGmRMqhtRIqq5/EqaWlxEr4oZnLgWztuhrx1E9O1OY27dzoQcO0SYjrn4hfJvDrHOmjCiaSS5dVt4tnfKzEVsxrhm2pX19wpVhWRI/0SNcua5/3U5DYrRU1gtcEdsj3htxgbLUpmrt8cqJr6rPLbxZGbYezNWRy3XpYwfUJWPbEzJOtzjcKxbhWyVTmIxX5dSi55ZIie4qrr1prP5eT2VJZEuvWms/l5PZUr41vKiruWr2o2JUTYqLBiC/R4PhtVDhirrKdsjnJUxRvcjuqVVTU1U720tornSOaxktTDHOup8LpE0mO42qm3NF1Ftgernoty+mlp36D9+emeSL++vKc5rDhKsbJNDbXpdpkVzJnSyI3fl2Oy0sstLXsy7xaVCQPkwuyUpKN88UWJiYm/I4lVea50NTRW1I80uT1gWTPXHmrW55cfxvwJPArdE7oUPlb+Q+ME0CXyovLr+1tXV2R7FpntVWpG/N+apo5I7Wxu3PYRRUasdjeqKibE83EWyMwMRUVdy8ZQtwrZVw2x61DdPfd+VNFda55Za+TlIZ1qqqatnWaok035ZZ5InqORoSyLI9XKWVPCkMaMQzM9xq7VuhUNbQ0ElfURQu0KeNFVz82vRdiKupFVdnEWkd5rpquea9WySzpK9Xx9FZsR+a60TSRM8tXlPmz/tdtPiZP+VIae6stN6rZoMSU76yGmlelOjVVmhr1/FVM9ibS0k5SwsbJtqVDFmSpkdFnZdNyohnhqGacErJW55aTHI5PwPp7tBiu5EzOVXhC6TzaeCnQUNsyyWKd6q7fONc3I5cssuMob/QYvwylK66V1O+Kql3tEhRq+HPqUNdKFXLdjksbK8Ta1LPaqKW+E6Tp2rcbOkWKS2TLA2lRM0emimvS4v1nJxFpW1K1lZJUK3R3xc8s88ibcaCmwyjrRZ4+hqGZN+ki0lfpPVcs83ZqmpqcfEVakdXIiuwN0QloYlRvNf5ylVijscq/A32kOFBiLEcmF6C302FK2ogp29RURxyKkia9epvvO+KOxyr8DfaQ1Vmrqmg3OrJJTSb250aIq6KLq18psU7mNpnK9Lpf+DVrGvdVtRi2W31UoY7jQSvRkdbTve5ckakrVVSSfc+GMKyQPZh+2Op7qqf2WWSaRWtf383Kn4KV/ArdE7fofK38hEtG1+cTsu8m7e6PKZiovd/kjV0i3C90mHFTQZcE0Vm26G3i49nKaSWLpNZ4MNtVZWUK6p11K7PNdnF8blKXAdPFeLLVYhrm79dLfNo00+at3tNFF+KnUrtXahYTzyVMzppn6b3bVyyPaj8mNIU16mNN/wBzKs66Jp3HMzVDdq+zbolbVW21y3KdYEZvESOVclazXqRf/FNKQ8Fftbrf5T/TGY8Pykd4fwZcU9E3x+inKnu9U+SV96oHWdznZxNqs41enHlpImeWryk+KWOaNJIpGyMdscxc0X7Szr4rLfal/CWmfWOp3K2DRc5miirr+KqZ7E25lNU4PxDNO6TCs1NSWdfk8Mr83N+dmrkcvxtJdpksEU3o1suymKVU0CWmbdN0Purn6Go56hG6SxRufly5JmfuE6NFjjx3pfpJUdB0JlqTXo56X2Z7CkqrfiS04itFqv1VDNT3OoZE9kWXVMVzWuRVRqKmaO4jY3GmisqrZLc3eKCLJzYc1dkq611rmu1eUz5fZY1cuq9UI1lStmRieamaopAmk32eSTLLTcrsvCZ7GfY+/wAY31l8UOM+x9/jG+s1Kb07fEsatLU7/AlriTENZbrZDJharhpaSFreit7foqzRb1aro5ImTc9pMiuFFO9I4auCR67GskRVU009U+HDVkp3O/s1RRMZUNy+OzQaipnxalXYUVVhexSwLHhGh6Du6r+hlmle5qJ+9qcrk2Z8RuzMhlkVNHfMrKeWeGJFtib8j5KqoZ0+xBDhVy7yytYrlqE6pWaKK/4vH8TLbxnWfCO6DT08k8lxodCNqudlo55ImfzCVgmnirMNPxVUM07xSzuiiqc1TRaui3LRTqV1PdtTjMY6bk3keqLbbcymrUqESKNFRV3LOsmWKjo7QmtlsZ0Okn0miiNzy4vikM+pJHSyOkeub3uVzl5VU4T1ENJC6eokSONu1y8XEV73LI+/VS2jY2KNE6IZ7DtvxHcMV3mPDlxhopUVd+WXY5uls+K4mV9VU4NmS3Yhm6Kq5G782SmTSboKqoiLno682rxE7cvljnxXiCaJyOY+LNrk400i7orw+iidH0PDNm7S0pUzVO8XFRJG2zJUyt7SipmTOc98K539nUqqWoZV0sdRGioyVqOajtuREv8AUS0lkqZ4HaEjETRcnFrQn1OB8O3eokuFRe6mnmqXLJJDGrUaxV2omrYVNFZKCxbqNmoaCtkraaSNZHLLkvVKkiZak5EQ14qWNXYmvv1sbEtdKjFa5lul+80Fkp4rfha3X2kYkVyr48qmoTWsm1daLq4k2IRydedV1qGJqaj9ScSEE06iTHIqlhSQ8uJN1MxjvrVB433KX1zsWNbdE68X29UlXS0jdKWOJV03N5ETQROPlM1jaup5KaOlZKizRy5uYm1NR6liaodS3emlaiO0Y/iu2LrXaWDXJHStxpkVcjVkrVwLmYW1Yjo7xUOgpo5kcxmmqvaiJlmicvfLYm3KKjxbTNt9ye23wxvSVJadERyuRFTLXnqycvkM/esBYet1lrKulv1XLPDC58cbnNycqJs1IQdngkW7HW7jYWrqIUtIy/eh9WGmhv8Aj+ps10YlTQRwb42FdSI7JmvNMl41LmsqJZZEhe/NkCqyNvzUTi/A+MNJluW2uZERJFkkRX5a1/SycZxMKt2G0SdPiZ0DeYrp16r7gZrB9pxRdHXduHrpT0cW+o2obMq9XnpZfuu75f1VZT0UW+1MqRszyzXlPncvejrVilzHalycip9V5LQ3ax7rbEHE7K5jb5lXWXZ2Fql1ovb31NbDk58lOmkxUcmaZKuS7F5C6hlbUQRzMz0ZGo5M9uvWWtJfH0lO2FKWCTL96RualXLgDDddM+slvtVFJUOWR8bFbkxV1qiathjhp5s0XCvUl5lVT5OTEnQqMUVlRQ2d01NIsciPamkiJsNPFR09ksdBU22JKeW6UzX1jk1767RRc1z2fHdsy2lBhS1Udq3V1ttLUvrKVlMrmvlyXSzai8hb1qqtbOmepJHZJya1Mp0SnhwIt79SOB3aqjG5LYehxMvjBsr57W2ByNlWZUY5eJ2bclNQZXENZTVF3tUUMzXviqkR7U/dXSbzENCirOip95G1xFUSmci93zQvrrasW2Bi3zEl2pq2liya9kCqr1z1Jkisam1U4zhar9SXh0jaZsrViRFdvjUTb4FXkNnfat9Hf99RjZNGNOofraurkKq52+3YvbHHc6jpalMqqxaZEbp57c80XZl+JNIsErla7J25qRJUwMRzfKbrbqQyDhCjp8R4lvFLd40qoaJNOnY5VTe10ss9WX4kLFOCrHZsPVVwob3VVFRFoaEb3Nydm9EXYnIqqauBGtwHYpGtRHup2aTk2r1KbTNkbadjpGriMJJ3VT2wqmEjVVXPWyJJUSLI9EyRVRNhFl/VP+qvqOhEr62mooFdUzNjR6Kjc+Ncirbdzt1LpcLGbIU2CLJi+7YdqEsd2pqShWpVskUyqiufotVV+IvFo8fEdajEUNinfarmss1ZSroSyRNRWuXvKuXqQu9zZVbuaXNUVU/trvZjLiC/Pgp2RdB08mimWk9uaqXNVJDzMMqHP0Uc/Lxwr3WKopMWV1TQWlk1LKsUizNbmiJsyXmLb4N8LfxJW+c38pxwDbqW37pt0t1PO6rpYKN29vlyVV6qLXycakUNLGjsSOxW6WJ566RWK1WK2/W5e1lHT2CmZR2uJKanq4kkmY1VVHOXVnr8CFafUrlWV2a59Up8ldLIsj1cpawRJFGjTM3yKsnxXZ4rdM2Gre9EhkfsY/S1KupfUXF2oMS4aRbzie5wVsEjki0afW/SVNS5K1qZZN5SqbWU1bugWBaaZsiNqmI7LiXSQ9Autc+ixHUyJGyVMmpoSa0+K0tFe2OnY2RuS/5KdGukq3uidmn+DKWm8U14ikkpmyIka5Lpoie8nne5WW04vkZPc611tdTpoMbTIjUei681zRTKYywjZsP2VtZbLxU1UyzNZoPcmWSouvUichrtpoZV8h9r9DZWtmhS0kd7dS2wNTQ3uO73C5M6IqbXI19HIq5LEvVLmmW3W1Nuewsp6marlWad+m9drizu7WxWy1b21GadMmlo6s9SbSnIqyS78KZIhLQRWZzFW6qRbr1nrfEP9lSuwrh7Gt3wrD0qvFLBbnPdoQSquaKjlz2MXjz4yVfK6lpbZURTzNY+WF6MRf3lyLbCDlbuUUqtXJd/f7amzSqrKZzlTqata1JKpjEXP5GdZiikp6xLbUNmdVRybxI9rU0Vei6Kqi57M+8XxZrdkqqRaCangZHLHvLpUb1TUVMlXPlKf4NsL/xJW+c38pHy6eXNrsJLz6qHKRuLwKu91ErLnaKRr1SGrqUimb89qq1FT8VNXc6WKyOdZ7cxKehyR+8prTSXWq5rrKHc7pIae7YrpWPWeKlzZDJJrXJHPRF8OpCaqq5c1VVXvipTkxpEnvPKRe0TOmd7tvux+GaqKe6VW6HQw2WqZS17oV3qWT4reocq56l/dzTYaRzka1XOXJqJmq8hTYdrKet3WrTLTStlZvUiZp4qQx4ffmKvcZ8UVOSid6He5w3zCLkrcUV0VcyrcrWdDa1R21VXNrTtarrT3eldUU7Xoxr1Zk9MlzyRfeaOe4voLvVqkbJkc9UylTNE18RXXLD9nxbUtr7lXvt00bEiSOnyRrmoqrpa025uVPsM3ciZVv5LiNnaadqL5zfjmR5VVsT1TiQ44EgjuOGKnEdW3fbrRVLo4KldSsbos1ZJq/fdxcZQ4twza8OpQS2y61FW6afRe17k1J9iHoOKkSO5sZGiMasSLk1Mk2qZ4Ep4lc1b36kfNdVztY5MNum5TySvnkdLK7Se7WqlXiHrBWfULLIpsTV1LDaainkma2WSPqWca6zQgRXSttuWlQqNhdfZfkfDLvi2NFRmE7m3PkhlT/Sfk1FiHFkfQFws1xoIo131JJIJFRVTVlrRPnfgbLhNdPpmejQcJrp9Mz0aG4lRTtzY2yletNVuye5FT77it3Rb5LZq610kNH0S+WDUmlkuaassslM7HdsSTMR8WEq6Ri7HNhkVF+1Gkm+VU13x9h1la5Ho6VrV0URurSTkNlXXKqs9a+gonoyCLLRarUXLNM11r31UkfyUa2RzL3IYkqcSwsfZW+6x5pc6PEl8qaZk9iuVBAi6Mr1gk0Uaqpmq5ompDSsmrrLg+CzW63y3OSKZX/omKrlRVVVXRRF2ZlpdcTXTpTWfpm/qH/uJ81T4wpWTLgqlveknR0sz43SZalbpLxbOJD3mYo7sSzE1Q95To5LSLeR2imaS54pbkrcI3BFRc9UEn5Tp07xh/C919HL+U13Ca6fTM9Gh+8J7p9Mz0aEPOpPU+ZOsFd66fD+CHhC0VNhtGIblUxzNkqqdJ1jljVmSo2Rypr27THUmJrvcERaLD01Si7N5Rz/U02V1xFcprNWxvlboup5EVNBPmqQtz+NtHgJLrB1NU2oe1HLrTLNE2bCfFHLGsjkvY1lZLBKjGrhxbZ5+0oKiuxTNBJEmEbkzTardJKeXVn/SdMF2qtst1hvVwiqI6mNHt6HqI1Y7JUyRdevj5DZ8Jrp9Mz0aFHQ3WrvW6VDba56PpnxKqtRqN2MVU1oYsla9qsp0wqZSRPY5JKtcSae34EC4XXEclxqZIMJ10sT5XOZIyGRUcmepUXR1nJl5xaxMmYTubU70Mqf6TZz3yvo6iSlgka2KByxsTQRcmouSHPhLdPpm+jQi5tMmrMyVIaxU8l+X33GQ6X3/ABXNFFcbTX0DKZ6SNdJDIqOXPvohbboOIam34rjoKagWpe+na9Ea5c11u4kTvF1wlun0zfRoZhsjr1uuWxK5d80oHNXLqdSRyKmwmifFLdiJkiXRCCaOeC0jlzvZVTX3aEJt2xNIxHMwlXua7Y5sUiov+Era62Ygv1yiWss1wt1No6L3up36Ddq5rmiJtPS6m9V1vqZKOnlRsULlYxFai5IhT4lxRdm4fq1SdvxU/cT5yGLJoWutG2ztCSSCoe3FI+7NfYRquuuFDhi32m3Wma4upFyXemOc5U168kRctpUtueKWuRzcIXFqpxpBJ+U11nqZKTCFsu8SolXVs/SvVM0XbxbE2IdOE11+nTzG8xg58bFtM27tzJjJpEvTLZm33cyHTzGP8LXX0cv5TQWe1S4O3P7097ZJFRyyo2RmhnqRPcT+E11+nTzG8xU4pv8AcarDVfBNMjo3xZOTQRDJk8KuRjEsi695jJTVCNV71RVTNO4zNJiG917UdR4dqalqpmiwtc/NOXU0+6uqxTUUssCYTuTN8ardJKeTV3/imswsiWrANruVImhUTI5j3LrRU0nLs+xCZwmuv0zPRoevdTxPsrM0PGJVzsxNkyUy+BaOpw1XPutUyZaqeB0MlPOxWOZm5FzXPX+6nFxkeS54nWRypg+4KiuVUVIJNf8AhLnDNbPiDdCudDcn77BHTLK1qIjcnIsacXeVS6diO5xOVjZm5JqTqEEj0R2KdLouncgiY5Uw0y4VTzu9fu5jWXnFzGo1uFLoiJyRSp/pJNrtl7xDf7bX3O211B0uqY3tSaF/Vppoq63ImXxTT8Jrr9M3zEHCe6/Tt8xDBKiBubGqima0tU/J7kVPvuM/jnElVSYyqbfS25alzWMXqXLmvUouxEKvpnifJF4IXDJdn6GT8pPtKJe91yXo9N80qbNcup2MTLYaeXENyhlfEyZqNY5WomgmpEJZezss5zNUuRQ9qfdjH2VuXQ80mst8vl0dJcLdX22nc3bLA/QRUTvoiazX3q73VLdbKO3WOor0pId6e6Brn5ZI1EVcmrlnkvkPjGGKLsyxOck7c98b/wCmnKaJtTLaLLa6qjcjJa6mbJOqpnpLotXj2fGU8dIjmo+35aZWPWxKx6sv+aud/v29DENumK2Lm3CNyavegk/KfTrji2tRaSXDd0jZOm9uesUqo1Has/imx4T3X6dvmIOE91+mb5iEXPpU0YTLT1q6vT79hXSQS4M3LZmujfK6OoRcpGrGq6T0MtT36/VjEfS4Zq52qiLnEx7kyXYuppcY7vlfW4VqIJ5GuY57FVEaifvIaG3vWy4Us1RQ/o5KqjiWVV16XUNXj2bVJldE6PmvbfOxro2aKXkMdhvmm3xMFcpsU19DJSphe5Qq/Lq2wSKqZKi/N7xbYPpKjDDKqpfFJNVVlPoPgkYrHNdty5c89Ww1HCa6/Tt9G3mKXCNbPfMT3xte/fEpEV8WSI3J2l3jxsiPYrYEsiZqZvjVj0fUrivkn3kUnTHFP8IXH0En5Tol6xe1Mm4VuiJyJFL+U2HCW6fTt8xvMOEt0+nb5jeYi5tL6hMsFcv/ANny/go8M2m7XbFNBfrlQ1lDJSqse9Twv6pNFdek5E+d+BX4jxNWx4tuNDSWx1SsMqp1Cqqr38kQ1vCa6fTt8xvMZrB0LLtuh36WrTSckKyatWvSaTxujnRUtdE0Q1pGTU6tcq2vkqoV/TPFP8H3D7vL+UqUw7ebzcZpbpSVtthd1Td/gejc+RM0Q9K4S3X6dvo28xm8b4pu0dtgc2due+/Rt5F7xjFNGq4YW2cpnLBMiY6h12pqhKxPfr1XVsUlBh+prGJHkroGveiLmurNGlOy7YrjdpMwncmrypDIn+k39zqJMPztp7cqRxvbpuRU0s12cZD4TXT6ZvmIRcyFuUjbqSpFUPS8LrM6IY18+Kb0xbbU4fudPDUdQ6V0Mio3v62mgv00mD9zS0wrC6Z8dTvWT00F174ufGWXCa6fTN8xDJ7o13rLhh6GKokRzW1TXIiNRNei5PeTRSQvekaJkvQgmhqI2LK5UunX7yIcN7xHUN0oMLVszeWOORyfg0i3ZcV3SkSBML3SBUcjtNtPKq+yel1kz7BDTR25d7bNGj3o7qs1yTlIvCa6/Tt9GhhzaeJ2bM0JOVVTsu2TyV9hnsMwz4Ys1xhhikq566P9XkqORyNXqURM1Vc1Kzplij+ELj6CT8peYFqprxDfKytdvk1A9HwORMtFeqXYm3YhccJbp9M3zEEjmsd/3CYlPImuen/aLhTr95mP6d4w4sL3T0Uv5S9wTZ7jNipuIrjSVVJLJE5joZonJlqRE1r4OQs+Et0+mb5iDhLdPpm+Yhj2mBvmJYzWkqXpaRUVPvYxNbii4TXyvp6OzyVO81L2folc5fjKiakTjyPrplij+ELj6GX8pY7ndPHV3DFNZMmlNDI2Vi55ZOzkXPLwoaThLdPpmejQlm7PE6zmEUDqqZvkP08Dzu02G6TXhLjdaasod4qGzRR1ELmo/qs1RFdlsyTymkxHe77V3V0tFhyrq4lY1Ekhje9vlRp84kxHc5rzY6Z8zVjnqNB6IxNaK5ie81dxrZ7JVrR0Dt7hREdoqmete+p4+TEiSPS7F0QRRK1VijW0iar3fdjBsu+LI897wnc257coZU/0iVcTYijW1VlhuVHBP8aZ8Mio3R6pNSoibURPtNlwluf0yeYg4S3T6dPMQj59MmbW2UmWmq185yKn33FTi6vlwrhbD1E2n6Iekax5O6lc0RvFkZ6O74jnZpw4UrZW7NJkT3J+DSTjm41NzrLKyqej2tqVREyRNqtzN1cquexVa0lvckcOij8lTS1r4SVyw4Elc29zXjSobIsDHWt06Hl92jxTdmRx8G7nSoxyqrm08n5UNLauicN4SrbVQ00lxlmm31qMaukqropkjURfm5l5Pia67y/9M34q/wDpoV2AaqWuwlWXqodpVtNVOZG/JERE0WcWz95THmI+P8pLNTVNzJY1jf8Anrd7vNXb7yKDplij+ELl6CT8h06eYx/he6+il/Ka/hLdPpmejQcJrp9Mz0aEaT0qfsJ1grvXT4fwRtz+yVsF7q71XQTwS1sHVRTROboLpJqzXwGJpMVXSv1UVhkqdeX6LSdr+xDf8Jrp9Mz0aGd3LqeNuFbjcUT+0U9R+jdns6lOL7Sdjo5mOcqXwms5s1PIiI7Di2zz9viVvTPFH8H3D0En5SPhay3KjvUF3udPV00lLMj44amJzNNO8ruY3nCW6fTt9GhR1t7r7jjWy0FTKjoKhytkajUTNPCYxysddlO2yqZywyNs+qXE1Pr7iLe7xiCovFRNS4YraiFypoyRxvc12pNio0hsu+LY0yZhO5tTvQyp/pNzXXastNW+ho5EZBFqa1Wo5UzTPapw4T3X6dno0IubTp5zM+viS8qrcnkP8nond06GMmpsRYpi6X19luNDEi74kkkMioqpxa0TlLzH15msUtmoYqTol76VETWqLmmSbMi34T3X6dno0Mpfaua8Y8w6ytdposjW6k0dSv7xNE+KVeWiZbEE0U8Kc1ypffr/AARY7riSViSR4SrnsXY5kMiov2o0gXKjxLeqmnZNYrlQwIujI9aeTRRqqmarmiJkiHptwuVVZ619BRPRkEWWi1Wo5UzTNda99VKu64muqWisVJmZ7w//ANNPmqYRzQsfZrLO0M3wVMjLufduvs1K2GorLLg2OzW+gluUscquTemqrlRXKvxURdmZU9MsUouaYQuXoJPymmwnVTLgmnvul/blkcxX5alTSVNmzYTOE11+mZ6NDxzmMdadt3bmUbZHtvSrhbt3/EyPTvGH8LXX0Uv5TR4Rs9TYrPiK5VMczZKunSdY5Y1YqKjZHKmvb8Yl8Jbp9Mz0aES7YiuUtnrY3ytVrqeRFTQT5qhtRDezEtfXvPH0tQrbvVFtp3fAx1Jie717UdRYemqUXZvKPfn5EO8tfiqSJ7OCNybpNVNVPLq/wl/gCNtHgFt1gTRqm1D2o7amWaJs2Fxwmun0zPRoZyLTxPwqwxi7XOzEyT5GHwbaK+0XinvVwjqYqmnc9Ep6mJzHKisVuevXl1S8XETLhdcRyXGpkgwpXSxPlc5kjIZFRyKupUXR1k6G7Vl43Srfbq2RJKeaJ2m1Go3PJj3JrTvohoJr5X0c8lLBI1sUD1jYitRckRckEr0vjmS7V07hFGvo4Fs5NV3MYy8YtjbkzClzanIkMv5R0vv+K5oorjabhQMpnpI10kD1Ry599ENhwlun0zPRoOEt0+mb6NCLtFO3NjbKSrS1T8nuRU++4qN0i/1FtxTTUNNR9EvkpGvREVc16p+rLLvGfZdcTyMR7MKV72rsc2CRUX/CWFVK+97q1m6OXT0oVYuWrUm+LxGtrLxW22sloqWVGwwu0WIrUXJPCpNLyGoj3Mvcgg7SqrEx9lb7rHmddbMQX25RLWWa4W6mVui97qeTQTaua5oiciGrq6+4UOFqC0221TXF1KqNzha5zlTXryRFyO+JcUXZuH6pUnZ8VP8A00+chYWepkpcI2y7wqjaurZlK5UzRdvFsTYh4smNmJE/LTJUCRKx+F6/mrmi/f8ABkUumKmrm3CFyRU40glT/SdOneMP4Wuvo5fymu4TXb6dno2n7wmuv07PRt5iLnUvqE/IrvXT79hX2i1y4O3Pr057ZJF0llRsjNDPU1PcZGkxDe65qOo8PVNSipmiwtc/NPsaafFN+uNVhmvglmarHxZORGInGSsLIlswDarlSpoVMqOa5y6800ncX2ITYo5I+a9MVl+9DXwTQy8lq4b5pbP5mRq6rFNVSS0/BO5M3xqt0kp5NX+Em4Ht9Xh6vS8VscyVb4nxvp52Kxzc1TJVz17ERdnGa3hLdfp2ejQpbFcKi/bo9bb7g9JIG02mjURG60azLWnhPGSI9qsp0w9VMpInRuSSrXEmiePwKqe6YmdUSOZhG4Pa56q1yQSZKmf1T8becXMbotwpdETkSKVP9JspMR3KGV8TJmo1jlaiaCbEPjhPdfp2+YhFzqVP2fMm5Nav7/v3GatdsveIMQW2vuVtrqDpfUxvak0L8nppoq63ImXxTrjjElTSYyqaCmty1L2sYvUuXNUVqLsRDQcJ7r9M3zEM1aES97rknR6b5pU2vLqdjEy2E0b4prstdES6Ia8zJqe0irZVWyqn8aEBLniZ7UVuEbgqLrRUhkVF/wAJXVFmvl9uencbbX2ynVutZYHozNNm1EQ9Klv1wpZpKeOVqRxOVjU0E2IuSGfxhim6ssL1bO1F3xv/AKbeXwGMcsSOwxNs5ciSSGdW4pnXYmaofV7u11S3Wyjt1jqLglJDvT3QNc/LJGoirki5Z5L5CnbdMVsXNuErki8qQSflNslTLabJa6qjVGS11M2SdVTPSdotXj2fGU5cJrp9M3zEI1fExbTNu7qZtjnemKndZnRPvvMi664uqUWB+GboxsvUK5YpdSL/AEmgipJcG7ldw0mOlcydr0SRqsVdJ8bSdwmuv0zfMQosa32vrMJVtPPK1Y36GaIxE2PapmyaFzkY1LIpHJT1DWLI9UVW5ou1ittVLinGDXOtu82xsDUcrqhXZTI7Zo9QuzL8UJdTuaY2rad1PUXi2viflpNWR6Z5Ln9GXkdJDR4Ssc0KOa+opInSLpLrXQbzqRd8f893lDqhsL8KMTIyZTPqWY1kXMjWa0y4X3yCmcyKrczeZ5GKrmuVPDxZ94+Pg+x/3ct3nu/6Z9bnCrLi7ESSLpJoLln9ZSVv0nz3eUSPWB13+Vi36HkcfaEwxrhw5ZdSH8H2Pu7lu893/TLrDOBbnQXSnuN6mpaqrgeuhLE93Uty1Jloom1V8pB36T6R3lG/SfSO8pGtY3oy3hkSpw+TrJfxzM5fp75cMcXeioa9IWQSqqI9EyRNSci8pbfB7j7u3b/Pd/0z63OUR+6Je0eml+hXb9ZpM3x/z3eU2J5mxW8hFumxrU8D5sTUeqYV3UpX7nVxt1TJXYhko6xJ+pTeXvz0uX4reJC3uFlxdimVtVbrrTQsiTe3JOqoue3VkxeUzWOpZOlkHVu/W8veU9ExX1FdCjF0f0f7urjMXSLhSddNuhm2JEetMnna4uu/3mZX4Psf93Lf57v+mfcO55jN8zGXC70E1K5cpY0e/qm8afq0JW+SfPd5Rvj/AJ7vKQ9tYv7EJuwSf7q/ftOmNoJ8K7m9JSUTkgdDVI39GukmTle7j8JnrThfGd6p1mpbzRtaiIqpKqouvwMU5Y4e5bE1Fcq/p27V7ym5vCrHbLRodTnToi5as9TTY5qclJcKL45mryHJOsOJUvnlknuMpWbmONa+Heaq7W2SPPS0Ve9Nf2Rky2W6e1UlRarU9lNPVt3l7s1VqvyVqKuaKuWa8hJ3x/z3eUibmjlfbsUK5dJWuzRV4tTzFsjp2rh8lG9NzN8SUrkx+Ursrr0Pn4Pce927d5z/APpj4Pce927d5z/+mTN+k+e7yjfZPnu8pF2xn+2nuJ+wS/7q/H+S2wlguts9ybcrq+mnrUa5j5oXuXNF1JqVE4u8efZ4hvWJbnTUVxjiSKscxN9RETW9yJsavIavfZPnu8pE3MkR0uLVVEVdJmvk/Wk8MrZGuW2m+ZrVELoXNu7XLLI+Pg+x53at3nO/6ZFgwBW2OsWsvklJVSSv043Qveqo9FzVV1JyoXO+yfPd5TOYplk6Y2bq3ZdE8vfaYR1HOXlMTDfqhJLSrA3nSOxInRfcXtdh3GGJKjphQXekjhcmijZVVHZp4GKR/g+x73ct3nu/6ZpMSucy7uRiq1NBupFKjfZPpHeUj7S2PyFYi26kiUj5UxteqIvTYj0+5ziyeZsd2uVBU0bv1kTXvzdxp+4nHku07bo8lXh/DFkoqGbeNB29dTrTU1OVD73yT6R3lMxjNznNt+k5Vyn418BJBO2WVG4bfL3EVRSvihV+O6p7/eTrdhHG10gdNT3qjRrXaKo9VRdicjF5T6rdzDGFc1nR11t0sca6WSyPT1RmwxWqx3SNGLopvKam6uNShmlk3l/6R3xV4zztfLdbCl07jJtGszMWNbL0XM/KS31jLZLY7BNHRrVP0k01XR0tWaquSrsaR/g9x93ct3nu/wCmdtzhyrucXN6r1SVrsncadTGSN8f9I/zg+TszlY5MS7qI4+1txxrgTSyEH4Psfd3Ld57v+manB2D6qw1rrhcHwS1ssLo5ZonuXS6pFTaicTU4ik3x/wBI7zhvj/pHecRrWNXRlvAk7A+1lkv45mQtEWJ8RVkrKK5xR/plYm+plr+xqmh+D7Hvdy3+e7/pnXc1T/8ARV7f+8lUuS/0tJO+yZfHd5TYqJmwvVuBF9hrUsD6iPEj1T2qVNuwRUYWq457i6mlq0eksMkD3LoKnhROPvE+swvjS/VL7nRXijjgny0WyuVHJkmiueTF40UqKiRzt0DDyK9VRZ2Zoq7eqQ1+IVVl7qGtcqImjqRck+Khg+RW2ndni6bGbIkcq0zMlb+5Ov3coPg/x93dt/nu/wCmdqXc3xLUSaF8r6Gspss0jbI/PS4l+InfO+m/57/OGm/57/OIlrGroxEJ0oJP9xV8Tjun1FfQ1lgt9vqd4dLG6LZqzzaibUIFDgzHFfTNqIb1RIxyqiI9zkXV4GKRLppOxthnNVX+2x7V/wDmMNriR7o71K1qqiaLdSeA2HSo2JsmFFuascD1mdCj1S3X/HtMnVbmWKJXx1d3uFvqaem6t7WyPzVu1UTqE4k5Syjtl0q7U2xWCpio0R2+NSVV0U15rryVeM43WSTpPW9W79Q/j/uqTcJKvwV00mfV7+/quP46mHMdJHzNEb06KZ8pIX8pc3P69UIHwfY+7u2/z3f9MfB9j3u7b/Pd/wBMm79J893lG/SfPd5SPtrfUQl/D5f91fj/ACWtswzJhiwXiqkWHouaicsksTnLpPRqqq60TjU89w9QYrxK1i0V1gj01cib9q2eBqmjuUsnSyr6t36l/H/dUkYH6ncuVyal6Jdr4/jITslR0Svtpvma8kLo5msxedtkQ3bnWO3sVjr3bVa5MlTTd/0znaMKTYPrI5Kl0LrlHm5k8DnKjWuRW5dUid/i4yz3yT57vKVVoe5265amuVXIsMmpdf8A6UhgyZZ0WNiYeuRJJB2a0si4+mfeS58HY3uk76+mvVEyGpXfGNe5yORF5cozn8H2Pe7lv893/TLi6SObdapEc5ESRdSLlxkTfX/Pf5xH2tqLZWISpQyOTEkipf73Pig3Ob9LPnfq2hrY2Kjo2tkfm13moRd0ysufDait9vqd436jautNWenJ3uRCbvr/AJ7/ADlKelVX7q1j0uq/Rrt8DyaCZJXKmHp7Pca9TTuhYj1dfP2+87U2Bcc1VMyeO90CMemaaTnZ/wDLOVTuZ4iWoZX3muoKqCBOra2R+kreROoQ0d5e9t3qEa5URH7MyhxDI/pBWdW79Xy98wbVeVga1EXS5ItG7BzHPVU1sufeTwR+mND27T+laOmND27T+laVvLfspb42blXVvbHj/Dz3uRrWztzVVyROqQtb/iWnfjquonPhZAxrFSdZUycug3V+PLxFDWzUVRjSyadTC6DfmpK5JEyamkm1eI1d0tO5xPcpZKqRsszstJ0dWqoupMti8hcJG10LWyJlb4lC+Rzal7otb/CxT3C4UU9tqYYayCSWSF7WMZIiq5VRURERNq5lvhqCam3MaOKeJ8b0qHqrXtyVOqcV1wtu59RW+pqrY5W10ML5KZVqHO/SImbdSrr15EyzX+nq9zylWtr6ZKvf3aTFka12Wk7LUYrGjIXIzNDLnLJUMdIll+APwj9MKHt2n9K3nHTCh7dp/St5yq5btlLzGzdBcetlV4l/qUj2K8xWncfkkRY5Jm1S/oVfkq5vQXCvolt1SjauByrE5ERJE16lP3BtLhaqwHoX2ePSWd2lH0Rov2plqRcyypW/lKjkyvn4FPXORZmq1c7Lbx6CmvVBNTRSvraZjnsRzmLM3Nqqmw/cLMdU7qFLWwNWWm3l7d+Z1TM9BdWaaiV0k3L+/wDenc5HsNztNo3Q4KC1VcUFlSJzlWWRMkerFz6pe/lxk0ULGOVYvjsQT1EkkaNmSyb95bXHrnVeOf61Ix+XC5291yqVbXUzkWV6oqSty2r3yP0xoe3af0recqXMfiXJS8je3AmaaEkqrXIyHdZtckr2sYkMmbnLkifo5Cb0xoe3af0recqKOW3VG6bblqamHoTeno+RZURqfo35dV4cjbomuR7suimlxFzFiTPqhYVWJaefFF0pZXQQxwzORkrpkyfr4iJfqymrLLUU9JURTzvREZHG9HOdrTYiF5W2fc1lrZnzuR8jnqrnNqnZKveycVV6pMD2q0VFdYl0blCiLAqzq/Jc0RdSrkupVNnkQ40c299ulzTSpmSNWOS7d+tv+DRUsT4dzyxxyMcx7W5K1yZKm3iIBIZfaOqwPaHVFxpVqcs5Gb61HN1LtTiK/pjQ9u0/pW85p1TXrKuRv0DmJAllJBW4h6xVfi1JXTGh7dp/St5yuv8AXUb7JVtZVwPcseSNbIiqpFCx3MbkuqE87m8p2fRfkS5L/Hadyayvj3ueVJ9B0WnkqIqyLn+CeU+m3a3qxF6PpUzTWm/N1fidbHSYOqsBW1t7niWTNVfG2pyci6Tss0Rc01H10k3MO/8Ae3fmLOaGKRfLyW/QpaaomibaNLp379T53PYpH7o1zrWsV1NLRuRkyJmxy6Uexdi7F8hLm/Wu8KkTBd5ttDjuvt9PWwwWaGld0Ms0iImelGuWku3a7jP2W5UG+u/ttPt+lbzmvWMdZqWNuge3G9d/nnc7Aj9MaHt2n9K3nHTGh7dp/St5yv5b9lLXG3ci4Zmig3WHvlkbGxKZeqcuSfEQ50eJqetrq5tS+CmSKZUYrpU6tM116yPY322o3S3vramFtMtOq74sqI3PQTLqsy9msu5msz1euk7SXNUq1yz84uHRsfG1smyHPtlkjme6LPNbp8jP4mniuVodT0MrKqZXtXe4XI9ypy5Ibm6NVmHbAxyK1zaRqKipkqdQwx+Io8JWO1OrMMP0Lgj0amc2+dSu3Uqqaa63q31FlsyrcaV0vQyLIiStza5WszzTPVxkUseGBWszT4k0UuOqa6RLL8OpBBG6ZUHbtP6Vo6ZUHbtP6VpWYH+qpdY27oVuMOx2b6zPaQtr9iOG2YRwrFEsUyyUsbZP0iJveUbNv/nEUeK6ulnsEzIamGR6ub1LZEVfjIaOOhwRV4Ys3Taojkl6EjVWx1WStcrG6WaIurWWlO38iz0yvn7ikrHqlTijXO2XvUh9Nbd3QpfTN5z73O4ZkxFiGp3p28TQqscmXUvTS4l4z66RbmPKv3p35j8wXfKKC+Xyh6Nhht0Easo0lka3NqKuSIq7dXfJI4WsReWt763I56h8tua21tDuCN0yoe3Kf0recdMqHtyn9K3nKflv2Uv+YzckldgSphpcc3+SaVkadCuy03Ima6TdRI6ZUPblP6VvOVeD0tNRja7uuVTAynWFdFz5UYjlzTYuZv0TXJjy6FZxFzFazPr9D7tGJaW4UjpqmSClej1akbpUzyyTXryIGK3sulBFFb3Nq5GyaSsgXTVEy25IaPpJuYd/7078xS4mfhrD9FFUYTk0KqSTQlzk3zqMlXYqrx5GyyGJsmKLXonQ1X1MzosEyZdV6m+xd1wi8V71KEs8U3e2TV8TorjSSIketWztXjXvlH0xoe3af0recrZmP5i5KWlI9vJbmSTN456xx/zDfZcXfTKh7dp/St5zP4zq6aezRshqIpHb+i5MejlyydyElIxyTtuhjXOatO5EU1WM8SQUlxs9Kx0MscsKacqSplHry1kPppbu6FL6ZvOWlytuAKtlK64VEUsiRJlvdXs8OTiB0j3MeX/i3fmNt0ET83KqL1sV0NTPGmGNLt6XP3c3p54bTiZ8sL42yZOYrmqiOTJ+zlOpwwPiCF9sxBBWV9PHGxNCmbI9rFVuTtnLxHz0yoe3Kf0qEFa16vS6Gxw1zEa6y5d5IBH6Y0PbtP6VB0xoe3af0qGjgfspaY27oR9z6tgoY8YyTSMaqNRWtc/R08kl1IcLTiKlr6NJ6manpX6SpvbpUz/E/MAssc9TiPpvUQsjc5uhpTozTRd80staZ8RadI9y/v8A3p3OXU8THraTLS1vA52nmkiziz1v78ijuSpccQ2J9AqVTYKtFlWDq9BFezLPLZsXyG5xP14d9RpjrlUYfsF7syYWmSOKpqUStV0mmmijm6Otc8tSvNNiS626W7OdFcKR7dBNbZ2r7zXqGKkCNbmnTf2m1Syo6pV7slVM9iCCP0xoO3af0recdMaDt2n9K3nK3lv2UuMbN0KTFKolfZlVUROiePwtNHjDEsEeMoaFHQ7xJTo51RvqZNXqubl4zK4nqaSorbVo1ET2pP1ei9FyTNvkNpebXueVFaj62eOaXRRNKOrVUy+xS2jYiwNbImWfzKKZ7m1TnR65e62ZUS3S3uieiV9Mq5bN9bzk7c9pqik3ObnHUwyQvWscqI9qoqpoxkeSzbmbInvjVdNrVVv9qdt8p0wdiOKqwHcOmVfTsqeiVRrHvaxyt0Y9icevM8SJGROSPNF1D53SysWRLKi5H2CN0xoe3af0recdMqDt2n9K3nKrlv2Uvcbd0JJVYFukVs3N77K50bpWzK5sTn5K7qWkzpjQdu0/pW85B3PIcO1GFbgy+TxNzny3t0+g5zdFNiZ69ZY0bXIx902+pU8Qcivjsu+m+Vj7t1+oquhinnqqeCR6LnG6VM26z5pP7dj+xT0i9EQwyfpJIuqazwqmwsekm5jyO+9O/MRIayxWLGVnp8P1DIaCd+lVrJLpIip/ecurUTRwxsfij1NeWolfFgmSybmgxB16qPCnqQrjvfLpbpbxUOjr6ZzVVMlbM1UXUnfIHTCh7cg9K3nKuRj8a5LqXUMjeW3PohIKSreyPHuHXvcjWpO3NzlyROqQs+mFD27B6RvOUddNQ1ONLFp1MS0++tSR++IiNTS414jZomOSW6p0U1OIOasC59U+ZfX/ABLTuxzXULnwtgY1itnWVMnLoNXL8fwIlwuFFPbamGGsgklkhe1jGSI5XKqakRE2qXF0tO5vNcJZKqVssy5aTo6tdFdSci8hW19u3PaK31NVbHK2ugifJTL0Qrv0iIqt1KuvXkbPIhVyOzRfqaTamdrFZa7d+ti0wxTy025dTxTxujek782vTJU6tSOfdjxBT1W55AtbcKbotZnaTHSNa7LSXLqfAROmND27B6VvOatY16y3sbnD3MSGyLlfqSCPcetlX4l/sqOmND27B6VvOR7hcKJ1tqWtq4FVYXoiJI3XqXvmvGx2NMlN2R7cC5n5Y71FadyB8qLHJM2qX9EsmSqivQ+qe9UE1LFK+spo3SMRysWZubVVNh+YNpcLVOA0ZfaiJHLO7Si6I0HKmaZasyX0j3MOVfvTvzFtPFHI5ceS92xRU08sTU5SXTv3IWHmuq91K2VlM1ZqdjJGumZ1TEXen6s01caF3cOuVV45/rUp7RcbRZ90SgoLNVRw2Z0b3yLJIioj9B/7y7NjeMnV90oHXGpcldTqizPyVJWqi6175r1bHIxqIl06G1RPasz3Lkq6+J+gj9MaHtyD0rR0xoe3IPStK7lv2UtsbdyBTSMh3UrJJI9GNbGubnLkiankq44kp5sX3KkldDFFE9dGZZUyfsKtJLfPuiWl1RUxdCrGu+P3xEamp+1c9XEaSvtG5tLXTPqHo+VXdU5lUuSr9ji4wNdE1siZW+JQcxzJ3uizW/ssUN9q6WsstRT0tTFPNIiIyOJ6Oc7WmxENVSwyQbndkjlY5j2t1tcmSpqUzt6pMD2q0z1thdlcokRYFWdX680RdSqvFmXcd9pKvA1pWe4Uq1OjnKzfWo5q69qcRg6PBArWZp8bmbZVkqWukSy/CxHBH6Y0PblP6VvOOmND25T+lbzlVgfspeY2boRsQ9YazxfvOkl/jtG5LZXxLHNNv2g+LfMlRFWRdfkTykS/19HJY6tjKqBznR5IiSIqqWFipMH1WAra29VETpM1V8banRejtJ2WaIuaai0pW/kqj0yv9ClrXf8AcIrFztl43ObLtb3MRej6XNU1pvzdX4n7gaKSXdMq62NivpZKVUbO3Wxy5MTU7ZtRfId+ke5j3/vTuc5YUvFstmP6m3UVZDBZIadd4WWRETSVGqvVL/eV3GZxQsjVVjW+XXYiqKh8rEbKltrbk2p+VS/XX1nI+Ki5UC1MqpW065vXZK3lOXTGh7dg9K3nKlWPvopfNeyyZkgrsMzRQbrL3zSNjb0MqaTlyT4iEnpjQ9uU/pW85V2OS21G6W51ZUwpSugX9IsqNbnoJlrzNyia9HOy6KV3EXMWNt16p9SSzEtPV3i5xVDoadsFQ5rHOlT9Imk7Xr8CeUhYmnhuVndT0MrKqZXtVI4XI92XLkhoKiz7mclTK6V+b1equVKpclXP6xT4hZhCx2p1Zhh+VwR6NRVlV/Urt1Kqm0kMXMR7NduhqLUzcpY5Ey362+RsLox0eHbAxyK1zaRqKipkqLoMKcn3W9UFTZLM5bjSOl6HRZEbM3NHK1meaZ6io6YUHbtP6VvOV9S16yrkWVE5qQNz3+ZIKfFnY3Vf0e20sOmFD27T+lbzlTiispZcPVLIqmGRy6GTWyIqr1aHkDHc1uXVPmZ1Lm8l+fRfkTcXXx9DhHCLaSqRMqViTNYqOXVHHqXk4yv4c2r6Kp8xvOaOPFdhwthqyq1kVXPVUkazNY5JFjc1jc80z6nW5fIcfhbtPcz/AC0LV8TZPPZfwKSKeSL0b0t3nbc3oJG3a63bTZvFdDpxt/eRFXPWfhnsMY6t1rxNerlWMnbDX5rEyJqLo5uz5dQ4bWnkqPRpzmvVwSuVLJc2qGphZixLa5oQZ7htaeSo9GnOOG1p5Kj0ac5p9kn9VSy7bT+uhOwTcobXj28zTNe5HRK1EYibdJpn7PjJsFO9tzdPNKrs2uYxuzL7CZhLGFqsuLLlc62Od1PVRq1iMjRy56SLrTPvGi+Fu0dym+iQt3RXSz23yT2FA2ZWvV0TrLddV12yMvXVcWMIko7fnE+Fd8cs6ZJls4s+U9Nxb8vh8X7zzbGuOaPEltgpqSl6HfFLpq5Go3NMlTL8S8v26RYrlVRyQMq9FrMl0o0Tj8JBPA/k4WJlsbEFS3tCPkVL9V6dxNBnuG1p+bUeYnOOG1p+bUeYnOV3ZJ/VUtu2U/rofuN+sTfHN9SkzGGKkj4P7w6ZkEUOU7NFvVomjs/EzuJMSUN1tiU9MkqPSRHdW1ETLJe/3zZt3VbFBQ0kMdFLI6KFrX75CmpURE1ayzhie2JEe3e6FPUTMdOrmOzystzP8ObX9DU+YnOafAFrmt9mv80rmK2qYkjEaq5omi7b5SN8LVn7m/5SFBhHG1ts1NfWVyVCuuDlWFI2o5E1O25qmW1DJsGFq8tqp9TCSoV6pzVRdrdPE0gM9w2tPzajzE5xw2tPzajzE5yq7JP6pd9spvXQ0JS4LuzLXDi9FR++Ss/RuYiLoqiS69fhOHDa0/NqPMTnOeB8aWrDtRe5q6KaTo1zHQtbGjtmnt16vjIb1LBKxr7pbQra6ohkVllvqRbVjOGGjRlxWeafSXNzWNyy4uNCSk0eLrjRdAKsfQUzXyb+mWaKqbMs+Q0PwtWjuZ/loZzFeOKK/VFsfTUzqdtJPpyaLUTSTNvMbDYG48TG2X4e41nVL+Xgkcjm/H3noOKOvC/UaU5W3rdFslwuCzwsqtDRROqjRF9ZX8N7T82o8xOcrZKWdXqqNLaCrgbE1FehojM4zXRjoFXinz9R14b2n5tR5ic5TYhxFQ3RtIlOkqbzLpO02omryklJTTMmRzm2QiraqF8DmtciqaXHOLdHF9HNG+ZtElMm+x6Lc1XSf/tx8RXuxpbJEVjYqnNyZJ1Cc5p6zdcsO+p0Nb5JGaOtZImouflIsu6zaZInsS2Jm5qp+qQ3HQNdbGxbleyokYipG9ETZSwwbaprRuf3KnnfG9zqpXorFVUyVsacad4jGcwlja2WXB9baq3ol1TPULIxWMRW6OixNuf91T64bWn5tR6NOc1qunmfJdEubdBUQMjVFW2fU0IM9w2tPzaj0ac44bWn5tR6NOc1eyT+ob/bKf10PvDN5S27n9+gjSRKiSZXRvaiZN1NT3EK341pI6GOOtSokqETq3NY3JdfhJeBsc2nDVmrqesgllmmnWSNEjRzcskTXr7xd/C3aO5ieiQt5okeqo9tyggmdGl43Im9yosmWJMW2q40btCKjqGaaS6nLrRdWWfIbDEfX2p/p9lDC3bHNFccW2e6MhfBT0T0WVrGIiqmlnqTjLK7boNlrrnNUxNqtB+jlnGmepqJy941qiB6xo1iZbG1S1LEnV0i5216LoWgM9w3tPzan0ac44b2n5tT6NOc0eyT+qW3baf10P28Stgxdh2Z6KrYqpj1y25JI1TpifF2hjioke+boHe25RaLc89FO/y98p6zEtvqMR2ava2beaKoZJKitTNWo9qrlr7ym1qt1yxb+u8W58jOJ0kTc/WWjInJC1r23yXL2lJLM1ahzo3Z3TPpoZmTFdBc4n2+COdJapqwsV7UREV2pM9ezWbSyW6W17msFLM9jntmcqqzPLW9eUoLruoWuvtFbRx27e5Kinkia7e0TRVzVRF/EhWPHVqt+B4bPUpUuqmSucqtYityVyrtz7546BUiVsbVTuPUqMUzXSql06l6DP8ADa08lR6NOccNrTyVHo05ys7JP6ql12yn9dC3uXWur8S/2VKigvy0G5LJTU7pI6lKnNHoiZImmhxrMY2ueinhYk+lJG5qZsTLNU8JMwdugWjDuFEt9RTSy1SSud+rRWZKvLmWFNDIyNUc3qVVbPFJI1Wr0XropCpcb0DKWJtQypdKjER6oxut2Wtdpb4PZ07x5QX2lXRpoUkjVsmp6rvbk2Jmn7ycZL+Fu09zG+iQoUx1b5N0WhxA6GSGjghcx8cbEzzVj0zyzy2uQlZA1HKrGqimvJUvczDI5HJ3Guu3Xaq8a71kQpq/HlnqK+eZjanRe9VTONOcj8NrT82o8xOcqnUk+JVwqXMdZToxEV6aGhKToplFul2apkRVayJVVG7f3zjw2tPzajzE5yDDiq2x43tt4eyZaWlaqPTQTS2O2Jn/AHkNqkp5mPVVS2SmrXVMD4kRHIuaEu5YvSHGFzfUundSK/8ARRo1ubdn/m0+KjEdFe6d9spmTNmqU0GLI1Eai9/JTSz7rlm3529W5zmZ6lfEma/iVd/3S7ddbHV0MNBvUk7NFr0jRMja5DVci4FvuaSVEjWq3EmHbrY//9k= \ No newline at end of file diff --git a/samples/resources/logo_ubuntu_transparent.png b/samples/resources/logo_ubuntu_transparent.png new file mode 100644 index 0000000000..88b74a3e22 Binary files /dev/null and b/samples/resources/logo_ubuntu_transparent.png differ diff --git a/samples/resources/tiger.svg b/samples/resources/tiger.svg new file mode 100644 index 0000000000..28763f2264 --- /dev/null +++ b/samples/resources/tiger.svg @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/PhpPresentation/AbstractShape.php b/src/PhpPresentation/AbstractShape.php index 4cece57b10..c8d3df00d8 100644 --- a/src/PhpPresentation/AbstractShape.php +++ b/src/PhpPresentation/AbstractShape.php @@ -10,127 +10,120 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; +use PhpOffice\PhpPresentation\Exception\ShapeContainerAlreadyAssignedException; use PhpOffice\PhpPresentation\Shape\Hyperlink; use PhpOffice\PhpPresentation\Shape\Placeholder; +use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Shadow; /** - * Abstract shape + * Abstract shape. */ abstract class AbstractShape implements ComparableInterface { /** - * Container + * Container. * - * @var \PhpOffice\PhpPresentation\ShapeContainerInterface + * @var ShapeContainerInterface|null */ protected $container; /** - * Offset X + * Offset X. * * @var int */ protected $offsetX; /** - * Offset Y + * Offset Y. * * @var int */ protected $offsetY; /** - * Width + * Width. * * @var int */ protected $width; /** - * Height + * Height. * * @var int */ protected $height; /** - * Fill - * - * @var \PhpOffice\PhpPresentation\Style\Fill + * @var Fill|null */ private $fill; /** - * Border + * Border. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $border; /** - * Rotation + * Rotation. * * @var int */ protected $rotation; /** - * Shadow + * Shadow. * - * @var \PhpOffice\PhpPresentation\Style\Shadow + * @var Shadow|null */ protected $shadow; /** - * Hyperlink - * - * @var \PhpOffice\PhpPresentation\Shape\Hyperlink + * @var Hyperlink|null */ protected $hyperlink; /** - * PlaceHolder - * @var \PhpOffice\PhpPresentation\Shape\Placeholder + * @var Placeholder|null */ protected $placeholder; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new self + * Create a new self. */ public function __construct() { - // Initialise values - $this->container = null; - $this->offsetX = 0; - $this->offsetY = 0; - $this->width = 0; - $this->height = 0; - $this->rotation = 0; - $this->fill = new Style\Fill(); - $this->border = new Style\Border(); - $this->shadow = new Style\Shadow(); - + $this->offsetX = $this->offsetY = $this->width = $this->height = $this->rotation = 0; + $this->fill = new Fill(); + $this->shadow = new Shadow(); + $this->border = new Border(); $this->border->setLineStyle(Style\Border::LINE_NONE); } /** - * Magic Method : clone + * Magic Method : clone. */ public function __clone() { @@ -141,34 +134,34 @@ public function __clone() } /** - * Get Container, Slide or Group - * - * @return \PhpOffice\PhpPresentation\Container + * Get Container, Slide or Group. */ - public function getContainer() + public function getContainer(): ?ShapeContainerInterface { return $this->container; } /** - * Set Container, Slide or Group + * Set Container, Slide or Group. * - * @param \PhpOffice\PhpPresentation\ShapeContainerInterface $pValue - * @param bool $pOverrideOld If a Slide has already been assigned, overwrite it and remove image from old Slide? - * @throws \Exception - * @return self + * @param ShapeContainerInterface $pValue + * @param bool $pOverrideOld If a Slide has already been assigned, overwrite it and remove image from old Slide? + * + * @throws ShapeContainerAlreadyAssignedException + * + * @return $this */ public function setContainer(ShapeContainerInterface $pValue = null, $pOverrideOld = false) { if (is_null($this->container)) { - // Add drawing to \PhpOffice\PhpPresentation\ShapeContainerInterface + // Add drawing to ShapeContainerInterface $this->container = $pValue; if (!is_null($this->container)) { $this->container->getShapeCollection()->append($this); } } else { if ($pOverrideOld) { - // Remove drawing from old \PhpOffice\PhpPresentation\ShapeContainerInterface + // Remove drawing from old ShapeContainerInterface $iterator = $this->container->getShapeCollection()->getIterator(); while ($iterator->valid()) { @@ -183,7 +176,7 @@ public function setContainer(ShapeContainerInterface $pValue = null, $pOverrideO // Set new \PhpOffice\PhpPresentation\Slide $this->setContainer($pValue); } else { - throw new \Exception("A \PhpOffice\PhpPresentation\ShapeContainerInterface has already been assigned. Shapes can only exist on one \PhpOffice\PhpPresentation\ShapeContainerInterface."); + throw new ShapeContainerAlreadyAssignedException(self::class); } } @@ -191,22 +184,19 @@ public function setContainer(ShapeContainerInterface $pValue = null, $pOverrideO } /** - * Get OffsetX - * - * @return int + * Get OffsetX. */ - public function getOffsetX() + public function getOffsetX(): int { return $this->offsetX; } /** - * Set OffsetX + * Set OffsetX. * - * @param int $pValue - * @return self + * @return $this */ - public function setOffsetX($pValue = 0) + public function setOffsetX(int $pValue = 0) { $this->offsetX = $pValue; @@ -214,7 +204,7 @@ public function setOffsetX($pValue = 0) } /** - * Get OffsetY + * Get OffsetY. * * @return int */ @@ -224,12 +214,11 @@ public function getOffsetY() } /** - * Set OffsetY + * Set OffsetY. * - * @param int $pValue - * @return self + * @return $this */ - public function setOffsetY($pValue = 0) + public function setOffsetY(int $pValue = 0) { $this->offsetY = $pValue; @@ -237,7 +226,7 @@ public function setOffsetY($pValue = 0) } /** - * Get Width + * Get Width. * * @return int */ @@ -247,19 +236,19 @@ public function getWidth() } /** - * Set Width + * Set Width. * - * @param int $pValue - * @return self + * @return $this */ - public function setWidth($pValue = 0) + public function setWidth(int $pValue = 0) { $this->width = $pValue; + return $this; } /** - * Get Height + * Get Height. * * @return int */ @@ -269,34 +258,32 @@ public function getHeight() } /** - * Set Height + * Set Height. * - * @param int $pValue - * @return self + * @return $this */ - public function setHeight($pValue = 0) + public function setHeight(int $pValue = 0) { $this->height = $pValue; + return $this; } /** - * Set width and height with proportional resize + * Set width and height with proportional resize. * - * @param int $width - * @param int $height - * @example $objDrawing->setWidthAndHeight(160,120); * @return self */ - public function setWidthAndHeight($width = 0, $height = 0) + public function setWidthAndHeight(int $width = 0, int $height = 0) { $this->width = $width; $this->height = $height; + return $this; } /** - * Get Rotation + * Get Rotation. * * @return int */ @@ -306,75 +293,55 @@ public function getRotation() } /** - * Set Rotation + * Set Rotation. * - * @param int $pValue - * @return self + * @param int $pValue + * + * @return $this */ public function setRotation($pValue = 0) { $this->rotation = $pValue; + return $this; } - /** - * Get Fill - * - * @return \PhpOffice\PhpPresentation\Style\Fill - */ - public function getFill() + public function getFill(): ?Fill { return $this->fill; } - /** - * Set Fill - * @param \PhpOffice\PhpPresentation\Style\Fill $pValue - * @return \PhpOffice\PhpPresentation\AbstractShape - */ - public function setFill(Fill $pValue = null) + public function setFill(Fill $pValue = null): self { $this->fill = $pValue; + return $this; } - /** - * Get Border - * - * @return \PhpOffice\PhpPresentation\Style\Border - */ - public function getBorder() + public function getBorder(): Border { return $this->border; } - /** - * Get Shadow - * - * @return \PhpOffice\PhpPresentation\Style\Shadow - */ - public function getShadow() + public function getShadow(): ?Shadow { return $this->shadow; } /** - * Set Shadow - * - * @param \PhpOffice\PhpPresentation\Style\Shadow $pValue - * @throws \Exception - * @return self + * @return $this */ public function setShadow(Shadow $pValue = null) { $this->shadow = $pValue; + return $this; } /** * Has Hyperlink? * - * @return boolean + * @return bool */ public function hasHyperlink() { @@ -383,86 +350,84 @@ public function hasHyperlink() /** * Get Hyperlink - * - * @return \PhpOffice\PhpPresentation\Shape\Hyperlink */ - public function getHyperlink() + public function getHyperlink(): Hyperlink { if (is_null($this->hyperlink)) { $this->hyperlink = new Hyperlink(); } + return $this->hyperlink; } /** * Set Hyperlink - * - * @param \PhpOffice\PhpPresentation\Shape\Hyperlink $pHyperlink - * @throws \Exception - * @return self */ - public function setHyperlink(Hyperlink $pHyperlink = null) + public function setHyperlink(Hyperlink $pHyperlink = null): self { $this->hyperlink = $pHyperlink; + return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5((is_object($this->container) ? $this->container->getHashCode() : '') . $this->offsetX . $this->offsetY . $this->width . $this->height . $this->rotation . (is_null($this->getFill()) ? '' : $this->getFill()->getHashCode()) . (is_null($this->shadow) ? '' : $this->shadow->getHashCode()) . (is_null($this->hyperlink) ? '' : $this->hyperlink->getHashCode()) . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } - public function isPlaceholder() + public function isPlaceholder(): bool { return !is_null($this->placeholder); } - public function getPlaceholder() + public function getPlaceholder(): ?Placeholder { if (!$this->isPlaceholder()) { return null; } + return $this->placeholder; } - /** - * @param \PhpOffice\PhpPresentation\Shape\Placeholder $placeholder - * @return $this - */ - public function setPlaceHolder(Placeholder $placeholder) + public function setPlaceHolder(Placeholder $placeholder): self { $this->placeholder = $placeholder; + return $this; } } diff --git a/src/PhpPresentation/Autoloader.php b/src/PhpPresentation/Autoloader.php index 605981b096..6c7211fde6 100644 --- a/src/PhpPresentation/Autoloader.php +++ b/src/PhpPresentation/Autoloader.php @@ -10,42 +10,44 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; /** - * Autoloader + * Autoloader. */ class Autoloader { /** @const string */ - const NAMESPACE_PREFIX = 'PhpOffice\\PhpPresentation\\'; + public const NAMESPACE_PREFIX = 'PhpOffice\\PhpPresentation\\'; /** - * Register - * - * @return void + * Register. */ - public static function register() + public static function register(): void { - spl_autoload_register(array(new self, 'autoload')); + spl_autoload_register([new self(), 'autoload']); } /** - * Autoload - * - * @param string $class + * Autoload. */ - public static function autoload($class) + public static function autoload(string $class): void { $prefixLength = strlen(self::NAMESPACE_PREFIX); if (0 === strncmp(self::NAMESPACE_PREFIX, $class, $prefixLength)) { $file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength)); $file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php'); + if (!$file) { + return; + } if (file_exists($file)) { /** @noinspection PhpIncludeInspection Dynamic includes */ require_once $file; diff --git a/src/PhpPresentation/ComparableInterface.php b/src/PhpPresentation/ComparableInterface.php index 87eae2c1bc..7fefbda1c0 100644 --- a/src/PhpPresentation/ComparableInterface.php +++ b/src/PhpPresentation/ComparableInterface.php @@ -10,42 +10,47 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; /** - * PhpOffice\PhpPresentation\ComparableInterface + * PhpOffice\PhpPresentation\ComparableInterface. */ interface ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode(); + public function getHashCode(): string; /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex(); + public function getHashIndex(): ?int; /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value); + public function setHashIndex(int $value); } diff --git a/src/PhpPresentation/DocumentLayout.php b/src/PhpPresentation/DocumentLayout.php index c8cf38564a..bf79104070 100644 --- a/src/PhpPresentation/DocumentLayout.php +++ b/src/PhpPresentation/DocumentLayout.php @@ -10,83 +10,90 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; use PhpOffice\Common\Drawing; /** - * \PhpOffice\PhpPresentation\DocumentLayout + * \PhpOffice\PhpPresentation\DocumentLayout. */ class DocumentLayout { - const LAYOUT_CUSTOM = ''; - const LAYOUT_SCREEN_4X3 = 'screen4x3'; - const LAYOUT_SCREEN_16X10 = 'screen16x10'; - const LAYOUT_SCREEN_16X9 = 'screen16x9'; - const LAYOUT_35MM = '35mm'; - const LAYOUT_A3 = 'A3'; - const LAYOUT_A4 = 'A4'; - const LAYOUT_B4ISO = 'B4ISO'; - const LAYOUT_B5ISO = 'B5ISO'; - const LAYOUT_BANNER = 'banner'; - const LAYOUT_LETTER = 'letter'; - const LAYOUT_OVERHEAD = 'overhead'; - - const UNIT_EMU = 'emu'; - const UNIT_CENTIMETER = 'cm'; - const UNIT_INCH = 'in'; - const UNIT_MILLIMETER = 'mm'; - const UNIT_PIXEL = 'px'; - const UNIT_POINT = 'pt'; + public const LAYOUT_CUSTOM = ''; + public const LAYOUT_SCREEN_4X3 = 'screen4x3'; + public const LAYOUT_SCREEN_16X10 = 'screen16x10'; + public const LAYOUT_SCREEN_16X9 = 'screen16x9'; + public const LAYOUT_35MM = '35mm'; + public const LAYOUT_A3 = 'A3'; + public const LAYOUT_A4 = 'A4'; + public const LAYOUT_B4ISO = 'B4ISO'; + public const LAYOUT_B5ISO = 'B5ISO'; + public const LAYOUT_BANNER = 'banner'; + public const LAYOUT_LETTER = 'letter'; + public const LAYOUT_OVERHEAD = 'overhead'; + + public const UNIT_EMU = 'emu'; + public const UNIT_CENTIMETER = 'cm'; + public const UNIT_INCH = 'in'; + public const UNIT_MILLIMETER = 'mm'; + public const UNIT_PIXEL = 'px'; + public const UNIT_POINT = 'pt'; /** - * Dimension types + * Dimension types. * * 1 px = 9525 EMU @ 96dpi (which is seems to be the default) * Absolute distances are specified in English Metric Units (EMUs), * occasionally referred to as A units; there are 360000 EMUs per * centimeter, 914400 EMUs per inch, 12700 EMUs per point. + * + * @var array> */ - private $dimension = array( - self::LAYOUT_SCREEN_4X3 => array('cx' => 9144000, 'cy' => 6858000), - self::LAYOUT_SCREEN_16X10 => array('cx' => 9144000, 'cy' => 5715000), - self::LAYOUT_SCREEN_16X9 => array('cx' => 9144000, 'cy' => 5143500), - self::LAYOUT_35MM => array('cx' => 10287000, 'cy' => 6858000), - self::LAYOUT_A3 => array('cx' => 15120000, 'cy' => 10692000), - self::LAYOUT_A4 => array('cx' => 10692000, 'cy' => 7560000), - self::LAYOUT_B4ISO => array('cx' => 10826750, 'cy' => 8120063), - self::LAYOUT_B5ISO => array('cx' => 7169150, 'cy' => 5376863), - self::LAYOUT_BANNER => array('cx' => 7315200, 'cy' => 914400), - self::LAYOUT_LETTER => array('cx' => 9144000, 'cy' => 6858000), - self::LAYOUT_OVERHEAD => array('cx' => 9144000, 'cy' => 6858000), - ); + private $dimension = [ + self::LAYOUT_SCREEN_4X3 => ['cx' => 9144000, 'cy' => 6858000], + self::LAYOUT_SCREEN_16X10 => ['cx' => 9144000, 'cy' => 5715000], + self::LAYOUT_SCREEN_16X9 => ['cx' => 9144000, 'cy' => 5143500], + self::LAYOUT_35MM => ['cx' => 10287000, 'cy' => 6858000], + self::LAYOUT_A3 => ['cx' => 15120000, 'cy' => 10692000], + self::LAYOUT_A4 => ['cx' => 10692000, 'cy' => 7560000], + self::LAYOUT_B4ISO => ['cx' => 10826750, 'cy' => 8120063], + self::LAYOUT_B5ISO => ['cx' => 7169150, 'cy' => 5376863], + self::LAYOUT_BANNER => ['cx' => 7315200, 'cy' => 914400], + self::LAYOUT_LETTER => ['cx' => 9144000, 'cy' => 6858000], + self::LAYOUT_OVERHEAD => ['cx' => 9144000, 'cy' => 6858000], + ]; /** - * Layout name + * Layout name. * * @var string */ private $layout; /** - * Layout X dimension + * Layout X dimension. + * * @var float */ private $dimensionX; /** - * Layout Y dimension + * Layout Y dimension. + * * @var float */ private $dimensionY; /** - * Create a new \PhpOffice\PhpPresentation\DocumentLayout + * Create a new \PhpOffice\PhpPresentation\DocumentLayout. */ public function __construct() { @@ -94,23 +101,20 @@ public function __construct() } /** - * Get Document Layout - * - * @return string + * Get Document Layout. */ - public function getDocumentLayout() + public function getDocumentLayout(): string { return $this->layout; } /** - * Set Document Layout + * Set Document Layout. * - * @param array|string $pValue - * @param boolean $isLandscape - * @return \PhpOffice\PhpPresentation\DocumentLayout + * @param array|string $pValue + * @param bool $isLandscape */ - public function setDocumentLayout($pValue = self::LAYOUT_SCREEN_4X3, $isLandscape = true) + public function setDocumentLayout($pValue = self::LAYOUT_SCREEN_4X3, $isLandscape = true): self { switch ($pValue) { case self::LAYOUT_SCREEN_4X3: @@ -146,63 +150,47 @@ public function setDocumentLayout($pValue = self::LAYOUT_SCREEN_4X3, $isLandscap } /** - * Get Document Layout cx - * - * @param string $unit - * @return integer + * Get Document Layout cx. */ - public function getCX($unit = self::UNIT_EMU) + public function getCX(string $unit = self::UNIT_EMU): float { return $this->convertUnit($this->dimensionX, self::UNIT_EMU, $unit); } /** - * Get Document Layout cy - * - * @param string $unit - * @return integer + * Get Document Layout cy. */ - public function getCY($unit = self::UNIT_EMU) + public function getCY(string $unit = self::UNIT_EMU): float { return $this->convertUnit($this->dimensionY, self::UNIT_EMU, $unit); } /** - * Get Document Layout cx - * - * @param float $value - * @param string $unit - * @return DocumentLayout + * Get Document Layout cx. */ - public function setCX($value, $unit = self::UNIT_EMU) + public function setCX(float $value, string $unit = self::UNIT_EMU): self { $this->layout = self::LAYOUT_CUSTOM; $this->dimensionX = $this->convertUnit($value, $unit, self::UNIT_EMU); + return $this; } /** - * Get Document Layout cy - * - * @param float $value - * @param string $unit - * @return DocumentLayout + * Get Document Layout cy. */ - public function setCY($value, $unit = self::UNIT_EMU) + public function setCY(float $value, string $unit = self::UNIT_EMU): self { $this->layout = self::LAYOUT_CUSTOM; $this->dimensionY = $this->convertUnit($value, $unit, self::UNIT_EMU); + return $this; } /** - * Convert EMUs to differents units - * @param float $value - * @param string $fromUnit - * @param string $toUnit - * @return float + * Convert EMUs to differents units. */ - protected function convertUnit($value, $fromUnit, $toUnit) + protected function convertUnit(float $value, string $fromUnit, string $toUnit): float { // Convert from $fromUnit to EMU switch ($fromUnit) { @@ -238,7 +226,7 @@ protected function convertUnit($value, $fromUnit, $toUnit) $value /= 914400; break; case self::UNIT_PIXEL: - $value = Drawing::emuToPixels($value); + $value = Drawing::emuToPixels((int) $value); break; case self::UNIT_POINT: $value /= 12700; @@ -247,6 +235,7 @@ protected function convertUnit($value, $fromUnit, $toUnit) default: // no changes } + return $value; } } diff --git a/src/PhpPresentation/DocumentProperties.php b/src/PhpPresentation/DocumentProperties.php index c9344fed25..ab45420437 100644 --- a/src/PhpPresentation/DocumentProperties.php +++ b/src/PhpPresentation/DocumentProperties.php @@ -10,108 +10,125 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; /** - * \PhpOffice\PhpPresentation\DocumentProperties + * \PhpOffice\PhpPresentation\DocumentProperties. */ class DocumentProperties { + public const PROPERTY_TYPE_BOOLEAN = 'b'; + public const PROPERTY_TYPE_INTEGER = 'i'; + public const PROPERTY_TYPE_FLOAT = 'f'; + public const PROPERTY_TYPE_DATE = 'd'; + public const PROPERTY_TYPE_STRING = 's'; + public const PROPERTY_TYPE_UNKNOWN = 'u'; + /** - * Creator + * Creator. * * @var string */ private $creator; /** - * LastModifiedBy + * LastModifiedBy. * * @var string */ private $lastModifiedBy; /** - * Created + * Created. * * @var int */ private $created; /** - * Modified + * Modified. * * @var int */ private $modified; /** - * Title + * Title. * * @var string */ private $title; /** - * Description + * Description. * * @var string */ private $description; /** - * Subject + * Subject. * * @var string */ private $subject; /** - * Keywords + * Keywords. * * @var string */ private $keywords; /** - * Category + * Category. * * @var string */ private $category; /** - * Company + * Company. * * @var string */ private $company; + /** + * Custom Properties. + * + * @var array> + */ + private $customProperties = []; + /** * Create a new \PhpOffice\PhpPresentation\DocumentProperties */ public function __construct() { // Initialise values - $this->creator = 'Unknown Creator'; + $this->creator = 'Unknown Creator'; $this->lastModifiedBy = $this->creator; - $this->created = time(); - $this->modified = time(); - $this->title = "Untitled Presentation"; - $this->subject = ''; - $this->description = ''; - $this->keywords = ''; - $this->category = ''; - $this->company = 'Microsoft Corporation'; + $this->created = time(); + $this->modified = time(); + $this->title = 'Untitled Presentation'; + $this->subject = ''; + $this->description = ''; + $this->keywords = ''; + $this->category = ''; + $this->company = 'Microsoft Corporation'; } /** - * Get Creator + * Get Creator. * * @return string */ @@ -121,9 +138,10 @@ public function getCreator() } /** - * Set Creator + * Set Creator. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setCreator($pValue = '') @@ -134,7 +152,7 @@ public function setCreator($pValue = '') } /** - * Get Last Modified By + * Get Last Modified By. * * @return string */ @@ -144,9 +162,10 @@ public function getLastModifiedBy() } /** - * Set Last Modified By + * Set Last Modified By. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setLastModifiedBy($pValue = '') @@ -157,7 +176,7 @@ public function setLastModifiedBy($pValue = '') } /** - * Get Created + * Get Created. * * @return int */ @@ -167,9 +186,10 @@ public function getCreated() } /** - * Set Created + * Set Created. * * @param int $pValue + * * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setCreated($pValue = null) @@ -183,7 +203,7 @@ public function setCreated($pValue = null) } /** - * Get Modified + * Get Modified. * * @return int */ @@ -193,9 +213,10 @@ public function getModified() } /** - * Set Modified + * Set Modified. + * + * @param int $pValue * - * @param int $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setModified($pValue = null) @@ -209,7 +230,7 @@ public function setModified($pValue = null) } /** - * Get Title + * Get Title. * * @return string */ @@ -219,9 +240,10 @@ public function getTitle() } /** - * Set Title + * Set Title. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setTitle($pValue = '') @@ -232,7 +254,7 @@ public function setTitle($pValue = '') } /** - * Get Description + * Get Description. * * @return string */ @@ -242,9 +264,10 @@ public function getDescription() } /** - * Set Description + * Set Description. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setDescription($pValue = '') @@ -255,7 +278,7 @@ public function setDescription($pValue = '') } /** - * Get Subject + * Get Subject. * * @return string */ @@ -265,9 +288,10 @@ public function getSubject() } /** - * Set Subject + * Set Subject. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setSubject($pValue = '') @@ -278,7 +302,7 @@ public function setSubject($pValue = '') } /** - * Get Keywords + * Get Keywords. * * @return string */ @@ -288,9 +312,10 @@ public function getKeywords() } /** - * Set Keywords + * Set Keywords. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setKeywords($pValue = '') @@ -301,7 +326,7 @@ public function setKeywords($pValue = '') } /** - * Get Category + * Get Category. * * @return string */ @@ -311,9 +336,10 @@ public function getCategory() } /** - * Set Category + * Set Category. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setCategory($pValue = '') @@ -324,7 +350,7 @@ public function setCategory($pValue = '') } /** - * Get Company + * Get Company. * * @return string */ @@ -334,9 +360,10 @@ public function getCompany() } /** - * Set Company + * Set Company. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\DocumentProperties */ public function setCompany($pValue = '') @@ -345,4 +372,99 @@ public function setCompany($pValue = '') return $this; } + + /** + * Get a List of Custom Property Names. + * + * @return array + */ + public function getCustomProperties(): array + { + return array_keys($this->customProperties); + } + + /** + * Check if a Custom Property is defined. + * + * @param string $propertyName + * + * @return bool + */ + public function isCustomPropertySet(string $propertyName): bool + { + return isset($this->customProperties[$propertyName]); + } + + /** + * Get a Custom Property Value. + * + * @param string $propertyName + * + * @return mixed|null + */ + public function getCustomPropertyValue(string $propertyName) + { + if ($this->isCustomPropertySet($propertyName)) { + return $this->customProperties[$propertyName]['value']; + } + + return null; + } + + /** + * Get a Custom Property Type. + * + * @param string $propertyName + * + * @return string|null + */ + public function getCustomPropertyType(string $propertyName): ?string + { + if ($this->isCustomPropertySet($propertyName)) { + return $this->customProperties[$propertyName]['type']; + } + + return null; + } + + /** + * Set a Custom Property. + * + * @param string $propertyName + * @param mixed $propertyValue + * @param string|null $propertyType + * 'i' : Integer + * 'f' : Floating Point + * 's' : String + * 'd' : Date/Time + * 'b' : Boolean + * + * @return self + */ + public function setCustomProperty(string $propertyName, $propertyValue = '', ?string $propertyType = null): self + { + if (!in_array($propertyType, [ + self::PROPERTY_TYPE_INTEGER, + self::PROPERTY_TYPE_FLOAT, + self::PROPERTY_TYPE_STRING, + self::PROPERTY_TYPE_DATE, + self::PROPERTY_TYPE_BOOLEAN, + ])) { + if (is_float($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_FLOAT; + } elseif (is_int($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_INTEGER; + } elseif (is_bool($propertyValue)) { + $propertyType = self::PROPERTY_TYPE_BOOLEAN; + } else { + $propertyType = self::PROPERTY_TYPE_STRING; + } + } + $this->customProperties[$propertyName] = [ + 'value' => $propertyValue, + 'type' => $propertyType, + ]; + + return $this; + } } diff --git a/src/PhpPresentation/Exception/DirectoryNotFoundException.php b/src/PhpPresentation/Exception/DirectoryNotFoundException.php new file mode 100644 index 0000000000..bfd444c440 --- /dev/null +++ b/src/PhpPresentation/Exception/DirectoryNotFoundException.php @@ -0,0 +1,32 @@ + $authorizedMimetypes + */ + public function __construct(string $expectedMimetype, array $authorizedMimetypes) + { + parent::__construct(sprintf( + 'The mime type %s is not found in autorized values (%s)', + $expectedMimetype, + implode(', ', $authorizedMimetypes) + )); + } +} diff --git a/src/PhpPresentation/Shape/MemoryDrawing.php b/src/PhpPresentation/Exception/UndefinedChartTypeException.php similarity index 67% rename from src/PhpPresentation/Shape/MemoryDrawing.php rename to src/PhpPresentation/Exception/UndefinedChartTypeException.php index e4b5c7a17b..5e77181a0c 100644 --- a/src/PhpPresentation/Shape/MemoryDrawing.php +++ b/src/PhpPresentation/Exception/UndefinedChartTypeException.php @@ -10,19 +10,20 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpPresentation\Shape; +declare(strict_types=1); -use PhpOffice\PhpPresentation\Shape\Drawing\Gd; +namespace PhpOffice\PhpPresentation\Exception; -/** - * Memory drawing shape - * @deprecated Drawing\Gd - */ -class MemoryDrawing extends Gd +class UndefinedChartTypeException extends PhpPresentationException { + public function __construct() + { + parent::__construct('The chart type has not been defined'); + } } diff --git a/src/PhpPresentation/GeometryCalculator.php b/src/PhpPresentation/GeometryCalculator.php index 987a7ba775..7eccbf8959 100644 --- a/src/PhpPresentation/GeometryCalculator.php +++ b/src/PhpPresentation/GeometryCalculator.php @@ -10,40 +10,42 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; /** - * PhpOffice\PhpPresentation\GeometryCalculator + * PhpOffice\PhpPresentation\GeometryCalculator. */ class GeometryCalculator { - const X = 'X'; - const Y = 'Y'; + public const X = 'X'; + public const Y = 'Y'; /** - * Calculate X and Y offsets for a set of shapes within a container such as a slide or group. - * - * @param \PhpOffice\PhpPresentation\ShapeContainerInterface $container - * @return array - */ - public static function calculateOffsets(ShapeContainerInterface $container) + * Calculate X and Y offsets for a set of shapes within a container such as a slide or group. + * + * @return array + */ + public static function calculateOffsets(ShapeContainerInterface $container): array { - $offsets = array(self::X => 0, self::Y => 0); + $offsets = [self::X => 0, self::Y => 0]; - if ($container !== null && count($container->getShapeCollection()) != 0) { + if (null !== $container && 0 != count($container->getShapeCollection())) { $shapes = $container->getShapeCollection(); - if ($shapes[0] !== null) { + if (null !== $shapes[0]) { $offsets[self::X] = $shapes[0]->getOffsetX(); $offsets[self::Y] = $shapes[0]->getOffsetY(); } foreach ($shapes as $shape) { - if ($shape !== null) { + if (null !== $shape) { if ($shape->getOffsetX() < $offsets[self::X]) { $offsets[self::X] = $shape->getOffsetX(); } @@ -59,26 +61,26 @@ public static function calculateOffsets(ShapeContainerInterface $container) } /** - * Calculate X and Y extents for a set of shapes within a container such as a slide or group. - * - * @param \PhpOffice\PhpPresentation\ShapeContainerInterface $container - * @return array - */ - public static function calculateExtents(ShapeContainerInterface $container) + * Calculate X and Y extents for a set of shapes within a container such as a slide or group. + * + * @return array + */ + public static function calculateExtents(ShapeContainerInterface $container): array { - $extents = array(self::X => 0, self::Y => 0); + /** @var array $extents */ + $extents = [self::X => 0, self::Y => 0]; - if ($container !== null && count($container->getShapeCollection()) != 0) { + if (null !== $container && 0 != count($container->getShapeCollection())) { $shapes = $container->getShapeCollection(); - if ($shapes[0] !== null) { - $extents[self::X] = $shapes[0]->getOffsetX() + $shapes[0]->getWidth(); - $extents[self::Y] = $shapes[0]->getOffsetY() + $shapes[0]->getHeight(); + if (null !== $shapes[0]) { + $extents[self::X] = (int) ($shapes[0]->getOffsetX() + $shapes[0]->getWidth()); + $extents[self::Y] = (int) ($shapes[0]->getOffsetY() + $shapes[0]->getHeight()); } foreach ($shapes as $shape) { - if ($shape !== null) { - $extentX = $shape->getOffsetX() + $shape->getWidth(); - $extentY = $shape->getOffsetY() + $shape->getHeight(); + if (null !== $shape) { + $extentX = (int) ($shape->getOffsetX() + $shape->getWidth()); + $extentY = (int) ($shape->getOffsetY() + $shape->getHeight()); if ($extentX > $extents[self::X]) { $extents[self::X] = $extentX; diff --git a/src/PhpPresentation/HashTable.php b/src/PhpPresentation/HashTable.php index 4e8378ee69..df5e5a29a8 100644 --- a/src/PhpPresentation/HashTable.php +++ b/src/PhpPresentation/HashTable.php @@ -10,89 +10,76 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; /** - * \PhpOffice\PhpPresentation\HashTable + * \PhpOffice\PhpPresentation\HashTable. */ class HashTable { /** - * HashTable elements + * HashTable elements. * - * @var array + * @var array */ - public $items = array(); + public $items = []; /** - * HashTable key map + * HashTable key map. * - * @var array + * @var array */ - public $keyMap = array(); + public $keyMap = []; /** - * Create a new \PhpOffice\PhpPresentation\HashTable + * Create a new \PhpOffice\PhpPresentation\HashTable. * - * @param \PhpOffice\PhpPresentation\ComparableInterface[] $pSource Optional source array to create HashTable from - * @throws \Exception + * @param array $pSource Optional source array to create HashTable from */ - public function __construct(array $pSource = null) + public function __construct(array $pSource = []) { - if (!is_null($pSource)) { - // Create HashTable - $this->addFromSource($pSource); - } + $this->addFromSource($pSource); } /** - * Add HashTable items from source + * Add HashTable items from source. * - * @param \PhpOffice\PhpPresentation\ComparableInterface[] $pSource Source array to create HashTable from - * @throws \Exception + * @param array $pSource Source array to create HashTable from */ - public function addFromSource($pSource = null) + public function addFromSource(array $pSource = []): void { - // Check if an array was passed - if ($pSource == null) { - return; - } elseif (!is_array($pSource)) { - throw new \Exception('Invalid array parameter passed.'); - } - foreach ($pSource as $item) { $this->add($item); } } /** - * Add HashTable item + * Add HashTable item. * - * @param \PhpOffice\PhpPresentation\ComparableInterface $pSource Item to add + * @param ComparableInterface $pSource Item to add */ - public function add(ComparableInterface $pSource) + public function add(ComparableInterface $pSource): void { // Determine hashcode $hashIndex = $pSource->getHashIndex(); - - if (is_null($hashIndex)) { - $hashCode = $pSource->getHashCode(); - } elseif (isset($this->keyMap[$hashIndex])) { + $hashCode = $pSource->getHashCode(); + if (isset($this->keyMap[$hashIndex])) { $hashCode = $this->keyMap[$hashIndex]; - } else { - $hashCode = $pSource->getHashCode(); } // Add value if (!isset($this->items[$hashCode])) { $this->items[$hashCode] = $pSource; - $index = count($this->items) - 1; - $this->keyMap[$index] = $hashCode; + $index = count($this->items) - 1; + $this->keyMap[$index] = $hashCode; $pSource->setHashIndex($index); } else { $pSource->setHashIndex($this->items[$hashCode]->getHashIndex()); @@ -100,12 +87,11 @@ public function add(ComparableInterface $pSource) } /** - * Remove HashTable item + * Remove HashTable item. * - * @param \PhpOffice\PhpPresentation\ComparableInterface $pSource Item to remove - * @throws \Exception + * @param ComparableInterface $pSource Item to remove */ - public function remove(ComparableInterface $pSource) + public function remove(ComparableInterface $pSource): void { if (isset($this->items[$pSource->getHashCode()])) { unset($this->items[$pSource->getHashCode()]); @@ -125,44 +111,38 @@ public function remove(ComparableInterface $pSource) } /** - * Clear HashTable - * + * Clear HashTable. */ - public function clear() + public function clear(): void { - $this->items = array(); - $this->keyMap = array(); + $this->items = []; + $this->keyMap = []; } /** - * Count - * - * @return int + * Count. */ - public function count() + public function count(): int { return count($this->items); } /** - * Get index for hash code + * Get index for hash code. * - * @param string $pHashCode - * @return int Index + * @return int Index (-1 if not found) */ - public function getIndexForHashCode($pHashCode = '') + public function getIndexForHashCode(string $pHashCode = ''): int { - return array_search($pHashCode, $this->keyMap); + $index = array_search($pHashCode, $this->keyMap); + + return false === $index ? -1 : $index; } /** - * Get by index - * - * @param int $pIndex - * @return \PhpOffice\PhpPresentation\ComparableInterface - * + * Get by index. */ - public function getByIndex($pIndex = 0) + public function getByIndex(int $pIndex = 0): ?ComparableInterface { if (isset($this->keyMap[$pIndex])) { return $this->getByHashCode($this->keyMap[$pIndex]); @@ -172,13 +152,9 @@ public function getByIndex($pIndex = 0) } /** - * Get by hashcode - * - * @param string $pHashCode - * @return \PhpOffice\PhpPresentation\ComparableInterface - * + * Get by hashcode. */ - public function getByHashCode($pHashCode = '') + public function getByHashCode(string $pHashCode = ''): ?ComparableInterface { if (isset($this->items[$pHashCode])) { return $this->items[$pHashCode]; @@ -188,11 +164,11 @@ public function getByHashCode($pHashCode = '') } /** - * HashTable to array + * HashTable to array. * - * @return \PhpOffice\PhpPresentation\ComparableInterface[] + * @return array */ - public function toArray() + public function toArray(): array { return $this->items; } diff --git a/src/PhpPresentation/IOFactory.php b/src/PhpPresentation/IOFactory.php index 5f94f157a1..0d7f90b291 100644 --- a/src/PhpPresentation/IOFactory.php +++ b/src/PhpPresentation/IOFactory.php @@ -10,58 +10,61 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; +use PhpOffice\PhpPresentation\Exception\InvalidClassException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; +use PhpOffice\PhpPresentation\Reader\ReaderInterface; +use PhpOffice\PhpPresentation\Writer\WriterInterface; +use ReflectionClass; + /** - * IOFactory + * IOFactory. */ class IOFactory { /** - * Autoresolve classes + * Autoresolve classes. * - * @var array + * @var array */ - private static $autoResolveClasses = array('Serialized', 'ODPresentation', 'PowerPoint97', 'PowerPoint2007'); + private static $autoResolveClasses = ['Serialized', 'ODPresentation', 'PowerPoint97', 'PowerPoint2007']; /** - * Create writer + * Create writer. * * @param PhpPresentation $phpPresentation * @param string $name - * @return \PhpOffice\PhpPresentation\Writer\WriterInterface */ - public static function createWriter(PhpPresentation $phpPresentation, $name = 'PowerPoint2007') + public static function createWriter(PhpPresentation $phpPresentation, string $name = 'PowerPoint2007'): WriterInterface { - $class = 'PhpOffice\\PhpPresentation\\Writer\\' . $name; - return self::loadClass($class, $name, 'writer', $phpPresentation); + return self::loadClass('PhpOffice\\PhpPresentation\\Writer\\' . $name, 'Writer', $phpPresentation); } /** - * Create reader + * Create reader. * - * @param string $name - * @return \PhpOffice\PhpPresentation\Reader\ReaderInterface + * @param string $name */ - public static function createReader($name = '') + public static function createReader(string $name): ReaderInterface { - $class = 'PhpOffice\\PhpPresentation\\Reader\\' . $name; - return self::loadClass($class, $name, 'reader'); + return self::loadClass('PhpOffice\\PhpPresentation\\Reader\\' . $name, 'Reader'); } /** - * Loads PhpPresentation from file using automatic \PhpOffice\PhpPresentation\Reader\ReaderInterface resolution + * Loads PhpPresentation from file using automatic ReaderInterface resolution. * - * @param string $pFilename - * @return PhpPresentation - * @throws \Exception + * @throws InvalidFileFormatException */ - public static function load($pFilename) + public static function load(string $pFilename): PhpPresentation { // Try loading using self::$autoResolveClasses foreach (self::$autoResolveClasses as $autoResolveClass) { @@ -71,41 +74,45 @@ public static function load($pFilename) } } - throw new \Exception("Could not automatically determine \PhpOffice\PhpPresentation\Reader\ReaderInterface for file."); + throw new InvalidFileFormatException( + $pFilename, + IOFactory::class, + 'Could not automatically determine the good ' . ReaderInterface::class + ); } /** * Load class * * @param string $class - * @param string $name * @param string $type - * @param \PhpOffice\PhpPresentation\PhpPresentation $phpPresentation - * @throws \Exception - * @return + * @param PhpPresentation|null $phpPresentation + * + * @return object + * + * @throws InvalidClassException */ - private static function loadClass($class, $name, $type, PhpPresentation $phpPresentation = null) + private static function loadClass(string $class, string $type, PhpPresentation $phpPresentation = null) { - if (class_exists($class) && self::isConcreteClass($class)) { - if (is_null($phpPresentation)) { - return new $class(); - } else { - return new $class($phpPresentation); - } - } else { - throw new \Exception('"'.$name.'" is not a valid '.$type.'.'); + if (!class_exists($class)) { + throw new InvalidClassException($class, $type . ': The class doesn\'t exist'); + } + if (!self::isConcreteClass($class)) { + throw new InvalidClassException($class, $type . ': The class is an abstract class or an interface'); + } + if (is_null($phpPresentation)) { + return new $class(); } + + return new $class($phpPresentation); } /** * Is it a concrete class? - * - * @param string $class - * @return bool */ - private static function isConcreteClass($class) + private static function isConcreteClass(string $class): bool { - $reflection = new \ReflectionClass($class); + $reflection = new ReflectionClass($class); return !$reflection->isAbstract() && !$reflection->isInterface(); } diff --git a/src/PhpPresentation/PhpPresentation.php b/src/PhpPresentation/PhpPresentation.php index 5803342898..e2db811f5a 100644 --- a/src/PhpPresentation/PhpPresentation.php +++ b/src/PhpPresentation/PhpPresentation.php @@ -10,65 +10,70 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; -use PhpOffice\PhpPresentation\Slide; +use ArrayObject; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Slide\Iterator; use PhpOffice\PhpPresentation\Slide\SlideMaster; /** - * PhpPresentation + * PhpPresentation. */ class PhpPresentation { /** - * Document properties + * Document properties. * - * @var \PhpOffice\PhpPresentation\DocumentProperties + * @var DocumentProperties */ protected $documentProperties; /** - * Presentation properties + * Presentation properties. * - * @var \PhpOffice\PhpPresentation\PresentationProperties + * @var PresentationProperties */ protected $presentationProps; /** - * Document layout + * Document layout. * - * @var \PhpOffice\PhpPresentation\DocumentLayout + * @var DocumentLayout */ protected $layout; /** - * Collection of Slide objects + * Collection of Slide objects. * - * @var \PhpOffice\PhpPresentation\Slide[] + * @var array */ - protected $slideCollection = array(); + protected $slideCollection = []; /** - * Active slide index + * Active slide index. * * @var int */ protected $activeSlideIndex = 0; /** - * Collection of Master Slides - * @var \ArrayObject|\PhpOffice\PhpPresentation\Slide\SlideMaster[] + * Collection of Master Slides. + * + * @var array|ArrayObject */ protected $slideMasters; /** - * Create a new PhpPresentation with one Slide + * Create a new PhpPresentation with one Slide. */ public function __construct() { @@ -86,45 +91,17 @@ public function __construct() } /** - * Get properties - * - * @return \PhpOffice\PhpPresentation\DocumentProperties - * @deprecated for getDocumentProperties - */ - public function getProperties() - { - return $this->getDocumentProperties(); - } - - /** - * Set properties - * - * @param \PhpOffice\PhpPresentation\DocumentProperties $value - * @deprecated for setDocumentProperties - * @return PhpPresentation - */ - public function setProperties(DocumentProperties $value) - { - return $this->setDocumentProperties($value); - } - - /** - * Get properties - * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * Get properties. */ - public function getDocumentProperties() + public function getDocumentProperties(): DocumentProperties { return $this->documentProperties; } /** - * Set properties - * - * @param \PhpOffice\PhpPresentation\DocumentProperties $value - * @return PhpPresentation + * Set properties. */ - public function setDocumentProperties(DocumentProperties $value) + public function setDocumentProperties(DocumentProperties $value): self { $this->documentProperties = $value; @@ -132,44 +109,37 @@ public function setDocumentProperties(DocumentProperties $value) } /** - * Get presentation properties - * - * @return \PhpOffice\PhpPresentation\PresentationProperties + * Get presentation properties. */ - public function getPresentationProperties() + public function getPresentationProperties(): PresentationProperties { return $this->presentationProps; } /** - * Set presentation properties + * Set presentation properties. * - * @param \PhpOffice\PhpPresentation\PresentationProperties $value * @return PhpPresentation */ - public function setPresentationProperties(PresentationProperties $value) + public function setPresentationProperties(PresentationProperties $value): self { $this->presentationProps = $value; + return $this; } /** - * Get layout - * - * @return \PhpOffice\PhpPresentation\DocumentLayout + * Get layout. */ - public function getLayout() + public function getLayout(): DocumentLayout { return $this->layout; } /** - * Set layout - * - * @param \PhpOffice\PhpPresentation\DocumentLayout $value - * @return PhpPresentation + * Set layout. */ - public function setLayout(DocumentLayout $value) + public function setLayout(DocumentLayout $value): self { $this->layout = $value; @@ -177,35 +147,28 @@ public function setLayout(DocumentLayout $value) } /** - * Get active slide - * - * @return \PhpOffice\PhpPresentation\Slide + * Get active slide. */ - public function getActiveSlide() + public function getActiveSlide(): Slide { return $this->slideCollection[$this->activeSlideIndex]; } /** - * Create slide and add it to this presentation - * - * @return \PhpOffice\PhpPresentation\Slide + * Create slide and add it to this presentation. */ - public function createSlide() + public function createSlide(): Slide { $newSlide = new Slide($this); $this->addSlide($newSlide); + return $newSlide; } /** - * Add slide - * - * @param \PhpOffice\PhpPresentation\Slide $slide - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Slide + * Add slide. */ - public function addSlide(Slide $slide = null) + public function addSlide(Slide $slide): Slide { $this->slideCollection[] = $slide; @@ -213,114 +176,106 @@ public function addSlide(Slide $slide = null) } /** - * Remove slide by index + * Remove slide by index. * - * @param int $index Slide index - * @throws \Exception - * @return PhpPresentation + * @param int $index Slide index + * + * @throws OutOfBoundsException */ - public function removeSlideByIndex($index = 0) + public function removeSlideByIndex(int $index = 0): self { if ($index > count($this->slideCollection) - 1) { - throw new \Exception("Slide index is out of bounds."); - } else { - array_splice($this->slideCollection, $index, 1); + throw new OutOfBoundsException(0, count($this->slideCollection) - 1, $index); } + array_splice($this->slideCollection, $index, 1); return $this; } /** - * Get slide by index + * Get slide by index. + * + * @param int $index Slide index * - * @param int $index Slide index - * @return \PhpOffice\PhpPresentation\Slide - * @throws \Exception + * @throws OutOfBoundsException */ - public function getSlide($index = 0) + public function getSlide(int $index = 0): Slide { if ($index > count($this->slideCollection) - 1) { - throw new \Exception("Slide index is out of bounds."); - } else { - return $this->slideCollection[$index]; + throw new OutOfBoundsException(0, count($this->slideCollection) - 1, $index); } + + return $this->slideCollection[$index]; } /** - * Get all slides + * Get all slides. * - * @return \PhpOffice\PhpPresentation\Slide[] + * @return array */ - public function getAllSlides() + public function getAllSlides(): array { return $this->slideCollection; } /** - * Get index for slide - * - * @param \PhpOffice\PhpPresentation\Slide\AbstractSlide $slide - * @return int - * @throws \Exception + * Get index for slide. */ - public function getIndex(Slide\AbstractSlide $slide) + public function getIndex(Slide\AbstractSlide $slide): ?int { - $index = null; + if (empty($this->slideCollection)) { + return null; + } foreach ($this->slideCollection as $key => $value) { if ($value->getHashCode() == $slide->getHashCode()) { - $index = $key; - break; + return $key; } } - return $index; + + return null; } /** - * Get slide count - * - * @return int + * Get slide count. */ - public function getSlideCount() + public function getSlideCount(): int { return count($this->slideCollection); } /** - * Get active slide index + * Get active slide index. * * @return int Active slide index */ - public function getActiveSlideIndex() + public function getActiveSlideIndex(): int { return $this->activeSlideIndex; } /** - * Set active slide index + * Set active slide index. * - * @param int $index Active slide index - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Slide + * @param int $index Active slide index + * + * @throws OutOfBoundsException */ - public function setActiveSlideIndex($index = 0) + public function setActiveSlideIndex(int $index = 0): Slide { if ($index > count($this->slideCollection) - 1) { - throw new \Exception("Active slide index is out of bounds."); - } else { - $this->activeSlideIndex = $index; + throw new OutOfBoundsException(0, count($this->slideCollection) - 1, $index); } + $this->activeSlideIndex = $index; return $this->getActiveSlide(); } /** - * Add external slide + * Add external slide. * - * @param \PhpOffice\PhpPresentation\Slide $slide External slide to add - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Slide + * @param Slide $slide External slide to add */ - public function addExternalSlide(Slide $slide) + public function addExternalSlide(Slide $slide): Slide { $slide->rebindParent($this); @@ -330,35 +285,28 @@ public function addExternalSlide(Slide $slide) } /** - * Get slide iterator - * - * @return \PhpOffice\PhpPresentation\Slide\Iterator + * Get slide iterator. */ - public function getSlideIterator() + public function getSlideIterator(): Iterator { return new Iterator($this); } /** - * Create a masterslide and add it to this presentation - * - * @return \PhpOffice\PhpPresentation\Slide\SlideMaster + * Create a masterslide and add it to this presentation. */ - public function createMasterSlide() + public function createMasterSlide(): SlideMaster { $newMasterSlide = new SlideMaster($this); $this->addMasterSlide($newMasterSlide); + return $newMasterSlide; } /** - * Add masterslide - * - * @param \PhpOffice\PhpPresentation\Slide\SlideMaster $slide - * @return \PhpOffice\PhpPresentation\Slide\SlideMaster - * @throws \Exception + * Add masterslide. */ - public function addMasterSlide(SlideMaster $slide = null) + public function addMasterSlide(SlideMaster $slide): SlideMaster { $this->slideMasters[] = $slide; @@ -366,11 +314,9 @@ public function addMasterSlide(SlideMaster $slide = null) } /** - * Copy presentation (!= clone!) - * - * @return PhpPresentation + * Copy presentation (!= clone!). */ - public function copy() + public function copy(): PhpPresentation { $copied = clone $this; @@ -384,49 +330,7 @@ public function copy() } /** - * Mark a document as final - * @param bool $state - * @return PhpPresentation - * @deprecated for getPresentationProperties()->markAsFinal() - */ - public function markAsFinal($state = true) - { - return $this->getPresentationProperties()->markAsFinal($state); - } - - /** - * Return if this document is marked as final - * @return bool - * @deprecated for getPresentationProperties()->isMarkedAsFinal() - */ - public function isMarkedAsFinal() - { - return $this->getPresentationProperties()->isMarkedAsFinal(); - } - - /** - * Set the zoom of the document (in percentage) - * @param float $zoom - * @return PhpPresentation - * @deprecated for getPresentationProperties()->setZoom() - */ - public function setZoom($zoom = 1) - { - return $this->getPresentationProperties()->setZoom($zoom); - } - - /** - * Return the zoom (in percentage) - * @return float - * @deprecated for getPresentationProperties()->getZoom() - */ - public function getZoom() - { - return $this->getPresentationProperties()->getZoom(); - } - - /** - * @return \ArrayObject|Slide\SlideMaster[] + * @return array|ArrayObject */ public function getAllMasterSlides() { @@ -434,14 +338,14 @@ public function getAllMasterSlides() } /** - * @param \ArrayObject|Slide\SlideMaster[] $slideMasters - * @return $this + * @param array|ArrayObject $slideMasters */ - public function setAllMasterSlides($slideMasters = array()) + public function setAllMasterSlides($slideMasters = []): self { - if ($slideMasters instanceof \ArrayObject || is_array($slideMasters)) { + if ($slideMasters instanceof ArrayObject || is_array($slideMasters)) { $this->slideMasters = $slideMasters; } + return $this; } } diff --git a/src/PhpPresentation/PresentationProperties.php b/src/PhpPresentation/PresentationProperties.php index 2e69f858cd..a8ee8eff3f 100644 --- a/src/PhpPresentation/PresentationProperties.php +++ b/src/PhpPresentation/PresentationProperties.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; -/** - * \PhpOffice\PhpPresentation\PresentationProperties - */ class PresentationProperties { - const VIEW_HANDOUT = 'handoutView'; - const VIEW_NOTES = 'notesView'; - const VIEW_NOTES_MASTER = 'notesMasterView'; - const VIEW_OUTLINE = 'outlineView'; - const VIEW_SLIDE = 'sldView'; - const VIEW_SLIDE_MASTER = 'sldMasterView'; - const VIEW_SLIDE_SORTER = 'sldSorterView'; - const VIEW_SLIDE_THUMBNAIL = 'sldThumbnailView'; - - protected $arrayView = array( + public const VIEW_HANDOUT = 'handoutView'; + public const VIEW_NOTES = 'notesView'; + public const VIEW_NOTES_MASTER = 'notesMasterView'; + public const VIEW_OUTLINE = 'outlineView'; + public const VIEW_SLIDE = 'sldView'; + public const VIEW_SLIDE_MASTER = 'sldMasterView'; + public const VIEW_SLIDE_SORTER = 'sldSorterView'; + public const VIEW_SLIDE_THUMBNAIL = 'sldThumbnailView'; + + /** + * @var array + */ + protected $arrayView = [ self::VIEW_HANDOUT, self::VIEW_NOTES, self::VIEW_NOTES_MASTER, @@ -39,163 +43,189 @@ class PresentationProperties self::VIEW_SLIDE_MASTER, self::VIEW_SLIDE_SORTER, self::VIEW_SLIDE_THUMBNAIL, - ); + ]; - /* - * @var boolean + public const SLIDESHOW_TYPE_PRESENT = 'present'; + public const SLIDESHOW_TYPE_BROWSE = 'browse'; + public const SLIDESHOW_TYPE_KIOSK = 'kiosk'; + + /** + * @var array + */ + protected $arraySlideshowTypes = [ + self::SLIDESHOW_TYPE_PRESENT, + self::SLIDESHOW_TYPE_BROWSE, + self::SLIDESHOW_TYPE_KIOSK, + ]; + + /** + * @var bool */ protected $isLoopUntilEsc = false; /** - * Mark as final + * Mark as final. + * * @var bool */ protected $markAsFinal = false; - /* - * @var string + /** + * @var string|null */ protected $thumbnail; /** - * Zoom + * Zoom. + * * @var float */ - protected $zoom = 1; + protected $zoom = 1.0; - /* + /** * @var string */ protected $lastView = self::VIEW_SLIDE; - /* - * @var boolean + /** + * @var string */ - protected $isCommentVisible = false; - + protected $slideshowType = self::SLIDESHOW_TYPE_PRESENT; + /** - * @return bool + * @var bool */ - public function isLoopContinuouslyUntilEsc() + protected $isCommentVisible = false; + + public function isLoopContinuouslyUntilEsc(): bool { return $this->isLoopUntilEsc; } - - /** - * @param bool $value - * @return \PhpOffice\PhpPresentation\PresentationProperties - */ - public function setLoopContinuouslyUntilEsc($value = false) + + public function setLoopContinuouslyUntilEsc(bool $value = false): self { - if (is_bool($value)) { - $this->isLoopUntilEsc = $value; - } + $this->isLoopUntilEsc = $value; + return $this; } - + /** - * Return the thumbnail file path - * @return string + * Return the thumbnail file path. + * + * @return string|null */ - public function getThumbnailPath() + public function getThumbnailPath(): ?string { return $this->thumbnail; } - + /** - * Define the path for the thumbnail file / preview picture + * Define the path for the thumbnail file / preview picture. + * * @param string $path - * @return \PhpOffice\PhpPresentation\PresentationProperties + * + * @return self */ - public function setThumbnailPath($path = '') + public function setThumbnailPath(string $path = ''): self { if (file_exists($path)) { $this->thumbnail = $path; } + return $this; } /** - * Mark a document as final - * @param bool $state - * @return PhpPresentation + * Mark a document as final. */ - public function markAsFinal($state = true) + public function markAsFinal(bool $state = true): self { - if (is_bool($state)) { - $this->markAsFinal = $state; - } + $this->markAsFinal = $state; + return $this; } /** - * Return if this document is marked as final + * Return if this document is marked as final. + * * @return bool */ - public function isMarkedAsFinal() + public function isMarkedAsFinal(): bool { return $this->markAsFinal; } /** - * Set the zoom of the document (in percentage) - * @param float $zoom - * @return PhpPresentation + * Set the zoom of the document (in percentage). */ - public function setZoom($zoom = 1) + public function setZoom(float $zoom = 1.0): self { - if (is_numeric($zoom)) { - $this->zoom = (float)$zoom; - } + $this->zoom = $zoom; + return $this; } /** - * Return the zoom (in percentage) - * @return float + * Return the zoom (in percentage). */ - public function getZoom() + public function getZoom(): float { return $this->zoom; } /** * @param string $value - * @return $this + * + * @return self */ - public function setLastView($value = self::VIEW_SLIDE) + public function setLastView(string $value = self::VIEW_SLIDE): self { if (in_array($value, $this->arrayView)) { $this->lastView = $value; } + return $this; } /** * @return string */ - public function getLastView() + public function getLastView(): string { return $this->lastView; } - /** - * @param bool $value - * @return $this - */ - public function setCommentVisible($value = false) + public function setCommentVisible(bool $value = false): self { - if (is_bool($value)) { - $this->isCommentVisible = $value; - } + $this->isCommentVisible = $value; + return $this; } + public function isCommentVisible(): bool + { + return $this->isCommentVisible; + } + /** * @return string */ - public function isCommentVisible() + public function getSlideshowType(): string { - return $this->isCommentVisible; + return $this->slideshowType; + } + + /** + * @param string $value + * + * @return self + */ + public function setSlideshowType(string $value = self::SLIDESHOW_TYPE_PRESENT): self + { + if (in_array($value, $this->arraySlideshowTypes)) { + $this->slideshowType = $value; + } + + return $this; } } diff --git a/src/PhpPresentation/Reader/ODPresentation.php b/src/PhpPresentation/Reader/ODPresentation.php index b81454f2eb..25a6d1cbb3 100644 --- a/src/PhpPresentation/Reader/ODPresentation.php +++ b/src/PhpPresentation/Reader/ODPresentation.php @@ -10,63 +10,76 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Reader; -use ZipArchive; -use PhpOffice\Common\XMLReader; +use DateTime; +use DOMElement; use PhpOffice\Common\Drawing as CommonDrawing; +use PhpOffice\Common\XMLReader; +use PhpOffice\PhpPresentation\DocumentProperties; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\PresentationProperties; +use PhpOffice\PhpPresentation\Shape\Drawing\Base64; use PhpOffice\PhpPresentation\Shape\Drawing\Gd; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Slide\Background\Image; +use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Color; +use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\Shadow; -use PhpOffice\PhpPresentation\Style\Alignment; +use ZipArchive; /** - * Serialized format reader + * Serialized format reader. */ class ODPresentation implements ReaderInterface { /** - * Output Object + * Output Object. + * * @var PhpPresentation */ protected $oPhpPresentation; /** - * Output Object + * Output Object. + * * @var \ZipArchive */ protected $oZip; /** * @var array[] */ - protected $arrayStyles = array(); + protected $arrayStyles = []; /** * @var array[] */ - protected $arrayCommonStyles = array(); + protected $arrayCommonStyles = []; /** * @var \PhpOffice\Common\XMLReader */ protected $oXMLReader; + /** + * @var int + */ + protected $levelParagraph = 0; /** * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file? - * - * @param string $pFilename - * @throws \Exception - * @return boolean */ - public function canRead($pFilename) + public function canRead(string $pFilename): bool { return $this->fileSupportsUnserializePhpPresentation($pFilename); } @@ -74,82 +87,81 @@ public function canRead($pFilename) /** * Does a file support UnserializePhpPresentation ? * - * @param string $pFilename - * @throws \Exception - * @return boolean + * @throws FileNotFoundException */ - public function fileSupportsUnserializePhpPresentation($pFilename = '') + public function fileSupportsUnserializePhpPresentation(string $pFilename = ''): bool { // Check if file exists if (!file_exists($pFilename)) { - throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist."); + throw new FileNotFoundException($pFilename); } - + $oZip = new ZipArchive(); // Is it a zip ? - if ($oZip->open($pFilename) === true) { + if (true === $oZip->open($pFilename)) { // Is it an OpenXML Document ? // Is it a Presentation ? - if (is_array($oZip->statName('META-INF/manifest.xml')) && is_array($oZip->statName('mimetype')) && $oZip->getFromName('mimetype') == 'application/vnd.oasis.opendocument.presentation') { + if (is_array($oZip->statName('META-INF/manifest.xml')) && is_array($oZip->statName('mimetype')) && 'application/vnd.oasis.opendocument.presentation' == $oZip->getFromName('mimetype')) { return true; } } + return false; } /** - * Loads PhpPresentation Serialized file + * Loads PhpPresentation Serialized file. * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation - * @throws \Exception + * @throws InvalidFileFormatException */ - public function load($pFilename) + public function load(string $pFilename): PhpPresentation { // Unserialize... First make sure the file supports it! if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) { - throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\ODPresentation: " . $pFilename . "."); + throw new InvalidFileFormatException($pFilename, ODPresentation::class); } return $this->loadFile($pFilename); } /** - * Load PhpPresentation Serialized file + * Load PhpPresentation Serialized file. * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation + * @param string $pFilename + * + * @return PhpPresentation */ protected function loadFile($pFilename) { $this->oPhpPresentation = new PhpPresentation(); $this->oPhpPresentation->removeSlideByIndex(); - + $this->oZip = new ZipArchive(); $this->oZip->open($pFilename); - + $this->oXMLReader = new XMLReader(); - if ($this->oXMLReader->getDomFromZip($pFilename, 'meta.xml') !== false) { + if (false !== $this->oXMLReader->getDomFromZip($pFilename, 'meta.xml')) { $this->loadDocumentProperties(); } $this->oXMLReader = new XMLReader(); - if ($this->oXMLReader->getDomFromZip($pFilename, 'styles.xml') !== false) { + if (false !== $this->oXMLReader->getDomFromZip($pFilename, 'styles.xml')) { $this->loadStylesFile(); } $this->oXMLReader = new XMLReader(); - if ($this->oXMLReader->getDomFromZip($pFilename, 'content.xml') !== false) { + if (false !== $this->oXMLReader->getDomFromZip($pFilename, 'content.xml')) { $this->loadSlides(); + $this->loadPresentationProperties(); } return $this->oPhpPresentation; } - + /** * Read Document Properties */ - protected function loadDocumentProperties() + protected function loadDocumentProperties(): void { - $arrayProperties = array( + $arrayProperties = [ '/office:document-meta/office:meta/meta:initial-creator' => 'setCreator', '/office:document-meta/office:meta/dc:creator' => 'setLastModifiedBy', '/office:document-meta/office:meta/dc:title' => 'setTitle', @@ -158,60 +170,99 @@ protected function loadDocumentProperties() '/office:document-meta/office:meta/meta:keyword' => 'setKeywords', '/office:document-meta/office:meta/meta:creation-date' => 'setCreated', '/office:document-meta/office:meta/dc:date' => 'setModified', - ); - $oProperties = $this->oPhpPresentation->getDocumentProperties(); + ]; + $properties = $this->oPhpPresentation->getDocumentProperties(); foreach ($arrayProperties as $path => $property) { $oElement = $this->oXMLReader->getElement($path); - if ($oElement instanceof \DOMElement) { - if (in_array($property, array('setCreated', 'setModified'))) { - $oDateTime = new \DateTime(); - $oDateTime->createFromFormat(\DateTime::W3C, $oElement->nodeValue); - $oProperties->{$property}($oDateTime->getTimestamp()); - } else { - $oProperties->{$property}($oElement->nodeValue); + if ($oElement instanceof DOMElement) { + $value = $oElement->nodeValue; + if (in_array($property, ['setCreated', 'setModified'])) { + $dateTime = DateTime::createFromFormat(DateTime::W3C, $value); + if (!$dateTime) { + $dateTime = new DateTime(); + } + $value = $dateTime->getTimestamp(); } + $properties->{$property}($value); } } + + foreach ($this->oXMLReader->getElements('/office:document-meta/office:meta/meta:user-defined') as $element) { + if (!($element instanceof DOMElement) + || !$element->hasAttribute('meta:name')) { + continue; + } + $propertyName = $element->getAttribute('meta:name'); + $propertyValue = (string) $element->nodeValue; + $propertyType = $element->getAttribute('meta:value-type'); + switch ($propertyType) { + case 'boolean': + $propertyType = DocumentProperties::PROPERTY_TYPE_BOOLEAN; + break; + case 'float': + $propertyType = filter_var($propertyValue, FILTER_VALIDATE_INT) === false + ? DocumentProperties::PROPERTY_TYPE_FLOAT + : DocumentProperties::PROPERTY_TYPE_INTEGER; + break; + case 'date': + $propertyType = DocumentProperties::PROPERTY_TYPE_DATE; + break; + case 'string': + default: + $propertyType = DocumentProperties::PROPERTY_TYPE_STRING; + break; + } + $properties->setCustomProperty($propertyName, $propertyValue, $propertyType); + } } - + /** * Extract all slides */ - protected function loadSlides() + protected function loadSlides(): void { foreach ($this->oXMLReader->getElements('/office:document-content/office:automatic-styles/*') as $oElement) { - if ($oElement->hasAttribute('style:name')) { + if ($oElement instanceof DOMElement && $oElement->hasAttribute('style:name')) { $this->loadStyle($oElement); } } foreach ($this->oXMLReader->getElements('/office:document-content/office:body/office:presentation/draw:page') as $oElement) { - if ($oElement->nodeName == 'draw:page') { + if ($oElement instanceof DOMElement && 'draw:page' == $oElement->nodeName) { $this->loadSlide($oElement); } } } - + + protected function loadPresentationProperties(): void + { + $element = $this->oXMLReader->getElement('/office:document-content/office:body/office:presentation/presentation:settings'); + if ($element instanceof DOMElement) { + if ($element->getAttribute('presentation:full-screen') === 'false') { + $this->oPhpPresentation->getPresentationProperties()->setSlideshowType(PresentationProperties::SLIDESHOW_TYPE_BROWSE); + } + } + } + /** * Extract style - * @param \DOMElement $nodeStyle */ - protected function loadStyle(\DOMElement $nodeStyle) + protected function loadStyle(DOMElement $nodeStyle): bool { $keyStyle = $nodeStyle->getAttribute('style:name'); $nodeDrawingPageProps = $this->oXMLReader->getElement('style:drawing-page-properties', $nodeStyle); - if ($nodeDrawingPageProps instanceof \DOMElement) { + if ($nodeDrawingPageProps instanceof DOMElement) { // Read Background Color - if ($nodeDrawingPageProps->hasAttribute('draw:fill-color') && $nodeDrawingPageProps->getAttribute('draw:fill') == 'solid') { + if ($nodeDrawingPageProps->hasAttribute('draw:fill-color') && 'solid' == $nodeDrawingPageProps->getAttribute('draw:fill')) { $oBackground = new \PhpOffice\PhpPresentation\Slide\Background\Color(); $oColor = new Color(); $oColor->setRGB(substr($nodeDrawingPageProps->getAttribute('draw:fill-color'), -6)); $oBackground->setColor($oColor); } // Read Background Image - if ($nodeDrawingPageProps->getAttribute('draw:fill') == 'bitmap' && $nodeDrawingPageProps->hasAttribute('draw:fill-image-name')) { + if ('bitmap' == $nodeDrawingPageProps->getAttribute('draw:fill') && $nodeDrawingPageProps->hasAttribute('draw:fill-image-name')) { $nameStyle = $nodeDrawingPageProps->getAttribute('draw:fill-image-name'); - if (!empty($this->arrayCommonStyles[$nameStyle]) && $this->arrayCommonStyles[$nameStyle]['type'] == 'image' && !empty($this->arrayCommonStyles[$nameStyle]['path'])) { + if (!empty($this->arrayCommonStyles[$nameStyle]) && 'image' == $this->arrayCommonStyles[$nameStyle]['type'] && !empty($this->arrayCommonStyles[$nameStyle]['path'])) { $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderODPBkg'); $contentImg = $this->oZip->getFromName($this->arrayCommonStyles[$nameStyle]['path']); file_put_contents($tmpBkgImg, $contentImg); @@ -223,113 +274,222 @@ protected function loadStyle(\DOMElement $nodeStyle) } $nodeGraphicProps = $this->oXMLReader->getElement('style:graphic-properties', $nodeStyle); - if ($nodeGraphicProps instanceof \DOMElement) { + if ($nodeGraphicProps instanceof DOMElement) { // Read Shadow - if ($nodeGraphicProps->hasAttribute('draw:shadow') && $nodeGraphicProps->getAttribute('draw:shadow') == 'visible') { + if ($nodeGraphicProps->hasAttribute('draw:shadow') && 'visible' == $nodeGraphicProps->getAttribute('draw:shadow')) { $oShadow = new Shadow(); $oShadow->setVisible(true); if ($nodeGraphicProps->hasAttribute('draw:shadow-color')) { $oShadow->getColor()->setRGB(substr($nodeGraphicProps->getAttribute('draw:shadow-color'), -6)); } if ($nodeGraphicProps->hasAttribute('draw:shadow-opacity')) { - $oShadow->setAlpha(100 - (int)substr($nodeGraphicProps->getAttribute('draw:shadow-opacity'), 0, -1)); + $oShadow->setAlpha(100 - (int) substr($nodeGraphicProps->getAttribute('draw:shadow-opacity'), 0, -1)); } if ($nodeGraphicProps->hasAttribute('draw:shadow-offset-x') && $nodeGraphicProps->hasAttribute('draw:shadow-offset-y')) { - $offsetX = substr($nodeGraphicProps->getAttribute('draw:shadow-offset-x'), 0, -2); - $offsetY = substr($nodeGraphicProps->getAttribute('draw:shadow-offset-y'), 0, -2); + $offsetX = (float) substr($nodeGraphicProps->getAttribute('draw:shadow-offset-x'), 0, -2); + $offsetY = (float) substr($nodeGraphicProps->getAttribute('draw:shadow-offset-y'), 0, -2); $distance = 0; - if ($offsetX != 0) { + if (0 != $offsetX) { $distance = ($offsetX < 0 ? $offsetX * -1 : $offsetX); - } elseif ($offsetY != 0) { + } elseif (0 != $offsetY) { $distance = ($offsetY < 0 ? $offsetY * -1 : $offsetY); } - $oShadow->setDirection(rad2deg(atan2($offsetY, $offsetX))); + $oShadow->setDirection((int) rad2deg(atan2($offsetY, $offsetX))); $oShadow->setDistance(CommonDrawing::centimetersToPixels($distance)); } } + // Read Fill + if ($nodeGraphicProps->hasAttribute('draw:fill')) { + $value = $nodeGraphicProps->getAttribute('draw:fill'); + + switch ($value) { + case 'none': + $oFill = new Fill(); + $oFill->setFillType(Fill::FILL_NONE); + break; + case 'solid': + $oFill = new Fill(); + $oFill->setFillType(Fill::FILL_SOLID); + if ($nodeGraphicProps->hasAttribute('draw:fill-color')) { + $oColor = new Color(); + $oColor->setRGB(substr($nodeGraphicProps->getAttribute('draw:fill-color'), 1)); + $oFill->setStartColor($oColor); + } + break; + } + } } - + $nodeTextProperties = $this->oXMLReader->getElement('style:text-properties', $nodeStyle); - if ($nodeTextProperties instanceof \DOMElement) { + if ($nodeTextProperties instanceof DOMElement) { $oFont = new Font(); if ($nodeTextProperties->hasAttribute('fo:color')) { $oFont->getColor()->setRGB(substr($nodeTextProperties->getAttribute('fo:color'), -6)); } + // Font Latin if ($nodeTextProperties->hasAttribute('fo:font-family')) { - $oFont->setName($nodeTextProperties->getAttribute('fo:font-family')); + $oFont + ->setName($nodeTextProperties->getAttribute('fo:font-family')) + ->setFormat(Font::FORMAT_LATIN); } - if ($nodeTextProperties->hasAttribute('fo:font-weight') && $nodeTextProperties->getAttribute('fo:font-weight') == 'bold') { - $oFont->setBold(true); + if ($nodeTextProperties->hasAttribute('fo:font-weight') && 'bold' == $nodeTextProperties->getAttribute('fo:font-weight')) { + $oFont + ->setBold(true) + ->setFormat(Font::FORMAT_LATIN); } if ($nodeTextProperties->hasAttribute('fo:font-size')) { - $oFont->setSize(substr($nodeTextProperties->getAttribute('fo:font-size'), 0, -2)); + $oFont + ->setSize((int) substr($nodeTextProperties->getAttribute('fo:font-size'), 0, -2)) + ->setFormat(Font::FORMAT_LATIN); + } + // Font East Asian + if ($nodeTextProperties->hasAttribute('style:font-family-asian')) { + $oFont + ->setName($nodeTextProperties->getAttribute('style:font-family-asian')) + ->setFormat(Font::FORMAT_EAST_ASIAN); + } + if ($nodeTextProperties->hasAttribute('style:font-weight-asian') && 'bold' == $nodeTextProperties->getAttribute('style:font-weight-asian')) { + $oFont + ->setBold(true) + ->setFormat(Font::FORMAT_EAST_ASIAN); + } + if ($nodeTextProperties->hasAttribute('style:font-size-asian')) { + $oFont + ->setSize((int) substr($nodeTextProperties->getAttribute('style:font-size-asian'), 0, -2)) + ->setFormat(Font::FORMAT_EAST_ASIAN); + } + // Font Complex Script + if ($nodeTextProperties->hasAttribute('style:font-family-complex')) { + $oFont + ->setName($nodeTextProperties->getAttribute('style:font-family-complex')) + ->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + } + if ($nodeTextProperties->hasAttribute('style:font-weight-complex') && 'bold' == $nodeTextProperties->getAttribute('style:font-weight-complex')) { + $oFont + ->setBold(true) + ->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + } + if ($nodeTextProperties->hasAttribute('style:font-size-complex')) { + $oFont + ->setSize((int) substr($nodeTextProperties->getAttribute('style:font-size-complex'), 0, -2)) + ->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + } + if ($nodeTextProperties->hasAttribute('style:script-type')) { + switch ($nodeTextProperties->getAttribute('style:script-type')) { + case 'latin': + $oFont->setFormat(Font::FORMAT_LATIN); + break; + case 'asian': + $oFont->setFormat(Font::FORMAT_EAST_ASIAN); + break; + case 'complex': + $oFont->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + break; + } } } $nodeParagraphProps = $this->oXMLReader->getElement('style:paragraph-properties', $nodeStyle); - if ($nodeParagraphProps instanceof \DOMElement) { + if ($nodeParagraphProps instanceof DOMElement) { + if ($nodeParagraphProps->hasAttribute('fo:line-height')) { + $lineHeightUnit = $this->getExpressionUnit($nodeParagraphProps->getAttribute('fo:margin-bottom')); + $lineSpacingMode = $lineHeightUnit == '%' ? Paragraph::LINE_SPACING_MODE_PERCENT : Paragraph::LINE_SPACING_MODE_POINT; + $lineSpacing = $this->getExpressionValue($nodeParagraphProps->getAttribute('fo:margin-bottom')); + } + if ($nodeParagraphProps->hasAttribute('fo:margin-bottom')) { + $spacingAfter = (float) substr($nodeParagraphProps->getAttribute('fo:margin-bottom'), 0, -2); + $spacingAfter = CommonDrawing::centimetersToPoints($spacingAfter); + } + if ($nodeParagraphProps->hasAttribute('fo:margin-top')) { + $spacingBefore = (float) substr($nodeParagraphProps->getAttribute('fo:margin-top'), 0, -2); + $spacingBefore = CommonDrawing::centimetersToPoints($spacingBefore); + } $oAlignment = new Alignment(); if ($nodeParagraphProps->hasAttribute('fo:text-align')) { $oAlignment->setHorizontal($nodeParagraphProps->getAttribute('fo:text-align')); } + if ($nodeParagraphProps->hasAttribute('style:writing-mode')) { + switch ($nodeParagraphProps->getAttribute('style:writing-mode')) { + case 'lr-tb': + case 'tb-lr': + case 'lr': + $oAlignment->setIsRTL(false); + break; + case 'rl-tb': + case 'tb-rl': + case 'rl': + $oAlignment->setIsRTL(false); + break; + case 'tb': + case 'page': + default: + break; + } + } } - - if ($nodeStyle->nodeName == 'text:list-style') { - $arrayListStyle = array(); + + if ('text:list-style' == $nodeStyle->nodeName) { + $arrayListStyle = []; foreach ($this->oXMLReader->getElements('text:list-level-style-bullet', $nodeStyle) as $oNodeListLevel) { $oAlignment = new Alignment(); $oBullet = new Bullet(); $oBullet->setBulletType(Bullet::TYPE_NONE); - if ($oNodeListLevel->hasAttribute('text:level')) { - $oAlignment->setLevel((int) $oNodeListLevel->getAttribute('text:level') - 1); - } - if ($oNodeListLevel->hasAttribute('text:bullet-char')) { - $oBullet->setBulletChar($oNodeListLevel->getAttribute('text:bullet-char')); - $oBullet->setBulletType(Bullet::TYPE_BULLET); - } - - $oNodeListProperties = $this->oXMLReader->getElement('style:list-level-properties', $oNodeListLevel); - if ($oNodeListProperties instanceof \DOMElement) { - if ($oNodeListProperties->hasAttribute('text:min-label-width')) { - $oAlignment->setIndent((int)round(CommonDrawing::centimetersToPixels(substr($oNodeListProperties->getAttribute('text:min-label-width'), 0, -2)))); + if ($oNodeListLevel instanceof DOMElement) { + if ($oNodeListLevel->hasAttribute('text:level')) { + $oAlignment->setLevel((int) $oNodeListLevel->getAttribute('text:level') - 1); } - if ($oNodeListProperties->hasAttribute('text:space-before')) { - $iSpaceBefore = CommonDrawing::centimetersToPixels(substr($oNodeListProperties->getAttribute('text:space-before'), 0, -2)); - $iMarginLeft = $iSpaceBefore + $oAlignment->getIndent(); - $oAlignment->setMarginLeft($iMarginLeft); + if ($oNodeListLevel->hasAttribute('text:bullet-char')) { + $oBullet->setBulletChar($oNodeListLevel->getAttribute('text:bullet-char')); + $oBullet->setBulletType(Bullet::TYPE_BULLET); } - } - $oNodeTextProperties = $this->oXMLReader->getElement('style:text-properties', $oNodeListLevel); - if ($oNodeTextProperties instanceof \DOMElement) { - if ($oNodeTextProperties->hasAttribute('fo:font-family')) { - $oBullet->setBulletFont($oNodeTextProperties->getAttribute('fo:font-family')); + + $oNodeListProperties = $this->oXMLReader->getElement('style:list-level-properties', $oNodeListLevel); + if ($oNodeListProperties instanceof DOMElement) { + if ($oNodeListProperties->hasAttribute('text:min-label-width')) { + $oAlignment->setIndent(CommonDrawing::centimetersToPixels((float) substr($oNodeListProperties->getAttribute('text:min-label-width'), 0, -2))); + } + if ($oNodeListProperties->hasAttribute('text:space-before')) { + $iSpaceBefore = CommonDrawing::centimetersToPixels((float) substr($oNodeListProperties->getAttribute('text:space-before'), 0, -2)); + $iMarginLeft = $iSpaceBefore + $oAlignment->getIndent(); + $oAlignment->setMarginLeft($iMarginLeft); + } + } + + $oNodeTextProperties = $this->oXMLReader->getElement('style:text-properties', $oNodeListLevel); + if ($oNodeTextProperties instanceof DOMElement) { + if ($oNodeTextProperties->hasAttribute('fo:font-family')) { + $oBullet->setBulletFont($oNodeTextProperties->getAttribute('fo:font-family')); + } } } - - $arrayListStyle[$oAlignment->getLevel()] = array( + + $arrayListStyle[$oAlignment->getLevel()] = [ 'alignment' => $oAlignment, 'bullet' => $oBullet, - ); - } - } - - $this->arrayStyles[$keyStyle] = array( - 'alignment' => isset($oAlignment) ? $oAlignment : null, - 'background' => isset($oBackground) ? $oBackground : null, - 'font' => isset($oFont) ? $oFont : null, - 'shadow' => isset($oShadow) ? $oShadow : null, - 'listStyle' => isset($arrayListStyle) ? $arrayListStyle : null, - ); - + ]; + } + } + + $this->arrayStyles[$keyStyle] = [ + 'alignment' => $oAlignment ?? null, + 'background' => $oBackground ?? null, + 'fill' => $oFill ?? null, + 'font' => $oFont ?? null, + 'shadow' => $oShadow ?? null, + 'listStyle' => $arrayListStyle ?? null, + 'spacingAfter' => $spacingAfter ?? null, + 'spacingBefore' => $spacingBefore ?? null, + 'lineSpacingMode' => $lineSpacingMode ?? null, + 'lineSpacing' => $lineSpacing ?? null, + ]; + return true; } /** * Read Slide - * - * @param \DOMElement $nodeSlide */ - protected function loadSlide(\DOMElement $nodeSlide) + protected function loadSlide(DOMElement $nodeSlide): bool { // Core $this->oPhpPresentation->createSlide(); @@ -344,123 +504,151 @@ protected function loadSlide(\DOMElement $nodeSlide) } } foreach ($this->oXMLReader->getElements('draw:frame', $nodeSlide) as $oNodeFrame) { - if ($this->oXMLReader->getElement('draw:image', $oNodeFrame)) { - $this->loadShapeDrawing($oNodeFrame); - continue; - } - if ($this->oXMLReader->getElement('draw:text-box', $oNodeFrame)) { - $this->loadShapeRichText($oNodeFrame); - continue; + if ($oNodeFrame instanceof DOMElement) { + if ($this->oXMLReader->getElement('draw:image', $oNodeFrame)) { + $this->loadShapeDrawing($oNodeFrame); + continue; + } + if ($this->oXMLReader->getElement('draw:text-box', $oNodeFrame)) { + $this->loadShapeRichText($oNodeFrame); + continue; + } } } + return true; } - + /** * Read Shape Drawing - * - * @param \DOMElement $oNodeFrame */ - protected function loadShapeDrawing(\DOMElement $oNodeFrame) + protected function loadShapeDrawing(DOMElement $oNodeFrame): void { // Core - $oShape = new Gd(); - $oShape->getShadow()->setVisible(false); + $mimetype = ''; $oNodeImage = $this->oXMLReader->getElement('draw:image', $oNodeFrame); - if ($oNodeImage instanceof \DOMElement) { + if ($oNodeImage instanceof DOMElement) { + if ($oNodeImage->hasAttribute('loext:mime-type')) { + $mimetype = $oNodeImage->getAttribute('loext:mime-type'); + } if ($oNodeImage->hasAttribute('xlink:href')) { $sFilename = $oNodeImage->getAttribute('xlink:href'); // svm = StarView Metafile - if (pathinfo($sFilename, PATHINFO_EXTENSION) == 'svm') { + if ('svm' == pathinfo($sFilename, PATHINFO_EXTENSION)) { return; } $imageFile = $this->oZip->getFromName($sFilename); - if (!empty($imageFile)) { - $oShape->setImageResource(imagecreatefromstring($imageFile)); - } } } - - $oShape->setName($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : ''); - $oShape->setDescription($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : ''); - $oShape->setResizeProportional(false); - $oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:width'), 0, -2))) : ''); - $oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:height'), 0, -2))) : ''); - $oShape->setResizeProportional(true); - $oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:x'), 0, -2))) : ''); - $oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:y'), 0, -2))) : ''); - + + if (empty($imageFile)) { + return; + } + + // Contents of file + if (empty($mimetype)) { + $shape = new Gd(); + $shape->setImageResource(imagecreatefromstring($imageFile)); + } else { + $shape = new Base64(); + $shape->setData('data:' . $mimetype . ';base64,' . base64_encode($imageFile)); + } + + $shape->getShadow()->setVisible(false); + $shape->setName($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : ''); + $shape->setDescription($oNodeFrame->hasAttribute('draw:name') ? $oNodeFrame->getAttribute('draw:name') : ''); + $shape->setResizeProportional(false); + $shape->setWidth($oNodeFrame->hasAttribute('svg:width') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:width'), 0, -2)) : 0); + $shape->setHeight($oNodeFrame->hasAttribute('svg:height') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:height'), 0, -2)) : 0); + $shape->setResizeProportional(true); + $shape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:x'), 0, -2)) : 0); + $shape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:y'), 0, -2)) : 0); + if ($oNodeFrame->hasAttribute('draw:style-name')) { $keyStyle = $oNodeFrame->getAttribute('draw:style-name'); if (isset($this->arrayStyles[$keyStyle])) { - $oShape->setShadow($this->arrayStyles[$keyStyle]['shadow']); + $shape->setShadow($this->arrayStyles[$keyStyle]['shadow']); + $shape->setFill($this->arrayStyles[$keyStyle]['fill']); } } - - $this->oPhpPresentation->getActiveSlide()->addShape($oShape); + + $this->oPhpPresentation->getActiveSlide()->addShape($shape); } /** * Read Shape RichText - * - * @param \DOMElement $oNodeFrame */ - protected function loadShapeRichText(\DOMElement $oNodeFrame) + protected function loadShapeRichText(DOMElement $oNodeFrame): void { // Core $oShape = $this->oPhpPresentation->getActiveSlide()->createRichTextShape(); - $oShape->setParagraphs(array()); - - $oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:width'), 0, -2))) : ''); - $oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:height'), 0, -2))) : ''); - $oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:x'), 0, -2))) : ''); - $oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? (int)round(CommonDrawing::centimetersToPixels(substr($oNodeFrame->getAttribute('svg:y'), 0, -2))) : ''); - + $oShape->setParagraphs([]); + + $oShape->setWidth($oNodeFrame->hasAttribute('svg:width') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:width'), 0, -2)) : 0); + $oShape->setHeight($oNodeFrame->hasAttribute('svg:height') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:height'), 0, -2)) : 0); + $oShape->setOffsetX($oNodeFrame->hasAttribute('svg:x') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:x'), 0, -2)) : 0); + $oShape->setOffsetY($oNodeFrame->hasAttribute('svg:y') ? CommonDrawing::centimetersToPixels((float) substr($oNodeFrame->getAttribute('svg:y'), 0, -2)) : 0); + foreach ($this->oXMLReader->getElements('draw:text-box/*', $oNodeFrame) as $oNodeParagraph) { $this->levelParagraph = 0; - if ($oNodeParagraph->nodeName == 'text:p') { - $this->readParagraph($oShape, $oNodeParagraph); - } - if ($oNodeParagraph->nodeName == 'text:list') { - $this->readList($oShape, $oNodeParagraph); + if ($oNodeParagraph instanceof DOMElement) { + if ('text:p' == $oNodeParagraph->nodeName) { + $this->readParagraph($oShape, $oNodeParagraph); + } + if ('text:list' == $oNodeParagraph->nodeName) { + $this->readList($oShape, $oNodeParagraph); + } } } - + if (count($oShape->getParagraphs()) > 0) { $oShape->setActiveParagraph(0); } } - - protected $levelParagraph = 0; - + /** * Read Paragraph - * @param RichText $oShape - * @param \DOMElement $oNodeParent */ - protected function readParagraph(RichText $oShape, \DOMElement $oNodeParent) + protected function readParagraph(RichText $oShape, DOMElement $oNodeParent): void { $oParagraph = $oShape->createParagraph(); + if ($oNodeParent->hasAttribute('text:style-name')) { + $keyStyle = $oNodeParent->getAttribute('text:style-name'); + if (isset($this->arrayStyles[$keyStyle])) { + if (!empty($this->arrayStyles[$keyStyle]['spacingAfter'])) { + $oParagraph->setSpacingAfter($this->arrayStyles[$keyStyle]['spacingAfter']); + } + if (!empty($this->arrayStyles[$keyStyle]['spacingBefore'])) { + $oParagraph->setSpacingBefore($this->arrayStyles[$keyStyle]['spacingBefore']); + } + if (!empty($this->arrayStyles[$keyStyle]['lineSpacingMode'])) { + $oParagraph->setLineSpacingMode($this->arrayStyles[$keyStyle]['lineSpacingMode']); + } + if (!empty($this->arrayStyles[$keyStyle]['lineSpacing'])) { + $oParagraph->setLineSpacing($this->arrayStyles[$keyStyle]['lineSpacing']); + } + } + } $oDomList = $this->oXMLReader->getElements('text:span', $oNodeParent); $oDomTextNodes = $this->oXMLReader->getElements('text()', $oNodeParent); foreach ($oDomTextNodes as $oDomTextNode) { - if (trim($oDomTextNode->nodeValue) != '') { + if ('' != trim($oDomTextNode->nodeValue)) { $oTextRun = $oParagraph->createTextRun(); $oTextRun->setText(trim($oDomTextNode->nodeValue)); } } foreach ($oDomList as $oNodeRichTextElement) { - $this->readParagraphItem($oParagraph, $oNodeRichTextElement); + if ($oNodeRichTextElement instanceof DOMElement) { + $this->readParagraphItem($oParagraph, $oNodeRichTextElement); + } } } - + /** * Read Paragraph Item - * @param Paragraph $oParagraph - * @param \DOMElement $oNodeParent */ - protected function readParagraphItem(Paragraph $oParagraph, \DOMElement $oNodeParent) + protected function readParagraphItem(Paragraph $oParagraph, DOMElement $oNodeParent): void { if ($this->oXMLReader->elementExists('text:line-break', $oNodeParent)) { $oParagraph->createBreak(); @@ -473,7 +661,7 @@ protected function readParagraphItem(Paragraph $oParagraph, \DOMElement $oNodePa } } $oTextRunLink = $this->oXMLReader->getElement('text:a', $oNodeParent); - if ($oTextRunLink instanceof \DOMElement) { + if ($oTextRunLink instanceof DOMElement) { $oTextRun->setText($oTextRunLink->nodeValue); if ($oTextRunLink->hasAttribute('xlink:href')) { $oTextRun->getHyperlink()->setUrl($oTextRunLink->getAttribute('xlink:href')); @@ -486,31 +674,27 @@ protected function readParagraphItem(Paragraph $oParagraph, \DOMElement $oNodePa /** * Read List - * - * @param RichText $oShape - * @param \DOMElement $oNodeParent */ - protected function readList(RichText $oShape, \DOMElement $oNodeParent) + protected function readList(RichText $oShape, DOMElement $oNodeParent): void { foreach ($this->oXMLReader->getElements('text:list-item/*', $oNodeParent) as $oNodeListItem) { - if ($oNodeListItem->nodeName == 'text:p') { - $this->readListItem($oShape, $oNodeListItem, $oNodeParent); - } - if ($oNodeListItem->nodeName == 'text:list') { - $this->levelParagraph++; - $this->readList($oShape, $oNodeListItem); - $this->levelParagraph--; + if ($oNodeListItem instanceof DOMElement) { + if ('text:p' == $oNodeListItem->nodeName) { + $this->readListItem($oShape, $oNodeListItem, $oNodeParent); + } + if ('text:list' == $oNodeListItem->nodeName) { + ++$this->levelParagraph; + $this->readList($oShape, $oNodeListItem); + --$this->levelParagraph; + } } } } - + /** * Read List Item - * @param RichText $oShape - * @param \DOMElement $oNodeParent - * @param \DOMElement $oNodeParagraph */ - protected function readListItem(RichText $oShape, \DOMElement $oNodeParent, \DOMElement $oNodeParagraph) + protected function readListItem(RichText $oShape, DOMElement $oNodeParent, DOMElement $oNodeParagraph): void { $oParagraph = $oShape->createParagraph(); if ($oNodeParagraph->hasAttribute('text:style-name')) { @@ -521,22 +705,52 @@ protected function readListItem(RichText $oShape, \DOMElement $oNodeParent, \DOM } } foreach ($this->oXMLReader->getElements('text:span', $oNodeParent) as $oNodeRichTextElement) { - $this->readParagraphItem($oParagraph, $oNodeRichTextElement); + if ($oNodeRichTextElement instanceof DOMElement) { + $this->readParagraphItem($oParagraph, $oNodeRichTextElement); + } } } /** - * Load file 'styles.xml' + * Load file 'styles.xml'. */ - protected function loadStylesFile() + protected function loadStylesFile(): void { foreach ($this->oXMLReader->getElements('/office:document-styles/office:styles/*') as $oElement) { - if ($oElement->nodeName == 'draw:fill-image') { - $this->arrayCommonStyles[$oElement->getAttribute('draw:name')] = array( + if ($oElement instanceof DOMElement && 'draw:fill-image' == $oElement->nodeName) { + $this->arrayCommonStyles[$oElement->getAttribute('draw:name')] = [ 'type' => 'image', - 'path' => $oElement->hasAttribute('xlink:href') ? $oElement->getAttribute('xlink:href') : null - ); + 'path' => $oElement->hasAttribute('xlink:href') ? $oElement->getAttribute('xlink:href') : null, + ]; } } } + + /** + * @param string $expr + * + * @return string + */ + private function getExpressionUnit(string $expr): string + { + if (substr($expr, -1) == '%') { + return '%'; + } + + return substr($expr, -2); + } + + /** + * @param string $expr + * + * @return string + */ + private function getExpressionValue(string $expr): string + { + if (substr($expr, -1) == '%') { + return substr($expr, 0, -1); + } + + return substr($expr, 0, -2); + } } diff --git a/src/PhpPresentation/Reader/PowerPoint2007.php b/src/PhpPresentation/Reader/PowerPoint2007.php index 0ee8261073..ad0deb9767 100644 --- a/src/PhpPresentation/Reader/PowerPoint2007.php +++ b/src/PhpPresentation/Reader/PowerPoint2007.php @@ -10,75 +10,88 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Reader; +use DateTime; +use DOMElement; +use DOMNode; +use DOMNodeList; +use PhpOffice\Common\Drawing as CommonDrawing; +use PhpOffice\Common\XMLReader; use PhpOffice\PhpPresentation\DocumentLayout; +use PhpOffice\PhpPresentation\DocumentProperties; +use PhpOffice\PhpPresentation\Exception\FeatureNotImplementedException; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\PresentationProperties; +use PhpOffice\PhpPresentation\Shape\Drawing\Base64; +use PhpOffice\PhpPresentation\Shape\Drawing\Gd; use PhpOffice\PhpPresentation\Shape\Placeholder; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Shape\Table\Cell; use PhpOffice\PhpPresentation\Slide; use PhpOffice\PhpPresentation\Slide\AbstractSlide; +use PhpOffice\PhpPresentation\Slide\Note; use PhpOffice\PhpPresentation\Slide\SlideLayout; use PhpOffice\PhpPresentation\Slide\SlideMaster; -use PhpOffice\PhpPresentation\Shape\Drawing\Gd; -use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Borders; +use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Fill; +use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\SchemeColor; use PhpOffice\PhpPresentation\Style\TextStyle; -use PhpOffice\Common\XMLReader; -use PhpOffice\Common\Drawing as CommonDrawing; use ZipArchive; /** - * Serialized format reader + * Serialized format reader. */ class PowerPoint2007 implements ReaderInterface { /** - * Output Object + * Output Object. + * * @var PhpPresentation */ protected $oPhpPresentation; /** - * Output Object + * Output Object. + * * @var \ZipArchive */ protected $oZip; /** * @var array[] */ - protected $arrayRels = array(); + protected $arrayRels = []; /** * @var SlideLayout[] */ - protected $arraySlideLayouts = array(); - /* + protected $arraySlideLayouts = []; + /** * @var string */ protected $filename; - /* + /** * @var string */ protected $fileRels; /** * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file? - * - * @param string $pFilename - * @throws \Exception - * @return boolean */ - public function canRead($pFilename) + public function canRead(string $pFilename): bool { return $this->fileSupportsUnserializePhpPresentation($pFilename); } @@ -86,102 +99,101 @@ public function canRead($pFilename) /** * Does a file support UnserializePhpPresentation ? * - * @param string $pFilename - * @throws \Exception - * @return boolean + * @throws FileNotFoundException */ - public function fileSupportsUnserializePhpPresentation($pFilename = '') + public function fileSupportsUnserializePhpPresentation(string $pFilename = ''): bool { // Check if file exists if (!file_exists($pFilename)) { - throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist."); + throw new FileNotFoundException($pFilename); } $oZip = new ZipArchive(); // Is it a zip ? - if ($oZip->open($pFilename) === true) { + if (true === $oZip->open($pFilename)) { // Is it an OpenXML Document ? // Is it a Presentation ? if (is_array($oZip->statName('[Content_Types].xml')) && is_array($oZip->statName('ppt/presentation.xml'))) { return true; } } + return false; } /** - * Loads PhpPresentation Serialized file + * Loads PhpPresentation Serialized file. * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation - * @throws \Exception + * @throws InvalidFileFormatException */ - public function load($pFilename) + public function load(string $pFilename): PhpPresentation { // Unserialize... First make sure the file supports it! if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) { - throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\PowerPoint2007: " . $pFilename . "."); + throw new InvalidFileFormatException($pFilename, PowerPoint2007::class); } return $this->loadFile($pFilename); } /** - * Load PhpPresentation Serialized file - * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation + * Load PhpPresentation Serialized file. */ - protected function loadFile($pFilename) + protected function loadFile(string $pFilename): PhpPresentation { $this->oPhpPresentation = new PhpPresentation(); $this->oPhpPresentation->removeSlideByIndex(); - $this->oPhpPresentation->setAllMasterSlides(array()); + $this->oPhpPresentation->setAllMasterSlides([]); $this->filename = $pFilename; $this->oZip = new ZipArchive(); $this->oZip->open($this->filename); $docPropsCore = $this->oZip->getFromName('docProps/core.xml'); - if ($docPropsCore !== false) { + if (false !== $docPropsCore) { $this->loadDocumentProperties($docPropsCore); } $docPropsCustom = $this->oZip->getFromName('docProps/custom.xml'); - if ($docPropsCustom !== false) { + if (false !== $docPropsCustom) { $this->loadCustomProperties($docPropsCustom); } $pptViewProps = $this->oZip->getFromName('ppt/viewProps.xml'); - if ($pptViewProps !== false) { + if (false !== $pptViewProps) { $this->loadViewProperties($pptViewProps); } $pptPresentation = $this->oZip->getFromName('ppt/presentation.xml'); - if ($pptPresentation !== false) { + if (false !== $pptPresentation) { $this->loadDocumentLayout($pptPresentation); $this->loadSlides($pptPresentation); } + $pptPresProps = $this->oZip->getFromName('ppt/presProps.xml'); + if (false !== $pptPresProps) { + $this->loadPresentationProperties($pptPresentation); + } + return $this->oPhpPresentation; } /** - * Read Document Layout - * @param $sPart + * Read Document Layout. */ - protected function loadDocumentLayout($sPart) + protected function loadDocumentLayout(string $sPart): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { foreach ($xmlReader->getElements('/p:presentation/p:sldSz') as $oElement) { - if (!($oElement instanceof \DOMElement)) { + if (!($oElement instanceof DOMElement)) { continue; } $type = $oElement->getAttribute('type'); $oLayout = $this->oPhpPresentation->getLayout(); - if ($type == DocumentLayout::LAYOUT_CUSTOM) { - $oLayout->setCX($oElement->getAttribute('cx')); - $oLayout->setCY($oElement->getAttribute('cy')); + if (DocumentLayout::LAYOUT_CUSTOM == $type) { + $oLayout->setCX((float) $oElement->getAttribute('cx')); + $oLayout->setCY((float) $oElement->getAttribute('cy')); } else { $oLayout->setDocumentLayout($type, true); if ($oElement->getAttribute('cx') < $oElement->getAttribute('cy')) { @@ -193,14 +205,14 @@ protected function loadDocumentLayout($sPart) } /** - * Read Document Properties - * @param string $sPart + * Read Document Properties. */ - protected function loadDocumentProperties($sPart) + protected function loadDocumentProperties(string $sPart): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { - $arrayProperties = array( + $arrayProperties = [ '/cp:coreProperties/dc:creator' => 'setCreator', '/cp:coreProperties/cp:lastModifiedBy' => 'setLastModifiedBy', '/cp:coreProperties/dc:title' => 'setTitle', @@ -210,15 +222,14 @@ protected function loadDocumentProperties($sPart) '/cp:coreProperties/cp:category' => 'setCategory', '/cp:coreProperties/dcterms:created' => 'setCreated', '/cp:coreProperties/dcterms:modified' => 'setModified', - ); + ]; $oProperties = $this->oPhpPresentation->getDocumentProperties(); foreach ($arrayProperties as $path => $property) { $oElement = $xmlReader->getElement($path); - if ($oElement instanceof \DOMElement) { - if ($oElement->hasAttribute('xsi:type') && $oElement->getAttribute('xsi:type') == 'dcterms:W3CDTF') { - $oDateTime = new \DateTime(); - $oDateTime->createFromFormat(\DateTime::W3C, $oElement->nodeValue); - $oProperties->{$property}($oDateTime->getTimestamp()); + if ($oElement instanceof DOMElement) { + if ($oElement->hasAttribute('xsi:type') && 'dcterms:W3CDTF' == $oElement->getAttribute('xsi:type')) { + $dateTime = DateTime::createFromFormat(DateTime::W3C, $oElement->nodeValue); + $oProperties->{$property}($dateTime->getTimestamp()); } else { $oProperties->{$property}($oElement->nodeValue); } @@ -228,34 +239,99 @@ protected function loadDocumentProperties($sPart) } /** - * Read Custom Properties - * @param string $sPart + * Read Custom Properties. */ - protected function loadCustomProperties($sPart) + protected function loadCustomProperties(string $sPart): void { $xmlReader = new XMLReader(); $sPart = str_replace(' xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"', '', $sPart); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { - $pathMarkAsFinal = '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="_MarkAsFinal"]/vt:bool'; - if (is_object($oElement = $xmlReader->getElement($pathMarkAsFinal))) { - if ($oElement->nodeValue == 'true') { - $this->oPhpPresentation->getPresentationProperties()->markAsFinal(true); + foreach ($xmlReader->getElements('/Properties/property[@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"]') as $element) { + if (!$element->hasAttribute('name')) { + continue; + } + $propertyName = $element->getAttribute('name'); + if ($propertyName == '_MarkAsFinal') { + $attributeElement = $xmlReader->getElement('vt:bool', $element); + if ($attributeElement && 'true' == $attributeElement->nodeValue) { + $this->oPhpPresentation->getPresentationProperties()->markAsFinal(true); + } + } else { + $attributeTypeInt = $xmlReader->getElement('vt:i4', $element); + $attributeTypeFloat = $xmlReader->getElement('vt:r8', $element); + $attributeTypeBoolean = $xmlReader->getElement('vt:bool', $element); + $attributeTypeDate = $xmlReader->getElement('vt:filetime', $element); + $attributeTypeString = $xmlReader->getElement('vt:lpwstr', $element); + + if ($attributeTypeInt) { + $propertyType = DocumentProperties::PROPERTY_TYPE_INTEGER; + $propertyValue = (int) $attributeTypeInt->nodeValue; + } elseif ($attributeTypeFloat) { + $propertyType = DocumentProperties::PROPERTY_TYPE_FLOAT; + $propertyValue = (float) $attributeTypeFloat->nodeValue; + } elseif ($attributeTypeBoolean) { + $propertyType = DocumentProperties::PROPERTY_TYPE_BOOLEAN; + $propertyValue = $attributeTypeBoolean->nodeValue == 'true' ? true : false; + } elseif ($attributeTypeDate) { + $propertyType = DocumentProperties::PROPERTY_TYPE_DATE; + $propertyValue = strtotime($attributeTypeDate->nodeValue); + } else { + $propertyType = DocumentProperties::PROPERTY_TYPE_STRING; + $propertyValue = $attributeTypeString->nodeValue; + } + + $this->oPhpPresentation->getDocumentProperties()->setCustomProperty($propertyName, $propertyValue, $propertyType); } } } } /** - * Read View Properties - * @param string $sPart + * Read Presentation Properties */ - protected function loadViewProperties($sPart) + protected function loadPresentationProperties(string $sPart): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ + if ($xmlReader->getDomFromString($sPart)) { + $element = $xmlReader->getElement('/p:presentationPr/p:showPr'); + if ($element instanceof DOMElement) { + if ($element->hasAttribute('loop')) { + $this->oPhpPresentation->getPresentationProperties()->setLoopContinuouslyUntilEsc( + (bool) $element->getAttribute('loop') + ); + } + if (null !== $xmlReader->getElement('p:present', $element)) { + $this->oPhpPresentation->getPresentationProperties()->setSlideshowType( + PresentationProperties::SLIDESHOW_TYPE_PRESENT + ); + } + if (null !== $xmlReader->getElement('p:browse', $element)) { + $this->oPhpPresentation->getPresentationProperties()->setSlideshowType( + PresentationProperties::SLIDESHOW_TYPE_BROWSE + ); + } + if (null !== $xmlReader->getElement('p:kiosk', $element)) { + $this->oPhpPresentation->getPresentationProperties()->setSlideshowType( + PresentationProperties::SLIDESHOW_TYPE_KIOSK + ); + } + } + } + } + + /** + * Read View Properties. + */ + protected function loadViewProperties(string $sPart): void + { + $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { $pathZoom = '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sx'; $oElement = $xmlReader->getElement($pathZoom); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('d') && $oElement->hasAttribute('n')) { $this->oPhpPresentation->getPresentationProperties()->setZoom($oElement->getAttribute('n') / $oElement->getAttribute('d')); } @@ -266,9 +342,10 @@ protected function loadViewProperties($sPart) /** * Extract all slides */ - protected function loadSlides($sPart) + protected function loadSlides(string $sPart): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { $fileRels = 'ppt/_rels/presentation.xml.rels'; $this->loadRels($fileRels); @@ -276,19 +353,19 @@ protected function loadSlides($sPart) $this->loadMasterSlides($xmlReader, $fileRels); // Continue with loading the slides foreach ($xmlReader->getElements('/p:presentation/p:sldIdLst/p:sldId') as $oElement) { - if (!($oElement instanceof \DOMElement)) { + if (!($oElement instanceof DOMElement)) { continue; } $rId = $oElement->getAttribute('r:id'); $pathSlide = isset($this->arrayRels[$fileRels][$rId]) ? $this->arrayRels[$fileRels][$rId]['Target'] : ''; if (!empty($pathSlide)) { $pptSlide = $this->oZip->getFromName('ppt/' . $pathSlide); - if ($pptSlide !== false) { + if (false !== $pptSlide) { $slideRels = 'ppt/slides/_rels/' . basename($pathSlide) . '.rels'; $this->loadRels($slideRels); $this->loadSlide($pptSlide, basename($pathSlide)); foreach ($this->arrayRels[$slideRels] as $rel) { - if ($rel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide') { + if ('http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide' == $rel['Type']) { $this->loadSlideNote(basename($rel['Target']), $this->oPhpPresentation->getActiveSlide()); } } @@ -300,14 +377,12 @@ protected function loadSlides($sPart) /** * Extract all MasterSlides - * @param XMLReader $xmlReader - * @param string $fileRels */ - protected function loadMasterSlides(XMLReader $xmlReader, $fileRels) + protected function loadMasterSlides(XMLReader $xmlReader, string $fileRels): void { // Get all the MasterSlide Id's from the presentation.xml file foreach ($xmlReader->getElements('/p:presentation/p:sldMasterIdLst/p:sldMasterId') as $oElement) { - if (!($oElement instanceof \DOMElement)) { + if (!($oElement instanceof DOMElement)) { continue; } $rId = $oElement->getAttribute('r:id'); @@ -316,7 +391,7 @@ protected function loadMasterSlides(XMLReader $xmlReader, $fileRels) $this->arrayRels[$fileRels][$rId]['Target'] : ''; if (!empty($pathMasterSlide)) { $pptMasterSlide = $this->oZip->getFromName('ppt/' . $pathMasterSlide); - if ($pptMasterSlide !== false) { + if (false !== $pptMasterSlide) { $this->loadRels('ppt/slideMasters/_rels/' . basename($pathMasterSlide) . '.rels'); $this->loadMasterSlide($pptMasterSlide, basename($pathMasterSlide)); } @@ -326,12 +401,11 @@ protected function loadMasterSlides(XMLReader $xmlReader, $fileRels) /** * Extract data from slide - * @param string $sPart - * @param string $baseFile */ - protected function loadSlide($sPart, $baseFile) + protected function loadSlide(string $sPart, string $baseFile): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { // Core $oSlide = $this->oPhpPresentation->createSlide(); @@ -340,9 +414,9 @@ protected function loadSlide($sPart, $baseFile) // Background $oElement = $xmlReader->getElement('/p:sld/p:cSld/p:bg/p:bgPr'); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement); - if ($oElementColor instanceof \DOMElement) { + if ($oElementColor instanceof DOMElement) { // Color $oColor = new Color(); $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null); @@ -353,15 +427,27 @@ protected function loadSlide($sPart, $baseFile) $oSlide = $this->oPhpPresentation->getActiveSlide(); $oSlide->setBackground($oBackground); } + $oElementColor = $xmlReader->getElement('a:solidFill/a:schemeClr', $oElement); + if ($oElementColor instanceof DOMElement) { + // Color + $oColor = new SchemeColor(); + $oColor->setValue($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null); + // Background + $oBackground = new Slide\Background\SchemeColor(); + $oBackground->setSchemeColor($oColor); + // Slide Background + $oSlide = $this->oPhpPresentation->getActiveSlide(); + $oSlide->setBackground($oBackground); + } $oElementImage = $xmlReader->getElement('a:blipFill/a:blip', $oElement); - if ($oElementImage instanceof \DOMElement) { + if ($oElementImage instanceof DOMElement) { $relImg = $this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'][$oElementImage->getAttribute('r:embed')]; if (is_array($relImg)) { // File $pathImage = 'ppt/slides/' . $relImg['Target']; $pathImage = explode('/', $pathImage); foreach ($pathImage as $key => $partPath) { - if ($partPath == '..') { + if ('..' == $partPath) { unset($pathImage[$key - 1]); unset($pathImage[$key]); } @@ -383,14 +469,12 @@ protected function loadSlide($sPart, $baseFile) // Shapes $arrayElements = $xmlReader->getElements('/p:sld/p:cSld/p:spTree/*'); - if ($arrayElements) { - $this->loadSlideShapes($oSlide, $arrayElements, $xmlReader); - } + $this->loadSlideShapes($oSlide, $arrayElements, $xmlReader); // Layout $oSlide = $this->oPhpPresentation->getActiveSlide(); foreach ($this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'] as $valueRel) { - if ($valueRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout') { + if ('http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout' == $valueRel['Type']) { $layoutBasename = basename($valueRel['Target']); if (array_key_exists($layoutBasename, $this->arraySlideLayouts)) { $oSlide->setSlideLayout($this->arraySlideLayouts[$layoutBasename]); @@ -401,13 +485,10 @@ protected function loadSlide($sPart, $baseFile) } } - /** - * @param string $sPart - * @param string $baseFile - */ - protected function loadMasterSlide($sPart, $baseFile) + protected function loadMasterSlide(string $sPart, string $baseFile): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { // Core $oSlideMaster = $this->oPhpPresentation->createMasterSlide(); @@ -416,19 +497,18 @@ protected function loadMasterSlide($sPart, $baseFile) // Background $oElement = $xmlReader->getElement('/p:sldMaster/p:cSld/p:bg'); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { $this->loadSlideBackground($xmlReader, $oElement, $oSlideMaster); } // Shapes $arrayElements = $xmlReader->getElements('/p:sldMaster/p:cSld/p:spTree/*'); - if ($arrayElements) { - $this->loadSlideShapes($oSlideMaster, $arrayElements, $xmlReader); - } + $this->loadSlideShapes($oSlideMaster, $arrayElements, $xmlReader); + // Header & Footer // ColorMapping - $colorMap = array(); + $colorMap = []; $oElement = $xmlReader->getElement('/p:sldMaster/p:clrMap'); if ($oElement->hasAttributes()) { foreach ($oElement->attributes as $attr) { @@ -439,81 +519,80 @@ protected function loadMasterSlide($sPart, $baseFile) // TextStyles $arrayElementTxStyles = $xmlReader->getElements('/p:sldMaster/p:txStyles/*'); - if ($arrayElementTxStyles) { - foreach ($arrayElementTxStyles as $oElementTxStyle) { - $arrayElementsLvl = $xmlReader->getElements('/p:sldMaster/p:txStyles/' . $oElementTxStyle->nodeName . '/*'); - foreach ($arrayElementsLvl as $oElementLvl) { - if (!($oElementLvl instanceof \DOMElement) || $oElementLvl->nodeName == 'a:extLst') { - continue; - } - $oRTParagraph = new Paragraph(); + foreach ($arrayElementTxStyles as $oElementTxStyle) { + $arrayElementsLvl = $xmlReader->getElements('/p:sldMaster/p:txStyles/' . $oElementTxStyle->nodeName . '/*'); + foreach ($arrayElementsLvl as $oElementLvl) { + if (!($oElementLvl instanceof DOMElement) || 'a:extLst' == $oElementLvl->nodeName) { + continue; + } + $oRTParagraph = new Paragraph(); - if ($oElementLvl->nodeName == 'a:defPPr') { - $level = 0; - } else { - $level = str_replace('a:lvl', '', $oElementLvl->nodeName); - $level = str_replace('pPr', '', $level); - } + if ('a:defPPr' == $oElementLvl->nodeName) { + $level = 0; + } else { + $level = str_replace('a:lvl', '', $oElementLvl->nodeName); + $level = str_replace('pPr', '', $level); + $level = intval($level); + } - if ($oElementLvl->hasAttribute('algn')) { - $oRTParagraph->getAlignment()->setHorizontal($oElementLvl->getAttribute('algn')); - } - if ($oElementLvl->hasAttribute('marL')) { - $val = $oElementLvl->getAttribute('marL'); - $val = CommonDrawing::emuToPixels($val); - $oRTParagraph->getAlignment()->setMarginLeft($val); - } - if ($oElementLvl->hasAttribute('marR')) { - $val = $oElementLvl->getAttribute('marR'); - $val = CommonDrawing::emuToPixels($val); - $oRTParagraph->getAlignment()->setMarginRight($val); + if ($oElementLvl->hasAttribute('algn')) { + $oRTParagraph->getAlignment()->setHorizontal($oElementLvl->getAttribute('algn')); + } + if ($oElementLvl->hasAttribute('marL')) { + $val = (int) $oElementLvl->getAttribute('marL'); + $val = CommonDrawing::emuToPixels((int) $val); + $oRTParagraph->getAlignment()->setMarginLeft($val); + } + if ($oElementLvl->hasAttribute('marR')) { + $val = (int) $oElementLvl->getAttribute('marR'); + $val = CommonDrawing::emuToPixels((int) $val); + $oRTParagraph->getAlignment()->setMarginRight($val); + } + if ($oElementLvl->hasAttribute('indent')) { + $val = (int) $oElementLvl->getAttribute('indent'); + $val = CommonDrawing::emuToPixels((int) $val); + $oRTParagraph->getAlignment()->setIndent($val); + } + $oElementLvlDefRPR = $xmlReader->getElement('a:defRPr', $oElementLvl); + if ($oElementLvlDefRPR instanceof DOMElement) { + if ($oElementLvlDefRPR->hasAttribute('sz')) { + $oRTParagraph->getFont()->setSize($oElementLvlDefRPR->getAttribute('sz') / 100); } - if ($oElementLvl->hasAttribute('indent')) { - $val = $oElementLvl->getAttribute('indent'); - $val = CommonDrawing::emuToPixels($val); - $oRTParagraph->getAlignment()->setIndent($val); + if ($oElementLvlDefRPR->hasAttribute('b') && 1 == $oElementLvlDefRPR->getAttribute('b')) { + $oRTParagraph->getFont()->setBold(true); } - $oElementLvlDefRPR = $xmlReader->getElement('a:defRPr', $oElementLvl); - if ($oElementLvlDefRPR instanceof \DOMElement) { - if ($oElementLvlDefRPR->hasAttribute('sz')) { - $oRTParagraph->getFont()->setSize($oElementLvlDefRPR->getAttribute('sz') / 100); - } - if ($oElementLvlDefRPR->hasAttribute('b') && $oElementLvlDefRPR->getAttribute('b') == 1) { - $oRTParagraph->getFont()->setBold(true); - } - if ($oElementLvlDefRPR->hasAttribute('i') && $oElementLvlDefRPR->getAttribute('i') == 1) { - $oRTParagraph->getFont()->setItalic(true); - } + if ($oElementLvlDefRPR->hasAttribute('i') && 1 == $oElementLvlDefRPR->getAttribute('i')) { + $oRTParagraph->getFont()->setItalic(true); } - $oElementSchemeColor = $xmlReader->getElement('a:defRPr/a:solidFill/a:schemeClr', $oElementLvl); - if ($oElementSchemeColor instanceof \DOMElement) { - if ($oElementSchemeColor->hasAttribute('val')) { - $oSchemeColor = new SchemeColor(); - $oSchemeColor->setValue($oElementSchemeColor->getAttribute('val')); - $oRTParagraph->getFont()->setColor($oSchemeColor); - } + } + $oElementSchemeColor = $xmlReader->getElement('a:defRPr/a:solidFill/a:schemeClr', $oElementLvl); + if ($oElementSchemeColor instanceof DOMElement) { + if ($oElementSchemeColor->hasAttribute('val')) { + $oSchemeColor = new SchemeColor(); + $oSchemeColor->setValue($oElementSchemeColor->getAttribute('val')); + $oRTParagraph->getFont()->setColor($oSchemeColor); } + } - switch ($oElementTxStyle->nodeName) { - case 'p:bodyStyle': - $oSlideMaster->getTextStyles()->setBodyStyleAtLvl($oRTParagraph, $level); - break; - case 'p:otherStyle': - $oSlideMaster->getTextStyles()->setOtherStyleAtLvl($oRTParagraph, $level); - break; - case 'p:titleStyle': - $oSlideMaster->getTextStyles()->setTitleStyleAtLvl($oRTParagraph, $level); - break; - } + switch ($oElementTxStyle->nodeName) { + case 'p:bodyStyle': + $oSlideMaster->getTextStyles()->setBodyStyleAtLvl($oRTParagraph, $level); + break; + case 'p:otherStyle': + $oSlideMaster->getTextStyles()->setOtherStyleAtLvl($oRTParagraph, $level); + break; + case 'p:titleStyle': + $oSlideMaster->getTextStyles()->setTitleStyleAtLvl($oRTParagraph, $level); + break; } } } // Load the theme foreach ($this->arrayRels[$oSlideMaster->getRelsIndex()] as $arrayRel) { - if ($arrayRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme') { + if ('http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' == $arrayRel['Type']) { $pptTheme = $this->oZip->getFromName('ppt/' . substr($arrayRel['Target'], strrpos($arrayRel['Target'], '../') + 3)); - if ($pptTheme !== false) { + if (false !== $pptTheme) { $this->loadTheme($pptTheme, $oSlideMaster); } break; @@ -522,7 +601,7 @@ protected function loadMasterSlide($sPart, $baseFile) // Load the Layoutslide foreach ($xmlReader->getElements('/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId') as $oElement) { - if (!($oElement instanceof \DOMElement)) { + if (!($oElement instanceof DOMElement)) { continue; } $rId = $oElement->getAttribute('r:id'); @@ -531,7 +610,7 @@ protected function loadMasterSlide($sPart, $baseFile) $this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]['Target'] : ''; if (!empty($pathLayoutSlide)) { $pptLayoutSlide = $this->oZip->getFromName('ppt/' . substr($pathLayoutSlide, strrpos($pathLayoutSlide, '../') + 3)); - if ($pptLayoutSlide !== false) { + if (false !== $pptLayoutSlide) { $this->loadRels('ppt/slideLayouts/_rels/' . basename($pathLayoutSlide) . '.rels'); $oSlideMaster->addSlideLayout( $this->loadLayoutSlide($pptLayoutSlide, basename($pathLayoutSlide), $oSlideMaster) @@ -542,15 +621,10 @@ protected function loadMasterSlide($sPart, $baseFile) } } - /** - * @param string $sPart - * @param string $baseFile - * @param SlideMaster $oSlideMaster - * @return SlideLayout|null - */ - protected function loadLayoutSlide($sPart, $baseFile, SlideMaster $oSlideMaster) + protected function loadLayoutSlide(string $sPart, string $baseFile, SlideMaster $oSlideMaster): ?SlideLayout { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { // Core $oSlideLayout = new SlideLayout($oSlideMaster); @@ -558,20 +632,20 @@ protected function loadLayoutSlide($sPart, $baseFile, SlideMaster $oSlideMaster) // Name $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld'); - if ($oElement instanceof \DOMElement && $oElement->hasAttribute('name')) { + if ($oElement instanceof DOMElement && $oElement->hasAttribute('name')) { $oSlideLayout->setLayoutName($oElement->getAttribute('name')); } // Background $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld/p:bg'); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { $this->loadSlideBackground($xmlReader, $oElement, $oSlideLayout); } // ColorMapping $oElement = $xmlReader->getElement('/p:sldLayout/p:clrMapOvr/a:overrideClrMapping'); - if ($oElement instanceof \DOMElement && $oElement->hasAttributes()) { - $colorMap = array(); + if ($oElement instanceof DOMElement && $oElement->hasAttributes()) { + $colorMap = []; foreach ($oElement->attributes as $attr) { $colorMap[$attr->nodeName] = $attr->nodeValue; } @@ -580,30 +654,27 @@ protected function loadLayoutSlide($sPart, $baseFile, SlideMaster $oSlideMaster) // Shapes $oElements = $xmlReader->getElements('/p:sldLayout/p:cSld/p:spTree/*'); - if ($oElements) { - $this->loadSlideShapes($oSlideLayout, $oElements, $xmlReader); - } + $this->loadSlideShapes($oSlideLayout, $oElements, $xmlReader); $this->arraySlideLayouts[$baseFile] = &$oSlideLayout; + return $oSlideLayout; } + /* @phpstan-ignore-next-line */ return null; } - /** - * @param string $sPart - * @param SlideMaster $oSlideMaster - */ - protected function loadTheme($sPart, SlideMaster $oSlideMaster) + protected function loadTheme(string $sPart, SlideMaster $oSlideMaster): void { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { $oElements = $xmlReader->getElements('/a:theme/a:themeElements/a:clrScheme/*'); - if ($oElements) { - foreach ($oElements as $oElement) { + foreach ($oElements as $oElement) { + if ($oElement instanceof DOMElement) { $oSchemeColor = new SchemeColor(); $oSchemeColor->setValue(str_replace('a:', '', $oElement->tagName)); $colorElement = $xmlReader->getElement('*', $oElement); - if ($colorElement instanceof \DOMElement) { + if ($colorElement instanceof DOMElement) { if ($colorElement->hasAttribute('lastClr')) { $oSchemeColor->setRGB($colorElement->getAttribute('lastClr')); } elseif ($colorElement->hasAttribute('val')) { @@ -616,16 +687,11 @@ protected function loadTheme($sPart, SlideMaster $oSlideMaster) } } - /** - * @param XMLReader $xmlReader - * @param \DOMElement $oElement - * @param AbstractSlide $oSlide - */ - protected function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oElement, AbstractSlide $oSlide) + protected function loadSlideBackground(XMLReader $xmlReader, DOMElement $oElement, AbstractSlide $oSlide): void { // Background color $oElementColor = $xmlReader->getElement('p:bgPr/a:solidFill/a:srgbClr', $oElement); - if ($oElementColor instanceof \DOMElement) { + if ($oElementColor instanceof DOMElement) { // Color $oColor = new Color(); $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null); @@ -638,7 +704,7 @@ protected function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oEleme // Background scheme color $oElementSchemeColor = $xmlReader->getElement('p:bgRef/a:schemeClr', $oElement); - if ($oElementSchemeColor instanceof \DOMElement) { + if ($oElementSchemeColor instanceof DOMElement) { // Color $oColor = new SchemeColor(); $oColor->setValue($oElementSchemeColor->hasAttribute('val') ? $oElementSchemeColor->getAttribute('val') : null); @@ -651,14 +717,14 @@ protected function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oEleme // Background image $oElementImage = $xmlReader->getElement('p:bgPr/a:blipFill/a:blip', $oElement); - if ($oElementImage instanceof \DOMElement) { + if ($oElementImage instanceof DOMElement) { $relImg = $this->arrayRels[$oSlide->getRelsIndex()][$oElementImage->getAttribute('r:embed')]; if (is_array($relImg)) { // File $pathImage = 'ppt/slides/' . $relImg['Target']; $pathImage = explode('/', $pathImage); foreach ($pathImage as $key => $partPath) { - if ($partPath == '..') { + if ('..' == $partPath) { unset($pathImage[$key - 1]); unset($pathImage[$key]); } @@ -677,50 +743,56 @@ protected function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oEleme } } - /** - * @param string $baseFile - * @param Slide $oSlide - */ - protected function loadSlideNote($baseFile, Slide $oSlide) + protected function loadSlideNote(string $baseFile, Slide $oSlide): void { $sPart = $this->oZip->getFromName('ppt/notesSlides/' . $baseFile); $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { $oNote = $oSlide->getNote(); $arrayElements = $xmlReader->getElements('/p:notes/p:cSld/p:spTree/*'); - if ($arrayElements) { - $this->loadSlideShapes($oNote, $arrayElements, $xmlReader); - } + $this->loadSlideShapes($oNote, $arrayElements, $xmlReader); } } - /** - * @param XMLReader $document - * @param \DOMElement $node - * @param AbstractSlide $oSlide - */ - protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide) + protected function loadShapeDrawing(XMLReader $document, DOMElement $node, AbstractSlide $oSlide): void { // Core - $oShape = new Gd(); + $document->registerNamespace('asvg', 'http://schemas.microsoft.com/office/drawing/2016/SVG/main'); + if ($document->getElement('p:blipFill/a:blip/a:extLst/a:ext/asvg:svgBlip', $node)) { + $oShape = new Base64(); + } else { + $oShape = new Gd(); + } $oShape->getShadow()->setVisible(false); // Variables $fileRels = $oSlide->getRelsIndex(); $oElement = $document->getElement('p:nvPicPr/p:cNvPr', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { $oShape->setName($oElement->hasAttribute('name') ? $oElement->getAttribute('name') : ''); $oShape->setDescription($oElement->hasAttribute('descr') ? $oElement->getAttribute('descr') : ''); + + // Hyperlink + $oElementHlinkClick = $document->getElement('a:hlinkClick', $oElement); + if (is_object($oElementHlinkClick)) { + if ($oElementHlinkClick->hasAttribute('tooltip')) { + $oShape->getHyperlink()->setTooltip($oElementHlinkClick->getAttribute('tooltip')); + } + if ($oElementHlinkClick->hasAttribute('r:id') && isset($this->arrayRels[$fileRels][$oElementHlinkClick->getAttribute('r:id')]['Target'])) { + $oShape->getHyperlink()->setUrl($this->arrayRels[$fileRels][$oElementHlinkClick->getAttribute('r:id')]['Target']); + } + } } $oElement = $document->getElement('p:blipFill/a:blip', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('r:embed') && isset($this->arrayRels[$fileRels][$oElement->getAttribute('r:embed')]['Target'])) { $pathImage = 'ppt/slides/' . $this->arrayRels[$fileRels][$oElement->getAttribute('r:embed')]['Target']; $pathImage = explode('/', $pathImage); foreach ($pathImage as $key => $partPath) { - if ($partPath == '..') { + if ('..' == $partPath) { unset($pathImage[$key - 1]); unset($pathImage[$key]); } @@ -728,52 +800,65 @@ protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, Abst $pathImage = implode('/', $pathImage); $imageFile = $this->oZip->getFromName($pathImage); if (!empty($imageFile)) { - $oShape->setImageResource(imagecreatefromstring($imageFile)); + if ($oShape instanceof Gd) { + $info = getimagesizefromstring($imageFile); + $oShape->setMimeType($info['mime']); + $oShape->setRenderingFunction(str_replace('/', '', $info['mime'])); + $oShape->setImageResource(imagecreatefromstring($imageFile)); + } elseif ($oShape instanceof Base64) { + $oShape->setData('data:image/svg+xml;base64,' . base64_encode($imageFile)); + } } } } + $oElement = $document->getElement('p:spPr', $node); + if ($oElement instanceof DOMElement) { + $oFill = $this->loadStyleFill($document, $oElement); + $oShape->setFill($oFill); + } + $oElement = $document->getElement('p:spPr/a:xfrm', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('rot')) { - $oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot'))); + $oShape->setRotation((int) CommonDrawing::angleToDegrees((int) $oElement->getAttribute('rot'))); } } $oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('x')) { - $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x'))); + $oShape->setOffsetX(CommonDrawing::emuToPixels((int) $oElement->getAttribute('x'))); } if ($oElement->hasAttribute('y')) { - $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y'))); + $oShape->setOffsetY(CommonDrawing::emuToPixels((int) $oElement->getAttribute('y'))); } } $oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('cx')) { - $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx'))); + $oShape->setWidth(CommonDrawing::emuToPixels((int) $oElement->getAttribute('cx'))); } if ($oElement->hasAttribute('cy')) { - $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy'))); + $oShape->setHeight(CommonDrawing::emuToPixels((int) $oElement->getAttribute('cy'))); } } $oElement = $document->getElement('p:spPr/a:effectLst', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { $oShape->getShadow()->setVisible(true); $oSubElement = $document->getElement('a:outerShdw', $oElement); - if ($oSubElement instanceof \DOMElement) { + if ($oSubElement instanceof DOMElement) { if ($oSubElement->hasAttribute('blurRad')) { - $oShape->getShadow()->setBlurRadius(CommonDrawing::emuToPixels($oSubElement->getAttribute('blurRad'))); + $oShape->getShadow()->setBlurRadius(CommonDrawing::emuToPixels((int) $oSubElement->getAttribute('blurRad'))); } if ($oSubElement->hasAttribute('dist')) { - $oShape->getShadow()->setDistance(CommonDrawing::emuToPixels($oSubElement->getAttribute('dist'))); + $oShape->getShadow()->setDistance(CommonDrawing::emuToPixels((int) $oSubElement->getAttribute('dist'))); } if ($oSubElement->hasAttribute('dir')) { - $oShape->getShadow()->setDirection(CommonDrawing::angleToDegrees($oSubElement->getAttribute('dir'))); + $oShape->getShadow()->setDirection((int) CommonDrawing::angleToDegrees((int) $oSubElement->getAttribute('dir'))); } if ($oSubElement->hasAttribute('algn')) { $oShape->getShadow()->setAlignment($oSubElement->getAttribute('algn')); @@ -781,7 +866,7 @@ protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, Abst } $oSubElement = $document->getElement('a:outerShdw/a:srgbClr', $oElement); - if ($oSubElement instanceof \DOMElement) { + if ($oSubElement instanceof DOMElement) { if ($oSubElement->hasAttribute('val')) { $oColor = new Color(); $oColor->setRGB($oSubElement->getAttribute('val')); @@ -790,9 +875,9 @@ protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, Abst } $oSubElement = $document->getElement('a:outerShdw/a:srgbClr/a:alpha', $oElement); - if ($oSubElement instanceof \DOMElement) { + if ($oSubElement instanceof DOMElement) { if ($oSubElement->hasAttribute('val')) { - $oShape->getShadow()->setAlpha((int)$oSubElement->getAttribute('val') / 1000); + $oShape->getShadow()->setAlpha((int) $oSubElement->getAttribute('val') / 1000); } } } @@ -800,52 +885,46 @@ protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, Abst $oSlide->addShape($oShape); } - /** - * @param XMLReader $document - * @param \DOMElement $node - * @param AbstractSlide $oSlide - * @throws \Exception - */ - protected function loadShapeRichText(XMLReader $document, \DOMElement $node, $oSlide) + protected function loadShapeRichText(XMLReader $document, DOMElement $node, AbstractSlide $oSlide): void { if (!$document->elementExists('p:txBody/a:p/a:r', $node)) { return; } // Core $oShape = $oSlide->createRichTextShape(); - $oShape->setParagraphs(array()); + $oShape->setParagraphs([]); // Variables if ($oSlide instanceof AbstractSlide) { $this->fileRels = $oSlide->getRelsIndex(); } $oElement = $document->getElement('p:spPr/a:xfrm', $node); - if ($oElement instanceof \DOMElement && $oElement->hasAttribute('rot')) { - $oShape->setRotation(CommonDrawing::angleToDegrees($oElement->getAttribute('rot'))); + if ($oElement instanceof DOMElement && $oElement->hasAttribute('rot')) { + $oShape->setRotation((int) CommonDrawing::angleToDegrees((int) $oElement->getAttribute('rot'))); } $oElement = $document->getElement('p:spPr/a:xfrm/a:off', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('x')) { - $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x'))); + $oShape->setOffsetX(CommonDrawing::emuToPixels((int) $oElement->getAttribute('x'))); } if ($oElement->hasAttribute('y')) { - $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y'))); + $oShape->setOffsetY(CommonDrawing::emuToPixels((int) $oElement->getAttribute('y'))); } } $oElement = $document->getElement('p:spPr/a:xfrm/a:ext', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('cx')) { - $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx'))); + $oShape->setWidth(CommonDrawing::emuToPixels((int) $oElement->getAttribute('cx'))); } if ($oElement->hasAttribute('cy')) { - $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy'))); + $oShape->setHeight(CommonDrawing::emuToPixels((int) $oElement->getAttribute('cy'))); } } $oElement = $document->getElement('p:nvSpPr/p:nvPr/p:ph', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('type')) { $placeholder = new Placeholder($oElement->getAttribute('type')); $oShape->setPlaceHolder($placeholder); @@ -854,7 +933,9 @@ protected function loadShapeRichText(XMLReader $document, \DOMElement $node, $oS $arrayElements = $document->getElements('p:txBody/a:p', $node); foreach ($arrayElements as $oElement) { - $this->loadParagraph($document, $oElement, $oShape); + if ($oElement instanceof DOMElement) { + $this->loadParagraph($document, $oElement, $oShape); + } } if (count($oShape->getParagraphs()) > 0) { @@ -862,20 +943,14 @@ protected function loadShapeRichText(XMLReader $document, \DOMElement $node, $oS } } - /** - * @param XMLReader $document - * @param \DOMElement $node - * @param AbstractSlide $oSlide - * @throws \Exception - */ - protected function loadShapeTable(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide) + protected function loadShapeTable(XMLReader $document, DOMElement $node, AbstractSlide $oSlide): void { $this->fileRels = $oSlide->getRelsIndex(); $oShape = $oSlide->createTableShape(); $oElement = $document->getElement('p:cNvPr', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('name')) { $oShape->setName($oElement->getAttribute('name')); } @@ -885,22 +960,22 @@ protected function loadShapeTable(XMLReader $document, \DOMElement $node, Abstra } $oElement = $document->getElement('p:xfrm/a:off', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('x')) { - $oShape->setOffsetX(CommonDrawing::emuToPixels($oElement->getAttribute('x'))); + $oShape->setOffsetX(CommonDrawing::emuToPixels((int) $oElement->getAttribute('x'))); } if ($oElement->hasAttribute('y')) { - $oShape->setOffsetY(CommonDrawing::emuToPixels($oElement->getAttribute('y'))); + $oShape->setOffsetY(CommonDrawing::emuToPixels((int) $oElement->getAttribute('y'))); } } $oElement = $document->getElement('p:xfrm/a:ext', $node); - if ($oElement instanceof \DOMElement) { + if ($oElement instanceof DOMElement) { if ($oElement->hasAttribute('cx')) { - $oShape->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('cx'))); + $oShape->setWidth(CommonDrawing::emuToPixels((int) $oElement->getAttribute('cx'))); } if ($oElement->hasAttribute('cy')) { - $oShape->setHeight(CommonDrawing::emuToPixels($oElement->getAttribute('cy'))); + $oShape->setHeight(CommonDrawing::emuToPixels((int) $oElement->getAttribute('cy'))); } } @@ -908,43 +983,46 @@ protected function loadShapeTable(XMLReader $document, \DOMElement $node, Abstra $oShape->setNumColumns($arrayElements->length); $oShape->createRow(); foreach ($arrayElements as $key => $oElement) { - if ($oElement instanceof \DOMElement && $oElement->getAttribute('w')) { - $oShape->getRow(0)->getCell($key)->setWidth(CommonDrawing::emuToPixels($oElement->getAttribute('w'))); + if ($oElement instanceof DOMElement && $oElement->getAttribute('w')) { + $oShape->getRow(0)->getCell($key)->setWidth(CommonDrawing::emuToPixels((int) $oElement->getAttribute('w'))); } } $arrayElements = $document->getElements('a:graphic/a:graphicData/a:tbl/a:tr', $node); foreach ($arrayElements as $keyRow => $oElementRow) { - if (!($oElementRow instanceof \DOMElement)) { + if (!($oElementRow instanceof DOMElement)) { continue; } - $oRow = $oShape->getRow($keyRow, true); - if (is_null($oRow)) { + if ($oShape->hasRow($keyRow)) { + $oRow = $oShape->getRow($keyRow); + } else { $oRow = $oShape->createRow(); } if ($oElementRow->hasAttribute('h')) { - $oRow->setHeight(CommonDrawing::emuToPixels($oElementRow->getAttribute('h'))); + $oRow->setHeight(CommonDrawing::emuToPixels((int) $oElementRow->getAttribute('h'))); } $arrayElementsCell = $document->getElements('a:tc', $oElementRow); foreach ($arrayElementsCell as $keyCell => $oElementCell) { - if (!($oElementCell instanceof \DOMElement)) { + if (!($oElementCell instanceof DOMElement)) { continue; } $oCell = $oRow->getCell($keyCell); - $oCell->setParagraphs(array()); + $oCell->setParagraphs([]); if ($oElementCell->hasAttribute('gridSpan')) { - $oCell->setColSpan($oElementCell->getAttribute('gridSpan')); + $oCell->setColSpan((int) $oElementCell->getAttribute('gridSpan')); } if ($oElementCell->hasAttribute('rowSpan')) { - $oCell->setRowSpan($oElementCell->getAttribute('rowSpan')); + $oCell->setRowSpan((int) $oElementCell->getAttribute('rowSpan')); } foreach ($document->getElements('a:txBody/a:p', $oElementCell) as $oElementPara) { - $this->loadParagraph($document, $oElementPara, $oCell); + if ($oElementPara instanceof DOMElement) { + $this->loadParagraph($document, $oElementPara, $oCell); + } } $oElementTcPr = $document->getElement('a:tcPr', $oElementCell); - if ($oElementTcPr instanceof \DOMElement) { + if ($oElementTcPr instanceof DOMElement) { $numParagraphs = count($oCell->getParagraphs()); if ($numParagraphs > 0) { if ($oElementTcPr->hasAttribute('vert')) { @@ -954,16 +1032,16 @@ protected function loadShapeTable(XMLReader $document, \DOMElement $node, Abstra $oCell->getParagraph(0)->getAlignment()->setVertical($oElementTcPr->getAttribute('anchor')); } if ($oElementTcPr->hasAttribute('marB')) { - $oCell->getParagraph(0)->getAlignment()->setMarginBottom($oElementTcPr->getAttribute('marB')); + $oCell->getParagraph(0)->getAlignment()->setMarginBottom((int) $oElementTcPr->getAttribute('marB')); } if ($oElementTcPr->hasAttribute('marL')) { - $oCell->getParagraph(0)->getAlignment()->setMarginLeft($oElementTcPr->getAttribute('marL')); + $oCell->getParagraph(0)->getAlignment()->setMarginLeft((int) $oElementTcPr->getAttribute('marL')); } if ($oElementTcPr->hasAttribute('marR')) { - $oCell->getParagraph(0)->getAlignment()->setMarginRight($oElementTcPr->getAttribute('marR')); + $oCell->getParagraph(0)->getAlignment()->setMarginRight((int) $oElementTcPr->getAttribute('marR')); } if ($oElementTcPr->hasAttribute('marT')) { - $oCell->getParagraph(0)->getAlignment()->setMarginTop($oElementTcPr->getAttribute('marT')); + $oCell->getParagraph(0)->getAlignment()->setMarginTop((int) $oElementTcPr->getAttribute('marT')); } } @@ -974,27 +1052,27 @@ protected function loadShapeTable(XMLReader $document, \DOMElement $node, Abstra $oBorders = new Borders(); $oElementBorderL = $document->getElement('a:lnL', $oElementTcPr); - if ($oElementBorderL instanceof \DOMElement) { + if ($oElementBorderL instanceof DOMElement) { $this->loadStyleBorder($document, $oElementBorderL, $oBorders->getLeft()); } $oElementBorderR = $document->getElement('a:lnR', $oElementTcPr); - if ($oElementBorderR instanceof \DOMElement) { + if ($oElementBorderR instanceof DOMElement) { $this->loadStyleBorder($document, $oElementBorderR, $oBorders->getRight()); } $oElementBorderT = $document->getElement('a:lnT', $oElementTcPr); - if ($oElementBorderT instanceof \DOMElement) { + if ($oElementBorderT instanceof DOMElement) { $this->loadStyleBorder($document, $oElementBorderT, $oBorders->getTop()); } $oElementBorderB = $document->getElement('a:lnB', $oElementTcPr); - if ($oElementBorderB instanceof \DOMElement) { + if ($oElementBorderB instanceof DOMElement) { $this->loadStyleBorder($document, $oElementBorderB, $oBorders->getBottom()); } $oElementBorderDiagDown = $document->getElement('a:lnTlToBr', $oElementTcPr); - if ($oElementBorderDiagDown instanceof \DOMElement) { + if ($oElementBorderDiagDown instanceof DOMElement) { $this->loadStyleBorder($document, $oElementBorderDiagDown, $oBorders->getDiagonalDown()); } $oElementBorderDiagUp = $document->getElement('a:lnBlToTr', $oElementTcPr); - if ($oElementBorderDiagUp instanceof \DOMElement) { + if ($oElementBorderDiagUp instanceof DOMElement) { $this->loadStyleBorder($document, $oElementBorderDiagUp, $oBorders->getDiagonalUp()); } $oCell->setBorders($oBorders); @@ -1004,19 +1082,16 @@ protected function loadShapeTable(XMLReader $document, \DOMElement $node, Abstra } /** - * @param XMLReader $document - * @param \DOMElement $oElement * @param Cell|RichText $oShape - * @throws \Exception */ - protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oShape) + protected function loadParagraph(XMLReader $document, DOMElement $oElement, $oShape): void { // Core $oParagraph = $oShape->createParagraph(); - $oParagraph->setRichTextElements(array()); + $oParagraph->setRichTextElements([]); $oSubElement = $document->getElement('a:pPr', $oElement); - if ($oSubElement instanceof \DOMElement) { + if ($oSubElement instanceof DOMElement) { if ($oSubElement->hasAttribute('algn')) { $oParagraph->getAlignment()->setHorizontal($oSubElement->getAttribute('algn')); } @@ -1024,51 +1099,73 @@ protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oS $oParagraph->getAlignment()->setVertical($oSubElement->getAttribute('fontAlgn')); } if ($oSubElement->hasAttribute('marL')) { - $oParagraph->getAlignment()->setMarginLeft(CommonDrawing::emuToPixels($oSubElement->getAttribute('marL'))); + $oParagraph->getAlignment()->setMarginLeft(CommonDrawing::emuToPixels((int) $oSubElement->getAttribute('marL'))); } if ($oSubElement->hasAttribute('marR')) { - $oParagraph->getAlignment()->setMarginRight(CommonDrawing::emuToPixels($oSubElement->getAttribute('marR'))); + $oParagraph->getAlignment()->setMarginRight(CommonDrawing::emuToPixels((int) $oSubElement->getAttribute('marR'))); } if ($oSubElement->hasAttribute('indent')) { - $oParagraph->getAlignment()->setIndent(CommonDrawing::emuToPixels($oSubElement->getAttribute('indent'))); + $oParagraph->getAlignment()->setIndent(CommonDrawing::emuToPixels((int) $oSubElement->getAttribute('indent'))); } if ($oSubElement->hasAttribute('lvl')) { - $oParagraph->getAlignment()->setLevel($oSubElement->getAttribute('lvl')); + $oParagraph->getAlignment()->setLevel((int) $oSubElement->getAttribute('lvl')); + } + if ($oSubElement->hasAttribute('rtl')) { + $oParagraph->getAlignment()->setIsRTL((bool) $oSubElement->getAttribute('rtl')); + } + + $oElementLineSpacingPoints = $document->getElement('a:lnSpc/a:spcPts', $oSubElement); + if ($oElementLineSpacingPoints instanceof DOMElement) { + $oParagraph->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT); + $oParagraph->setLineSpacing($oElementLineSpacingPoints->getAttribute('val') / 100); + } + $oElementLineSpacingPercent = $document->getElement('a:lnSpc/a:spcPct', $oSubElement); + if ($oElementLineSpacingPercent instanceof DOMElement) { + $oParagraph->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_PERCENT); + $oParagraph->setLineSpacing($oElementLineSpacingPercent->getAttribute('val') / 1000); + } + $oElementSpacingBefore = $document->getElement('a:spcBef/a:spcPts', $oSubElement); + if ($oElementSpacingBefore instanceof DOMElement) { + $oParagraph->setSpacingBefore($oElementSpacingBefore->getAttribute('val') / 100); + } + $oElementSpacingAfter = $document->getElement('a:spcAft/a:spcPts', $oSubElement); + if ($oElementSpacingAfter instanceof DOMElement) { + $oParagraph->setSpacingAfter($oElementSpacingAfter->getAttribute('val') / 100); } $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NONE); $oElementBuFont = $document->getElement('a:buFont', $oSubElement); - if ($oElementBuFont instanceof \DOMElement) { + if ($oElementBuFont instanceof DOMElement) { if ($oElementBuFont->hasAttribute('typeface')) { $oParagraph->getBulletStyle()->setBulletFont($oElementBuFont->getAttribute('typeface')); } } $oElementBuChar = $document->getElement('a:buChar', $oSubElement); - if ($oElementBuChar instanceof \DOMElement) { + if ($oElementBuChar instanceof DOMElement) { $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); if ($oElementBuChar->hasAttribute('char')) { $oParagraph->getBulletStyle()->setBulletChar($oElementBuChar->getAttribute('char')); } } $oElementBuAutoNum = $document->getElement('a:buAutoNum', $oSubElement); - if ($oElementBuAutoNum instanceof \DOMElement) { + if ($oElementBuAutoNum instanceof DOMElement) { $oParagraph->getBulletStyle()->setBulletType(Bullet::TYPE_NUMERIC); if ($oElementBuAutoNum->hasAttribute('type')) { $oParagraph->getBulletStyle()->setBulletNumericStyle($oElementBuAutoNum->getAttribute('type')); } - if ($oElementBuAutoNum->hasAttribute('startAt') && $oElementBuAutoNum->getAttribute('startAt') != 1) { + if ($oElementBuAutoNum->hasAttribute('startAt') && 1 != $oElementBuAutoNum->getAttribute('startAt')) { $oParagraph->getBulletStyle()->setBulletNumericStartAt($oElementBuAutoNum->getAttribute('startAt')); } } $oElementBuClr = $document->getElement('a:buClr', $oSubElement); - if ($oElementBuClr instanceof \DOMElement) { + if ($oElementBuClr instanceof DOMElement) { $oColor = new Color(); /** * @todo Create protected for reading Color */ $oElementColor = $document->getElement('a:srgbClr', $oElementBuClr); - if ($oElementColor instanceof \DOMElement) { + if ($oElementColor instanceof DOMElement) { $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null); } $oParagraph->getBulletStyle()->setBulletColor($oColor); @@ -1076,27 +1173,30 @@ protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oS } $arraySubElements = $document->getElements('(a:r|a:br)', $oElement); foreach ($arraySubElements as $oSubElement) { - if ($oSubElement->tagName == 'a:br') { + if (!($oSubElement instanceof DOMElement)) { + continue; + } + if ('a:br' == $oSubElement->tagName) { $oParagraph->createBreak(); } - if ($oSubElement->tagName == 'a:r') { + if ('a:r' == $oSubElement->tagName) { $oElementrPr = $document->getElement('a:rPr', $oSubElement); if (is_object($oElementrPr)) { $oText = $oParagraph->createTextRun(); if ($oElementrPr->hasAttribute('b')) { $att = $oElementrPr->getAttribute('b'); - $oText->getFont()->setBold($att == 'true' || $att == '1' ? true : false); + $oText->getFont()->setBold('true' == $att || '1' == $att ? true : false); } if ($oElementrPr->hasAttribute('i')) { $att = $oElementrPr->getAttribute('i'); - $oText->getFont()->setItalic($att == 'true' || $att == '1' ? true : false); + $oText->getFont()->setItalic('true' == $att || '1' == $att ? true : false); } if ($oElementrPr->hasAttribute('strike')) { - $oText->getFont()->setStrikethrough($oElementrPr->getAttribute('strike') == 'noStrike' ? false : true); + $oText->getFont()->setStrikethrough('noStrike' == $oElementrPr->getAttribute('strike') ? false : true); } if ($oElementrPr->hasAttribute('sz')) { - $oText->getFont()->setSize((int)($oElementrPr->getAttribute('sz') / 100)); + $oText->getFont()->setSize((int) ($oElementrPr->getAttribute('sz') / 100)); } if ($oElementrPr->hasAttribute('u')) { $oText->getFont()->setUnderline($oElementrPr->getAttribute('u')); @@ -1118,6 +1218,27 @@ protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oS $oText->getHyperlink()->setUrl($this->arrayRels[$this->fileRels][$oElementHlinkClick->getAttribute('r:id')]['Target']); } } + // Font + $oElementFontFormat = null; + $oElementFontFormatLatin = $document->getElement('a:latin', $oElementrPr); + if (is_object($oElementFontFormatLatin)) { + $oText->getFont()->setFormat(Font::FORMAT_LATIN); + $oElementFontFormat = $oElementFontFormatLatin; + } + $oElementFontFormatEastAsian = $document->getElement('a:ea', $oElementrPr); + if (is_object($oElementFontFormatEastAsian)) { + $oText->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $oElementFontFormat = $oElementFontFormatEastAsian; + } + $oElementFontFormatComplexScript = $document->getElement('a:cs', $oElementrPr); + if (is_object($oElementFontFormatComplexScript)) { + $oText->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $oElementFontFormat = $oElementFontFormatComplexScript; + } + if (is_object($oElementFontFormat) && $oElementFontFormat->hasAttribute('typeface')) { + $oText->getFont()->setName($oElementFontFormat->getAttribute('typeface')); + } + //} else { // $oText = $oParagraph->createText(); @@ -1128,12 +1249,7 @@ protected function loadParagraph(XMLReader $document, \DOMElement $oElement, $oS } } - /** - * @param XMLReader $xmlReader - * @param \DOMElement $oElement - * @param Border $oBorder - */ - protected function loadStyleBorder(XMLReader $xmlReader, \DOMElement $oElement, Border $oBorder) + protected function loadStyleBorder(XMLReader $xmlReader, DOMElement $oElement, Border $oBorder): void { if ($oElement->hasAttribute('w')) { $oBorder->setLineWidth($oElement->getAttribute('w') / 12700); @@ -1143,115 +1259,111 @@ protected function loadStyleBorder(XMLReader $xmlReader, \DOMElement $oElement, } $oElementNoFill = $xmlReader->getElement('a:noFill', $oElement); - if ($oElementNoFill instanceof \DOMElement && $oBorder->getLineStyle() == Border::LINE_SINGLE) { + if ($oElementNoFill instanceof DOMElement && Border::LINE_SINGLE == $oBorder->getLineStyle()) { $oBorder->setLineStyle(Border::LINE_NONE); } $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement); - if ($oElementColor instanceof \DOMElement) { + if ($oElementColor instanceof DOMElement) { $oBorder->setColor($this->loadStyleColor($xmlReader, $oElementColor)); } $oElementDashStyle = $xmlReader->getElement('a:prstDash', $oElement); - if ($oElementDashStyle instanceof \DOMElement && $oElementDashStyle->hasAttribute('val')) { + if ($oElementDashStyle instanceof DOMElement && $oElementDashStyle->hasAttribute('val')) { $oBorder->setDashStyle($oElementDashStyle->getAttribute('val')); } } - /** - * @param XMLReader $xmlReader - * @param \DOMElement $oElement - * @return Color - */ - protected function loadStyleColor(XMLReader $xmlReader, \DOMElement $oElement) + protected function loadStyleColor(XMLReader $xmlReader, DOMElement $oElement): Color { $oColor = new Color(); $oColor->setRGB($oElement->getAttribute('val')); $oElementAlpha = $xmlReader->getElement('a:alpha', $oElement); - if ($oElementAlpha instanceof \DOMElement && $oElementAlpha->hasAttribute('val')) { + if ($oElementAlpha instanceof DOMElement && $oElementAlpha->hasAttribute('val')) { $alpha = strtoupper(dechex((($oElementAlpha->getAttribute('val') / 1000) / 100) * 255)); $oColor->setRGB($oElement->getAttribute('val'), $alpha); } + return $oColor; } - /** - * @param XMLReader $xmlReader - * @param \DOMElement $oElement - * @return null|Fill - */ - protected function loadStyleFill(XMLReader $xmlReader, \DOMElement $oElement) + protected function loadStyleFill(XMLReader $xmlReader, DOMElement $oElement): ?Fill { // Gradient fill $oElementFill = $xmlReader->getElement('a:gradFill', $oElement); - if ($oElementFill instanceof \DOMElement) { + if ($oElementFill instanceof DOMElement) { $oFill = new Fill(); $oFill->setFillType(Fill::FILL_GRADIENT_LINEAR); $oElementColor = $xmlReader->getElement('a:gsLst/a:gs[@pos="0"]/a:srgbClr', $oElementFill); - if ($oElementColor instanceof \DOMElement && $oElementColor->hasAttribute('val')) { + if ($oElementColor instanceof DOMElement && $oElementColor->hasAttribute('val')) { $oFill->setStartColor($this->loadStyleColor($xmlReader, $oElementColor)); } $oElementColor = $xmlReader->getElement('a:gsLst/a:gs[@pos="100000"]/a:srgbClr', $oElementFill); - if ($oElementColor instanceof \DOMElement && $oElementColor->hasAttribute('val')) { + if ($oElementColor instanceof DOMElement && $oElementColor->hasAttribute('val')) { $oFill->setEndColor($this->loadStyleColor($xmlReader, $oElementColor)); } $oRotation = $xmlReader->getElement('a:lin', $oElementFill); - if ($oRotation instanceof \DOMElement && $oRotation->hasAttribute('ang')) { - $oFill->setRotation(CommonDrawing::angleToDegrees($oRotation->getAttribute('ang'))); + if ($oRotation instanceof DOMElement && $oRotation->hasAttribute('ang')) { + $oFill->setRotation(CommonDrawing::angleToDegrees((int) $oRotation->getAttribute('ang'))); } + return $oFill; } // Solid fill $oElementFill = $xmlReader->getElement('a:solidFill', $oElement); - if ($oElementFill instanceof \DOMElement) { + if ($oElementFill instanceof DOMElement) { $oFill = new Fill(); $oFill->setFillType(Fill::FILL_SOLID); $oElementColor = $xmlReader->getElement('a:srgbClr', $oElementFill); - if ($oElementColor instanceof \DOMElement) { + if ($oElementColor instanceof DOMElement) { $oFill->setStartColor($this->loadStyleColor($xmlReader, $oElementColor)); } + return $oFill; } + return null; } - /** - * @param string $fileRels - * @return string - */ - protected function loadRels($fileRels) + protected function loadRels(string $fileRels): void { $sPart = $this->oZip->getFromName($fileRels); - if ($sPart !== false) { + if (false !== $sPart) { $xmlReader = new XMLReader(); + /* @phpstan-ignore-next-line */ if ($xmlReader->getDomFromString($sPart)) { foreach ($xmlReader->getElements('*') as $oNode) { - if (!($oNode instanceof \DOMElement)) { + if (!($oNode instanceof DOMElement)) { continue; } - $this->arrayRels[$fileRels][$oNode->getAttribute('Id')] = array( + $this->arrayRels[$fileRels][$oNode->getAttribute('Id')] = [ 'Target' => $oNode->getAttribute('Target'), 'Type' => $oNode->getAttribute('Type'), - ); + ]; } } } } /** - * @param $oSlide - * @param \DOMNodeList $oElements - * @param XMLReader $xmlReader + * @param AbstractSlide|Note $oSlide + * @param DOMNodeList $oElements + * + * @throws FeatureNotImplementedException + * * @internal param $baseFile */ - protected function loadSlideShapes($oSlide, $oElements, $xmlReader) + protected function loadSlideShapes($oSlide, DOMNodeList $oElements, XMLReader $xmlReader): void { foreach ($oElements as $oNode) { + if (!($oNode instanceof DOMElement)) { + continue; + } switch ($oNode->tagName) { case 'p:graphicFrame': $this->loadShapeTable($xmlReader, $oNode, $oSlide); @@ -1263,7 +1375,7 @@ protected function loadSlideShapes($oSlide, $oElements, $xmlReader) $this->loadShapeRichText($xmlReader, $oNode, $oSlide); break; default: - //var_export($oNode->tagName); + //throw new FeatureNotImplementedException(); } } } diff --git a/src/PhpPresentation/Reader/PowerPoint97.php b/src/PhpPresentation/Reader/PowerPoint97.php index 98755ab8db..acd074ca26 100644 --- a/src/PhpPresentation/Reader/PowerPoint97.php +++ b/src/PhpPresentation/Reader/PowerPoint97.php @@ -10,17 +10,24 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Reader; +use Exception; use PhpOffice\Common\Microsoft\OLERead; use PhpOffice\Common\Text; -use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\AbstractShape; +use PhpOffice\PhpPresentation\Exception\FeatureNotImplementedException; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; +use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\Shape\Drawing; use PhpOffice\PhpPresentation\Shape\Group; @@ -28,350 +35,368 @@ use PhpOffice\PhpPresentation\Shape\Line; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Style\Alignment; -use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Bullet; +use PhpOffice\PhpPresentation\Style\Color; +use PhpOffice\PhpPresentation\Style\Font; /** - * Serialized format reader + * Serialized format reader. */ class PowerPoint97 implements ReaderInterface { - const OFFICEARTBLIPEMF = 0xF01A; - const OFFICEARTBLIPWMF = 0xF01B; - const OFFICEARTBLIPPICT = 0xF01C; - const OFFICEARTBLIPJPG = 0xF01D; - const OFFICEARTBLIPPNG = 0xF01E; - const OFFICEARTBLIPDIB = 0xF01F; - const OFFICEARTBLIPTIFF = 0xF029; - const OFFICEARTBLIPJPEG = 0xF02A; - - /** - * @link http://msdn.microsoft.com/en-us/library/dd945336(v=office.12).aspx - */ - const RT_ANIMATIONINFO = 0x1014; - const RT_ANIMATIONINFOATOM = 0x0FF1; - const RT_BINARYTAGDATABLOB = 0x138B; - const RT_BLIPCOLLECTION9 = 0x07F8; - const RT_BLIPENTITY9ATOM = 0x07F9; - const RT_BOOKMARKCOLLECTION = 0x07E3; - const RT_BOOKMARKENTITYATOM = 0x0FD0; - const RT_BOOKMARKSEEDATOM = 0x07E9; - const RT_BROADCASTDOCINFO9 = 0x177E; - const RT_BROADCASTDOCINFO9ATOM = 0x177F; - const RT_BUILDATOM = 0x2B03; - const RT_BUILDLIST = 0x2B02; - const RT_CHARTBUILD = 0x2B04; - const RT_CHARTBUILDATOM = 0x2B05; - const RT_COLORSCHEMEATOM = 0x07F0; - const RT_COMMENT10 = 0x2EE0; - const RT_COMMENT10ATOM = 0x2EE1; - const RT_COMMENTINDEX10 = 0x2EE4; - const RT_COMMENTINDEX10ATOM = 0x2EE5; - const RT_CRYPTSESSION10CONTAINER = 0x2F14; - const RT_CURRENTUSERATOM = 0x0FF6; - const RT_CSTRING = 0x0FBA; - const RT_DATETIMEMETACHARATOM = 0x0FF7; - const RT_DEFAULTRULERATOM = 0x0FAB; - const RT_DOCROUTINGSLIPATOM = 0x0406; - const RT_DIAGRAMBUILD = 0x2B06; - const RT_DIAGRAMBUILDATOM = 0x2B07; - const RT_DIFF10 = 0x2EED; - const RT_DIFF10ATOM = 0x2EEE; - const RT_DIFFTREE10 = 0x2EEC; - const RT_DOCTOOLBARSTATES10ATOM = 0x36B1; - const RT_DOCUMENT = 0x03E8; - const RT_DOCUMENTATOM = 0x03E9; - const RT_DRAWING = 0x040C; - const RT_DRAWINGGROUP = 0x040B; - const RT_ENDDOCUMENTATOM = 0x03EA; - const RT_EXTERNALAVIMOVIE = 0x1006; - const RT_EXTERNALCDAUDIO = 0x100E; - const RT_EXTERNALCDAUDIOATOM = 0x1012; - const RT_EXTERNALHYPERLINK = 0x0FD7; - const RT_EXTERNALHYPERLINK9 = 0x0FE4; - const RT_EXTERNALHYPERLINKATOM = 0x0FD3; - const RT_EXTERNALHYPERLINKFLAGSATOM = 0x1018; - const RT_EXTERNALMCIMOVIE = 0x1007; - const RT_EXTERNALMEDIAATOM = 0x1004; - const RT_EXTERNALMIDIAUDIO = 0x100D; - const RT_EXTERNALOBJECTLIST = 0x0409; - const RT_EXTERNALOBJECTLISTATOM = 0x040A; - const RT_EXTERNALOBJECTREFATOM = 0x0BC1; - const RT_EXTERNALOLECONTROL = 0x0FEE; - const RT_EXTERNALOLECONTROLATOM = 0x0FFB; - const RT_EXTERNALOLEEMBED = 0x0FCC; - const RT_EXTERNALOLEEMBEDATOM = 0x0FCD; - const RT_EXTERNALOLELINK = 0x0FCE; - const RT_EXTERNALOLELINKATOM = 0x0FD1; - const RT_EXTERNALOLEOBJECTATOM = 0x0FC3; - const RT_EXTERNALOLEOBJECTSTG = 0x1011; - const RT_EXTERNALVIDEO = 0x1005; - const RT_EXTERNALWAVAUDIOEMBEDDED = 0x100F; - const RT_EXTERNALWAVAUDIOEMBEDDEDATOM = 0x1013; - const RT_EXTERNALWAVAUDIOLINK = 0x1010; - const RT_ENVELOPEDATA9ATOM = 0x1785; - const RT_ENVELOPEFLAGS9ATOM = 0x1784; - const RT_ENVIRONMENT = 0x03F2; - const RT_FONTCOLLECTION = 0x07D5; - const RT_FONTCOLLECTION10 = 0x07D6; - const RT_FONTEMBEDDATABLOB = 0x0FB8; - const RT_FONTEMBEDFLAGS10ATOM = 0x32C8; - const RT_FILTERPRIVACYFLAGS10ATOM = 0x36B0; - const RT_FONTENTITYATOM = 0x0FB7; - const RT_FOOTERMETACHARATOM = 0x0FFA; - const RT_GENERICDATEMETACHARATOM = 0x0FF8; - const RT_GRIDSPACING10ATOM = 0x040D; - const RT_GUIDEATOM = 0x03FB; - const RT_HANDOUT = 0x0FC9; - const RT_HASHCODEATOM = 0x2B00; - const RT_HEADERSFOOTERS = 0x0FD9; - const RT_HEADERSFOOTERSATOM = 0x0FDA; - const RT_HEADERMETACHARATOM = 0x0FF9; - const RT_HTMLDOCINFO9ATOM = 0x177B; - const RT_HTMLPUBLISHINFOATOM = 0x177C; - const RT_HTMLPUBLISHINFO9 = 0x177D; - const RT_INTERACTIVEINFO = 0x0FF2; - const RT_INTERACTIVEINFOATOM = 0x0FF3; - const RT_KINSOKU = 0x0FC8; - const RT_KINSOKUATOM = 0x0FD2; - const RT_LEVELINFOATOM = 0x2B0A; - const RT_LINKEDSHAPE10ATOM = 0x2EE6; - const RT_LINKEDSLIDE10ATOM = 0x2EE7; - const RT_LIST = 0x07D0; - const RT_MAINMASTER = 0x03F8; - const RT_MASTERTEXTPROPATOM = 0x0FA2; - const RT_METAFILE = 0x0FC1; - const RT_NAMEDSHOW = 0x0411; - const RT_NAMEDSHOWS = 0x0410; - const RT_NAMEDSHOWSLIDESATOM = 0x0412; - const RT_NORMALVIEWSETINFO9 = 0x0414; - const RT_NORMALVIEWSETINFO9ATOM = 0x0415; - const RT_NOTES= 0x03F0; - const RT_NOTESATOM = 0x03F1; - const RT_NOTESTEXTVIEWINFO9 = 0x0413; - const RT_OUTLINETEXTPROPS9 = 0x0FAE; - const RT_OUTLINETEXTPROPS10 = 0x0FB3; - const RT_OUTLINETEXTPROPS11 = 0x0FB5; - const RT_OUTLINETEXTPROPSHEADER9ATOM = 0x0FAF; - const RT_OUTLINETEXTREFATOM = 0x0F9E; - const RT_OUTLINEVIEWINFO = 0x0407; - const RT_PERSISTDIRECTORYATOM = 0x1772; - const RT_PARABUILD = 0x2B08; - const RT_PARABUILDATOM = 0x2B09; - const RT_PHOTOALBUMINFO10ATOM = 0x36B2; - const RT_PLACEHOLDERATOM = 0x0BC3; - const RT_PRESENTATIONADVISORFLAGS9ATOM = 0x177A; - const RT_PRINTOPTIONSATOM = 0x1770; - const RT_PROGBINARYTAG = 0x138A; - const RT_PROGSTRINGTAG = 0x1389; - const RT_PROGTAGS = 0x1388; - const RT_RECOLORINFOATOM = 0x0FE7; - const RT_RTFDATETIMEMETACHARATOM = 0x1015; - const RT_ROUNDTRIPANIMATIONATOM12ATOM = 0x2B0B; - const RT_ROUNDTRIPANIMATIONHASHATOM12ATOM = 0x2B0D; - const RT_ROUNDTRIPCOLORMAPPING12ATOM = 0x040F; - const RT_ROUNDTRIPCOMPOSITEMASTERID12ATOM = 0x041D; - const RT_ROUNDTRIPCONTENTMASTERID12ATOM = 0x0422; - const RT_ROUNDTRIPCONTENTMASTERINFO12ATOM = 0x041E; - const RT_ROUNDTRIPCUSTOMTABLESTYLES12ATOM = 0x0428; - const RT_ROUNDTRIPDOCFLAGS12ATOM = 0x0425; - const RT_ROUNDTRIPHEADERFOOTERDEFAULTS12ATOM = 0x0424; - const RT_ROUNDTRIPHFPLACEHOLDER12ATOM = 0x0420; - const RT_ROUNDTRIPNEWPLACEHOLDERID12ATOM = 0x0BDD; - const RT_ROUNDTRIPNOTESMASTERTEXTSTYLES12ATOM = 0x0427; - const RT_ROUNDTRIPOARTTEXTSTYLES12ATOM = 0x0423; - const RT_ROUNDTRIPORIGINALMAINMASTERID12ATOM = 0x041C; - const RT_ROUNDTRIPSHAPECHECKSUMFORCL12ATOM = 0x0426; - const RT_ROUNDTRIPSHAPEID12ATOM = 0x041F; - const RT_ROUNDTRIPSLIDESYNCINFO12 = 0x3714; - const RT_ROUNDTRIPSLIDESYNCINFOATOM12 = 0x3715; - const RT_ROUNDTRIPTHEME12ATOM = 0x040E; - const RT_SHAPEATOM = 0x0BDB; - const RT_SHAPEFLAGS10ATOM = 0x0BDC; - const RT_SLIDE = 0x03EE; - const RT_SLIDEATOM = 0x03EF; - const RT_SLIDEFLAGS10ATOM = 0x2EEA; - const RT_SLIDELISTENTRY10ATOM = 0x2EF0; - const RT_SLIDELISTTABLE10 = 0x2EF1; - const RT_SLIDELISTWITHTEXT = 0x0FF0; - const RT_SLIDELISTTABLESIZE10ATOM = 0x2EEF; - const RT_SLIDENUMBERMETACHARATOM = 0x0FD8; - const RT_SLIDEPERSISTATOM = 0x03F3; - const RT_SLIDESHOWDOCINFOATOM = 0x0401; - const RT_SLIDESHOWSLIDEINFOATOM = 0x03F9; - const RT_SLIDETIME10ATOM = 0x2EEB; - const RT_SLIDEVIEWINFO = 0x03FA; - const RT_SLIDEVIEWINFOATOM = 0x03FE; - const RT_SMARTTAGSTORE11CONTAINER = 0x36B3; - const RT_SOUND = 0x07E6; - const RT_SOUNDCOLLECTION = 0x07E4; - const RT_SOUNDCOLLECTIONATOM = 0x07E5; - const RT_SOUNDDATABLOB = 0x07E7; - const RT_SORTERVIEWINFO = 0x0408; - const RT_STYLETEXTPROPATOM = 0x0FA1; - const RT_STYLETEXTPROP10ATOM = 0x0FB1; - const RT_STYLETEXTPROP11ATOM = 0x0FB6; - const RT_STYLETEXTPROP9ATOM = 0x0FAC; - const RT_SUMMARY = 0x0402; - const RT_TEXTBOOKMARKATOM = 0x0FA7; - const RT_TEXTBYTESATOM = 0x0FA8; - const RT_TEXTCHARFORMATEXCEPTIONATOM = 0x0FA4; - const RT_TEXTCHARSATOM = 0x0FA0; - const RT_TEXTDEFAULTS10ATOM = 0x0FB4; - const RT_TEXTDEFAULTS9ATOM = 0x0FB0; - const RT_TEXTHEADERATOM = 0x0F9F; - const RT_TEXTINTERACTIVEINFOATOM = 0x0FDF; - const RT_TEXTMASTERSTYLEATOM = 0x0FA3; - const RT_TEXTMASTERSTYLE10ATOM = 0x0FB2; - const RT_TEXTMASTERSTYLE9ATOM = 0x0FAD; - const RT_TEXTPARAGRAPHFORMATEXCEPTIONATOM = 0x0FA5; - const RT_TEXTRULERATOM = 0x0FA6; - const RT_TEXTSPECIALINFOATOM = 0x0FAA; - const RT_TEXTSPECIALINFODEFAULTATOM = 0x0FA9; - const RT_TIMEANIMATEBEHAVIOR = 0xF134; - const RT_TIMEANIMATEBEHAVIORCONTAINER = 0xF12B; - const RT_TIMEANIMATIONVALUE = 0xF143; - const RT_TIMEANIMATIONVALUELIST = 0xF13F; - const RT_TIMEBEHAVIOR = 0xF133; - const RT_TIMEBEHAVIORCONTAINER = 0xF12A; - const RT_TIMECOLORBEHAVIOR = 0xF135; - const RT_TIMECOLORBEHAVIORCONTAINER = 0xF12C; - const RT_TIMECLIENTVISUALELEMENT = 0xF13C; - const RT_TIMECOMMANDBEHAVIOR = 0xF13B; - const RT_TIMECOMMANDBEHAVIORCONTAINER = 0xF132; - const RT_TIMECONDITION = 0xF128; - const RT_TIMECONDITIONCONTAINER = 0xF125; - const RT_TIMEEFFECTBEHAVIOR = 0xF136; - const RT_TIMEEFFECTBEHAVIORCONTAINER = 0xF12D; - const RT_TIMEEXTTIMENODECONTAINER = 0xF144; - const RT_TIMEITERATEDATA = 0xF140; - const RT_TIMEMODIFIER = 0xF129; - const RT_TIMEMOTIONBEHAVIOR = 0xF137; - const RT_TIMEMOTIONBEHAVIORCONTAINER = 0xF12E; - const RT_TIMENODE = 0xF127; - const RT_TIMEPROPERTYLIST = 0xF13D; - const RT_TIMEROTATIONBEHAVIOR = 0xF138; - const RT_TIMEROTATIONBEHAVIORCONTAINER = 0xF12F; - const RT_TIMESCALEBEHAVIOR = 0xF139; - const RT_TIMESCALEBEHAVIORCONTAINER = 0xF130; - const RT_TIMESEQUENCEDATA = 0xF141; - const RT_TIMESETBEHAVIOR = 0xF13A; - const RT_TIMESETBEHAVIORCONTAINER = 0xF131; - const RT_TIMESUBEFFECTCONTAINER = 0xF145; - const RT_TIMEVARIANT = 0xF142; - const RT_TIMEVARIANTLIST = 0xF13E; - const RT_USEREDITATOM = 0x0FF5; - const RT_VBAINFO = 0x03FF; - const RT_VBAINFOATOM = 0x0400; - const RT_VIEWINFOATOM = 0x03FD; - const RT_VISUALPAGEATOM = 0x2B01; - const RT_VISUALSHAPEATOM = 0x2AFB; - - /** - * @var http://msdn.microsoft.com/en-us/library/dd926394(v=office.12).aspx - */ - const SL_BIGOBJECT = 0x0000000F; - const SL_BLANK = 0x00000010; - const SL_COLUMNTWOROWS = 0x0000000A; - const SL_FOUROBJECTS = 0x0000000E; - const SL_MASTERTITLE = 0x00000002; - const SL_TITLEBODY = 0x00000001; - const SL_TITLEONLY = 0x00000007; - const SL_TITLESLIDE = 0x00000000; - const SL_TWOCOLUMNS = 0x00000008; - const SL_TWOCOLUMNSROW = 0x0000000D; - const SL_TWOROWS = 0x00000009; - const SL_TWOROWSCOLUMN = 0x0000000B; - const SL_VERTICALTITLEBODY = 0x00000011; - const SL_VERTICALTWOROWS = 0x00000012; - - /** - * Array with Fonts - */ - private $arrayFonts = array(); - /** - * Array with Hyperlinks - */ - private $arrayHyperlinks = array(); - /** - * Array with Notes - */ - private $arrayNotes = array(); - /** - * Array with Pictures - */ - private $arrayPictures = array(); + public const OFFICEARTBLIPEMF = 0xF01A; + public const OFFICEARTBLIPWMF = 0xF01B; + public const OFFICEARTBLIPPICT = 0xF01C; + public const OFFICEARTBLIPJPG = 0xF01D; + public const OFFICEARTBLIPPNG = 0xF01E; + public const OFFICEARTBLIPDIB = 0xF01F; + public const OFFICEARTBLIPTIFF = 0xF029; + public const OFFICEARTBLIPJPEG = 0xF02A; + + /** + * @see http://msdn.microsoft.com/en-us/library/dd945336(v=office.12).aspx + */ + public const RT_ANIMATIONINFO = 0x1014; + public const RT_ANIMATIONINFOATOM = 0x0FF1; + public const RT_BINARYTAGDATABLOB = 0x138B; + public const RT_BLIPCOLLECTION9 = 0x07F8; + public const RT_BLIPENTITY9ATOM = 0x07F9; + public const RT_BOOKMARKCOLLECTION = 0x07E3; + public const RT_BOOKMARKENTITYATOM = 0x0FD0; + public const RT_BOOKMARKSEEDATOM = 0x07E9; + public const RT_BROADCASTDOCINFO9 = 0x177E; + public const RT_BROADCASTDOCINFO9ATOM = 0x177F; + public const RT_BUILDATOM = 0x2B03; + public const RT_BUILDLIST = 0x2B02; + public const RT_CHARTBUILD = 0x2B04; + public const RT_CHARTBUILDATOM = 0x2B05; + public const RT_COLORSCHEMEATOM = 0x07F0; + public const RT_COMMENT10 = 0x2EE0; + public const RT_COMMENT10ATOM = 0x2EE1; + public const RT_COMMENTINDEX10 = 0x2EE4; + public const RT_COMMENTINDEX10ATOM = 0x2EE5; + public const RT_CRYPTSESSION10CONTAINER = 0x2F14; + public const RT_CURRENTUSERATOM = 0x0FF6; + public const RT_CSTRING = 0x0FBA; + public const RT_DATETIMEMETACHARATOM = 0x0FF7; + public const RT_DEFAULTRULERATOM = 0x0FAB; + public const RT_DOCROUTINGSLIPATOM = 0x0406; + public const RT_DIAGRAMBUILD = 0x2B06; + public const RT_DIAGRAMBUILDATOM = 0x2B07; + public const RT_DIFF10 = 0x2EED; + public const RT_DIFF10ATOM = 0x2EEE; + public const RT_DIFFTREE10 = 0x2EEC; + public const RT_DOCTOOLBARSTATES10ATOM = 0x36B1; + public const RT_DOCUMENT = 0x03E8; + public const RT_DOCUMENTATOM = 0x03E9; + public const RT_DRAWING = 0x040C; + public const RT_DRAWINGGROUP = 0x040B; + public const RT_ENDDOCUMENTATOM = 0x03EA; + public const RT_EXTERNALAVIMOVIE = 0x1006; + public const RT_EXTERNALCDAUDIO = 0x100E; + public const RT_EXTERNALCDAUDIOATOM = 0x1012; + public const RT_EXTERNALHYPERLINK = 0x0FD7; + public const RT_EXTERNALHYPERLINK9 = 0x0FE4; + public const RT_EXTERNALHYPERLINKATOM = 0x0FD3; + public const RT_EXTERNALHYPERLINKFLAGSATOM = 0x1018; + public const RT_EXTERNALMCIMOVIE = 0x1007; + public const RT_EXTERNALMEDIAATOM = 0x1004; + public const RT_EXTERNALMIDIAUDIO = 0x100D; + public const RT_EXTERNALOBJECTLIST = 0x0409; + public const RT_EXTERNALOBJECTLISTATOM = 0x040A; + public const RT_EXTERNALOBJECTREFATOM = 0x0BC1; + public const RT_EXTERNALOLECONTROL = 0x0FEE; + public const RT_EXTERNALOLECONTROLATOM = 0x0FFB; + public const RT_EXTERNALOLEEMBED = 0x0FCC; + public const RT_EXTERNALOLEEMBEDATOM = 0x0FCD; + public const RT_EXTERNALOLELINK = 0x0FCE; + public const RT_EXTERNALOLELINKATOM = 0x0FD1; + public const RT_EXTERNALOLEOBJECTATOM = 0x0FC3; + public const RT_EXTERNALOLEOBJECTSTG = 0x1011; + public const RT_EXTERNALVIDEO = 0x1005; + public const RT_EXTERNALWAVAUDIOEMBEDDED = 0x100F; + public const RT_EXTERNALWAVAUDIOEMBEDDEDATOM = 0x1013; + public const RT_EXTERNALWAVAUDIOLINK = 0x1010; + public const RT_ENVELOPEDATA9ATOM = 0x1785; + public const RT_ENVELOPEFLAGS9ATOM = 0x1784; + public const RT_ENVIRONMENT = 0x03F2; + public const RT_FONTCOLLECTION = 0x07D5; + public const RT_FONTCOLLECTION10 = 0x07D6; + public const RT_FONTEMBEDDATABLOB = 0x0FB8; + public const RT_FONTEMBEDFLAGS10ATOM = 0x32C8; + public const RT_FILTERPRIVACYFLAGS10ATOM = 0x36B0; + public const RT_FONTENTITYATOM = 0x0FB7; + public const RT_FOOTERMETACHARATOM = 0x0FFA; + public const RT_GENERICDATEMETACHARATOM = 0x0FF8; + public const RT_GRIDSPACING10ATOM = 0x040D; + public const RT_GUIDEATOM = 0x03FB; + public const RT_HANDOUT = 0x0FC9; + public const RT_HASHCODEATOM = 0x2B00; + public const RT_HEADERSFOOTERS = 0x0FD9; + public const RT_HEADERSFOOTERSATOM = 0x0FDA; + public const RT_HEADERMETACHARATOM = 0x0FF9; + public const RT_HTMLDOCINFO9ATOM = 0x177B; + public const RT_HTMLPUBLISHINFOATOM = 0x177C; + public const RT_HTMLPUBLISHINFO9 = 0x177D; + public const RT_INTERACTIVEINFO = 0x0FF2; + public const RT_INTERACTIVEINFOATOM = 0x0FF3; + public const RT_KINSOKU = 0x0FC8; + public const RT_KINSOKUATOM = 0x0FD2; + public const RT_LEVELINFOATOM = 0x2B0A; + public const RT_LINKEDSHAPE10ATOM = 0x2EE6; + public const RT_LINKEDSLIDE10ATOM = 0x2EE7; + public const RT_LIST = 0x07D0; + public const RT_MAINMASTER = 0x03F8; + public const RT_MASTERTEXTPROPATOM = 0x0FA2; + public const RT_METAFILE = 0x0FC1; + public const RT_NAMEDSHOW = 0x0411; + public const RT_NAMEDSHOWS = 0x0410; + public const RT_NAMEDSHOWSLIDESATOM = 0x0412; + public const RT_NORMALVIEWSETINFO9 = 0x0414; + public const RT_NORMALVIEWSETINFO9ATOM = 0x0415; + public const RT_NOTES = 0x03F0; + public const RT_NOTESATOM = 0x03F1; + public const RT_NOTESTEXTVIEWINFO9 = 0x0413; + public const RT_OUTLINETEXTPROPS9 = 0x0FAE; + public const RT_OUTLINETEXTPROPS10 = 0x0FB3; + public const RT_OUTLINETEXTPROPS11 = 0x0FB5; + public const RT_OUTLINETEXTPROPSHEADER9ATOM = 0x0FAF; + public const RT_OUTLINETEXTREFATOM = 0x0F9E; + public const RT_OUTLINEVIEWINFO = 0x0407; + public const RT_PERSISTDIRECTORYATOM = 0x1772; + public const RT_PARABUILD = 0x2B08; + public const RT_PARABUILDATOM = 0x2B09; + public const RT_PHOTOALBUMINFO10ATOM = 0x36B2; + public const RT_PLACEHOLDERATOM = 0x0BC3; + public const RT_PRESENTATIONADVISORFLAGS9ATOM = 0x177A; + public const RT_PRINTOPTIONSATOM = 0x1770; + public const RT_PROGBINARYTAG = 0x138A; + public const RT_PROGSTRINGTAG = 0x1389; + public const RT_PROGTAGS = 0x1388; + public const RT_RECOLORINFOATOM = 0x0FE7; + public const RT_RTFDATETIMEMETACHARATOM = 0x1015; + public const RT_ROUNDTRIPANIMATIONATOM12ATOM = 0x2B0B; + public const RT_ROUNDTRIPANIMATIONHASHATOM12ATOM = 0x2B0D; + public const RT_ROUNDTRIPCOLORMAPPING12ATOM = 0x040F; + public const RT_ROUNDTRIPCOMPOSITEMASTERID12ATOM = 0x041D; + public const RT_ROUNDTRIPCONTENTMASTERID12ATOM = 0x0422; + public const RT_ROUNDTRIPCONTENTMASTERINFO12ATOM = 0x041E; + public const RT_ROUNDTRIPCUSTOMTABLESTYLES12ATOM = 0x0428; + public const RT_ROUNDTRIPDOCFLAGS12ATOM = 0x0425; + public const RT_ROUNDTRIPHEADERFOOTERDEFAULTS12ATOM = 0x0424; + public const RT_ROUNDTRIPHFPLACEHOLDER12ATOM = 0x0420; + public const RT_ROUNDTRIPNEWPLACEHOLDERID12ATOM = 0x0BDD; + public const RT_ROUNDTRIPNOTESMASTERTEXTSTYLES12ATOM = 0x0427; + public const RT_ROUNDTRIPOARTTEXTSTYLES12ATOM = 0x0423; + public const RT_ROUNDTRIPORIGINALMAINMASTERID12ATOM = 0x041C; + public const RT_ROUNDTRIPSHAPECHECKSUMFORCL12ATOM = 0x0426; + public const RT_ROUNDTRIPSHAPEID12ATOM = 0x041F; + public const RT_ROUNDTRIPSLIDESYNCINFO12 = 0x3714; + public const RT_ROUNDTRIPSLIDESYNCINFOATOM12 = 0x3715; + public const RT_ROUNDTRIPTHEME12ATOM = 0x040E; + public const RT_SHAPEATOM = 0x0BDB; + public const RT_SHAPEFLAGS10ATOM = 0x0BDC; + public const RT_SLIDE = 0x03EE; + public const RT_SLIDEATOM = 0x03EF; + public const RT_SLIDEFLAGS10ATOM = 0x2EEA; + public const RT_SLIDELISTENTRY10ATOM = 0x2EF0; + public const RT_SLIDELISTTABLE10 = 0x2EF1; + public const RT_SLIDELISTWITHTEXT = 0x0FF0; + public const RT_SLIDELISTTABLESIZE10ATOM = 0x2EEF; + public const RT_SLIDENUMBERMETACHARATOM = 0x0FD8; + public const RT_SLIDEPERSISTATOM = 0x03F3; + public const RT_SLIDESHOWDOCINFOATOM = 0x0401; + public const RT_SLIDESHOWSLIDEINFOATOM = 0x03F9; + public const RT_SLIDETIME10ATOM = 0x2EEB; + public const RT_SLIDEVIEWINFO = 0x03FA; + public const RT_SLIDEVIEWINFOATOM = 0x03FE; + public const RT_SMARTTAGSTORE11CONTAINER = 0x36B3; + public const RT_SOUND = 0x07E6; + public const RT_SOUNDCOLLECTION = 0x07E4; + public const RT_SOUNDCOLLECTIONATOM = 0x07E5; + public const RT_SOUNDDATABLOB = 0x07E7; + public const RT_SORTERVIEWINFO = 0x0408; + public const RT_STYLETEXTPROPATOM = 0x0FA1; + public const RT_STYLETEXTPROP10ATOM = 0x0FB1; + public const RT_STYLETEXTPROP11ATOM = 0x0FB6; + public const RT_STYLETEXTPROP9ATOM = 0x0FAC; + public const RT_SUMMARY = 0x0402; + public const RT_TEXTBOOKMARKATOM = 0x0FA7; + public const RT_TEXTBYTESATOM = 0x0FA8; + public const RT_TEXTCHARFORMATEXCEPTIONATOM = 0x0FA4; + public const RT_TEXTCHARSATOM = 0x0FA0; + public const RT_TEXTDEFAULTS10ATOM = 0x0FB4; + public const RT_TEXTDEFAULTS9ATOM = 0x0FB0; + public const RT_TEXTHEADERATOM = 0x0F9F; + public const RT_TEXTINTERACTIVEINFOATOM = 0x0FDF; + public const RT_TEXTMASTERSTYLEATOM = 0x0FA3; + public const RT_TEXTMASTERSTYLE10ATOM = 0x0FB2; + public const RT_TEXTMASTERSTYLE9ATOM = 0x0FAD; + public const RT_TEXTPARAGRAPHFORMATEXCEPTIONATOM = 0x0FA5; + public const RT_TEXTRULERATOM = 0x0FA6; + public const RT_TEXTSPECIALINFOATOM = 0x0FAA; + public const RT_TEXTSPECIALINFODEFAULTATOM = 0x0FA9; + public const RT_TIMEANIMATEBEHAVIOR = 0xF134; + public const RT_TIMEANIMATEBEHAVIORCONTAINER = 0xF12B; + public const RT_TIMEANIMATIONVALUE = 0xF143; + public const RT_TIMEANIMATIONVALUELIST = 0xF13F; + public const RT_TIMEBEHAVIOR = 0xF133; + public const RT_TIMEBEHAVIORCONTAINER = 0xF12A; + public const RT_TIMECOLORBEHAVIOR = 0xF135; + public const RT_TIMECOLORBEHAVIORCONTAINER = 0xF12C; + public const RT_TIMECLIENTVISUALELEMENT = 0xF13C; + public const RT_TIMECOMMANDBEHAVIOR = 0xF13B; + public const RT_TIMECOMMANDBEHAVIORCONTAINER = 0xF132; + public const RT_TIMECONDITION = 0xF128; + public const RT_TIMECONDITIONCONTAINER = 0xF125; + public const RT_TIMEEFFECTBEHAVIOR = 0xF136; + public const RT_TIMEEFFECTBEHAVIORCONTAINER = 0xF12D; + public const RT_TIMEEXTTIMENODECONTAINER = 0xF144; + public const RT_TIMEITERATEDATA = 0xF140; + public const RT_TIMEMODIFIER = 0xF129; + public const RT_TIMEMOTIONBEHAVIOR = 0xF137; + public const RT_TIMEMOTIONBEHAVIORCONTAINER = 0xF12E; + public const RT_TIMENODE = 0xF127; + public const RT_TIMEPROPERTYLIST = 0xF13D; + public const RT_TIMEROTATIONBEHAVIOR = 0xF138; + public const RT_TIMEROTATIONBEHAVIORCONTAINER = 0xF12F; + public const RT_TIMESCALEBEHAVIOR = 0xF139; + public const RT_TIMESCALEBEHAVIORCONTAINER = 0xF130; + public const RT_TIMESEQUENCEDATA = 0xF141; + public const RT_TIMESETBEHAVIOR = 0xF13A; + public const RT_TIMESETBEHAVIORCONTAINER = 0xF131; + public const RT_TIMESUBEFFECTCONTAINER = 0xF145; + public const RT_TIMEVARIANT = 0xF142; + public const RT_TIMEVARIANTLIST = 0xF13E; + public const RT_USEREDITATOM = 0x0FF5; + public const RT_VBAINFO = 0x03FF; + public const RT_VBAINFOATOM = 0x0400; + public const RT_VIEWINFOATOM = 0x03FD; + public const RT_VISUALPAGEATOM = 0x2B01; + public const RT_VISUALSHAPEATOM = 0x2AFB; + + /** + * @see http://msdn.microsoft.com/en-us/library/dd926394(v=office.12).aspx + */ + public const SL_BIGOBJECT = 0x0000000F; + public const SL_BLANK = 0x00000010; + public const SL_COLUMNTWOROWS = 0x0000000A; + public const SL_FOUROBJECTS = 0x0000000E; + public const SL_MASTERTITLE = 0x00000002; + public const SL_TITLEBODY = 0x00000001; + public const SL_TITLEONLY = 0x00000007; + public const SL_TITLESLIDE = 0x00000000; + public const SL_TWOCOLUMNS = 0x00000008; + public const SL_TWOCOLUMNSROW = 0x0000000D; + public const SL_TWOROWS = 0x00000009; + public const SL_TWOROWSCOLUMN = 0x0000000B; + public const SL_VERTICALTITLEBODY = 0x00000011; + public const SL_VERTICALTWOROWS = 0x00000012; + + /** + * Array with Fonts. + * + * @var array + */ + private $arrayFonts = []; + /** + * Array with Hyperlinks. + * + * @var array> + */ + private $arrayHyperlinks = []; + /** + * Array with Notes. + * + * @var array + */ + private $arrayNotes = []; + /** + * Array with Pictures. + * + * @var array + */ + private $arrayPictures = []; /** * Offset (in bytes) from the beginning of the PowerPoint Document Stream to the UserEditAtom record for the most recent user edit. + * * @var int */ private $offsetToCurrentEdit; /** * A structure that specifies a compressed table of sequential persist object identifiers and stream offsets to associated persist objects. - * @var int[] + * + * @var array */ private $rgPersistDirEntry; /** - * Offset (in bytes) from the beginning of the PowerPoint Document Stream to the PersistDirectoryAtom record for this user edit + * Offset (in bytes) from the beginning of the PowerPoint Document Stream to the PersistDirectoryAtom record for this user edit. + * * @var int */ private $offsetPersistDirectory; /** - * Output Object + * Output Object. + * * @var PhpPresentation */ private $oPhpPresentation; /** - * Group Object - * @var Group + * @var Group|null */ private $oCurrentGroup; /** - * @var boolean + * @var bool */ private $bFirstShapeGroup = false; /** - * Stream "Powerpoint Document" + * Stream "Powerpoint Document". + * * @var string */ private $streamPowerpointDocument; /** - * Stream "Current User" + * Stream "Current User". + * * @var string */ private $streamCurrentUser; /** - * Stream "Summary Information" + * Stream "Summary Information". + * * @var string */ private $streamSummaryInformation; /** - * Stream "Document Summary Information" + * Stream "Document Summary Information". + * * @var string */ private $streamDocumentSummaryInformation; /** - * Stream "Pictures" + * Stream "Pictures". + * * @var string */ private $streamPictures; /** - * @var integer + * @var int */ private $inMainType; /** - * @var integer + * @var int|null */ private $currentNote; + /** + * @var string|null + */ + private $filename; + /** * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file? - * - * @param string $pFilename - * @throws \Exception - * @return boolean */ - public function canRead($pFilename) + public function canRead(string $pFilename): bool { return $this->fileSupportsUnserializePhpPresentation($pFilename); } @@ -379,15 +404,13 @@ public function canRead($pFilename) /** * Does a file support UnserializePhpPresentation ? * - * @param string $pFilename - * @throws \Exception - * @return boolean + * @throws FileNotFoundException */ - public function fileSupportsUnserializePhpPresentation($pFilename = '') + public function fileSupportsUnserializePhpPresentation(string $pFilename = ''): bool { // Check if file exists if (!file_exists($pFilename)) { - throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist."); + throw new FileNotFoundException($pFilename); } try { @@ -395,42 +418,40 @@ public function fileSupportsUnserializePhpPresentation($pFilename = '') $ole = new OLERead(); // get excel data $ole->read($pFilename); + return true; - } catch (\Exception $e) { + } catch (Exception $e) { return false; } } /** - * Loads PhpPresentation Serialized file + * Loads PhpPresentation Serialized file. * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation - * @throws \Exception + * @throws InvalidFileFormatException */ - public function load($pFilename) + public function load(string $pFilename): PhpPresentation { // Unserialize... First make sure the file supports it! if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) { - throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\PowerPoint97: " . $pFilename . "."); + throw new InvalidFileFormatException($pFilename, PowerPoint97::class); } - return $this->loadFile($pFilename); + $this->filename = $pFilename; + + return $this->loadFile(); } /** * Load PhpPresentation Serialized file - * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation */ - private function loadFile($pFilename) + private function loadFile(): PhpPresentation { $this->oPhpPresentation = new PhpPresentation(); $this->oPhpPresentation->removeSlideByIndex(); // Read OLE Blocks - $this->loadOLE($pFilename); + $this->loadOLE(); // Read pictures in the Pictures Stream $this->loadPicturesStream(); // Read information in the Current User Stream @@ -443,13 +464,12 @@ private function loadFile($pFilename) /** * Read OLE Part - * @param string $pFilename */ - private function loadOLE($pFilename) + private function loadOLE(): void { // OLE reader $oOLE = new OLERead(); - $oOLE->read($pFilename); + $oOLE->read($this->filename); // PowerPoint Document Stream $this->streamPowerpointDocument = $oOLE->getStream($oOLE->powerpointDocument); @@ -468,10 +488,13 @@ private function loadOLE($pFilename) } /** - * Stream Pictures - * @link http://msdn.microsoft.com/en-us/library/dd920746(v=office.12).aspx + * Stream Pictures. + * + * @throws FeatureNotImplementedException + * + * @see http://msdn.microsoft.com/en-us/library/dd920746(v=office.12).aspx */ - private function loadPicturesStream() + private function loadPicturesStream(): void { $stream = $this->streamPictures; @@ -480,11 +503,11 @@ private function loadPicturesStream() $arrayRH = $this->loadRecordHeader($stream, $pos); $pos += 8; $readSuccess = false; - if ($arrayRH['recVer'] == 0x00 && ($arrayRH['recType'] == 0xF007 || ($arrayRH['recType'] >= 0xF018 && $arrayRH['recType'] <= 0xF117))) { + if (0x00 == $arrayRH['recVer'] && (0xF007 == $arrayRH['recType'] || ($arrayRH['recType'] >= 0xF018 && $arrayRH['recType'] <= 0xF117))) { //@link : http://msdn.microsoft.com/en-us/library/dd950560(v=office.12).aspx - if ($arrayRH['recType'] == 0xF007) { + if (0xF007 == $arrayRH['recType']) { // OfficeArtFBSE - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + throw new FeatureNotImplementedException(); } if ($arrayRH['recType'] >= 0xF018 && $arrayRH['recType'] <= 0xF117) { $arrayRecord = $this->readRecordOfficeArtBlip($stream, $pos - 8); @@ -495,39 +518,44 @@ private function loadPicturesStream() } $readSuccess = true; } - } while ($readSuccess === true); + } while (true === $readSuccess); } /** - * Stream Current User - * @link http://msdn.microsoft.com/en-us/library/dd908567(v=office.12).aspx + * Stream Current User. + * + * @throws FeatureNotImplementedException + * @throws InvalidFileFormatException + * + * @see http://msdn.microsoft.com/en-us/library/dd908567(v=office.12).aspx */ - private function loadCurrentUserStream() + private function loadCurrentUserStream(): void { $pos = 0; /** - * CurrentUserAtom : http://msdn.microsoft.com/en-us/library/dd948895(v=office.12).aspx + * CurrentUserAtom : http://msdn.microsoft.com/en-us/library/dd948895(v=office.12).aspx. */ // RecordHeader : http://msdn.microsoft.com/en-us/library/dd926377(v=office.12).aspx $rHeader = $this->loadRecordHeader($this->streamCurrentUser, $pos); $pos += 8; - if ($rHeader['recVer'] != 0x0 || $rHeader['recInstance'] != 0x000 || $rHeader['recType'] != self::RT_CURRENTUSERATOM) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > RecordHeader).'); + if (0x0 != $rHeader['recVer'] || 0x000 != $rHeader['recInstance'] || self::RT_CURRENTUSERATOM != $rHeader['recType']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > RecordHeader'); } // Size $size = self::getInt4d($this->streamCurrentUser, $pos); $pos += 4; - if ($size != 0x00000014) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > Size).'); + if (0x00000014 != $size) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > Size'); } // headerToken $headerToken = self::getInt4d($this->streamCurrentUser, $pos); $pos += 4; - if ($headerToken == 0xF3D1C4DF && $headerToken != 0xE391C05F) { - throw new \Exception('Feature not implemented (l.'.__LINE__.') : Encrypted file'); + if (0xF3D1C4DF == $headerToken && 0xE391C05F != $headerToken) { + // Encrypted file + throw new FeatureNotImplementedException(); } // offsetToCurrentEdit @@ -538,69 +566,70 @@ private function loadCurrentUserStream() $lenUserName = self::getInt2d($this->streamCurrentUser, $pos); $pos += 2; if ($lenUserName > 255) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > lenUserName).'); + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > lenUserName'); } // docFileVersion $docFileVersion = self::getInt2d($this->streamCurrentUser, $pos); $pos += 2; - if ($docFileVersion != 0x03F4) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > docFileVersion).'); + if (0x03F4 != $docFileVersion) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > docFileVersion'); } // majorVersion $majorVersion = self::getInt1d($this->streamCurrentUser, $pos); - $pos += 1; - if ($majorVersion != 0x03) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > majorVersion).'); + ++$pos; + if (0x03 != $majorVersion) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > majorVersion'); } // minorVersion $minorVersion = self::getInt1d($this->streamCurrentUser, $pos); - $pos += 1; - if ($minorVersion != 0x00) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > minorVersion).'); + ++$pos; + if (0x00 != $minorVersion) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > minorVersion'); } // unused $pos += 2; // ansiUserName - $ansiUserName = ''; + // $ansiUserName = ''; do { $char = self::getInt1d($this->streamCurrentUser, $pos); if (($char >= 0x00 && $char <= 0x1F) || ($char >= 0x7F && $char <= 0x9F)) { $char = false; } else { - $ansiUserName .= chr($char); - $pos += 1; + // $ansiUserName .= chr($char); + ++$pos; } - } while ($char !== false); + } while (false !== $char); // relVersion $relVersion = self::getInt4d($this->streamCurrentUser, $pos); $pos += 4; - if ($relVersion != 0x00000008 && $relVersion != 0x00000009) { - throw new \Exception('File PowerPoint 97 in error (Location : CurrentUserAtom > relVersion).'); + if (0x00000008 != $relVersion && 0x00000009 != $relVersion) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : CurrentUserAtom > relVersion'); } // unicodeUserName - $unicodeUserName = ''; - for ($inc = 0; $inc < $lenUserName; $inc++) { + // $unicodeUserName = ''; + for ($inc = 0; $inc < $lenUserName; ++$inc) { $char = self::getInt2d($this->streamCurrentUser, $pos); if (($char >= 0x00 && $char <= 0x1F) || ($char >= 0x7F && $char <= 0x9F)) { break; } - $unicodeUserName .= chr($char); + // $unicodeUserName .= chr($char); $pos += 2; } } /** - * Stream Powerpoint Document - * @link http://msdn.microsoft.com/en-us/library/dd921564(v=office.12).aspx + * Stream Powerpoint Document. + * + * @see http://msdn.microsoft.com/en-us/library/dd921564(v=office.12).aspx */ - private function loadPowerpointDocumentStream() + private function loadPowerpointDocumentStream(): void { $this->readRecordUserEditAtom($this->streamPowerpointDocument, $this->offsetToCurrentEdit); @@ -609,11 +638,11 @@ private function loadPowerpointDocumentStream() foreach ($this->rgPersistDirEntry as $offsetDir) { $pos = $offsetDir; - $rh = $this->loadRecordHeader($this->streamPowerpointDocument, $pos); + $rHeader = $this->loadRecordHeader($this->streamPowerpointDocument, $pos); $pos += 8; - $this->inMainType = $rh['recType']; + $this->inMainType = $rHeader['recType']; $this->currentNote = null; - switch ($rh['recType']) { + switch ($rHeader['recType']) { case self::RT_DOCUMENT: $this->readRecordDocumentContainer($this->streamPowerpointDocument, $pos); break; @@ -624,63 +653,50 @@ private function loadPowerpointDocumentStream() $this->readRecordSlideContainer($this->streamPowerpointDocument, $pos); break; default: - // throw new \Exception('Feature not implemented : l.'.__LINE__.'('.dechex($rh['recType']).')'); break; } } } /** - * Read a record header - * @param string $stream - * @param integer $pos - * @return array + * Read a record header. + * + * @return array */ - private function loadRecordHeader($stream, $pos) + private function loadRecordHeader(string $stream, int $pos): array { $rec = self::getInt2d($stream, $pos); $recType = self::getInt2d($stream, $pos + 2); $recLen = self::getInt4d($stream, $pos + 4); - return array( + + return [ 'recVer' => ($rec >> 0) & bindec('1111'), 'recInstance' => ($rec >> 4) & bindec('111111111111'), 'recType' => $recType, 'recLen' => $recLen, - ); + ]; } /** - * Read 8-bit unsigned integer - * - * @param string $data - * @param int $pos - * @return int + * Read 8-bit unsigned integer. */ - public static function getInt1d($data, $pos) + public static function getInt1d(string $data, int $pos): int { return ord($data[$pos]); } /** - * Read 16-bit unsigned integer - * - * @param string $data - * @param int $pos - * @return int + * Read 16-bit unsigned integer. */ - public static function getInt2d($data, $pos) + public static function getInt2d(string $data, int $pos): int { - return ord($data[$pos]) | (ord($data[$pos+1]) << 8); + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8); } /** - * Read 32-bit signed integer - * - * @param string $data - * @param int $pos - * @return int + * Read 32-bit signed integer. */ - public static function getInt4d($data, $pos) + public static function getInt4d(string $data, int $pos): int { // FIX: represent numbers correctly on 64-bit system // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334 @@ -692,28 +708,32 @@ public static function getInt4d($data, $pos) // negative number $ord24 = -abs((256 - $or24) << 24); } - return ord($data[$pos]) | (ord($data[$pos+1]) << 8) | (ord($data[$pos+2]) << 16) | $ord24; + + return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $ord24; } /** * A container record that specifies the animation and sound information for a shape. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd772900(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd772900(v=office.12).aspx */ - private function readRecordAnimationInfoContainer($stream, $pos) + private function readRecordAnimationInfoContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ANIMATIONINFO) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_ANIMATIONINFO == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // animationAtom // animationSound - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + throw new FeatureNotImplementedException(); } return $arrayReturn; @@ -721,26 +741,28 @@ private function readRecordAnimationInfoContainer($stream, $pos) /** * A container record that specifies information about the document. - * @param string $stream - * @param integer $pos - * @link http://msdn.microsoft.com/en-us/library/dd947357(v=office.12).aspx + * + * @throws FeatureNotImplementedException + * @throws InvalidFileFormatException + * + * @see http://msdn.microsoft.com/en-us/library/dd947357(v=office.12).aspx */ - private function readRecordDocumentContainer($stream, $pos) + private function readRecordDocumentContainer(string $stream, int $pos): void { $documentAtom = $this->loadRecordHeader($stream, $pos); $pos += 8; - if ($documentAtom['recVer'] != 0x1 || $documentAtom['recInstance'] != 0x000 || $documentAtom['recType'] != self::RT_DOCUMENTATOM) { - throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > DocumentAtom).'); + if (0x1 != $documentAtom['recVer'] || 0x000 != $documentAtom['recInstance'] || self::RT_DOCUMENTATOM != $documentAtom['recType']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : RTDocument > DocumentAtom'); } $pos += $documentAtom['recLen']; $exObjList = $this->loadRecordHeader($stream, $pos); - if ($exObjList['recVer'] == 0xF && $exObjList['recInstance'] == 0x000 && $exObjList['recType'] == self::RT_EXTERNALOBJECTLIST) { + if (0xF == $exObjList['recVer'] && 0x000 == $exObjList['recInstance'] && self::RT_EXTERNALOBJECTLIST == $exObjList['recType']) { $pos += 8; // exObjListAtom > rh $exObjListAtom = $this->loadRecordHeader($stream, $pos); - if ($exObjListAtom['recVer'] != 0x0 || $exObjListAtom['recInstance'] != 0x000 || $exObjListAtom['recType'] != self::RT_EXTERNALOBJECTLISTATOM || $exObjListAtom['recLen'] != 0x00000004) { - throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > DocumentAtom > exObjList > exObjListAtom).'); + if (0x0 != $exObjListAtom['recVer'] || 0x000 != $exObjListAtom['recInstance'] || self::RT_EXTERNALOBJECTLISTATOM != $exObjListAtom['recType'] || 0x00000004 != $exObjListAtom['recLen']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : RTDocument > DocumentAtom > exObjList > exObjListAtom'); } $pos += 8; // exObjListAtom > exObjIdSeed @@ -756,8 +778,8 @@ private function readRecordDocumentContainer($stream, $pos) //@link : http://msdn.microsoft.com/en-us/library/dd944995(v=office.12).aspx // exHyperlinkAtom > rh $exHyperlinkAtom = $this->loadRecordHeader($stream, $pos); - if ($exHyperlinkAtom['recVer'] != 0x0 || $exHyperlinkAtom['recInstance'] != 0x000 || $exHyperlinkAtom['recType'] != self::RT_EXTERNALHYPERLINKATOM || $exObjListAtom['recLen'] != 0x00000004) { - throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > DocumentAtom > exObjList > rgChildRec > RT_ExternalHyperlink).'); + if (0x0 != $exHyperlinkAtom['recVer'] || 0x000 != $exHyperlinkAtom['recInstance'] || self::RT_EXTERNALHYPERLINKATOM != $exHyperlinkAtom['recType'] || 0x00000004 != $exObjListAtom['recLen']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : RTDocument > DocumentAtom > exObjList > rgChildRec > RT_ExternalHyperlink'); } $pos += 8; $exObjList['recLen'] -= 8; @@ -766,14 +788,14 @@ private function readRecordDocumentContainer($stream, $pos) $pos += 4; $exObjList['recLen'] -= 4; - $this->arrayHyperlinks[$exHyperlinkId] = array(); + $this->arrayHyperlinks[$exHyperlinkId] = []; // friendlyNameAtom - $friendlyNameAtom = $this->loadRecordHeader($stream, $pos); - if ($friendlyNameAtom['recVer'] == 0x0 && $friendlyNameAtom['recInstance'] == 0x000 && $friendlyNameAtom['recType'] == self::RT_CSTRING && $friendlyNameAtom['recLen'] % 2 == 0) { + $friendlyNameAtom = $this->loadRecordHeader($stream, $pos); + if (0x0 == $friendlyNameAtom['recVer'] && 0x000 == $friendlyNameAtom['recInstance'] && self::RT_CSTRING == $friendlyNameAtom['recType'] && $friendlyNameAtom['recLen'] % 2 == 0) { $pos += 8; $exObjList['recLen'] -= 8; $this->arrayHyperlinks[$exHyperlinkId]['text'] = ''; - for ($inc = 0; $inc < ($friendlyNameAtom['recLen'] / 2); $inc++) { + for ($inc = 0; $inc < ($friendlyNameAtom['recLen'] / 2); ++$inc) { $char = self::getInt2d($stream, $pos); $pos += 2; $exObjList['recLen'] -= 2; @@ -781,12 +803,12 @@ private function readRecordDocumentContainer($stream, $pos) } } // targetAtom - $targetAtom = $this->loadRecordHeader($stream, $pos); - if ($targetAtom['recVer'] == 0x0 && $targetAtom['recInstance'] == 0x001 && $targetAtom['recType'] == self::RT_CSTRING && $targetAtom['recLen'] % 2 == 0) { + $targetAtom = $this->loadRecordHeader($stream, $pos); + if (0x0 == $targetAtom['recVer'] && 0x001 == $targetAtom['recInstance'] && self::RT_CSTRING == $targetAtom['recType'] && $targetAtom['recLen'] % 2 == 0) { $pos += 8; $exObjList['recLen'] -= 8; $this->arrayHyperlinks[$exHyperlinkId]['url'] = ''; - for ($inc = 0; $inc < ($targetAtom['recLen'] / 2); $inc++) { + for ($inc = 0; $inc < ($targetAtom['recLen'] / 2); ++$inc) { $char = self::getInt2d($stream, $pos); $pos += 2; $exObjList['recLen'] -= 2; @@ -794,12 +816,12 @@ private function readRecordDocumentContainer($stream, $pos) } } // locationAtom - $locationAtom = $this->loadRecordHeader($stream, $pos); - if ($locationAtom['recVer'] == 0x0 && $locationAtom['recInstance'] == 0x003 && $locationAtom['recType'] == self::RT_CSTRING && $locationAtom['recLen'] % 2 == 0) { + $locationAtom = $this->loadRecordHeader($stream, $pos); + if (0x0 == $locationAtom['recVer'] && 0x003 == $locationAtom['recInstance'] && self::RT_CSTRING == $locationAtom['recType'] && $locationAtom['recLen'] % 2 == 0) { $pos += 8; $exObjList['recLen'] -= 8; $string = ''; - for ($inc = 0; $inc < ($locationAtom['recLen'] / 2); $inc++) { + for ($inc = 0; $inc < ($locationAtom['recLen'] / 2); ++$inc) { $char = self::getInt2d($stream, $pos); $pos += 2; $exObjList['recLen'] -= 2; @@ -808,35 +830,36 @@ private function readRecordDocumentContainer($stream, $pos) } break; default: - throw new \Exception('Feature not implemented (l.'.__LINE__.' : '.dechex($childRec['recType'].')')); + // var_dump(dechex((int) $childRec['recType'])); + throw new FeatureNotImplementedException(); } } while ($exObjList['recLen'] > 0); } //@link : http://msdn.microsoft.com/en-us/library/dd907813(v=office.12).aspx $documentTextInfo = $this->loadRecordHeader($stream, $pos); - if ($documentTextInfo['recVer'] == 0xF && $documentTextInfo['recInstance'] == 0x000 && $documentTextInfo['recType'] == self::RT_ENVIRONMENT) { + if (0xF == $documentTextInfo['recVer'] && 0x000 == $documentTextInfo['recInstance'] && self::RT_ENVIRONMENT == $documentTextInfo['recType']) { $pos += 8; //@link : http://msdn.microsoft.com/en-us/library/dd952717(v=office.12).aspx $kinsoku = $this->loadRecordHeader($stream, $pos); - if ($kinsoku['recVer'] == 0xF && $kinsoku['recInstance'] == 0x002 && $kinsoku['recType'] == self::RT_KINSOKU) { + if (0xF == $kinsoku['recVer'] && 0x002 == $kinsoku['recInstance'] && self::RT_KINSOKU == $kinsoku['recType']) { $pos += 8; $pos += $kinsoku['recLen']; } //@link : http://msdn.microsoft.com/en-us/library/dd948152(v=office.12).aspx $fontCollection = $this->loadRecordHeader($stream, $pos); - if ($fontCollection['recVer'] == 0xF && $fontCollection['recInstance'] == 0x000 && $fontCollection['recType'] == self::RT_FONTCOLLECTION) { + if (0xF == $fontCollection['recVer'] && 0x000 == $fontCollection['recInstance'] && self::RT_FONTCOLLECTION == $fontCollection['recType']) { $pos += 8; do { $fontEntityAtom = $this->loadRecordHeader($stream, $pos); $pos += 8; $fontCollection['recLen'] -= 8; - if ($fontEntityAtom['recVer'] != 0x0 || $fontEntityAtom['recInstance'] > 128 || $fontEntityAtom['recType'] != self::RT_FONTENTITYATOM) { - throw new \Exception('File PowerPoint 97 in error (Location : RTDocument > RT_Environment > RT_FontCollection > RT_FontEntityAtom).'); + if (0x0 != $fontEntityAtom['recVer'] || $fontEntityAtom['recInstance'] > 128 || self::RT_FONTENTITYATOM != $fontEntityAtom['recType']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : RTDocument > RT_Environment > RT_FontCollection > RT_FontEntityAtom'); } $string = ''; - for ($inc = 0; $inc < 32; $inc++) { + for ($inc = 0; $inc < 32; ++$inc) { $char = self::getInt2d($stream, $pos); $pos += 2; $fontCollection['recLen'] -= 2; @@ -845,28 +868,28 @@ private function readRecordDocumentContainer($stream, $pos) $this->arrayFonts[] = $string; // lfCharSet (1 byte) - $pos += 1; - $fontCollection['recLen'] -= 1; + ++$pos; + --$fontCollection['recLen']; // fEmbedSubsetted (1 bit) // unused (7 bits) - $pos += 1; - $fontCollection['recLen'] -= 1; + ++$pos; + --$fontCollection['recLen']; // rasterFontType (1 bit) // deviceFontType (1 bit) // truetypeFontType (1 bit) // fNoFontSubstitution (1 bit) // reserved (4 bits) - $pos += 1; - $fontCollection['recLen'] -= 1; + ++$pos; + --$fontCollection['recLen']; // lfPitchAndFamily (1 byte) - $pos += 1; - $fontCollection['recLen'] -= 1; + ++$pos; + --$fontCollection['recLen']; $fontEmbedData1 = $this->loadRecordHeader($stream, $pos); - if ($fontEmbedData1['recVer'] == 0x0 && $fontEmbedData1['recInstance'] >= 0x000 && $fontEmbedData1['recInstance'] <= 0x003 && $fontEmbedData1['recType'] == self::RT_FONTEMBEDDATABLOB) { + if (0x0 == $fontEmbedData1['recVer'] && $fontEmbedData1['recInstance'] >= 0x000 && $fontEmbedData1['recInstance'] <= 0x003 && self::RT_FONTEMBEDDATABLOB == $fontEmbedData1['recType']) { $pos += 8; $fontCollection['recLen'] -= 8; $pos += $fontEmbedData1['recLen']; @@ -874,7 +897,7 @@ private function readRecordDocumentContainer($stream, $pos) } $fontEmbedData2 = $this->loadRecordHeader($stream, $pos); - if ($fontEmbedData2['recVer'] == 0x0 && $fontEmbedData2['recInstance'] >= 0x000 && $fontEmbedData2['recInstance'] <= 0x003 && $fontEmbedData2['recType'] == self::RT_FONTEMBEDDATABLOB) { + if (0x0 == $fontEmbedData2['recVer'] && $fontEmbedData2['recInstance'] >= 0x000 && $fontEmbedData2['recInstance'] <= 0x003 && self::RT_FONTEMBEDDATABLOB == $fontEmbedData2['recType']) { $pos += 8; $fontCollection['recLen'] -= 8; $pos += $fontEmbedData2['recLen']; @@ -882,7 +905,7 @@ private function readRecordDocumentContainer($stream, $pos) } $fontEmbedData3 = $this->loadRecordHeader($stream, $pos); - if ($fontEmbedData3['recVer'] == 0x0 && $fontEmbedData3['recInstance'] >= 0x000 && $fontEmbedData3['recInstance'] <= 0x003 && $fontEmbedData3['recType'] == self::RT_FONTEMBEDDATABLOB) { + if (0x0 == $fontEmbedData3['recVer'] && $fontEmbedData3['recInstance'] >= 0x000 && $fontEmbedData3['recInstance'] <= 0x003 && self::RT_FONTEMBEDDATABLOB == $fontEmbedData3['recType']) { $pos += 8; $fontCollection['recLen'] -= 8; $pos += $fontEmbedData3['recLen']; @@ -890,7 +913,7 @@ private function readRecordDocumentContainer($stream, $pos) } $fontEmbedData4 = $this->loadRecordHeader($stream, $pos); - if ($fontEmbedData4['recVer'] == 0x0 && $fontEmbedData4['recInstance'] >= 0x000 && $fontEmbedData4['recInstance'] <= 0x003 && $fontEmbedData4['recType'] == self::RT_FONTEMBEDDATABLOB) { + if (0x0 == $fontEmbedData4['recVer'] && $fontEmbedData4['recInstance'] >= 0x000 && $fontEmbedData4['recInstance'] <= 0x003 && self::RT_FONTEMBEDDATABLOB == $fontEmbedData4['recType']) { $pos += 8; $fontCollection['recLen'] -= 8; $pos += $fontEmbedData4['recLen']; @@ -900,81 +923,81 @@ private function readRecordDocumentContainer($stream, $pos) } $textCFDefaultsAtom = $this->loadRecordHeader($stream, $pos); - if ($textCFDefaultsAtom['recVer'] == 0x0 && $textCFDefaultsAtom['recInstance'] == 0x000 && $textCFDefaultsAtom['recType'] == self::RT_TEXTCHARFORMATEXCEPTIONATOM) { + if (0x0 == $textCFDefaultsAtom['recVer'] && 0x000 == $textCFDefaultsAtom['recInstance'] && self::RT_TEXTCHARFORMATEXCEPTIONATOM == $textCFDefaultsAtom['recType']) { $pos += 8; $pos += $textCFDefaultsAtom['recLen']; } $textPFDefaultsAtom = $this->loadRecordHeader($stream, $pos); - if ($textPFDefaultsAtom['recVer'] == 0x0 && $textPFDefaultsAtom['recInstance'] == 0x000 && $textPFDefaultsAtom['recType'] == self::RT_TEXTPARAGRAPHFORMATEXCEPTIONATOM) { + if (0x0 == $textPFDefaultsAtom['recVer'] && 0x000 == $textPFDefaultsAtom['recInstance'] && self::RT_TEXTPARAGRAPHFORMATEXCEPTIONATOM == $textPFDefaultsAtom['recType']) { $pos += 8; $pos += $textPFDefaultsAtom['recLen']; } $defaultRulerAtom = $this->loadRecordHeader($stream, $pos); - if ($defaultRulerAtom['recVer'] == 0x0 && $defaultRulerAtom['recInstance'] == 0x000 && $defaultRulerAtom['recType'] == self::RT_DEFAULTRULERATOM) { + if (0x0 == $defaultRulerAtom['recVer'] && 0x000 == $defaultRulerAtom['recInstance'] && self::RT_DEFAULTRULERATOM == $defaultRulerAtom['recType']) { $pos += 8; $pos += $defaultRulerAtom['recLen']; } $textSIDefaultsAtom = $this->loadRecordHeader($stream, $pos); - if ($textSIDefaultsAtom['recVer'] == 0x0 && $textSIDefaultsAtom['recInstance'] == 0x000 && $textSIDefaultsAtom['recType'] == self::RT_TEXTSPECIALINFODEFAULTATOM) { + if (0x0 == $textSIDefaultsAtom['recVer'] && 0x000 == $textSIDefaultsAtom['recInstance'] && self::RT_TEXTSPECIALINFODEFAULTATOM == $textSIDefaultsAtom['recType']) { $pos += 8; $pos += $textSIDefaultsAtom['recLen']; } $textMasterStyleAtom = $this->loadRecordHeader($stream, $pos); - if ($textMasterStyleAtom['recVer'] == 0x0 && $textMasterStyleAtom['recType'] == self::RT_TEXTMASTERSTYLEATOM) { + if (0x0 == $textMasterStyleAtom['recVer'] && self::RT_TEXTMASTERSTYLEATOM == $textMasterStyleAtom['recType']) { $pos += 8; $pos += $textMasterStyleAtom['recLen']; } } $soundCollection = $this->loadRecordHeader($stream, $pos); - if ($soundCollection['recVer'] == 0xF && $soundCollection['recInstance'] == 0x005 && $soundCollection['recType'] == self::RT_SOUNDCOLLECTION) { + if (0xF == $soundCollection['recVer'] && 0x005 == $soundCollection['recInstance'] && self::RT_SOUNDCOLLECTION == $soundCollection['recType']) { $pos += 8; $pos += $soundCollection['recLen']; } $drawingGroup = $this->loadRecordHeader($stream, $pos); - if ($drawingGroup['recVer'] == 0xF && $drawingGroup['recInstance'] == 0x000 && $drawingGroup['recType'] == self::RT_DRAWINGGROUP) { + if (0xF == $drawingGroup['recVer'] && 0x000 == $drawingGroup['recInstance'] && self::RT_DRAWINGGROUP == $drawingGroup['recType']) { $drawing = $this->readRecordDrawingGroupContainer($stream, $pos); $pos += 8; $pos += $drawing['length']; } $masterList = $this->loadRecordHeader($stream, $pos); - if ($masterList['recVer'] == 0xF && $masterList['recInstance'] == 0x001 && $masterList['recType'] == self::RT_SLIDELISTWITHTEXT) { + if (0xF == $masterList['recVer'] && 0x001 == $masterList['recInstance'] && self::RT_SLIDELISTWITHTEXT == $masterList['recType']) { $pos += 8; $pos += $masterList['recLen']; } $docInfoList = $this->loadRecordHeader($stream, $pos); - if ($docInfoList['recVer'] == 0xF && $docInfoList['recInstance'] == 0x000 && $docInfoList['recType'] == self::RT_LIST) { + if (0xF == $docInfoList['recVer'] && 0x000 == $docInfoList['recInstance'] && self::RT_LIST == $docInfoList['recType']) { $pos += 8; $pos += $docInfoList['recLen']; } $slideHF = $this->loadRecordHeader($stream, $pos); - if ($slideHF['recVer'] == 0xF && $slideHF['recInstance'] == 0x003 && $slideHF['recType'] == self::RT_HEADERSFOOTERS) { + if (0xF == $slideHF['recVer'] && 0x003 == $slideHF['recInstance'] && self::RT_HEADERSFOOTERS == $slideHF['recType']) { $pos += 8; $pos += $slideHF['recLen']; } $notesHF = $this->loadRecordHeader($stream, $pos); - if ($notesHF['recVer'] == 0xF && $notesHF['recInstance'] == 0x004 && $notesHF['recType'] == self::RT_HEADERSFOOTERS) { + if (0xF == $notesHF['recVer'] && 0x004 == $notesHF['recInstance'] && self::RT_HEADERSFOOTERS == $notesHF['recType']) { $pos += 8; $pos += $notesHF['recLen']; } // SlideListWithTextContainer $slideList = $this->loadRecordHeader($stream, $pos); - if ($slideList['recVer'] == 0xF && $slideList['recInstance'] == 0x000 && $slideList['recType'] == self::RT_SLIDELISTWITHTEXT) { + if (0xF == $slideList['recVer'] && 0x000 == $slideList['recInstance'] && self::RT_SLIDELISTWITHTEXT == $slideList['recType']) { $pos += 8; do { // SlideListWithTextSubContainerOrAtom $rhSlideList = $this->loadRecordHeader($stream, $pos); - if ($rhSlideList['recVer'] == 0x0 && $rhSlideList['recInstance'] == 0x000 && $rhSlideList['recType'] == self::RT_SLIDEPERSISTATOM && $rhSlideList['recLen'] == 0x00000014) { + if (0x0 == $rhSlideList['recVer'] && 0x000 == $rhSlideList['recInstance'] && self::RT_SLIDEPERSISTATOM == $rhSlideList['recType'] && 0x00000014 == $rhSlideList['recLen']) { $pos += 8; $slideList['recLen'] -= 8; // persistIdRef @@ -988,7 +1011,7 @@ private function readRecordDocumentContainer($stream, $pos) $slideList['recLen'] -= 4; // slideId $slideId = self::getInt4d($stream, $pos); - if ($slideId == -2147483648) { + if (-2147483648 == $slideId) { $slideId = 0; } if ($slideId > 0) { @@ -1006,59 +1029,63 @@ private function readRecordDocumentContainer($stream, $pos) /** * An atom record that specifies information about a slide. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx */ - private function readRecordDrawingContainer($stream, $pos) + private function readRecordDrawingContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_DRAWING) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_DRAWING == $data['recType']) { // Record Header $arrayReturn['length'] += 8; $officeArtDg = $this->readRecordOfficeArtDgContainer($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $officeArtDg['length']; } + return $arrayReturn; } - private function readRecordDrawingGroupContainer($stream, $pos) + /** + * @return array + */ + private function readRecordDrawingGroupContainer(string $stream, int $pos): array { - - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_DRAWINGGROUP) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_DRAWINGGROUP == $data['recType']) { // Record Header $arrayReturn['length'] += 8; $arrayReturn['length'] += $data['recLen']; } + return $arrayReturn; } /** * An atom record that specifies a reference to an external object. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd910388(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd910388(v=office.12).aspx */ - private function readRecordExObjRefAtom($stream, $pos) + private function readRecordExObjRefAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_EXTERNALOBJECTREFATOM && $data['recLen'] == 0x00000004) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_EXTERNALOBJECTREFATOM == $data['recType'] && 0x00000004 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -1070,19 +1097,19 @@ private function readRecordExObjRefAtom($stream, $pos) /** * An atom record that specifies a type of action to be performed. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd953300(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd953300(v=office.12).aspx */ - private function readRecordInteractiveInfoAtom($stream, $pos) + private function readRecordInteractiveInfoAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_INTERACTIVEINFOATOM && $data['recLen'] == 0x00000010) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_INTERACTIVEINFOATOM == $data['recType'] && 0x00000010 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // soundIdRef @@ -1091,19 +1118,19 @@ private function readRecordInteractiveInfoAtom($stream, $pos) $arrayReturn['exHyperlinkIdRef'] = self::getInt4d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; // action - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; // oleVerb - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; // jump - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; // fAnimated (1 bit) // fStopSound (1 bit) // fCustomShowReturn (1 bit) // fVisited (1 bit) // reserved (4 bits) - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; // hyperlinkType - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; // unused $arrayReturn['length'] += 3; } @@ -1113,19 +1140,19 @@ private function readRecordInteractiveInfoAtom($stream, $pos) /** * An atom record that specifies the name of a macro, a file name, or a named show. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd925121(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd925121(v=office.12).aspx */ - private function readRecordMacroNameAtom($stream, $pos) + private function readRecordMacroNameAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x002 && $data['recType'] == self::RT_CSTRING && $data['recLen'] % 2 == 0) { + if (0x0 == $data['recVer'] && 0x002 == $data['recInstance'] && self::RT_CSTRING == $data['recType'] && $data['recLen'] % 2 == 0) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -1137,19 +1164,19 @@ private function readRecordMacroNameAtom($stream, $pos) /** * A container record that specifies what actions to perform when interacting with an object by means of a mouse click. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd952348(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd952348(v=office.12).aspx */ - private function readRecordMouseClickInteractiveInfoContainer($stream, $pos) + private function readRecordMouseClickInteractiveInfoContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_INTERACTIVEINFO) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_INTERACTIVEINFO == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // interactiveInfoAtom @@ -1168,25 +1195,26 @@ private function readRecordMouseClickInteractiveInfoContainer($stream, $pos) /** * A container record that specifies what actions to perform when interacting with an object by moving the mouse cursor over it. - * @param string $stream - * @param integer $pos - * @return array - * @throws \Exception - * @link https://msdn.microsoft.com/en-us/library/dd925811(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd925811(v=office.12).aspx */ - private function readRecordMouseOverInteractiveInfoContainer($stream, $pos) + private function readRecordMouseOverInteractiveInfoContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x001 && $data['recType'] == self::RT_INTERACTIVEINFO) { + if (0xF == $data['recVer'] && 0x001 == $data['recInstance'] && self::RT_INTERACTIVEINFO == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // interactiveInfoAtom // macroNameAtom - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + throw new FeatureNotImplementedException(); } return $arrayReturn; @@ -1194,21 +1222,22 @@ private function readRecordMouseOverInteractiveInfoContainer($stream, $pos) /** * The OfficeArtBlip record specifies BLIP file data. - * @param string $stream - * @param integer $pos - * @return array - * @throws \Exception - * @link https://msdn.microsoft.com/en-us/library/dd910081(v=office.12).aspx + * + * @return array{'length': int, 'picture': null|string} + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd910081(v=office.12).aspx */ - private function readRecordOfficeArtBlip($stream, $pos) + private function readRecordOfficeArtBlip(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - 'picture' => null - ); + 'picture' => null, + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && ($data['recType'] >= 0xF018 && $data['recType'] <= 0xF117)) { + if (0x0 == $data['recVer'] && ($data['recType'] >= 0xF018 && $data['recType'] <= 0xF117)) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -1218,20 +1247,21 @@ private function readRecordOfficeArtBlip($stream, $pos) // rgbUid1 $arrayReturn['length'] += 16; $data['recLen'] -= 16; - if ($data['recInstance'] == 0x6E1) { + if (0x6E1 == $data['recInstance']) { // rgbUid2 $arrayReturn['length'] += 16; $data['recLen'] -= 16; } // tag - $arrayReturn['length'] += 1; - $data['recLen'] -= 1; + ++$arrayReturn['length']; + --$data['recLen']; // BLIPFileData $arrayReturn['picture'] = substr($this->streamPictures, $pos + $arrayReturn['length'], $data['recLen']); $arrayReturn['length'] += $data['recLen']; break; default: - throw new \Exception('Feature not implemented (l.'.__LINE__.' : '.dechex($data['recType'].')')); + // var_dump(dechex((int) $data['recType'])) + throw new FeatureNotImplementedException(); } } @@ -1240,19 +1270,19 @@ private function readRecordOfficeArtBlip($stream, $pos) /** * The OfficeArtChildAnchor record specifies four signed integers that specify the anchor for the shape that contains this record. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd922720(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd922720(v=office.12).aspx */ - private function readRecordOfficeArtChildAnchor($stream, $pos) + private function readRecordOfficeArtChildAnchor(string $stream, int $pos) { - $arrayReturn = array( - 'length' => 0 - ); + $arrayReturn = [ + 'length' => 0, + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF00F && $data['recLen'] == 0x00000010) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF00F == $data['recType'] && 0x00000010 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -1271,20 +1301,21 @@ private function readRecordOfficeArtChildAnchor($stream, $pos) /** * An atom record that specifies the location of a shape. - * @param string $stream - * @param integer $pos - * @return array - * @throws \Exception - * @link https://msdn.microsoft.com/en-us/library/dd922797(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd922797(v=office.12).aspx */ - private function readRecordOfficeArtClientAnchor($stream, $pos) + private function readRecordOfficeArtClientAnchor(string $stream, int $pos) { - $arrayReturn = array( - 'length' => 0 - ); + $arrayReturn = [ + 'length' => 0, + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF010 && ($data['recLen'] == 0x00000008 || $data['recLen'] == 0x00000010)) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF010 == $data['recType'] && (0x00000008 == $data['recLen'] || 0x00000010 == $data['recLen'])) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -1301,7 +1332,8 @@ private function readRecordOfficeArtClientAnchor($stream, $pos) $pos += 8; break; case 0x00000010: - throw new \Exception('PowerPoint97 Reader : record OfficeArtClientAnchor (0x00000010)'); + // record OfficeArtClientAnchor (0x00000010) + throw new FeatureNotImplementedException(); } } @@ -1310,45 +1342,47 @@ private function readRecordOfficeArtClientAnchor($stream, $pos) /** * A container record that specifies text related data for a shape. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd910958(v=office.12).aspx + * + * @return array{'length': int, 'text': string, 'numParts': int, 'numTexts': int, 'hyperlink': array>, 'part': array} + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd910958(v=office.12).aspx */ - private function readRecordOfficeArtClientTextbox($stream, $pos) + private function readRecordOfficeArtClientTextbox(string $stream, int $pos) { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, 'text' => '', 'numParts' => 0, 'numTexts' => 0, - 'hyperlink' => array(), - ); + 'hyperlink' => [], + ]; $data = $this->loadRecordHeader($stream, $pos); // recVer 0xF // Doc : 0x0 https://msdn.microsoft.com/en-us/library/dd910958(v=office.12).aspx // Sample : 0xF https://msdn.microsoft.com/en-us/library/dd953497(v=office.12).aspx - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF00D) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF00D == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Datas $strLen = 0; do { $rhChild = $this->loadRecordHeader($stream, $pos + $arrayReturn['length']); - /** + /* * @link : https://msdn.microsoft.com/en-us/library/dd947039(v=office.12).aspx */ // echo dechex($rhChild['recType']).'-'.$rhChild['recType'].EOL; switch ($rhChild['recType']) { case self::RT_INTERACTIVEINFO: //@link : http://msdn.microsoft.com/en-us/library/dd948623(v=office.12).aspx - if ($rhChild['recInstance'] == 0x0000) { + if (0x0000 == $rhChild['recInstance']) { $mouseClickInfo = $this->readRecordMouseClickInteractiveInfoContainer($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $mouseClickInfo['length']; $arrayReturn['hyperlink'][]['id'] = $mouseClickInfo['exHyperlinkIdRef']; } - if ($rhChild['recInstance'] == 0x0001) { + if (0x0001 == $rhChild['recInstance']) { $mouseOverInfo = $this->readRecordMouseOverInteractiveInfoContainer($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $mouseOverInfo['length']; } @@ -1360,8 +1394,8 @@ private function readRecordOfficeArtClientTextbox($stream, $pos) $strLenRT = $strLen + 1; do { $strucTextPFRun = $this->readStructureTextPFRun($stream, $pos + $arrayReturn['length'], $strLenRT); - $arrayReturn['numTexts']++; - $arrayReturn['text'.$arrayReturn['numTexts']] = $strucTextPFRun; + ++$arrayReturn['numTexts']; + $arrayReturn['text' . $arrayReturn['numTexts']] = $strucTextPFRun; if (isset($strucTextPFRun['alignH'])) { $arrayReturn['alignH'] = $strucTextPFRun['alignH']; } @@ -1372,8 +1406,8 @@ private function readRecordOfficeArtClientTextbox($stream, $pos) $strLenRT = $strLen + 1; do { $strucTextCFRun = $this->readStructureTextCFRun($stream, $pos + $arrayReturn['length'], $strLenRT); - $arrayReturn['numParts']++; - $arrayReturn['part'.$arrayReturn['numParts']] = $strucTextCFRun; + ++$arrayReturn['numParts']; + $arrayReturn['part' . $arrayReturn['numParts']] = $strucTextCFRun; $strLenRT = $strucTextCFRun['strLenRT']; $arrayReturn['length'] += $strucTextCFRun['length']; } while ($strLenRT > 0); @@ -1381,23 +1415,23 @@ private function readRecordOfficeArtClientTextbox($stream, $pos) case self::RT_TEXTBYTESATOM: $arrayReturn['length'] += 8; // @link : https://msdn.microsoft.com/en-us/library/dd947905(v=office.12).aspx - $strLen = (int)$rhChild['recLen']; - for ($inc = 0; $inc < $strLen; $inc++) { + $strLen = (int) $rhChild['recLen']; + for ($inc = 0; $inc < $strLen; ++$inc) { $char = self::getInt1d($stream, $pos + $arrayReturn['length']); - if ($char == 0x0B) { + if (0x0B == $char) { $char = 0x20; } $arrayReturn['text'] .= Text::chr($char); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; } break; case self::RT_TEXTCHARSATOM: $arrayReturn['length'] += 8; // @link : http://msdn.microsoft.com/en-us/library/dd772921(v=office.12).aspx - $strLen = (int)($rhChild['recLen']/2); - for ($inc = 0; $inc < $strLen; $inc++) { + $strLen = (int) ($rhChild['recLen'] / 2); + for ($inc = 0; $inc < $strLen; ++$inc) { $char = self::getInt2d($stream, $pos + $arrayReturn['length']); - if ($char == 0x0B) { + if (0x0B == $char) { $char = 0x20; } $arrayReturn['text'] .= Text::chr($char); @@ -1413,16 +1447,16 @@ private function readRecordOfficeArtClientTextbox($stream, $pos) case self::RT_TEXTINTERACTIVEINFOATOM: $arrayReturn['length'] += 8; //@link : http://msdn.microsoft.com/en-us/library/dd947973(v=office.12).aspx - if ($rhChild['recInstance'] == 0x0000) { + if (0x0000 == $rhChild['recInstance']) { //@todo : MouseClickTextInteractiveInfoAtom - $arrayReturn['hyperlink'][count($arrayReturn['hyperlink']) - 1]['start'] = self::getInt4d($stream, $pos + + $arrayReturn['length']); + $arrayReturn['hyperlink'][count($arrayReturn['hyperlink']) - 1]['start'] = self::getInt4d($stream, $pos + +$arrayReturn['length']); $arrayReturn['length'] += 4; - $arrayReturn['hyperlink'][count($arrayReturn['hyperlink']) - 1]['end'] = self::getInt4d($stream, $pos + + $arrayReturn['length']); + $arrayReturn['hyperlink'][count($arrayReturn['hyperlink']) - 1]['end'] = self::getInt4d($stream, $pos + +$arrayReturn['length']); $arrayReturn['length'] += 4; } - if ($rhChild['recInstance'] == 0x0001) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (0x0001 == $rhChild['recInstance']) { + throw new FeatureNotImplementedException(); } break; case self::RT_TEXTSPECIALINFOATOM: @@ -1448,29 +1482,31 @@ private function readRecordOfficeArtClientTextbox($stream, $pos) default: $arrayReturn['length'] += 8; $arrayReturn['length'] += $rhChild['recLen']; - // throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($rhChild['recType']).')'); } } while (($data['recLen'] - $arrayReturn['length']) > 0); } + return $arrayReturn; } /** * The OfficeArtSpContainer record specifies a shape container. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd943794(v=office.12).aspx + * + * @return array{'length': int, 'shape': null|AbstractShape} + * + * @throws InvalidFileFormatException + * + * @see https://msdn.microsoft.com/en-us/library/dd943794(v=office.12).aspx */ - private function readRecordOfficeArtSpContainer($stream, $pos) + private function readRecordOfficeArtSpContainer(string $stream, int $pos) { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, 'shape' => null, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF004) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF004 == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // shapeGroup @@ -1479,12 +1515,12 @@ private function readRecordOfficeArtSpContainer($stream, $pos) // shapeProp $shapeProp = $this->readRecordOfficeArtFSP($stream, $pos + $arrayReturn['length']); - if ($shapeProp['length'] == 0) { - throw new \Exception('PowerPoint97 Reader : record OfficeArtFSP'); + if (0 == $shapeProp['length']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class); } $arrayReturn['length'] += $shapeProp['length']; - if ($shapeProp['fDeleted'] == 0x1 && $shapeProp['fChild'] == 0x0) { + if (0x1 == $shapeProp['fDeleted'] && 0x0 == $shapeProp['fChild']) { // deletedShape $deletedShape = $this->readRecordOfficeArtFPSPL($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $deletedShape['length']; @@ -1519,20 +1555,20 @@ private function readRecordOfficeArtSpContainer($stream, $pos) $arrayReturn['length'] += $clientTextbox['length']; // shapeSecondaryOptions2 - if ($shpSecondaryOptions1['length'] == 0) { + if (0 == $shpSecondaryOptions1['length']) { $shpSecondaryOptions2 = $this->readRecordOfficeArtSecondaryFOPT($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $shpSecondaryOptions2['length']; } // shapeTertiaryOptions2 - if ($shpTertiaryOptions1['length'] == 0) { + if (0 == $shpTertiaryOptions1['length']) { $shpTertiaryOptions2 = $this->readRecordOfficeArtTertiaryFOPT($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $shpTertiaryOptions2['length']; } // Core : Shape // Informations about group are not defined - $arrayDimensions = array(); + $arrayDimensions = []; $bIsGroup = false; if (is_object($this->oCurrentGroup)) { if (!$this->bFirstShapeGroup) { @@ -1576,39 +1612,40 @@ private function readRecordOfficeArtSpContainer($stream, $pos) $start = 0; $lastLevel = -1; $lastMarginLeft = 0; - for ($inc = 1; $inc <= $clientTextbox['numParts']; $inc++) { - if ($clientTextbox['numParts'] == $clientTextbox['numTexts'] && isset($clientTextbox['text'.$inc])) { - if (isset($clientTextbox['text'.$inc]['bulletChar'])) { + /* @phpstan-ignore-next-line */ + for ($inc = 1; $inc <= $clientTextbox['numParts']; ++$inc) { + if ($clientTextbox['numParts'] == $clientTextbox['numTexts'] && isset($clientTextbox['text' . $inc])) { + if (isset($clientTextbox['text' . $inc]['bulletChar'])) { $arrayReturn['shape']->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); - $arrayReturn['shape']->getActiveParagraph()->getBulletStyle()->setBulletChar($clientTextbox['text'.$inc]['bulletChar']); + $arrayReturn['shape']->getActiveParagraph()->getBulletStyle()->setBulletChar($clientTextbox['text' . $inc]['bulletChar']); } // Indent $indent = 0; - if (isset($clientTextbox['text'.$inc]['indent'])) { - $indent = $clientTextbox['text'.$inc]['indent']; + if (isset($clientTextbox['text' . $inc]['indent'])) { + $indent = $clientTextbox['text' . $inc]['indent']; } - if (isset($clientTextbox['text'.$inc]['leftMargin'])) { - if ($lastMarginLeft > $clientTextbox['text'.$inc]['leftMargin']) { - $lastLevel--; + if (isset($clientTextbox['text' . $inc]['leftMargin'])) { + if ($lastMarginLeft > $clientTextbox['text' . $inc]['leftMargin']) { + --$lastLevel; } - if ($lastMarginLeft < $clientTextbox['text'.$inc]['leftMargin']) { - $lastLevel++; + if ($lastMarginLeft < $clientTextbox['text' . $inc]['leftMargin']) { + ++$lastLevel; } $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setLevel($lastLevel); - $lastMarginLeft = $clientTextbox['text'.$inc]['leftMargin']; + $lastMarginLeft = $clientTextbox['text' . $inc]['leftMargin']; - $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setMarginLeft($clientTextbox['text'.$inc]['leftMargin']); - $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setIndent($indent - $clientTextbox['text'.$inc]['leftMargin']); + $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setMarginLeft($clientTextbox['text' . $inc]['leftMargin']); + $arrayReturn['shape']->getActiveParagraph()->getAlignment()->setIndent($indent - $clientTextbox['text' . $inc]['leftMargin']); } } // Texte - $sText = substr(isset($clientTextbox['text']) ? $clientTextbox['text'] : '', $start, $clientTextbox['part'.$inc]['partLength']); + $sText = substr(isset($clientTextbox['text']) ? $clientTextbox['text'] : '', $start, $clientTextbox['part' . $inc]['partLength']); $sHyperlinkURL = ''; if (empty($sText)) { // Is there a hyperlink ? - if (isset($clientTextbox['hyperlink']) && is_array($clientTextbox['hyperlink']) && !empty($clientTextbox['hyperlink'])) { + if (!empty($clientTextbox['hyperlink'])) { foreach ($clientTextbox['hyperlink'] as $itmHyperlink) { - if ($itmHyperlink['start'] == $start && ($itmHyperlink['end'] - $itmHyperlink['start']) == $clientTextbox['part'.$inc]['partLength']) { + if ($itmHyperlink['start'] == $start && ($itmHyperlink['end'] - $itmHyperlink['start']) == $clientTextbox['part' . $inc]['partLength']) { $sText = $this->arrayHyperlinks[$itmHyperlink['id']]['text']; $sHyperlinkURL = $this->arrayHyperlinks[$itmHyperlink['id']]['url']; break; @@ -1618,36 +1655,38 @@ private function readRecordOfficeArtSpContainer($stream, $pos) } // New paragraph $bCreateParagraph = false; - if (strpos($sText, "\r") !== false) { + if (false !== strpos($sText, "\r")) { $bCreateParagraph = true; $sText = str_replace("\r", '', $sText); } // TextRun $txtRun = $arrayReturn['shape']->createTextRun($sText); - if (isset($clientTextbox['part'.$inc]['bold'])) { - $txtRun->getFont()->setBold($clientTextbox['part'.$inc]['bold']); + if (isset($clientTextbox['part' . $inc]['bold'])) { + $txtRun->getFont()->setBold($clientTextbox['part' . $inc]['bold']); } - if (isset($clientTextbox['part'.$inc]['italic'])) { - $txtRun->getFont()->setItalic($clientTextbox['part'.$inc]['italic']); + if (isset($clientTextbox['part' . $inc]['italic'])) { + $txtRun->getFont()->setItalic($clientTextbox['part' . $inc]['italic']); } - if (isset($clientTextbox['part'.$inc]['underline'])) { - $txtRun->getFont()->setUnderline($clientTextbox['part'.$inc]['underline']); + if (isset($clientTextbox['part' . $inc]['underline'])) { + $txtRun->getFont()->setUnderline( + $clientTextbox['part' . $inc]['underline'] ? Font::UNDERLINE_SINGLE : Font::UNDERLINE_NONE + ); } - if (isset($clientTextbox['part'.$inc]['fontName'])) { - $txtRun->getFont()->setName($clientTextbox['part'.$inc]['fontName']); + if (isset($clientTextbox['part' . $inc]['fontName'])) { + $txtRun->getFont()->setName($clientTextbox['part' . $inc]['fontName']); } - if (isset($clientTextbox['part'.$inc]['fontSize'])) { - $txtRun->getFont()->setSize($clientTextbox['part'.$inc]['fontSize']); + if (isset($clientTextbox['part' . $inc]['fontSize'])) { + $txtRun->getFont()->setSize($clientTextbox['part' . $inc]['fontSize']); } - if (isset($clientTextbox['part'.$inc]['color'])) { - $txtRun->getFont()->setColor($clientTextbox['part'.$inc]['color']); + if (isset($clientTextbox['part' . $inc]['color'])) { + $txtRun->getFont()->setColor($clientTextbox['part' . $inc]['color']); } // Hyperlink if (!empty($sHyperlinkURL)) { $txtRun->setHyperlink(new Hyperlink($sHyperlinkURL)); } - $start += $clientTextbox['part'.$inc]['partLength']; + $start += $clientTextbox['part' . $inc]['partLength']; if ($bCreateParagraph) { $arrayReturn['shape']->createParagraph(); } @@ -1669,10 +1708,10 @@ private function readRecordOfficeArtSpContainer($stream, $pos) $arrayReturn['shape']->setRotation($rotation); } // Shadow - if (isset($shpPrimaryOptions['shadowOffsetX']) && isset($shpPrimaryOptions['shadowOffsetY'])) { + if (isset($shpPrimaryOptions['shadowOffsetX'], $shpPrimaryOptions['shadowOffsetY'])) { $shadowOffsetX = $shpPrimaryOptions['shadowOffsetX']; $shadowOffsetY = $shpPrimaryOptions['shadowOffsetY']; - if ($shadowOffsetX != 0 && $shadowOffsetX != 0) { + if (0 != $shadowOffsetX && 0 != $shadowOffsetX) { $arrayReturn['shape']->getShadow()->setVisible(true); if ($shadowOffsetX > 0 && $shadowOffsetX == $shadowOffsetY) { $arrayReturn['shape']->getShadow()->setDistance($shadowOffsetX)->setDirection(45); @@ -1682,7 +1721,7 @@ private function readRecordOfficeArtSpContainer($stream, $pos) // Specific Line if ($arrayReturn['shape'] instanceof Line) { if (isset($shpPrimaryOptions['lineColor'])) { - $arrayReturn['shape']->getBorder()->getColor()->setARGB('FF'.$shpPrimaryOptions['lineColor']); + $arrayReturn['shape']->getBorder()->getColor()->setARGB('FF' . $shpPrimaryOptions['lineColor']); } if (isset($shpPrimaryOptions['lineWidth'])) { $arrayReturn['shape']->setHeight($shpPrimaryOptions['lineWidth']); @@ -1718,26 +1757,31 @@ private function readRecordOfficeArtSpContainer($stream, $pos) /** * The OfficeArtSpgrContainer record specifies a container for groups of shapes. + * * @param string $stream - * @param integer $pos - * @param boolean $bInGroup - * @return array - * @link : https://msdn.microsoft.com/en-us/library/dd910416(v=office.12).aspx + * @param int $pos + * @param bool $bInGroup + * + * @return array + * + * @throws InvalidFileFormatException + * + * @see : https://msdn.microsoft.com/en-us/library/dd910416(v=office.12).aspx */ private function readRecordOfficeArtSpgrContainer($stream, $pos, $bInGroup = false) { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF003) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF003 == $data['recType']) { $arrayReturn['length'] += 8; do { $rhFileBlock = $this->loadRecordHeader($stream, $pos + $arrayReturn['length']); - if (!($rhFileBlock['recVer'] == 0xF && $rhFileBlock['recInstance'] == 0x0000 && ($rhFileBlock['recType'] == 0xF003 || $rhFileBlock['recType'] == 0xF004))) { - throw new \Exception('PowerPoint97 Reader : readRecordOfficeArtSpgrContainer.'); + if (!(0xF == $rhFileBlock['recVer'] && 0x0000 == $rhFileBlock['recInstance'] && (0xF003 == $rhFileBlock['recType'] || 0xF004 == $rhFileBlock['recType']))) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class); } switch ($rhFileBlock['recType']) { @@ -1767,7 +1811,7 @@ private function readRecordOfficeArtSpgrContainer($stream, $pos, $bInGroup = fal $arrayIdxSlide = array_flip($this->arrayNotes); if ($this->currentNote > 0 && isset($arrayIdxSlide[$this->currentNote])) { $oSlide = $this->oPhpPresentation->getSlide($arrayIdxSlide[$this->currentNote]); - if ($oSlide->getNote()->getShapeCollection()->count() == 0) { + if (0 == $oSlide->getNote()->getShapeCollection()->count()) { $oSlide->getNote()->addShape($fileBlock['shape']); } } @@ -1786,39 +1830,42 @@ private function readRecordOfficeArtSpgrContainer($stream, $pos, $bInGroup = fal } } while ($data['recLen'] > 0); } + return $arrayReturn; } /** * The OfficeArtTertiaryFOPT record specifies a table of OfficeArtRGFOPTE records,. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd950206(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd950206(v=office.12).aspx */ - private function readRecordOfficeArtTertiaryFOPT($stream, $pos) + private function readRecordOfficeArtTertiaryFOPT(string $stream, int $pos) { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x3 && $data['recType'] == 0xF122) { + if (0x3 == $data['recVer'] && 0xF122 == $data['recType']) { // Record Header $arrayReturn['length'] += 8; - $officeArtFOPTE = array(); - for ($inc = 0; $inc < $data['recInstance']; $inc++) { + $officeArtFOPTE = []; + for ($inc = 0; $inc < $data['recInstance']; ++$inc) { $opid = self::getInt2d($this->streamPowerpointDocument, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; $optOp = self::getInt4d($this->streamPowerpointDocument, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; - $officeArtFOPTE[] = array( + $officeArtFOPTE[] = [ 'opid' => ($opid >> 0) & bindec('11111111111111'), 'fBid' => ($opid >> 14) & bindec('1'), 'fComplex' => ($opid >> 15) & bindec('1'), 'op' => $optOp, - ); + ]; } //@link : http://code.metager.de/source/xref/kde/calligra/filters/libmso/OPID foreach ($officeArtFOPTE as $opt) { @@ -1830,14 +1877,14 @@ private function readRecordOfficeArtTertiaryFOPT($stream, $pos) case 0x03A0: // Table Row Properties //@link : https://msdn.microsoft.com/en-us/library/dd923419(v=office.12).aspx - if ($opt['fComplex'] == 0x1) { + if (0x1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; } break; case 0x03A9: // GroupShape : metroBlob //@link : https://msdn.microsoft.com/en-us/library/dd943388(v=office.12).aspx - if ($opt['fComplex'] == 0x1) { + if (0x1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; } break; @@ -1846,32 +1893,34 @@ private function readRecordOfficeArtTertiaryFOPT($stream, $pos) //@link : https://msdn.microsoft.com/en-us/library/dd951605(v=office.12).aspx break; default: - throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($opt['opid']).')'); + // var_dump('0x' . dechex($opt['opid'])); + throw new FeatureNotImplementedException(); } } } + return $arrayReturn; } /** * The OfficeArtDgContainer record specifies the container for all the file records for the objects in a drawing. - * @param string $stream - * @param integer $pos - * @return array - * @link : https://msdn.microsoft.com/en-us/library/dd924455(v=office.12).aspx + * + * @return array + * + * @see : https://msdn.microsoft.com/en-us/library/dd924455(v=office.12).aspx */ - private function readRecordOfficeArtDgContainer($stream, $pos) + private function readRecordOfficeArtDgContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF002) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF002 == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // drawingData - $drawingData = $this->readRecordOfficeArtFDG($stream, $pos + $arrayReturn['length']); + $drawingData = $this->readRecordOfficeArtFDG($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += $drawingData['length']; // regroupItems //@todo @@ -1894,19 +1943,19 @@ private function readRecordOfficeArtDgContainer($stream, $pos) /** * The OfficeArtFDG record specifies the number of shapes, the drawing identifier, and the shape identifier of the last shape in a drawing. - * @param string $stream - * @param integer $pos - * @return array - * @link : https://msdn.microsoft.com/en-us/library/dd946757(v=office.12).aspx + * + * @return array + * + * @see : https://msdn.microsoft.com/en-us/library/dd946757(v=office.12).aspx */ - private function readRecordOfficeArtFDG($stream, $pos) + private function readRecordOfficeArtFDG(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] <= 0xFFE && $data['recType'] == 0xF008 && $data['recLen'] == 0x00000008) { + if (0x0 == $data['recVer'] && $data['recInstance'] <= 0xFFE && 0xF008 == $data['recType'] && 0x00000008 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Length @@ -1918,37 +1967,37 @@ private function readRecordOfficeArtFDG($stream, $pos) /** * The OfficeArtFOPT record specifies a table of OfficeArtRGFOPTE records. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd943404(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd943404(v=office.12).aspx */ - private function readRecordOfficeArtFOPT($stream, $pos) + private function readRecordOfficeArtFOPT(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x3 && $data['recType'] == 0xF00B) { + if (0x3 == $data['recVer'] && 0xF00B == $data['recType']) { // Record Header $arrayReturn['length'] += 8; //@link : http://msdn.microsoft.com/en-us/library/dd906086(v=office.12).aspx - $officeArtFOPTE = array(); - for ($inc = 0; $inc < $data['recInstance']; $inc++) { + $officeArtFOPTE = []; + for ($inc = 0; $inc < $data['recInstance']; ++$inc) { $opid = self::getInt2d($this->streamPowerpointDocument, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; $data['recLen'] -= 2; $optOp = self::getInt4d($this->streamPowerpointDocument, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; $data['recLen'] -= 4; - $officeArtFOPTE[] = array( + $officeArtFOPTE[] = [ 'opid' => ($opid >> 0) & bindec('11111111111111'), 'fBid' => ($opid >> 14) & bindec('1'), 'fComplex' => ($opid >> 15) & bindec('1'), 'op' => $optOp, - ); + ]; } //@link : http://code.metager.de/source/xref/kde/calligra/filters/libmso/OPID foreach ($officeArtFOPTE as $opt) { @@ -1970,22 +2019,22 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x0081: // Text : dxTextLeft //@link : http://msdn.microsoft.com/en-us/library/dd953234(v=office.12).aspx - $arrayReturn['insetLeft'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['insetLeft'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x0082: // Text : dyTextTop //@link : http://msdn.microsoft.com/en-us/library/dd925068(v=office.12).aspx - $arrayReturn['insetTop'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['insetTop'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x0083: // Text : dxTextRight //@link : http://msdn.microsoft.com/en-us/library/dd906782(v=office.12).aspx - $arrayReturn['insetRight'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['insetRight'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x0084: // Text : dyTextBottom //@link : http://msdn.microsoft.com/en-us/library/dd772858(v=office.12).aspx - $arrayReturn['insetBottom'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['insetBottom'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x0085: // Text : WrapText @@ -2002,7 +2051,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x0104: // Blip : pib //@link : http://msdn.microsoft.com/en-us/library/dd772837(v=office.12).aspx - if ($opt['fComplex'] == 0) { + if (0 == $opt['fComplex']) { $arrayReturn['pib'] = $opt['op']; $data['recLen'] -= $opt['op']; } else { @@ -2041,7 +2090,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x145: // Geometry : pVertices //@link : http://msdn.microsoft.com/en-us/library/dd949814(v=office.12).aspx - if ($opt['fComplex'] == 1) { + if (1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; $data['recLen'] -= $opt['op']; } @@ -2049,7 +2098,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x146: // Geometry : pSegmentInfo //@link : http://msdn.microsoft.com/en-us/library/dd905742(v=office.12).aspx - if ($opt['fComplex'] == 1) { + if (1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; $data['recLen'] -= $opt['op']; } @@ -2057,7 +2106,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x155: // Geometry : pAdjustHandles //@link : http://msdn.microsoft.com/en-us/library/dd905890(v=office.12).aspx - if ($opt['fComplex'] == 1) { + if (1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; $data['recLen'] -= $opt['op']; } @@ -2065,7 +2114,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x156: // Geometry : pGuides //@link : http://msdn.microsoft.com/en-us/library/dd910801(v=office.12).aspx - if ($opt['fComplex'] == 1) { + if (1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; $data['recLen'] -= $opt['op']; } @@ -2073,7 +2122,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x157: // Geometry : pInscribe //@link : http://msdn.microsoft.com/en-us/library/dd904889(v=office.12).aspx - if ($opt['fComplex'] == 1) { + if (1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; $data['recLen'] -= $opt['op']; } @@ -2089,28 +2138,28 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x0181: // Fill : fillColor //@link : http://msdn.microsoft.com/en-us/library/dd921332(v=office.12).aspx - $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); + $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, '0', STR_PAD_LEFT); // echo 'fillColor : '.$strColor.EOL; break; case 0x0183: // Fill : fillBackColor //@link : http://msdn.microsoft.com/en-us/library/dd950634(v=office.12).aspx - $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); + $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, '0', STR_PAD_LEFT); // echo 'fillBackColor : '.$strColor.EOL; break; case 0x0193: // Fill : fillRectRight //@link : http://msdn.microsoft.com/en-us/library/dd951294(v=office.12).aspx - // echo 'fillRectRight : '.\PhpOffice\Common\Drawing::emuToPixels($opt['op']).EOL; + // echo 'fillRectRight : '.\PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']).EOL; break; case 0x0194: // Fill : fillRectBottom //@link : http://msdn.microsoft.com/en-us/library/dd910194(v=office.12).aspx - // echo 'fillRectBottom : '.\PhpOffice\Common\Drawing::emuToPixels($opt['op']).EOL; + // echo 'fillRectBottom : '.\PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']).EOL; break; case 0x01BF: // Fill : Fill Style Boolean Properties @@ -2119,9 +2168,9 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x01C0: // Line Style : lineColor //@link : http://msdn.microsoft.com/en-us/library/dd920397(v=office.12).aspx - $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, STR_PAD_LEFT, '0'); + $strColor = str_pad(dechex(($opt['op'] >> 0) & bindec('11111111')), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex(($opt['op'] >> 8) & bindec('11111111')), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex(($opt['op'] >> 16) & bindec('11111111')), 2, '0', STR_PAD_LEFT); $arrayReturn['lineColor'] = $strColor; break; case 0x01C1: @@ -2136,7 +2185,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x01CB: // Line Style : lineWidth //@link : http://msdn.microsoft.com/en-us/library/dd926964(v=office.12).aspx - $arrayReturn['lineWidth'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['lineWidth'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x01D6: // Line Style : lineJoinStyle @@ -2161,12 +2210,12 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x0205: // Shadow Style : shadowOffsetX //@link : http://msdn.microsoft.com/en-us/library/dd945280(v=office.12).aspx - $arrayReturn['shadowOffsetX'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['shadowOffsetX'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x0206: // Shadow Style : shadowOffsetY //@link : http://msdn.microsoft.com/en-us/library/dd907855(v=office.12).aspx - $arrayReturn['shadowOffsetY'] = \PhpOffice\Common\Drawing::emuToPixels($opt['op']); + $arrayReturn['shadowOffsetY'] = \PhpOffice\Common\Drawing::emuToPixels((int) $opt['op']); break; case 0x023F: // Shadow Style : Shadow Style Boolean Properties @@ -2183,7 +2232,7 @@ private function readRecordOfficeArtFOPT($stream, $pos) case 0x0380: // Group Shape Property Set : wzName //@link : http://msdn.microsoft.com/en-us/library/dd950681(v=office.12).aspx - if ($opt['fComplex'] == 1) { + if (1 == $opt['fComplex']) { $arrayReturn['length'] += $opt['op']; $data['recLen'] -= $opt['op']; } @@ -2193,7 +2242,6 @@ private function readRecordOfficeArtFOPT($stream, $pos) //@link : http://msdn.microsoft.com/en-us/library/dd949807(v=office.12).aspx break; default: - // throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($opt['opid']).')'); } } if ($data['recLen'] > 0) { @@ -2206,19 +2254,19 @@ private function readRecordOfficeArtFOPT($stream, $pos) /** * The OfficeArtFPSPL record specifies the former hierarchical position of the containing object that is either a shape or a group of shapes. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd947479(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd947479(v=office.12).aspx */ - private function readRecordOfficeArtFPSPL($stream, $pos) + private function readRecordOfficeArtFPSPL(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF11D && $data['recLen'] == 0x00000004) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF11D == $data['recType'] && 0x00000004 == $data['recLen']) { $arrayReturn['length'] += 8; $arrayReturn['length'] += $data['recLen']; } @@ -2228,19 +2276,19 @@ private function readRecordOfficeArtFPSPL($stream, $pos) /** * The OfficeArtFSP record specifies an instance of a shape. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd925898(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd925898(v=office.12).aspx */ - private function readRecordOfficeArtFSP($stream, $pos) + private function readRecordOfficeArtFSP(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x2 && $data['recType'] == 0xF00A && $data['recLen'] == 0x00000008) { + if (0x2 == $data['recVer'] && 0xF00A == $data['recType'] && 0x00000008 == $data['recLen']) { $arrayReturn['length'] += 8; // spid $arrayReturn['length'] += 4; @@ -2258,19 +2306,19 @@ private function readRecordOfficeArtFSP($stream, $pos) /** * The OfficeArtFSPGR record specifies the coordinate system of the group shape that the anchors of the child shape are expressed in. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd925381(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd925381(v=office.12).aspx */ - private function readRecordOfficeArtFSPGR($stream, $pos) + private function readRecordOfficeArtFSPGR(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x1 && $data['recInstance'] == 0x000 && $data['recType'] == 0xF009 && $data['recLen'] == 0x00000010) { + if (0x1 == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF009 == $data['recType'] && 0x00000010 == $data['recLen']) { $arrayReturn['length'] += 8; //$arrShapeGroup['xLeft'] = self::getInt4d($this->streamPowerpointDocument, $pos); $arrayReturn['length'] += 4; @@ -2287,41 +2335,45 @@ private function readRecordOfficeArtFSPGR($stream, $pos) /** * The OfficeArtSecondaryFOPT record specifies a table of OfficeArtRGFOPTE records. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd950259(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd950259(v=office.12).aspx */ - private function readRecordOfficeArtSecondaryFOPT($stream, $pos) + private function readRecordOfficeArtSecondaryFOPT(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x3 && $data['recType'] == 0xF121) { + if (0x3 == $data['recVer'] && 0xF121 == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Length $arrayReturn['length'] += $data['recLen']; } + return $arrayReturn; } /** * A container record that specifies information about a shape. - * @param string $stream - * @param integer $pos - * @link : https://msdn.microsoft.com/en-us/library/dd950927(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see : https://msdn.microsoft.com/en-us/library/dd950927(v=office.12).aspx */ - private function readRecordOfficeArtClientData($stream, $pos) + private function readRecordOfficeArtClientData(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == 0xF011) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && 0xF011 == $data['recType']) { $arrayReturn['length'] += 8; // shapeFlagsAtom (9 bytes) $dataShapeFlagsAtom = $this->readRecordShapeFlagsAtom($stream, $pos + $arrayReturn['length']); @@ -2356,13 +2408,13 @@ private function readRecordOfficeArtClientData($stream, $pos) $arrayReturn['length'] += $dataRecolorInfo['length']; // rgShapeClientRoundtripData (variable) - $array = array( + $array = [ self::RT_PROGTAGS, self::RT_ROUNDTRIPNEWPLACEHOLDERID12ATOM, self::RT_ROUNDTRIPSHAPEID12ATOM, self::RT_ROUNDTRIPHFPLACEHOLDER12ATOM, self::RT_ROUNDTRIPSHAPECHECKSUMFORCL12ATOM, - ); + ]; do { $dataHeaderRG = $this->loadRecordHeader($stream, $pos + $arrayReturn['length']); if (in_array($dataHeaderRG['recType'], $array)) { @@ -2380,7 +2432,8 @@ private function readRecordOfficeArtClientData($stream, $pos) $arrayReturn['length'] += $dataRG['length']; break; default: - throw new \Exception('Feature not implemented (l.'.__LINE__.' : 0x'.dechex($dataHeaderRG['recType']).')'); + // var_dump('0x' . dechex($dataHeaderRG['recType'])); + throw new FeatureNotImplementedException(); } } } while (in_array($dataHeaderRG['recType'], $array)); @@ -2391,17 +2444,17 @@ private function readRecordOfficeArtClientData($stream, $pos) /** * An atom record that specifies a persist object directory. Each persist object identifier specified MUST be unique in that persist object directory. - * @link http://msdn.microsoft.com/en-us/library/dd952680(v=office.12).aspx - * @param string $stream - * @param integer $pos - * @throws \Exception + * + * @see http://msdn.microsoft.com/en-us/library/dd952680(v=office.12).aspx + * + * @throws InvalidFileFormatException */ - private function readRecordPersistDirectoryAtom($stream, $pos) + private function readRecordPersistDirectoryAtom(string $stream, int $pos): void { $rHeader = $this->loadRecordHeader($stream, $pos); $pos += 8; - if ($rHeader['recVer'] != 0x0 || $rHeader['recInstance'] != 0x000 || $rHeader['recType'] != self::RT_PERSISTDIRECTORYATOM) { - throw new \Exception('File PowerPoint 97 in error (Location : PersistDirectoryAtom > RecordHeader).'); + if (0x0 != $rHeader['recVer'] || 0x000 != $rHeader['recInstance'] || self::RT_PERSISTDIRECTORYATOM != $rHeader['recType']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : PersistDirectoryAtom > RecordHeader'); } // rgPersistDirEntry // @link : http://msdn.microsoft.com/en-us/library/dd947347(v=office.12).aspx @@ -2410,10 +2463,10 @@ private function readRecordPersistDirectoryAtom($stream, $pos) $pos += 4; $rHeader['recLen'] -= 4; //$persistId = ($data >> 0) & bindec('11111111111111111111'); - $cPersist = ($data >> 20) & bindec('111111111111'); + $cPersist = ($data >> 20) & bindec('111111111111'); - $rgPersistOffset = array(); - for ($inc = 0; $inc < $cPersist; $inc++) { + $rgPersistOffset = []; + for ($inc = 0; $inc < $cPersist; ++$inc) { $rgPersistOffset[] = self::getInt4d($stream, $pos); $pos += 4; $rHeader['recLen'] -= 4; @@ -2424,18 +2477,19 @@ private function readRecordPersistDirectoryAtom($stream, $pos) /** * A container record that specifies information about the headers (1) and footers within a slide. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd904856(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd904856(v=office.12).aspx + * + * @return array */ - private function readRecordPerSlideHeadersFootersContainer($stream, $pos) + private function readRecordPerSlideHeadersFootersContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_HEADERSFOOTERS) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_HEADERSFOOTERS == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Length @@ -2447,18 +2501,19 @@ private function readRecordPerSlideHeadersFootersContainer($stream, $pos) /** * An atom record that specifies whether a shape is a placeholder shape. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd923930(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd923930(v=office.12).aspx + * + * @return array */ - private function readRecordPlaceholderAtom($stream, $pos) + private function readRecordPlaceholderAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PLACEHOLDERATOM && $data['recLen'] == 0x00000008) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_PLACEHOLDERATOM == $data['recType'] && 0x00000008 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2470,18 +2525,19 @@ private function readRecordPlaceholderAtom($stream, $pos) /** * An atom record that specifies a collection of re-color mappings for a metafile ([MS-WMF]). - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd904899(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd904899(v=office.12).aspx + * + * @return array */ - private function readRecordRecolorInfoAtom($stream, $pos) + private function readRecordRecolorInfoAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_RECOLORINFOATOM) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_RECOLORINFOATOM == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2493,18 +2549,19 @@ private function readRecordRecolorInfoAtom($stream, $pos) /** * An atom record that specifies that a shape is a header or footerplaceholder shape. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd910800(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd910800(v=office.12).aspx + * + * @return array */ - private function readRecordRoundTripHFPlaceholder12Atom($stream, $pos) + private function readRecordRoundTripHFPlaceholder12Atom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ROUNDTRIPHFPLACEHOLDER12ATOM && $data['recLen'] == 0x00000001) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_ROUNDTRIPHFPLACEHOLDER12ATOM == $data['recType'] && 0x00000001 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2516,18 +2573,19 @@ private function readRecordRoundTripHFPlaceholder12Atom($stream, $pos) /** * An atom record that specifies a shape identifier. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd772926(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd772926(v=office.12).aspx + * + * @return array */ - private function readRecordRoundTripShapeId12Atom($stream, $pos) + private function readRecordRoundTripShapeId12Atom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ROUNDTRIPSHAPEID12ATOM && $data['recLen'] == 0x00000004) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_ROUNDTRIPSHAPEID12ATOM == $data['recType'] && 0x00000004 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Length @@ -2539,18 +2597,19 @@ private function readRecordRoundTripShapeId12Atom($stream, $pos) /** * A container record that specifies information about a slide that synchronizes to a slide in a slide library. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx + * + * @return array */ - private function readRecordRoundTripSlideSyncInfo12Container($stream, $pos) + private function readRecordRoundTripSlideSyncInfo12Container(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_ROUNDTRIPSLIDESYNCINFO12) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_ROUNDTRIPSLIDESYNCINFO12 == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Length @@ -2562,18 +2621,19 @@ private function readRecordRoundTripSlideSyncInfo12Container($stream, $pos) /** * An atom record that specifies shape-level Boolean flags. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd908949(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd908949(v=office.12).aspx + * + * @return array */ - private function readRecordShapeFlags10Atom($stream, $pos) + private function readRecordShapeFlags10Atom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SHAPEFLAGS10ATOM && $data['recLen'] == 0x00000001) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_SHAPEFLAGS10ATOM == $data['recType'] && 0x00000001 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2585,18 +2645,19 @@ private function readRecordShapeFlags10Atom($stream, $pos) /** * An atom record that specifies shape-level Boolean flags. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd925824(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd925824(v=office.12).aspx + * + * @return array */ - private function readRecordShapeFlagsAtom($stream, $pos) + private function readRecordShapeFlagsAtom(string $stream, int $pos): array { - $arrayReturn = array( - 'length' => 0, - ); + $arrayReturn = [ + 'length' => 0, + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SHAPEATOM && $data['recLen'] == 0x00000001) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_SHAPEATOM == $data['recType'] && 0x00000001 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2608,18 +2669,19 @@ private function readRecordShapeFlagsAtom($stream, $pos) /** * A container record that specifies programmable tags with additional binary shape data. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd911033(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd911033(v=office.12).aspx + * + * @return array */ - private function readRecordShapeProgBinaryTagContainer($stream, $pos) + private function readRecordShapeProgBinaryTagContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PROGBINARYTAG) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_PROGBINARYTAG == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2631,18 +2693,21 @@ private function readRecordShapeProgBinaryTagContainer($stream, $pos) /** * A container record that specifies programmable tags with additional shape data. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd911266(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd911266(v=office.12).aspx */ - private function readRecordShapeProgTagsContainer($stream, $pos) + private function readRecordShapeProgTagsContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PROGTAGS) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_PROGTAGS == $data['recType']) { // Record Header $arrayReturn['length'] += 8; @@ -2656,7 +2721,8 @@ private function readRecordShapeProgTagsContainer($stream, $pos) break; //case self::RT_PROGSTRINGTAG: default: - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + // var_dump('0x' . dechex($dataHeaderRG['recType'])); + throw new FeatureNotImplementedException(); } } while ($length < $data['recLen']); // Datas @@ -2668,28 +2734,28 @@ private function readRecordShapeProgTagsContainer($stream, $pos) /** * An atom record that specifies information about a slide. - * @param string $stream - * @param integer $pos - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx + * + * @return array + * + * @see https://msdn.microsoft.com/en-us/library/dd923801(v=office.12).aspx */ - private function readRecordSlideAtom($stream, $pos) + private function readRecordSlideAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x2 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SLIDEATOM) { + if (0x2 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_SLIDEATOM == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // slideAtom > geom $arrayReturn['length'] += 4; // slideAtom > rgPlaceholderTypes - $rgPlaceholderTypes = array(); - for ($inc = 0; $inc < 8; $inc++) { + $rgPlaceholderTypes = []; + for ($inc = 0; $inc < 8; ++$inc) { $rgPlaceholderTypes[] = self::getInt1d($this->streamPowerpointDocument, $pos); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; } // slideAtom > masterIdRef @@ -2707,11 +2773,12 @@ private function readRecordSlideAtom($stream, $pos) /** * A container record that specifies a presentation slide or title master slide. - * @param string $stream - * @param int $pos - * @link http://msdn.microsoft.com/en-us/library/dd946323(v=office.12).aspx + * + * @throws InvalidFileFormatException + * + * @see http://msdn.microsoft.com/en-us/library/dd946323(v=office.12).aspx */ - private function readRecordSlideContainer($stream, $pos) + private function readRecordSlideContainer(string $stream, int $pos): void { // Core $this->oPhpPresentation->createSlide(); @@ -2719,8 +2786,8 @@ private function readRecordSlideContainer($stream, $pos) // *** slideAtom (32 bytes) $slideAtom = $this->readRecordSlideAtom($stream, $pos); - if ($slideAtom['length'] == 0) { - throw new \Exception('PowerPoint97 Reader : record SlideAtom'); + if (0 == $slideAtom['length']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class); } $pos += $slideAtom['length']; @@ -2742,8 +2809,9 @@ private function readRecordSlideContainer($stream, $pos) // *** slideSchemeColorSchemeAtom (40 bytes) $slideSchemeColorAtom = $this->readRecordSlideSchemeColorSchemeAtom($stream, $pos); - if ($slideSchemeColorAtom['length'] == 0) { - throw new \Exception('PowerPoint97 Reader : record SlideSchemeColorSchemeAtom'); + if (0 == $slideSchemeColorAtom['length']) { + // Record SlideSchemeColorSchemeAtom + throw new InvalidFileFormatException($this->filename, PowerPoint97::class); } $pos += $slideSchemeColorAtom['length']; @@ -2760,24 +2828,25 @@ private function readRecordSlideContainer($stream, $pos) /** * An atom record that specifies the name of a slide. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd906297(v=office.12).aspx + * + * @return array{'length': int, 'slideName': string} */ - private function readRecordSlideNameAtom($stream, $pos) + private function readRecordSlideNameAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, 'slideName' => '', - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x003 && $data['recType'] == self::RT_CSTRING && $data['recLen'] % 2 == 0) { + if (0x0 == $data['recVer'] && 0x003 == $data['recInstance'] && self::RT_CSTRING == $data['recType'] && $data['recLen'] % 2 == 0) { // Record Header $arrayReturn['length'] += 8; // Length $strLen = ($data['recLen'] / 2); - for ($inc = 0; $inc < $strLen; $inc++) { + for ($inc = 0; $inc < $strLen; ++$inc) { $char = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; $arrayReturn['slideName'] .= Text::chr($char); @@ -2789,18 +2858,19 @@ private function readRecordSlideNameAtom($stream, $pos) /** * An atom record that specifies a slide number metacharacter. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd945703(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd945703(v=office.12).aspx + * + * @return array */ - private function readRecordSlideNumberMCAtom($stream, $pos) + private function readRecordSlideNumberMCAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SLIDENUMBERMETACHARATOM && $data['recLen'] == 0x00000004) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_SLIDENUMBERMETACHARATOM == $data['recType'] && 0x00000004 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Datas @@ -2812,18 +2882,19 @@ private function readRecordSlideNumberMCAtom($stream, $pos) /** * A container record that specifies programmable tags with additional slide data. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd951946(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd951946(v=office.12).aspx + * + * @return array */ - private function readRecordSlideProgTagsContainer($stream, $pos) + private function readRecordSlideProgTagsContainer(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0xF && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_PROGTAGS) { + if (0xF == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_PROGTAGS == $data['recType']) { // Record Header $arrayReturn['length'] += 8; // Length @@ -2835,28 +2906,29 @@ private function readRecordSlideProgTagsContainer($stream, $pos) /** * A container record that specifies the color scheme used by a slide. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd949420(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd949420(v=office.12).aspx + * + * @return array */ - private function readRecordSlideSchemeColorSchemeAtom($stream, $pos) + private function readRecordSlideSchemeColorSchemeAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x001 && $data['recType'] == self::RT_COLORSCHEMEATOM && $data['recLen'] == 0x00000020) { + if (0x0 == $data['recVer'] && 0x001 == $data['recInstance'] && self::RT_COLORSCHEMEATOM == $data['recType'] && 0x00000020 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Length - $rgSchemeColor = array(); - for ($inc = 0; $inc <= 7; $inc++) { - $rgSchemeColor[] = array( + $rgSchemeColor = []; + for ($inc = 0; $inc <= 7; ++$inc) { + $rgSchemeColor[] = [ 'red' => self::getInt1d($stream, $pos + $arrayReturn['length'] + $inc * 4), 'green' => self::getInt1d($stream, $pos + $arrayReturn['length'] + $inc * 4 + 1), 'blue' => self::getInt1d($stream, $pos + $arrayReturn['length'] + $inc * 4 + 2), - ); + ]; } $arrayReturn['length'] += (8 * 4); } @@ -2866,18 +2938,19 @@ private function readRecordSlideSchemeColorSchemeAtom($stream, $pos) /** * An atom record that specifies what transition effect to perform during a slide show, and how to advance to the next presentation slide. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd943408(v=office.12).aspx + * + * @see https://msdn.microsoft.com/en-us/library/dd943408(v=office.12).aspx + * + * @return array */ - private function readRecordSlideShowSlideInfoAtom($stream, $pos) + private function readRecordSlideShowSlideInfoAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] == 0x0 && $data['recInstance'] == 0x000 && $data['recType'] == self::RT_SLIDESHOWSLIDEINFOATOM && $data['recLen'] == 0x00000010) { + if (0x0 == $data['recVer'] && 0x000 == $data['recInstance'] && self::RT_SLIDESHOWSLIDEINFOATOM == $data['recType'] && 0x00000010 == $data['recLen']) { // Record Header $arrayReturn['length'] += 8; // Length; @@ -2888,18 +2961,18 @@ private function readRecordSlideShowSlideInfoAtom($stream, $pos) } /** - * UserEditAtom - * @link http://msdn.microsoft.com/en-us/library/dd945746(v=office.12).aspx - * @param string $stream - * @param integer $pos - * @throws \Exception + * UserEditAtom. + * + * @see http://msdn.microsoft.com/en-us/library/dd945746(v=office.12).aspx + * + * @throws InvalidFileFormatException */ - private function readRecordUserEditAtom($stream, $pos) + private function readRecordUserEditAtom(string $stream, int $pos): void { $rHeader = $this->loadRecordHeader($stream, $pos); $pos += 8; - if ($rHeader['recVer'] != 0x0 || $rHeader['recInstance'] != 0x000 || $rHeader['recType'] != self::RT_USEREDITATOM || ($rHeader['recLen'] != 0x0000001C && $rHeader['recLen'] != 0x00000020)) { - throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > RecordHeader).'); + if (0x0 != $rHeader['recVer'] || 0x000 != $rHeader['recInstance'] || self::RT_USEREDITATOM != $rHeader['recType'] || (0x0000001C != $rHeader['recLen'] && 0x00000020 != $rHeader['recLen'])) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : UserEditAtom > RecordHeader'); } // lastSlideIdRef @@ -2909,16 +2982,16 @@ private function readRecordUserEditAtom($stream, $pos) // minorVersion $minorVersion = self::getInt1d($stream, $pos); - $pos += 1; - if ($minorVersion != 0x00) { - throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > minorVersion).'); + ++$pos; + if (0x00 != $minorVersion) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : UserEditAtom > minorVersion'); } // majorVersion $majorVersion = self::getInt1d($stream, $pos); - $pos += 1; - if ($majorVersion != 0x03) { - throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > majorVersion).'); + ++$pos; + if (0x03 != $majorVersion) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : UserEditAtom > majorVersion'); } // offsetLastEdit @@ -2928,10 +3001,10 @@ private function readRecordUserEditAtom($stream, $pos) $pos += 4; // docPersistIdRef - $docPersistIdRef = self::getInt4d($stream, $pos); + $docPersistIdRef = self::getInt4d($stream, $pos); $pos += 4; - if ($docPersistIdRef != 0x00000001) { - throw new \Exception('File PowerPoint 97 in error (Location : UserEditAtom > docPersistIdRef).'); + if (0x00000001 != $docPersistIdRef) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : UserEditAtom > docPersistIdRef'); } // persistIdSeed @@ -2944,17 +3017,19 @@ private function readRecordUserEditAtom($stream, $pos) /** * A structure that specifies the character-level formatting of a run of text. - * @param string $stream - * @param int $pos - * @param int $strLenRT - * @link https://msdn.microsoft.com/en-us/library/dd945870(v=office.12).aspx + * + * @return array{'length': int, 'strLenRT': int, 'partLength': int, 'bold': bool, 'italic': bool, 'underline': bool, 'fontName': string, 'fontSize': int, 'color': Color} + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd945870(v=office.12).aspx */ - private function readStructureTextCFRun($stream, $pos, $strLenRT) + private function readStructureTextCFRun(string $stream, int $pos, int $strLenRT): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, 'strLenRT' => $strLenRT, - ); + ]; // rgTextCFRun $countRgTextCFRun = self::getInt4d($stream, $pos + $arrayReturn['length']); @@ -2965,7 +3040,7 @@ private function readStructureTextCFRun($stream, $pos, $strLenRT) $masks = self::getInt4d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; - $masksData = array(); + $masksData = []; $masksData['bold'] = ($masks >> 0) & bindec('1'); $masksData['italic'] = ($masks >> 1) & bindec('1'); $masksData['underline'] = ($masks >> 2) & bindec('1'); @@ -2989,11 +3064,11 @@ private function readStructureTextCFRun($stream, $pos, $strLenRT) $masksData['newEATypeface'] = ($masks >> 24) & bindec('1'); $masksData['csTypeface'] = ($masks >> 25) & bindec('1'); $masksData['pp11ext'] = ($masks >> 26) & bindec('1'); - if ($masksData['bold'] == 1 || $masksData['italic'] == 1 || $masksData['underline'] == 1 || $masksData['shadow'] == 1 || $masksData['fehint'] == 1 || $masksData['kumi'] == 1 || $masksData['emboss'] == 1 || $masksData['fHasStyle'] == 1) { + if (1 == $masksData['bold'] || 1 == $masksData['italic'] || 1 == $masksData['underline'] || 1 == $masksData['shadow'] || 1 == $masksData['fehint'] || 1 == $masksData['kumi'] || 1 == $masksData['emboss'] || 1 == $masksData['fHasStyle']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; - $fontStyleFlags = array(); + $fontStyleFlags = []; $fontStyleFlags['bold'] = ($data >> 0) & bindec('1'); $fontStyleFlags['italic'] = ($data >> 1) & bindec('1'); $fontStyleFlags['underline'] = ($data >> 2) & bindec('1'); @@ -3007,51 +3082,51 @@ private function readStructureTextCFRun($stream, $pos, $strLenRT) $fontStyleFlags['pp9rt'] = ($data >> 10) & bindec('1111'); $fontStyleFlags['unused4'] = ($data >> 14) & bindec('11'); - $arrayReturn['bold'] = ($fontStyleFlags['bold'] == 1) ? true : false; - $arrayReturn['italic'] = ($fontStyleFlags['italic'] == 1) ? true : false; - $arrayReturn['underline'] = ($fontStyleFlags['underline'] == 1) ? true : false; + $arrayReturn['bold'] = (1 == $fontStyleFlags['bold']) ? true : false; + $arrayReturn['italic'] = (1 == $fontStyleFlags['italic']) ? true : false; + $arrayReturn['underline'] = (1 == $fontStyleFlags['underline']) ? true : false; } - if ($masksData['typeface'] == 1) { + if (1 == $masksData['typeface']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; $arrayReturn['fontName'] = isset($this->arrayFonts[$data]) ? $this->arrayFonts[$data] : ''; } - if ($masksData['oldEATypeface'] == 1) { + if (1 == $masksData['oldEATypeface']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['ansiTypeface'] == 1) { + if (1 == $masksData['ansiTypeface']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['symbolTypeface'] == 1) { + if (1 == $masksData['symbolTypeface']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['size'] == 1) { + if (1 == $masksData['size']) { $arrayReturn['fontSize'] = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['color'] == 1) { + if (1 == $masksData['color']) { $red = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; $green = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; $blue = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; $index = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; - if ($index == 0xFE) { - $strColor = str_pad(dechex($red), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex($green), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex($blue), 2, STR_PAD_LEFT, '0'); + if (0xFE == $index) { + $strColor = str_pad(dechex($red), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex($green), 2, '0', STR_PAD_LEFT); + $strColor .= str_pad(dechex($blue), 2, '0', STR_PAD_LEFT); - $arrayReturn['color'] = new Color('FF'.$strColor); + $arrayReturn['color'] = new Color('FF' . $strColor); } } - if ($masksData['position'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['position']) { + throw new FeatureNotImplementedException(); } return $arrayReturn; @@ -3059,16 +3134,19 @@ private function readStructureTextCFRun($stream, $pos, $strLenRT) /** * A structure that specifies the paragraph-level formatting of a run of text. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd923535(v=office.12).aspx + * + * @return array{'length': int, 'strLenRT': int, 'alignH': string, 'bulletChar': string, 'leftMargin': int, 'indent': int} + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd923535(v=office.12).aspx */ - private function readStructureTextPFRun($stream, $pos, $strLenRT) + private function readStructureTextPFRun(string $stream, int $pos, int $strLenRT): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, 'strLenRT' => $strLenRT, - ); + ]; // rgTextPFRun $countRgTextPFRun = self::getInt4d($stream, $pos + $arrayReturn['length']); @@ -3081,7 +3159,7 @@ private function readStructureTextPFRun($stream, $pos, $strLenRT) $masks = self::getInt4d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; - $masksData = array(); + $masksData = []; $masksData['hasBullet'] = ($masks >> 0) & bindec('1'); $masksData['bulletHasFont'] = ($masks >> 1) & bindec('1'); $masksData['bulletHasColor'] = ($masks >> 2) & bindec('1'); @@ -3109,8 +3187,8 @@ private function readStructureTextPFRun($stream, $pos, $strLenRT) $masksData['bulletScheme'] = ($masks >> 24) & bindec('1'); $masksData['bulletHasScheme'] = ($masks >> 25) & bindec('1'); - $bulletFlags = array(); - if ($masksData['hasBullet'] == 1 || $masksData['bulletHasFont'] == 1 || $masksData['bulletHasColor'] == 1 || $masksData['bulletHasSize'] == 1) { + $bulletFlags = []; + if (1 == $masksData['hasBullet'] || 1 == $masksData['bulletHasFont'] || 1 == $masksData['bulletHasColor'] || 1 == $masksData['bulletHasSize']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; @@ -3119,36 +3197,36 @@ private function readStructureTextPFRun($stream, $pos, $strLenRT) $bulletFlags['fBulletHasColor'] = ($data >> 2) & bindec('1'); $bulletFlags['fBulletHasSize'] = ($data >> 3) & bindec('1'); } - if ($masksData['bulletChar'] == 1) { + if (1 == $masksData['bulletChar']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; $arrayReturn['bulletChar'] = chr($data); } - if ($masksData['bulletFont'] == 1) { + if (1 == $masksData['bulletFont']) { // $data = self::getInt2d($stream, $pos); $arrayReturn['length'] += 2; } - if ($masksData['bulletSize'] == 1) { + if (1 == $masksData['bulletSize']) { // $data = self::getInt2d($stream, $pos); $arrayReturn['length'] += 2; } - if ($masksData['bulletColor'] == 1) { - $red = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; - $green = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; - $blue = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; + if (1 == $masksData['bulletColor']) { + // $red = self::getInt1d($stream, $pos + $arrayReturn['length']); + ++$arrayReturn['length']; + // $green = self::getInt1d($stream, $pos + $arrayReturn['length']); + ++$arrayReturn['length']; + // $blue = self::getInt1d($stream, $pos + $arrayReturn['length']); + ++$arrayReturn['length']; $index = self::getInt1d($stream, $pos + $arrayReturn['length']); - $arrayReturn['length'] += 1; + ++$arrayReturn['length']; - if ($index == 0xFE) { - $strColor = str_pad(dechex($red), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex($green), 2, STR_PAD_LEFT, '0'); - $strColor .= str_pad(dechex($blue), 2, STR_PAD_LEFT, '0'); + if (0xFE == $index) { + // $strColor = str_pad(dechex($red), 2, '0', STR_PAD_LEFT); + // $strColor .= str_pad(dechex($green), 2, '0', STR_PAD_LEFT); + // $strColor .= str_pad(dechex($blue), 2, '0', STR_PAD_LEFT); } } - if ($masksData['align'] == 1) { + if (1 == $masksData['align']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; switch ($data) { @@ -3177,45 +3255,45 @@ private function readStructureTextPFRun($stream, $pos, $strLenRT) break; } } - if ($masksData['lineSpacing'] == 1) { + if (1 == $masksData['lineSpacing']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['spaceBefore'] == 1) { + if (1 == $masksData['spaceBefore']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['spaceAfter'] == 1) { + if (1 == $masksData['spaceAfter']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['leftMargin'] == 1) { + if (1 == $masksData['leftMargin']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; - $arrayReturn['leftMargin'] = (int)round($data/6); + $arrayReturn['leftMargin'] = (int) round($data / 6); } - if ($masksData['indent'] == 1) { + if (1 == $masksData['indent']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; - $arrayReturn['indent'] = (int)round($data/6); + $arrayReturn['indent'] = (int) round($data / 6); } - if ($masksData['defaultTabSize'] == 1) { + if (1 == $masksData['defaultTabSize']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['tabStops'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['tabStops']) { + throw new FeatureNotImplementedException(); } - if ($masksData['fontAlign'] == 1) { + if (1 == $masksData['fontAlign']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['charWrap'] == 1 || $masksData['wordWrap'] == 1 || $masksData['overflow'] == 1) { + if (1 == $masksData['charWrap'] || 1 == $masksData['wordWrap'] || 1 == $masksData['overflow']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['textDirection'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['textDirection']) { + throw new FeatureNotImplementedException(); } return $arrayReturn; @@ -3223,25 +3301,26 @@ private function readStructureTextPFRun($stream, $pos, $strLenRT) /** * A structure that specifies language and spelling information for a run of text. - * @param string $stream - * @param integer $pos - * @param string $strLenRT - * @return array - * @link https://msdn.microsoft.com/en-us/library/dd909603(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd909603(v=office.12).aspx */ - private function readStructureTextSIRun($stream, $pos, $strLenRT) + private function readStructureTextSIRun(string $stream, int $pos, int $strLenRT): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, 'strLenRT' => $strLenRT, - ); + ]; $arrayReturn['strLenRT'] -= self::getInt4d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; $data = self::getInt4d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; - $masksData = array(); + $masksData = []; $masksData['spell'] = ($data >> 0) & bindec('1'); $masksData['lang'] = ($data >> 1) & bindec('1'); $masksData['altLang'] = ($data >> 2) & bindec('1'); @@ -3253,30 +3332,30 @@ private function readStructureTextSIRun($stream, $pos, $strLenRT) $masksData['reserved1'] = ($data >> 8) & bindec('1'); $masksData['smartTag'] = ($data >> 9) & bindec('1'); - if ($masksData['spell'] == 1) { + if (1 == $masksData['spell']) { $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; - $masksSpell = array(); + $masksSpell = []; $masksSpell['error'] = ($data >> 0) & bindec('1'); $masksSpell['clean'] = ($data >> 1) & bindec('1'); $masksSpell['grammar'] = ($data >> 2) & bindec('1'); } - if ($masksData['lang'] == 1) { + if (1 == $masksData['lang']) { // $data = self::getInt2d($stream, $pos); $arrayReturn['length'] += 2; } - if ($masksData['altLang'] == 1) { + if (1 == $masksData['altLang']) { // $data = self::getInt2d($stream, $pos); $arrayReturn['length'] += 2; } - if ($masksData['fBidi'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['fBidi']) { + throw new FeatureNotImplementedException(); } - if ($masksData['fPp10ext'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['fPp10ext']) { + throw new FeatureNotImplementedException(); } - if ($masksData['smartTag'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['smartTag']) { + throw new FeatureNotImplementedException(); } return $arrayReturn; @@ -3284,20 +3363,23 @@ private function readStructureTextSIRun($stream, $pos, $strLenRT) /** * A structure that specifies tabbing, margins, and indentation for text. - * @param string $stream - * @param integer $pos - * @link https://msdn.microsoft.com/en-us/library/dd922749(v=office.12).aspx + * + * @return array + * + * @throws FeatureNotImplementedException + * + * @see https://msdn.microsoft.com/en-us/library/dd922749(v=office.12).aspx */ - private function readStructureTextRuler($stream, $pos) + private function readStructureTextRuler(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = self::getInt4d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 4; - $masksData = array(); + $masksData = []; $masksData['fDefaultTabSize'] = ($data >> 0) & bindec('1'); $masksData['fCLevels'] = ($data >> 1) & bindec('1'); $masksData['fTabStops'] = ($data >> 2) & bindec('1'); @@ -3312,64 +3394,64 @@ private function readStructureTextRuler($stream, $pos) $masksData['fIndent4'] = ($data >> 11) & bindec('1'); $masksData['fIndent5'] = ($data >> 12) & bindec('1'); - if ($masksData['fCLevels'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['fCLevels']) { + throw new FeatureNotImplementedException(); } - if ($masksData['fDefaultTabSize'] == 1) { - throw new \Exception('Feature not implemented (l.'.__LINE__.')'); + if (1 == $masksData['fDefaultTabSize']) { + throw new FeatureNotImplementedException(); } - if ($masksData['fTabStops'] == 1) { + if (1 == $masksData['fTabStops']) { $count = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; - $arrayTabStops = array(); - for ($inc = 0; $inc < $count; $inc++) { + $arrayTabStops = []; + for ($inc = 0; $inc < $count; ++$inc) { $position = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; $type = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; - $arrayTabStops[] = array( + $arrayTabStops[] = [ 'position' => $position, 'type' => $type, - ); + ]; } } - if ($masksData['fLeftMargin1'] == 1) { + if (1 == $masksData['fLeftMargin1']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fIndent1'] == 1) { + if (1 == $masksData['fIndent1']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fLeftMargin2'] == 1) { + if (1 == $masksData['fLeftMargin2']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fIndent2'] == 1) { + if (1 == $masksData['fIndent2']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fLeftMargin3'] == 1) { + if (1 == $masksData['fLeftMargin3']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fIndent3'] == 1) { + if (1 == $masksData['fIndent3']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fLeftMargin4'] == 1) { + if (1 == $masksData['fLeftMargin4']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fIndent4'] == 1) { + if (1 == $masksData['fIndent4']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fLeftMargin5'] == 1) { + if (1 == $masksData['fLeftMargin5']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } - if ($masksData['fIndent5'] == 1) { + if (1 == $masksData['fIndent5']) { // $data = self::getInt2d($stream, $pos + $arrayReturn['length']); $arrayReturn['length'] += 2; } @@ -3377,12 +3459,7 @@ private function readStructureTextRuler($stream, $pos) return $arrayReturn; } - /** - * @param $stream - * @param int $pos - * @throws \Exception - */ - private function readRecordNotesContainer($stream, $pos) + private function readRecordNotesContainer(string $stream, int $pos): void { // notesAtom $notesAtom = $this->readRecordNotesAtom($stream, $pos); @@ -3399,26 +3476,25 @@ private function readRecordNotesContainer($stream, $pos) } /** - * @param $stream - * @param int $pos - * @return array - * @throws \Exception + * @return array + * + * @throws InvalidFileFormatException */ - private function readRecordNotesAtom($stream, $pos) + private function readRecordNotesAtom(string $stream, int $pos): array { - $arrayReturn = array( + $arrayReturn = [ 'length' => 0, - ); + ]; $data = $this->loadRecordHeader($stream, $pos); - if ($data['recVer'] != 0x1 || $data['recInstance'] != 0x000 || $data['recType'] != self::RT_NOTESATOM || $data['recLen'] != 0x00000008) { - throw new \Exception('File PowerPoint 97 in error (Location : NotesAtom > RecordHeader)'); + if (0x1 != $data['recVer'] || 0x000 != $data['recInstance'] || self::RT_NOTESATOM != $data['recType'] || 0x00000008 != $data['recLen']) { + throw new InvalidFileFormatException($this->filename, PowerPoint97::class, 'Location : NotesAtom > RecordHeader)'); } // Record Header $arrayReturn['length'] += 8; // NotesAtom > slideIdRef $notesIdRef = self::getInt4d($stream, $pos + $arrayReturn['length']); - if ($notesIdRef == -2147483648) { + if (-2147483648 == $notesIdRef) { $notesIdRef = 0; } $this->currentNote = $notesIdRef; diff --git a/src/PhpPresentation/Reader/ReaderInterface.php b/src/PhpPresentation/Reader/ReaderInterface.php index c5149e99c7..d3e06d393c 100644 --- a/src/PhpPresentation/Reader/ReaderInterface.php +++ b/src/PhpPresentation/Reader/ReaderInterface.php @@ -10,32 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Reader; +use PhpOffice\PhpPresentation\PhpPresentation; + /** - * Reader interface + * Reader interface. */ interface ReaderInterface { /** * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file? - * - * @param string $pFilename - * @return boolean */ - public function canRead($pFilename); + public function canRead(string $pFilename): bool; /** - * Loads PhpPresentation from file - * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation - * @throws \Exception + * Loads PhpPresentation from file. */ - public function load($pFilename); + public function load(string $pFilename): PhpPresentation; } diff --git a/src/PhpPresentation/Reader/Serialized.php b/src/PhpPresentation/Reader/Serialized.php index 5843107e42..33de31b412 100644 --- a/src/PhpPresentation/Reader/Serialized.php +++ b/src/PhpPresentation/Reader/Serialized.php @@ -10,29 +10,33 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Reader; use PhpOffice\Common\File; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; +use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter; +use PhpOffice\PhpPresentation\Shape\Drawing\File as DrawingFile; +use ZipArchive; /** - * Serialized format reader + * Serialized format reader. */ class Serialized implements ReaderInterface { /** * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file? - * - * @param string $pFilename - * @throws \Exception - * @return boolean */ - public function canRead($pFilename) + public function canRead(string $pFilename): bool { return $this->fileSupportsUnserializePhpPresentation($pFilename); } @@ -40,15 +44,13 @@ public function canRead($pFilename) /** * Does a file support UnserializePhpPresentation ? * - * @param string $pFilename - * @throws \Exception - * @return boolean + * @throws FileNotFoundException */ - public function fileSupportsUnserializePhpPresentation($pFilename = '') + public function fileSupportsUnserializePhpPresentation(string $pFilename): bool { // Check if file exists if (!file_exists($pFilename)) { - throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist."); + throw new FileNotFoundException($pFilename); } // File exists, does it contain PhpPresentation.xml? @@ -56,57 +58,63 @@ public function fileSupportsUnserializePhpPresentation($pFilename = '') } /** - * Loads PhpPresentation Serialized file + * Loads PhpPresentation Serialized file. * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation - * @throws \Exception + * @throws FileNotFoundException + * @throws InvalidFileFormatException */ - public function load($pFilename) + public function load(string $pFilename): PhpPresentation { // Check if file exists if (!file_exists($pFilename)) { - throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist."); + throw new FileNotFoundException($pFilename); } // Unserialize... First make sure the file supports it! if (!$this->fileSupportsUnserializePhpPresentation($pFilename)) { - throw new \Exception("Invalid file format for PhpOffice\PhpPresentation\Reader\Serialized: " . $pFilename . "."); + throw new InvalidFileFormatException($pFilename, Serialized::class); } return $this->loadSerialized($pFilename); } /** - * Load PhpPresentation Serialized file + * Load PhpPresentation Serialized file. * - * @param string $pFilename - * @return \PhpOffice\PhpPresentation\PhpPresentation + * @throws InvalidFileFormatException */ - private function loadSerialized($pFilename) + private function loadSerialized(string $pFilename): PhpPresentation { - $oArchive = new \ZipArchive(); - if ($oArchive->open($pFilename) === true) { - $xmlContent = $oArchive->getFromName('PhpPresentation.xml'); + $oArchive = new ZipArchive(); + if (true !== $oArchive->open($pFilename)) { + throw new InvalidFileFormatException($pFilename, Serialized::class); + } - if (!empty($xmlContent)) { - $xmlData = simplexml_load_string($xmlContent); - $file = unserialize(base64_decode((string) $xmlData->data)); + $xmlContent = $oArchive->getFromName('PhpPresentation.xml'); + if (empty($xmlContent)) { + throw new InvalidFileFormatException($pFilename, Serialized::class, 'The file PhpPresentation.xml is malformed'); + } + + $xmlData = simplexml_load_string($xmlContent); + $file = unserialize(base64_decode((string) $xmlData->data)); - // Update media links - for ($i = 0; $i < $file->getSlideCount(); ++$i) { - for ($j = 0; $j < $file->getSlide($i)->getShapeCollection()->count(); ++$j) { - if ($file->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { - $file->getSlide($i)->getShapeCollection()->offsetGet($j)->setPath('zip://' . $pFilename . '#media/' . $file->getSlide($i)->getShapeCollection()->offsetGet($j)->getIndexedFilename(), false); - } + // Update media links + for ($i = 0; $i < $file->getSlideCount(); ++$i) { + for ($j = 0; $j < $file->getSlide($i)->getShapeCollection()->count(); ++$j) { + if ($file->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { + $imgTemp = $file->getSlide($i)->getShapeCollection()->offsetGet($j); + $imgPath = 'zip://' . $pFilename . '#media/' . $imgTemp->getImageIndex() . '/' . pathinfo($imgTemp->getPath(), PATHINFO_BASENAME); + if ($imgTemp instanceof DrawingFile) { + $imgTemp->setPath($imgPath, false); + } else { + $imgTemp->setPath($imgPath); } } - - $oArchive->close(); - return $file; } } - return null; + $oArchive->close(); + + return $file; } } diff --git a/src/PhpPresentation/Shape/AbstractGraphic.php b/src/PhpPresentation/Shape/AbstractGraphic.php index 0df5a195e6..e7a4e731d7 100644 --- a/src/PhpPresentation/Shape/AbstractGraphic.php +++ b/src/PhpPresentation/Shape/AbstractGraphic.php @@ -10,91 +10,94 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\ComparableInterface; /** - * Abstract drawing + * Abstract drawing. */ abstract class AbstractGraphic extends AbstractShape implements ComparableInterface { /** - * Image counter + * Image counter. * * @var int */ private static $imageCounter = 0; /** - * Image index + * Image index. * * @var int */ private $imageIndex = 0; /** - * Name + * Name. * * @var string */ protected $name; /** - * Description + * Description. * * @var string */ protected $description; /** - * Proportional resize + * Proportional resize. * - * @var boolean + * @var bool */ protected $resizeProportional; /** - * Slide relation ID (should not be used by user code!) + * Slide relation ID (should not be used by user code!). * * @var string */ public $relationId = null; /** - * Create a new \PhpOffice\PhpPresentation\Slide\AbstractDrawing + * Create a new \PhpOffice\PhpPresentation\Slide\AbstractDrawing. */ public function __construct() { // Initialise values - $this->name = ''; - $this->description = ''; + $this->name = ''; + $this->description = ''; $this->resizeProportional = true; // Set image index - self::$imageCounter++; + ++self::$imageCounter; $this->imageIndex = self::$imageCounter; // Initialize parent parent::__construct(); } - + public function __clone() { parent::__clone(); - - self::$imageCounter++; + + ++self::$imageCounter; $this->imageIndex = self::$imageCounter; } /** - * Get image index + * Get image index. * * @return int */ @@ -104,7 +107,7 @@ public function getImageIndex() } /** - * Get Name + * Get Name. * * @return string */ @@ -114,19 +117,21 @@ public function getName() } /** - * Set Name + * Set Name. + * + * @param string $pValue * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Shape\AbstractGraphic + * @return $this */ public function setName($pValue = '') { $this->name = $pValue; + return $this; } /** - * Get Description + * Get Description. * * @return string */ @@ -136,10 +141,11 @@ public function getDescription() } /** - * Set Description + * Set Description. + * + * @param string $pValue * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Shape\AbstractDrawing + * @return $this */ public function setDescription($pValue = '') { @@ -149,16 +155,15 @@ public function setDescription($pValue = '') } /** - * Set Width + * Set Width. * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Shape\AbstractGraphic + * @return self */ - public function setWidth($pValue = 0) + public function setWidth(int $pValue = 0) { // Resize proportional? - if ($this->resizeProportional && $pValue != 0) { - $ratio = $this->height / $this->width; + if ($this->resizeProportional && 0 != $pValue && 0 != $this->width) { + $ratio = $this->height / $this->width; $this->height = (int) round($ratio * $pValue); } @@ -169,16 +174,15 @@ public function setWidth($pValue = 0) } /** - * Set Height + * Set Height. * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Shape\AbstractGraphic + * @return self */ - public function setHeight($pValue = 0) + public function setHeight(int $pValue = 0) { // Resize proportional? - if ($this->resizeProportional && $pValue != 0) { - $ratio = $this->width / $this->height; + if ($this->resizeProportional && 0 != $pValue && 0 != $this->height) { + $ratio = $this->width / $this->height; $this->width = (int) round($ratio * $pValue); } @@ -189,22 +193,22 @@ public function setHeight($pValue = 0) } /** - * Set width and height with proportional resize + * Set width and height with proportional resize. + * * @author Vincent@luo MSN:kele_100@hotmail.com - * @param int $width - * @param int $height - * @return \PhpOffice\PhpPresentation\Shape\AbstractGraphic + * + * @return self */ - public function setWidthAndHeight($width = 0, $height = 0) + public function setWidthAndHeight(int $width = 0, int $height = 0) { $xratio = $width / $this->width; $yratio = $height / $this->height; - if ($this->resizeProportional && !($width == 0 || $height == 0)) { + if ($this->resizeProportional && !(0 == $width || 0 == $height)) { if (($xratio * $this->height) < $height) { $this->height = (int) ceil($xratio * $this->height); - $this->width = $width; + $this->width = $width; } else { - $this->width = (int) ceil($yratio * $this->width); + $this->width = (int) ceil($yratio * $this->width); $this->height = $height; } } @@ -213,9 +217,9 @@ public function setWidthAndHeight($width = 0, $height = 0) } /** - * Get ResizeProportional + * Get ResizeProportional. * - * @return boolean + * @return bool */ public function isResizeProportional() { @@ -223,12 +227,11 @@ public function isResizeProportional() } /** - * Set ResizeProportional + * Set ResizeProportional. * - * @param boolean $pValue - * @return \PhpOffice\PhpPresentation\Shape\AbstractDrawing + * @param bool $pValue */ - public function setResizeProportional($pValue = true) + public function setResizeProportional($pValue = true): self { $this->resizeProportional = $pValue; @@ -236,11 +239,11 @@ public function setResizeProportional($pValue = true) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->name . $this->description . parent::getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/AutoShape.php b/src/PhpPresentation/Shape/AutoShape.php new file mode 100644 index 0000000000..3d2c21ca59 --- /dev/null +++ b/src/PhpPresentation/Shape/AutoShape.php @@ -0,0 +1,300 @@ +outline = new Outline(); + } + + /** + * @return string + */ + public function getText(): string + { + return $this->text; + } + + /** + * @param string $text + * + * @return self + */ + public function setText(string $text): self + { + $this->text = $text; + + return $this; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @param string $type + * + * @return self + */ + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } + + /** + * @return Outline + */ + public function getOutline(): Outline + { + return $this->outline; + } + + /** + * @param Outline $outline + * + * @return self + */ + public function setOutline(Outline $outline): self + { + $this->outline = $outline; + + return $this; + } +} diff --git a/src/PhpPresentation/Shape/Chart.php b/src/PhpPresentation/Shape/Chart.php index a851801fbe..3d56b7378e 100644 --- a/src/PhpPresentation/Shape/Chart.php +++ b/src/PhpPresentation/Shape/Chart.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\ComparableInterface; @@ -24,148 +27,187 @@ use PhpOffice\PhpPresentation\Shape\Chart\View3D; /** - * Chart element + * Chart element. */ class Chart extends AbstractGraphic implements ComparableInterface { + public const BLANKAS_GAP = 'gap'; + public const BLANKAS_ZERO = 'zero'; + public const BLANKAS_SPAN = 'span'; + /** - * Title + * Title. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\Title + * @var Title */ private $title; /** - * Legend + * Legend. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @var Legend */ private $legend; /** - * Plot area + * Plot area. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\PlotArea + * @var PlotArea */ private $plotArea; /** - * View 3D + * View 3D. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\View3D + * @var View3D */ private $view3D; /** - * Include spreadsheet for editing data? Requires PHPExcel in the same folder as PhpPresentation + * Is the spreadsheet included for editing data ? * * @var bool */ private $includeSpreadsheet = false; /** - * Create a new Chart + * How to display blank (missing) values? Not set by default. + * + * @var string + */ + private $displayBlankAs = self::BLANKAS_ZERO; + + /** + * Create a new Chart. */ public function __construct() { // Initialize - $this->title = new Title(); - $this->legend = new Legend(); + $this->title = new Title(); + $this->legend = new Legend(); $this->plotArea = new PlotArea(); - $this->view3D = new View3D(); + $this->view3D = new View3D(); // Initialize parent parent::__construct(); } - + public function __clone() { parent::__clone(); - - $this->title = clone $this->title; - $this->legend = clone $this->legend; - $this->plotArea = clone $this->plotArea; - $this->view3D = clone $this->view3D; + + $this->title = clone $this->title; + $this->legend = clone $this->legend; + $this->plotArea = clone $this->plotArea; + $this->view3D = clone $this->view3D; } /** - * Get Title + * How missing/blank values are displayed on chart (dispBlanksAs property) * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return string */ - public function getTitle() + public function getDisplayBlankAs(): string + { + return $this->displayBlankAs; + } + + /** + * Get Title. + * + * @return Title + */ + public function getTitle(): Title { return $this->title; } /** - * Get Legend + * Get Legend. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @return Legend */ - public function getLegend() + public function getLegend(): Legend { return $this->legend; } /** - * Get PlotArea + * Get PlotArea. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\PlotArea + * @return PlotArea */ - public function getPlotArea() + public function getPlotArea(): PlotArea { return $this->plotArea; } /** - * Get View3D + * Get View3D. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D + * @return View3D */ - public function getView3D() + public function getView3D(): View3D { return $this->view3D; } /** - * Include spreadsheet for editing data? Requires PHPExcel in the same folder as PhpPresentation + * Is the spreadsheet included for editing data ? * - * @return boolean + * @return bool */ - public function hasIncludedSpreadsheet() + public function hasIncludedSpreadsheet(): bool { return $this->includeSpreadsheet; } /** - * Include spreadsheet for editing data? Requires PHPExcel in the same folder as PhpPresentation + * Define a way to display missing/blank values (dispBlanksAs property) * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart + * @param string $value + * + * @return self */ - public function setIncludeSpreadsheet($value = false) + public function setDisplayBlankAs(string $value): self + { + if (in_array($value, [self::BLANKAS_GAP, self::BLANKAS_SPAN, self::BLANKAS_ZERO])) { + $this->displayBlankAs = $value; + } + + return $this; + } + + /** + * Is the spreadsheet included for editing data ? + * + * @param bool $value + * + * @return self + */ + public function setIncludeSpreadsheet(bool $value = false): self { $this->includeSpreadsheet = $value; + return $this; } /** - * Get indexed filename (using image index) + * Get indexed filename (using image index). * * @return string */ - public function getIndexedFilename() + public function getIndexedFilename(): string { return 'chart' . $this->getImageIndex() . '.xml'; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(parent::getHashCode() . $this->title->getHashCode() . $this->legend->getHashCode() . $this->plotArea->getHashCode() . $this->view3D->getHashCode() . ($this->includeSpreadsheet ? 1 : 0) . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Chart/Axis.php b/src/PhpPresentation/Shape/Chart/Axis.php index b2559bd2db..e82a85eb09 100644 --- a/src/PhpPresentation/Shape/Chart/Axis.php +++ b/src/PhpPresentation/Shape/Chart/Axis.php @@ -10,37 +10,46 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\Outline; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Axis - */ class Axis implements ComparableInterface { - const AXIS_X = 'x'; - const AXIS_Y = 'y'; + public const AXIS_X = 'x'; + public const AXIS_Y = 'y'; + + public const TICK_MARK_NONE = 'none'; + public const TICK_MARK_CROSS = 'cross'; + public const TICK_MARK_INSIDE = 'in'; + public const TICK_MARK_OUTSIDE = 'out'; - const TICK_MARK_NONE = 'none'; - const TICK_MARK_CROSS = 'cross'; - const TICK_MARK_INSIDE = 'in'; - const TICK_MARK_OUTSIDE = 'out'; + public const TICK_LABEL_POSITION_NEXT_TO = 'nextTo'; + public const TICK_LABEL_POSITION_HIGH = 'high'; + public const TICK_LABEL_POSITION_LOW = 'low'; /** - * Title + * Title. * * @var string */ private $title = 'Axis Title'; + /** + * @var int + */ + private $titleRotation = 0; + /** * Format code * @@ -49,19 +58,19 @@ class Axis implements ComparableInterface private $formatCode = ''; /** - * Font + * Font. * - * @var \PhpOffice\PhpPresentation\Style\Font + * @var Font */ private $font; /** - * @var Gridlines + * @var Gridlines|null */ protected $majorGridlines; /** - * @var Gridlines + * @var Gridlines|null */ protected $minorGridlines; @@ -85,6 +94,11 @@ class Axis implements ComparableInterface */ protected $majorTickMark = self::TICK_MARK_NONE; + /** + * @var string + */ + protected $tickLabelPosition = self::TICK_LABEL_POSITION_NEXT_TO; + /** * @var float */ @@ -101,39 +115,40 @@ class Axis implements ComparableInterface protected $outline; /** - * @var boolean + * @var bool */ protected $isVisible = true; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Axis instance + * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Axis instance. * * @param string $title Title */ - public function __construct($title = 'Axis Title') + public function __construct(string $title = 'Axis Title') { $this->title = $title; $this->outline = new Outline(); - $this->font = new Font(); + $this->font = new Font(); } /** - * Get Title + * Get Title. * * @return string */ - public function getTitle() + public function getTitle(): string { return $this->title; } /** - * Set Title + * Set Title. * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Axis + * @param string $value + * + * @return self */ - public function setTitle($value = 'Axis Title') + public function setTitle(string $value = 'Axis Title'): self { $this->title = $value; @@ -141,45 +156,47 @@ public function setTitle($value = 'Axis Title') } /** - * Get font + * Get font. * - * @return \PhpOffice\PhpPresentation\Style\Font + * @return Font|null */ - public function getFont() + public function getFont(): ?Font { return $this->font; } /** - * Set font + * Set font. + * + * @param Font|null $font * - * @param \PhpOffice\PhpPresentation\Style\Font $pFont Font - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @return self */ - public function setFont(Font $pFont = null) + public function setFont(Font $font = null): self { - $this->font = $pFont; + $this->font = $font; + return $this; } /** - * Get Format Code + * Get Format Code. * * @return string */ - public function getFormatCode() + public function getFormatCode(): string { return $this->formatCode; } /** - * Set Format Code + * Set Format Code. + * + * @param string $value * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Axis + * @return self */ - public function setFormatCode($value = '') + public function setFormatCode(string $value = ''): self { $this->formatCode = $value; @@ -189,162 +206,190 @@ public function setFormatCode($value = '') /** * @return int|null */ - public function getMinBounds() + public function getMinBounds(): ?int { return $this->minBounds; } /** * @param int|null $minBounds - * @return Axis + * + * @return self */ - public function setMinBounds($minBounds = null) + public function setMinBounds(int $minBounds = null): self { - $this->minBounds = is_null($minBounds) ? null : (int)$minBounds; + $this->minBounds = is_null($minBounds) ? null : $minBounds; + return $this; } /** * @return int|null */ - public function getMaxBounds() + public function getMaxBounds(): ?int { return $this->maxBounds; } /** * @param int|null $maxBounds - * @return Axis + * + * @return self */ - public function setMaxBounds($maxBounds = null) + public function setMaxBounds(int $maxBounds = null): self { - $this->maxBounds = is_null($maxBounds) ? null : (int)$maxBounds; + $this->maxBounds = is_null($maxBounds) ? null : $maxBounds; + return $this; } - /** - * @return Gridlines - */ - public function getMajorGridlines() + public function getMajorGridlines(): ?Gridlines { return $this->majorGridlines; } - /** - * @param Gridlines $majorGridlines - * @return Axis - */ - public function setMajorGridlines(Gridlines $majorGridlines) + public function setMajorGridlines(Gridlines $majorGridlines): self { $this->majorGridlines = $majorGridlines; + return $this; } - /** - * @return Gridlines - */ - public function getMinorGridlines() + public function getMinorGridlines(): ?Gridlines { return $this->minorGridlines; } - /** - * @param Gridlines $minorGridlines - * @return Axis - */ - public function setMinorGridlines(Gridlines $minorGridlines) + public function setMinorGridlines(Gridlines $minorGridlines): self { $this->minorGridlines = $minorGridlines; + return $this; } /** * @return string */ - public function getMinorTickMark() + public function getMinorTickMark(): string { return $this->minorTickMark; } /** - * @param string $pTickMark - * @return Axis + * @param string $tickMark + * + * @return self */ - public function setMinorTickMark($pTickMark = self::TICK_MARK_NONE) + public function setMinorTickMark(string $tickMark = self::TICK_MARK_NONE): self { - $this->minorTickMark = $pTickMark; + $this->minorTickMark = $tickMark; + return $this; } /** * @return string */ - public function getMajorTickMark() + public function getMajorTickMark(): string { return $this->majorTickMark; } /** - * @param string $pTickMark - * @return Axis + * @param string $tickMark + * + * @return self */ - public function setMajorTickMark($pTickMark = self::TICK_MARK_NONE) + public function setMajorTickMark(string $tickMark = self::TICK_MARK_NONE): self { - $this->majorTickMark = $pTickMark; + $this->majorTickMark = $tickMark; + return $this; } /** - * @return float + * @return float|null */ - public function getMinorUnit() + public function getMinorUnit(): ?float { return $this->minorUnit; } /** - * @param float $pUnit - * @return Axis + * @param float|null $unit + * + * @return self */ - public function setMinorUnit($pUnit = null) + public function setMinorUnit($unit = null): self { - $this->minorUnit = $pUnit; + $this->minorUnit = $unit; + return $this; } /** - * @return float + * @return float|null */ - public function getMajorUnit() + public function getMajorUnit(): ?float { return $this->majorUnit; } /** - * @param float $pUnit - * @return Axis + * @param float|null $unit + * + * @return self */ - public function setMajorUnit($pUnit = null) + public function setMajorUnit(float $unit = null): self { - $this->majorUnit = $pUnit; + $this->majorUnit = $unit; + return $this; } /** * @return Outline */ - public function getOutline() + public function getOutline(): Outline { return $this->outline; } /** * @param Outline $outline - * @return Axis + * + * @return self */ - public function setOutline($outline) + public function setOutline(Outline $outline): self { $this->outline = $outline; + + return $this; + } + + /** + * @return int + */ + public function getTitleRotation(): int + { + return $this->titleRotation; + } + + /** + * @param int $titleRotation + * + * @return self + */ + public function setTitleRotation(int $titleRotation): self + { + if ($titleRotation < 0) { + $titleRotation = 0; + } + if ($titleRotation > 360) { + $titleRotation = 360; + } + $this->titleRotation = $titleRotation; + return $this; } @@ -353,64 +398,95 @@ public function setOutline($outline) * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->title . $this->formatCode . __CLASS__); } /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index - * @return $this + * @param int $value Hash index + * + * @return self */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + return $this; } /** * Axis is hidden ? - * @return boolean + * + * @return bool */ - public function isVisible() + public function isVisible(): bool { return $this->isVisible; } /** - * Hide an axis + * Hide an axis. + * + * @param bool $value delete + * + * @return self + */ + public function setIsVisible(bool $value): self + { + $this->isVisible = $value; + + return $this; + } + + /** + * @return string + */ + public function getTickLabelPosition(): string + { + return $this->tickLabelPosition; + } + + /** + * @param string $value * - * @param boolean $value delete - * @return $this + * @return self */ - public function setIsVisible($value) + public function setTickLabelPosition(string $value = self::TICK_LABEL_POSITION_NEXT_TO): self { - $this->isVisible = (bool)$value; + if (in_array($value, [ + self::TICK_LABEL_POSITION_HIGH, + self::TICK_LABEL_POSITION_LOW, + self::TICK_LABEL_POSITION_NEXT_TO, + ])) { + $this->tickLabelPosition = $value; + } + return $this; } } diff --git a/src/PhpPresentation/Shape/Chart/Gridlines.php b/src/PhpPresentation/Shape/Chart/Gridlines.php index 4040a5a4be..83f1248865 100644 --- a/src/PhpPresentation/Shape/Chart/Gridlines.php +++ b/src/PhpPresentation/Shape/Chart/Gridlines.php @@ -1,4 +1,22 @@ outline = $outline; + return $this; } } diff --git a/src/PhpPresentation/Shape/Chart/Legend.php b/src/PhpPresentation/Shape/Chart/Legend.php index b169d69e33..6878f62a8f 100644 --- a/src/PhpPresentation/Shape/Chart/Legend.php +++ b/src/PhpPresentation/Shape/Chart/Legend.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\ComparableInterface; @@ -24,102 +27,102 @@ use PhpOffice\PhpPresentation\Style\Font; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Legend + * \PhpOffice\PhpPresentation\Shape\Chart\Legend. */ class Legend implements ComparableInterface { /** Legend positions */ - const POSITION_BOTTOM = 'b'; - const POSITION_LEFT = 'l'; - const POSITION_RIGHT = 'r'; - const POSITION_TOP = 't'; - const POSITION_TOPRIGHT = 'tr'; + public const POSITION_BOTTOM = 'b'; + public const POSITION_LEFT = 'l'; + public const POSITION_RIGHT = 'r'; + public const POSITION_TOP = 't'; + public const POSITION_TOPRIGHT = 'tr'; /** - * Visible + * Visible. * - * @var boolean + * @var bool */ private $visible = true; /** - * Position + * Position. * * @var string */ private $position = self::POSITION_RIGHT; /** - * OffsetX (as a fraction of the chart) + * OffsetX (as a fraction of the chart). * * @var float */ private $offsetX = 0; /** - * OffsetY (as a fraction of the chart) + * OffsetY (as a fraction of the chart). * * @var float */ private $offsetY = 0; /** - * Width (as a fraction of the chart) + * Width (as a fraction of the chart). * * @var float */ private $width = 0; /** - * Height (as a fraction of the chart) + * Height (as a fraction of the chart). * * @var float */ private $height = 0; /** - * Font + * Font. * - * @var \PhpOffice\PhpPresentation\Style\Font + * @var Font|null */ private $font; /** - * Border + * Border. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $border; /** - * Fill + * Fill. * * @var \PhpOffice\PhpPresentation\Style\Fill */ private $fill; /** - * Alignment + * Alignment. * * @var \PhpOffice\PhpPresentation\Style\Alignment */ private $alignment; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Legend instance + * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Legend instance. */ public function __construct() { - $this->font = new Font(); - $this->border = new Border(); - $this->fill = new Fill(); + $this->font = new Font(); + $this->border = new Border(); + $this->fill = new Fill(); $this->alignment = new Alignment(); } /** - * Get Visible + * Get Visible. * - * @return boolean + * @return bool */ public function isVisible() { @@ -127,19 +130,21 @@ public function isVisible() } /** - * Set Visible + * Set Visible. + * + * @param bool $value * - * @param boolean $value * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend */ public function setVisible($value = true) { $this->visible = $value; + return $this; } /** - * Get Position + * Get Position. * * @return string */ @@ -149,130 +154,113 @@ public function getPosition() } /** - * Set Position + * Set Position. + * + * @param string $value * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend */ public function setPosition($value = self::POSITION_RIGHT) { $this->position = $value; + return $this; } /** - * Get OffsetX (as a fraction of the chart) - * - * @return float + * Get OffsetX (as a fraction of the chart). */ - public function getOffsetX() + public function getOffsetX(): float { return $this->offsetX; } /** - * Set OffsetX (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * Set OffsetX (as a fraction of the chart). */ - public function setOffsetX($value = 0) + public function setOffsetX(float $pValue = 0): self { - $this->offsetX = (double)$value; + $this->offsetX = $pValue; + return $this; } /** - * Get OffsetY (as a fraction of the chart) - * - * @return float + * Get OffsetY (as a fraction of the chart). */ - public function getOffsetY() + public function getOffsetY(): float { return $this->offsetY; } /** - * Set OffsetY (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * Set OffsetY (as a fraction of the chart). */ - public function setOffsetY($value = 0) + public function setOffsetY(float $pValue = 0): self { - $this->offsetY = (double)$value; + $this->offsetY = $pValue; + return $this; } /** - * Get Width (as a fraction of the chart) - * - * @return float + * Get Width (as a fraction of the chart). */ - public function getWidth() + public function getWidth(): float { return $this->width; } /** - * Set Width (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * Set Width (as a fraction of the chart). */ - public function setWidth($value = 0) + public function setWidth(float $pValue = 0): self { - $this->width = (double)$value; + $this->width = $pValue; + return $this; } /** - * Get Height (as a fraction of the chart) - * - * @return float + * Get Height (as a fraction of the chart). */ - public function getHeight() + public function getHeight(): float { return $this->height; } /** - * Set Height (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * Set Height (as a fraction of the chart). */ - public function setHeight($value = 0) + public function setHeight(float $value = 0): self { - $this->height = (double)$value; + $this->height = $value; + return $this; } /** - * Get font - * - * @return \PhpOffice\PhpPresentation\Style\Font + * Get font. */ - public function getFont() + public function getFont(): ?Font { return $this->font; } /** - * Set font + * Set font. * - * @param \PhpOffice\PhpPresentation\Style\Font $pFont Font - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param Font|null $pFont Font */ - public function setFont(Font $pFont = null) + public function setFont(Font $pFont = null): self { $this->font = $pFont; + return $this; } /** - * Get Border + * Get Border. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -282,19 +270,19 @@ public function getBorder() } /** - * Set Border + * Set Border. * - * @param \PhpOffice\PhpPresentation\Style\Border $border - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend */ public function setBorder(Border $border) { $this->border = $border; + return $this; } /** - * Get Fill + * Get Fill. * * @return \PhpOffice\PhpPresentation\Style\Fill */ @@ -304,19 +292,19 @@ public function getFill() } /** - * Set Fill + * Set Fill. * - * @param \PhpOffice\PhpPresentation\Style\Fill $fill - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend */ public function setFill(Fill $fill) { $this->fill = $fill; + return $this; } /** - * Get alignment + * Get alignment. * * @return \PhpOffice\PhpPresentation\Style\Alignment */ @@ -326,58 +314,61 @@ public function getAlignment() } /** - * Set alignment + * Set alignment. * - * @param \PhpOffice\PhpPresentation\Style\Alignment $alignment - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend */ public function setAlignment(Alignment $alignment) { $this->alignment = $alignment; + return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->position . $this->offsetX . $this->offsetY . $this->width . $this->height . $this->font->getHashCode() . $this->border->getHashCode() . $this->fill->getHashCode() . $this->alignment->getHashCode() . ($this->visible ? 't' : 'f') . __CLASS__); } /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return Legend */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + return $this; } } diff --git a/src/PhpPresentation/Shape/Chart/Marker.php b/src/PhpPresentation/Shape/Chart/Marker.php index 7360697750..008f787b3b 100644 --- a/src/PhpPresentation/Shape/Chart/Marker.php +++ b/src/PhpPresentation/Shape/Chart/Marker.php @@ -10,30 +10,36 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Axis - */ +use PhpOffice\PhpPresentation\Style\Border; +use PhpOffice\PhpPresentation\Style\Fill; + class Marker { - const SYMBOL_CIRCLE = 'circle'; - const SYMBOL_DASH = 'dash'; - const SYMBOL_DIAMOND = 'diamond'; - const SYMBOL_DOT = 'dot'; - const SYMBOL_NONE = 'none'; - const SYMBOL_PLUS = 'plus'; - const SYMBOL_SQUARE = 'square'; - const SYMBOL_STAR = 'star'; - const SYMBOL_TRIANGLE = 'triangle'; - const SYMBOL_X = 'x'; - - public static $arraySymbol = array( + public const SYMBOL_CIRCLE = 'circle'; + public const SYMBOL_DASH = 'dash'; + public const SYMBOL_DIAMOND = 'diamond'; + public const SYMBOL_DOT = 'dot'; + public const SYMBOL_NONE = 'none'; + public const SYMBOL_PLUS = 'plus'; + public const SYMBOL_SQUARE = 'square'; + public const SYMBOL_STAR = 'star'; + public const SYMBOL_TRIANGLE = 'triangle'; + public const SYMBOL_X = 'x'; + + /** + * @var array + */ + public static $arraySymbol = [ self::SYMBOL_CIRCLE, self::SYMBOL_DASH, self::SYMBOL_DIAMOND, @@ -43,8 +49,8 @@ class Marker self::SYMBOL_SQUARE, self::SYMBOL_STAR, self::SYMBOL_TRIANGLE, - self::SYMBOL_X - ); + self::SYMBOL_X, + ]; /** * @var string @@ -57,39 +63,81 @@ class Marker protected $size = 5; /** - * @return string + * @var Fill + */ + protected $fill; + + /** + * @var Border */ - public function getSymbol() + protected $border; + + public function __construct() + { + $this->fill = new Fill(); + $this->border = new Border(); + } + + public function getSymbol(): string { return $this->symbol; } + public function setSymbol(string $symbol = self::SYMBOL_NONE): self + { + $this->symbol = $symbol; + + return $this; + } + + public function getSize(): int + { + return $this->size; + } + + public function setSize(int $size = 5): self + { + $this->size = $size; + + return $this; + } + /** - * @param string $symbol - * @return Marker + * @return Fill */ - public function setSymbol($symbol = self::SYMBOL_NONE) + public function getFill(): Fill { - $this->symbol = $symbol; + return $this->fill; + } + + /** + * @param Fill $fill + * + * @return self + */ + public function setFill(Fill $fill): self + { + $this->fill = $fill; return $this; } /** - * @return int + * @return Border */ - public function getSize() + public function getBorder(): Border { - return $this->size; + return $this->border; } /** - * @param int $size - * @return Marker + * @param Border $border + * + * @return self */ - public function setSize($size = 5) + public function setBorder(Border $border): self { - $this->size = $size; + $this->border = $border; return $this; } diff --git a/src/PhpPresentation/Shape/Chart/PlotArea.php b/src/PhpPresentation/Shape/Chart/PlotArea.php index cdabff69fd..2eb97174f8 100644 --- a/src/PhpPresentation/Shape/Chart/PlotArea.php +++ b/src/PhpPresentation/Shape/Chart/PlotArea.php @@ -10,108 +10,99 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException; use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType; /** - * \PhpOffice\PhpPresentation\Shape\Chart\PlotArea + * \PhpOffice\PhpPresentation\Shape\Chart\PlotArea. */ class PlotArea implements ComparableInterface { /** - * Type + * Type. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType + * @var AbstractType|null */ private $type; /** - * Axis X + * Axis X. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\Axis + * @var Axis */ private $axisX; /** - * Axis Y + * Axis Y. * - * @var \PhpOffice\PhpPresentation\Shape\Chart\Axis + * @var Axis */ private $axisY; /** - * OffsetX (as a fraction of the chart) + * OffsetX (as a fraction of the chart). * * @var float */ private $offsetX = 0; /** - * OffsetY (as a fraction of the chart) + * OffsetY (as a fraction of the chart). * * @var float */ private $offsetY = 0; /** - * Width (as a fraction of the chart) + * Width (as a fraction of the chart). * * @var float */ private $width = 0; /** - * Height (as a fraction of the chart) + * Height (as a fraction of the chart). * * @var float */ private $height = 0; - /** - * Create a new \PhpOffice\PhpPresentation\Shape\Chart\PlotArea instance - */ public function __construct() { - $this->type = null; $this->axisX = new Axis(); $this->axisY = new Axis(); } - + public function __clone() { - $this->axisX = clone $this->axisX; - $this->axisY = clone $this->axisY; + $this->axisX = clone $this->axisX; + $this->axisY = clone $this->axisY; } /** - * Get type - * - * @return AbstractType - * @throws \Exception + * @throws UndefinedChartTypeException */ - public function getType() + public function getType(): AbstractType { if (is_null($this->type)) { - throw new \Exception('Chart type has not been set.'); + throw new UndefinedChartTypeException(); } return $this->type; } - /** - * Set type - * - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\PlotArea - */ - public function setType(Type\AbstractType $value) + public function setType(AbstractType $value): self { $this->type = $value; @@ -119,158 +110,141 @@ public function setType(Type\AbstractType $value) } /** - * Get Axis X - * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Axis + * Get Axis X. */ - public function getAxisX() + public function getAxisX(): Axis { return $this->axisX; } /** - * Get Axis Y - * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Axis + * Get Axis Y. */ - public function getAxisY() + public function getAxisY(): Axis { return $this->axisY; } /** - * Get OffsetX (as a fraction of the chart) - * - * @return float + * Get OffsetX (as a fraction of the chart). */ - public function getOffsetX() + public function getOffsetX(): float { return $this->offsetX; } /** - * Set OffsetX (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * Set OffsetX (as a fraction of the chart). */ - public function setOffsetX($value = 0) + public function setOffsetX(float $pValue = 0): self { - $this->offsetX = (double)$value; + $this->offsetX = $pValue; return $this; } /** - * Get OffsetY (as a fraction of the chart) - * - * @return float + * Get OffsetY (as a fraction of the chart). */ - public function getOffsetY() + public function getOffsetY(): float { return $this->offsetY; } /** - * Set OffsetY (as a fraction of the chart) + * Set OffsetY (as a fraction of the chart). * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return \PhpOffice\PhpPresentation\Shape\Chart\PlotArea */ - public function setOffsetY($value = 0) + public function setOffsetY(float $pValue = 0): self { - $this->offsetY = (double)$value; + $this->offsetY = $pValue; return $this; } /** - * Get Width (as a fraction of the chart) - * - * @return float + * Get Width (as a fraction of the chart). */ - public function getWidth() + public function getWidth(): float { return $this->width; } /** - * Set Width (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * Set Width (as a fraction of the chart). */ - public function setWidth($value = 0) + public function setWidth(int $pValue = 0): self { - $this->width = (double)$value; + $this->width = $pValue; return $this; } /** - * Get Height (as a fraction of the chart) - * - * @return float + * Get Height (as a fraction of the chart). */ - public function getHeight() + public function getHeight(): float { return $this->height; } /** - * Set Height (as a fraction of the chart) + * Set Height (as a fraction of the chart). * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return \PhpOffice\PhpPresentation\Shape\Chart\PlotArea */ - public function setHeight($value = 0) + public function setHeight(float $value = 0): self { - $this->height = (double)$value; + $this->height = $value; return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5((is_null($this->type) ? 'null' : $this->type->getHashCode()) . $this->axisX->getHashCode() . $this->axisY->getHashCode() . $this->offsetX . $this->offsetY . $this->width . $this->height . __CLASS__); } /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return PlotArea */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + return $this; } } diff --git a/src/PhpPresentation/Shape/Chart/Series.php b/src/PhpPresentation/Shape/Chart/Series.php index 63010293dd..ea1bf49965 100644 --- a/src/PhpPresentation/Shape/Chart/Series.php +++ b/src/PhpPresentation/Shape/Chart/Series.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\ComparableInterface; @@ -22,54 +25,49 @@ use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\Outline; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Series - */ class Series implements ComparableInterface { /* Label positions */ - const LABEL_BESTFIT = 'bestFit'; - const LABEL_BOTTOM = 'b'; - const LABEL_CENTER = 'ctr'; - const LABEL_INSIDEBASE = 'inBase'; - const LABEL_INSIDEEND = 'inEnd'; - const LABEL_LEFT = 'i'; - const LABEL_OUTSIDEEND = 'outEnd'; - const LABEL_RIGHT = 'r'; - const LABEL_TOP = 't'; + public const LABEL_BESTFIT = 'bestFit'; + public const LABEL_BOTTOM = 'b'; + public const LABEL_CENTER = 'ctr'; + public const LABEL_INSIDEBASE = 'inBase'; + public const LABEL_INSIDEEND = 'inEnd'; + public const LABEL_LEFT = 'i'; + public const LABEL_OUTSIDEEND = 'outEnd'; + public const LABEL_RIGHT = 'r'; + public const LABEL_TOP = 't'; /** - * DataPointFills (key/value) - * @var array + * DataPointFills (key/value). + * + * @var array */ - protected $dataPointFills = array(); + protected $dataPointFills = []; /** - * Data Label Number Format + * Data Label Number Format. + * * @var string */ protected $DlblNumFormat = ''; /** - * Separator - * @var string + * @var string|null */ - protected $separator = null; + protected $separator; /** - * Fill - * @var \PhpOffice\PhpPresentation\Style\Fill + * @var Fill|null */ protected $fill; /** - * Font - * @var \PhpOffice\PhpPresentation\Style\Font + * @var Font|null */ protected $font; /** - * Label position * @var string */ protected $labelPosition = 'ctr'; @@ -80,98 +78,101 @@ class Series implements ComparableInterface protected $marker; /** - * @var Outline + * @var Outline|null */ protected $outline; /** - * Show Category Name - * @var boolean + * Show Category Name. + * + * @var bool */ private $showCategoryName = false; /** - * Show Leader Lines - * @var boolean + * Show Leader Lines. + * + * @var bool */ private $showLeaderLines = true; /** - * Show Legend Key - * @var boolean + * Show Legend Key. + * + * @var bool */ private $showLegendKey = false; /** - * ShowPercentage - * @var boolean + * ShowPercentage. + * + * @var bool */ private $showPercentage = false; /** - * ShowSeriesName - * @var boolean + * ShowSeriesName. + * + * @var bool */ private $showSeriesName = false; /** - * ShowValue - * @var boolean + * ShowValue. + * + * @var bool */ private $showValue = true; /** - * Title + * Title. + * * @var string */ private $title = 'Series Title'; /** - * Values (key/value) - * @var array + * Values (key/value). + * + * @var array */ - private $values = array(); + private $values = []; /** - * Hash index - * @var string + * Hash index. + * + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Series instance - * - * @param string $title Title - * @param array $values Values + * @param string $title + * @param array $values */ - public function __construct($title = 'Series Title', $values = array()) + public function __construct(string $title = 'Series Title', array $values = []) { $this->fill = new Fill(); $this->font = new Font(); $this->font->setName('Calibri'); $this->font->setSize(9); - $this->title = $title; - $this->values = $values; $this->marker = new Marker(); + + $this->title = $title; + $this->values = $values; } /** - * Get Title - * - * @return string + * Get Title. */ - public function getTitle() + public function getTitle(): string { return $this->title; } /** - * Set Title - * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set Title. */ - public function setTitle($value = 'Series Title') + public function setTitle(string $value = 'Series Title'): self { $this->title = $value; @@ -179,66 +180,50 @@ public function setTitle($value = 'Series Title') } /** - * Get Data Label NumFormat - * - * @return string + * Get Data Label NumFormat. */ - public function getDlblNumFormat() + public function getDlblNumFormat(): string { return $this->DlblNumFormat; } /** - * Has Data Label NumFormat - * - * @return string + * Has Data Label NumFormat. */ - public function hasDlblNumFormat() + public function hasDlblNumFormat(): bool { return !empty($this->DlblNumFormat); } /** - * Set Data Label NumFormat - * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set Data Label NumFormat. */ - public function setDlblNumFormat($value = '') + public function setDlblNumFormat(string $value = ''): self { $this->DlblNumFormat = $value; + return $this; } /** - * Get Fill - * - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return Fill */ - public function getFill() + public function getFill(): ?Fill { return $this->fill; } - /** - * Set Fill - * - * @param \PhpOffice\PhpPresentation\Style\Fill $fill - * @return Series - */ - public function setFill(Fill $fill = null) + public function setFill(Fill $fill = null): self { $this->fill = $fill; + return $this; } /** - * Get DataPointFill - * - * @param int $dataPointIndex Data point index. - * @return \PhpOffice\PhpPresentation\Style\Fill + * @param int $dataPointIndex data point index */ - public function getDataPointFill($dataPointIndex) + public function getDataPointFill(int $dataPointIndex): Fill { if (!isset($this->dataPointFills[$dataPointIndex])) { $this->dataPointFills[$dataPointIndex] = new Fill(); @@ -248,46 +233,44 @@ public function getDataPointFill($dataPointIndex) } /** - * Get DataPointFills - * * @return Fill[] */ - public function getDataPointFills() + public function getDataPointFills(): array { return $this->dataPointFills; } /** - * Get Values + * Get Values. * - * @return array + * @return array */ - public function getValues() + public function getValues(): array { return $this->values; } /** - * Set Values + * Set Values. * - * @param array $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * @param array $values */ - public function setValues($value = array()) + public function setValues(array $values = []): self { - $this->values = $value; + $this->values = $values; return $this; } /** - * Add Value + * Add Value. * - * @param mixed $key - * @param mixed $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * @param string $key + * @param string|null $value + * + * @return self */ - public function addValue($key, $value) + public function addValue(string $key, ?string $value): self { $this->values[$key] = $value; @@ -295,22 +278,17 @@ public function addValue($key, $value) } /** - * Get ShowSeriesName - * - * @return boolean + * Get ShowSeriesName. */ - public function hasShowSeriesName() + public function hasShowSeriesName(): bool { return $this->showSeriesName; } /** - * Set ShowSeriesName - * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set ShowSeriesName. */ - public function setShowSeriesName($value) + public function setShowSeriesName(bool $value): self { $this->showSeriesName = $value; @@ -318,22 +296,17 @@ public function setShowSeriesName($value) } /** - * Get ShowCategoryName - * - * @return boolean + * Get ShowCategoryName. */ - public function hasShowCategoryName() + public function hasShowCategoryName(): bool { return $this->showCategoryName; } /** - * Set ShowCategoryName - * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set ShowCategoryName. */ - public function setShowCategoryName($value) + public function setShowCategoryName(bool $value): self { $this->showCategoryName = $value; @@ -341,45 +314,35 @@ public function setShowCategoryName($value) } /** - * Get ShowValue - * - * @return boolean + * Get ShowValue. */ - public function hasShowLegendKey() + public function hasShowLegendKey(): bool { return $this->showLegendKey; } /** - * Set ShowValue - * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set ShowValue. */ - public function setShowLegendKey($value) + public function setShowLegendKey(bool $value): self { - $this->showLegendKey = (bool)$value; + $this->showLegendKey = $value; return $this; } /** - * Get ShowValue - * - * @return boolean + * Get ShowValue. */ - public function hasShowValue() + public function hasShowValue(): bool { return $this->showValue; } /** - * Set ShowValue - * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set ShowValue. */ - public function setShowValue($value) + public function setShowValue(bool $value): self { $this->showValue = $value; @@ -387,73 +350,54 @@ public function setShowValue($value) } /** - * Get ShowPercentage - * - * @return boolean + * Get ShowPercentage. */ - public function hasShowPercentage() + public function hasShowPercentage(): bool { return $this->showPercentage; } /** - * Set ShowPercentage - * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set ShowPercentage. */ - public function setShowPercentage($value) + public function setShowPercentage(bool $value): self { $this->showPercentage = $value; return $this; } - /** - * Get ShowLeaderLines - * - * @return boolean - */ - public function hasShowSeparator() + public function hasShowSeparator(): bool { - return is_null($this->separator) ? false : true; + return !is_null($this->separator); } - /** - * Set Separator - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series - */ - public function setSeparator($pValue) + public function setSeparator(?string $pValue): self { $this->separator = $pValue; + return $this; } - /** - * Get Separator - * @return string - */ - public function getSeparator() + public function getSeparator(): ?string { return $this->separator; } /** - * Get ShowLeaderLines - * - * @return boolean + * Get ShowLeaderLines. */ - public function hasShowLeaderLines() + public function hasShowLeaderLines(): bool { return $this->showLeaderLines; } /** - * Set ShowLeaderLines + * Set ShowLeaderLines. * - * @param boolean $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * @param bool $value + * + * @return self */ public function setShowLeaderLines($value) { @@ -463,23 +407,21 @@ public function setShowLeaderLines($value) } /** - * Get font + * Get font. * - * @return \PhpOffice\PhpPresentation\Style\Font + * @return Font */ - public function getFont() + public function getFont(): ?Font { return $this->font; } /** - * Set font + * Set font. * - * @param \PhpOffice\PhpPresentation\Style\Font $pFont Font - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param Font|null $pFont Font */ - public function setFont(Font $pFont = null) + public function setFont(Font $pFont = null): self { $this->font = $pFont; @@ -487,105 +429,87 @@ public function setFont(Font $pFont = null) } /** - * Get label position - * - * @return string + * Get label position. */ - public function getLabelPosition() + public function getLabelPosition(): string { return $this->labelPosition; } /** - * Set label position - * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * Set label position. */ - public function setLabelPosition($value) + public function setLabelPosition(string $value): self { $this->labelPosition = $value; return $this; } - /** - * @return Marker - */ - public function getMarker() + public function getMarker(): Marker { return $this->marker; } - /** - * @param Marker $marker - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series - */ - public function setMarker(Marker $marker) + public function setMarker(Marker $marker): self { $this->marker = $marker; + return $this; } - /** - * @return Outline - */ - public function getOutline() + public function getOutline(): ?Outline { return $this->outline; } - /** - * @param Outline $outline - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series - */ - public function setOutline(Outline $outline) + public function setOutline(?Outline $outline): self { $this->outline = $outline; + return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5((is_null($this->fill) ? 'null' : $this->fill->getHashCode()) . (is_null($this->font) ? 'null' : $this->font->getHashCode()) . var_export($this->values, true) . var_export($this, true) . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series + * @param int $value Hash index */ - public function setHashIndex($value) + public function setHashIndex(int $value): self { $this->hashIndex = $value; + return $this; } /** - * @return mixed - * @link http://php.net/manual/en/language.oop5.cloning.php + * @see http://php.net/manual/en/language.oop5.cloning.php */ public function __clone() { diff --git a/src/PhpPresentation/Shape/Chart/Title.php b/src/PhpPresentation/Shape/Chart/Title.php index ef5fe783a2..a03165724b 100644 --- a/src/PhpPresentation/Shape/Chart/Title.php +++ b/src/PhpPresentation/Shape/Chart/Title.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\ComparableInterface; @@ -22,88 +25,88 @@ use PhpOffice\PhpPresentation\Style\Font; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Title + * \PhpOffice\PhpPresentation\Shape\Chart\Title. */ class Title implements ComparableInterface { /** - * Visible + * Visible. * - * @var boolean + * @var bool */ private $visible = true; /** - * Text + * Text. * * @var string */ private $text = 'Chart Title'; /** - * OffsetX (as a fraction of the chart) + * OffsetX (as a fraction of the chart). * * @var float */ private $offsetX = 0.01; /** - * OffsetY (as a fraction of the chart) + * OffsetY (as a fraction of the chart). * * @var float */ private $offsetY = 0.01; /** - * Width (as a fraction of the chart) + * Width (as a fraction of the chart). * * @var float */ private $width = 0; /** - * Height (as a fraction of the chart) + * Height (as a fraction of the chart). * * @var float */ private $height = 0; /** - * Alignment + * Alignment. * * @var \PhpOffice\PhpPresentation\Style\Alignment */ private $alignment; /** - * Font + * Font. * * @var \PhpOffice\PhpPresentation\Style\Font */ private $font; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Title instance + * Create a new \PhpOffice\PhpPresentation\Shape\Chart\Title instance. */ public function __construct() { $this->alignment = new Alignment(); - $this->font = new Font(); + $this->font = new Font(); $this->font->setName('Calibri'); $this->font->setSize(18); } /** - * Get Visible + * Get Visible. * - * @return boolean + * @return bool */ public function isVisible() { @@ -111,9 +114,10 @@ public function isVisible() } /** - * Set Visible + * Set Visible. + * + * @param bool $value * - * @param boolean $value * @return \PhpOffice\PhpPresentation\Shape\Chart\Title */ public function setVisible($value = true) @@ -124,7 +128,7 @@ public function setVisible($value = true) } /** - * Get Text + * Get Text. * * @return string */ @@ -134,9 +138,10 @@ public function getText() } /** - * Set Text + * Set Text. + * + * @param string $value * - * @param string $value * @return \PhpOffice\PhpPresentation\Shape\Chart\Title */ public function setText($value = null) @@ -147,22 +152,17 @@ public function setText($value = null) } /** - * Get OffsetX (as a fraction of the chart) - * - * @return float + * Get OffsetX (as a fraction of the chart). */ - public function getOffsetX() + public function getOffsetX(): float { return $this->offsetX; } /** - * Set OffsetX (as a fraction of the chart) - * - * @param float $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * Set OffsetX (as a fraction of the chart). */ - public function setOffsetX($value = 0.01) + public function setOffsetX(float $value = 0.01): self { $this->offsetX = $value; @@ -170,92 +170,73 @@ public function setOffsetX($value = 0.01) } /** - * Get OffsetY (as a fraction of the chart) - * - * @return float + * Get OffsetY (as a fraction of the chart). */ - public function getOffsetY() + public function getOffsetY(): float { return $this->offsetY; } /** - * Set OffsetY (as a fraction of the chart) - * - * @param float $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * Set OffsetY (as a fraction of the chart). */ - public function setOffsetY($value = 0.01) + public function setOffsetY(float $pValue = 0.01): self { - $this->offsetY = $value; + $this->offsetY = $pValue; return $this; } /** - * Get Width (as a fraction of the chart) - * - * @return float + * Get Width (as a fraction of the chart). */ - public function getWidth() + public function getWidth(): float { return $this->width; } /** - * Set Width (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * Set Width (as a fraction of the chart). */ - public function setWidth($value = 0) + public function setWidth(float $pValue = 0): self { - $this->width = (double)$value; + $this->width = $pValue; return $this; } /** - * Get Height (as a fraction of the chart) - * - * @return float + * Get Height (as a fraction of the chart). */ - public function getHeight() + public function getHeight(): float { return $this->height; } /** - * Set Height (as a fraction of the chart) - * - * @param float|int $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * Set Height (as a fraction of the chart). */ - public function setHeight($value = 0) + public function setHeight(float $value = 0): self { - $this->height = (double)$value; + $this->height = $value; return $this; } /** - * Get font - * - * @return \PhpOffice\PhpPresentation\Style\Font + * Get font. */ - public function getFont() + public function getFont(): ?Font { return $this->font; } /** - * Set font + * Set font. * - * @param \PhpOffice\PhpPresentation\Style\Font $pFont Font - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param Font|null $pFont Font */ - public function setFont(Font $pFont = null) + public function setFont(Font $pFont = null): self { $this->font = $pFont; @@ -263,7 +244,7 @@ public function setFont(Font $pFont = null) } /** - * Get alignment + * Get alignment. * * @return \PhpOffice\PhpPresentation\Style\Alignment */ @@ -273,9 +254,8 @@ public function getAlignment() } /** - * Set alignment + * Set alignment. * - * @param \PhpOffice\PhpPresentation\Style\Alignment $alignment * @return \PhpOffice\PhpPresentation\Shape\Chart\Title */ public function setAlignment(Alignment $alignment) @@ -286,39 +266,42 @@ public function setAlignment(Alignment $alignment) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->text . $this->offsetX . $this->offsetY . $this->width . $this->height . $this->font->getHashCode() . $this->alignment->getHashCode() . ($this->visible ? 't' : 'f') . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return Title */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + return $this; } } diff --git a/src/PhpPresentation/Shape/Chart/Type/AbstractType.php b/src/PhpPresentation/Shape/Chart/Type/AbstractType.php index 9e91520b1d..1121231157 100644 --- a/src/PhpPresentation/Shape/Chart/Type/AbstractType.php +++ b/src/PhpPresentation/Shape/Chart/Type/AbstractType.php @@ -10,160 +10,141 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\Shape\Chart\Series; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Type + * \PhpOffice\PhpPresentation\Shape\Chart\Type. */ abstract class AbstractType implements ComparableInterface { /** * Has Axis X? * - * @var boolean + * @var bool */ protected $hasAxisX = true; /** * Has Axis Y? * - * @var boolean + * @var bool */ protected $hasAxisY = true; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; - + /** - * Data - * - * @var array + * @var array */ - private $data = array(); + private $series = []; /** * Has Axis X? - * - * @return boolean */ - public function hasAxisX() + public function hasAxisX(): bool { return $this->hasAxisX; } /** * Has Axis Y? - * - * @return boolean */ - public function hasAxisY() + public function hasAxisY(): bool { return $this->hasAxisY; } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return AbstractType */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + return $this; } /** - * Add Series + * Add Series. * - * @param \PhpOffice\PhpPresentation\Shape\Chart\Series $value - * @return self + * @return $this */ public function addSeries(Series $value) { - $this->data[] = $value; + $this->series[] = $value; + return $this; } /** - * Get Series + * Get Series. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Series[] + * @return array */ - public function getSeries() + public function getSeries(): array { - return $this->data; + return $this->series; } /** - * Set Series + * Set Series. * - * @param array $value Array of \PhpOffice\PhpPresentation\Shape\Chart\Series - * @return self - */ - public function setSeries($value = array()) - { - $this->data = $value; - return $this; - } - - /** - * Get Data + * @param array $series * - * @deprecated getSeries + * @return $this */ - public function getData() + public function setSeries(array $series = []) { - return $this->getSeries(); - } + $this->series = $series; - /** - * Set Data - * - * @deprecated setSeries - */ - public function setData($value = array()) - { - return $this->setSeries($value); + return $this; } /** - * @return mixed - * @link http://php.net/manual/en/language.oop5.cloning.php + * @see http://php.net/manual/en/language.oop5.cloning.php */ public function __clone() { - $arrayClone = array(); - foreach ($this->data as $itemSeries) { + $arrayClone = []; + foreach ($this->series as $itemSeries) { $arrayClone[] = clone $itemSeries; } - $this->data = $arrayClone; + $this->series = $arrayClone; } } diff --git a/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php index 4b2357b69a..234717698d 100644 --- a/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php +++ b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php @@ -10,66 +10,75 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar + * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar. */ class AbstractTypeBar extends AbstractType { /** Orientation of bars */ - const DIRECTION_VERTICAL = 'col'; - const DIRECTION_HORIZONTAL = 'bar'; + public const DIRECTION_VERTICAL = 'col'; + public const DIRECTION_HORIZONTAL = 'bar'; /** Grouping of bars */ - const GROUPING_CLUSTERED = 'clustered'; //Chart series are drawn next to each other along the category axis. - const GROUPING_STACKED = 'stacked'; //Chart series are drawn next to each other on the value axis. - const GROUPING_PERCENTSTACKED = 'percentStacked'; //Chart series are drawn next to each other along the value axis and scaled to total 100% - + public const GROUPING_CLUSTERED = 'clustered'; //Chart series are drawn next to each other along the category axis. + public const GROUPING_STACKED = 'stacked'; //Chart series are drawn next to each other on the value axis. + public const GROUPING_PERCENTSTACKED = 'percentStacked'; //Chart series are drawn next to each other along the value axis and scaled to total 100% /** - * Orientation of bars + * Orientation of bars. * * @var string */ protected $barDirection = self::DIRECTION_VERTICAL; - /** - * Grouping of bars + * Grouping of bars. * * @var string */ protected $barGrouping = self::GROUPING_CLUSTERED; - /** - * Space between bar or columns clusters + * Space between bar or columns clusters. * * @var int */ protected $gapWidthPercent = 150; + /** + * Overlap within bar or columns clusters. Value between 100 and -100 percent. + * For stacked bar charts, the default overlap will be 100, for grouped bar charts 0. + * + * @var int + */ + protected $overlapWidthPercent = 0; /** - * Set bar orientation + * Set bar orientation. * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar + * @param string $value + * + * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar */ public function setBarDirection($value = self::DIRECTION_VERTICAL) { $this->barDirection = $value; + return $this; } /** - * Get orientation + * Get orientation. * * @return string */ @@ -79,19 +88,26 @@ public function getBarDirection() } /** - * Set bar grouping (stack or expanded style bar) + * Set bar grouping (stack or expanded style bar). + * + * @param string $value * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar + * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar */ public function setBarGrouping($value = self::GROUPING_CLUSTERED) { $this->barGrouping = $value; + $this->overlapWidthPercent = 0; + + if ($value === self::GROUPING_STACKED || $value === self::GROUPING_PERCENTSTACKED) { + $this->overlapWidthPercent = 100; + } + return $this; } /** - * Get grouping (stack or expanded style bar) + * Get grouping (stack or expanded style bar). * * @return string */ @@ -110,6 +126,7 @@ public function getGapWidthPercent() /** * @param int $gapWidthPercent + * * @return $this */ public function setGapWidthPercent($gapWidthPercent) @@ -121,20 +138,48 @@ public function setGapWidthPercent($gapWidthPercent) $gapWidthPercent = 500; } $this->gapWidthPercent = $gapWidthPercent; + return $this; } - + /** - * Get hash code + * @return int + */ + public function getOverlapWidthPercent(): int + { + return $this->overlapWidthPercent; + } + + /** + * @param int $value overlap width percentage + * + * @return self + */ + public function setOverlapWidthPercent(int $value): self + { + if ($value < -100) { + $value = -100; + } + if ($value > 100) { + $value = 100; + } + $this->overlapWidthPercent = $value; + + return $this; + } + + /** + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hash = ''; foreach ($this->getSeries() as $series) { $hash .= $series->getHashCode(); } + return $hash; } } diff --git a/src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php new file mode 100644 index 0000000000..3040f0bc3e --- /dev/null +++ b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php @@ -0,0 +1,65 @@ +isSmooth; + } + + /** + * Set Line Smoothness + * + * @param bool $value + * + * @return AbstractTypeLine + */ + public function setIsSmooth(bool $value = true): AbstractTypeLine + { + $this->isSmooth = $value; + + return $this; + } + + /** + * Get hash code. + * + * @return string Hash code + */ + public function getHashCode(): string + { + return md5($this->isSmooth() ? '1' : '0'); + } +} diff --git a/src/PhpPresentation/Shape/Chart/Type/AbstractTypePie.php b/src/PhpPresentation/Shape/Chart/Type/AbstractTypePie.php index f055fe3d49..b538d9a16b 100644 --- a/src/PhpPresentation/Shape/Chart/Type/AbstractTypePie.php +++ b/src/PhpPresentation/Shape/Chart/Type/AbstractTypePie.php @@ -10,67 +10,67 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar + * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar. */ class AbstractTypePie extends AbstractType { /** - * Create a new self instance + * Create a new self instance. */ public function __construct() { $this->hasAxisX = false; $this->hasAxisY = false; } - + /** - * Explosion of the Pie + * Explosion of the Pie. * - * @var integer + * @var int */ protected $explosion = 0; - + /** - * Set explosion - * - * @param integer $value - * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypePie + * Set explosion. */ - public function setExplosion($value = 0) + public function setExplosion(int $value = 0): self { $this->explosion = $value; + return $this; } - + /** - * Get orientation - * - * @return string + * Get orientation. */ - public function getExplosion() + public function getExplosion(): int { return $this->explosion; } - + /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hash = ''; foreach ($this->getSeries() as $series) { $hash .= $series->getHashCode(); } + return $hash; } } diff --git a/src/PhpPresentation/Shape/Chart/Type/Area.php b/src/PhpPresentation/Shape/Chart/Type/Area.php index fdfc5aaed3..49fc9bd6b2 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Area.php +++ b/src/PhpPresentation/Shape/Chart/Type/Area.php @@ -10,31 +10,35 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Area + * \PhpOffice\PhpPresentation\Shape\Chart\Type\Area. */ class Area extends AbstractType implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hash = ''; foreach ($this->getSeries() as $series) { $hash .= $series->getHashCode(); } + return md5($hash . __CLASS__); } } diff --git a/src/PhpPresentation/Shape/Chart/Type/Bar.php b/src/PhpPresentation/Shape/Chart/Type/Bar.php index da44e04c68..9ea5b3dc7e 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Bar.php +++ b/src/PhpPresentation/Shape/Chart/Type/Bar.php @@ -10,26 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar + * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar. */ class Bar extends AbstractTypeBar implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(parent::getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Chart/Type/Bar3D.php b/src/PhpPresentation/Shape/Chart/Type/Bar3D.php index 540a53069f..1011ad071b 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Bar3D.php +++ b/src/PhpPresentation/Shape/Chart/Type/Bar3D.php @@ -10,26 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D + * \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D. */ class Bar3D extends AbstractTypeBar implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(parent::getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Chart/Type/Doughnut.php b/src/PhpPresentation/Shape/Chart/Type/Doughnut.php new file mode 100644 index 0000000000..292c823262 --- /dev/null +++ b/src/PhpPresentation/Shape/Chart/Type/Doughnut.php @@ -0,0 +1,74 @@ +holeSize; + } + + /** + * @param int $holeSize + * + * @return Doughnut + * + * @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.holesize(v=office.14).aspx + */ + public function setHoleSize($holeSize = 50) + { + if ($holeSize < 10) { + $holeSize = 10; + } + if ($holeSize > 90) { + $holeSize = 90; + } + $this->holeSize = $holeSize; + + return $this; + } + + /** + * Get hash code. + * + * @return string Hash code + */ + public function getHashCode(): string + { + return md5(parent::getHashCode() . __CLASS__); + } +} diff --git a/src/PhpPresentation/Shape/Chart/Type/Line.php b/src/PhpPresentation/Shape/Chart/Type/Line.php index 9be7a7852e..cefca9dddc 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Line.php +++ b/src/PhpPresentation/Shape/Chart/Type/Line.php @@ -10,31 +10,32 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Line - */ -class Line extends AbstractType implements ComparableInterface +class Line extends AbstractTypeLine implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hash = ''; foreach ($this->getSeries() as $series) { $hash .= $series->getHashCode(); } - return md5($hash . __CLASS__); + + return md5(parent::getHashCode() . $hash . __CLASS__); } } diff --git a/src/PhpPresentation/Shape/Chart/Type/Pie.php b/src/PhpPresentation/Shape/Chart/Type/Pie.php index a1c0d57e57..53cb6b1fe2 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Pie.php +++ b/src/PhpPresentation/Shape/Chart/Type/Pie.php @@ -10,26 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; /** - * self + * self. */ class Pie extends AbstractTypePie implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(parent::getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Chart/Type/Pie3D.php b/src/PhpPresentation/Shape/Chart/Type/Pie3D.php index b7bc6bb294..05689c61ac 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Pie3D.php +++ b/src/PhpPresentation/Shape/Chart/Type/Pie3D.php @@ -10,26 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; /** - * self + * self. */ class Pie3D extends AbstractTypePie implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(parent::getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Chart/Type/Radar.php b/src/PhpPresentation/Shape/Chart/Type/Radar.php new file mode 100644 index 0000000000..9f45b5d5ef --- /dev/null +++ b/src/PhpPresentation/Shape/Chart/Type/Radar.php @@ -0,0 +1,41 @@ +getSeries() as $series) { + $hash .= $series->getHashCode(); + } + + return md5($hash . __CLASS__); + } +} diff --git a/src/PhpPresentation/Shape/Chart/Type/Scatter.php b/src/PhpPresentation/Shape/Chart/Type/Scatter.php index ba1fa3b9b0..58f2576e7c 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Scatter.php +++ b/src/PhpPresentation/Shape/Chart/Type/Scatter.php @@ -10,31 +10,32 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart\Type; use PhpOffice\PhpPresentation\ComparableInterface; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter - */ -class Scatter extends AbstractType implements ComparableInterface +class Scatter extends AbstractTypeLine implements ComparableInterface { /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hash = ''; foreach ($this->getSeries() as $series) { $hash .= $series->getHashCode(); } - return md5($hash . __CLASS__); + + return md5(parent::getHashCode() . $hash . __CLASS__); } } diff --git a/src/PhpPresentation/Shape/Chart/View3D.php b/src/PhpPresentation/Shape/Chart/View3D.php index 541468fcea..21bbaeefe6 100644 --- a/src/PhpPresentation/Shape/Chart/View3D.php +++ b/src/PhpPresentation/Shape/Chart/View3D.php @@ -10,78 +10,81 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Shape\Chart\View3D + * \PhpOffice\PhpPresentation\Shape\Chart\View3D. */ class View3D implements ComparableInterface { /** - * Rotation X + * Rotation X. * * @var int */ protected $rotationX = 0; /** - * Rotation Y + * Rotation Y. * * @var int */ protected $rotationY = 0; /** - * Right Angle Axes + * Right Angle Axes. * - * @var boolean + * @var bool */ private $rightAngleAxes = true; /** - * Perspective + * Perspective. * * @var int */ private $perspective = 30; /** - * Height Percent + * Height Percent. * - * @var int + * @var int|null */ private $heightPercent = 100; /** - * Depth Percent + * Depth Percent. * * @var int */ private $depthPercent = 100; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Chart\View3D instance + * Create a new \PhpOffice\PhpPresentation\Shape\Chart\View3D instance. */ public function __construct() { } /** - * Get Rotation X + * Get Rotation X. * * @return int */ @@ -91,9 +94,10 @@ public function getRotationX() } /** - * Set Rotation X (-90 to 90) + * Set Rotation X (-90 to 90). + * + * @param int $pValue * - * @param int $pValue * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D */ public function setRotationX($pValue = 0) @@ -104,7 +108,7 @@ public function setRotationX($pValue = 0) } /** - * Get Rotation Y + * Get Rotation Y. * * @return int */ @@ -114,9 +118,10 @@ public function getRotationY() } /** - * Set Rotation Y (-90 to 90) + * Set Rotation Y (-90 to 90). + * + * @param int $pValue * - * @param int $pValue * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D */ public function setRotationY($pValue = 0) @@ -127,9 +132,9 @@ public function setRotationY($pValue = 0) } /** - * Get RightAngleAxes + * Get RightAngleAxes. * - * @return boolean + * @return bool */ public function hasRightAngleAxes() { @@ -137,9 +142,10 @@ public function hasRightAngleAxes() } /** - * Set RightAngleAxes + * Set RightAngleAxes. + * + * @param bool $value * - * @param boolean $value * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D */ public function setRightAngleAxes($value = true) @@ -150,7 +156,7 @@ public function setRightAngleAxes($value = true) } /** - * Get Perspective + * Get Perspective. * * @return int */ @@ -160,9 +166,10 @@ public function getPerspective() } /** - * Set Perspective (0 to 100) + * Set Perspective (0 to 100). + * + * @param int $value * - * @param int $value * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D */ public function setPerspective($value = 30) @@ -173,7 +180,7 @@ public function setPerspective($value = 30) } /** - * Get HeightPercent + * Get HeightPercent. * * @return int */ @@ -183,12 +190,9 @@ public function getHeightPercent() } /** - * Set HeightPercent (5 to 500) - * - * @param int $value - * @return self + * Set HeightPercent (5 to 500). */ - public function setHeightPercent($value = 100) + public function setHeightPercent(?int $value = 100): self { $this->heightPercent = $value; @@ -196,20 +200,19 @@ public function setHeightPercent($value = 100) } /** - * Get DepthPercent - * - * @return int + * Get DepthPercent. */ - public function getDepthPercent() + public function getDepthPercent(): ?int { return $this->depthPercent; } /** - * Set DepthPercent (20 to 2000) + * Set DepthPercent (20 to 2000). * - * @param int $value - * @return self + * @param int $value + * + * @return $this */ public function setDepthPercent($value = 100) { @@ -219,39 +222,42 @@ public function setDepthPercent($value = 100) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->rotationX . $this->rotationY . ($this->rightAngleAxes ? 't' : 'f') . $this->perspective . $this->heightPercent . $this->depthPercent . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return View3D */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + return $this; } } diff --git a/src/PhpPresentation/Shape/Comment.php b/src/PhpPresentation/Shape/Comment.php index 96f2fb6011..d909e05483 100644 --- a/src/PhpPresentation/Shape/Comment.php +++ b/src/PhpPresentation/Shape/Comment.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\AbstractShape; @@ -22,12 +25,12 @@ use PhpOffice\PhpPresentation\Shape\Comment\Author; /** - * Comment shape + * Comment shape. */ class Comment extends AbstractShape implements ComparableInterface { /** - * @var Author + * @var Author|null */ protected $author; @@ -47,21 +50,15 @@ public function __construct() $this->setDate(time()); } - /** - * @return Author - */ - public function getAuthor() + public function getAuthor(): ?Author { return $this->author; } - /** - * @param Author $author - * @return Comment - */ - public function setAuthor(Author $author) + public function setAuthor(Author $author): self { $this->author = $author; + return $this; } @@ -75,11 +72,13 @@ public function getDate() /** * @param int $dtComment timestamp of the comment + * * @return Comment */ public function setDate($dtComment) { - $this->dtComment = (int)$dtComment; + $this->dtComment = (int) $dtComment; + return $this; } @@ -93,18 +92,20 @@ public function getText() /** * @param string $text + * * @return Comment */ public function setText($text = '') { $this->text = $text; + return $this; } /** - * Comment has not height + * Comment has not height. * - * @return null + * @return int|null */ public function getHeight() { @@ -112,20 +113,19 @@ public function getHeight() } /** - * Set Height + * Set Height. * - * @param int $pValue - * @return self + * @return $this */ - public function setHeight($pValue = 0) + public function setHeight(int $pValue = 0) { return $this; } /** - * Comment has not width + * Comment has not width. * - * @return null + * @return int|null */ public function getWidth() { @@ -133,12 +133,11 @@ public function getWidth() } /** - * Set Width + * Set Width. * - * @param int $pValue * @return self */ - public function setWidth($pValue = 0) + public function setWidth(int $pValue = 0) { return $this; } diff --git a/src/PhpPresentation/Shape/Comment/Author.php b/src/PhpPresentation/Shape/Comment/Author.php index 3c0ba2abff..59784f3e94 100644 --- a/src/PhpPresentation/Shape/Comment/Author.php +++ b/src/PhpPresentation/Shape/Comment/Author.php @@ -1,4 +1,22 @@ idxAuthor = (int) $idxAuthor; + return $this; } @@ -47,11 +67,13 @@ public function getInitials() /** * @param mixed $initials + * * @return Author */ public function setInitials($initials) { $this->initials = $initials; + return $this; } @@ -65,20 +87,22 @@ public function getName() /** * @param string $name + * * @return Author */ public function setName($name) { $this->name = $name; + return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->getInitials() . $this->getName() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Drawing/AbstractDrawingAdapter.php b/src/PhpPresentation/Shape/Drawing/AbstractDrawingAdapter.php index 1301e25715..f361ba7d49 100644 --- a/src/PhpPresentation/Shape/Drawing/AbstractDrawingAdapter.php +++ b/src/PhpPresentation/Shape/Drawing/AbstractDrawingAdapter.php @@ -1,4 +1,22 @@ */ - protected $arrayMimeExtension = array( + protected $arrayMimeExtension = [ 'image/jpeg' => 'jpg', - ); + 'image/png' => 'png', + 'image/gif' => 'gif', + 'image/svg+xml' => 'svg', + ]; + + /** + * @var string + */ + protected $path; /** * Base64 constructor. @@ -30,64 +58,58 @@ public function __construct() { parent::__construct(); $this->uniqueName = md5(rand(0, 9999) . time() . rand(0, 9999)); + $this->data = ''; } - /** - * @return mixed - */ - public function getData() + public function getData(): string { return $this->data; } - /** - * @param mixed $data - * @return Base64 - */ - public function setData($data) + public function setData(string $data): self { $this->data = $data; + return $this; } - /** - * @return string - */ - public function getContents() + public function getContents(): string { list(, $imageContents) = explode(';', $this->getData()); list(, $imageContents) = explode(',', $imageContents); + return base64_decode($imageContents); } /** - * @return string - * @throws \Exception + * @throws UnauthorizedMimetypeException */ - public function getExtension() + public function getExtension(): string { - list($data, ) = explode(';', $this->getData()); + list($data) = explode(';', $this->getData()); list(, $mime) = explode(':', $data); if (!array_key_exists($mime, $this->arrayMimeExtension)) { - throw new \Exception('Type Mime not found : "'.$mime.'"'); + throw new UnauthorizedMimetypeException($mime, $this->arrayMimeExtension); } + return $this->arrayMimeExtension[$mime]; } - /** - * @return string - */ - public function getIndexedFilename() + public function getIndexedFilename(): string { return $this->uniqueName . $this->getImageIndex() . '.' . $this->getExtension(); } - /** - * @return string - */ - public function getMimeType() + public function getMimeType(): string { + list($data) = explode(';', $this->getData()); + list(, $mime) = explode(':', $data); + + if (!empty($mime)) { + return $mime; + } + $sImage = $this->getContents(); if (!function_exists('getimagesizefromstring')) { $uri = 'data://application/octet-stream;base64,' . base64_encode($sImage); @@ -95,6 +117,22 @@ public function getMimeType() } else { $image = getimagesizefromstring($sImage); } + return image_type_to_mime_type($image[2]); } + + /** + * Get Path. + */ + public function getPath(): string + { + return $this->path; + } + + public function setPath(string $path): self + { + $this->path = $path; + + return $this; + } } diff --git a/src/PhpPresentation/Shape/Drawing/File.php b/src/PhpPresentation/Shape/Drawing/File.php index 1995f561ab..754985a44c 100644 --- a/src/PhpPresentation/Shape/Drawing/File.php +++ b/src/PhpPresentation/Shape/Drawing/File.php @@ -1,43 +1,64 @@ path; } /** - * Set Path + * Set Path. + * + * @param string $pValue File path + * @param bool $pVerifyFile Verify file * - * @param string $pValue File path - * @param boolean $pVerifyFile Verify file - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\Drawing + * @throws FileNotFoundException + * + * @return self */ - public function setPath($pValue = '', $pVerifyFile = true) + public function setPath(string $pValue = '', bool $pVerifyFile = true): self { if ($pVerifyFile) { if (!file_exists($pValue)) { - throw new \Exception("File $pValue not found!"); + throw new FileNotFoundException($pValue); } } $this->path = $pValue; if ($pVerifyFile) { - if ($this->width == 0 && $this->height == 0) { + if (0 == $this->width && 0 == $this->height) { list($this->width, $this->height) = getimagesize($this->getPath()); } } @@ -45,45 +66,40 @@ public function setPath($pValue = '', $pVerifyFile = true) return $this; } - /** - * @return string - */ - public function getContents() + public function getContents(): string { - return file_get_contents($this->getPath()); + return CommonFile::fileGetContents($this->getPath()); } - - /** - * @return string - */ - public function getExtension() + public function getExtension(): string { return pathinfo($this->getPath(), PATHINFO_EXTENSION); } /** - * @throws \Exception - * @return string + * @throws FileNotFoundException */ - public function getMimeType() + public function getMimeType(): string { - if (!file_exists($this->getPath())) { - throw new \Exception('File '.$this->getPath().' does not exist'); + if (!CommonFile::fileExists($this->getPath())) { + throw new FileNotFoundException($this->getPath()); + } + $image = getimagesizefromstring(CommonFile::fileGetContents($this->getPath())); + + if (is_array($image)) { + return image_type_to_mime_type($image[2]); } - $image = getimagesize($this->getPath()); - return image_type_to_mime_type($image[2]); + + return mime_content_type($this->getPath()); } - /** - * @return string - */ - public function getIndexedFilename() + public function getIndexedFilename(): string { $output = str_replace('.' . $this->getExtension(), '', pathinfo($this->getPath(), PATHINFO_FILENAME)); $output .= $this->getImageIndex(); - $output .= '.'.$this->getExtension(); + $output .= '.' . $this->getExtension(); $output = str_replace(' ', '_', $output); + return $output; } } diff --git a/src/PhpPresentation/Shape/Drawing/Gd.php b/src/PhpPresentation/Shape/Drawing/Gd.php index f69b345ea9..59bcf8d3dd 100644 --- a/src/PhpPresentation/Shape/Drawing/Gd.php +++ b/src/PhpPresentation/Shape/Drawing/Gd.php @@ -1,51 +1,69 @@ imageResource)) { // Get width/height - $this->width = imagesx($this->imageResource); + $this->width = imagesx($this->imageResource); $this->height = imagesy($this->imageResource); } @@ -83,7 +102,7 @@ public function setImageResource($value = null) } /** - * Get rendering function + * Get rendering function. * * @return string */ @@ -93,67 +112,86 @@ public function getRenderingFunction() } /** - * Set rendering function + * Set rendering function. + * + * @param string $value * - * @param string $value * @return $this */ public function setRenderingFunction($value = self::RENDERING_DEFAULT) { $this->renderingFunction = $value; + return $this; } /** - * Get mime type - * - * @return string + * Get mime type. */ - public function getMimeType() + public function getMimeType(): string { return $this->mimeType; } /** - * Set mime type + * Set mime type. + * + * @param string $value * - * @param string $value * @return $this */ public function setMimeType($value = self::MIMETYPE_DEFAULT) { $this->mimeType = $value; + return $this; } - /** - * @return string - */ - public function getContents() + public function getContents(): string { ob_start(); + if (self::MIMETYPE_DEFAULT === $this->getMimeType()) { + imagealphablending($this->getImageResource(), false); + imagesavealpha($this->getImageResource(), true); + } call_user_func($this->getRenderingFunction(), $this->getImageResource()); $imageContents = ob_get_contents(); ob_end_clean(); + return $imageContents; } - /** - * @return string - */ - public function getExtension() + public function getExtension(): string { $extension = strtolower($this->getMimeType()); $extension = explode('/', $extension); $extension = $extension[1]; + return $extension; } + public function getIndexedFilename(): string + { + return $this->uniqueName . $this->getImageIndex() . '.' . $this->getExtension(); + } + /** - * @return string + * @var string */ - public function getIndexedFilename() + protected $path; + + /** + * Get Path. + */ + public function getPath(): string { - return $this->uniqueName . $this->getImageIndex() . '.' . $this->getExtension(); + return $this->path; + } + + public function setPath(string $path): self + { + $this->path = $path; + + return $this; } } diff --git a/src/PhpPresentation/Shape/Drawing/ZipFile.php b/src/PhpPresentation/Shape/Drawing/ZipFile.php index 3b8e5867b0..2a921e9d25 100644 --- a/src/PhpPresentation/Shape/Drawing/ZipFile.php +++ b/src/PhpPresentation/Shape/Drawing/ZipFile.php @@ -1,8 +1,27 @@ path; } /** - * Set Path + * Set Path. * - * @param string $pValue File path - * @return \PhpOffice\PhpPresentation\Shape\Drawing + * @param string $pValue File path + * + * @return \PhpOffice\PhpPresentation\Shape\Drawing\ZipFile */ - public function setPath($pValue = '') + public function setPath(string $pValue = ''): self { $this->path = $pValue; + return $this; } /** - * @return string + * @throws FileNotFoundException */ - public function getContents() + public function getContents(): string { if (!CommonFile::fileExists($this->getZipFileOut())) { - throw new \Exception('File '.$this->getZipFileOut().' does not exist'); + throw new FileNotFoundException($this->getZipFileOut()); } $imageZip = new \ZipArchive(); @@ -47,25 +66,22 @@ public function getContents() $imageContents = $imageZip->getFromName($this->getZipFileIn()); $imageZip->close(); unset($imageZip); + return $imageContents; } - - /** - * @return string - */ - public function getExtension() + public function getExtension(): string { return pathinfo($this->getZipFileIn(), PATHINFO_EXTENSION); } /** - * @return string + * @throws FileNotFoundException */ - public function getMimeType() + public function getMimeType(): string { if (!CommonFile::fileExists($this->getZipFileOut())) { - throw new \Exception('File '.$this->getZipFileOut().' does not exist'); + throw new FileNotFoundException($this->getZipFileOut()); } $oArchive = new \ZipArchive(); $oArchive->open($this->getZipFileOut()); @@ -75,33 +91,34 @@ public function getMimeType() } else { $image = getimagesizefromstring($oArchive->getFromName($this->getZipFileIn())); } + return image_type_to_mime_type($image[2]); } - /** - * @return string - */ - public function getIndexedFilename() + public function getIndexedFilename(): string { $output = pathinfo($this->getZipFileIn(), PATHINFO_FILENAME); $output = str_replace('.' . $this->getExtension(), '', $output); $output .= $this->getImageIndex(); - $output .= '.'.$this->getExtension(); + $output .= '.' . $this->getExtension(); $output = str_replace(' ', '_', $output); + return $output; } - protected function getZipFileOut() + protected function getZipFileOut(): string { $path = str_replace('zip://', '', $this->getPath()); $path = explode('#', $path); + return empty($path[0]) ? '' : $path[0]; } - protected function getZipFileIn() + protected function getZipFileIn(): string { $path = str_replace('zip://', '', $this->getPath()); $path = explode('#', $path); + return empty($path[1]) ? '' : $path[1]; } } diff --git a/src/PhpPresentation/Shape/Group.php b/src/PhpPresentation/Shape/Group.php index 8b13dd79b0..dcb29ac4e9 100644 --- a/src/PhpPresentation/Shape/Group.php +++ b/src/PhpPresentation/Shape/Group.php @@ -10,72 +10,68 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; +use ArrayObject; use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\GeometryCalculator; -use PHPOffice\PhpPresentation\ShapeContainerInterface; -use PhpOffice\PhpPresentation\Shape\Drawing; -use PhpOffice\PhpPresentation\Shape\RichText; -use PhpOffice\PhpPresentation\Shape\Table; +use PhpOffice\PhpPresentation\ShapeContainerInterface; class Group extends AbstractShape implements ShapeContainerInterface { /** - * Collection of shapes - * - * @var \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] - */ - private $shapeCollection = null; + * Collection of shapes. + * + * @var array|ArrayObject + */ + private $shapeCollection; /** - * Extent X - * - * @var int - */ + * Extent X. + * + * @var int + */ protected $extentX; /** - * Extent Y - * - * @var int - */ + * Extent Y. + * + * @var int + */ protected $extentY; public function __construct() { parent::__construct(); - // For logic purposes. - $this->offsetX = null; - $this->offsetY = null; - // Shape collection - $this->shapeCollection = new \ArrayObject(); + $this->shapeCollection = new ArrayObject(); } /** - * Get collection of shapes - * - * @return \ArrayObject|AbstractShape[] - */ + * Get collection of shapes. + * + * @return array|ArrayObject + */ public function getShapeCollection() { return $this->shapeCollection; } /** - * Add shape to slide - * - * @param \PhpOffice\PhpPresentation\AbstractShape $shape - * @return \PhpOffice\PhpPresentation\AbstractShape - */ - public function addShape(AbstractShape $shape) + * Add shape to slide. + * + * @return AbstractShape + */ + public function addShape(AbstractShape $shape): AbstractShape { $shape->setContainer($this); @@ -83,13 +79,11 @@ public function addShape(AbstractShape $shape) } /** - * Get X Offset - * - * @return int - */ - public function getOffsetX() + * Get X Offset. + */ + public function getOffsetX(): int { - if ($this->offsetX === null) { + if (empty($this->offsetX)) { $offsets = GeometryCalculator::calculateOffsets($this); $this->offsetX = $offsets[GeometryCalculator::X]; $this->offsetY = $offsets[GeometryCalculator::Y]; @@ -99,24 +93,21 @@ public function getOffsetX() } /** - * Ignores setting the X Offset, preserving the default behavior. - * - * @param int $pValue - * @return self - */ - public function setOffsetX($pValue = 0) + * Ignores setting the X Offset, preserving the default behavior. + * + * @return $this + */ + public function setOffsetX(int $pValue = 0) { return $this; } /** - * Get Y Offset - * - * @return int - */ - public function getOffsetY() + * Get Y Offset. + */ + public function getOffsetY(): int { - if ($this->offsetY === null) { + if (empty($this->offsetY)) { $offsets = GeometryCalculator::calculateOffsets($this); $this->offsetX = $offsets[GeometryCalculator::X]; $this->offsetY = $offsets[GeometryCalculator::Y]; @@ -126,76 +117,69 @@ public function getOffsetY() } /** - * Ignores setting the Y Offset, preserving the default behavior. - * - * @param int $pValue - * @return self - */ - public function setOffsetY($pValue = 0) + * Ignores setting the Y Offset, preserving the default behavior. + * + * @return $this + */ + public function setOffsetY(int $pValue = 0) { return $this; } /** - * Get X Extent - * - * @return int - */ - public function getExtentX() + * Get X Extent. + */ + public function getExtentX(): int { - if ($this->extentX === null) { + if (null === $this->extentX) { $extents = GeometryCalculator::calculateExtents($this); - $this->extentX = $extents[GeometryCalculator::X]; - $this->extentY = $extents[GeometryCalculator::Y]; + $this->extentX = $extents[GeometryCalculator::X] - $this->getOffsetX(); + $this->extentY = $extents[GeometryCalculator::Y] - $this->getOffsetY(); } return $this->extentX; } /** - * Get Y Extent - * - * @return int - */ - public function getExtentY() + * Get Y Extent. + */ + public function getExtentY(): int { - if ($this->extentY === null) { + if (null === $this->extentY) { $extents = GeometryCalculator::calculateExtents($this); - $this->extentX = $extents[GeometryCalculator::X]; - $this->extentY = $extents[GeometryCalculator::Y]; + $this->extentX = $extents[GeometryCalculator::X] - $this->getOffsetX(); + $this->extentY = $extents[GeometryCalculator::Y] - $this->getOffsetY(); } return $this->extentY; } /** - * Ignores setting the width, preserving the default behavior. - * - * @param int $pValue - * @return self - */ - public function setWidth($pValue = 0) + * Ignores setting the width, preserving the default behavior. + * + * @return self + */ + public function setWidth(int $pValue = 0) { return $this; } /** - * Ignores setting the height, preserving the default behavior. - * - * @param int $pValue - * @return self - */ - public function setHeight($pValue = 0) + * Ignores setting the height, preserving the default behavior. + * + * @return $this + */ + public function setHeight(int $pValue = 0) { return $this; } /** - * Create rich text shape - * - * @return \PhpOffice\PhpPresentation\Shape\RichText - */ - public function createRichTextShape() + * Create rich text shape. + * + * @return RichText + */ + public function createRichTextShape(): RichText { $shape = new RichText(); $this->addShape($shape); @@ -204,15 +188,16 @@ public function createRichTextShape() } /** - * Create line shape - * - * @param int $fromX Starting point x offset - * @param int $fromY Starting point y offset - * @param int $toX Ending point x offset - * @param int $toY Ending point y offset - * @return \PhpOffice\PhpPresentation\Shape\Line - */ - public function createLineShape($fromX, $fromY, $toX, $toY) + * Create line shape. + * + * @param int $fromX Starting point x offset + * @param int $fromY Starting point y offset + * @param int $toX Ending point x offset + * @param int $toY Ending point y offset + * + * @return Line + */ + public function createLineShape(int $fromX, int $fromY, int $toX, int $toY): Line { $shape = new Line($fromX, $fromY, $toX, $toY); $this->addShape($shape); @@ -221,11 +206,11 @@ public function createLineShape($fromX, $fromY, $toX, $toY) } /** - * Create chart shape - * - * @return \PhpOffice\PhpPresentation\Shape\Chart - */ - public function createChartShape() + * Create chart shape. + * + * @return Chart + */ + public function createChartShape(): Chart { $shape = new Chart(); $this->addShape($shape); @@ -234,11 +219,11 @@ public function createChartShape() } /** - * Create drawing shape - * - * @return \PhpOffice\PhpPresentation\Shape\Drawing\File - */ - public function createDrawingShape() + * Create drawing shape. + * + * @return Drawing\File + */ + public function createDrawingShape(): Drawing\File { $shape = new Drawing\File(); $this->addShape($shape); @@ -247,12 +232,13 @@ public function createDrawingShape() } /** - * Create table shape - * - * @param int $columns Number of columns - * @return \PhpOffice\PhpPresentation\Shape\Table - */ - public function createTableShape($columns = 1) + * Create table shape. + * + * @param int $columns Number of columns + * + * @return Table + */ + public function createTableShape(int $columns = 1): Table { $shape = new Table($columns); $this->addShape($shape); diff --git a/src/PhpPresentation/Shape/Hyperlink.php b/src/PhpPresentation/Shape/Hyperlink.php index 0a95507760..694fe2acf2 100644 --- a/src/PhpPresentation/Shape/Hyperlink.php +++ b/src/PhpPresentation/Shape/Hyperlink.php @@ -10,61 +10,63 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; /** - * Hyperlink element + * Hyperlink element. */ class Hyperlink { /** - * URL to link the shape to + * URL to link the shape to. * * @var string */ private $url; /** - * Tooltip to display on the hyperlink + * Tooltip to display on the hyperlink. * * @var string */ private $tooltip; /** - * Slide number to link to + * Slide number to link to. * * @var int */ private $slideNumber = null; /** - * Slide relation ID (should not be used by user code!) + * Slide relation ID (should not be used by user code!). * * @var string */ public $relationId = null; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Hyperlink + * Create a new \PhpOffice\PhpPresentation\Shape\Hyperlink. * - * @param string $pUrl Url to link the shape to - * @param string $pTooltip Tooltip to display on the hyperlink - * @throws \Exception + * @param string $pUrl Url to link the shape to + * @param string $pTooltip Tooltip to display on the hyperlink */ - public function __construct($pUrl = '', $pTooltip = '') + public function __construct(string $pUrl = '', string $pTooltip = '') { // Initialise member variables $this->setUrl($pUrl); @@ -72,22 +74,23 @@ public function __construct($pUrl = '', $pTooltip = '') } /** - * Get URL + * Get URL. * * @return string */ - public function getUrl() + public function getUrl(): string { return $this->url; } /** - * Set URL + * Set URL. + * + * @param string $value * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Hyperlink + * @return self */ - public function setUrl($value = '') + public function setUrl(string $value = ''): self { $this->url = $value; @@ -95,22 +98,23 @@ public function setUrl($value = '') } /** - * Get tooltip + * Get tooltip. * * @return string */ - public function getTooltip() + public function getTooltip(): string { return $this->tooltip; } /** - * Set tooltip + * Set tooltip. * - * @param string $value - * @return \PhpOffice\PhpPresentation\Shape\Hyperlink + * @param string $value + * + * @return self */ - public function setTooltip($value = '') + public function setTooltip(string $value = ''): self { $this->tooltip = $value; @@ -118,72 +122,77 @@ public function setTooltip($value = '') } /** - * Get slide number + * Get slide number. * * @return int */ - public function getSlideNumber() + public function getSlideNumber(): int { return $this->slideNumber; } /** - * Set slide number + * Set slide number. + * + * @param int $value * - * @param int $value - * @return \PhpOffice\PhpPresentation\Shape\Hyperlink + * @return self */ - public function setSlideNumber($value = 1) + public function setSlideNumber(int $value = 1): self { - $this->url = 'ppaction://hlinksldjump'; + $this->url = 'ppaction://hlinksldjump'; $this->slideNumber = $value; return $this; } /** - * Is this hyperlink internal? (to another slide) + * Is this hyperlink internal? (to another slide). * - * @return boolean + * @return bool */ - public function isInternal() + public function isInternal(): bool { - return strpos($this->url, 'ppaction://') !== false; + return false !== strpos($this->url, 'ppaction://'); } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->url . $this->tooltip . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Shape/Line.php b/src/PhpPresentation/Shape/Line.php index e9a7a074c4..be7574d557 100644 --- a/src/PhpPresentation/Shape/Line.php +++ b/src/PhpPresentation/Shape/Line.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\AbstractShape; @@ -22,12 +25,12 @@ use PhpOffice\PhpPresentation\Style\Border; /** - * Line shape + * Line shape. */ class Line extends AbstractShape implements ComparableInterface { /** - * Create a new \PhpOffice\PhpPresentation\Shape\Line instance + * Create a new \PhpOffice\PhpPresentation\Shape\Line instance. * * @param int $fromX * @param int $fromY @@ -46,11 +49,11 @@ public function __construct($fromX, $fromY, $toX, $toY) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->getBorder()->getLineStyle() . parent::getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/Media.php b/src/PhpPresentation/Shape/Media.php index 64a98b72c4..1207195d57 100644 --- a/src/PhpPresentation/Shape/Media.php +++ b/src/PhpPresentation/Shape/Media.php @@ -10,26 +10,25 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\Shape\Drawing\File; /** - * Media element + * Media element. */ class Media extends File implements ComparableInterface { - - /** - * @return string - */ - public function getMimeType() + public function getMimeType(): string { switch (strtolower($this->getExtension())) { case 'mp4': @@ -44,6 +43,7 @@ public function getMimeType() default: $mimetype = 'application/octet-stream'; } + return $mimetype; } } diff --git a/src/PhpPresentation/Shape/Placeholder.php b/src/PhpPresentation/Shape/Placeholder.php index a334104bf5..45f6ac8202 100644 --- a/src/PhpPresentation/Shape/Placeholder.php +++ b/src/PhpPresentation/Shape/Placeholder.php @@ -10,86 +10,75 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; class Placeholder { /** Placeholder Type constants */ - const PH_TYPE_BODY = 'body'; - const PH_TYPE_CHART = 'chart'; - const PH_TYPE_SUBTITLE = 'subTitle'; - const PH_TYPE_TITLE = 'title'; - const PH_TYPE_FOOTER = 'ftr'; - const PH_TYPE_DATETIME = 'dt'; - const PH_TYPE_SLIDENUM = 'sldNum'; + public const PH_TYPE_BODY = 'body'; + public const PH_TYPE_CHART = 'chart'; + public const PH_TYPE_SUBTITLE = 'subTitle'; + public const PH_TYPE_TITLE = 'title'; + public const PH_TYPE_FOOTER = 'ftr'; + public const PH_TYPE_DATETIME = 'dt'; + public const PH_TYPE_SLIDENUM = 'sldNum'; + /** - * hasCustomPrompt * Indicates whether the placeholder should have a customer prompt. * * @var bool */ protected $hasCustomPrompt; + /** - * idx * Specifies the index of the placeholder. This is used when applying templates or changing layouts to * match a placeholder on one template or master to another. * - * @var int + * @var int|null */ protected $idx; + /** - * type - * Specifies what content type the placeholder is to contains + * Specifies what content type the placeholder is to contains. + * + * @var string */ protected $type; - /** - * Placeholder constructor. - * @param $type - */ - public function __construct($type) + public function __construct(string $type) { $this->type = $type; } - /** - * @return mixed - */ - public function getType() + public function getType(): string { return $this->type; } - /** - * @param mixed $type - * @return Placeholder - */ - public function setType($type) + public function setType(string $type): self { $this->type = $type; + return $this; } - /** - * @return int - */ - public function getIdx() + public function getIdx(): ?int { return $this->idx; } - /** - * @param int $idx - * @return Placeholder - */ - public function setIdx($idx) + public function setIdx(int $idx): self { $this->idx = $idx; + return $this; } } diff --git a/src/PhpPresentation/Shape/RichText.php b/src/PhpPresentation/Shape/RichText.php index 9782aaae8e..b9082773ad 100644 --- a/src/PhpPresentation/Shape/RichText.php +++ b/src/PhpPresentation/Shape/RichText.php @@ -10,74 +10,78 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface; /** - * \PhpOffice\PhpPresentation\Shape\RichText + * \PhpOffice\PhpPresentation\Shape\RichText. */ class RichText extends AbstractShape implements ComparableInterface { /** Wrapping */ - const WRAP_NONE = 'none'; - const WRAP_SQUARE = 'square'; + public const WRAP_NONE = 'none'; + public const WRAP_SQUARE = 'square'; /** Autofit */ - const AUTOFIT_DEFAULT = 'spAutoFit'; - const AUTOFIT_SHAPE = 'spAutoFit'; - const AUTOFIT_NOAUTOFIT = 'noAutofit'; - const AUTOFIT_NORMAL = 'normAutofit'; + public const AUTOFIT_DEFAULT = 'spAutoFit'; + public const AUTOFIT_SHAPE = 'spAutoFit'; + public const AUTOFIT_NOAUTOFIT = 'noAutofit'; + public const AUTOFIT_NORMAL = 'normAutofit'; /** Overflow */ - const OVERFLOW_CLIP = 'clip'; - const OVERFLOW_OVERFLOW = 'overflow'; + public const OVERFLOW_CLIP = 'clip'; + public const OVERFLOW_OVERFLOW = 'overflow'; /** - * Rich text paragraphs + * Rich text paragraphs. * - * @var \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] + * @var array */ private $richTextParagraphs; /** - * Active paragraph + * Active paragraph. * * @var int */ private $activeParagraph = 0; /** - * Text wrapping + * Text wrapping. * * @var string */ private $wrap = self::WRAP_SQUARE; /** - * Autofit + * Autofit. * * @var string */ private $autoFit = self::AUTOFIT_DEFAULT; /** - * Horizontal overflow + * Horizontal overflow. * * @var string */ private $horizontalOverflow = self::OVERFLOW_OVERFLOW; /** - * Vertical overflow + * Vertical overflow. * * @var string */ @@ -86,122 +90,125 @@ class RichText extends AbstractShape implements ComparableInterface /** * Text upright? * - * @var boolean + * @var bool */ private $upright = false; /** * Vertical text? * - * @var boolean + * @var bool */ private $vertical = false; /** - * Number of columns (1 - 16) + * Number of columns (1 - 16). * * @var int */ private $columns = 1; /** - * Bottom inset (in pixels) + * The spacing between columns + * + * @var int + */ + private $columnSpacing = 0; + + /** + * Bottom inset (in pixels). * * @var float */ private $bottomInset = 4.8; /** - * Left inset (in pixels) + * Left inset (in pixels). * * @var float */ private $leftInset = 9.6; /** - * Right inset (in pixels) + * Right inset (in pixels). * * @var float */ private $rightInset = 9.6; /** - * Top inset (in pixels) + * Top inset (in pixels). * * @var float */ private $topInset = 4.8; /** - * Horizontal Auto Shrink - * @var boolean + * Horizontal Auto Shrink. + * + * @var bool|null */ private $autoShrinkHorizontal; /** - * Vertical Auto Shrink - * @var boolean + * Vertical Auto Shrink. + * + * @var bool|null */ private $autoShrinkVertical; - + /** - * The percentage of the original font size to which the text is scaled - * @var float + * The percentage of the original font size to which the text is scaled. + * + * @var float|null */ private $fontScale; - + /** - * The percentage of the reduction of the line spacing - * @var float + * The percentage of the reduction of the line spacing. + * + * @var float|null */ private $lnSpcReduction; /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText instance + * Create a new \PhpOffice\PhpPresentation\Shape\RichText instance. */ public function __construct() { // Initialise variables - $this->richTextParagraphs = array( - new Paragraph() - ); - $this->activeParagraph = 0; + $this->richTextParagraphs = [ + new Paragraph(), + ]; // Initialize parent parent::__construct(); } /** - * Get active paragraph index + * Get active paragraph index. * * @return int */ - public function getActiveParagraphIndex() + public function getActiveParagraphIndex(): int { return $this->activeParagraph; } - /** - * Get active paragraph - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph - */ - public function getActiveParagraph() + public function getActiveParagraph(): Paragraph { return $this->richTextParagraphs[$this->activeParagraph]; } /** - * Set active paragraph + * Set active paragraph. * - * @param int $index - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @throws OutOfBoundsException */ - public function setActiveParagraph($index = 0) + public function setActiveParagraph(int $index = 0): Paragraph { if ($index >= count($this->richTextParagraphs)) { - throw new \Exception("Invalid paragraph count."); + throw new OutOfBoundsException(0, count($this->richTextParagraphs), $index); } $this->activeParagraph = $index; @@ -210,37 +217,33 @@ public function setActiveParagraph($index = 0) } /** - * Get paragraph + * Get paragraph. * - * @param int $index - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @throws OutOfBoundsException */ - public function getParagraph($index = 0) + public function getParagraph(int $index = 0): Paragraph { if ($index >= count($this->richTextParagraphs)) { - throw new \Exception("Invalid paragraph count."); + throw new OutOfBoundsException(0, count($this->richTextParagraphs), $index); } return $this->richTextParagraphs[$index]; } /** - * Create paragraph - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * Create paragraph. */ - public function createParagraph() + public function createParagraph(): Paragraph { $numParagraphs = count($this->richTextParagraphs); if ($numParagraphs > 0) { - $alignment = clone $this->getActiveParagraph()->getAlignment(); - $font = clone $this->getActiveParagraph()->getFont(); + $alignment = clone $this->getActiveParagraph()->getAlignment(); + $font = clone $this->getActiveParagraph()->getFont(); $bulletStyle = clone $this->getActiveParagraph()->getBulletStyle(); } $this->richTextParagraphs[] = new Paragraph(); - $this->activeParagraph = count($this->richTextParagraphs) - 1; + $this->activeParagraph = count($this->richTextParagraphs) - 1; if (isset($alignment)) { $this->getActiveParagraph()->setAlignment($alignment); @@ -251,17 +254,18 @@ public function createParagraph() if (isset($bulletStyle)) { $this->getActiveParagraph()->setBulletStyle($bulletStyle); } + return $this->getActiveParagraph(); } /** - * Add text + * Add text. * - * @param \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface $pText Rich text element - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param TextElementInterface|null $pText Rich text element + * + * @return self */ - public function addText(TextElementInterface $pText = null) + public function addText(TextElementInterface $pText = null): self { $this->richTextParagraphs[$this->activeParagraph]->addText($pText); @@ -269,51 +273,50 @@ public function addText(TextElementInterface $pText = null) } /** - * Create text (can not be formatted !) + * Create text (can not be formatted !). + * + * @param string $pText Text * - * @param string $pText Text - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElement - * @throws \Exception + * @return RichText\TextElement */ - public function createText($pText = '') + public function createText(string $pText = ''): RichText\TextElement { return $this->richTextParagraphs[$this->activeParagraph]->createText($pText); } /** - * Create break + * Create break. * - * @return \PhpOffice\PhpPresentation\Shape\RichText\BreakElement - * @throws \Exception + * @return RichText\BreakElement */ - public function createBreak() + public function createBreak(): RichText\BreakElement { return $this->richTextParagraphs[$this->activeParagraph]->createBreak(); } /** - * Create text run (can be formatted) + * Create text run (can be formatted). + * + * @param string $pText Text * - * @param string $pText Text - * @return \PhpOffice\PhpPresentation\Shape\RichText\Run - * @throws \Exception + * @return RichText\Run */ - public function createTextRun($pText = '') + public function createTextRun(string $pText = ''): RichText\Run { return $this->richTextParagraphs[$this->activeParagraph]->createTextRun($pText); } /** - * Get plain text + * Get plain text. * * @return string */ - public function getPlainText() + public function getPlainText(): string { // Return value $returnValue = ''; - // Loop trough all \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + // Loop trough all Paragraph foreach ($this->richTextParagraphs as $p) { $returnValue .= $p->getPlainText(); } @@ -323,7 +326,7 @@ public function getPlainText() } /** - * Convert to string + * Convert to string. * * @return string */ @@ -333,50 +336,44 @@ public function __toString() } /** - * Get paragraphs - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] + * @return array */ - public function getParagraphs() + public function getParagraphs(): array { return $this->richTextParagraphs; } /** - * Set paragraphs + * Set paragraphs. * - * @param \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] $paragraphs Array of paragraphs - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param array $paragraphs Array of paragraphs */ - public function setParagraphs($paragraphs = null) + public function setParagraphs(array $paragraphs = []): self { - if (!is_array($paragraphs)) { - throw new \Exception("Invalid \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] array passed."); - } - $this->richTextParagraphs = $paragraphs; - $this->activeParagraph = count($this->richTextParagraphs) - 1; + $this->activeParagraph = count($this->richTextParagraphs) - 1; + return $this; } /** - * Get text wrapping + * Get text wrapping. * * @return string */ - public function getWrap() + public function getWrap(): string { return $this->wrap; } /** - * Set text wrapping + * Set text wrapping. + * + * @param string $value * - * @param $value string - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setWrap($value = self::WRAP_SQUARE) + public function setWrap(string $value = self::WRAP_SQUARE): self { $this->wrap = $value; @@ -384,51 +381,48 @@ public function setWrap($value = self::WRAP_SQUARE) } /** - * Get autofit + * Get autofit. * * @return string */ - public function getAutoFit() + public function getAutoFit(): string { return $this->autoFit; } /** - * Get pourcentage of fontScale - * - * @return float + * Get pourcentage of fontScale. */ - public function getFontScale() + public function getFontScale(): ?float { return $this->fontScale; } /** - * Get pourcentage of the line space reduction - * - * @return float + * Get pourcentage of the line space reduction. */ - public function getLineSpaceReduction() + public function getLineSpaceReduction(): ?float { return $this->lnSpcReduction; } /** - * Set autofit + * Set autofit. + * + * @param string $value + * @param float|null $fontScale + * @param float|null $lnSpcReduction * - * @param $value string - * @param $fontScale float - * @param $lnSpcReduction float - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setAutoFit($value = self::AUTOFIT_DEFAULT, $fontScale = null, $lnSpcReduction = null) + public function setAutoFit(string $value = self::AUTOFIT_DEFAULT, float $fontScale = null, float $lnSpcReduction = null): self { $this->autoFit = $value; - + if (!is_null($fontScale)) { $this->fontScale = $fontScale; } - + if (!is_null($lnSpcReduction)) { $this->lnSpcReduction = $lnSpcReduction; } @@ -437,22 +431,23 @@ public function setAutoFit($value = self::AUTOFIT_DEFAULT, $fontScale = null, $l } /** - * Get horizontal overflow + * Get horizontal overflow. * * @return string */ - public function getHorizontalOverflow() + public function getHorizontalOverflow(): string { return $this->horizontalOverflow; } /** - * Set horizontal overflow + * Set horizontal overflow. + * + * @param string $value * - * @param $value string - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setHorizontalOverflow($value = self::OVERFLOW_OVERFLOW) + public function setHorizontalOverflow(string $value = self::OVERFLOW_OVERFLOW): self { $this->horizontalOverflow = $value; @@ -460,22 +455,23 @@ public function setHorizontalOverflow($value = self::OVERFLOW_OVERFLOW) } /** - * Get vertical overflow + * Get vertical overflow. * * @return string */ - public function getVerticalOverflow() + public function getVerticalOverflow(): string { return $this->verticalOverflow; } /** - * Set vertical overflow + * Set vertical overflow. * - * @param $value string - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param string $value + * + * @return self */ - public function setVerticalOverflow($value = self::OVERFLOW_OVERFLOW) + public function setVerticalOverflow(string $value = self::OVERFLOW_OVERFLOW): self { $this->verticalOverflow = $value; @@ -483,22 +479,23 @@ public function setVerticalOverflow($value = self::OVERFLOW_OVERFLOW) } /** - * Get upright + * Get upright. * - * @return boolean + * @return bool */ - public function isUpright() + public function isUpright(): bool { return $this->upright; } /** - * Set vertical + * Set vertical. * - * @param $value boolean - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param bool $value + * + * @return self */ - public function setUpright($value = false) + public function setUpright(bool $value = false): self { $this->upright = $value; @@ -506,22 +503,23 @@ public function setUpright($value = false) } /** - * Get vertical + * Get vertical. * - * @return boolean + * @return bool */ - public function isVertical() + public function isVertical(): bool { return $this->vertical; } /** - * Set vertical + * Set vertical. * - * @param $value boolean - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param bool $value + * + * @return self */ - public function setVertical($value = false) + public function setVertical(bool $value = false): self { $this->vertical = $value; @@ -529,26 +527,28 @@ public function setVertical($value = false) } /** - * Get columns + * Get columns. * * @return int */ - public function getColumns() + public function getColumns(): int { return $this->columns; } /** - * Set columns + * Set columns. + * + * @param int $value * - * @param $value int - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self + * + * @throws OutOfBoundsException */ - public function setColumns($value = 1) + public function setColumns(int $value = 1): self { if ($value > 16 || $value < 1) { - throw new \Exception('Number of columns should be 1-16'); + throw new OutOfBoundsException(1, 16, $value); } $this->columns = $value; @@ -557,22 +557,23 @@ public function setColumns($value = 1) } /** - * Get bottom inset + * Get bottom inset. * * @return float */ - public function getInsetBottom() + public function getInsetBottom(): float { return $this->bottomInset; } /** - * Set bottom inset + * Set bottom inset. + * + * @param float $value * - * @param $value float - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setInsetBottom($value = 4.8) + public function setInsetBottom(float $value = 4.8): self { $this->bottomInset = $value; @@ -580,22 +581,23 @@ public function setInsetBottom($value = 4.8) } /** - * Get left inset + * Get left inset. * * @return float */ - public function getInsetLeft() + public function getInsetLeft(): float { return $this->leftInset; } /** - * Set left inset + * Set left inset. + * + * @param float $value * - * @param $value float - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setInsetLeft($value = 9.6) + public function setInsetLeft(float $value = 9.6): self { $this->leftInset = $value; @@ -603,22 +605,23 @@ public function setInsetLeft($value = 9.6) } /** - * Get right inset + * Get right inset. * * @return float */ - public function getInsetRight() + public function getInsetRight(): float { return $this->rightInset; } /** - * Set left inset + * Set left inset. * - * @param $value float - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param float $value + * + * @return self */ - public function setInsetRight($value = 9.6) + public function setInsetRight(float $value = 9.6): self { $this->rightInset = $value; @@ -626,82 +629,115 @@ public function setInsetRight($value = 9.6) } /** - * Get top inset + * Get top inset. * * @return float */ - public function getInsetTop() + public function getInsetTop(): float { return $this->topInset; } /** - * Set top inset + * Set top inset. + * + * @param float $value * - * @param $value float - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setInsetTop($value = 4.8) + public function setInsetTop(float $value = 4.8): self { $this->topInset = $value; return $this; } + public function setAutoShrinkHorizontal(bool $value = null): self + { + $this->autoShrinkHorizontal = $value; + + return $this; + } + + public function hasAutoShrinkHorizontal(): ?bool + { + return $this->autoShrinkHorizontal; + } + /** - * Set horizontal auto shrink - * @param bool $value + * Set vertical auto shrink. + * + * @return RichText */ - public function setAutoShrinkHorizontal($value = null) + public function setAutoShrinkVertical(bool $value = null): self { - if (is_bool($value)) { - $this->autoShrinkHorizontal = $value; - } + $this->autoShrinkVertical = $value; + return $this; } - + /** - * Get horizontal auto shrink - * @return bool + * Set vertical auto shrink. */ - public function hasAutoShrinkHorizontal() + public function hasAutoShrinkVertical(): ?bool { - return $this->autoShrinkHorizontal; + return $this->autoShrinkVertical; } - + /** - * Set vertical auto shrink - * @param bool $value + * Get spacing between columns + * + * @return int */ - public function setAutoShrinkVertical($value = null) + public function getColumnSpacing(): int { - if (is_bool($value)) { - $this->autoShrinkVertical = $value; - } - return $this; + return $this->columnSpacing; } - + /** - * Set vertical auto shrink - * @return bool + * Set spacing between columns + * + * @param int $value + * + * @return self */ - public function hasAutoShrinkVertical() + public function setColumnSpacing(int $value = 0): self { - return $this->autoShrinkVertical; + if ($value >= 0) { + $this->columnSpacing = $value; + } + + return $this; } - + /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hashElements = ''; foreach ($this->richTextParagraphs as $element) { $hashElements .= $element->getHashCode(); } - return md5($hashElements . $this->wrap . $this->autoFit . $this->horizontalOverflow . $this->verticalOverflow . ($this->upright ? '1' : '0') . ($this->vertical ? '1' : '0') . $this->columns . $this->bottomInset . $this->leftInset . $this->rightInset . $this->topInset . parent::getHashCode() . __CLASS__); + return md5( + $hashElements + . $this->wrap + . $this->autoFit + . $this->horizontalOverflow + . $this->verticalOverflow + . ($this->upright ? '1' : '0') + . ($this->vertical ? '1' : '0') + . $this->columns + . $this->columnSpacing + . $this->bottomInset + . $this->leftInset + . $this->rightInset + . $this->topInset + . parent::getHashCode() + . __CLASS__ + ); } } diff --git a/src/PhpPresentation/Shape/RichText/BreakElement.php b/src/PhpPresentation/Shape/RichText/BreakElement.php index dbd5bb7c3b..5df5f06486 100644 --- a/src/PhpPresentation/Shape/RichText/BreakElement.php +++ b/src/PhpPresentation/Shape/RichText/BreakElement.php @@ -10,27 +10,32 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\RichText; +use PhpOffice\PhpPresentation\Style\Font; + /** - * Rich text break + * Rich text break. */ class BreakElement implements TextElementInterface { /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Break instance + * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Break instance. */ public function __construct() { } /** - * Get text + * Get text. * * @return string Text */ @@ -40,53 +45,47 @@ public function getText() } /** - * Set text + * Set text. * - * @param $pText string Text - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + * @param string $pText Text value */ - public function setText($pText = '') + public function setText($pText = ''): self { return $this; } /** - * Get font - * - * @return \PhpOffice\PhpPresentation\Style\Font + * Get font. */ - public function getFont() + public function getFont(): ?Font { return null; } /** - * Set language + * Set language. * - * @param $lang - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + * @param string $lang */ - public function setLanguage($lang) + public function setLanguage($lang): self { return $this; } /** - * Get language - * - * @return string Language + * Get language. */ - public function getLanguage() + public function getLanguage(): ?string { return null; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(__CLASS__); } diff --git a/src/PhpPresentation/Shape/RichText/Paragraph.php b/src/PhpPresentation/Shape/RichText/Paragraph.php index aa2bf79d88..5fa26925cc 100644 --- a/src/PhpPresentation/Shape/RichText/Paragraph.php +++ b/src/PhpPresentation/Shape/RichText/Paragraph.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\ComparableInterface; @@ -23,79 +26,90 @@ use PhpOffice\PhpPresentation\Style\Font; /** - * \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * \PhpOffice\PhpPresentation\Shape\RichText\Paragraph. */ class Paragraph implements ComparableInterface { + public const LINE_SPACING_MODE_PERCENT = 'percent'; + public const LINE_SPACING_MODE_POINT = 'point'; + /** - * Rich text elements + * Rich text elements. * - * @var \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface[] + * @var array */ - private $richTextElements; + private $richTextElements = []; /** - * Alignment + * Alignment. * - * @var \PhpOffice\PhpPresentation\Style\Alignment + * @var Alignment */ private $alignment; /** - * Font + * Font. * - * @var \PhpOffice\PhpPresentation\Style\Font + * @var Font|null */ private $font; /** - * Bullet style + * Bullet style. * - * @var \PhpOffice\PhpPresentation\Style\Bullet + * @var Bullet */ private $bulletStyle; /** - * @var integer + * @var int */ private $lineSpacing = 100; /** - * Hash index - * * @var string */ + private $lineSpacingMode = self::LINE_SPACING_MODE_PERCENT; + + /** + * @var int + */ + private $spacingBefore = 0; + + /** + * @var int + */ + private $spacingAfter = 0; + + /** + * Hash index. + * + * @var int + */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Paragraph instance + * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Paragraph instance. */ public function __construct() { - // Initialise variables - $this->richTextElements = array(); $this->alignment = new Alignment(); $this->font = new Font(); $this->bulletStyle = new Bullet(); } /** - * Get alignment - * - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Get alignment. */ - public function getAlignment() + public function getAlignment(): Alignment { return $this->alignment; } /** - * Set alignment - * - * @param \PhpOffice\PhpPresentation\Style\Alignment $alignment - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * Set alignment. */ - public function setAlignment(Alignment $alignment) + public function setAlignment(Alignment $alignment): self { $this->alignment = $alignment; @@ -103,23 +117,19 @@ public function setAlignment(Alignment $alignment) } /** - * Get font - * - * @return \PhpOffice\PhpPresentation\Style\Font + * Get font. */ - public function getFont() + public function getFont(): ?Font { return $this->font; } /** - * Set font + * Set font. * - * @param \PhpOffice\PhpPresentation\Style\Font $pFont Font - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param Font|null $pFont Font */ - public function setFont(Font $pFont = null) + public function setFont(Font $pFont = null): self { $this->font = $pFont; @@ -127,23 +137,17 @@ public function setFont(Font $pFont = null) } /** - * Get bullet style - * - * @return \PhpOffice\PhpPresentation\Style\Bullet + * Get bullet style. */ - public function getBulletStyle() + public function getBulletStyle(): ?Bullet { return $this->bulletStyle; } /** * Set bullet style - * - * @param \PhpOffice\PhpPresentation\Style\Bullet $style - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph */ - public function setBulletStyle(Bullet $style = null) + public function setBulletStyle(Bullet $style = null): self { $this->bulletStyle = $style; @@ -151,13 +155,11 @@ public function setBulletStyle(Bullet $style = null) } /** - * Create text (can not be formatted !) + * Create text (can not be formatted !). * - * @param string $pText Text - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElement - * @throws \Exception + * @param string $pText Text */ - public function createText($pText = '') + public function createText(string $pText = ''): TextElement { $objText = new TextElement($pText); $this->addText($objText); @@ -166,13 +168,11 @@ public function createText($pText = '') } /** - * Add text + * Add text. * - * @param \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface $pText Rich text element - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param TextElementInterface|null $pText Rich text element */ - public function addText(TextElementInterface $pText = null) + public function addText(TextElementInterface $pText = null): self { $this->richTextElements[] = $pText; @@ -180,12 +180,9 @@ public function addText(TextElementInterface $pText = null) } /** - * Create break - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\BreakElement - * @throws \Exception + * Create break. */ - public function createBreak() + public function createBreak(): BreakElement { $objText = new BreakElement(); $this->addText($objText); @@ -194,13 +191,11 @@ public function createBreak() } /** - * Create text run (can be formatted) + * Create text run (can be formatted). * - * @param string $pText Text - * @return \PhpOffice\PhpPresentation\Shape\RichText\Run - * @throws \Exception + * @param string $pText Text */ - public function createTextRun($pText = '') + public function createTextRun(string $pText = ''): Run { $objText = new Run($pText); $objText->setFont(clone $this->font); @@ -210,7 +205,7 @@ public function createTextRun($pText = '') } /** - * Convert to string + * Convert to string. * * @return string */ @@ -220,16 +215,14 @@ public function __toString() } /** - * Get plain text - * - * @return string + * Get plain text. */ - public function getPlainText() + public function getPlainText(): string { // Return value $returnValue = ''; - // Loop trough all \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + // Loop trough all TextElementInterface foreach ($this->richTextElements as $text) { if ($text instanceof TextElementInterface) { $returnValue .= $text->getText(); @@ -241,39 +234,33 @@ public function getPlainText() } /** - * Get Rich Text elements + * Get Rich Text elements. * - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface[] + * @return array */ - public function getRichTextElements() + public function getRichTextElements(): array { return $this->richTextElements; } /** - * Set Rich Text elements + * Set Rich Text elements. * - * @param \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface[] $pElements Array of elements - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param array $pElements Array of elements */ - public function setRichTextElements($pElements = null) + public function setRichTextElements(array $pElements = []): self { - if (is_array($pElements)) { - $this->richTextElements = $pElements; - } else { - throw new \Exception("Invalid \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface[] array passed."); - } + $this->richTextElements = $pElements; return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hashElements = ''; foreach ($this->richTextElements as $element) { @@ -284,46 +271,127 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } /** * @return int */ - public function getLineSpacing() + public function getLineSpacing(): int { return $this->lineSpacing; } /** + * Value in points + * * @param int $lineSpacing - * @return Paragraph + * + * @return self */ - public function setLineSpacing($lineSpacing) + public function setLineSpacing($lineSpacing): self { $this->lineSpacing = $lineSpacing; + + return $this; + } + + /** + * @return string + */ + public function getLineSpacingMode(): string + { + return $this->lineSpacingMode; + } + + /** + * @param string $lineSpacingMode + * + * @return self + */ + public function setLineSpacingMode(string $lineSpacingMode): self + { + if (in_array($lineSpacingMode, [ + self::LINE_SPACING_MODE_PERCENT, + self::LINE_SPACING_MODE_POINT, + ])) { + $this->lineSpacingMode = $lineSpacingMode; + } + + return $this; + } + + /** + * Value in points + * + * @return int + */ + public function getSpacingBefore(): int + { + return $this->spacingBefore; + } + + /** + * Value in points + * + * @param int $spacingBefore + * + * @return self + */ + public function setSpacingBefore(int $spacingBefore): self + { + $this->spacingBefore = $spacingBefore; + + return $this; + } + + /** + * Value in points + * + * @return int + */ + public function getSpacingAfter(): int + { + return $this->spacingAfter; + } + + /** + * Value in points + * + * @param int $spacingAfter + * + * @return self + */ + public function setSpacingAfter(int $spacingAfter): self + { + $this->spacingAfter = $spacingAfter; + return $this; } } diff --git a/src/PhpPresentation/Shape/RichText/Run.php b/src/PhpPresentation/Shape/RichText/Run.php index 97455c0f11..ba4f53250e 100644 --- a/src/PhpPresentation/Shape/RichText/Run.php +++ b/src/PhpPresentation/Shape/RichText/Run.php @@ -10,29 +10,32 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Style\Font; /** - * Rich text run + * Rich text run. */ class Run extends TextElement implements TextElementInterface { /** - * Font + * Font. * * @var \PhpOffice\PhpPresentation\Style\Font */ private $font; /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Run instance + * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Run instance. * * @param string $pText Text */ @@ -44,20 +47,18 @@ public function __construct($pText = '') } /** - * Get font - * - * @return \PhpOffice\PhpPresentation\Style\Font + * Get font. */ - public function getFont() + public function getFont(): Font { return $this->font; } /** - * Set font + * Set font. + * + * @param Font|null $pFont Font * - * @param \PhpOffice\PhpPresentation\Style\Font $pFont Font - * @throws \Exception * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface */ public function setFont(Font $pFont = null) @@ -68,11 +69,11 @@ public function setFont(Font $pFont = null) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->getText() . $this->font->getHashCode() . __CLASS__); } diff --git a/src/PhpPresentation/Shape/RichText/TextElement.php b/src/PhpPresentation/Shape/RichText/TextElement.php index 2cdbd499bd..3c74d02fd6 100644 --- a/src/PhpPresentation/Shape/RichText/TextElement.php +++ b/src/PhpPresentation/Shape/RichText/TextElement.php @@ -10,22 +10,26 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Shape\Hyperlink; +use PhpOffice\PhpPresentation\Style\Font; /** - * Rich text text element + * Rich text text element. */ class TextElement implements TextElementInterface { /** - * Text + * Text. * * @var string */ @@ -37,14 +41,14 @@ class TextElement implements TextElementInterface protected $language; /** - * Hyperlink + * Hyperlink. * - * @var \PhpOffice\PhpPresentation\Shape\Hyperlink + * @var Hyperlink|null */ protected $hyperlink; /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText\TextElement instance + * Create a new \PhpOffice\PhpPresentation\Shape\RichText\TextElement instance. * * @param string $pText Text */ @@ -55,7 +59,7 @@ public function __construct($pText = '') } /** - * Get text + * Get text. * * @return string Text */ @@ -65,9 +69,10 @@ public function getText() } /** - * Set text + * Set text. + * + * @param string $pText Text value * - * @param $pText string Text * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface */ public function setText($pText = '') @@ -78,31 +83,19 @@ public function setText($pText = '') } /** - * Get font - * - * @return \PhpOffice\PhpPresentation\Style\Font + * Get font. */ - public function getFont() + public function getFont(): ?Font { return null; } - /** - * Has Hyperlink? - * - * @return boolean - */ - public function hasHyperlink() + public function hasHyperlink(): bool { return !is_null($this->hyperlink); } - /** - * Get Hyperlink - * - * @return \PhpOffice\PhpPresentation\Shape\Hyperlink - */ - public function getHyperlink() + public function getHyperlink(): Hyperlink { if (is_null($this->hyperlink)) { $this->hyperlink = new Hyperlink(); @@ -112,11 +105,9 @@ public function getHyperlink() } /** - * Set Hyperlink + * Set Hyperlink. * - * @param \PhpOffice\PhpPresentation\Shape\Hyperlink $pHyperlink - * @throws \Exception - * @return \PhpOffice\PhpPresentation\AbstractShape + * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElement */ public function setHyperlink(Hyperlink $pHyperlink = null) { @@ -126,7 +117,8 @@ public function setHyperlink(Hyperlink $pHyperlink = null) } /** - * Get language + * Get language. + * * @return string */ public function getLanguage() @@ -135,22 +127,25 @@ public function getLanguage() } /** - * Set language + * Set language. + * * @param string $language + * * @return TextElement */ public function setLanguage($language) { $this->language = $language; + return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->text . (is_null($this->hyperlink) ? '' : $this->hyperlink->getHashCode()) . __CLASS__); } diff --git a/src/PhpPresentation/Shape/RichText/TextElementInterface.php b/src/PhpPresentation/Shape/RichText/TextElementInterface.php index 98302447a5..4c704436cd 100644 --- a/src/PhpPresentation/Shape/RichText/TextElementInterface.php +++ b/src/PhpPresentation/Shape/RichText/TextElementInterface.php @@ -10,35 +10,39 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\RichText; /** - * Rich text element interface + * Rich text element interface. */ interface TextElementInterface { /** - * Get text + * Get text. * * @return string Text */ public function getText(); /** - * Set text + * Set text. + * + * @param string $pText Text value * - * @param $pText string Text * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface */ public function setText($pText = ''); /** - * Get font + * Get font. * * @return \PhpOffice\PhpPresentation\Style\Font */ @@ -51,14 +55,15 @@ public function getLanguage(); /** * @param string $lang + * * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface */ public function setLanguage($lang); /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode(); + public function getHashCode(): string; } diff --git a/src/PhpPresentation/Shape/Table.php b/src/PhpPresentation/Shape/Table.php index 21da32196a..d6313be119 100644 --- a/src/PhpPresentation/Shape/Table.php +++ b/src/PhpPresentation/Shape/Table.php @@ -10,44 +10,46 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\Table\Row; /** - * Table shape + * Table shape. */ class Table extends AbstractGraphic implements ComparableInterface { /** - * Rows + * Rows. * - * @var \PhpOffice\PhpPresentation\Shape\Table\Row[] + * @var array */ - private $rows; + private $rows = []; /** - * Number of columns + * Number of columns. * * @var int */ private $columnCount = 1; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Table instance + * Create a new \PhpOffice\PhpPresentation\Shape\Table instance. * * @param int $columns Number of columns */ public function __construct($columns = 1) { - // Initialise variables - $this->rows = array(); $this->columnCount = $columns; // Initialize parent @@ -58,43 +60,53 @@ public function __construct($columns = 1) } /** - * Get row + * Get row. + * + * @param int $row Row number * - * @param int $row Row number - * @param boolean $exceptionAsNull Return a null value instead of an exception? - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\Table\Row + * @throws OutOfBoundsException */ - public function getRow($row = 0, $exceptionAsNull = false) + public function getRow(int $row = 0): Row { if (!isset($this->rows[$row])) { - if ($exceptionAsNull) { - return null; - } - throw new \Exception('Row number out of bounds.'); + throw new OutOfBoundsException( + 0, + (count($this->rows) - 1) < 0 ? 0 : count($this->rows) - 1, + $row + ); } return $this->rows[$row]; } /** - * Get rows + * @param int $row * - * @return \PhpOffice\PhpPresentation\Shape\Table\Row[] + * @return bool */ - public function getRows() + public function hasRow(int $row): bool + { + return isset($this->rows[$row]); + } + + /** + * Get rows. + * + * @return Row[] + */ + public function getRows(): array { return $this->rows; } /** - * Create row + * Create row. * - * @return \PhpOffice\PhpPresentation\Shape\Table\Row + * @return Row */ - public function createRow() + public function createRow(): Row { - $row = new Row($this->columnCount); + $row = new Row($this->columnCount); $this->rows[] = $row; return $row; @@ -103,27 +115,29 @@ public function createRow() /** * @return int */ - public function getNumColumns() + public function getNumColumns(): int { return $this->columnCount; } /** * @param int $numColumn - * @return Table + * + * @return self */ - public function setNumColumns($numColumn) + public function setNumColumns(int $numColumn): self { $this->columnCount = $numColumn; + return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hashElements = ''; foreach ($this->rows as $row) { diff --git a/src/PhpPresentation/Shape/Table/Cell.php b/src/PhpPresentation/Shape/Table/Cell.php index 2307d06909..c8e8a942c5 100644 --- a/src/PhpPresentation/Shape/Table/Cell.php +++ b/src/PhpPresentation/Shape/Table/Cell.php @@ -10,90 +10,94 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Table; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface; use PhpOffice\PhpPresentation\Style\Borders; use PhpOffice\PhpPresentation\Style\Fill; /** - * Table cell + * Table cell. */ class Cell implements ComparableInterface { /** - * Rich text paragraphs + * Rich text paragraphs. * - * @var \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] + * @var array */ private $richTextParagraphs; /** - * Active paragraph + * Active paragraph. * * @var int */ private $activeParagraph = 0; /** - * Fill + * Fill. * * @var \PhpOffice\PhpPresentation\Style\Fill */ private $fill; /** - * Borders + * Borders. * * @var \PhpOffice\PhpPresentation\Style\Borders */ private $borders; /** - * Width (in pixels) + * Width (in pixels). * * @var int */ private $width = 0; /** - * Colspan + * Colspan. * * @var int */ private $colSpan = 0; /** - * Rowspan + * Rowspan. * * @var int */ private $rowSpan = 0; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText instance + * Create a new \PhpOffice\PhpPresentation\Shape\RichText instance. */ public function __construct() { // Initialise variables - $this->richTextParagraphs = array( - new Paragraph() - ); - $this->activeParagraph = 0; + $this->richTextParagraphs = [ + new Paragraph(), + ]; + $this->activeParagraph = 0; // Set fill $this->fill = new Fill(); @@ -103,7 +107,7 @@ public function __construct() } /** - * Get active paragraph index + * Get active paragraph index. * * @return int */ @@ -113,26 +117,24 @@ public function getActiveParagraphIndex() } /** - * Get active paragraph - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * Get active paragraph. */ - public function getActiveParagraph() + public function getActiveParagraph(): Paragraph { return $this->richTextParagraphs[$this->activeParagraph]; } /** - * Set active paragraph + * Set active paragraph. * - * @param int $index - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @param int $index + * + * @throws OutOfBoundsException */ - public function setActiveParagraph($index = 0) + public function setActiveParagraph($index = 0): Paragraph { if ($index >= count($this->richTextParagraphs)) { - throw new \Exception("Invalid paragraph count."); + throw new OutOfBoundsException(0, count($this->richTextParagraphs), $index); } $this->activeParagraph = $index; @@ -141,53 +143,49 @@ public function setActiveParagraph($index = 0) } /** - * Get paragraph + * Get paragraph. + * + * @param int $index * - * @param int $index - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @throws OutOfBoundsException */ - public function getParagraph($index = 0) + public function getParagraph(int $index = 0): Paragraph { if ($index >= count($this->richTextParagraphs)) { - throw new \Exception("Invalid paragraph count."); + throw new OutOfBoundsException(0, count($this->richTextParagraphs), $index); } return $this->richTextParagraphs[$index]; } /** - * Create paragraph - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * Create paragraph. */ - public function createParagraph() + public function createParagraph(): Paragraph { $this->richTextParagraphs[] = new Paragraph(); + $totalRichTextParagraphs = count($this->richTextParagraphs); + $this->activeParagraph = $totalRichTextParagraphs - 1; - if (count($this->richTextParagraphs) > 1) { + if ($totalRichTextParagraphs > 1) { $alignment = clone $this->getActiveParagraph()->getAlignment(); $font = clone $this->getActiveParagraph()->getFont(); $bulletStyle = clone $this->getActiveParagraph()->getBulletStyle(); - $this->activeParagraph = count($this->richTextParagraphs) - 1; - $this->getActiveParagraph()->setAlignment($alignment); $this->getActiveParagraph()->setFont($font); $this->getActiveParagraph()->setBulletStyle($bulletStyle); - } else { - $this->activeParagraph = count($this->richTextParagraphs) - 1; } return $this->getActiveParagraph(); } /** - * Add text + * Add text. * - * @param \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface $pText Rich text element - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @param TextElementInterface $pText Rich text element + * + * @return \PhpOffice\PhpPresentation\Shape\Table\Cell */ public function addText(TextElementInterface $pText = null) { @@ -197,11 +195,11 @@ public function addText(TextElementInterface $pText = null) } /** - * Create text (can not be formatted !) + * Create text (can not be formatted !). + * + * @param string $pText Text * - * @param string $pText Text * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElement - * @throws \Exception */ public function createText($pText = '') { @@ -209,10 +207,9 @@ public function createText($pText = '') } /** - * Create break + * Create break. * * @return \PhpOffice\PhpPresentation\Shape\RichText\BreakElement - * @throws \Exception */ public function createBreak() { @@ -220,19 +217,19 @@ public function createBreak() } /** - * Create text run (can be formatted) + * Create text run (can be formatted). + * + * @param string $pText Text * - * @param string $pText Text * @return \PhpOffice\PhpPresentation\Shape\RichText\Run - * @throws \Exception */ - public function createTextRun($pText = '') + public function createTextRun(string $pText = '') { return $this->richTextParagraphs[$this->activeParagraph]->createTextRun($pText); } /** - * Get plain text + * Get plain text. * * @return string */ @@ -241,7 +238,7 @@ public function getPlainText() // Return value $returnValue = ''; - // Loop trough all \PhpOffice\PhpPresentation\Shape\RichText\Paragraph + // Loop trough all Paragraph foreach ($this->richTextParagraphs as $p) { $returnValue .= $p->getPlainText(); } @@ -251,7 +248,7 @@ public function getPlainText() } /** - * Convert to string + * Convert to string. * * @return string */ @@ -261,9 +258,9 @@ public function __toString() } /** - * Get paragraphs + * Get paragraphs. * - * @return \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] + * @return array */ public function getParagraphs() { @@ -271,26 +268,22 @@ public function getParagraphs() } /** - * Set paragraphs + * Set paragraphs. + * + * @param array $paragraphs Array of paragraphs * - * @param \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] $paragraphs Array of paragraphs - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return \PhpOffice\PhpPresentation\Shape\Table\Cell */ - public function setParagraphs($paragraphs = null) + public function setParagraphs(array $paragraphs = []): self { - if (is_array($paragraphs)) { - $this->richTextParagraphs = $paragraphs; - $this->activeParagraph = count($this->richTextParagraphs) - 1; - } else { - throw new \Exception("Invalid \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] array passed."); - } + $this->richTextParagraphs = $paragraphs; + $this->activeParagraph = count($this->richTextParagraphs) - 1; return $this; } /** - * Get fill + * Get fill. * * @return \PhpOffice\PhpPresentation\Style\Fill */ @@ -300,10 +293,9 @@ public function getFill() } /** - * Set fill + * Set fill. * - * @param \PhpOffice\PhpPresentation\Style\Fill $fill - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return \PhpOffice\PhpPresentation\Shape\Table\Cell */ public function setFill(Fill $fill) { @@ -313,7 +305,7 @@ public function setFill(Fill $fill) } /** - * Get borders + * Get borders. * * @return \PhpOffice\PhpPresentation\Style\Borders */ @@ -323,10 +315,9 @@ public function getBorders() } /** - * Set borders + * Set borders. * - * @param \PhpOffice\PhpPresentation\Style\Borders $borders - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return \PhpOffice\PhpPresentation\Shape\Table\Cell */ public function setBorders(Borders $borders) { @@ -336,7 +327,7 @@ public function setBorders(Borders $borders) } /** - * Get width + * Get width. * * @return int */ @@ -346,58 +337,35 @@ public function getWidth() } /** - * Set width + * Set width. * - * @param int $value - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setWidth($value = 0) + public function setWidth(int $pValue = 0) { - $this->width = $value; + $this->width = $pValue; return $this; } - /** - * Get colSpan - * - * @return int - */ - public function getColSpan() + public function getColSpan(): int { return $this->colSpan; } - /** - * Set colSpan - * - * @param int $value - * @return \PhpOffice\PhpPresentation\Shape\RichText - */ - public function setColSpan($value = 0) + public function setColSpan(int $value = 0): self { $this->colSpan = $value; return $this; } - /** - * Get rowSpan - * - * @return int - */ - public function getRowSpan() + public function getRowSpan(): int { return $this->rowSpan; } - /** - * Set rowSpan - * - * @param int $value - * @return \PhpOffice\PhpPresentation\Shape\RichText - */ - public function setRowSpan($value = 0) + public function setRowSpan(int $value = 0): self { $this->rowSpan = $value; @@ -405,11 +373,11 @@ public function setRowSpan($value = 0) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hashElements = ''; foreach ($this->richTextParagraphs as $element) { @@ -420,28 +388,32 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Shape/Table/Row.php b/src/PhpPresentation/Shape/Table/Row.php index 4f427f02d6..039bbf16d0 100644 --- a/src/PhpPresentation/Shape/Table/Row.php +++ b/src/PhpPresentation/Shape/Table/Row.php @@ -10,138 +10,154 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Shape\Table; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Style\Fill; /** - * Table row + * Table row. */ class Row implements ComparableInterface { /** - * Cells + * Cells. * - * @var \PhpOffice\PhpPresentation\Shape\Table\Cell[] + * @var Cell[] */ - private $cells; + private $cells = []; /** - * Fill + * Fill. * - * @var \PhpOffice\PhpPresentation\Style\Fill + * @var Fill */ private $fill; /** - * Height (in pixels) + * Height (in pixels). * * @var int */ private $height = 38; /** - * Active cell index + * Active cell index. * * @var int */ private $activeCellIndex = -1; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Shape\Table\Row instance - * * @param int $columns Number of columns */ - public function __construct($columns = 1) + public function __construct(int $columns = 1) { - // Initialise variables - $this->cells = array(); - for ($i = 0; $i < $columns; $i++) { + // Fill + $this->fill = new Fill(); + // Cells + for ($inc = 0; $inc < $columns; ++$inc) { $this->cells[] = new Cell(); } - - // Set fill - $this->fill = new Fill(); } /** - * Get cell + * Get cell. + * + * @param int $cell Cell number * - * @param int $cell Cell number - * @param boolean $exceptionAsNull Return a null value instead of an exception? - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\Table\Cell + * @throws OutOfBoundsException */ - public function getCell($cell = 0, $exceptionAsNull = false) + public function getCell(int $cell = 0): Cell { if (!isset($this->cells[$cell])) { - if ($exceptionAsNull) { - return null; - } - throw new \Exception('Cell number out of bounds.'); + throw new OutOfBoundsException( + 0, + (count($this->cells) - 1) < 0 ? count($this->cells) - 1 : 0, + $cell + ); } return $this->cells[$cell]; } /** - * Get cells + * Get cell. + * + * @param int $cell Cell number * - * @return \PhpOffice\PhpPresentation\Shape\Table\Cell[] + * @return bool */ - public function getCells() + public function hasCell(int $cell): bool + { + return isset($this->cells[$cell]); + } + + /** + * Get cells. + * + * @return array + */ + public function getCells(): array { return $this->cells; } /** - * Next cell (moves one cell to the right) + * Next cell (moves one cell to the right). + * + * @return Cell * - * @return \PhpOffice\PhpPresentation\Shape\Table\Cell - * @throws \Exception + * @throws OutOfBoundsException */ - public function nextCell() + public function nextCell(): Cell { - $this->activeCellIndex++; + ++$this->activeCellIndex; if (isset($this->cells[$this->activeCellIndex])) { $this->cells[$this->activeCellIndex]->setFill(clone $this->getFill()); return $this->cells[$this->activeCellIndex]; - } else { - throw new \Exception("Cell count out of bounds."); } + + throw new OutOfBoundsException( + 0, + (count($this->cells) - 1) < 0 ? count($this->cells) - 1 : 0, + $this->activeCellIndex + ); } /** - * Get fill + * Get fill. * - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return Fill */ - public function getFill() + public function getFill(): Fill { return $this->fill; } /** - * Set fill + * Set fill. * - * @param \PhpOffice\PhpPresentation\Style\Fill $fill - * @return \PhpOffice\PhpPresentation\Shape\Table\Row + * @return self */ - public function setFill(Fill $fill) + public function setFill(Fill $fill): self { $this->fill = $fill; @@ -149,22 +165,23 @@ public function setFill(Fill $fill) } /** - * Get height + * Get height. * * @return int */ - public function getHeight() + public function getHeight(): int { return $this->height; } /** - * Set height + * Set height. + * + * @param int $value * - * @param int $value - * @return \PhpOffice\PhpPresentation\Shape\RichText + * @return self */ - public function setHeight($value = 0) + public function setHeight(int $value = 0): self { $this->height = $value; @@ -172,11 +189,11 @@ public function setHeight($value = 0) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { $hashElements = ''; foreach ($this->cells as $cell) { @@ -187,28 +204,32 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/ShapeContainerInterface.php b/src/PhpPresentation/ShapeContainerInterface.php index 4575c749e7..48e24f1674 100644 --- a/src/PhpPresentation/ShapeContainerInterface.php +++ b/src/PhpPresentation/ShapeContainerInterface.php @@ -10,58 +10,56 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; +use ArrayObject; + /** - * PhpOffice\PhpPresentation\ShapeContainerInterface + * PhpOffice\PhpPresentation\ShapeContainerInterface. */ interface ShapeContainerInterface { /** - * Get collection of shapes - * - * @return \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] - */ + * Get collection of shapes. + * + * @return array|ArrayObject + */ public function getShapeCollection(); /** - * Add shape to slide - * - * @param \PhpOffice\PhpPresentation\AbstractShape $shape - * @return \PhpOffice\PhpPresentation\AbstractShape - */ + * Add shape to slide. + * + * @return AbstractShape + */ public function addShape(AbstractShape $shape); /** - * Get X Offset - * - * @return int - */ - public function getOffsetX(); + * Get X Offset. + */ + public function getOffsetX(): int; /** - * Get Y Offset - * - * @return int - */ - public function getOffsetY(); + * Get Y Offset. + */ + public function getOffsetY(): int; /** - * Get X Extent - * - * @return int - */ - public function getExtentX(); + * Get X Extent. + */ + public function getExtentX(): int; /** - * Get Y Extent - * - * @return int - */ - public function getExtentY(); + * Get Y Extent. + */ + public function getExtentY(): int; + + public function getHashCode(): string; } diff --git a/src/PhpPresentation/Slide.php b/src/PhpPresentation/Slide.php index 473d7b73b4..61c0d57757 100644 --- a/src/PhpPresentation/Slide.php +++ b/src/PhpPresentation/Slide.php @@ -10,66 +10,65 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation; -use PhpOffice\PhpPresentation\Shape\Chart; -use PhpOffice\PhpPresentation\Shape\RichText; -use PhpOffice\PhpPresentation\Shape\Table; use PhpOffice\PhpPresentation\Slide\AbstractSlide; use PhpOffice\PhpPresentation\Slide\Note; use PhpOffice\PhpPresentation\Slide\SlideLayout; /** - * Slide class + * Slide class. */ class Slide extends AbstractSlide implements ComparableInterface, ShapeContainerInterface { /** - * The slide is shown in presentation + * The slide is shown in presentation. + * * @var bool */ protected $isVisible = true; /** - * Slide layout + * Slide layout. * - * @var SlideLayout + * @var SlideLayout|null */ private $slideLayout; /** - * Slide master id + * Slide master id. * - * @var integer + * @var int */ private $slideMasterId = 1; /** - * - * @var \PhpOffice\PhpPresentation\Slide\Note + * @var Note */ private $slideNote; /** - * * @var \PhpOffice\PhpPresentation\Slide\Animation[] */ - protected $animations = array(); + protected $animations = []; /** - * Name of the title + * Name of the title. * - * @var string + * @var string|null */ protected $name; /** - * Create a new slide + * Create a new slide. * * @param PhpPresentation $pParent */ @@ -89,32 +88,30 @@ public function __construct(PhpPresentation $pParent = null) $oSlideLayout = reset($arraySlideLayouts); $this->setSlideLayout($oSlideLayout); } + // Set note + $this->setNote(new Note()); } /** - * Get slide layout - * - * @return SlideLayout + * Get slide layout. */ - public function getSlideLayout() + public function getSlideLayout(): ?SlideLayout { return $this->slideLayout; } /** - * Set slide layout - * - * @param SlideLayout $layout - * @return \PhpOffice\PhpPresentation\Slide + * Set slide layout. */ - public function setSlideLayout(SlideLayout $layout) + public function setSlideLayout(SlideLayout $layout): self { $this->slideLayout = $layout; + return $this; } /** - * Get slide master id + * Get slide master id. * * @return int */ @@ -124,9 +121,10 @@ public function getSlideMasterId() } /** - * Set slide master id + * Set slide master id. + * + * @param int $masterId * - * @param int $masterId * @return \PhpOffice\PhpPresentation\Slide */ public function setSlideMasterId($masterId = 1) @@ -137,7 +135,7 @@ public function setSlideMasterId($masterId = 1) } /** - * Copy slide (!= clone!) + * Copy slide (!= clone!). * * @return \PhpOffice\PhpPresentation\Slide */ @@ -148,24 +146,12 @@ public function copy() return $copied; } - /** - * - * @return \PhpOffice\PhpPresentation\Slide\Note - */ - public function getNote() + public function getNote(): Note { - if (is_null($this->slideNote)) { - $this->setNote(); - } return $this->slideNote; } - /** - * - * @param \PhpOffice\PhpPresentation\Slide\Note $note - * @return \PhpOffice\PhpPresentation\Slide - */ - public function setNote(Note $note = null) + public function setNote(Note $note = null): self { $this->slideNote = (is_null($note) ? new Note() : $note); $this->slideNote->setParent($this); @@ -174,27 +160,27 @@ public function setNote(Note $note = null) } /** - * Get the name of the slide + * Get the name of the slide. + * * @return string */ - public function getName() + public function getName(): ?string { return $this->name; } /** - * Set the name of the slide - * @param string $name - * @return $this + * Set the name of the slide. */ - public function setName($name = null) + public function setName(?string $name = null): self { $this->name = $name; + return $this; } /** - * @return boolean + * @return bool */ public function isVisible() { @@ -202,29 +188,33 @@ public function isVisible() } /** - * @param boolean $value + * @param bool $value + * * @return Slide */ public function setIsVisible($value = true) { - $this->isVisible = (bool)$value; + $this->isVisible = (bool) $value; + return $this; } /** - * Add an animation to the slide + * Add an animation to the slide. + * + * @param \PhpOffice\PhpPresentation\Slide\Animation $animation * - * @param \PhpOffice\PhpPresentation\Slide\Animation * @return Slide */ public function addAnimation($animation) { $this->animations[] = $animation; + return $this; } /** - * Get collection of animations + * Get collection of animations. * * @return \PhpOffice\PhpPresentation\Slide\Animation[] */ @@ -234,13 +224,16 @@ public function getAnimations() } /** - * Set collection of animations + * Set collection of animations. + * * @param \PhpOffice\PhpPresentation\Slide\Animation[] $array + * * @return Slide */ - public function setAnimations(array $array = array()) + public function setAnimations(array $array = []) { $this->animations = $array; + return $this; } } diff --git a/src/PhpPresentation/Slide/AbstractBackground.php b/src/PhpPresentation/Slide/AbstractBackground.php index 72edbdf212..42aa4d5856 100644 --- a/src/PhpPresentation/Slide/AbstractBackground.php +++ b/src/PhpPresentation/Slide/AbstractBackground.php @@ -1,8 +1,25 @@ |ArrayObject */ - protected $shapeCollection = null; + protected $shapeCollection = []; /** - * Extent Y + * Extent Y. * * @var int */ protected $extentY; /** - * Extent X + * Extent X. * * @var int */ protected $extentX; /** - * Offset X + * Offset X. * * @var int */ protected $offsetX; /** - * Offset Y + * Offset Y. * * @var int */ protected $offsetY; /** - * Slide identifier + * Slide identifier. * * @var string */ protected $identifier; /** - * Hash index + * Hash index. * - * @var string + * @var int */ protected $hashIndex; /** - * Parent presentation + * Parent presentation. * - * @var PhpPresentation + * @var PhpPresentation|null */ protected $parent; /** - * Background of the slide + * Background of the slide. * * @var AbstractBackground */ protected $background; /** - * Get collection of shapes + * Get collection of shapes. * - * @return \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] + * @return array|ArrayObject */ public function getShapeCollection() { @@ -107,275 +110,252 @@ public function getShapeCollection() } /** - * Get collection of shapes + * Get collection of shapes. + * + * @param array|ArrayObject $shapeCollection * * @return AbstractSlide */ - public function setShapeCollection($shapeCollection = array()) + public function setShapeCollection($shapeCollection = []) { $this->shapeCollection = $shapeCollection; + return $this; } /** - * Add shape to slide + * Add shape to slide. * - * @param \PhpOffice\PhpPresentation\AbstractShape $shape - * @return \PhpOffice\PhpPresentation\AbstractShape + * @return AbstractShape */ - public function addShape(AbstractShape $shape) + public function addShape(AbstractShape $shape): AbstractShape { $shape->setContainer($this); + return $shape; } /** - * Get X Offset - * - * @return int + * Get X Offset. */ - public function getOffsetX() + public function getOffsetX(): int { - if ($this->offsetX === null) { + if (null === $this->offsetX) { $offsets = GeometryCalculator::calculateOffsets($this); $this->offsetX = $offsets[GeometryCalculator::X]; $this->offsetY = $offsets[GeometryCalculator::Y]; } + return $this->offsetX; } /** - * Get Y Offset - * - * @return int + * Get Y Offset. */ - public function getOffsetY() + public function getOffsetY(): int { - if ($this->offsetY === null) { + if (null === $this->offsetY) { $offsets = GeometryCalculator::calculateOffsets($this); $this->offsetX = $offsets[GeometryCalculator::X]; $this->offsetY = $offsets[GeometryCalculator::Y]; } + return $this->offsetY; } /** - * Get X Extent - * - * @return int + * Get X Extent. */ - public function getExtentX() + public function getExtentX(): int { - if ($this->extentX === null) { + if (null === $this->extentX) { $extents = GeometryCalculator::calculateExtents($this); $this->extentX = $extents[GeometryCalculator::X]; $this->extentY = $extents[GeometryCalculator::Y]; } + return $this->extentX; } /** - * Get Y Extent - * - * @return int + * Get Y Extent. */ - public function getExtentY() + public function getExtentY(): int { - if ($this->extentY === null) { + if (null === $this->extentY) { $extents = GeometryCalculator::calculateExtents($this); $this->extentX = $extents[GeometryCalculator::X]; $this->extentY = $extents[GeometryCalculator::Y]; } + return $this->extentY; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->identifier . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } /** - * Create rich text shape - * - * @return \PhpOffice\PhpPresentation\Shape\RichText + * Create rich text shape. */ - public function createRichTextShape() + public function createRichTextShape(): RichText { $shape = new RichText(); $this->addShape($shape); + return $shape; } /** - * Create line shape + * Create line shape. * - * @param int $fromX Starting point x offset - * @param int $fromY Starting point y offset - * @param int $toX Ending point x offset - * @param int $toY Ending point y offset - * @return \PhpOffice\PhpPresentation\Shape\Line + * @param int $fromX Starting point x offset + * @param int $fromY Starting point y offset + * @param int $toX Ending point x offset + * @param int $toY Ending point y offset */ - public function createLineShape($fromX, $fromY, $toX, $toY) + public function createLineShape(int $fromX, int $fromY, int $toX, int $toY): Line { $shape = new Line($fromX, $fromY, $toX, $toY); $this->addShape($shape); + return $shape; } /** - * Create chart shape - * - * @return \PhpOffice\PhpPresentation\Shape\Chart + * Create chart shape. */ - public function createChartShape() + public function createChartShape(): Chart { $shape = new Chart(); $this->addShape($shape); + return $shape; } /** - * Create drawing shape - * - * @return \PhpOffice\PhpPresentation\Shape\Drawing\File + * Create drawing shape. */ - public function createDrawingShape() + public function createDrawingShape(): File { $shape = new File(); $this->addShape($shape); + return $shape; } /** - * Create table shape + * Create table shape. * - * @param int $columns Number of columns - * @return \PhpOffice\PhpPresentation\Shape\Table + * @param int $columns Number of columns */ - public function createTableShape($columns = 1) + public function createTableShape(int $columns = 1): Table { $shape = new Table($columns); $this->addShape($shape); + return $shape; } /** - * Creates a group within this slide - * - * @return \PhpOffice\PhpPresentation\Shape\Group + * Creates a group within this slide. */ - public function createGroup() + public function createGroup(): Group { $shape = new Group(); $this->addShape($shape); + return $shape; } /** - * Get parent - * - * @return PhpPresentation + * Get parent. */ - public function getParent() + public function getParent(): ?PhpPresentation { return $this->parent; } /** - * Re-bind parent - * - * @param \PhpOffice\PhpPresentation\PhpPresentation $parent - * @return \PhpOffice\PhpPresentation\Slide + * Re-bind parent. */ - public function rebindParent(PhpPresentation $parent) + public function rebindParent(PhpPresentation $parent): AbstractSlide { $this->parent->removeSlideByIndex($this->parent->getIndex($this)); $this->parent = $parent; + return $this; } - /** - * @return AbstractBackground - */ - public function getBackground() + public function getBackground(): ?AbstractBackground { return $this->background; } - /** - * @param AbstractBackground $background - * @return Slide - */ - public function setBackground(AbstractBackground $background = null) + public function setBackground(AbstractBackground $background = null): AbstractSlide { $this->background = $background; + return $this; } - /** - * - * @return \PhpOffice\PhpPresentation\Slide\Transition - */ - public function getTransition() + public function getTransition(): ?Transition { return $this->slideTransition; } - /** - * - * @param \PhpOffice\PhpPresentation\Slide\Transition $transition - * @return \PhpOffice\PhpPresentation\Slide - */ - public function setTransition(Transition $transition = null) + public function setTransition(Transition $transition = null): self { $this->slideTransition = $transition; + return $this; } - /** - * @return string - */ - public function getRelsIndex() + public function getRelsIndex(): string { return $this->relsIndex; } - /** - * @param string $indexName - */ - public function setRelsIndex($indexName) + public function setRelsIndex(string $indexName): self { $this->relsIndex = $indexName; + + return $this; } } diff --git a/src/PhpPresentation/Slide/Animation.php b/src/PhpPresentation/Slide/Animation.php index 54f77daa56..2e6d1dc48a 100644 --- a/src/PhpPresentation/Slide/Animation.php +++ b/src/PhpPresentation/Slide/Animation.php @@ -1,4 +1,23 @@ */ - protected $shapeCollection = array(); + protected $shapeCollection = []; /** - * @param AbstractShape $shape * @return Animation */ public function addShape(AbstractShape $shape) { $this->shapeCollection[] = $shape; + return $this; } /** - * @return array + * @return array */ - public function getShapeCollection() + public function getShapeCollection(): array { return $this->shapeCollection; } /** - * @param array $array + * @param array $array + * * @return Animation */ - public function setShapeCollection(array $array = array()) + public function setShapeCollection(array $array = []) { $this->shapeCollection = $array; + return $this; } } diff --git a/src/PhpPresentation/Slide/Background/Color.php b/src/PhpPresentation/Slide/Background/Color.php index fb975f62c4..24507d8dc4 100644 --- a/src/PhpPresentation/Slide/Background/Color.php +++ b/src/PhpPresentation/Slide/Background/Color.php @@ -1,4 +1,22 @@ color = $color; + return $this; } - /** - * @return StyleColor - */ - public function getColor() + public function getColor(): ?StyleColor { return $this->color; } diff --git a/src/PhpPresentation/Slide/Background/Image.php b/src/PhpPresentation/Slide/Background/Image.php index 4aaf9b505e..39c998e2ba 100644 --- a/src/PhpPresentation/Slide/Background/Image.php +++ b/src/PhpPresentation/Slide/Background/Image.php @@ -1,7 +1,26 @@ path; } /** - * Set Path + * Set Path. + * + * @param string $pValue File path + * @param bool $pVerifyFile Verify file + * + * @throws FileNotFoundException * - * @param string $pValue File path - * @param boolean $pVerifyFile Verify file - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Shape\Drawing + * @return self */ - public function setPath($pValue = '', $pVerifyFile = true) + public function setPath(string $pValue = '', bool $pVerifyFile = true) { if ($pVerifyFile) { if (!file_exists($pValue)) { - throw new \Exception("File not found : $pValue"); + throw new FileNotFoundException($pValue); } - if ($this->width == 0 && $this->height == 0) { + if (0 == $this->width && 0 == $this->height) { // Get width/height list($this->width, $this->height) = getimagesize($pValue); } } $this->path = $pValue; + return $this; } /** - * Get Filename + * Get Filename. * * @return string */ - public function getFilename() + public function getFilename(): string { - return basename($this->path); + return $this->path ? basename($this->path) : ''; } /** - * Get Extension + * Get Extension. * * @return string */ - public function getExtension() + public function getExtension(): string { - $exploded = explode('.', basename($this->path)); + $exploded = explode('.', $this->getFilename()); return $exploded[count($exploded) - 1]; } /** - * Get indexed filename (using image index) + * Get indexed filename (using image index). + * + * @param string $numSlide * * @return string */ diff --git a/src/PhpPresentation/Slide/Background/SchemeColor.php b/src/PhpPresentation/Slide/Background/SchemeColor.php index 51bba87938..3cb785df53 100644 --- a/src/PhpPresentation/Slide/Background/SchemeColor.php +++ b/src/PhpPresentation/Slide/Background/SchemeColor.php @@ -1,4 +1,22 @@ schemeColor = $color; + return $this; } - /** - * @return StyleSchemeColor - */ - public function getSchemeColor() + public function getSchemeColor(): ?StyleSchemeColor { return $this->schemeColor; } diff --git a/src/PhpPresentation/Slide/Iterator.php b/src/PhpPresentation/Slide/Iterator.php index 72043c1d41..787d06153f 100644 --- a/src/PhpPresentation/Slide/Iterator.php +++ b/src/PhpPresentation/Slide/Iterator.php @@ -10,49 +10,46 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Slide; +use IteratorIterator; use PhpOffice\PhpPresentation\PhpPresentation; -/** - * \PhpOffice\PhpPresentation\Slide\Iterator - * - * Used to iterate slides in PhpPresentation - */ -class Iterator extends \IteratorIterator +// @phpstan-ignore-next-line +class Iterator extends IteratorIterator { /** - * Presentation to iterate + * Presentation to iterate. * - * @var \PhpOffice\PhpPresentation\PhpPresentation + * @var PhpPresentation */ private $subject; /** - * Current iterator position + * Current iterator position. * * @var int */ private $position = 0; /** - * Create a new slide iterator - * - * @param PhpPresentation $subject + * Create a new slide iterator. */ - public function __construct(PhpPresentation $subject = null) + public function __construct(PhpPresentation $subject) { - // Set subject $this->subject = $subject; } /** - * Destructor + * Destructor. */ public function __destruct() { @@ -60,7 +57,7 @@ public function __destruct() } /** - * Rewind iterator + * Rewind iterator. */ public function rewind() { @@ -68,7 +65,7 @@ public function rewind() } /** - * Current \PhpOffice\PhpPresentation\Slide + * Current \PhpOffice\PhpPresentation\Slide. * * @return \PhpOffice\PhpPresentation\Slide */ @@ -78,7 +75,7 @@ public function current() } /** - * Current key + * Current key. * * @return int */ @@ -88,7 +85,7 @@ public function key() } /** - * Next value + * Next value. */ public function next() { @@ -98,7 +95,7 @@ public function next() /** * More \PhpOffice\PhpPresentation\Slide instances available? * - * @return boolean + * @return bool */ public function valid() { diff --git a/src/PhpPresentation/Slide/Layout.php b/src/PhpPresentation/Slide/Layout.php index b4fc027673..1c1ec93cb6 100644 --- a/src/PhpPresentation/Slide/Layout.php +++ b/src/PhpPresentation/Slide/Layout.php @@ -10,28 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Slide; /** - * \PhpOffice\PhpPresentation\Slide\Layout + * \PhpOffice\PhpPresentation\Slide\Layout. */ class Layout { /** Layout constants */ - const TITLE_SLIDE = 'Title Slide'; - const TITLE_AND_CONTENT = 'Title and Content'; - const SECTION_HEADER = 'Section Header'; - const TWO_CONTENT = 'Two Content'; - const COMPARISON = 'Comparison'; - const TITLE_ONLY = 'Title Only'; - const BLANK = 'Blank'; - const CONTENT_WITH_CAPTION = 'Content with Caption'; - const PICTURE_WITH_CAPTION = 'Picture with Caption'; - const TITLE_AND_VERTICAL_TEXT = 'Title and Vertical Text'; - const VERTICAL_TITLE_AND_TEXT = 'Vertical Title and Text'; + public const TITLE_SLIDE = 'Title Slide'; + public const TITLE_AND_CONTENT = 'Title and Content'; + public const SECTION_HEADER = 'Section Header'; + public const TWO_CONTENT = 'Two Content'; + public const COMPARISON = 'Comparison'; + public const TITLE_ONLY = 'Title Only'; + public const BLANK = 'Blank'; + public const CONTENT_WITH_CAPTION = 'Content with Caption'; + public const PICTURE_WITH_CAPTION = 'Picture with Caption'; + public const TITLE_AND_VERTICAL_TEXT = 'Title and Vertical Text'; + public const VERTICAL_TITLE_AND_TEXT = 'Vertical Title and Text'; } diff --git a/src/PhpPresentation/Slide/Note.php b/src/PhpPresentation/Slide/Note.php index 2dd9bb3ab6..d1423a0262 100644 --- a/src/PhpPresentation/Slide/Note.php +++ b/src/PhpPresentation/Slide/Note.php @@ -10,83 +10,84 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Slide; +use ArrayObject; use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\GeometryCalculator; +use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\ShapeContainerInterface; use PhpOffice\PhpPresentation\Slide; -use PhpOffice\PhpPresentation\Shape\RichText; -/** - * Note class - */ class Note implements ComparableInterface, ShapeContainerInterface { /** - * Parent slide + * Parent slide. * * @var Slide */ private $parent; /** - * Collection of shapes + * Collection of shapes. * - * @var \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] + * @var array|ArrayObject */ - private $shapeCollection = null; + private $shapeCollection; /** - * Note identifier + * Note identifier. * * @var string */ private $identifier; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Offset X + * Offset X. * * @var int */ protected $offsetX; /** - * Offset Y + * Offset Y. * * @var int */ protected $offsetY; /** - * Extent X + * Extent X. * * @var int */ protected $extentX; /** - * Extent Y + * Extent Y. * * @var int */ protected $extentY; /** - * Create a new note + * Create a new note. * * @param Slide $pParent */ @@ -96,16 +97,16 @@ public function __construct(Slide $pParent = null) $this->parent = $pParent; // Shape collection - $this->shapeCollection = new \ArrayObject(); + $this->shapeCollection = new ArrayObject(); // Set identifier $this->identifier = md5(rand(0, 9999) . time()); } /** - * Get collection of shapes + * Get collection of shapes. * - * @return \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] + * @return array|ArrayObject */ public function getShapeCollection() { @@ -113,12 +114,11 @@ public function getShapeCollection() } /** - * Add shape to slide + * Add shape to slide. * - * @param \PhpOffice\PhpPresentation\AbstractShape $shape - * @return \PhpOffice\PhpPresentation\AbstractShape + * @return AbstractShape */ - public function addShape(AbstractShape $shape) + public function addShape(AbstractShape $shape): AbstractShape { $shape->setContainer($this); @@ -126,11 +126,9 @@ public function addShape(AbstractShape $shape) } /** - * Create rich text shape - * - * @return \PhpOffice\PhpPresentation\Shape\RichText + * Create rich text shape. */ - public function createRichTextShape() + public function createRichTextShape(): RichText { $shape = new RichText(); $this->addShape($shape); @@ -139,7 +137,7 @@ public function createRichTextShape() } /** - * Get parent + * Get parent. * * @return Slide */ @@ -149,111 +147,110 @@ public function getParent() } /** - * Set parent + * Set parent. * - * @param Slide $parent * @return Note */ public function setParent(Slide $parent) { $this->parent = $parent; + return $this; } - /** - * Get X Offset - * - * @return int + * Get X Offset. */ - public function getOffsetX() + public function getOffsetX(): int { - if ($this->offsetX === null) { + if (null === $this->offsetX) { $offsets = GeometryCalculator::calculateOffsets($this); $this->offsetX = $offsets[GeometryCalculator::X]; $this->offsetY = $offsets[GeometryCalculator::Y]; } + return $this->offsetX; } - + /** - * Get Y Offset - * - * @return int + * Get Y Offset. */ - public function getOffsetY() + public function getOffsetY(): int { - if ($this->offsetY === null) { + if (null === $this->offsetY) { $offsets = GeometryCalculator::calculateOffsets($this); $this->offsetX = $offsets[GeometryCalculator::X]; $this->offsetY = $offsets[GeometryCalculator::Y]; } + return $this->offsetY; } - + /** - * Get X Extent - * - * @return int + * Get X Extent. */ - public function getExtentX() + public function getExtentX(): int { - if ($this->extentX === null) { + if (null === $this->extentX) { $extents = GeometryCalculator::calculateExtents($this); $this->extentX = $extents[GeometryCalculator::X]; $this->extentY = $extents[GeometryCalculator::Y]; } + return $this->extentX; } - + /** - * Get Y Extent - * - * @return int + * Get Y Extent. */ - public function getExtentY() + public function getExtentY(): int { - if ($this->extentY === null) { + if (null === $this->extentY) { $extents = GeometryCalculator::calculateExtents($this); $this->extentX = $extents[GeometryCalculator::X]; $this->extentY = $extents[GeometryCalculator::Y]; } + return $this->extentY; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5($this->identifier . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Slide/SlideLayout.php b/src/PhpPresentation/Slide/SlideLayout.php index 72f42b8e5b..9c30db23ba 100644 --- a/src/PhpPresentation/Slide/SlideLayout.php +++ b/src/PhpPresentation/Slide/SlideLayout.php @@ -10,10 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Slide; use PhpOffice\PhpPresentation\ComparableInterface; @@ -22,42 +26,43 @@ class SlideLayout extends AbstractSlide implements ComparableInterface, ShapeContainerInterface { + /** + * @var SlideMaster + */ protected $slideMaster; /** - * Slide relation ID (should not be used by user code!) + * Slide relation ID (should not be used by user code!). * * @var string */ public $relationId; /** - * Slide layout NR (should not be used by user code!) + * Slide layout NR (should not be used by user code!). * * @var int */ public $layoutNr; /** - * Slide layout ID (should not be used by user code!) + * Slide layout ID (should not be used by user code!). * * @var int */ public $layoutId; /** - * Slide layout ID (should not be used by user code!) + * Slide layout ID (should not be used by user code!). * - * @var int + * @var string|null */ protected $layoutName; /** - * Mapping of colors to the theme + * Mapping of colors to the theme. * * @var \PhpOffice\PhpPresentation\Style\ColorMap */ public $colorMap; /** - * Create a new slideLayout - * - * @param SlideMaster $pSlideMaster + * Create a new slideLayout. */ public function __construct(SlideMaster $pSlideMaster) { @@ -71,28 +76,19 @@ public function __construct(SlideMaster $pSlideMaster) $this->colorMap = new ColorMap(); } - /** - * @return int - */ - public function getLayoutName() + public function getLayoutName(): ?string { return $this->layoutName; } - /** - * @param int $layoutName - * @return SlideLayout - */ - public function setLayoutName($layoutName) + public function setLayoutName(string $layoutName): self { $this->layoutName = $layoutName; + return $this; } - /** - * @return SlideMaster - */ - public function getSlideMaster() + public function getSlideMaster(): SlideMaster { return $this->slideMaster; } diff --git a/src/PhpPresentation/Slide/SlideMaster.php b/src/PhpPresentation/Slide/SlideMaster.php index ee5d6bd3b5..3966f008cf 100644 --- a/src/PhpPresentation/Slide/SlideMaster.php +++ b/src/PhpPresentation/Slide/SlideMaster.php @@ -10,10 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Slide; use PhpOffice\PhpPresentation\ComparableInterface; @@ -25,35 +29,32 @@ use PhpOffice\PhpPresentation\Style\SchemeColor; use PhpOffice\PhpPresentation\Style\TextStyle; -/** - * Class SlideMaster - */ class SlideMaster extends AbstractSlide implements ComparableInterface, ShapeContainerInterface { /** - * Collection of Slide objects + * Collection of Slide objects. * - * @var \PhpOffice\PhpPresentation\Slide\SlideLayout[] + * @var array */ - protected $slideLayouts = array(); + protected $slideLayouts = []; /** - * Mapping of colors to the theme + * Mapping of colors to the theme. * - * @var \PhpOffice\PhpPresentation\Style\ColorMap + * @var ColorMap */ public $colorMap; /** - * @var \PhpOffice\PhpPresentation\Style\TextStyle + * @var TextStyle */ protected $textStyles; /** - * @var \PhpOffice\PhpPresentation\Style\SchemeColor[] + * @var array */ - protected $arraySchemeColor = array(); + protected $arraySchemeColor = []; /** - * @var array + * @var array */ - protected $defaultSchemeColor = array( + protected $defaultSchemeColor = [ 'dk1' => '000000', 'lt1' => 'FFFFFF', 'dk2' => '1F497D', @@ -66,12 +67,10 @@ class SlideMaster extends AbstractSlide implements ComparableInterface, ShapeCon 'accent6' => 'F79646', 'hlink' => '0000FF', 'folHlink' => '800080', - ); + ]; /** - * Create a new slideMaster - * - * @param PhpPresentation $pParent + * Create a new slideMaster. */ public function __construct(PhpPresentation $pParent = null) { @@ -98,34 +97,36 @@ public function __construct(PhpPresentation $pParent = null) } /** - * Create a slideLayout and add it to this presentation + * Create a slideLayout and add it to this presentation. * - * @return \PhpOffice\PhpPresentation\Slide\SlideLayout + * @return SlideLayout */ - public function createSlideLayout() + public function createSlideLayout(): SlideLayout { $newSlideLayout = new SlideLayout($this); $this->addSlideLayout($newSlideLayout); + return $newSlideLayout; } /** - * Add slideLayout + * Add slideLayout. + * + * @param SlideLayout|null $slideLayout * - * @param \PhpOffice\PhpPresentation\Slide\SlideLayout $slideLayout - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Slide\SlideLayout + * @return SlideLayout */ - public function addSlideLayout(SlideLayout $slideLayout = null) + public function addSlideLayout(SlideLayout $slideLayout = null): SlideLayout { $this->slideLayouts[] = $slideLayout; + return $slideLayout; } /** - * @return SlideLayout[] + * @return array */ - public function getAllSlideLayouts() + public function getAllSlideLayouts(): array { return $this->slideLayouts; } @@ -133,35 +134,35 @@ public function getAllSlideLayouts() /** * @return TextStyle */ - public function getTextStyles() + public function getTextStyles(): TextStyle { return $this->textStyles; } /** - * @param TextStyle $textStyle - * @return $this + * @return self */ - public function setTextStyles(TextStyle $textStyle) + public function setTextStyles(TextStyle $textStyle): self { $this->textStyles = $textStyle; + return $this; } /** - * @param SchemeColor $schemeColor - * @return $this + * @return self */ - public function addSchemeColor(SchemeColor $schemeColor) + public function addSchemeColor(SchemeColor $schemeColor): self { $this->arraySchemeColor[$schemeColor->getValue()] = $schemeColor; + return $this; } /** - * @return \PhpOffice\PhpPresentation\Style\SchemeColor[] + * @return array */ - public function getAllSchemeColors() + public function getAllSchemeColors(): array { return $this->arraySchemeColor; } diff --git a/src/PhpPresentation/Slide/Transition.php b/src/PhpPresentation/Slide/Transition.php index 56c760e396..9836f7c62e 100644 --- a/src/PhpPresentation/Slide/Transition.php +++ b/src/PhpPresentation/Slide/Transition.php @@ -10,73 +10,72 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ -namespace PhpOffice\PhpPresentation\Slide; +declare(strict_types=1); -use PhpOffice\PhpPresentation\Slide; -use PhpOffice\PhpPresentation\Shape\RichText; +namespace PhpOffice\PhpPresentation\Slide; /** - * Transition class + * Transition class. */ class Transition { - const SPEED_FAST = 'fast'; - const SPEED_MEDIUM = 'med'; - const SPEED_SLOW = 'slow'; - - const TRANSITION_BLINDS_HORIZONTAL = 'blinds_horz'; - const TRANSITION_BLINDS_VERTICAL = 'blinds_vert'; - const TRANSITION_CHECKER_HORIZONTAL = 'checker_horz'; - const TRANSITION_CHECKER_VERTICAL = 'checker_vert'; - const TRANSITION_CIRCLE_HORIZONTAL = 'circle_horz'; - const TRANSITION_CIRCLE_VERTICAL = 'circle_vert'; - const TRANSITION_COMB_HORIZONTAL = 'comb_horz'; - const TRANSITION_COMB_VERTICAL = 'comb_vert'; - const TRANSITION_COVER_DOWN = 'cover_d'; - const TRANSITION_COVER_LEFT = 'cover_l'; - const TRANSITION_COVER_LEFT_DOWN = 'cover_ld'; - const TRANSITION_COVER_LEFT_UP = 'cover_lu'; - const TRANSITION_COVER_RIGHT = 'cover_r'; - const TRANSITION_COVER_RIGHT_DOWN = 'cover_rd'; - const TRANSITION_COVER_RIGHT_UP = 'cover_ru'; - const TRANSITION_COVER_UP = 'cover_u'; - const TRANSITION_CUT = 'cut'; - const TRANSITION_DIAMOND = 'diamond'; - const TRANSITION_DISSOLVE = 'dissolve'; - const TRANSITION_FADE = 'fade'; - const TRANSITION_NEWSFLASH = 'newsflash'; - const TRANSITION_PLUS = 'plus'; - const TRANSITION_PULL_DOWN = 'pull_d'; - const TRANSITION_PULL_LEFT = 'pull_l'; - const TRANSITION_PULL_RIGHT = 'pull_r'; - const TRANSITION_PULL_UP = 'pull_u'; - const TRANSITION_PUSH_DOWN = 'push_d'; - const TRANSITION_PUSH_LEFT = 'push_l'; - const TRANSITION_PUSH_RIGHT = 'push_r'; - const TRANSITION_PUSH_UP = 'push_u'; - const TRANSITION_RANDOM = 'random'; - const TRANSITION_RANDOMBAR_HORIZONTAL = 'randomBar_horz'; - const TRANSITION_RANDOMBAR_VERTICAL = 'randomBar_vert'; - const TRANSITION_SPLIT_IN_HORIZONTAL = 'split_in_horz'; - const TRANSITION_SPLIT_OUT_HORIZONTAL = 'split_out_horz'; - const TRANSITION_SPLIT_IN_VERTICAL = 'split_in_vert'; - const TRANSITION_SPLIT_OUT_VERTICAL = 'split_out_vert'; - const TRANSITION_STRIPS_LEFT_DOWN = 'strips_ld'; - const TRANSITION_STRIPS_LEFT_UP = 'strips_lu'; - const TRANSITION_STRIPS_RIGHT_DOWN = 'strips_rd'; - const TRANSITION_STRIPS_RIGHT_UP = 'strips_ru'; - const TRANSITION_WEDGE = 'wedge'; - const TRANSITION_WIPE_DOWN = 'wipe_d'; - const TRANSITION_WIPE_LEFT = 'wipe_l'; - const TRANSITION_WIPE_RIGHT = 'wipe_r'; - const TRANSITION_WIPE_UP = 'wipe_u'; - const TRANSITION_ZOOM_IN = 'zoom_in'; - const TRANSITION_ZOOM_OUT = 'zoom_out'; + public const SPEED_FAST = 'fast'; + public const SPEED_MEDIUM = 'med'; + public const SPEED_SLOW = 'slow'; + + public const TRANSITION_BLINDS_HORIZONTAL = 'blinds_horz'; + public const TRANSITION_BLINDS_VERTICAL = 'blinds_vert'; + public const TRANSITION_CHECKER_HORIZONTAL = 'checker_horz'; + public const TRANSITION_CHECKER_VERTICAL = 'checker_vert'; + public const TRANSITION_CIRCLE = 'circle'; + public const TRANSITION_COMB_HORIZONTAL = 'comb_horz'; + public const TRANSITION_COMB_VERTICAL = 'comb_vert'; + public const TRANSITION_COVER_DOWN = 'cover_d'; + public const TRANSITION_COVER_LEFT = 'cover_l'; + public const TRANSITION_COVER_LEFT_DOWN = 'cover_ld'; + public const TRANSITION_COVER_LEFT_UP = 'cover_lu'; + public const TRANSITION_COVER_RIGHT = 'cover_r'; + public const TRANSITION_COVER_RIGHT_DOWN = 'cover_rd'; + public const TRANSITION_COVER_RIGHT_UP = 'cover_ru'; + public const TRANSITION_COVER_UP = 'cover_u'; + public const TRANSITION_CUT = 'cut'; + public const TRANSITION_DIAMOND = 'diamond'; + public const TRANSITION_DISSOLVE = 'dissolve'; + public const TRANSITION_FADE = 'fade'; + public const TRANSITION_NEWSFLASH = 'newsflash'; + public const TRANSITION_PLUS = 'plus'; + public const TRANSITION_PULL_DOWN = 'pull_d'; + public const TRANSITION_PULL_LEFT = 'pull_l'; + public const TRANSITION_PULL_RIGHT = 'pull_r'; + public const TRANSITION_PULL_UP = 'pull_u'; + public const TRANSITION_PUSH_DOWN = 'push_d'; + public const TRANSITION_PUSH_LEFT = 'push_l'; + public const TRANSITION_PUSH_RIGHT = 'push_r'; + public const TRANSITION_PUSH_UP = 'push_u'; + public const TRANSITION_RANDOM = 'random'; + public const TRANSITION_RANDOMBAR_HORIZONTAL = 'randomBar_horz'; + public const TRANSITION_RANDOMBAR_VERTICAL = 'randomBar_vert'; + public const TRANSITION_SPLIT_IN_HORIZONTAL = 'split_in_horz'; + public const TRANSITION_SPLIT_OUT_HORIZONTAL = 'split_out_horz'; + public const TRANSITION_SPLIT_IN_VERTICAL = 'split_in_vert'; + public const TRANSITION_SPLIT_OUT_VERTICAL = 'split_out_vert'; + public const TRANSITION_STRIPS_LEFT_DOWN = 'strips_ld'; + public const TRANSITION_STRIPS_LEFT_UP = 'strips_lu'; + public const TRANSITION_STRIPS_RIGHT_DOWN = 'strips_rd'; + public const TRANSITION_STRIPS_RIGHT_UP = 'strips_ru'; + public const TRANSITION_WEDGE = 'wedge'; + public const TRANSITION_WIPE_DOWN = 'wipe_d'; + public const TRANSITION_WIPE_LEFT = 'wipe_l'; + public const TRANSITION_WIPE_RIGHT = 'wipe_r'; + public const TRANSITION_WIPE_UP = 'wipe_u'; + public const TRANSITION_ZOOM_IN = 'zoom_in'; + public const TRANSITION_ZOOM_OUT = 'zoom_out'; /** * @var bool @@ -87,25 +86,21 @@ class Transition */ protected $hasTimeTrigger = false; /** - * @var int + * @var int|null */ protected $advanceTimeTrigger = null; /** - * @var null|self::SPEED_SLOW|self::SPEED_MEDIUM|self::SPEED_FAST + * @var string|null */ protected $speed = null; /** - * @var null|self::TRANSITION_* + * @var string|null */ protected $transitionType = null; - /** - * @var array - */ - protected $transitionOptions = array(); - public function setSpeed($speed = self::SPEED_MEDIUM) + public function setSpeed(?string $speed = self::SPEED_MEDIUM): self { - if (in_array($speed, array(self::SPEED_FAST, self::SPEED_MEDIUM, self::SPEED_SLOW))) { + if (in_array($speed, [self::SPEED_FAST, self::SPEED_MEDIUM, self::SPEED_SLOW])) { $this->speed = $speed; } else { $this->speed = null; @@ -114,53 +109,49 @@ public function setSpeed($speed = self::SPEED_MEDIUM) return $this; } - public function getSpeed() + public function getSpeed(): ?string { return $this->speed; } - public function setManualTrigger($value = false) + public function setManualTrigger(bool $value = false): self { - if (is_bool($value)) { - $this->hasManualTrigger = $value; - } + $this->hasManualTrigger = $value; + return $this; } - public function hasManualTrigger() + public function hasManualTrigger(): bool { return $this->hasManualTrigger; } - public function setTimeTrigger($value = false, $advanceTime = 1000) + public function setTimeTrigger(bool $value = false, int $advanceTime = 1000): self { - if (is_bool($value)) { - $this->hasTimeTrigger = $value; - } - $this->advanceTimeTrigger = null; - if ($this->hasTimeTrigger === true) { - $this->advanceTimeTrigger = (int) $advanceTime; - } + $this->hasTimeTrigger = $value; + $this->advanceTimeTrigger = true === $value ? $advanceTime : null; + return $this; } - public function hasTimeTrigger() + public function hasTimeTrigger(): bool { return $this->hasTimeTrigger; } - public function getAdvanceTimeTrigger() + public function getAdvanceTimeTrigger(): ?int { return $this->advanceTimeTrigger; } - public function setTransitionType($type = null) + public function setTransitionType(string $type = null): self { $this->transitionType = $type; + return $this; } - public function getTransitionType() + public function getTransitionType(): ?string { return $this->transitionType; } diff --git a/src/PhpPresentation/Style/Alignment.php b/src/PhpPresentation/Style/Alignment.php index 89cde6a780..fae963ebe7 100644 --- a/src/PhpPresentation/Style/Alignment.php +++ b/src/PhpPresentation/Style/Alignment.php @@ -10,136 +10,142 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; -/** - * \PhpOffice\PhpPresentation\Style\Alignment - */ class Alignment implements ComparableInterface { /* Horizontal alignment */ - const HORIZONTAL_GENERAL = 'l'; - const HORIZONTAL_LEFT = 'l'; - const HORIZONTAL_RIGHT = 'r'; - const HORIZONTAL_CENTER = 'ctr'; - const HORIZONTAL_JUSTIFY = 'just'; - const HORIZONTAL_DISTRIBUTED = 'dist'; + public const HORIZONTAL_GENERAL = 'l'; + public const HORIZONTAL_LEFT = 'l'; + public const HORIZONTAL_RIGHT = 'r'; + public const HORIZONTAL_CENTER = 'ctr'; + public const HORIZONTAL_JUSTIFY = 'just'; + public const HORIZONTAL_DISTRIBUTED = 'dist'; /* Vertical alignment */ - const VERTICAL_BASE = 'base'; - const VERTICAL_AUTO = 'auto'; - const VERTICAL_BOTTOM = 'b'; - const VERTICAL_TOP = 't'; - const VERTICAL_CENTER = 'ctr'; + public const VERTICAL_BASE = 'base'; + public const VERTICAL_AUTO = 'auto'; + public const VERTICAL_BOTTOM = 'b'; + public const VERTICAL_TOP = 't'; + public const VERTICAL_CENTER = 'ctr'; /* Text direction */ - const TEXT_DIRECTION_HORIZONTAL = 'horz'; - const TEXT_DIRECTION_VERTICAL_90 = 'vert'; - const TEXT_DIRECTION_VERTICAL_270 = 'vert270'; - const TEXT_DIRECTION_STACKED = 'wordArtVert'; + public const TEXT_DIRECTION_HORIZONTAL = 'horz'; + public const TEXT_DIRECTION_VERTICAL_90 = 'vert'; + public const TEXT_DIRECTION_VERTICAL_270 = 'vert270'; + public const TEXT_DIRECTION_STACKED = 'wordArtVert'; - private $supportedStyles = array( + /** + * @var array + */ + private $supportedStyles = [ self::HORIZONTAL_GENERAL, self::HORIZONTAL_LEFT, self::HORIZONTAL_RIGHT, - ); + ]; /** - * Horizontal + * Horizontal. + * * @var string */ - private $horizontal; + private $horizontal = self::HORIZONTAL_LEFT; /** - * Vertical + * Vertical. + * * @var string */ - private $vertical; + private $vertical = self::VERTICAL_BASE; /** - * Text Direction + * Text Direction. + * * @var string */ private $textDirection = self::TEXT_DIRECTION_HORIZONTAL; /** - * Level + * Level. + * * @var int */ private $level = 0; /** - * Indent - only possible with horizontal alignment left and right - * @var int + * Indent - only possible with horizontal alignment left and right. + * + * @var float */ private $indent = 0; /** - * Margin left - only possible with horizontal alignment left and right - * @var int + * Margin left - only possible with horizontal alignment left and right. + * + * @var float */ private $marginLeft = 0; /** - * Margin right - only possible with horizontal alignment left and right - * @var int + * Margin right - only possible with horizontal alignment left and right. + * + * @var float */ private $marginRight = 0; /** - * Margin top - * @var int + * Margin top. + * + * @var float */ private $marginTop = 0; /** - * Margin bottom - * @var int + * Margin bottom. + * + * @var float */ private $marginBottom = 0; /** - * Hash index - * @var string + * RTL Direction Support + * + * @var bool */ - private $hashIndex; + private $isRTL = false; /** - * Create a new \PhpOffice\PhpPresentation\Style\Alignment + * Hash index. + * + * @var int */ - public function __construct() - { - // Initialise values - $this->horizontal = self::HORIZONTAL_LEFT; - $this->vertical = self::VERTICAL_BASE; - } + private $hashIndex; /** - * Get Horizontal - * - * @return string + * Get Horizontal. */ - public function getHorizontal() + public function getHorizontal(): string { return $this->horizontal; } /** - * Set Horizontal - * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set Horizontal. */ - public function setHorizontal($pValue = self::HORIZONTAL_LEFT) + public function setHorizontal(string $pValue = self::HORIZONTAL_LEFT): self { - if ($pValue == '') { + if ('' == $pValue) { $pValue = self::HORIZONTAL_LEFT; } $this->horizontal = $pValue; @@ -148,24 +154,19 @@ public function setHorizontal($pValue = self::HORIZONTAL_LEFT) } /** - * Get Vertical - * - * @return string + * Get Vertical. */ - public function getVertical() + public function getVertical(): string { return $this->vertical; } /** - * Set Vertical - * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set Vertical. */ - public function setVertical($pValue = self::VERTICAL_BASE) + public function setVertical(string $pValue = self::VERTICAL_BASE): self { - if ($pValue == '') { + if ('' == $pValue) { $pValue = self::VERTICAL_BASE; } $this->vertical = $pValue; @@ -174,26 +175,24 @@ public function setVertical($pValue = self::VERTICAL_BASE) } /** - * Get Level - * - * @return int + * Get Level. */ - public function getLevel() + public function getLevel(): int { return $this->level; } /** - * Set Level + * Set Level. * - * @param int $pValue Ranging 0 - 8 - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Style\Alignment + * @param int $pValue Ranging 0 - 8 + * + * @throws OutOfBoundsException */ - public function setLevel($pValue = 0) + public function setLevel(int $pValue = 0): self { if ($pValue < 0) { - throw new \Exception("Invalid value should be more than 0."); + throw new OutOfBoundsException(0, null, $pValue); } $this->level = $pValue; @@ -201,22 +200,17 @@ public function setLevel($pValue = 0) } /** - * Get indent - * - * @return int + * Get indent. */ - public function getIndent() + public function getIndent(): float { return $this->indent; } /** - * Set indent - * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set indent. */ - public function setIndent($pValue = 0) + public function setIndent(float $pValue = 0): self { if ($pValue > 0 && !in_array($this->getHorizontal(), $this->supportedStyles)) { $pValue = 0; // indent not supported @@ -228,22 +222,17 @@ public function setIndent($pValue = 0) } /** - * Get margin left - * - * @return int + * Get margin left. */ - public function getMarginLeft() + public function getMarginLeft(): float { return $this->marginLeft; } /** - * Set margin left - * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set margin left. */ - public function setMarginLeft($pValue = 0) + public function setMarginLeft(float $pValue = 0): self { if ($pValue > 0 && !in_array($this->getHorizontal(), $this->supportedStyles)) { $pValue = 0; // margin left not supported @@ -255,22 +244,17 @@ public function setMarginLeft($pValue = 0) } /** - * Get margin right - * - * @return int + * Get margin right. */ - public function getMarginRight() + public function getMarginRight(): float { return $this->marginRight; } /** - * Set margin ight - * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set margin ight. */ - public function setMarginRight($pValue = 0) + public function setMarginRight(float $pValue = 0): self { if ($pValue > 0 && !in_array($this->getHorizontal(), $this->supportedStyles)) { $pValue = 0; // margin right not supported @@ -282,22 +266,17 @@ public function setMarginRight($pValue = 0) } /** - * Get margin top - * - * @return int + * Get margin top. */ - public function getMarginTop() + public function getMarginTop(): float { return $this->marginTop; } /** - * Set margin top - * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set margin top. */ - public function setMarginTop($pValue = 0) + public function setMarginTop(float $pValue = 0): self { $this->marginTop = $pValue; @@ -305,55 +284,64 @@ public function setMarginTop($pValue = 0) } /** - * Get margin bottom - * - * @return int + * Get margin bottom. */ - public function getMarginBottom() + public function getMarginBottom(): float { return $this->marginBottom; } /** - * Set margin bottom - * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Set margin bottom. */ - public function setMarginBottom($pValue = 0) + public function setMarginBottom(float $pValue = 0): self { $this->marginBottom = $pValue; return $this; } - /** - * @return string - */ - public function getTextDirection() + public function getTextDirection(): string { return $this->textDirection; } - /** - * @param string $pValue - * @return Alignment - */ - public function setTextDirection($pValue = self::TEXT_DIRECTION_HORIZONTAL) + public function setTextDirection(string $pValue = self::TEXT_DIRECTION_HORIZONTAL): self { if (empty($pValue)) { $pValue = self::TEXT_DIRECTION_HORIZONTAL; } $this->textDirection = $pValue; + return $this; } /** - * Get hash code + * @return bool + */ + public function isRTL(): bool + { + return $this->isRTL; + } + + /** + * @param bool $value + * + * @return self + */ + public function setIsRTL(bool $value = false): self + { + $this->isRTL = $value; + + return $this; + } + + /** + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5( $this->horizontal @@ -362,33 +350,38 @@ public function getHashCode() . $this->indent . $this->marginLeft . $this->marginRight + . ($this->isRTL ? '1' : '0') . __CLASS__ ); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/Border.php b/src/PhpPresentation/Style/Border.php index f8dddf81f8..59b55ba3ad 100644 --- a/src/PhpPresentation/Style/Border.php +++ b/src/PhpPresentation/Style/Border.php @@ -10,105 +10,99 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; -/** - * \PhpOffice\PhpPresentation\Style\Border - */ class Border implements ComparableInterface { /* Line style */ - const LINE_NONE = 'none'; - const LINE_SINGLE = 'sng'; - const LINE_DOUBLE = 'dbl'; - const LINE_THICKTHIN = 'thickThin'; - const LINE_THINTHICK = 'thinThick'; - const LINE_TRI = 'tri'; + public const LINE_NONE = 'none'; + public const LINE_SINGLE = 'sng'; + public const LINE_DOUBLE = 'dbl'; + public const LINE_THICKTHIN = 'thickThin'; + public const LINE_THINTHICK = 'thinThick'; + public const LINE_TRI = 'tri'; /* Dash style */ - const DASH_DASH = 'dash'; - const DASH_DASHDOT = 'dashDot'; - const DASH_DOT = 'dot'; - const DASH_LARGEDASH = 'lgDash'; - const DASH_LARGEDASHDOT = 'lgDashDot'; - const DASH_LARGEDASHDOTDOT = 'lgDashDotDot'; - const DASH_SOLID = 'solid'; - const DASH_SYSDASH = 'sysDash'; - const DASH_SYSDASHDOT = 'sysDashDot'; - const DASH_SYSDASHDOTDOT = 'sysDashDotDot'; - const DASH_SYSDOT = 'sysDot'; + public const DASH_DASH = 'dash'; + public const DASH_DASHDOT = 'dashDot'; + public const DASH_DOT = 'dot'; + public const DASH_LARGEDASH = 'lgDash'; + public const DASH_LARGEDASHDOT = 'lgDashDot'; + public const DASH_LARGEDASHDOTDOT = 'lgDashDotDot'; + public const DASH_SOLID = 'solid'; + public const DASH_SYSDASH = 'sysDash'; + public const DASH_SYSDASHDOT = 'sysDashDot'; + public const DASH_SYSDASHDOTDOT = 'sysDashDotDot'; + public const DASH_SYSDOT = 'sysDot'; /** - * Line width + * Line width. * * @var int */ private $lineWidth = 1; /** - * Line style + * Line style. * * @var string */ - private $lineStyle; + private $lineStyle = self::LINE_SINGLE; /** - * Dash style + * Dash style. * * @var string */ - private $dashStyle; + private $dashStyle = self::DASH_SOLID; /** - * Border color + * Border color. * - * @var \PhpOffice\PhpPresentation\Style\Color + * @var Color */ private $color; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; - /** - * Create a new \PhpOffice\PhpPresentation\Style\Border - */ public function __construct() { - // Initialise values - $this->lineWidth = 1; - $this->lineStyle = self::LINE_SINGLE; - $this->dashStyle = self::DASH_SOLID; - $this->color = new Color(Color::COLOR_BLACK); + $this->color = new Color(Color::COLOR_BLACK); } /** - * Get line width (in points) + * Get line width (in points). * * @return int */ - public function getLineWidth() + public function getLineWidth(): int { return $this->lineWidth; } /** - * Set line width (in points) + * Set line width (in points). * - * @param int $pValue - * @return \PhpOffice\PhpPresentation\Style\Border + * @param int $pValue + * + * @return self */ - public function setLineWidth($pValue = 1) + public function setLineWidth(int $pValue = 1): self { $this->lineWidth = $pValue; @@ -116,24 +110,25 @@ public function setLineWidth($pValue = 1) } /** - * Get line style + * Get line style. * * @return string */ - public function getLineStyle() + public function getLineStyle(): string { return $this->lineStyle; } /** - * Set line style + * Set line style. + * + * @param string $pValue * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Border + * @return self */ - public function setLineStyle($pValue = self::LINE_SINGLE) + public function setLineStyle(string $pValue = self::LINE_SINGLE): self { - if ($pValue == '') { + if ('' == $pValue) { $pValue = self::LINE_SINGLE; } $this->lineStyle = $pValue; @@ -142,24 +137,25 @@ public function setLineStyle($pValue = self::LINE_SINGLE) } /** - * Get dash style + * Get dash style. * * @return string */ - public function getDashStyle() + public function getDashStyle(): string { return $this->dashStyle; } /** - * Set dash style + * Set dash style. * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Border + * @param string $pValue + * + * @return self */ - public function setDashStyle($pValue = self::DASH_SOLID) + public function setDashStyle(string $pValue = self::DASH_SOLID): self { - if ($pValue == '') { + if ('' == $pValue) { $pValue = self::DASH_SOLID; } $this->dashStyle = $pValue; @@ -168,23 +164,23 @@ public function setDashStyle($pValue = self::DASH_SOLID) } /** - * Get Border Color + * Get Border Color. * - * @return \PhpOffice\PhpPresentation\Style\Color + * @return Color */ - public function getColor() + public function getColor(): ?Color { return $this->color; } /** - * Set Border Color + * Set Border Color. + * + * @param Color|null $color * - * @param \PhpOffice\PhpPresentation\Style\Color $color - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Style\Border + * @return self */ - public function setColor(Color $color = null) + public function setColor(Color $color = null): self { $this->color = $color; @@ -192,11 +188,11 @@ public function setColor(Color $color = null) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5( $this->lineStyle @@ -208,28 +204,32 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/Borders.php b/src/PhpPresentation/Style/Borders.php index 3d015686f1..01fa0112ac 100644 --- a/src/PhpPresentation/Style/Borders.php +++ b/src/PhpPresentation/Style/Borders.php @@ -10,87 +10,90 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Style\Borders + * \PhpOffice\PhpPresentation\Style\Borders. */ class Borders implements ComparableInterface { /** - * Left + * Left. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $left; /** - * Right + * Right. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $right; /** - * Top + * Top. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $top; /** - * Bottom + * Bottom. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $bottom; /** - * Diagonal up + * Diagonal up. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $diagonalUp; /** - * Diagonal down + * Diagonal down. * * @var \PhpOffice\PhpPresentation\Style\Border */ private $diagonalDown; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Style\Borders + * Create a new \PhpOffice\PhpPresentation\Style\Borders. */ public function __construct() { // Initialise values - $this->left = new Border(); - $this->right = new Border(); - $this->top = new Border(); - $this->bottom = new Border(); - $this->diagonalUp = new Border(); + $this->left = new Border(); + $this->right = new Border(); + $this->top = new Border(); + $this->bottom = new Border(); + $this->diagonalUp = new Border(); $this->diagonalUp->setLineStyle(Border::LINE_NONE); - $this->diagonalDown = new Border(); + $this->diagonalDown = new Border(); $this->diagonalDown->setLineStyle(Border::LINE_NONE); } /** - * Get Left + * Get Left. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -100,7 +103,7 @@ public function getLeft() } /** - * Get Right + * Get Right. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -110,7 +113,7 @@ public function getRight() } /** - * Get Top + * Get Top. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -120,7 +123,7 @@ public function getTop() } /** - * Get Bottom + * Get Bottom. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -130,7 +133,7 @@ public function getBottom() } /** - * Get Diagonal Up + * Get Diagonal Up. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -140,7 +143,7 @@ public function getDiagonalUp() } /** - * Get Diagonal Down + * Get Diagonal Down. * * @return \PhpOffice\PhpPresentation\Style\Border */ @@ -150,11 +153,11 @@ public function getDiagonalDown() } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5( $this->getLeft()->getHashCode() @@ -168,28 +171,32 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/Bullet.php b/src/PhpPresentation/Style/Bullet.php index de078a1343..dd3729d5d7 100644 --- a/src/PhpPresentation/Style/Bullet.php +++ b/src/PhpPresentation/Style/Bullet.php @@ -10,134 +10,133 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Style\Bullet + * \PhpOffice\PhpPresentation\Style\Bullet. */ class Bullet implements ComparableInterface { /* Bullet types */ - const TYPE_NONE = 'none'; - const TYPE_BULLET = 'bullet'; - const TYPE_NUMERIC = 'numeric'; + public const TYPE_NONE = 'none'; + public const TYPE_BULLET = 'bullet'; + public const TYPE_NUMERIC = 'numeric'; /* Numeric bullet styles */ - const NUMERIC_DEFAULT = 'arabicPeriod'; - const NUMERIC_ALPHALCPARENBOTH = 'alphaLcParenBoth'; - const NUMERIC_ALPHAUCPARENBOTH = 'alphaUcParenBoth'; - const NUMERIC_ALPHALCPARENR = 'alphaLcParenR'; - const NUMERIC_ALPHAUCPARENR = 'alphaUcParenR'; - const NUMERIC_ALPHALCPERIOD = 'alphaLcPeriod'; - const NUMERIC_ALPHAUCPERIOD = 'alphaUcPeriod'; - const NUMERIC_ARABICPARENBOTH = 'arabicParenBoth'; - const NUMERIC_ARABICPARENR = 'arabicParenR'; - const NUMERIC_ARABICPERIOD = 'arabicPeriod'; - const NUMERIC_ARABICPLAIN = 'arabicPlain'; - const NUMERIC_ROMANLCPARENBOTH = 'romanLcParenBoth'; - const NUMERIC_ROMANUCPARENBOTH = 'romanUcParenBoth'; - const NUMERIC_ROMANLCPARENR = 'romanLcParenR'; - const NUMERIC_ROMANUCPARENR = 'romanUcParenR'; - const NUMERIC_ROMANLCPERIOD = 'romanLcPeriod'; - const NUMERIC_ROMANUCPERIOD = 'romanUcPeriod'; - const NUMERIC_CIRCLENUMDBPLAIN = 'circleNumDbPlain'; - const NUMERIC_CIRCLENUMWDBLACKPLAIN = 'circleNumWdBlackPlain'; - const NUMERIC_CIRCLENUMWDWHITEPLAIN = 'circleNumWdWhitePlain'; - const NUMERIC_ARABICDBPERIOD = 'arabicDbPeriod'; - const NUMERIC_ARABICDBPLAIN = 'arabicDbPlain'; - const NUMERIC_EA1CHSPERIOD = 'ea1ChsPeriod'; - const NUMERIC_EA1CHSPLAIN = 'ea1ChsPlain'; - const NUMERIC_EA1CHTPERIOD = 'ea1ChtPeriod'; - const NUMERIC_EA1CHTPLAIN = 'ea1ChtPlain'; - const NUMERIC_EA1JPNCHSDBPERIOD = 'ea1JpnChsDbPeriod'; - const NUMERIC_EA1JPNKORPLAIN = 'ea1JpnKorPlain'; - const NUMERIC_EA1JPNKORPERIOD = 'ea1JpnKorPeriod'; - const NUMERIC_ARABIC1MINUS = 'arabic1Minus'; - const NUMERIC_ARABIC2MINUS = 'arabic2Minus'; - const NUMERIC_HEBREW2MINUS = 'hebrew2Minus'; - const NUMERIC_THAIALPHAPERIOD = 'thaiAlphaPeriod'; - const NUMERIC_THAIALPHAPARENR = 'thaiAlphaParenR'; - const NUMERIC_THAIALPHAPARENBOTH = 'thaiAlphaParenBoth'; - const NUMERIC_THAINUMPERIOD = 'thaiNumPeriod'; - const NUMERIC_THAINUMPARENR = 'thaiNumParenR'; - const NUMERIC_THAINUMPARENBOTH = 'thaiNumParenBoth'; - const NUMERIC_HINDIALPHAPERIOD = 'hindiAlphaPeriod'; - const NUMERIC_HINDINUMPERIOD = 'hindiNumPeriod'; - const NUMERIC_HINDINUMPARENR = 'hindiNumParenR'; - const NUMERIC_HINDIALPHA1PERIOD = 'hindiAlpha1Period'; + public const NUMERIC_DEFAULT = 'arabicPeriod'; + public const NUMERIC_ALPHALCPARENBOTH = 'alphaLcParenBoth'; + public const NUMERIC_ALPHAUCPARENBOTH = 'alphaUcParenBoth'; + public const NUMERIC_ALPHALCPARENR = 'alphaLcParenR'; + public const NUMERIC_ALPHAUCPARENR = 'alphaUcParenR'; + public const NUMERIC_ALPHALCPERIOD = 'alphaLcPeriod'; + public const NUMERIC_ALPHAUCPERIOD = 'alphaUcPeriod'; + public const NUMERIC_ARABICPARENBOTH = 'arabicParenBoth'; + public const NUMERIC_ARABICPARENR = 'arabicParenR'; + public const NUMERIC_ARABICPERIOD = 'arabicPeriod'; + public const NUMERIC_ARABICPLAIN = 'arabicPlain'; + public const NUMERIC_ROMANLCPARENBOTH = 'romanLcParenBoth'; + public const NUMERIC_ROMANUCPARENBOTH = 'romanUcParenBoth'; + public const NUMERIC_ROMANLCPARENR = 'romanLcParenR'; + public const NUMERIC_ROMANUCPARENR = 'romanUcParenR'; + public const NUMERIC_ROMANLCPERIOD = 'romanLcPeriod'; + public const NUMERIC_ROMANUCPERIOD = 'romanUcPeriod'; + public const NUMERIC_CIRCLENUMDBPLAIN = 'circleNumDbPlain'; + public const NUMERIC_CIRCLENUMWDBLACKPLAIN = 'circleNumWdBlackPlain'; + public const NUMERIC_CIRCLENUMWDWHITEPLAIN = 'circleNumWdWhitePlain'; + public const NUMERIC_ARABICDBPERIOD = 'arabicDbPeriod'; + public const NUMERIC_ARABICDBPLAIN = 'arabicDbPlain'; + public const NUMERIC_EA1CHSPERIOD = 'ea1ChsPeriod'; + public const NUMERIC_EA1CHSPLAIN = 'ea1ChsPlain'; + public const NUMERIC_EA1CHTPERIOD = 'ea1ChtPeriod'; + public const NUMERIC_EA1CHTPLAIN = 'ea1ChtPlain'; + public const NUMERIC_EA1JPNCHSDBPERIOD = 'ea1JpnChsDbPeriod'; + public const NUMERIC_EA1JPNKORPLAIN = 'ea1JpnKorPlain'; + public const NUMERIC_EA1JPNKORPERIOD = 'ea1JpnKorPeriod'; + public const NUMERIC_ARABIC1MINUS = 'arabic1Minus'; + public const NUMERIC_ARABIC2MINUS = 'arabic2Minus'; + public const NUMERIC_HEBREW2MINUS = 'hebrew2Minus'; + public const NUMERIC_THAIALPHAPERIOD = 'thaiAlphaPeriod'; + public const NUMERIC_THAIALPHAPARENR = 'thaiAlphaParenR'; + public const NUMERIC_THAIALPHAPARENBOTH = 'thaiAlphaParenBoth'; + public const NUMERIC_THAINUMPERIOD = 'thaiNumPeriod'; + public const NUMERIC_THAINUMPARENR = 'thaiNumParenR'; + public const NUMERIC_THAINUMPARENBOTH = 'thaiNumParenBoth'; + public const NUMERIC_HINDIALPHAPERIOD = 'hindiAlphaPeriod'; + public const NUMERIC_HINDINUMPERIOD = 'hindiNumPeriod'; + public const NUMERIC_HINDINUMPARENR = 'hindiNumParenR'; + public const NUMERIC_HINDIALPHA1PERIOD = 'hindiAlpha1Period'; /** - * Bullet type + * Bullet type. * * @var string */ private $bulletType = self::TYPE_NONE; /** - * Bullet font + * Bullet font. * * @var string */ private $bulletFont; /** - * Bullet char + * Bullet char. * * @var string */ private $bulletChar = '-'; /** - * Bullet char + * Bullet char. * * @var Color */ private $bulletColor; /** - * Bullet numeric style + * Bullet numeric style. * * @var string */ private $bulletNumericStyle = self::NUMERIC_DEFAULT; /** - * Bullet numeric start at + * Bullet numeric start at. * - * @var int + * @var int|string */ - private $bulletNumericStartAt = 1; + private $bulletNumericStartAt; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; - /** - * Create a new \PhpOffice\PhpPresentation\Style\Bullet - */ public function __construct() { - // Initialise values - $this->bulletType = self::TYPE_NONE; - $this->bulletFont = 'Calibri'; - $this->bulletChar = '-'; - $this->bulletColor = new Color(); - $this->bulletNumericStyle = self::NUMERIC_DEFAULT; - $this->bulletNumericStartAt = 1; + $this->bulletType = self::TYPE_NONE; + $this->bulletFont = 'Calibri'; + $this->bulletChar = '-'; + $this->bulletColor = new Color(); + $this->bulletNumericStyle = self::NUMERIC_DEFAULT; + $this->bulletNumericStartAt = 1; } /** - * Get bullet type + * Get bullet type. * * @return string */ @@ -147,9 +146,10 @@ public function getBulletType() } /** - * Set bullet type + * Set bullet type. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\Style\Bullet */ public function setBulletType($pValue = self::TYPE_NONE) @@ -160,7 +160,7 @@ public function setBulletType($pValue = self::TYPE_NONE) } /** - * Get bullet font + * Get bullet font. * * @return string */ @@ -170,14 +170,15 @@ public function getBulletFont() } /** - * Set bullet font + * Set bullet font. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\Style\Bullet */ public function setBulletFont($pValue = 'Calibri') { - if ($pValue == '') { + if ('' == $pValue) { $pValue = 'Calibri'; } $this->bulletFont = $pValue; @@ -186,7 +187,7 @@ public function setBulletFont($pValue = 'Calibri') } /** - * Get bullet char + * Get bullet char. * * @return string */ @@ -196,9 +197,10 @@ public function getBulletChar() } /** - * Set bullet char + * Set bullet char. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\Style\Bullet */ public function setBulletChar($pValue = '-') @@ -209,7 +211,7 @@ public function setBulletChar($pValue = '-') } /** - * Get bullet numeric style + * Get bullet numeric style. * * @return string */ @@ -219,9 +221,10 @@ public function getBulletNumericStyle() } /** - * Set bullet numeric style + * Set bullet numeric style. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\Style\Bullet */ public function setBulletNumericStyle($pValue = self::NUMERIC_DEFAULT) @@ -232,9 +235,9 @@ public function setBulletNumericStyle($pValue = self::NUMERIC_DEFAULT) } /** - * Get bullet numeric start at + * Get bullet numeric start at. * - * @return string + * @return int|string */ public function getBulletNumericStartAt() { @@ -242,9 +245,10 @@ public function getBulletNumericStartAt() } /** - * Set bullet numeric start at + * Set bullet numeric start at. * * @param int|string $pValue + * * @return \PhpOffice\PhpPresentation\Style\Bullet */ public function setBulletNumericStartAt($pValue = 1) @@ -255,11 +259,11 @@ public function setBulletNumericStartAt($pValue = 1) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5( $this->bulletType @@ -272,29 +276,33 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } /** @@ -306,12 +314,12 @@ public function getBulletColor() } /** - * @param Color $bulletColor * @return Bullet */ public function setBulletColor(Color $bulletColor) { $this->bulletColor = $bulletColor; + return $this; } } diff --git a/src/PhpPresentation/Style/Color.php b/src/PhpPresentation/Style/Color.php index e65fc8724b..56e51029f8 100644 --- a/src/PhpPresentation/Style/Color.php +++ b/src/PhpPresentation/Style/Color.php @@ -10,59 +10,62 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Style\Color + * \PhpOffice\PhpPresentation\Style\Color. */ class Color implements ComparableInterface { /* Colors */ - const COLOR_BLACK = 'FF000000'; - const COLOR_WHITE = 'FFFFFFFF'; - const COLOR_RED = 'FFFF0000'; - const COLOR_DARKRED = 'FF800000'; - const COLOR_BLUE = 'FF0000FF'; - const COLOR_DARKBLUE = 'FF000080'; - const COLOR_GREEN = 'FF00FF00'; - const COLOR_DARKGREEN = 'FF008000'; - const COLOR_YELLOW = 'FFFFFF00'; - const COLOR_DARKYELLOW = 'FF808000'; + public const COLOR_BLACK = 'FF000000'; + public const COLOR_WHITE = 'FFFFFFFF'; + public const COLOR_RED = 'FFFF0000'; + public const COLOR_DARKRED = 'FF800000'; + public const COLOR_BLUE = 'FF0000FF'; + public const COLOR_DARKBLUE = 'FF000080'; + public const COLOR_GREEN = 'FF00FF00'; + public const COLOR_DARKGREEN = 'FF008000'; + public const COLOR_YELLOW = 'FFFFFF00'; + public const COLOR_DARKYELLOW = 'FF808000'; /** - * ARGB - Alpha RGB + * ARGB - Alpha RGB. * * @var string */ private $argb; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Style\Color + * Create a new \PhpOffice\PhpPresentation\Style\Color. * * @param string $pARGB */ public function __construct($pARGB = self::COLOR_BLACK) { // Initialise values - $this->argb = $pARGB; + $this->argb = $pARGB; } /** - * Get ARGB + * Get ARGB. * * @return string */ @@ -72,14 +75,15 @@ public function getARGB() } /** - * Set ARGB + * Set ARGB. + * + * @param string $pValue * - * @param string $pValue * @return \PhpOffice\PhpPresentation\Style\Color */ public function setARGB($pValue = self::COLOR_BLACK) { - if ($pValue == '') { + if ('' == $pValue) { $pValue = self::COLOR_BLACK; } $this->argb = $pValue; @@ -89,27 +93,52 @@ public function setARGB($pValue = self::COLOR_BLACK) /** * Get the alpha % of the ARGB - * Will return 100 if no ARGB - * @return integer + * Will return 100 if no ARGB. + * + * @return int */ - public function getAlpha() + public function getAlpha(): int { $alpha = 100; if (strlen($this->argb) >= 6) { $dec = hexdec(substr($this->argb, 0, 2)); - $alpha = number_format(($dec/255) * 100, 2); + $alpha = (int) number_format(($dec / 255) * 100, 0); } + return $alpha; } /** - * Get RGB + * Set the alpha % of the ARGB. + * + * @param int $alpha + * + * @return $this + */ + public function setAlpha(int $alpha = 100): self + { + if ($alpha < 0) { + $alpha = 0; + } + if ($alpha > 100) { + $alpha = 100; + } + $alpha = round(($alpha / 100) * 255); + $alpha = dechex((int) $alpha); + $alpha = str_pad($alpha, 2, '0', STR_PAD_LEFT); + $this->argb = $alpha . substr($this->argb, 2); + + return $this; + } + + /** + * Get RGB. * * @return string */ public function getRGB() { - if (strlen($this->argb) == 6) { + if (6 == strlen($this->argb)) { return $this->argb; } else { return substr($this->argb, 2); @@ -117,18 +146,19 @@ public function getRGB() } /** - * Set RGB + * Set RGB. + * + * @param string $pValue + * @param string $pAlpha * - * @param string $pValue - * @param string $pAlpha * @return \PhpOffice\PhpPresentation\Style\Color */ public function setRGB($pValue = '000000', $pAlpha = 'FF') { - if ($pValue == '') { + if ('' == $pValue) { $pValue = '000000'; } - if ($pAlpha == '') { + if ('' == $pAlpha) { $pAlpha = 'FF'; } $this->argb = $pAlpha . $pValue; @@ -137,11 +167,11 @@ public function setRGB($pValue = '000000', $pAlpha = 'FF') } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5( $this->argb @@ -150,28 +180,32 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/ColorMap.php b/src/PhpPresentation/Style/ColorMap.php index 77f66b902c..f95a3bc55b 100644 --- a/src/PhpPresentation/Style/ColorMap.php +++ b/src/PhpPresentation/Style/ColorMap.php @@ -10,39 +10,45 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; /** - * PhpOffice\PhpPresentation\Style\ColorMap + * PhpOffice\PhpPresentation\Style\ColorMap. */ class ColorMap { - const COLOR_BG1 = 'bg1'; - const COLOR_BG2 = 'bg2'; - const COLOR_TX1 = 'tx1'; - const COLOR_TX2 = 'tx2'; - const COLOR_ACCENT1 = 'accent1'; - const COLOR_ACCENT2 = 'accent2'; - const COLOR_ACCENT3 = 'accent3'; - const COLOR_ACCENT4 = 'accent4'; - const COLOR_ACCENT5 = 'accent5'; - const COLOR_ACCENT6 = 'accent6'; - const COLOR_HLINK = 'hlink'; - const COLOR_FOLHLINK = 'folHlink'; + public const COLOR_BG1 = 'bg1'; + public const COLOR_BG2 = 'bg2'; + public const COLOR_TX1 = 'tx1'; + public const COLOR_TX2 = 'tx2'; + public const COLOR_ACCENT1 = 'accent1'; + public const COLOR_ACCENT2 = 'accent2'; + public const COLOR_ACCENT3 = 'accent3'; + public const COLOR_ACCENT4 = 'accent4'; + public const COLOR_ACCENT5 = 'accent5'; + public const COLOR_ACCENT6 = 'accent6'; + public const COLOR_HLINK = 'hlink'; + public const COLOR_FOLHLINK = 'folHlink'; /** - * Mapping - Stores the mapping betweenSlide and theme + * Mapping - Stores the mapping betweenSlide and theme. * - * @var array + * @var array */ - protected $mapping = array(); + protected $mapping = []; - public static $mappingDefault = array( + /** + * @var array + */ + public static $mappingDefault = [ self::COLOR_BG1 => 'lt1', self::COLOR_TX1 => 'dk1', self::COLOR_BG2 => 'lt2', @@ -54,12 +60,12 @@ class ColorMap self::COLOR_ACCENT5 => 'accent5', self::COLOR_ACCENT6 => 'accent6', self::COLOR_HLINK => 'hlink', - self::COLOR_FOLHLINK => 'folHlink' - ); + self::COLOR_FOLHLINK => 'folHlink', + ]; /** * ColorMap constructor. - * Create a new ColorMap with standard values + * Create a new ColorMap with standard values. */ public function __construct() { @@ -67,36 +73,33 @@ public function __construct() } /** - * Change the color of one of the elements in the map - * - * @param string $item - * @param string $newThemeColor - * @return ColorMap + * Change the color of one of the elements in the map. */ - public function changeColor($item, $newThemeColor) + public function changeColor(string $item, string $newThemeColor): self { $this->mapping[$item] = $newThemeColor; + return $this; } /** - * Store a new map. For use with the reader + * Store a new map. For use with the reader. * - * @param array $arrayMapping - * @return ColorMap + * @param array $arrayMapping */ - public function setMapping(array $arrayMapping = array()) + public function setMapping(array $arrayMapping = []): self { $this->mapping = $arrayMapping; + return $this; } /** - * Get the whole mapping as an array + * Get the whole mapping as an array. * - * @return array + * @return array */ - public function getMapping() + public function getMapping(): array { return $this->mapping; } diff --git a/src/PhpPresentation/Style/Fill.php b/src/PhpPresentation/Style/Fill.php index b2527625a8..19b92dbc2e 100644 --- a/src/PhpPresentation/Style/Fill.php +++ b/src/PhpPresentation/Style/Fill.php @@ -10,107 +10,105 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; -/** - * \PhpOffice\PhpPresentation\Style\Fill - */ class Fill implements ComparableInterface { /* Fill types */ - const FILL_NONE = 'none'; - const FILL_SOLID = 'solid'; - const FILL_GRADIENT_LINEAR = 'linear'; - const FILL_GRADIENT_PATH = 'path'; - const FILL_PATTERN_DARKDOWN = 'darkDown'; - const FILL_PATTERN_DARKGRAY = 'darkGray'; - const FILL_PATTERN_DARKGRID = 'darkGrid'; - const FILL_PATTERN_DARKHORIZONTAL = 'darkHorizontal'; - const FILL_PATTERN_DARKTRELLIS = 'darkTrellis'; - const FILL_PATTERN_DARKUP = 'darkUp'; - const FILL_PATTERN_DARKVERTICAL = 'darkVertical'; - const FILL_PATTERN_GRAY0625 = 'gray0625'; - const FILL_PATTERN_GRAY125 = 'gray125'; - const FILL_PATTERN_LIGHTDOWN = 'lightDown'; - const FILL_PATTERN_LIGHTGRAY = 'lightGray'; - const FILL_PATTERN_LIGHTGRID = 'lightGrid'; - const FILL_PATTERN_LIGHTHORIZONTAL = 'lightHorizontal'; - const FILL_PATTERN_LIGHTTRELLIS = 'lightTrellis'; - const FILL_PATTERN_LIGHTUP = 'lightUp'; - const FILL_PATTERN_LIGHTVERTICAL = 'lightVertical'; - const FILL_PATTERN_MEDIUMGRAY = 'mediumGray'; - - /** - * Fill type + public const FILL_NONE = 'none'; + public const FILL_SOLID = 'solid'; + public const FILL_GRADIENT_LINEAR = 'linear'; + public const FILL_GRADIENT_PATH = 'path'; + public const FILL_PATTERN_DARKDOWN = 'darkDown'; + public const FILL_PATTERN_DARKGRAY = 'darkGray'; + public const FILL_PATTERN_DARKGRID = 'darkGrid'; + public const FILL_PATTERN_DARKHORIZONTAL = 'darkHorizontal'; + public const FILL_PATTERN_DARKTRELLIS = 'darkTrellis'; + public const FILL_PATTERN_DARKUP = 'darkUp'; + public const FILL_PATTERN_DARKVERTICAL = 'darkVertical'; + public const FILL_PATTERN_GRAY0625 = 'gray0625'; + public const FILL_PATTERN_GRAY125 = 'gray125'; + public const FILL_PATTERN_LIGHTDOWN = 'lightDown'; + public const FILL_PATTERN_LIGHTGRAY = 'lightGray'; + public const FILL_PATTERN_LIGHTGRID = 'lightGrid'; + public const FILL_PATTERN_LIGHTHORIZONTAL = 'lightHorizontal'; + public const FILL_PATTERN_LIGHTTRELLIS = 'lightTrellis'; + public const FILL_PATTERN_LIGHTUP = 'lightUp'; + public const FILL_PATTERN_LIGHTVERTICAL = 'lightVertical'; + public const FILL_PATTERN_MEDIUMGRAY = 'mediumGray'; + + /** + * Fill type. * * @var string */ - private $fillType; + private $fillType = self::FILL_NONE; /** - * Rotation + * Rotation. * - * @var double + * @var float */ - private $rotation; + private $rotation = 0.0; /** - * Start color + * Start color. * - * @var \PhpOffice\PhpPresentation\Style\Color + * @var Color */ private $startColor; /** - * End color + * End color. * - * @var \PhpOffice\PhpPresentation\Style\Color + * @var Color */ private $endColor; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Style\Fill + * Create a new \PhpOffice\PhpPresentation\Style\Fill. */ public function __construct() { - // Initialise values - $this->fillType = self::FILL_NONE; - $this->rotation = (double)0; - $this->startColor = new Color(Color::COLOR_WHITE); - $this->endColor = new Color(Color::COLOR_BLACK); + $this->startColor = new Color(Color::COLOR_BLACK); + $this->endColor = new Color(Color::COLOR_WHITE); } /** - * Get Fill Type + * Get Fill Type. * * @return string */ - public function getFillType() + public function getFillType(): string { return $this->fillType; } /** - * Set Fill Type + * Set Fill Type. + * + * @param string $pValue Fill type * - * @param string $pValue \PhpOffice\PhpPresentation\Style\Fill fill type - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return self */ - public function setFillType($pValue = self::FILL_NONE) + public function setFillType(string $pValue = self::FILL_NONE): self { $this->fillType = $pValue; @@ -118,34 +116,35 @@ public function setFillType($pValue = self::FILL_NONE) } /** - * Get Rotation + * Get Rotation. * - * @return double + * @return float */ - public function getRotation() + public function getRotation(): float { return $this->rotation; } /** - * Set Rotation + * Set Rotation. * - * @param float|int $pValue - * @return \PhpOffice\PhpPresentation\Style\Fill + * @param float $pValue + * + * @return self */ - public function setRotation($pValue = 0) + public function setRotation(float $pValue = 0): self { - $this->rotation = (double)$pValue; + $this->rotation = $pValue; return $this; } /** - * Get Start Color + * Get Start Color. * - * @return \PhpOffice\PhpPresentation\Style\Color + * @return Color */ - public function getStartColor() + public function getStartColor(): Color { // It's a get but it may lead to a modified color which we won't detect but in which case we must bind. // So bind as an assurance. @@ -153,13 +152,13 @@ public function getStartColor() } /** - * Set Start Color + * Set Start Color. + * + * @param Color $pValue * - * @param \PhpOffice\PhpPresentation\Style\Color $pValue - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return self */ - public function setStartColor(Color $pValue = null) + public function setStartColor(Color $pValue): self { $this->startColor = $pValue; @@ -167,11 +166,11 @@ public function setStartColor(Color $pValue = null) } /** - * Get End Color + * Get End Color. * - * @return \PhpOffice\PhpPresentation\Style\Color + * @return Color */ - public function getEndColor() + public function getEndColor(): Color { // It's a get but it may lead to a modified color which we won't detect but in which case we must bind. // So bind as an assurance. @@ -179,13 +178,13 @@ public function getEndColor() } /** - * Set End Color + * Set End Color. + * + * @param Color $pValue * - * @param \PhpOffice\PhpPresentation\Style\Color $pValue - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return self */ - public function setEndColor(Color $pValue = null) + public function setEndColor(Color $pValue): self { $this->endColor = $pValue; @@ -193,11 +192,11 @@ public function setEndColor(Color $pValue = null) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5( $this->getFillType() @@ -209,28 +208,32 @@ public function getHashCode() } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/Font.php b/src/PhpPresentation/Style/Font.php index 966c7a90fd..2e25b257a4 100644 --- a/src/PhpPresentation/Style/Font.php +++ b/src/PhpPresentation/Style/Font.php @@ -10,133 +10,134 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Style\Font + * \PhpOffice\PhpPresentation\Style\Font. */ class Font implements ComparableInterface { /* Underline types */ - const UNDERLINE_NONE = 'none'; - const UNDERLINE_DASH = 'dash'; - const UNDERLINE_DASHHEAVY = 'dashHeavy'; - const UNDERLINE_DASHLONG = 'dashLong'; - const UNDERLINE_DASHLONGHEAVY = 'dashLongHeavy'; - const UNDERLINE_DOUBLE = 'dbl'; - const UNDERLINE_DOTHASH = 'dotDash'; - const UNDERLINE_DOTHASHHEAVY = 'dotDashHeavy'; - const UNDERLINE_DOTDOTDASH = 'dotDotDash'; - const UNDERLINE_DOTDOTDASHHEAVY = 'dotDotDashHeavy'; - const UNDERLINE_DOTTED = 'dotted'; - const UNDERLINE_DOTTEDHEAVY = 'dottedHeavy'; - const UNDERLINE_HEAVY = 'heavy'; - const UNDERLINE_SINGLE = 'sng'; - const UNDERLINE_WAVY = 'wavy'; - const UNDERLINE_WAVYDOUBLE = 'wavyDbl'; - const UNDERLINE_WAVYHEAVY = 'wavyHeavy'; - const UNDERLINE_WORDS = 'words'; - - /** - * Name + public const UNDERLINE_NONE = 'none'; + public const UNDERLINE_DASH = 'dash'; + public const UNDERLINE_DASHHEAVY = 'dashHeavy'; + public const UNDERLINE_DASHLONG = 'dashLong'; + public const UNDERLINE_DASHLONGHEAVY = 'dashLongHeavy'; + public const UNDERLINE_DOUBLE = 'dbl'; + public const UNDERLINE_DOTHASH = 'dotDash'; + public const UNDERLINE_DOTHASHHEAVY = 'dotDashHeavy'; + public const UNDERLINE_DOTDOTDASH = 'dotDotDash'; + public const UNDERLINE_DOTDOTDASHHEAVY = 'dotDotDashHeavy'; + public const UNDERLINE_DOTTED = 'dotted'; + public const UNDERLINE_DOTTEDHEAVY = 'dottedHeavy'; + public const UNDERLINE_HEAVY = 'heavy'; + public const UNDERLINE_SINGLE = 'sng'; + public const UNDERLINE_WAVY = 'wavy'; + public const UNDERLINE_WAVYDOUBLE = 'wavyDbl'; + public const UNDERLINE_WAVYHEAVY = 'wavyHeavy'; + public const UNDERLINE_WORDS = 'words'; + + public const FORMAT_LATIN = 'latin'; + public const FORMAT_EAST_ASIAN = 'ea'; + public const FORMAT_COMPLEX_SCRIPT = 'cs'; + + /** + * Name. * * @var string */ - private $name; - + private $name = 'Calibri'; + /** - * Font Size + * Font Size. * - * @var float|int + * @var int */ - private $size; - + private $size = 10; + /** - * Bold + * Bold. * - * @var boolean + * @var bool */ - private $bold; + private $bold = false; /** - * Italic + * Italic. * - * @var boolean + * @var bool */ - private $italic; + private $italic = false; /** - * Superscript + * Superscript. * - * @var boolean + * @var bool */ - private $superScript; + private $superScript = false; /** - * Subscript + * Subscript. * - * @var boolean + * @var bool */ - private $subScript; + private $subScript = false; /** - * Underline + * Underline. * * @var string */ - private $underline; + private $underline = self::UNDERLINE_NONE; /** - * Strikethrough + * Strikethrough. * - * @var boolean + * @var bool */ - private $strikethrough; + private $strikethrough = false; /** - * Foreground color + * Foreground color. * - * @var \PhpOffice\PhpPresentation\Style\Color + * @var Color */ private $color; /** - * Character Spacing + * Character Spacing. * - * @var int + * @var float */ - private $characterSpacing; + private $characterSpacing = 0; /** - * Hash index + * Format * * @var string */ - private $hashIndex; + private $format = self::FORMAT_LATIN; /** - * Create a new \PhpOffice\PhpPresentation\Style\Font + * Hash index. + * + * @var int */ + private $hashIndex; + public function __construct() { - // Initialise values - $this->name = 'Calibri'; - $this->size = 10; - $this->characterSpacing = 0; - $this->bold = false; - $this->italic = false; - $this->superScript = false; - $this->subScript = false; - $this->underline = self::UNDERLINE_NONE; - $this->strikethrough = false; - $this->color = new Color(Color::COLOR_BLACK); + $this->color = new Color(Color::COLOR_BLACK); } /** @@ -144,7 +145,7 @@ public function __construct() * * @return string */ - public function getName() + public function getName(): string { return $this->name; } @@ -152,196 +153,165 @@ public function getName() /** * Set Name * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * @param string $pValue + * + * @return self */ - public function setName($pValue = 'Calibri') + public function setName(string $pValue = 'Calibri'): self { - if ($pValue == '') { + if ('' == $pValue) { $pValue = 'Calibri'; } $this->name = $pValue; return $this; } - + /** - * Get Character Spacing + * Get Character Spacing. * - * @return double + * @return float */ - public function getCharacterSpacing() + public function getCharacterSpacing(): float { return $this->characterSpacing; } - + /** * Set Character Spacing - * Value in pt - * @param float|int $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Value in pt. + * + * @param float $pValue + * + * @return self */ - public function setCharacterSpacing($pValue = 0) + public function setCharacterSpacing(float $pValue = 0): self { - if ($pValue == '') { - $pValue = 0; - } $this->characterSpacing = $pValue * 100; - + return $this; } /** - * Get Size - * - * @return double + * Get Size. */ - public function getSize() + public function getSize(): int { return $this->size; } /** - * Set Size - * - * @param float|int $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set Size. */ - public function setSize($pValue = 10) + public function setSize(int $pValue = 10): self { - if ($pValue == '') { - $pValue = 10; - } $this->size = $pValue; return $this; } /** - * Get Bold + * Get Bold. * - * @return boolean + * @return bool */ - public function isBold() + public function isBold(): bool { return $this->bold; } /** - * Set Bold - * - * @param boolean $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set Bold. */ - public function setBold($pValue = false) + public function setBold(bool $pValue = false): self { - if ($pValue == '') { - $pValue = false; - } $this->bold = $pValue; return $this; } /** - * Get Italic + * Get Italic. * - * @return boolean + * @return bool */ - public function isItalic() + public function isItalic(): bool { return $this->italic; } /** - * Set Italic - * - * @param boolean $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set Italic. */ - public function setItalic($pValue = false) + public function setItalic(bool $pValue = false): self { - if ($pValue == '') { - $pValue = false; - } $this->italic = $pValue; return $this; } /** - * Get SuperScript + * Get SuperScript. * - * @return boolean + * @return bool */ - public function isSuperScript() + public function isSuperScript(): bool { return $this->superScript; } /** - * Set SuperScript - * - * @param boolean $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set SuperScript. */ - public function setSuperScript($pValue = false) + public function setSuperScript(bool $pValue = false): self { - if ($pValue == '') { - $pValue = false; - } $this->superScript = $pValue; - $this->subScript = !$pValue; + + // Set SubScript at false only if SuperScript is true + if (true === $pValue) { + $this->subScript = false; + } return $this; } - /** - * Get SubScript - * - * @return boolean - */ - public function isSubScript() + public function isSubScript(): bool { return $this->subScript; } - /** - * Set SubScript - * - * @param boolean $pValue - * @return \PhpOffice\PhpPresentation\Style\Font - */ - public function setSubScript($pValue = false) + public function setSubScript(bool $pValue = false): self { - if ($pValue == '') { - $pValue = false; + $this->subScript = $pValue; + + // Set SuperScript at false only if SubScript is true + if (true === $pValue) { + $this->superScript = false; } - $this->subScript = $pValue; - $this->superScript = !$pValue; return $this; } /** - * Get Underline + * Get Underline. * * @return string */ - public function getUnderline() + public function getUnderline(): string { return $this->underline; } /** - * Set Underline + * Set Underline. * - * @param string $pValue \PhpOffice\PhpPresentation\Style\Font underline type - * @return \PhpOffice\PhpPresentation\Style\Font + * @param string $pValue Underline type + * + * @return self */ - public function setUnderline($pValue = self::UNDERLINE_NONE) + public function setUnderline(string $pValue = self::UNDERLINE_NONE): self { - if ($pValue == '') { + if ('' == $pValue) { $pValue = self::UNDERLINE_NONE; } $this->underline = $pValue; @@ -350,91 +320,122 @@ public function setUnderline($pValue = self::UNDERLINE_NONE) } /** - * Get Strikethrough + * Get Strikethrough. * - * @return boolean + * @return bool */ - public function isStrikethrough() + public function isStrikethrough(): bool { return $this->strikethrough; } /** - * Set Strikethrough - * - * @param boolean $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set Strikethrough. */ - public function setStrikethrough($pValue = false) + public function setStrikethrough(bool $pValue = false): self { - if ($pValue == '') { - $pValue = false; - } $this->strikethrough = $pValue; return $this; } /** - * Get Color - * - * @return \PhpOffice\PhpPresentation\Style\Color|\PhpOffice\PhpPresentation\Style\SchemeColor + * Get Color. */ - public function getColor() + public function getColor(): Color { return $this->color; } /** - * Set Color + * Set Color. + */ + public function setColor(Color $pValue): self + { + $this->color = $pValue; + + return $this; + } + + /** + * Get format * - * @param \PhpOffice\PhpPresentation\Style\Color|\PhpOffice\PhpPresentation\Style\SchemeColor $pValue - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Style\Font + * @return string */ - public function setColor($pValue = null) + public function getFormat(): string { - if (!$pValue instanceof Color) { - throw new \Exception('$pValue must be an instance of \PhpOffice\PhpPresentation\Style\Color'); + return $this->format; + } + + /** + * Set format + * + * @param string $value + * + * @return self + */ + public function setFormat(string $value = self::FORMAT_LATIN): self + { + if (in_array($value, [ + self::FORMAT_COMPLEX_SCRIPT, + self::FORMAT_EAST_ASIAN, + self::FORMAT_LATIN, + ])) { + $this->format = $value; } - $this->color = $pValue; return $this; } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { - return md5($this->name . $this->size . ($this->bold ? 't' : 'f') . ($this->italic ? 't' : 'f') . ($this->superScript ? 't' : 'f') . ($this->subScript ? 't' : 'f') . $this->underline . ($this->strikethrough ? 't' : 'f') . $this->color->getHashCode() . __CLASS__); + return md5( + $this->name + . $this->size + . ($this->bold ? 't' : 'f') + . ($this->italic ? 't' : 'f') + . ($this->superScript ? 't' : 'f') + . ($this->subScript ? 't' : 'f') + . $this->underline + . ($this->strikethrough ? 't' : 'f') + . $this->format + . $this->color->getHashCode() + . __CLASS__ + ); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/Outline.php b/src/PhpPresentation/Style/Outline.php index 90c443eb22..99714e27d6 100644 --- a/src/PhpPresentation/Style/Outline.php +++ b/src/PhpPresentation/Style/Outline.php @@ -10,15 +10,18 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; /** - * \PhpOffice\PhpPresentation\Style\Outline + * \PhpOffice\PhpPresentation\Style\Outline. */ class Outline { @@ -26,53 +29,41 @@ class Outline * @var Fill */ protected $fill; - /** - * @var int - */ - protected $width; /** - * @return Outline + * @var float */ + protected $width = 1; + public function __construct() { $this->fill = new Fill(); } - /** - * @return Fill - */ - public function getFill() + public function getFill(): Fill { return $this->fill; } - /** - * @param Fill $fill - * @return Outline - */ - public function setFill(Fill $fill) + public function setFill(Fill $fill): self { $this->fill = $fill; + return $this; } - /** - * @return int - */ - public function getWidth() + public function getWidth(): float { return $this->width; } /** - * Value in points - * @param int $width - * @return Outline + * Value in points. */ - public function setWidth($width) + public function setWidth(float $pValue = 1): self { - $this->width = intval($width); + $this->width = $pValue; + return $this; } } diff --git a/src/PhpPresentation/Style/SchemeColor.php b/src/PhpPresentation/Style/SchemeColor.php index 7b8c7fbab6..040e103b13 100644 --- a/src/PhpPresentation/Style/SchemeColor.php +++ b/src/PhpPresentation/Style/SchemeColor.php @@ -10,30 +10,32 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; class SchemeColor extends Color { - protected $value; - /** - * @return string + * @var string */ - public function getValue() + protected $value; + + public function getValue(): string { return $this->value; } - /** - * @param string $value - */ - public function setValue($value) + public function setValue(string $value): self { $this->value = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/Shadow.php b/src/PhpPresentation/Style/Shadow.php index f500de9517..826dd47d95 100644 --- a/src/PhpPresentation/Style/Shadow.php +++ b/src/PhpPresentation/Style/Shadow.php @@ -10,122 +10,105 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; /** - * \PhpOffice\PhpPresentation\Style\Shadow + * \PhpOffice\PhpPresentation\Style\Shadow. */ class Shadow implements ComparableInterface { /* Shadow alignment */ - const SHADOW_BOTTOM = 'b'; - const SHADOW_BOTTOM_LEFT = 'bl'; - const SHADOW_BOTTOM_RIGHT = 'br'; - const SHADOW_CENTER = 'ctr'; - const SHADOW_LEFT = 'l'; - const SHADOW_TOP = 't'; - const SHADOW_TOP_LEFT = 'tl'; - const SHADOW_TOP_RIGHT = 'tr'; + public const SHADOW_BOTTOM = 'b'; + public const SHADOW_BOTTOM_LEFT = 'bl'; + public const SHADOW_BOTTOM_RIGHT = 'br'; + public const SHADOW_CENTER = 'ctr'; + public const SHADOW_LEFT = 'l'; + public const SHADOW_TOP = 't'; + public const SHADOW_TOP_LEFT = 'tl'; + public const SHADOW_TOP_RIGHT = 'tr'; /** - * Visible + * Visible. * - * @var boolean + * @var bool */ - private $visible; + private $visible = false; /** - * Blur radius - * - * Defaults to 6 + * Blur radius. * * @var int */ - private $blurRadius; + private $blurRadius = 6; /** - * Shadow distance - * - * Defaults to 2 + * Shadow distance. * * @var int */ - private $distance; + private $distance = 2; /** - * Shadow direction (in degrees) + * Shadow direction (in degrees). * * @var int */ - private $direction; + private $direction = 0; /** - * Shadow alignment + * Shadow alignment. * * @var string */ - private $alignment; + private $alignment = self::SHADOW_BOTTOM_RIGHT; /** - * Color - * - * @var \PhpOffice\PhpPresentation\Style\Color + * @var Color|null */ private $color; /** - * Alpha - * * @var int */ - private $alpha; + private $alpha = 50; /** - * Hash index + * Hash index. * - * @var string + * @var int */ private $hashIndex; /** - * Create a new \PhpOffice\PhpPresentation\Style\Shadow + * Create a new \PhpOffice\PhpPresentation\Style\Shadow. */ public function __construct() { - // Initialise values - $this->visible = false; - $this->blurRadius = 6; - $this->distance = 2; - $this->direction = 0; - $this->alignment = self::SHADOW_BOTTOM_RIGHT; - $this->color = new Color(Color::COLOR_BLACK); - $this->alpha = 50; + $this->color = new Color(Color::COLOR_BLACK); } /** - * Get Visible - * - * @return boolean + * Get Visible. */ - public function isVisible() + public function isVisible(): bool { return $this->visible; } /** - * Set Visible - * - * @param boolean $pValue - * @return self + * Set Visible. */ - public function setVisible($pValue = false) + public function setVisible(bool $pValue = false): self { $this->visible = $pValue; @@ -133,22 +116,17 @@ public function setVisible($pValue = false) } /** - * Get Blur radius - * - * @return int + * Get Blur radius. */ - public function getBlurRadius() + public function getBlurRadius(): int { return $this->blurRadius; } /** - * Set Blur radius - * - * @param int $pValue - * @return self + * Set Blur radius. */ - public function setBlurRadius($pValue = 6) + public function setBlurRadius(int $pValue = 6): self { $this->blurRadius = $pValue; @@ -156,22 +134,19 @@ public function setBlurRadius($pValue = 6) } /** - * Get Shadow distance - * - * @return int + * Get Shadow distance. */ - public function getDistance() + public function getDistance(): int { return $this->distance; } /** - * Set Shadow distance + * Set Shadow distance. * - * @param int $pValue - * @return self + * @return $this */ - public function setDistance($pValue = 2) + public function setDistance(int $pValue = 2): self { $this->distance = $pValue; @@ -179,22 +154,17 @@ public function setDistance($pValue = 2) } /** - * Get Shadow direction (in degrees) - * - * @return int + * Get Shadow direction (in degrees). */ - public function getDirection() + public function getDirection(): int { return $this->direction; } /** - * Set Shadow direction (in degrees) - * - * @param int $pValue - * @return self + * Set Shadow direction (in degrees). */ - public function setDirection($pValue = 0) + public function setDirection(int $pValue = 0): self { $this->direction = $pValue; @@ -202,22 +172,17 @@ public function setDirection($pValue = 0) } /** - * Get Shadow alignment - * - * @return int + * Get Shadow alignment. */ - public function getAlignment() + public function getAlignment(): string { return $this->alignment; } /** - * Set Shadow alignment - * - * @param string $pValue - * @return self + * Set Shadow alignment. */ - public function setAlignment($pValue = self::SHADOW_BOTTOM_RIGHT) + public function setAlignment(string $pValue = self::SHADOW_BOTTOM_RIGHT): self { $this->alignment = $pValue; @@ -225,23 +190,17 @@ public function setAlignment($pValue = self::SHADOW_BOTTOM_RIGHT) } /** - * Get Color - * - * @return \PhpOffice\PhpPresentation\Style\Color + * Get Color. */ - public function getColor() + public function getColor(): ?Color { return $this->color; } /** - * Set Color - * - * @param \PhpOffice\PhpPresentation\Style\Color $pValue - * @throws \Exception - * @return self + * Set Color. */ - public function setColor(Color $pValue = null) + public function setColor(Color $pValue = null): self { $this->color = $pValue; @@ -249,22 +208,17 @@ public function setColor(Color $pValue = null) } /** - * Get Alpha - * - * @return int + * Get Alpha. */ - public function getAlpha() + public function getAlpha(): int { return $this->alpha; } /** - * Set Alpha - * - * @param int $pValue - * @return self + * Set Alpha. */ - public function setAlpha($pValue = 0) + public function setAlpha(int $pValue = 0): self { $this->alpha = $pValue; @@ -272,38 +226,42 @@ public function setAlpha($pValue = 0) } /** - * Get hash code + * Get hash code. * * @return string Hash code */ - public function getHashCode() + public function getHashCode(): string { return md5(($this->visible ? 't' : 'f') . $this->blurRadius . $this->distance . $this->direction . $this->alignment . $this->color->getHashCode() . $this->alpha . __CLASS__); } /** - * Get hash index + * Get hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @return string Hash index + * @return int|null Hash index */ - public function getHashIndex() + public function getHashIndex(): ?int { return $this->hashIndex; } /** - * Set hash index + * Set hash index. * * Note that this index may vary during script execution! Only reliable moment is * while doing a write of a workbook and when changes are not allowed. * - * @param string $value Hash index + * @param int $value Hash index + * + * @return $this */ - public function setHashIndex($value) + public function setHashIndex(int $value) { $this->hashIndex = $value; + + return $this; } } diff --git a/src/PhpPresentation/Style/TextStyle.php b/src/PhpPresentation/Style/TextStyle.php index 2903955cca..64d7c5abf2 100644 --- a/src/PhpPresentation/Style/TextStyle.php +++ b/src/PhpPresentation/Style/TextStyle.php @@ -10,38 +10,39 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph as RichTextParagraph; -/** - * Class TextStyle - */ class TextStyle { /** - * @var array + * @var array */ - protected $bodyStyle = array(); + protected $bodyStyle = []; /** - * @var array + * @var array */ - protected $titleStyle = array(); + protected $titleStyle = []; /** - * @var array + * @var array */ - protected $otherStyle = array(); + protected $otherStyle = []; /** * TextStyle constructor. + * * @param bool $default */ - public function __construct($default = true) + public function __construct(bool $default = true) { if ($default) { $oColorLT1 = new SchemeColor(); @@ -69,116 +70,92 @@ public function __construct($default = true) } } - /** - * @param $lvl - * @return bool - */ - private function checkLvl($lvl) + private function checkLvl(?int $lvl): bool { - if (!is_int($lvl)) { - return false; - } - if ($lvl > 9) { + if (is_null($lvl) || $lvl > 9) { return false; } + return true; } - /** - * @param RichTextParagraph $style - * @param $lvl - * @return TextStyle - */ - public function setBodyStyleAtLvl(RichTextParagraph $style, $lvl) + public function setBodyStyleAtLvl(RichTextParagraph $style, ?int $lvl): self { if ($this->checkLvl($lvl)) { $this->bodyStyle[$lvl] = $style; } + return $this; } - /** - * @param RichTextParagraph $style - * @param $lvl - * @return TextStyle - */ - public function setTitleStyleAtLvl(RichTextParagraph $style, $lvl) + public function setTitleStyleAtLvl(RichTextParagraph $style, ?int $lvl): self { if ($this->checkLvl($lvl)) { $this->titleStyle[$lvl] = $style; } + return $this; } /** - * @param RichTextParagraph $style - * @param $lvl * @return TextStyle */ - public function setOtherStyleAtLvl(RichTextParagraph $style, $lvl) + public function setOtherStyleAtLvl(RichTextParagraph $style, ?int $lvl): self { if ($this->checkLvl($lvl)) { $this->otherStyle[$lvl] = $style; } + return $this; } - /** - * @param $lvl - * @return mixed - */ - public function getBodyStyleAtLvl($lvl) + public function getBodyStyleAtLvl(?int $lvl): ?RichTextParagraph { if ($this->checkLvl($lvl) && !empty($this->bodyStyle[$lvl])) { return $this->bodyStyle[$lvl]; } + return null; } - /** - * @param $lvl - * @return mixed - */ - public function getTitleStyleAtLvl($lvl) + public function getTitleStyleAtLvl(?int $lvl): ?RichTextParagraph { if ($this->checkLvl($lvl) && !empty($this->titleStyle[$lvl])) { return $this->titleStyle[$lvl]; } + return null; } - /** - * @param $lvl - * @return mixed - */ - public function getOtherStyleAtLvl($lvl) + public function getOtherStyleAtLvl(?int $lvl): ?RichTextParagraph { if ($this->checkLvl($lvl) && !empty($this->otherStyle[$lvl])) { return $this->otherStyle[$lvl]; } + return null; } /** - * @return array + * @return array */ - public function getBodyStyle() + public function getBodyStyle(): array { return $this->bodyStyle; } /** - * @return array + * @return array */ - public function getTitleStyle() + public function getTitleStyle(): array { return $this->titleStyle; } /** - * @return array + * @return array */ - public function getOtherStyle() + public function getOtherStyle(): array { return $this->otherStyle; } diff --git a/src/PhpPresentation/Writer/AbstractDecoratorWriter.php b/src/PhpPresentation/Writer/AbstractDecoratorWriter.php index 1d174040d1..9b12bf9364 100644 --- a/src/PhpPresentation/Writer/AbstractDecoratorWriter.php +++ b/src/PhpPresentation/Writer/AbstractDecoratorWriter.php @@ -1,4 +1,22 @@ oHashTable = $hashTable; + return $this; } @@ -47,12 +65,12 @@ public function getDrawingHashTable() } /** - * @param PhpPresentation $oPresentation * @return $this */ public function setPresentation(PhpPresentation $oPresentation) { $this->oPresentation = $oPresentation; + return $this; } @@ -65,12 +83,12 @@ public function getPresentation() } /** - * @param ZipInterface $oZip * @return $this */ public function setZip(ZipInterface $oZip) { $this->oZip = $oZip; + return $this; } diff --git a/src/PhpPresentation/Writer/AbstractWriter.php b/src/PhpPresentation/Writer/AbstractWriter.php index b3a6b69857..14179efc39 100644 --- a/src/PhpPresentation/Writer/AbstractWriter.php +++ b/src/PhpPresentation/Writer/AbstractWriter.php @@ -1,8 +1,29 @@ oDrawingHashTable; } /** - * Get PhpPresentation object - * - * @return PhpPresentation - * @throws \Exception + * Get PhpPresentation object. */ - public function getPhpPresentation() + public function getPhpPresentation(): ?PhpPresentation { - if (empty($this->oPresentation)) { - throw new \Exception("No PhpPresentation assigned."); - } return $this->oPresentation; } /** - * Get PhpPresentation object + * Get PhpPresentation object. * - * @param PhpPresentation $pPhpPresentation PhpPresentation object - * @throws \Exception - * @return \PhpOffice\PhpPresentation\Writer\ODPresentation + * @param PhpPresentation|null $pPhpPresentation PhpPresentation object + * + * @return self */ public function setPhpPresentation(PhpPresentation $pPhpPresentation = null) { $this->oPresentation = $pPhpPresentation; + return $this; } - - /** - * @param ZipInterface $oZipAdapter - * @return $this - */ - public function setZipAdapter(ZipInterface $oZipAdapter) + public function setZipAdapter(ZipInterface $oZipAdapter): self { $this->oZipAdapter = $oZipAdapter; + return $this; } - /** - * @return ZipInterface - */ - public function getZipAdapter() + public function getZipAdapter(): ?ZipInterface { return $this->oZipAdapter; } /** - * Get an array of all drawings + * Get an array of all drawings. * - * @return \PhpOffice\PhpPresentation\Shape\AbstractDrawing[] All drawings in PhpPresentation - * @throws \Exception + * @return array */ - protected function allDrawings() + protected function allDrawings(): array { // Get an array of all drawings - $aDrawings = array(); + $aDrawings = []; + + // Get an array of all master slides + $aSlideMasters = $this->getPhpPresentation()->getAllMasterSlides(); + + $aSlideMasterLayouts = array_map(function ($oSlideMaster) { + return $oSlideMaster->getAllSlideLayouts(); + }, $aSlideMasters); + + // Get an array of all slide layouts + $aSlideLayouts = []; + array_walk_recursive($aSlideMasterLayouts, function ($oSlideLayout) use (&$aSlideLayouts) { + $aSlideLayouts[] = $oSlideLayout; + }); // Loop through PhpPresentation - foreach (array_merge($this->getPhpPresentation()->getAllSlides(), $this->getPhpPresentation()->getAllMasterSlides()) as $oSlide) { + foreach (array_merge($this->getPhpPresentation()->getAllSlides(), $aSlideMasters, $aSlideLayouts) as $oSlide) { $arrayReturn = $this->iterateCollection($oSlide->getShapeCollection()->getIterator()); $aDrawings = array_merge($aDrawings, $arrayReturn); } @@ -105,9 +124,14 @@ protected function allDrawings() return $aDrawings; } - private function iterateCollection(\ArrayIterator $oIterator) + /** + * @param ArrayIterator $oIterator + * + * @return array + */ + private function iterateCollection(ArrayIterator $oIterator): array { - $arrayReturn = array(); + $arrayReturn = []; if ($oIterator->count() <= 0) { return $arrayReturn; } @@ -124,6 +148,7 @@ private function iterateCollection(\ArrayIterator $oIterator) } $oIterator->next(); } + return $arrayReturn; } } diff --git a/src/PhpPresentation/Writer/ODPresentation.php b/src/PhpPresentation/Writer/ODPresentation.php index 8408c29de5..a963259dbe 100644 --- a/src/PhpPresentation/Writer/ODPresentation.php +++ b/src/PhpPresentation/Writer/ODPresentation.php @@ -10,53 +10,58 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Writer; +use DirectoryIterator; use PhpOffice\Common\Adapter\Zip\ZipArchiveAdapter; +use PhpOffice\PhpPresentation\Exception\DirectoryNotFoundException; +use PhpOffice\PhpPresentation\Exception\FileCopyException; +use PhpOffice\PhpPresentation\Exception\FileRemoveException; +use PhpOffice\PhpPresentation\Exception\InvalidParameterException; use PhpOffice\PhpPresentation\HashTable; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Shape\AbstractDrawing; -use PhpOffice\PhpPresentation\Shape\Table; -use DirectoryIterator; /** - * ODPresentation writer + * ODPresentation writer. */ class ODPresentation extends AbstractWriter implements WriterInterface { /** * @var \PhpOffice\PhpPresentation\Shape\Chart[] */ - public $chartArray = array(); + public $chartArray = []; /** - * Use disk caching where possible? - * - * @var boolean - */ + * Use disk caching where possible? + * + * @var bool + */ private $useDiskCaching = false; /** - * Disk caching directory + * Disk caching directory. * * @var string */ private $diskCachingDirectory; /** - * Create a new \PhpOffice\PhpPresentation\Writer\ODPresentation + * Create a new \PhpOffice\PhpPresentation\Writer\ODPresentation. * * @param PhpPresentation $pPhpPresentation */ public function __construct(PhpPresentation $pPhpPresentation = null) { // Assign PhpPresentation - $this->setPhpPresentation($pPhpPresentation); + $this->setPhpPresentation($pPhpPresentation ?? new PhpPresentation()); // Set up disk caching location $this->diskCachingDirectory = './'; @@ -68,21 +73,22 @@ public function __construct(PhpPresentation $pPhpPresentation = null) } /** - * Save PhpPresentation to file + * Save PhpPresentation to file. * - * @param string $pFilename - * @throws \Exception + * @throws FileCopyException + * @throws FileRemoveException + * @throws InvalidParameterException */ - public function save($pFilename) + public function save(string $pFilename): void { if (empty($pFilename)) { - throw new \Exception("Filename is empty"); + throw new InvalidParameterException('pFilename', ''); } // If $pFilename is php://output or php://stdout, make it a temporary file... $originalFilename = $pFilename; - if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { + if ('php://output' == strtolower($pFilename) || 'php://stdout' == strtolower($pFilename)) { $pFilename = @tempnam('./', 'phppttmp'); - if ($pFilename == '') { + if ('' == $pFilename) { $pFilename = $originalFilename; } } @@ -96,22 +102,22 @@ public function save($pFilename) // Variables $oPresentation = $this->getPhpPresentation(); - $arrayChart = array(); + $arrayChart = []; - $arrayFiles = array(); - $oDir = new DirectoryIterator(dirname(__FILE__).DIRECTORY_SEPARATOR.'ODPresentation'); + $arrayFiles = []; + $oDir = new DirectoryIterator(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'ODPresentation'); foreach ($oDir as $oFile) { if (!$oFile->isFile()) { continue; } $class = __NAMESPACE__ . '\\ODPresentation\\' . $oFile->getBasename('.php'); - $o = new \ReflectionClass($class); + $class = new \ReflectionClass($class); - if ($o->isAbstract() || !$o->isSubclassOf('PhpOffice\PhpPresentation\Writer\ODPresentation\AbstractDecoratorWriter')) { + if ($class->isAbstract() || !$class->isSubclassOf('PhpOffice\PhpPresentation\Writer\ODPresentation\AbstractDecoratorWriter')) { continue; } - $arrayFiles[$oFile->getBasename('.php')] = $o; + $arrayFiles[$oFile->getBasename('.php')] = $class; } ksort($arrayFiles); @@ -132,11 +138,11 @@ public function save($pFilename) // If a temporary file was used, copy it to the correct file stream if ($originalFilename != $pFilename) { - if (copy($pFilename, $originalFilename) === false) { - throw new \Exception("Could not copy temporary zip file $pFilename to $originalFilename."); + if (false === copy($pFilename, $originalFilename)) { + throw new FileCopyException($pFilename, $originalFilename); } - if (@unlink($pFilename) === false) { - throw new \Exception('The file ' . $pFilename . ' could not be removed.'); + if (false === @unlink($pFilename)) { + throw new FileRemoveException($pFilename); } } } @@ -144,7 +150,7 @@ public function save($pFilename) /** * Get use disk caching where possible? * - * @return boolean + * @return bool */ public function hasDiskCaching() { @@ -154,27 +160,29 @@ public function hasDiskCaching() /** * Set use disk caching where possible? * - * @param boolean $pValue - * @param string $pDirectory Disk caching directory - * @throws \Exception + * @param bool $pValue + * @param string $directory Disk caching directory + * + * @throws DirectoryNotFoundException + * * @return \PhpOffice\PhpPresentation\Writer\ODPresentation */ - public function setUseDiskCaching($pValue = false, $pDirectory = null) + public function setUseDiskCaching(bool $pValue = false, string $directory = null) { $this->useDiskCaching = $pValue; - if (!is_null($pDirectory)) { - if (!is_dir($pDirectory)) { - throw new \Exception("Directory does not exist: $pDirectory"); + if (!is_null($directory)) { + if (!is_dir($directory)) { + throw new DirectoryNotFoundException($directory); } - $this->diskCachingDirectory = $pDirectory; + $this->diskCachingDirectory = $directory; } return $this; } /** - * Get disk caching directory + * Get disk caching directory. * * @return string */ diff --git a/src/PhpPresentation/Writer/ODPresentation/AbstractDecoratorWriter.php b/src/PhpPresentation/Writer/ODPresentation/AbstractDecoratorWriter.php index c5e390e705..7683106b67 100644 --- a/src/PhpPresentation/Writer/ODPresentation/AbstractDecoratorWriter.php +++ b/src/PhpPresentation/Writer/ODPresentation/AbstractDecoratorWriter.php @@ -1,4 +1,22 @@ arrayChart = $arrayChart; + return $this; } } diff --git a/src/PhpPresentation/Writer/ODPresentation/Content.php b/src/PhpPresentation/Writer/ODPresentation/Content.php index 028836e757..bf9fc5b655 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Content.php +++ b/src/PhpPresentation/Writer/ODPresentation/Content.php @@ -1,4 +1,22 @@ > */ - protected $arrStyleBullet = array(); + protected $arrStyleBullet = []; /** * Stores paragraph information for text shapes. * - * @var array + * @var array */ - protected $arrStyleParagraph = array(); + protected $arrStyleParagraph = []; /** * Stores font styles for text shapes that include lists. * - * @var Run[] + * @var array */ - protected $arrStyleTextFont = array(); + protected $arrStyleTextFont = []; /** * Used to track the current shape ID. * - * @var integer + * @var int */ protected $shapeId; - /** - * @return ZipInterface - */ - public function render() + public function render(): ZipInterface { $this->getZip()->addFromString('content.xml', $this->writeContent()); + return $this->getZip(); } - - /** - * Write content file to XML format + * Write content file to XML format. * - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - public function writeContent() + protected function writeContent(): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -113,12 +128,13 @@ public function writeContent() $objWriter->writeAttribute('xmlns:rdfa', 'http://docs.oasis-open.org/opendocument/meta/rdfa#'); $objWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); $objWriter->writeAttribute('xmlns:officeooo', 'http://openoffice.org/2009/office'); + $objWriter->writeAttribute('xmlns:loext', 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0'); $objWriter->writeAttribute('office:version', '1.2'); // office:automatic-styles $objWriter->startElement('office:automatic-styles'); - $this->shapeId = 0; + $this->shapeId = 0; $incSlide = 0; foreach ($this->getPresentation()->getAllSlides() as $pSlide) { // Slides @@ -148,31 +164,31 @@ public function writeContent() } } - $incSlide++; + ++$incSlide; } // Style : Bullet if (!empty($this->arrStyleBullet)) { foreach ($this->arrStyleBullet as $key => $item) { - $oStyle = $item['oStyle']; + $oStyle = $item['oStyle']; $arrLevel = explode(';', $item['level']); // style:style $objWriter->startElement('text:list-style'); $objWriter->writeAttribute('style:name', 'L_' . $key); foreach ($arrLevel as $level) { - if ($level != '') { + if ('' != $level) { $oAlign = $item['oAlign_' . $level]; // text:list-level-style-bullet $objWriter->startElement('text:list-level-style-bullet'); - $objWriter->writeAttribute('text:level', $level + 1); + $objWriter->writeAttribute('text:level', intval($level) + 1); $objWriter->writeAttribute('text:bullet-char', $oStyle->getBulletChar()); // style:list-level-properties $objWriter->startElement('style:list-level-properties'); if ($oAlign->getIndent() < 0) { - $objWriter->writeAttribute('text:space-before', CommonDrawing::pixelsToCentimeters($oAlign->getMarginLeft() - (-1 * $oAlign->getIndent())) . 'cm'); - $objWriter->writeAttribute('text:min-label-width', CommonDrawing::pixelsToCentimeters(-1 * $oAlign->getIndent()) . 'cm'); + $objWriter->writeAttribute('text:space-before', CommonDrawing::pixelsToCentimeters((int) ($oAlign->getMarginLeft() - (-1 * $oAlign->getIndent()))) . 'cm'); + $objWriter->writeAttribute('text:min-label-width', CommonDrawing::pixelsToCentimeters((int) (-1 * $oAlign->getIndent())) . 'cm'); } else { - $objWriter->writeAttribute('text:space-before', (CommonDrawing::pixelsToCentimeters($oAlign->getMarginLeft() - $oAlign->getIndent())) . 'cm'); - $objWriter->writeAttribute('text:min-label-width', CommonDrawing::pixelsToCentimeters($oAlign->getIndent()) . 'cm'); + $objWriter->writeAttribute('text:space-before', (CommonDrawing::pixelsToCentimeters((int) ($oAlign->getMarginLeft() - $oAlign->getIndent()))) . 'cm'); + $objWriter->writeAttribute('text:min-label-width', CommonDrawing::pixelsToCentimeters((int) $oAlign->getIndent()) . 'cm'); } $objWriter->endElement(); @@ -181,7 +197,7 @@ public function writeContent() $objWriter->writeAttribute('fo:font-family', $oStyle->getBulletFont()); $objWriter->writeAttribute('style:font-family-generic', 'swiss'); $objWriter->writeAttribute('style:use-window-font-color', 'true'); - $objWriter->writeAttribute('fo:font-size', '100'); + $objWriter->writeAttribute('fo:font-size', '100%'); $objWriter->endElement(); $objWriter->endElement(); } @@ -198,6 +214,24 @@ public function writeContent() $objWriter->writeAttribute('style:family', 'paragraph'); // style:paragraph-properties $objWriter->startElement('style:paragraph-properties'); + $objWriter->writeAttributeIf( + $item->getLineSpacingMode() === Paragraph::LINE_SPACING_MODE_PERCENT, + 'fo:line-height', + $item->getLineSpacing() . '%' + ); + $objWriter->writeAttributeIf( + $item->getLineSpacingMode() === Paragraph::LINE_SPACING_MODE_POINT, + 'fo:line-height', + $item->getLineSpacing() . 'pt' + ); + $objWriter->writeAttribute( + 'fo:margin-top', + Text::numberFormat(CommonDrawing::pointstoCentimeters($item->getSpacingBefore()), 3) . 'cm' + ); + $objWriter->writeAttribute( + 'fo:margin-bottom', + Text::numberFormat(CommonDrawing::pointstoCentimeters($item->getSpacingAfter()), 3) . 'cm' + ); switch ($item->getAlignment()->getHorizontal()) { case Alignment::HORIZONTAL_LEFT: $objWriter->writeAttribute('fo:text-align', 'left'); @@ -218,6 +252,10 @@ public function writeContent() $objWriter->writeAttribute('fo:text-align', 'left'); break; } + $objWriter->writeAttribute( + 'style:writing-mode', + $item->getAlignment()->isRTL() ? 'rl-tb' : 'lr-tb' + ); $objWriter->endElement(); $objWriter->endElement(); } @@ -229,19 +267,37 @@ public function writeContent() $objWriter->startElement('style:style'); $objWriter->writeAttribute('style:name', 'T_' . $key); $objWriter->writeAttribute('style:family', 'text'); - // style:text-properties + + // style:style > style:text-properties $objWriter->startElement('style:text-properties'); $objWriter->writeAttribute('fo:color', '#' . $item->getFont()->getColor()->getRGB()); - $objWriter->writeAttribute('fo:font-family', $item->getFont()->getName()); - $objWriter->writeAttribute('fo:font-size', $item->getFont()->getSize() . 'pt'); - // @todo : fo:font-style - if ($item->getFont()->isBold()) { - $objWriter->writeAttribute('fo:font-weight', 'bold'); + switch ($item->getFont()->getFormat()) { + case Font::FORMAT_LATIN: + $objWriter->writeAttribute('fo:font-family', $item->getFont()->getName()); + $objWriter->writeAttribute('fo:font-size', $item->getFont()->getSize() . 'pt'); + $objWriter->writeAttributeIf($item->getFont()->isBold(), 'fo:font-weight', 'bold'); + $objWriter->writeAttribute('fo:language', ($item->getLanguage() ? $item->getLanguage() : 'en')); + $objWriter->writeAttribute('style:script-type', 'latin'); + break; + case Font::FORMAT_EAST_ASIAN: + $objWriter->writeAttribute('style:font-family-asian', $item->getFont()->getName()); + $objWriter->writeAttribute('style:font-size-asian', $item->getFont()->getSize() . 'pt'); + $objWriter->writeAttributeIf($item->getFont()->isBold(), 'style:font-weight-asian', 'bold'); + $objWriter->writeAttribute('style:language-asian', ($item->getLanguage() ? $item->getLanguage() : 'en')); + $objWriter->writeAttribute('style:script-type', 'asian'); + break; + case Font::FORMAT_COMPLEX_SCRIPT: + $objWriter->writeAttribute('style:font-family-complex', $item->getFont()->getName()); + $objWriter->writeAttribute('style:font-size-complex', $item->getFont()->getSize() . 'pt'); + $objWriter->writeAttributeIf($item->getFont()->isBold(), 'style:font-weight-complex', 'bold'); + $objWriter->writeAttribute('style:language-complex', ($item->getLanguage() ? $item->getLanguage() : 'en')); + $objWriter->writeAttribute('style:script-type', 'complex'); + break; } - $objWriter->writeAttribute('fo:language', ($item->getLanguage() ? $item->getLanguage() : 'en-US')); - // @todo : style:text-underline-style + // > style:style > style:text-properties $objWriter->endElement(); + // > style:style $objWriter->endElement(); } } @@ -252,12 +308,12 @@ public function writeContent() //=============================================== // office:body $objWriter->startElement('office:body'); - // office:presentation + // office:body > office:presentation $objWriter->startElement('office:presentation'); // Write slides $slideCount = $this->getPresentation()->getSlideCount(); - $this->shapeId = 0; + $this->shapeId = 0; for ($i = 0; $i < $slideCount; ++$i) { $pSlide = $this->getPresentation()->getSlide($i); $objWriter->startElement('draw:page'); @@ -300,13 +356,18 @@ public function writeContent() $objWriter->endElement(); } + // office:document-content > office:body > office:presentation > presentation:settings + $objWriter->startElement('presentation:settings'); if ($this->getPresentation()->getPresentationProperties()->isLoopContinuouslyUntilEsc()) { - $objWriter->startElement('presentation:settings'); $objWriter->writeAttribute('presentation:endless', 'true'); - $objWriter->writeAttribute('presentation:pause', 'P0s'); + $objWriter->writeAttribute('presentation:pause', 'PT0S'); $objWriter->writeAttribute('presentation:mouse-visible', 'false'); - $objWriter->endElement(); } + if ($this->getPresentation()->getPresentationProperties()->getSlideshowType() === PresentationProperties::SLIDESHOW_TYPE_BROWSE) { + $objWriter->writeAttribute('presentation:full-screen', 'false'); + } + $objWriter->endElement(); + // > office:presentation $objWriter->endElement(); // > office:body @@ -319,20 +380,17 @@ public function writeContent() } /** - * Write picture - * - * @param \PhpOffice\Common\XMLWriter $objWriter - * @param \PhpOffice\PhpPresentation\Shape\Media $shape + * Write picture. */ - public function writeShapeMedia(XMLWriter $objWriter, Media $shape) + protected function writeShapeMedia(XMLWriter $objWriter, Media $shape): void { // draw:frame $objWriter->startElement('draw:frame'); $objWriter->writeAttribute('draw:name', $shape->getName()); - $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getWidth()), 3) . 'cm'); - $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getHeight()), 3) . 'cm'); - $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()), 3) . 'cm'); + $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getWidth()), 3) . 'cm'); + $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getHeight()), 3) . 'cm'); + $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY()), 3) . 'cm'); $objWriter->writeAttribute('draw:style-name', 'gr' . $this->shapeId); // draw:frame > draw:plugin $objWriter->startElement('draw:plugin'); @@ -367,20 +425,19 @@ public function writeShapeMedia(XMLWriter $objWriter, Media $shape) } /** - * Write picture + * Write picture. * - * @param \PhpOffice\Common\XMLWriter $objWriter - * @param \PhpOffice\PhpPresentation\Shape\AbstractDrawingAdapter $shape + * @param AbstractDrawingAdapter $shape */ - public function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape) + protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape): void { // draw:frame $objWriter->startElement('draw:frame'); $objWriter->writeAttribute('draw:name', $shape->getName()); - $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getWidth()), 3) . 'cm'); - $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getHeight()), 3) . 'cm'); - $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()), 3) . 'cm'); + $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getWidth()), 3) . 'cm'); + $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getHeight()), 3) . 'cm'); + $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY()), 3) . 'cm'); $objWriter->writeAttribute('draw:style-name', 'gr' . $this->shapeId); // draw:image $objWriter->startElement('draw:image'); @@ -390,6 +447,7 @@ public function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDra $objWriter->writeAttribute('xlink:type', 'simple'); $objWriter->writeAttribute('xlink:show', 'embed'); $objWriter->writeAttribute('xlink:actuate', 'onLoad'); + $objWriter->writeAttribute('loext:mime-type', $shape->getMimeType()); $objWriter->writeElement('text:p'); $objWriter->endElement(); @@ -414,33 +472,30 @@ public function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDra } /** - * Write text - * - * @param \PhpOffice\Common\XMLWriter $objWriter - * @param \PhpOffice\PhpPresentation\Shape\RichText $shape + * Write text. */ - public function writeShapeTxt(XMLWriter $objWriter, RichText $shape) + protected function writeShapeTxt(XMLWriter $objWriter, RichText $shape): void { // draw:frame $objWriter->startElement('draw:frame'); $objWriter->writeAttribute('draw:style-name', 'gr' . $this->shapeId); - $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getWidth()), 3) . 'cm'); - $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getHeight()), 3) . 'cm'); - $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()), 3) . 'cm'); + $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getWidth()), 3) . 'cm'); + $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getHeight()), 3) . 'cm'); + $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY()), 3) . 'cm'); // draw:text-box $objWriter->startElement('draw:text-box'); - $paragraphs = $shape->getParagraphs(); - $paragraphId = 0; - $sCstShpLastBullet = ''; - $iCstShpLastBulletLvl = 0; - $bCstShpHasBullet = false; + $paragraphs = $shape->getParagraphs(); + $paragraphId = 0; + $sCstShpLastBullet = ''; + $iCstShpLastBulletLvl = 0; + $bCstShpHasBullet = false; foreach ($paragraphs as $paragraph) { // Close the bullet list - if ($sCstShpLastBullet != 'bullet' && $bCstShpHasBullet === true) { - for ($iInc = $iCstShpLastBulletLvl; $iInc >= 0; $iInc--) { + if ('bullet' != $sCstShpLastBullet && true === $bCstShpHasBullet) { + for ($iInc = $iCstShpLastBulletLvl; $iInc >= 0; --$iInc) { // text:list-item $objWriter->endElement(); // text:list @@ -450,26 +505,27 @@ public function writeShapeTxt(XMLWriter $objWriter, RichText $shape) //=============================================== // Paragraph //=============================================== - if ($paragraph->getBulletStyle()->getBulletType() == 'none') { + if ('none' == $paragraph->getBulletStyle()->getBulletType()) { ++$paragraphId; // text:p $objWriter->startElement('text:p'); $objWriter->writeAttribute('text:style-name', 'P_' . $paragraph->getHashCode()); // Loop trough rich text elements - $richtexts = $paragraph->getRichTextElements(); + $richtexts = $paragraph->getRichTextElements(); $richtextId = 0; foreach ($richtexts as $richtext) { ++$richtextId; - if ($richtext instanceof TextElement || $richtext instanceof Run) { + if ($richtext instanceof TextElement) { // text:span $objWriter->startElement('text:span'); if ($richtext instanceof Run) { $objWriter->writeAttribute('text:style-name', 'T_' . $richtext->getHashCode()); } - if ($richtext->hasHyperlink() === true && $richtext->getHyperlink()->getUrl() != '') { + if (true === $richtext->hasHyperlink() && '' != $richtext->getHyperlink()->getUrl()) { // text:a $objWriter->startElement('text:a'); + $objWriter->writeAttribute('xlink:type', 'simple'); $objWriter->writeAttribute('xlink:href', $richtext->getHyperlink()->getUrl()); $objWriter->text($richtext->getText()); $objWriter->endElement(); @@ -484,23 +540,21 @@ public function writeShapeTxt(XMLWriter $objWriter, RichText $shape) $objWriter->startElement('text:line-break'); $objWriter->endElement(); $objWriter->endElement(); - } else { - //echo '
        '.print_r($richtext, true).'
        '; } } $objWriter->endElement(); - //=============================================== - // Bullet list - //=============================================== - } elseif ($paragraph->getBulletStyle()->getBulletType() == 'bullet') { + //=============================================== + // Bullet list + //=============================================== + } elseif ('bullet' == $paragraph->getBulletStyle()->getBulletType()) { $bCstShpHasBullet = true; // Open the bullet list - if ($sCstShpLastBullet != 'bullet' || ($sCstShpLastBullet == $paragraph->getBulletStyle()->getBulletType() && $iCstShpLastBulletLvl < $paragraph->getAlignment()->getLevel())) { + if ('bullet' != $sCstShpLastBullet || ($sCstShpLastBullet == $paragraph->getBulletStyle()->getBulletType() && $iCstShpLastBulletLvl < $paragraph->getAlignment()->getLevel())) { // text:list $objWriter->startElement('text:list'); $objWriter->writeAttribute('text:style-name', 'L_' . $paragraph->getBulletStyle()->getHashCode()); } - if ($sCstShpLastBullet == 'bullet') { + if ('bullet' == $sCstShpLastBullet) { if ($iCstShpLastBulletLvl == $paragraph->getAlignment()->getLevel()) { // text:list-item $objWriter->endElement(); @@ -522,19 +576,20 @@ public function writeShapeTxt(XMLWriter $objWriter, RichText $shape) $objWriter->writeAttribute('text:style-name', 'P_' . $paragraph->getHashCode()); // Loop trough rich text elements - $richtexts = $paragraph->getRichTextElements(); + $richtexts = $paragraph->getRichTextElements(); $richtextId = 0; foreach ($richtexts as $richtext) { ++$richtextId; - if ($richtext instanceof TextElement || $richtext instanceof Run) { + if ($richtext instanceof TextElement) { // text:span $objWriter->startElement('text:span'); if ($richtext instanceof Run) { $objWriter->writeAttribute('text:style-name', 'T_' . $richtext->getHashCode()); } - if ($richtext->hasHyperlink() === true && $richtext->getHyperlink()->getUrl() != '') { + if (true === $richtext->hasHyperlink() && '' != $richtext->getHyperlink()->getUrl()) { // text:a $objWriter->startElement('text:a'); + $objWriter->writeAttribute('xlink:type', 'simple'); $objWriter->writeAttribute('xlink:href', $richtext->getHyperlink()->getUrl()); $objWriter->text($richtext->getText()); $objWriter->endElement(); @@ -549,19 +604,17 @@ public function writeShapeTxt(XMLWriter $objWriter, RichText $shape) $objWriter->startElement('text:line-break'); $objWriter->endElement(); $objWriter->endElement(); - } else { - //echo '
        '.print_r($richtext, true).'
        '; } } $objWriter->endElement(); } - $sCstShpLastBullet = $paragraph->getBulletStyle()->getBulletType(); + $sCstShpLastBullet = $paragraph->getBulletStyle()->getBulletType(); $iCstShpLastBulletLvl = $paragraph->getAlignment()->getLevel(); } // Close the bullet list - if ($sCstShpLastBullet == 'bullet' && $bCstShpHasBullet === true) { - for ($iInc = $iCstShpLastBulletLvl; $iInc >= 0; $iInc--) { + if ('bullet' == $sCstShpLastBullet && true === $bCstShpHasBullet) { + for ($iInc = $iCstShpLastBulletLvl; $iInc >= 0; --$iInc) { // text:list-item $objWriter->endElement(); // text:list @@ -574,17 +627,19 @@ public function writeShapeTxt(XMLWriter $objWriter, RichText $shape) // > draw:frame $objWriter->endElement(); } + /** - * Write Comment - * @param XMLWriter $objWriter - * @param Comment $oShape + * Write Comment. */ - public function writeShapeComment(XMLWriter $objWriter, Comment $oShape) + protected function writeShapeComment(XMLWriter $objWriter, Comment $oShape): void { + /* + * Note : This element is not valid in the Schema 1.2 + */ // officeooo:annotation $objWriter->startElement('officeooo:annotation'); - $objWriter->writeAttribute('svg:x', number_format(CommonDrawing::pixelsToCentimeters($oShape->getOffsetX()), 2, '.', '').'cm'); - $objWriter->writeAttribute('svg:y', number_format(CommonDrawing::pixelsToCentimeters($oShape->getOffsetY()), 2, '.', '').'cm'); + $objWriter->writeAttribute('svg:x', number_format(CommonDrawing::pixelsToCentimeters((int) $oShape->getOffsetX()), 2, '.', '') . 'cm'); + $objWriter->writeAttribute('svg:y', number_format(CommonDrawing::pixelsToCentimeters((int) $oShape->getOffsetY()), 2, '.', '') . 'cm'); if ($oShape->getAuthor() instanceof Comment\Author) { $objWriter->writeElement('dc:creator', $oShape->getAuthor()->getName()); @@ -596,19 +651,15 @@ public function writeShapeComment(XMLWriter $objWriter, Comment $oShape) $objWriter->endElement(); } - /** - * @param XMLWriter $objWriter - * @param Line $shape - */ - public function writeShapeLine(XMLWriter $objWriter, Line $shape) + protected function writeShapeLine(XMLWriter $objWriter, Line $shape): void { // draw:line $objWriter->startElement('draw:line'); $objWriter->writeAttribute('draw:style-name', 'gr' . $this->shapeId); - $objWriter->writeAttribute('svg:x1', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y1', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()), 3) . 'cm'); - $objWriter->writeAttribute('svg:x2', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()+$shape->getWidth()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y2', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()+$shape->getHeight()), 3) . 'cm'); + $objWriter->writeAttribute('svg:x1', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y1', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY()), 3) . 'cm'); + $objWriter->writeAttribute('svg:x2', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX() + $shape->getWidth()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y2', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY() + $shape->getHeight()), 3) . 'cm'); // text:p $objWriter->writeElement('text:p'); @@ -617,99 +668,103 @@ public function writeShapeLine(XMLWriter $objWriter, Line $shape) } /** - * Write table Shape - * @param XMLWriter $objWriter - * @param Table $shape + * Write table Shape. */ - public function writeShapeTable(XMLWriter $objWriter, Table $shape) + protected function writeShapeTable(XMLWriter $objWriter, Table $shape): void { // draw:frame $objWriter->startElement('draw:frame'); - $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()), 3) . 'cm'); - $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getHeight()), 3) . 'cm'); - $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getWidth()), 3) . 'cm'); - - // table:table - $objWriter->startElement('table:table'); + $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY()), 3) . 'cm'); + $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getHeight()), 3) . 'cm'); + $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getWidth()), 3) . 'cm'); + + $arrayRows = $shape->getRows(); + if (!empty($arrayRows)) { + $firstRow = reset($arrayRows); + $arrayCells = $firstRow->getCells(); + // table:table + $objWriter->startElement('table:table'); + foreach ($arrayCells as $shapeCell) { + $objWriter->startElement('table:table-column'); + $objWriter->endElement(); + } + foreach ($arrayRows as $keyRow => $shapeRow) { + // table:table-row + $objWriter->startElement('table:table-row'); + $objWriter->writeAttribute('table:style-name', 'gr' . $this->shapeId . 'r' . $keyRow); + //@todo getFill + + $numColspan = 0; + foreach ($shapeRow->getCells() as $keyCell => $shapeCell) { + if (0 == $numColspan) { + // table:table-cell + $objWriter->startElement('table:table-cell'); + $objWriter->writeAttribute('table:style-name', 'gr' . $this->shapeId . 'r' . $keyRow . 'c' . $keyCell); + if ($shapeCell->getColspan() > 1) { + $objWriter->writeAttribute('table:number-columns-spanned', $shapeCell->getColspan()); + $numColspan = $shapeCell->getColspan() - 1; + } - foreach ($shape->getRows() as $keyRow => $shapeRow) { - // table:table-row - $objWriter->startElement('table:table-row'); - $objWriter->writeAttribute('table:style-name', 'gr'.$this->shapeId.'r'.$keyRow); - //@todo getFill + // text:p + $objWriter->startElement('text:p'); - $numColspan = 0; - foreach ($shapeRow->getCells() as $keyCell => $shapeCell) { - if ($numColspan == 0) { - // table:table-cell - $objWriter->startElement('table:table-cell'); - $objWriter->writeAttribute('table:style-name', 'gr' . $this->shapeId.'r'.$keyRow.'c'.$keyCell); - if ($shapeCell->getColspan() > 1) { - $objWriter->writeAttribute('table:number-columns-spanned', $shapeCell->getColspan()); - $numColspan = $shapeCell->getColspan() - 1; - } - - // text:p - $objWriter->startElement('text:p'); - - // text:span - foreach ($shapeCell->getParagraphs() as $shapeParagraph) { - foreach ($shapeParagraph->getRichTextElements() as $shapeRichText) { - if ($shapeRichText instanceof TextElement || $shapeRichText instanceof Run) { - // text:span - $objWriter->startElement('text:span'); - if ($shapeRichText instanceof Run) { - $objWriter->writeAttribute('text:style-name', 'T_' . $shapeRichText->getHashCode()); - } - if ($shapeRichText->hasHyperlink() === true && $shapeRichText->getHyperlink()->getUrl() != '') { - // text:a - $objWriter->startElement('text:a'); - $objWriter->writeAttribute('xlink:href', $shapeRichText->getHyperlink()->getUrl()); - $objWriter->text($shapeRichText->getText()); + // text:span + foreach ($shapeCell->getParagraphs() as $shapeParagraph) { + foreach ($shapeParagraph->getRichTextElements() as $shapeRichText) { + if ($shapeRichText instanceof TextElement) { + // text:span + $objWriter->startElement('text:span'); + if ($shapeRichText instanceof Run) { + $objWriter->writeAttribute('text:style-name', 'T_' . $shapeRichText->getHashCode()); + } + if (true === $shapeRichText->hasHyperlink() && '' !== $shapeRichText->getHyperlink()->getUrl()) { + // text:a + $objWriter->startElement('text:a'); + $objWriter->writeAttribute('xlink:type', 'simple'); + $objWriter->writeAttribute('xlink:href', $shapeRichText->getHyperlink()->getUrl()); + $objWriter->text($shapeRichText->getText()); + $objWriter->endElement(); + } else { + $objWriter->text($shapeRichText->getText()); + } + $objWriter->endElement(); + } elseif ($shapeRichText instanceof BreakElement) { + // text:span + $objWriter->startElement('text:span'); + // text:line-break + $objWriter->startElement('text:line-break'); + $objWriter->endElement(); $objWriter->endElement(); - } else { - $objWriter->text($shapeRichText->getText()); } - $objWriter->endElement(); - } elseif ($shapeRichText instanceof BreakElement) { - // text:span - $objWriter->startElement('text:span'); - // text:line-break - $objWriter->startElement('text:line-break'); - $objWriter->endElement(); - $objWriter->endElement(); } } - } - // > text:p - $objWriter->endElement(); + // > text:p + $objWriter->endElement(); - // > table:table-cell - $objWriter->endElement(); - } else { - // table:covered-table-cell - $objWriter->writeElement('table:covered-table-cell'); - $numColspan--; + // > table:table-cell + $objWriter->endElement(); + } else { + // table:covered-table-cell + $objWriter->writeElement('table:covered-table-cell'); + --$numColspan; + } } + // > table:table-row + $objWriter->endElement(); } - // > table:table-row + // > table:table $objWriter->endElement(); } - // > table:table - $objWriter->endElement(); // > draw:frame $objWriter->endElement(); } /** - * Write table Chart - * @param XMLWriter $objWriter - * @param Chart $shape - * @throws \Exception + * Write table Chart. */ - public function writeShapeChart(XMLWriter $objWriter, Chart $shape) + protected function writeShapeChart(XMLWriter $objWriter, Chart $shape): void { $arrayChart = $this->getArrayChart(); $arrayChart[$this->shapeId] = $shape; @@ -718,14 +773,14 @@ public function writeShapeChart(XMLWriter $objWriter, Chart $shape) // draw:frame $objWriter->startElement('draw:frame'); $objWriter->writeAttribute('draw:name', $shape->getTitle()->getText()); - $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetX()), 3) . 'cm'); - $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getOffsetY()), 3) . 'cm'); - $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getHeight()), 3) . 'cm'); - $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters($shape->getWidth()), 3) . 'cm'); + $objWriter->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetX()), 3) . 'cm'); + $objWriter->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getOffsetY()), 3) . 'cm'); + $objWriter->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getHeight()), 3) . 'cm'); + $objWriter->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $shape->getWidth()), 3) . 'cm'); // draw:object $objWriter->startElement('draw:object'); - $objWriter->writeAttribute('xlink:href', './Object '.$this->shapeId); + $objWriter->writeAttribute('xlink:href', './Object ' . $this->shapeId); $objWriter->writeAttribute('xlink:type', 'simple'); $objWriter->writeAttribute('xlink:show', 'embed'); @@ -736,12 +791,9 @@ public function writeShapeChart(XMLWriter $objWriter, Chart $shape) } /** - * Writes a group of shapes - * - * @param XMLWriter $objWriter - * @param Group $group + * Writes a group of shapes. */ - public function writeShapeGroup(XMLWriter $objWriter, Group $group) + protected function writeShapeGroup(XMLWriter $objWriter, Group $group): void { // draw:g $objWriter->startElement('draw:g'); @@ -771,12 +823,9 @@ public function writeShapeGroup(XMLWriter $objWriter, Group $group) } /** - * Writes the style information for a group of shapes - * - * @param XMLWriter $objWriter - * @param Group $group + * Writes the style information for a group of shapes. */ - public function writeGroupStyle(XMLWriter $objWriter, Group $group) + protected function writeGroupStyle(XMLWriter $objWriter, Group $group): void { $shapes = $group->getShapeCollection(); foreach ($shapes as $shape) { @@ -800,12 +849,9 @@ public function writeGroupStyle(XMLWriter $objWriter, Group $group) } /** - * Write the default style information for a RichText shape - * - * @param \PhpOffice\Common\XMLWriter $objWriter - * @param \PhpOffice\PhpPresentation\Shape\RichText $shape + * Write the default style information for a RichText shape. */ - public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) + protected function writeTxtStyle(XMLWriter $objWriter, RichText $shape): void { // style:style $objWriter->startElement('style:style'); @@ -814,9 +860,8 @@ public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) $objWriter->writeAttribute('style:parent-style-name', 'standard'); // style:graphic-properties $objWriter->startElement('style:graphic-properties'); - if ($shape->getShadow()->isVisible()) { - $this->writeStylePartShadow($objWriter, $shape->getShadow()); - } + $objWriter->writeAttribute('style:mirror', 'none'); + $this->writeStylePartShadow($objWriter, $shape->getShadow()); if (is_bool($shape->hasAutoShrinkVertical())) { $objWriter->writeAttribute('draw:auto-grow-height', var_export($shape->hasAutoShrinkVertical(), true)); } @@ -828,24 +873,24 @@ public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) case Fill::FILL_GRADIENT_LINEAR: case Fill::FILL_GRADIENT_PATH: $objWriter->writeAttribute('draw:fill', 'gradient'); - $objWriter->writeAttribute('draw:fill-gradient-name', 'gradient_'.$shape->getFill()->getHashCode()); + $objWriter->writeAttribute('draw:fill-gradient-name', 'gradient_' . $shape->getFill()->getHashCode()); break; case Fill::FILL_SOLID: $objWriter->writeAttribute('draw:fill', 'solid'); - $objWriter->writeAttribute('draw:fill-color', '#'.$shape->getFill()->getStartColor()->getRGB()); + $objWriter->writeAttribute('draw:fill-color', '#' . $shape->getFill()->getStartColor()->getRGB()); break; case Fill::FILL_NONE: default: $objWriter->writeAttribute('draw:fill', 'none'); - $objWriter->writeAttribute('draw:fill-color', '#'.$shape->getFill()->getStartColor()->getRGB()); + $objWriter->writeAttribute('draw:fill-color', '#' . $shape->getFill()->getStartColor()->getRGB()); break; } // Border - if ($shape->getBorder()->getLineStyle() == Border::LINE_NONE) { + if (Border::LINE_NONE == $shape->getBorder()->getLineStyle()) { $objWriter->writeAttribute('draw:stroke', 'none'); } else { - $objWriter->writeAttribute('svg:stroke-color', '#'.$shape->getBorder()->getColor()->getRGB()); - $objWriter->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($shape->getBorder()->getLineWidth()), 3, '.', '').'cm'); + $objWriter->writeAttribute('svg:stroke-color', '#' . $shape->getBorder()->getColor()->getRGB()); + $objWriter->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($shape->getBorder()->getLineWidth()), 3, '.', '') . 'cm'); switch ($shape->getBorder()->getDashStyle()) { case Border::DASH_SOLID: $objWriter->writeAttribute('draw:stroke', 'solid'); @@ -861,7 +906,7 @@ public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) case Border::DASH_SYSDASHDOTDOT: case Border::DASH_SYSDOT: $objWriter->writeAttribute('draw:stroke', 'dash'); - $objWriter->writeAttribute('draw:stroke-dash', 'strokeDash_'.$shape->getBorder()->getDashStyle()); + $objWriter->writeAttribute('draw:stroke-dash', 'strokeDash_' . $shape->getBorder()->getDashStyle()); break; default: $objWriter->writeAttribute('draw:stroke', 'none'); @@ -875,7 +920,7 @@ public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) // > style:style $objWriter->endElement(); - $paragraphs = $shape->getParagraphs(); + $paragraphs = $shape->getParagraphs(); $paragraphId = 0; foreach ($paragraphs as $paragraph) { ++$paragraphId; @@ -889,14 +934,14 @@ public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) $bulletStyleHashCode = $paragraph->getBulletStyle()->getHashCode(); if (!isset($this->arrStyleBullet[$bulletStyleHashCode])) { $this->arrStyleBullet[$bulletStyleHashCode]['oStyle'] = $paragraph->getBulletStyle(); - $this->arrStyleBullet[$bulletStyleHashCode]['level'] = ''; + $this->arrStyleBullet[$bulletStyleHashCode]['level'] = ''; } - if (strpos($this->arrStyleBullet[$bulletStyleHashCode]['level'], ';' . $paragraph->getAlignment()->getLevel()) === false) { + if (false === strpos($this->arrStyleBullet[$bulletStyleHashCode]['level'], ';' . $paragraph->getAlignment()->getLevel())) { $this->arrStyleBullet[$bulletStyleHashCode]['level'] .= ';' . $paragraph->getAlignment()->getLevel(); $this->arrStyleBullet[$bulletStyleHashCode]['oAlign_' . $paragraph->getAlignment()->getLevel()] = $paragraph->getAlignment(); } - $richtexts = $paragraph->getRichTextElements(); + $richtexts = $paragraph->getRichTextElements(); $richtextId = 0; foreach ($richtexts as $richtext) { ++$richtextId; @@ -912,12 +957,9 @@ public function writeTxtStyle(XMLWriter $objWriter, RichText $shape) } /** - * Write the default style information for an AbstractDrawingAdapter - * - * @param \PhpOffice\Common\XMLWriter $objWriter - * @param \PhpOffice\PhpPresentation\Shape\AbstractDrawingAdapter $shape + * Write the default style information for an AbstractDrawingAdapter. */ - public function writeDrawingStyle(XMLWriter $objWriter, AbstractDrawingAdapter $shape) + protected function writeDrawingStyle(XMLWriter $objWriter, AbstractDrawingAdapter $shape): void { // style:style $objWriter->startElement('style:style'); @@ -928,10 +970,9 @@ public function writeDrawingStyle(XMLWriter $objWriter, AbstractDrawingAdapter $ // style:graphic-properties $objWriter->startElement('style:graphic-properties'); $objWriter->writeAttribute('draw:stroke', 'none'); - $objWriter->writeAttribute('draw:fill', 'none'); - if ($shape->getShadow()->isVisible()) { - $this->writeStylePartShadow($objWriter, $shape->getShadow()); - } + $objWriter->writeAttribute('style:mirror', 'none'); + $this->writeStylePartFill($objWriter, $shape->getFill()); + $this->writeStylePartShadow($objWriter, $shape->getShadow()); $objWriter->endElement(); $objWriter->endElement(); @@ -939,11 +980,8 @@ public function writeDrawingStyle(XMLWriter $objWriter, AbstractDrawingAdapter $ /** * Write the default style information for a Line shape. - * - * @param XMLWriter $objWriter - * @param Line $shape */ - public function writeLineStyle(XMLWriter $objWriter, Line $shape) + protected function writeLineStyle(XMLWriter $objWriter, Line $shape): void { // style:style $objWriter->startElement('style:style'); @@ -965,30 +1003,27 @@ public function writeLineStyle(XMLWriter $objWriter, Line $shape) $objWriter->writeAttribute('draw:stroke', 'none'); break; } - $objWriter->writeAttribute('svg:stroke-color', '#'.$shape->getBorder()->getColor()->getRGB()); - $objWriter->writeAttribute('svg:stroke-width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((CommonDrawing::pointsToPixels($shape->getBorder()->getLineWidth()))), 3).'cm'); + $objWriter->writeAttribute('svg:stroke-color', '#' . $shape->getBorder()->getColor()->getRGB()); + $objWriter->writeAttribute('svg:stroke-width', Text::numberFormat(CommonDrawing::pointsToCentimeters($shape->getBorder()->getLineWidth()), 3) . 'cm'); $objWriter->endElement(); $objWriter->endElement(); } /** - * Write the default style information for a Table shape - * - * @param XMLWriter $objWriter - * @param Table $shape + * Write the default style information for a Table shape. */ - public function writeTableStyle(XMLWriter $objWriter, Table $shape) + protected function writeTableStyle(XMLWriter $objWriter, Table $shape): void { foreach ($shape->getRows() as $keyRow => $shapeRow) { // style:style $objWriter->startElement('style:style'); - $objWriter->writeAttribute('style:name', 'gr' . $this->shapeId.'r'.$keyRow); + $objWriter->writeAttribute('style:name', 'gr' . $this->shapeId . 'r' . $keyRow); $objWriter->writeAttribute('style:family', 'table-row'); // style:table-row-properties $objWriter->startElement('style:table-row-properties'); - $objWriter->writeAttribute('style:row-height', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::pointsToPixels($shapeRow->getHeight())), 3).'cm'); + $objWriter->writeAttribute('style:row-height', Text::numberFormat(CommonDrawing::pointsToCentimeters($shapeRow->getHeight()), 3) . 'cm'); $objWriter->endElement(); $objWriter->endElement(); @@ -996,28 +1031,34 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) foreach ($shapeRow->getCells() as $keyCell => $shapeCell) { // style:style $objWriter->startElement('style:style'); - $objWriter->writeAttribute('style:name', 'gr' . $this->shapeId.'r'.$keyRow.'c'.$keyCell); + $objWriter->writeAttribute('style:name', 'gr' . $this->shapeId . 'r' . $keyRow . 'c' . $keyCell); $objWriter->writeAttribute('style:family', 'table-cell'); + /* + * Note : This element is not valid in the Schema 1.2 + */ // style:graphic-properties - $objWriter->startElement('style:graphic-properties'); - if ($shapeCell->getFill()->getFillType() == Fill::FILL_SOLID) { - $objWriter->writeAttribute('draw:fill', 'solid'); - $objWriter->writeAttribute('draw:fill-color', '#'.$shapeCell->getFill()->getStartColor()->getRGB()); - } - if ($shapeCell->getFill()->getFillType() == Fill::FILL_GRADIENT_LINEAR) { - $objWriter->writeAttribute('draw:fill', 'gradient'); - $objWriter->writeAttribute('draw:fill-gradient-name', 'gradient_'.$shapeCell->getFill()->getHashCode()); + if (Fill::FILL_NONE != $shapeCell->getFill()->getFillType()) { + $objWriter->startElement('style:graphic-properties'); + if (Fill::FILL_SOLID == $shapeCell->getFill()->getFillType()) { + $objWriter->writeAttribute('draw:fill', 'solid'); + $objWriter->writeAttribute('draw:fill-color', '#' . $shapeCell->getFill()->getStartColor()->getRGB()); + } + if (Fill::FILL_GRADIENT_LINEAR == $shapeCell->getFill()->getFillType()) { + $objWriter->writeAttribute('draw:fill', 'gradient'); + $objWriter->writeAttribute('draw:fill-gradient-name', 'gradient_' . $shapeCell->getFill()->getHashCode()); + } + $objWriter->endElement(); } - $objWriter->endElement(); - // style:graphic-properties // style:paragraph-properties $objWriter->startElement('style:paragraph-properties'); $cellBorders = $shapeCell->getBorders(); - if ($cellBorders->getBottom()->getHashCode() == $cellBorders->getTop()->getHashCode() - && $cellBorders->getBottom()->getHashCode() == $cellBorders->getLeft()->getHashCode() - && $cellBorders->getBottom()->getHashCode() == $cellBorders->getRight()->getHashCode()) { + $cellBordersBottomHashCode = $cellBorders->getBottom()->getHashCode(); + if ($cellBordersBottomHashCode == $cellBorders->getTop()->getHashCode() + && $cellBordersBottomHashCode == $cellBorders->getLeft()->getHashCode() + && $cellBordersBottomHashCode == $cellBorders->getRight()->getHashCode()) { $lineStyle = 'none'; $lineWidth = Text::numberFormat($cellBorders->getBottom()->getLineWidth() / 1.75, 2); $lineColor = $cellBorders->getBottom()->getColor()->getRGB(); @@ -1025,7 +1066,7 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) case Border::LINE_SINGLE: $lineStyle = 'solid'; } - $objWriter->writeAttribute('fo:border', $lineWidth.'pt '.$lineStyle.' #'.$lineColor); + $objWriter->writeAttribute('fo:border', $lineWidth . 'pt ' . $lineStyle . ' #' . $lineColor); } else { $lineStyle = 'none'; $lineWidth = Text::numberFormat($cellBorders->getBottom()->getLineWidth() / 1.75, 2); @@ -1034,7 +1075,7 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) case Border::LINE_SINGLE: $lineStyle = 'solid'; } - $objWriter->writeAttribute('fo:border-bottom', $lineWidth.'pt '.$lineStyle.' #'.$lineColor); + $objWriter->writeAttribute('fo:border-bottom', $lineWidth . 'pt ' . $lineStyle . ' #' . $lineColor); // TOP $lineStyle = 'none'; $lineWidth = Text::numberFormat($cellBorders->getTop()->getLineWidth() / 1.75, 2); @@ -1043,7 +1084,7 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) case Border::LINE_SINGLE: $lineStyle = 'solid'; } - $objWriter->writeAttribute('fo:border-top', $lineWidth.'pt '.$lineStyle.' #'.$lineColor); + $objWriter->writeAttribute('fo:border-top', $lineWidth . 'pt ' . $lineStyle . ' #' . $lineColor); // RIGHT $lineStyle = 'none'; $lineWidth = Text::numberFormat($cellBorders->getRight()->getLineWidth() / 1.75, 2); @@ -1052,7 +1093,7 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) case Border::LINE_SINGLE: $lineStyle = 'solid'; } - $objWriter->writeAttribute('fo:border-right', $lineWidth.'pt '.$lineStyle.' #'.$lineColor); + $objWriter->writeAttribute('fo:border-right', $lineWidth . 'pt ' . $lineStyle . ' #' . $lineColor); // LEFT $lineStyle = 'none'; $lineWidth = Text::numberFormat($cellBorders->getLeft()->getLineWidth() / 1.75, 2); @@ -1061,10 +1102,11 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) case Border::LINE_SINGLE: $lineStyle = 'solid'; } - $objWriter->writeAttribute('fo:border-left', $lineWidth.'pt '.$lineStyle.' #'.$lineColor); + $objWriter->writeAttribute('fo:border-left', $lineWidth . 'pt ' . $lineStyle . ' #' . $lineColor); } + // >style:paragraph-properties $objWriter->endElement(); - + // >style:style $objWriter->endElement(); foreach ($shapeCell->getParagraphs() as $shapeParagraph) { @@ -1082,11 +1124,9 @@ public function writeTableStyle(XMLWriter $objWriter, Table $shape) } /** - * Write the slide note - * @param XMLWriter $objWriter - * @param \PhpOffice\PhpPresentation\Slide\Note $note + * Write the slide note. */ - public function writeSlideNote(XMLWriter $objWriter, Note $note) + protected function writeSlideNote(XMLWriter $objWriter, Note $note): void { $shapesNote = $note->getShapeCollection(); if (count($shapesNote) > 0) { @@ -1106,22 +1146,19 @@ public function writeSlideNote(XMLWriter $objWriter, Note $note) } /** - * Write style of a slide - * @param XMLWriter $objWriter - * @param Slide $slide - * @param int $incPage + * Write style of a slide. */ - public function writeStyleSlide(XMLWriter $objWriter, Slide $slide, $incPage) + protected function writeStyleSlide(XMLWriter $objWriter, Slide $slide, int $incPage): void { // style:style $objWriter->startElement('style:style'); $objWriter->writeAttribute('style:family', 'drawing-page'); - $objWriter->writeAttribute('style:name', 'stylePage'.$incPage); + $objWriter->writeAttribute('style:name', 'stylePage' . $incPage); // style:style/style:drawing-page-properties $objWriter->startElement('style:drawing-page-properties'); $objWriter->writeAttributeIf(!$slide->isVisible(), 'presentation:visibility', 'hidden'); if (!is_null($oTransition = $slide->getTransition())) { - $objWriter->writeAttribute('presentation:duration', 'PT'.number_format($oTransition->getAdvanceTimeTrigger() / 1000, 6, '.', '').'S'); + $objWriter->writeAttribute('presentation:duration', 'PT' . number_format($oTransition->getAdvanceTimeTrigger() / 1000, 6, '.', '') . 'S'); $objWriter->writeAttributeIf($oTransition->hasManualTrigger(), 'presentation:transition-type', 'manual'); $objWriter->writeAttributeIf($oTransition->hasTimeTrigger(), 'presentation:transition-type', 'automatic'); switch ($oTransition->getSpeed()) { @@ -1136,7 +1173,7 @@ public function writeStyleSlide(XMLWriter $objWriter, Slide $slide, $incPage) break; } - /** + /* * http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#property-presentation_transition-style */ switch ($oTransition->getTransitionType()) { @@ -1152,10 +1189,7 @@ public function writeStyleSlide(XMLWriter $objWriter, Slide $slide, $incPage) case Transition::TRANSITION_CHECKER_VERTICAL: $objWriter->writeAttribute('presentation:transition-style', 'vertical-checkerboard'); break; - case Transition::TRANSITION_CIRCLE_HORIZONTAL: - $objWriter->writeAttribute('presentation:transition-style', 'none'); - break; - case Transition::TRANSITION_CIRCLE_VERTICAL: + case Transition::TRANSITION_CIRCLE: $objWriter->writeAttribute('presentation:transition-style', 'none'); break; case Transition::TRANSITION_COMB_HORIZONTAL: @@ -1295,7 +1329,7 @@ public function writeStyleSlide(XMLWriter $objWriter, Slide $slide, $incPage) } if ($oBackground instanceof Slide\Background\Image) { $objWriter->writeAttribute('draw:fill', 'bitmap'); - $objWriter->writeAttribute('draw:fill-image-name', 'background_'.$incPage); + $objWriter->writeAttribute('draw:fill-image-name', 'background_' . $incPage); $objWriter->writeAttribute('style:repeat', 'stretch'); } } @@ -1304,44 +1338,60 @@ public function writeStyleSlide(XMLWriter $objWriter, Slide $slide, $incPage) $objWriter->endElement(); } + protected function writeStylePartFill(XMLWriter $objWriter, ?Fill $oFill): void + { + if (!$oFill) { + return; + } + switch ($oFill->getFillType()) { + case Fill::FILL_SOLID: + $objWriter->writeAttribute('draw:fill', 'solid'); + $objWriter->writeAttribute('draw:fill-color', '#' . $oFill->getStartColor()->getRGB()); + break; + case Fill::FILL_NONE: + default: + $objWriter->writeAttribute('draw:fill', 'none'); + break; + } + } /** - * @param XMLWriter $objWriter - * @param Shadow $oShadow * @todo Improve for supporting any direction (https://sinepost.wordpress.com/2012/02/16/theyve-got-atan-you-want-atan2/) */ - protected function writeStylePartShadow(XMLWriter $objWriter, Shadow $oShadow) + protected function writeStylePartShadow(XMLWriter $objWriter, Shadow $oShadow): void { + if (!$oShadow->isVisible()) { + return; + } $objWriter->writeAttribute('draw:shadow', 'visible'); $objWriter->writeAttribute('draw:shadow-color', '#' . $oShadow->getColor()->getRGB()); - $distanceCms = CommonDrawing::pixelsToCentimeters($oShadow->getDistance()); - if ($oShadow->getDirection() == 0 || $oShadow->getDirection() == 360) { + $distanceCms = CommonDrawing::pixelsToCentimeters((int) $oShadow->getDistance()); + if (0 == $oShadow->getDirection() || 360 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', $distanceCms . 'cm'); $objWriter->writeAttribute('draw:shadow-offset-y', '0cm'); - } elseif ($oShadow->getDirection() == 45) { + } elseif (45 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', $distanceCms . 'cm'); $objWriter->writeAttribute('draw:shadow-offset-y', $distanceCms . 'cm'); - } elseif ($oShadow->getDirection() == 90) { + } elseif (90 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', '0cm'); $objWriter->writeAttribute('draw:shadow-offset-y', $distanceCms . 'cm'); - } elseif ($oShadow->getDirection() == 135) { + } elseif (135 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', '-' . $distanceCms . 'cm'); $objWriter->writeAttribute('draw:shadow-offset-y', $distanceCms . 'cm'); - } elseif ($oShadow->getDirection() == 180) { + } elseif (180 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', '-' . $distanceCms . 'cm'); $objWriter->writeAttribute('draw:shadow-offset-y', '0cm'); - } elseif ($oShadow->getDirection() == 225) { + } elseif (225 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', '-' . $distanceCms . 'cm'); $objWriter->writeAttribute('draw:shadow-offset-y', '-' . $distanceCms . 'cm'); - } elseif ($oShadow->getDirection() == 270) { + } elseif (270 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', '0cm'); $objWriter->writeAttribute('draw:shadow-offset-y', '-' . $distanceCms . 'cm'); - } elseif ($oShadow->getDirection() == 315) { + } elseif (315 == $oShadow->getDirection()) { $objWriter->writeAttribute('draw:shadow-offset-x', $distanceCms . 'cm'); $objWriter->writeAttribute('draw:shadow-offset-y', '-' . $distanceCms . 'cm'); } $objWriter->writeAttribute('draw:shadow-opacity', (100 - $oShadow->getAlpha()) . '%'); - $objWriter->writeAttribute('style:mirror', 'none'); } } diff --git a/src/PhpPresentation/Writer/ODPresentation/Meta.php b/src/PhpPresentation/Writer/ODPresentation/Meta.php index b73dfae219..d976503e8b 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Meta.php +++ b/src/PhpPresentation/Writer/ODPresentation/Meta.php @@ -1,15 +1,35 @@ writeElement('meta:keyword', $this->getPresentation()->getDocumentProperties()->getKeywords()); + // meta:user-defined + $oDocumentProperties = $this->oPresentation->getDocumentProperties(); + foreach ($oDocumentProperties->getCustomProperties() as $customProperty) { + $propertyValue = $oDocumentProperties->getCustomPropertyValue($customProperty); + $propertyType = $oDocumentProperties->getCustomPropertyType($customProperty); + + $objWriter->startElement('meta:user-defined'); + $objWriter->writeAttribute('meta:name', $customProperty); + switch ($propertyType) { + case DocumentProperties::PROPERTY_TYPE_INTEGER: + case DocumentProperties::PROPERTY_TYPE_FLOAT: + $objWriter->writeAttribute('meta:value-type', 'float'); + $objWriter->writeRaw((string) $propertyValue); + break; + case DocumentProperties::PROPERTY_TYPE_BOOLEAN: + $objWriter->writeAttribute('meta:value-type', 'boolean'); + $objWriter->writeRaw($propertyValue ? 'true' : 'false'); + break; + case DocumentProperties::PROPERTY_TYPE_DATE: + $objWriter->writeAttribute('meta:value-type', 'date'); + $objWriter->writeRaw(date(DATE_W3C, (int) $propertyValue)); + break; + case DocumentProperties::PROPERTY_TYPE_STRING: + case DocumentProperties::PROPERTY_TYPE_UNKNOWN: + default: + $objWriter->writeAttribute('meta:value-type', 'string'); + $objWriter->writeRaw((string) $propertyValue); + break; + } + $objWriter->endElement(); + } + // @todo : Where these properties are written ? // $this->getPresentation()->getDocumentProperties()->getCategory() // $this->getPresentation()->getDocumentProperties()->getCompany() @@ -57,8 +109,9 @@ public function render() $objWriter->endElement(); $objWriter->endElement(); - + $this->getZip()->addFromString('meta.xml', $objWriter->getData()); + return $this->getZip(); } } diff --git a/src/PhpPresentation/Writer/ODPresentation/MetaInfManifest.php b/src/PhpPresentation/Writer/ODPresentation/MetaInfManifest.php index 1a2710a9be..49f023e763 100644 --- a/src/PhpPresentation/Writer/ODPresentation/MetaInfManifest.php +++ b/src/PhpPresentation/Writer/ODPresentation/MetaInfManifest.php @@ -1,4 +1,22 @@ getArrayChart() as $key => $shape) { $objWriter->startElement('manifest:file-entry'); $objWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.chart'); - $objWriter->writeAttribute('manifest:full-path', 'Object '.$key.'/'); + $objWriter->writeAttribute('manifest:full-path', 'Object ' . $key . '/'); $objWriter->endElement(); $objWriter->startElement('manifest:file-entry'); $objWriter->writeAttribute('manifest:media-type', 'text/xml'); - $objWriter->writeAttribute('manifest:full-path', 'Object '.$key.'/content.xml'); + $objWriter->writeAttribute('manifest:full-path', 'Object ' . $key . '/content.xml'); $objWriter->endElement(); } - $arrMedia = array(); + $arrMedia = []; for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { $shape = $this->getDrawingHashTable()->getByIndex($i); - if (! ($shape instanceof ShapeDrawing\AbstractDrawingAdapter)) { + if (!($shape instanceof ShapeDrawing\AbstractDrawingAdapter)) { continue; } $arrMedia[] = $shape->getIndexedFilename(); @@ -77,11 +94,11 @@ public function render() $oBkgImage = $oSlide->getBackground(); if ($oBkgImage instanceof Image) { $arrayImage = getimagesize($oBkgImage->getPath()); - $mimeType = image_type_to_mime_type($arrayImage[2]); + $mimeType = image_type_to_mime_type($arrayImage[2]); $objWriter->startElement('manifest:file-entry'); $objWriter->writeAttribute('manifest:media-type', $mimeType); - $objWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $oBkgImage->getIndexedFilename($numSlide))); + $objWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $oBkgImage->getIndexedFilename((string) $numSlide))); $objWriter->endElement(); } } @@ -103,6 +120,7 @@ public function render() $objWriter->endElement(); $this->getZip()->addFromString('META-INF/manifest.xml', $objWriter->getData()); + return $this->getZip(); } } diff --git a/src/PhpPresentation/Writer/ODPresentation/Mimetype.php b/src/PhpPresentation/Writer/ODPresentation/Mimetype.php index 342da946db..80101241df 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Mimetype.php +++ b/src/PhpPresentation/Writer/ODPresentation/Mimetype.php @@ -1,15 +1,36 @@ getZip()->addFromString('mimetype', 'application/vnd.oasis.opendocument.presentation'); + return $this->getZip(); } } diff --git a/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php b/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php index d9d760d620..38c8057ae3 100644 --- a/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php +++ b/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php @@ -1,4 +1,22 @@ getArrayChart() as $keyChart => $shapeChart) { $content = $this->writeContentPart($shapeChart); if (!empty($content)) { - $this->getZip()->addFromString('Object '.$keyChart.'/content.xml', $content); + $this->getZip()->addFromString('Object ' . $keyChart . '/content.xml', $content); } } return $this->getZip(); } - /** - * @param Chart $chart - * @return string - * @throws \Exception - */ - protected function writeContentPart(Chart $chart) + protected function writeContentPart(Chart $chart): string { $this->xmlContent = new XMLWriter(XMLWriter::STORAGE_MEMORY); $chartType = $chart->getPlotArea()->getType(); // Data - $this->arrayData = array(); - $this->arrayTitle = array(); + $this->arrayData = []; + $this->arrayTitle = []; $this->numData = 0; foreach ($chartType->getSeries() as $series) { $inc = 0; $this->arrayTitle[] = $series->getTitle(); foreach ($series->getValues() as $key => $value) { if (!isset($this->arrayData[$inc])) { - $this->arrayData[$inc] = array(); + $this->arrayData[$inc] = []; } if (empty($this->arrayData[$inc])) { $this->arrayData[$inc][] = $key; } $this->arrayData[$inc][] = $value; - $inc++; + ++$inc; } if ($inc > $this->numData) { $this->numData = $inc; @@ -137,33 +152,18 @@ protected function writeContentPart(Chart $chart) // office:automatic-styles $this->xmlContent->startElement('office:automatic-styles'); - // Chart + // Styles $this->writeChartStyle($chart); - - // Axis $this->writeAxisStyle($chart); - - // Series $this->numSeries = 0; foreach ($chartType->getSeries() as $series) { $this->writeSeriesStyle($chart, $series); - - $this->numSeries++; + ++$this->numSeries; } - - // Floor $this->writeFloorStyle(); - - // Legend $this->writeLegendStyle($chart); - - // PlotArea $this->writePlotAreaStyle($chart); - - // Title $this->writeTitleStyle($chart->getTitle()); - - // Wall $this->writeWallStyle($chart); // > office:automatic-styles @@ -175,27 +175,24 @@ protected function writeContentPart(Chart $chart) $this->xmlContent->startElement('office:chart'); // office:chart $this->xmlContent->startElement('chart:chart'); - $this->xmlContent->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters($chart->getWidth()), 3) . 'cm'); - $this->xmlContent->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters($chart->getHeight()), 3) . 'cm'); + $this->xmlContent->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getWidth()), 3) . 'cm'); + $this->xmlContent->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getHeight()), 3) . 'cm'); $this->xmlContent->writeAttribute('xlink:href', '.'); $this->xmlContent->writeAttribute('xlink:type', 'simple'); $this->xmlContent->writeAttribute('chart:style-name', 'styleChart'); $this->xmlContent->writeAttributeIf($chartType instanceof Area, 'chart:class', 'chart:area'); $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypeBar, 'chart:class', 'chart:bar'); + if (!($chartType instanceof Doughnut)) { + $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypePie, 'chart:class', 'chart:circle'); + } + $this->xmlContent->writeAttributeIf($chartType instanceof Doughnut, 'chart:class', 'chart:ring'); $this->xmlContent->writeAttributeIf($chartType instanceof Line, 'chart:class', 'chart:line'); - $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypePie, 'chart:class', 'chart:circle'); + $this->xmlContent->writeAttributeIf($chartType instanceof Radar, 'chart:class', 'chart:radar'); $this->xmlContent->writeAttributeIf($chartType instanceof Scatter, 'chart:class', 'chart:scatter'); - //**** Title **** $this->writeTitle($chart->getTitle()); - - //**** Legend **** $this->writeLegend($chart); - - //**** Plotarea **** $this->writePlotArea($chart); - - //**** Table **** $this->writeTable(); // > chart:chart @@ -210,10 +207,7 @@ protected function writeContentPart(Chart $chart) return $this->xmlContent->getData(); } - /** - * @param Chart $chart - */ - private function writeAxis(Chart $chart) + protected function writeAxis(Chart $chart): void { $chartType = $chart->getPlotArea()->getType(); @@ -221,11 +215,17 @@ private function writeAxis(Chart $chart) $this->xmlContent->startElement('chart:axis'); $this->xmlContent->writeAttribute('chart:dimension', 'x'); $this->xmlContent->writeAttribute('chart:name', 'primary-x'); - $this->xmlContent->writeAttribute('chartooo:axis-type', 'text'); $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisX'); + // chart:axis > chart:title + if ($chart->getPlotArea()->getAxisX()->isVisible()) { + $this->xmlContent->startElement('chart:title'); + $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisXTitle'); + $this->xmlContent->writeElement('text:p', $chart->getPlotArea()->getAxisX()->getTitle()); + $this->xmlContent->endElement(); + } // chart:axis > chart:categories $this->xmlContent->startElement('chart:categories'); - $this->xmlContent->writeAttribute('table:cell-range-address', 'table-local.$A$2:.$A$'.($this->numData+1)); + $this->xmlContent->writeAttribute('table:cell-range-address', 'table-local.$A$2:.$A$' . ($this->numData + 1)); $this->xmlContent->endElement(); // chart:axis > chart:grid $this->writeGridline($chart->getPlotArea()->getAxisX()->getMajorGridlines(), 'styleAxisXGridlinesMajor', 'major'); @@ -239,6 +239,13 @@ private function writeAxis(Chart $chart) $this->xmlContent->writeAttribute('chart:dimension', 'y'); $this->xmlContent->writeAttribute('chart:name', 'primary-y'); $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisY'); + // chart:axis > chart:title + if ($chart->getPlotArea()->getAxisY()->isVisible()) { + $this->xmlContent->startElement('chart:title'); + $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisYTitle'); + $this->xmlContent->writeElement('text:p', $chart->getPlotArea()->getAxisY()->getTitle()); + $this->xmlContent->endElement(); + } // chart:axis > chart:grid $this->writeGridline($chart->getPlotArea()->getAxisY()->getMajorGridlines(), 'styleAxisYGridlinesMajor', 'major'); // chart:axis > chart:grid @@ -256,10 +263,10 @@ private function writeAxis(Chart $chart) } } - protected function writeGridline($oGridlines, $styleName, $chartClass) + protected function writeGridline(?Chart\Gridlines $oGridlines, string $styleName, string $chartClass): void { - if (!($oGridlines instanceof Chart\Gridlines)) { - return ; + if (!$oGridlines) { + return; } $this->xmlContent->startElement('chart:grid'); @@ -269,48 +276,17 @@ protected function writeGridline($oGridlines, $styleName, $chartClass) } /** - * @param Chart $chart * @todo Set function in \PhpPresentation\Shape\Chart\Axis for defining width and color of the axis */ - protected function writeAxisStyle(Chart $chart) + protected function writeAxisStyle(Chart $chart): void { $chartType = $chart->getPlotArea()->getType(); // AxisX - // style:style - $this->xmlContent->startElement('style:style'); - $this->xmlContent->writeAttribute('style:name', 'styleAxisX'); - $this->xmlContent->writeAttribute('style:family', 'chart'); - // style:style > style:chart-properties - $this->xmlContent->startElement('style:chart-properties'); - $this->xmlContent->writeAttribute('chart:display-label', 'true'); - $this->xmlContent->writeAttribute('chart:tick-marks-major-inner', 'false'); - $this->xmlContent->writeAttribute('chart:tick-marks-major-outer', 'false'); - if ($chartType instanceof AbstractTypePie) { - $this->xmlContent->writeAttribute('chart:reverse-direction', 'true'); - } - if ($chart->getPlotArea()->getAxisX()->getMinBounds() != null) { - $this->xmlContent->writeAttribute('chart:minimum', $chart->getPlotArea()->getAxisX()->getMinBounds()); - } - if ($chart->getPlotArea()->getAxisX()->getMaxBounds() != null) { - $this->xmlContent->writeAttribute('chart:maximum', $chart->getPlotArea()->getAxisX()->getMaxBounds()); - } - $this->xmlContent->endElement(); - // style:style > style:text-properties - $oFont = $chart->getPlotArea()->getAxisX()->getFont(); - $this->xmlContent->startElement('style:text-properties'); - $this->xmlContent->writeAttribute('fo:color', '#'.$oFont->getColor()->getRGB()); - $this->xmlContent->writeAttribute('fo:font-family', $oFont->getName()); - $this->xmlContent->writeAttribute('fo:font-size', $oFont->getSize().'pt'); - $this->xmlContent->writeAttribute('fo:font-style', $oFont->isItalic() ? 'italic' : 'normal'); - $this->xmlContent->endElement(); - // style:style > style:graphic-properties - $this->xmlContent->startElement('style:graphic-properties'); - $this->xmlContent->writeAttribute('svg:stroke-width', '0.026cm'); - $this->xmlContent->writeAttribute('svg:stroke-color', '#878787'); - $this->xmlContent->endElement(); - // ##style:style - $this->xmlContent->endElement(); + $this->writeAxisMainStyle($chart->getPlotArea()->getAxisX(), 'styleAxisX', $chartType); + + // AxisX Title + $this->writeAxisTitleStyle($chart->getPlotArea()->getAxisX(), 'styleAxisXTitle'); // AxisX GridLines Major $this->writeGridlineStyle($chart->getPlotArea()->getAxisX()->getMajorGridlines(), 'styleAxisXGridlinesMajor'); @@ -319,55 +295,94 @@ protected function writeAxisStyle(Chart $chart) $this->writeGridlineStyle($chart->getPlotArea()->getAxisX()->getMinorGridlines(), 'styleAxisXGridlinesMinor'); // AxisY + $this->writeAxisMainStyle($chart->getPlotArea()->getAxisY(), 'styleAxisY', $chartType); + + // AxisY Title + $this->writeAxisTitleStyle($chart->getPlotArea()->getAxisY(), 'styleAxisYTitle'); + + // AxisY GridLines Major + $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMajorGridlines(), 'styleAxisYGridlinesMajor'); + + // AxisY GridLines Minor + $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMinorGridlines(), 'styleAxisYGridlinesMinor'); + } + + protected function writeAxisMainStyle(Chart\Axis $axis, string $styleName, AbstractType $chartType): void + { // style:style $this->xmlContent->startElement('style:style'); - $this->xmlContent->writeAttribute('style:name', 'styleAxisY'); + $this->xmlContent->writeAttribute('style:name', $styleName); $this->xmlContent->writeAttribute('style:family', 'chart'); // style:style > style:chart-properties $this->xmlContent->startElement('style:chart-properties'); $this->xmlContent->writeAttribute('chart:display-label', 'true'); $this->xmlContent->writeAttribute('chart:tick-marks-major-inner', 'false'); $this->xmlContent->writeAttribute('chart:tick-marks-major-outer', 'false'); - if ($chartType instanceof AbstractTypePie) { - $this->xmlContent->writeAttribute('chart:reverse-direction', 'true'); - } - if ($chart->getPlotArea()->getAxisY()->getMinBounds() != null) { - $this->xmlContent->writeAttribute('chart:minimum', $chart->getPlotArea()->getAxisY()->getMinBounds()); - } - if ($chart->getPlotArea()->getAxisY()->getMaxBounds() != null) { - $this->xmlContent->writeAttribute('chart:maximum', $chart->getPlotArea()->getAxisY()->getMaxBounds()); - } - $this->xmlContent->endElement(); - // style:style > style:text-properties - $oFont = $chart->getPlotArea()->getAxisY()->getFont(); - $this->xmlContent->startElement('style:text-properties'); - $this->xmlContent->writeAttribute('fo:color', '#'.$oFont->getColor()->getRGB()); - $this->xmlContent->writeAttribute('fo:font-family', $oFont->getName()); - $this->xmlContent->writeAttribute('fo:font-size', $oFont->getSize().'pt'); - $this->xmlContent->writeAttribute('fo:font-style', $oFont->isItalic() ? 'italic' : 'normal'); + $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypePie, 'chart:reverse-direction', 'true'); + $this->xmlContent->writeAttributeIf(null !== $axis->getMinBounds(), 'chart:minimum', $axis->getMinBounds()); + $this->xmlContent->writeAttributeIf(null !== $axis->getMaxBounds(), 'chart:maximum', $axis->getMaxBounds()); + $this->xmlContent->writeAttributeIf(null !== $axis->getMajorUnit(), 'chart:interval-major', $axis->getMajorUnit()); + $this->xmlContent->writeAttributeIf(null !== $axis->getMinorUnit(), 'chart:interval-minor-divisor', $axis->getMinorUnit()); + switch ($axis->getTickLabelPosition()) { + case Axis::TICK_LABEL_POSITION_NEXT_TO: + $this->xmlContent->writeAttribute('chart:axis-label-position', 'near-axis'); + break; + case Axis::TICK_LABEL_POSITION_HIGH: + $this->xmlContent->writeAttribute('chart:axis-position', '0'); + $this->xmlContent->writeAttribute('chart:axis-label-position', 'outside-end'); + break; + case Axis::TICK_LABEL_POSITION_LOW: + $this->xmlContent->writeAttribute('chart:axis-position', '0'); + $this->xmlContent->writeAttribute('chart:axis-label-position', 'outside-start'); + $this->xmlContent->writeAttribute('chart:tick-mark-position', 'at-axis'); + break; + } + $this->xmlContent->writeAttributeIf($chartType instanceof Radar && $styleName == 'styleAxisX', 'chart:reverse-direction', 'true'); $this->xmlContent->endElement(); // style:graphic-properties $this->xmlContent->startElement('style:graphic-properties'); - $this->xmlContent->writeAttribute('svg:stroke-width', '0.026cm'); - $this->xmlContent->writeAttribute('svg:stroke-color', '#878787'); + $this->xmlContent->writeAttribute('draw:stroke', $axis->getOutline()->getFill()->getFillType()); + $this->xmlContent->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($axis->getOutline()->getWidth()), 3, '.', '') . 'cm'); + $this->xmlContent->writeAttribute('svg:stroke-color', '#' . $axis->getOutline()->getFill()->getStartColor()->getRGB()); + $this->xmlContent->endElement(); + // style:style > style:text-properties + $this->xmlContent->startElement('style:text-properties'); + $this->xmlContent->writeAttribute('fo:color', '#' . $axis->getFont()->getColor()->getRGB()); + $this->xmlContent->writeAttribute('fo:font-family', $axis->getFont()->getName()); + $this->xmlContent->writeAttribute('fo:font-size', $axis->getFont()->getSize() . 'pt'); + $this->xmlContent->writeAttribute('fo:font-style', $axis->getFont()->isItalic() ? 'italic' : 'normal'); $this->xmlContent->endElement(); // ## style:style $this->xmlContent->endElement(); + } - // AxisY GridLines Major - $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMajorGridlines(), 'styleAxisYGridlinesMajor'); - - // AxisY GridLines Minor - $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMinorGridlines(), 'styleAxisYGridlinesMinor'); + protected function writeAxisTitleStyle(Chart\Axis $axis, string $styleName): void + { + // style:style + $this->xmlContent->startElement('style:style'); + $this->xmlContent->writeAttribute('style:name', $styleName); + $this->xmlContent->writeAttribute('style:family', 'chart'); + // style:chart-properties + $this->xmlContent->startElement('style:chart-properties'); + $this->xmlContent->writeAttribute('chart:auto-position', 'true'); + $this->xmlContent->writeAttributeIf($axis->getTitleRotation() != 0, 'style:rotation-angle', '-' . $axis->getTitleRotation()); + // > style:chart-properties + $this->xmlContent->endElement(); + // style:text-properties + $this->xmlContent->startElement('style:text-properties'); + $this->xmlContent->writeAttribute('fo:color', '#' . $axis->getFont()->getColor()->getRGB()); + $this->xmlContent->writeAttribute('fo:font-family', $axis->getFont()->getName()); + $this->xmlContent->writeAttribute('fo:font-size', $axis->getFont()->getSize() . 'pt'); + $this->xmlContent->writeAttribute('fo:font-style', $axis->getFont()->isItalic() ? 'italic' : 'normal'); + // > style:text-properties + $this->xmlContent->endElement(); + // > style:style + $this->xmlContent->endElement(); } - /** - * @param Chart\Gridlines $oGridlines - * @param string $styleName - */ - protected function writeGridlineStyle($oGridlines, $styleName) + protected function writeGridlineStyle(?Chart\Gridlines $oGridlines, string $styleName): void { - if (!($oGridlines instanceof Chart\Gridlines)) { + if (!$oGridlines) { return; } // style:style @@ -376,17 +391,14 @@ protected function writeGridlineStyle($oGridlines, $styleName) $this->xmlContent->writeAttribute('style:family', 'chart'); // style:style > style:graphic-properties $this->xmlContent->startElement('style:graphic-properties'); - $this->xmlContent->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($oGridlines->getOutline()->getWidth()), 2, '.', '').'cm'); - $this->xmlContent->writeAttribute('svg:stroke-color', '#'.$oGridlines->getOutline()->getFill()->getStartColor()->getRGB()); + $this->xmlContent->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($oGridlines->getOutline()->getWidth()), 2, '.', '') . 'cm'); + $this->xmlContent->writeAttribute('svg:stroke-color', '#' . $oGridlines->getOutline()->getFill()->getStartColor()->getRGB()); $this->xmlContent->endElement(); // ##style:style $this->xmlContent->endElement(); } - /** - * @param Chart $chart - */ - private function writeChartStyle(Chart $chart) + protected function writeChartStyle(Chart $chart): void { // style:style $this->xmlContent->startElement('style:style'); @@ -395,14 +407,14 @@ private function writeChartStyle(Chart $chart) // style:graphic-properties $this->xmlContent->startElement('style:graphic-properties'); $this->xmlContent->writeAttribute('draw:stroke', $chart->getFill()->getFillType()); - $this->xmlContent->writeAttribute('draw:fill-color', '#'.$chart->getFill()->getStartColor()->getRGB()); + $this->xmlContent->writeAttribute('draw:fill-color', '#' . $chart->getFill()->getStartColor()->getRGB()); // > style:graphic-properties $this->xmlContent->endElement(); // > style:style $this->xmlContent->endElement(); } - private function writeFloor() + protected function writeFloor(): void { // chart:floor $this->xmlContent->startElement('chart:floor'); @@ -411,7 +423,7 @@ private function writeFloor() $this->xmlContent->endElement(); } - private function writeFloorStyle() + protected function writeFloorStyle(): void { // style:style $this->xmlContent->startElement('style:style'); @@ -430,36 +442,53 @@ private function writeFloorStyle() $this->xmlContent->endElement(); } - /** - * @param Chart $chart - */ - private function writeLegend(Chart $chart) + protected function writeLegend(Chart $chart): void { // chart:legend $this->xmlContent->startElement('chart:legend'); - $this->xmlContent->writeAttribute('chart:legend-position', 'end'); - $this->xmlContent->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($chart->getLegend()->getOffsetX()), 3) . 'cm'); - $this->xmlContent->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($chart->getLegend()->getOffsetY()), 3) . 'cm'); + switch ($chart->getLegend()->getPosition()) { + case Chart\Legend::POSITION_BOTTOM: + $position = 'bottom'; + break; + case Chart\Legend::POSITION_LEFT: + $position = 'start'; + break; + case Chart\Legend::POSITION_TOP: + $position = 'top'; + break; + case Chart\Legend::POSITION_TOPRIGHT: + $position = 'top-end'; + break; + case Chart\Legend::POSITION_RIGHT: + default: + $position = 'end'; + break; + } + $this->xmlContent->writeAttribute('chart:legend-position', $position); + $this->xmlContent->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getLegend()->getOffsetX()), 3) . 'cm'); + $this->xmlContent->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getLegend()->getOffsetY()), 3) . 'cm'); $this->xmlContent->writeAttribute('style:legend-expansion', 'high'); $this->xmlContent->writeAttribute('chart:style-name', 'styleLegend'); // > chart:legend $this->xmlContent->endElement(); } - /** - * @param Chart $chart - */ - private function writeLegendStyle(Chart $chart) + protected function writeLegendStyle(Chart $chart): void { // style:style $this->xmlContent->startElement('style:style'); $this->xmlContent->writeAttribute('style:name', 'styleLegend'); $this->xmlContent->writeAttribute('style:family', 'chart'); + // style:chart-properties + $this->xmlContent->startElement('style:chart-properties'); + $this->xmlContent->writeAttribute('chart:auto-position', 'true'); + // > style:chart-properties + $this->xmlContent->endElement(); // style:text-properties $this->xmlContent->startElement('style:text-properties'); - $this->xmlContent->writeAttribute('fo:color', '#'.$chart->getLegend()->getFont()->getColor()->getRGB()); + $this->xmlContent->writeAttribute('fo:color', '#' . $chart->getLegend()->getFont()->getColor()->getRGB()); $this->xmlContent->writeAttribute('fo:font-family', $chart->getLegend()->getFont()->getName()); - $this->xmlContent->writeAttribute('fo:font-size', $chart->getLegend()->getFont()->getSize().'pt'); + $this->xmlContent->writeAttribute('fo:font-size', $chart->getLegend()->getFont()->getSize() . 'pt'); $this->xmlContent->writeAttribute('fo:font-style', $chart->getLegend()->getFont()->isItalic() ? 'italic' : 'normal'); // > style:text-properties $this->xmlContent->endElement(); @@ -467,10 +496,7 @@ private function writeLegendStyle(Chart $chart) $this->xmlContent->endElement(); } - /** - * @param Chart $chart - */ - private function writePlotArea(Chart $chart) + protected function writePlotArea(Chart $chart): void { $chartType = $chart->getPlotArea()->getType(); @@ -483,15 +509,15 @@ private function writePlotArea(Chart $chart) } if ($chartType instanceof Bar3D || $chartType instanceof Pie3D) { // dr3d:light - $arrayLight = array( - array('#808080', '(0 0 1)', 'false', 'true'), - array('#666666', '(0.2 0.4 1)', 'true', 'false'), - array('#808080', '(0 0 1)', 'false', 'false'), - array('#808080', '(0 0 1)', 'false', 'false'), - array('#808080', '(0 0 1)', 'false', 'false'), - array('#808080', '(0 0 1)', 'false', 'false'), - array('#808080', '(0 0 1)', 'false', 'false'), - ); + $arrayLight = [ + ['#808080', '(0 0 1)', 'false', 'true'], + ['#666666', '(0.2 0.4 1)', 'true', 'false'], + ['#808080', '(0 0 1)', 'false', 'false'], + ['#808080', '(0 0 1)', 'false', 'false'], + ['#808080', '(0 0 1)', 'false', 'false'], + ['#808080', '(0 0 1)', 'false', 'false'], + ['#808080', '(0 0 1)', 'false', 'false'], + ]; foreach ($arrayLight as $light) { $this->xmlContent->startElement('dr3d:light'); $this->xmlContent->writeAttribute('dr3d:diffuse-color', $light[0]); @@ -510,8 +536,8 @@ private function writePlotArea(Chart $chart) $this->numSeries = 0; foreach ($chartType->getSeries() as $series) { $this->writeSeries($chart, $series); - $this->rangeCol++; - $this->numSeries++; + ++$this->rangeCol; + ++$this->numSeries; } //**** Wall **** @@ -523,10 +549,9 @@ private function writePlotArea(Chart $chart) } /** - * @param Chart $chart - * @link : http://books.evc-cit.info/odbook/ch08.html#chart-plot-area-section + * @see : http://books.evc-cit.info/odbook/ch08.html#chart-plot-area-section */ - private function writePlotAreaStyle(Chart $chart) + protected function writePlotAreaStyle(Chart $chart): void { $chartType = $chart->getPlotArea()->getType(); @@ -542,20 +567,33 @@ private function writePlotAreaStyle(Chart $chart) } elseif ($chartType instanceof Pie3D) { $this->xmlContent->writeAttribute('chart:three-dimensional', 'true'); $this->xmlContent->writeAttribute('chart:right-angled-axes', 'true'); + } elseif ($chartType instanceof AbstractTypeLine) { + $this->xmlContent->writeAttributeIf($chartType->isSmooth(), 'chart:interpolation', 'cubic-spline'); + } + switch ($chart->getDisplayBlankAs()) { + case Chart::BLANKAS_ZERO: + $this->xmlContent->writeAttribute('chart:treat-empty-cells', 'use-zero'); + break; + case Chart::BLANKAS_GAP: + $this->xmlContent->writeAttribute('chart:treat-empty-cells', 'leave-gap'); + break; + case Chart::BLANKAS_SPAN: + $this->xmlContent->writeAttribute('chart:treat-empty-cells', 'ignore'); + break; } if ($chartType instanceof AbstractTypeBar) { $chartVertical = 'false'; - if ($chartType->getBarDirection() == AbstractTypeBar::DIRECTION_HORIZONTAL) { + if (AbstractTypeBar::DIRECTION_HORIZONTAL == $chartType->getBarDirection()) { $chartVertical = 'true'; } $this->xmlContent->writeAttribute('chart:vertical', $chartVertical); - if ($chartType->getBarGrouping() == Bar::GROUPING_CLUSTERED) { + if (Bar::GROUPING_CLUSTERED == $chartType->getBarGrouping()) { $this->xmlContent->writeAttribute('chart:stacked', 'false'); $this->xmlContent->writeAttribute('chart:overlap', '0'); - } elseif ($chartType->getBarGrouping() == Bar::GROUPING_STACKED) { + } elseif (Bar::GROUPING_STACKED == $chartType->getBarGrouping()) { $this->xmlContent->writeAttribute('chart:stacked', 'true'); $this->xmlContent->writeAttribute('chart:overlap', '100'); - } elseif ($chartType->getBarGrouping() == Bar::GROUPING_PERCENTSTACKED) { + } elseif (Bar::GROUPING_PERCENTSTACKED == $chartType->getBarGrouping()) { $this->xmlContent->writeAttribute('chart:stacked', 'true'); $this->xmlContent->writeAttribute('chart:overlap', '100'); $this->xmlContent->writeAttribute('chart:percentage', 'true'); @@ -563,7 +601,7 @@ private function writePlotAreaStyle(Chart $chart) } $labelFormat = 'value'; if ($chartType instanceof AbstractTypeBar) { - if ($chartType->getBarGrouping() == Bar::GROUPING_PERCENTSTACKED) { + if (Bar::GROUPING_PERCENTSTACKED == $chartType->getBarGrouping()) { $labelFormat = 'percentage'; } } @@ -575,59 +613,48 @@ private function writePlotAreaStyle(Chart $chart) $this->xmlContent->endElement(); } - /** - * @param Chart $chart - * @param Chart\Series $series - * @throws \Exception - */ - private function writeSeries(Chart $chart, Chart\Series $series) + protected function writeSeries(Chart $chart, Chart\Series $series): void { $chartType = $chart->getPlotArea()->getType(); $numRange = count($series->getValues()); // chart:series $this->xmlContent->startElement('chart:series'); - $this->xmlContent->writeAttribute('chart:values-cell-range-address', 'table-local.$'.$this->rangeCol.'$2:.$'.$this->rangeCol.'$'.($numRange+1)); - $this->xmlContent->writeAttribute('chart:label-cell-address', 'table-local.$'.$this->rangeCol.'$1'); - if ($chartType instanceof Area) { - $this->xmlContent->writeAttribute('chart:class', 'chart:area'); - } elseif ($chartType instanceof AbstractTypeBar) { - $this->xmlContent->writeAttribute('chart:class', 'chart:bar'); - } elseif ($chartType instanceof Line) { - $this->xmlContent->writeAttribute('chart:class', 'chart:line'); - } elseif ($chartType instanceof AbstractTypePie) { - $this->xmlContent->writeAttribute('chart:class', 'chart:circle'); - } elseif ($chartType instanceof Scatter) { - $this->xmlContent->writeAttribute('chart:class', 'chart:scatter'); - } - $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries'.$this->numSeries); - if ($chartType instanceof Area || $chartType instanceof AbstractTypeBar || $chartType instanceof Line || $chartType instanceof Scatter) { + $this->xmlContent->writeAttribute('chart:values-cell-range-address', 'table-local.$' . $this->rangeCol . '$2:.$' . $this->rangeCol . '$' . ($numRange + 1)); + $this->xmlContent->writeAttribute('chart:label-cell-address', 'table-local.$' . $this->rangeCol . '$1'); + $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries' . $this->numSeries); + if ($chartType instanceof Area + || $chartType instanceof AbstractTypeBar + || $chartType instanceof Line + || $chartType instanceof Radar + || $chartType instanceof Scatter + ) { $dataPointFills = $series->getDataPointFills(); $incRepeat = $numRange; if (!empty($dataPointFills)) { $inc = 0; - $incRepeat = 0; + $incRepeat = 1; $newFill = new Fill(); do { - if ($series->getDataPointFill($inc)->getHashCode() != $newFill->getHashCode()) { + if ($series->getDataPointFill($inc)->getHashCode() !== $newFill->getHashCode()) { // chart:data-point $this->xmlContent->startElement('chart:data-point'); $this->xmlContent->writeAttribute('chart:repeated', $incRepeat); // > chart:data-point $this->xmlContent->endElement(); - $incRepeat = 0; + $incRepeat = 1; // chart:data-point $this->xmlContent->startElement('chart:data-point'); - $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries'.$this->numSeries.'_'.$inc); + $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries' . $this->numSeries . '_' . $inc); // > chart:data-point $this->xmlContent->endElement(); } - $inc++; - $incRepeat++; + ++$inc; + ++$incRepeat; } while ($inc < $numRange); - $incRepeat--; + --$incRepeat; } // chart:data-point $this->xmlContent->startElement('chart:data-point'); @@ -636,10 +663,10 @@ private function writeSeries(Chart $chart, Chart\Series $series) $this->xmlContent->endElement(); } elseif ($chartType instanceof AbstractTypePie) { $count = count($series->getDataPointFills()); - for ($inc = 0; $inc < $count; $inc++) { + for ($inc = 0; $inc < $count; ++$inc) { // chart:data-point $this->xmlContent->startElement('chart:data-point'); - $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries'.$this->numSeries.'_'.$inc); + $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries' . $this->numSeries . '_' . $inc); // > chart:data-point $this->xmlContent->endElement(); } @@ -649,17 +676,13 @@ private function writeSeries(Chart $chart, Chart\Series $series) $this->xmlContent->endElement(); } - /** - * @param Chart $chart - * @param Chart\Series $series - */ - private function writeSeriesStyle(Chart $chart, Chart\Series $series) + protected function writeSeriesStyle(Chart $chart, Chart\Series $series): void { $chartType = $chart->getPlotArea()->getType(); // style:style $this->xmlContent->startElement('style:style'); - $this->xmlContent->writeAttribute('style:name', 'styleSeries'.$this->numSeries); + $this->xmlContent->writeAttribute('style:name', 'styleSeries' . $this->numSeries); $this->xmlContent->writeAttribute('style:family', 'chart'); // style:chart-properties $this->xmlContent->startElement('style:chart-properties'); @@ -683,15 +706,15 @@ private function writeSeriesStyle(Chart $chart, Chart\Series $series) } if ($chartType instanceof Line || $chartType instanceof Scatter) { $oMarker = $series->getMarker(); - /** + /* * @link : http://www.datypic.com/sc/odf/a-chart_symbol-type.html */ - $this->xmlContent->writeAttributeIf($oMarker->getSymbol() == Chart\Marker::SYMBOL_NONE, 'chart:symbol-type', 'none'); - /** + $this->xmlContent->writeAttributeIf(Chart\Marker::SYMBOL_NONE == $oMarker->getSymbol(), 'chart:symbol-type', 'none'); + /* * @link : http://www.datypic.com/sc/odf/a-chart_symbol-name.html */ - $this->xmlContent->writeAttributeIf($oMarker->getSymbol() != Chart\Marker::SYMBOL_NONE, 'chart:symbol-type', 'named-symbol'); - if ($oMarker->getSymbol() != Chart\Marker::SYMBOL_NONE) { + $this->xmlContent->writeAttributeIf(Chart\Marker::SYMBOL_NONE != $oMarker->getSymbol(), 'chart:symbol-type', 'named-symbol'); + if (Chart\Marker::SYMBOL_NONE != $oMarker->getSymbol()) { switch ($oMarker->getSymbol()) { case Chart\Marker::SYMBOL_DASH: $symbolName = 'horizontal-bar'; @@ -708,15 +731,28 @@ private function writeSeriesStyle(Chart $chart, Chart\Series $series) } $this->xmlContent->writeAttribute('chart:symbol-name', $symbolName); $symbolSize = number_format(CommonDrawing::pointsToCentimeters($oMarker->getSize()), 2, '.', ''); - $this->xmlContent->writeAttribute('chart:symbol-width', $symbolSize.'cm'); - $this->xmlContent->writeAttribute('chart:symbol-height', $symbolSize.'cm'); + $this->xmlContent->writeAttribute('chart:symbol-width', $symbolSize . 'cm'); + $this->xmlContent->writeAttribute('chart:symbol-height', $symbolSize . 'cm'); } } + + $separator = $series->getSeparator(); + if (!empty($separator)) { + // style:chart-properties/chart:label-separator + $this->xmlContent->startElement('chart:label-separator'); + if (PHP_EOL == $separator) { + $this->xmlContent->writeRaw(''); + } else { + $this->xmlContent->writeElement('text:p', $separator); + } + $this->xmlContent->endElement(); + } + // > style:chart-properties $this->xmlContent->endElement(); // style:graphic-properties $this->xmlContent->startElement('style:graphic-properties'); - if ($chartType instanceof Line || $chartType instanceof Scatter) { + if ($chartType instanceof Line || $chartType instanceof Radar || $chartType instanceof Scatter) { $outlineWidth = ''; $outlineColor = ''; @@ -734,22 +770,22 @@ private function writeSeriesStyle(Chart $chart, Chart\Series $series) if (empty($outlineColor)) { $outlineColor = '4a7ebb'; } - $this->xmlContent->writeAttribute('svg:stroke-width', $outlineWidth.'cm'); - $this->xmlContent->writeAttribute('svg:stroke-color', '#'.$outlineColor); + $this->xmlContent->writeAttribute('svg:stroke-width', $outlineWidth . 'cm'); + $this->xmlContent->writeAttribute('svg:stroke-color', '#' . $outlineColor); } else { $this->xmlContent->writeAttribute('draw:stroke', 'none'); if (!($chartType instanceof Area)) { $this->xmlContent->writeAttribute('draw:fill', $series->getFill()->getFillType()); } } - $this->xmlContent->writeAttribute('draw:fill-color', '#'.$series->getFill()->getStartColor()->getRGB()); + $this->xmlContent->writeAttribute('draw:fill-color', '#' . $series->getFill()->getStartColor()->getRGB()); // > style:graphic-properties $this->xmlContent->endElement(); // style:text-properties $this->xmlContent->startElement('style:text-properties'); - $this->xmlContent->writeAttribute('fo:color', '#'.$series->getFont()->getColor()->getRGB()); + $this->xmlContent->writeAttribute('fo:color', '#' . $series->getFont()->getColor()->getRGB()); $this->xmlContent->writeAttribute('fo:font-family', $series->getFont()->getName()); - $this->xmlContent->writeAttribute('fo:font-size', $series->getFont()->getSize().'pt'); + $this->xmlContent->writeAttribute('fo:font-size', $series->getFont()->getSize() . 'pt'); // > style:text-properties $this->xmlContent->endElement(); @@ -759,12 +795,12 @@ private function writeSeriesStyle(Chart $chart, Chart\Series $series) foreach ($series->getDataPointFills() as $idx => $oFill) { // style:style $this->xmlContent->startElement('style:style'); - $this->xmlContent->writeAttribute('style:name', 'styleSeries'.$this->numSeries.'_'.$idx); + $this->xmlContent->writeAttribute('style:name', 'styleSeries' . $this->numSeries . '_' . $idx); $this->xmlContent->writeAttribute('style:family', 'chart'); // style:graphic-properties $this->xmlContent->startElement('style:graphic-properties'); $this->xmlContent->writeAttribute('draw:fill', $oFill->getFillType()); - $this->xmlContent->writeAttribute('draw:fill-color', '#'.$oFill->getStartColor()->getRGB()); + $this->xmlContent->writeAttribute('draw:fill-color', '#' . $oFill->getStartColor()->getRGB()); // > style:graphic-properties $this->xmlContent->endElement(); // > style:style @@ -772,23 +808,12 @@ private function writeSeriesStyle(Chart $chart, Chart\Series $series) } } - /** - */ - private function writeTable() + protected function writeTable(): void { // table:table $this->xmlContent->startElement('table:table'); $this->xmlContent->writeAttribute('table:name', 'table-local'); - // table:table-header-columns - $this->xmlContent->startElement('table:table-header-columns'); - // table:table-column - $this->xmlContent->startElement('table:table-column'); - // > table:table-column - $this->xmlContent->endElement(); - // > table:table-header-columns - $this->xmlContent->endElement(); - // table:table-columns $this->xmlContent->startElement('table:table-columns'); // table:table-column @@ -802,11 +827,21 @@ private function writeTable() // > table:table-columns $this->xmlContent->endElement(); + // table:table-header-columns + $this->xmlContent->startElement('table:table-header-columns'); + // table:table-column + $this->xmlContent->writeElement('table:table-column'); + // > table:table-header-columns + $this->xmlContent->endElement(); + // table:table-header-rows $this->xmlContent->startElement('table:table-header-rows'); // table:table-row $this->xmlContent->startElement('table:table-row'); - if (!empty($this->arrayData)) { + if (empty($this->arrayData)) { + $this->xmlContent->startElement('table:table-cell'); + $this->xmlContent->endElement(); + } else { $rowFirst = reset($this->arrayData); foreach ($rowFirst as $key => $cell) { // table:table-cell @@ -832,62 +867,60 @@ private function writeTable() // table:table-rows $this->xmlContent->startElement('table:table-rows'); - - foreach ($this->arrayData as $row) { - // table:table-row + if (empty($this->arrayData)) { $this->xmlContent->startElement('table:table-row'); - foreach ($row as $cell) { - // table:table-cell - $this->xmlContent->startElement('table:table-cell'); - - $cellNumeric = is_numeric($cell); - $this->xmlContent->writeAttributeIf(!$cellNumeric, 'office:value-type', 'string'); - $this->xmlContent->writeAttributeIf($cellNumeric, 'office:value-type', 'float'); - $this->xmlContent->writeAttributeIf($cellNumeric, 'office:value', $cell); - // text:p - $this->xmlContent->startElement('text:p'); - $this->xmlContent->text($cell); - // > text:p - $this->xmlContent->endElement(); - // > table:table-cell + $this->xmlContent->startElement('table:table-cell'); + $this->xmlContent->endElement(); + $this->xmlContent->endElement(); + } else { + foreach ($this->arrayData as $row) { + // table:table-row + $this->xmlContent->startElement('table:table-row'); + foreach ($row as $cell) { + // table:table-cell + $this->xmlContent->startElement('table:table-cell'); + + $cellValueTypeFloat = is_null($cell) ? true : is_numeric($cell); + $this->xmlContent->writeAttributeIf(!$cellValueTypeFloat, 'office:value-type', 'string'); + $this->xmlContent->writeAttributeIf($cellValueTypeFloat, 'office:value-type', 'float'); + $this->xmlContent->writeAttributeIf($cellValueTypeFloat, 'office:value', is_null($cell) ? 'NaN' : $cell); + // text:p + $this->xmlContent->startElement('text:p'); + $this->xmlContent->text(is_null($cell) ? 'NaN' : $cell); + $this->xmlContent->endElement(); + // > table:table-cell + $this->xmlContent->endElement(); + } + // > table:table-row $this->xmlContent->endElement(); } - // > table:table-row - $this->xmlContent->endElement(); } - // > table:table-rows $this->xmlContent->endElement(); + // > table:table $this->xmlContent->endElement(); } - /** - * @param Title $oTitle - */ - private function writeTitle(Title $oTitle) + protected function writeTitle(Title $oTitle): void { if (!$oTitle->isVisible()) { return; } // chart:title $this->xmlContent->startElement('chart:title'); - $this->xmlContent->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters($oTitle->getOffsetX()), 3) . 'cm'); - $this->xmlContent->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters($oTitle->getOffsetY()), 3) . 'cm'); + $this->xmlContent->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $oTitle->getOffsetX()), 3) . 'cm'); + $this->xmlContent->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $oTitle->getOffsetY()), 3) . 'cm'); $this->xmlContent->writeAttribute('chart:style-name', 'styleTitle'); // > text:p $this->xmlContent->startElement('text:p'); $this->xmlContent->text($oTitle->getText()); - // > text:p $this->xmlContent->endElement(); // > chart:title $this->xmlContent->endElement(); } - /** - * @param Title $oTitle - */ - private function writeTitleStyle(Title $oTitle) + protected function writeTitleStyle(Title $oTitle): void { if (!$oTitle->isVisible()) { return; @@ -898,9 +931,9 @@ private function writeTitleStyle(Title $oTitle) $this->xmlContent->writeAttribute('style:family', 'chart'); // style:text-properties $this->xmlContent->startElement('style:text-properties'); - $this->xmlContent->writeAttribute('fo:color', '#'.$oTitle->getFont()->getColor()->getRGB()); + $this->xmlContent->writeAttribute('fo:color', '#' . $oTitle->getFont()->getColor()->getRGB()); $this->xmlContent->writeAttribute('fo:font-family', $oTitle->getFont()->getName()); - $this->xmlContent->writeAttribute('fo:font-size', $oTitle->getFont()->getSize().'pt'); + $this->xmlContent->writeAttribute('fo:font-size', $oTitle->getFont()->getSize() . 'pt'); $this->xmlContent->writeAttribute('fo:font-style', $oTitle->getFont()->isItalic() ? 'italic' : 'normal'); // > style:text-properties $this->xmlContent->endElement(); @@ -908,19 +941,15 @@ private function writeTitleStyle(Title $oTitle) $this->xmlContent->endElement(); } - private function writeWall() + protected function writeWall(): void { // chart:wall $this->xmlContent->startElement('chart:wall'); $this->xmlContent->writeAttribute('chart:style-name', 'styleWall'); - // > chart:wall $this->xmlContent->endElement(); } - /** - * @param Chart $chart - */ - private function writeWallStyle(Chart $chart) + protected function writeWallStyle(Chart $chart): void { $chartType = $chart->getPlotArea()->getType(); diff --git a/src/PhpPresentation/Writer/ODPresentation/Pictures.php b/src/PhpPresentation/Writer/ODPresentation/Pictures.php index 32ce96819d..ac8cfa9335 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Pictures.php +++ b/src/PhpPresentation/Writer/ODPresentation/Pictures.php @@ -1,4 +1,22 @@ getDrawingHashTable()->count(); ++$i) { $shape = $this->getDrawingHashTable()->getByIndex($i); if (!($shape instanceof Drawing\AbstractDrawingAdapter)) { @@ -28,10 +45,10 @@ public function render() // Add background image slide $oBkgImage = $oSlide->getBackground(); if ($oBkgImage instanceof Image) { - $this->getZip()->addFromString('Pictures/'.$oBkgImage->getIndexedFilename($keySlide), file_get_contents($oBkgImage->getPath())); + $this->getZip()->addFromString('Pictures/' . $oBkgImage->getIndexedFilename((string) $keySlide), file_get_contents($oBkgImage->getPath())); } } - + return $this->getZip(); } } diff --git a/src/PhpPresentation/Writer/ODPresentation/Styles.php b/src/PhpPresentation/Writer/ODPresentation/Styles.php index 7cbd0d4cdb..6bc8cbfb2a 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Styles.php +++ b/src/PhpPresentation/Writer/ODPresentation/Styles.php @@ -1,48 +1,64 @@ */ - protected $arrayGradient = array(); + protected $arrayGradient = []; /** - * Stores font styles draw:stroke-dash nodes + * Stores font styles draw:stroke-dash nodes. * - * @var array + * @var array */ - protected $arrayStrokeDash = array(); + protected $arrayStrokeDash = []; - /** - * @return ZipInterface - */ - public function render() + public function render(): ZipInterface { $this->getZip()->addFromString('styles.xml', $this->writePart()); + return $this->getZip(); } /** - * Write Meta file to XML format + * Write Meta file to XML format. * - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - protected function writePart() + protected function writePart(): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -133,8 +149,8 @@ protected function writePart() $objWriter->writeAttribute('fo:margin-bottom', '0cm'); $objWriter->writeAttribute('fo:margin-left', '0cm'); $objWriter->writeAttribute('fo:margin-right', '0cm'); - $objWriter->writeAttribute('fo:page-width', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::emuToPixels($this->getPresentation()->getLayout()->getCX())), 1) . 'cm'); - $objWriter->writeAttribute('fo:page-height', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::emuToPixels($this->getPresentation()->getLayout()->getCY())), 1) . 'cm'); + $objWriter->writeAttribute('fo:page-width', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::emuToPixels((int) $this->getPresentation()->getLayout()->getCX())), 1) . 'cm'); + $objWriter->writeAttribute('fo:page-height', Text::numberFormat(CommonDrawing::pixelsToCentimeters(CommonDrawing::emuToPixels((int) $this->getPresentation()->getLayout()->getCY())), 1) . 'cm'); $printOrientation = 'portrait'; if ($this->getPresentation()->getLayout()->getCX() > $this->getPresentation()->getLayout()->getCY()) { $printOrientation = 'landscape'; @@ -162,24 +178,21 @@ protected function writePart() } /** - * Write the default style information for a RichText shape - * - * @param XMLWriter $objWriter - * @param RichText $shape + * Write the default style information for a RichText shape. */ - protected function writeRichTextStyle(XMLWriter $objWriter, RichText $shape) + protected function writeRichTextStyle(XMLWriter $objWriter, RichText $shape): void { $oFill = $shape->getFill(); - if ($oFill->getFillType() == Fill::FILL_GRADIENT_LINEAR || $oFill->getFillType() == Fill::FILL_GRADIENT_PATH) { + if (Fill::FILL_GRADIENT_LINEAR == $oFill->getFillType() || Fill::FILL_GRADIENT_PATH == $oFill->getFillType()) { if (!in_array($oFill->getHashCode(), $this->arrayGradient)) { $this->writeGradientFill($objWriter, $oFill); } } $oBorder = $shape->getBorder(); - if ($oBorder->getDashStyle() != Border::DASH_SOLID) { + if (Border::DASH_SOLID != $oBorder->getDashStyle()) { if (!in_array($oBorder->getDashStyle(), $this->arrayStrokeDash)) { $objWriter->startElement('draw:stroke-dash'); - $objWriter->writeAttribute('draw:name', 'strokeDash_'.$oBorder->getDashStyle()); + $objWriter->writeAttribute('draw:name', 'strokeDash_' . $oBorder->getDashStyle()); $objWriter->writeAttribute('draw:style', 'rect'); switch ($oBorder->getDashStyle()) { case Border::DASH_DASH: @@ -250,16 +263,13 @@ protected function writeRichTextStyle(XMLWriter $objWriter, RichText $shape) } /** - * Write the default style information for a Table shape - * - * @param XMLWriter $objWriter - * @param Table $shape + * Write the default style information for a Table shape. */ - protected function writeTableStyle(XMLWriter $objWriter, Table $shape) + protected function writeTableStyle(XMLWriter $objWriter, Table $shape): void { foreach ($shape->getRows() as $row) { foreach ($row->getCells() as $cell) { - if ($cell->getFill()->getFillType() == Fill::FILL_GRADIENT_LINEAR) { + if (Fill::FILL_GRADIENT_LINEAR == $cell->getFill()->getFillType()) { if (!in_array($cell->getFill()->getHashCode(), $this->arrayGradient)) { $this->writeGradientFill($objWriter, $cell->getFill()); } @@ -269,12 +279,9 @@ protected function writeTableStyle(XMLWriter $objWriter, Table $shape) } /** - * Writes the style information for a group of shapes - * - * @param XMLWriter $objWriter - * @param Group $group + * Writes the style information for a group of shapes. */ - protected function writeGroupStyle(XMLWriter $objWriter, Group $group) + protected function writeGroupStyle(XMLWriter $objWriter, Group $group): void { $shapes = $group->getShapeCollection(); foreach ($shapes as $shape) { @@ -287,20 +294,18 @@ protected function writeGroupStyle(XMLWriter $objWriter, Group $group) } /** - * Write the gradient style - * @param XMLWriter $objWriter - * @param Fill $oFill + * Write the gradient style. */ - protected function writeGradientFill(XMLWriter $objWriter, Fill $oFill) + protected function writeGradientFill(XMLWriter $objWriter, Fill $oFill): void { $objWriter->startElement('draw:gradient'); - $objWriter->writeAttribute('draw:name', 'gradient_'.$oFill->getHashCode()); - $objWriter->writeAttribute('draw:display-name', 'gradient_'.$oFill->getHashCode()); + $objWriter->writeAttribute('draw:name', 'gradient_' . $oFill->getHashCode()); + $objWriter->writeAttribute('draw:display-name', 'gradient_' . $oFill->getHashCode()); $objWriter->writeAttribute('draw:style', 'linear'); $objWriter->writeAttribute('draw:start-intensity', '100%'); $objWriter->writeAttribute('draw:end-intensity', '100%'); - $objWriter->writeAttribute('draw:start-color', '#'.$oFill->getStartColor()->getRGB()); - $objWriter->writeAttribute('draw:end-color', '#'.$oFill->getEndColor()->getRGB()); + $objWriter->writeAttribute('draw:start-color', '#' . $oFill->getStartColor()->getRGB()); + $objWriter->writeAttribute('draw:end-color', '#' . $oFill->getEndColor()->getRGB()); $objWriter->writeAttribute('draw:border', '0%'); $objWriter->writeAttribute('draw:angle', $oFill->getRotation() - 90); $objWriter->endElement(); @@ -308,15 +313,13 @@ protected function writeGradientFill(XMLWriter $objWriter, Fill $oFill) } /** - * Write the background image style - * @param XMLWriter $objWriter - * @param Image $oBkgImage + * Write the background image style. */ - protected function writeBackgroundStyle(XMLWriter $objWriter, Image $oBkgImage, $numSlide) + protected function writeBackgroundStyle(XMLWriter $objWriter, Image $oBkgImage, int $numSlide): void { $objWriter->startElement('draw:fill-image'); - $objWriter->writeAttribute('draw:name', 'background_'.$numSlide); - $objWriter->writeAttribute('xlink:href', 'Pictures/'.str_replace(' ', '_', $oBkgImage->getIndexedFilename($numSlide))); + $objWriter->writeAttribute('draw:name', 'background_' . (string) $numSlide); + $objWriter->writeAttribute('xlink:href', 'Pictures/' . str_replace(' ', '_', $oBkgImage->getIndexedFilename((string) $numSlide))); $objWriter->writeAttribute('xlink:type', 'simple'); $objWriter->writeAttribute('xlink:show', 'embed'); $objWriter->writeAttribute('xlink:actuate', 'onLoad'); diff --git a/src/PhpPresentation/Writer/ODPresentation/ThumbnailsThumbnail.php b/src/PhpPresentation/Writer/ODPresentation/ThumbnailsThumbnail.php index c211761d79..1d754335f8 100644 --- a/src/PhpPresentation/Writer/ODPresentation/ThumbnailsThumbnail.php +++ b/src/PhpPresentation/Writer/ODPresentation/ThumbnailsThumbnail.php @@ -1,13 +1,30 @@ getPresentation()->getPresentationProperties()->getThumbnailPath(); if ($pathThumbnail) { @@ -36,6 +53,7 @@ public function render() $this->getZip()->addFromString('Thumbnails/thumbnail.png', $imageContents); } } + return $this->getZip(); } } diff --git a/src/PhpPresentation/Writer/PowerPoint2007.php b/src/PhpPresentation/Writer/PowerPoint2007.php index 65bbb39fd5..e98a61837b 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007.php +++ b/src/PhpPresentation/Writer/PowerPoint2007.php @@ -10,62 +10,59 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Writer; use DirectoryIterator; use PhpOffice\Common\Adapter\Zip\ZipArchiveAdapter; +use PhpOffice\PhpPresentation\Exception\DirectoryNotFoundException; +use PhpOffice\PhpPresentation\Exception\FileCopyException; +use PhpOffice\PhpPresentation\Exception\FileRemoveException; +use PhpOffice\PhpPresentation\Exception\InvalidParameterException; use PhpOffice\PhpPresentation\HashTable; use PhpOffice\PhpPresentation\PhpPresentation; -use PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\AbstractLayoutPack; -use PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\PackDefault; +use PhpOffice\PhpPresentation\Writer\PowerPoint2007\AbstractDecoratorWriter; +use ReflectionClass; /** - * \PhpOffice\PhpPresentation\Writer\PowerPoint2007 + * \PhpOffice\PhpPresentation\Writer\PowerPoint2007. */ class PowerPoint2007 extends AbstractWriter implements WriterInterface { /** * Use disk caching where possible? * - * @var boolean + * @var bool */ protected $useDiskCaching = false; /** - * Disk caching directory + * Disk caching directory. * * @var string */ protected $diskCachingDir; /** - * Layout pack to use - * @deprecated 0.7 - * @var \PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\AbstractLayoutPack - */ - protected $layoutPack; - - /** - * Create a new PowerPoint2007 file + * Create a new PowerPoint2007 file. * * @param PhpPresentation $pPhpPresentation */ public function __construct(PhpPresentation $pPhpPresentation = null) { // Assign PhpPresentation - $this->setPhpPresentation($pPhpPresentation); + $this->setPhpPresentation($pPhpPresentation ?? new PhpPresentation()); // Set up disk caching location $this->diskCachingDir = './'; - // Set layout pack - $this->layoutPack = new PackDefault(); - // Set HashTable variables $this->oDrawingHashTable = new HashTable(); @@ -73,23 +70,24 @@ public function __construct(PhpPresentation $pPhpPresentation = null) } /** - * Save PhpPresentation to file + * Save PhpPresentation to file. * - * @param string $pFilename - * @throws \Exception + * @throws FileCopyException + * @throws FileRemoveException + * @throws InvalidParameterException */ - public function save($pFilename) + public function save(string $pFilename): void { if (empty($pFilename)) { - throw new \Exception("Filename is empty"); + throw new InvalidParameterException('pFilename', ''); } $oPresentation = $this->getPhpPresentation(); // If $pFilename is php://output or php://stdout, make it a temporary file... $originalFilename = $pFilename; - if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { + if ('php://output' == strtolower($pFilename) || 'php://stdout' == strtolower($pFilename)) { $pFilename = @tempnam('./', 'phppttmp'); - if ($pFilename == '') { + if ('' == $pFilename) { $pFilename = $originalFilename; } } @@ -100,20 +98,20 @@ public function save($pFilename) $oZip = $this->getZipAdapter(); $oZip->open($pFilename); - $oDir = new DirectoryIterator(dirname(__FILE__).DIRECTORY_SEPARATOR.'PowerPoint2007'); - $arrayFiles = array(); + $oDir = new DirectoryIterator(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'PowerPoint2007'); + $arrayFiles = []; foreach ($oDir as $oFile) { if (!$oFile->isFile()) { continue; } $class = __NAMESPACE__ . '\\PowerPoint2007\\' . $oFile->getBasename('.php'); - $o = new \ReflectionClass($class); + $class = new ReflectionClass($class); - if ($o->isAbstract() || !$o->isSubclassOf('PhpOffice\PhpPresentation\Writer\PowerPoint2007\AbstractDecoratorWriter')) { + if ($class->isAbstract() || !$class->isSubclassOf(AbstractDecoratorWriter::class)) { continue; } - $arrayFiles[$oFile->getBasename('.php')] = $o; + $arrayFiles[$oFile->getBasename('.php')] = $class; } ksort($arrayFiles); @@ -132,11 +130,11 @@ public function save($pFilename) // If a temporary file was used, copy it to the correct file stream if ($originalFilename != $pFilename) { - if (copy($pFilename, $originalFilename) === false) { - throw new \Exception("Could not copy temporary zip file $pFilename to $originalFilename."); + if (false === copy($pFilename, $originalFilename)) { + throw new FileCopyException($pFilename, $originalFilename); } - if (@unlink($pFilename) === false) { - throw new \Exception('The file '.$pFilename.' could not be removed.'); + if (false === @unlink($pFilename)) { + throw new FileRemoveException($pFilename); } } } @@ -144,7 +142,7 @@ public function save($pFilename) /** * Get use disk caching where possible? * - * @return boolean + * @return bool */ public function hasDiskCaching() { @@ -154,27 +152,29 @@ public function hasDiskCaching() /** * Set use disk caching where possible? * - * @param boolean $pValue - * @param string $pDirectory Disk caching directory - * @throws \Exception + * @param bool $useDiskCaching + * @param string $directory Disk caching directory + * + * @throws DirectoryNotFoundException + * * @return \PhpOffice\PhpPresentation\Writer\PowerPoint2007 */ - public function setUseDiskCaching($pValue = false, $pDirectory = null) + public function setUseDiskCaching(bool $useDiskCaching = false, string $directory = null) { - $this->useDiskCaching = $pValue; + $this->useDiskCaching = $useDiskCaching; - if (!is_null($pDirectory)) { - if (!is_dir($pDirectory)) { - throw new \Exception("Directory does not exist: $pDirectory"); + if (!is_null($directory)) { + if (!is_dir($directory)) { + throw new DirectoryNotFoundException($directory); } - $this->diskCachingDir = $pDirectory; + $this->diskCachingDir = $directory; } return $this; } /** - * Get disk caching directory + * Get disk caching directory. * * @return string */ @@ -182,29 +182,4 @@ public function getDiskCachingDirectory() { return $this->diskCachingDir; } - - /** - * Get layout pack to use - * - * @deprecated 0.7 - * @return \PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\AbstractLayoutPack - */ - public function getLayoutPack() - { - return $this->layoutPack; - } - - /** - * Set layout pack to use - * - * @deprecated 0.7 - * @param \PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\AbstractLayoutPack $pValue - * @return \PhpOffice\PhpPresentation\Writer\PowerPoint2007 - */ - public function setLayoutPack(AbstractLayoutPack $pValue = null) - { - $this->layoutPack = $pValue; - - return $this; - } } diff --git a/src/PhpPresentation/Writer/PowerPoint2007/AbstractDecoratorWriter.php b/src/PhpPresentation/Writer/PowerPoint2007/AbstractDecoratorWriter.php index 2fd94c3ec4..672d828a2b 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/AbstractDecoratorWriter.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/AbstractDecoratorWriter.php @@ -1,4 +1,22 @@ startElement('Relationship'); - $objWriter->writeAttribute('Id', $pId); + $objWriter->writeAttribute('Id', 'rId' . (string) $pId); $objWriter->writeAttribute('Type', $pType); $objWriter->writeAttribute('Target', $pTarget); - if ($pTargetMode != '') { + if ('' != $pTargetMode) { $objWriter->writeAttribute('TargetMode', $pTargetMode); } @@ -44,26 +54,26 @@ protected function writeRelationship(XMLWriter $objWriter, $pId = 1, $pType = '' } /** - * Write Border + * Write Border. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Style\Border $pBorder Border - * @param string $pElementName Element name - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Border $pBorder Border + * @param string $pElementName Element name + * @param bool $isMarker */ - protected function writeBorder(XMLWriter $objWriter, $pBorder, $pElementName = 'L') + protected function writeBorder(XMLWriter $objWriter, Border $pBorder, string $pElementName = 'L', bool $isMarker = false): void { if (!($pBorder instanceof Border)) { return; } - if ($pBorder->getLineStyle() == Border::LINE_NONE && $pElementName == '') { + if (Border::LINE_NONE == $pBorder->getLineStyle() && '' == $pElementName && !$isMarker) { return; } // Line style $lineStyle = $pBorder->getLineStyle(); - if ($lineStyle == Border::LINE_NONE) { + if (Border::LINE_NONE == $lineStyle) { $lineStyle = Border::LINE_SINGLE; } @@ -78,7 +88,7 @@ protected function writeBorder(XMLWriter $objWriter, $pBorder, $pElementName = ' $objWriter->writeAttribute('algn', 'ctr'); // Fill? - if ($pBorder->getLineStyle() == Border::LINE_NONE) { + if (Border::LINE_NONE == $pBorder->getLineStyle()) { // a:noFill $objWriter->writeElement('a:noFill', null); } else { @@ -113,12 +123,7 @@ protected function writeBorder(XMLWriter $objWriter, $pBorder, $pElementName = ' $objWriter->endElement(); } - /** - * @param XMLWriter $objWriter - * @param Color $color - * @param int|null $alpha - */ - protected function writeColor(XMLWriter $objWriter, Color $color, $alpha = null) + protected function writeColor(XMLWriter $objWriter, Color $color, ?int $alpha = null): void { if (is_null($alpha)) { $alpha = $color->getAlpha(); @@ -130,55 +135,56 @@ protected function writeColor(XMLWriter $objWriter, Color $color, $alpha = null) // a:alpha $objWriter->startElement('a:alpha'); - $objWriter->writeAttribute('val', $alpha . '%'); + $objWriter->writeAttribute('val', $alpha * 1000); $objWriter->endElement(); $objWriter->endElement(); } /** - * Write Fill + * Write Fill. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Style\Fill $pFill Fill style - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Fill|null $pFill Fill style */ - protected function writeFill(XMLWriter $objWriter, $pFill) + protected function writeFill(XMLWriter $objWriter, ?Fill $pFill): void { - if (! $pFill instanceof Fill) { + if (!$pFill) { return; } // Is it a fill? - if ($pFill->getFillType() == Fill::FILL_NONE) { + if (Fill::FILL_NONE == $pFill->getFillType()) { $objWriter->writeElement('a:noFill'); + return; } // Is it a solid fill? - if ($pFill->getFillType() == Fill::FILL_SOLID) { + if (Fill::FILL_SOLID == $pFill->getFillType()) { $this->writeSolidFill($objWriter, $pFill); + return; } - // Check if this is a pattern type or gradient type - if ($pFill->getFillType() == Fill::FILL_GRADIENT_LINEAR || $pFill->getFillType() == Fill::FILL_GRADIENT_PATH) { - // Gradient fill + // Is it a gradient fill? + if (Fill::FILL_GRADIENT_LINEAR == $pFill->getFillType() || Fill::FILL_GRADIENT_PATH == $pFill->getFillType()) { $this->writeGradientFill($objWriter, $pFill); - } else { - // Pattern fill - $this->writePatternFill($objWriter, $pFill); + + return; } + + // Is it a pattern fill? + $this->writePatternFill($objWriter, $pFill); } /** - * Write Solid Fill + * Write Solid Fill. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Style\Fill $pFill Fill style - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Fill $pFill Fill style */ - protected function writeSolidFill(XMLWriter $objWriter, Fill $pFill) + protected function writeSolidFill(XMLWriter $objWriter, Fill $pFill): void { // a:gradFill $objWriter->startElement('a:solidFill'); @@ -187,13 +193,12 @@ protected function writeSolidFill(XMLWriter $objWriter, Fill $pFill) } /** - * Write Gradient Fill + * Write Gradient Fill. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Style\Fill $pFill Fill style - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Fill $pFill Fill style */ - protected function writeGradientFill(XMLWriter $objWriter, Fill $pFill) + protected function writeGradientFill(XMLWriter $objWriter, Fill $pFill): void { // a:gradFill $objWriter->startElement('a:gradFill'); @@ -202,13 +207,13 @@ protected function writeGradientFill(XMLWriter $objWriter, Fill $pFill) $objWriter->startElement('a:gsLst'); // a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '0%'); + $objWriter->writeAttribute('pos', '0'); $this->writeColor($objWriter, $pFill->getStartColor()); $objWriter->endElement(); // a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '100%'); + $objWriter->writeAttribute('pos', '100000'); $this->writeColor($objWriter, $pFill->getEndColor()); $objWriter->endElement(); @@ -216,7 +221,7 @@ protected function writeGradientFill(XMLWriter $objWriter, Fill $pFill) // a:lin $objWriter->startElement('a:lin'); - $objWriter->writeAttribute('ang', CommonDrawing::degreesToAngle($pFill->getRotation())); + $objWriter->writeAttribute('ang', CommonDrawing::degreesToAngle((int) $pFill->getRotation())); $objWriter->writeAttribute('scaled', '0'); $objWriter->endElement(); @@ -224,13 +229,12 @@ protected function writeGradientFill(XMLWriter $objWriter, Fill $pFill) } /** - * Write Pattern Fill + * Write Pattern Fill. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Style\Fill $pFill Fill style - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Fill $pFill Fill style */ - protected function writePatternFill(XMLWriter $objWriter, Fill $pFill) + protected function writePatternFill(XMLWriter $objWriter, Fill $pFill): void { // a:pattFill $objWriter->startElement('a:pattFill'); @@ -254,20 +258,15 @@ protected function writePatternFill(XMLWriter $objWriter, Fill $pFill) /** * Write Outline - * @param XMLWriter $objWriter - * @param Outline $oOutline */ - protected function writeOutline(XMLWriter $objWriter, $oOutline) + protected function writeOutline(XMLWriter $objWriter, ?Outline $oOutline): void { - if (!$oOutline instanceof Outline) { + if (!$oOutline) { return; } // Width : pts - $width = $oOutline->getWidth(); - // Width : pts => px - $width = CommonDrawing::pointsToPixels($width); - // Width : px => emu - $width = CommonDrawing::pixelsToEmu($width); + $width = $oOutline->getWidth() ?? 0; + $width = CommonDrawing::pointsToEmu($width); // a:ln $objWriter->startElement('a:ln'); @@ -281,19 +280,18 @@ protected function writeOutline(XMLWriter $objWriter, $oOutline) } /** - * Determine absolute zip path - * - * @param string $path - * @return string + * Determine absolute zip path. */ - protected function absoluteZipPath($path) + protected function absoluteZipPath(string $path): string { - $path = str_replace(array( + $path = str_replace([ '/', - '\\' - ), DIRECTORY_SEPARATOR, $path); - $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); - $absolutes = array(); + '\\', + ], DIRECTORY_SEPARATOR, $path); + $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), function (string $var) { + return (bool) strlen($var); + }); + $absolutes = []; foreach ($parts as $part) { if ('.' == $part) { continue; diff --git a/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php b/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php index 483c23aa80..d7f533108f 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php @@ -10,47 +10,54 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ + +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007; +use ArrayObject; use PhpOffice\Common\Drawing as CommonDrawing; use PhpOffice\Common\Text; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpPresentation\AbstractShape; +use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException; use PhpOffice\PhpPresentation\Shape\AbstractGraphic; +use PhpOffice\PhpPresentation\Shape\AutoShape; use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart; use PhpOffice\PhpPresentation\Shape\Comment; -use PhpOffice\PhpPresentation\Shape\Drawing\Gd as ShapeDrawingGd; +use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter; use PhpOffice\PhpPresentation\Shape\Drawing\File as ShapeDrawingFile; +use PhpOffice\PhpPresentation\Shape\Drawing\Gd as ShapeDrawingGd; use PhpOffice\PhpPresentation\Shape\Group; use PhpOffice\PhpPresentation\Shape\Line; use PhpOffice\PhpPresentation\Shape\Media; use PhpOffice\PhpPresentation\Shape\Placeholder; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\BreakElement; +use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Shape\RichText\Run; use PhpOffice\PhpPresentation\Shape\RichText\TextElement; use PhpOffice\PhpPresentation\Shape\Table as ShapeTable; use PhpOffice\PhpPresentation\Slide; +use PhpOffice\PhpPresentation\Slide\AbstractSlide as AbstractSlideAlias; use PhpOffice\PhpPresentation\Slide\Note; use PhpOffice\PhpPresentation\Style\Alignment; -use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Border; +use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Shadow; -use PhpOffice\PhpPresentation\Slide\AbstractSlide as AbstractSlideAlias; abstract class AbstractSlide extends AbstractDecoratorWriter { /** - * @param AbstractSlideAlias $pSlideMaster - * @param $objWriter - * @param $relId - * @throws \Exception + * @return mixed */ - protected function writeDrawingRelations(AbstractSlideAlias $pSlideMaster, $objWriter, $relId) + protected function writeDrawingRelations(AbstractSlideAlias $pSlideMaster, XMLWriter $objWriter, int $relId) { if ($pSlideMaster->getShapeCollection()->count() > 0) { // Loop trough images and write relationships @@ -113,14 +120,14 @@ protected function writeDrawingRelations(AbstractSlideAlias $pSlideMaster, $objW } /** - * @param XMLWriter $objWriter - * @param \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] $shapes + * @param array|ArrayObject $shapes * @param int $shapeId - * @throws \Exception + * + * @throws UndefinedChartTypeException */ - protected function writeShapeCollection(XMLWriter $objWriter, $shapes = array(), &$shapeId = 0) + protected function writeShapeCollection(XMLWriter $objWriter, $shapes = [], &$shapeId = 0): void { - if (count($shapes) == 0) { + if (0 == count($shapes)) { return; } foreach ($shapes as $shape) { @@ -137,24 +144,25 @@ protected function writeShapeCollection(XMLWriter $objWriter, $shapes = array(), $this->writeShapeChart($objWriter, $shape, $shapeId); } elseif ($shape instanceof AbstractGraphic) { $this->writeShapePic($objWriter, $shape, $shapeId); + } elseif ($shape instanceof AutoShape) { + $this->writeShapeAutoShape($objWriter, $shape, $shapeId); } elseif ($shape instanceof Group) { $this->writeShapeGroup($objWriter, $shape, $shapeId); } elseif ($shape instanceof Comment) { } else { - throw new \Exception("Unknown Shape type: {get_class($shape)}"); + throw new UndefinedChartTypeException(); } } } /** - * Write txt + * Write txt. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\RichText $shape - * @param int $shapeId - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param RichText $shape + * @param int $shapeId */ - protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeId) + protected function writeShapeText(XMLWriter $objWriter, RichText $shape, int $shapeId): void { // p:sp $objWriter->startElement('p:sp'); @@ -199,7 +207,7 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeI if (!$shape->isPlaceholder()) { // p:sp\p:spPr\a:xfrm $objWriter->startElement('a:xfrm'); - $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation())); + $objWriter->writeAttributeIf(0 != $shape->getRotation(), 'rot', CommonDrawing::degreesToAngle((int) $shape->getRotation())); // p:sp\p:spPr\a:xfrm\a:off $objWriter->startElement('a:off'); $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX())); @@ -234,17 +242,17 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeI $objWriter->startElement('a:bodyPr'); if (!$shape->isPlaceholder()) { $verticalAlign = $shape->getActiveParagraph()->getAlignment()->getVertical(); - if ($verticalAlign != Alignment::VERTICAL_BASE && $verticalAlign != Alignment::VERTICAL_AUTO) { + if (Alignment::VERTICAL_BASE != $verticalAlign && Alignment::VERTICAL_AUTO != $verticalAlign) { $objWriter->writeAttribute('anchor', $verticalAlign); } - if ($shape->getWrap() != RichText::WRAP_SQUARE) { + if (RichText::WRAP_SQUARE != $shape->getWrap()) { $objWriter->writeAttribute('wrap', $shape->getWrap()); } $objWriter->writeAttribute('rtlCol', '0'); - if ($shape->getHorizontalOverflow() != RichText::OVERFLOW_OVERFLOW) { + if (RichText::OVERFLOW_OVERFLOW != $shape->getHorizontalOverflow()) { $objWriter->writeAttribute('horzOverflow', $shape->getHorizontalOverflow()); } - if ($shape->getVerticalOverflow() != RichText::OVERFLOW_OVERFLOW) { + if (RichText::OVERFLOW_OVERFLOW != $shape->getVerticalOverflow()) { $objWriter->writeAttribute('vertOverflow', $shape->getVerticalOverflow()); } if ($shape->isUpright()) { @@ -257,17 +265,18 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeI $objWriter->writeAttribute('lIns', CommonDrawing::pixelsToEmu($shape->getInsetLeft())); $objWriter->writeAttribute('rIns', CommonDrawing::pixelsToEmu($shape->getInsetRight())); $objWriter->writeAttribute('tIns', CommonDrawing::pixelsToEmu($shape->getInsetTop())); - if ($shape->getColumns() <> 1) { + if (1 != $shape->getColumns()) { $objWriter->writeAttribute('numCol', $shape->getColumns()); + $objWriter->writeAttribute('spcCol', CommonDrawing::pixelsToEmu($shape->getColumnSpacing())); } // a:spAutoFit $objWriter->startElement('a:' . $shape->getAutoFit()); - if ($shape->getAutoFit() == RichText::AUTOFIT_NORMAL) { + if (RichText::AUTOFIT_NORMAL == $shape->getAutoFit()) { if (!is_null($shape->getFontScale())) { - $objWriter->writeAttribute('fontScale', (int)($shape->getFontScale() * 1000)); + $objWriter->writeAttribute('fontScale', $shape->getFontScale() * 1000); } if (!is_null($shape->getLineSpaceReduction())) { - $objWriter->writeAttribute('lnSpcReduction', (int)($shape->getLineSpaceReduction() * 1000)); + $objWriter->writeAttribute('lnSpcReduction', $shape->getLineSpaceReduction() * 1000); } } $objWriter->endElement(); @@ -276,16 +285,18 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeI // a:lstStyle $objWriter->writeElement('a:lstStyle', null); if ($shape->isPlaceholder() && - ($shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_SLIDENUM || - $shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_DATETIME) + (Placeholder::PH_TYPE_SLIDENUM == $shape->getPlaceholder()->getType() || + Placeholder::PH_TYPE_DATETIME == $shape->getPlaceholder()->getType()) ) { $objWriter->startElement('a:p'); $objWriter->startElement('a:fld'); $objWriter->writeAttribute('id', $this->getGUID()); $objWriter->writeAttribute('type', ( - $shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_SLIDENUM ? 'slidenum' : 'datetime')); + Placeholder::PH_TYPE_SLIDENUM == $shape->getPlaceholder()->getType() ? 'slidenum' : 'datetime' + )); $objWriter->writeElement('a:t', ( - $shape->getPlaceholder()->getType() == Placeholder::PH_TYPE_SLIDENUM ? '' : '03-04-05')); + Placeholder::PH_TYPE_SLIDENUM == $shape->getPlaceholder()->getType() ? '' : '03-04-05' + )); $objWriter->endElement(); $objWriter->endElement(); } else { @@ -297,14 +308,13 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, $shapeI } /** - * Write table + * Write table. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Table $shape - * @param int $shapeId - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param ShapeTable $shape + * @param int $shapeId */ - protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $shapeId) + protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, int $shapeId): void { // p:graphicFrame $objWriter->startElement('p:graphicFrame'); @@ -364,12 +374,12 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha $objWriter->startElement('a:tblGrid'); // Write cell widths $countCells = count($shape->getRow(0)->getCells()); - for ($cell = 0; $cell < $countCells; $cell++) { + for ($cell = 0; $cell < $countCells; ++$cell) { // p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tblGrid/a:gridCol $objWriter->startElement('a:gridCol'); // Calculate column width $width = $shape->getRow(0)->getCell($cell)->getWidth(); - if ($width == 0) { + if (0 == $width) { $colCount = count($shape->getRow(0)->getCells()); $totalWidth = $shape->getWidth(); $width = $totalWidth / $colCount; @@ -380,29 +390,24 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha // p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tblGrid/ $objWriter->endElement(); // Colspan / rowspan containers - $colSpan = array(); - $rowSpan = array(); + $colSpan = $rowSpan = []; // Default border style $defaultBorder = new Border(); // Write rows $countRows = count($shape->getRows()); - for ($row = 0; $row < $countRows; $row++) { + for ($row = 0; $row < $countRows; ++$row) { // p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr $objWriter->startElement('a:tr'); $objWriter->writeAttribute('h', CommonDrawing::pixelsToEmu($shape->getRow($row)->getHeight())); // Write cells $countCells = count($shape->getRow($row)->getCells()); - for ($cell = 0; $cell < $countCells; $cell++) { + for ($cell = 0; $cell < $countCells; ++$cell) { // Current cell $currentCell = $shape->getRow($row)->getCell($cell); // Next cell right - $nextCellRight = $shape->getRow($row)->getCell($cell + 1, true); + $hasNextCellRight = $shape->getRow($row)->hasCell($cell + 1); // Next cell below - $nextRowBelow = $shape->getRow($row + 1, true); - $nextCellBelow = null; - if ($nextRowBelow != null) { - $nextCellBelow = $nextRowBelow->getCell($cell, true); - } + $hasNextRowBelow = $shape->hasRow($row + 1); // a:tc $objWriter->startElement('a:tc'); // Colspan @@ -410,7 +415,7 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha $objWriter->writeAttribute('gridSpan', $currentCell->getColSpan()); $colSpan[$row] = $currentCell->getColSpan() - 1; } elseif (isset($colSpan[$row]) && $colSpan[$row] > 0) { - $colSpan[$row]--; + --$colSpan[$row]; $objWriter->writeAttribute('hMerge', '1'); } // Rowspan @@ -418,7 +423,7 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha $objWriter->writeAttribute('rowSpan', $currentCell->getRowSpan()); $rowSpan[$cell] = $currentCell->getRowSpan() - 1; } elseif (isset($rowSpan[$cell]) && $rowSpan[$cell] > 0) { - $rowSpan[$cell]--; + --$rowSpan[$cell]; $objWriter->writeAttribute('vMerge', '1'); } // a:txBody @@ -443,12 +448,12 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha // Text Direction $textDirection = $firstParagraphAlignment->getTextDirection(); - if ($textDirection != Alignment::TEXT_DIRECTION_HORIZONTAL) { + if (Alignment::TEXT_DIRECTION_HORIZONTAL != $textDirection) { $objWriter->writeAttribute('vert', $textDirection); } // Alignment (horizontal) $verticalAlign = $firstParagraphAlignment->getVertical(); - if ($verticalAlign != Alignment::VERTICAL_BASE && $verticalAlign != Alignment::VERTICAL_AUTO) { + if (Alignment::VERTICAL_BASE != $verticalAlign && Alignment::VERTICAL_AUTO != $verticalAlign) { $objWriter->writeAttribute('anchor', $verticalAlign); } @@ -466,15 +471,18 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha $borderDiagonalDown = $currentCell->getBorders()->getDiagonalDown(); $borderDiagonalUp = $currentCell->getBorders()->getDiagonalUp(); // Fix PowerPoint implementation - if (!is_null($nextCellRight) - && $nextCellRight->getBorders()->getRight()->getHashCode() != $defaultBorder->getHashCode() - ) { - $borderRight = $nextCellRight->getBorders()->getLeft(); + if ($hasNextCellRight) { + $nextCellRight = $shape->getRow($row)->getCell($cell + 1); + if ($nextCellRight->getBorders()->getRight()->getHashCode() != $defaultBorder->getHashCode()) { + $borderRight = $nextCellRight->getBorders()->getLeft(); + } } - if (!is_null($nextCellBelow) - && $nextCellBelow->getBorders()->getBottom()->getHashCode() != $defaultBorder->getHashCode() - ) { - $borderBottom = $nextCellBelow->getBorders()->getTop(); + if ($hasNextRowBelow) { + $nextRowBelow = $shape->getRow($row + 1); + $nextCellBelow = $nextRowBelow->getCell($cell); + if ($nextCellBelow->getBorders()->getBottom()->getHashCode() != $defaultBorder->getHashCode()) { + $borderBottom = $nextCellBelow->getBorders()->getTop(); + } } // Write borders $this->writeBorder($objWriter, $borderLeft, 'L'); @@ -497,14 +505,12 @@ protected function writeShapeTable(XMLWriter $objWriter, ShapeTable $shape, $sha } /** - * Write paragraphs + * Write paragraphs. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] $paragraphs - * @param bool $bIsPlaceholder - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param array $paragraphs */ - protected function writeParagraphs(XMLWriter $objWriter, $paragraphs, $bIsPlaceholder = false) + protected function writeParagraphs(XMLWriter $objWriter, array $paragraphs, bool $bIsPlaceholder = false): void { // Loop trough paragraphs foreach ($paragraphs as $paragraph) { @@ -513,22 +519,44 @@ protected function writeParagraphs(XMLWriter $objWriter, $paragraphs, $bIsPlaceh // a:pPr if (!$bIsPlaceholder) { + // a:pPr $objWriter->startElement('a:pPr'); $objWriter->writeAttribute('algn', $paragraph->getAlignment()->getHorizontal()); + $objWriter->writeAttribute('rtl', $paragraph->getAlignment()->isRTL() ? '1' : '0'); $objWriter->writeAttribute('fontAlgn', $paragraph->getAlignment()->getVertical()); $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($paragraph->getAlignment()->getMarginLeft())); $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($paragraph->getAlignment()->getMarginRight())); $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($paragraph->getAlignment()->getIndent())); $objWriter->writeAttribute('lvl', $paragraph->getAlignment()->getLevel()); + // a:pPr:a:lnSpc $objWriter->startElement('a:lnSpc'); - $objWriter->startElement('a:spcPct'); - $objWriter->writeAttribute('val', $paragraph->getLineSpacing() . "%"); + if ($paragraph->getLineSpacingMode() == Paragraph::LINE_SPACING_MODE_POINT) { + $objWriter->startElement('a:spcPts'); + $objWriter->writeAttribute('val', $paragraph->getLineSpacing() * 100); + $objWriter->endElement(); + } else { + $objWriter->startElement('a:spcPct'); + $objWriter->writeAttribute('val', $paragraph->getLineSpacing() * 1000); + $objWriter->endElement(); + } + // >a:pPr:a:lnSpc + $objWriter->endElement(); + + $objWriter->startElement('a:spcBef'); + $objWriter->startElement('a:spcPts'); + $objWriter->writeAttribute('val', $paragraph->getSpacingBefore() * 100); + $objWriter->endElement(); + $objWriter->endElement(); + + $objWriter->startElement('a:spcAft'); + $objWriter->startElement('a:spcPts'); + $objWriter->writeAttribute('val', $paragraph->getSpacingAfter() * 100); $objWriter->endElement(); $objWriter->endElement(); // Bullet type specified? - if ($paragraph->getBulletStyle()->getBulletType() != Bullet::TYPE_NONE) { + if (Bullet::TYPE_NONE != $paragraph->getBulletStyle()->getBulletType()) { // Color // a:buClr must be before a:buFont (else PowerPoint crashes at launch) if ($paragraph->getBulletStyle()->getBulletColor() instanceof Color) { @@ -542,16 +570,16 @@ protected function writeParagraphs(XMLWriter $objWriter, $paragraphs, $bIsPlaceh $objWriter->writeAttribute('typeface', $paragraph->getBulletStyle()->getBulletFont()); $objWriter->endElement(); - if ($paragraph->getBulletStyle()->getBulletType() == Bullet::TYPE_BULLET) { + if (Bullet::TYPE_BULLET == $paragraph->getBulletStyle()->getBulletType()) { // a:buChar $objWriter->startElement('a:buChar'); $objWriter->writeAttribute('char', $paragraph->getBulletStyle()->getBulletChar()); $objWriter->endElement(); - } elseif ($paragraph->getBulletStyle()->getBulletType() == Bullet::TYPE_NUMERIC) { + } elseif (Bullet::TYPE_NUMERIC == $paragraph->getBulletStyle()->getBulletType()) { // a:buAutoNum $objWriter->startElement('a:buAutoNum'); $objWriter->writeAttribute('type', $paragraph->getBulletStyle()->getBulletNumericStyle()); - if ($paragraph->getBulletStyle()->getBulletNumericStartAt() != 1) { + if (1 != $paragraph->getBulletStyle()->getBulletNumericStartAt()) { $objWriter->writeAttribute('startAt', $paragraph->getBulletStyle()->getBulletNumericStartAt()); } $objWriter->endElement(); @@ -578,31 +606,25 @@ protected function writeParagraphs(XMLWriter $objWriter, $paragraphs, $bIsPlaceh // Lang $objWriter->writeAttribute('lang', ($element->getLanguage() ? $element->getLanguage() : 'en-US')); - $objWriter->writeAttributeIf($element->getFont()->isBold(), 'b', '1'); $objWriter->writeAttributeIf($element->getFont()->isItalic(), 'i', '1'); $objWriter->writeAttributeIf($element->getFont()->isStrikethrough(), 'strike', 'sngStrike'); - - // Size $objWriter->writeAttribute('sz', ($element->getFont()->getSize() * 100)); - - // Character spacing $objWriter->writeAttribute('spc', $element->getFont()->getCharacterSpacing()); - - // Underline $objWriter->writeAttribute('u', $element->getFont()->getUnderline()); - - // Superscript / subscript - $objWriter->writeAttributeIf($element->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($element->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($element->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($element->getFont()->isSubScript(), 'baseline', '-250000'); // Color - a:solidFill $objWriter->startElement('a:solidFill'); $this->writeColor($objWriter, $element->getFont()->getColor()); $objWriter->endElement(); - // Font - a:latin - $objWriter->startElement('a:latin'); + // Font + // - a:latin + // - a:ea + // - a:cs + $objWriter->startElement('a:' . $element->getFont()->getFormat()); $objWriter->writeAttribute('typeface', $element->getFont()->getName()); $objWriter->endElement(); @@ -626,13 +648,11 @@ protected function writeParagraphs(XMLWriter $objWriter, $paragraphs, $bIsPlaceh } /** - * Write Line Shape + * Write Line Shape. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Line $shape - * @param int $shapeId + * @param XMLWriter $objWriter XML Writer */ - protected function writeShapeLine(XMLWriter $objWriter, Line $shape, $shapeId) + protected function writeShapeLine(XMLWriter $objWriter, Line $shape, int $shapeId): void { // p:sp $objWriter->startElement('p:cxnSp'); @@ -720,11 +740,9 @@ protected function writeShapeLine(XMLWriter $objWriter, Line $shape, $shapeId) } /** - * Write Shadow - * @param XMLWriter $objWriter - * @param Shadow $oShadow + * Write Shadow. */ - protected function writeShadow(XMLWriter $objWriter, $oShadow) + protected function writeShadow(XMLWriter $objWriter, Shadow $oShadow): void { if (!($oShadow instanceof Shadow)) { return; @@ -741,7 +759,7 @@ protected function writeShadow(XMLWriter $objWriter, $oShadow) $objWriter->startElement('a:outerShdw'); $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($oShadow->getBlurRadius())); $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($oShadow->getDistance())); - $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle($oShadow->getDirection())); + $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $oShadow->getDirection())); $objWriter->writeAttribute('algn', $oShadow->getAlignment()); $objWriter->writeAttribute('rotWithShape', '0'); @@ -753,12 +771,12 @@ protected function writeShadow(XMLWriter $objWriter, $oShadow) } /** - * Write hyperlink + * Write hyperlink. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\AbstractShape|\PhpOffice\PhpPresentation\Shape\RichText\TextElement $shape + * @param XMLWriter $objWriter XML Writer + * @param AbstractShape|TextElement $shape */ - protected function writeHyperlink(XMLWriter $objWriter, $shape) + protected function writeHyperlink(XMLWriter $objWriter, $shape): void { if (!$shape->hasHyperlink()) { return; @@ -774,12 +792,9 @@ protected function writeHyperlink(XMLWriter $objWriter, $shape) } /** - * Write Note Slide - * @param Note $pNote - * @throws \Exception - * @return string + * Write Note Slide. */ - protected function writeNote(Note $pNote) + protected function writeNote(Note $pNote): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -1060,14 +1075,109 @@ protected function writeNote(Note $pNote) return $objWriter->getData(); } + /** + * Write AutoShape + * + * @param XMLWriter $objWriter XML Writer + * @param AutoShape $shape + * @param int $shapeId + */ + protected function writeShapeAutoShape(XMLWriter $objWriter, AutoShape $shape, int $shapeId): void + { + // p:sp + $objWriter->startElement('p:sp'); + + // p:sp\p:nvSpPr + $objWriter->startElement('p:nvSpPr'); + // p:sp\p:nvSpPr\p:cNvPr + $objWriter->startElement('p:cNvPr'); + $objWriter->writeAttribute('id', $shapeId); + $objWriter->writeAttribute('name', ''); + $objWriter->writeAttribute('descr', ''); + // p:sp\p:nvSpPr\p:cNvPr\ + $objWriter->endElement(); + // p:sp\p:nvSpPr\p:cNvSpPr + $objWriter->writeElement('p:cNvSpPr'); + // p:sp\p:nvSpPr\p:nvPr + $objWriter->writeElement('p:nvPr'); + // p:sp\p:nvSpPr\ + $objWriter->endElement(); + + // p:sp\p:spPr + $objWriter->startElement('p:spPr'); + + // p:sp\p:spPr\a:xfrm + $objWriter->startElement('a:xfrm'); + $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $shape->getRotation())); + // p:sp\p:spPr\a:xfrm\a:off + $objWriter->startElement('a:off'); + $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX())); + $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY())); + $objWriter->endElement(); + // p:sp\p:spPr\a:xfrm\a:ext + $objWriter->startElement('a:ext'); + $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth())); + $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight())); + $objWriter->endElement(); + // p:sp\p:spPr\a:xfrm\ + $objWriter->endElement(); + + // p:sp\p:spPr\a:prstGeom + $objWriter->startElement('a:prstGeom'); + $objWriter->writeAttribute('prst', $shape->getType()); + // p:sp\p:spPr\a:prstGeom\a:avLst + $objWriter->writeElement('a:avLst'); + // p:sp\p:spPr\a:prstGeom\ + $objWriter->endElement(); + // Fill + $this->writeFill($objWriter, $shape->getFill()); + // Outline + $this->writeOutline($objWriter, $shape->getOutline()); + + // p:sp\p:spPr\ + $objWriter->endElement(); + // p:sp\p:txBody + $objWriter->startElement('p:txBody'); + // p:sp\p:txBody\a:bodyPr + $objWriter->startElement('a:bodyPr'); + $objWriter->writeAttribute('vertOverflow', 'clip'); + $objWriter->writeAttribute('rtlCol', '0'); + $objWriter->writeAttribute('anchor', 'ctr'); + // p:sp\p:txBody\a:bodyPr\ + $objWriter->endElement(); + + // p:sp\p:txBody\a:lstStyle + $objWriter->writeElement('a:lstStyle'); + + // p:sp\p:txBody\a:p + $objWriter->startElement('a:p'); + + // p:sp\p:txBody\a:p\a:pPr + $objWriter->writeElementBlock('a:pPr', [ + 'algn' => 'ctr', + ]); + // p:sp\p:txBody\a:p\a:r + $objWriter->startElement('a:r'); + // p:sp\p:txBody\a:p\a:r\a:t + $objWriter->startElement('a:t'); + $objWriter->writeCData(Text::controlCharacterPHP2OOXML($shape->getText())); + $objWriter->endElement(); + // p:sp\p:txBody\a:p\a:r\ + $objWriter->endElement(); + // p:sp\p:txBody\a:p\ + $objWriter->endElement(); + // p:sp\p:txBody\ + $objWriter->endElement(); + // p:sp\ + $objWriter->endElement(); + } + /** * Write chart * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart $shape - * @param int $shapeId + * @param XMLWriter $objWriter XML Writer */ - protected function writeShapeChart(XMLWriter $objWriter, ShapeChart $shape, $shapeId) + protected function writeShapeChart(XMLWriter $objWriter, ShapeChart $shape, int $shapeId): void { // p:graphicFrame $objWriter->startElement('p:graphicFrame'); @@ -1092,7 +1202,7 @@ protected function writeShapeChart(XMLWriter $objWriter, ShapeChart $shape, $sha $objWriter->endElement(); // p:xfrm $objWriter->startElement('p:xfrm'); - $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation())); + $objWriter->writeAttributeIf(0 != $shape->getRotation(), 'rot', CommonDrawing::degreesToAngle((int) $shape->getRotation())); // a:off $objWriter->startElement('a:off'); $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX())); @@ -1121,39 +1231,63 @@ protected function writeShapeChart(XMLWriter $objWriter, ShapeChart $shape, $sha } /** - * Write pic + * Write pic. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\AbstractGraphic $shape - * @param int $shapeId - * @throws \Exception + * @param XMLWriter $objWriter XML Writer */ - protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, $shapeId) + protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, int $shapeId): void { // p:pic $objWriter->startElement('p:pic'); + // p:nvPicPr $objWriter->startElement('p:nvPicPr'); + // p:cNvPr $objWriter->startElement('p:cNvPr'); $objWriter->writeAttribute('id', $shapeId); $objWriter->writeAttribute('name', $shape->getName()); $objWriter->writeAttribute('descr', $shape->getDescription()); + // a:hlinkClick if ($shape->hasHyperlink()) { $this->writeHyperlink($objWriter, $shape); } + + if ($shape instanceof AbstractDrawingAdapter && $shape->getExtension() == 'svg') { + $objWriter->startElement('a:extLst'); + $objWriter->startElement('a:ext'); + $objWriter->writeAttribute('uri', '{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}'); + $objWriter->startElement('a16:creationId'); + $objWriter->writeAttribute('xmlns:a16', 'http://schemas.microsoft.com/office/drawing/2014/main'); + $objWriter->writeAttribute('id', '{F8CFD691-5332-EB49-9B42-7D7B3DB9185D}'); + $objWriter->endElement(); + $objWriter->endElement(); + $objWriter->endElement(); + } + $objWriter->endElement(); + // p:cNvPicPr $objWriter->startElement('p:cNvPicPr'); + // a:picLocks $objWriter->startElement('a:picLocks'); $objWriter->writeAttribute('noChangeAspect', '1'); $objWriter->endElement(); + + // #p:cNvPicPr $objWriter->endElement(); + // p:nvPr $objWriter->startElement('p:nvPr'); - /** + // PlaceHolder + if ($shape->isPlaceholder()) { + $objWriter->startElement('p:ph'); + $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType()); + $objWriter->endElement(); + } + /* * @link : https://github.com/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128 */ if ($shape instanceof Media) { @@ -1168,7 +1302,7 @@ protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, $ $objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}'); // p:nvPr > p:extLst > p:ext > p14:media $objWriter->startElement('p14:media'); - $objWriter->writeAttribute('r:embed', $shape->relationId); + $objWriter->writeAttribute('r:embed', ((int) $shape->relationId + 1)); $objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main'); // p:nvPr > p:extLst > p:ext > ##p14:media $objWriter->endElement(); @@ -1180,57 +1314,98 @@ protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, $ // ##p:nvPr $objWriter->endElement(); $objWriter->endElement(); + // p:blipFill $objWriter->startElement('p:blipFill'); + // a:blip $objWriter->startElement('a:blip'); $objWriter->writeAttribute('r:embed', $shape->relationId); + + if ($shape instanceof AbstractDrawingAdapter && $shape->getExtension() == 'svg') { + // a:extLst + $objWriter->startElement('a:extLst'); + + // a:extLst > a:ext + $objWriter->startElement('a:ext'); + $objWriter->writeAttribute('uri', '{28A0092B-C50C-407E-A947-70E740481C1C}'); + // a:extLst > a:ext > a14:useLocalDpi + $objWriter->startElement('a14:useLocalDpi'); + $objWriter->writeAttribute('xmlns:a14', 'http://schemas.microsoft.com/office/drawing/2010/main'); + $objWriter->writeAttribute('val', '0'); + // a:extLst > a:ext > ##a14:useLocalDpi + $objWriter->endElement(); + // a:extLst > ##a:ext + $objWriter->endElement(); + + // a:extLst > a:ext + $objWriter->startElement('a:ext'); + $objWriter->writeAttribute('uri', '{96DAC541-7B7A-43D3-8B79-37D633B846F1}'); + // a:extLst > a:ext > asvg:svgBlip + $objWriter->startElement('asvg:svgBlip'); + $objWriter->writeAttribute('xmlns:asvg', 'http://schemas.microsoft.com/office/drawing/2016/SVG/main'); + $objWriter->writeAttribute('r:embed', $shape->relationId); + // a:extLst > a:ext > ##asvg:svgBlip + $objWriter->endElement(); + // a:extLst > ##a:ext + $objWriter->endElement(); + + // ##a:extLst + $objWriter->endElement(); + } + $objWriter->endElement(); + // a:stretch $objWriter->startElement('a:stretch'); - $objWriter->writeElement('a:fillRect', null); + $objWriter->writeElement('a:fillRect'); $objWriter->endElement(); + $objWriter->endElement(); + // p:spPr $objWriter->startElement('p:spPr'); // a:xfrm $objWriter->startElement('a:xfrm'); - $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation())); + $objWriter->writeAttributeIf(0 != $shape->getRotation(), 'rot', CommonDrawing::degreesToAngle((int) $shape->getRotation())); + // a:off $objWriter->startElement('a:off'); $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX())); $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY())); $objWriter->endElement(); + // a:ext $objWriter->startElement('a:ext'); $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth())); $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight())); $objWriter->endElement(); + $objWriter->endElement(); + // a:prstGeom $objWriter->startElement('a:prstGeom'); $objWriter->writeAttribute('prst', 'rect'); - // a:avLst + // // a:prstGeom/a:avLst $objWriter->writeElement('a:avLst', null); + // ##a:prstGeom $objWriter->endElement(); - if ($shape->getBorder()->getLineStyle() != Border::LINE_NONE) { - $this->writeBorder($objWriter, $shape->getBorder(), ''); - } - if ($shape->getShadow()->isVisible()) { - $this->writeShadow($objWriter, $shape->getShadow()); - } + + $this->writeFill($objWriter, $shape->getFill()); + $this->writeBorder($objWriter, $shape->getBorder(), ''); + $this->writeShadow($objWriter, $shape->getShadow()); + $objWriter->endElement(); + $objWriter->endElement(); } /** - * Write group + * Write group. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Group $group - * @param int $shapeId + * @param XMLWriter $objWriter XML Writer */ - protected function writeShapeGroup(XMLWriter $objWriter, Group $group, &$shapeId) + protected function writeShapeGroup(XMLWriter $objWriter, Group $group, int &$shapeId): void { // p:grpSp $objWriter->startElement('p:grpSp'); @@ -1279,11 +1454,7 @@ protected function writeShapeGroup(XMLWriter $objWriter, Group $group, &$shapeId $objWriter->endElement(); // p:grpSp } - /** - * @param \PhpOffice\PhpPresentation\Slide\AbstractSlide $pSlide - * @param $objWriter - */ - protected function writeSlideBackground(AbstractSlideAlias $pSlide, XMLWriter $objWriter) + protected function writeSlideBackground(AbstractSlideAlias $pSlide, XMLWriter $objWriter): void { if (!($pSlide->getBackground() instanceof Slide\AbstractBackground)) { return; @@ -1330,7 +1501,7 @@ protected function writeSlideBackground(AbstractSlideAlias $pSlide, XMLWriter $o // > p:bgPr $objWriter->endElement(); } - /** + /* * @link : http://www.officeopenxml.com/prSlide-background.php */ if ($oBackground instanceof Slide\Background\SchemeColor) { @@ -1348,16 +1519,14 @@ protected function writeSlideBackground(AbstractSlideAlias $pSlide, XMLWriter $o $objWriter->endElement(); } - /** - * Write Transition Slide - * @link http://officeopenxml.com/prSlide-transitions.php - * @param XMLWriter $objWriter - * @param Slide\Transition $transition + * Write Transition Slide. + * + * @see http://officeopenxml.com/prSlide-transitions.php */ - protected function writeSlideTransition(XMLWriter $objWriter, $transition) + protected function writeSlideTransition(XMLWriter $objWriter, ?Slide\Transition $transition): void { - if (!$transition instanceof Slide\Transition) { + if (!$transition) { return; } $objWriter->startElement('p:transition'); @@ -1390,15 +1559,8 @@ protected function writeSlideTransition(XMLWriter $objWriter, $transition) $objWriter->writeAttribute('dir', 'vert'); $objWriter->endElement(); break; - case Slide\Transition::TRANSITION_CIRCLE_HORIZONTAL: - $objWriter->startElement('p:circle'); - $objWriter->writeAttribute('dir', 'horz'); - $objWriter->endElement(); - break; - case Slide\Transition::TRANSITION_CIRCLE_VERTICAL: - $objWriter->startElement('p:circle'); - $objWriter->writeAttribute('dir', 'vert'); - $objWriter->endElement(); + case Slide\Transition::TRANSITION_CIRCLE: + $objWriter->writeElement('p:circle'); break; case Slide\Transition::TRANSITION_COMB_HORIZONTAL: $objWriter->startElement('p:comb'); @@ -1603,21 +1765,22 @@ protected function writeSlideTransition(XMLWriter $objWriter, $transition) $objWriter->endElement(); } - private function getGUID() + private function getGUID(): string { if (function_exists('com_create_guid')) { return com_create_guid(); } else { - mt_srand((double)microtime() * 10000);//optional for php 4.2.0 and up. - $charid = strtoupper(md5(uniqid(rand(), true))); - $hyphen = chr(45);// "-" + mt_srand(intval(microtime(true) * 10000)); + $charid = strtoupper(md5(uniqid((string) rand(), true))); + $hyphen = chr(45); // "-" $uuid = chr(123)// "{" . substr($charid, 0, 8) . $hyphen . substr($charid, 8, 4) . $hyphen . substr($charid, 12, 4) . $hyphen . substr($charid, 16, 4) . $hyphen . substr($charid, 20, 12) - . chr(125);// "}" + . chr(125); // "}" + return $uuid; } } diff --git a/src/PhpPresentation/Writer/PowerPoint2007/CommentAuthors.php b/src/PhpPresentation/Writer/PowerPoint2007/CommentAuthors.php index b730bd2019..35b90e1774 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/CommentAuthors.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/CommentAuthors.php @@ -1,4 +1,22 @@ getPresentation()->getAllSlides() as $oSlide) { foreach ($oSlide->getShapeCollection() as $oShape) { if (!($oShape instanceof Comment)) { @@ -42,6 +57,7 @@ public function render() /** * @param Author[] $arrayAuthors + * * @return string */ protected function writeCommentsAuthors($arrayAuthors) @@ -62,7 +78,7 @@ protected function writeCommentsAuthors($arrayAuthors) $objWriter->writeAttribute('id', $oAuthor->getIndex()); $objWriter->writeAttribute('name', $oAuthor->getName()); $objWriter->writeAttribute('initials', $oAuthor->getInitials()); - $objWriter->writeAttribute('lastIdx', "2"); + $objWriter->writeAttribute('lastIdx', '2'); $objWriter->writeAttribute('clrIdx', 0); $objWriter->endElement(); } diff --git a/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php b/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php index 34ca83ec80..6d0a6d7e34 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php @@ -10,29 +10,28 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007; +use PhpOffice\Common\Adapter\Zip\ZipInterface; +use PhpOffice\Common\XMLWriter; use PhpOffice\PhpPresentation\Shape\Chart as ShapeChart; use PhpOffice\PhpPresentation\Shape\Comment; -use PhpOffice\PhpPresentation\Shape\Drawing as ShapeDrawing; -use PhpOffice\Common\XMLWriter; -use PhpOffice\PhpPresentation\Writer\PowerPoint2007; +use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter; /** - * \PhpOffice\PhpPresentation\Writer\PowerPoint2007\ContentTypes + * \PhpOffice\PhpPresentation\Writer\PowerPoint2007\ContentTypes. */ class ContentTypes extends AbstractDecoratorWriter { - /** - * @return \PhpOffice\Common\Adapter\Zip\ZipInterface - * @throws \Exception - */ - public function render() + public function render(): ZipInterface { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -50,6 +49,9 @@ public function render() // XML $this->writeDefaultContentType($objWriter, 'xml', 'application/xml'); + // SVG + $this->writeDefaultContentType($objWriter, 'svg', 'image/svg+xml'); + // Presentation $this->writeOverrideContentType($objWriter, '/ppt/presentation.xml', 'application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml'); @@ -67,11 +69,12 @@ public function render() $sldLayoutNr = 0; $sldLayoutId = time() + 689016272; // requires minimum value of 2 147 483 648 foreach ($this->oPresentation->getAllMasterSlides() as $idx => $oSlideMaster) { - $oSlideMaster->setRelsIndex($idx + 1); + $oSlideMaster->setRelsIndex((string) ($idx + 1)); $this->writeOverrideContentType($objWriter, '/ppt/slideMasters/slideMaster' . $oSlideMaster->getRelsIndex() . '.xml', 'application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml'); $this->writeOverrideContentType($objWriter, '/ppt/theme/theme' . $oSlideMaster->getRelsIndex() . '.xml', 'application/vnd.openxmlformats-officedocument.theme+xml'); foreach ($oSlideMaster->getAllSlideLayouts() as $oSlideLayout) { $oSlideLayout->layoutNr = ++$sldLayoutNr; + $oSlideLayout->setRelsIndex((string) $oSlideLayout->layoutNr); $oSlideLayout->layoutId = ++$sldLayoutId; $this->writeOverrideContentType($objWriter, '/ppt/slideLayouts/slideLayout' . $oSlideLayout->layoutNr . '.xml', 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml'); } @@ -100,13 +103,13 @@ public function render() } // Add media content-types - $aMediaContentTypes = array(); + $aMediaContentTypes = []; // GIF, JPEG, PNG - $aMediaContentTypes['gif'] = 'image/gif'; - $aMediaContentTypes['jpg'] = 'image/jpeg'; + $aMediaContentTypes['gif'] = 'image/gif'; + $aMediaContentTypes['jpg'] = 'image/jpeg'; $aMediaContentTypes['jpeg'] = 'image/jpeg'; - $aMediaContentTypes['png'] = 'image/png'; + $aMediaContentTypes['png'] = 'image/png'; foreach ($aMediaContentTypes as $key => $value) { $this->writeDefaultContentType($objWriter, $key, $value); } @@ -120,8 +123,12 @@ public function render() $shapeIndex = $this->getDrawingHashTable()->getByIndex($i); if ($shapeIndex instanceof ShapeChart) { // Chart content type - $this->writeOverrideContentType($objWriter, '/ppt/charts/chart' . $shapeIndex->getImageIndex() . '.xml', 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml'); - } else { + $this->writeOverrideContentType( + $objWriter, + '/ppt/charts/chart' . $shapeIndex->getImageIndex() . '.xml', + 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml' + ); + } elseif ($shapeIndex instanceof AbstractDrawingAdapter) { $extension = strtolower($shapeIndex->getExtension()); $mimeType = $shapeIndex->getMimeType(); @@ -141,18 +148,14 @@ public function render() } /** - * Write Default content type + * Write Default content type. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param string $pPartname Part name - * @param string $pContentType Content type - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param string $pPartname Part name + * @param string $pContentType Content type */ - private function writeDefaultContentType(XMLWriter $objWriter, $pPartname = '', $pContentType = '') + protected function writeDefaultContentType(XMLWriter $objWriter, string $pPartname, string $pContentType): void { - if ($pPartname == '' || $pContentType == '') { - throw new \Exception("Invalid parameters passed."); - } // Write content type $objWriter->startElement('Default'); $objWriter->writeAttribute('Extension', $pPartname); @@ -161,18 +164,14 @@ private function writeDefaultContentType(XMLWriter $objWriter, $pPartname = '', } /** - * Write Override content type + * Write Override content type. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param string $pPartname Part name - * @param string $pContentType Content type - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param string $pPartname Part name + * @param string $pContentType Content type */ - private function writeOverrideContentType(XMLWriter $objWriter, $pPartname = '', $pContentType = '') + protected function writeOverrideContentType(XMLWriter $objWriter, string $pPartname, string $pContentType): void { - if ($pPartname == '' || $pContentType == '') { - throw new \Exception("Invalid parameters passed."); - } // Write content type $objWriter->startElement('Override'); $objWriter->writeAttribute('PartName', $pPartname); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsApp.php b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsApp.php index c5a301098a..fe81c5086c 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsApp.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsApp.php @@ -1,15 +1,31 @@ writeElement('Application', 'Microsoft Office PowerPoint'); // Slides - $objWriter->writeElement('Slides', $this->getPresentation()->getSlideCount()); + $objWriter->writeElement('Slides', (string) $this->getPresentation()->getSlideCount()); // ScaleCrop $objWriter->writeElement('ScaleCrop', 'false'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php index dd954246a2..f1afb28df9 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php @@ -1,15 +1,31 @@ startElement('property'); $objWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'); - $objWriter->writeAttribute('pid', 2); + $objWriter->writeAttribute('pid', (++$pId) * 2); $objWriter->writeAttribute('name', '_MarkAsFinal'); // property > vt:bool @@ -36,6 +56,37 @@ public function render() $objWriter->endElement(); } + $oDocumentProperties = $this->oPresentation->getDocumentProperties(); + foreach ($oDocumentProperties->getCustomProperties() as $customProperty) { + $propertyValue = $oDocumentProperties->getCustomPropertyValue($customProperty); + $propertyType = $oDocumentProperties->getCustomPropertyType($customProperty); + + $objWriter->startElement('property'); + $objWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}'); + $objWriter->writeAttribute('pid', (++$pId) * 2); + $objWriter->writeAttribute('name', $customProperty); + switch ($propertyType) { + case DocumentProperties::PROPERTY_TYPE_INTEGER: + $objWriter->writeElement('vt:i4', (string) $propertyValue); + break; + case DocumentProperties::PROPERTY_TYPE_FLOAT: + $objWriter->writeElement('vt:r8', (string) $propertyValue); + break; + case DocumentProperties::PROPERTY_TYPE_BOOLEAN: + $objWriter->writeElement('vt:bool', $propertyValue ? 'true' : 'false'); + break; + case DocumentProperties::PROPERTY_TYPE_DATE: + $objWriter->startElement('vt:filetime'); + $objWriter->writeRaw(date(DATE_W3C, (int) $propertyValue)); + $objWriter->endElement(); + break; + default: + $objWriter->writeElement('vt:lpwstr', (string) $propertyValue); + break; + } + $objWriter->endElement(); + } + // > Properties $objWriter->endElement(); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php index edd79caa76..6c54be1ecf 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php @@ -1,13 +1,30 @@ getPresentation()->getPresentationProperties()->getThumbnailPath(); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/AbstractLayoutPack.php b/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/AbstractLayoutPack.php deleted file mode 100644 index 1e3cf69f17..0000000000 --- a/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/AbstractLayoutPack.php +++ /dev/null @@ -1,225 +0,0 @@ -masterSlides; - } - - /** - * Get master slide relations - * - * @return array - */ - public function getMasterSlideRelations() - { - return $this->masterSlideRels; - } - - /** - * Get themes - * - * @return array - */ - public function getThemes() - { - return $this->themes; - } - - /** - * Get theme relations - * - * @return array - */ - public function getThemeRelations() - { - return $this->themeRelations; - } - - /** - * Get array of slide layouts - * - * @return array - */ - public function getLayouts() - { - return $this->layouts; - } - - /** - * Get array of slide layout relations - * - * @return array - */ - public function getLayoutRelations() - { - return $this->layoutRelations; - } - - /** - * Find specific slide layout. - * - * This is an array consisting of: - * - masterid - * - name (string) - * - body (string) - * - * @param string $name - * @param int $masterId - * @return array - * @throws \Exception - */ - public function findLayout($name = '', $masterId = 1) - { - foreach ($this->layouts as $layout) { - if ($layout['name'] == $name && $layout['masterid'] == $masterId) { - return $layout; - } - } - - throw new \Exception("Could not find slide layout $name in current layout pack."); - } - - /** - * Find specific slide layout id. - * - * @param string $name - * @return int - * @throws \Exception - */ - public function findLayoutId($name = '') - { - foreach ($this->layouts as $layoutId => $layout) { - if ($layout['name'] == $name) { - return $layoutId; - } - } - - throw new \Exception("Could not find slide layout $name in current layout pack."); - } - - /** - * Find specific slide layout name. - * - * @param int $idLayout - * @return int - * @throws \Exception - */ - public function findLayoutName($idLayout = null) - { - foreach ($this->layouts as $layoutId => $layout) { - if ($layoutId == $idLayout) { - return $layout['name']; - } - } - - throw new \Exception("Could not find slide layout $idLayout in current layout pack."); - } -} diff --git a/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/PackDefault.php b/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/PackDefault.php deleted file mode 100644 index 0df0c01ce5..0000000000 --- a/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/PackDefault.php +++ /dev/null @@ -1,3281 +0,0 @@ -masterSlides = array( - array( - 'masterid' => 1, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <#> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')); - - // Master slide relations - $this->masterSlideRels = array( - //array('masterid' => '', 'id' => '', 'type' => '', 'contentType' => '', 'target' => '', 'contents' => '') - ); - - // Theme - $this->themes = array( - array( - 'masterid' => 1, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')); - - // Theme relations - $this->themeRelations = array( - //array('masterid' => 1, 'id' => '', 'type' => '', 'contentType' => '', 'target' => '', 'contents' => '') - ); - - // Layouts - Layout::TITLE_SLIDE - $this->layouts[1] = array( - 'masterid' => 1, - 'name' => Layout::TITLE_SLIDE, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master subtitle style - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::TITLE_AND_CONTENT - $this->layouts[2] = array( - 'masterid' => 1, - 'name' => Layout::TITLE_AND_CONTENT, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::SECTION_HEADER - $this->layouts[3] = array( - 'masterid' => 1, - 'name' => Layout::SECTION_HEADER, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::TWO_CONTENT - $this->layouts[4] = array( - 'masterid' => 1, - 'name' => Layout::TWO_CONTENT, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::COMPARISON - $this->layouts[5] = array( - 'masterid' => 1, - 'name' => Layout::COMPARISON, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::TITLE_ONLY - $this->layouts[6] = array( - 'masterid' => 1, - 'name' => Layout::TITLE_ONLY, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::BLANK - $this->layouts[7] = array( - 'masterid' => 1, - 'name' => Layout::BLANK, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::CONTENT_WITH_CAPTION - $this->layouts[8] = array( - 'masterid' => 1, - 'name' => Layout::CONTENT_WITH_CAPTION, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::PICTURE_WITH_CAPTION - $this->layouts[9] = array( - 'masterid' => 1, - 'name' => Layout::PICTURE_WITH_CAPTION, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::TITLE_AND_VERTICAL_TEXT - $this->layouts[10] = array( - 'masterid' => 1, - 'name' => Layout::TITLE_AND_VERTICAL_TEXT, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layouts - Layout::VERTICAL_TITLE_AND_TEXT - $this->layouts[11] = array( - 'masterid' => 1, - 'name' => Layout::VERTICAL_TITLE_AND_TEXT, - 'body' => ' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master title style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Click to edit Master text styles - - - - - - - Second level - - - - - - - Third level - - - - - - - Fourth level - - - - - - - Fifth level - - - - - - - - - - - - - - - - - - - - - - - 16/04/2009 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ‹#› - - - - - - - - - - -'); - - // Layout relations - $this->layoutRelations = array( - //array('layoutId' => 0, 'id' => '', 'type' => '', 'contentType' => '', 'target' => '', 'contents' => '') - ); - } -} diff --git a/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/TemplateBased.php b/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/TemplateBased.php deleted file mode 100644 index 7a42c4cc51..0000000000 --- a/src/PhpPresentation/Writer/PowerPoint2007/LayoutPack/TemplateBased.php +++ /dev/null @@ -1,203 +0,0 @@ -masterSlideRels = array(); - - // Theme relations - $this->themeRelations = array(); - - // Layout relations - $this->layoutRelations = array(); - - // Open package - $package = new \ZipArchive; - $package->open($fileName); - - // Read relations and search for officeDocument - $relations = simplexml_load_string($package->getFromName("_rels/.rels")); - foreach ($relations->Relationship as $rel) { - if ($rel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument") { - // Found office document! Search for master slide... - $presentationRels = simplexml_load_string($package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/_rels/" . basename($rel["Target"]) . ".rels"))); - foreach ($presentationRels->Relationship as $presRel) { - if ($presRel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster") { - // Found slide master! - $slideMasterId = str_replace('slideMaster', '', basename($presRel["Target"], '.xml')); - $this->masterSlides[] = array( - 'masterid' => $slideMasterId, - 'body' => $package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . basename($presRel["Target"]))) - ); - - // Search for theme & slide layouts - $masterRelations = simplexml_load_string($package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/_rels/" . basename($presRel["Target"]) . ".rels"))); - foreach ($masterRelations->Relationship as $masterRel) { - if ($masterRel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme") { - // Found theme! - $themeId = str_replace('theme', '', basename($masterRel["Target"], '.xml')); - $this->themes[$themeId - 1] = array( - 'masterid' => $slideMasterId, - 'body' => $package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/" . basename($masterRel["Target"]))) - ); - - // Search for theme relations - $themeRelations = @simplexml_load_string($package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/_rels/" . basename($masterRel["Target"]) . ".rels"))); - if ($themeRelations && $themeRelations->Relationship) { - foreach ($themeRelations->Relationship as $themeRel) { - if ($themeRel["Type"] != "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" && $themeRel["Type"] != "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" && $themeRel["Type"] != "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme") { - // Theme relation - $this->themeRelations[] = array( - 'masterid' => $slideMasterId, - 'id' => $themeRel["Id"], - 'type' => $themeRel["Type"], - 'contentType' => '', - 'target' => $themeRel["Target"], - 'contents' => $package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/" . dirname($themeRel["Target"]) . "/" . basename($themeRel["Target"]))) - ); - } - } - } - } elseif ($masterRel["Type"] == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout") { - // Found slide layout! - $layoutId = str_replace('slideLayout', '', basename($masterRel["Target"], '.xml')); - $layout = array( - 'id' => $layoutId, - 'masterid' => $slideMasterId, - 'name' => '-unknown-', - 'body' => $package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/" . basename($masterRel["Target"]))) - ); - if (utf8_encode(utf8_decode($layout['body'])) == $layout['body']) { - $layoutXml = simplexml_load_string($layout['body']); - } else { - $layoutXml = simplexml_load_string(utf8_encode($layout['body'])); - } - $layoutXml->registerXPathNamespace("p", "http://schemas.openxmlformats.org/presentationml/2006/main"); - $slide = $layoutXml->xpath('/p:sldLayout/p:cSld'); - $layout['name'] = (string) $slide[0]['name']; - $this->layouts[$layoutId] = $layout; - - // Search for slide layout relations - $layoutRelations = @simplexml_load_string($package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/_rels/" . basename($masterRel["Target"]) . ".rels"))); - if ($layoutRelations && $layoutRelations->Relationship) { - foreach ($layoutRelations->Relationship as $layoutRel) { - if ($layoutRel["Type"] != "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster" && $layoutRel["Type"] != "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" && $layoutRel["Type"] != "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme") { - // Layout relation - $this->layoutRelations[] = array( - 'layoutId' => $layoutId, - 'id' => $layoutRel["Id"], - 'type' => $layoutRel["Type"], - 'contentType' => '', - 'target' => $layoutRel["Target"], - 'contents' => $package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/" . dirname($layoutRel["Target"]) . "/" . basename($layoutRel["Target"]))) - ); - } - } - } - } else { - // Master slide relation - $this->masterSlideRels[] = array( - 'masterid' => $slideMasterId, - 'id' => $masterRel["Id"], - 'type' => $masterRel["Type"], - 'contentType' => '', - 'target' => $masterRel["Target"], - 'contents' => $package->getFromName($this->absoluteZipPath(dirname($rel["Target"]) . "/" . dirname($presRel["Target"]) . "/" . dirname($masterRel["Target"]) . "/" . basename($masterRel["Target"]))) - ); - } - } - } - } - - break; - } - } - - // Sort master slides - usort($this->masterSlides, array( - "\PhpOffice\PhpPresentation\Writer\PowerPoint2007\LayoutPack\TemplateBased", - "cmpMaster" - )); - - // Close package - $package->close(); - } - - /** - * Compare master slides - * - * @param array $firstSlide - * @param array $secondSlide - * @return int - */ - public static function cmpMaster($firstSlide, $secondSlide) - { - if ($firstSlide['masterid'] == $secondSlide['masterid']) { - return 0; - } - - return ($firstSlide['masterid'] < $secondSlide['masterid']) ? -1 : 1; - } - - /** - * Determine absolute zip path - * - * @param string $path - * @return string - */ - protected function absoluteZipPath($path) - { - $path = str_replace(array( - '/', - '\\' - ), DIRECTORY_SEPARATOR, $path); - $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); - $absolutes = array(); - foreach ($parts as $part) { - if ('.' == $part) { - continue; - } - if ('..' == $part) { - array_pop($absolutes); - } else { - $absolutes[] = $part; - } - } - - return implode('/', $absolutes); - } -} diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php b/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php index d8064aec03..0010dac78a 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php @@ -1,9 +1,30 @@ getDrawingHashTable()->count(); ++$i) { $shape = $this->getDrawingHashTable()->getByIndex($i); @@ -35,23 +60,26 @@ public function render() if ($shape->hasIncludedSpreadsheet()) { $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape)); - $pFilename = tempnam(sys_get_temp_dir(), 'PHPExcel'); + $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet'); $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx')); + + // remove temp file + if (false === @unlink($pFilename)) { + throw new FileRemoveException($pFilename); + } } } } + return $this->getZip(); } - /** - * Write chart to XML format + * Write chart to XML format. * - * @param \PhpOffice\PhpPresentation\Shape\Chart $chart - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - public function writeChart(Chart $chart) + protected function writeChart(Chart $chart): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -99,7 +127,7 @@ public function writeChart(Chart $chart) // c:hPercent $hPercent = $chart->getView3D()->getHeightPercent(); - $objWriter->writeElementIf($hPercent != null, 'c:hPercent', 'val', $hPercent . '%'); + $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent); // c:rotY $objWriter->startElement('c:rotY'); @@ -137,6 +165,11 @@ public function writeChart(Chart $chart) $objWriter->writeAttribute('val', '1'); $objWriter->endElement(); + // c:dispBlanksAs + $objWriter->startElement('c:dispBlanksAs'); + $objWriter->writeAttribute('val', $chart->getDisplayBlankAs()); + $objWriter->endElement(); + $objWriter->endElement(); // c:spPr @@ -146,7 +179,7 @@ public function writeChart(Chart $chart) $this->writeFill($objWriter, $chart->getFill()); // Border - if ($chart->getBorder()->getLineStyle() != Border::LINE_NONE) { + if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) { $this->writeBorder($objWriter, $chart->getBorder(), ''); } @@ -159,7 +192,7 @@ public function writeChart(Chart $chart) $objWriter->startElement('a:outerShdw'); $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius())); $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance())); - $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle($chart->getShadow()->getDirection())); + $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection())); $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment()); $objWriter->writeAttribute('rotWithShape', '0'); @@ -193,38 +226,31 @@ public function writeChart(Chart $chart) } /** - * Write chart to XML format + * Write chart to XML format. + * + * @return string String output * - * @param PhpPresentation $presentation - * @param \PhpOffice\PhpPresentation\Shape\Chart $chart - * @param string $tempName - * @return string String output - * @throws \Exception + * @throws FileRemoveException */ - public function writeSpreadsheet(PhpPresentation $presentation, $chart, $tempName) + protected function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string { - // Need output? - if (!$chart->hasIncludedSpreadsheet()) { - throw new \Exception('No spreadsheet output is required for the given chart.'); - } - - // Verify PHPExcel - if (!class_exists('PHPExcel')) { - throw new \Exception('PHPExcel has not been loaded. Include PHPExcel.php in your script, e.g. require_once \'PHPExcel.php\'.'); - } - // Create new spreadsheet - $workbook = new \PHPExcel(); + $spreadsheet = new Spreadsheet(); // Set properties $title = $chart->getTitle()->getText(); - if (strlen($title) == 0) { + if (0 == strlen($title)) { $title = 'Chart'; } - $workbook->getProperties()->setCreator($presentation->getDocumentProperties()->getCreator())->setLastModifiedBy($presentation->getDocumentProperties()->getLastModifiedBy())->setTitle($title); + $spreadsheet->getProperties() + ->setCreator( + $presentation->getDocumentProperties()->getCreator())->setLastModifiedBy( + $presentation->getDocumentProperties()->getLastModifiedBy() + ) + ->setTitle($title); // Add chart data - $sheet = $workbook->setActiveSheetIndex(0); + $sheet = $spreadsheet->setActiveSheetIndex(0); $sheet->setTitle('Sheet1'); // Write series @@ -236,14 +262,14 @@ public function writeSpreadsheet(PhpPresentation $presentation, $chart, $tempNam // X-axis $axisXData = array_keys($series->getValues()); $numAxisXData = count($axisXData); - for ($i = 0; $i < $numAxisXData; $i++) { + for ($i = 0; $i < $numAxisXData; ++$i) { $sheet->setCellValueByColumnAndRow(0, $i + 2, $axisXData[$i]); } // Y-axis $axisYData = array_values($series->getValues()); $numAxisYData = count($axisYData); - for ($i = 0; $i < $numAxisYData; $i++) { + for ($i = 0; $i < $numAxisYData; ++$i) { $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, $i + 2, $axisYData[$i]); } @@ -251,26 +277,24 @@ public function writeSpreadsheet(PhpPresentation $presentation, $chart, $tempNam } // Save to string - $writer = \PHPExcel_IOFactory::createWriter($workbook, 'Excel2007'); + $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); $writer->save($tempName); // Load file in memory $returnValue = file_get_contents($tempName); - if (@unlink($tempName) === false) { - throw new \Exception('The file ' . $tempName . ' could not removed.'); + if (false === @unlink($tempName)) { + throw new FileRemoveException($tempName); } return $returnValue; } /** - * Write element with value attribute + * Write element with value attribute. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param string $elementName - * @param string $value + * @param XMLWriter $objWriter XML Writer */ - protected function writeElementWithValAttribute($objWriter, $elementName, $value) + protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void { $objWriter->startElement($elementName); $objWriter->writeAttribute('val', $value); @@ -278,54 +302,56 @@ protected function writeElementWithValAttribute($objWriter, $elementName, $value } /** - * Write single value or reference + * Write single value or reference. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param boolean $isReference - * @param mixed $value - * @param string $reference + * @param XMLWriter $objWriter XML Writer */ - protected function writeSingleValueOrReference($objWriter, $isReference, $value, $reference) + protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void { if (!$isReference) { // Value $objWriter->writeElement('c:v', $value); + return; } // Reference and cache + // c:strRef $objWriter->startElement('c:strRef'); + // c:strRef/c:f $objWriter->writeElement('c:f', $reference); + // c:strRef/c:strCache $objWriter->startElement('c:strCache'); + // c:strRef/c:strCache/c:ptCount $objWriter->startElement('c:ptCount'); $objWriter->writeAttribute('val', '1'); $objWriter->endElement(); + // c:strRef/c:strCache/c:pt $objWriter->startElement('c:pt'); $objWriter->writeAttribute('idx', '0'); + // c:strRef/c:strCache/c:pt/c:v $objWriter->writeElement('c:v', $value); + // c:strRef/c:strCache/c:pt $objWriter->endElement(); + // c:strRef/c:strCache $objWriter->endElement(); + // c:strRef $objWriter->endElement(); } /** - * Write series value or reference + * Write series value or reference. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param boolean $isReference - * @param mixed $values - * @param string $reference + * @param XMLWriter $objWriter XML Writer + * @param array $values */ - protected function writeMultipleValuesOrReference($objWriter, $isReference, $values, $reference) + protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void { // c:strLit / c:numLit // c:strRef / c:numRef $referenceType = ($isReference ? 'Ref' : 'Lit'); - $dataType = 'str'; - if (is_int($values[0]) || is_float($values[0])) { - $dataType = 'num'; - } + $dataType = is_numeric($values[0]) ? 'num' : 'str'; $objWriter->startElement('c:' . $dataType . $referenceType); $numValues = count($values); @@ -338,11 +364,11 @@ protected function writeMultipleValuesOrReference($objWriter, $isReference, $val $objWriter->endElement(); // Add points - for ($i = 0; $i < $numValues; $i++) { + for ($i = 0; $i < $numValues; ++$i) { // c:pt $objWriter->startElement('c:pt'); $objWriter->writeAttribute('idx', $i); - $objWriter->writeElement('c:v', $values[$i]); + $objWriter->writeElement('c:v', strval($values[$i])); $objWriter->endElement(); } } else { @@ -356,11 +382,11 @@ protected function writeMultipleValuesOrReference($objWriter, $isReference, $val $objWriter->endElement(); // Add points - for ($i = 0; $i < $numValues; $i++) { + for ($i = 0; $i < $numValues; ++$i) { // c:pt $objWriter->startElement('c:pt'); $objWriter->writeAttribute('idx', $i); - $objWriter->writeElement('c:v', $values[$i]); + $objWriter->writeElement('c:v', strval($values[$i])); $objWriter->endElement(); } @@ -372,12 +398,8 @@ protected function writeMultipleValuesOrReference($objWriter, $isReference, $val /** * Write Title - * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Title $subject - * @throws \Exception */ - protected function writeTitle(XMLWriter $objWriter, Title $subject) + protected function writeTitle(XMLWriter $objWriter, Title $subject): void { // c:title $objWriter->startElement('c:title'); @@ -418,14 +440,13 @@ protected function writeTitle(XMLWriter $objWriter, Title $subject) $objWriter->startElement('a:rPr'); $objWriter->writeAttribute('lang', 'en-US'); $objWriter->writeAttribute('dirty', '0'); - $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false')); $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $subject->getFont()->getUnderline()); - $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -470,14 +491,13 @@ protected function writeTitle(XMLWriter $objWriter, Title $subject) } /** - * Write Plot Area + * Write Plot Area. + * + * @param XMLWriter $objWriter XML Writer * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\PlotArea $subject - * @param \PhpOffice\PhpPresentation\Shape\Chart $chart - * @throws \Exception + * @throws UndefinedChartTypeException */ - protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart) + protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void { // c:plotArea $objWriter->startElement('c:plotArea'); @@ -493,16 +513,20 @@ protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); } elseif ($chartType instanceof Bar3D) { $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); + } elseif ($chartType instanceof Doughnut) { + $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); } elseif ($chartType instanceof Pie) { $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); } elseif ($chartType instanceof Pie3D) { $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); } elseif ($chartType instanceof Line) { $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); + } elseif ($chartType instanceof Radar) { + $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); } elseif ($chartType instanceof Scatter) { $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet()); } else { - throw new \Exception('The chart type provided could not be rendered.'); + throw new UndefinedChartTypeException(); } // Write X axis? @@ -519,13 +543,12 @@ protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart } /** - * Write Legend + * Write Legend. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Legend $subject - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Chart\Legend $subject */ - protected function writeLegend(XMLWriter $objWriter, Legend $subject) + protected function writeLegend(XMLWriter $objWriter, Legend $subject): void { // c:legend $objWriter->startElement('c:legend'); @@ -550,7 +573,7 @@ protected function writeLegend(XMLWriter $objWriter, Legend $subject) $this->writeFill($objWriter, $subject->getFill()); // Border - if ($subject->getBorder()->getLineStyle() != Border::LINE_NONE) { + if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) { $this->writeBorder($objWriter, $subject->getBorder(), ''); } @@ -585,8 +608,8 @@ protected function writeLegend(XMLWriter $objWriter, Legend $subject) $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $subject->getFont()->getUnderline()); - $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -618,13 +641,12 @@ protected function writeLegend(XMLWriter $objWriter, Legend $subject) } /** - * Write Layout + * Write Layout. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param mixed $subject - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Legend|PlotArea|Title $subject */ - protected function writeLayout(XMLWriter $objWriter, $subject) + protected function writeLayout(XMLWriter $objWriter, $subject): void { // c:layout $objWriter->startElement('c:layout'); @@ -641,28 +663,28 @@ protected function writeLayout(XMLWriter $objWriter, $subject) $objWriter->writeAttribute('val', 'edge'); $objWriter->endElement(); - if ($subject->getOffsetX() != 0) { + if (0 != $subject->getOffsetX()) { // c:x $objWriter->startElement('c:x'); $objWriter->writeAttribute('val', $subject->getOffsetX()); $objWriter->endElement(); } - if ($subject->getOffsetY() != 0) { + if (0 != $subject->getOffsetY()) { // c:y $objWriter->startElement('c:y'); $objWriter->writeAttribute('val', $subject->getOffsetY()); $objWriter->endElement(); } - if ($subject->getWidth() != 0) { + if (0 != $subject->getWidth()) { // c:w $objWriter->startElement('c:w'); $objWriter->writeAttribute('val', $subject->getWidth()); $objWriter->endElement(); } - if ($subject->getHeight() != 0) { + if (0 != $subject->getHeight()) { // c:h $objWriter->startElement('c:h'); $objWriter->writeAttribute('val', $subject->getHeight()); @@ -674,14 +696,13 @@ protected function writeLayout(XMLWriter $objWriter, $subject) } /** - * Write Type Area + * Write Type Area. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Area $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Chart\Type\Area $subject + * @param bool $includeSheet */ - protected function writeTypeArea(XMLWriter $objWriter, Area $subject, $includeSheet = false) + protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void { // c:lineChart $objWriter->startElement('c:areaChart'); @@ -709,7 +730,7 @@ protected function writeTypeArea(XMLWriter $objWriter, Area $subject, $includeSh // c:ser > c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -732,7 +753,7 @@ protected function writeTypeArea(XMLWriter $objWriter, Area $subject, $includeSh // c:ser > ##c:dLbls $objWriter->endElement(); - if ($series->getFill()->getFillType() != Fill::FILL_NONE) { + if (Fill::FILL_NONE != $series->getFill()->getFillType()) { // c:spPr $objWriter->startElement('c:spPr'); // Write fill @@ -754,7 +775,7 @@ protected function writeTypeArea(XMLWriter $objWriter, Area $subject, $includeSh // c:val $objWriter->startElement('c:val'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); @@ -777,16 +798,15 @@ protected function writeTypeArea(XMLWriter $objWriter, Area $subject, $includeSh } /** - * Write Type Bar + * Write Type Bar. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Chart\Type\Bar $subject + * @param bool $includeSheet */ - protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeSheet = false) + protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void { - // c:bar3DChart + // c:barChart $objWriter->startElement('c:barChart'); // c:barDir @@ -817,7 +837,7 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee // c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -828,9 +848,9 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee $objWriter->startElement('c:dPt'); // c:idx - $this->writeElementWithValAttribute($objWriter, 'c:idx', $key); + $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key); - if ($value->getFillType() != Fill::FILL_NONE) { + if (Fill::FILL_NONE != $value->getFillType()) { // c:spPr $objWriter->startElement('c:spPr'); // Write fill @@ -858,10 +878,10 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee $objWriter->startElement('c:txPr'); // a:bodyPr - $objWriter->writeElement('a:bodyPr', null); + $objWriter->writeElement('a:bodyPr'); // a:lstStyle - $objWriter->writeElement('a:lstStyle', null); + $objWriter->writeElement('a:lstStyle'); // a:p $objWriter->startElement('a:p'); @@ -877,23 +897,23 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); - // Font - a:solidFill + // a:solidFill $objWriter->startElement('a:solidFill'); - $this->writeColor($objWriter, $series->getFont()->getColor()); - + // >a:solidFill $objWriter->endElement(); - - // Font - a:latin + // a:latin $objWriter->startElement('a:latin'); $objWriter->writeAttribute('typeface', $series->getFont()->getName()); + // >a:latin $objWriter->endElement(); + // >a:defRPr $objWriter->endElement(); - + // >a:pPr $objWriter->endElement(); // a:endParaRPr @@ -902,8 +922,9 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee $objWriter->writeAttribute('dirty', '0'); $objWriter->endElement(); + // >a:p $objWriter->endElement(); - + // >a:lstStyle $objWriter->endElement(); // c:dLblPos @@ -921,16 +942,16 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee // c:showPercent $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0'); + // c:separator + $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : ''); + // c:showLeaderLines $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); - // c:separator - $objWriter->writeElementIf($series->hasShowSeparator(), 'c:separator', 'val', $series->getSeparator()); - $objWriter->endElement(); // c:spPr - if ($series->getFill()->getFillType() != Fill::FILL_NONE) { + if (Fill::FILL_NONE != $series->getFill()->getFillType()) { // c:spPr $objWriter->startElement('c:spPr'); // Write fill @@ -952,7 +973,7 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee // c:val $objWriter->startElement('c:val'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); @@ -961,23 +982,14 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee ++$seriesIndex; } - // c:overlap - $objWriter->startElement('c:overlap'); - if ($subject->getBarGrouping() == Bar::GROUPING_CLUSTERED) { - $objWriter->writeAttribute('val', '0'); - } elseif ($subject->getBarGrouping() == Bar::GROUPING_STACKED || $subject->getBarGrouping() == Bar::GROUPING_PERCENTSTACKED) { - $objWriter->writeAttribute('val', '100'); - } - $objWriter->endElement(); - // c:gapWidth $objWriter->startElement('c:gapWidth'); $objWriter->writeAttribute('val', $subject->getGapWidthPercent()); $objWriter->endElement(); - // c:shape - $objWriter->startElement('c:shape'); - $objWriter->writeAttribute('val', 'box'); + // c:overlap + $objWriter->startElement('c:overlap'); + $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent()); $objWriter->endElement(); // c:axId @@ -990,23 +1002,21 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, $includeShee $objWriter->writeAttribute('val', '52749440'); $objWriter->endElement(); - // c:axId - $objWriter->startElement('c:axId'); - $objWriter->writeAttribute('val', '0'); + // c:extLst + $objWriter->startElement('c:extLst'); $objWriter->endElement(); $objWriter->endElement(); } /** - * Write Type Bar3D + * Write Type Bar3D. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Chart\Type\Bar3D $subject + * @param bool $includeSheet */ - protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $includeSheet = false) + protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void { // c:bar3DChart $objWriter->startElement('c:bar3DChart'); @@ -1039,7 +1049,7 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include // c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -1050,9 +1060,9 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include $objWriter->startElement('c:dPt'); // c:idx - $this->writeElementWithValAttribute($objWriter, 'c:idx', $key); + $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key); - if ($value->getFillType() != Fill::FILL_NONE) { + if (Fill::FILL_NONE != $value->getFillType()) { // c:spPr $objWriter->startElement('c:spPr'); // Write fill @@ -1091,8 +1101,8 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1135,13 +1145,10 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include // c:showLeaderLines $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); - // c:separator - $objWriter->writeElementIf($series->hasShowSeparator(), 'c:separator', 'val', $series->getSeparator()); - $objWriter->endElement(); // c:spPr - if ($series->getFill()->getFillType() != Fill::FILL_NONE) { + if (Fill::FILL_NONE != $series->getFill()->getFillType()) { // c:spPr $objWriter->startElement('c:spPr'); // Write fill @@ -1163,7 +1170,7 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include // c:val $objWriter->startElement('c:val'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); @@ -1177,11 +1184,6 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include $objWriter->writeAttribute('val', $subject->getGapWidthPercent()); $objWriter->endElement(); - // c:shape - $objWriter->startElement('c:shape'); - $objWriter->writeAttribute('val', 'box'); - $objWriter->endElement(); - // c:axId $objWriter->startElement('c:axId'); $objWriter->writeAttribute('val', '52743552'); @@ -1201,17 +1203,16 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, $include } /** - * Write Type Pie + * Write Type Pie. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Pie $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Doughnut $subject + * @param bool $includeSheet */ - protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeSheet = false) + protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void { // c:pieChart - $objWriter->startElement('c:pieChart'); + $objWriter->startElement('c:doughnutChart'); // c:varyColors $objWriter->startElement('c:varyColors'); @@ -1236,7 +1237,7 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeShee // c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -1245,18 +1246,172 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeShee foreach ($dataPointFills as $key => $value) { // c:dPt $objWriter->startElement('c:dPt'); + $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key); + // c:dPt/c:spPr + $objWriter->startElement('c:spPr'); + $this->writeFill($objWriter, $value); + // c:dPt/##c:spPr + $objWriter->endElement(); + // ##c:dPt + $objWriter->endElement(); + } - // c:idx - $this->writeElementWithValAttribute($objWriter, 'c:idx', $key); + // Write X axis data + $axisXData = array_keys($series->getValues()); - // c:spPr - $objWriter->startElement('c:spPr'); + // c:cat + $objWriter->startElement('c:cat'); + $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData))); + $objWriter->endElement(); - // Write fill - $this->writeFill($objWriter, $value); + // Write Y axis data + $axisYData = array_values($series->getValues()); + + // c:val + $objWriter->startElement('c:val'); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); + $objWriter->endElement(); + + $objWriter->endElement(); + ++$seriesIndex; + } + + if (isset($series) && is_object($series) && $series instanceof Chart\Series) { + // c:dLbls + $objWriter->startElement('c:dLbls'); + + $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0'); + $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0'); + $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0'); + $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0'); + $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0'); + $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0'); + $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); + + if ($series->hasDlblNumFormat()) { + //c:numFmt + $objWriter->startElement('c:numFmt'); + $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat()); + $objWriter->writeAttribute('sourceLinked', '0'); $objWriter->endElement(); + } + + // c:dLbls\c:txPr + $objWriter->startElement('c:txPr'); + $objWriter->writeElement('a:bodyPr', null); + $objWriter->writeElement('a:lstStyle', null); + // c:dLbls\c:txPr\a:p + $objWriter->startElement('a:p'); + + // c:dLbls\c:txPr\a:p\a:pPr + $objWriter->startElement('a:pPr'); + + // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr + $objWriter->startElement('a:defRPr'); + $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); + $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); + $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); + $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + + // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill + $objWriter->startElement('a:solidFill'); + $this->writeColor($objWriter, $series->getFont()->getColor()); + $objWriter->endElement(); + + // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin + $objWriter->startElement('a:latin'); + $objWriter->writeAttribute('typeface', $series->getFont()->getName()); + $objWriter->endElement(); + + // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\ + $objWriter->endElement(); + // c:dLbls\c:txPr\a:p\a:pPr\ + $objWriter->endElement(); + + // c:dLbls\c:txPr\a:p\a:endParaRPr + $objWriter->startElement('a:endParaRPr'); + $objWriter->writeAttribute('lang', 'en-US'); + $objWriter->writeAttribute('dirty', '0'); + $objWriter->endElement(); + + // c:dLbls\c:txPr\a:p\ + $objWriter->endElement(); + // c:dLbls\c:txPr\ + $objWriter->endElement(); + + $separator = $series->getSeparator(); + if (!empty($separator) && PHP_EOL != $separator) { + // c:dLbls\c:separator + $objWriter->writeElement('c:separator', $separator); + } + + // c:dLbls\ + $objWriter->endElement(); + } + + $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0'); + $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize()); + + $objWriter->endElement(); + } + + /** + * Write Type Pie. + * + * @param XMLWriter $objWriter XML Writer + * @param Pie $subject + * @param bool $includeSheet + */ + protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void + { + // c:pieChart + $objWriter->startElement('c:pieChart'); + + // c:varyColors + $objWriter->startElement('c:varyColors'); + $objWriter->writeAttribute('val', '1'); + $objWriter->endElement(); + + // Write series + $seriesIndex = 0; + foreach ($subject->getSeries() as $series) { + // c:ser + $objWriter->startElement('c:ser'); + + // c:idx + $objWriter->startElement('c:idx'); + $objWriter->writeAttribute('val', $seriesIndex); + $objWriter->endElement(); + + // c:order + $objWriter->startElement('c:order'); + $objWriter->writeAttribute('val', $seriesIndex); + $objWriter->endElement(); + + // c:tx + $objWriter->startElement('c:tx'); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); + $objWriter->endElement(); + + // Fills for points? + $dataPointFills = $series->getDataPointFills(); + foreach ($dataPointFills as $key => $value) { + // c:dPt + $objWriter->startElement('c:dPt'); + $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key); + // c:dPt/c:spPr + $objWriter->startElement('c:spPr'); + $this->writeFill($objWriter, $value); + // c:dPt/##c:spPr + $objWriter->endElement(); + // ##c:dPt $objWriter->endElement(); } @@ -1294,8 +1449,8 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeShee $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1344,9 +1499,6 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeShee // c:showLeaderLines $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); - // c:separator - $objWriter->writeElementIf($series->hasShowSeparator(), 'c:separator', 'val', $series->getSeparator()); - $objWriter->endElement(); // Write X axis data @@ -1362,7 +1514,7 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeShee // c:val $objWriter->startElement('c:val'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); @@ -1375,14 +1527,13 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, $includeShee } /** - * Write Type Pie3D + * Write Type Pie3D. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Pie3D $subject + * @param bool $includeSheet */ - protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $includeSheet = false) + protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void { // c:pie3DChart $objWriter->startElement('c:pie3DChart'); @@ -1410,7 +1561,7 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $include // c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -1424,18 +1575,13 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $include foreach ($dataPointFills as $key => $value) { // c:dPt $objWriter->startElement('c:dPt'); - - // c:idx - $this->writeElementWithValAttribute($objWriter, 'c:idx', $key); - - // c:spPr + $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key); + // c:dPt/c:spPr $objWriter->startElement('c:spPr'); - - // Write fill $this->writeFill($objWriter, $value); - + // c:dPt/##c:spPr $objWriter->endElement(); - + // ##c:dPt $objWriter->endElement(); } @@ -1465,8 +1611,8 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $include $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1512,9 +1658,6 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $include // c:showLeaderLines $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); - // c:separator - $objWriter->writeElementIf($series->hasShowSeparator(), 'c:separator', 'val', $series->getSeparator()); - $objWriter->endElement(); // Write X axis data @@ -1530,7 +1673,7 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $include // c:val $objWriter->startElement('c:val'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); @@ -1543,14 +1686,13 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, $include } /** - * Write Type Line + * Write Type Line. * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Line $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Line $subject + * @param bool $includeSheet */ - protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSheet = false) + protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void { // c:lineChart $objWriter->startElement('c:lineChart'); @@ -1578,7 +1720,7 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSh // c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -1620,8 +1762,8 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSh $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1664,9 +1806,6 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSh // c:showLeaderLines $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); - // c:separator - $objWriter->writeElementIf($series->hasShowSeparator(), 'c:separator', 'val', $series->getSeparator()); - // > c:dLbls $objWriter->endElement(); @@ -1683,10 +1822,15 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSh // c:val $objWriter->startElement('c:val'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); + // c:smooth + $objWriter->startElement('c:smooth'); + $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0'); + $objWriter->endElement(); + $objWriter->endElement(); ++$seriesIndex; @@ -1697,11 +1841,6 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSh $objWriter->writeAttribute('val', '1'); $objWriter->endElement(); - // c:smooth - $objWriter->startElement('c:smooth'); - $objWriter->writeAttribute('val', '0'); - $objWriter->endElement(); - // c:axId $objWriter->startElement('c:axId'); $objWriter->writeAttribute('val', '52743552'); @@ -1716,21 +1855,20 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, $includeSh } /** - * Write Type Scatter + * Write Type Radar * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter $subject - * @param boolean $includeSheet - * @throws \Exception + * @param XMLWriter $objWriter XML Writer + * @param Radar $subject + * @param bool $includeSheet */ - protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, $includeSheet = false) + protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void { // c:scatterChart - $objWriter->startElement('c:scatterChart'); + $objWriter->startElement('c:radarChart'); - // c:scatterStyle - $objWriter->startElement('c:scatterStyle'); - $objWriter->writeAttribute('val', 'lineMarker'); + // c:radarStyle + $objWriter->startElement('c:radarStyle'); + $objWriter->writeAttribute('val', 'marker'); $objWriter->endElement(); // c:varyColors @@ -1756,7 +1894,7 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, $inc // c:tx $objWriter->startElement('c:tx'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); @@ -1836,9 +1974,99 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, $inc // c:showLeaderLines $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); - // c:separator - $objWriter->writeElementIf($series->hasShowSeparator(), 'c:separator', 'val', $series->getSeparator()); + $objWriter->endElement(); + + // c:spPr + $objWriter->startElement('c:spPr'); + // Write fill + $this->writeFill($objWriter, $series->getFill()); + // Write outline + $this->writeOutline($objWriter, $series->getOutline()); + // ## c:spPr + $objWriter->endElement(); + + // Write X axis data + $axisXData = array_keys($series->getValues()); + + // c:cat + $objWriter->startElement('c:cat'); + $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData))); + $objWriter->endElement(); + + // Write Y axis data + $axisYData = array_values($series->getValues()); + + // c:val + $objWriter->startElement('c:val'); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); + $objWriter->endElement(); + + // c:smooth + $objWriter->startElement('c:smooth'); + $objWriter->writeAttribute('val', '0'); + $objWriter->endElement(); + + $objWriter->endElement(); + + ++$seriesIndex; + } + + // c:axId + $objWriter->startElement('c:axId'); + $objWriter->writeAttribute('val', '52743552'); + $objWriter->endElement(); + + // c:axId + $objWriter->startElement('c:axId'); + $objWriter->writeAttribute('val', '52749440'); + $objWriter->endElement(); + + $objWriter->endElement(); + } + + /** + * Write Type Scatter + * + * @param XMLWriter $objWriter + * @param Scatter $subject + * @param bool $includeSheet + */ + protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void + { + // c:scatterChart + $objWriter->startElement('c:scatterChart'); + + // c:scatterStyle + $objWriter->startElement('c:scatterStyle'); + $objWriter->writeAttribute('val', 'lineMarker'); + $objWriter->endElement(); + + // c:varyColors + $objWriter->startElement('c:varyColors'); + $objWriter->writeAttribute('val', '0'); + $objWriter->endElement(); + + // Write series + $seriesIndex = 0; + foreach ($subject->getSeries() as $series) { + // c:ser + $objWriter->startElement('c:ser'); + + // c:idx + $objWriter->startElement('c:idx'); + $objWriter->writeAttribute('val', $seriesIndex); + $objWriter->endElement(); + + // c:order + $objWriter->startElement('c:order'); + $objWriter->writeAttribute('val', $seriesIndex); + $objWriter->endElement(); + // c:tx + $objWriter->startElement('c:tx'); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : ''); + $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords); $objWriter->endElement(); // c:spPr @@ -1850,6 +2078,91 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, $inc // ## c:spPr $objWriter->endElement(); + // Marker + $this->writeSeriesMarker($objWriter, $series->getMarker()); + + // c:dLbls + $objWriter->startElement('c:dLbls'); + + // c:txPr + $objWriter->startElement('c:txPr'); + + // a:bodyPr + $objWriter->writeElement('a:bodyPr', null); + + // a:lstStyle + $objWriter->writeElement('a:lstStyle', null); + + // a:p + $objWriter->startElement('a:p'); + + // a:pPr + $objWriter->startElement('a:pPr'); + + // a:defRPr + $objWriter->startElement('a:defRPr'); + + $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); + $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); + $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); + $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); + $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + + // Font - a:solidFill + $objWriter->startElement('a:solidFill'); + + $this->writeColor($objWriter, $series->getFont()->getColor()); + + $objWriter->endElement(); + + // Font - a:latin + $objWriter->startElement('a:latin'); + $objWriter->writeAttribute('typeface', $series->getFont()->getName()); + $objWriter->endElement(); + + $objWriter->endElement(); + + $objWriter->endElement(); + + // a:endParaRPr + $objWriter->startElement('a:endParaRPr'); + $objWriter->writeAttribute('lang', 'en-US'); + $objWriter->writeAttribute('dirty', '0'); + $objWriter->endElement(); + + $objWriter->endElement(); + + $objWriter->endElement(); + + // c:showLegendKey + $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0'); + + // c:showVal + $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0'); + + // c:showCatName + $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0'); + + // c:showSerName + $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0'); + + // c:showPercent + $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0'); + + // c:separator + $separator = $series->getSeparator(); + if (!empty($separator) && PHP_EOL != $separator) { + // c:dLbls\c:separator + $objWriter->writeElement('c:separator', $separator); + } + + // c:showLeaderLines + $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0'); + + $objWriter->endElement(); + // Write X axis data $axisXData = array_keys($series->getValues()); @@ -1863,13 +2176,13 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, $inc // c:yVal $objWriter->startElement('c:yVal'); - $coords = ($includeSheet ? 'Sheet1!$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . \PHPExcel_Cell::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); + $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : ''); $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); // c:smooth $objWriter->startElement('c:smooth'); - $objWriter->writeAttribute('val', '0'); + $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0'); $objWriter->endElement(); $objWriter->endElement(); @@ -1891,13 +2204,13 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, $inc } /** - * Write chart relationships to XML format + * Write chart relationships to XML format. * - * @param \PhpOffice\PhpPresentation\Shape\Chart $pChart - * @return string XML Output - * @throws \Exception + * @param Chart $pChart + * + * @return string XML Output */ - public function writeChartRelationships(Chart $pChart) + protected function writeChartRelationships(Chart $pChart): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -1922,20 +2235,20 @@ public function writeChartRelationships(Chart $pChart) /** * @param XMLWriter $objWriter - * @param Chart\Marker $oMarker + * @param Chart\Marker $marker */ - protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $oMarker) + protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void { // c:marker $objWriter->startElement('c:marker'); // c:marker > c:symbol $objWriter->startElement('c:symbol'); - $objWriter->writeAttribute('val', $oMarker->getSymbol()); + $objWriter->writeAttribute('val', $marker->getSymbol()); $objWriter->endElement(); // Size if different of none - if ($oMarker->getSymbol() != Chart\Marker::SYMBOL_NONE) { - $markerSize = (int)$oMarker->getSize(); + if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) { + $markerSize = (int) $marker->getSize(); if ($markerSize < 2) { $markerSize = 2; } @@ -1943,7 +2256,7 @@ protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $oMarker $markerSize = 72; } - /** + /* * c:marker > c:size * Size in points * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx @@ -1952,22 +2265,30 @@ protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $oMarker $objWriter->writeAttribute('val', $markerSize); $objWriter->endElement(); } + + // // c:marker > c:spPr + $objWriter->startElement('c:spPr'); + $this->writeFill($objWriter, $marker->getFill()); + $this->writeBorder($objWriter, $marker->getBorder(), '', true); + $objWriter->endElement(); + + // > c:marker $objWriter->endElement(); } /** * @param XMLWriter $objWriter * @param Chart\Axis $oAxis - * @param $typeAxis + * @param string $typeAxis * @param Chart\Type\AbstractType $typeChart */ - protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, Chart\Type\AbstractType $typeChart) + protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void { - if ($typeAxis != Chart\Axis::AXIS_X && $typeAxis != Chart\Axis::AXIS_Y) { + if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) { return; } - if ($typeAxis == Chart\Axis::AXIS_X) { + if (Chart\Axis::AXIS_X == $typeAxis) { $mainElement = 'c:catAx'; $axIdVal = '52743552'; $axPosVal = 'b'; @@ -1995,13 +2316,13 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, $objWriter->writeAttribute('val', 'minMax'); $objWriter->endElement(); - if ($oAxis->getMaxBounds() != null) { + if (null != $oAxis->getMaxBounds()) { $objWriter->startElement('c:max'); $objWriter->writeAttribute('val', $oAxis->getMaxBounds()); $objWriter->endElement(); } - if ($oAxis->getMinBounds() != null) { + if (null != $oAxis->getMinBounds()) { $objWriter->startElement('c:min'); $objWriter->writeAttribute('val', $oAxis->getMinBounds()); $objWriter->endElement(); @@ -2038,7 +2359,7 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, $objWriter->endElement(); } - if ($oAxis->getTitle() != '') { + if ('' != $oAxis->getTitle()) { // c:title $objWriter->startElement('c:title'); @@ -2049,7 +2370,9 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, $objWriter->startElement('c:rich'); // a:bodyPr - $objWriter->writeElement('a:bodyPr', null); + $objWriter->startElement('a:bodyPr'); + $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation())); + $objWriter->endElement(); // a:lstStyle $objWriter->writeElement('a:lstStyle', null); @@ -2068,8 +2391,8 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline()); - $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000'); + $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000'); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -2138,7 +2461,7 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, // c:tickLblPos $objWriter->startElement('c:tickLblPos'); - $objWriter->writeAttribute('val', 'nextTo'); + $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition()); $objWriter->endElement(); // c:spPr @@ -2158,7 +2481,7 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, $objWriter->writeAttribute('val', 'autoZero'); $objWriter->endElement(); - if ($typeAxis == Chart\Axis::AXIS_X) { + if (Chart\Axis::AXIS_X == $typeAxis) { // c:lblAlgn $objWriter->startElement('c:lblAlgn'); $objWriter->writeAttribute('val', 'ctr'); @@ -2166,11 +2489,18 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, // c:lblOffset $objWriter->startElement('c:lblOffset'); - $objWriter->writeAttribute('val', '100%'); + $objWriter->writeAttribute('val', '100'); $objWriter->endElement(); + + // c:majorUnit + if ($oAxis->getMajorUnit() != null) { + $objWriter->startElement('c:tickLblSkip'); + $objWriter->writeAttribute('val', $oAxis->getMajorUnit()); + $objWriter->endElement(); + } } - if ($typeAxis == Chart\Axis::AXIS_Y) { + if (Chart\Axis::AXIS_Y == $typeAxis) { // c:crossBetween $objWriter->startElement('c:crossBetween'); // midCat : Position Axis On Tick Marks @@ -2183,14 +2513,14 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, $objWriter->endElement(); // c:majorUnit - if ($oAxis->getMajorUnit() != null) { + if (null != $oAxis->getMajorUnit()) { $objWriter->startElement('c:majorUnit'); $objWriter->writeAttribute('val', $oAxis->getMajorUnit()); $objWriter->endElement(); } // c:minorUnit - if ($oAxis->getMinorUnit() != null) { + if (null != $oAxis->getMinorUnit()) { $objWriter->startElement('c:minorUnit'); $objWriter->writeAttribute('val', $oAxis->getMinorUnit()); $objWriter->endElement(); @@ -2204,7 +2534,7 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, $typeAxis, * @param XMLWriter $objWriter * @param Gridlines $oGridlines */ - protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines) + protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void { // c:spPr $objWriter->startElement('c:spPr'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptComments.php b/src/PhpPresentation/Writer/PowerPoint2007/PptComments.php index badf1ac7e9..5a30c08a4b 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptComments.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptComments.php @@ -1,4 +1,22 @@ getPresentation()->getAllSlides() as $numSlide => $oSlide) { $contentXml = $this->writeSlideComments($oSlide); if (empty($contentXml)) { continue; } - $this->getZip()->addFromString('ppt/comments/comment'.($numSlide + 1).'.xml', $contentXml); + $this->getZip()->addFromString('ppt/comments/comment' . ($numSlide + 1) . '.xml', $contentXml); } + return $this->getZip(); } /** - * @param Slide $oSlide * @return string */ - protected function writeSlideComments(Slide $oSlide) + protected function writeSlideComments(Slide $oSlide): string { /** * @var Comment[] */ - $arrayComment = array(); + $arrayComment = []; foreach ($oSlide->getShapeCollection() as $oShape) { if ($oShape instanceof Comment) { $arrayComment[] = $oShape; diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptMedia.php b/src/PhpPresentation/Writer/PowerPoint2007/PptMedia.php index 0196e391f6..85a7acecc1 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptMedia.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptMedia.php @@ -1,15 +1,34 @@ getDrawingHashTable()->count(); ++$i) { $shape = $this->getDrawingHashTable()->getByIndex($i); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptPresProps.php b/src/PhpPresentation/Writer/PowerPoint2007/PptPresProps.php index df1234979c..c28f12d22f 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptPresProps.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptPresProps.php @@ -1,14 +1,34 @@ oPresentation->getPresentationProperties(); @@ -25,11 +45,18 @@ public function render() $objWriter->writeAttribute('xmlns:p', 'http://schemas.openxmlformats.org/presentationml/2006/main'); // p:presentationPr > p:showPr + $objWriter->startElement('p:showPr'); if ($presentationPpts->isLoopContinuouslyUntilEsc()) { - $objWriter->startElement('p:showPr'); $objWriter->writeAttribute('loop', '1'); - $objWriter->endElement(); } + // Depends on the slideshow type + // p:presentationPr > p:showPr > p:present + // p:presentationPr > p:showPr > p:browse + // p:presentationPr > p:showPr > p:kiosk + $objWriter->writeElement('p:' . $presentationPpts->getSlideshowType()); + + // > p:presentationPr > p:showPr + $objWriter->endElement(); // p:extLst $objWriter->startElement('p:extLst'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptPresentation.php b/src/PhpPresentation/Writer/PowerPoint2007/PptPresentation.php index 5e9b3305a2..a6aa3c1336 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptPresentation.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptPresentation.php @@ -1,16 +1,35 @@ startElement('p:sldMasterIdLst'); // Add slide masters - $relationId = 1; + $relationId = 1; $slideMasterId = 2147483648; $countMasterSlides = count($this->oPresentation->getAllMasterSlides()); - for ($inc = 1; $inc <= $countMasterSlides; $inc++) { + for ($inc = 1; $inc <= $countMasterSlides; ++$inc) { // p:sldMasterId $objWriter->startElement('p:sldMasterId'); $objWriter->writeAttribute('id', $slideMasterId); @@ -45,7 +64,7 @@ public function render() $objWriter->endElement(); // theme - $relationId++; + ++$relationId; // p:sldIdLst $objWriter->startElement('p:sldIdLst'); @@ -64,7 +83,7 @@ public function render() $objWriter->startElement('p:sldSz'); $objWriter->writeAttribute('cx', $this->oPresentation->getLayout()->getCX()); $objWriter->writeAttribute('cy', $this->oPresentation->getLayout()->getCY()); - if ($this->oPresentation->getLayout()->getDocumentLayout() != DocumentLayout::LAYOUT_CUSTOM) { + if (DocumentLayout::LAYOUT_CUSTOM != $this->oPresentation->getLayout()->getDocumentLayout()) { $objWriter->writeAttribute('type', $this->oPresentation->getLayout()->getDocumentLayout()); } $objWriter->endElement(); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptSlideLayouts.php b/src/PhpPresentation/Writer/PowerPoint2007/PptSlideLayouts.php index eaf3ac78ef..b482579d79 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptSlideLayouts.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptSlideLayouts.php @@ -1,39 +1,62 @@ oPresentation->getAllMasterSlides() as $oSlideMaster) { foreach ($oSlideMaster->getAllSlideLayouts() as $oSlideLayout) { - $this->oZip->addFromString('ppt/slideLayouts/_rels/slideLayout' . $oSlideLayout->layoutNr . '.xml.rels', $this->writeSlideLayoutRelationships($oSlideMaster->getRelsIndex())); + $this->oZip->addFromString('ppt/slideLayouts/_rels/slideLayout' . $oSlideLayout->layoutNr . '.xml.rels', $this->writeSlideLayoutRelationships($oSlideLayout)); $this->oZip->addFromString('ppt/slideLayouts/slideLayout' . $oSlideLayout->layoutNr . '.xml', $this->writeSlideLayout($oSlideLayout)); + + // Add background image slide + $oBkgImage = $oSlideLayout->getBackground(); + if ($oBkgImage instanceof Image) { + $this->oZip->addFromString('ppt/media/' . $oBkgImage->getIndexedFilename($oSlideLayout->getRelsIndex()), file_get_contents($oBkgImage->getPath())); + } } } return $this->oZip; } - /** - * Write slide layout relationships to XML format + * Write slide layout relationships to XML format. * - * @param int $masterId - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - public function writeSlideLayoutRelationships($masterId = 1) + protected function writeSlideLayoutRelationships(SlideLayout $oSlideLayout): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -45,8 +68,22 @@ public function writeSlideLayoutRelationships($masterId = 1) $objWriter->startElement('Relationships'); $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); + $relId = 0; + // Write slideMaster relationship - $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster', '../slideMasters/slideMaster' . $masterId . '.xml'); + $this->writeRelationship($objWriter, ++$relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster', '../slideMasters/slideMaster' . $oSlideLayout->getSlideMaster()->getRelsIndex() . '.xml'); + + // Write drawing relationships? + $relId = $this->writeDrawingRelations($oSlideLayout, $objWriter, ++$relId); + + // Write background relationships? + $oBackground = $oSlideLayout->getBackground(); + if ($oBackground instanceof Image) { + $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename($oSlideLayout->getRelsIndex())); + $oBackground->relationId = 'rId' . $relId; + + ++$relId; + } $objWriter->endElement(); @@ -55,13 +92,11 @@ public function writeSlideLayoutRelationships($masterId = 1) } /** - * Write slide to XML format + * Write slide to XML format. * - * @param \PhpOffice\PhpPresentation\Slide\SlideLayout $pSlideLayout * @return string XML Output - * @throws \Exception */ - public function writeSlideLayout(SlideLayout $pSlideLayout) + protected function writeSlideLayout(SlideLayout $pSlideLayout): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -75,7 +110,7 @@ public function writeSlideLayout(SlideLayout $pSlideLayout) $objWriter->writeAttribute('preserve', 1); // p:sldLayout\p:cSld $objWriter->startElement('p:cSld'); - $objWriter->writeAttributeIf($pSlideLayout->getLayoutName() != '', 'name', $pSlideLayout->getLayoutName()); + $objWriter->writeAttributeIf('' != $pSlideLayout->getLayoutName(), 'name', $pSlideLayout->getLayoutName()); // Background $this->writeSlideBackground($pSlideLayout, $objWriter); // p:sldLayout\p:cSld\p:spTree diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptSlideMasters.php b/src/PhpPresentation/Writer/PowerPoint2007/PptSlideMasters.php index b8ce79cab0..a7758a8984 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptSlideMasters.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptSlideMasters.php @@ -1,24 +1,39 @@ oPresentation->getAllMasterSlides() as $oMasterSlide) { // Add the relations from the masterSlide to the ZIP file @@ -37,14 +52,13 @@ public function render() } /** - * Write slide master relationships to XML format + * Write slide master relationships to XML format. + * + * @todo Set method in protected * - * @param SlideMaster $oMasterSlide * @return string XML Output - * @throws \Exception - * @internal param int $masterId Master slide id */ - public function writeSlideMasterRelationships(SlideMaster $oMasterSlide) + public function writeSlideMasterRelationships(SlideMaster $oMasterSlide): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -71,7 +85,7 @@ public function writeSlideMasterRelationships(SlideMaster $oMasterSlide) $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename($oMasterSlide->getRelsIndex())); $oBackground->relationId = 'rId' . $relId; - $relId++; + ++$relId; } // TODO: Write hyperlink relationships? @@ -84,13 +98,11 @@ public function writeSlideMasterRelationships(SlideMaster $oMasterSlide) } /** - * Write slide to XML format + * Write slide to XML format. * - * @param \PhpOffice\PhpPresentation\Slide\SlideMaster $pSlide * @return string XML Output - * @throws \Exception */ - public function writeSlideMaster(SlideMaster $pSlide) + protected function writeSlideMaster(SlideMaster $pSlide): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -177,35 +189,35 @@ public function writeSlideMaster(SlideMaster $pSlide) // p:sldMaster\p:txStyles $objWriter->startElement('p:txStyles'); - foreach (array( - 'p:titleStyle' => $pSlide->getTextStyles()->getTitleStyle(), - 'p:bodyStyle' => $pSlide->getTextStyles()->getBodyStyle(), - 'p:otherStyle' => $pSlide->getTextStyles()->getOtherStyle() - ) as $startElement => $stylesArray) { + foreach ([ + 'p:titleStyle' => $pSlide->getTextStyles()->getTitleStyle(), + 'p:bodyStyle' => $pSlide->getTextStyles()->getBodyStyle(), + 'p:otherStyle' => $pSlide->getTextStyles()->getOtherStyle(), + ] as $startElement => $stylesArray) { // titleStyle $objWriter->startElement($startElement); foreach ($stylesArray as $lvl => $oParagraph) { /** @var RichText\Paragraph $oParagraph */ - $elementName = ($lvl == 0 ? 'a:defPPr' : 'a:lvl' . $lvl . 'pPr'); + $elementName = (0 == $lvl ? 'a:defPPr' : 'a:lvl' . $lvl . 'pPr'); $objWriter->startElement($elementName); $objWriter->writeAttribute('algn', $oParagraph->getAlignment()->getHorizontal()); $objWriter->writeAttributeIf( - $oParagraph->getAlignment()->getMarginLeft() != 0, + 0 != $oParagraph->getAlignment()->getMarginLeft(), 'marL', CommonDrawing::pixelsToEmu($oParagraph->getAlignment()->getMarginLeft()) ); $objWriter->writeAttributeIf( - $oParagraph->getAlignment()->getMarginRight() != 0, + 0 != $oParagraph->getAlignment()->getMarginRight(), 'marR', CommonDrawing::pixelsToEmu($oParagraph->getAlignment()->getMarginRight()) ); $objWriter->writeAttributeIf( - $oParagraph->getAlignment()->getIndent() != 0, + 0 != $oParagraph->getAlignment()->getIndent(), 'indent', CommonDrawing::pixelsToEmu($oParagraph->getAlignment()->getIndent()) ); $objWriter->startElement('a:defRPr'); - $objWriter->writeAttributeIf($oParagraph->getFont()->getSize() != 10, 'sz', $oParagraph->getFont()->getSize() * 100); + $objWriter->writeAttributeIf(10 != $oParagraph->getFont()->getSize(), 'sz', $oParagraph->getFont()->getSize() * 100); $objWriter->writeAttributeIf($oParagraph->getFont()->isBold(), 'b', 1); $objWriter->writeAttributeIf($oParagraph->getFont()->isItalic(), 'i', 1); $objWriter->writeAttribute('kern', '1200'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php b/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php index 21637bf57c..8c2999d04a 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php @@ -1,7 +1,26 @@ oPresentation->getAllSlides() as $idx => $oSlide) { $this->oZip->addFromString('ppt/slides/_rels/slide' . ($idx + 1) . '.xml.rels', $this->writeSlideRelationships($oSlide)); @@ -39,7 +59,7 @@ public function render() // Add background image slide $oBkgImage = $oSlide->getBackground(); if ($oBkgImage instanceof Image) { - $this->oZip->addFromString('ppt/media/'.$oBkgImage->getIndexedFilename($idx), file_get_contents($oBkgImage->getPath())); + $this->oZip->addFromString('ppt/media/' . $oBkgImage->getIndexedFilename((string) $idx), file_get_contents($oBkgImage->getPath())); } } @@ -47,13 +67,11 @@ public function render() } /** - * Write slide relationships to XML format + * Write slide relationships to XML format. * - * @param \PhpOffice\PhpPresentation\Slide $pSlide - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - protected function writeSlideRelationships(Slide $pSlide) + protected function writeSlideRelationships(Slide $pSlide): string { //@todo Group all getShapeCollection()->getIterator @@ -109,9 +127,9 @@ protected function writeSlideRelationships(Slide $pSlide) if ($iterator2->current() instanceof Media) { // Write relationship for image drawing $iterator2->current()->relationId = 'rId' . $relId; - $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator->current()->getIndexedFilename()); + $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/video', '../media/' . $iterator2->current()->getIndexedFilename()); ++$relId; - $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator->current()->getIndexedFilename()); + $this->writeRelationship($objWriter, $relId, 'http://schemas.microsoft.com/office/2007/relationships/media', '../media/' . $iterator2->current()->getIndexedFilename()); ++$relId; } elseif ($iterator2->current() instanceof ShapeDrawing\AbstractDrawingAdapter) { // Write relationship for image drawing @@ -137,7 +155,7 @@ protected function writeSlideRelationships(Slide $pSlide) // Write background relationships? $oBackground = $pSlide->getBackground(); if ($oBackground instanceof Image) { - $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename($idxSlide)); + $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', '../media/' . $oBackground->getIndexedFilename((string) $idxSlide)); $oBackground->relationId = 'rId' . $relId; ++$relId; } @@ -150,7 +168,7 @@ protected function writeSlideRelationships(Slide $pSlide) // Hyperlink on shape if ($iterator->current()->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $iterator->current()->getHyperlink(); + $hyperlink = $iterator->current()->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -169,7 +187,7 @@ protected function writeSlideRelationships(Slide $pSlide) if ($element instanceof Run || $element instanceof TextElement) { if ($element->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $element->getHyperlink(); + $hyperlink = $element->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -189,10 +207,10 @@ protected function writeSlideRelationships(Slide $pSlide) if ($iterator->current() instanceof ShapeTable) { // Rows $countRows = count($iterator->current()->getRows()); - for ($row = 0; $row < $countRows; $row++) { + for ($row = 0; $row < $countRows; ++$row) { // Cells in rows $countCells = count($iterator->current()->getRow($row)->getCells()); - for ($cell = 0; $cell < $countCells; $cell++) { + for ($cell = 0; $cell < $countCells; ++$cell) { $currentCell = $iterator->current()->getRow($row)->getCell($cell); // Paragraphs in cell foreach ($currentCell->getParagraphs() as $paragraph) { @@ -202,7 +220,7 @@ protected function writeSlideRelationships(Slide $pSlide) if ($element instanceof Run || $element instanceof TextElement) { if ($element->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $element->getHyperlink(); + $hyperlink = $element->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -226,7 +244,7 @@ protected function writeSlideRelationships(Slide $pSlide) // Hyperlink on shape if ($iterator2->current()->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $iterator2->current()->getHyperlink(); + $hyperlink = $iterator2->current()->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -245,7 +263,7 @@ protected function writeSlideRelationships(Slide $pSlide) if ($element instanceof Run || $element instanceof TextElement) { if ($element->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $element->getHyperlink(); + $hyperlink = $element->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -265,10 +283,10 @@ protected function writeSlideRelationships(Slide $pSlide) if ($iterator2->current() instanceof ShapeTable) { // Rows $countRows = count($iterator2->current()->getRows()); - for ($row = 0; $row < $countRows; $row++) { + for ($row = 0; $row < $countRows; ++$row) { // Cells in rows $countCells = count($iterator2->current()->getRow($row)->getCells()); - for ($cell = 0; $cell < $countCells; $cell++) { + for ($cell = 0; $cell < $countCells; ++$cell) { $currentCell = $iterator2->current()->getRow($row)->getCell($cell); // Paragraphs in cell foreach ($currentCell->getParagraphs() as $paragraph) { @@ -278,7 +296,7 @@ protected function writeSlideRelationships(Slide $pSlide) if ($element instanceof Run || $element instanceof TextElement) { if ($element->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $element->getHyperlink(); + $hyperlink = $element->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -329,13 +347,13 @@ protected function writeSlideRelationships(Slide $pSlide) } if ($hasSlideComment) { - $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments/comment'.($idxSlide + 1).'.xml'); + $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments', '../comments/comment' . ($idxSlide + 1) . '.xml'); ++$relId; } } if ($pSlide->getNote()->getShapeCollection()->count() > 0) { - $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide'.($idxSlide + 1).'.xml'); + $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide' . ($idxSlide + 1) . '.xml'); } $objWriter->endElement(); @@ -345,13 +363,11 @@ protected function writeSlideRelationships(Slide $pSlide) } /** - * Write slide to XML format + * Write slide to XML format. * - * @param \PhpOffice\PhpPresentation\Slide $pSlide - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - public function writeSlide(Slide $pSlide) + protected function writeSlide(Slide $pSlide): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -498,11 +514,7 @@ public function writeSlide(Slide $pSlide) return $objWriter->getData(); } - /** - * @param XMLWriter $objWriter - * @param Slide $oSlide - */ - protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide) + protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide): void { $arrayAnimations = $oSlide->getAnimations(); if (empty($arrayAnimations)) { @@ -512,8 +524,8 @@ protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide) // Variables $shapeId = 1; $idCount = 1; - $hashToIdMap = array(); - $arrayAnimationIds = array(); + $hashToIdMap = []; + $arrayAnimationIds = []; foreach ($oSlide->getShapeCollection() as $shape) { $hashToIdMap[$shape->getHashCode()] = ++$shapeId; @@ -745,132 +757,4 @@ protected function writeSlideAnimations(XMLWriter $objWriter, Slide $oSlide) // ##p:timing $objWriter->endElement(); } - - /** - * Write pic - * - * @param \PhpOffice\Common\XMLWriter $objWriter XML Writer - * @param \PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter $shape - * @param int $shapeId - * @throws \Exception - */ - protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape, $shapeId) - { - // p:pic - $objWriter->startElement('p:pic'); - - // p:nvPicPr - $objWriter->startElement('p:nvPicPr'); - - // p:cNvPr - $objWriter->startElement('p:cNvPr'); - $objWriter->writeAttribute('id', $shapeId); - $objWriter->writeAttribute('name', $shape->getName()); - $objWriter->writeAttribute('descr', $shape->getDescription()); - - // a:hlinkClick - if ($shape->hasHyperlink()) { - $this->writeHyperlink($objWriter, $shape); - } - - $objWriter->endElement(); - - // p:cNvPicPr - $objWriter->startElement('p:cNvPicPr'); - - // a:picLocks - $objWriter->startElement('a:picLocks'); - $objWriter->writeAttribute('noChangeAspect', '1'); - $objWriter->endElement(); - - $objWriter->endElement(); - - // p:nvPr - $objWriter->startElement('p:nvPr'); - // PlaceHolder - if ($shape->isPlaceholder()) { - $objWriter->startElement('p:ph'); - $objWriter->writeAttribute('type', $shape->getPlaceholder()->getType()); - $objWriter->endElement(); - } - /** - * @link : https://github.com/stefslon/exportToPPTX/blob/master/exportToPPTX.m#L2128 - */ - if ($shape instanceof Media) { - // p:nvPr > a:videoFile - $objWriter->startElement('a:videoFile'); - $objWriter->writeAttribute('r:link', $shape->relationId); - $objWriter->endElement(); - // p:nvPr > p:extLst - $objWriter->startElement('p:extLst'); - // p:nvPr > p:extLst > p:ext - $objWriter->startElement('p:ext'); - $objWriter->writeAttribute('uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}'); - // p:nvPr > p:extLst > p:ext > p14:media - $objWriter->startElement('p14:media'); - $objWriter->writeAttribute('r:embed', ($shape->relationId + 1)); - $objWriter->writeAttribute('xmlns:p14', 'http://schemas.microsoft.com/office/powerpoint/2010/main'); - // p:nvPr > p:extLst > p:ext > ##p14:media - $objWriter->endElement(); - // p:nvPr > p:extLst > ##p:ext - $objWriter->endElement(); - // p:nvPr > ##p:extLst - $objWriter->endElement(); - } - // ##p:nvPr - $objWriter->endElement(); - $objWriter->endElement(); - - // p:blipFill - $objWriter->startElement('p:blipFill'); - - // a:blip - $objWriter->startElement('a:blip'); - $objWriter->writeAttribute('r:embed', $shape->relationId); - $objWriter->endElement(); - - // a:stretch - $objWriter->startElement('a:stretch'); - $objWriter->writeElement('a:fillRect', null); - $objWriter->endElement(); - - $objWriter->endElement(); - - // p:spPr - $objWriter->startElement('p:spPr'); - // a:xfrm - $objWriter->startElement('a:xfrm'); - $objWriter->writeAttributeIf($shape->getRotation() != 0, 'rot', CommonDrawing::degreesToAngle($shape->getRotation())); - - // a:off - $objWriter->startElement('a:off'); - $objWriter->writeAttribute('x', CommonDrawing::pixelsToEmu($shape->getOffsetX())); - $objWriter->writeAttribute('y', CommonDrawing::pixelsToEmu($shape->getOffsetY())); - $objWriter->endElement(); - - // a:ext - $objWriter->startElement('a:ext'); - $objWriter->writeAttribute('cx', CommonDrawing::pixelsToEmu($shape->getWidth())); - $objWriter->writeAttribute('cy', CommonDrawing::pixelsToEmu($shape->getHeight())); - $objWriter->endElement(); - - $objWriter->endElement(); - - // a:prstGeom - $objWriter->startElement('a:prstGeom'); - $objWriter->writeAttribute('prst', 'rect'); - - // a:avLst - $objWriter->writeElement('a:avLst', null); - - $objWriter->endElement(); - - $this->writeBorder($objWriter, $shape->getBorder(), ''); - - $this->writeShadow($objWriter, $shape->getShadow()); - - $objWriter->endElement(); - - $objWriter->endElement(); - } } diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptTableProps.php b/src/PhpPresentation/Writer/PowerPoint2007/PptTableProps.php index f79a1a15aa..ff2c5f851f 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptTableProps.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptTableProps.php @@ -1,14 +1,34 @@ oPresentation->getAllMasterSlides() as $oMasterSlide) { $this->getZip()->addFromString('ppt/theme/theme' . $oMasterSlide->getRelsIndex() . '.xml', $this->writeTheme($oMasterSlide)); @@ -20,16 +38,14 @@ public function render() return $this->getZip(); } - /** - * Write theme to XML format + * Write theme to XML format. * - * @param Slide\SlideMaster $oMasterSlide * @return string XML Output */ - protected function writeTheme(Slide\SlideMaster $oMasterSlide) + protected function writeTheme(Slide\SlideMaster $oMasterSlide): string { - $arrayFont = array( + $arrayFont = [ 'Jpan' => 'MS Pゴシック', 'Hang' => '맑은 고딕', 'Hans' => '宋体', @@ -59,12 +75,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) 'Mong' => 'Mongolian Baiti', 'Viet' => 'Times New Roman', 'Uigh' => 'Microsoft Uighur', - ); + ]; // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - $name = 'Theme'.rand(1, 100); + $name = 'Theme' . rand(1, 100); // XML header $objWriter->startDocument('1.0', 'UTF-8', 'yes'); @@ -83,13 +99,13 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) foreach ($oMasterSlide->getAllSchemeColors() as $oSchemeColor) { // a:theme/a:themeElements/a:clrScheme/a:* - $objWriter->startElement('a:'.$oSchemeColor->getValue()); + $objWriter->startElement('a:' . $oSchemeColor->getValue()); - if (in_array($oSchemeColor->getValue(), array( - 'dk1', 'lt1' - ))) { + if (in_array($oSchemeColor->getValue(), [ + 'dk1', 'lt1', + ])) { $objWriter->startElement('a:sysClr'); - $objWriter->writeAttribute('val', ($oSchemeColor->getValue() == 'dk1' ? 'windowText' : 'window')); + $objWriter->writeAttribute('val', ('dk1' == $oSchemeColor->getValue() ? 'windowText' : 'window')); $objWriter->writeAttribute('lastClr', $oSchemeColor->getRGB()); $objWriter->endElement(); } else { @@ -199,7 +215,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '0%'); + $objWriter->writeAttribute('pos', '0'); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -207,12 +223,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:tint $objWriter->startElement('a:tint'); - $objWriter->writeAttribute('val', '50%'); + $objWriter->writeAttribute('val', '50000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '300%'); + $objWriter->writeAttribute('val', '300000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -223,7 +239,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '35%'); + $objWriter->writeAttribute('pos', '35000'); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -231,12 +247,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:tint $objWriter->startElement('a:tint'); - $objWriter->writeAttribute('val', '37%'); + $objWriter->writeAttribute('val', '37000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '300%'); + $objWriter->writeAttribute('val', '300000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -247,7 +263,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '100%'); + $objWriter->writeAttribute('pos', '100000'); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -255,12 +271,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:tint $objWriter->startElement('a:tint'); - $objWriter->writeAttribute('val', '15%'); + $objWriter->writeAttribute('val', '15000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '350%'); + $objWriter->writeAttribute('val', '350000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -290,7 +306,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '0%'); + $objWriter->writeAttribute('pos', '0'); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -298,12 +314,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '51%'); + $objWriter->writeAttribute('val', '51000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '130%'); + $objWriter->writeAttribute('val', '130000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -314,7 +330,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '80%'); + $objWriter->writeAttribute('pos', '80000'); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -322,12 +338,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '93%'); + $objWriter->writeAttribute('val', '93000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '130%'); + $objWriter->writeAttribute('val', '130000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -338,7 +354,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '100%'); + $objWriter->writeAttribute('pos', '100000'); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -346,12 +362,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '94%'); + $objWriter->writeAttribute('val', '94000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '135%'); + $objWriter->writeAttribute('val', '135000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -394,12 +410,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '95%'); + $objWriter->writeAttribute('val', '95000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:fillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '105%'); + $objWriter->writeAttribute('val', '105000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:lnStyleLst/a:ln/a:solidFill/a:schemeClr/ @@ -497,7 +513,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst/a:effectStyle/a:effectLst/a:outerShdw/a:srgbClr/a:alpha $objWriter->startElement('a:alpha'); - $objWriter->writeAttribute('val', '38%'); + $objWriter->writeAttribute('val', '38000'); // a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst/a:effectStyle/a:effectLst/a:outerShdw/a:srgbClr/a:alpha/ $objWriter->endElement(); @@ -533,7 +549,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst/a:effectStyle/a:effectLst/a:outerShdw/a:srgbClr/a:alpha $objWriter->startElement('a:alpha'); - $objWriter->writeAttribute('val', '35%'); + $objWriter->writeAttribute('val', '35'); // a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst/a:effectStyle/a:effectLst/a:outerShdw/a:srgbClr/a:alpha/ $objWriter->endElement(); @@ -569,7 +585,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst/a:effectStyle/a:effectLst/a:outerShdw/a:srgbClr/a:alpha $objWriter->startElement('a:alpha'); - $objWriter->writeAttribute('val', '35%'); + $objWriter->writeAttribute('val', '35000'); // a:theme/a:themeElements/a:fmtScheme/a:effectStyleLst/a:effectStyle/a:effectLst/a:outerShdw/a:srgbClr/a:alpha/ $objWriter->endElement(); @@ -661,7 +677,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '0%'); + $objWriter->writeAttribute('pos', '0'); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -669,12 +685,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:tint $objWriter->startElement('a:tint'); - $objWriter->writeAttribute('val', '40%'); + $objWriter->writeAttribute('val', '40000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '350%'); + $objWriter->writeAttribute('val', '350000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -685,7 +701,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '40%'); + $objWriter->writeAttribute('pos', '40000'); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -693,17 +709,17 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:tint'); - $objWriter->writeAttribute('val', '45%'); + $objWriter->writeAttribute('val', '45000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '99%'); + $objWriter->writeAttribute('val', '99000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '350%'); + $objWriter->writeAttribute('val', '350000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -714,7 +730,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '100%'); + $objWriter->writeAttribute('pos', '100000'); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -722,12 +738,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '20%'); + $objWriter->writeAttribute('val', '20000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '255%'); + $objWriter->writeAttribute('val', '255000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -745,10 +761,10 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:path/a:fillToRect $objWriter->startElement('a:fillToRect'); - $objWriter->writeAttribute('b', '180%'); - $objWriter->writeAttribute('l', '50%'); - $objWriter->writeAttribute('r', '50%'); - $objWriter->writeAttribute('t', '-80%'); + $objWriter->writeAttribute('b', '180000'); + $objWriter->writeAttribute('l', '50000'); + $objWriter->writeAttribute('r', '50000'); + $objWriter->writeAttribute('t', '-80000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:path/ @@ -766,7 +782,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '0%'); + $objWriter->writeAttribute('pos', '0'); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -774,12 +790,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:tint $objWriter->startElement('a:tint'); - $objWriter->writeAttribute('val', '80%'); + $objWriter->writeAttribute('val', '80000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '300%'); + $objWriter->writeAttribute('val', '300000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -790,7 +806,7 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs $objWriter->startElement('a:gs'); - $objWriter->writeAttribute('pos', '100%'); + $objWriter->writeAttribute('pos', '100000'); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr $objWriter->startElement('a:schemeClr'); @@ -798,12 +814,12 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:shade $objWriter->startElement('a:shade'); - $objWriter->writeAttribute('val', '30%'); + $objWriter->writeAttribute('val', '30000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/a:satMod $objWriter->startElement('a:satMod'); - $objWriter->writeAttribute('val', '200%'); + $objWriter->writeAttribute('val', '200000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:gsLst/a:gs/a:schemeClr/ @@ -821,10 +837,10 @@ protected function writeTheme(Slide\SlideMaster $oMasterSlide) // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:path/a:fillToRect $objWriter->startElement('a:fillToRect'); - $objWriter->writeAttribute('b', '50%'); - $objWriter->writeAttribute('l', '50%'); - $objWriter->writeAttribute('r', '50%'); - $objWriter->writeAttribute('t', '50%'); + $objWriter->writeAttribute('b', '50000'); + $objWriter->writeAttribute('l', '50000'); + $objWriter->writeAttribute('r', '50000'); + $objWriter->writeAttribute('t', '50000'); $objWriter->endElement(); // a:theme/a:themeElements/a:fmtScheme/a:bgFillStyleLst/a:gradFill/a:path/ diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptViewProps.php b/src/PhpPresentation/Writer/PowerPoint2007/PptViewProps.php index 2c155d5c96..2a89473843 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptViewProps.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptViewProps.php @@ -1,14 +1,34 @@ startElement('a:sx'); $objWriter->writeAttribute('d', '100'); - $objWriter->writeAttribute('n', (int)($this->getPresentation()->getPresentationProperties()->getZoom() * 100)); + $objWriter->writeAttribute('n', (int) ($this->getPresentation()->getPresentationProperties()->getZoom() * 100)); $objWriter->endElement(); $objWriter->startElement('a:sy'); $objWriter->writeAttribute('d', '100'); - $objWriter->writeAttribute('n', (int)($this->getPresentation()->getPresentationProperties()->getZoom() * 100)); + $objWriter->writeAttribute('n', (int) ($this->getPresentation()->getPresentationProperties()->getZoom() * 100)); $objWriter->endElement(); // > // p:viewPr > p:slideViewPr > p:cSldViewPr > p:cViewPr > p:scale diff --git a/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php b/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php index fc0af80950..9069ed485f 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php @@ -1,18 +1,38 @@ getZip()->addFromString('_rels/.rels', $this->writeRelationships()); $this->getZip()->addFromString('ppt/_rels/presentation.xml.rels', $this->writePresentationRelationships()); @@ -21,12 +41,11 @@ public function render() } /** - * Write relationships to XML format + * Write relationships to XML format. * - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - public function writeRelationships() + protected function writeRelationships(): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -66,12 +85,11 @@ public function writeRelationships() } /** - * Write presentation relationships to XML format + * Write presentation relationships to XML format. * - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - public function writePresentationRelationships() + protected function writePresentationRelationships(): string { // Create XML writer $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); @@ -105,7 +123,6 @@ public function writePresentationRelationships() $this->writeRelationship($objWriter, $relationId++, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/viewProps', 'viewProps.xml'); $this->writeRelationship($objWriter, $relationId++, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableStyles', 'tableStyles.xml'); - // Comments Authors foreach ($this->getPresentation()->getAllSlides() as $oSlide) { foreach ($oSlide->getShapeCollection() as $oShape) { diff --git a/src/PhpPresentation/Writer/Serialized.php b/src/PhpPresentation/Writer/Serialized.php index da8aa403f5..5482c1e2ee 100644 --- a/src/PhpPresentation/Writer/Serialized.php +++ b/src/PhpPresentation/Writer/Serialized.php @@ -10,47 +10,56 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Writer; use PhpOffice\Common\Adapter\Zip\ZipArchiveAdapter; use PhpOffice\Common\XMLWriter; +use PhpOffice\PhpPresentation\Exception\DirectoryNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidParameterException; use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter; +use PhpOffice\PhpPresentation\Shape\Drawing\File; /** - * \PhpOffice\PhpPresentation\Writer\Serialized + * \PhpOffice\PhpPresentation\Writer\Serialized. */ class Serialized extends AbstractWriter implements WriterInterface { /** - * Create a new \PhpOffice\PhpPresentation\Writer\Serialized + * Create a new \PhpOffice\PhpPresentation\Writer\Serialized. * * @param \PhpOffice\PhpPresentation\PhpPresentation $pPhpPresentation */ public function __construct(PhpPresentation $pPhpPresentation = null) { // Set PhpPresentation - $this->setPhpPresentation($pPhpPresentation); + $this->setPhpPresentation($pPhpPresentation ?? new PhpPresentation()); // Set ZIP Adapter $this->setZipAdapter(new ZipArchiveAdapter()); } /** - * Save PhpPresentation to file + * Save PhpPresentation to file. * - * @param string $pFilename - * @throws \Exception + * @throws DirectoryNotFoundException + * @throws InvalidParameterException */ - public function save($pFilename) + public function save(string $pFilename): void { if (empty($pFilename)) { - throw new \Exception("Filename is empty."); + throw new InvalidParameterException('pFilename', ''); + } + if (!is_dir(dirname($pFilename))) { + throw new DirectoryNotFoundException(dirname($pFilename)); } $oPresentation = $this->getPhpPresentation(); @@ -66,7 +75,10 @@ public function save($pFilename) for ($j = 0; $j < $oPresentation->getSlide($i)->getShapeCollection()->count(); ++$j) { if ($oPresentation->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { $imgTemp = $oPresentation->getSlide($i)->getShapeCollection()->offsetGet($j); - $objZip->addFromString('media/' . $imgTemp->getIndexedFilename(), file_get_contents($imgTemp->getPath())); + $objZip->addFromString( + 'media/' . $imgTemp->getImageIndex() . '/' . pathinfo($imgTemp->getPath(), PATHINFO_BASENAME), + file_get_contents($imgTemp->getPath()) + ); } } } @@ -79,14 +91,14 @@ public function save($pFilename) } /** - * Serialize PhpPresentation object to XML + * Serialize PhpPresentation object to XML. + * + * @param PhpPresentation|null $pPhpPresentation + * @param string $pFilename * - * @param PhpPresentation $pPhpPresentation - * @param string $pFilename - * @return string XML Output - * @throws \Exception + * @return string XML Output */ - private function writeSerialized(PhpPresentation $pPhpPresentation = null, $pFilename = '') + protected function writeSerialized(PhpPresentation $pPhpPresentation = null, $pFilename = '') { // Clone $pPhpPresentation $pPhpPresentation = clone $pPhpPresentation; @@ -96,7 +108,13 @@ private function writeSerialized(PhpPresentation $pPhpPresentation = null, $pFil for ($i = 0; $i < $slideCount; ++$i) { for ($j = 0; $j < $pPhpPresentation->getSlide($i)->getShapeCollection()->count(); ++$j) { if ($pPhpPresentation->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { - $pPhpPresentation->getSlide($i)->getShapeCollection()->offsetGet($j)->setPath('zip://' . $pFilename . '#media/' . $pPhpPresentation->getSlide($i)->getShapeCollection()->offsetGet($j)->getIndexedFilename(), false); + $imgTemp = $pPhpPresentation->getSlide($i)->getShapeCollection()->offsetGet($j); + $imgPath = 'zip://' . $pFilename . '#media/' . $imgTemp->getImageIndex() . '/' . pathinfo($imgTemp->getPath(), PATHINFO_BASENAME); + if ($imgTemp instanceof File) { + $imgTemp->setPath($imgPath, false); + } else { + $imgTemp->setPath($imgPath); + } } } } diff --git a/src/PhpPresentation/Writer/WriterInterface.php b/src/PhpPresentation/Writer/WriterInterface.php index bf63a35cf6..ab64192e1a 100644 --- a/src/PhpPresentation/Writer/WriterInterface.php +++ b/src/PhpPresentation/Writer/WriterInterface.php @@ -10,23 +10,23 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @link https://github.com/PHPOffice/PHPPresentation + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Writer; /** - * Writer interface + * Writer interface. */ interface WriterInterface { /** * Save PhpPresentation to file - * - * @param string $pFilename - * @throws \Exception */ - public function save($pFilename); + public function save(string $pFilename): void; } diff --git a/tests/PhpPresentation/Tests/AbstractShapeTest.php b/tests/PhpPresentation/Tests/AbstractShapeTest.php index 4b06e6b13a..8cb097b2d5 100644 --- a/tests/PhpPresentation/Tests/AbstractShapeTest.php +++ b/tests/PhpPresentation/Tests/AbstractShapeTest.php @@ -10,30 +10,36 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @copyright 2010-2014 PhpPresentation contributors + * @see https://github.com/PHPOffice/PHPPresentation + * + * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; -use PhpOffice\PhpPresentation\Shape\Placeholder; -use PhpOffice\PhpPresentation\Slide; +use PhpOffice\PhpPresentation\AbstractShape; +use PhpOffice\PhpPresentation\Exception\ShapeContainerAlreadyAssignedException; use PhpOffice\PhpPresentation\Shape\Hyperlink; +use PhpOffice\PhpPresentation\Shape\Placeholder; use PhpOffice\PhpPresentation\Shape\RichText; +use PhpOffice\PhpPresentation\Slide; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Shadow; +use PHPUnit\Framework\TestCase; /** - * Test class for Autoloader + * Test class for Autoloader. */ -class AbstractShapeTest extends \PHPUnit_Framework_TestCase +class AbstractShapeTest extends TestCase { /** - * Register + * Register. */ - public function testConstruct() + public function testConstruct(): void { $object = new RichText(); @@ -42,141 +48,141 @@ public function testConstruct() $this->assertEquals(0, $object->getHeight()); $this->assertEquals(0, $object->getRotation()); $this->assertEquals(0, $object->getWidth()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->getBorder()); + $this->assertInstanceOf(Border::class, $object->getBorder()); $this->assertEquals(Border::LINE_NONE, $object->getBorder()->getLineStyle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->getShadow()); + $this->assertInstanceOf(Fill::class, $object->getFill()); + $this->assertInstanceOf(Shadow::class, $object->getShadow()); } - public function testFill() + public function testFill(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setFill()); + $this->assertInstanceOf(AbstractShape::class, $object->setFill()); $this->assertNull($object->getFill()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setFill(new Fill())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertInstanceOf(AbstractShape::class, $object->setFill(new Fill())); + $this->assertInstanceOf(Fill::class, $object->getFill()); } - public function testHeight() + public function testHeight(): void { $object = new RichText(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setHeight()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(AbstractShape::class, $object->setHeight()); $this->assertEquals(0, $object->getHeight()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setHeight($value)); + $this->assertInstanceOf(AbstractShape::class, $object->setHeight($value)); $this->assertEquals($value, $object->getHeight()); } - public function testHyperlink() + public function testHyperlink(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setHyperlink()); + $this->assertInstanceOf(AbstractShape::class, $object->setHyperlink()); $this->assertFalse($object->hasHyperlink()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Hyperlink', $object->getHyperlink()); + $this->assertInstanceOf(Hyperlink::class, $object->getHyperlink()); $this->assertTrue($object->hasHyperlink()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setHyperlink(new Hyperlink('http://www.google.fr'))); + $this->assertInstanceOf(AbstractShape::class, $object->setHyperlink(new Hyperlink('http://www.google.fr'))); $this->assertTrue($object->hasHyperlink()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Hyperlink', $object->getHyperlink()); + $this->assertInstanceOf(Hyperlink::class, $object->getHyperlink()); $this->assertTrue($object->hasHyperlink()); } - public function testOffsetX() + public function testOffsetX(): void { $object = new RichText(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setOffsetX()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(AbstractShape::class, $object->setOffsetX()); $this->assertEquals(0, $object->getOffsetX()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setOffsetX($value)); + $this->assertInstanceOf(AbstractShape::class, $object->setOffsetX($value)); $this->assertEquals($value, $object->getOffsetX()); } - public function testOffsetY() + public function testOffsetY(): void { $object = new RichText(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setOffsetY()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(AbstractShape::class, $object->setOffsetY()); $this->assertEquals(0, $object->getOffsetY()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setOffsetY($value)); + $this->assertInstanceOf(AbstractShape::class, $object->setOffsetY($value)); $this->assertEquals($value, $object->getOffsetY()); } - public function testRotation() + public function testRotation(): void { $object = new RichText(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setRotation()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(AbstractShape::class, $object->setRotation()); $this->assertEquals(0, $object->getRotation()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setRotation($value)); + $this->assertInstanceOf(AbstractShape::class, $object->setRotation($value)); $this->assertEquals($value, $object->getRotation()); } - public function testShadow() + public function testShadow(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setShadow()); + $this->assertInstanceOf(AbstractShape::class, $object->setShadow()); $this->assertNull($object->getShadow()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setShadow(new Shadow())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->getShadow()); + $this->assertInstanceOf(AbstractShape::class, $object->setShadow(new Shadow())); + $this->assertInstanceOf(Shadow::class, $object->getShadow()); } - public function testWidth() + public function testWidth(): void { $object = new RichText(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setWidth()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(AbstractShape::class, $object->setWidth()); $this->assertEquals(0, $object->getWidth()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setWidth($value)); + $this->assertInstanceOf(AbstractShape::class, $object->setWidth($value)); $this->assertEquals($value, $object->getWidth()); } - public function testWidthAndHeight() + public function testWidthAndHeight(): void { $object = new RichText(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setWidthAndHeight()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(AbstractShape::class, $object->setWidthAndHeight()); $this->assertEquals(0, $object->getWidth()); $this->assertEquals(0, $object->getHeight()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setWidthAndHeight($value)); + $this->assertInstanceOf(AbstractShape::class, $object->setWidthAndHeight($value)); $this->assertEquals($value, $object->getWidth()); $this->assertEquals(0, $object->getHeight()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setWidthAndHeight($value, $value)); + $this->assertInstanceOf(AbstractShape::class, $object->setWidthAndHeight($value, $value)); $this->assertEquals($value, $object->getWidth()); $this->assertEquals($value, $object->getHeight()); } - public function testPlaceholder() + public function testPlaceholder(): void { $object = new RichText(); $this->assertFalse($object->isPlaceholder(), 'Standard Shape should not be a placeholder object'); $this->assertNull($object->getPlaceholder()); $this->assertInstanceOf( - 'PhpOffice\\PhpPresentation\\AbstractShape', + AbstractShape::class, $object->setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_TITLE)) ); $this->assertTrue($object->isPlaceholder()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Placeholder', $object->getPlaceholder()); + $this->assertInstanceOf(Placeholder::class, $object->getPlaceholder()); $this->assertEquals('title', $object->getPlaceholder()->getType()); $object = new RichText(); $this->assertFalse($object->isPlaceholder(), 'Standard Shape should not be a placeholder object'); $placeholder = new Placeholder(Placeholder::PH_TYPE_TITLE); $placeholder->setType(Placeholder::PH_TYPE_SUBTITLE); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setPlaceHolder($placeholder)); + $this->assertInstanceOf(AbstractShape::class, $object->setPlaceHolder($placeholder)); $this->assertTrue($object->isPlaceholder()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Placeholder', $object->getPlaceholder()); + $this->assertInstanceOf(Placeholder::class, $object->getPlaceholder()); $this->assertEquals('subTitle', $object->getPlaceholder()->getType()); } - public function testContainer() + public function testContainer(): void { $object = new RichText(); $object2 = new RichText(); @@ -185,24 +191,22 @@ public function testContainer() $oSlide->addShape($object2); $this->assertNull($object->getContainer()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setContainer($oSlide)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->getContainer()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setContainer(null, true)); + $this->assertInstanceOf(AbstractShape::class, $object->setContainer($oSlide)); + $this->assertInstanceOf(Slide::class, $object->getContainer()); + $this->assertInstanceOf(AbstractShape::class, $object->setContainer(null, true)); $this->assertNull($object->getContainer()); } - /** - * @expectedException \Exception - * @expectedExceptionMessage A \PhpOffice\PhpPresentation\ShapeContainerInterface has already been assigned. Shapes can only exist on one \PhpOffice\PhpPresentation\ShapeContainerInterface. - */ - public function testContainerException() + public function testContainerException(): void { $object = new RichText(); $oSlide = new Slide(); $this->assertNull($object->getContainer()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setContainer($oSlide)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->getContainer()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\AbstractShape', $object->setContainer(null)); + $this->assertInstanceOf(AbstractShape::class, $object->setContainer($oSlide)); + $this->assertInstanceOf(Slide::class, $object->getContainer()); + $this->expectException(ShapeContainerAlreadyAssignedException::class); + $this->expectExceptionMessage('The shape PhpOffice\PhpPresentation\AbstractShape has already a container assigned'); + $object->setContainer(null); } } diff --git a/tests/PhpPresentation/Tests/AutoloaderTest.php b/tests/PhpPresentation/Tests/AutoloaderTest.php index 31fd2c99ed..c1b32c0c4e 100644 --- a/tests/PhpPresentation/Tests/AutoloaderTest.php +++ b/tests/PhpPresentation/Tests/AutoloaderTest.php @@ -10,36 +10,40 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @copyright 2010-2014 PhpPresentation contributors + * @see https://github.com/PHPOffice/PHPPresentation + * + * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\Autoloader; +use PHPUnit\Framework\TestCase; /** - * Test class for Autoloader + * Test class for Autoloader. */ -class AutoloaderTest extends \PHPUnit_Framework_TestCase +class AutoloaderTest extends TestCase { /** - * Register + * Register. */ - public function testRegister() + public function testRegister(): void { Autoloader::register(); $this->assertContains( - array('PhpOffice\\PhpPresentation\\Autoloader', 'autoload'), + ['PhpOffice\\PhpPresentation\\Autoloader', 'autoload'], spl_autoload_functions() ); } /** - * Autoload + * Autoload. */ - public function testAutoload() + public function testAutoload(): void { $declared = get_declared_classes(); $declaredCount = count($declared); diff --git a/tests/PhpPresentation/Tests/DocumentLayoutTest.php b/tests/PhpPresentation/Tests/DocumentLayoutTest.php index bbbc6e86ed..1d1c1c4883 100644 --- a/tests/PhpPresentation/Tests/DocumentLayoutTest.php +++ b/tests/PhpPresentation/Tests/DocumentLayoutTest.php @@ -10,26 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\DocumentLayout; +use PHPUnit\Framework\TestCase; /** - * Test class for DocumentLayout + * Test class for DocumentLayout. * - * @coversDefaultClass PhpOffice\PhpPresentation\DocumentLayout + * @coversDefaultClass \PhpOffice\PhpPresentation\DocumentLayout */ -class DocumentLayoutTest extends \PHPUnit_Framework_TestCase +class DocumentLayoutTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new DocumentLayout(); @@ -39,24 +43,24 @@ public function testConstruct() } /** - * Test set custom layout + * Test set custom layout. */ - public function testSetCustomLayout() + public function testSetCustomLayout(): void { $object = new DocumentLayout(); - $object->setDocumentLayout(array('cx' => 6858000, 'cy' => 9144000), false); + $object->setDocumentLayout(['cx' => 6858000, 'cy' => 9144000], false); $this->assertEquals(DocumentLayout::LAYOUT_CUSTOM, $object->getDocumentLayout()); $this->assertEquals(9144000, $object->getCX()); $this->assertEquals(6858000, $object->getCY()); - $object->setDocumentLayout(array('cx' => 6858000, 'cy' => 9144000), true); + $object->setDocumentLayout(['cx' => 6858000, 'cy' => 9144000], true); $this->assertEquals(DocumentLayout::LAYOUT_CUSTOM, $object->getDocumentLayout()); $this->assertEquals(6858000, $object->getCX()); $this->assertEquals(9144000, $object->getCY()); } - public function testCX() + public function testCX(): void { - $value = rand(1, 100000); + $value = mt_rand(1, 100000); $object = new DocumentLayout(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentLayout', $object->setCX($value)); $this->assertEquals($value, $object->getCX()); @@ -74,9 +78,9 @@ public function testCX() $this->assertEquals($value, $object->getCX(DocumentLayout::UNIT_PIXEL)); } - public function testCY() + public function testCY(): void { - $value = rand(1, 100000); + $value = mt_rand(1, 100000); $object = new DocumentLayout(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentLayout', $object->setCY($value)); $this->assertEquals($value, $object->getCY()); diff --git a/tests/PhpPresentation/Tests/DocumentPropertiesTest.php b/tests/PhpPresentation/Tests/DocumentPropertiesTest.php index 34a2db853e..3e520d0457 100644 --- a/tests/PhpPresentation/Tests/DocumentPropertiesTest.php +++ b/tests/PhpPresentation/Tests/DocumentPropertiesTest.php @@ -10,29 +10,33 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\DocumentProperties; +use PHPUnit\Framework\TestCase; /** - * Test class for DocumentProperties + * Test class for DocumentProperties. * - * @coversDefaultClass PhpOffice\PhpPresentation\DocumentProperties + * @coversDefaultClass \PhpOffice\PhpPresentation\DocumentProperties */ -class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase +class DocumentPropertiesTest extends TestCase { /** - * Test get set value + * Test get set value. */ - public function testGetSet() + public function testGetSet(): void { $object = new DocumentProperties(); - $properties = array( + $properties = [ 'creator' => '', 'lastModifiedBy' => '', 'created' => '', @@ -43,7 +47,7 @@ public function testGetSet() 'keywords' => '', 'category' => '', 'company' => '', - ); + ]; foreach ($properties as $key => $val) { $get = "get{$key}"; @@ -54,15 +58,15 @@ public function testGetSet() } /** - * Test get set with null value + * Test get set with null value. */ - public function testGetSetNull() + public function testGetSetNull(): void { $object = new DocumentProperties(); - $properties = array( + $properties = [ 'created' => '', 'modified' => '', - ); + ]; $time = time(); foreach (array_keys($properties) as $key) { @@ -72,4 +76,58 @@ public function testGetSetNull() $this->assertEquals($time, $object->$get()); } } + + public function testCustomProperties(): void + { + $valueTime = time(); + + $object = new DocumentProperties(); + $this->assertIsArray($object->getCustomProperties()); + $this->assertCount(0, $object->getCustomProperties()); + $this->assertFalse($object->isCustomPropertySet('pName')); + $this->assertNull($object->getCustomPropertyType('pName')); + $this->assertNull($object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', 'pValue', null)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_STRING, $object->getCustomPropertyType('pName')); + $this->assertEquals('pValue', $object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', 2, null)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_INTEGER, $object->getCustomPropertyType('pName')); + $this->assertEquals(2, $object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', 2.1, null)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_FLOAT, $object->getCustomPropertyType('pName')); + $this->assertEquals(2.1, $object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', true, null)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_BOOLEAN, $object->getCustomPropertyType('pName')); + $this->assertEquals(true, $object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', null, null)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_STRING, $object->getCustomPropertyType('pName')); + $this->assertEquals(null, $object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', $valueTime, DocumentProperties::PROPERTY_TYPE_DATE)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_DATE, $object->getCustomPropertyType('pName')); + $this->assertEquals($valueTime, $object->getCustomPropertyValue('pName')); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->setCustomProperty('pName', (string) $valueTime, DocumentProperties::PROPERTY_TYPE_UNKNOWN)); + $this->assertCount(1, $object->getCustomProperties()); + $this->assertTrue($object->isCustomPropertySet('pName')); + $this->assertEquals(DocumentProperties::PROPERTY_TYPE_STRING, $object->getCustomPropertyType('pName')); + $this->assertEquals($valueTime, $object->getCustomPropertyValue('pName')); + } } diff --git a/tests/PhpPresentation/Tests/HashTableTest.php b/tests/PhpPresentation/Tests/HashTableTest.php index 572f1dd6ec..18c3a149a5 100644 --- a/tests/PhpPresentation/Tests/HashTableTest.php +++ b/tests/PhpPresentation/Tests/HashTableTest.php @@ -10,90 +10,86 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\HashTable; use PhpOffice\PhpPresentation\Slide; +use PHPUnit\Framework\TestCase; /** - * Test class for HashTable + * Test class for HashTable. * - * @coversDefaultClass PhpOffice\PhpPresentation\HashTable + * @coversDefaultClass \PhpOffice\PhpPresentation\HashTable */ -class HashTableTest extends \PHPUnit_Framework_TestCase +class HashTableTest extends TestCase { - /** - */ - public function testConstructNull() + public function testConstructNull(): void { $object = new HashTable(); $this->assertEquals(0, $object->count()); $this->assertNull($object->getByIndex()); $this->assertNull($object->getByHashCode()); - $this->assertInternalType('array', $object->toArray()); + $this->assertIsArray($object->toArray()); $this->assertEmpty($object->toArray()); } - /** - */ - public function testConstructSource() + public function testConstructSource(): void { - $object = new HashTable(array( + $object = new HashTable([ new Slide(), new Slide(), - )); + ]); $this->assertEquals(2, $object->count()); - $this->assertInternalType('array', $object->toArray()); + $this->assertIsArray($object->toArray()); $this->assertCount(2, $object->toArray()); } - /** - */ - public function testAdd() + public function testAdd(): void { $object = new HashTable(); $oSlide = new Slide(); // Add From Source : Null - $this->assertNull($object->addFromSource()); + $object->addFromSource(); // Add From Source : Array - $this->assertNull($object->addFromSource(array($oSlide))); - $this->assertInternalType('array', $object->toArray()); + $object->addFromSource([$oSlide]); + $this->assertIsArray($object->toArray()); $this->assertCount(1, $object->toArray()); // Clear - $this->assertNull($object->clear()); + $object->clear(); $this->assertEmpty($object->toArray()); // Add Object - $this->assertNull($object->add($oSlide)); + $object->add($oSlide); $this->assertCount(1, $object->toArray()); - $this->assertNull($object->clear()); + $object->clear(); // Add Object w/Hash Index $oSlide->setHashIndex(rand(1, 100)); - $this->assertNull($object->add($oSlide)); + $object->add($oSlide); $this->assertCount(1, $object->toArray()); // Add Object w/the same Hash Index - $this->assertNull($object->add($oSlide)); + $object->add($oSlide); $this->assertCount(1, $object->toArray()); } - /** - */ - public function testIndex() + public function testIndex(): void { $object = new HashTable(); $oSlide1 = new Slide(); $oSlide2 = new Slide(); // Add Object - $this->assertNull($object->add($oSlide1)); - $this->assertNull($object->add($oSlide2)); + $object->add($oSlide1); + $object->add($oSlide2); // Index $this->assertEquals(0, $object->getIndexForHashCode($oSlide1->getHashCode())); $this->assertEquals(1, $object->getIndexForHashCode($oSlide2->getHashCode())); @@ -101,9 +97,7 @@ public function testIndex() $this->assertEquals($oSlide2, $object->getByIndex(1)); } - /** - */ - public function testRemove() + public function testRemove(): void { $object = new HashTable(); $oSlide1 = new Slide(); @@ -111,24 +105,13 @@ public function testRemove() $oSlide3 = new Slide(); // Add Object - $this->assertNull($object->add($oSlide1)); - $this->assertNull($object->add($oSlide2)); - $this->assertNull($object->add($oSlide3)); + $object->add($oSlide1); + $object->add($oSlide2); + $object->add($oSlide3); // Remove - $this->assertNull($object->remove($oSlide2)); + $object->remove($oSlide2); $this->assertCount(2, $object->toArray()); - $this->assertNull($object->remove($oSlide3)); + $object->remove($oSlide3); $this->assertCount(1, $object->toArray()); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Invalid array parameter passed. - */ - public function testAddException() - { - $object = new HashTable(); - $oSlide = new Slide(); - $object->addFromSource($oSlide); - } } diff --git a/tests/PhpPresentation/Tests/IOFactoryTest.php b/tests/PhpPresentation/Tests/IOFactoryTest.php index c030899838..d17f615482 100644 --- a/tests/PhpPresentation/Tests/IOFactoryTest.php +++ b/tests/PhpPresentation/Tests/IOFactoryTest.php @@ -10,27 +10,33 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; +use PhpOffice\PhpPresentation\Exception\InvalidClassException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; use PhpOffice\PhpPresentation\IOFactory; use PhpOffice\PhpPresentation\PhpPresentation; +use PHPUnit\Framework\TestCase; /** - * Test class for IOFactory + * Test class for IOFactory. * - * @coversDefaultClass PhpOffice\PhpPresentation\IOFactory + * @coversDefaultClass \PhpOffice\PhpPresentation\IOFactory */ -class IOFactoryTest extends \PHPUnit_Framework_TestCase +class IOFactoryTest extends TestCase { /** - * Test create writer + * Test create writer. */ - public function testCreateWriter() + public function testCreateWriter(): void { $class = 'PhpOffice\\PhpPresentation\\Writer\\PowerPoint2007'; @@ -38,9 +44,9 @@ public function testCreateWriter() } /** - * Test create reader + * Test create reader. */ - public function testCreateReader() + public function testCreateReader(): void { $class = 'PhpOffice\\PhpPresentation\\Reader\\ReaderInterface'; @@ -48,29 +54,31 @@ public function testCreateReader() } /** - * Test load class exception - * - * @expectedException \Exception - * @expectedExceptionMessage is not a valid reader + * Test load class exception. */ - public function testLoadClassException() + public function testLoadClassException(): void { - IOFactory::createReader(); + $this->expectException(InvalidClassException::class); + $this->expectExceptionMessage('The class PhpOffice\PhpPresentation\Reader\ is invalid (Reader: The class doesn\'t exist)'); + IOFactory::createReader(''); } - public function testLoad() + public function testLoad(): void { - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', IOFactory::load(PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'serialized.phppt')); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', IOFactory::load(PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'serialized.phppt')); } /** - * Test load class exception - * - * @expectedException \Exception - * @expectedExceptionMessage Could not automatically determine \PhpOffice\PhpPresentation\Reader\ReaderInterface for file. + * Test load class exception. */ - public function testLoadException() + public function testLoadException(): void { - IOFactory::load(PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'); + $file = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; + $this->expectException(InvalidFileFormatException::class); + $this->expectExceptionMessage(sprintf( + 'The file %s is not in the format supported by class PhpOffice\PhpPresentation\IOFactory (Could not automatically determine the good PhpOffice\PhpPresentation\Reader\ReaderInterface)', + $file + )); + IOFactory::load($file); } } diff --git a/tests/PhpPresentation/Tests/PhpPresentationTest.php b/tests/PhpPresentation/Tests/PhpPresentationTest.php index c5321e2c6e..3370f92460 100644 --- a/tests/PhpPresentation/Tests/PhpPresentationTest.php +++ b/tests/PhpPresentation/Tests/PhpPresentationTest.php @@ -10,29 +10,34 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\DocumentLayout; use PhpOffice\PhpPresentation\DocumentProperties; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\PresentationProperties; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class PhpPresentationTest extends \PHPUnit_Framework_TestCase +class PhpPresentationTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new PhpPresentation(); $slide = $object->getSlide(); @@ -40,27 +45,22 @@ public function testConstruct() $this->assertEquals(new DocumentProperties(), $object->getDocumentProperties()); $this->assertEquals(new DocumentLayout(), $object->getLayout()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->getSlide()); - $this->assertEquals(1, count($object->getAllSlides())); + $this->assertCount(1, $object->getAllSlides()); $this->assertEquals(0, $object->getIndex($slide)); $this->assertEquals(1, $object->getSlideCount()); $this->assertEquals(0, $object->getActiveSlideIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Iterator', $object->getSlideIterator()); } - public function testProperties() + public function testProperties(): void { $object = new PhpPresentation(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->getProperties()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->getDocumentProperties()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $object->setProperties(new DocumentProperties())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->getProperties()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->getDocumentProperties()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $object->setDocumentProperties(new DocumentProperties())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->getProperties()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\DocumentProperties', $object->getDocumentProperties()); } - public function testPresentationProperties() + public function testPresentationProperties(): void { $object = new PhpPresentation(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->getPresentationProperties()); @@ -69,9 +69,9 @@ public function testPresentationProperties() } /** - * Test add external slide + * Test add external slide. */ - public function testAddExternalSlide() + public function testAddExternalSlide(): void { $origin = new PhpPresentation(); $slide = $origin->getSlide(); @@ -82,75 +82,47 @@ public function testAddExternalSlide() } /** - * Test copy presentation + * Test copy presentation. */ - public function testCopy() + public function testCopy(): void { $object = new PhpPresentation(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $object->copy()); } /** - * Test remove slide by index exception - * - * @expectedException Exception - * @expectedExceptionMessage Slide index is out of bounds. + * Test remove slide by index exception. */ - public function testRemoveSlideByIndexException() + public function testRemoveSlideByIndexException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1) is out of bounds (0, 0)'); + $object = new PhpPresentation(); $object->removeSlideByIndex(1); } /** - * Test get slide exception - * - * @expectedException Exception - * @expectedExceptionMessage Slide index is out of bounds. + * Test get slide exception. */ - public function testGetSlideException() + public function testGetSlideException(): void { - $object = new PhpPresentation(); - $object->getSlide(1); - } + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1) is out of bounds (0, 0)'); - /** - * Test set active slide index exception - * - * @expectedException Exception - * @expectedExceptionMessage Active slide index is out of bounds. - */ - public function testSetActiveSlideIndexException() - { $object = new PhpPresentation(); - $object->setActiveSlideIndex(1); + $object->getSlide(1); } /** - * @deprecated + * Test set active slide index exception. */ - public function testMarkAsFinal() + public function testSetActiveSlideIndexException(): void { - $object = new PhpPresentation(); - $this->assertFalse($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal(true)); - $this->assertTrue($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal(false)); - $this->assertFalse($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal()); - $this->assertTrue($object->isMarkedAsFinal()); - } + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1) is out of bounds (0, 0)'); - /** - * @deprecated - */ - public function testZoom() - { $object = new PhpPresentation(); - $this->assertEquals(1, $object->getZoom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setZoom(0.3)); - $this->assertEquals(0.3, $object->getZoom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setZoom()); - $this->assertEquals(1, $object->getZoom()); + $object->setActiveSlideIndex(1); } } diff --git a/tests/PhpPresentation/Tests/PresentationPropertiesTest.php b/tests/PhpPresentation/Tests/PresentationPropertiesTest.php index 5350b65951..56d88f5d4a 100644 --- a/tests/PhpPresentation/Tests/PresentationPropertiesTest.php +++ b/tests/PhpPresentation/Tests/PresentationPropertiesTest.php @@ -10,101 +10,144 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\PresentationProperties; +use PHPUnit\Framework\TestCase; /** - * Test class for DocumentProperties + * Test class for DocumentProperties. * - * @coversDefaultClass PhpOffice\PhpPresentation\PresentationProperties + * @coversDefaultClass \PhpOffice\PhpPresentation\PresentationProperties */ -class PresentationPropertiesTest extends \PHPUnit_Framework_TestCase +class PresentationPropertiesTest extends TestCase { - public function testCommentVisible() + public function testCommentVisible(): void { $object = new PresentationProperties(); $this->assertFalse($object->isCommentVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setCommentVisible('AAAA')); - $this->assertFalse($object->isCommentVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setCommentVisible(true)); + $this->assertInstanceOf(PresentationProperties::class, $object->setCommentVisible(true)); $this->assertTrue($object->isCommentVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setCommentVisible(false)); + $this->assertInstanceOf(PresentationProperties::class, $object->setCommentVisible(false)); $this->assertFalse($object->isCommentVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setCommentVisible()); + $this->assertInstanceOf(PresentationProperties::class, $object->setCommentVisible()); $this->assertFalse($object->isCommentVisible()); } - public function testLoopUntilEsc() + public function testLoopUntilEsc(): void { $object = new PresentationProperties(); $this->assertFalse($object->isLoopContinuouslyUntilEsc()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLoopContinuouslyUntilEsc('AAAA')); - $this->assertFalse($object->isLoopContinuouslyUntilEsc()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLoopContinuouslyUntilEsc(true)); + $this->assertInstanceOf(PresentationProperties::class, $object->setLoopContinuouslyUntilEsc(true)); $this->assertTrue($object->isLoopContinuouslyUntilEsc()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLoopContinuouslyUntilEsc(false)); + $this->assertInstanceOf(PresentationProperties::class, $object->setLoopContinuouslyUntilEsc(false)); $this->assertFalse($object->isLoopContinuouslyUntilEsc()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLoopContinuouslyUntilEsc()); + $this->assertInstanceOf(PresentationProperties::class, $object->setLoopContinuouslyUntilEsc()); $this->assertFalse($object->isLoopContinuouslyUntilEsc()); } - public function testLastView() + public function testLastView(): void { $object = new PresentationProperties(); $this->assertEquals(PresentationProperties::VIEW_SLIDE, $object->getLastView()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLastView('AAAA')); + $this->assertInstanceOf(PresentationProperties::class, $object->setLastView('AAAA')); $this->assertEquals(PresentationProperties::VIEW_SLIDE, $object->getLastView()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLastView(PresentationProperties::VIEW_OUTLINE)); + $this->assertInstanceOf(PresentationProperties::class, $object->setLastView(PresentationProperties::VIEW_OUTLINE)); $this->assertEquals(PresentationProperties::VIEW_OUTLINE, $object->getLastView()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setLastView()); + $this->assertInstanceOf(PresentationProperties::class, $object->setLastView()); $this->assertEquals(PresentationProperties::VIEW_SLIDE, $object->getLastView()); } - public function testMarkAsFinal() + public function testMarkAsFinal(): void { $object = new PresentationProperties(); $this->assertFalse($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal('AAAA')); - $this->assertFalse($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal(true)); + $this->assertInstanceOf(PresentationProperties::class, $object->markAsFinal(true)); $this->assertTrue($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal(false)); + $this->assertInstanceOf(PresentationProperties::class, $object->markAsFinal(false)); $this->assertFalse($object->isMarkedAsFinal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->markAsFinal()); + $this->assertInstanceOf(PresentationProperties::class, $object->markAsFinal()); $this->assertTrue($object->isMarkedAsFinal()); } - public function testThumbnail() + /** + * @dataProvider dataProviderSlideshowType + */ + public function testSlideshowType(?string $value, string $expected): void { - $imagePath = PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'; + $object = new PresentationProperties(); + // Default + $this->assertEquals(PresentationProperties::SLIDESHOW_TYPE_PRESENT, $object->getSlideshowType()); + // Set value + if (is_null($value)) { + $this->assertInstanceOf(PresentationProperties::class, $object->setSlideshowType()); + } else { + $this->assertInstanceOf(PresentationProperties::class, $object->setSlideshowType($value)); + } + // Check value + $this->assertEquals($expected, $object->getSlideshowType()); + } + + /** + * @return array> + */ + public function dataProviderSlideshowType(): array + { + return [ + [ + null, + PresentationProperties::SLIDESHOW_TYPE_PRESENT, + ], + [ + PresentationProperties::SLIDESHOW_TYPE_PRESENT, + PresentationProperties::SLIDESHOW_TYPE_PRESENT, + ], + [ + PresentationProperties::SLIDESHOW_TYPE_KIOSK, + PresentationProperties::SLIDESHOW_TYPE_KIOSK, + ], + [ + PresentationProperties::SLIDESHOW_TYPE_BROWSE, + PresentationProperties::SLIDESHOW_TYPE_BROWSE, + ], + [ + 'unauthorizedValue', + PresentationProperties::SLIDESHOW_TYPE_PRESENT, + ], + ]; + } + + public function testThumbnail(): void + { + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; $object = new PresentationProperties(); $this->assertNull($object->getThumbnailPath()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setThumbnailPath('AAAA')); + $this->assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath('AAAA')); $this->assertNull($object->getThumbnailPath()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setThumbnailPath()); + $this->assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath()); $this->assertNull($object->getThumbnailPath()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setThumbnailPath($imagePath)); + $this->assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath($imagePath)); $this->assertEquals($imagePath, $object->getThumbnailPath()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setThumbnailPath()); + $this->assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath()); $this->assertEquals($imagePath, $object->getThumbnailPath()); } - public function testZoom() + public function testZoom(): void { $object = new PresentationProperties(); $this->assertEquals(1, $object->getZoom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setZoom('AAAA')); - $this->assertEquals(1, $object->getZoom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setZoom(2.3)); + $this->assertInstanceOf(PresentationProperties::class, $object->setZoom(2.3)); $this->assertEquals(2.3, $object->getZoom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PresentationProperties', $object->setZoom()); + $this->assertInstanceOf(PresentationProperties::class, $object->setZoom()); $this->assertEquals(1, $object->getZoom()); } } diff --git a/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php b/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php index 5e6bb66f43..418215bbf5 100644 --- a/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php +++ b/tests/PhpPresentation/Tests/Reader/ODPresentationTest.php @@ -10,76 +10,87 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Reader; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; +use PhpOffice\PhpPresentation\PresentationProperties; use PhpOffice\PhpPresentation\Reader\ODPresentation; +use PhpOffice\PhpPresentation\Shape\Drawing\Gd; +use PhpOffice\PhpPresentation\Shape\RichText; +use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Bullet; +use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for ODPresentation reader + * Test class for ODPresentation reader. * - * @coversDefaultClass PhpOffice\PhpPresentation\Reader\ODPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\Reader\ODPresentation */ -class ODPresentationTest extends \PHPUnit_Framework_TestCase +class ODPresentationTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testCanRead() + public function testCanRead(): void { $object = new ODPresentation(); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.ppt'; $this->assertFalse($object->canRead($file)); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/serialized.phppt'; $this->assertFalse($object->canRead($file)); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.pptx'; $this->assertFalse($object->canRead($file)); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.odp'; $this->assertTrue($object->canRead($file)); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testLoadFileNotExists() + + public function testLoadFileNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new ODPresentation(); $object->load(''); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Invalid file format for PhpOffice\PhpPresentation\Reader\ODPresentation: - */ - public function testLoadFileBadFormat() + + public function testLoadFileBadFormat(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.ppt'; + $this->expectException(InvalidFileFormatException::class); + $this->expectExceptionMessage(sprintf( + 'The file %s is not in the format supported by class PhpOffice\PhpPresentation\Reader\ODPresentation', + $file + )); + $object = new ODPresentation(); $object->load($file); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testFileSupportsNotExists() + + public function testFileSupportsNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new ODPresentation(); $object->fileSupportsUnserializePhpPresentation(''); } - - public function testLoadFile01() + + public function testLoadFile01(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.odp'; $object = new ODPresentation(); @@ -92,35 +103,49 @@ public function testLoadFile01() $this->assertEquals('Sample 02 Subject', $oPhpPresentation->getDocumentProperties()->getSubject()); $this->assertEquals('Sample 02 Description', $oPhpPresentation->getDocumentProperties()->getDescription()); $this->assertEquals('office 2007 openxml libreoffice odt php', $oPhpPresentation->getDocumentProperties()->getKeywords()); - // + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); + + // Presentation Properties + $this->assertEquals(PresentationProperties::SLIDESHOW_TYPE_PRESENT, $oPhpPresentation->getPresentationProperties()->getSlideshowType()); + $this->assertCount(4, $oPhpPresentation->getAllSlides()); - + // Slide 1 $oSlide1 = $oPhpPresentation->getSlide(0); - $arrayShape = $oSlide1->getShapeCollection(); + $arrayShape = (array) $oSlide1->getShapeCollection(); $this->assertCount(2, $arrayShape); // Slide 1 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/png', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 1 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(200, $oShape->getHeight()); $this->assertEquals(600, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(400, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $oParagraph); + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(3, $arrayRichText); // Slide 1 : Shape 2 : Paragraph 1 @@ -130,6 +155,8 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(28, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 1 : Shape 2 : Paragraph 2 $oRichText = $arrayRichText[1]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $oRichText); @@ -140,25 +167,30 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(60, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); - + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); + // Slide 2 $oSlide2 = $oPhpPresentation->getSlide(1); - $arrayShape = $oSlide2->getShapeCollection(); + $arrayShape = (array) $oSlide2->getShapeCollection(); $this->assertCount(3, $arrayShape); // Slide 2 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/png', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 2 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(100, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); @@ -167,6 +199,7 @@ public function testLoadFile01() $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); // Slide 2 : Shape 2 : Paragraph 1 @@ -177,8 +210,9 @@ public function testLoadFile01() $this->assertEquals(48, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); // Slide 2 : Shape 3 + /** @var RichText $oShape */ $oShape = $arrayShape[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(600, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); @@ -188,6 +222,7 @@ public function testLoadFile01() // Slide 2 : Shape 3 : Paragraph 1 $oParagraph = $arrayParagraphs[0]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); @@ -198,9 +233,12 @@ public function testLoadFile01() $this->assertEquals('A class library', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 : Paragraph 2 $oParagraph = $arrayParagraphs[1]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); @@ -211,9 +249,12 @@ public function testLoadFile01() $this->assertEquals('Written in PHP', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 : Paragraph 3 $oParagraph = $arrayParagraphs[2]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); @@ -224,9 +265,12 @@ public function testLoadFile01() $this->assertEquals('Representing a presentation', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 : Paragraph 4 $oParagraph = $arrayParagraphs[3]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); @@ -237,33 +281,43 @@ public function testLoadFile01() $this->assertEquals('Supports writing to different file formats', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); - + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); + // Slide 3 $oSlide2 = $oPhpPresentation->getSlide(2); - $arrayShape = $oSlide2->getShapeCollection(); + $arrayShape = (array) $oSlide2->getShapeCollection(); $this->assertCount(3, $arrayShape); // Slide 3 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/png', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 3 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(100, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(50, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); // Slide 3 : Shape 2 : Paragraph 1 @@ -273,9 +327,12 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(48, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(600, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); @@ -285,6 +342,7 @@ public function testLoadFile01() // Slide 3 : Shape 3 : Paragraph 1 $oParagraph = $arrayParagraphs[0]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(0, $oParagraph->getAlignment()->getLevel()); @@ -296,9 +354,12 @@ public function testLoadFile01() $this->assertEquals('Generate slide decks', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 2 $oParagraph = $arrayParagraphs[1]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(75, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); @@ -310,9 +371,12 @@ public function testLoadFile01() $this->assertEquals('Represent business data', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 3 $oParagraph = $arrayParagraphs[2]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(75, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); @@ -324,9 +388,12 @@ public function testLoadFile01() $this->assertEquals('Show a family slide show', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 4 $oParagraph = $arrayParagraphs[3]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(75, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); @@ -338,9 +405,12 @@ public function testLoadFile01() $this->assertEquals('...', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 5 $oParagraph = $arrayParagraphs[4]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(0, $oParagraph->getAlignment()->getLevel()); @@ -352,9 +422,12 @@ public function testLoadFile01() $this->assertEquals('Export these to different formats', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 6 $oParagraph = $arrayParagraphs[5]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(75, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); @@ -366,9 +439,12 @@ public function testLoadFile01() $this->assertEquals('PHPPresentation 2007', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 7 $oParagraph = $arrayParagraphs[6]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(75, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); @@ -380,9 +456,12 @@ public function testLoadFile01() $this->assertEquals('Serialized', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 8 $oParagraph = $arrayParagraphs[7]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); // $this->assertEquals(75, $oParagraph->getAlignment()->getMarginLeft()); // $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); @@ -394,33 +473,43 @@ public function testLoadFile01() $this->assertEquals('... (more to come) ...', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); - + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); + // Slide 4 $oSlide3 = $oPhpPresentation->getSlide(3); - $arrayShape = $oSlide3->getShapeCollection(); + $arrayShape = (array) $oSlide3->getShapeCollection(); $this->assertCount(3, $arrayShape); // Slide 4 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/png', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 4 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(100, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(50, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); // Slide 4 : Shape 2 : Paragraph 1 @@ -429,18 +518,26 @@ public function testLoadFile01() $this->assertEquals('Need more info?', $oRichText->getText()); $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(48, $oRichText->getFont()->getSize()); - $this->assertEquals('FF000000', $oShape->getActiveParagraph()->getFont()->getColor()->getARGB()); + $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 4 : Shape 3 + /** @var RichText $oShape */ $oShape = $arrayShape[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(600, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(130, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(3, $arrayRichText); // Slide 4 : Shape 3 : Paragraph 1 @@ -449,48 +546,58 @@ public function testLoadFile01() $this->assertEquals('Check the project site on GitHub:', $oRichText->getText()); $this->assertFalse($oRichText->getFont()->isBold()); $this->assertEquals(36, $oRichText->getFont()->getSize()); - $this->assertEquals('FF000000', $oShape->getActiveParagraph()->getFont()->getColor()->getARGB()); + $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 4 : Shape 3 : Paragraph 2 $oRichText = $arrayRichText[1]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $oRichText); // Slide 4 : Shape 3 : Paragraph 3 + /** @var RichText\Run $oRichText */ $oRichText = $arrayRichText[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $oRichText); + $this->assertInstanceOf(RichText\Run::class, $oRichText); $this->assertEquals('https://github.com/PHPOffice/PHPPresentation/', $oRichText->getText()); $this->assertFalse($oRichText->getFont()->isBold()); $this->assertEquals(32, $oRichText->getFont()->getSize()); - $this->assertEquals('FF000000', $oShape->getActiveParagraph()->getFont()->getColor()->getARGB()); + $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); $this->assertTrue($oRichText->hasHyperlink()); $this->assertEquals('https://github.com/PHPOffice/PHPPresentation/', $oRichText->getHyperlink()->getUrl()); //$this->assertEquals('PHPPresentation', $oRichText->getHyperlink()->getTooltip()); } - public function testSlideName() + public function testSlideName(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/ODP_Slide_Name.odp'; $object = new ODPresentation(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); $this->assertEquals('MaDiapo', $oPhpPresentation->getSlide(0)->getName()); } - public function testIssue00141() + public function testIssue00141(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Issue_00141.odp'; $object = new ODPresentation(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); $this->assertCount(3, $oPhpPresentation->getAllSlides()); // Slide 1 $oSlide = $oPhpPresentation->getSlide(1); - $arrayShape = $oSlide->getShapeCollection(); + $arrayShape = (array) $oSlide->getShapeCollection(); $this->assertCount(2, $arrayShape); // Slide 1 : Shape 1 + /** @var RichText $oShape */ $oShape = reset($arrayShape); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); // Slide 1 : Shape 1 : Paragraph 1 $oParagraph = $oShape->getParagraph(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $oParagraph); diff --git a/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php b/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php index 2a2c5f4f97..7db18c9e1e 100644 --- a/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php +++ b/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php @@ -10,74 +10,85 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Reader; use PhpOffice\PhpPresentation\DocumentLayout; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; +use PhpOffice\PhpPresentation\PresentationProperties; use PhpOffice\PhpPresentation\Reader\PowerPoint2007; +use PhpOffice\PhpPresentation\Shape\Drawing\Gd; +use PhpOffice\PhpPresentation\Shape\RichText; +use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Bullet; +use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for PowerPoint2007 reader + * Test class for PowerPoint2007 reader. * - * @coversDefaultClass PhpOffice\PhpPresentation\Reader\PowerPoint2007 + * @coversDefaultClass \PhpOffice\PhpPresentation\Reader\PowerPoint2007 */ -class PowerPoint2007Test extends \PHPUnit_Framework_TestCase +class PowerPoint2007Test extends TestCase { /** - * Test can read + * Test can read. */ - public function testCanRead() + public function testCanRead(): void { $object = new PowerPoint2007(); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.ppt'; $this->assertFalse($object->canRead($file)); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/serialized.phppt'; $this->assertFalse($object->canRead($file)); - + $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.pptx'; $this->assertTrue($object->canRead($file)); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testLoadFileNotExists() + + public function testLoadFileNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new PowerPoint2007(); $object->load(''); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Invalid file format for PhpOffice\PhpPresentation\Reader\PowerPoint2007: - */ - public function testLoadFileBadFormat() + + public function testLoadFileBadFormat(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.ppt'; + $this->expectException(InvalidFileFormatException::class); + $this->expectExceptionMessage(sprintf( + 'The file %s is not in the format supported by class PhpOffice\PhpPresentation\Reader\PowerPoint2007', + $file + )); + $object = new PowerPoint2007(); $object->load($file); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testFileSupportsNotExists() + + public function testFileSupportsNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new PowerPoint2007(); $object->fileSupportsUnserializePhpPresentation(''); } - - public function testLoadFile01() + + public function testLoadFile01(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.pptx'; $object = new PowerPoint2007(); @@ -91,6 +102,11 @@ public function testLoadFile01() $this->assertEquals('Sample 02 Description', $oPhpPresentation->getDocumentProperties()->getDescription()); $this->assertEquals('office 2007 openxml libreoffice odt php', $oPhpPresentation->getDocumentProperties()->getKeywords()); $this->assertEquals('Sample Category', $oPhpPresentation->getDocumentProperties()->getCategory()); + $this->assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); + $this->assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); + + // Presentation Properties + $this->assertEquals(PresentationProperties::SLIDESHOW_TYPE_PRESENT, $oPhpPresentation->getPresentationProperties()->getSlideshowType()); // Document Layout $this->assertEquals(DocumentLayout::LAYOUT_SCREEN_4X3, $oPhpPresentation->getLayout()->getDocumentLayout()); $this->assertEquals(254, $oPhpPresentation->getLayout()->getCX(DocumentLayout::UNIT_MILLIMETER)); @@ -98,33 +114,41 @@ public function testLoadFile01() // Slides $this->assertCount(4, $oPhpPresentation->getAllSlides()); - + // Slide 1 $oSlide1 = $oPhpPresentation->getSlide(0); - $arrayShape = $oSlide1->getShapeCollection(); + $arrayShape = (array) $oSlide1->getShapeCollection(); $this->assertCount(2, $arrayShape); // Slide 1 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/gif', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 1 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(200, $oShape->getHeight()); $this->assertEquals(600, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(400, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(3, $arrayRichText); // Slide 1 : Shape 2 : Paragraph 1 @@ -134,6 +158,8 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(28, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 1 : Shape 2 : Paragraph 2 $oRichText = $arrayRichText[1]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $oRichText); @@ -144,25 +170,30 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(60, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); - + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); + // Slide 2 $oSlide2 = $oPhpPresentation->getSlide(1); - $arrayShape = $oSlide2->getShapeCollection(); + $arrayShape = (array) $oSlide2->getShapeCollection(); $this->assertCount(3, $arrayShape); // Slide 2 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/gif', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 2 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(100, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); @@ -171,6 +202,7 @@ public function testLoadFile01() $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); // Slide 2 : Shape 2 : Paragraph 1 @@ -180,9 +212,12 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(48, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 + /** @var RichText $oShape */ $oShape = $arrayShape[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(600, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); @@ -195,6 +230,7 @@ public function testLoadFile01() $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -202,12 +238,15 @@ public function testLoadFile01() $this->assertEquals('A class library', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 : Paragraph 2 $oParagraph = $arrayParagraphs[1]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -215,12 +254,15 @@ public function testLoadFile01() $this->assertEquals('Written in PHP', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 : Paragraph 3 $oParagraph = $arrayParagraphs[2]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -228,12 +270,15 @@ public function testLoadFile01() $this->assertEquals('Representing a presentation', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 2 : Shape 3 : Paragraph 4 $oParagraph = $arrayParagraphs[3]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); $this->assertEquals(25, $oParagraph->getAlignment()->getMarginLeft()); $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -241,33 +286,43 @@ public function testLoadFile01() $this->assertEquals('Supports writing to different file formats', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); - + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); + // Slide 3 $oSlide2 = $oPhpPresentation->getSlide(2); - $arrayShape = $oSlide2->getShapeCollection(); + $arrayShape = (array) $oSlide2->getShapeCollection(); $this->assertCount(3, $arrayShape); // Slide 3 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/gif', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 3 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(100, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(50, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); // Slide 3 : Shape 2 : Paragraph 1 @@ -277,9 +332,12 @@ public function testLoadFile01() $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(48, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(600, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); @@ -293,6 +351,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(0, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -300,6 +359,8 @@ public function testLoadFile01() $this->assertEquals('Generate slide decks', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 2 $oParagraph = $arrayParagraphs[1]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -307,6 +368,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -314,6 +376,8 @@ public function testLoadFile01() $this->assertEquals('Represent business data', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 3 $oParagraph = $arrayParagraphs[2]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -321,6 +385,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -328,6 +393,8 @@ public function testLoadFile01() $this->assertEquals('Show a family slide show', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 4 $oParagraph = $arrayParagraphs[3]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -335,6 +402,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -342,6 +410,8 @@ public function testLoadFile01() $this->assertEquals('...', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 5 $oParagraph = $arrayParagraphs[4]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -349,6 +419,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(0, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -356,6 +427,8 @@ public function testLoadFile01() $this->assertEquals('Export these to different formats', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 6 $oParagraph = $arrayParagraphs[5]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -363,6 +436,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -370,6 +444,8 @@ public function testLoadFile01() $this->assertEquals('PHPPresentation 2007', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 7 $oParagraph = $arrayParagraphs[6]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -377,6 +453,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -384,6 +461,8 @@ public function testLoadFile01() $this->assertEquals('Serialized', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 3 : Shape 3 : Paragraph 8 $oParagraph = $arrayParagraphs[7]; $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); @@ -391,6 +470,7 @@ public function testLoadFile01() $this->assertEquals(-25, $oParagraph->getAlignment()->getIndent()); $this->assertEquals(1, $oParagraph->getAlignment()->getLevel()); $this->assertEquals(Bullet::TYPE_BULLET, $oParagraph->getBulletStyle()->getBulletType()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); $oRichText = $arrayRichText[0]; @@ -398,33 +478,43 @@ public function testLoadFile01() $this->assertEquals('... (more to come) ...', $oRichText->getText()); $this->assertEquals(36, $oRichText->getFont()->getSize()); $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); - + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); + // Slide 4 $oSlide3 = $oPhpPresentation->getSlide(3); - $arrayShape = $oSlide3->getShapeCollection(); + $arrayShape = (array) $oSlide3->getShapeCollection(); $this->assertCount(3, $arrayShape); // Slide 4 : Shape 1 + /** @var Gd $oShape */ $oShape = $arrayShape[0]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\Gd', $oShape); + $this->assertInstanceOf(Gd::class, $oShape); $this->assertEquals('PHPPresentation logo', $oShape->getName()); $this->assertEquals('PHPPresentation logo', $oShape->getDescription()); $this->assertEquals(36, $oShape->getHeight()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(10, $oShape->getOffsetY()); + $this->assertEquals('image/gif', $oShape->getMimeType()); $this->assertTrue($oShape->getShadow()->isVisible()); $this->assertEquals(45, $oShape->getShadow()->getDirection()); $this->assertEquals(10, $oShape->getShadow()->getDistance()); // Slide 4 : Shape 2 + /** @var RichText $oShape */ $oShape = $arrayShape[1]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(100, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(50, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(1, $arrayRichText); // Slide 4 : Shape 2 : Paragraph 1 @@ -433,18 +523,26 @@ public function testLoadFile01() $this->assertEquals('Need more info?', $oRichText->getText()); $this->assertTrue($oRichText->getFont()->isBold()); $this->assertEquals(48, $oRichText->getFont()->getSize()); - $this->assertEquals('FF000000', $oShape->getActiveParagraph()->getFont()->getColor()->getARGB()); + $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 4 : Shape 3 + /** @var RichText $oShape */ $oShape = $arrayShape[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $oShape); + $this->assertInstanceOf(RichText::class, $oShape); $this->assertEquals(600, $oShape->getHeight()); $this->assertEquals(930, $oShape->getWidth()); $this->assertEquals(10, $oShape->getOffsetX()); $this->assertEquals(130, $oShape->getOffsetY()); - $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oShape->getActiveParagraph()->getAlignment()->getHorizontal()); $arrayParagraphs = $oShape->getParagraphs(); $this->assertCount(1, $arrayParagraphs); $oParagraph = $arrayParagraphs[0]; + $this->assertEquals(Alignment::HORIZONTAL_LEFT, $oParagraph->getAlignment()->getHorizontal()); + $this->assertFalse($oParagraph->getAlignment()->isRTL()); + $this->assertEquals(0, $oParagraph->getSpacingAfter()); + $this->assertEquals(0, $oParagraph->getSpacingBefore()); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $oParagraph->getLineSpacingMode()); + $this->assertEquals(100, $oParagraph->getLineSpacing()); $arrayRichText = $oParagraph->getRichTextElements(); $this->assertCount(3, $arrayRichText); // Slide 4 : Shape 3 : Paragraph 1 @@ -453,23 +551,28 @@ public function testLoadFile01() $this->assertEquals('Check the project site on GitHub:', $oRichText->getText()); $this->assertFalse($oRichText->getFont()->isBold()); $this->assertEquals(36, $oRichText->getFont()->getSize()); - $this->assertEquals('FF000000', $oShape->getActiveParagraph()->getFont()->getColor()->getARGB()); + $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); // Slide 4 : Shape 3 : Paragraph 2 $oRichText = $arrayRichText[1]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $oRichText); // Slide 4 : Shape 3 : Paragraph 3 + /** @var RichText\Run $oRichText */ $oRichText = $arrayRichText[2]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $oRichText); + $this->assertInstanceOf(RichText\Run::class, $oRichText); $this->assertEquals('https://github.com/PHPOffice/PHPPresentation/', $oRichText->getText()); $this->assertFalse($oRichText->getFont()->isBold()); $this->assertEquals(32, $oRichText->getFont()->getSize()); - $this->assertEquals('FF000000', $oShape->getActiveParagraph()->getFont()->getColor()->getARGB()); + $this->assertEquals('FF000000', $oRichText->getFont()->getColor()->getARGB()); $this->assertTrue($oRichText->hasHyperlink()); $this->assertEquals('https://github.com/PHPOffice/PHPPresentation/', $oRichText->getHyperlink()->getUrl()); $this->assertEquals('PHPPresentation', $oRichText->getHyperlink()->getTooltip()); + $this->assertEquals('Calibri', $oRichText->getFont()->getName()); + $this->assertEquals(Font::FORMAT_LATIN, $oRichText->getFont()->getFormat()); } - public function testMarkAsFinal() + public function testMarkAsFinal(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.pptx'; $object = new PowerPoint2007(); @@ -477,7 +580,6 @@ public function testMarkAsFinal() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); $this->assertFalse($oPhpPresentation->getPresentationProperties()->isMarkedAsFinal()); - $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/PPTX_MarkAsFinal.pptx'; $object = new PowerPoint2007(); $oPhpPresentation = $object->load($file); @@ -485,7 +587,7 @@ public function testMarkAsFinal() $this->assertTrue($oPhpPresentation->getPresentationProperties()->isMarkedAsFinal()); } - public function testZoom() + public function testZoom(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_12.pptx'; $object = new PowerPoint2007(); @@ -493,7 +595,6 @@ public function testZoom() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); $this->assertEquals(1, $oPhpPresentation->getPresentationProperties()->getZoom()); - $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/PPTX_Zoom.pptx'; $object = new PowerPoint2007(); $oPhpPresentation = $object->load($file); @@ -501,7 +602,7 @@ public function testZoom() $this->assertEquals(2.68, $oPhpPresentation->getPresentationProperties()->getZoom()); } - public function testSlideLayout() + public function testSlideLayout(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Issue_00150.pptx'; $object = new PowerPoint2007(); diff --git a/tests/PhpPresentation/Tests/Reader/PowerPoint97Test.php b/tests/PhpPresentation/Tests/Reader/PowerPoint97Test.php index 12aa1a6c17..73cfb5ab64 100644 --- a/tests/PhpPresentation/Tests/Reader/PowerPoint97Test.php +++ b/tests/PhpPresentation/Tests/Reader/PowerPoint97Test.php @@ -10,129 +10,134 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Reader; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; use PhpOffice\PhpPresentation\Reader\PowerPoint97; +use PHPUnit\Framework\TestCase; /** - * Test class for PowerPoint97 reader + * Test class for PowerPoint97 reader. * - * @coversDefaultClass PhpOffice\PhpPresentation\Reader\PowerPoint97 + * @coversDefaultClass \PhpOffice\PhpPresentation\Reader\PowerPoint97 */ -class PowerPoint97Test extends \PHPUnit_Framework_TestCase +class PowerPoint97Test extends TestCase { /** - * Test can read + * Test can read. */ - public function testCanRead() + public function testCanRead(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.ppt'; $object = new PowerPoint97(); $this->assertTrue($object->canRead($file)); } - /** - * Test cant read + * Test cant read. */ - public function testCantRead() + public function testCantRead(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/serialized.phppt'; $object = new PowerPoint97(); - + $this->assertFalse($object->canRead($file)); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testLoadFileNotExists() + + public function testLoadFileNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new PowerPoint97(); $object->load(''); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Invalid file format for PhpOffice\PhpPresentation\Reader\PowerPoint97: - */ - public function testLoadFileBadFormat() + + public function testLoadFileBadFormat(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_01_Simple.pptx'; + $this->expectException(InvalidFileFormatException::class); + $this->expectExceptionMessage(sprintf( + 'The file %s is not in the format supported by class PhpOffice\PhpPresentation\Reader\PowerPoint97', + $file + )); + $object = new PowerPoint97(); $object->load($file); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testFileSupportsNotExists() + + public function testFileSupportsNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new PowerPoint97(); $object->fileSupportsUnserializePhpPresentation(''); } - - public function testLoadFile01() + + public function testLoadFile01(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.ppt'; $object = new PowerPoint97(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); $this->assertEquals(1, $oPhpPresentation->getSlideCount()); - + $oSlide = $oPhpPresentation->getSlide(0); $this->assertCount(2, $oSlide->getShapeCollection()); } - - public function testLoadFile02() + + public function testLoadFile02(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_02.ppt'; $object = new PowerPoint97(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); $this->assertEquals(4, $oPhpPresentation->getSlideCount()); - + $oSlide = $oPhpPresentation->getSlide(0); $this->assertCount(2, $oSlide->getShapeCollection()); - + $oSlide = $oPhpPresentation->getSlide(1); $this->assertCount(3, $oSlide->getShapeCollection()); - + $oSlide = $oPhpPresentation->getSlide(2); $this->assertCount(3, $oSlide->getShapeCollection()); - + $oSlide = $oPhpPresentation->getSlide(3); $this->assertCount(3, $oSlide->getShapeCollection()); } - - public function testLoadFile03() + + public function testLoadFile03(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_03.ppt'; $object = new PowerPoint97(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); $this->assertEquals(1, $oPhpPresentation->getSlideCount()); - + $oSlide = $oPhpPresentation->getSlide(0); $this->assertCount(1, $oSlide->getShapeCollection()); } - - public function testLoadFile04() + + public function testLoadFile04(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_04.ppt'; $object = new PowerPoint97(); $oPhpPresentation = $object->load($file); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $oPhpPresentation); $this->assertEquals(1, $oPhpPresentation->getSlideCount()); - + $oSlide = $oPhpPresentation->getSlide(0); $this->assertCount(4, $oSlide->getShapeCollection()); } diff --git a/tests/PhpPresentation/Tests/Reader/SerializedTest.php b/tests/PhpPresentation/Tests/Reader/SerializedTest.php index 6f7bbfddd8..a4d79d0a74 100644 --- a/tests/PhpPresentation/Tests/Reader/SerializedTest.php +++ b/tests/PhpPresentation/Tests/Reader/SerializedTest.php @@ -10,73 +10,87 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Reader; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidFileFormatException; use PhpOffice\PhpPresentation\Reader\Serialized; +use PHPUnit\Framework\TestCase; +use ZipArchive; /** - * Test class for serialized reader + * Test class for serialized reader. * - * @coversDefaultClass PhpOffice\PhpPresentation\Reader\Serialized + * @coversDefaultClass \PhpOffice\PhpPresentation\Reader\Serialized */ -class SerializedTest extends \PHPUnit_Framework_TestCase +class SerializedTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testCanRead() + public function testCanRead(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/serialized.phppt'; $object = new Serialized(); $this->assertTrue($object->canRead($file)); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testLoadFileNotExists() + + public function testLoadFileNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new Serialized(); $object->load(''); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Invalid file format for PhpOffice\PhpPresentation\Reader\Serialized: - */ - public function testLoadFileBadFormat() + + public function testLoadFileBadFormat(): void { $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_01_Simple.pptx'; + $this->expectException(InvalidFileFormatException::class); + $this->expectExceptionMessage(sprintf( + 'The file %s is not in the format supported by class PhpOffice\PhpPresentation\Reader\Serialized', + $file + )); + $object = new Serialized(); $object->load($file); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open for reading! File does not exist. - */ - public function testFileSupportsNotExists() + + public function testFileSupportsNotExists(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new Serialized(); $object->fileSupportsUnserializePhpPresentation(''); } - - public function testLoadSerializedFileNotExists() + + public function testLoadSerializedFileNotExists(): void { $file = tempnam(sys_get_temp_dir(), 'PhpPresentation_Serialized'); - $oArchive = new \ZipArchive(); - $oArchive->open($file, \ZipArchive::CREATE); + + $this->expectException(InvalidFileFormatException::class); + $this->expectExceptionMessage(sprintf( + 'The file %s is not in the format supported by class PhpOffice\PhpPresentation\Reader\Serialized (The file PhpPresentation.xml is malformed)', + $file + )); + + $oArchive = new ZipArchive(); + $oArchive->open($file, ZipArchive::CREATE); $oArchive->addFromString('PhpPresentation.xml', ''); $oArchive->close(); - + $object = new Serialized(); - $this->assertNull($object->load($file)); + $object->load($file); } } diff --git a/tests/PhpPresentation/Tests/Shape/AbstractGraphicTest.php b/tests/PhpPresentation/Tests/Shape/AbstractGraphicTest.php index 2f6b2cb767..54d6cf41ed 100644 --- a/tests/PhpPresentation/Tests/Shape/AbstractGraphicTest.php +++ b/tests/PhpPresentation/Tests/Shape/AbstractGraphicTest.php @@ -10,23 +10,27 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\AbstractGraphic; +use PHPUnit\Framework\TestCase; /** - * Test class for Table element + * Test class for Table element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\AbstractGraphic + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\AbstractGraphic */ -class AbstractGraphicTest extends \PHPUnit_Framework_TestCase +class AbstractGraphicTest extends TestCase { - public function testWidthAndHeight() + public function testWidthAndHeight(): void { $min = 10; $max = 20; @@ -59,7 +63,7 @@ public function testWidthAndHeight() $this->assertEquals($min, $stub->getHeight()); } - public function testWidthAndHeight2() + public function testWidthAndHeight2(): void { $min = 10; $max = 20; diff --git a/tests/PhpPresentation/Tests/Shape/AutoShapeTest.php b/tests/PhpPresentation/Tests/Shape/AutoShapeTest.php new file mode 100644 index 0000000000..9e235e2df7 --- /dev/null +++ b/tests/PhpPresentation/Tests/Shape/AutoShapeTest.php @@ -0,0 +1,67 @@ +assertEquals(AutoShape::TYPE_HEART, $object->getType()); + $this->assertEquals('', $object->getText()); + $this->assertInstanceOf(Outline::class, $object->getOutline()); + $this->assertIsString($object->getHashCode()); + } + + public function testOutline(): void + { + /** @var Outline $mock */ + $mock = $this->getMockBuilder(Outline::class)->getMock(); + + $object = new AutoShape(); + $this->assertInstanceOf(Outline::class, $object->getOutline()); + $this->assertInstanceOf(AutoShape::class, $object->setOutline($mock)); + $this->assertInstanceOf(Outline::class, $object->getOutline()); + } + + public function testText(): void + { + $object = new AutoShape(); + + $this->assertEquals('', $object->getText()); + $this->assertInstanceOf(AutoShape::class, $object->setText('Text')); + $this->assertEquals('Text', $object->getText()); + } + + public function testType(): void + { + $object = new AutoShape(); + + $this->assertEquals(AutoShape::TYPE_HEART, $object->getType()); + $this->assertInstanceOf(AutoShape::class, $object->setType(AutoShape::TYPE_HEXAGON)); + $this->assertEquals(AutoShape::TYPE_HEXAGON, $object->getType()); + } +} diff --git a/tests/PhpPresentation/Tests/Shape/Chart/AxisTest.php b/tests/PhpPresentation/Tests/Shape/Chart/AxisTest.php index f29046416b..8696d38742 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/AxisTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/AxisTest.php @@ -10,143 +10,189 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Chart\Axis; +use PhpOffice\PhpPresentation\Shape\Chart\Gridlines; use PhpOffice\PhpPresentation\Style\Font; +use PhpOffice\PhpPresentation\Style\Outline; +use PHPUnit\Framework\TestCase; /** - * Test class for Axis element + * Test class for Axis element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Axis + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Axis */ -class AxisTest extends \PHPUnit_Framework_TestCase +class AxisTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Axis(); $this->assertEquals('Axis Title', $object->getTitle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); + $this->assertInstanceOf(Font::class, $object->getFont()); $this->assertNull($object->getMinorGridlines()); $this->assertNull($object->getMajorGridlines()); } - public function testBounds() + public function testBounds(): void { - $value = rand(0, 100); + $value = mt_rand(0, 100); $object = new Axis(); $this->assertNull($object->getMinBounds()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinBounds($value)); + $this->assertInstanceOf(Axis::class, $object->setMinBounds($value)); $this->assertEquals($value, $object->getMinBounds()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinBounds()); + $this->assertInstanceOf(Axis::class, $object->setMinBounds()); $this->assertNull($object->getMinBounds()); $this->assertNull($object->getMaxBounds()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMaxBounds($value)); + $this->assertInstanceOf(Axis::class, $object->setMaxBounds($value)); $this->assertEquals($value, $object->getMaxBounds()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMaxBounds()); + $this->assertInstanceOf(Axis::class, $object->setMaxBounds()); $this->assertNull($object->getMaxBounds()); } - public function testFont() + public function testFont(): void { $object = new Axis(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setFont()); + $this->assertInstanceOf(Axis::class, $object->setFont()); $this->assertNull($object->getFont()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setFont(new Font())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); + $this->assertInstanceOf(Axis::class, $object->setFont(new Font())); + $this->assertInstanceOf(Font::class, $object->getFont()); } - public function testFormatCode() + public function testFormatCode(): void { $object = new Axis(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setFormatCode()); + $this->assertInstanceOf(Axis::class, $object->setFormatCode()); $this->assertEquals('', $object->getFormatCode()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setFormatCode('AAAA')); + $this->assertInstanceOf(Axis::class, $object->setFormatCode('AAAA')); $this->assertEquals('AAAA', $object->getFormatCode()); } - public function testGridLines() + public function testGridLines(): void { $object = new Axis(); - $oMock = $this->getMockBuilder('PhpOffice\PhpPresentation\Shape\Chart\Gridlines')->getMock(); + /** @var Gridlines $oMock */ + $oMock = $this->getMockBuilder(Gridlines::class)->getMock(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMajorGridlines($oMock)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Gridlines', $object->getMajorGridlines()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinorGridlines($oMock)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Gridlines', $object->getMinorGridlines()); + $this->assertInstanceOf(Axis::class, $object->setMajorGridlines($oMock)); + $this->assertInstanceOf(Gridlines::class, $object->getMajorGridlines()); + $this->assertInstanceOf(Axis::class, $object->setMinorGridlines($oMock)); + $this->assertInstanceOf(Gridlines::class, $object->getMinorGridlines()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new Axis(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setHashIndex($value)); + $this->assertInstanceOf(Axis::class, $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testIsVisible() + public function testIsVisible(): void { $object = new Axis(); $this->assertTrue($object->isVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setIsVisible(false)); + $this->assertInstanceOf(Axis::class, $object->setIsVisible(false)); $this->assertFalse($object->isVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setIsVisible(true)); + $this->assertInstanceOf(Axis::class, $object->setIsVisible(true)); $this->assertTrue($object->isVisible()); } - public function testTitle() + public function testLabelRotation(): void { $object = new Axis(); - $this->assertEquals('Axis Title', $object->getTitle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setTitle('AAAA')); - $this->assertEquals('AAAA', $object->getTitle()); + $this->assertEquals(0, $object->getTitleRotation()); + $this->assertInstanceOf(Axis::class, $object->setTitleRotation(-1)); + $this->assertEquals(0, $object->getTitleRotation()); + $this->assertInstanceOf(Axis::class, $object->setTitleRotation(361)); + $this->assertEquals(360, $object->getTitleRotation()); + $value = rand(0, 360); + $this->assertInstanceOf(Axis::class, $object->setTitleRotation($value)); + $this->assertEquals($value, $object->getTitleRotation()); + } + + public function testOutline(): void + { + /** @var Outline $oMock */ + $oMock = $this->getMockBuilder(Outline::class)->getMock(); + + $object = new Axis(); + $this->assertInstanceOf(Outline::class, $object->getOutline()); + $this->assertInstanceOf(Axis::class, $object->setOutline($oMock)); + $this->assertInstanceOf(Outline::class, $object->getOutline()); + } + + public function testTickLabelPosition(): void + { + $object = new Axis(); + + $this->assertEquals(Axis::TICK_LABEL_POSITION_NEXT_TO, $object->getTickLabelPosition()); + $this->assertInstanceOf(Axis::class, $object->setTickLabelPosition(Axis::TICK_LABEL_POSITION_HIGH)); + $this->assertEquals(Axis::TICK_LABEL_POSITION_HIGH, $object->getTickLabelPosition()); + $this->assertInstanceOf(Axis::class, $object->setTickLabelPosition(Axis::TICK_LABEL_POSITION_NEXT_TO)); + $this->assertEquals(Axis::TICK_LABEL_POSITION_NEXT_TO, $object->getTickLabelPosition()); + $this->assertInstanceOf(Axis::class, $object->setTickLabelPosition(Axis::TICK_LABEL_POSITION_LOW)); + $this->assertEquals(Axis::TICK_LABEL_POSITION_LOW, $object->getTickLabelPosition()); + $this->assertInstanceOf(Axis::class, $object->setTickLabelPosition('Unauthorized')); + $this->assertEquals(Axis::TICK_LABEL_POSITION_LOW, $object->getTickLabelPosition()); } - public function testTickMark() + public function testTickMark(): void { $value = Axis::TICK_MARK_INSIDE; $object = new Axis(); $this->assertEquals(Axis::TICK_MARK_NONE, $object->getMinorTickMark()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinorTickMark($value)); + $this->assertInstanceOf(Axis::class, $object->setMinorTickMark($value)); $this->assertEquals($value, $object->getMinorTickMark()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinorTickMark()); + $this->assertInstanceOf(Axis::class, $object->setMinorTickMark()); $this->assertEquals(Axis::TICK_MARK_NONE, $object->getMinorTickMark()); $this->assertEquals(Axis::TICK_MARK_NONE, $object->getMajorTickMark()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMajorTickMark($value)); + $this->assertInstanceOf(Axis::class, $object->setMajorTickMark($value)); $this->assertEquals($value, $object->getMajorTickMark()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMajorTickMark()); + $this->assertInstanceOf(Axis::class, $object->setMajorTickMark()); $this->assertEquals(Axis::TICK_MARK_NONE, $object->getMajorTickMark()); } - public function testUnit() + public function testTitle(): void + { + $object = new Axis(); + $this->assertEquals('Axis Title', $object->getTitle()); + $this->assertInstanceOf(Axis::class, $object->setTitle('AAAA')); + $this->assertEquals('AAAA', $object->getTitle()); + } + + public function testUnit(): void { - $value = rand(0, 100); + $value = mt_rand(0, 100); $object = new Axis(); $this->assertNull($object->getMinorUnit()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinorUnit($value)); + $this->assertInstanceOf(Axis::class, $object->setMinorUnit($value)); $this->assertEquals($value, $object->getMinorUnit()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMinorUnit()); + $this->assertInstanceOf(Axis::class, $object->setMinorUnit()); $this->assertNull($object->getMinorUnit()); $this->assertNull($object->getMajorUnit()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMajorUnit($value)); + $this->assertInstanceOf(Axis::class, $object->setMajorUnit($value)); $this->assertEquals($value, $object->getMajorUnit()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->setMajorUnit()); + $this->assertInstanceOf(Axis::class, $object->setMajorUnit()); $this->assertNull($object->getMajorUnit()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/GridlinesTest.php b/tests/PhpPresentation/Tests/Shape/Chart/GridlinesTest.php index 6a4fd4ea0d..fe0e964519 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/GridlinesTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/GridlinesTest.php @@ -1,26 +1,47 @@ assertInstanceOf('PhpOffice\PhpPresentation\Style\Outline', $object->getOutline()); + $this->assertInstanceOf(Outline::class, $object->getOutline()); } - public function testGetSetOutline() + public function testGetSetOutline(): void { $object = new Gridlines(); - $oStub = $this->getMockBuilder('PhpOffice\PhpPresentation\Style\Outline')->getMock(); + /** @var Outline $oStub */ + $oStub = $this->getMockBuilder(Outline::class)->getMock(); - $this->assertInstanceOf('PhpOffice\PhpPresentation\Style\Outline', $object->getOutline()); + $this->assertInstanceOf(Outline::class, $object->getOutline()); $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\Chart\Gridlines', $object->setOutline($oStub)); - $this->assertInstanceOf('PhpOffice\PhpPresentation\Style\Outline', $object->getOutline()); + $this->assertInstanceOf(Outline::class, $object->getOutline()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/LegendTest.php b/tests/PhpPresentation/Tests/Shape/Chart/LegendTest.php index b9be6f5d82..3b57adbb25 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/LegendTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/LegendTest.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Chart\Legend; @@ -22,15 +25,16 @@ use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for Legend element + * Test class for Legend element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Legend + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Legend */ -class LegendTest extends \PHPUnit_Framework_TestCase +class LegendTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Legend(); @@ -40,7 +44,7 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->getAlignment()); } - public function testAlignment() + public function testAlignment(): void { $object = new Legend(); @@ -48,7 +52,7 @@ public function testAlignment() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->getAlignment()); } - public function testBorder() + public function testBorder(): void { $object = new Legend(); @@ -57,7 +61,7 @@ public function testBorder() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->getBorder()); } - public function testFill() + public function testFill(): void { $object = new Legend(); @@ -66,7 +70,7 @@ public function testFill() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); } - public function testFont() + public function testFont(): void { $object = new Legend(); @@ -76,20 +80,20 @@ public function testFont() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new Legend(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testHeight() + public function testHeight(): void { $object = new Legend(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->setHeight()); $this->assertEquals(0, $object->getHeight()); @@ -97,10 +101,10 @@ public function testHeight() $this->assertEquals($value, $object->getHeight()); } - public function testOffsetX() + public function testOffsetX(): void { $object = new Legend(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->setOffsetX()); $this->assertEquals(0, $object->getOffsetX()); @@ -108,10 +112,10 @@ public function testOffsetX() $this->assertEquals($value, $object->getOffsetX()); } - public function testOffsetY() + public function testOffsetY(): void { $object = new Legend(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->setOffsetY()); $this->assertEquals(0, $object->getOffsetY()); @@ -119,7 +123,7 @@ public function testOffsetY() $this->assertEquals($value, $object->getOffsetY()); } - public function testPosition() + public function testPosition(): void { $object = new Legend(); @@ -129,7 +133,7 @@ public function testPosition() $this->assertEquals(Legend::POSITION_BOTTOM, $object->getPosition()); } - public function testVisible() + public function testVisible(): void { $object = new Legend(); @@ -141,10 +145,10 @@ public function testVisible() $this->assertFalse($object->isVisible()); } - public function testWidth() + public function testWidth(): void { $object = new Legend(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->setWidth()); $this->assertEquals(0, $object->getWidth()); diff --git a/tests/PhpPresentation/Tests/Shape/Chart/MarkerTest.php b/tests/PhpPresentation/Tests/Shape/Chart/MarkerTest.php index d351d9460e..9904ea6607 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/MarkerTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/MarkerTest.php @@ -10,23 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Chart\Marker; +use PhpOffice\PhpPresentation\Style\Border; +use PhpOffice\PhpPresentation\Style\Fill; +use PHPUnit\Framework\TestCase; /** - * Test class for Legend element + * Test class for Legend element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Marker + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Marker */ -class MarkerTest extends \PHPUnit_Framework_TestCase +class MarkerTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Marker(); @@ -34,22 +40,38 @@ public function testConstruct() $this->assertEquals(5, $object->getSize()); } - public function testSymbol() + public function testBorder(): void { $object = new Marker(); - $expected = array_rand(Marker::$arraySymbol); + $this->assertInstanceOf(Border::class, $object->getBorder()); + $this->assertInstanceOf(Marker::class, $object->setBorder(new Border())); + } - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Marker', $object->setSymbol($expected)); - $this->assertEquals($expected, $object->getSymbol()); + public function testFill(): void + { + $object = new Marker(); + + $this->assertInstanceOf(Fill::class, $object->getFill()); + $this->assertInstanceOf(Marker::class, $object->setFill(new Fill())); } - public function testSize() + public function testSize(): void { $object = new Marker(); - $value = rand(1, 100); + $value = mt_rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Marker', $object->setSize($value)); + $this->assertInstanceOf(Marker::class, $object->setSize($value)); $this->assertEquals($value, $object->getSize()); } + + public function testSymbol(): void + { + $object = new Marker(); + + $expected = Marker::$arraySymbol[array_rand(Marker::$arraySymbol)]; + + $this->assertInstanceOf(Marker::class, $object->setSymbol($expected)); + $this->assertEquals($expected, $object->getSymbol()); + } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/PlotAreaTest.php b/tests/PhpPresentation/Tests/Shape/Chart/PlotAreaTest.php index 7a0c2fd2d4..42c6a193b4 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/PlotAreaTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/PlotAreaTest.php @@ -10,102 +10,106 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; -use PhpOffice\PhpPresentation\Shape\Chart; +use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException; use PhpOffice\PhpPresentation\Shape\Chart\Axis; use PhpOffice\PhpPresentation\Shape\Chart\PlotArea; +use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType; use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D; +use PHPUnit\Framework\TestCase; /** - * Test class for PlotArea element + * Test class for PlotArea element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\PlotArea + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\PlotArea */ -class PlotAreaTest extends \PHPUnit_Framework_TestCase +class PlotAreaTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new PlotArea(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->getAxisX()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Axis', $object->getAxisY()); + $this->assertInstanceOf(Axis::class, $object->getAxisX()); + $this->assertInstanceOf(Axis::class, $object->getAxisY()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new PlotArea(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setHashIndex($value)); + $this->assertInstanceOf(PlotArea::class, $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testHeight() + public function testHeight(): void { $object = new PlotArea(); - $value = rand(0, 100); + $value = mt_rand(0, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setHeight()); + $this->assertInstanceOf(PlotArea::class, $object->setHeight()); $this->assertEquals(0, $object->getHeight()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setHeight($value)); + $this->assertInstanceOf(PlotArea::class, $object->setHeight($value)); $this->assertEquals($value, $object->getHeight()); } - public function testOffsetX() + public function testOffsetX(): void { $object = new PlotArea(); - $value = rand(0, 100); + $value = mt_rand(0, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setOffsetX()); + $this->assertInstanceOf(PlotArea::class, $object->setOffsetX()); $this->assertEquals(0, $object->getOffsetX()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setOffsetX($value)); + $this->assertInstanceOf(PlotArea::class, $object->setOffsetX($value)); $this->assertEquals($value, $object->getOffsetX()); } - public function testOffsetY() + public function testOffsetY(): void { $object = new PlotArea(); - $value = rand(0, 100); + $value = mt_rand(0, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setOffsetY()); + $this->assertInstanceOf(PlotArea::class, $object->setOffsetY()); $this->assertEquals(0, $object->getOffsetY()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setOffsetY($value)); + $this->assertInstanceOf(PlotArea::class, $object->setOffsetY($value)); $this->assertEquals($value, $object->getOffsetY()); } - public function testType() + public function testType(): void { $object = new PlotArea(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setType(new Bar3D())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\AbstractType', $object->getType()); + $this->assertInstanceOf(PlotArea::class, $object->setType(new Bar3D())); + $this->assertInstanceOf(AbstractType::class, $object->getType()); } - /** - * @expectedException \Exception - * @expectedExceptionMessage Chart type has not been set. - */ - public function testTypeException() + public function testTypeException(): void { + $this->expectException(UndefinedChartTypeException::class); + $this->expectExceptionMessage('The chart type has not been defined'); + $object = new PlotArea(); $object->getType(); } - public function testWidth() + public function testWidth(): void { $object = new PlotArea(); - $value = rand(0, 100); + $value = mt_rand(0, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setWidth()); + $this->assertInstanceOf(PlotArea::class, $object->setWidth()); $this->assertEquals(0, $object->getWidth()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->setWidth($value)); + $this->assertInstanceOf(PlotArea::class, $object->setWidth($value)); $this->assertEquals($value, $object->getWidth()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/SeriesTest.php b/tests/PhpPresentation/Tests/Shape/Chart/SeriesTest.php index 5e3db19c90..f3cc6b7b16 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/SeriesTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/SeriesTest.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Chart\Marker; @@ -22,236 +25,234 @@ use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\Outline; +use PHPUnit\Framework\TestCase; /** - * Test class for Series element + * Test class for Series element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Series + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Series */ -class SeriesTest extends \PHPUnit_Framework_TestCase +class SeriesTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); + $this->assertInstanceOf(Fill::class, $object->getFill()); + $this->assertInstanceOf(Font::class, $object->getFont()); $this->assertEquals('Calibri', $object->getFont()->getName()); $this->assertEquals(9, $object->getFont()->getSize()); $this->assertEquals('Series Title', $object->getTitle()); - $this->assertInternalType('array', $object->getValues()); + $this->assertIsArray($object->getValues()); $this->assertEmpty($object->getValues()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Marker', $object->getMarker()); + $this->assertInstanceOf(Marker::class, $object->getMarker()); $this->assertNull($object->getOutline()); $this->assertFalse($object->hasShowLegendKey()); } - - public function testDataLabelNumFormat() + + public function testDataLabelNumFormat(): void { $object = new Series(); - + $this->assertEmpty($object->getDlblNumFormat()); $this->assertFalse($object->hasDlblNumFormat()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setDlblNumFormat('#%')); - + + $this->assertInstanceOf(Series::class, $object->setDlblNumFormat('#%')); + $this->assertEquals('#%', $object->getDlblNumFormat()); $this->assertTrue($object->hasDlblNumFormat()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setDlblNumFormat()); - + + $this->assertInstanceOf(Series::class, $object->setDlblNumFormat()); + $this->assertEmpty($object->getDlblNumFormat()); $this->assertFalse($object->hasDlblNumFormat()); } - public function testDataPointFills() + public function testDataPointFills(): void { $object = new Series(); - $this->assertInternalType('array', $object->getDataPointFills()); + $this->assertIsArray($object->getDataPointFills()); $this->assertEmpty($object->getDataPointFills()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getDataPointFill(0)); + $this->assertInstanceOf(Fill::class, $object->getDataPointFill(0)); } - public function testFill() + public function testFill(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setFill()); + $this->assertInstanceOf(Series::class, $object->setFill()); $this->assertNull($object->getFill()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setFill(new Fill())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertInstanceOf(Series::class, $object->setFill(new Fill())); + $this->assertInstanceOf(Fill::class, $object->getFill()); } - public function testFont() + public function testFont(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setFont()); + $this->assertInstanceOf(Series::class, $object->setFont()); $this->assertNull($object->getFont()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setFont(new Font())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); + $this->assertInstanceOf(Series::class, $object->setFont(new Font())); + $this->assertInstanceOf(Font::class, $object->getFont()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new Series(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setHashIndex($value)); + $this->assertInstanceOf(Series::class, $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testHashCode() + public function testHashCode(): void { $object = new Series(); - $this->assertEquals(md5($object->getFill()->getHashCode().$object->getFont()->getHashCode().var_export($object->getValues(), true) . var_export($object, true).get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($object->getFill()->getHashCode() . $object->getFont()->getHashCode() . var_export($object->getValues(), true) . var_export($object, true) . get_class($object)), $object->getHashCode()); } - public function testLabelPosition() + public function testLabelPosition(): void { $object = new Series(); $this->assertEmpty($object->getHashIndex()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setLabelPosition(Series::LABEL_INSIDEBASE)); + $this->assertInstanceOf(Series::class, $object->setLabelPosition(Series::LABEL_INSIDEBASE)); $this->assertEquals(Series::LABEL_INSIDEBASE, $object->getLabelPosition()); } - public function testMarker() + public function testMarker(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setMarker(new Marker())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Marker', $object->getMarker()); + $this->assertInstanceOf(Series::class, $object->setMarker(new Marker())); + $this->assertInstanceOf(Marker::class, $object->getMarker()); } - public function testOutline() + public function testOutline(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setOutline(new Outline())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Outline', $object->getOutline()); + $this->assertInstanceOf(Series::class, $object->setOutline(new Outline())); + $this->assertInstanceOf(Outline::class, $object->getOutline()); } - public function testShowCategoryName() + public function testShowCategoryName(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowCategoryName(true)); + $this->assertInstanceOf(Series::class, $object->setShowCategoryName(true)); $this->assertTrue($object->hasShowCategoryName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowCategoryName(false)); + $this->assertInstanceOf(Series::class, $object->setShowCategoryName(false)); $this->assertFalse($object->hasShowCategoryName()); } - public function testShowLeaderLines() + public function testShowLeaderLines(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowLeaderLines(true)); + $this->assertInstanceOf(Series::class, $object->setShowLeaderLines(true)); $this->assertTrue($object->hasShowLeaderLines()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowLeaderLines(false)); + $this->assertInstanceOf(Series::class, $object->setShowLeaderLines(false)); $this->assertFalse($object->hasShowLeaderLines()); } - public function testShowLegendKey() + public function testShowLegendKey(): void { $object = new Series(); $this->assertFalse($object->hasShowLegendKey()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowLegendKey(true)); - $this->assertTrue($object->hasShowLegendKey()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowLegendKey(false)); - $this->assertFalse($object->hasShowLegendKey()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowLegendKey(1)); + $this->assertInstanceOf(Series::class, $object->setShowLegendKey(true)); $this->assertTrue($object->hasShowLegendKey()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowLegendKey(0)); + $this->assertInstanceOf(Series::class, $object->setShowLegendKey(false)); $this->assertFalse($object->hasShowLegendKey()); } - public function testShowPercentage() + public function testShowPercentage(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowPercentage(true)); + $this->assertInstanceOf(Series::class, $object->setShowPercentage(true)); $this->assertTrue($object->hasShowPercentage()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowPercentage(false)); + $this->assertInstanceOf(Series::class, $object->setShowPercentage(false)); $this->assertFalse($object->hasShowPercentage()); } - public function testShowSeparator() + public function testShowSeparator(): void { $value = ';'; $object = new Series(); $this->assertFalse($object->hasShowSeparator()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setSeparator($value)); + $this->assertInstanceOf(Series::class, $object->setSeparator($value)); $this->assertEquals($value, $object->getSeparator()); $this->assertTrue($object->hasShowSeparator()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setSeparator('')); + $this->assertInstanceOf(Series::class, $object->setSeparator('')); $this->assertFalse($object->hasShowPercentage()); } - public function testShowSeriesName() + public function testShowSeriesName(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowSeriesName(true)); + $this->assertInstanceOf(Series::class, $object->setShowSeriesName(true)); $this->assertTrue($object->hasShowSeriesName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowSeriesName(false)); + $this->assertInstanceOf(Series::class, $object->setShowSeriesName(false)); $this->assertFalse($object->hasShowSeriesName()); } - public function testShowValue() + public function testShowValue(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowValue(true)); + $this->assertInstanceOf(Series::class, $object->setShowValue(true)); $this->assertTrue($object->hasShowValue()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setShowValue(false)); + $this->assertInstanceOf(Series::class, $object->setShowValue(false)); $this->assertFalse($object->hasShowValue()); } - public function testTitle() + public function testTitle(): void { $object = new Series(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setTitle()); + $this->assertInstanceOf(Series::class, $object->setTitle()); $this->assertEquals('Series Title', $object->getTitle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setTitle('AAAA')); + $this->assertInstanceOf(Series::class, $object->setTitle('AAAA')); $this->assertEquals('AAAA', $object->getTitle()); } - public function testValue() + public function testValue(): void { $object = new Series(); - $array = array( + /** @var array $array */ + $array = [ '0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd', - ); + ]; - $this->assertInternalType('array', $object->getValues()); + $this->assertIsArray($object->getValues()); $this->assertEmpty($object->getValues()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setValues()); + $this->assertInstanceOf(Series::class, $object->setValues()); $this->assertEmpty($object->getValues()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->setValues($array)); + $this->assertInstanceOf(Series::class, $object->setValues($array)); $this->assertCount(count($array), $object->getValues()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $object->addValue(4, 'e')); + $this->assertInstanceOf(Series::class, $object->addValue('4', 'e')); $this->assertCount(count($array) + 1, $object->getValues()); } - public function testClone() + public function testClone(): void { $object = new Series(); $object->setOutline(new Outline()); $clone = clone $object; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Series', $clone); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Outline', $clone->getOutline()); + $this->assertInstanceOf(Series::class, $clone); + $this->assertInstanceOf(Outline::class, $clone->getOutline()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/TitleTest.php b/tests/PhpPresentation/Tests/Shape/Chart/TitleTest.php index a2ba66f9e8..a2e076451b 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/TitleTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/TitleTest.php @@ -10,25 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Chart\Title; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for Title element + * Test class for Title element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Title + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Title */ -class TitleTest extends \PHPUnit_Framework_TestCase +class TitleTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Title(); @@ -38,7 +42,7 @@ public function testConstruct() $this->assertEquals(18, $object->getFont()->getSize()); } - public function testAlignment() + public function testAlignment(): void { $object = new Title(); @@ -46,7 +50,7 @@ public function testAlignment() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->getAlignment()); } - public function testFont() + public function testFont(): void { $object = new Title(); @@ -56,20 +60,20 @@ public function testFont() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new Title(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testHeight() + public function testHeight(): void { $object = new Title(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->setHeight()); $this->assertEquals(0, $object->getHeight()); @@ -77,10 +81,10 @@ public function testHeight() $this->assertEquals($value, $object->getHeight()); } - public function testOffsetX() + public function testOffsetX(): void { $object = new Title(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->setOffsetX()); $this->assertEquals(0.01, $object->getOffsetX()); @@ -88,10 +92,10 @@ public function testOffsetX() $this->assertEquals($value, $object->getOffsetX()); } - public function testOffsetY() + public function testOffsetY(): void { $object = new Title(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->setOffsetY()); $this->assertEquals(0.01, $object->getOffsetY()); @@ -99,7 +103,7 @@ public function testOffsetY() $this->assertEquals($value, $object->getOffsetY()); } - public function testText() + public function testText(): void { $object = new Title(); @@ -109,7 +113,7 @@ public function testText() $this->assertEquals('AAAA', $object->getText()); } - public function testVisible() + public function testVisible(): void { $object = new Title(); @@ -121,10 +125,10 @@ public function testVisible() $this->assertFalse($object->isVisible()); } - public function testWidth() + public function testWidth(): void { $object = new Title(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->setWidth()); $this->assertEquals(0, $object->getWidth()); diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/AbstractTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/AbstractTest.php index bb57012bf8..d19327eba2 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/AbstractTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/AbstractTest.php @@ -10,24 +10,29 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType; use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter; +use PHPUnit\Framework\TestCase; /** - * Test class for Scatter element + * Test class for Scatter element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter */ -class AbstractTest extends \PHPUnit_Framework_TestCase +class AbstractTest extends TestCase { - public function testAxis() + public function testAxis(): void { $object = new Scatter(); @@ -35,46 +40,48 @@ public function testAxis() $this->assertTrue($object->hasAxisY()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new Scatter(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testData() + public function testSeries(): void { - $stub = $this->getMockForAbstractClass('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\AbstractType'); - $this->assertEmpty($stub->getData()); - $this->assertInternalType('array', $stub->getData()); + /** @var AbstractType $stub */ + $stub = $this->getMockForAbstractClass(AbstractType::class); + $this->assertEmpty($stub->getSeries()); + $this->assertIsArray($stub->getSeries()); - $arraySeries = array( + $arraySeries = [ + new Series(), new Series(), - new Series() - ); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\AbstractType', $stub->setData($arraySeries)); - $this->assertInternalType('array', $stub->getData()); - $this->assertCount(count($arraySeries), $stub->getData()); + ]; + $this->assertInstanceOf(AbstractType::class, $stub->setSeries($arraySeries)); + $this->assertIsArray($stub->getSeries()); + $this->assertCount(count($arraySeries), $stub->getSeries()); } - public function testClone() + public function testClone(): void { - $arraySeries = array( + $arraySeries = [ new Series(), new Series(), new Series(), new Series(), - ); + ]; - $stub = $this->getMockForAbstractClass('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\AbstractType'); - $stub->setData($arraySeries); + /** @var AbstractType $stub */ + $stub = $this->getMockForAbstractClass(AbstractType::class); + $stub->setSeries($arraySeries); $clone = clone $stub; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\AbstractType', $clone); - $this->assertInternalType('array', $stub->getData()); - $this->assertCount(count($arraySeries), $stub->getData()); + $this->assertInstanceOf(AbstractType::class, $clone); + $this->assertIsArray($stub->getSeries()); + $this->assertCount(count($arraySeries), $stub->getSeries()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/AreaTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/AreaTest.php index 321d8a0e55..e1eba28f60 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/AreaTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/AreaTest.php @@ -10,34 +10,38 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Area; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Area; +use PHPUnit\Framework\TestCase; /** - * Test class for Bar3D element + * Test class for Bar3D element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D */ -class AreaTest extends \PHPUnit_Framework_TestCase +class AreaTest extends TestCase { - public function testData() + public function testData(): void { $object = new Area(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Area', $object->setSeries()); $this->assertEmpty($object->getSeries()); @@ -45,7 +49,7 @@ public function testData() $this->assertCount(count($array), $object->getSeries()); } - public function testSeries() + public function testSeries(): void { $object = new Area(); @@ -53,13 +57,13 @@ public function testSeries() $this->assertCount(1, $object->getSeries()); } - public function testHashCode() + public function testHashCode(): void { $oSeries = new Series(); $object = new Area(); $object->addSeries($oSeries); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/Bar3DTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/Bar3DTest.php index 1fdbc092f3..68df16e1f9 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/Bar3DTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/Bar3DTest.php @@ -10,34 +10,38 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D; +use PHPUnit\Framework\TestCase; /** - * Test class for Bar3D element + * Test class for Bar3D element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D */ -class Bar3DTest extends \PHPUnit_Framework_TestCase +class Bar3DTest extends TestCase { - public function testData() + public function testData(): void { $object = new Bar3D(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Bar3D', $object->setSeries()); $this->assertEmpty($object->getSeries()); @@ -45,15 +49,15 @@ public function testData() $this->assertCount(count($array), $object->getSeries()); } - public function testSeries() + public function testSeries(): void { $object = new Bar3D(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Bar3D', $object->addSeries(new Series())); $this->assertCount(1, $object->getSeries()); } - - public function testBarDirection() + + public function testBarDirection(): void { $object = new Bar3D(); $this->assertEquals(Bar3D::DIRECTION_VERTICAL, $object->getBarDirection()); @@ -63,7 +67,7 @@ public function testBarDirection() $this->assertEquals(Bar3D::DIRECTION_VERTICAL, $object->getBarDirection()); } - public function testBarGrouping() + public function testBarGrouping(): void { $object = new Bar3D(); $this->assertEquals(Bar3D::GROUPING_CLUSTERED, $object->getBarGrouping()); @@ -75,9 +79,9 @@ public function testBarGrouping() $this->assertEquals(Bar3D::GROUPING_PERCENTSTACKED, $object->getBarGrouping()); } - public function testGapWidthPercent() + public function testGapWidthPercent(): void { - $value = rand(0, 500); + $value = mt_rand(0, 500); $object = new Bar3D(); $this->assertEquals(150, $object->getGapWidthPercent()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Bar3D', $object->setGapWidthPercent($value)); @@ -88,13 +92,13 @@ public function testGapWidthPercent() $this->assertEquals(500, $object->getGapWidthPercent()); } - public function testHashCode() + public function testHashCode(): void { $oSeries = new Series(); $object = new Bar3D(); $object->addSeries($oSeries); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/BarTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/BarTest.php index 382684ead2..8b7dbd7dc9 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/BarTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/BarTest.php @@ -10,34 +10,38 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar; +use PHPUnit\Framework\TestCase; /** - * Test class for Bar element + * Test class for Bar element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Bar + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Bar */ -class BarTest extends \PHPUnit_Framework_TestCase +class BarTest extends TestCase { - public function testData() + public function testData(): void { $object = new Bar(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Bar', $object->setSeries()); $this->assertEmpty($object->getSeries()); @@ -45,15 +49,15 @@ public function testData() $this->assertCount(count($array), $object->getSeries()); } - public function testSeries() + public function testSeries(): void { $object = new Bar(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Bar', $object->addSeries(new Series())); $this->assertCount(1, $object->getSeries()); } - - public function testBarDirection() + + public function testBarDirection(): void { $object = new Bar(); $this->assertEquals(Bar::DIRECTION_VERTICAL, $object->getBarDirection()); @@ -63,7 +67,7 @@ public function testBarDirection() $this->assertEquals(Bar::DIRECTION_VERTICAL, $object->getBarDirection()); } - public function testBarGrouping() + public function testBarGrouping(): void { $object = new Bar(); $this->assertEquals(Bar::GROUPING_CLUSTERED, $object->getBarGrouping()); @@ -75,9 +79,9 @@ public function testBarGrouping() $this->assertEquals(Bar::GROUPING_PERCENTSTACKED, $object->getBarGrouping()); } - public function testGapWidthPercent() + public function testGapWidthPercent(): void { - $value = rand(0, 500); + $value = mt_rand(0, 500); $object = new Bar(); $this->assertEquals(150, $object->getGapWidthPercent()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Bar', $object->setGapWidthPercent($value)); @@ -88,13 +92,39 @@ public function testGapWidthPercent() $this->assertEquals(500, $object->getGapWidthPercent()); } - public function testHashCode() + public function testOverlapWidthPercentDefaults(): void + { + $object = new Bar(); + $this->assertEquals(0, $object->getOverlapWidthPercent()); + + $object->setBarGrouping(Bar::GROUPING_STACKED); + $this->assertEquals(100, $object->getOverlapWidthPercent()); + $object->setBarGrouping(Bar::GROUPING_CLUSTERED); + $this->assertEquals(0, $object->getOverlapWidthPercent()); + $object->setBarGrouping(Bar::GROUPING_PERCENTSTACKED); + $this->assertEquals(100, $object->getOverlapWidthPercent()); + } + + public function testOverlapWidthPercent(): void + { + $value = mt_rand(-100, 100); + $object = new Bar(); + $this->assertEquals(0, $object->getOverlapWidthPercent()); + $this->assertInstanceOf(Bar::class, $object->setOverlapWidthPercent($value)); + $this->assertEquals($value, $object->getOverlapWidthPercent()); + $this->assertInstanceOf(Bar::class, $object->setOverlapWidthPercent(101)); + $this->assertEquals(100, $object->getOverlapWidthPercent()); + $this->assertInstanceOf(Bar::class, $object->setOverlapWidthPercent(-101)); + $this->assertEquals(-100, $object->getOverlapWidthPercent()); + } + + public function testHashCode(): void { $oSeries = new Series(); $object = new Bar(); $object->addSeries($oSeries); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/DoughnutTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/DoughnutTest.php new file mode 100644 index 0000000000..a6c8a22045 --- /dev/null +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/DoughnutTest.php @@ -0,0 +1,85 @@ +assertIsArray($object->getSeries()); + $this->assertEmpty($object->getSeries()); + + $array = [ + new Series(), + new Series(), + ]; + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->setSeries()); + $this->assertEmpty($object->getSeries()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->setSeries($array)); + $this->assertCount(count($array), $object->getSeries()); + } + + public function testHoleSize(): void + { + $rand = mt_rand(10, 90); + $object = new Doughnut(); + + $this->assertEquals(50, $object->getHoleSize()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->setHoleSize(9)); + $this->assertEquals(10, $object->getHoleSize()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->setHoleSize(91)); + $this->assertEquals(90, $object->getHoleSize()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->setHoleSize($rand)); + $this->assertEquals($rand, $object->getHoleSize()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->setHoleSize()); + $this->assertEquals(50, $object->getHoleSize()); + } + + public function testSeries(): void + { + $object = new Doughnut(); + + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Doughnut', $object->addSeries(new Series())); + $this->assertCount(1, $object->getSeries()); + } + + public function testHashCode(): void + { + $oSeries = new Series(); + + $object = new Doughnut(); + $object->addSeries($oSeries); + + $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); + } +} diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php index f8d0006a9d..05b6cb6f3f 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php @@ -10,56 +10,72 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Line; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Line; +use PHPUnit\Framework\TestCase; /** - * Test class for Line element + * Test class for Line element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Line + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Line */ -class LineTest extends \PHPUnit_Framework_TestCase +class LineTest extends TestCase { - public function testData() + public function testData(): void { $object = new Line(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Line', $object->setSeries()); + $this->assertInstanceOf(Line::class, $object->setSeries()); $this->assertEmpty($object->getSeries()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Line', $object->setSeries($array)); + $this->assertInstanceOf(Line::class, $object->setSeries($array)); $this->assertCount(count($array), $object->getSeries()); } - public function testSerties() + public function testSeries(): void { $object = new Line(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Line', $object->addSeries(new Series())); + $this->assertInstanceOf(Line::class, $object->addSeries(new Series())); $this->assertCount(1, $object->getSeries()); } - public function testHashCode() + public function testSmooth(): void { - $oSeries = new Series(); + $object = new Line(); + + $this->assertFalse($object->isSmooth()); + $this->assertInstanceOf(Line::class, $object->setIsSmooth(true)); + $this->assertTrue($object->isSmooth()); + } + + public function testHashCode(): void + { + $series = new Series(); $object = new Line(); - $object->addSeries($oSeries); + $object->addSeries($series); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals( + md5(md5($object->isSmooth() ? '1' : '0') . $series->getHashCode() . get_class($object)), + $object->getHashCode() + ); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/Pie3DTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/Pie3DTest.php index ebdf555cf6..33f825c179 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/Pie3DTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/Pie3DTest.php @@ -10,34 +10,38 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D; +use PHPUnit\Framework\TestCase; /** - * Test class for Pie3D element + * Test class for Pie3D element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D */ -class Pie3DTest extends \PHPUnit_Framework_TestCase +class Pie3DTest extends TestCase { - public function testData() + public function testData(): void { $object = new Pie3D(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Pie3D', $object->setSeries()); $this->assertEmpty($object->getSeries()); @@ -45,7 +49,7 @@ public function testData() $this->assertCount(count($array), $object->getSeries()); } - public function testSeries() + public function testSeries(): void { $object = new Pie3D(); @@ -53,10 +57,9 @@ public function testSeries() $this->assertCount(1, $object->getSeries()); } - public function testExplosion() + public function testExplosion(): void { - $value = rand(0, 100); - + $value = mt_rand(0, 100); $object = new Pie3D(); $this->assertEquals(0, $object->getExplosion()); @@ -64,13 +67,13 @@ public function testExplosion() $this->assertEquals($value, $object->getExplosion()); } - public function testHashCode() + public function testHashCode(): void { $oSeries = new Series(); $object = new Pie3D(); $object->addSeries($oSeries); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/PieTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/PieTest.php index a0d77e8cd7..42f5b5d6aa 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/PieTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/PieTest.php @@ -10,34 +10,38 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie; +use PHPUnit\Framework\TestCase; /** - * Test class for Pie element + * Test class for Pie element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Pie + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Pie */ -class PieTest extends \PHPUnit_Framework_TestCase +class PieTest extends TestCase { - public function testData() + public function testData(): void { $object = new Pie(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Pie', $object->setSeries()); $this->assertEmpty($object->getSeries()); @@ -45,7 +49,7 @@ public function testData() $this->assertCount(count($array), $object->getSeries()); } - public function testSeries() + public function testSeries(): void { $object = new Pie(); @@ -53,14 +57,13 @@ public function testSeries() $this->assertCount(1, $object->getSeries()); } - - public function testHashCode() + public function testHashCode(): void { $oSeries = new Series(); $object = new Pie(); $object->addSeries($oSeries); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/RadarTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/RadarTest.php new file mode 100644 index 0000000000..07a3cb2f97 --- /dev/null +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/RadarTest.php @@ -0,0 +1,38 @@ +addSeries($series); + + $this->assertEquals(md5($series->getHashCode() . get_class($object)), $object->getHashCode()); + } +} diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php index f74c92091b..ca8134be77 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php @@ -10,56 +10,72 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart\Type; -use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter; use PhpOffice\PhpPresentation\Shape\Chart\Series; +use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter; +use PHPUnit\Framework\TestCase; /** - * Test class for Scatter element + * Test class for Scatter element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter */ -class ScatterTest extends \PHPUnit_Framework_TestCase +class ScatterTest extends TestCase { - public function testData() + public function testData(): void { $object = new Scatter(); - $this->assertInternalType('array', $object->getSeries()); + $this->assertIsArray($object->getSeries()); $this->assertEmpty($object->getSeries()); - $array = array( + $array = [ new Series(), new Series(), - ); + ]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->setSeries()); + $this->assertInstanceOf(Scatter::class, $object->setSeries()); $this->assertEmpty($object->getSeries()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->setSeries($array)); + $this->assertInstanceOf(Scatter::class, $object->setSeries($array)); $this->assertCount(count($array), $object->getSeries()); } - public function testSerties() + public function testSeries(): void { $object = new Scatter(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->addSeries(new Series())); + $this->assertInstanceOf(Scatter::class, $object->addSeries(new Series())); $this->assertCount(1, $object->getSeries()); } - public function testHashCode() + public function testSmooth(): void { - $oSeries = new Series(); + $object = new Scatter(); + + $this->assertFalse($object->isSmooth()); + $this->assertInstanceOf(Scatter::class, $object->setIsSmooth(true)); + $this->assertTrue($object->isSmooth()); + } + + public function testHashCode(): void + { + $series = new Series(); $object = new Scatter(); - $object->addSeries($oSeries); + $object->addSeries($series); - $this->assertEquals(md5($oSeries->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals( + md5(md5($object->isSmooth() ? '1' : '0') . $series->getHashCode() . get_class($object)), + $object->getHashCode() + ); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/View3DTest.php b/tests/PhpPresentation/Tests/Shape/Chart/View3DTest.php index 720376be84..f86d39fb15 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/View3DTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/View3DTest.php @@ -10,26 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Chart\View3D; +use PHPUnit\Framework\TestCase; /** - * Test class for View3D element + * Test class for View3D element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart\View3D + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart\View3D */ -class View3DTest extends \PHPUnit_Framework_TestCase +class View3DTest extends TestCase { - public function testDepthPercent() + public function testDepthPercent(): void { $object = new View3D(); - $value = rand(20, 20000); + $value = mt_rand(20, 20000); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->setDepthPercent()); $this->assertEquals(100, $object->getDepthPercent()); @@ -37,20 +41,20 @@ public function testDepthPercent() $this->assertEquals($value, $object->getDepthPercent()); } - public function testHashIndex() + public function testHashIndex(): void { $object = new View3D(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertEmpty($object->getHashIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->setHashIndex($value)); $this->assertEquals($value, $object->getHashIndex()); } - public function testHeightPercent() + public function testHeightPercent(): void { $object = new View3D(); - $value = rand(5, 500); + $value = mt_rand(5, 500); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->setHeightPercent()); $this->assertEquals(100, $object->getHeightPercent()); @@ -58,10 +62,10 @@ public function testHeightPercent() $this->assertEquals($value, $object->getHeightPercent()); } - public function testPerspective() + public function testPerspective(): void { $object = new View3D(); - $value = rand(0, 100); + $value = mt_rand(0, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->setPerspective()); $this->assertEquals(30, $object->getPerspective()); @@ -69,7 +73,7 @@ public function testPerspective() $this->assertEquals($value, $object->getPerspective()); } - public function testRightAngleAxes() + public function testRightAngleAxes(): void { $object = new View3D(); @@ -81,10 +85,10 @@ public function testRightAngleAxes() $this->assertFalse($object->hasRightAngleAxes()); } - public function testRotationX() + public function testRotationX(): void { $object = new View3D(); - $value = rand(-90, 90); + $value = mt_rand(-90, 90); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->setRotationX()); $this->assertEquals(0, $object->getRotationX()); @@ -92,10 +96,10 @@ public function testRotationX() $this->assertEquals($value, $object->getRotationX()); } - public function testRotationY() + public function testRotationY(): void { $object = new View3D(); - $value = rand(-90, 90); + $value = mt_rand(-90, 90); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->setRotationY()); $this->assertEquals(0, $object->getRotationY()); diff --git a/tests/PhpPresentation/Tests/Shape/ChartTest.php b/tests/PhpPresentation/Tests/Shape/ChartTest.php index 4ff2ff232b..b51d857757 100644 --- a/tests/PhpPresentation/Tests/Shape/ChartTest.php +++ b/tests/PhpPresentation/Tests/Shape/ChartTest.php @@ -10,56 +10,74 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\Chart; +use PHPUnit\Framework\TestCase; /** - * Test class for Chart element + * Test class for Chart element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Chart + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Chart */ -class ChartTest extends \PHPUnit_Framework_TestCase +class ChartTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Chart(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $object->getTitle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $object->getLegend()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $object->getPlotArea()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $object->getView3D()); + $this->assertInstanceOf(Chart\Title::class, $object->getTitle()); + $this->assertInstanceOf(Chart\Legend::class, $object->getLegend()); + $this->assertInstanceOf(Chart\PlotArea::class, $object->getPlotArea()); + $this->assertInstanceOf(Chart\View3D::class, $object->getView3D()); } - - public function testClone() + public function testClone(): void { $object = new Chart(); - + $oClone = clone $object; - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $oClone); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Title', $oClone->getTitle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Legend', $oClone->getLegend()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\PlotArea', $oClone->getPlotArea()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\View3D', $oClone->getView3D()); + + $this->assertInstanceOf(Chart::class, $oClone); + $this->assertInstanceOf(Chart\Title::class, $oClone->getTitle()); + $this->assertInstanceOf(Chart\Legend::class, $oClone->getLegend()); + $this->assertInstanceOf(Chart\PlotArea::class, $oClone->getPlotArea()); + $this->assertInstanceOf(Chart\View3D::class, $oClone->getView3D()); + } + + public function testDisplayBlankAs(): void + { + $object = new Chart(); + + $this->assertEquals(Chart::BLANKAS_ZERO, $object->getDisplayBlankAs()); + $this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs(Chart::BLANKAS_GAP)); + $this->assertEquals(Chart::BLANKAS_GAP, $object->getDisplayBlankAs()); + $this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs(Chart::BLANKAS_ZERO)); + $this->assertEquals(Chart::BLANKAS_ZERO, $object->getDisplayBlankAs()); + $this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs(Chart::BLANKAS_SPAN)); + $this->assertEquals(Chart::BLANKAS_SPAN, $object->getDisplayBlankAs()); + $this->assertInstanceOf(Chart::class, $object->setDisplayBlankAs('Unauthorized value')); + $this->assertEquals(Chart::BLANKAS_SPAN, $object->getDisplayBlankAs()); } - public function testIncludeSpreadsheet() + public function testIncludeSpreadsheet(): void { $object = new Chart(); $this->assertFalse($object->hasIncludedSpreadsheet()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->setIncludeSpreadsheet()); + $this->assertInstanceOf(Chart::class, $object->setIncludeSpreadsheet()); $this->assertFalse($object->hasIncludedSpreadsheet()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->setIncludeSpreadsheet(false)); + $this->assertInstanceOf(Chart::class, $object->setIncludeSpreadsheet(false)); $this->assertFalse($object->hasIncludedSpreadsheet()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->setIncludeSpreadsheet(true)); + $this->assertInstanceOf(Chart::class, $object->setIncludeSpreadsheet(true)); $this->assertTrue($object->hasIncludedSpreadsheet()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Comment/AuthorTest.php b/tests/PhpPresentation/Tests/Shape/Comment/AuthorTest.php index cc4afc082a..e705542467 100644 --- a/tests/PhpPresentation/Tests/Shape/Comment/AuthorTest.php +++ b/tests/PhpPresentation/Tests/Shape/Comment/AuthorTest.php @@ -10,23 +10,27 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Comment; use PhpOffice\PhpPresentation\Shape\Comment\Author; +use PHPUnit\Framework\TestCase; /** - * Test class for Author element + * Test class for Author element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Comment\Author + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Comment\Author */ -class AuthorTest extends \PHPUnit_Framework_TestCase +class AuthorTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Author(); @@ -35,9 +39,9 @@ public function testConstruct() $this->assertNull($object->getInitials()); } - public function testGetSetIndex() + public function testGetSetIndex(): void { - $expectedVal = rand(1, 100); + $expectedVal = mt_rand(1, 100); $object = new Author(); $this->assertNull($object->getIndex()); @@ -45,7 +49,7 @@ public function testGetSetIndex() $this->assertEquals($expectedVal, $object->getIndex()); } - public function testGetSetInitials() + public function testGetSetInitials(): void { $expectedVal = 'AABBCCDD'; @@ -55,7 +59,7 @@ public function testGetSetInitials() $this->assertEquals($expectedVal, $object->getInitials()); } - public function testGetSetName() + public function testGetSetName(): void { $expectedVal = 'AABBCCDD'; diff --git a/tests/PhpPresentation/Tests/Shape/CommentTest.php b/tests/PhpPresentation/Tests/Shape/CommentTest.php index 84391c1632..b1c3490e7d 100644 --- a/tests/PhpPresentation/Tests/Shape/CommentTest.php +++ b/tests/PhpPresentation/Tests/Shape/CommentTest.php @@ -10,72 +10,78 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\Comment; +use PhpOffice\PhpPresentation\Shape\Comment\Author; +use PHPUnit\Framework\TestCase; /** - * Test class for Chart element + * Test class for Chart element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Comment + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Comment */ -class CommentTest extends \PHPUnit_Framework_TestCase +class CommentTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Comment(); $this->assertNull($object->getAuthor()); $this->assertNull($object->getText()); - $this->assertInternalType('int', $object->getDate()); + $this->assertIsInt($object->getDate()); $this->assertNull($object->getHeight()); $this->assertNull($object->getWidth()); } - public function testGetSetAuthor() + public function testGetSetAuthor(): void { $object = new Comment(); - $oStub = $this->getMockBuilder('PhpOffice\PhpPresentation\Shape\Comment\Author')->getMock(); + /** @var Author $oStub */ + $oStub = $this->getMockBuilder(Author::class)->getMock(); $this->assertNull($object->getAuthor()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Comment', $object->setAuthor($oStub)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Comment\\Author', $object->getAuthor()); + $this->assertInstanceOf(Comment::class, $object->setAuthor($oStub)); + $this->assertInstanceOf(Author::class, $object->getAuthor()); } - public function testGetSetDate() + public function testGetSetDate(): void { $expectedDate = time(); $object = new Comment(); - $this->assertInternalType('int', $object->getDate()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Comment', $object->setDate($expectedDate)); + $this->assertIsInt($object->getDate()); + $this->assertInstanceOf(Comment::class, $object->setDate($expectedDate)); $this->assertEquals($expectedDate, $object->getDate()); - $this->assertInternalType('int', $object->getDate()); + $this->assertIsInt($object->getDate()); } - public function testGetSetText() + public function testGetSetText(): void { $expectedText = 'AABBCCDD'; $object = new Comment(); $this->assertNull($object->getText()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Comment', $object->setText($expectedText)); + $this->assertInstanceOf(Comment::class, $object->setText($expectedText)); $this->assertEquals($expectedText, $object->getText()); } - public function testGetSetHeightAndWidtg() + public function testGetSetHeightAndWidtg(): void { $object = new Comment(); $this->assertNull($object->getHeight()); $this->assertNull($object->getWidth()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Comment', $object->setHeight(1)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Comment', $object->setWidth(1)); + $this->assertInstanceOf(Comment::class, $object->setHeight(1)); + $this->assertInstanceOf(Comment::class, $object->setWidth(1)); $this->assertNull($object->getHeight()); $this->assertNull($object->getWidth()); } diff --git a/tests/PhpPresentation/Tests/Shape/Drawing/Base64Test.php b/tests/PhpPresentation/Tests/Shape/Drawing/Base64Test.php index c47b0149bc..c73b8af448 100644 --- a/tests/PhpPresentation/Tests/Shape/Drawing/Base64Test.php +++ b/tests/PhpPresentation/Tests/Shape/Drawing/Base64Test.php @@ -10,78 +10,88 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Drawing; +use PhpOffice\PhpPresentation\Exception\UnauthorizedMimetypeException; use PhpOffice\PhpPresentation\Shape\Drawing\Base64; +use PHPUnit\Framework\TestCase; /** - * Test class for Drawing element + * Test class for Drawing element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Drawing + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Drawing */ -class Base64Test extends \PHPUnit_Framework_TestCase +class Base64Test extends TestCase { - public function setUp() + /** @var string */ + protected $imageDataPNG = ''; + + /** @var string */ + protected $imageDataSVG = ''; + + protected function setUp(): void { parent::setUp(); - DrawingTest::$getimagesizefromstringExists = true; - } + $this->imageDataPNG = file_get_contents(dirname(__DIR__, 4) . '/resources/images/base64_png.txt'); - protected $imageData = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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'; + $this->imageDataSVG = file_get_contents(dirname(__DIR__, 4) . '/resources/images/base64_svg.txt'); + } - public function testData() + public function testData(): void { $oDrawing = new Base64(); - $this->assertNull($oDrawing->getData()); - $oDrawing->setData($this->imageData); + $this->assertEmpty($oDrawing->getData()); + $oDrawing->setData($this->imageDataPNG); $this->assertNotEmpty($oDrawing->getData()); } - public function testExtension() + public function testExtension(): void { $oDrawing = new Base64(); - $oDrawing->setData($this->imageData); + $oDrawing->setData($this->imageDataPNG); $this->assertEquals('jpg', $oDrawing->getExtension()); } - /** - * @expectedException \Exception - * @expectedExceptionMessage Type Mime not found : "fake/fake" - */ - public function testExtensionException() + public function testExtensionException(): void { - $imgData = str_replace('image/jpeg', 'fake/fake', $this->imageData); + $this->expectException(UnauthorizedMimetypeException::class); + $this->expectExceptionMessage('The mime type fake/fake is not found in autorized values (jpg, png, gif, svg)'); + + $imgData = str_replace('image/jpeg', 'fake/fake', $this->imageDataPNG); $oDrawing = new Base64(); $oDrawing->setData($imgData); $oDrawing->getExtension(); } - /** - * @requires PHP 5.4 - */ - public function testMimeType() + public function testMimeType(): void { $oDrawing = new Base64(); - $oDrawing->setData($this->imageData); + $oDrawing->setData($this->imageDataPNG); $this->assertEquals('image/jpeg', $oDrawing->getMimeType()); } - /** - * @requires PHP 5.4 - */ - public function testMimeTypeFunctionNotExists() + public function testMimeTypeSVG(): void + { + $oDrawing = new Base64(); + $oDrawing->setData($this->imageDataSVG); + $this->assertEquals('image/svg+xml', $oDrawing->getMimeType()); + } + + public function testMimeTypeFunctionNotExists(): void { - DrawingTest::$getimagesizefromstringExists = false; $oDrawing = new Base64(); - $oDrawing->setData($this->imageData); + $oDrawing->setData($this->imageDataPNG); $this->assertEquals('image/jpeg', $oDrawing->getMimeType()); } } diff --git a/tests/PhpPresentation/Tests/Shape/Drawing/DrawingTest.php b/tests/PhpPresentation/Tests/Shape/Drawing/DrawingTest.php deleted file mode 100644 index eb520c00cb..0000000000 --- a/tests/PhpPresentation/Tests/Shape/Drawing/DrawingTest.php +++ /dev/null @@ -1,43 +0,0 @@ -assertEmpty($object->getPath()); } - /** - * @expectedException \Exception - * @expectedExceptionMessage File not found! - */ - public function testPathBasic() + public function testPathBasic(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "" doesn\'t exist'); + $object = new File(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\File', $object->setPath()); + $this->assertInstanceOf(File::class, $object->setPath()); } - public function testPathWithoutVerifyFile() + public function testPathWithoutVerifyFile(): void { $object = new File(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\File', $object->setPath('', false)); + $this->assertInstanceOf(File::class, $object->setPath('', false)); $this->assertEmpty($object->getPath()); } - public function testPathWithRealFile() + public function testPathWithRealFile(): void { $object = new File(); - $imagePath = PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'; + $imagePath = dirname(__DIR__, 4) . '/resources/images/PhpPresentationLogo.png'; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\File', $object->setPath($imagePath, false)); + $this->assertInstanceOf(File::class, $object->setPath($imagePath, false)); $this->assertEquals($imagePath, $object->getPath()); $this->assertEquals(0, $object->getWidth()); $this->assertEquals(0, $object->getHeight()); } + + /** + * @dataProvider dataProviderMimeType + */ + public function testMimeType(string $pathFile, string $mimeType): void + { + $object = new File(); + $this->assertInstanceOf(File::class, $object->setPath($pathFile)); + $this->assertEquals($mimeType, $object->getMimeType()); + } + + /** + * @return array> + */ + public function dataProviderMimeType(): array + { + return [ + [ + dirname(__DIR__, 4) . '/resources/images/PhpPresentationLogo.png', + 'image/png', + ], + [ + dirname(__DIR__, 4) . '/resources/images/tiger.svg', + 'image/svg+xml', + ], + ]; + } } diff --git a/tests/PhpPresentation/Tests/Shape/Drawing/ZipFileTest.php b/tests/PhpPresentation/Tests/Shape/Drawing/ZipFileTest.php index a62bd1dbe4..3a5a7fbb25 100644 --- a/tests/PhpPresentation/Tests/Shape/Drawing/ZipFileTest.php +++ b/tests/PhpPresentation/Tests/Shape/Drawing/ZipFileTest.php @@ -10,71 +10,73 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Drawing; +use PhpOffice\PhpPresentation\Exception\FileNotFoundException; use PhpOffice\PhpPresentation\Shape\Drawing\ZipFile; +use PHPUnit\Framework\TestCase; /** - * Test class for Drawing element + * Test class for Drawing element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Drawing + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Drawing */ -class ZipFileTest extends \PHPUnit_Framework_TestCase +class ZipFileTest extends TestCase { + /** + * @var string + */ protected $fileOk; + + /** + * @var string + */ protected $fileKoZip; + + /** + * @var string + */ protected $fileKoFile; - public function setUp() + protected function setUp(): void { parent::setUp(); - DrawingTest::$getimagesizefromstringExists = true; - - $this->fileOk = 'zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'Sample_01_Simple.pptx#ppt/media/phppowerpoint_logo1.gif'; - $this->fileKoZip = 'zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'fileNotExist.pptx#ppt/media/phppowerpoint_logo1.gif'; - $this->fileKoFile = 'zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'Sample_01_Simple.pptx#ppt/media/filenotexists.gif'; + $this->fileOk = 'zip://' . PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'Sample_01_Simple.pptx#ppt/media/phppowerpoint_logo1.gif'; + $this->fileKoZip = 'zip://' . PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'fileNotExist.pptx#ppt/media/phppowerpoint_logo1.gif'; + $this->fileKoFile = 'zip://' . PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'Sample_01_Simple.pptx#ppt/media/filenotexists.gif'; } - /** - * @expectedException \Exception - * @expectedExceptionMessage fileNotExist.pptx does not exist - */ - public function testContentsException() + public function testContentsException(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage(sprintf( + 'The file "%s" doesn\'t exist', + str_replace(['zip://', '#ppt/media/phppowerpoint_logo1.gif'], '', $this->fileKoZip) + )); + $oDrawing = new ZipFile(); $oDrawing->setPath($this->fileKoZip); $oDrawing->getContents(); } - public function testExtension() + public function testExtension(): void { $oDrawing = new ZipFile(); $oDrawing->setPath($this->fileOk); $this->assertEquals('gif', $oDrawing->getExtension()); } - /** - * @requires PHP 5.4 - */ - public function testMimeType() - { - $oDrawing = new ZipFile(); - $oDrawing->setPath($this->fileOk); - $this->assertEquals('image/gif', $oDrawing->getMimeType()); - } - - /** - * @requires PHP 5.4 - */ - public function testMimeTypeFunctionNotExists() + public function testMimeType(): void { - DrawingTest::$getimagesizefromstringExists = false; $oDrawing = new ZipFile(); $oDrawing->setPath($this->fileOk); $this->assertEquals('image/gif', $oDrawing->getMimeType()); diff --git a/tests/PhpPresentation/Tests/Shape/GroupTest.php b/tests/PhpPresentation/Tests/Shape/GroupTest.php index 959e7ac311..85cb4cd607 100644 --- a/tests/PhpPresentation/Tests/Shape/GroupTest.php +++ b/tests/PhpPresentation/Tests/Shape/GroupTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\Group; use PhpOffice\PhpPresentation\Shape\Line; +use PHPUnit\Framework\TestCase; /** - * Test class for Group element + * Test class for Group element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Group + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Group */ -class GroupTest extends \PHPUnit_Framework_TestCase +class GroupTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Group(); - + $this->assertEquals(0, $object->getOffsetX()); $this->assertEquals(0, $object->getOffsetY()); $this->assertEquals(0, $object->getExtentX()); @@ -39,11 +43,11 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->setWidth(rand(1, 100))); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->setHeight(rand(1, 100))); } - - public function testAdd() + + public function testAdd(): void { $object = new Group(); - + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart', $object->createChartShape()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\File', $object->createDrawingShape()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Line', $object->createLineShape(10, 10, 10, 10)); @@ -51,70 +55,72 @@ public function testAdd() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table', $object->createTableShape()); $this->assertEquals(5, $object->getShapeCollection()->count()); } - - public function testExtentX() + + public function testExtentX(): void { $object = new Group(); - $line1 = new Line(10, 20, 30, 40); + $line1 = new Line(10, 20, 30, 50); $object->addShape($line1); - $this->assertEquals(30, $object->getExtentX()); + $this->assertEquals(20, $object->getExtentX()); } - - public function testExtentY() + + public function testExtentY(): void { $object = new Group(); - $line1 = new Line(10, 20, 30, 40); + $line1 = new Line(10, 20, 30, 50); $object->addShape($line1); - $this->assertEquals(40, $object->getExtentY()); + $this->assertEquals(30, $object->getExtentY()); } - - public function testOffsetX() + + public function testOffsetX(): void { $object = new Group(); - $line1 = new Line(10, 20, 30, 40); + $line1 = new Line(10, 20, 30, 50); $object->addShape($line1); $this->assertEquals(10, $object->getOffsetX()); - + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->setOffsetX(rand(1, 100))); $this->assertEquals(10, $object->getOffsetX()); } - - public function testOffsetY() + + public function testOffsetY(): void { $object = new Group(); - $line1 = new Line(10, 20, 30, 40); + $line1 = new Line(10, 20, 30, 50); $object->addShape($line1); $this->assertEquals(20, $object->getOffsetY()); - + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->setOffsetY(rand(1, 100))); $this->assertEquals(20, $object->getOffsetY()); } - - public function testExtentsAndOffsetsForOneShape() + + public function testExtentsAndOffsetsForOneShape(): void { // We record initial values here because // PhpOffice\PhpPresentation\Shape\Line subtracts the offsets // from the extents to produce a raw width and height. $offsetX = 100; $offsetY = 100; - $extentX = 1000; - $extentY = 450; + $endX = 1000; + $endY = 450; + $extentX = $endX - $offsetX; + $extentY = $endY - $offsetY; $object = new Group(); - $line1 = new Line($offsetX, $offsetY, $extentX, $extentY); + $line1 = new Line($offsetX, $offsetY, $endX, $endY); $object->addShape($line1); - + $this->assertEquals($offsetX, $object->getOffsetX()); $this->assertEquals($offsetY, $object->getOffsetY()); $this->assertEquals($extentX, $object->getExtentX()); $this->assertEquals($extentY, $object->getExtentY()); } - public function testExtentsAndOffsetsForTwoShapes() + public function testExtentsAndOffsetsForTwoShapes(): void { // Since Groups and Slides cache offsets and extents on first // calculation, this test is separate from the above. @@ -122,26 +128,28 @@ public function testExtentsAndOffsetsForTwoShapes() // combined with the above. $offsetX = 100; $offsetY = 100; - $extentX = 1000; - $extentY = 450; + $endX = 1000; + $endY = 450; $increase = 50; + $extentX = ($endX - $offsetX) + $increase; + $extentY = ($endY - $offsetY) + $increase; - $line1 = new Line($offsetX, $offsetY, $extentX, $extentY); + $line1 = new Line($offsetX, $offsetY, $endX, $endY); $line2 = new Line( - $offsetX+$increase, - $offsetY+$increase, - $extentX+$increase, - $extentY+$increase + $offsetX + $increase, + $offsetY + $increase, + $endX + $increase, + $endY + $increase ); $object = new Group(); - + $object->addShape($line1); $object->addShape($line2); - + $this->assertEquals($offsetX, $object->getOffsetX()); $this->assertEquals($offsetY, $object->getOffsetY()); - $this->assertEquals($extentX+$increase, $object->getExtentX()); - $this->assertEquals($extentY+$increase, $object->getExtentY()); + $this->assertEquals($extentX, $object->getExtentX()); + $this->assertEquals($extentY, $object->getExtentY()); } } diff --git a/tests/PhpPresentation/Tests/Shape/HyperlinkTest.php b/tests/PhpPresentation/Tests/Shape/HyperlinkTest.php index 85e2418070..991f728525 100644 --- a/tests/PhpPresentation/Tests/Shape/HyperlinkTest.php +++ b/tests/PhpPresentation/Tests/Shape/HyperlinkTest.php @@ -10,26 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\Hyperlink; +use PHPUnit\Framework\TestCase; /** - * Test class for hyperlink element + * Test class for hyperlink element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Hyperlink + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Hyperlink */ -class HyperlinkTest extends \PHPUnit_Framework_TestCase +class HyperlinkTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { $object = new Hyperlink(); $this->assertEmpty($object->getUrl()); @@ -45,32 +49,32 @@ public function testConstruct() } /** - * Test get hash code + * Test get hash code. */ - public function testGetHashCode() + public function testGetHashCode(): void { $object = new Hyperlink(); $this->assertEquals(md5(get_class($object)), $object->getHashCode()); $object = new Hyperlink('http://test.com'); - $this->assertEquals(md5('http://test.com'.get_class($object)), $object->getHashCode()); + $this->assertEquals(md5('http://test.com' . get_class($object)), $object->getHashCode()); $object = new Hyperlink('http://test.com', 'Test'); - $this->assertEquals(md5('http://test.com'.'Test'.get_class($object)), $object->getHashCode()); + $this->assertEquals(md5('http://test.com' . 'Test' . get_class($object)), $object->getHashCode()); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Hyperlink(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } - public function testGetSetSlideNumber() + public function testGetSetSlideNumber(): void { $object = new Hyperlink(); @@ -78,14 +82,14 @@ public function testGetSetSlideNumber() $this->assertEquals(1, $object->getSlideNumber()); $this->assertEquals('ppaction://hlinksldjump', $object->getUrl()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Hyperlink', $object->setSlideNumber($value)); $this->assertEquals($value, $object->getSlideNumber()); $this->assertEquals('ppaction://hlinksldjump', $object->getUrl()); } - public function testGetSetTooltip() + public function testGetSetTooltip(): void { $object = new Hyperlink(); @@ -96,7 +100,7 @@ public function testGetSetTooltip() $this->assertEquals('TEST', $object->getTooltip()); } - public function testGetSetUrl() + public function testGetSetUrl(): void { $object = new Hyperlink(); @@ -107,7 +111,7 @@ public function testGetSetUrl() $this->assertEquals('http://www.github.com', $object->getUrl()); } - public function testIsInternal() + public function testIsInternal(): void { $object = new Hyperlink(); diff --git a/tests/PhpPresentation/Tests/Shape/LineTest.php b/tests/PhpPresentation/Tests/Shape/LineTest.php index cac59a992c..12ada15315 100644 --- a/tests/PhpPresentation/Tests/Shape/LineTest.php +++ b/tests/PhpPresentation/Tests/Shape/LineTest.php @@ -10,29 +10,33 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\Line; use PhpOffice\PhpPresentation\Style\Border; +use PHPUnit\Framework\TestCase; /** - * Test class for memory drawing element + * Test class for memory drawing element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Line + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Line */ -class LineTest extends \PHPUnit_Framework_TestCase +class LineTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { - $value = rand(1, 100); + $value = mt_rand(1, 100); $object = new Line($value, $value, $value, $value); $this->assertEquals(Border::LINE_SINGLE, $object->getBorder()->getLineStyle()); @@ -40,6 +44,6 @@ public function testConstruct() $this->assertEquals($value, $object->getOffsetY()); $this->assertEquals(0, $object->getWidth()); $this->assertEquals(0, $object->getHeight()); - $this->assertInternalType('string', $object->getHashCode()); + $this->assertIsString($object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/MediaTest.php b/tests/PhpPresentation/Tests/Shape/MediaTest.php index ef634299e4..14508464c6 100644 --- a/tests/PhpPresentation/Tests/Shape/MediaTest.php +++ b/tests/PhpPresentation/Tests/Shape/MediaTest.php @@ -1,19 +1,38 @@ assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Drawing\\File', $object); } - public function testMimeType() + public function testMimeType(): void { $object = new Media(); $object->setPath('file.mp4', false); diff --git a/tests/PhpPresentation/Tests/Shape/PlaceholderTest.php b/tests/PhpPresentation/Tests/Shape/PlaceholderTest.php index 864dddba60..eb741d24f3 100644 --- a/tests/PhpPresentation/Tests/Shape/PlaceholderTest.php +++ b/tests/PhpPresentation/Tests/Shape/PlaceholderTest.php @@ -10,32 +10,36 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; use PhpOffice\PhpPresentation\Shape\Placeholder; +use PHPUnit\Framework\TestCase; /** - * Test class for Table element + * Test class for Table element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Table + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Table */ -class PlaceholderTest extends \PHPUnit_Framework_TestCase +class PlaceholderTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Placeholder(Placeholder::PH_TYPE_BODY); $this->assertEquals(Placeholder::PH_TYPE_BODY, $object->getType()); $this->assertNull($object->getIdx()); } - public function testIdx() + public function testIdx(): void { - $value = rand(0, 100); + $value = mt_rand(0, 100); $object = new Placeholder(Placeholder::PH_TYPE_BODY); $this->assertNull($object->getIdx()); @@ -43,7 +47,7 @@ public function testIdx() $this->assertEquals($value, $object->getIdx()); } - public function testType() + public function testType(): void { $rcPlaceholder = new \ReflectionClass('PhpOffice\PhpPresentation\Shape\Placeholder'); $arrayConstants = $rcPlaceholder->getConstants(); diff --git a/tests/PhpPresentation/Tests/Shape/RichText/BreakElementTest.php b/tests/PhpPresentation/Tests/Shape/RichText/BreakElementTest.php index 6a03b335a3..512af22a9d 100644 --- a/tests/PhpPresentation/Tests/Shape/RichText/BreakElementTest.php +++ b/tests/PhpPresentation/Tests/Shape/RichText/BreakElementTest.php @@ -10,26 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\BreakElement; +use PHPUnit\Framework\TestCase; /** - * Test class for BreakElement element + * Test class for BreakElement element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\RichText\BreakElement + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\RichText\BreakElement */ -class BreakElementTest extends \PHPUnit_Framework_TestCase +class BreakElementTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testText() + public function testText(): void { $object = new BreakElement(); $this->assertEquals("\r\n", $object->getText()); @@ -39,24 +43,24 @@ public function testText() $this->assertEquals("\r\n", $object->getText()); } - public function testFont() + public function testFont(): void { $object = new BreakElement(); $this->assertNull($object->getFont()); } - public function testLanguage() + public function testLanguage(): void { $object = new BreakElement(); $this->assertNull($object->getLanguage()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $object->setLanguage('en-US')); $this->assertNull($object->getLanguage()); } - + /** - * Test get/set hash index + * Test get/set hash index. */ - public function testHashCode() + public function testHashCode(): void { $object = new BreakElement(); $this->assertEquals(md5(get_class($object)), $object->getHashCode()); diff --git a/tests/PhpPresentation/Tests/Shape/RichText/ParagraphTest.php b/tests/PhpPresentation/Tests/Shape/RichText/ParagraphTest.php index 4ab5ca6cf3..be34b6f1cf 100644 --- a/tests/PhpPresentation/Tests/Shape/RichText/ParagraphTest.php +++ b/tests/PhpPresentation/Tests/Shape/RichText/ParagraphTest.php @@ -10,11 +10,14 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; @@ -22,142 +25,164 @@ use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for Paragraph element + * Test class for Paragraph element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\RichText\Paragraph + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\RichText\Paragraph */ -class ParagraphTest extends \PHPUnit_Framework_TestCase +class ParagraphTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { $object = new Paragraph(); $this->assertEmpty($object->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->getAlignment()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->getBulletStyle()); + $this->assertInstanceOf(Alignment::class, $object->getAlignment()); + $this->assertInstanceOf(Font::class, $object->getFont()); + $this->assertInstanceOf(Bullet::class, $object->getBulletStyle()); } - public function testAlignment() + public function testAlignment(): void { $object = new Paragraph(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->getAlignment()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setAlignment(new Alignment())); + $this->assertInstanceOf(Alignment::class, $object->getAlignment()); + $this->assertInstanceOf(Paragraph::class, $object->setAlignment(new Alignment())); } /** - * Test get/set bullet style + * Test get/set bullet style. */ - public function testBulletStyle() + public function testBulletStyle(): void { $object = new Paragraph(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->getBulletStyle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setBulletStyle()); + $this->assertInstanceOf(Bullet::class, $object->getBulletStyle()); + $this->assertInstanceOf(Paragraph::class, $object->setBulletStyle()); $this->assertNull($object->getBulletStyle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setBulletStyle(new Bullet())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->getBulletStyle()); + $this->assertInstanceOf(Paragraph::class, $object->setBulletStyle(new Bullet())); + $this->assertInstanceOf(Bullet::class, $object->getBulletStyle()); } /** - * Test get/set font + * Test get/set font. */ - public function testFont() + public function testFont(): void { $object = new Paragraph(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setFont()); + $this->assertInstanceOf(Font::class, $object->getFont()); + $this->assertInstanceOf(Paragraph::class, $object->setFont()); $this->assertNull($object->getFont()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setFont(new Font())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); + $this->assertInstanceOf(Paragraph::class, $object->setFont(new Font())); + $this->assertInstanceOf(Font::class, $object->getFont()); } /** - * Test get/set hashCode + * Test get/set hashCode. */ - public function testHashCode() + public function testHashCode(): void { $object = new Paragraph(); $oElement = new TextElement(); $object->addText($oElement); - $this->assertEquals(md5($oElement->getHashCode().$object->getFont()->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($oElement->getHashCode() . $object->getFont()->getHashCode() . get_class($object)), $object->getHashCode()); } /** - * Test get/set hashIndex + * Test get/set hashIndex. */ - public function testHashIndex() + public function testHashIndex(): void { $object = new Paragraph(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } /** - * Test get/set linespacing + * Test get/set linespacing. */ - public function testLineSpacing() + public function testLineSpacing(): void { $object = new Paragraph(); - $valueExpected = rand(1, 100); + $valueExpected = mt_rand(1, 100); $this->assertEquals(100, $object->getLineSpacing()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setLineSpacing($valueExpected)); + $this->assertInstanceOf(Paragraph::class, $object->setLineSpacing($valueExpected)); $this->assertEquals($valueExpected, $object->getLineSpacing()); } /** - * Test get/set richTextElements + * Test text methods. + */ + public function testLineSpacingMode(): void + { + $object = new Paragraph(); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $object->getLineSpacingMode()); + $this->assertInstanceOf(Paragraph::class, $object->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT)); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_POINT, $object->getLineSpacingMode()); + $this->assertInstanceOf(Paragraph::class, $object->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_PERCENT)); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $object->getLineSpacingMode()); + $this->assertInstanceOf(Paragraph::class, $object->setLineSpacingMode('Unauthorized')); + $this->assertEquals(Paragraph::LINE_SPACING_MODE_PERCENT, $object->getLineSpacingMode()); + } + + /** + * Test get/set richTextElements. */ - public function testRichTextElements() + public function testRichTextElements(): void { $object = new Paragraph(); - $this->assertInternalType('array', $object->getRichTextElements()); + $this->assertIsArray($object->getRichTextElements()); $this->assertEmpty($object->getRichTextElements()); $object->createBreak(); $this->assertCount(1, $object->getRichTextElements()); - $array = array( + $array = [ new TextElement(), new TextElement(), new TextElement(), - ); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setRichTextElements($array)); + ]; + $this->assertInstanceOf(Paragraph::class, $object->setRichTextElements($array)); $this->assertCount(3, $object->getRichTextElements()); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface[] array passed. - */ - public function testRichTextElementsException() + public function testSpacingAfter(): void + { + $object = new Paragraph(); + $this->assertEquals(0, $object->getSpacingAfter()); + $this->assertInstanceOf(Paragraph::class, $object->setSpacingAfter(1)); + $this->assertEquals(1, $object->getSpacingAfter()); + } + + public function testSpacingBefore(): void { $object = new Paragraph(); - $object->setRichTextElements(1); + $this->assertEquals(0, $object->getSpacingBefore()); + $this->assertInstanceOf(Paragraph::class, $object->setSpacingBefore(1)); + $this->assertEquals(1, $object->getSpacingBefore()); } /** - * Test text methods + * Test text methods. */ - public function testText() + public function testText(): void { $object = new Paragraph(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->addText(new TextElement())); - $this->assertcount(1, $object->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\TextElement', $object->createText()); - $this->assertcount(2, $object->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\TextElement', $object->createText('AAA')); - $this->assertcount(3, $object->getRichTextElements()); + $this->assertInstanceOf(Paragraph::class, $object->addText(new TextElement())); + $this->assertCount(1, $object->getRichTextElements()); + $this->assertInstanceOf(TextElement::class, $object->createText()); + $this->assertCount(2, $object->getRichTextElements()); + $this->assertInstanceOf(TextElement::class, $object->createText('AAA')); + $this->assertCount(3, $object->getRichTextElements()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $object->createBreak()); - $this->assertcount(4, $object->getRichTextElements()); + $this->assertCount(4, $object->getRichTextElements()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $object->createTextRun()); - $this->assertcount(5, $object->getRichTextElements()); + $this->assertCount(5, $object->getRichTextElements()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $object->createTextRun('BBB')); - $this->assertcount(6, $object->getRichTextElements()); - $this->assertEquals('AAA'."\r\n".'BBB', $object->getPlainText()); - $this->assertEquals('AAA'."\r\n".'BBB', (string) $object); + $this->assertCount(6, $object->getRichTextElements()); + $this->assertEquals('AAA' . "\r\n" . 'BBB', $object->getPlainText()); + $this->assertEquals('AAA' . "\r\n" . 'BBB', (string) $object); } } diff --git a/tests/PhpPresentation/Tests/Shape/RichText/RunTest.php b/tests/PhpPresentation/Tests/Shape/RichText/RunTest.php index 8dda48d656..0deb0b3336 100644 --- a/tests/PhpPresentation/Tests/Shape/RichText/RunTest.php +++ b/tests/PhpPresentation/Tests/Shape/RichText/RunTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\Run; use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for Run element + * Test class for Run element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\RichText\Run + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\RichText\Run */ -class RunTest extends \PHPUnit_Framework_TestCase +class RunTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { $object = new Run(); $this->assertEquals('', $object->getText()); @@ -41,14 +45,14 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); } - public function testFont() + public function testFont(): void { $object = new Run(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $object->setFont(new Font())); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->getFont()); } - public function testLanguage() + public function testLanguage(): void { $object = new Run(); $this->assertNull($object->getLanguage()); @@ -56,7 +60,7 @@ public function testLanguage() $this->assertEquals('en-US', $object->getLanguage()); } - public function testText() + public function testText(): void { $object = new Run(); $this->assertEquals('', $object->getText()); @@ -70,11 +74,11 @@ public function testText() } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testHashCode() + public function testHashCode(): void { $object = new Run(); - $this->assertEquals(md5($object->getFont()->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($object->getFont()->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Shape/RichText/TextElementTest.php b/tests/PhpPresentation/Tests/Shape/RichText/TextElementTest.php index 4a9034cf80..f63de69d45 100644 --- a/tests/PhpPresentation/Tests/Shape/RichText/TextElementTest.php +++ b/tests/PhpPresentation/Tests/Shape/RichText/TextElementTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\RichText; use PhpOffice\PhpPresentation\Shape\Hyperlink; use PhpOffice\PhpPresentation\Shape\RichText\TextElement; +use PHPUnit\Framework\TestCase; /** - * Test class for TextElement element + * Test class for TextElement element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\RichText\TextElement + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\RichText\TextElement */ -class TextElementTest extends \PHPUnit_Framework_TestCase +class TextElementTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { $object = new TextElement(); $this->assertEquals('', $object->getText()); @@ -39,13 +43,13 @@ public function testConstruct() $this->assertEquals('AAA', $object->getText()); } - public function testFont() + public function testFont(): void { $object = new TextElement(); $this->assertNull($object->getFont()); } - public function testHyperlink() + public function testHyperlink(): void { $object = new TextElement(); $this->assertFalse($object->hasHyperlink()); @@ -58,7 +62,7 @@ public function testHyperlink() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Hyperlink', $object->getHyperlink()); } - public function testLanguage() + public function testLanguage(): void { $object = new TextElement(); $this->assertNull($object->getLanguage()); @@ -66,7 +70,7 @@ public function testLanguage() $this->assertEquals('en-US', $object->getLanguage()); } - public function testText() + public function testText(): void { $object = new TextElement(); $this->assertEquals('', $object->getText()); @@ -77,9 +81,9 @@ public function testText() } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testHashCode() + public function testHashCode(): void { $object = new TextElement(); $this->assertEquals(md5(get_class($object)), $object->getHashCode()); diff --git a/tests/PhpPresentation/Tests/Shape/RichTextTest.php b/tests/PhpPresentation/Tests/Shape/RichTextTest.php index 07cac16fc6..7019fc292a 100644 --- a/tests/PhpPresentation/Tests/Shape/RichTextTest.php +++ b/tests/PhpPresentation/Tests/Shape/RichTextTest.php @@ -10,268 +10,275 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\RichText; -use PhpOffice\PhpPresentation\Shape\RichText\TextElement; +use PhpOffice\PhpPresentation\Shape\RichText\BreakElement; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; +use PhpOffice\PhpPresentation\Shape\RichText\Run; +use PhpOffice\PhpPresentation\Shape\RichText\TextElement; +use PHPUnit\Framework\TestCase; /** - * Test class for RichText element + * Test class for RichText element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\RichText + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\RichText */ -class RichTextTest extends \PHPUnit_Framework_TestCase +class RichTextTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new RichText(); $this->assertEquals(0, $object->getActiveParagraphIndex()); $this->assertCount(1, $object->getParagraphs()); } - public function testActiveParagraph() + public function testActiveParagraph(): void { $object = new RichText(); $this->assertEquals(0, $object->getActiveParagraphIndex()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->createParagraph()); + $this->assertInstanceOf(Paragraph::class, $object->createParagraph()); $this->assertCount(2, $object->getParagraphs()); - $value = rand(0, 1); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setActiveParagraph($value)); + $value = mt_rand(0, 1); + $this->assertInstanceOf(Paragraph::class, $object->setActiveParagraph($value)); $this->assertEquals($value, $object->getActiveParagraphIndex()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->getActiveParagraph()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->getParagraph()); - $value = rand(0, 1); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->getParagraph($value)); + $this->assertInstanceOf(Paragraph::class, $object->getActiveParagraph()); + $this->assertInstanceOf(Paragraph::class, $object->getParagraph()); + $value = mt_rand(0, 1); + $this->assertInstanceOf(Paragraph::class, $object->getParagraph($value)); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid paragraph count. - */ - public function testActiveParagraphException() + public function testActiveParagraphException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1000) is out of bounds (0, 1)'); + $object = new RichText(); $object->setActiveParagraph(1000); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid paragraph count. - */ - public function testGetParagraphException() + public function testGetParagraphException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1000) is out of bounds (0, 1)'); + $object = new RichText(); $object->getParagraph(1000); } - public function testColumns() + public function testColumns(): void { $object = new RichText(); - $value = rand(1, 16); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setColumns($value)); + $value = mt_rand(1, 16); + $this->assertInstanceOf(RichText::class, $object->setColumns($value)); $this->assertEquals($value, $object->getColumns()); } - /** - * @expectedException \Exception - * expectedExceptionMessage Number of columns should be 1-16 - */ - public function testColumnsException() + public function testColumnSpacing(): void { + $object = new RichText(); + + $this->assertEquals(0, $object->getColumnSpacing()); + $value = mt_rand(1, 16); + $this->assertInstanceOf(RichText::class, $object->setColumnSpacing($value)); + $this->assertEquals($value, $object->getColumnSpacing()); + $this->assertInstanceOf(RichText::class, $object->setColumnSpacing(-1)); + $this->assertEquals($value, $object->getColumnSpacing()); + } + + public function testColumnsException(): void + { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1000) is out of bounds (1, 16)'); + $object = new RichText(); $object->setColumns(1000); } - public function testParagraphs() + public function testParagraphs(): void { $object = new RichText(); - $array = array( + $array = [ new Paragraph(), new Paragraph(), new Paragraph(), - ); + ]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setParagraphs($array)); + $this->assertInstanceOf(RichText::class, $object->setParagraphs($array)); $this->assertCount(3, $object->getParagraphs()); $this->assertEquals(2, $object->getActiveParagraphIndex()); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] array passed. - */ - public function testParagraphsException() - { - $object = new RichText(); - $object->setParagraphs(1000); - } - - public function testText() + public function testText(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->addText()); + $this->assertInstanceOf(RichText::class, $object->addText()); $this->assertCount(1, $object->getActiveParagraph()->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->addText(new TextElement())); + $this->assertInstanceOf(RichText::class, $object->addText(new TextElement())); $this->assertCount(2, $object->getActiveParagraph()->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\TextElement', $object->createText()); + $this->assertInstanceOf(TextElement::class, $object->createText()); $this->assertCount(3, $object->getActiveParagraph()->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\TextElement', $object->createText('ALPHA')); + $this->assertInstanceOf(TextElement::class, $object->createText('ALPHA')); $this->assertCount(4, $object->getActiveParagraph()->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\BreakElement', $object->createBreak()); + $this->assertInstanceOf(BreakElement::class, $object->createBreak()); $this->assertCount(5, $object->getActiveParagraph()->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $object->createTextRun()); + $this->assertInstanceOf(Run::class, $object->createTextRun()); $this->assertCount(6, $object->getActiveParagraph()->getRichTextElements()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $object->createTextRun('BETA')); + $this->assertInstanceOf(Run::class, $object->createTextRun('BETA')); $this->assertCount(7, $object->getActiveParagraph()->getRichTextElements()); - $this->assertEquals('ALPHA'."\r\n".'BETA', $object->getPlainText()); - $this->assertEquals('ALPHA'."\r\n".'BETA', (string) $object); + $this->assertEquals('ALPHA' . "\r\n" . 'BETA', $object->getPlainText()); + $this->assertEquals('ALPHA' . "\r\n" . 'BETA', (string) $object); } - public function testGetSetAutoFit() + public function testGetSetAutoFit(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoFit()); + $this->assertInstanceOf(RichText::class, $object->setAutoFit()); $this->assertEquals(RichText::AUTOFIT_DEFAULT, $object->getAutoFit()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoFit(RichText::AUTOFIT_NORMAL)); + $this->assertInstanceOf(RichText::class, $object->setAutoFit(RichText::AUTOFIT_NORMAL)); $this->assertEquals(RichText::AUTOFIT_NORMAL, $object->getAutoFit()); } - public function testGetSetHAutoShrink() + public function testGetSetHAutoShrink(): void { $object = new RichText(); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkHorizontal()); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkHorizontal()); $this->assertNull($object->hasAutoShrinkHorizontal()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkHorizontal(2)); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkHorizontal(null)); $this->assertNull($object->hasAutoShrinkHorizontal()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkHorizontal(true)); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkHorizontal(true)); $this->assertTrue($object->hasAutoShrinkHorizontal()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkHorizontal(false)); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkHorizontal(false)); $this->assertFalse($object->hasAutoShrinkHorizontal()); } - public function testGetSetVAutoShrink() + + public function testGetSetVAutoShrink(): void { $object = new RichText(); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkVertical()); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkVertical()); $this->assertNull($object->hasAutoShrinkVertical()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkVertical(2)); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkVertical(null)); $this->assertNull($object->hasAutoShrinkVertical()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkVertical(true)); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkVertical(true)); $this->assertTrue($object->hasAutoShrinkVertical()); - - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setAutoShrinkVertical(false)); + + $this->assertInstanceOf(RichText::class, $object->setAutoShrinkVertical(false)); $this->assertFalse($object->hasAutoShrinkVertical()); } - - public function testGetSetHOverflow() + + public function testGetSetHOverflow(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setHorizontalOverflow()); + $this->assertInstanceOf(RichText::class, $object->setHorizontalOverflow()); $this->assertEquals(RichText::OVERFLOW_OVERFLOW, $object->getHorizontalOverflow()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setHorizontalOverflow(RichText::OVERFLOW_CLIP)); + $this->assertInstanceOf(RichText::class, $object->setHorizontalOverflow(RichText::OVERFLOW_CLIP)); $this->assertEquals(RichText::OVERFLOW_CLIP, $object->getHorizontalOverflow()); } - public function testGetSetInset() + public function testGetSetInset(): void { $object = new RichText(); // Default - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetBottom()); + $this->assertInstanceOf(RichText::class, $object->setInsetBottom()); $this->assertEquals(4.8, $object->getInsetBottom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetLeft()); + $this->assertInstanceOf(RichText::class, $object->setInsetLeft()); $this->assertEquals(9.6, $object->getInsetLeft()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetRight()); + $this->assertInstanceOf(RichText::class, $object->setInsetRight()); $this->assertEquals(9.6, $object->getInsetRight()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetTop()); + $this->assertInstanceOf(RichText::class, $object->setInsetTop()); $this->assertEquals(4.8, $object->getInsetTop()); // Value - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetBottom($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(RichText::class, $object->setInsetBottom($value)); $this->assertEquals($value, $object->getInsetBottom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetLeft($value)); + $this->assertInstanceOf(RichText::class, $object->setInsetLeft($value)); $this->assertEquals($value, $object->getInsetLeft()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetRight($value)); + $this->assertInstanceOf(RichText::class, $object->setInsetRight($value)); $this->assertEquals($value, $object->getInsetRight()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setInsetTop($value)); + $this->assertInstanceOf(RichText::class, $object->setInsetTop($value)); $this->assertEquals($value, $object->getInsetTop()); } - public function testGetSetUpright() + public function testGetSetUpright(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setUpright()); + $this->assertInstanceOf(RichText::class, $object->setUpright()); $this->assertFalse($object->isUpright()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setUpright(true)); + $this->assertInstanceOf(RichText::class, $object->setUpright(true)); $this->assertTrue($object->isUpright()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setUpright(false)); + $this->assertInstanceOf(RichText::class, $object->setUpright(false)); $this->assertFalse($object->isUpright()); } - public function testGetSetVertical() + public function testGetSetVertical(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setVertical()); + $this->assertInstanceOf(RichText::class, $object->setVertical()); $this->assertFalse($object->isVertical()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setVertical(true)); + $this->assertInstanceOf(RichText::class, $object->setVertical(true)); $this->assertTrue($object->isVertical()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setVertical(false)); + $this->assertInstanceOf(RichText::class, $object->setVertical(false)); $this->assertFalse($object->isVertical()); } - public function testGetSetVOverflow() + public function testGetSetVOverflow(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setVerticalOverflow()); + $this->assertInstanceOf(RichText::class, $object->setVerticalOverflow()); $this->assertEquals(RichText::OVERFLOW_OVERFLOW, $object->getVerticalOverflow()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setVerticalOverflow(RichText::OVERFLOW_CLIP)); + $this->assertInstanceOf(RichText::class, $object->setVerticalOverflow(RichText::OVERFLOW_CLIP)); $this->assertEquals(RichText::OVERFLOW_CLIP, $object->getVerticalOverflow()); } - public function testGetSetWrap() + public function testGetSetWrap(): void { $object = new RichText(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setWrap()); + $this->assertInstanceOf(RichText::class, $object->setWrap()); $this->assertEquals(RichText::WRAP_SQUARE, $object->getWrap()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->setWrap(RichText::WRAP_NONE)); + $this->assertInstanceOf(RichText::class, $object->setWrap(RichText::WRAP_NONE)); $this->assertEquals(RichText::WRAP_NONE, $object->getWrap()); } - public function testHashCode() + public function testHashCode(): void { $object = new RichText(); - $hash = $object->getActiveParagraph()->getHashCode(); - $hash .= RichText::WRAP_SQUARE.RichText::AUTOFIT_DEFAULT.RichText::OVERFLOW_OVERFLOW.RichText::OVERFLOW_OVERFLOW.'0014.89.69.64.8'; + $hash = $object->getActiveParagraph()->getHashCode(); + $hash .= RichText::WRAP_SQUARE . RichText::AUTOFIT_DEFAULT . RichText::OVERFLOW_OVERFLOW . RichText::OVERFLOW_OVERFLOW . '00104.89.69.64.8'; $hash .= md5('00000' . $object->getFill()->getHashCode() . $object->getShadow()->getHashCode() . '' . get_parent_class($object)); $hash .= get_class($object); $this->assertEquals(md5($hash), $object->getHashCode()); diff --git a/tests/PhpPresentation/Tests/Shape/Table/CellTest.php b/tests/PhpPresentation/Tests/Shape/Table/CellTest.php index 94d6b24205..7f0ccc502a 100644 --- a/tests/PhpPresentation/Tests/Shape/Table/CellTest.php +++ b/tests/PhpPresentation/Tests/Shape/Table/CellTest.php @@ -10,30 +10,35 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Table; -use PhpOffice\PhpPresentation\Shape\Table\Cell; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Shape\RichText\TextElement; +use PhpOffice\PhpPresentation\Shape\Table\Cell; use PhpOffice\PhpPresentation\Style\Borders; use PhpOffice\PhpPresentation\Style\Fill; +use PHPUnit\Framework\TestCase; /** - * Test class for Cell element + * Test class for Cell element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Cell + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Cell */ -class CellTest extends \PHPUnit_Framework_TestCase +class CellTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { $object = new Cell(); $this->assertEquals(0, $object->getActiveParagraphIndex()); @@ -42,58 +47,56 @@ public function testConstruct() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Borders', $object->getBorders()); } - public function testActiveParagraph() + public function testActiveParagraph(): void { $object = new Cell(); $this->assertEquals(0, $object->getActiveParagraphIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->createParagraph()); $this->assertCount(2, $object->getParagraphs()); - $value = rand(0, 1); + $value = mt_rand(0, 1); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->setActiveParagraph($value)); $this->assertEquals($value, $object->getActiveParagraphIndex()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->getActiveParagraph()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->getParagraph()); - $value = rand(0, 1); + $value = mt_rand(0, 1); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->getParagraph($value)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setParagraphs(array())); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setParagraphs([])); $this->assertCount(0, $object->getParagraphs()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Paragraph', $object->createParagraph()); $this->assertCount(1, $object->getParagraphs()); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid paragraph count. - */ - public function testActiveParagraphException() + public function testActiveParagraphException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1000) is out of bounds (0, 1)'); + $object = new Cell(); $object->setActiveParagraph(1000); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid paragraph count. - */ - public function testGetParagraphException() + public function testGetParagraphException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1000) is out of bounds (0, 1)'); + $object = new Cell(); $object->getParagraph(1000); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Cell(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } - public function testText() + public function testText(): void { $object = new Cell(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->addText()); @@ -110,36 +113,26 @@ public function testText() $this->assertCount(6, $object->getActiveParagraph()->getRichTextElements()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText\\Run', $object->createTextRun('BETA')); $this->assertCount(7, $object->getActiveParagraph()->getRichTextElements()); - $this->assertEquals('ALPHA'."\r\n".'BETA', $object->getPlainText()); - $this->assertEquals('ALPHA'."\r\n".'BETA', (string) $object); + $this->assertEquals('ALPHA' . "\r\n" . 'BETA', $object->getPlainText()); + $this->assertEquals('ALPHA' . "\r\n" . 'BETA', (string) $object); } - public function testParagraphs() + public function testParagraphs(): void { $object = new Cell(); - $array = array( + $array = [ new Paragraph(), new Paragraph(), new Paragraph(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setParagraphs($array)); $this->assertCount(3, $object->getParagraphs()); $this->assertEquals(2, $object->getActiveParagraphIndex()); } - /** - * @expectedException \Exception - * expectedExceptionMessage Invalid \PhpOffice\PhpPresentation\Shape\RichText\Paragraph[] array passed. - */ - public function testParagraphsException() - { - $object = new Cell(); - $object->setParagraphs(1000); - } - - public function testGetSetBorders() + public function testGetSetBorders(): void { $object = new Cell(); @@ -147,19 +140,19 @@ public function testGetSetBorders() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Borders', $object->getBorders()); } - public function testGetSetColspan() + public function testGetSetColspan(): void { $object = new Cell(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setColSpan()); $this->assertEquals(0, $object->getColSpan()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setColSpan($value)); $this->assertEquals($value, $object->getColSpan()); } - public function testGetSetFill() + public function testGetSetFill(): void { $object = new Cell(); @@ -167,26 +160,26 @@ public function testGetSetFill() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); } - public function testGetSetRowspan() + public function testGetSetRowspan(): void { $object = new Cell(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setRowSpan()); $this->assertEquals(0, $object->getRowSpan()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setRowSpan($value)); $this->assertEquals($value, $object->getRowSpan()); } - public function testGetSetWidth() + public function testGetSetWidth(): void { $object = new Cell(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setWidth()); $this->assertEquals(0, $object->getWidth()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->setWidth($value)); $this->assertEquals($value, $object->getWidth()); } diff --git a/tests/PhpPresentation/Tests/Shape/Table/RowTest.php b/tests/PhpPresentation/Tests/Shape/Table/RowTest.php index 8df703e235..2e8ed0595e 100644 --- a/tests/PhpPresentation/Tests/Shape/Table/RowTest.php +++ b/tests/PhpPresentation/Tests/Shape/Table/RowTest.php @@ -10,101 +10,104 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape\Table; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; +use PhpOffice\PhpPresentation\Shape\Table\Cell; use PhpOffice\PhpPresentation\Shape\Table\Row; use PhpOffice\PhpPresentation\Style\Fill; +use PHPUnit\Framework\TestCase; /** - * Test class for Row element + * Test class for Row element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Row + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Row */ -class RowTest extends \PHPUnit_Framework_TestCase +class RowTest extends TestCase { /** - * Test can read + * Test can read. */ - public function testConstruct() + public function testConstruct(): void { $object = new Row(); $this->assertCount(1, $object->getCells()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertInstanceOf(Fill::class, $object->getFill()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object = new Row($value); $this->assertCount($value, $object->getCells()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertInstanceOf(Fill::class, $object->getFill()); } - public function testGetCell() + public function testGetCell(): void { $object = new Row(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->getCell(0)); - $this->assertNull($object->getCell(1000, true)); + $this->assertInstanceOf(Cell::class, $object->getCell(0)); } - /** - * @expectedException \Exception - * expectedExceptionMessage Cell number out of bounds. - */ - public function testGetCellException() + public function testGetCellException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1) is out of bounds (0, 0)'); + $object = new Row(); $object->getCell(1); } - public function testNextCell() + public function testNextCell(): void { $object = new Row(2); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Cell', $object->nextCell()); + $this->assertInstanceOf(Cell::class, $object->nextCell()); } - /** - * @expectedException \Exception - * expectedExceptionMessage Cell count out of bounds. - */ - public function testNextCellException() + public function testNextCellException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1) is out of bounds (0, 0)'); + $object = new Row(); $object->nextCell(); $object->nextCell(); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Row(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } - public function testGetSetFill() + public function testGetSetFill(): void { $object = new Row(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Row', $object->setFill(new Fill())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertInstanceOf(Fill::class, $object->getFill()); } - public function testGetSetHeight() + public function testGetSetHeight(): void { $object = new Row(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Row', $object->setHeight()); $this->assertEquals(0, $object->getHeight()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Row', $object->setHeight($value)); $this->assertEquals($value, $object->getHeight()); } diff --git a/tests/PhpPresentation/Tests/Shape/TableTest.php b/tests/PhpPresentation/Tests/Shape/TableTest.php index b3bab6e34f..286b151e9c 100644 --- a/tests/PhpPresentation/Tests/Shape/TableTest.php +++ b/tests/PhpPresentation/Tests/Shape/TableTest.php @@ -10,66 +10,70 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Shape; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\Table; +use PhpOffice\PhpPresentation\Shape\Table\Row; +use PHPUnit\Framework\TestCase; /** - * Test class for Table element + * Test class for Table element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\Table + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\Table */ -class TableTest extends \PHPUnit_Framework_TestCase +class TableTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Table(); $this->assertEmpty($object->getRows()); $this->assertFalse($object->isResizeProportional()); } - public function testNumColums() + public function testNumColums(): void { - $value = rand(1, 100); + $value = mt_rand(1, 100); $object = new Table(); $this->assertEquals(1, $object->getNumColumns()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table', $object->setNumColumns($value)); + $this->assertInstanceOf(Table::class, $object->setNumColumns($value)); $this->assertEquals($value, $object->getNumColumns()); } - public function testRows() + public function testRows(): void { $object = new Table(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Row', $object->createRow()); + $this->assertInstanceOf(Row::class, $object->createRow()); $this->assertCount(1, $object->getRows()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table\\Row', $object->getRow(0)); - $this->assertNull($object->getRow(1, true)); + $this->assertInstanceOf(Row::class, $object->getRow(0)); } - /** - * @expectedException \Exception - * expectedExceptionMessage Row number out of bounds. - */ - public function testGetRowException() + public function testGetRowException(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (1) is out of bounds (0, 0)'); + $object = new Table(); - $object->getRow(); + $object->getRow(1); } - public function testHashCode() + public function testHashCode(): void { $object = new Table(); $this->assertEquals(md5(get_class($object)), $object->getHashCode()); $row = $object->createRow(); - $this->assertEquals(md5($row->getHashCode().get_class($object)), $object->getHashCode()); + $this->assertEquals(md5($row->getHashCode() . get_class($object)), $object->getHashCode()); } } diff --git a/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php b/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php index e84939eb32..16fd597785 100644 --- a/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php +++ b/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php @@ -10,40 +10,44 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Slide; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Slide\AbstractSlide; +use PHPUnit\Framework\TestCase; /** - * Test class for Table element + * Test class for Table element. * - * @coversDefaultClass PhpOffice\PhpPresentation\Shape\AbstractGraphic + * @coversDefaultClass \PhpOffice\PhpPresentation\Shape\AbstractGraphic */ -class AbstractSlideTest extends \PHPUnit_Framework_TestCase +class AbstractSlideTest extends TestCase { - public function testCollection() + public function testCollection(): void { /** @var AbstractSlide $stub */ $stub = $this->getMockForAbstractClass('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide'); - $array = array(); + $array = []; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $stub->setShapeCollection($array)); - $this->assertInternalType('array', $stub->getShapeCollection()); + $this->assertIsArray($stub->getShapeCollection()); $this->assertCount(count($array), $stub->getShapeCollection()); - $array = array( + $array = [ new RichText(), new RichText(), new RichText(), - ); + ]; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $stub->setShapeCollection($array)); - $this->assertInternalType('array', $stub->getShapeCollection()); + $this->assertIsArray($stub->getShapeCollection()); $this->assertCount(count($array), $stub->getShapeCollection()); } } diff --git a/tests/PhpPresentation/Tests/Slide/AnimationTest.php b/tests/PhpPresentation/Tests/Slide/AnimationTest.php index 0a1a065e37..84d48cee0a 100644 --- a/tests/PhpPresentation/Tests/Slide/AnimationTest.php +++ b/tests/PhpPresentation/Tests/Slide/AnimationTest.php @@ -10,38 +10,44 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; +use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\Slide\Animation; +use PHPUnit\Framework\TestCase; /** - * Test class for Animation + * Test class for Animation. * - * @coversDefaultClass PhpOffice\PhpPresentation\Slide\Animation + * @coversDefaultClass \PhpOffice\PhpPresentation\Slide\Animation */ -class AnimationTest extends \PHPUnit_Framework_TestCase +class AnimationTest extends TestCase { - public function testShape() + public function testShape(): void { - $oStub = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\AbstractShape'); + /** @var AbstractShape $oStub */ + $oStub = $this->getMockForAbstractClass(AbstractShape::class); $object = new Animation(); - $this->assertInternalType('array', $object->getShapeCollection()); + $this->assertIsArray($object->getShapeCollection()); $this->assertCount(0, $object->getShapeCollection()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Animation', $object->addShape($oStub)); - $this->assertInternalType('array', $object->getShapeCollection()); + $this->assertIsArray($object->getShapeCollection()); $this->assertCount(1, $object->getShapeCollection()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Animation', $object->setShapeCollection()); - $this->assertInternalType('array', $object->getShapeCollection()); + $this->assertIsArray($object->getShapeCollection()); $this->assertCount(0, $object->getShapeCollection()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Animation', $object->setShapeCollection(array($oStub))); - $this->assertInternalType('array', $object->getShapeCollection()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Animation', $object->setShapeCollection([$oStub])); + $this->assertIsArray($object->getShapeCollection()); $this->assertCount(1, $object->getShapeCollection()); } } diff --git a/tests/PhpPresentation/Tests/Slide/Background/ColorTest.php b/tests/PhpPresentation/Tests/Slide/Background/ColorTest.php index 7221cf81ad..02946f7a86 100644 --- a/tests/PhpPresentation/Tests/Slide/Background/ColorTest.php +++ b/tests/PhpPresentation/Tests/Slide/Background/ColorTest.php @@ -1,13 +1,32 @@ assertNull($object->getPath()); $this->assertEmpty($object->getFilename()); @@ -24,19 +44,18 @@ public function testColor() $this->assertEquals('png', $object->getExtension()); $this->assertEquals('background_' . $numSlide . '.png', $object->getIndexedFilename($numSlide)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Background\\Image', $object->setPath(null, false)); - $this->assertNull($object->getPath()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Background\\Image', $object->setPath('', false)); + $this->assertEquals('', $object->getPath()); $this->assertEmpty($object->getFilename()); $this->assertEmpty($object->getExtension()); $this->assertEquals('background_' . $numSlide . '.', $object->getIndexedFilename($numSlide)); } - /** - * @expectedException \Exception - * @expectedExceptionMessage File not found : - */ - public function testPathException() + public function testPathException(): void { + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('The file "pathDoesntExist" doesn\'t exist'); + $object = new Image(); $object->setPath('pathDoesntExist', true); } diff --git a/tests/PhpPresentation/Tests/Slide/Background/SchemeColorTest.php b/tests/PhpPresentation/Tests/Slide/Background/SchemeColorTest.php index 680e773a6f..cdf5142ff1 100644 --- a/tests/PhpPresentation/Tests/Slide/Background/SchemeColorTest.php +++ b/tests/PhpPresentation/Tests/Slide/Background/SchemeColorTest.php @@ -1,13 +1,32 @@ addSlide(new Slide()); @@ -39,13 +41,13 @@ public function testMethod() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->current()); $this->assertEquals(0, $object->key()); - $this->assertNull($object->next()); + $object->next(); $this->assertEquals(1, $object->key()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->current()); $this->assertTrue($object->valid()); - $this->assertNull($object->next()); + $object->next(); $this->assertFalse($object->valid()); - $this->assertNull($object->rewind()); + $object->rewind(); $this->assertEquals(0, $object->key()); } } diff --git a/tests/PhpPresentation/Tests/Slide/NoteTest.php b/tests/PhpPresentation/Tests/Slide/NoteTest.php index b57499fa26..7b40555fb8 100644 --- a/tests/PhpPresentation/Tests/Slide/NoteTest.php +++ b/tests/PhpPresentation/Tests/Slide/NoteTest.php @@ -10,36 +10,40 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Slide\Note; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class NoteTest extends \PHPUnit_Framework_TestCase +class NoteTest extends TestCase { - public function testParent() + public function testParent(): void { $object = new Note(); $this->assertNull($object->getParent()); - + $oPhpPresentation = new PhpPresentation(); $oSlide = $oPhpPresentation->createSlide(); $oSlide->setNote($object); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->getParent()); } - - public function testExtent() + + public function testExtent(): void { $object = new Note(); $this->assertNotNull($object->getExtentX()); @@ -47,14 +51,14 @@ public function testExtent() $object = new Note(); $this->assertNotNull($object->getExtentY()); } - - public function testHashCode() + + public function testHashCode(): void { $object = new Note(); - $this->assertInternalType('string', $object->getHashCode()); + $this->assertIsString($object->getHashCode()); } - - public function testOffset() + + public function testOffset(): void { $object = new Note(); $this->assertNotNull($object->getOffsetX()); @@ -62,26 +66,26 @@ public function testOffset() $object = new Note(); $this->assertNotNull($object->getOffsetY()); } - - public function testShape() + + public function testShape(): void { $object = new Note(); $this->assertEquals(0, $object->getShapeCollection()->count()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->createRichTextShape()); $this->assertEquals(1, $object->getShapeCollection()->count()); - + $oRichText = new RichText(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->addShape($oRichText)); $this->assertEquals(2, $object->getShapeCollection()->count()); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Note(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertNull($object->getHashIndex()); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); diff --git a/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php b/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php index aa01d46ff3..2fc7f7df00 100644 --- a/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php +++ b/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php @@ -10,54 +10,60 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\Slide\SlideLayout; +use PhpOffice\PhpPresentation\Slide\SlideMaster; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\Slide\SlideLayout + * @coversDefaultClass \PhpOffice\PhpPresentation\Slide\SlideLayout */ -class SlideLayoutTest extends \PHPUnit_Framework_TestCase +class SlideLayoutTest extends TestCase { - public function testBase() + public function testBase(): void { - $mockSlideMaster = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Slide\SlideMaster'); + /** @var SlideMaster $mockSlideMaster */ + $mockSlideMaster = $this->getMockForAbstractClass(SlideMaster::class); $object = new SlideLayout($mockSlideMaster); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $object); $this->assertInstanceOf('\\ArrayObject', $object->getShapeCollection()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->colorMap); } - - public function testLayoutName() + + public function testLayoutName(): void { - // Mocks - $mockSlideMaster = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Slide\SlideMaster'); + /** @var SlideMaster $mockSlideMaster */ + $mockSlideMaster = $this->getMockForAbstractClass(SlideMaster::class); // Expected - $expectedLayoutName = 'Title'.rand(1, 100); + $expectedLayoutName = 'Title' . rand(1, 100); $object = new SlideLayout($mockSlideMaster); $this->assertNull($object->getLayoutName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\SlideLayout', $object->setLayoutName($expectedLayoutName)); + $this->assertInstanceOf(SlideLayout::class, $object->setLayoutName($expectedLayoutName)); $this->assertEquals($expectedLayoutName, $object->getLayoutName()); } - public function testSlideMaster() + public function testSlideMaster(): void { - // Mocks - $mockSlideMaster = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Slide\SlideMaster'); + /** @var SlideMaster $mockSlideMaster */ + $mockSlideMaster = $this->getMockForAbstractClass(SlideMaster::class); $object = new SlideLayout($mockSlideMaster); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\SlideMaster', $object->getSlideMaster()); + $this->assertInstanceOf(SlideMaster::class, $object->getSlideMaster()); } } diff --git a/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php b/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php index ae44d2afa6..4bda4aa516 100644 --- a/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php +++ b/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php @@ -10,60 +10,73 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; +use PhpOffice\PhpPresentation\Slide\Background\Color; +use PhpOffice\PhpPresentation\Slide\SlideLayout; use PhpOffice\PhpPresentation\Slide\SlideMaster; +use PhpOffice\PhpPresentation\Style\SchemeColor; +use PhpOffice\PhpPresentation\Style\TextStyle; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\Slide\SlideMaster + * @coversDefaultClass \PhpOffice\PhpPresentation\Slide\SlideMaster */ -class SlideMasterTest extends \PHPUnit_Framework_TestCase +class SlideMasterTest extends TestCase { - public function testBase() + public function testBase(): void { $object = new SlideMaster(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $object); $this->assertNull($object->getParent()); $this->assertInstanceOf('\\ArrayObject', $object->getShapeCollection()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->colorMap); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Background\\Color', $object->getBackground()); - $this->assertEquals('FFFFFF', $object->getBackground()->getColor()->getRGB()); + /** @var Color $background */ + $background = $object->getBackground(); + $this->assertInstanceOf(Color::class, $background); + $this->assertEquals('FFFFFF', $background->getColor()->getRGB()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->getTextStyles()); } - public function testLayout() + public function testLayout(): void { $object = new SlideMaster(); // Mock Post - $mockSlideLayout = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Slide\SlideLayout', array($object)); + /** @var SlideLayout $mockSlideLayout */ + $mockSlideLayout = $this->getMockForAbstractClass(SlideLayout::class, [$object]); $this->assertEmpty($object->getAllSlideLayouts()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\SlideLayout', $object->createSlideLayout()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\SlideLayout', $object->addSlideLayout($mockSlideLayout)); + $this->assertInstanceOf(SlideLayout::class, $object->createSlideLayout()); + $this->assertInstanceOf(SlideLayout::class, $object->addSlideLayout($mockSlideLayout)); $this->assertCount(2, $object->getAllSlideLayouts()); } - public function testSchemeColors() + public function testSchemeColors(): void { // Mock Pre - $mockSchemeColorAccent1 = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Style\SchemeColor'); + /** @var SchemeColor $mockSchemeColorAccent1 */ + $mockSchemeColorAccent1 = $this->getMockForAbstractClass(SchemeColor::class); $mockSchemeColorAccent1->setValue('accent1'); $mockSchemeColorAccent1->setRGB('ABCDEF'); - $mockSchemeColorNew = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Style\SchemeColor'); + /** @var SchemeColor $mockSchemeColorNew */ + $mockSchemeColorNew = $this->getMockForAbstractClass(SchemeColor::class); $mockSchemeColorNew->setValue('new'); $mockSchemeColorNew->setRGB('ABCDEF'); $object = new SlideMaster(); - $this->assertInternalType('array', $object->getAllSchemeColors()); + $this->assertIsArray($object->getAllSchemeColors()); $this->assertCount(12, $object->getAllSchemeColors()); // Add idem value $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\SlideMaster', $object->addSchemeColor($mockSchemeColorAccent1)); @@ -73,10 +86,11 @@ public function testSchemeColors() $this->assertCount(13, $object->getAllSchemeColors()); } - public function testTextStyles() + public function testTextStyles(): void { // Mock Pre - $mockTextStyle = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Style\TextStyle'); + /** @var TextStyle $mockTextStyle */ + $mockTextStyle = $this->getMockForAbstractClass(TextStyle::class); $object = new SlideMaster(); diff --git a/tests/PhpPresentation/Tests/Slide/TransitionTest.php b/tests/PhpPresentation/Tests/Slide/TransitionTest.php index 31dace8b2f..5afda6050a 100644 --- a/tests/PhpPresentation/Tests/Slide/TransitionTest.php +++ b/tests/PhpPresentation/Tests/Slide/TransitionTest.php @@ -10,23 +10,27 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; use PhpOffice\PhpPresentation\Slide\Transition; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\Slide\Transition + * @coversDefaultClass \PhpOffice\PhpPresentation\Slide\Transition */ -class TransitionTest extends \PHPUnit_Framework_TestCase +class TransitionTest extends TestCase { - public function testSpeed() + public function testSpeed(): void { $object = new Transition(); $this->assertNull($object->getSpeed()); @@ -34,11 +38,11 @@ public function testSpeed() $this->assertEquals(Transition::SPEED_MEDIUM, $object->getSpeed()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setSpeed(Transition::SPEED_FAST)); $this->assertEquals(Transition::SPEED_FAST, $object->getSpeed()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setSpeed(rand(1, 1000))); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setSpeed('notagoodvalue')); $this->assertNull($object->getSpeed()); } - public function testManualTrigger() + public function testManualTrigger(): void { $object = new Transition(); $this->assertFalse($object->hasManualTrigger()); @@ -46,15 +50,11 @@ public function testManualTrigger() $this->assertFalse($object->hasManualTrigger()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setManualTrigger(true)); $this->assertTrue($object->hasManualTrigger()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setManualTrigger(null)); - $this->assertTrue($object->hasManualTrigger()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setManualTrigger(false)); $this->assertFalse($object->hasManualTrigger()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setManualTrigger(null)); - $this->assertFalse($object->hasManualTrigger()); } - public function testTimeTrigger() + public function testTimeTrigger(): void { $object = new Transition(); $this->assertFalse($object->hasTimeTrigger()); @@ -62,25 +62,17 @@ public function testTimeTrigger() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setTimeTrigger()); $this->assertFalse($object->hasTimeTrigger()); $this->assertNull($object->getAdvanceTimeTrigger()); - $value = rand(1, 1000); + $value = mt_rand(1, 1000); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setTimeTrigger(true, $value)); $this->assertTrue($object->hasTimeTrigger()); $this->assertEquals($value, $object->getAdvanceTimeTrigger()); - $value = rand(1, 1000); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setTimeTrigger(null, $value)); - $this->assertTrue($object->hasTimeTrigger()); - $this->assertEquals($value, $object->getAdvanceTimeTrigger()); - $value = rand(1, 1000); + $value = mt_rand(1, 1000); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setTimeTrigger(false, $value)); $this->assertFalse($object->hasTimeTrigger()); $this->assertNull($object->getAdvanceTimeTrigger()); - $value = rand(1, 1000); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->setTimeTrigger(null, $value)); - $this->assertFalse($object->hasTimeTrigger()); - $this->assertNull($object->getAdvanceTimeTrigger()); } - public function testTransitionType() + public function testTransitionType(): void { $object = new Transition(); $this->assertNull($object->getTransitionType()); diff --git a/tests/PhpPresentation/Tests/SlideTest.php b/tests/PhpPresentation/Tests/SlideTest.php index 3d967e7409..eea3f731d9 100644 --- a/tests/PhpPresentation/Tests/SlideTest.php +++ b/tests/PhpPresentation/Tests/SlideTest.php @@ -10,130 +10,137 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests; +use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\Slide; +use PhpOffice\PhpPresentation\Slide\AbstractBackground; +use PhpOffice\PhpPresentation\Slide\Animation; use PhpOffice\PhpPresentation\Slide\Transition; -use PhpOffice\PhpPresentation\PhpPresentation; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class SlideTest extends \PHPUnit_Framework_TestCase +class SlideTest extends TestCase { - public function testExtents() + public function testExtents(): void { $object = new Slide(); $this->assertNotNull($object->getExtentX()); - + $object = new Slide(); $this->assertNotNull($object->getExtentY()); } - - public function testOffset() + + public function testOffset(): void { $object = new Slide(); $this->assertNotNull($object->getOffsetX()); - + $object = new Slide(); $this->assertNotNull($object->getOffsetY()); } - - public function testParent() + + public function testParent(): void { $object = new Slide(); $this->assertNull($object->getParent()); - + $oPhpPresentation = new PhpPresentation(); $object = new Slide($oPhpPresentation); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $object->getParent()); + $this->assertInstanceOf(PhpPresentation::class, $object->getParent()); } - - public function testSlideMasterId() + + public function testSlideMasterId(): void { - $value = rand(1, 100); - + $value = mt_rand(1, 100); $object = new Slide(); $this->assertEquals(1, $object->getSlideMasterId()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setSlideMasterId()); + $this->assertInstanceOf(Slide::class, $object->setSlideMasterId()); $this->assertEquals(1, $object->getSlideMasterId()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setSlideMasterId($value)); + $this->assertInstanceOf(Slide::class, $object->setSlideMasterId($value)); $this->assertEquals($value, $object->getSlideMasterId()); } - public function testAnimations() + public function testAnimations(): void { - $oStub = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Slide\Animation'); + /** @var Animation $oStub */ + $oStub = $this->getMockForAbstractClass(Animation::class); $object = new Slide(); - $this->assertInternalType('array', $object->getAnimations()); + $this->assertIsArray($object->getAnimations()); $this->assertCount(0, $object->getAnimations()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->addAnimation($oStub)); - $this->assertInternalType('array', $object->getAnimations()); + $this->assertInstanceOf(Slide::class, $object->addAnimation($oStub)); + $this->assertIsArray($object->getAnimations()); $this->assertCount(1, $object->getAnimations()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setAnimations()); - $this->assertInternalType('array', $object->getAnimations()); + $this->assertInstanceOf(Slide::class, $object->setAnimations()); + $this->assertIsArray($object->getAnimations()); $this->assertCount(0, $object->getAnimations()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setAnimations(array($oStub))); - $this->assertInternalType('array', $object->getAnimations()); + $this->assertInstanceOf(Slide::class, $object->setAnimations([$oStub])); + $this->assertIsArray($object->getAnimations()); $this->assertCount(1, $object->getAnimations()); } - public function testBackground() + public function testBackground(): void { - $oStub = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Slide\AbstractBackground'); + /** @var AbstractBackground $oStub */ + $oStub = $this->getMockForAbstractClass(AbstractBackground::class); $object = new Slide(); $this->assertNull($object->getBackground()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setBackground($oStub)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractBackground', $object->getBackground()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setBackground()); + $this->assertInstanceOf(Slide::class, $object->setBackground($oStub)); + $this->assertInstanceOf(AbstractBackground::class, $object->getBackground()); + $this->assertInstanceOf(Slide::class, $object->setBackground()); $this->assertNull($object->getBackground()); } - public function testGroup() + public function testGroup(): void { $object = new Slide(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->createGroup()); } - public function testName() + public function testName(): void { $object = new Slide(); $this->assertNull($object->getName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setName('AAAA')); + $this->assertInstanceOf(Slide::class, $object->setName('AAAA')); $this->assertEquals('AAAA', $object->getName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setName()); + $this->assertInstanceOf(Slide::class, $object->setName()); $this->assertNull($object->getName()); } - public function testTransition() + public function testTransition(): void { $object = new Slide(); $oTransition = new Transition(); $this->assertNull($object->getTransition()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setTransition()); + $this->assertInstanceOf(Slide::class, $object->setTransition()); $this->assertNull($object->getTransition()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setTransition($oTransition)); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\Transition', $object->getTransition()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setTransition(null)); + $this->assertInstanceOf(Slide::class, $object->setTransition($oTransition)); + $this->assertInstanceOf(Transition::class, $object->getTransition()); + $this->assertInstanceOf(Slide::class, $object->setTransition(null)); $this->assertNull($object->getTransition()); } - public function testVisible() + public function testVisible(): void { $object = new Slide(); $this->assertTrue($object->isVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setIsVisible(false)); + $this->assertInstanceOf(Slide::class, $object->setIsVisible(false)); $this->assertFalse($object->isVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Slide', $object->setIsVisible()); + $this->assertInstanceOf(Slide::class, $object->setIsVisible()); $this->assertTrue($object->isVisible()); } } diff --git a/tests/PhpPresentation/Tests/Style/AlignmentTest.php b/tests/PhpPresentation/Tests/Style/AlignmentTest.php index 7a0d05fe1e..510811fb48 100644 --- a/tests/PhpPresentation/Tests/Style/AlignmentTest.php +++ b/tests/PhpPresentation/Tests/Style/AlignmentTest.php @@ -10,26 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; +use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Style\Alignment; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class AlignmentTest extends \PHPUnit_Framework_TestCase +class AlignmentTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Alignment(); $this->assertEquals(Alignment::HORIZONTAL_LEFT, $object->getHorizontal()); @@ -44,168 +49,182 @@ public function testConstruct() } /** - * Test get/set horizontal + * Test get/set horizontal. */ - public function testSetGetHorizontal() + public function testSetGetHorizontal(): void { $object = new Alignment(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setHorizontal('')); + $this->assertInstanceOf(Alignment::class, $object->setHorizontal('')); $this->assertEquals(Alignment::HORIZONTAL_LEFT, $object->getHorizontal()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setHorizontal(Alignment::HORIZONTAL_GENERAL)); + $this->assertInstanceOf(Alignment::class, $object->setHorizontal(Alignment::HORIZONTAL_GENERAL)); $this->assertEquals(Alignment::HORIZONTAL_GENERAL, $object->getHorizontal()); } /** - * Test get/set vertical + * Test get/set vertical. */ - public function testTextDirection() + public function testTextDirection(): void { $object = new Alignment(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setTextDirection(null)); + $this->assertInstanceOf(Alignment::class, $object->setTextDirection('')); $this->assertEquals(Alignment::TEXT_DIRECTION_HORIZONTAL, $object->getTextDirection()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setTextDirection(Alignment::TEXT_DIRECTION_VERTICAL_90)); + $this->assertInstanceOf(Alignment::class, $object->setTextDirection(Alignment::TEXT_DIRECTION_VERTICAL_90)); $this->assertEquals(Alignment::TEXT_DIRECTION_VERTICAL_90, $object->getTextDirection()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setTextDirection()); + $this->assertInstanceOf(Alignment::class, $object->setTextDirection()); $this->assertEquals(Alignment::TEXT_DIRECTION_HORIZONTAL, $object->getTextDirection()); } /** - * Test get/set vertical + * Test get/set vertical. */ - public function testSetGetVertical() + public function testSetGetVertical(): void { $object = new Alignment(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setVertical('')); + $this->assertInstanceOf(Alignment::class, $object->setVertical('')); $this->assertEquals(Alignment::VERTICAL_BASE, $object->getVertical()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setVertical(Alignment::VERTICAL_AUTO)); + $this->assertInstanceOf(Alignment::class, $object->setVertical(Alignment::VERTICAL_AUTO)); $this->assertEquals(Alignment::VERTICAL_AUTO, $object->getVertical()); } /** - * Test get/set min level exception + * Test get/set min level exception. */ - public function testSetGetLevelExceptionMin() + public function testSetGetLevelExceptionMin(): void { + $this->expectException(OutOfBoundsException::class); + $this->expectExceptionMessage('The expected value (-1) is out of bounds (0, Infinite)'); + $object = new Alignment(); - $this->setExpectedException('\Exception', 'Invalid value should be more than 0.'); $object->setLevel(-1); } /** - * Test get/set level + * Test get/set level. */ - public function testSetGetLevel() + public function testSetGetLevel(): void { $object = new Alignment(); - $value = rand(1, 8); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setLevel($value)); + $value = mt_rand(1, 8); + $this->assertInstanceOf(Alignment::class, $object->setLevel($value)); $this->assertEquals($value, $object->getLevel()); } /** - * Test get/set indent + * Test get/set indent. */ - public function testSetGetIndent() + public function testSetGetIndent(): void { $object = new Alignment(); // != Alignment::HORIZONTAL_GENERAL $object->setHorizontal(Alignment::HORIZONTAL_CENTER); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setIndent($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setIndent($value)); $this->assertEquals(0, $object->getIndent()); - $value = rand(-100, 0); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setIndent($value)); + $value = mt_rand(-100, 0); + $this->assertInstanceOf(Alignment::class, $object->setIndent($value)); $this->assertEquals($value, $object->getIndent()); $object->setHorizontal(Alignment::HORIZONTAL_GENERAL); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setIndent($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setIndent($value)); $this->assertEquals($value, $object->getIndent()); - $value = rand(-100, 0); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setIndent($value)); + $value = mt_rand(-100, 0); + $this->assertInstanceOf(Alignment::class, $object->setIndent($value)); $this->assertEquals($value, $object->getIndent()); } /** - * Test get/set margin bottom + * Test get/set margin bottom. */ - public function testSetGetMarginBottom() + public function testSetGetMarginBottom(): void { $object = new Alignment(); - $value = rand(0, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginBottom($value)); + $value = mt_rand(0, 100); + $this->assertInstanceOf(Alignment::class, $object->setMarginBottom($value)); $this->assertEquals($value, $object->getMarginBottom()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginBottom()); + $this->assertInstanceOf(Alignment::class, $object->setMarginBottom()); $this->assertEquals(0, $object->getMarginBottom()); } /** - * Test get/set margin left + * Test get/set margin left. */ - public function testSetGetMarginLeft() + public function testSetGetMarginLeft(): void { $object = new Alignment(); // != Alignment::HORIZONTAL_GENERAL $object->setHorizontal(Alignment::HORIZONTAL_CENTER); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginLeft($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setMarginLeft($value)); $this->assertEquals(0, $object->getMarginLeft()); - $value = rand(-100, 0); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginLeft($value)); + $value = mt_rand(-100, 0); + $this->assertInstanceOf(Alignment::class, $object->setMarginLeft($value)); $this->assertEquals($value, $object->getMarginLeft()); $object->setHorizontal(Alignment::HORIZONTAL_GENERAL); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginLeft($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setMarginLeft($value)); $this->assertEquals($value, $object->getMarginLeft()); - $value = rand(-100, 0); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginLeft($value)); + $value = mt_rand(-100, 0); + $this->assertInstanceOf(Alignment::class, $object->setMarginLeft($value)); $this->assertEquals($value, $object->getMarginLeft()); } /** - * Test get/set margin right + * Test get/set margin right. */ - public function testSetGetMarginRight() + public function testSetGetMarginRight(): void { $object = new Alignment(); // != Alignment::HORIZONTAL_GENERAL $object->setHorizontal(Alignment::HORIZONTAL_CENTER); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginRight($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setMarginRight($value)); $this->assertEquals(0, $object->getMarginRight()); - $value = rand(-100, 0); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginRight($value)); + $value = mt_rand(-100, 0); + $this->assertInstanceOf(Alignment::class, $object->setMarginRight($value)); $this->assertEquals($value, $object->getMarginRight()); $object->setHorizontal(Alignment::HORIZONTAL_GENERAL); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginRight($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setMarginRight($value)); $this->assertEquals($value, $object->getMarginRight()); - $value = rand(-100, 0); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginRight($value)); + $value = mt_rand(-100, 0); + $this->assertInstanceOf(Alignment::class, $object->setMarginRight($value)); $this->assertEquals($value, $object->getMarginRight()); } /** - * Test get/set margin top + * Test get/set margin top. */ - public function testSetGetMarginTop() + public function testSetGetMarginTop(): void { $object = new Alignment(); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginTop($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Alignment::class, $object->setMarginTop($value)); $this->assertEquals($value, $object->getMarginTop()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Alignment', $object->setMarginTop()); + $this->assertInstanceOf(Alignment::class, $object->setMarginTop()); $this->assertEquals(0, $object->getMarginTop()); } + public function testRTL(): void + { + $object = new Alignment(); + $this->assertFalse($object->isRTL()); + $this->assertInstanceOf(Alignment::class, $object->setIsRTL(true)); + $this->assertTrue($object->isRTL()); + $this->assertInstanceOf(Alignment::class, $object->setIsRTL(false)); + $this->assertFalse($object->isRTL()); + $this->assertInstanceOf(Alignment::class, $object->setIsRTL()); + $this->assertFalse($object->isRTL()); + } + /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { - $value = md5(rand(1, 100)); + $value = rand(1, 100); $object = new Alignment(); $object->setHashIndex($value); diff --git a/tests/PhpPresentation/Tests/Style/BorderTest.php b/tests/PhpPresentation/Tests/Style/BorderTest.php index fb851dcd8e..6084fa10c7 100644 --- a/tests/PhpPresentation/Tests/Style/BorderTest.php +++ b/tests/PhpPresentation/Tests/Style/BorderTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Color; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class BorderTest extends \PHPUnit_Framework_TestCase +class BorderTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Border(); $this->assertEquals(1, $object->getLineWidth()); @@ -41,9 +45,9 @@ public function testConstruct() } /** - * Test get/set color + * Test get/set color. */ - public function testSetGetColor() + public function testSetGetColor(): void { $object = new Border(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setColor()); @@ -54,9 +58,9 @@ public function testSetGetColor() } /** - * Test get/set dash style + * Test get/set dash style. */ - public function testSetGetDashStyle() + public function testSetGetDashStyle(): void { $object = new Border(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setDashStyle()); @@ -68,20 +72,20 @@ public function testSetGetDashStyle() } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Border(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } /** - * Test get/set line style + * Test get/set line style. */ - public function testSetGetLineStyle() + public function testSetGetLineStyle(): void { $object = new Border(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setLineStyle()); @@ -93,14 +97,14 @@ public function testSetGetLineStyle() } /** - * Test get/set line width + * Test get/set line width. */ - public function testSetGetLineWidth() + public function testSetGetLineWidth(): void { $object = new Border(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setLineWidth()); $this->assertEquals(1, $object->getLineWidth()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setLineWidth($value)); $this->assertEquals($value, $object->getLineWidth()); } diff --git a/tests/PhpPresentation/Tests/Style/BordersTest.php b/tests/PhpPresentation/Tests/Style/BordersTest.php index 2b4152c1a3..72e9ce8bf4 100644 --- a/tests/PhpPresentation/Tests/Style/BordersTest.php +++ b/tests/PhpPresentation/Tests/Style/BordersTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Borders; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class BordersTest extends \PHPUnit_Framework_TestCase +class BordersTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Borders(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->getBottom()); @@ -44,20 +48,20 @@ public function testConstruct() } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Borders(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } /** - * Test get/set hash code + * Test get/set hash code. */ - public function testGetHashCode() + public function testGetHashCode(): void { $object = new Borders(); $this->assertEquals( diff --git a/tests/PhpPresentation/Tests/Style/BulletTest.php b/tests/PhpPresentation/Tests/Style/BulletTest.php index 468c232730..8d8b965630 100644 --- a/tests/PhpPresentation/Tests/Style/BulletTest.php +++ b/tests/PhpPresentation/Tests/Style/BulletTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Color; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class BulletTest extends \PHPUnit_Framework_TestCase +class BulletTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Bullet(); $this->assertEquals(Bullet::TYPE_NONE, $object->getBulletType()); @@ -41,9 +45,9 @@ public function testConstruct() } /** - * Test get/set bullet char + * Test get/set bullet char. */ - public function testSetGetBulletChar() + public function testSetGetBulletChar(): void { $object = new Bullet(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletChar()); @@ -53,9 +57,9 @@ public function testSetGetBulletChar() } /** - * Test get/set bullet color + * Test get/set bullet color. */ - public function testSetGetBulletColor() + public function testSetGetBulletColor(): void { $object = new Bullet(); @@ -65,16 +69,15 @@ public function testSetGetBulletColor() $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getBulletColor()); $this->assertEquals(Color::COLOR_BLACK, $object->getBulletColor()->getARGB()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletColor(new Color($expectedARGB))); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getBulletColor()); $this->assertEquals($expectedARGB, $object->getBulletColor()->getARGB()); } /** - * Test get/set bullet font + * Test get/set bullet font. */ - public function testSetGetBulletFont() + public function testSetGetBulletFont(): void { $object = new Bullet(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletFont()); @@ -86,22 +89,22 @@ public function testSetGetBulletFont() } /** - * Test get/set bullet numeric start at + * Test get/set bullet numeric start at. */ - public function testSetGetBulletNumericStartAt() + public function testSetGetBulletNumericStartAt(): void { $object = new Bullet(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletNumericStartAt()); $this->assertEquals(1, $object->getBulletNumericStartAt()); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletNumericStartAt($value)); $this->assertEquals($value, $object->getBulletNumericStartAt()); } /** - * Test get/set bullet numeric style + * Test get/set bullet numeric style. */ - public function testSetGetBulletNumericStyle() + public function testSetGetBulletNumericStyle(): void { $object = new Bullet(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletNumericStyle()); @@ -111,9 +114,9 @@ public function testSetGetBulletNumericStyle() } /** - * Test get/set bullet type + * Test get/set bullet type. */ - public function testSetGetBulletType() + public function testSetGetBulletType(): void { $object = new Bullet(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Bullet', $object->setBulletType()); @@ -123,12 +126,12 @@ public function testSetGetBulletType() } /** - * Test get/set has index + * Test get/set has index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Bullet(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } diff --git a/tests/PhpPresentation/Tests/Style/ColorMapTest.php b/tests/PhpPresentation/Tests/Style/ColorMapTest.php index 8a17bb59a6..126c80ac11 100644 --- a/tests/PhpPresentation/Tests/Style/ColorMapTest.php +++ b/tests/PhpPresentation/Tests/Style/ColorMapTest.php @@ -10,37 +10,41 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\ColorMap; +use PHPUnit\Framework\TestCase; -class ColorMapTest extends \PHPUnit_Framework_TestCase +class ColorMapTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new ColorMap(); - $this->assertInternalType('array', $object->getMapping()); + $this->assertIsArray($object->getMapping()); $this->assertEquals(ColorMap::$mappingDefault, $object->getMapping()); } - public function testMapping() + public function testMapping(): void { $object = new ColorMap(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->setMapping(array())); - $this->assertInternalType('array', $object->getMapping()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->setMapping([])); + $this->assertIsArray($object->getMapping()); $this->assertCount(0, $object->getMapping()); $array = ColorMap::$mappingDefault; $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->setMapping($array)); - $this->assertInternalType('array', $object->getMapping()); + $this->assertIsArray($object->getMapping()); $this->assertEquals(ColorMap::$mappingDefault, $object->getMapping()); } - public function testModifier() + public function testModifier(): void { $object = new ColorMap(); $key = array_rand(ColorMap::$mappingDefault); diff --git a/tests/PhpPresentation/Tests/Style/ColorTest.php b/tests/PhpPresentation/Tests/Style/ColorTest.php index 672b0e27b2..afdfcd26ac 100644 --- a/tests/PhpPresentation/Tests/Style/ColorTest.php +++ b/tests/PhpPresentation/Tests/Style/ColorTest.php @@ -10,26 +10,30 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Color; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class ColorTest extends \PHPUnit_Framework_TestCase +class ColorTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Color(); $this->assertEquals(Color::COLOR_BLACK, $object->getARGB()); @@ -38,23 +42,26 @@ public function testConstruct() } /** - * Test Alpha + * Test Alpha. */ - public function testAlpha() + public function testAlpha(): void { + $randAlpha = mt_rand(0, 100); $object = new Color(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setARGB()); $this->assertEquals(100, $object->getAlpha()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setARGB('AA0000FF')); + $this->assertEquals(67, $object->getAlpha()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setARGB(Color::COLOR_BLUE)); $this->assertEquals(100, $object->getAlpha()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setARGB('AA0000FF')); - $this->assertEquals(66.67, $object->getAlpha()); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setAlpha($randAlpha)); + $this->assertEquals($randAlpha, round($object->getAlpha())); } /** - * Test get/set ARGB + * Test get/set ARGB. */ - public function testSetGetARGB() + public function testSetGetARGB(): void { $object = new Color(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setARGB()); @@ -66,9 +73,9 @@ public function testSetGetARGB() } /** - * Test get/set RGB + * Test get/set RGB. */ - public function testSetGetRGB() + public function testSetGetRGB(): void { $object = new Color(); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->setRGB()); @@ -86,12 +93,12 @@ public function testSetGetRGB() } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Color(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } diff --git a/tests/PhpPresentation/Tests/Style/FillTest.php b/tests/PhpPresentation/Tests/Style/FillTest.php index bf2976aecd..2ac5eb183d 100644 --- a/tests/PhpPresentation/Tests/Style/FillTest.php +++ b/tests/PhpPresentation/Tests/Style/FillTest.php @@ -10,95 +10,95 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Fill; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class FillTest extends \PHPUnit_Framework_TestCase +class FillTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Fill(); $this->assertEquals(Fill::FILL_NONE, $object->getFillType()); $this->assertEquals(0, $object->getRotation()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getStartColor()); - $this->assertEquals(Color::COLOR_WHITE, $object->getStartColor()->getARGB()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getEndColor()); - $this->assertEquals(Color::COLOR_BLACK, $object->getEndColor()->getARGB()); + $this->assertInstanceOf(Color::class, $object->getStartColor()); + $this->assertEquals(Color::COLOR_WHITE, $object->getEndColor()->getARGB()); + $this->assertInstanceOf(Color::class, $object->getEndColor()); + $this->assertEquals(Color::COLOR_BLACK, $object->getStartColor()->getARGB()); } /** - * Test get/set end color + * Test get/set end color. */ - public function testSetGetEndColor() + public function testSetGetEndColor(): void { $object = new Fill(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setEndColor()); - $this->assertNull($object->getEndColor()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setEndColor(new Color(COLOR::COLOR_BLUE))); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getEndColor()); + $this->assertInstanceOf(Fill::class, $object->setEndColor(new Color(COLOR::COLOR_BLUE))); + $this->assertInstanceOf(Color::class, $object->getEndColor()); $this->assertEquals(COLOR::COLOR_BLUE, $object->getEndColor()->getARGB()); } /** - * Test get/set fill type + * Test get/set fill type. */ - public function testSetGetFillType() + public function testSetGetFillType(): void { $object = new Fill(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setFillType()); + $this->assertInstanceOf(Fill::class, $object->setFillType()); $this->assertEquals(Fill::FILL_NONE, $object->getFillType()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setFillType(Fill::FILL_GRADIENT_LINEAR)); + $this->assertInstanceOf(Fill::class, $object->setFillType(Fill::FILL_GRADIENT_LINEAR)); $this->assertEquals(Fill::FILL_GRADIENT_LINEAR, $object->getFillType()); } /** - * Test get/set rotation + * Test get/set rotation. */ - public function testSetGetRotation() + public function testSetGetRotation(): void { $object = new Fill(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setRotation()); + $this->assertInstanceOf(Fill::class, $object->setRotation()); $this->assertEquals(0, $object->getRotation()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setRotation($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Fill::class, $object->setRotation($value)); $this->assertEquals($value, $object->getRotation()); } /** - * Test get/set start color + * Test get/set start color. */ - public function testSetGetStartColor() + public function testSetGetStartColor(): void { $object = new Fill(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setStartColor()); - $this->assertNull($object->getStartColor()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->setStartColor(new Color(COLOR::COLOR_BLUE))); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getStartColor()); + $this->assertInstanceOf(Fill::class, $object->setStartColor(new Color(COLOR::COLOR_BLUE))); + $this->assertInstanceOf(Color::class, $object->getStartColor()); $this->assertEquals(COLOR::COLOR_BLUE, $object->getStartColor()->getARGB()); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Fill(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } diff --git a/tests/PhpPresentation/Tests/Style/FontTest.php b/tests/PhpPresentation/Tests/Style/FontTest.php index 6f1b1e6a7d..47deb3f0ba 100644 --- a/tests/PhpPresentation/Tests/Style/FontTest.php +++ b/tests/PhpPresentation/Tests/Style/FontTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Font; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class FontTest extends \PHPUnit_Framework_TestCase +class FontTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Font(); $this->assertEquals('Calibri', $object->getName()); @@ -47,181 +51,193 @@ public function testConstruct() } /** - * Test get/set color - * @expectedException \Exception - * @expectedExceptionMessage $pValue must be an instance of \PhpOffice\PhpPresentation\Style\Color + * Test get/set Character Spacing. */ - public function testSetGetColorException() - { - $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setColor()); - } - - /** - * Test get/set Character Spacing - */ - public function testSetGetCharacterSpacing() + public function testCharacterSpacing(): void { $object = new Font(); $this->assertEquals(0, $object->getCharacterSpacing()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setCharacterSpacing(0)); + $this->assertInstanceOf(Font::class, $object->setCharacterSpacing(0)); $this->assertEquals(0, $object->getCharacterSpacing()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setCharacterSpacing(10)); + $this->assertInstanceOf(Font::class, $object->setCharacterSpacing(10)); $this->assertEquals(1000, $object->getCharacterSpacing()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setCharacterSpacing()); + $this->assertInstanceOf(Font::class, $object->setCharacterSpacing()); $this->assertEquals(0, $object->getCharacterSpacing()); } /** - * Test get/set color + * Test get/set color. */ - public function testSetGetColor() + public function testColor(): void { $object = new Font(); $this->assertEquals(Color::COLOR_BLACK, $object->getColor()->getARGB()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setColor(new Color(Color::COLOR_BLUE))); + $this->assertInstanceOf(Font::class, $object->setColor(new Color(Color::COLOR_BLUE))); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getColor()); $this->assertEquals(Color::COLOR_BLUE, $object->getColor()->getARGB()); } /** - * Test get/set name + * Test get/set name. + */ + public function testFormat(): void + { + $object = new Font(); + $this->assertEquals(Font::FORMAT_LATIN, $object->getFormat()); + $this->assertInstanceOf(Font::class, $object->setFormat()); + $this->assertEquals(Font::FORMAT_LATIN, $object->getFormat()); + $this->assertInstanceOf(Font::class, $object->setFormat('UnAuthorized')); + $this->assertEquals(Font::FORMAT_LATIN, $object->getFormat()); + $this->assertInstanceOf(Font::class, $object->setFormat(Font::FORMAT_EAST_ASIAN)); + $this->assertEquals(Font::FORMAT_EAST_ASIAN, $object->getFormat()); + $this->assertInstanceOf(Font::class, $object->setFormat(Font::FORMAT_COMPLEX_SCRIPT)); + $this->assertEquals(Font::FORMAT_COMPLEX_SCRIPT, $object->getFormat()); + } + + /** + * Test get/set name. */ - public function testSetGetName() + public function testName(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setName()); + $this->assertInstanceOf(Font::class, $object->setName()); $this->assertEquals('Calibri', $object->getName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setName('')); + $this->assertInstanceOf(Font::class, $object->setName('')); $this->assertEquals('Calibri', $object->getName()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setName('Arial')); + $this->assertInstanceOf(Font::class, $object->setName('Arial')); $this->assertEquals('Arial', $object->getName()); } /** - * Test get/set size + * Test get/set size. */ - public function testSetGetSize() + public function testSize(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSize()); + $this->assertInstanceOf(Font::class, $object->setSize()); $this->assertEquals(10, $object->getSize()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSize('')); - $this->assertEquals(10, $object->getSize()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSize($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Font::class, $object->setSize($value)); $this->assertEquals($value, $object->getSize()); } /** - * Test get/set underline + * Test get/set underline. */ - public function testSetGetUnderline() + public function testUnderline(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setUnderline()); + $this->assertInstanceOf(Font::class, $object->setUnderline()); $this->assertEquals(FONT::UNDERLINE_NONE, $object->getUnderline()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setUnderline('')); + $this->assertInstanceOf(Font::class, $object->setUnderline('')); $this->assertEquals(FONT::UNDERLINE_NONE, $object->getUnderline()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setUnderline(FONT::UNDERLINE_DASH)); + $this->assertInstanceOf(Font::class, $object->setUnderline(FONT::UNDERLINE_DASH)); $this->assertEquals(FONT::UNDERLINE_DASH, $object->getUnderline()); } /** - * Test get/set bold + * Test get/set bold. */ - public function testSetIsBold() + public function testSetIsBold(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setBold()); - $this->assertFalse($object->isBold()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setBold('')); + $this->assertInstanceOf(Font::class, $object->setBold()); $this->assertFalse($object->isBold()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setBold(false)); + $this->assertInstanceOf(Font::class, $object->setBold(false)); $this->assertFalse($object->isBold()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setBold(true)); + $this->assertInstanceOf(Font::class, $object->setBold(true)); $this->assertTrue($object->isBold()); } /** - * Test get/set italic + * Test get/set italic. */ - public function testSetIsItalic() + public function testSetIsItalic(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setItalic()); + $this->assertInstanceOf(Font::class, $object->setItalic()); $this->assertFalse($object->isItalic()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setItalic('')); + $this->assertInstanceOf(Font::class, $object->setItalic(false)); $this->assertFalse($object->isItalic()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setItalic(false)); - $this->assertFalse($object->isItalic()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setItalic(true)); + $this->assertInstanceOf(Font::class, $object->setItalic(true)); $this->assertTrue($object->isItalic()); } /** - * Test get/set strikethrough + * Test get/set strikethrough. */ - public function testSetIsStriketrough() + public function testSetIsStriketrough(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setStrikethrough()); - $this->assertFalse($object->isStrikethrough()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setStrikethrough('')); + $this->assertInstanceOf(Font::class, $object->setStrikethrough()); $this->assertFalse($object->isStrikethrough()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setStrikethrough(false)); + $this->assertInstanceOf(Font::class, $object->setStrikethrough(false)); $this->assertFalse($object->isStrikethrough()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setStrikethrough(true)); + $this->assertInstanceOf(Font::class, $object->setStrikethrough(true)); $this->assertTrue($object->isStrikethrough()); } /** - * Test get/set subscript + * Test get/set subscript. */ - public function testSetIsSubScript() + public function testSetIsSubScript(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSubScript()); + $this->assertInstanceOf(Font::class, $object->setSubScript()); $this->assertFalse($object->isSubScript()); - $this->assertTrue($object->isSuperScript()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSubScript('')); + $this->assertInstanceOf(Font::class, $object->setSubScript(false)); $this->assertFalse($object->isSubScript()); - $this->assertTrue($object->isSuperScript()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSubScript(false)); + $this->assertInstanceOf(Font::class, $object->setSubScript(true)); + $this->assertTrue($object->isSubScript()); + + // Test toggle of SubScript + $this->assertInstanceOf(Font::class, $object->setSubScript(false)); + $this->assertInstanceOf(Font::class, $object->setSuperScript(false)); $this->assertFalse($object->isSubScript()); - $this->assertTrue($object->isSuperScript()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSubScript(true)); + + $this->assertInstanceOf(Font::class, $object->setSubScript(true)); + $this->assertInstanceOf(Font::class, $object->setSuperScript(true)); + $this->assertFalse($object->isSubScript()); + + $this->assertInstanceOf(Font::class, $object->setSubScript(true)); + $this->assertInstanceOf(Font::class, $object->setSuperScript(false)); $this->assertTrue($object->isSubScript()); - $this->assertFalse($object->isSuperScript()); } /** - * Test get/set superscript + * Test get/set superscript. */ - public function testSetIsSuperScript() + public function testSetIsSuperScript(): void { $object = new Font(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSuperScript()); + $this->assertInstanceOf(Font::class, $object->setSuperScript()); $this->assertFalse($object->isSuperScript()); - $this->assertTrue($object->isSubScript()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSuperScript('')); + $this->assertInstanceOf(Font::class, $object->setSuperScript(false)); $this->assertFalse($object->isSuperScript()); - $this->assertTrue($object->isSubScript()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSuperScript(false)); + $this->assertInstanceOf(Font::class, $object->setSuperScript(true)); + $this->assertTrue($object->isSuperScript()); + + // Test toggle of SubScript + $this->assertInstanceOf(Font::class, $object->setSuperScript(false)); + $this->assertInstanceOf(Font::class, $object->setSubScript(false)); $this->assertFalse($object->isSuperScript()); - $this->assertTrue($object->isSubScript()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Font', $object->setSuperScript(true)); + + $this->assertInstanceOf(Font::class, $object->setSuperScript(true)); + $this->assertInstanceOf(Font::class, $object->setSubScript(true)); + $this->assertFalse($object->isSuperScript()); + + $this->assertInstanceOf(Font::class, $object->setSuperScript(true)); + $this->assertInstanceOf(Font::class, $object->setSubScript(false)); $this->assertTrue($object->isSuperScript()); - $this->assertFalse($object->isSubScript()); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testHashIndex(): void { $object = new Font(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } diff --git a/tests/PhpPresentation/Tests/Style/OutlineTest.php b/tests/PhpPresentation/Tests/Style/OutlineTest.php index e7cdc8900c..30411f12b2 100644 --- a/tests/PhpPresentation/Tests/Style/OutlineTest.php +++ b/tests/PhpPresentation/Tests/Style/OutlineTest.php @@ -10,55 +10,57 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Outline; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\Style\Outline + * @coversDefaultClass \PhpOffice\PhpPresentation\Style\Outline */ -class OutlineTest extends \PHPUnit_Framework_TestCase +class OutlineTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Outline(); - $this->assertNull($object->getWidth()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertEquals(1, $object->getWidth()); + $this->assertInstanceOf(Fill::class, $object->getFill()); } /** - * Test get/set fill + * Test get/set fill. */ - public function testSetGetFill() + public function testSetGetFill(): void { $object = new Outline(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Outline', $object->setFill(new Fill())); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Fill', $object->getFill()); + $this->assertInstanceOf(Fill::class, $object->getFill()); + $this->assertInstanceOf(Outline::class, $object->setFill(new Fill())); + $this->assertInstanceOf(Fill::class, $object->getFill()); } /** - * Test get/set width + * Test get/set width. */ - public function testSetGetWidth() + public function testSetGetWidth(): void { $object = new Outline(); - $this->assertNull($object->getWidth()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Outline', $object->setWidth($value)); - $this->assertEquals($value, $object->getWidth()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Outline', $object->setWidth(1.5)); $this->assertEquals(1, $object->getWidth()); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Outline::class, $object->setWidth($value)); + $this->assertEquals($value, $object->getWidth()); } } diff --git a/tests/PhpPresentation/Tests/Style/ShadowTest.php b/tests/PhpPresentation/Tests/Style/ShadowTest.php index 78bfae9b1a..ec22869827 100644 --- a/tests/PhpPresentation/Tests/Style/ShadowTest.php +++ b/tests/PhpPresentation/Tests/Style/ShadowTest.php @@ -10,27 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Shadow; +use PHPUnit\Framework\TestCase; /** - * Test class for PhpPresentation + * Test class for PhpPresentation. * - * @coversDefaultClass PhpOffice\PhpPresentation\PhpPresentation + * @coversDefaultClass \PhpOffice\PhpPresentation\PhpPresentation */ -class ShadowTest extends \PHPUnit_Framework_TestCase +class ShadowTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { $object = new Shadow(); $this->assertFalse($object->isVisible()); @@ -38,110 +42,110 @@ public function testConstruct() $this->assertEquals(2, $object->getDistance()); $this->assertEquals(0, $object->getDirection()); $this->assertEquals(Shadow::SHADOW_BOTTOM_RIGHT, $object->getAlignment()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getColor()); + $this->assertInstanceOf(Color::class, $object->getColor()); $this->assertEquals(Color::COLOR_BLACK, $object->getColor()->getARGB()); $this->assertEquals(50, $object->getAlpha()); } /** - * Test get/set alignment + * Test get/set alignment. */ - public function testSetGetAlignment() + public function testSetGetAlignment(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setAlignment()); + $this->assertInstanceOf(Shadow::class, $object->setAlignment()); $this->assertEquals(Shadow::SHADOW_BOTTOM_RIGHT, $object->getAlignment()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setAlignment(Shadow::SHADOW_CENTER)); + $this->assertInstanceOf(Shadow::class, $object->setAlignment(Shadow::SHADOW_CENTER)); $this->assertEquals(Shadow::SHADOW_CENTER, $object->getAlignment()); } /** - * Test get/set alpha + * Test get/set alpha. */ - public function testSetGetAlpha() + public function testSetGetAlpha(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setAlpha()); + $this->assertInstanceOf(Shadow::class, $object->setAlpha()); $this->assertEquals(0, $object->getAlpha()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setAlpha($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Shadow::class, $object->setAlpha($value)); $this->assertEquals($value, $object->getAlpha()); } /** - * Test get/set blur radius + * Test get/set blur radius. */ - public function testSetGetBlurRadius() + public function testSetGetBlurRadius(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setBlurRadius()); + $this->assertInstanceOf(Shadow::class, $object->setBlurRadius()); $this->assertEquals(6, $object->getBlurRadius()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setBlurRadius($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Shadow::class, $object->setBlurRadius($value)); $this->assertEquals($value, $object->getBlurRadius()); } /** - * Test get/set color + * Test get/set color. */ - public function testSetGetColor() + public function testSetGetColor(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setColor()); + $this->assertInstanceOf(Shadow::class, $object->setColor()); $this->assertNull($object->getColor()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setColor(new Color(Color::COLOR_BLUE))); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getColor()); + $this->assertInstanceOf(Shadow::class, $object->setColor(new Color(Color::COLOR_BLUE))); + $this->assertInstanceOf(Color::class, $object->getColor()); $this->assertEquals(Color::COLOR_BLUE, $object->getColor()->getARGB()); } /** - * Test get/set direction + * Test get/set direction. */ - public function testSetGetDirection() + public function testSetGetDirection(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setDirection()); + $this->assertInstanceOf(Shadow::class, $object->setDirection()); $this->assertEquals(0, $object->getDirection()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setDirection($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Shadow::class, $object->setDirection($value)); $this->assertEquals($value, $object->getDirection()); } /** - * Test get/set distance + * Test get/set distance. */ - public function testSetGetDistance() + public function testSetGetDistance(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setDistance()); + $this->assertInstanceOf(Shadow::class, $object->setDistance()); $this->assertEquals(2, $object->getDistance()); - $value = rand(1, 100); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setDistance($value)); + $value = mt_rand(1, 100); + $this->assertInstanceOf(Shadow::class, $object->setDistance($value)); $this->assertEquals($value, $object->getDistance()); } /** - * Test get/set hash index + * Test get/set hash index. */ - public function testSetGetHashIndex() + public function testSetGetHashIndex(): void { $object = new Shadow(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $object->setHashIndex($value); $this->assertEquals($value, $object->getHashIndex()); } /** - * Test get/set visible + * Test get/set visible. */ - public function testSetIsVisible() + public function testSetIsVisible(): void { $object = new Shadow(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setVisible()); + $this->assertInstanceOf(Shadow::class, $object->setVisible()); $this->assertFalse($object->isVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setVisible(false)); + $this->assertInstanceOf(Shadow::class, $object->setVisible(false)); $this->assertFalse($object->isVisible()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Shadow', $object->setVisible(true)); + $this->assertInstanceOf(Shadow::class, $object->setVisible(true)); $this->assertTrue($object->isVisible()); } } diff --git a/tests/PhpPresentation/Tests/Style/TextStyleTest.php b/tests/PhpPresentation/Tests/Style/TextStyleTest.php index 1e3a3c1151..b85da8f1fe 100644 --- a/tests/PhpPresentation/Tests/Style/TextStyleTest.php +++ b/tests/PhpPresentation/Tests/Style/TextStyleTest.php @@ -10,28 +10,31 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Style; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Style\Alignment; +use PhpOffice\PhpPresentation\Style\SchemeColor; use PhpOffice\PhpPresentation\Style\TextStyle; +use PHPUnit\Framework\TestCase; -class TextStyleTest extends \PHPUnit_Framework_TestCase +class TextStyleTest extends TestCase { - public function testConstructDefaultTrue() + public function testConstructDefaultTrue(): void { - /** - * @var \PhpOffice\PhpPresentation\Shape\RichText\Paragraph $oParagraph - */ + /** @var TextStyle $object */ $object = new TextStyle(); $arrayBodyStyle = $object->getBodyStyle(); - $this->assertInternalType('array', $arrayBodyStyle); + $this->assertIsArray($arrayBodyStyle); $this->assertCount(1, $arrayBodyStyle); $this->assertArrayHasKey(1, $arrayBodyStyle); $this->assertNull($object->getBodyStyleAtLvl(0)); @@ -42,11 +45,13 @@ public function testConstructDefaultTrue() $this->assertEquals((-324900 / 9525), $oParagraph->getAlignment()->getIndent()); $this->assertEquals(0, $oParagraph->getAlignment()->getMarginLeft()); $this->assertEquals(32, $oParagraph->getFont()->getSize()); - $this->assertInstanceOf('PhpOffice\PhpPresentation\Style\SchemeColor', $oParagraph->getFont()->getColor()); - $this->assertEquals('tx1', $oParagraph->getFont()->getColor()->getValue()); + /** @var SchemeColor $color */ + $color = $oParagraph->getFont()->getColor(); + $this->assertInstanceOf(SchemeColor::class, $color); + $this->assertEquals('tx1', $color->getValue()); $arrayOtherStyle = $object->getOtherStyle(); - $this->assertInternalType('array', $arrayOtherStyle); + $this->assertIsArray($arrayOtherStyle); $this->assertCount(1, $arrayOtherStyle); $this->assertArrayHasKey(0, $arrayOtherStyle); $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\RichText\Paragraph', $object->getOtherStyleAtLvl(0)); @@ -55,11 +60,13 @@ public function testConstructDefaultTrue() $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\RichText\Paragraph', $oParagraph); $this->assertEquals(Alignment::HORIZONTAL_CENTER, $oParagraph->getAlignment()->getHorizontal()); $this->assertEquals(10, $oParagraph->getFont()->getSize()); - $this->assertInstanceOf('PhpOffice\PhpPresentation\Style\SchemeColor', $oParagraph->getFont()->getColor()); - $this->assertEquals('tx1', $oParagraph->getFont()->getColor()->getValue()); + /** @var SchemeColor $color */ + $color = $oParagraph->getFont()->getColor(); + $this->assertInstanceOf(SchemeColor::class, $color); + $this->assertEquals('tx1', $color->getValue()); $arrayTitleStyle = $object->getTitleStyle(); - $this->assertInternalType('array', $arrayTitleStyle); + $this->assertIsArray($arrayTitleStyle); $this->assertCount(1, $arrayTitleStyle); $this->assertArrayHasKey(1, $arrayTitleStyle); $this->assertNull($object->getTitleStyleAtLvl(0)); @@ -68,30 +75,32 @@ public function testConstructDefaultTrue() $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\RichText\Paragraph', $oParagraph); $this->assertEquals(Alignment::HORIZONTAL_CENTER, $oParagraph->getAlignment()->getHorizontal()); $this->assertEquals(44, $oParagraph->getFont()->getSize()); - $this->assertInstanceOf('PhpOffice\PhpPresentation\Style\SchemeColor', $oParagraph->getFont()->getColor()); - $this->assertEquals('lt1', $oParagraph->getFont()->getColor()->getValue()); + /** @var SchemeColor $color */ + $color = $oParagraph->getFont()->getColor(); + $this->assertInstanceOf(SchemeColor::class, $color); + $this->assertEquals('lt1', $color->getValue()); } - public function testConstructDefaultFalse() + public function testConstructDefaultFalse(): void { $object = new TextStyle(false); - $this->assertInternalType('array', $object->getBodyStyle()); + $this->assertIsArray($object->getBodyStyle()); $this->assertCount(0, $object->getBodyStyle()); - $this->assertInternalType('array', $object->getOtherStyle()); + $this->assertIsArray($object->getOtherStyle()); $this->assertCount(0, $object->getOtherStyle()); - $this->assertInternalType('array', $object->getTitleStyle()); + $this->assertIsArray($object->getTitleStyle()); $this->assertCount(0, $object->getTitleStyle()); } - public function testLevel() + public function testLevel(): void { - $value = rand(0, 9); + $value = mt_rand(0, 9); $object = new TextStyle(false); $oParagraph = new Paragraph(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setBodyStyleAtLvl($oParagraph, '')); - $this->assertNull($object->getBodyStyleAtLvl('')); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setBodyStyleAtLvl($oParagraph, null)); + $this->assertNull($object->getBodyStyleAtLvl(null)); $this->assertCount(0, $object->getBodyStyle()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setBodyStyleAtLvl($oParagraph, 10)); $this->assertNull($object->getBodyStyleAtLvl(10)); @@ -100,8 +109,8 @@ public function testLevel() $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\RichText\Paragraph', $object->getBodyStyleAtLvl($value)); $this->assertCount(1, $object->getBodyStyle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setOtherStyleAtLvl($oParagraph, '')); - $this->assertNull($object->getOtherStyleAtLvl('')); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setOtherStyleAtLvl($oParagraph, null)); + $this->assertNull($object->getOtherStyleAtLvl(null)); $this->assertCount(0, $object->getOtherStyle()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setOtherStyleAtLvl($oParagraph, 10)); $this->assertNull($object->getOtherStyleAtLvl(10)); @@ -110,8 +119,8 @@ public function testLevel() $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\RichText\Paragraph', $object->getOtherStyleAtLvl($value)); $this->assertCount(1, $object->getOtherStyle()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setTitleStyleAtLvl($oParagraph, '')); - $this->assertNull($object->getTitleStyleAtLvl('')); + $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setTitleStyleAtLvl($oParagraph, null)); + $this->assertNull($object->getTitleStyleAtLvl(null)); $this->assertCount(0, $object->getTitleStyle()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\TextStyle', $object->setTitleStyleAtLvl($oParagraph, 10)); $this->assertNull($object->getTitleStyleAtLvl(10)); diff --git a/tests/PhpPresentation/Tests/Writer/AbstractWriter.php b/tests/PhpPresentation/Tests/Writer/AbstractWriter.php index 2b94d31d91..7da382b974 100644 --- a/tests/PhpPresentation/Tests/Writer/AbstractWriter.php +++ b/tests/PhpPresentation/Tests/Writer/AbstractWriter.php @@ -10,28 +10,32 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @copyright 2009-2017 PHPPresentation contributors + * @see https://github.com/PHPOffice/PHPPresentation + * + * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Writer; +use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\Writer; /** - * Mock class for AbstractWriter - * + * Mock class for AbstractWriter. */ class AbstractWriter extends Writer\AbstractWriter { /** - * public wrapper for protected method + * public wrapper for protected method. + * + * @return AbstractShape[] All drawings in PhpPresentation * - * @return \PhpOffice\PhpPresentation\Shape\AbstractDrawing[] All drawings in PhpPresentation * @throws \Exception */ - public function allDrawings() + public function allDrawings(): array { return parent::allDrawings(); } diff --git a/tests/PhpPresentation/Tests/Writer/AbstractWriterTest.php b/tests/PhpPresentation/Tests/Writer/AbstractWriterTest.php index 2606d41b86..101ed117ca 100644 --- a/tests/PhpPresentation/Tests/Writer/AbstractWriterTest.php +++ b/tests/PhpPresentation/Tests/Writer/AbstractWriterTest.php @@ -10,41 +10,50 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Writer; +use PhpOffice\Common\Adapter\Zip\ZipInterface; use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\Tests\Writer\AbstractWriter as TestAbstractWriter; +use PhpOffice\PhpPresentation\Writer\AbstractWriter; +use PHPUnit\Framework\TestCase; require 'AbstractWriter.php'; /** - * Test class for AbstractWriter + * Test class for AbstractWriter. * - * @coversDefaultClass AbstractWriter + * @coversDefaultClass \AbstractWriter */ -class AbstractWriterTest extends \PHPUnit_Framework_TestCase +class AbstractWriterTest extends TestCase { /** - * Test create new instance + * Test create new instance. */ - public function testConstruct() + public function testConstruct(): void { - $oStubWriter = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Writer\AbstractWriter'); - $oStubZip = $this->getMockForAbstractClass('PhpOffice\Common\Adapter\Zip\ZipInterface'); + /** @var AbstractWriter $oStubWriter */ + $oStubWriter = $this->getMockForAbstractClass(AbstractWriter::class); + /** @var ZipInterface $oStubZip */ + $oStubZip = $this->getMockForAbstractClass(ZipInterface::class); $this->assertNull($oStubWriter->getZipAdapter()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Writer\\AbstractWriter', $oStubWriter->setZipAdapter($oStubZip)); - $this->assertInstanceOf('PhpOffice\\Common\\Adapter\\Zip\\ZipInterface', $oStubWriter->getZipAdapter()); + $this->assertInstanceOf(AbstractWriter::class, $oStubWriter->setZipAdapter($oStubZip)); + $this->assertInstanceOf(ZipInterface::class, $oStubWriter->getZipAdapter()); } /** - * Test all drawings method + * Test all drawings method. */ - public function testAllDrawingsIncludesMasterSlides() + public function testAllDrawingsIncludesMasterSlides(): void { $presentation = new PhpPresentation(); @@ -55,10 +64,11 @@ public function testAllDrawingsIncludesMasterSlides() $masterSlide = $masterSlides[0]; $masterSlide->createDrawingShape(); - $writer = $this->getMockForAbstractClass('PhpOffice\\PhpPresentation\\Tests\\Writer\\AbstractWriter'); + /** @var TestAbstractWriter $writer */ + $writer = $this->getMockForAbstractClass(TestAbstractWriter::class); $writer->setPhpPresentation($presentation); $drawings = $writer->allDrawings(); - $this->assertEquals(2, count($drawings), 'Number of drawings should equal two: one from normal slide and one from master slide'); + $this->assertCount(2, $drawings, 'Number of drawings should equal two: one from normal slide and one from master slide'); } } diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/ContentTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/ContentTest.php index 4134c8c20e..c67a78bc96 100644 --- a/tests/PhpPresentation/Tests/Writer/ODPresentation/ContentTest.php +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/ContentTest.php @@ -1,11 +1,32 @@ oPresentation->getActiveSlide(); - $oShape = $oSlide->createDrawingShape(); - $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/PhpPresentationLogo.png'); - $oShape->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/'); - - $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/office:event-listeners/presentation:event-listener'; - $this->assertZipXmlElementExists('content.xml', $element); - $this->assertZipXmlAttributeEquals('content.xml', $element, 'xlink:href', 'https://github.com/PHPOffice/PHPPresentation/'); - } - - public function testComment() + public function testComment(): void { $expectedName = 'Name'; $expectedText = 'Text'; @@ -61,9 +69,10 @@ public function testComment() $element = '/office:document-content/office:body/office:presentation/draw:page/officeooo:annotation/text:p'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlElementEquals('content.xml', $element, $expectedText); + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testCommentWithoutAuthor() + public function testCommentWithoutAuthor(): void { $oComment = new Comment(); $this->oPresentation->getActiveSlide()->addShape($oComment); @@ -71,9 +80,71 @@ public function testCommentWithoutAuthor() $element = '/office:document-content/office:body/office:presentation/draw:page/officeooo:annotation'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'dc:creator'); + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testDrawingMimetype(): void + { + $oShape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); + + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:image'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeExists('content.xml', $element, 'loext:mime-type'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'loext:mime-type', 'image/png'); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/tiger.svg'); + + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:image'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeExists('content.xml', $element, 'loext:mime-type'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'loext:mime-type', 'image/svg+xml'); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testDrawingShapeFill(): void + { + $oShape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); + + $element = '/office:document-content/office:automatic-styles/style:style/style:graphic-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill', 'none'); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oColor = new Color(Color::COLOR_DARKRED); + $oColor->setAlpha(rand(0, 100)); + $oShape->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor($oColor); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:automatic-styles/style:style/style:graphic-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill', 'solid'); + $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:fill-color', '#'); + $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'draw:fill-color', $oColor->getRGB()); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testDrawingWithHyperlink(): void + { + $oShape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); + $oShape->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/'); + + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/office:event-listeners/presentation:event-listener'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'xlink:href', 'https://github.com/PHPOffice/PHPPresentation/'); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testFillGradientLinearRichText() + public function testFillGradientLinearRichText(): void { $oShape = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oShape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR)->setStartColor(new Color('FFFF7700'))->setEndColor(new Color('FFFFFFFF')); @@ -85,9 +156,10 @@ public function testFillGradientLinearRichText() $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill', 'gradient'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill-gradient-name', 'gradient_' . $oShape->getFill()->getHashCode()); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testFillSolidRichText() + public function testFillSolidRichText(): void { $oShape = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oShape->getFill()->setFillType(Fill::FILL_SOLID)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF4672A8')); @@ -97,22 +169,25 @@ public function testFillSolidRichText() $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill', 'solid'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill-color', '#' . $oShape->getFill()->getStartColor()->getRGB()); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill-color', '#' . $oShape->getFill()->getEndColor()->getRGB()); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testGroup() + public function testGroup(): void { $oShapeGroup = $this->oPresentation->getActiveSlide()->createGroup(); $oShape = $oShapeGroup->createDrawingShape(); - $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/PhpPresentationLogo.png'); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); $oShape->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/'); - + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:g'; $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:g/draw:frame/office:event-listeners/presentation:event-listener'; $this->assertZipXmlElementExists('content.xml', $element); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testList() + + public function testList(): void { $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRichText->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); @@ -120,43 +195,45 @@ public function testList() $oRichText->createParagraph()->createTextRun('Beta'); $oRichText->createParagraph()->createTextRun('Delta'); $oRichText->createParagraph()->createTextRun('Epsilon'); - + $element = '/office:document-content/office:automatic-styles/text:list-style/text:list-level-style-bullet'; $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box'; $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box/text:list/text:list-item/text:p/text:span'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testInnerList() + public function testInnerList(): void { $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRichText->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT)->setMarginLeft(25)->setIndent(-25); $oRichText->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); - + $oRichText->createTextRun('Alpha'); $oRichText->createParagraph()->getAlignment()->setLevel(1)->setMarginLeft(75)->setIndent(-25); $oRichText->createTextRun('Alpha.Alpha'); $oRichText->createParagraph()->createTextRun('Alpha.Beta'); $oRichText->createParagraph()->createTextRun('Alpha.Delta'); - + $oRichText->createParagraph()->getAlignment()->setLevel(0)->setMarginLeft(25)->setIndent(-25); $oRichText->createTextRun('Beta'); $oRichText->createParagraph()->getAlignment()->setLevel(1)->setMarginLeft(75)->setIndent(-25); $oRichText->createTextRun('Beta.Alpha'); $oRichText->createParagraph()->createTextRun('Beta.Beta'); $oRichText->createParagraph()->createTextRun('Beta.Delta'); - + $element = '/office:document-content/office:automatic-styles/text:list-style/text:list-level-style-bullet'; $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box'; $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box/text:list/text:list-item/text:list/text:list-item/text:p/text:span'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testParagraphRichText() + public function testParagraphRichText(): void { $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRichText->createTextRun('Alpha'); @@ -165,16 +242,17 @@ public function testParagraphRichText() $oRichText->createBreak(); $oRun = $oRichText->createTextRun('Delta'); $oRun->getHyperlink()->setUrl('http://www.google.fr'); - + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box/text:p/text:span/text:line-break'; $this->assertZipXmlElementExists('content.xml', $element); - + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box/text:p/text:span/text:a'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'xlink:href', 'http://www.google.fr'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testListWithRichText() + public function testListWithRichText(): void { $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRichText->getActiveParagraph()->getBulletStyle()->setBulletType(Bullet::TYPE_BULLET); @@ -182,20 +260,21 @@ public function testListWithRichText() $oRun->getHyperlink()->setUrl('http://www.google.fr'); $oRichText->createBreak(); $oRichText->createTextRun('Beta'); - + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box/text:list/text:list-item/text:p/text:span/text:a'; $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/draw:text-box/text:list/text:list-item/text:p/text:span/text:line-break'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testMedia() + public function testMedia(): void { $expectedName = 'MyName'; - $expectedWidth = rand(1, 100); - $expectedHeight = rand(1, 100); - $expectedX = rand(1, 100); - $expectedY = rand(1, 100); + $expectedWidth = mt_rand(1, 100); + $expectedHeight = mt_rand(1, 100); + $expectedX = mt_rand(1, 100); + $expectedY = mt_rand(1, 100); $oMedia = new Media(); $oMedia->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/videos/sintel_trailer-480p.ogv') @@ -207,10 +286,10 @@ public function testMedia() ->setOffsetY($expectedY); $this->oPresentation->getActiveSlide()->addShape($oMedia); - $expectedWidth = Text::numberFormat(CommonDrawing::pixelsToCentimeters($expectedWidth), 3) . 'cm'; - $expectedHeight = Text::numberFormat(CommonDrawing::pixelsToCentimeters($expectedHeight), 3) . 'cm'; - $expectedX = Text::numberFormat(CommonDrawing::pixelsToCentimeters($expectedX), 3) . 'cm'; - $expectedY = Text::numberFormat(CommonDrawing::pixelsToCentimeters($expectedY), 3) . 'cm'; + $expectedWidth = Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $expectedWidth), 3) . 'cm'; + $expectedHeight = Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $expectedHeight), 3) . 'cm'; + $expectedX = Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $expectedX), 3) . 'cm'; + $expectedY = Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $expectedY), 3) . 'cm'; $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame'; $this->assertZipXmlElementExists('content.xml', $element); @@ -225,9 +304,10 @@ public function testMedia() $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:mime-type', 'application/vnd.sun.star.media'); $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'xlink:href', 'Pictures/'); $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'xlink:href', 'ogv'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testNote() + public function testNote(): void { $oNote = $this->oPresentation->getActiveSlide()->getNote(); $oRichText = $oNote->createRichTextShape()->setHeight(300)->setWidth(600); @@ -237,15 +317,58 @@ public function testNote() $this->assertZipXmlElementExists('content.xml', $element); $element = '/office:document-content/office:body/office:presentation/draw:page/presentation:notes/draw:frame/draw:text-box/text:p/text:span'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testParagraphLineSpacing(): void + { + $richText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + $richText->getActiveParagraph()->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_PERCENT); + $richText->getActiveParagraph()->setLineSpacing(200); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $richText->getActiveParagraph()->getHashCode() . '\']/style:paragraph-properties'; + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:line-height'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:line-height', '200%'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $richText->getActiveParagraph()->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT); + $this->resetPresentationFile(); + + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:line-height'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:line-height', '200pt'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testRichTextAutoShrink() + public function testParagraphSpacingBefore(): void + { + $richText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + $richText->getActiveParagraph()->setSpacingBefore(123); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $richText->getActiveParagraph()->getHashCode() . '\']/style:paragraph-properties'; + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:margin-top'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:margin-top', '4.339cm'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testParagraphSpacingAfter(): void + { + $richText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + $richText->getActiveParagraph()->setSpacingAfter(123); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $richText->getActiveParagraph()->getHashCode() . '\']/style:paragraph-properties'; + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:margin-bottom'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:margin-bottom', '4.339cm'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testRichTextAutoShrink(): void { $oRichText1 = $this->oPresentation->getActiveSlide()->createRichTextShape(); $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'gr1\']/style:graphic-properties'; $this->assertZipXmlAttributeNotExists('content.xml', $element, 'draw:auto-grow-height'); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'draw:auto-grow-width'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oRichText1->setAutoShrinkHorizontal(false); $oRichText1->setAutoShrinkVertical(true); @@ -255,6 +378,7 @@ public function testRichTextAutoShrink() $this->assertZipXmlAttributeExists('content.xml', $element, 'draw:auto-grow-width'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:auto-grow-height', 'true'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:auto-grow-width', 'false'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oRichText1->setAutoShrinkHorizontal(true); $oRichText1->setAutoShrinkVertical(false); @@ -264,38 +388,99 @@ public function testRichTextAutoShrink() $this->assertZipXmlAttributeExists('content.xml', $element, 'draw:auto-grow-width'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:auto-grow-height', 'false'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:auto-grow-width', 'true'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testRichTextRunLanguage() + public function testRichTextRunLanguage(): void { $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); - $oRun = $oRichText->createTextRun('MyText'); + $oRun = $oRichText->createTextRun('Run1'); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $oRun->getHashCode() . '\']/style:text-properties'; + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-complex'); $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:language'); - $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:language', 'en-US'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:language', 'en'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); - $oRun->setLanguage('de_DE'); + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:language'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:language-asian'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:language-asian', 'en'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); $this->resetPresentationFile(); + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:language'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-asian'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:language-complex'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:language-complex', 'en'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->setLanguage('de'); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-complex'); $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:language'); - $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:language', 'de_DE'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:language', 'de'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:language'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:language-asian'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:language-asian', 'de'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:language'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:language-asian'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:language-complex'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:language-complex', 'de'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testRichTextBorder() + public function testRichTextBorder(): void { $oRichText1 = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRichText1->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_SOLID)->setLineStyle(Border::LINE_NONE); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'gr1\']/style:graphic-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'svg:stroke-color'); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'svg:stroke-width'); $this->assertZipXmlAttributeExists('content.xml', $element, 'draw:stroke'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:stroke', 'none'); - + $this->assertIsSchemaOpenDocumentValid('1.2'); + $oRichText1->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_SOLID)->setLineStyle(Border::LINE_SINGLE); $this->resetPresentationFile(); @@ -303,11 +488,12 @@ public function testRichTextBorder() $this->assertZipXmlAttributeExists('content.xml', $element, 'svg:stroke-color'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'svg:stroke-color', '#' . $oRichText1->getBorder()->getColor()->getRGB()); $this->assertZipXmlAttributeExists('content.xml', $element, 'svg:stroke-width'); - $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'svg:stroke-width', (string)number_format(CommonDrawing::pointsToCentimeters($oRichText1->getBorder()->getLineWidth()), 3, '.', '')); + $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'svg:stroke-width', (string) number_format(CommonDrawing::pointsToCentimeters($oRichText1->getBorder()->getLineWidth()), 3, '.', '')); $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'svg:stroke-width', 'cm'); $this->assertZipXmlAttributeExists('content.xml', $element, 'draw:stroke'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:stroke', 'solid'); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'draw:stroke-dash'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oRichText1->getBorder()->setColor(new Color('FF4672A8'))->setDashStyle(Border::DASH_DASH); $this->resetPresentationFile(); @@ -316,58 +502,61 @@ public function testRichTextBorder() $this->assertZipXmlAttributeExists('content.xml', $element, 'draw:stroke-dash'); $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:stroke-dash', 'strokeDash_'); $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'draw:stroke-dash', $oRichText1->getBorder()->getDashStyle()); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testRichTextShadow() + + public function testRichTextShadow(): void { - $randAlpha = rand(0, 100); + $randAlpha = mt_rand(0, 100); $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRichText->createTextRun('AAA'); $oRichText->getShadow()->setVisible(true)->setAlpha($randAlpha)->setBlurRadius(2); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'gr1\']/style:graphic-properties'; for ($inc = 0; $inc <= 360; $inc += 45) { - $randDistance = rand(0, 100); + $randDistance = mt_rand(0, 100); $oRichText->getShadow()->setDirection($inc)->setDistance($randDistance); $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow', 'visible'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:mirror', 'none'); // Opacity - $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:shadow-opacity', (string)(100 - $randAlpha)); + $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:shadow-opacity', (string) (100 - $randAlpha)); $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'draw:shadow-opacity', '%'); // Color $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:shadow-color', '#'); // X - if ($inc == 90 || $inc == 270) { + if (90 == $inc || 270 == $inc) { $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-x', '0cm'); } else { if ($inc > 90 && $inc < 270) { - $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-x', '-' . Drawing::pixelsToCentimeters($randDistance) . 'cm'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-x', '-' . Drawing::pixelsToCentimeters((int) $randDistance) . 'cm'); } else { - $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-x', Drawing::pixelsToCentimeters($randDistance) . 'cm'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-x', Drawing::pixelsToCentimeters((int) $randDistance) . 'cm'); } } // Y - if ($inc == 0 || $inc == 180 || $inc == 360) { + if (0 == $inc || 180 == $inc || 360 == $inc) { $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-y', '0cm'); } else { - if (($inc > 0 && $inc < 180) || $inc == 360) { - $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-y', Drawing::pixelsToCentimeters($randDistance) . 'cm'); + if (($inc > 0 && $inc < 180) || 360 == $inc) { + $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-y', Drawing::pixelsToCentimeters((int) $randDistance) . 'cm'); } else { - $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-y', '-' . Drawing::pixelsToCentimeters($randDistance) . 'cm'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:shadow-offset-y', '-' . Drawing::pixelsToCentimeters((int) $randDistance) . 'cm'); } } + $this->assertIsSchemaOpenDocumentValid('1.2'); $this->resetPresentationFile(); } } - public function testSlideName() + public function testSlideName(): void { $element = '/office:document-content/office:body/office:presentation/draw:page'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'draw:name'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $this->oPresentation->getActiveSlide()->setName('AAAA'); $this->resetPresentationFile(); @@ -375,15 +564,17 @@ public function testSlideName() $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeExists('content.xml', $element, 'draw:name'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:name', 'AAAA'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $this->oPresentation->getActiveSlide()->setName(); $this->resetPresentationFile(); $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'draw:name'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testStyleAlignment() + public function testStyleAlignment(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText1 = $oSlide->createRichTextShape(); @@ -411,58 +602,275 @@ public function testStyleAlignment() $p4HashCode = $oRichText4->getActiveParagraph()->getHashCode(); $p5HashCode = $oRichText5->getActiveParagraph()->getHashCode(); $p6HashCode = $oRichText6->getActiveParagraph()->getHashCode(); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_'.$p1HashCode.'\']/style:paragraph-properties'; + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p1HashCode . '\']/style:paragraph-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:text-align', 'center'); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_'.$p2HashCode.'\']/style:paragraph-properties'; + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p2HashCode . '\']/style:paragraph-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:text-align', 'justify'); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_'.$p3HashCode.'\']/style:paragraph-properties'; + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p3HashCode . '\']/style:paragraph-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:text-align', 'left'); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_'.$p4HashCode.'\']/style:paragraph-properties'; + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p4HashCode . '\']/style:paragraph-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:text-align', 'justify'); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_'.$p5HashCode.'\']/style:paragraph-properties'; + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p5HashCode . '\']/style:paragraph-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:text-align', 'left'); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_'.$p6HashCode.'\']/style:paragraph-properties'; + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p6HashCode . '\']/style:paragraph-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:text-align', 'right'); + + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testStyleAlignmentRTL(): void + { + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText1 = $oSlide->createRichTextShape(); + $oRichText1->getActiveParagraph()->getAlignment()->setIsRTL(true); + $oRichText1->createTextRun('Run1'); + $oRichText2 = $oSlide->createRichTextShape(); + $oRichText2->getActiveParagraph()->getAlignment()->setIsRTL(false); + $oRichText2->createTextRun('Run2'); + + $p1HashCode = $oRichText1->getActiveParagraph()->getHashCode(); + $p2HashCode = $oRichText2->getActiveParagraph()->getHashCode(); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p1HashCode . '\']/style:paragraph-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:writing-mode', 'rl-tb'); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'P_' . $p2HashCode . '\']/style:paragraph-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:writing-mode', 'lr-tb'); + + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testStyleFont() + + public function testStyleFontBold(): void { $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); $oRun = $oRichText->createTextRun('Run1'); $oRun->getFont()->setBold(true); - + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + $expectedHashCode = $oRun->getHashCode(); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_'.$expectedHashCode.'\']/style:text-properties'; + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:font-weight'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:font-weight', 'bold'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-weight'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:font-weight-asian'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:font-weight-asian', 'bold'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-weight'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-asian'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:font-weight-complex'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:font-weight-complex', 'bold'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setBold(false); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-weight'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-complex'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-weight'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-complex'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-weight'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-weight-complex'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testTable() + + public function testStyleFontFormat(): void { - $this->oPresentation->getActiveSlide()->createTableShape(); + $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + $oRun = $oRichText->createTextRun('Run1'); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:script-type'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:script-type', 'latin'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:script-type'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:script-type', 'asian'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:script-type'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:script-type', 'complex'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testStyleFontName(): void + { + $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + $oRun = $oRichText->createTextRun('Run1'); + $oRun->getFont()->setName('Calibri'); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-family-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-family-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:font-family'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:font-family', 'Calibri'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-family'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-family-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:font-family-asian'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:font-family-asian', 'Calibri'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-family'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-family-asian'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:font-family-complex'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:font-family-complex', 'Calibri'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testStyleFontSize(): void + { + $oRichText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + $oRun = $oRichText->createTextRun('Run1'); + $oRun->getFont()->setSize(12); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-size-asian'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-size-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'fo:font-size'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'fo:font-size', '12pt'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-size'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-size-complex'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:font-size-asian'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:font-size-asian', '12pt'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $expectedHashCode = $oRun->getHashCode(); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'T_' . $expectedHashCode . '\']/style:text-properties'; + $this->assertZipXmlElementExists('content.xml', $element); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'fo:font-size'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'style:font-size-asian'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'style:font-size-complex'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'style:font-size-complex', '12pt'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testTable(): void + { + $oShape = $this->oPresentation->getActiveSlide()->createTableShape(); + $oShape->createRow(); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/table:table'; $this->assertZipXmlElementExists('content.xml', $element); + + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testTableCellFill() + + public function testTableEmpty(): void + { + $this->oPresentation->getActiveSlide()->createTableShape(); + + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/table:table'; + $this->assertZipXmlElementNotExists('content.xml', $element); + + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + public function testTableCellFill(): void { $oColor = new Color(); $oColor->setRGB(Color::COLOR_BLUE); - + $oFill = new Fill(); $oFill->setFillType(Fill::FILL_SOLID)->setStartColor($oColor); @@ -480,11 +888,13 @@ public function testTableCellFill() $this->assertZipXmlAttributeEquals('content.xml', $element, 'draw:fill', 'solid'); $this->assertZipXmlAttributeStartsWith('content.xml', $element, 'draw:fill-color', '#'); $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'draw:fill-color', $oColor->getRGB()); + + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testTableWithColspan() + + public function testTableWithColspan(): void { - $value = rand(2, 100); + $value = mt_rand(2, 100); $oShape = $this->oPresentation->getActiveSlide()->createTableShape($value); $oRow = $oShape->createRow(); @@ -494,12 +904,14 @@ public function testTableWithColspan() $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/table:table/table:table-row/table:table-cell'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'table:number-columns-spanned', $value); + + $this->assertIsSchemaOpenDocumentValid('1.2'); } - + /** - * @link : https://github.com/PHPOffice/PHPPresentation/issues/70 + * @see : https://github.com/PHPOffice/PHPPresentation/issues/70 */ - public function testTableWithHyperlink() + public function testTableWithHyperlink(): void { $oShape = $this->oPresentation->getActiveSlide()->createTableShape(4); $oShape->setHeight(200)->setWidth(600)->setOffsetX(150)->setOffsetY(300); @@ -508,13 +920,15 @@ public function testTableWithHyperlink() $oTextRun = $oCell->createTextRun('AAA'); $oHyperlink = $oTextRun->getHyperlink(); $oHyperlink->setUrl('https://github.com/PHPOffice/PHPPresentation/'); - + $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/table:table/table:table-row/table:table-cell/text:p/text:span/text:a'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeEquals('content.xml', $element, 'xlink:href', 'https://github.com/PHPOffice/PHPPresentation/'); + + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testTableWithText() + + public function testTableWithText(): void { $oRun = new Run(); $oRun->setText('Test'); @@ -530,16 +944,19 @@ public function testTableWithText() $this->assertZipXmlElementEquals('content.xml', $element, 'Test'); $element = '/office:document-content/office:body/office:presentation/draw:page/draw:frame/table:table/table:table-row/table:table-cell/text:p/text:span/text:line-break'; $this->assertZipXmlElementExists('content.xml', $element); + + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testTransition() + public function testTransition(): void { - $value = rand(1000, 5000); + $value = mt_rand(1000, 5000); $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePage0\']/style:drawing-page-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'presentation:duration'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oTransition = new Transition(); $oTransition->setTimeTrigger(true, $value); @@ -552,26 +969,30 @@ public function testTransition() $this->assertZipXmlAttributeEndsWith('content.xml', $element, 'presentation:duration', 'S'); $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:duration', number_format($value / 1000, 6, '.', '')); $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:transition-type', 'automatic'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oTransition->setSpeed(Transition::SPEED_FAST); $this->resetPresentationFile(); $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:transition-speed', 'fast'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oTransition->setSpeed(Transition::SPEED_MEDIUM); $this->resetPresentationFile(); $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:transition-speed', 'medium'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oTransition->setSpeed(Transition::SPEED_SLOW); $this->resetPresentationFile(); $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:transition-speed', 'slow'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $rcTransition = new \ReflectionClass('PhpOffice\PhpPresentation\Slide\Transition'); $arrayConstants = $rcTransition->getConstants(); foreach ($arrayConstants as $key => $value) { - if (strpos($key, 'TRANSITION_') !== 0) { + if (0 !== strpos($key, 'TRANSITION_')) { continue; } $this->resetPresentationFile(); @@ -723,20 +1144,23 @@ public function testTransition() $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:transition-style', 'none'); break; } + $this->assertIsSchemaOpenDocumentValid('1.2'); } $oTransition->setTimeTrigger(false); $oTransition->setManualTrigger(true); $this->resetPresentationFile(); $this->assertZipXmlAttributeContains('content.xml', $element, 'presentation:transition-type', 'manual'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - public function testVisibility() + public function testVisibility(): void { $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePage0\']/style:drawing-page-properties'; $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeNotExists('content.xml', $element, 'presentation:visibility'); + $this->assertIsSchemaOpenDocumentValid('1.2'); $oSlide = $this->oPresentation->getActiveSlide(); $oSlide->setIsVisible(false); @@ -745,5 +1169,86 @@ public function testVisibility() $this->assertZipXmlElementExists('content.xml', $element); $this->assertZipXmlAttributeExists('content.xml', $element, 'presentation:visibility'); $this->assertZipXmlAttributeEquals('content.xml', $element, 'presentation:visibility', 'hidden'); + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + /** + * @dataProvider dataProviderShowType + */ + public function testShowType(string $slideshowType, bool $withAttribute): void + { + $this->oPresentation->getPresentationProperties()->setSlideshowType($slideshowType); + + $this->assertZipFileExists('content.xml'); + $element = '/office:document-content/office:body/office:presentation/presentation:settings'; + $this->assertZipXmlElementExists('content.xml', $element); + if ($withAttribute) { + $this->assertZipXmlAttributeExists('content.xml', $element, 'presentation:full-screen'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'presentation:full-screen', 'false'); + } else { + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'presentation:full-screen'); + } + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + /** + * @return array> + */ + public function dataProviderShowType(): array + { + return [ + [ + PresentationProperties::SLIDESHOW_TYPE_PRESENT, + false, + ], + [ + PresentationProperties::SLIDESHOW_TYPE_BROWSE, + true, + ], + [ + PresentationProperties::SLIDESHOW_TYPE_KIOSK, + false, + ], + ]; + } + + /** + * @dataProvider dataProviderLoopContinuouslyUntilEsc + */ + public function testLoopContinuouslyUntilEsc(bool $isLoopContinuouslyUntilEsc): void + { + $this->oPresentation->getPresentationProperties()->setLoopContinuouslyUntilEsc($isLoopContinuouslyUntilEsc); + + $this->assertZipFileExists('content.xml'); + $element = '/office:document-content/office:body/office:presentation/presentation:settings'; + $this->assertZipXmlElementExists('content.xml', $element); + if ($isLoopContinuouslyUntilEsc) { + $this->assertZipXmlAttributeExists('content.xml', $element, 'presentation:endless'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'presentation:endless', 'true'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'presentation:pause'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'presentation:pause', 'PT0S'); + $this->assertZipXmlAttributeExists('content.xml', $element, 'presentation:mouse-visible'); + $this->assertZipXmlAttributeEquals('content.xml', $element, 'presentation:mouse-visible', 'false'); + } else { + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'presentation:endless'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'presentation:pause'); + $this->assertZipXmlAttributeNotExists('content.xml', $element, 'presentation:mouse-visible'); + } + $this->assertIsSchemaOpenDocumentValid('1.2'); + } + + /** + * @return array> + */ + public function dataProviderLoopContinuouslyUntilEsc(): array + { + return [ + [ + true, + ], + [ + false, + ], + ]; } } diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaInfManifestTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaInfManifestTest.php index 99e0de277d..6019d6666e 100644 --- a/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaInfManifestTest.php +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaInfManifestTest.php @@ -1,51 +1,72 @@ oPresentation->getActiveSlide(); - $oShape = $oSlide->createDrawingShape(); - $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/PhpPresentationLogo.png'); + $oShape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); $element = '/manifest:manifest/manifest:file-entry[5]'; $this->assertZipXmlElementExists('META-INF/manifest.xml', $element); $this->assertZipXmlAttributeStartsWith('META-INF/manifest.xml', $element, 'manifest:full-path', 'Pictures/PhpPresentationLogo'); $this->assertZipXmlAttributeEndsWith('META-INF/manifest.xml', $element, 'manifest:full-path', '.png'); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage does not exist - */ - public function testDrawingException() + public function testDrawingException(): void { - $oSlide = $this->oPresentation->getActiveSlide(); - $oShape = $oSlide->createDrawingShape(); - $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/filedoesntexist.png', false); + $path = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/filedoesntexist.png'; + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage(sprintf( + 'The file "%s" doesn\'t exist', + $path + )); + + $oShape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $oShape->setPath($path, false); $this->writePresentationFile($this->oPresentation, 'ODPresentation'); } - - public function testMemoryDrawing() + + public function testMemoryDrawing(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = new Drawing\Gd(); - + $gdImage = @imagecreatetruecolor(140, 20); $textColor = imagecolorallocate($gdImage, 255, 255, 255); imagestring($gdImage, 1, 5, 5, 'Created with PhpPresentation', $textColor); @@ -55,42 +76,42 @@ public function testMemoryDrawing() $element = '/manifest:manifest/manifest:file-entry[5]'; $this->assertZipXmlElementExists('META-INF/manifest.xml', $element); $this->assertZipXmlAttributeEquals('META-INF/manifest.xml', $element, 'manifest:full-path', 'Pictures/' . $oShape->getIndexedFilename()); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - /** - * @requires PHP 5.4 - */ - public function testDrawingZip() + public function testDrawingZip(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = new Drawing\ZipFile(); - $oShape->setPath('zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'Sample_01_Simple.pptx#ppt/media/phppowerpoint_logo1.gif', false); + $oShape->setPath('zip://' . PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'Sample_01_Simple.pptx#ppt/media/phppowerpoint_logo1.gif'); $oSlide->addShape($oShape); $element = '/manifest:manifest/manifest:file-entry[5]'; $this->assertZipXmlElementExists('META-INF/manifest.xml', $element); $this->assertZipXmlAttributeEquals('META-INF/manifest.xml', $element, 'manifest:full-path', 'Pictures/' . $oShape->getIndexedFilename()); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - /** - * @expectedException \Exception - * @expectedExceptionMessage does not exist - * @requires PHP 5.4 - */ - public function testDrawingZipException() + public function testDrawingZipException(): void { + $path = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'filedoesntexist.zip'; + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage(sprintf( + 'The file "%s" doesn\'t exist', + $path + )); + $oShape = new Drawing\ZipFile(); - $oShape->setPath('zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'filedoesntexist.zip', false); + $oShape->setPath('zip://' . $path); $this->oPresentation->getActiveSlide()->addShape($oShape); $this->writePresentationFile($this->oPresentation, 'ODPresentation'); } - /** - * @requires PHP 5.4 - */ - public function testDrawingBase64() + public function testDrawingBase64(): void { $oShape = new Drawing\Base64(); $oShape->setData('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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'); @@ -99,16 +120,19 @@ public function testDrawingBase64() $element = '/manifest:manifest/manifest:file-entry[5]'; $this->assertZipXmlElementExists('META-INF/manifest.xml', $element); $this->assertZipXmlAttributeEquals('META-INF/manifest.xml', $element, 'manifest:full-path', 'Pictures/' . $oShape->getIndexedFilename()); + // Invalid because `draw:image` has attribute `loext:mime-type` + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testSlideBackground() + public function testSlideBackground(): void { $oBkgImage = new Image(); - $oBkgImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/PhpPresentationLogo.png'); + $oBkgImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); $this->oPresentation->getActiveSlide()->setBackground($oBkgImage); $element = '/manifest:manifest/manifest:file-entry[5]'; $this->assertZipXmlElementExists('META-INF/manifest.xml', $element); - $this->assertZipXmlAttributeEquals('META-INF/manifest.xml', $element, 'manifest:full-path', 'Pictures/' . str_replace(' ', '_', $oBkgImage->getIndexedFilename(0))); + $this->assertZipXmlAttributeEquals('META-INF/manifest.xml', $element, 'manifest:full-path', 'Pictures/' . str_replace(' ', '_', $oBkgImage->getIndexedFilename((string) 0))); + $this->assertIsSchemaOpenDocumentValid('1.2'); } } diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaTest.php new file mode 100644 index 0000000000..a6a142e699 --- /dev/null +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/MetaTest.php @@ -0,0 +1,98 @@ +oPresentation->getDocumentProperties()->setCustomProperty('pName', $propertyValue, $propertyType); + + $this->assertZipXmlElementExists('meta.xml', '/office:document-meta'); + $this->assertZipXmlElementExists('meta.xml', '/office:document-meta/office:meta'); + $this->assertZipXmlElementExists('meta.xml', '/office:document-meta/office:meta/meta:user-defined'); + $this->assertZipXmlElementEquals('meta.xml', '/office:document-meta/office:meta/meta:user-defined', $expectedValue); + $this->assertZipXmlAttributeExists('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:name'); + $this->assertZipXmlAttributeEquals('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:name', 'pName'); + $this->assertZipXmlAttributeExists('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:value-type'); + $this->assertZipXmlAttributeEquals('meta.xml', '/office:document-meta/office:meta/meta:user-defined', 'meta:value-type', $expectedValueType); + } + + /** + * @return array> + */ + public function dataProviderCustomProperties(): array + { + $valueTime = time(); + + return [ + [ + false, + null, + 'false', + 'boolean', + ], + [ + $valueTime, + DocumentProperties::PROPERTY_TYPE_DATE, + date(DATE_W3C, $valueTime), + 'date', + ], + [ + 2.1, + null, + '2.1', + 'float', + ], + [ + 2, + null, + '2', + 'float', + ], + [ + null, + null, + '', + 'string', + ], + [ + (string) $valueTime, + DocumentProperties::PROPERTY_TYPE_UNKNOWN, + (string) $valueTime, + 'string', + ], + ]; + } +} diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php index ab159f7817..59e668c8ae 100644 --- a/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php @@ -1,37 +1,70 @@ + */ + protected $seriesData = [ + 'A' => '1', + 'B' => '2', + 'C' => '4', + 'D' => '3', + 'E' => '2', + ]; + + public function testAxisFont(): void { $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', $this->seriesData); $oBar = new Bar(); $oBar->addSeries($oSeries); $oShape->getPlotArea()->setType($oBar); @@ -61,19 +94,154 @@ public function testAxisFont() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'fo:font-style', 'normal'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'fo:font-size', '16pt'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'fo:font-family', 'Arial'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testAxisTitleRotation(): void + { + $oSeries = new Series('Series', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipFileExists('Object 1/content.xml'); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisXTitle\']/style:chart-properties'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'style:rotation-angle'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $value = rand(1, 360); + $oShape->getPlotArea()->getAxisX()->setTitleRotation($value); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisXTitle\']/style:chart-properties'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'style:rotation-angle'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'style:rotation-angle', '-' . $value); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testLegend() + public function testAxisVisibility(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', $this->seriesData); + + $oBar = new Bar(); + $oBar->addSeries($oSeries); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oBar); + $oShape->getPlotArea()->getAxisX()->setTitle('Axis X'); + $oShape->getPlotArea()->getAxisY()->setTitle('Axis Y'); + + $oShape->getPlotArea()->getAxisX()->setIsVisible(false); + $oShape->getPlotArea()->getAxisY()->setIsVisible(false); + + $this->assertZipFileExists('Object 1/content.xml'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'x\']/chart:title'; + + $this->assertZipXmlElementNotExists('Object 1/content.xml', $element); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'y\']/chart:title'; + + $this->assertZipXmlElementNotExists('Object 1/content.xml', $element); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oShape->getPlotArea()->getAxisX()->setIsVisible(true); + $oShape->getPlotArea()->getAxisY()->setIsVisible(true); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'x\']/chart:title'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:style-name', 'styleAxisXTitle'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'x\']/chart:title/text:p'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlElementEquals('Object 1/content.xml', $element, 'Axis X'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'y\']/chart:title'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:style-name', 'styleAxisYTitle'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'y\']/chart:title/text:p'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlElementEquals('Object 1/content.xml', $element, 'Axis Y'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testChartDisplayBlankAs(): void + { + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + $oShape->setDisplayBlankAs(Chart::BLANKAS_ZERO); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:treat-empty-cells'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:treat-empty-cells', 'use-zero'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oShape->setDisplayBlankAs(Chart::BLANKAS_SPAN); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:treat-empty-cells'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:treat-empty-cells', 'ignore'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oShape->setDisplayBlankAs(Chart::BLANKAS_GAP); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:treat-empty-cells'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:treat-empty-cells', 'leave-gap'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testLegend(): void + { + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oLine = new Line(); $oLine->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oLine); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleLegend\']/style:chart-properties'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:auto-position', 'true'); $element = '/office:document-content/office:body/office:chart/chart:chart/chart:legend'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:legend-position', 'end'); $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-header-rows'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-header-rows/table:table-row'; @@ -82,9 +250,183 @@ public function testLegend() $this->assertZipXmlElementExists('Object 1/content.xml', $element); $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-header-rows/table:table-row/table:table-cell[@office:value-type=\'string\']'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oChart->getLegend()->setPosition(Legend::POSITION_RIGHT); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:legend'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:legend-position', 'end'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oChart->getLegend()->setPosition(Legend::POSITION_LEFT); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:legend'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:legend-position', 'start'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oChart->getLegend()->setPosition(Legend::POSITION_BOTTOM); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:legend'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:legend-position', 'bottom'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oChart->getLegend()->setPosition(Legend::POSITION_TOP); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:legend'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:legend-position', 'top'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oChart->getLegend()->setPosition(Legend::POSITION_TOPRIGHT); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:legend'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:legend-position', 'top-end'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testSeriesValues(): void + { + $series = new Series('Series', ['Jan' => null]); + + $pie = new Pie(); + $pie->addSeries($series); + + $chart = $this->oPresentation->getActiveSlide()->createChartShape(); + $chart->getPlotArea()->setType($pie); + + $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-rows/table:table-row/table:table-cell[2]'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'office:value-type'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'office:value-type', 'float'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'office:value'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'office:value', 'NaN'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-rows/table:table-row/table:table-cell[2]/text:p'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlElementEquals('Object 1/content.xml', $element, 'NaN'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + + $series = new Series('Series', ['Jan' => '12.3']); + $chart->getPlotArea()->getType()->setSeries([$series]); + + $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-rows/table:table-row/table:table-cell[2]'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'office:value-type'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'office:value-type', 'float'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'office:value'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'office:value', '12.3'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-rows/table:table-row/table:table-cell[2]/text:p'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlElementEquals('Object 1/content.xml', $element, '12.3'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + + $series = new Series('Series', ['Jan' => 'data']); + $chart->getPlotArea()->getType()->setSeries([$series]); + + $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-rows/table:table-row/table:table-cell[2]'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'office:value-type'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'office:value-type', 'string'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'office:value'); + + $element = '/office:document-content/office:body/office:chart/chart:chart/table:table/table:table-rows/table:table-row/table:table-cell[2]/text:p'; + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlElementEquals('Object 1/content.xml', $element, 'data'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTitleVisibility() + public function testSeriesShowConfig(): void + { + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); + $oPie = new Pie(); + $oPie->addSeries($oSeries); + $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); + $oChart->getPlotArea()->setType($oPie); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\']/style:chart-properties'; + + // $showCategoryName = false / $showPercentage = false / $showValue = true + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-number'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'value'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $oSeries->setShowValue(false); + $this->resetPresentationFile(); + + // $showCategoryName = false / $showPercentage = false / $showValue = false + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-number'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + // $showCategoryName = false / $showPercentage = true / $showValue = true + $oSeries->setShowValue(true); + $oSeries->setShowPercentage(true); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-number'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'value-and-percentage'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + // $showCategoryName = false / $showPercentage = true / $showValue = false + $oSeries->setShowValue(false); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-number'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'percentage'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + // $showCategoryName = false / $showPercentage = true / $showValue = false + $oSeries->setShowCategoryName(true); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-text'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-text', 'true'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTitleVisibility(): void { $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oLine = new Line(); @@ -98,15 +440,21 @@ public function testTitleVisibility() $this->assertZipXmlElementExists('Object 1/content.xml', $elementTitle); $this->assertZipXmlElementExists('Object 1/content.xml', $elementStyle); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\Chart\Title', $oShape->getTitle()->setVisible(false)); $this->resetPresentationFile(); $this->assertZipXmlElementNotExists('Object 1/content.xml', $elementTitle); $this->assertZipXmlElementNotExists('Object 1/content.xml', $elementStyle); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeArea() + public function testTypeArea(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->getFill()->setStartColor(new Color('FF93A9CE')); $oArea = new Area(); $oArea->addSeries($oSeries); @@ -119,21 +467,22 @@ public function testTypeArea() $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:series'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:area'); $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\']/style:graphic-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'draw:fill'); $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'draw:fill-color'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'draw:fill-color', '#93A9CE'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeAxisBounds() + public function testTypeAxisBounds(): void { - $value = rand(0, 100); + $value = mt_rand(0, 100); - $oSeries = new Series('Downloads', array('A' => 1, 'B' => 2, 'C' => 4, 'D' => 3, 'E' => 2)); - $oSeries->getFill()->setStartColor(new Color('FFAABBCC')); + $oSeries = new Series('Downloads', $this->seriesData); $oLine = new Line(); $oLine->addSeries($oSeries); $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); @@ -144,6 +493,9 @@ public function testTypeAxisBounds() $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:minimum'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:maximum'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oShape->getPlotArea()->getAxisX()->setMinBounds($value); $this->resetPresentationFile(); @@ -151,6 +503,9 @@ public function testTypeAxisBounds() $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:minimum'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:minimum', $value); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oShape->getPlotArea()->getAxisX()->setMinBounds(null); $oShape->getPlotArea()->getAxisX()->setMaxBounds($value); $this->resetPresentationFile(); @@ -159,6 +514,9 @@ public function testTypeAxisBounds() $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:maximum'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:maximum', $value); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oShape->getPlotArea()->getAxisX()->setMinBounds($value); $oShape->getPlotArea()->getAxisX()->setMaxBounds($value); $this->resetPresentationFile(); @@ -167,11 +525,146 @@ public function testTypeAxisBounds() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:minimum', $value); $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:maximum'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:maximum', $value); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeBar() + public function testTypeAxisOutline(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisX\']/style:graphic-properties'; + + $series = new Series('Series', $this->seriesData); + $lineChart = new Line(); + $lineChart->addSeries($series); + $shape = $this->oPresentation->getActiveSlide()->createChartShape(); + $shape->getPlotArea()->setType($lineChart); + + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'draw:stroke'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'draw:stroke', 'none'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'svg:stroke-width'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-width', '0.035cm'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'svg:stroke-color'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-color', '#000000'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $shape->getPlotArea()->getAxisX()->getOutline()->setWidth(10); + $shape->getPlotArea()->getAxisX()->getOutline()->getFill()->setFillType(Fill::FILL_SOLID); + $shape->getPlotArea()->getAxisX()->getOutline()->getFill()->getStartColor()->setRGB('ABCDEF'); + + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'draw:stroke'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'draw:stroke', 'solid'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'svg:stroke-width'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-width', '0.353cm'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'svg:stroke-color'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-color', '#ABCDEF'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypeAxisTickLabelPosition(): void + { + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisX\']/style:chart-properties'; + + $oSeries = new Series('Series', $this->seriesData); + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:axis-label-position'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:axis-label-position', 'near-axis'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:axis-position'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:tick-mark-position'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oShape->getPlotArea()->getAxisX()->setTickLabelPosition(Axis::TICK_LABEL_POSITION_HIGH); + + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:axis-label-position'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:axis-label-position', 'outside-end'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:axis-position'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:axis-position', '0'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:tick-mark-position'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oShape->getPlotArea()->getAxisX()->setTickLabelPosition(Axis::TICK_LABEL_POSITION_LOW); + + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:axis-label-position'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:axis-label-position', 'outside-start'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:axis-position'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:axis-position', '0'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:tick-mark-position'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:tick-mark-position', 'at-axis'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypeAxisUnit(): void + { + $value = mt_rand(0, 100); + + $series = new Series('Downloads', $this->seriesData); + $line = new Line(); + $line->addSeries($series); + $shape = $this->oPresentation->getActiveSlide()->createChartShape(); + $shape->getPlotArea()->setType($line); + + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisX\']/style:chart-properties'; + + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interval-minor-divisor'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interval-major'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $shape->getPlotArea()->getAxisX()->setMinorUnit($value); + $this->resetPresentationFile(); + + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interval-major'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interval-minor-divisor'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interval-minor-divisor', $value); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $shape->getPlotArea()->getAxisX()->setMinorUnit(null); + $shape->getPlotArea()->getAxisX()->setMajorUnit($value); + $this->resetPresentationFile(); + + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interval-minor-divisor'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interval-major'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interval-major', $value); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $shape->getPlotArea()->getAxisX()->setMinorUnit($value); + $shape->getPlotArea()->getAxisX()->setMajorUnit($value); + $this->resetPresentationFile(); + + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interval-minor-divisor'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interval-minor-divisor', $value); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interval-major'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interval-major', $value); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypeBar(): void + { + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4672A8')); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFAB4744')); @@ -197,12 +690,15 @@ public function testTypeBar() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:overlap', '0'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:percentage'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'value'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeBarGroupingStacked() + public function testTypeBarGroupingStacked(): void { $oBar = new Bar(); - $oBar->addSeries(new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2))); + $oBar->addSeries(new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2'])); $oBar->setBarGrouping(Bar::GROUPING_STACKED); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oBar); @@ -213,12 +709,15 @@ public function testTypeBarGroupingStacked() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:overlap', '100'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:percentage'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'value'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeBarGroupingPercentStacked() + public function testTypeBarGroupingPercentStacked(): void { $oBar = new Bar(); - $oBar->addSeries(new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2))); + $oBar->addSeries(new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2'])); $oBar->setBarGrouping(Bar::GROUPING_PERCENTSTACKED); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oBar); @@ -229,11 +728,14 @@ public function testTypeBarGroupingPercentStacked() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:overlap', '100'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:percentage', 'true'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'percentage'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeBarHorizontal() + public function testTypeBarHorizontal(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4672A8')); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFAB4744')); @@ -253,11 +755,14 @@ public function testTypeBarHorizontal() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:vertical', 'true'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:three-dimensional'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:right-angled-axes'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeBar3D() + public function testTypeBar3D(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4672A8')); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFAB4744')); @@ -266,14 +771,14 @@ public function testTypeBar3D() $oBar3D->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oBar3D); - + $element = '/office:document-content/office:body/office:chart/chart:chart'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:bar'); - + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:series/chart:data-point'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:vertical', 'false'); @@ -281,11 +786,14 @@ public function testTypeBar3D() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:three-dimensional', 'true'); $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:right-angled-axes'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:right-angled-axes', 'true'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeBar3DHorizontal() + public function testTypeBar3DHorizontal(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4672A8')); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFAB4744')); @@ -295,11 +803,11 @@ public function testTypeBar3DHorizontal() $oBar3D->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oBar3D); - + $element = '/office:document-content/office:body/office:chart/chart:chart'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:bar'); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:vertical', 'true'); @@ -307,17 +815,59 @@ public function testTypeBar3DHorizontal() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:three-dimensional', 'true'); $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:right-angled-axes'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:right-angled-axes', 'true'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testTypeLine() + + public function testTypeDoughnut(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + // $randHoleSize = mt_rand(10, 90); + $randSeparator = chr(mt_rand(ord('A'), ord('Z'))); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oDoughnut = new Doughnut(); + $oSeries = new Series('Downloads', $this->seriesData); + $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); + $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKBLUE)); + $oSeries->getDataPointFill(2)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKGREEN)); + $oSeries->getDataPointFill(3)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKRED)); + $oSeries->getDataPointFill(4)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKYELLOW)); + $oDoughnut->addSeries($oSeries); + $oShape->getPlotArea()->setType($oDoughnut); + + $element = '/office:document-content/office:body/office:chart/chart:chart'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:ring'); + $element = '/office:document-content/office:automatic-styles/style:style/style:chart-properties/chart:label-separator/text:p'; + $this->assertZipXmlElementNotExists('Object 1/content.xml', $element); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + // $oDoughnut->setHoleSize($randHoleSize); + // $this->resetPresentationFile(); + + $oSeries->setSeparator($randSeparator); + $this->resetPresentationFile(); + + $element = '/office:document-content/office:automatic-styles/style:style/style:chart-properties/chart:label-separator/text:p'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlElementEquals('Object 1/content.xml', $element, $randSeparator); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypeLine(): void + { + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oLine = new Line(); $oLine->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oLine); - + $element = '/office:document-content/office:body/office:chart/chart:chart'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:line'); @@ -329,9 +879,8 @@ public function testTypeLine() $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisX\']/style:graphic-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-width', '0.026cm'); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-color', '#878787'); - + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-width', '0.035cm'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-color', '#000000'); $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisY\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); @@ -340,62 +889,59 @@ public function testTypeLine() $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisY\']/style:graphic-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-width', '0.026cm'); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-color', '#878787'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-width', '0.035cm'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'svg:stroke-color', '#000000'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeLineGridlines() + public function testTypeLineGridlines(): void { - $arrayTests = array( - array( + $arrayTests = [ + [ 'dimension' => 'x', 'styleName' => 'styleAxisXGridlinesMajor', 'styleClass' => 'major', 'methodAxis' => 'getAxisX', - 'methodGrid' => 'setMajorGridlines' - ), - array( + 'methodGrid' => 'setMajorGridlines', + ], + [ 'dimension' => 'x', 'styleName' => 'styleAxisXGridlinesMinor', 'styleClass' => 'minor', 'methodAxis' => 'getAxisX', - 'methodGrid' => 'setMinorGridlines' - ), - array( + 'methodGrid' => 'setMinorGridlines', + ], + [ 'dimension' => 'y', 'styleName' => 'styleAxisYGridlinesMajor', 'styleClass' => 'major', 'methodAxis' => 'getAxisY', - 'methodGrid' => 'setMajorGridlines' - ), - array( + 'methodGrid' => 'setMajorGridlines', + ], + [ 'dimension' => 'y', 'styleName' => 'styleAxisYGridlinesMinor', 'styleClass' => 'minor', 'methodAxis' => 'getAxisY', - 'methodGrid' => 'setMinorGridlines' - ), - ); + 'methodGrid' => 'setMinorGridlines', + ], + ]; $expectedColor = new Color(Color::COLOR_BLUE); foreach ($arrayTests as $arrayTest) { $this->resetPresentationFile(); $this->oPresentation->removeSlideByIndex(0)->createSlide(); - $expectedSizePts = rand(1, 100); - $expectedSizeCm = number_format(CommonDrawing::pointsToCentimeters($expectedSizePts), 2, '.', '').'cm'; - $expectedElementGrid = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\''.$arrayTest['dimension'].'\']/chart:grid'; - $expectedElementStyle = '/office:document-content/office:automatic-styles/style:style[@style:name=\''.$arrayTest['styleName'].'\']/style:graphic-properties'; + $expectedSizePts = mt_rand(1, 100); + $expectedSizeCm = number_format(CommonDrawing::pointsToCentimeters($expectedSizePts), 2, '.', '') . 'cm'; + $expectedElementGrid = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:axis[@chart:dimension=\'' . $arrayTest['dimension'] . '\']/chart:grid'; + $expectedElementStyle = '/office:document-content/office:automatic-styles/style:style[@style:name=\'' . $arrayTest['styleName'] . '\']/style:graphic-properties'; $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oLine = new Line(); - $oLine->addSeries(new Series('Downloads', array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - ))); + $oLine->addSeries(new Series('Downloads', $this->seriesData)); $oShape->getPlotArea()->setType($oLine); $oGridlines = new Gridlines(); $oGridlines->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor($expectedColor); @@ -414,10 +960,13 @@ public function testTypeLineGridlines() $this->assertZipXmlAttributeEndsWith('Object 1/content.xml', $expectedElementStyle, 'svg:stroke-width', 'cm'); $this->assertZipXmlAttributeStartsWith('Object 1/content.xml', $expectedElementStyle, 'svg:stroke-color', '#'); $this->assertZipXmlAttributeEndsWith('Object 1/content.xml', $expectedElementStyle, 'svg:stroke-color', $expectedColor->getRGB()); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } } - public function testTypeLineMarker() + public function testTypeLineMarker(): void { $expectedSymbol1 = Marker::SYMBOL_PLUS; $expectedSymbol2 = Marker::SYMBOL_DASH; @@ -426,18 +975,12 @@ public function testTypeLineMarker() $expectedSymbol5 = Marker::SYMBOL_NONE; $expectedElement = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\'][@style:family=\'chart\']/style:chart-properties'; - $expectedSize = rand(1, 100); - $expectedSizeCm = number_format(CommonDrawing::pointsToCentimeters($expectedSize), 2, '.', '').'cm'; + $expectedSize = mt_rand(1, 100); + $expectedSizeCm = number_format(CommonDrawing::pointsToCentimeters($expectedSize), 2, '.', '') . 'cm'; $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oLine = new Line(); - $oSeries = new Series('Downloads', array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - )); + $oSeries = new Series('Downloads', $this->seriesData); $oSeries->getMarker()->setSymbol($expectedSymbol1)->setSize($expectedSize); $oLine->addSeries($oSeries); $oShape->getPlotArea()->setType($oLine); @@ -448,37 +991,52 @@ public function testTypeLineMarker() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-width', $expectedSizeCm); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-height', $expectedSizeCm); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol2); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-name', 'horizontal-bar'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol3); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-name', 'circle'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol4); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-name', 'arrow-up'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol5); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $expectedElement, 'chart:symbol-name'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $expectedElement, 'chart:symbol-width'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $expectedElement, 'chart:symbol-height'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeLineSeriesOutline() + public function testTypeLineSeriesOutline(): void { - $expectedWidth = rand(1, 100); - $expectedWidthCm = number_format(CommonDrawing::pointsToCentimeters($expectedWidth), 3, '.', '').'cm'; + $expectedWidth = mt_rand(1, 100); + $expectedWidthCm = number_format(CommonDrawing::pointsToCentimeters($expectedWidth), 3, '.', '') . 'cm'; $expectedElement = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\'][@style:family=\'chart\']/style:graphic-properties'; @@ -491,13 +1049,7 @@ public function testTypeLineSeriesOutline() $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); $oLine = new Line(); - $oSeries = new Series('Downloads', array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - )); + $oSeries = new Series('Downloads', $this->seriesData); $oLine->addSeries($oSeries); $oShape->getPlotArea()->setType($oLine); @@ -507,9 +1059,11 @@ public function testTypeLineSeriesOutline() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-width', '0.079cm'); $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-color'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-color', '#4a7ebb'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); $oSeries->setOutline($oOutline); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipFileExists('Object 1/content.xml'); @@ -518,11 +1072,44 @@ public function testTypeLineSeriesOutline() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-width', $expectedWidthCm); $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-color'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-color', '#' . $oColor->getRGB()); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testTypePie() + + public function testTypeLineSmooth(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oLine->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interpolation'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oLine->setIsSmooth(true); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interpolation'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interpolation', 'cubic-spline'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypePie(): void + { + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4672A8')); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFAB4744')); @@ -531,26 +1118,29 @@ public function testTypePie() $oPie->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oPie); - + $element = '/office:document-content/office:body/office:chart/chart:chart'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:circle'); - + $element = '/office:document-content/office:body/office:chart/chart:chart/chart:plot-area/chart:series/chart:data-point'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisX\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:reverse-direction', 'true'); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisY\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:reverse-direction', 'true'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypePie3D() + public function testTypePie3D(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FF4672A8')); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFAB4744')); @@ -574,40 +1164,117 @@ public function testTypePie3D() $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisY\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:reverse-direction', 'true'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testTypePie3DExplosion() + + public function testTypePie3DExplosion(): void { - $value = rand(0, 100); - - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $value = mt_rand(0, 100); + + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oPie3D = new Pie3D(); $oPie3D->setExplosion($value); $oPie3D->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oPie3D); - + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\'][@style:family=\'chart\']/style:chart-properties'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:pie-offset', $value); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypeRadar(): void + { + $series = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); + $series->setShowSeriesName(true); + + $radarChart = new Radar(); + $radarChart->addSeries($series); + + $chart = $this->oPresentation->getActiveSlide()->createChartShape(); + $chart->getPlotArea()->setType($radarChart); + + $element = '/office:document-content/office:body/office:chart/chart:chart'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:class'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:radar'); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisX\']/style:chart-properties'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:reverse-direction'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:reverse-direction', 'true'); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleAxisY\']/style:chart-properties'; + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:reverse-direction'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + + public function testTypeRadarSeriesOutline(): void + { + $expectedWidth = mt_rand(1, 100); + $expectedWidthCm = number_format(CommonDrawing::pointsToCentimeters($expectedWidth), 3, '.', '') . 'cm'; + + $expectedElement = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\'][@style:family=\'chart\']/style:graphic-properties'; + + $color = new Color(Color::COLOR_YELLOW); + + $outline = new Outline(); + $outline->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor($color); + $outline->setWidth($expectedWidth); // (in points) + + $series = new Series('Downloads', $this->seriesData); + + $radarChart = new Radar(); + $radarChart->addSeries($series); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($radarChart); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $expectedElement); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-width'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-width', '0.079cm'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-color'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-color', '#4a7ebb'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $series->setOutline($outline); + $radarChart->setSeries([$series]); + $this->resetPresentationFile(); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $expectedElement); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-width'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-width', $expectedWidthCm); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-color'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-color', '#' . $color->getRGB()); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testTypeScatter() + + public function testTypeScatter(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); + $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); $oSeries->setShowSeriesName(true); $oScatter = new Scatter(); $oScatter->addSeries($oSeries); $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); $oChart->getPlotArea()->setType($oScatter); - + $element = '/office:document-content/office:body/office:chart/chart:chart'; $this->assertZipXmlElementExists('Object 1/content.xml', $element); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:class', 'chart:scatter'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeScatterMarker() + public function testTypeScatterMarker(): void { $expectedSymbol1 = Marker::SYMBOL_PLUS; $expectedSymbol2 = Marker::SYMBOL_DASH; @@ -615,18 +1282,12 @@ public function testTypeScatterMarker() $expectedSymbol4 = Marker::SYMBOL_TRIANGLE; $expectedSymbol5 = Marker::SYMBOL_NONE; $expectedElement = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\'][@style:family=\'chart\']/style:chart-properties'; - $expectedSize = rand(1, 100); - $expectedSizeCm = number_format(CommonDrawing::pointsToCentimeters($expectedSize), 2, '.', '').'cm'; + $expectedSize = mt_rand(1, 100); + $expectedSizeCm = number_format(CommonDrawing::pointsToCentimeters($expectedSize), 2, '.', '') . 'cm'; $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oScatter = new Scatter(); - $oSeries = new Series('Downloads', array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - )); + $oSeries = new Series('Downloads', $this->seriesData); $oSeries->getMarker()->setSymbol($expectedSymbol1)->setSize($expectedSize); $oScatter->addSeries($oSeries); $oShape->getPlotArea()->setType($oScatter); @@ -637,37 +1298,52 @@ public function testTypeScatterMarker() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-width', $expectedSizeCm); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-height', $expectedSizeCm); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol2); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-name', 'horizontal-bar'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol3); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-name', 'circle'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol4); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'chart:symbol-name', 'arrow-up'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + $oSeries->getMarker()->setSymbol($expectedSymbol5); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $expectedElement, 'chart:symbol-name'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $expectedElement, 'chart:symbol-width'); $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $expectedElement, 'chart:symbol-height'); + + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testTypeScatterSeriesOutline() + public function testTypeScatterSeriesOutline(): void { - $expectedWidth = rand(1, 100); - $expectedWidthCm = number_format(CommonDrawing::pointsToCentimeters($expectedWidth), 3, '.', '').'cm'; + $expectedWidth = mt_rand(1, 100); + $expectedWidthCm = number_format(CommonDrawing::pointsToCentimeters($expectedWidth), 3, '.', '') . 'cm'; $expectedElement = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\'][@style:family=\'chart\']/style:graphic-properties'; @@ -679,13 +1355,7 @@ public function testTypeScatterSeriesOutline() $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); $oScatter = new Scatter(); - $oSeries = new Series('Downloads', array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - )); + $oSeries = new Series('Downloads', $this->seriesData); $oScatter->addSeries($oSeries); $oShape->getPlotArea()->setType($oScatter); @@ -695,9 +1365,11 @@ public function testTypeScatterSeriesOutline() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-width', '0.079cm'); $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-color'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-color', '#4a7ebb'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); $oSeries->setOutline($oOutline); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipFileExists('Object 1/content.xml'); @@ -706,57 +1378,38 @@ public function testTypeScatterSeriesOutline() $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-width', $expectedWidthCm); $this->assertZipXmlAttributeExists('Object 1/content.xml', $expectedElement, 'svg:stroke-color'); $this->assertZipXmlAttributeEquals('Object 1/content.xml', $expectedElement, 'svg:stroke-color', '#' . $oColor->getRGB()); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - public function testSeries() + public function testTypeScatterSmooth(): void { - $oSeries = new Series('Series', array('Jan' => 1, 'Feb' => 5, 'Mar' => 2)); - $oPie = new Pie(); - $oPie->addSeries($oSeries); - $oChart = $this->oPresentation->getActiveSlide()->createChartShape(); - $oChart->getPlotArea()->setType($oPie); - - $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'styleSeries0\']/style:chart-properties'; - - // $showCategoryName = false / $showPercentage = false / $showValue = true - $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-number'); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'value'); - $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); - - $oSeries->setShowValue(false); - $this->resetPresentationFile(); - - // $showCategoryName = false / $showPercentage = false / $showValue = false - $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-number'); - $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; - // $showCategoryName = false / $showPercentage = true / $showValue = true - $oSeries->setShowValue(true); - $oSeries->setShowPercentage(true); - $this->resetPresentationFile(); + $oSeries = new Series('Downloads', $this->seriesData); - $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-number'); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'value-and-percentage'); - $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + $scatter = new Scatter(); + $scatter->addSeries($oSeries); + $scatter->setIsSmooth(false); - // $showCategoryName = false / $showPercentage = true / $showValue = false - $oSeries->setShowValue(false); - $this->resetPresentationFile(); + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($scatter); + $this->assertZipFileExists('Object 1/content.xml'); $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-number'); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-number', 'percentage'); - $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:data-label-text'); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interpolation'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); - // $showCategoryName = false / $showPercentage = true / $showValue = false - $oSeries->setShowCategoryName(true); $this->resetPresentationFile(); + $scatter->setIsSmooth(true); + $oShape->getPlotArea()->setType($scatter); + $this->assertZipFileExists('Object 1/content.xml'); $this->assertZipXmlElementExists('Object 1/content.xml', $element); - $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:data-label-text'); - $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:data-label-text', 'true'); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interpolation'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interpolation', 'cubic-spline'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } } diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/StylesTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/StylesTest.php index 1d013fef5c..523087adfd 100644 --- a/tests/PhpPresentation/Tests/Writer/ODPresentation/StylesTest.php +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/StylesTest.php @@ -1,4 +1,22 @@ setDocumentLayout(DocumentLayout::LAYOUT_A4, true); @@ -28,31 +45,35 @@ public function testDocumentLayout() $this->assertZipXmlElementExists('styles.xml', $element); $this->assertZipXmlAttributeEquals('styles.xml', $element, 'style:print-orientation', 'landscape'); - + $this->assertIsSchemaOpenDocumentValid('1.2'); + $oDocumentLayout->setDocumentLayout(DocumentLayout::LAYOUT_A4, false); $this->oPresentation->setLayout($oDocumentLayout); $this->resetPresentationFile(); $this->assertZipXmlElementExists('styles.xml', $element); $this->assertZipXmlAttributeEquals('styles.xml', $element, 'style:print-orientation', 'portrait'); + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testCustomDocumentLayout() + + public function testCustomDocumentLayout(): void { $oDocumentLayout = new DocumentLayout(); - $oDocumentLayout->setDocumentLayout(array('cx' => rand(1, 100),'cy' => rand(1, 100),)); + $oDocumentLayout->setDocumentLayout(['cx' => rand(1, 100), 'cy' => rand(1, 100)]); $this->oPresentation->setLayout($oDocumentLayout); - - $element = "/office:document-styles/office:automatic-styles/style:page-layout"; + + $element = '/office:document-styles/office:automatic-styles/style:page-layout'; $this->assertZipXmlElementExists('styles.xml', $element); $this->assertZipXmlAttributeEquals('styles.xml', $element, 'style:name', 'sPL0'); - - $element = "/office:document-styles/office:master-styles/style:master-page"; + + $element = '/office:document-styles/office:master-styles/style:master-page'; $this->assertZipXmlElementExists('styles.xml', $element); $this->assertZipXmlAttributeEquals('styles.xml', $element, 'style:page-layout-name', 'sPL0'); + + $this->assertIsSchemaOpenDocumentValid('1.2'); } - - public function testGradientTable() + + public function testGradientTable(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(); @@ -60,16 +81,18 @@ public function testGradientTable() $oCell = $oRow->getCell(); $oCell->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR)->setStartColor(new Color('FFFF7700'))->setEndColor(new Color('FFFFFFFF')); - $element = "/office:document-styles/office:styles/draw:gradient"; + $element = '/office:document-styles/office:styles/draw:gradient'; $this->assertZipXmlAttributeEquals('styles.xml', $element, 'draw:name', 'gradient_' . $oCell->getFill()->getHashCode()); + + $this->assertIsSchemaOpenDocumentNotValid('1.2'); } - - public function testStrokeDash() + + public function testStrokeDash(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText1 = $oSlide->createRichTextShape(); $oRichText1->getBorder()->setColor(new Color('FF4672A8'))->setLineStyle(Border::LINE_SINGLE); - $arrayDashStyle = array( + $arrayDashStyle = [ Border::DASH_DASH, Border::DASH_DASHDOT, Border::DASH_DOT, @@ -80,16 +103,16 @@ public function testStrokeDash() Border::DASH_SYSDASHDOT, Border::DASH_SYSDASHDOTDOT, Border::DASH_SYSDOT, - ); - + ]; + foreach ($arrayDashStyle as $style) { $oRichText1->getBorder()->setDashStyle($style); - $element = '/office:document-styles/office:styles/draw:stroke-dash[@draw:name=\'strokeDash_'.$style.'\']'; + $element = '/office:document-styles/office:styles/draw:stroke-dash[@draw:name=\'strokeDash_' . $style . '\']'; $this->assertZipXmlElementExists('styles.xml', $element); $this->assertZipXmlAttributeEquals('styles.xml', $element, 'draw:style', 'rect'); $this->assertZipXmlAttributeExists('styles.xml', $element, 'draw:distance'); - + switch ($style) { case Border::DASH_DOT: case Border::DASH_SYSDOT: @@ -113,6 +136,7 @@ public function testStrokeDash() $this->assertZipXmlAttributeExists('styles.xml', $element, 'draw:dots2-length'); break; } + $this->assertIsSchemaOpenDocumentValid('1.2'); $this->resetPresentationFile(); } } diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentationTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentationTest.php index 3cbcade42f..ba8724708d 100644 --- a/tests/PhpPresentation/Tests/Writer/ODPresentationTest.php +++ b/tests/PhpPresentation/Tests/Writer/ODPresentationTest.php @@ -1,26 +1,45 @@ oPresentation->getActiveSlide()->createDrawingShape(); $object = new ODPresentation($this->oPresentation); @@ -30,9 +49,9 @@ public function testConstruct() } /** - * Test save + * Test save. */ - public function testSave() + public function testSave(): void { $filename = tempnam(sys_get_temp_dir(), 'PhpPresentation'); $imageFile = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'; @@ -53,33 +72,21 @@ public function testSave() } /** - * Test get PhpPresentation exception - * - * @expectedException \Exception - * @expectedExceptionMessage Filename is empty + * Test get PhpPresentation exception. */ - public function testSaveEmpty() + public function testSaveEmpty(): void { - $object = new ODPresentation(); - $object->save(''); - } + $this->expectException(InvalidParameterException::class); + $this->expectExceptionMessage('The parameter pFilename can\'t have the value ""'); - /** - * Test get PhpPresentation exception - * - * @expectedException \Exception - * @expectedExceptionMessage No PhpPresentation assigned. - */ - public function testGetPhpPresentationException() - { $object = new ODPresentation(); - $object->getPhpPresentation(); + $object->save(''); } /** - * Test set/get disk caching + * Test set/get disk caching. */ - public function testSetGetUseDiskCaching() + public function testSetGetUseDiskCaching(): void { $object = new ODPresentation($this->oPresentation); $this->assertFalse($object->hasDiskCaching()); @@ -90,19 +97,19 @@ public function testSetGetUseDiskCaching() } /** - * Test set/get disk caching exception - * - * @expectedException \Exception + * Test set/get disk caching exception. */ - public function testSetUseDiskCachingException() + public function testSetUseDiskCachingException(): void { + $this->expectException(DirectoryNotFoundException::class); + $object = new ODPresentation($this->oPresentation); $object->setUseDiskCaching(true, 'foo'); } - public function testFeatureThumbnail() + public function testFeatureThumbnail(): void { - $imagePath = PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'; + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; $xPathManifest = '/manifest:manifest/manifest:file-entry[@manifest:media-type=\'image/png\'][@manifest:full-path=\'Thumbnails/thumbnail.png\']'; diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/CommentAuthorsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/CommentAuthorsTest.php index 453f0a97af..18552dbbc9 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/CommentAuthorsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/CommentAuthorsTest.php @@ -1,4 +1,22 @@ assertZipXmlAttributeEquals('ppt/commentAuthors.xml', $expectedElement, 'id', 0); $this->assertZipXmlAttributeEquals('ppt/commentAuthors.xml', $expectedElement, 'name', $expectedName); $this->assertZipXmlAttributeEquals('ppt/commentAuthors.xml', $expectedElement, 'initials', $expectedInitials); + $this->assertIsSchemaECMA376Valid(); } - public function testWithoutComment() + public function testWithoutComment(): void { $this->assertZipFileNotExists('ppt/commentAuthors.xml'); + $this->assertIsSchemaECMA376Valid(); } - public function testWithoutCommentAuthor() + public function testWithoutCommentAuthor(): void { $oComment = new Comment(); $this->oPresentation->getActiveSlide()->addShape($oComment); $this->assertZipFileNotExists('ppt/commentAuthors.xml'); + $this->assertIsSchemaECMA376Valid(); } - public function testWithSameAuthor() + public function testWithSameAuthor(): void { $expectedElement = '/p:cmAuthorLst/p:cmAuthor'; @@ -58,5 +79,6 @@ public function testWithSameAuthor() $this->assertZipFileExists('ppt/commentAuthors.xml'); $this->assertZipXmlElementExists('ppt/commentAuthors.xml', $expectedElement); $this->assertZipXmlElementCount('ppt/commentAuthors.xml', $expectedElement, 1); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsAppTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsAppTest.php index e8019c551a..fc9ba5aefa 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsAppTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsAppTest.php @@ -1,11 +1,23 @@ assertZipFileExists('docProps/app.xml'); + $this->assertIsSchemaECMA376Valid(); } - public function testCompany() + public function testCompany(): void { $expected = 'aAbBcDeE'; @@ -28,5 +41,6 @@ public function testCompany() $this->assertZipFileExists('docProps/app.xml'); $this->assertZipXmlElementExists('docProps/app.xml', '/Properties/Company'); $this->assertZipXmlElementEquals('docProps/app.xml', '/Properties/Company', $expected); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php index 2c3fb61126..2f7f87732c 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php @@ -1,4 +1,22 @@ assertZipFileExists('docProps/core.xml'); $this->assertZipXmlElementNotExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); + $this->assertIsSchemaECMA376Valid(); } - public function testDocumentProperties() + public function testDocumentProperties(): void { $expected = 'aAbBcDeE'; @@ -39,20 +58,23 @@ public function testDocumentProperties() $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:keywords', $expected); $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/cp:category'); $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:category', $expected); + $this->assertIsSchemaECMA376Valid(); } - public function testMarkAsFinalTrue() + public function testMarkAsFinalTrue(): void { $this->oPresentation->getPresentationProperties()->markAsFinal(true); $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:contentStatus', 'Final'); + $this->assertIsSchemaECMA376Valid(); } - public function testMarkAsFinalFalse() + public function testMarkAsFinalFalse(): void { $this->oPresentation->getPresentationProperties()->markAsFinal(false); $this->assertZipXmlElementNotExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php index 7e031f1625..057b2b8397 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCustomTest.php @@ -1,20 +1,40 @@ assertZipFileExists('docProps/custom.xml'); $this->assertZipXmlElementNotExists('docProps/custom.xml', '/Properties/property[@name="_MarkAsFinal"]'); + $this->assertIsSchemaECMA376Valid(); } - public function testMarkAsFinalTrue() + public function testMarkAsFinalTrue(): void { $this->oPresentation->getPresentationProperties()->markAsFinal(true); @@ -22,12 +42,93 @@ public function testMarkAsFinalTrue() $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="_MarkAsFinal"]'); $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="_MarkAsFinal"]/vt:bool'); + $this->assertIsSchemaECMA376Valid(); } - public function testMarkAsFinalFalse() + public function testMarkAsFinalFalse(): void { $this->oPresentation->getPresentationProperties()->markAsFinal(false); $this->assertZipXmlElementNotExists('docProps/custom.xml', '/Properties/property[@name="_MarkAsFinal"]'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testCustomPropertiesBoolean(): void + { + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', false, null); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:bool'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:bool', 'false'); + } + + public function testCustomPropertiesDate(): void + { + $value = time(); + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', $value, DocumentProperties::PROPERTY_TYPE_DATE); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:filetime'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:filetime', date(DATE_W3C, $value)); + } + + public function testCustomPropertiesFloat(): void + { + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', 2.1, null); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:r8'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:r8', 2.1); + } + + public function testCustomPropertiesInteger(): void + { + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', 2, null); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:i4'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:i4', 2); + } + + public function testCustomPropertiesNull(): void + { + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', null, null); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr', ''); + } + + public function testCustomPropertiesString(): void + { + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', 'pValue', null); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr', 'pValue'); + } + + public function testCustomPropertiesUnknown(): void + { + $value = time(); + $this->oPresentation->getDocumentProperties()->setCustomProperty('pName', (string) $value, DocumentProperties::PROPERTY_TYPE_UNKNOWN); + + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]'); + $this->assertZipXmlElementExists('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr'); + $this->assertZipXmlElementEquals('docProps/custom.xml', '/Properties/property[@pid="2"][@fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"][@name="pName"]/vt:lpwstr', $value); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php index aa4d46dbe9..c65bba64ec 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php @@ -1,27 +1,46 @@ assertZipFileNotExists('docProps/thumbnail.jpeg'); + $this->assertIsSchemaECMA376Valid(); } - public function testFeatureThumbnail() + public function testFeatureThumbnail(): void { - $imagePath = PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'; + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; $this->oPresentation->getPresentationProperties()->setThumbnailPath($imagePath); $this->assertZipFileExists('docProps/thumbnail.jpeg'); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/LayoutPack/TemplateBasedTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/LayoutPack/TemplateBasedTest.php deleted file mode 100644 index 24002cd6be..0000000000 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/LayoutPack/TemplateBasedTest.php +++ /dev/null @@ -1,94 +0,0 @@ -getLayouts(); - - foreach ($layouts as $layout) { - $foundLayout = $templateBased->findLayout($layout['name']); - $this->assertEquals($layout, $foundLayout); - } - } - - /** - * @expectedException \Exception - */ - public function testFindLayoutException() - { - $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.pptx'; - $templateBased = new TemplateBased($file); - $name = 'Invalid'; - $templateBased->findLayout($name); - } - - public function testFindLayoutId() - { - $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.pptx'; - $templateBased = new TemplateBased($file); - $layouts = $templateBased->getLayouts(); - - foreach ($layouts as $layout) { - $foundLayoutId = $templateBased->findLayoutId($layout['name']); - $this->assertEquals($layout['id'], $foundLayoutId); - } - } - - /** - * @expectedException \Exception - */ - public function testFindLayoutIdException() - { - $file = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/files/Sample_00_01.pptx'; - $templateBased = new TemplateBased($file); - $name = 'Invalid'; - $templateBased->findLayoutId($name); - } - - public function testFindLayoutName() - { - $oLayout = new PackDefault(); - foreach ($oLayout->getLayouts() as $keyLayout => $layout) { - $foundLayoutName = $oLayout->findLayoutName($keyLayout); - $this->assertEquals($layout['name'], $foundLayoutName); - } - } - - /** - * @expectedException \Exception - */ - public function testFindLayoutNameException() - { - $oLayout = new PackDefault(); - $oLayout->findLayoutName(1000); - } -} diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php index 5f407eec3e..a7a2fb53b7 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php @@ -1,24 +1,46 @@ */ - protected $seriesData = array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - ); + protected $seriesData = [ + 'A' => '1', + 'B' => '2', + 'C' => '4', + 'D' => '3', + 'E' => '2', + ]; + + public function testChartDisplayBlankAs(): void + { + $oSeries = new Series('Downloads', $this->seriesData); - /** - * @expectedException Exception - * @expectedExceptionMessage The chart type provided could not be rendered - */ - public function testPlotAreaBadType() + $oLine = new Line(); + $oLine->addSeries($oSeries); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + $oShape->setDisplayBlankAs(Chart::BLANKAS_ZERO); + + $element = '/c:chartSpace/c:chart/c:dispBlanksAs'; + + $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Chart::BLANKAS_ZERO); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oShape->setDisplayBlankAs(Chart::BLANKAS_SPAN); + + $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Chart::BLANKAS_SPAN); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oShape->setDisplayBlankAs(Chart::BLANKAS_GAP); + + $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Chart::BLANKAS_GAP); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testChartIncludeSpreadsheet(): void + { + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->setIncludeSpreadsheet(true); + $oLine = new Line(); + $oSeries = new Series('Downloads', $this->seriesData); + $oLine->addSeries($oSeries); + $oShape->getPlotArea()->setType($oLine); + + $this->assertTrue($oShape->hasIncludedSpreadsheet()); + + $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); + $this->assertZipFileExists('ppt/embeddings/' . $oShape->getIndexedFilename() . '.xlsx'); + + $this->assertZipFileExists('ppt/charts/_rels/' . $oShape->getIndexedFilename() . '.rels'); + $element = '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/package"]'; + $this->assertZipXmlElementExists('ppt/charts/_rels/' . $oShape->getIndexedFilename() . '.rels', $element); + + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:v'; + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:strRef'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:strRef/c:f'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'Sheet1!$A$1'); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:strRef/c:strCache'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:strRef/c:strCache/c:pt'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:strRef/c:strCache/c:pt/c:v'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'Downloads'); + $element = '/c:chartSpace/c:externalData'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'r:id'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'r:id', 'rId1'); + $element = '/c:chartSpace/c:externalData/c:autoUpdate'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oShape->setIncludeSpreadsheet(false); + + $this->assertFalse($oShape->hasIncludedSpreadsheet()); + + $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); + $this->assertZipFileNotExists('ppt/charts/_rels/' . $oShape->getIndexedFilename() . '.rels'); + $this->assertZipFileNotExists('ppt/embeddings/' . $oShape->getIndexedFilename() . '.xlsx'); + + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:v'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'Downloads'); + $element = '/c:chartSpace/c:externalData'; + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testPlotAreaBadType(): void { + $this->expectException(UndefinedChartTypeException::class); + $this->expectExceptionMessage('The chart type has not been defined'); + $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + /** @var AbstractType $stub */ $stub = $this->getMockForAbstractClass('PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType'); $oShape->getPlotArea()->setType($stub); $this->writePresentationFile($this->oPresentation, 'PowerPoint2007'); } - public function testTitleVisibilityTrue() + public function testTitleVisibilityTrue(): void { $element = '/c:chartSpace/c:chart/c:autoTitleDeleted'; - + $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); $oLine = new Line(); @@ -69,9 +206,10 @@ public function testTitleVisibilityTrue() $this->assertTrue($oShape->getTitle()->isVisible()); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + $this->assertIsSchemaECMA376Valid(); } - public function testTitleVisibilityFalse() + public function testTitleVisibilityFalse(): void { $element = '/c:chartSpace/c:chart/c:autoTitleDeleted'; @@ -85,9 +223,60 @@ public function testTitleVisibilityFalse() $this->assertFalse($oShape->getTitle()->isVisible()); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); + $this->assertIsSchemaECMA376Valid(); } - public function testAxisFont() + public function testAxisBounds(): void + { + $value = mt_rand(0, 100); + + $oSeries = new Series('Downloads', $this->seriesData); + $oSeries->getFill()->setStartColor(new Color('FFAABBCC')); + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $elementMax = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:scaling/c:max'; + $elementMin = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:scaling/c:min'; + + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + + $this->assertIsSchemaECMA376Valid(); + + $oShape->getPlotArea()->getAxisX()->setMinBounds($value); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); + + $oShape->getPlotArea()->getAxisX()->setMinBounds(null); + $oShape->getPlotArea()->getAxisX()->setMaxBounds($value); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); + + $oShape->getPlotArea()->getAxisX()->setMinBounds($value); + $oShape->getPlotArea()->getAxisX()->setMaxBounds($value); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testAxisFont(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -124,9 +313,11 @@ public function testAxisFont() $this->assertZipXmlAttributeEquals($pathShape, $element, 'sz', 1600); $this->assertZipXmlAttributeEquals($pathShape, $element, 'strike', 'noStrike'); $this->assertZipXmlAttributeEquals($pathShape, $element, 'u', Font::UNDERLINE_DASH); + + $this->assertIsSchemaECMA376Valid(); } - public function testAxisOutline() + public function testAxisOutline(): void { $expectedWidthX = 2; $expectedColorX = 'ABCDEF'; @@ -146,12 +337,11 @@ public function testAxisOutline() $oShape->getPlotArea()->getAxisY()->getOutline()->getFill()->setFillType(Fill::FILL_SOLID); $oShape->getPlotArea()->getAxisY()->getOutline()->getFill()->getStartColor()->setRGB($expectedColorY); - $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:spPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:spPr/a:ln'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'w', Drawing::pixelsToEmu(Drawing::pointsToPixels($expectedWidthX))); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'w', Drawing::pointsToEmu($expectedWidthX)); $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:spPr/a:ln/a:solidFill/a:srgbClr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $expectedColorX); @@ -159,106 +349,46 @@ public function testAxisOutline() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $element = '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:spPr/a:ln'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'w', Drawing::pixelsToEmu(Drawing::pointsToPixels($expectedWidthY))); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'w', Drawing::pointsToEmu($expectedWidthY)); $element = '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:spPr/a:ln/a:solidFill/a:srgbClr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $expectedColorY); - } - - public function testAxisVisibilityFalse() - { - $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:delete'; - - $oSlide = $this->oPresentation->getActiveSlide(); - $oShape = $oSlide->createChartShape(); - $oLine = new Line(); - $oShape->getPlotArea()->setType($oLine); - // Set Visible : FALSE - $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\Chart\Axis', $oShape->getPlotArea()->getAxisX()->setIsVisible(false)); - $this->assertFalse($oShape->getPlotArea()->getAxisX()->isVisible()); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); + $this->assertIsSchemaECMA376Valid(); } - public function testAxisVisibilityTrue() + public function testAxisTickLabelPosition(): void { - $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:delete'; - - $oSlide = $this->oPresentation->getActiveSlide(); - $oShape = $oSlide->createChartShape(); - $oLine = new Line(); - $oShape->getPlotArea()->setType($oLine); - - // Set Visible : TRUE - $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\Chart\Axis', $oShape->getPlotArea()->getAxisX()->setIsVisible(true)); - $this->assertTrue($oShape->getPlotArea()->getAxisX()->isVisible()); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); - } - - public function testTypeArea() - { - $oSlide = $this->oPresentation->getActiveSlide(); - $oShape = $oSlide->createChartShape(); - $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); - $oArea = new Area(); - $oSeries = new Series('Downloads', $this->seriesData); - $oSeries->getFill()->setStartColor(new Color('FFAABBCC')); - $oArea->addSeries($oSeries); - $oShape->getPlotArea()->setType($oArea); - - $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData'; - $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); - $element = '/c:chartSpace/c:chart/c:plotArea/c:areaChart'; - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $element = '/c:chartSpace/c:chart/c:plotArea/c:areaChart/c:ser'; - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - } - - public function testTypeAxisBounds() - { - $value = rand(0, 100); + $element = '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:tickLblPos'; $oSeries = new Series('Downloads', $this->seriesData); - $oSeries->getFill()->setStartColor(new Color('FFAABBCC')); $oLine = new Line(); $oLine->addSeries($oSeries); $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oShape->getPlotArea()->setType($oLine); - $elementMax = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:scaling/c:max'; - $elementMin = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:scaling/c:min'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Axis::TICK_LABEL_POSITION_NEXT_TO); - $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); - $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + $this->assertIsSchemaECMA376Valid(); - $oShape->getPlotArea()->getAxisX()->setMinBounds($value); + $oShape->getPlotArea()->getAxisY()->setTickLabelPosition(Axis::TICK_LABEL_POSITION_HIGH); $this->resetPresentationFile(); - $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Axis::TICK_LABEL_POSITION_HIGH); + $this->assertIsSchemaECMA376Valid(); - $oShape->getPlotArea()->getAxisX()->setMinBounds(null); - $oShape->getPlotArea()->getAxisX()->setMaxBounds($value); + $oShape->getPlotArea()->getAxisY()->setTickLabelPosition(Axis::TICK_LABEL_POSITION_LOW); $this->resetPresentationFile(); - $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); - - $oShape->getPlotArea()->getAxisX()->setMinBounds($value); - $oShape->getPlotArea()->getAxisX()->setMaxBounds($value); - $this->resetPresentationFile(); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Axis::TICK_LABEL_POSITION_LOW); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + $this->assertIsSchemaECMA376Valid(); } - public function testTypeAxisTickMark() + public function testAxisTickMark(): void { $value = Axis::TICK_MARK_CROSS; @@ -277,6 +407,8 @@ public function testTypeAxisTickMark() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', Axis::TICK_MARK_NONE); + $this->assertIsSchemaECMA376Valid(); + $oShape->getPlotArea()->getAxisY()->setMinorTickMark($value); $this->resetPresentationFile(); @@ -285,6 +417,8 @@ public function testTypeAxisTickMark() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); + $this->assertIsSchemaECMA376Valid(); + $oShape->getPlotArea()->getAxisY()->setMinorTickMark(); $oShape->getPlotArea()->getAxisY()->setMajorTickMark($value); $this->resetPresentationFile(); @@ -294,6 +428,8 @@ public function testTypeAxisTickMark() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + $this->assertIsSchemaECMA376Valid(); + $oShape->getPlotArea()->getAxisY()->setMinorTickMark($value); $oShape->getPlotArea()->getAxisY()->setMajorTickMark($value); $this->resetPresentationFile(); @@ -302,14 +438,95 @@ public function testTypeAxisTickMark() $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeAxisUnit() + public function testAxisTitleRotation(): void { - $value = rand(0, 100); + $oSeries = new Series('Downloads', $this->seriesData); + + $oBar = new Bar(); + $oBar->addSeries($oSeries); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->getPlotArea()->setType($oBar); + + $pathShape = 'ppt/charts/' . $oShape->getIndexedFilename(); + $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:title/c:tx/c:rich/a:bodyPr'; + $this->assertZipXmlElementExists($pathShape, $element); + $this->assertZipXmlAttributeNotExists($pathShape, $element, 'rot'); + + $this->resetPresentationFile(); + $value = rand(0, 360); + $oShape->getPlotArea()->getAxisX()->setTitleRotation($value); + + $pathShape = 'ppt/charts/' . $oShape->getIndexedFilename(); + $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:title/c:tx/c:rich/a:bodyPr'; + $this->assertZipXmlElementExists($pathShape, $element); + $this->assertZipXmlAttributeExists($pathShape, $element, 'rot'); + $this->assertZipXmlAttributeEquals($pathShape, $element, 'rot', Drawing::degreesToAngle((int) $value)); + } + + public function testAxisVisibility(): void + { + $element = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:delete'; + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oLine = new Line(); + $oShape->getPlotArea()->setType($oLine); + + // Set Visible : FALSE + $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\Chart\Axis', $oShape->getPlotArea()->getAxisX()->setIsVisible(false)); + $this->assertFalse($oShape->getPlotArea()->getAxisX()->isVisible()); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + + // Set Visible : TRUE + $this->assertInstanceOf('PhpOffice\PhpPresentation\Shape\Chart\Axis', $oShape->getPlotArea()->getAxisX()->setIsVisible(true)); + $this->assertTrue($oShape->getPlotArea()->getAxisX()->isVisible()); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testAxisXUnit(): void + { + $value = mt_rand(0, 100); + + $oSeries = new Series('Downloads', $this->seriesData); + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $elementMax = '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:tickLblSkip'; + + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + + $this->assertIsSchemaECMA376Valid(); + + $oShape->getPlotArea()->getAxisX()->setMajorUnit($value); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testAxisYUnit(): void + { + $value = mt_rand(0, 100); $oSeries = new Series('Downloads', $this->seriesData); - $oSeries->getFill()->setStartColor(new Color('FFAABBCC')); $oLine = new Line(); $oLine->addSeries($oSeries); $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); @@ -321,6 +538,8 @@ public function testTypeAxisUnit() $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + $this->assertIsSchemaECMA376Valid(); + $oShape->getPlotArea()->getAxisY()->setMinorUnit($value); $this->resetPresentationFile(); @@ -328,6 +547,8 @@ public function testTypeAxisUnit() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); + $this->assertIsSchemaECMA376Valid(); + $oShape->getPlotArea()->getAxisY()->setMinorUnit(null); $oShape->getPlotArea()->getAxisY()->setMajorUnit($value); $this->resetPresentationFile(); @@ -336,24 +557,50 @@ public function testTypeAxisUnit() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); - $oShape->getPlotArea()->getAxisY()->setMinorUnit($value); - $oShape->getPlotArea()->getAxisY()->setMajorUnit($value); - $this->resetPresentationFile(); + $this->assertIsSchemaECMA376Valid(); + + $oShape->getPlotArea()->getAxisY()->setMinorUnit($value); + $oShape->getPlotArea()->getAxisY()->setMajorUnit($value); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeArea(): void + { + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oArea = new Area(); + $oSeries = new Series('Downloads', $this->seriesData); + $oSeries->getFill()->setStartColor(new Color('FFAABBCC')); + $oArea->addSeries($oSeries); + $oShape->getPlotArea()->setType($oArea); + + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:areaChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:areaChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMin, 'val', $value); - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $elementMax, 'val', $value); + $this->assertIsSchemaECMA376Valid(); } - public function testTypeBar() + public function testTypeBar(): void { - $valueGapWidthPercent = rand(0, 500); + $valueGapWidthPercent = mt_rand(0, 500); $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); $oBar = new Bar(); $oBar->setGapWidthPercent($valueGapWidthPercent); + $oBar->setOverlapWidthPercent(-10); $oSeries = new Series('Downloads', $this->seriesData); $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKBLUE)); @@ -375,11 +622,15 @@ public function testTypeBar() $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $oSeries->getTitle()); $element = '/c:chartSpace/c:chart/c:plotArea/c:barChart/c:gapWidth'; $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $valueGapWidthPercent); + $element = '/c:chartSpace/c:chart/c:plotArea/c:barChart/c:overlap'; + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $oBar->getOverlapWidthPercent()); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeBar3D() + public function testTypeBar3D(): void { - $valueGapWidthPercent = rand(0, 500); + $valueGapWidthPercent = mt_rand(0, 500); $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); @@ -406,9 +657,11 @@ public function testTypeBar3D() $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $oSeries->getTitle()); $element = '/c:chartSpace/c:chart/c:plotArea/c:bar3DChart/c:gapWidth'; $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $valueGapWidthPercent); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeBar3DSubScript() + public function testTypeBar3DSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -421,10 +674,11 @@ public function testTypeBar3DSubScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:bar3DChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-25000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-250000'); + $this->assertIsSchemaECMA376Valid(); } - public function testTypeBar3DSuperScript() + public function testTypeBar3DSuperScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -437,10 +691,66 @@ public function testTypeBar3DSuperScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:bar3DChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '30000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '300000'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeDoughnut(): void + { + $randHoleSize = mt_rand(10, 90); + $randSeparator = chr(rand(ord('A'), ord('Z'))); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oDoughnut = new Doughnut(); + $oSeries = new Series('Downloads', $this->seriesData); + $oSeries->getDataPointFill(0)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_BLUE)); + $oSeries->getDataPointFill(1)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKBLUE)); + $oSeries->getDataPointFill(2)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKGREEN)); + $oSeries->getDataPointFill(3)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKRED)); + $oSeries->getDataPointFill(4)->setFillType(Fill::FILL_SOLID)->setStartColor(new Color(Color::COLOR_DARKYELLOW)); + $oDoughnut->addSeries($oSeries); + $oShape->getPlotArea()->setType($oDoughnut); + + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:ser/c:dPt/c:spPr'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:ser/c:tx/c:v'; + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $oSeries->getTitle()); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:dLbls/c:separator'; + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:dLbls/c:showBubbleSize'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 0); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:firstSliceAng'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 0); + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:holeSize'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 50); + + $oDoughnut->setHoleSize($randHoleSize); + $this->resetPresentationFile(); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:holeSize'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $randHoleSize); + + $oSeries->setSeparator($randSeparator); + $this->resetPresentationFile(); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:doughnutChart/c:dLbls/c:separator'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $randSeparator); } - public function testTypeBar3DBarDirection() + public function testTypeBar3DBarDirection(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -454,9 +764,11 @@ public function testTypeBar3DBarDirection() $element = '/c:chartSpace/c:chart/c:plotArea/c:bar3DChart/c:barDir'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', Bar3D::DIRECTION_HORIZONTAL); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeLine() + public function testTypeLine(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -474,51 +786,53 @@ public function testTypeLine() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:tx/c:v'; $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $oSeries->getTitle()); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeLineGridlines() + public function testTypeLineGridlines(): void { - $arrayTests = array( - array( + $arrayTests = [ + [ 'methodAxis' => 'getAxisX', 'methodGrid' => 'setMajorGridlines', 'expectedElement' => '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:majorGridlines/c:spPr/a:ln', 'expectedElementColor' => '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:majorGridlines/c:spPr/a:ln/a:solidFill/a:srgbClr', - ), - array( + ], + [ 'methodAxis' => 'getAxisX', 'methodGrid' => 'setMinorGridlines', 'expectedElement' => '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:minorGridlines/c:spPr/a:ln', 'expectedElementColor' => '/c:chartSpace/c:chart/c:plotArea/c:catAx/c:minorGridlines/c:spPr/a:ln/a:solidFill/a:srgbClr', - ), - array( + ], + [ 'methodAxis' => 'getAxisY', 'methodGrid' => 'setMajorGridlines', 'expectedElement' => '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:majorGridlines/c:spPr/a:ln', 'expectedElementColor' => '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:majorGridlines/c:spPr/a:ln/a:solidFill/a:srgbClr', - ), - array( + ], + [ 'methodAxis' => 'getAxisY', 'methodGrid' => 'setMinorGridlines', 'expectedElement' => '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:minorGridlines/c:spPr/a:ln', 'expectedElementColor' => '/c:chartSpace/c:chart/c:plotArea/c:valAx/c:minorGridlines/c:spPr/a:ln/a:solidFill/a:srgbClr', - ), - ); + ], + ]; $expectedColor = new Color(Color::COLOR_BLUE); foreach ($arrayTests as $arrayTest) { - $expectedSizePts = rand(1, 100); - $expectedSizeEmu = round(Drawing::pointsToPixels(Drawing::pixelsToEmu($expectedSizePts))); + $expectedSizePts = mt_rand(1, 100); + $expectedSizeEmu = Drawing::pointsToEmu($expectedSizePts); $this->oPresentation->removeSlideByIndex()->createSlide(); $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); $oLine = new Line(); - $oLine->addSeries(new Series('Downloads', array( - 'A' => 1, - 'B' => 2, - 'C' => 4, - 'D' => 3, - 'E' => 2, - ))); + $oLine->addSeries(new Series('Downloads', [ + 'A' => '1', + 'B' => '2', + 'C' => '4', + 'D' => '3', + 'E' => '2', + ])); $oShape->getPlotArea()->setType($oLine); $oGridlines = new Gridlines(); $oGridlines->getOutline()->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor($expectedColor); @@ -533,16 +847,18 @@ public function testTypeLineGridlines() $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $arrayTest['expectedElementColor'], 'val'); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $arrayTest['expectedElementColor'], 'val', $expectedColor->getRGB()); + $this->assertIsSchemaECMA376Valid(); + $this->resetPresentationFile(); } } - public function testTypeLineMarker() + /** + * @dataProvider dataProviderMarkerSymbol + */ + public function testTypeLineMarker(string $expectedSymbol): void { - do { - $expectedSymbol = array_rand(Marker::$arraySymbol); - } while ($expectedSymbol == Marker::SYMBOL_NONE); - $expectedSize = rand(2, 72); + $expectedSize = mt_rand(2, 72); $expectedEltSymbol = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:marker/c:symbol'; $expectedElementSize = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:marker/c:size'; @@ -559,32 +875,80 @@ public function testTypeLineMarker() $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedEltSymbol, 'val', $expectedSymbol); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize, 'val', $expectedSize); + $this->assertIsSchemaECMA376Valid(); + $oSeries->getMarker()->setSize(1); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize, 'val', 2); + $this->assertIsSchemaECMA376Valid(); + $oSeries->getMarker()->setSize(73); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize, 'val', 72); + $this->assertIsSchemaECMA376Valid(); + $oSeries->getMarker()->setSymbol(Marker::SYMBOL_NONE); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedEltSymbol); $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeLineSeriesOutline() + public function testTypeLineMarkerBorder(): void { - $expectedWidth = rand(1, 100); - $expectedWidthEmu = Drawing::pixelsToEmu(Drawing::pointsToPixels($expectedWidth)); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:marker/c:spPr/a:ln'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'w', 12700); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'cmpd', Border::LINE_SINGLE); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element . '/a:prstDash'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element . '/a:prstDash', 'val', Border::DASH_SOLID); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeLineMarkerFill(): void + { + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:marker/c:spPr/a:noFill'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeLineSeriesOutline(): void + { + $expectedWidth = mt_rand(1, 100); + $expectedWidthEmu = Drawing::pointsToEmu($expectedWidth); $expectedElement = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:spPr/a:ln'; $oOutline = new Outline(); @@ -603,17 +967,58 @@ public function testTypeLineSeriesOutline() $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement); + $this->assertIsSchemaECMA376Valid(); + $oSeries->setOutline($oOutline); - $oLine->setSeries(array($oSeries)); + $oLine->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement, 'w', $expectedWidthEmu); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement . '/a:solidFill'); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeLineSubScript() + public function testTypeLineSmooth(): void + { + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oLine->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oShape->getPlotArea()->setType($oLine); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oLine->setIsSmooth(true); + $oShape->getPlotArea()->setType($oLine); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); + } + + public function testTypeLineSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -626,10 +1031,12 @@ public function testTypeLineSubScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-25000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-250000'); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeLineSuperScript() + public function testTypeLineSuperScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -642,10 +1049,12 @@ public function testTypeLineSuperScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '30000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '300000'); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypePie() + public function testTypePie(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -674,37 +1083,19 @@ public function testTypePie() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 0); + $this->assertIsSchemaECMA376Valid(); + $oSeries->setShowLegendKey(true); $this->resetPresentationFile(); $element = '/c:chartSpace/c:chart/c:plotArea/c:pieChart/c:ser/c:dLbls/c:showLegendKey'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 1); - } - - public function testTypePieSeparator() - { - $value = ';'; - - $oSlide = $this->oPresentation->getActiveSlide(); - $oShape = $oSlide->createChartShape(); - $oPie = new Pie(); - $oSeries = new Series('Downloads', $this->seriesData); - $oPie->addSeries($oSeries); - $oShape->getPlotArea()->setType($oPie); - - $element = '/c:chartSpace/c:chart/c:plotArea/c:pieChart/c:ser/c:dLbls/c:separator'; - $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $oSeries->setSeparator($value); - $this->resetPresentationFile(); - - $element = '/c:chartSpace/c:chart/c:plotArea/c:pieChart/c:ser/c:dLbls/c:separator'; - $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $value); + $this->assertIsSchemaECMA376Valid(); } - public function testTypePie3D() + public function testTypePie3D(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -729,11 +1120,13 @@ public function testTypePie3D() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $element = '/c:chartSpace/c:chart/c:plotArea/c:pie3DChart/c:ser/c:tx/c:v'; $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $oSeries->getTitle()); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypePie3DExplosion() + public function testTypePie3DExplosion(): void { - $value = rand(1, 100); + $value = mt_rand(1, 100); $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -747,9 +1140,11 @@ public function testTypePie3DExplosion() $element = '/c:chartSpace/c:chart/c:plotArea/c:pie3DChart/c:ser/c:explosion'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', $value); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypePie3DSubScript() + public function testTypePie3DSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -762,10 +1157,12 @@ public function testTypePie3DSubScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:pie3DChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-25000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-250000'); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypePie3DSuperScript() + public function testTypePie3DSuperScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -778,10 +1175,35 @@ public function testTypePie3DSuperScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:pie3DChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '30000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '300000'); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeRadar(): void + { + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oRadar = new Radar(); + $oSeries = new Series('Downloads', $this->seriesData); + $oRadar->addSeries($oSeries); + $oShape->getPlotArea()->setType($oRadar); + + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:radarChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:radarChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:radarChart/c:ser/c:tx/c:v'; + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, $oSeries->getTitle()); + $element = '/c:chartSpace/c:chart/c:plotArea/c:radarChart/c:ser/c:dLbls/c:showLegendKey'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 0); } - public function testTypeScatter() + public function testTypeScatter(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -803,20 +1225,24 @@ public function testTypeScatter() $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 0); + $this->assertIsSchemaECMA376Valid(); + $oSeries->setShowLegendKey(true); $this->resetPresentationFile(); $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:dLbls/c:showLegendKey'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', 1); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeScatterMarker() + /** + * @dataProvider dataProviderMarkerSymbol + */ + public function testTypeScatterMarkerSymbol(string $expectedSymbol): void { - do { - $expectedSymbol = array_rand(Marker::$arraySymbol); - } while ($expectedSymbol == Marker::SYMBOL_NONE); - $expectedSize = rand(2, 72); + $expectedSize = mt_rand(2, 72); $expectedEltSymbol = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:marker/c:symbol'; $expectedElementSize = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:marker/c:size'; @@ -833,32 +1259,103 @@ public function testTypeScatterMarker() $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedEltSymbol, 'val', $expectedSymbol); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize, 'val', $expectedSize); + $this->assertIsSchemaECMA376Valid(); + $oSeries->getMarker()->setSize(1); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize, 'val', 2); + $this->assertIsSchemaECMA376Valid(); + $oSeries->getMarker()->setSize(73); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize, 'val', 72); + $this->assertIsSchemaECMA376Valid(); + $oSeries->getMarker()->setSymbol(Marker::SYMBOL_NONE); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedEltSymbol); $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElementSize); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeScatterMarkerBorder(): void + { + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:marker/c:spPr/a:ln'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $oScatter = new Scatter(); + $oScatter->addSeries($oSeries); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->getPlotArea()->setType($oScatter); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'w', 12700); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'cmpd', Border::LINE_SINGLE); + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element . '/a:prstDash'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element . '/a:prstDash', 'val', Border::DASH_SOLID); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeScatterMarkerFill(): void + { + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:marker/c:spPr/a:noFill'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $oScatter = new Scatter(); + $oScatter->addSeries($oSeries); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oShape->getPlotArea()->setType($oScatter); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeScatterSeparator(): void + { + $expectedSeparator = ';'; + $expectedElement = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:dLbls/c:separator'; + + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createChartShape(); + $oScatter = new Scatter(); + $oSeries = new Series('Downloads', $this->seriesData); + $oScatter->addSeries($oSeries); + $oShape->getPlotArea()->setType($oScatter); + + $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement); + $this->assertIsSchemaECMA376Valid(); + + $oSeries->setSeparator($expectedSeparator); + $this->resetPresentationFile(); + + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement); + $this->assertZipXmlElementEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement, $expectedSeparator); + $this->assertIsSchemaECMA376Valid(); } - public function testTypeScatterSeriesOutline() + public function testTypeScatterSeriesOutline(): void { - $expectedWidth = rand(1, 100); - $expectedWidthEmu = Drawing::pixelsToEmu(Drawing::pointsToPixels($expectedWidth)); + $expectedWidth = mt_rand(1, 100); + $expectedWidthEmu = Drawing::pointsToEmu($expectedWidth); $expectedElement = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:spPr/a:ln'; $oOutline = new Outline(); @@ -879,17 +1376,58 @@ public function testTypeScatterSeriesOutline() $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement); + $this->assertIsSchemaECMA376Valid(); + $oSeries->setOutline($oOutline); - $oScatter->setSeries(array($oSeries)); + $oScatter->setSeries([$oSeries]); $this->resetPresentationFile(); $this->assertZipFileExists('ppt/charts/' . $oShape->getIndexedFilename()); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement); $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement, 'w', $expectedWidthEmu); $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $expectedElement . '/a:solidFill'); + + $this->assertIsSchemaECMA376Valid(); + } + + public function testTypeScatterSmooth(): void + { + $oSeries = new Series('Downloads', $this->seriesData); + + $oScatter = new Scatter(); + $oScatter->addSeries($oSeries); + $oScatter->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oShape->getPlotArea()->setType($oScatter); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oScatter->setIsSmooth(true); + $oShape->getPlotArea()->setType($oScatter); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); } - public function testTypeScatterSubScript() + public function testTypeScatterSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -902,10 +1440,12 @@ public function testTypeScatterSubScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-25000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '-250000'); + + $this->assertIsSchemaECMA376Valid(); } - public function testTypeScatterSuperScript() + public function testTypeScatterSuperScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createChartShape(); @@ -918,10 +1458,12 @@ public function testTypeScatterSuperScript() $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:dLbls/c:txPr/a:p/a:pPr/a:defRPr'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '30000'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'baseline', '300000'); + + $this->assertIsSchemaECMA376Valid(); } - public function testView3D() + public function testView3D(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oLine = new Line(); @@ -931,11 +1473,26 @@ public function testView3D() $element = '/c:chartSpace/c:chart/c:view3D/c:hPercent'; $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); - $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '100%'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '100'); + $this->assertIsSchemaECMA376Valid(); $oShape->getView3D()->setHeightPercent(null); $this->resetPresentationFile(); $this->assertZipXmlElementNotExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertIsSchemaECMA376Valid(); + } + + /** + * @return array> + */ + public function dataProviderMarkerSymbol(): iterable + { + foreach (Marker::$arraySymbol as $symbol) { + if ($symbol === Marker::SYMBOL_NONE) { + continue; + } + yield [$symbol]; + } } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptCommentsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptCommentsTest.php index 1d790770dd..8c67c8ac76 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptCommentsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptCommentsTest.php @@ -1,4 +1,22 @@ assertZipFileExists('ppt/comments/comment1.xml'); $this->assertZipXmlElementExists('ppt/comments/comment1.xml', $expectedElement); $this->assertZipXmlAttributeEquals('ppt/comments/comment1.xml', $expectedElement, 'authorId', 0); + $this->assertIsSchemaECMA376Valid(); } - public function testWithoutComment() + + public function testWithoutComment(): void { $this->assertZipFileNotExists('ppt/comments/comment1.xml'); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptMediaTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptMediaTest.php index 52efb3a9a8..ca77f4d336 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptMediaTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptMediaTest.php @@ -1,63 +1,88 @@ oPresentation->getActiveSlide(); $oShape = $oSlide->createDrawingShape(); - $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/PhpPresentationLogo.png'); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); $this->assertZipFileExists('ppt/media/' . $oShape->getIndexedFilename()); + $this->assertIsSchemaECMA376Valid(); } - /** - * @expectedException \Exception - * @expectedExceptionMessage does not exist - */ - public function testDrawingException() + public function testDrawingException(): void { + $path = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/filedoesntexist.png'; + + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage(sprintf( + 'The file "%s" doesn\'t exist', + $path + )); + $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createDrawingShape(); - $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR.'/resources/images/filedoesntexist.png', false); + $oShape->setPath($path, false); $this->writePresentationFile($this->oPresentation, 'PowerPoint2007'); } - /** - * @requires PHP 5.4 - */ - public function testDrawingZip() + public function testDrawingZip(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oDrawing = new Drawing\ZipFile(); - $oDrawing->setPath('zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'Sample_01_Simple.pptx#ppt/media/phppowerpoint_logo1.gif', false); + $oDrawing->setPath('zip://' . PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR . 'Sample_01_Simple.pptx#ppt/media/phppowerpoint_logo1.gif'); $oSlide->addShape($oDrawing); $this->assertZipFileExists('ppt/media/' . $oDrawing->getIndexedFilename()); + $this->assertIsSchemaECMA376Valid(); } - /** - * @expectedException \Exception - * @expectedExceptionMessage does not exist - * @requires PHP 5.4 - */ - public function testDrawingZipException() + public function testDrawingZipException(): void { + $path = PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/filedoesntexist.png'; + + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage(sprintf( + 'The file "%s" doesn\'t exist', + $path + )); + $oDrawing = new Drawing\ZipFile(); - $oDrawing->setPath('zip://'.PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'filedoesntexist.zip#secondpath', false); + $oDrawing->setPath('zip://' . $path . '#secondpath'); $oSlide = $this->oPresentation->getActiveSlide(); $oSlide->addShape($oDrawing); @@ -65,20 +90,18 @@ public function testDrawingZipException() $this->writePresentationFile($this->oPresentation, 'PowerPoint2007'); } - /** - * @requires PHP 5.4 - */ - public function testDrawingBase64() + public function testDrawingBase64(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = new Drawing\Base64(); - $oShape->setData('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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', false); + $oShape->setData('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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'); $oSlide->addShape($oShape); $this->assertZipFileExists('ppt/media/' . $oShape->getIndexedFilename()); + $this->assertIsSchemaECMA376Valid(); } - public function testMemoryDrawing() + public function testMemoryDrawing(): void { $gdImage = imagecreatetruecolor(140, 20); $textColor = imagecolorallocate($gdImage, 255, 255, 255); @@ -91,5 +114,6 @@ public function testMemoryDrawing() $oSlide->addShape($oShape); $this->assertZipFileExists('ppt/media/' . $oShape->getIndexedFilename()); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresPropsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresPropsTest.php index c482e101ee..6acf0e83be 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresPropsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresPropsTest.php @@ -1,26 +1,48 @@ assertZipFileExists('ppt/presProps.xml'); $element = '/p:presentationPr/p:extLst/p:ext'; $this->assertZipXmlElementExists('ppt/presProps.xml', $element); $this->assertZipXmlAttributeEquals('ppt/presProps.xml', $element, 'uri', '{E76CE94A-603C-4142-B9EB-6D1370010A27}'); + $this->assertIsSchemaECMA376Valid(); } - public function testLoopContinuously() + public function testLoopContinuously(): void { $this->assertZipFileExists('ppt/presProps.xml'); $element = '/p:presentationPr/p:showPr'; - $this->assertZipXmlElementNotExists('ppt/presProps.xml', $element); + $this->assertZipXmlElementExists('ppt/presProps.xml', $element); + $this->assertZipXmlAttributeNotExists('ppt/presProps.xml', $element, 'loop'); + $this->assertIsSchemaECMA376Valid(); $this->oPresentation->getPresentationProperties()->setLoopContinuouslyUntilEsc(true); $this->resetPresentationFile(); @@ -30,5 +52,39 @@ public function testLoopContinuously() $this->assertZipXmlElementExists('ppt/presProps.xml', $element); $this->assertZipXmlAttributeExists('ppt/presProps.xml', $element, 'loop'); $this->assertZipXmlAttributeEquals('ppt/presProps.xml', $element, 'loop', 1); + $this->assertIsSchemaECMA376Valid(); + } + + /** + * @dataProvider dataProviderShowType + */ + public function testShowType(string $slideshowType, string $element): void + { + $this->oPresentation->getPresentationProperties()->setSlideshowType($slideshowType); + + $this->assertZipFileExists('ppt/presProps.xml'); + $this->assertZipXmlElementExists('ppt/presProps.xml', $element); + $this->assertIsSchemaECMA376Valid(); + } + + /** + * @return array> + */ + public function dataProviderShowType(): array + { + return [ + [ + PresentationProperties::SLIDESHOW_TYPE_PRESENT, + '/p:presentationPr/p:showPr/p:present', + ], + [ + PresentationProperties::SLIDESHOW_TYPE_BROWSE, + '/p:presentationPr/p:showPr/p:browse', + ], + [ + PresentationProperties::SLIDESHOW_TYPE_KIOSK, + '/p:presentationPr/p:showPr/p:kiosk', + ], + ]; } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresentationTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresentationTest.php index 1ca1e94e00..b3b02454a4 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresentationTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptPresentationTest.php @@ -1,4 +1,22 @@ assertZipFileExists('ppt/presentation.xml'); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php index d19136d7c8..bc99f27c71 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php @@ -1,32 +1,57 @@ getMockBuilder('PhpOffice\\PhpPresentation\\Slide\\SlideMaster') - ->setMethods(array('getAllSlideLayouts', 'getRelsIndex', 'getShapeCollection')) + /** @var \PHPUnit\Framework\MockObject\MockObject|SlideMaster $slideMaster */ + $slideMaster = $this->getMockBuilder(SlideMaster::class) + ->setMethods(['getAllSlideLayouts', 'getRelsIndex', 'getShapeCollection']) ->getMock(); - $layouts = array(new SlideLayout($slideMaster)); + $layouts = [new SlideLayout($slideMaster)]; $slideMaster->expects($this->once()) ->method('getAllSlideLayouts') ->will($this->returnValue($layouts)); - $collection = new \ArrayObject(); + $collection = new ArrayObject(); $collection[] = new ShapeDrawingFile(); $collection[] = new ShapeDrawingFile(); $collection[] = new ShapeDrawingFile(); @@ -37,19 +62,20 @@ public function testWriteSlideMasterRelationships() $data = $writer->writeSlideMasterRelationships($slideMaster); - $dom = new \DomDocument(); + $dom = new DOMDocument(); $dom->loadXml($data); - $xpath = new \DomXpath($dom); + $xpath = new DOMXPath($dom); $xpath->registerNamespace('r', 'http://schemas.openxmlformats.org/package/2006/relationships'); $list = $xpath->query('//r:Relationship'); $this->assertEquals(5, $list->length); - $this->assertEquals('rId1', $list->item(0)->getAttribute('Id')); - $this->assertEquals('rId2', $list->item(1)->getAttribute('Id')); - $this->assertEquals('rId3', $list->item(2)->getAttribute('Id')); - $this->assertEquals('rId4', $list->item(3)->getAttribute('Id')); - $this->assertEquals('rId5', $list->item(4)->getAttribute('Id')); + foreach (range(0, 4) as $id) { + /** @var DOMElement $domItem */ + $domItem = $list->item($id); + $this->assertInstanceOf(DOMElement::class, $domItem); + $this->assertEquals('rId' . (string) ($id + 1), $domItem->getAttribute('Id')); + } } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php index d4fe82a562..0d0f60681d 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php @@ -1,35 +1,68 @@ oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRichText->createTextRun('AAA'); + $oRichText->getActiveParagraph()->getAlignment()->setIsRTL(false); + + $expectedElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $expectedElement); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $expectedElement, 'rtl', '0'); + $this->assertIsSchemaECMA376Valid(); + + $oRichText->getActiveParagraph()->getAlignment()->setIsRTL(true); + $this->resetPresentationFile(); + + $expectedElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $expectedElement); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $expectedElement, 'rtl', '1'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testAlignmentShapeAuto(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createRichTextShape()->setWidth(400)->setHeight(400)->setOffsetX(100)->setOffsetY(100); @@ -38,12 +71,10 @@ public function testAlignmentShapeAuto() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $element, 'anchor'); + $this->assertIsSchemaECMA376Valid(); } - /** - * @link https://github.com/PHPOffice/PHPPresentation/issues/42 - */ - public function testAlignmentShapeBase() + public function testAlignmentShapeBase(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createRichTextShape()->setWidth(400)->setHeight(400)->setOffsetX(100)->setOffsetY(100); @@ -53,12 +84,10 @@ public function testAlignmentShapeBase() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $element, 'anchor'); + $this->assertIsSchemaECMA376Valid(); } - /** - * @link https://github.com/PHPOffice/PHPPresentation/issues/35 - */ - public function testAlignmentShapeBottom() + public function testAlignmentShapeBottom(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createRichTextShape()->setWidth(400)->setHeight(400)->setOffsetX(100)->setOffsetY(100); @@ -68,12 +97,10 @@ public function testAlignmentShapeBottom() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'anchor', Alignment::VERTICAL_BOTTOM); + $this->assertIsSchemaECMA376Valid(); } - /** - * @link https://github.com/PHPOffice/PHPPresentation/issues/35 - */ - public function testAlignmentShapeCenter() + public function testAlignmentShapeCenter(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createRichTextShape()->setWidth(400)->setHeight(400)->setOffsetX(100)->setOffsetY(100); @@ -83,12 +110,10 @@ public function testAlignmentShapeCenter() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'anchor', Alignment::VERTICAL_CENTER); + $this->assertIsSchemaECMA376Valid(); } - /** - * @link https://github.com/PHPOffice/PHPPresentation/issues/35 - */ - public function testAlignmentShapeTop() + public function testAlignmentShapeTop(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createRichTextShape()->setWidth(400)->setHeight(400)->setOffsetX(100)->setOffsetY(100); @@ -98,9 +123,10 @@ public function testAlignmentShapeTop() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'anchor', Alignment::VERTICAL_TOP); + $this->assertIsSchemaECMA376Valid(); } - public function testAnimation() + public function testAnimation(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape1 = $oSlide->createRichTextShape(); @@ -116,18 +142,36 @@ public function testAnimation() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $element = '/p:sld/p:timing/p:tnLst/p:par/p:cTn/p:childTnLst/p:seq/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par/p:cTn/p:childTnLst/p:par'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); + } + + public function testAutoShape(): void + { + $autoShape = new AutoShape(); + $autoShape->setText('AlphaBeta'); + $this->oPresentation->getActiveSlide()->addShape($autoShape); + + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:prstGeom'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $element, 'prst'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'prst', AutoShape::TYPE_HEART); + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:t'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlElementEquals('ppt/slides/slide1.xml', $element, 'AlphaBeta'); + $this->assertIsSchemaECMA376Valid(); } - public function testCommentRelationship() + public function testCommentRelationship(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oSlide->addShape(new Comment()); $element = '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"]'; $this->assertZipXmlElementExists('ppt/slides/_rels/slide1.xml.rels', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testCommentInGroupRelationship() + public function testCommentInGroupRelationship(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oGroup = new Group(); @@ -136,9 +180,10 @@ public function testCommentInGroupRelationship() $element = '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"]'; $this->assertZipXmlElementExists('ppt/slides/_rels/slide1.xml.rels', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testDrawingWithHyperlink() + public function testDrawingWithHyperlink(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createDrawingShape(); @@ -148,9 +193,44 @@ public function testDrawingWithHyperlink() $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:cNvPr/a:hlinkClick'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'r:id', 'rId3'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testDrawingShapeMimetypePNG(): void + { + $shape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $shape->setHeight(10)->setWidth(10); + $shape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); + + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:cNvPr/a:extLst'; + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $element); + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:blipFill/a:blip/a:extLst'; + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); + } + + public function testDrawingShapeMimetypeSVG(): void + { + $shape = $this->oPresentation->getActiveSlide()->createDrawingShape(); + $shape->setHeight(10)->setWidth(10); + $shape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/tiger.svg'); + + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:cNvPr/a:extLst'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:cNvPr/a:extLst/a:ext'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:cNvPr/a:extLst/a:ext[@uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}"]'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:blipFill/a:blip/a:extLst'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:blipFill/a:blip/a:extLst/a:ext[@uri="{28A0092B-C50C-407E-A947-70E740481C1C}"]'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + + $this->assertIsSchemaECMA376Valid(); } - public function testDrawingShapeBorder() + public function testDrawingShapeBorder(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createDrawingShape(); @@ -160,9 +240,29 @@ public function testDrawingShapeBorder() $element = '/p:sld/p:cSld/p:spTree/p:pic/p:spPr/a:ln'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'cmpd', Border::LINE_DOUBLE); + $this->assertIsSchemaECMA376Valid(); + } + + public function testDrawingShapeFill(): void + { + $oColor = new Color(Color::COLOR_DARKRED); + $oColor->setAlpha(mt_rand(0, 100)); + $oSlide = $this->oPresentation->getActiveSlide(); + $oShape = $oSlide->createDrawingShape(); + $oShape->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/images/PhpPresentationLogo.png'); + $oShape->getFill()->setFillType(Fill::FILL_SOLID)->setStartColor($oColor); + + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:spPr/a:solidFill/a:srgbClr'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $oColor->getRGB()); + + $element = '/p:sld/p:cSld/p:spTree/p:pic/p:spPr/a:solidFill/a:srgbClr/a:alpha'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', (string) ($oColor->getAlpha() * 1000)); + $this->assertIsSchemaECMA376Valid(); } - public function testDrawingShapeShadow() + public function testDrawingShapeShadow(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createDrawingShape(); @@ -171,9 +271,10 @@ public function testDrawingShapeShadow() $element = '/p:sld/p:cSld/p:spTree/p:pic/p:spPr/a:effectLst/a:outerShdw'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testFillGradientLinearTable() + public function testFillGradientLinearTable(): void { $expected1 = 'E06B20'; $expected2 = strrev($expected1); @@ -187,18 +288,19 @@ public function testFillGradientLinearTable() $oFill = $oCell->getFill(); $oFill->setFillType(Fill::FILL_GRADIENT_LINEAR)->setStartColor(new Color('FF' . $expected1))->setEndColor(new Color('FF' . $expected2)); - $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="0%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="0"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected1); - $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="100%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="100000"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected2); + $this->assertIsSchemaECMA376Valid(); } /** - * @link : https://github.com/PHPOffice/PHPPresentation/issues/61 + * @see : https://github.com/PHPOffice/PHPPresentation/issues/61 */ - public function testFillGradientLinearRichText() + public function testFillGradientLinearRichText(): void { $expected1 = 'E06B20'; $expected2 = strrev($expected1); @@ -209,15 +311,16 @@ public function testFillGradientLinearRichText() $oFill = $oShape->getFill(); $oFill->setFillType(Fill::FILL_GRADIENT_LINEAR)->setStartColor(new Color('FF' . $expected1))->setEndColor(new Color('FF' . $expected2)); - $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="0%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="0"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected1); - $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="100%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="100000"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected2); + $this->assertIsSchemaECMA376Valid(); } - public function testFillGradientPathTable() + public function testFillGradientPathTable(): void { $expected1 = 'E06B20'; $expected2 = strrev($expected1); @@ -231,18 +334,19 @@ public function testFillGradientPathTable() $oFill = $oCell->getFill(); $oFill->setFillType(Fill::FILL_GRADIENT_PATH)->setStartColor(new Color('FF' . $expected1))->setEndColor(new Color('FF' . $expected2)); - $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="0%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="0"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected1); - $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="100%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:gradFill/a:gsLst/a:gs[@pos="100000"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected2); + $this->assertIsSchemaECMA376Valid(); } /** - * @link : https://github.com/PHPOffice/PHPPresentation/issues/61 + * @see : https://github.com/PHPOffice/PHPPresentation/issues/61 */ - public function testFillGradientPathText() + public function testFillGradientPathText(): void { $expected1 = 'E06B20'; $expected2 = strrev($expected1); @@ -253,15 +357,16 @@ public function testFillGradientPathText() $oFill = $oShape->getFill(); $oFill->setFillType(Fill::FILL_GRADIENT_PATH)->setStartColor(new Color('FF' . $expected1))->setEndColor(new Color('FF' . $expected2)); - $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="0%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="0"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected1); - $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="100%"]/a:srgbClr'; + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:gradFill/a:gsLst/a:gs[@pos="100000"]/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected2); + $this->assertIsSchemaECMA376Valid(); } - public function testFillPatternTable() + public function testFillPatternTable(): void { $expected1 = 'E06B20'; $expected2 = strrev($expected1); @@ -281,9 +386,10 @@ public function testFillPatternTable() $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:pattFill/a:bgClr/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected2); + $this->assertIsSchemaECMA376Valid(); } - public function testFillSolidTable() + public function testFillSolidTable(): void { $expected = 'E06B20'; @@ -299,12 +405,13 @@ public function testFillSolidTable() $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:tcPr/a:solidFill/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected); + $this->assertIsSchemaECMA376Valid(); } /** - * @link : https://github.com/PHPOffice/PHPPresentation/issues/61 + * @see : https://github.com/PHPOffice/PHPPresentation/issues/61 */ - public function testFillSolidText() + public function testFillSolidText(): void { $expected = 'E06B20'; @@ -317,9 +424,10 @@ public function testFillSolidText() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:solidFill/a:srgbClr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expected); + $this->assertIsSchemaECMA376Valid(); } - public function testHyperlink() + public function testHyperlink(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -328,9 +436,10 @@ public function testHyperlink() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:hlinkClick'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testHyperlinkInternal() + public function testHyperlinkInternal(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -340,9 +449,10 @@ public function testHyperlinkInternal() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:hlinkClick'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'action', 'ppaction://hlinksldjump'); + $this->assertIsSchemaECMA376Valid(); } - public function testListBullet() + public function testListBullet(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -352,7 +462,7 @@ public function testListBullet() $oExpectedFont = $oRichText->getActiveParagraph()->getBulletStyle()->getBulletFont(); $oExpectedChar = $oRichText->getActiveParagraph()->getBulletStyle()->getBulletChar(); $oExpectedColor = $oRichText->getActiveParagraph()->getBulletStyle()->getBulletColor()->getRGB(); - $oExpectedAlpha = $oRichText->getActiveParagraph()->getBulletStyle()->getBulletColor()->getAlpha() . "%"; + $oExpectedAlpha = $oRichText->getActiveParagraph()->getBulletStyle()->getBulletColor()->getAlpha() * 1000; $oRichText->createTextRun('Alpha'); $oRichText->createParagraph()->createTextRun('Beta'); @@ -369,9 +479,10 @@ public function testListBullet() $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element . '/a:buClr/a:srgbClr', 'val', $oExpectedColor); $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/a:buClr/a:srgbClr/a:alpha'); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element . '/a:buClr/a:srgbClr/a:alpha', 'val', $oExpectedAlpha); + $this->assertIsSchemaECMA376Valid(); } - public function testListNumeric() + public function testListNumeric(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -392,9 +503,10 @@ public function testListNumeric() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/a:buAutoNum'); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element . '/a:buAutoNum', 'type', $oExpectedChar); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element . '/a:buAutoNum', 'startAt', $oExpectedStart); + $this->assertIsSchemaECMA376Valid(); } - public function testLine() + public function testLine(): void { $valEmu10 = Drawing::pixelsToEmu(10); $valEmu90 = Drawing::pixelsToEmu(90); @@ -417,15 +529,17 @@ public function testLine() $element = '/p:sld/p:cSld/p:spTree/p:cxnSp/p:spPr/a:xfrm[@flipV="1"]/a:off[@x="' . $valEmu10 . '"][@y="' . $valEmu10 . '"]'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + + $this->assertIsSchemaECMA376Valid(); } - public function testMedia() + public function testMedia(): void { $expectedName = 'MyName'; - $expectedWidth = rand(1, 100); - $expectedHeight = rand(1, 100); - $expectedX = rand(1, 100); - $expectedY = rand(1, 100); + $expectedWidth = mt_rand(1, 100); + $expectedHeight = mt_rand(1, 100); + $expectedX = mt_rand(1, 100); + $expectedY = mt_rand(1, 100); $oMedia = new Media(); $oMedia->setPath(PHPPRESENTATION_TESTS_BASE_DIR . '/resources/videos/sintel_trailer-480p.ogv') @@ -448,16 +562,18 @@ public function testMedia() $element = '/p:sld/p:cSld/p:spTree/p:pic/p:nvPicPr/p:nvPr/p:extLst/p:ext'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'uri', '{DAA4B4D4-6D71-4841-9C94-3DE7FCFB9230}'); + + $this->assertIsSchemaECMA376Valid(); } - public function testNote() + public function testNote(): void { $oLayout = $this->oPresentation->getLayout(); $oSlide = $this->oPresentation->getActiveSlide(); $oNote = $oSlide->getNote(); $oRichText = $oNote->createRichTextShape() - ->setHeight($oLayout->getCY($oLayout::UNIT_PIXEL)) - ->setWidth($oLayout->getCX($oLayout::UNIT_PIXEL)) + ->setHeight((int) $oLayout->getCY($oLayout::UNIT_PIXEL)) + ->setWidth((int) $oLayout->getCX($oLayout::UNIT_PIXEL)) ->setOffsetX(170) ->setOffsetY(180); $oRichText->createTextRun('testNote'); @@ -495,22 +611,109 @@ public function testNote() $this->assertZipXmlAttributeEquals('ppt/notesSlides/notesSlide1.xml', $element, 'cy', 3600450); $element = '/p:notes/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:t'; $this->assertZipXmlElementExists('ppt/notesSlides/notesSlide1.xml', $element); + + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextAutoFitNormal() + public function testParagraphColumns(): void { + $richText = $this->oPresentation->getActiveSlide()->createRichTextShape(); + + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $element, 'numCol'); + $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $element, 'spcCol'); + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $richText + ->setColumns(2) + ->setColumnSpacing(123); + + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $element, 'numCol'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'numCol', '2'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $element, 'spcCol'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'spcCol', '1171575'); + } + + public function testParagraphLineSpacing(): void + { + $expectedLineSpacing = mt_rand(1, 100); + $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); - $oRichText->setAutoFit(RichText::AUTOFIT_NORMAL, 47.5, 20); + $oRichText->getActiveParagraph() + ->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_PERCENT) + ->setLineSpacing($expectedLineSpacing); + + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:lnSpc/a:spcPct'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expectedLineSpacing * 1000); + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:lnSpc/a:spcPts'; + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oRichText->getActiveParagraph() + ->setLineSpacingMode(Paragraph::LINE_SPACING_MODE_POINT); + + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:lnSpc/a:spcPct'; + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $element); + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:lnSpc/a:spcPts'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expectedLineSpacing * 100); + $this->assertIsSchemaECMA376Valid(); + } + + public function testParagraphSpacingAfter(): void + { + $expectedVal = mt_rand(1, 100); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRichText->getActiveParagraph() + ->setSpacingAfter($expectedVal); + + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:spcAft/a:spcPts'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expectedVal * 100); + $this->assertIsSchemaECMA376Valid(); + } + + public function testParagraphSpacingBefore(): void + { + $expectedVal = mt_rand(1, 100); + + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRichText->getActiveParagraph() + ->setSpacingBefore($expectedVal); + + $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:spcBef/a:spcPts'; + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expectedVal * 100); + $this->assertIsSchemaECMA376Valid(); + } + + public function testRichTextAutoFitNormal(): void + { + $expectedFontScale = 47.5; + $expectedLnSpcReduction = 20; + + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRichText->setAutoFit(RichText::AUTOFIT_NORMAL, $expectedFontScale, $expectedLnSpcReduction); $oRichText->createTextRun('This is my text for the test.'); $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr/a:normAutofit'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); - $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'fontScale', 47500); - $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'lnSpcReduction', 20000); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'fontScale', $expectedFontScale * 1000); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'lnSpcReduction', $expectedLnSpcReduction * 1000); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextBreak() + public function testRichTextBreak(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -518,9 +721,10 @@ public function testRichTextBreak() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:br'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextHyperlink() + public function testRichTextHyperlink(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -528,23 +732,49 @@ public function testRichTextHyperlink() $element = '/p:sld/p:cSld/p:spTree/p:sp//a:hlinkClick'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextLineSpacing() + public function testRichTextRunFontFormat(): void { - $expectedLineSpacing = rand(1, 100); + $latinElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:latin'; + $eastAsianElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:ea'; + $complexScriptElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:cs'; $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); - $oRichText->createTextRun('AAA'); - $oRichText->getActiveParagraph()->setLineSpacing($expectedLineSpacing); + $oRun = $oRichText->createTextRun('MyText'); + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); - $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:pPr/a:lnSpc/a:spcPct'; - $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); - $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'val', $expectedLineSpacing . '%'); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'typeface', 'Calibri'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'typeface', 'Calibri'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'typeface', 'Calibri'); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextRunLanguage() + public function testRichTextRunLanguage(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -554,6 +784,7 @@ public function testRichTextRunLanguage() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $expectedElement); $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $expectedElement, 'lang'); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $expectedElement, 'lang', 'en-US'); + $this->assertIsSchemaECMA376Valid(); $oRun->setLanguage('de_DE'); $this->resetPresentationFile(); @@ -562,9 +793,10 @@ public function testRichTextRunLanguage() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $expectedElement); $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $expectedElement, 'lang'); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $expectedElement, 'lang', 'de_DE'); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextShadow() + public function testRichTextShadow(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -573,9 +805,10 @@ public function testRichTextShadow() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:effectLst/a:outerShdw'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextUpright() + public function testRichTextUpright(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -585,9 +818,10 @@ public function testRichTextUpright() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'upright', '1'); + $this->assertIsSchemaECMA376Valid(); } - public function testRichTextVertical() + public function testRichTextVertical(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -597,14 +831,16 @@ public function testRichTextVertical() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'vert', 'vert'); + $this->assertIsSchemaECMA376Valid(); } - public function testSlideLayoutExists() + public function testSlideLayoutExists(): void { $this->assertZipFileExists('ppt/slideLayouts/slideLayout1.xml'); + $this->assertIsSchemaECMA376Valid(); } - public function testStyleCharacterSpacing() + public function testStyleCharacterSpacing(): void { $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr'; @@ -615,15 +851,17 @@ public function testStyleCharacterSpacing() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'spc', '0'); - + $this->assertIsSchemaECMA376Valid(); + $oRun->getFont()->setCharacterSpacing(42); $this->resetPresentationFile(); $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'spc', '4200'); + $this->assertIsSchemaECMA376Valid(); } - public function testStyleSubScript() + public function testStyleSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -632,10 +870,11 @@ public function testStyleSubScript() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); - $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'baseline', '-25000'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'baseline', '-250000'); + $this->assertIsSchemaECMA376Valid(); } - public function testStyleSuperScript() + public function testStyleSuperScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oRichText = $oSlide->createRichTextShape(); @@ -644,10 +883,11 @@ public function testStyleSuperScript() $element = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); - $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'baseline', '30000'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'baseline', '300000'); + $this->assertIsSchemaECMA376Valid(); } - public function testTableWithAlignment() + public function testTableWithAlignment(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(4); @@ -660,6 +900,7 @@ public function testTableWithAlignment() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $element, 'anchor'); $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $element, 'vert'); + $this->assertIsSchemaECMA376Valid(); $oCell->getActiveParagraph()->getAlignment()->setVertical(Alignment::VERTICAL_BOTTOM); $oCell->getActiveParagraph()->getAlignment()->setTextDirection(Alignment::TEXT_DIRECTION_STACKED); @@ -668,9 +909,10 @@ public function testTableWithAlignment() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'anchor', Alignment::VERTICAL_BOTTOM); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'vert', Alignment::TEXT_DIRECTION_STACKED); + $this->assertIsSchemaECMA376Valid(); } - public function testTableWithBorder() + public function testTableWithBorder(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(4); @@ -706,9 +948,10 @@ public function testTableWithBorder() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/a:lnT[@cmpd="' . Border::LINE_SINGLE . '"]/a:prstDash[@val="' . Border::DASH_DASHDOT . '"]'); $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/a:lnB[@cmpd="' . Border::LINE_SINGLE . '"]'); $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/a:lnB[@cmpd="' . Border::LINE_SINGLE . '"]/a:prstDash[@val="' . Border::DASH_SOLID . '"]'); + $this->assertIsSchemaECMA376Valid(); } - public function testTableWithCellMargin() + public function testTableWithCellMargin(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(4); @@ -728,9 +971,10 @@ public function testTableWithCellMargin() $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'marL', Drawing::pixelsToEmu(20)); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'marR', Drawing::pixelsToEmu(30)); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'marT', Drawing::pixelsToEmu(40)); + $this->assertIsSchemaECMA376Valid(); } - public function testTableWithColspan() + public function testTableWithColspan(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(4); @@ -743,9 +987,10 @@ public function testTableWithColspan() $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'gridSpan', 2); + $this->assertIsSchemaECMA376Valid(); } - public function testTableWithRowspan() + public function testTableWithRowspan(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(4); @@ -762,12 +1007,13 @@ public function testTableWithRowspan() $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '[@rowSpan="2"]'); $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '[@vMerge="1"]'); + $this->assertIsSchemaECMA376Valid(); } /** - * @link : https://github.com/PHPOffice/PHPPresentation/issues/70 + * @see : https://github.com/PHPOffice/PHPPresentation/issues/70 */ - public function testTableWithHyperlink() + public function testTableWithHyperlink(): void { $oSlide = $this->oPresentation->getActiveSlide(); $oShape = $oSlide->createTableShape(4); @@ -781,11 +1027,12 @@ public function testTableWithHyperlink() $element = '/p:sld/p:cSld/p:spTree/p:graphicFrame/a:graphic/a:graphicData/a:tbl/a:tr/a:tc/a:txBody/a:p/a:r/a:rPr/a:hlinkClick'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'r:id', 'rId2'); + $this->assertIsSchemaECMA376Valid(); } - public function testTransition() + public function testTransition(): void { - $value = rand(1000, 5000); + $value = mt_rand(1000, 5000); $element = '/p:sld/p:transition'; $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $element); @@ -799,23 +1046,27 @@ public function testTransition() $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $element, 'advTm'); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'advTm', $value); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'advClick', '0'); + $this->assertIsSchemaECMA376Valid(); $oTransition->setSpeed(Transition::SPEED_FAST); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'spd', 'fast'); + $this->assertIsSchemaECMA376Valid(); $oTransition->setSpeed(Transition::SPEED_MEDIUM); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'spd', 'med'); + $this->assertIsSchemaECMA376Valid(); $oTransition->setSpeed(Transition::SPEED_SLOW); $this->resetPresentationFile(); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'spd', 'slow'); + $this->assertIsSchemaECMA376Valid(); $rcTransition = new \ReflectionClass('PhpOffice\PhpPresentation\Slide\Transition'); $arrayConstants = $rcTransition->getConstants(); foreach ($arrayConstants as $key => $value) { - if (strpos($key, 'TRANSITION_') !== 0) { + if (0 !== strpos($key, 'TRANSITION_')) { continue; } @@ -835,11 +1086,8 @@ public function testTransition() case 'TRANSITION_CHECKER_VERTICAL': $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/p:checker[@dir=\'vert\']'); break; - case 'TRANSITION_CIRCLE_HORIZONTAL': - $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/p:circle[@dir=\'horz\']'); - break; - case 'TRANSITION_CIRCLE_VERTICAL': - $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/p:circle[@dir=\'vert\']'); + case 'TRANSITION_CIRCLE': + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/p:circle'); break; case 'TRANSITION_COMB_HORIZONTAL': $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/p:comb[@dir=\'horz\']'); @@ -968,19 +1216,23 @@ public function testTransition() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $element . '/p:zoom[@dir=\'out\']'); break; } + $this->assertIsSchemaECMA376Valid(); } $oTransition->setManualTrigger(true); $this->resetPresentationFile(); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $element, 'advClick', '1'); + $this->assertIsSchemaECMA376Valid(); } - public function testVisibility() + public function testVisibility(): void { $expectedElement = '/p:sld'; $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $expectedElement); $this->assertZipXmlAttributeNotExists('ppt/slides/slide1.xml', $expectedElement, 'show'); + $this->assertIsSchemaECMA376Valid(); $this->oPresentation->getActiveSlide()->setIsVisible(false); $this->resetPresentationFile(); @@ -988,5 +1240,6 @@ public function testVisibility() $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $expectedElement); $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $expectedElement, 'show'); $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $expectedElement, 'show', 0); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptTablePropsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptTablePropsTest.php index 98a5cb59fb..dd4957b0d9 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptTablePropsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptTablePropsTest.php @@ -1,4 +1,22 @@ assertZipFileExists('ppt/tableStyles.xml'); $element = '/a:tblStyleLst'; $this->assertZipXmlElementExists('ppt/tableStyles.xml', $element); $this->assertZipXmlAttributeEquals('ppt/tableStyles.xml', $element, 'def', '{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}'); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptViewPropsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptViewPropsTest.php index fa4852be85..a2bed9edfa 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptViewPropsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptViewPropsTest.php @@ -1,4 +1,22 @@ assertZipXmlElementExists('ppt/viewProps.xml', $expectedElement); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', $expectedElement, 'showComments', 0); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', $expectedElement, 'lastView', PresentationProperties::VIEW_SLIDE); + $this->assertIsSchemaECMA376Valid(); } - public function testCommentVisible() + public function testCommentVisible(): void { - $expectedElement ='/p:viewPr'; + $expectedElement = '/p:viewPr'; $this->oPresentation->getPresentationProperties()->setCommentVisible(true); $this->assertZipFileExists('ppt/viewProps.xml'); $this->assertZipXmlElementExists('ppt/viewProps.xml', $expectedElement); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', $expectedElement, 'showComments', 1); + $this->assertIsSchemaECMA376Valid(); } - public function testLastView() + public function testLastView(): void { - $expectedElement ='/p:viewPr'; + $expectedElement = '/p:viewPr'; $expectedLastView = PresentationProperties::VIEW_OUTLINE; $this->oPresentation->getPresentationProperties()->setLastView($expectedLastView); @@ -40,5 +60,6 @@ public function testLastView() $this->assertZipFileExists('ppt/viewProps.xml'); $this->assertZipXmlElementExists('ppt/viewProps.xml', $expectedElement); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', $expectedElement, 'lastView', $expectedLastView); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/RelationshipsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/RelationshipsTest.php index 5f359cd12e..015e5464c1 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/RelationshipsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/RelationshipsTest.php @@ -1,4 +1,22 @@ oPresentation->getActiveSlide()->addShape($oComment); $this->assertZipXmlElementExists('ppt/_rels/presentation.xml.rels', '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/commentAuthors"]'); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/SchemaTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/SchemaTest.php deleted file mode 100644 index b7ee6fbb98..0000000000 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/SchemaTest.php +++ /dev/null @@ -1,485 +0,0 @@ -internalErrors = libxml_use_internal_errors(true); - } - - public function tearDown() - { - parent::tearDown(); - - libxml_use_internal_errors($this->internalErrors); - } - - /** - * Test whether the generated XML validates against the Office Open XML File Formats schema - * - * @see http://www.ecma-international.org/publications/standards/Ecma-376.htm - * @dataProvider pptProvider - */ - public function testSchema(PhpPresentation $presentation) - { - $this->writePresentationFile($presentation, 'PowerPoint2007'); - - // validate all XML files - $path = realpath($this->workDirectory . '/ppt'); - $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); - - foreach ($iterator as $file) { - /** @var SplFileInfo $file */ - if ($file->getExtension() !== "xml") { - continue; - } - - $fileName = str_replace('\\', '/', substr($file->getRealPath(), strlen($path) + 1)); - $dom = $this->getXmlDom('ppt/' . $fileName); - $xmlSource = $dom->saveXML(); - - // In the ISO/ECMA standard the namespace has changed from - // http://schemas.openxmlformats.org/ to http://purl.oclc.org/ooxml/ - // We need to use the http://purl.oclc.org/ooxml/ namespace to validate - // the xml against the current schema - $xmlSource = str_replace(array( - "http://schemas.openxmlformats.org/drawingml/2006/main", - "http://schemas.openxmlformats.org/drawingml/2006/chart", - "http://schemas.openxmlformats.org/officeDocument/2006/relationships", - "http://schemas.openxmlformats.org/presentationml/2006/main", - ), array( - "http://purl.oclc.org/ooxml/drawingml/main", - "http://purl.oclc.org/ooxml/drawingml/chart", - "http://purl.oclc.org/ooxml/officeDocument/relationships", - "http://purl.oclc.org/ooxml/presentationml/main", - ), $xmlSource); - - $dom->loadXML($xmlSource); - $dom->schemaValidate(__DIR__ . '/../../../../resources/schema/ooxml/pml.xsd'); - - $error = libxml_get_last_error(); - if ($error) { - $this->fail(sprintf("Validation error: %s in file %s on line %s\n%s", $error->message, $file, $error->line, $dom->saveXML())); - } - } - } - - public function pptProvider() - { - return array( - array($this->generatePresentation01()), - array($this->generatePresentation02()), - ); - } - - /** - * Generates a ppt which contains different elements per slide i.e. shape, table, etc. - * - * @return PhpPresentation - */ - private function generatePresentation01() - { - $objPHPPresentation = new PhpPresentation(); - - $objPHPPresentation->getDocumentProperties() - ->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 02 Title') - ->setSubject('Sample 02 Subject') - ->setDescription('Sample 02 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); - - $currentSlide = $objPHPPresentation->getActiveSlide(); - - // text shape - $shape = $currentSlide->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); - $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); - $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor(new Color('FFE06B20')); - - // image - $currentSlide = $objPHPPresentation->createSlide(); - $gdImage = @imagecreatetruecolor(140, 20); - $textColor = imagecolorallocate($gdImage, 255, 255, 255); - imagestring($gdImage, 1, 5, 5, 'Created with PHPPresentation', $textColor); - - $shape = new Drawing\Gd(); - $shape->setName('Sample image') - ->setDescription('Sample image') - ->setImageResource($gdImage) - ->setRenderingFunction(Drawing\Gd::RENDERING_JPEG) - ->setMimeType(Drawing\Gd::MIMETYPE_DEFAULT) - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); - $currentSlide->addShape($shape); - - // table - $currentSlide = $objPHPPresentation->createSlide(); - $shape = $currentSlide->createTableShape(3); - $shape->setHeight(200); - $shape->setWidth(600); - $shape->setOffsetX(150); - $shape->setOffsetY(300); - - $row = $shape->createRow(); - $row->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setRotation(90) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFFFFFFF')); - $cell = $row->nextCell(); - $cell->setColSpan(3); - $cell->createTextRun('Title row')->getFont()->setBold(true)->setSize(16); - $cell->getBorders()->getBottom()->setLineWidth(4) - ->setLineStyle(Border::LINE_SINGLE) - ->setDashStyle(Border::DASH_DASH); - - $row = $shape->createRow(); - $row->setHeight(20); - $row->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR) - ->setRotation(90) - ->setStartColor(new Color('FFE06B20')) - ->setEndColor(new Color('FFFFFFFF')); - $row->nextCell()->createTextRun('R1C1')->getFont()->setBold(true); - $row->nextCell()->createTextRun('R1C2')->getFont()->setBold(true); - $row->nextCell()->createTextRun('R1C3')->getFont()->setBold(true); - - foreach ($row->getCells() as $cell) { - $cell->getBorders()->getTop()->setLineWidth(4) - ->setLineStyle(Border::LINE_SINGLE) - ->setDashStyle(Border::DASH_DASH); - } - - // chart - $currentSlide = $objPHPPresentation->createSlide(); - - $oFill = new Fill(); - $oFill->setFillType(Fill::FILL_SOLID)->setStartColor(new Color('FFE06B20')); - - $oShadow = new Shadow(); - $oShadow->setVisible(true)->setDirection(45)->setDistance(10); - - $seriesData = array( - 'Monday' => 12, - 'Tuesday' => 15, - 'Wednesday' => 13, - 'Thursday' => 17, - 'Friday' => 14, - 'Saturday' => 9, - 'Sunday' => 7 - ); - - $lineChart = new Line(); - $series = new Series('Downloads', $seriesData); - $series->setShowSeriesName(true); - $series->setShowValue(true); - $lineChart->addSeries($series); - - $shape = $currentSlide->createChartShape(); - $shape->setName('PHPPresentation Daily Downloads')->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); - $shape->setShadow($oShadow); - $shape->setFill($oFill); - $shape->getBorder()->setLineStyle(Border::LINE_SINGLE); - $shape->getTitle()->setText('PHPPresentation Daily Downloads'); - $shape->getTitle()->getFont()->setItalic(true); - $shape->getPlotArea()->setType($lineChart); - $shape->getView3D()->setRotationX(30); - $shape->getView3D()->setPerspective(30); - $shape->getLegend()->getBorder()->setLineStyle(Border::LINE_SINGLE); - $shape->getLegend()->getFont()->setItalic(true); - - // fill - $currentSlide = $objPHPPresentation->createSlide(); - - for ($inc = 1; $inc <= 4; $inc++) { - // Create a shape (text) - $shape = $currentSlide->createRichTextShape() - ->setHeight(200) - ->setWidth(300); - if ($inc == 1 || $inc == 3) { - $shape->setOffsetX(10); - } else { - $shape->setOffsetX(320); - } - if ($inc == 1 || $inc == 2) { - $shape->setOffsetY(10); - } else { - $shape->setOffsetY(220); - } - $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - - switch ($inc) { - case 1: - $shape->getFill()->setFillType(Fill::FILL_NONE); - break; - case 2: - $shape->getFill()->setFillType(Fill::FILL_GRADIENT_LINEAR)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF000000')); - break; - case 3: - $shape->getFill()->setFillType(Fill::FILL_GRADIENT_PATH)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF000000')); - break; - case 4: - $shape->getFill()->setFillType(Fill::FILL_SOLID)->setRotation(90)->setStartColor(new Color('FF4672A8'))->setEndColor(new Color('FF4672A8')); - break; - } - - $textRun = $shape->createTextRun('Use PHPPresentation!'); - $textRun->getFont()->setBold(true) - ->setSize(30) - ->setColor(new Color('FFE06B20')); - } - - // slide note - $currentSlide = $objPHPPresentation->createSlide(); - - $shape = $currentSlide->createDrawingShape(); - $shape->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath(__DIR__ . '/../../../../../samples/resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); - $shape->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - $shape->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/')->setTooltip('PHPPresentation'); - - $shape = $currentSlide->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); - $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $textRun = $shape->createTextRun('Thank you for using PHPPresentation!'); - $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor(new Color('FFE06B20')); - - $oNote = $currentSlide->getNote(); - $oLayout = $objPHPPresentation->getLayout(); - $oRichText = $oNote->createRichTextShape() - ->setHeight($oLayout->getCY($oLayout::UNIT_PIXEL)) - ->setWidth($oLayout->getCX($oLayout::UNIT_PIXEL)) - ->setOffsetX(170) - ->setOffsetY(180); - $oRichText->createTextRun('A class library'); - $oRichText->createParagraph()->createTextRun('Written in PHP'); - $oRichText->createParagraph()->createTextRun('Representing a presentation'); - $oRichText->createParagraph()->createTextRun('Supports writing to different file formats'); - - // transition - $currentSlide = $objPHPPresentation->createSlide(); - - $shapeDrawing = $currentSlide->createDrawingShape(); - $shapeDrawing->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath(__DIR__ . '/../../../../../samples/resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); - $shapeDrawing->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - $shapeDrawing->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/')->setTooltip('PHPPresentation'); - - $shapeRichText = $currentSlide->createRichTextShape() - ->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); - $shapeRichText->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $textRun = $shapeRichText->createTextRun('Thank you for using PHPPresentation!'); - $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor(new Color('FFE06B20')); - - $oTransition = new Transition(); - $oTransition->setManualTrigger(false); - $oTransition->setTimeTrigger(true, 4000); - $oTransition->setTransitionType(Transition::TRANSITION_SPLIT_IN_VERTICAL); - $currentSlide->setTransition($oTransition); - - // comment - $currentSlide = $objPHPPresentation->createSlide(); - - $oShapeDrawing = new Drawing\File(); - $oShapeDrawing->setName('PHPPresentation logo') - ->setDescription('PHPPresentation logo') - ->setPath(__DIR__ . '/../../../../../samples/resources/phppowerpoint_logo.gif') - ->setHeight(36) - ->setOffsetX(10) - ->setOffsetY(10); - $oShapeDrawing->getShadow()->setVisible(true) - ->setDirection(45) - ->setDistance(10); - $oShapeDrawing->getHyperlink()->setUrl('https://github.com/PHPOffice/PHPPresentation/')->setTooltip('PHPPresentation'); - - $oShapeRichText = new RichText(); - $oShapeRichText->setHeight(300) - ->setWidth(600) - ->setOffsetX(170) - ->setOffsetY(180); - $oShapeRichText->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $textRun = $oShapeRichText->createTextRun('Thank you for using PHPPresentation!'); - $textRun->getFont()->setBold(true) - ->setSize(60) - ->setColor(new Color('FFE06B20')); - - $currentSlide->addShape(clone $oShapeDrawing); - $currentSlide->addShape(clone $oShapeRichText); - - $oAuthor = new \PhpOffice\PhpPresentation\Shape\Comment\Author(); - $oAuthor->setName('Progi1984'); - $oAuthor->setInitials('P'); - - $oComment1 = new \PhpOffice\PhpPresentation\Shape\Comment(); - $oComment1->setText('Text A'); - $oComment1->setOffsetX(10); - $oComment1->setOffsetY(55); - $oComment1->setDate(time()); - $oComment1->setAuthor($oAuthor); - $currentSlide->addShape($oComment1); - - $oComment2 = new \PhpOffice\PhpPresentation\Shape\Comment(); - $oComment2->setText('Text B'); - $oComment2->setOffsetX(170); - $oComment2->setOffsetY(180); - $oComment2->setDate(time()); - $oComment2->setAuthor($oAuthor); - $currentSlide->addShape($oComment2); - - // animation - $currentSlide = $objPHPPresentation->createSlide(); - - $oDrawing1 = clone $oShapeDrawing; - $oRichText1 = clone $oShapeRichText; - - $oSlide1 = $objPHPPresentation->getActiveSlide(); - $oSlide1->addShape($oDrawing1); - $oSlide1->addShape($oRichText1); - - $oAnimation1 = new Animation(); - $oAnimation1->addShape($oDrawing1); - $oSlide1->addAnimation($oAnimation1); - - $oAnimation2 = new Animation(); - $oAnimation2->addShape($oRichText1); - $oSlide1->addAnimation($oAnimation2); - - $oDrawing2 = clone $oShapeDrawing; - $oRichText2 = clone $oShapeRichText; - - $oSlide2 = $objPHPPresentation->createSlide(); - $oSlide2->addShape($oDrawing2); - $oSlide2->addShape($oRichText2); - - $oAnimation4 = new Animation(); - $oAnimation4->addShape($oRichText2); - $oSlide2->addAnimation($oAnimation4); - - $oAnimation3 = new Animation(); - $oAnimation3->addShape($oDrawing2); - $oSlide2->addAnimation($oAnimation3); - - $oDrawing3 = clone $oShapeDrawing; - $oRichText3 = clone $oShapeRichText; - - $currentSlide->addShape($oDrawing3); - $currentSlide->addShape($oRichText3); - - $oAnimation5 = new Animation(); - $oAnimation5->addShape($oRichText3); - $oAnimation5->addShape($oDrawing3); - $currentSlide->addAnimation($oAnimation5); - - // @TODO add more complex elements - - return $objPHPPresentation; - } - - /** - * Generates a ppt containing placeholder in the master and the slide - * - * @return PhpPresentation - */ - private function generatePresentation02() - { - $objPHPPresentation = new PhpPresentation(); - - $objPHPPresentation->getDocumentProperties() - ->setCreator('PHPOffice') - ->setLastModifiedBy('PHPPresentation Team') - ->setTitle('Sample 02 Title') - ->setSubject('Sample 02 Subject') - ->setDescription('Sample 02 Description') - ->setKeywords('office 2007 openxml libreoffice odt php') - ->setCategory('Sample Category'); - - // master slide - $masterSlides = $objPHPPresentation->getAllMasterSlides(); - /** @var Slide $objMaster */ - $objMaster = reset($masterSlides); - - $objShape = $objMaster->createRichTextShape(); - $objShape->setWidthAndHeight(270, 30)->setOffsetX(600)->setOffsetY(655); - $objShape->createTextRun("Footer") - ->getFont() - ->setName("Arial") - ->setSize(7); - $objShape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); - - $objShape = $objMaster->createRichTextShape(); - $objShape->setWidthAndHeight(50, 30)->setOffsetX(870)->setOffsetY(655); - $objShape->createTextRun("") - ->getFont() - ->setName("Arial") - ->setSize(7); - $objShape->setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_SLIDENUM)); - - // slide with placeholder - $currentSlide = $objPHPPresentation->getActiveSlide(); - - $objShape = $currentSlide->createRichTextShape(); - $objShape->setWidthAndHeight(50, 30)->setOffsetX(870)->setOffsetY(655); - $objShape->createTextRun("") - ->getFont() - ->setName("Arial") - ->setSize(7); - $objShape->setPlaceHolder(new Placeholder(Placeholder::PH_TYPE_SLIDENUM)); - - return $objPHPPresentation; - } -} diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007Test.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007Test.php index 903b822ce9..e8b283b572 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007Test.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007Test.php @@ -1,37 +1,54 @@ oPresentation); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $object->getPhpPresentation()); $this->assertEquals('./', $object->getDiskCachingDirectory()); - $this->assertInstanceOf("{$objectPrefix}LayoutPack\\PackDefault", $object->getLayoutPack()); } /** - * Test save + * Test save. */ - public function testSave() + public function testSave(): void { $filename = tempnam(sys_get_temp_dir(), 'PhpPresentation'); @@ -44,45 +61,21 @@ public function testSave() } /** - * Test save with empty filename - * - * @expectedException \Exception - * @expectedExceptionMessage Filename is empty + * Test save with empty filename. */ - public function testSaveEmptyException() + public function testSaveEmptyException(): void { + $this->expectException(InvalidParameterException::class); + $this->expectExceptionMessage('The parameter pFilename can\'t have the value ""'); + $object = new PowerPoint2007($this->oPresentation); $object->save(''); } /** - * Test save with empty assignation - * - * @expectedException \Exception - * @expectedExceptionMessage No PhpPresentation assigned. - */ - public function testSaveUnassignedException() - { - $object = new PowerPoint2007(); - $object->save('filename.pptx'); - } - - /** - * Test get PhpPresentation exception - * - * @expectedException \Exception - * @expectedExceptionMessage No PhpPresentation assigned. + * Test disk caching. */ - public function testGetPhpPresentationException() - { - $object = new PowerPoint2007(); - $object->getPhpPresentation(); - } - - /** - * Test disk caching - */ - public function testDiskCaching() + public function testDiskCaching(): void { $object = new PowerPoint2007($this->oPresentation); $this->assertFalse($object->hasDiskCaching()); @@ -97,35 +90,18 @@ public function testDiskCaching() } /** - * Test set/get disk caching exception - * - * @expectedException \Exception - * @expectedExceptionMessage Directory does not exist: foo + * Test set/get disk caching exception. */ - public function testCachingException() + public function testCachingException(): void { + $this->expectException(DirectoryNotFoundException::class); + $this->expectExceptionMessage('The directory foo doesn\'t exist'); + $object = new PowerPoint2007($this->oPresentation); $object->setUseDiskCaching(true, 'foo'); } - /** - * Test LayoutPack - * @deprecated 0.7 - */ - public function testLayoutPack() - { - $oLayoutPack = $this->getMockBuilder('PhpOffice\\PhpPresentation\\Writer\\PowerPoint2007\\LayoutPack\\AbstractLayoutPack')->getMock(); - - $object = new PowerPoint2007(); - - $this->assertInstanceOf("PhpOffice\\PhpPresentation\\Writer\\PowerPoint2007\\LayoutPack\\AbstractLayoutPack", $object->getLayoutPack()); - $this->assertInstanceOf("PhpOffice\\PhpPresentation\\Writer\\PowerPoint2007", $object->setLayoutPack()); - $this->assertNull($object->getLayoutPack()); - $this->assertInstanceOf("PhpOffice\\PhpPresentation\\Writer\\PowerPoint2007", $object->setLayoutPack($oLayoutPack)); - $this->assertInstanceOf("PhpOffice\\PhpPresentation\\Writer\\PowerPoint2007\\LayoutPack\\AbstractLayoutPack", $object->getLayoutPack()); - } - - public function testZoom() + public function testZoom(): void { $this->assertZipXmlElementExists('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sx'); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sx', 'n', 100); @@ -133,8 +109,9 @@ public function testZoom() $this->assertZipXmlElementExists('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sy'); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sy', 'n', 100); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sy', 'd', 100); + $this->assertIsSchemaECMA376Valid(); - $value = rand(1, 100); + $value = mt_rand(1, 100); $this->oPresentation->getPresentationProperties()->setZoom($value); $this->resetPresentationFile(); @@ -144,21 +121,24 @@ public function testZoom() $this->assertZipXmlElementExists('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sy'); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sy', 'n', $value * 100); $this->assertZipXmlAttributeEquals('ppt/viewProps.xml', '/p:viewPr/p:slideViewPr/p:cSldViewPr/p:cViewPr/p:scale/a:sy', 'd', 100); + $this->assertIsSchemaECMA376Valid(); } - public function testFeatureThumbnail() + public function testFeatureThumbnail(): void { - $imagePath = PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'; + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; $xPathManifest = '/Relationships/Relationship[@Target=\'docProps/thumbnail.jpeg\'][@Type=\'http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\']'; $this->assertZipFileExists('_rels/.rels'); $this->assertZipXmlElementNotExists('_rels/.rels', $xPathManifest); + $this->assertIsSchemaECMA376Valid(); $this->oPresentation->getPresentationProperties()->setThumbnailPath($imagePath); $this->resetPresentationFile(); $this->assertZipFileExists('_rels/.rels'); $this->assertZipXmlElementExists('_rels/.rels', $xPathManifest); + $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/SerializedTest.php b/tests/PhpPresentation/Tests/Writer/SerializedTest.php index 3e3d084c4c..4d495d6d1b 100644 --- a/tests/PhpPresentation/Tests/Writer/SerializedTest.php +++ b/tests/PhpPresentation/Tests/Writer/SerializedTest.php @@ -10,100 +10,89 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * + * @see https://github.com/PHPOffice/PHPPresentation + * * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); + namespace PhpOffice\PhpPresentation\Tests\Writer; -use PhpOffice\PhpPresentation\Writer\Serialized; +use PhpOffice\PhpPresentation\Exception\DirectoryNotFoundException; +use PhpOffice\PhpPresentation\Exception\InvalidParameterException; use PhpOffice\PhpPresentation\PhpPresentation; +use PhpOffice\PhpPresentation\Writer\Serialized; +use PHPUnit\Framework\TestCase; /** - * Test class for serialized reader + * Test class for serialized reader. * - * @coversDefaultClass PhpOffice\PhpPresentation\Reader\Serialized + * @coversDefaultClass \PhpOffice\PhpPresentation\Reader\Serialized */ -class SerializedTest extends \PHPUnit_Framework_TestCase +class SerializedTest extends TestCase { - public function testConstruct() + public function testConstruct(): void { $object = new Serialized(new PhpPresentation()); $this->assertInstanceOf('PhpOffice\\PhpPresentation\\PhpPresentation', $object->getPhpPresentation()); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage No PhpPresentation assigned. - */ - public function testEmptyConstruct() - { - $object = new Serialized(); - $object->getPhpPresentation(); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Filename is empty. - */ - public function testSaveEmpty() + + public function testSaveEmpty(): void { + $this->expectException(InvalidParameterException::class); + $this->expectExceptionMessage('The parameter pFilename can\'t have the value ""'); + $object = new Serialized(new PhpPresentation()); $object->save(''); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage No PhpPresentation assigned. - */ - public function testSaveNoObject() - { - $object = new Serialized(); - $object->save('file.phpppt'); - } - - public function testSave() + + public function testSave(): void { $oPhpPresentation = new PhpPresentation(); $oSlide = $oPhpPresentation->getActiveSlide(); $oImage = $oSlide->createDrawingShape(); - $oImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'); - $object = new Serialized($oPhpPresentation); - + $oImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'); $file = tempnam(sys_get_temp_dir(), 'PhpPresentation_Serialized'); - - $this->assertFileExists($file, $object->save($file)); + $object = new Serialized($oPhpPresentation); + $object->save($file); + + $this->assertFileExists($file); } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Could not open - */ - public function testSaveNotExistingDir() + + public function testSaveNotExistingDir(): void { + $path = tempnam(sys_get_temp_dir(), 'PhpPresentation_Serialized' . DIRECTORY_SEPARATOR . 'test'); + + $this->expectException(DirectoryNotFoundException::class); + $this->expectExceptionMessage(sprintf( + 'The directory %s doesn\'t exist', + $path + )); + $oPhpPresentation = new PhpPresentation(); $oSlide = $oPhpPresentation->getActiveSlide(); $oImage = $oSlide->createDrawingShape(); - $oImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'); + $oImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'); + $object = new Serialized($oPhpPresentation); - - $file = tempnam(sys_get_temp_dir(), 'PhpPresentation_Serialized'); - - $this->assertFileExists($file, $object->save($file.DIRECTORY_SEPARATOR.'test'.DIRECTORY_SEPARATOR.'test')); + $object->save($path . DIRECTORY_SEPARATOR . 'test'); } - - public function testSaveOverwriting() + + public function testSaveOverwriting(): void { $oPhpPresentation = new PhpPresentation(); $oSlide = $oPhpPresentation->getActiveSlide(); $oImage = $oSlide->createDrawingShape(); - $oImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'images'.DIRECTORY_SEPARATOR.'PhpPresentationLogo.png'); - $object = new Serialized($oPhpPresentation); - + $oImage->setPath(PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'); + $file = tempnam(sys_get_temp_dir(), 'PhpPresentation_Serialized'); file_put_contents($file, rand(1, 100)); - - $this->assertFileExists($file, $object->save($file)); + + $object = new Serialized($oPhpPresentation); + $object->save($file); + + $this->assertFileExists($file); } } diff --git a/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php b/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php index 2d5d97a12f..77cba12ca8 100644 --- a/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php +++ b/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php @@ -1,14 +1,39 @@ > + */ + private $arrayOpenDocumentRNG = [ + '1.0' => [ + 'META-INF/manifest.xml' => 'OpenDocument-manifest-schema-v1.0-os.rng', + '*' => 'OpenDocument-strict-schema-v1.0-os.rng', + ], + '1.1' => [ + 'META-INF/manifest.xml' => 'OpenDocument-manifest-schema-v1.1.rng', + '*' => 'OpenDocument-strict-schema-v1.1.rng', + ], + '1.2' => [ + 'META-INF/manifest.xml' => 'OpenDocument-v1.2-os-manifest-schema.rng', + '*' => 'OpenDocument-v1.2-os-schema.rng', + ], + ]; + + /** + * Executed before each method of the class. + */ + protected function setUp(): void { + $this->xmlDisableEntityLoader = libxml_disable_entity_loader(false); $this->workDirectory = sys_get_temp_dir() . '/PhpPresentation_Unit_Test/'; $this->oPresentation = new PhpPresentation(); - $this->filePath = tempnam(sys_get_temp_dir(), 'PhpPresentation'); + + // Error XML + libxml_clear_errors(); + $this->xmlInternalErrors = libxml_use_internal_errors(true); + + // Reset file $this->resetPresentationFile(); } /** - * Executed after each method of the class + * Executed after each method of the class. */ - public function tearDown() + protected function tearDown(): void { + libxml_disable_entity_loader($this->xmlDisableEntityLoader); + libxml_use_internal_errors($this->xmlInternalErrors); $this->oPresentation = null; $this->resetPresentationFile(); } /** - * Delete directory - * - * @param string $dir + * Delete directory. */ - private function deleteDir($dir) + private function deleteDir(string $dir): void { foreach (scandir($dir) as $file) { - if ($file === '.' || $file === '..') { + if ('.' === $file || '..' === $file) { continue; - } elseif (is_file($dir . "/" . $file)) { - unlink($dir . "/" . $file); - } elseif (is_dir($dir . "/" . $file)) { - $this->deleteDir($dir . "/" . $file); + } elseif (is_file($dir . '/' . $file)) { + unlink($dir . '/' . $file); + } elseif (is_dir($dir . '/' . $file)) { + $this->deleteDir($dir . '/' . $file); } } rmdir($dir); } - protected function getXmlDom($file) + protected function getXmlDom(string $file): DOMDocument { $baseFile = $file; if (null !== $this->xmlDom && $file === $this->xmlFile) { @@ -100,42 +157,45 @@ protected function getXmlDom($file) $this->xmlFile = $file; $file = $this->workDirectory . '/' . $file; - $this->xmlDom = new \DOMDocument(); + $this->xmlDom = new DOMDocument(); $strContent = file_get_contents($file); // docProps/app.xml - if ($baseFile == 'docProps/app.xml') { + if ('docProps/app.xml' == $baseFile) { $strContent = str_replace(' xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"', '', $strContent); } // docProps/custom.xml - if ($baseFile == 'docProps/custom.xml') { + if ('docProps/custom.xml' == $baseFile) { $strContent = str_replace(' xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"', '', $strContent); } // _rels/.rels - if (strpos($baseFile, '_rels/') !== false && strpos($baseFile, '.rels') !== false) { + if (false !== strpos($baseFile, '_rels/') && false !== strpos($baseFile, '.rels')) { $strContent = str_replace(' xmlns="http://schemas.openxmlformats.org/package/2006/relationships"', '', $strContent); } $this->xmlDom->loadXML($strContent); + return $this->xmlDom; } - private function getXmlNodeList($file, $xpath) + /** + * @return DOMNodeList + */ + private function getXmlNodeList(string $file, string $xpath): DOMNodeList { - if ($this->xmlDom === null || $file !== $this->xmlFile) { + if (null === $this->xmlDom || $file !== $this->xmlFile) { $this->getXmlDom($file); } if (null === $this->xmlXPath) { - $this->xmlXPath = new \DOMXpath($this->xmlDom); + $this->xmlXPath = new DOMXPath($this->xmlDom); } return $this->xmlXPath->query($xpath); } /** - * @param PhpPresentation $oPhpPresentation * @param string $writerName */ - protected function writePresentationFile(PhpPresentation $oPhpPresentation, $writerName) + protected function writePresentationFile(PhpPresentation $oPhpPresentation, $writerName): void { if (is_file($this->filePath)) { return; @@ -144,15 +204,15 @@ protected function writePresentationFile(PhpPresentation $oPhpPresentation, $wri $xmlWriter = IOFactory::createWriter($oPhpPresentation, $writerName); $xmlWriter->save($this->filePath); - $zip = new \ZipArchive; + $zip = new \ZipArchive(); $res = $zip->open($this->filePath); - if ($res === true) { + if (true === $res) { $zip->extractTo($this->workDirectory); $zip->close(); } } - protected function resetPresentationFile() + protected function resetPresentationFile(): void { $this->xmlFile = null; $this->xmlDom = null; @@ -171,41 +231,57 @@ protected function resetPresentationFile() /** * @param string $filePath */ - public function assertZipFileExists($filePath) + public function assertZipFileExists($filePath): void { $this->writePresentationFile($this->oPresentation, $this->writerName); - self::assertThat(is_file($this->workDirectory . $filePath), self::isTrue()); + self::assertTrue(is_file($this->workDirectory . $filePath)); } /** * @param string $filePath */ - public function assertZipFileNotExists($filePath) + public function assertZipFileNotExists($filePath): void { $this->writePresentationFile($this->oPresentation, $this->writerName); - self::assertThat(is_file($this->workDirectory . $filePath), self::isFalse()); + self::assertFalse(is_file($this->workDirectory . $filePath)); } /** * @param string $filePath * @param string $xPath */ - public function assertZipXmlElementExists($filePath, $xPath) + public function assertZipXmlElementExists($filePath, $xPath): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertThat(!($nodeList->length == 0), self::isTrue()); + self::assertNotEquals( + 0, + $nodeList->length, + sprintf( + 'The element "%s" doesn\'t exist in the file "%s"', + $xPath, + $filePath + ) + ); } /** * @param string $filePath * @param string $xPath */ - public function assertZipXmlElementNotExists($filePath, $xPath) + public function assertZipXmlElementNotExists($filePath, $xPath): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertThat(!($nodeList->length == 0), self::isFalse()); + self::assertEquals( + 0, + $nodeList->length, + sprintf( + 'The element "%s" exist in the file "%s"', + $xPath, + $filePath + ) + ); } /** @@ -213,7 +289,7 @@ public function assertZipXmlElementNotExists($filePath, $xPath) * @param string $xPath * @param mixed $value */ - public function assertZipXmlElementEquals($filePath, $xPath, $value) + public function assertZipXmlElementEquals($filePath, $xPath, $value): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); @@ -225,7 +301,7 @@ public function assertZipXmlElementEquals($filePath, $xPath, $value) * @param string $xPath * @param int $num */ - public function assertZipXmlElementCount($filePath, $xPath, $num) + public function assertZipXmlElementCount($filePath, $xPath, $num): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); @@ -238,11 +314,14 @@ public function assertZipXmlElementCount($filePath, $xPath, $num) * @param string $attribute * @param mixed $value */ - public function assertZipXmlAttributeEquals($filePath, $xPath, $attribute, $value) + public function assertZipXmlAttributeEquals($filePath, $xPath, $attribute, $value): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertEquals($value, $nodeList->item(0)->getAttribute($attribute)); + /** @var DOMElement $nodeItem */ + $nodeItem = $nodeList->item(0); + self::assertInstanceOf(DOMElement::class, $nodeItem); + self::assertEquals($value, $nodeItem->getAttribute($attribute)); } /** @@ -251,11 +330,14 @@ public function assertZipXmlAttributeEquals($filePath, $xPath, $attribute, $valu * @param string $attribute * @param mixed $value */ - public function assertZipXmlAttributeStartsWith($filePath, $xPath, $attribute, $value) + public function assertZipXmlAttributeStartsWith($filePath, $xPath, $attribute, $value): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertStringStartsWith($value, $nodeList->item(0)->getAttribute($attribute)); + /** @var DOMElement $nodeItem */ + $nodeItem = $nodeList->item(0); + self::assertInstanceOf(DOMElement::class, $nodeItem); + self::assertStringStartsWith($value, $nodeItem->getAttribute($attribute)); } /** @@ -264,11 +346,14 @@ public function assertZipXmlAttributeStartsWith($filePath, $xPath, $attribute, $ * @param string $attribute * @param mixed $value */ - public function assertZipXmlAttributeEndsWith($filePath, $xPath, $attribute, $value) + public function assertZipXmlAttributeEndsWith($filePath, $xPath, $attribute, $value): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertStringEndsWith($value, $nodeList->item(0)->getAttribute($attribute)); + /** @var DOMElement $nodeItem */ + $nodeItem = $nodeList->item(0); + self::assertInstanceOf(DOMElement::class, $nodeItem); + self::assertStringEndsWith($value, $nodeItem->getAttribute($attribute)); } /** @@ -277,11 +362,14 @@ public function assertZipXmlAttributeEndsWith($filePath, $xPath, $attribute, $va * @param string $attribute * @param mixed $value */ - public function assertZipXmlAttributeContains($filePath, $xPath, $attribute, $value) + public function assertZipXmlAttributeContains($filePath, $xPath, $attribute, $value): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertContains($value, $nodeList->item(0)->getAttribute($attribute)); + /** @var DOMElement $nodeItem */ + $nodeItem = $nodeList->item(0); + self::assertInstanceOf(DOMElement::class, $nodeItem); + self::assertStringContainsString($value, $nodeItem->getAttribute($attribute)); } /** @@ -289,11 +377,14 @@ public function assertZipXmlAttributeContains($filePath, $xPath, $attribute, $va * @param string $xPath * @param string $attribute */ - public function assertZipXmlAttributeExists($filePath, $xPath, $attribute) + public function assertZipXmlAttributeExists($filePath, $xPath, $attribute): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertTrue($nodeList->item(0)->hasAttribute($attribute)); + /** @var DOMElement $nodeItem */ + $nodeItem = $nodeList->item(0); + self::assertInstanceOf(DOMElement::class, $nodeItem); + self::assertTrue($nodeItem->hasAttribute($attribute)); } /** @@ -301,10 +392,182 @@ public function assertZipXmlAttributeExists($filePath, $xPath, $attribute) * @param string $xPath * @param string $attribute */ - public function assertZipXmlAttributeNotExists($filePath, $xPath, $attribute) + public function assertZipXmlAttributeNotExists($filePath, $xPath, $attribute): void { $this->writePresentationFile($this->oPresentation, $this->writerName); $nodeList = $this->getXmlNodeList($filePath, $xPath); - self::assertFalse($nodeList->item(0)->hasAttribute($attribute)); + /** @var DOMElement $nodeItem */ + $nodeItem = $nodeList->item(0); + self::assertInstanceOf(DOMElement::class, $nodeItem); + self::assertFalse($nodeItem->hasAttribute($attribute)); + } + + public function assertIsSchemaECMA376Valid(): void + { + // validate all XML files + $path = realpath($this->workDirectory . '/ppt'); + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); + + foreach ($iterator as $file) { + /** @var \SplFileInfo $file */ + if ('xml' !== $file->getExtension()) { + continue; + } + + $fileName = str_replace('\\', '/', substr($file->getRealPath(), strlen($path) + 1)); + $dom = $this->getXmlDom('ppt/' . $fileName); + $xmlSource = $dom->saveXML(); + + $dom->loadXML($xmlSource); + $dom->schemaValidate(__DIR__ . '/../../../resources/schema/ecma-376/pml.xsd'); + + $error = libxml_get_last_error(); + if ($error instanceof LibXMLError) { + $this->failXmlError($error, $fileName, $xmlSource); + } + } + unset($iterator); + } + + public function assertIsSchemaOOXMLValid(): void + { + // validate all XML files + $path = realpath($this->workDirectory . '/ppt'); + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); + + foreach ($iterator as $file) { + /** @var \SplFileInfo $file */ + if ('xml' !== $file->getExtension()) { + continue; + } + + $fileName = str_replace('\\', '/', substr($file->getRealPath(), strlen($path) + 1)); + $dom = $this->getXmlDom('ppt/' . $fileName); + $xmlSource = $dom->saveXML(); + // In the ISO/ECMA standard the namespace has changed from + // http://schemas.openxmlformats.org/ to http://purl.oclc.org/ooxml/ + // We need to use the http://purl.oclc.org/ooxml/ namespace to validate + // the xml against the current schema + $xmlSource = str_replace([ + 'http://schemas.openxmlformats.org/drawingml/2006/main', + 'http://schemas.openxmlformats.org/drawingml/2006/chart', + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships', + 'http://schemas.openxmlformats.org/presentationml/2006/main', + ], [ + 'http://purl.oclc.org/ooxml/drawingml/main', + 'http://purl.oclc.org/ooxml/drawingml/chart', + 'http://purl.oclc.org/ooxml/officeDocument/relationships', + 'http://purl.oclc.org/ooxml/presentationml/main', + ], $xmlSource); + + $dom->loadXML($xmlSource); + $dom->schemaValidate(__DIR__ . '/../../../resources/schema/ooxml/pml.xsd'); + + $error = libxml_get_last_error(); + if ($error instanceof LibXMLError) { + $this->failXmlError($error, $fileName, $xmlSource); + } + } + unset($iterator); + } + + public function assertIsSchemaOpenDocumentValid(string $version = '1.0', bool $triggerError = true): bool + { + if (!array_key_exists($version, $this->arrayOpenDocumentRNG)) { + self::fail('assertIsSchemaOpenDocumentValid > Use a valid version'); + } + + // validate all XML files + $path = realpath($this->workDirectory); + $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); + + $isValid = true; + foreach ($iterator as $file) { + /** @var \SplFileInfo $file */ + if ('xml' !== $file->getExtension()) { + continue; + } + + $fileName = str_replace('\\', '/', substr($file->getRealPath(), strlen($path) + 1)); + $dom = $this->getXmlDom($fileName); + $xmlSource = $dom->saveXML(); + + $dom->loadXML($xmlSource); + $pathRNG = __DIR__ . '/../../../resources/schema/opendocument/' . $version . '/'; + if (isset($this->arrayOpenDocumentRNG[$version][$fileName])) { + $pathRNG .= $this->arrayOpenDocumentRNG[$version][$fileName]; + } else { + $pathRNG .= $this->arrayOpenDocumentRNG[$version]['*']; + } + $dom->relaxNGValidate($pathRNG); + + $error = libxml_get_last_error(); + if ($error instanceof LibXMLError) { + if ($triggerError) { + $this->failXmlError($error, $fileName, $xmlSource, ['version' => $version]); + } + $isValid = false; + } + } + unset($iterator); + + return $isValid; + } + + public function assertIsSchemaOpenDocumentNotValid(string $version = '1.0'): void + { + $isValid = $this->assertIsSchemaOpenDocumentValid($version, false); + if ($isValid) { + self::fail('Failed : This document is currently valid (Schema version: ' . $version . ')'); + } + } + + /** + * @param array $params + */ + protected function failXmlError(LibXMLError $error, string $fileName, string $source, array $params = []): void + { + switch ($error->level) { + case LIBXML_ERR_WARNING: + $errorType = 'warning'; + break; + case LIBXML_ERR_ERROR: + $errorType = 'error'; + break; + case LIBXML_ERR_FATAL: + $errorType = 'fatal'; + break; + default: + $errorType = 'Error'; + break; + } + $errorLine = (int) $error->line; + $contents = explode("\n", $source); + $lines = []; + if (isset($contents[$errorLine - 2])) { + $lines[] = '>> ' . $contents[$errorLine - 2]; + } + if (isset($contents[$errorLine - 1])) { + $lines[] = '>>> ' . $contents[$errorLine - 1]; + } + if (isset($contents[$errorLine])) { + $lines[] = '>> ' . $contents[$errorLine]; + } + $paramStr = ''; + if (!empty($params)) { + $paramStr .= "\n" . ' - Parameters :' . "\n"; + foreach ($params as $key => $val) { + $paramStr .= ' - ' . $key . ' : ' . $val . "\n"; + } + } + self::fail(sprintf( + "Validation %s :\n - File : %s\n - Line : %s\n - Message : %s - Lines :\n%s%s", + $errorType, + $fileName, + $error->line, + $error->message, + implode(PHP_EOL, $lines), + $paramStr + )); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 0f97f20aab..88d30d03ca 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -10,11 +10,13 @@ * file that was distributed with this source code. For the full list of * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors. * - * @copyright 2010-2014 PhpPresentation contributors + * @see https://github.com/PHPOffice/PHPPresentation + * + * @copyright 2009-2015 PHPPresentation contributors * @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3 - * @link https://github.com/PHPOffice/PHPPresentation */ +declare(strict_types=1); date_default_timezone_set('UTC'); // defining base dir for tests @@ -24,23 +26,23 @@ $vendor = realpath(__DIR__ . '/../vendor'); -if (file_exists($vendor . "/autoload.php")) { - require $vendor . "/autoload.php"; +if (file_exists($vendor . '/autoload.php')) { + require $vendor . '/autoload.php'; } else { $vendor = realpath(__DIR__ . '/../../../'); - if (file_exists($vendor . "/autoload.php")) { - require $vendor . "/autoload.php"; + if (file_exists($vendor . '/autoload.php')) { + require $vendor . '/autoload.php'; } else { - throw new Exception("Unable to load dependencies"); + throw new Exception('Unable to load dependencies'); } } spl_autoload_register(function ($class) { $class = ltrim($class, '\\'); $prefix = 'PhpOffice\\PhpPresentation\\Tests'; - if (strpos($class, $prefix) === 0) { + if (0 === strpos($class, $prefix)) { $class = str_replace('\\', DIRECTORY_SEPARATOR, $class); - $class = join(DIRECTORY_SEPARATOR, array('PhpPresentation', 'Tests', '_includes')) . + $class = join(DIRECTORY_SEPARATOR, ['PhpPresentation', 'Tests', '_includes']) . substr($class, strlen($prefix)); $file = __DIR__ . DIRECTORY_SEPARATOR . $class . '.php'; if (file_exists($file)) { @@ -49,5 +51,5 @@ } }); -require_once __DIR__ . "/../src/PhpPresentation/Autoloader.php"; +require_once __DIR__ . '/../src/PhpPresentation/Autoloader.php'; \PhpOffice\PhpPresentation\Autoloader::register(); diff --git a/tests/resources/images/base64_png.txt b/tests/resources/images/base64_png.txt new file mode 100644 index 0000000000..28f3c3fcce --- /dev/null +++ b/tests/resources/images/base64_png.txt @@ -0,0 +1 @@ +data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9PjsBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O//AABEIAtAFAAMBIgACEQEDEQH/xAAcAAEAAwEBAQEBAAAAAAAAAAAABAUGAwcCAQj/xABdEAABAwICAwYQCgcGBQIFBQEAAQIDBAUGERIhMQcTFkFR0RQVIjU2VFVhcXORkpOxssEXMjRSU3KBlKHSIzM3QlZ0giRioqPC4aSz0+LwQ2QlY2XD8SZFR4OERv/EABsBAQACAwEBAAAAAAAAAAAAAAADBQIEBgEH/8QAQREAAQMCBAMDCgUDAwQDAQEAAAECAwQREiExUQUTQRRhcSIyM1KBkaGxwfAVIzRC0TZy4QZT8RYkkqIlQ2KCNf/aAAwDAQACEQMRAD8A+eklo7l0f3dnMOklo7l0f3dnMTQddy2bIVeJ25C6SWjuXR/d2cw6SWjuXR/d2cxNA5bNkPMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7s5iaBy2bIMTtyF0ktHcuj+7s5h0ktHcuj+7t5iaBy2bIMTtzhT0VJSaXQtLDBp5aW9xo3PLlyO4BkiImh5cAAyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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 \ No newline at end of file diff --git a/tests/resources/images/base64_svg.txt b/tests/resources/images/base64_svg.txt new file mode 100644 index 0000000000..c752da2145 --- /dev/null +++ b/tests/resources/images/base64_svg.txt @@ -0,0 +1,1697 @@ +data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJM +SUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3Mv +U1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAw +MC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBoZWlnaHQ9 +IjgwMCI+CiA8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyMDAsMjAwKSIgc3R5bGU9ImZpbGwtb3Bh +Y2l0eToxOyBmaWxsOm5vbmU7Ij4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAw +MDAwMDsgc3Ryb2tlLXdpZHRoOjAuMTcyIj4KICA8cGF0aCBkPSJNLTEyMi4zMDQgODQuMjg1Qy0x +MjIuMzA0IDg0LjI4NSAtMTIyLjIwMyA4Ni4xNzkgLTEyMy4wMjcgODYuMTZDLTEyMy44NTEgODYu +MTQxIC0xNDAuMzA1IDM4LjA2NiAtMTYwLjgzMyA0MC4zMDlDLTE2MC44MzMgNDAuMzA5IC0xNDMu +MDUgMzIuOTU2IC0xMjIuMzA0IDg0LjI4NXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZm +ZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMTcyIj4KICA8cGF0aCBkPSJNLTEx +OC43NzQgODEuMjYyQy0xMTguNzc0IDgxLjI2MiAtMTE5LjMyMyA4My4wNzggLTEyMC4wOTIgODIu +Nzc5Qy0xMjAuODYgODIuNDgxIC0xMTkuOTc3IDMxLjY3NSAtMTQwLjA0MyAyNi44MDFDLTE0MC4w +NDMgMjYuODAxIC0xMjAuODIgMjUuOTM3IC0xMTguNzc0IDgxLjI2MnoiLz4KIDwvZz4KIDxnIHN0 +eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMTcyIj4K +ICA8cGF0aCBkPSJNLTkxLjI4NCAxMjMuNTlDLTkxLjI4NCAxMjMuNTkgLTg5LjY0OCAxMjQuNTUg +LTkwLjExOCAxMjUuMjI3Qy05MC41ODkgMTI1LjkwNCAtMTM5Ljc2MyAxMTMuMTAyIC0xNDkuMjE4 +IDEzMS40NTlDLTE0OS4yMTggMTMxLjQ1OSAtMTQ1LjUzOSAxMTIuNTcyIC05MS4yODQgMTIzLjU5 +eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAwMDAwOyBzdHJv +a2Utd2lkdGg6MC4xNzIiPgogIDxwYXRoIGQ9Ik0tOTQuMDkzIDEzMy44MDFDLTk0LjA5MyAxMzMu +ODAxIC05Mi4yMzcgMTM0LjE5NyAtOTIuNDcxIDEzNC45ODhDLTkyLjcwNCAxMzUuNzc5IC0xNDMu +NDA3IDEzOS4xMjEgLTE0Ni41OTcgMTU5LjUyMkMtMTQ2LjU5NyAxNTkuNTIyIC0xNDkuMDU1IDE0 +MC40MzcgLTk0LjA5MyAxMzMuODAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7 +IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xNzIiPgogIDxwYXRoIGQ9Ik0tOTguMzA0 +IDEyOC4yNzZDLTk4LjMwNCAxMjguMjc2IC05Ni41MjYgMTI4LjkzOSAtOTYuODcyIDEyOS42ODdD +LTk3LjIxOCAxMzAuNDM1IC0xNDcuODY2IDEyNi4zNDYgLTE1My45OTggMTQ2LjA2NEMtMTUzLjk5 +OCAxNDYuMDY0IC0xNTMuNjQ2IDEyNi44MjUgLTk4LjMwNCAxMjguMjc2eiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xNzIi +PgogIDxwYXRoIGQ9Ik0tMTA5LjAwOSAxMTAuMDcyQy0xMDkuMDA5IDExMC4wNzIgLTEwNy43MDEg +MTExLjQ0NiAtMTA4LjM0IDExMS45NjdDLTEwOC45NzkgMTEyLjQ4OCAtMTUyLjcyMiA4Ni42MzQg +LTE2Ni44NjkgMTAxLjY3NkMtMTY2Ljg2OSAxMDEuNjc2IC0xNTguMTI4IDg0LjUzMyAtMTA5LjAw +OSAxMTAuMDcyeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAw +MDAwOyBzdHJva2Utd2lkdGg6MC4xNzIiPgogIDxwYXRoIGQ9Ik0tMTE2LjU1NCAxMTQuMjYzQy0x +MTYuNTU0IDExNC4yNjMgLTExNS4wOTggMTE1LjQ4IC0xMTUuNjc0IDExNi4wNzFDLTExNi4yNSAx +MTYuNjYxIC0xNjIuNjM4IDk1LjkyMiAtMTc0Ljk5MiAxMTIuNDY5Qy0xNzQuOTkyIDExMi40Njkg +LTE2OC4yNDcgOTQuNDQ3IC0xMTYuNTU0IDExNC4yNjN6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmls +bDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjE3MiI+CiAgPHBhdGgg +ZD0iTS0xMTkuMTU0IDExOC4zMzVDLTExOS4xNTQgMTE4LjMzNSAtMTE3LjU0NiAxMTkuMzQzIC0x +MTguMDM2IDEyMC4wMDZDLTExOC41MjYgMTIwLjY2OSAtMTY3LjMwOCAxMDYuNDQ2IC0xNzcuMjkx +IDEyNC41MjJDLTE3Ny4yOTEgMTI0LjUyMiAtMTczLjA2NiAxMDUuNzQ5IC0xMTkuMTU0IDExOC4z +MzV6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0 +cm9rZS13aWR0aDowLjE3MiI+CiAgPHBhdGggZD0iTS0xMDguNDIgMTE4Ljk0OUMtMTA4LjQyIDEx +OC45NDkgLTEwNy4yOTggMTIwLjQ4IC0xMDcuOTk5IDEyMC45MTVDLTEwOC43IDEyMS4zNSAtMTQ4 +Ljc2OSA5MC4xMDIgLTE2NC43MjcgMTAzLjIwN0MtMTY0LjcyNyAxMDMuMjA3IC0xNTMuODYyIDg3 +LjMyNiAtMTA4LjQyIDExOC45NDl6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsg +c3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjE3MiI+CiAgPHBhdGggZD0iTS0xMjguMiA5 +MEMtMTI4LjIgOTAgLTEyNy42IDkxLjggLTEyOC40IDkyQy0xMjkuMiA5Mi4yIC0xNTcuOCA1MC4y +IC0xNzcuMDAxIDU3LjhDLTE3Ny4wMDEgNTcuOCAtMTYxLjggNDYgLTEyOC4yIDkweiIvPgogPC9n +PgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6 +MC4xNzIiPgogIDxwYXRoIGQ9Ik0tMTI3LjUwNSA5Ni45NzlDLTEyNy41MDUgOTYuOTc5IC0xMjYu +NTMgOTguNjA4IC0xMjcuMjY5IDk4Ljk3NUMtMTI4LjAwNyA5OS4zNDMgLTE2NC45OTIgNjQuNDk5 +IC0xODIuMTAxIDc2LjA2MUMtMTgyLjEwMSA3Ni4wNjEgLTE2OS44MDQgNjEuMjYxIC0xMjcuNTA1 +IDk2Ljk3OXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAw +MDsgc3Ryb2tlLXdpZHRoOjAuMTcyIj4KICA8cGF0aCBkPSJNLTEyNy42MiAxMDEuMzQ5Qy0xMjcu +NjIgMTAxLjM0OSAtMTI2LjQ5OCAxMDIuODggLTEyNy4xOTkgMTAzLjMxNUMtMTI3LjkgMTAzLjc0 +OSAtMTY3Ljk2OSA3Mi41MDIgLTE4My45MjcgODUuNjA3Qy0xODMuOTI3IDg1LjYwNyAtMTczLjA2 +MiA2OS43MjYgLTEyNy42MiAxMDEuMzQ5eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZm +ZmY7IHN0cm9rZTojMDAwMDAwIj4KICA8cGF0aCBkPSJNLTEyOS44MyAxMDMuMDY1Qy0xMjkuMzI3 +IDEwOS4xMTMgLTEyOC4zMzkgMTE1LjY4MiAtMTI2LjYgMTE4LjgwMUMtMTI2LjYgMTE4LjgwMSAt +MTMwLjIgMTMxLjIwMSAtMTIxLjQgMTQ0LjQwMUMtMTIxLjQgMTQ0LjQwMSAtMTIxLjggMTUxLjYw +MSAtMTIwLjIgMTU0LjgwMUMtMTIwLjIgMTU0LjgwMSAtMTE2LjIgMTYzLjIwMSAtMTExLjQgMTY0 +LjAwMUMtMTA3LjUxNiAxNjQuNjQ4IC05OC43OTMgMTY3LjcxNyAtODguOTMyIDE2OS4xMjFDLTg4 +LjkzMiAxNjkuMTIxIC03MS44IDE4My4yMDEgLTc1IDE5Ni4wMDFDLTc1IDE5Ni4wMDEgLTc1LjQg +MjEyLjQwMSAtNzkgMjE0LjAwMUMtNzkgMjE0LjAwMSAtNjcuNCAyMDIuODAxIC03NyAyMTkuNjAx +TC04MS40IDIzOC40MDFDLTgxLjQgMjM4LjQwMSAtNTUuOCAyMTYuODAxIC03MS40IDIzNS4yMDFM +LTgxLjQgMjYxLjIwMUMtODEuNCAyNjEuMjAxIC02MS44IDI0Mi44MDEgLTY5IDI1MS4yMDFMLTcy +LjIgMjYwLjAwMUMtNzIuMiAyNjAuMDAxIC0yOSAyMzIuODAxIC01OS44IDI2Mi40MDFDLTU5Ljgg +MjYyLjQwMSAtNTEuOCAyNTguODAxIC00Ny40IDI2MS42MDFDLTQ3LjQgMjYxLjYwMSAtNDAuNiAy +NjAuNDAxIC00MS40IDI2Mi4wMDFDLTQxLjQgMjYyLjAwMSAtNjIuMiAyNzIuNDAxIC02NS44IDI5 +MC44MDFDLTY1LjggMjkwLjgwMSAtNTcuNCAyODAuODAxIC02MC42IDI5MS42MDFMLTYwLjIgMzAz +LjIwMUMtNjAuMiAzMDMuMjAxIC01Ni4yIDI4MS42MDEgLTU2LjYgMzE5LjIwMUMtNTYuNiAzMTku +MjAxIC0zNy40IDMwMS4yMDEgLTQ5IDMyMi4wMDFMLTQ5IDMzOC44MDFDLTQ5IDMzOC44MDEgLTMz +LjggMzIyLjQwMSAtNDAuMiAzMzUuMjAxQy00MC4yIDMzNS4yMDEgLTMwLjIgMzI2LjQwMSAtMzQu +MiAzNDEuNjAxQy0zNC4yIDM0MS42MDEgLTM1IDM1Mi4wMDEgLTMwLjYgMzQwLjgwMUMtMzAuNiAz +NDAuODAxIC0xNC42IDMxMC4yMDEgLTIwLjYgMzM2LjQwMUMtMjAuNiAzMzYuNDAxIC0yMS40IDM1 +NS42MDEgLTE2LjYgMzQwLjgwMUMtMTYuNiAzNDAuODAxIC0xNi4yIDM1MS4yMDEgLTcgMzU4LjQw +MUMtNyAzNTguNDAxIC04LjIgMzA3LjYwMSA0LjYgMzQzLjYwMUw4LjYgMzYwLjAwMUM4LjYgMzYw +LjAwMSAxMS40IDM1MC44MDEgMTEgMzQ1LjYwMUMxMSAzNDUuNjAxIDI1LjggMzI5LjIwMSAxOSAz +NTMuNjAxQzE5IDM1My42MDEgMzQuMiAzMzAuODAxIDMxIDM0NC4wMDFDMzEgMzQ0LjAwMSAyMy40 +IDM2MC4wMDEgMjUgMzY0LjgwMUMyNSAzNjQuODAxIDQxLjggMzMwLjAwMSA0MyAzMjguNDAxQzQz +IDMyOC40MDEgNDEgMzcwLjgwMiA1MS44IDMzNC44MDFDNTEuOCAzMzQuODAxIDU3LjQgMzQ2Ljgw +MSA1NC42IDM1MS4yMDFDNTQuNiAzNTEuMjAxIDYyLjYgMzQzLjIwMSA2MS44IDM0MC4wMDFDNjEu +OCAzNDAuMDAxIDY2LjQgMzMxLjgwMSA2OS4yIDM0NS40MDFDNjkuMiAzNDUuNDAxIDcxIDM1NC44 +MDEgNzIuNiAzNTEuNjAxQzcyLjYgMzUxLjYwMSA3Ni42IDM3NS42MDIgNzcuOCAzNTIuODAxQzc3 +LjggMzUyLjgwMSA3OS40IDMzOS4yMDEgNzIuMiAzMjcuNjAxQzcyLjIgMzI3LjYwMSA3MyAzMjQu +NDAxIDcwLjIgMzIwLjQwMUM3MC4yIDMyMC40MDEgODMuOCAzNDIuMDAxIDc2LjYgMzEzLjIwMUM3 +Ni42IDMxMy4yMDEgODcuODAxIDMyMS4yMDEgODkuMDAxIDMyMS4yMDFDODkuMDAxIDMyMS4yMDEg +NzUuNCAyOTguMDAxIDg0LjIgMzAyLjgwMUM4NC4yIDMwMi44MDEgNzkgMjkyLjQwMSA5Ny4wMDEg +MzA0LjQwMUM5Ny4wMDEgMzA0LjQwMSA4MSAyODguNDAxIDk4LjYwMSAyOTguMDAxQzk4LjYwMSAy +OTguMDAxIDEwNi42MDEgMzA0LjQwMSA5OS4wMDEgMjk0LjQwMUM5OS4wMDEgMjk0LjQwMSA4NC42 +IDI3OC40MDEgMTA2LjYwMSAyOTYuNDAxQzEwNi42MDEgMjk2LjQwMSAxMTguMjAxIDMxMi44MDEg +MTE5LjAwMSAzMTUuNjAxQzExOS4wMDEgMzE1LjYwMSAxMDkuMDAxIDI4Ni40MDEgMTA0LjYwMSAy +ODMuNjAxQzEwNC42MDEgMjgzLjYwMSAxMTMuMDAxIDI0Ny4yMDEgMTU0LjIwMSAyNjIuODAxQzE1 +NC4yMDEgMjYyLjgwMSAxNjEuMDAxIDI4MC4wMDEgMTY1LjQwMSAyNjEuNjAxQzE2NS40MDEgMjYx +LjYwMSAxNzguMjAxIDI1NS4yMDEgMTg5LjQwMSAyODIuODAxQzE4OS40MDEgMjgyLjgwMSAxOTMu +NDAxIDI2OS4yMDEgMTkyLjYwMSAyNjYuNDAxQzE5Mi42MDEgMjY2LjQwMSAxOTkuNDAxIDI2Ny42 +MDEgMTk4LjYwMSAyNjYuNDAxQzE5OC42MDEgMjY2LjQwMSAyMTEuODAxIDI3MC44MDEgMjEzLjAw +MSAyNzAuMDAxQzIxMy4wMDEgMjcwLjAwMSAyMTkuODAxIDI3Ni44MDEgMjIwLjIwMSAyNzMuMjAx +QzIyMC4yMDEgMjczLjIwMSAyMjkuNDAxIDI3Ni4wMDEgMjI3LjQwMSAyNzIuNDAxQzIyNy40MDEg +MjcyLjQwMSAyMzYuMjAxIDI4OC4wMDEgMjM2LjYwMSAyOTEuNjAxTDIzOS4wMDEgMjc3LjYwMUwy +NDEuMDAxIDI4MC40MDFDMjQxLjAwMSAyODAuNDAxIDI0Mi42MDEgMjcyLjgwMSAyNDEuODAxIDI3 +MS42MDFDMjQxLjAwMSAyNzAuNDAxIDI2MS44MDEgMjc4LjQwMSAyNjYuNjAxIDI5OS4yMDFMMjY4 +LjYwMSAzMDcuNjAxQzI2OC42MDEgMzA3LjYwMSAyNzQuNjAxIDI5Mi44MDEgMjczLjAwMSAyODgu +ODAxQzI3My4wMDEgMjg4LjgwMSAyNzguMjAxIDI4OS42MDEgMjc4LjYwMSAyOTQuMDAxQzI3OC42 +MDEgMjk0LjAwMSAyODIuNjAxIDI3MC44MDEgMjc3LjgwMSAyNjQuODAxQzI3Ny44MDEgMjY0Ljgw +MSAyODIuMjAxIDI2NC4wMDEgMjgzLjQwMSAyNjcuNjAxTDI4My40MDEgMjYwLjQwMUMyODMuNDAx +IDI2MC40MDEgMjkwLjYwMSAyNjEuMjAxIDI5MC42MDEgMjU4LjgwMUMyOTAuNjAxIDI1OC44MDEg +Mjk1LjAwMSAyNTQuODAxIDI5Ny4wMDEgMjU5LjYwMUMyOTcuMDAxIDI1OS42MDEgMjg0LjYwMSAy +MjQuNDAxIDMwMy4wMDEgMjQzLjYwMUMzMDMuMDAxIDI0My42MDEgMzEwLjIwMSAyNTQuNDAxIDMw +Ni42MDEgMjM1LjYwMUMzMDMuMDAxIDIxNi44MDEgMjk5LjAwMSAyMTUuMjAxIDMwMy44MDEgMjE0 +LjgwMUMzMDMuODAxIDIxNC44MDEgMzA0LjYwMSAyMTEuMjAxIDMwMi42MDEgMjA5LjYwMUMzMDAu +NjAxIDIwOC4wMDEgMzAzLjgwMSAyMDkuNjAxIDMwMy44MDEgMjA5LjYwMUMzMDMuODAxIDIwOS42 +MDEgMzA4LjYwMSAyMTMuNjAxIDMwMy40MDEgMTkxLjYwMUMzMDMuNDAxIDE5MS42MDEgMzA5Ljgw +MSAxOTMuMjAxIDI5Ny44MDEgMTY0LjAwMUMyOTcuODAxIDE2NC4wMDEgMzAwLjYwMSAxNjEuNjAx +IDI5Ni42MDEgMTUzLjIwMUMyOTYuNjAxIDE1My4yMDEgMzA0LjYwMSAxNTcuNjAxIDMwNy40MDEg +MTU2LjAwMUMzMDcuNDAxIDE1Ni4wMDEgMzA3LjAwMSAxNTQuNDAxIDMwMy44MDEgMTUwLjQwMUMz +MDMuODAxIDE1MC40MDEgMjgyLjIwMSA5NS42IDMwMi42MDEgMTE3LjYwMUMzMDIuNjAxIDExNy42 +MDEgMzE0LjQ1MSAxMzEuMTUxIDMwOC4wNTEgMTA4LjM1MUMzMDguMDUxIDEwOC4zNTEgMjk4Ljk0 +IDg0LjM0MSAyOTkuNzE3IDgwLjA0NUwtMTI5LjgzIDEwMy4wNjV6Ii8+CiA8L2c+CiA8ZyBzdHls +ZT0iZmlsbDogI2NjNzIyNjsgc3Ryb2tlOiMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0yOTkuNzE3IDgw +LjI0NUMzMDAuMzQ1IDgwLjQyNiAzMDIuNTUxIDgxLjU1IDMwMy44MDEgODMuMkMzMDMuODAxIDgz +LjIgMzEwLjYwMSA5NCAzMDUuNDAxIDc1LjZDMzA1LjQwMSA3NS42IDI5Ni4yMDEgNDYuOCAzMDUu +MDAxIDU4QzMwNS4wMDEgNTggMzExLjAwMSA2NS4yIDMwNy44MDEgNTEuNkMzMDMuOTM2IDM1LjE3 +MyAzMDEuNDAxIDI4LjggMzAxLjQwMSAyOC44QzMwMS40MDEgMjguOCAzMTMuMDAxIDMzLjYgMjg2 +LjIwMSAtNkwyOTUuMDAxIC0yLjRDMjk1LjAwMSAtMi40IDI3NS40MDEgLTQyIDI1My44MDEgLTQ3 +LjJMMjQ1LjgwMSAtNTMuMkMyNDUuODAxIC01My4yIDI4NC4yMDEgLTkxLjIgMjcxLjQwMSAtMTI4 +QzI3MS40MDEgLTEyOCAyNjQuNjAxIC0xMzMuMiAyNTUuMDAxIC0xMjRDMjU1LjAwMSAtMTI0IDI0 +OC42MDEgLTExOS4yIDI0Mi42MDEgLTEyMC44QzI0Mi42MDEgLTEyMC44IDIxMS44MDEgLTExOS42 +IDIwOS44MDEgLTExOS42QzIwNy44MDEgLTExOS42IDE3My4wMDEgLTE1Ni44IDEwNy40MDEgLTEz +OS4yQzEwNy40MDEgLTEzOS4yIDEwMi4yMDEgLTEzNy4yIDk3LjgwMSAtMTM4LjRDOTcuODAxIC0x +MzguNCA3OS40IC0xNTQuNCAzMC42IC0xMzEuNkMzMC42IC0xMzEuNiAyMC42IC0xMjkuNiAxOSAt +MTI5LjZDMTcuNCAtMTI5LjYgMTQuNiAtMTI5LjYgNi42IC0xMjMuMkMtMS40IC0xMTYuOCAtMS44 +IC0xMTYgLTMuOCAtMTE0LjRDLTMuOCAtMTE0LjQgLTIwLjIgLTEwMy4yIC0yNSAtMTAyLjRDLTI1 +IC0xMDIuNCAtMzYuNiAtOTYgLTQxIC04NkwtNDQuNiAtODQuOEMtNDQuNiAtODQuOCAtNDYuMiAt +NzcuNiAtNDYuNiAtNzYuNEMtNDYuNiAtNzYuNCAtNTEuNCAtNzIuOCAtNTIuMiAtNjcuMkMtNTIu +MiAtNjcuMiAtNjEgLTYxLjIgLTYwLjYgLTU2LjhDLTYwLjYgLTU2LjggLTYyLjIgLTUxLjYgLTYz +IC00Ni44Qy02MyAtNDYuOCAtNzAuMiAtNDIgLTY5LjQgLTM5LjJDLTY5LjQgLTM5LjIgLTc3IC0y +NS4yIC03NS44IC0xOC40Qy03NS44IC0xOC40IC04Mi4yIC0xOC44IC04NSAtMTYuNEMtODUgLTE2 +LjQgLTg1LjggLTExLjYgLTg3LjQgLTExLjJDLTg3LjQgLTExLjIgLTkwLjIgLTEwIC04Ny44IC02 +Qy04Ny44IC02IC04OS40IC0zLjIgLTg5LjggLTEuNkMtODkuOCAtMS42IC04OSAxLjIgLTkzLjQg +Ni44Qy05My40IDYuOCAtOTkuOCAyNS42IC05Ny44IDMwLjhDLTk3LjggMzAuOCAtOTcuNCAzNS42 +IC0xMDAuMiAzNy4yQy0xMDAuMiAzNy4yIC0xMDMuOCAzNi44IC05NS40IDQ4LjhDLTk1LjQgNDgu +OCAtOTQuNiA1MCAtOTcuOCA1Mi40Qy05Ny44IDUyLjQgLTExNSA1NiAtMTE3LjQgNzIuNEMtMTE3 +LjQgNzIuNCAtMTMxIDg3LjIgLTEzMSA5Mi40Qy0xMzEgOTQuNzA1IC0xMzAuNzI5IDk3Ljg1MiAt +MTMwLjAzIDEwMi40NjVDLTEzMC4wMyAxMDIuNDY1IC0xMzAuNiAxMTAuODAxIC0xMDMgMTExLjYw +MUMtNzUuNCAxMTIuNDAxIDI5OS43MTcgODAuMjQ1IDI5OS43MTcgODAuMjQ1eiIvPgogPC9nPgog +PGcgc3R5bGU9ImZpbGw6ICNjYzcyMjYiPgogIDxwYXRoIGQ9Ik0tMTE1LjYgMTAyLjZDLTE0MC42 +IDYzLjIgLTEyNi4yIDExOS42MDEgLTEyNi4yIDExOS42MDFDLTExNy40IDE1NC4wMDEgMTIuMiAx +MTYuNDAxIDEyLjIgMTE2LjQwMUMxMi4yIDExNi40MDEgMTgxLjAwMSA4NiAxOTIuMjAxIDgyQzIw +My40MDEgNzggMjk4LjYwMSA4NC40IDI5OC42MDEgODQuNEwyOTMuMDAxIDY3LjZDMjI4LjIwMSAy +MS4yIDIwOS4wMDEgNDQuNCAxOTUuNDAxIDQwLjRDMTgxLjgwMSAzNi40IDE4NC4yMDEgNDYgMTgx +LjAwMSA0Ni44QzE3Ny44MDEgNDcuNiAxMzguNjAxIDIyLjggMTMyLjIwMSAyMy42QzEyNS44MDEg +MjQuNCAxMDAuNDU5IDAuNjQ5IDExNS40MDEgMzIuNEMxMzEuNDAxIDY2LjQgNTcgNzEuNiA0MC4y +IDYwLjRDMjMuNCA0OS4yIDQ3LjQgNzguOCA0Ny40IDc4LjhDNjUuOCA5OC44IDMxLjQgODIgMzEu +NCA4MkMtMyA2OS4yIC0yNyA5NC44IC0zMC4yIDk1LjZDLTMzLjQgOTYuNCAtMzguMiA5OS42IC0z +OSA5My4yQy0zOS44IDg2LjggLTQ3LjMxIDcwLjA5OSAtNzkgOTYuNEMtOTkgMTEzLjAwMSAtMTEy +LjggOTEgLTExMi44IDkxTC0xMTUuNiAxMDIuNnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +ZTg3ZjNhIj4KICA8cGF0aCBkPSJNMTMzLjUxIDI1LjM0NkMxMjcuMTEgMjYuMTQ2IDEwMS43NDMg +Mi40MDcgMTE2LjcxIDM0LjE0NkMxMzMuMzEgNjkuMzQ2IDU4LjMxIDczLjM0NiA0MS41MSA2Mi4x +NDZDMjQuNzA5IDUwLjk0NiA0OC43MSA4MC41NDYgNDguNzEgODAuNTQ2QzY3LjExIDEwMC41NDYg +MzIuNzA5IDgzLjc0NiAzMi43MDkgODMuNzQ2Qy0xLjY5MSA3MC45NDYgLTI1LjY5MSA5Ni41NDYg +LTI4Ljg5MSA5Ny4zNDZDLTMyLjA5MSA5OC4xNDYgLTM2Ljg5MSAxMDEuMzQ2IC0zNy42OTEgOTQu +OTQ2Qy0zOC40OTEgODguNTQ2IC00NS44NyA3Mi4wMTIgLTc3LjY5MSA5OC4xNDZDLTk4LjkyNyAx +MTUuNDkyIC0xMTIuNDE4IDk0LjAzNyAtMTEyLjQxOCA5NC4wMzdMLTExNS42MTggMTA0LjE0NkMt +MTQwLjYxOCA2NC4zNDYgLTEyNS41NDYgMTIyLjY1NSAtMTI1LjU0NiAxMjIuNjU1Qy0xMTYuNzQ1 +IDE1Ny4wNTYgMTMuNTA5IDExOC4xNDYgMTMuNTA5IDExOC4xNDZDMTMuNTA5IDExOC4xNDYgMTgy +LjMxIDg3Ljc0NiAxOTMuNTEgODMuNzQ2QzIwNC43MSA3OS43NDYgMjk5LjAzOCA4Ni4wNzMgMjk5 +LjAzOCA4Ni4wNzNMMjkzLjUxIDY4Ljc2NEMyMjguNzEgMjIuMzY0IDIxMC4zMSA0Ni4xNDYgMTk2 +LjcxIDQyLjE0NkMxODMuMTEgMzguMTQ2IDE4NS41MSA0Ny43NDYgMTgyLjMxIDQ4LjU0NkMxNzku +MTEgNDkuMzQ2IDEzOS45MSAyNC41NDYgMTMzLjUxIDI1LjM0NnoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjZWE4YzRkIj4KICA8cGF0aCBkPSJNMTM0LjgxOSAyNy4wOTFDMTI4LjQxOSAyNy44 +OTEgMTAzLjY4NSAzLjg2MiAxMTguMDE5IDM1Ljg5MUMxMzQuMjE5IDcyLjA5MiA1OS42MTkgNzUu +MDkyIDQyLjgxOSA2My44OTJDMjYuMDE5IDUyLjY5MiA1MC4wMTkgODIuMjkyIDUwLjAxOSA4Mi4y +OTJDNjguNDE5IDEwMi4yOTIgMzQuMDE5IDg1LjQ5MiAzNC4wMTkgODUuNDkyQy0wLjM4MSA3Mi42 +OTIgLTI0LjM4MiA5OC4yOTIgLTI3LjU4MiA5OS4wOTJDLTMwLjc4MiA5OS44OTIgLTM1LjU4MiAx +MDMuMDkyIC0zNi4zODIgOTYuNjkyQy0zNy4xODIgOTAuMjkyIC00NC40MyA3My45MjUgLTc2LjM4 +MiA5OS44OTJDLTk4Ljg1NSAxMTcuOTgzIC0xMTIuMDM2IDk3LjA3NCAtMTEyLjAzNiA5Ny4wNzRM +LTExNS42MzYgMTA1LjY5MkMtMTM5LjQzNiA2Ni42OTIgLTEyNC44OTEgMTI1LjcxIC0xMjQuODkx +IDEyNS43MUMtMTE2LjA5MSAxNjAuMTEgMTQuODE5IDExOS44OTIgMTQuODE5IDExOS44OTJDMTQu +ODE5IDExOS44OTIgMTgzLjYxOSA4OS40OTIgMTk0LjgxOSA4NS40OTJDMjA2LjAxOSA4MS40OTIg +Mjk5LjQ3NCA4Ny43NDYgMjk5LjQ3NCA4Ny43NDZMMjk0LjAyIDY5LjkyOEMyMjkuMjE5IDIzLjUy +OCAyMTEuNjE5IDQ3Ljg5MSAxOTguMDE5IDQzLjg5MUMxODQuNDE5IDM5Ljg5MSAxODYuODE5IDQ5 +LjQ5MSAxODMuNjE5IDUwLjI5MkMxODAuNDE5IDUxLjA5MiAxNDEuMjE5IDI2LjI5MSAxMzQuODE5 +IDI3LjA5MXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZWM5OTYxIj4KICA8cGF0aCBkPSJN +MTM2LjEyOCAyOC44MzdDMTI5LjcyOCAyOS42MzcgMTA0Ljk5OSA1LjYwNSAxMTkuMzI4IDM3LjYz +N0MxMzYuMTI4IDc1LjE5MyA2MC4zOTQgNzYuNDgyIDQ0LjEyOCA2NS42MzdDMjcuMzI4IDU0LjQz +NyA1MS4zMjggODQuMDM3IDUxLjMyOCA4NC4wMzdDNjkuNzI4IDEwNC4wMzcgMzUuMzI4IDg3LjIz +NyAzNS4zMjggODcuMjM3QzAuOTI4IDc0LjQzNyAtMjMuMDcyIDEwMC4wMzcgLTI2LjI3MiAxMDAu +ODM3Qy0yOS40NzIgMTAxLjYzNyAtMzQuMjcyIDEwNC44MzcgLTM1LjA3MiA5OC40MzdDLTM1Ljg3 +MiA5Mi4wMzcgLTQyLjk4OSA3NS44MzkgLTc1LjA3MyAxMDEuNjM3Qy05OC43ODIgMTIwLjQ3NCAt +MTExLjY1NSAxMDAuMTEgLTExMS42NTUgMTAwLjExTC0xMTUuNjU1IDEwNy4yMzdDLTEzNy40NTUg +NzAuNDM3IC0xMjQuMjM2IDEyOC43NjUgLTEyNC4yMzYgMTI4Ljc2NUMtMTE1LjQzNiAxNjMuMTY1 +IDE2LjEyOCAxMjEuNjM3IDE2LjEyOCAxMjEuNjM3QzE2LjEyOCAxMjEuNjM3IDE4NC45MjggOTEu +MjM3IDE5Ni4xMjkgODcuMjM3QzIwNy4zMjkgODMuMjM3IDI5OS45MTEgODkuNDE5IDI5OS45MTEg +ODkuNDE5TDI5NC41MjkgNzEuMDkyQzIyOS43MjkgMjQuNjkxIDIxMi45MjkgNDkuNjM3IDE5OS4z +MjkgNDUuNjM3QzE4NS43MjggNDEuNjM3IDE4OC4xMjggNTEuMjM3IDE4NC45MjggNTIuMDM3QzE4 +MS43MjggNTIuODM3IDE0Mi41MjggMjguMDM3IDEzNi4xMjggMjguODM3eiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNlZWE1NzUiPgogIDxwYXRoIGQ9Ik0xMzcuNDM4IDMwLjU4M0MxMzEuMDM3 +IDMxLjM4MyAxMDYuODE0IDcuMTI5IDEyMC42MzcgMzkuMzgzQzEzNy40MzggNzguNTgzIDYyLjIz +NyA3OC41ODMgNDUuNDM3IDY3LjM4M0MyOC42MzcgNTYuMTgzIDUyLjYzNyA4NS43ODMgNTIuNjM3 +IDg1Ljc4M0M3MS4wMzcgMTA1Ljc4MyAzNi42MzcgODguOTgzIDM2LjYzNyA4OC45ODNDMi4yMzcg +NzYuMTgzIC0yMS43NjMgMTAxLjc4MyAtMjQuOTYzIDEwMi41ODNDLTI4LjE2MyAxMDMuMzgzIC0z +Mi45NjMgMTA2LjU4MyAtMzMuNzYzIDEwMC4xODNDLTM0LjU2MyA5My43ODMgLTQxLjU0OCA3Ny43 +NTIgLTczLjc2MyAxMDMuMzgzQy05OC43MDkgMTIyLjk2NSAtMTExLjI3MyAxMDMuMTQ2IC0xMTEu +MjczIDEwMy4xNDZMLTExNS42NzMgMTA4Ljc4M0MtMTM1LjQ3MyA3My45ODIgLTEyMy41ODIgMTMx +LjgxOSAtMTIzLjU4MiAxMzEuODE5Qy0xMTQuNzgyIDE2Ni4yMiAxNy40MzcgMTIzLjM4MyAxNy40 +MzcgMTIzLjM4M0MxNy40MzcgMTIzLjM4MyAxODYuMjM4IDkyLjk4MyAxOTcuNDM4IDg4Ljk4M0My +MDguNjM4IDg0Ljk4MyAzMDAuMzQ3IDkxLjA5MiAzMDAuMzQ3IDkxLjA5MkwyOTUuMDM4IDcyLjI1 +NUMyMzAuMjM4IDI1Ljg1NSAyMTQuMjM4IDUxLjM4MyAyMDAuNjM4IDQ3LjM4M0MxODcuMDM4IDQz +LjM4MyAxODkuNDM4IDUyLjk4MyAxODYuMjM4IDUzLjc4M0MxODMuMDM4IDU0LjU4MyAxNDMuODM4 +IDI5Ljc4MyAxMzcuNDM4IDMwLjU4M3oiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZjFiMjg4 +Ij4KICA8cGF0aCBkPSJNMTM4Ljc0NyAzMi4zMjhDMTMyLjM0NyAzMy4xMjggMTA2LjM4MyA5LjY3 +NyAxMjEuOTQ3IDQxLjEyOEMxNDEuMTQ3IDc5LjkyOCA2My41NDYgODAuMzI4IDQ2Ljc0NiA2OS4x +MjhDMjkuOTQ2IDU3LjkyOCA1My45NDYgODcuNTI4IDUzLjk0NiA4Ny41MjhDNzIuMzQ2IDEwNy41 +MjggMzcuOTQ2IDkwLjcyOCAzNy45NDYgOTAuNzI4QzMuNTQ2IDc3LjkyOCAtMjAuNDU0IDEwMy41 +MjggLTIzLjY1NCAxMDQuMzI4Qy0yNi44NTQgMTA1LjEyOCAtMzEuNjU0IDEwOC4zMjggLTMyLjQ1 +NCAxMDEuOTI4Qy0zMy4yNTQgOTUuNTI4IC00MC4xMDggNzkuNjY1IC03Mi40NTQgMTA1LjEyOEMt +OTguNjM2IDEyNS40NTYgLTExMC44OTEgMTA2LjE4MyAtMTEwLjg5MSAxMDYuMTgzTC0xMTUuNjkx +IDExMC4zMjhDLTEzMy42OTEgNzcuMTI4IC0xMjIuOTI3IDEzNC44NzQgLTEyMi45MjcgMTM0Ljg3 +NEMtMTE0LjEyNyAxNjkuMjc0IDE4Ljc0NiAxMjUuMTI4IDE4Ljc0NiAxMjUuMTI4QzE4Ljc0NiAx +MjUuMTI4IDE4Ny41NDcgOTQuNzI4IDE5OC43NDcgOTAuNzI4QzIwOS45NDcgODYuNzI4IDMwMC43 +ODMgOTIuNzY0IDMwMC43ODMgOTIuNzY0TDI5NS41NDcgNzMuNDE5QzIzMC43NDcgMjcuMDE5IDIx +NS41NDcgNTMuMTI4IDIwMS45NDcgNDkuMTI4QzE4OC4zNDcgNDUuMTI4IDE5MC43NDcgNTQuNzI4 +IDE4Ny41NDcgNTUuNTI4QzE4NC4zNDcgNTYuMzI4IDE0NS4xNDcgMzEuNTI4IDEzOC43NDcgMzIu +MzI4eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmM2JmOWMiPgogIDxwYXRoIGQ9Ik0xNDAu +MDU2IDM0LjA3M0MxMzMuNjU1IDM0Ljg3MyAxMDcuMzEzIDExLjYxMyAxMjMuMjU1IDQyLjg3M0Mx +NDMuNjU2IDgyLjg3NCA2NC44NTUgODIuMDc0IDQ4LjA1NSA3MC44NzRDMzEuMjU1IDU5LjY3NCA1 +NS4yNTUgODkuMjc0IDU1LjI1NSA4OS4yNzRDNzMuNjU1IDEwOS4yNzQgMzkuMjU1IDkyLjQ3NCAz +OS4yNTUgOTIuNDc0QzQuODU1IDc5LjY3NCAtMTkuMTQ1IDEwNS4yNzQgLTIyLjM0NSAxMDYuMDc0 +Qy0yNS41NDUgMTA2Ljg3NCAtMzAuMzQ1IDExMC4wNzQgLTMxLjE0NSAxMDMuNjc0Qy0zMS45NDUg +OTcuMjc0IC0zOC42NjggODEuNTc4IC03MS4xNDUgMTA2Ljg3NEMtOTguNTY0IDEyNy45NDcgLTEx +MC41MDkgMTA5LjIxOSAtMTEwLjUwOSAxMDkuMjE5TC0xMTUuNzA5IDExMS44NzRDLTEzMS43MDkg +ODEuNjc0IC0xMjIuMjczIDEzNy45MjkgLTEyMi4yNzMgMTM3LjkyOUMtMTEzLjQ3MyAxNzIuMzI5 +IDIwLjA1NSAxMjYuODc0IDIwLjA1NSAxMjYuODc0QzIwLjA1NSAxMjYuODc0IDE4OC44NTYgOTYu +NDc0IDIwMC4wNTYgOTIuNDc0QzIxMS4yNTYgODguNDc0IDMwMS4yMiA5NC40MzcgMzAxLjIyIDk0 +LjQzN0wyOTYuMDU2IDc0LjU4M0MyMzEuMjU2IDI4LjE4MyAyMTYuODU2IDU0Ljg3NCAyMDMuMjU2 +IDUwLjg3NEMxODkuNjU2IDQ2Ljg3MyAxOTIuMDU2IDU2LjQ3NCAxODguODU2IDU3LjI3NEMxODUu +NjU2IDU4LjA3NCAxNDYuNDU2IDMzLjI3MyAxNDAuMDU2IDM0LjA3M3oiLz4KIDwvZz4KIDxnIHN0 +eWxlPSJmaWxsOiAjZjVjY2IwIj4KICA8cGF0aCBkPSJNMTQxLjM2NSAzNS44MTlDMTM0Ljk2NSAz +Ni42MTkgMTA3LjUyMyAxMy45NDQgMTI0LjU2NSA0NC42MTlDMTQ2LjU2NSA4NC4yMTkgNjYuMTY0 +IDgzLjgxOSA0OS4zNjQgNzIuNjE5QzMyLjU2NCA2MS40MTkgNTYuNTY0IDkxLjAxOSA1Ni41NjQg +OTEuMDE5Qzc0Ljk2NCAxMTEuMDE5IDQwLjU2NCA5NC4yMTkgNDAuNTY0IDk0LjIxOUM2LjE2NCA4 +MS40MTkgLTE3LjgzNiAxMDcuMDE5IC0yMS4wMzYgMTA3LjgxOUMtMjQuMjM2IDEwOC42MTkgLTI5 +LjAzNiAxMTEuODE5IC0yOS44MzYgMTA1LjQxOUMtMzAuNjM2IDk5LjAxOSAtMzcuMjI3IDgzLjQ5 +MiAtNjkuODM2IDEwOC42MTlDLTk4LjQ5MSAxMzAuNDM4IC0xMTAuMTI3IDExMi4yNTYgLTExMC4x +MjcgMTEyLjI1NkwtMTE1LjcyNyAxMTMuNDE5Qy0xMzAuMTI4IDg1LjAxOSAtMTIxLjYxOCAxNDAu +OTgzIC0xMjEuNjE4IDE0MC45ODNDLTExMi44MTggMTc1LjM4NCAyMS4zNjQgMTI4LjYxOSAyMS4z +NjQgMTI4LjYxOUMyMS4zNjQgMTI4LjYxOSAxOTAuMTY1IDk4LjIxOSAyMDEuMzY1IDk0LjIxOUMy +MTIuNTY1IDkwLjIxOSAzMDEuNjU2IDk2LjExIDMwMS42NTYgOTYuMTFMMjk2LjU2NSA3NS43NDZD +MjMxLjc2NSAyOS4zNDYgMjE4LjE2NSA1Ni42MTkgMjA0LjU2NSA1Mi42MTlDMTkwLjk2NSA0OC42 +MTkgMTkzLjM2NSA1OC4yMTkgMTkwLjE2NSA1OS4wMTlDMTg2Ljk2NSA1OS44MTkgMTQ3Ljc2NSAz +NS4wMTkgMTQxLjM2NSAzNS44MTl6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2Y4ZDhjNCI+ +CiAgPHBhdGggZD0iTTE0Mi42NzQgMzcuNTY1QzEzNi4yNzQgMzguMzY1IDEwOC44MzIgMTUuNjg5 +IDEyNS44NzQgNDYuMzY1QzE0Ny44NzQgODUuOTY1IDY3LjQ3NCA4NS41NjUgNTAuNjc0IDc0LjM2 +NUMzMy44NzQgNjMuMTY1IDU3Ljg3NCA5Mi43NjUgNTcuODc0IDkyLjc2NUM3Ni4yNzQgMTEyLjc2 +NSA0MS44NzQgOTUuOTY1IDQxLjg3NCA5NS45NjVDNy40NzMgODMuMTY1IC0xNi41MjcgMTA4Ljc2 +NSAtMTkuNzI3IDEwOS41NjVDLTIyLjkyNyAxMTAuMzY1IC0yNy43MjcgMTEzLjU2NSAtMjguNTI3 +IDEwNy4xNjVDLTI5LjMyNyAxMDAuNzY1IC0zNS43ODYgODUuNDA1IC02OC41MjcgMTEwLjM2NUMt +OTguNDE4IDEzMi45MjkgLTEwOS43NDUgMTE1LjI5MyAtMTA5Ljc0NSAxMTUuMjkzTC0xMTUuNzQ1 +IDExNC45NjVDLTEyOS4zNDYgODguNTY0IC0xMjAuOTYzIDE0NC4wMzggLTEyMC45NjMgMTQ0LjAz +OEMtMTEyLjE2MyAxNzguNDM4IDIyLjY3MyAxMzAuMzY1IDIyLjY3MyAxMzAuMzY1QzIyLjY3MyAx +MzAuMzY1IDE5MS40NzQgOTkuOTY1IDIwMi42NzQgOTUuOTY1QzIxMy44NzQgOTEuOTY1IDMwMi4w +OTMgOTcuNzgzIDMwMi4wOTMgOTcuNzgzTDI5Ny4wNzUgNzYuOTFDMjMyLjI3NCAzMC41MSAyMTku +NDc0IDU4LjM2NSAyMDUuODc0IDU0LjM2NUMxOTIuMjc0IDUwLjM2NSAxOTQuNjc0IDU5Ljk2NSAx +OTEuNDc0IDYwLjc2NUMxODguMjc0IDYxLjU2NSAxNDkuMDc0IDM2Ljc2NSAxNDIuNjc0IDM3LjU2 +NXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmFlNWQ3Ij4KICA8cGF0aCBkPSJNMTQzLjk4 +MyAzOS4zMUMxMzcuNTgzIDQwLjExIDExMC41MjkgMTcuMjIzIDEyNy4xODMgNDguMTFDMTQ5LjE4 +MyA4OC45MSA2OC43ODMgODcuMzEgNTEuOTgzIDc2LjExQzM1LjE4MyA2NC45MSA1OS4xODMgOTQu +NTEgNTkuMTgzIDk0LjUxQzc3LjU4MyAxMTQuNTEgNDMuMTgzIDk3LjcxIDQzLjE4MyA5Ny43MUM4 +Ljc4MyA4NC45MSAtMTUuMjE3IDExMC41MSAtMTguNDE3IDExMS4zMUMtMjEuNjE4IDExMi4xMSAt +MjYuNDE4IDExNS4zMSAtMjcuMjE4IDEwOC45MUMtMjguMDE4IDEwMi41MSAtMzQuMzQ2IDg3LjMx +OCAtNjcuMjE4IDExMi4xMUMtOTguMzQ1IDEzNS40MiAtMTA5LjM2MyAxMTguMzI5IC0xMDkuMzYz +IDExOC4zMjlMLTExNS43NjQgMTE2LjUxQy0xMjguNzY0IDkyLjUxIC0xMjAuMzA5IDE0Ny4wOTMg +LTEyMC4zMDkgMTQ3LjA5M0MtMTExLjUwOSAxODEuNDkzIDIzLjk4MyAxMzIuMTEgMjMuOTgzIDEz +Mi4xMUMyMy45ODMgMTMyLjExIDE5Mi43ODMgMTAxLjcxIDIwMy45ODMgOTcuNzFDMjE1LjE4MyA5 +My43MSAzMDIuNTI5IDk5LjQ1NiAzMDIuNTI5IDk5LjQ1NkwyOTcuNTgzIDc4LjA3NEMyMzIuNzgz +IDMxLjY3MyAyMjAuNzgzIDYwLjExIDIwNy4xODMgNTYuMTFDMTkzLjU4MyA1Mi4xMSAxOTUuOTgz +IDYxLjcxIDE5Mi43ODMgNjIuNTFDMTg5LjU4MyA2My4zMSAxNTAuMzgzIDM4LjUxIDE0My45ODMg +MzkuMzF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZjZjJlYiI+CiAgPHBhdGggZD0iTTE0 +NS4yOTIgNDEuMDU1QzEzOC44OTIgNDEuODU1IDExMi45MTcgMTguNDExIDEyOC40OTIgNDkuODU1 +QzE0OS42OTIgOTIuNjU2IDcwLjA5MiA4OS4wNTYgNTMuMjkyIDc3Ljg1NkMzNi40OTIgNjYuNjU2 +IDYwLjQ5MiA5Ni4yNTYgNjAuNDkyIDk2LjI1NkM3OC44OTIgMTE2LjI1NiA0NC40OTIgOTkuNDU2 +IDQ0LjQ5MiA5OS40NTZDMTAuMDkyIDg2LjY1NiAtMTMuOTA4IDExMi4yNTYgLTE3LjEwOCAxMTMu +MDU2Qy0yMC4zMDggMTEzLjg1NiAtMjUuMTA4IDExNy4wNTYgLTI1LjkwOCAxMTAuNjU2Qy0yNi43 +MDggMTA0LjI1NiAtMzIuOTA1IDg5LjIzMiAtNjUuOTA4IDExMy44NTZDLTk4LjI3MyAxMzcuOTEx +IC0xMDguOTgyIDEyMS4zNjUgLTEwOC45ODIgMTIxLjM2NUwtMTE1Ljc4MiAxMTguMDU2Qy0xMjgu +NTgyIDk0Ljg1NiAtMTE5LjY1NCAxNTAuMTQ3IC0xMTkuNjU0IDE1MC4xNDdDLTExMC44NTQgMTg0 +LjU0NyAyNS4yOTIgMTMzLjg1NiAyNS4yOTIgMTMzLjg1NkMyNS4yOTIgMTMzLjg1NiAxOTQuMDkz +IDEwMy40NTYgMjA1LjI5MyA5OS40NTZDMjE2LjQ5MyA5NS40NTYgMzAyLjk2NSAxMDEuMTI4IDMw +Mi45NjUgMTAxLjEyOEwyOTguMDkzIDc5LjIzN0MyMzMuMjkyIDMyLjgzNyAyMjIuMDkzIDYxLjg1 +NiAyMDguNDkzIDU3Ljg1NkMxOTQuODkzIDUzLjg1NSAxOTcuMjkzIDYzLjQ1NiAxOTQuMDkzIDY0 +LjI1NkMxOTAuODkyIDY1LjA1NiAxNTEuNjkyIDQwLjI1NSAxNDUuMjkyIDQxLjA1NXoiLz4KIDwv +Zz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmIj4KICA8cGF0aCBkPSJNLTExNS44IDExOS42MDFD +LTEyOC42IDk3LjYgLTExOSAxNTMuMjAxIC0xMTkgMTUzLjIwMUMtMTEwLjIgMTg3LjYwMSAyNi42 +IDEzNS42MDEgMjYuNiAxMzUuNjAxQzI2LjYgMTM1LjYwMSAxOTUuNDAxIDEwNS4yIDIwNi42MDEg +MTAxLjJDMjE3LjgwMSA5Ny4yIDMwMy40MDEgMTAyLjggMzAzLjQwMSAxMDIuOEwyOTguNjAxIDgw +LjRDMjMzLjgwMSAzNCAyMjMuNDAxIDYzLjYgMjA5LjgwMSA1OS42QzE5Ni4yMDEgNTUuNiAxOTgu +NjAxIDY1LjIgMTk1LjQwMSA2NkMxOTIuMjAxIDY2LjggMTUzLjAwMSA0MiAxNDYuNjAxIDQyLjhD +MTQwLjIwMSA0My42IDExNC45ODEgMTkuNzkzIDEyOS44MDEgNTEuNkMxNTIuMDI4IDk5LjMwNyA2 +OS4wNDEgODkuMjI3IDU0LjYgNzkuNkMzNy44IDY4LjQgNjEuOCA5OCA2MS44IDk4QzgwLjIgMTE4 +LjAwMSA0NS44IDEwMS4yIDQ1LjggMTAxLjJDMTEuNCA4OC40IC0xMi42IDExNC4wMDEgLTE1Ljgg +MTE0LjgwMUMtMTkgMTE1LjYwMSAtMjMuOCAxMTguODAxIC0yNC42IDExMi40MDFDLTI1LjQgMTA2 +IC0zMS40NjUgOTEuMTQ0IC02NC42IDExNS42MDFDLTk4LjIgMTQwLjQwMSAtMTA4LjYgMTI0LjQw +MSAtMTA4LjYgMTI0LjQwMUwtMTE1LjggMTE5LjYwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxs +OiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNLTc0LjIgMTQ5LjYwMUMtNzQuMiAxNDkuNjAxIC04MS40 +IDE2MS4yMDEgLTYwLjYgMTc0LjQwMUMtNjAuNiAxNzQuNDAxIC01OS4yIDE3NS44MDEgLTc3LjIg +MTcxLjYwMUMtNzcuMiAxNzEuNjAxIC04My40IDE2OS42MDEgLTg1IDE1OS4yMDFDLTg1IDE1OS4y +MDEgLTg5LjggMTU0LjgwMSAtOTQuNiAxNDkuMjAxQy05OS40IDE0My42MDEgLTc0LjIgMTQ5LjYw +MSAtNzQuMiAxNDkuNjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxw +YXRoIGQ9Ik02NS44IDEwMkM2NS44IDEwMiA4My40OTggMTI4LjgyMSA4Mi45IDEzMy42MDFDODEu +NiAxNDQuMDAxIDgxLjQgMTUzLjYwMSA4NC42IDE1Ny42MDFDODcuODAxIDE2MS42MDEgOTYuNjAx +IDE5NC44MDEgOTYuNjAxIDE5NC44MDFDOTYuNjAxIDE5NC44MDEgOTYuMjAxIDE5Ni4wMDEgMTA4 +LjYwMSAxNTguMDAxQzEwOC42MDEgMTU4LjAwMSAxMjAuMjAxIDE0Mi4wMDEgMTAwLjIwMSAxMjMu +NjAxQzEwMC4yMDEgMTIzLjYwMSA2NSA5NC44IDY1LjggMTAyeiIvPgogPC9nPgogPGcgc3R5bGU9 +ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tNTQuMiAxNzYuNDAxQy01NC4yIDE3Ni40MDEg +LTQzIDE4My42MDEgLTU3LjQgMjE0LjgwMUwtNTEgMjEyLjQwMUMtNTEgMjEyLjQwMSAtNTEuOCAy +MjMuNjAxIC01NSAyMjYuMDAxTC00Ny44IDIyMi44MDFDLTQ3LjggMjIyLjgwMSAtNDMgMjMwLjgw +MSAtNDcgMjM1LjYwMUMtNDcgMjM1LjYwMSAtMzAuMiAyNDMuNjAxIC0zMSAyNTAuMDAxQy0zMSAy +NTAuMDAxIC0yNC42IDI0Mi4wMDEgLTI4LjYgMjM1LjYwMUMtMzIuNiAyMjkuMjAxIC0zOS44IDIz +My4yMDEgLTM5IDIxNC44MDFMLTQ3LjggMjE4LjAwMUMtNDcuOCAyMTguMDAxIC00Mi4yIDIwOS4y +MDEgLTQyLjIgMjAyLjgwMUwtNTAuMiAyMDUuMjAxQy01MC4yIDIwNS4yMDEgLTM0LjczMSAxNzgu +NjIzIC00NS40IDE3Ny4yMDFDLTUxLjQgMTc2LjQwMSAtNTQuMiAxNzYuNDAxIC01NC4yIDE3Ni40 +MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGggZD0iTS0yMS44 +IDE5My4yMDFDLTIxLjggMTkzLjIwMSAtMTkgMTg4LjgwMSAtMjEuOCAxODkuNjAxQy0yNC42IDE5 +MC40MDEgLTU1LjggMjA1LjIwMSAtNjEuOCAyMTQuODAxQy02MS44IDIxNC44MDEgLTI3LjQgMTkw +LjQwMSAtMjEuOCAxOTMuMjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgog +IDxwYXRoIGQ9Ik0tMTEuNCAyMDEuMjAxQy0xMS40IDIwMS4yMDEgLTguNiAxOTYuODAxIC0xMS40 +IDE5Ny42MDFDLTE0LjIgMTk4LjQwMSAtNDUuNCAyMTMuMjAxIC01MS40IDIyMi44MDFDLTUxLjQg +MjIyLjgwMSAtMTcgMTk4LjQwMSAtMTEuNCAyMDEuMjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZp +bGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0xLjggMTg2LjAwMUMxLjggMTg2LjAwMSA0LjYgMTgx +LjYwMSAxLjggMTgyLjQwMUMtMSAxODMuMjAxIC0zMi4yIDE5OC4wMDEgLTM4LjIgMjA3LjYwMUMt +MzguMiAyMDcuNjAxIC0zLjggMTgzLjIwMSAxLjggMTg2LjAwMXoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNLTIxLjQgMjI5LjYwMUMtMjEuNCAyMjkuNjAx +IC0yMS40IDIyMy42MDEgLTI0LjIgMjI0LjQwMUMtMjcgMjI1LjIwMSAtNjMgMjQyLjgwMSAtNjkg +MjUyLjQwMUMtNjkgMjUyLjQwMSAtMjcgMjI2LjgwMSAtMjEuNCAyMjkuNjAxeiIvPgogPC9nPgog +PGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tMjAuMiAyMTguODAxQy0yMC4y +IDIxOC44MDEgLTE5IDIxNC4wMDEgLTIxLjggMjE0LjgwMUMtMjMuOCAyMTQuODAxIC01MC4yIDIy +Ni40MDEgLTU2LjIgMjM2LjAwMUMtNTYuMiAyMzYuMDAxIC0yNi42IDIxNC40MDEgLTIwLjIgMjE4 +LjgwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNLTM0 +LjYgMjY2LjQwMUwtNDQuNiAyNzQuMDAxQy00NC42IDI3NC4wMDEgLTM0LjIgMjY2LjQwMSAtMzAu +NiAyNjcuNjAxQy0zMC42IDI2Ny42MDEgLTM3LjQgMjc4LjgwMSAtMzguMiAyODQuMDAxQy0zOC4y +IDI4NC4wMDEgLTI3LjggMjcxLjIwMSAtMjIuMiAyNzEuNjAxQy0yMi4yIDI3MS42MDEgLTE0LjYg +MjcyLjAwMSAtMTQuNiAyODIuODAxQy0xNC42IDI4Mi44MDEgLTkgMjcyLjQwMSAtNS44IDI3Mi44 +MDFDLTUuOCAyNzIuODAxIC00LjYgMjc5LjIwMSAtNS44IDI4Ni4wMDFDLTUuOCAyODYuMDAxIC0x +LjggMjc4LjQwMSAyLjIgMjgwLjAwMUMyLjIgMjgwLjAwMSA4LjYgMjc4LjAwMSA3LjggMjg5LjYw +MUM3LjggMjg5LjYwMSA3LjggMzAwLjAwMSA3IDMwMi44MDFDNyAzMDIuODAxIDEyLjYgMjc2LjQw +MSAxNSAyNzYuMDAxQzE1IDI3Ni4wMDEgMjMgMjc0LjgwMSAyNy44IDI4My42MDFDMjcuOCAyODMu +NjAxIDIzLjggMjc2LjAwMSAyOC42IDI3OC4wMDFDMjguNiAyNzguMDAxIDM5LjQgMjc5LjYwMSA0 +Mi42IDI4Ni40MDFDNDIuNiAyODYuNDAxIDM1LjggMjc0LjQwMSA0MS40IDI3Ny42MDFDNDEuNCAy +NzcuNjAxIDQ4LjIgMjc3LjYwMSA0OS40IDI4NC4wMDFDNDkuNCAyODQuMDAxIDU3LjggMzA1LjIw +MSA1OS44IDMwNi44MDFDNTkuOCAzMDYuODAxIDUyLjIgMjg1LjIwMSA1My44IDI4NS4yMDFDNTMu +OCAyODUuMjAxIDUxLjggMjczLjIwMSA1NyAyODguMDAxQzU3IDI4OC4wMDEgNTMuOCAyNzQuMDAx +IDU5LjQgMjc0LjgwMUM2NSAyNzUuNjAxIDY5LjQgMjg1LjYwMSA3Ny44IDI4My4yMDFDNzcuOCAy +ODMuMjAxIDg3LjQwMSAyODguODAxIDg5LjQwMSAyMTkuNjAxTC0zNC42IDI2Ni40MDF6Ii8+CiA8 +L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTS0yOS44IDE3My42MDFD +LTI5LjggMTczLjYwMSAtMTUgMTY3LjYwMSAyNSAxNzMuNjAxQzI1IDE3My42MDEgMzIuMiAxNzQu +MDAxIDM5IDE2NS4yMDFDNDUuOCAxNTYuNDAxIDcyLjYgMTQ5LjIwMSA3OSAxNTEuMjAxTDg4LjYw +MSAxNTcuNjAxTDg5LjQwMSAxNTguODAxQzg5LjQwMSAxNTguODAxIDEwMS44MDEgMTY5LjIwMSAx +MDIuMjAxIDE3Ni44MDFDMTAyLjYwMSAxODQuNDAxIDg3LjgwMSAyMzIuNDAxIDc4LjIgMjQ4LjQw +MUM2OC42IDI2NC40MDEgNTkgMjc2LjgwMSAzOS44IDI3NC40MDFDMzkuOCAyNzQuNDAxIDE5IDI3 +MC40MDEgLTYuNiAyNzQuNDAxQy02LjYgMjc0LjQwMSAtMzUuOCAyNzIuODAxIC0zOC42IDI2NC44 +MDFDLTQxLjQgMjU2LjgwMSAtMjcuNCAyNDEuNjAxIC0yNy40IDI0MS42MDFDLTI3LjQgMjQxLjYw +MSAtMjMgMjMzLjIwMSAtMjQuMiAyMTguODAxQy0yNS40IDIwNC40MDEgLTI1IDE3Ni40MDEgLTI5 +LjggMTczLjYwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZTU2NjhjIj4KICA8cGF0aCBk +PSJNLTcuOCAxNzUuNjAxQzAuNiAxOTQuMDAxIC0yOSAyNTkuMjAxIC0yOSAyNTkuMjAxQy0zMSAy +NjAuODAxIC0xNi4zNCAyNjYuODQ2IC02LjIgMjY0LjQwMUM0Ljc0NiAyNjEuNzYzIDQ1IDI2Ni4w +MDEgNDUgMjY2LjAwMUM2OC42IDI1MC40MDEgODEuNCAyMDYuMDAxIDgxLjQgMjA2LjAwMUM4MS40 +IDIwNi4wMDEgOTEuODAxIDE4Mi4wMDEgNzQuMiAxNzguODAxQzU2LjYgMTc1LjYwMSAtNy44IDE3 +NS42MDEgLTcuOCAxNzUuNjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNiMjMyNTkiPgog +IDxwYXRoIGQ9Ik0tOS44MzEgMjA2LjQ5N0MtNi41MDUgMTkzLjcwNyAtNC45MjEgMTgxLjkwNiAt +Ny44IDE3NS42MDFDLTcuOCAxNzUuNjAxIDU0LjYgMTgyLjAwMSA2NS44IDE2MS4yMDFDNzAuMDQx +IDE1My4zMjYgODQuODAxIDE4NC4wMDEgODQuNCAxOTMuNjAxQzg0LjQgMTkzLjYwMSAyMS40IDIw +OC4wMDEgNi42IDE5Ni44MDFMLTkuODMxIDIwNi40OTd6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmls +bDogI2E1MjY0YyI+CiAgPHBhdGggZD0iTS01LjQgMjIyLjgwMUMtNS40IDIyMi44MDEgLTMuNCAy +MzAuMDAxIC01LjggMjM0LjAwMUMtNS44IDIzNC4wMDEgLTcuNCAyMzQuODAxIC04LjYgMjM1LjIw +MUMtOC42IDIzNS4yMDEgLTcuNCAyMzguODAxIC0xLjQgMjQwLjQwMUMtMS40IDI0MC40MDEgMC42 +IDI0NC44MDEgMyAyNDUuMjAxQzUuNCAyNDUuNjAxIDEwLjIgMjUxLjIwMSAxNC4yIDI1MC4wMDFD +MTguMiAyNDguODAxIDI5LjQgMjQ0LjgwMSAyOS40IDI0NC44MDFDMjkuNCAyNDQuODAxIDM1IDI0 +MS42MDEgNDMuOCAyNDUuMjAxQzQzLjggMjQ1LjIwMSA0Ni4xNzUgMjQ0LjM5OSA0Ni42IDI0MC40 +MDFDNDcuMSAyMzUuNzAxIDUwLjIgMjMyLjAwMSA1Mi4yIDIzMC4wMDFDNTQuMiAyMjguMDAxIDYz +LjggMjE1LjIwMSA2Mi42IDIxNC44MDFDNjEuNCAyMTQuNDAxIC01LjQgMjIyLjgwMSAtNS40IDIy +Mi44MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmNzI3Zjsgc3Ryb2tlOiMwMDAwMDAi +PgogIDxwYXRoIGQ9Ik0tOS44IDE3NC40MDFDLTkuOCAxNzQuNDAxIC0xMi42IDE5Ni44MDEgLTku +NCAyMDUuMjAxQy02LjIgMjEzLjYwMSAtNyAyMTUuNjAxIC03LjggMjE5LjYwMUMtOC42IDIyMy42 +MDEgLTQuMiAyMzMuNjAxIDEuNCAyMzkuNjAxTDEzLjQgMjQxLjIwMUMxMy40IDI0MS4yMDEgMjgu +NiAyMzcuNjAxIDM3LjggMjQwLjQwMUMzNy44IDI0MC40MDEgNDYuNzk0IDI0MS43NDQgNTAuMiAy +MjYuODAxQzUwLjIgMjI2LjgwMSA1NSAyMjAuNDAxIDYyLjIgMjE3LjYwMUM2OS40IDIxNC44MDEg +NzYuNiAxNzMuMjAxIDcyLjYgMTY1LjIwMUM2OC42IDE1Ny4yMDEgNTQuMiAxNTIuODAxIDM4LjIg +MTY4LjQwMUMyMi4yIDE4NC4wMDEgMjAuMiAxNjcuMjAxIC05LjggMTc0LjQwMXoiLz4KIDwvZz4K +IDxnIHN0eWxlPSJmaWxsOiAjZmZmZmNjOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAu +NSI+CiAgPHBhdGggZD0iTS04LjIgMjQ5LjIwMUMtOC4yIDI0OS4yMDEgLTkgMjQ3LjIwMSAtMTMu +NCAyNDYuODAxQy0xMy40IDI0Ni44MDEgLTM1LjggMjQzLjIwMSAtNDQuMiAyMzAuODAxQy00NC4y +IDIzMC44MDEgLTUxIDIyNS4yMDEgLTQ2LjYgMjM2LjgwMUMtNDYuNiAyMzYuODAxIC0zNi4yIDI1 +Ny4yMDEgLTI5LjQgMjYwLjAwMUMtMjkuNCAyNjAuMDAxIC0xMyAyNjQuMDAxIC04LjIgMjQ5LjIw +MXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2MzZjRjIj4KICA8cGF0aCBkPSJNNzEuNzQy +IDE4NS4yMjlDNzIuNDAxIDE3Ny4zMjMgNzQuMzU0IDE2OC43MDkgNzIuNiAxNjUuMjAxQzY2LjE1 +NCAxNTIuMzA3IDQ5LjE4MSAxNTcuNjk1IDM4LjIgMTY4LjQwMUMyMi4yIDE4NC4wMDEgMjAuMiAx +NjcuMjAxIC05LjggMTc0LjQwMUMtOS44IDE3NC40MDEgLTExLjU0NSAxODguMzY0IC0xMC43MDUg +MTk4LjM3NkMtMTAuNzA1IDE5OC4zNzYgMjYuNiAxODYuODAxIDI3LjQgMTkyLjQwMUMyNy40IDE5 +Mi40MDEgMjkgMTg5LjIwMSAzOC4yIDE4OS4yMDFDNDcuNCAxODkuMjAxIDcwLjE0MiAxODguMDI5 +IDcxLjc0MiAxODUuMjI5eiIvPgogPC9nPgogPGcgc3R5bGU9InN0cm9rZTojYTUxOTI2OyBzdHJv +a2Utd2lkdGg6MiI+CiAgPHBhdGggZD0iTTI4LjYgMTc1LjIwMUMyOC42IDE3NS4yMDEgMzMuNCAx +ODAuMDAxIDI5LjggMTg5LjYwMUMyOS44IDE4OS42MDEgMTUuNCAyMDUuNjAxIDE3LjQgMjE5LjYw +MSIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJv +a2Utd2lkdGg6MC41Ij4KICA8cGF0aCBkPSJNLTE5LjQgMjYwLjAwMUMtMTkuNCAyNjAuMDAxIC0y +My44IDI0Ny4yMDEgLTE1IDI1NC4wMDFDLTE1IDI1NC4wMDEgLTEwLjIgMjU2LjAwMSAtMTEuNCAy +NTcuNjAxQy0xMi42IDI1OS4yMDEgLTE4LjIgMjYzLjIwMSAtMTkuNCAyNjAuMDAxeiIvPgogPC9n +PgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6 +MC41Ij4KICA8cGF0aCBkPSJNLTE0LjM2IDI2MS4yMDFDLTE0LjM2IDI2MS4yMDEgLTE3Ljg4IDI1 +MC45NjEgLTEwLjg0IDI1Ni40MDFDLTEwLjg0IDI1Ni40MDEgLTYuNDE5IDI1OC44NDkgLTcuOTYg +MjU5LjI4MUMtMTIuNTIgMjYwLjU2MSAtNy45NiAyNjMuMTIxIC0xNC4zNiAyNjEuMjAxeiIvPgog +PC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lk +dGg6MC41Ij4KICA8cGF0aCBkPSJNLTkuNTYgMjYxLjIwMUMtOS41NiAyNjEuMjAxIC0xMy4wOCAy +NTAuOTYxIC02LjA0IDI1Ni40MDFDLTYuMDQgMjU2LjQwMSAtMS42NjUgMjU4LjcxMSAtMy4xNiAy +NTkuMjgxQy02LjUyIDI2MC41NjEgLTMuMTYgMjYzLjEyMSAtOS41NiAyNjEuMjAxeiIvPgogPC9n +PgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6 +MC41Ij4KICA8cGF0aCBkPSJNLTIuOTYgMjYxLjQwMUMtMi45NiAyNjEuNDAxIC02LjQ4IDI1MS4x +NjEgMC41NiAyNTYuNjAxQzAuNTYgMjU2LjYwMSA0Ljk0MyAyNTguOTMzIDMuNDQxIDI1OS40ODFD +MC40OCAyNjAuNTYxIDMuNDQxIDI2My4zMjEgLTIuOTYgMjYxLjQwMXoiLz4KIDwvZz4KIDxnIHN0 +eWxlPSJmaWxsOiAjZmZmZmNjOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuNSI+CiAg +PHBhdGggZD0iTTMuNTIgMjYxLjMyMUMzLjUyIDI2MS4zMjEgMCAyNTEuMDgxIDcuMDQxIDI1Ni41 +MjFDNy4wNDEgMjU2LjUyMSAxMC44ODEgMjU4LjEyMSA5LjkyMSAyNTkuNDAxQzguOTYxIDI2MC42 +ODEgOS45MjEgMjYzLjI0MSAzLjUyIDI2MS4zMjF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDog +I2ZmZmZjYzsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjUiPgogIDxwYXRoIGQ9Ik0x +MC4yIDI2Mi4wMDFDMTAuMiAyNjIuMDAxIDUuNCAyNDkuNjAxIDE0LjYgMjU2LjAwMUMxNC42IDI1 +Ni4wMDEgMTkuNCAyNTguMDAxIDE4LjIgMjU5LjYwMUMxNyAyNjEuMjAxIDE4LjIgMjY0LjQwMSAx +MC4yIDI2Mi4wMDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0ic3Ryb2tlOiNhNTI2NGM7IHN0cm9rZS13 +aWR0aDoyIj4KICA8cGF0aCBkPSJNLTE4LjIgMjQ0LjgwMUMtMTguMiAyNDQuODAxIC01IDI0Mi4w +MDEgMSAyNDUuMjAxQzEgMjQ1LjIwMSA3IDI0Ni40MDEgOC4yIDI0Ni4wMDFDOS40IDI0NS42MDEg +MTIuNiAyNDUuMjAxIDEyLjYgMjQ1LjIwMSIvPgogPC9nPgogPGcgc3R5bGU9InN0cm9rZTojYTUy +NjRjOyBzdHJva2Utd2lkdGg6MiI+CiAgPHBhdGggZD0iTTE1LjggMjUzLjYwMUMxNS44IDI1My42 +MDEgMjcuOCAyNDAuMDAxIDM5LjggMjQ0LjQwMUM0Ni44MTYgMjQ2Ljk3NCA0NS44IDI0My42MDEg +NDYuNiAyNDAuODAxQzQ3LjQgMjM4LjAwMSA0Ny42IDIzMy44MDEgNTIuNiAyMzAuODAxIi8+CiA8 +L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZjYzsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0 +aDowLjUiPgogIDxwYXRoIGQ9Ik0zMyAyMzcuNjAxQzMzIDIzNy42MDEgMjkgMjI2LjgwMSAyNi4y +IDIzOS42MDFDMjMuNCAyNTIuNDAxIDIwLjIgMjU2LjAwMSAxOC42IDI1OC44MDFDMTguNiAyNTgu +ODAxIDE4LjYgMjY0LjAwMSAyNyAyNjMuNjAxQzI3IDI2My42MDEgMzcuOCAyNjMuMjAxIDM4LjIg +MjYwLjQwMUMzOC42IDI1Ny42MDEgMzcgMjQ2LjAwMSAzMyAyMzcuNjAxeiIvPgogPC9nPgogPGcg +c3R5bGU9InN0cm9rZTojYTUyNjRjOyBzdHJva2Utd2lkdGg6MiI+CiAgPHBhdGggZD0iTTQ3IDI0 +NC44MDFDNDcgMjQ0LjgwMSA1MC42IDI0Mi40MDEgNTMgMjQzLjYwMSIvPgogPC9nPgogPGcgc3R5 +bGU9InN0cm9rZTojYTUyNjRjOyBzdHJva2Utd2lkdGg6MiI+CiAgPHBhdGggZD0iTTUzLjUgMjI4 +LjQwMUM1My41IDIyOC40MDEgNTYuNCAyMjMuNTAxIDYxLjIgMjIyLjcwMSIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNiMmIyYjIiPgogIDxwYXRoIGQ9Ik0tMjUuOCAyNjUuMjAxQy0yNS44IDI2 +NS4yMDEgLTcuOCAyNjguNDAxIC0zLjQgMjY2LjgwMUMtMy40IDI2Ni44MDEgNS40IDI2Ni44MDEg +LTMgMjY4LjgwMUMtMyAyNjguODAxIC0xNS44IDI2OC44MDEgLTIzLjggMjY3LjYwMUMtMjMuOCAy +NjcuNjAxIC0zNS40IDI2Mi4wMDEgLTI1LjggMjY1LjIwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJm +aWxsOiAjZmZmZmNjOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuNSI+CiAgPHBhdGgg +ZD0iTS0xMS44IDE3Mi4wMDFDLTExLjggMTcyLjAwMSA1LjggMTcyLjAwMSA3LjggMTcyLjgwMUM3 +LjggMTcyLjgwMSAxNSAyMDMuNjAxIDExLjQgMjExLjIwMUMxMS40IDIxMS4yMDEgMTAuMiAyMTQu +MDAxIDcuNCAyMDguNDAxQzcuNCAyMDguNDAxIC0xMSAxNzUuNjAxIC0xNC4yIDE3My42MDFDLTE3 +LjQgMTcxLjYwMSAtMTMgMTcyLjAwMSAtMTEuOCAxNzIuMDAxeiIvPgogPC9nPgogPGcgc3R5bGU9 +ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC41Ij4KICA8cGF0 +aCBkPSJNLTg4LjkgMTY5LjMwMUMtODguOSAxNjkuMzAxIC04MCAxNzEuMDAxIC02Ny40IDE3My42 +MDFDLTY3LjQgMTczLjYwMSAtNjIuNiAxOTYuMDAxIC01OS40IDIwMC44MDFDLTU2LjIgMjA1LjYw +MSAtNTkuOCAyMDUuNjAxIC02My40IDIwMi44MDFDLTY3IDIwMC4wMDEgLTgxLjggMTg2LjAwMSAt +ODMuOCAxODEuNjAxQy04NS44IDE3Ny4yMDEgLTg4LjkgMTY5LjMwMSAtODguOSAxNjkuMzAxeiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Ut +d2lkdGg6MC41Ij4KICA8cGF0aCBkPSJNLTY3LjAzOSAxNzMuODE4Qy02Ny4wMzkgMTczLjgxOCAt +NjEuMjM5IDE3NS4zNjYgLTYwLjIzIDE3Ny41ODFDLTU5LjIyMiAxNzkuNzk1IC02MS40MzIgMTgz +LjA5MiAtNjEuNDMyIDE4My4wOTJDLTYxLjQzMiAxODMuMDkyIC02Mi40MzIgMTg2LjM5NyAtNjMu +NjM0IDE4NC4yMzVDLTY0LjgzNiAxODIuMDcyIC02Ny43MDggMTc0LjQxMiAtNjcuMDM5IDE3My44 +MTh6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTS02NyAx +NzMuNjAxQy02NyAxNzMuNjAxIC02My40IDE3OC44MDEgLTU5LjggMTc4LjgwMUMtNTYuMiAxNzgu +ODAxIC01NS44MTggMTc4LjM4OCAtNTMgMTc5LjAwMUMtNDguNCAxODAuMDAxIC00OC44IDE3OC4w +MDEgLTQyLjIgMTc5LjIwMUMtMzkuNTYgMTc5LjY4MSAtMzcgMTc4LjgwMSAtMzQuMiAxODAuMDAx +Qy0zMS40IDE4MS4yMDEgLTI4LjIgMTgwLjQwMSAtMjcgMTc4LjQwMUMtMjUuOCAxNzYuNDAxIC0y +MSAxNzIuMjAxIC0yMSAxNzIuMjAxQy0yMSAxNzIuMjAxIC0zMy44IDE3NC4wMDEgLTM2LjYgMTc0 +LjgwMUMtMzYuNiAxNzQuODAxIC01OSAxNzYuMDAxIC02NyAxNzMuNjAxeiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC41Ij4K +ICA8cGF0aCBkPSJNLTIyLjQgMTczLjgwMUMtMjIuNCAxNzMuODAxIC0yOC44NSAxNzcuMzAxIC0y +OS4yNSAxNzkuNzAxQy0yOS42NSAxODIuMTAxIC0yNCAxODUuODAxIC0yNCAxODUuODAxQy0yNCAx +ODUuODAxIC0yMS4yNSAxOTAuNDAxIC0yMC42NSAxODguMDAxQy0yMC4wNSAxODUuNjAxIC0yMS42 +IDE3NC4yMDEgLTIyLjQgMTczLjgwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmNj +OyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuNSI+CiAgPHBhdGggZD0iTS01OS44ODUg +MTc5LjI2NUMtNTkuODg1IDE3OS4yNjUgLTUyLjg3OCAxOTAuNDUzIC01Mi42NjEgMTc5LjI0MkMt +NTIuNjYxIDE3OS4yNDIgLTUyLjEwNCAxNzcuOTg0IC01My44NjQgMTc3Ljk2MkMtNTkuOTM5IDE3 +Ny44ODYgLTU4LjQxOCAxNzMuNzg0IC01OS44ODUgMTc5LjI2NXoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjZmZmZmNjOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuNSI+CiAgPHBh +dGggZD0iTS01Mi43MDcgMTc5LjUxNEMtNTIuNzA3IDE3OS41MTQgLTQ0Ljc4NiAxOTAuNzAxIC00 +NS40MjIgMTc5LjQyMUMtNDUuNDIyIDE3OS40MjEgLTQ1LjQxNSAxNzkuMDg5IC00Ny4xNjggMTc4 +LjkzNkMtNTEuOTE1IDE3OC41MjIgLTUxLjU3IDE3NC4wMDQgLTUyLjcwNyAxNzkuNTE0eiIvPgog +PC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lk +dGg6MC41Ij4KICA8cGF0aCBkPSJNLTQ1LjQ5NCAxNzkuNTIyQy00NS40OTQgMTc5LjUyMiAtMzcu +NTM0IDE5MC4xNSAtMzguMjAzIDE4MC40ODRDLTM4LjIwMyAxODAuNDg0IC0zOC4wODQgMTc5LjI1 +MSAtMzkuNzM4IDE3OC45NUMtNDMuNjMgMTc4LjI0NCAtNDMuODQxIDE3NC45OTUgLTQ1LjQ5NCAx +NzkuNTIyeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmY2M7IHN0cm9rZTojMDAwMDAw +OyBzdHJva2Utd2lkdGg6MC41Ij4KICA8cGF0aCBkPSJNLTM4LjYxOCAxNzkuNjAyQy0zOC42MTgg +MTc5LjYwMiAtMzAuNzE4IDE5MS4xNjMgLTMwLjM3IDE4MS4zODJDLTMwLjM3IDE4MS4zODIgLTI4 +LjcyNiAxODAuMDA0IC0zMC40NzIgMTc5Ljc4MkMtMzYuMjkgMTc5LjA0MiAtMzUuNDkyIDE3NC41 +ODggLTM4LjYxOCAxNzkuNjAyeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNlNWU1YjIiPgog +IDxwYXRoIGQ9Ik0tNzQuNzkyIDE4My4xMzJMLTgyLjQ1IDE4MS42MDFDLTg1LjA1IDE3Ni42MDEg +LTg3LjE1IDE3MC40NTEgLTg3LjE1IDE3MC40NTFDLTg3LjE1IDE3MC40NTEgLTgwLjggMTcxLjQ1 +MSAtNjguMyAxNzQuMjUxQy02OC4zIDE3NC4yNTEgLTY3LjQyNCAxNzcuNTY5IC02NS45NTIgMTgz +LjM2NEwtNzQuNzkyIDE4My4xMzJ6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2U1ZTViMiI+ +CiAgPHBhdGggZD0iTS05LjcyNCAxNzguNDdDLTExLjM5IDE3NS45NjQgLTEyLjcwNyAxNzQuMjA2 +IC0xMy4zNTcgMTczLjhDLTE2LjM3IDE3MS45MTcgLTEyLjIyNyAxNzIuMjk0IC0xMS4wOTggMTcy +LjI5NEMtMTEuMDk4IDE3Mi4yOTQgNS40NzMgMTcyLjI5NCA3LjM1NiAxNzMuMDQ3QzcuMzU2IDE3 +My4wNDcgNy44OCAxNzUuMjg5IDguNTY0IDE3OC42OEM4LjU2NCAxNzguNjggLTEuNTI0IDE3Ni42 +NyAtOS43MjQgMTc4LjQ3eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjYzcyMjYiPgogIDxw +YXRoIGQ9Ik00My44OCA0MC4zMjFDNzEuNjAxIDQ0LjI4MSA5Ny4xMjEgOC42NDEgOTguODgxIC0x +LjA0QzEwMC42NDEgLTEwLjcyIDkwLjUyMSAtMjIuNiA5MC41MjEgLTIyLjZDOTEuODQxIC0yNS42 +OCA4Ny4wMDEgLTM5Ljc2IDgxLjcyMSAtNDlDNzYuNDQxIC01OC4yNCA2MC41NCAtNTcuMjY2IDQz +IC01OC4yNEMyNy4xNiAtNTkuMTIgOC42OCAtMzUuOCA3LjM2IC0zNC4wNEM2LjA0IC0zMi4yOCAx +Mi4yIDYuMDAxIDEzLjUyIDExLjcyMUMxNC44NCAxNy40NDEgMTIuMiA0My44NDEgMTIuMiA0My44 +NDFDNDYuNDQgMzQuNzQxIDE2LjE2IDM2LjM2MSA0My44OCA0MC4zMjF6Ii8+CiA8L2c+CiA8ZyBz +dHlsZT0iZmlsbDogI2VhOGU1MSI+CiAgPHBhdGggZD0iTTguMDg4IC0zMy4zOTJDNi43OTIgLTMx +LjY2NCAxMi44NCA1LjkyMSAxNC4xMzYgMTEuNTM3QzE1LjQzMiAxNy4xNTMgMTIuODQgNDMuMDcz +IDEyLjg0IDQzLjA3M0M0NS41MTIgMzQuMTkzIDE2LjcyOCAzNS43MjkgNDMuOTQ0IDM5LjYxN0M3 +MS4xNjEgNDMuNTA1IDk2LjIxNyA4LjUxMyA5Ny45NDUgLTAuOTkyQzk5LjY3MyAtMTAuNDk2IDg5 +LjczNyAtMjIuMTYgODkuNzM3IC0yMi4xNkM5MS4wMzMgLTI1LjE4NCA4Ni4yODEgLTM5LjAwOCA4 +MS4wOTcgLTQ4LjA4Qzc1LjkxMyAtNTcuMTUyIDYwLjMwMiAtNTYuMTk1IDQzLjA4IC01Ny4xNTJD +MjcuNTI4IC01OC4wMTYgOS4zODQgLTM1LjEyIDguMDg4IC0zMy4zOTJ6Ii8+CiA8L2c+CiA8ZyBz +dHlsZT0iZmlsbDogI2VmYWE3YyI+CiAgPHBhdGggZD0iTTguODE2IC0zMi43NDRDNy41NDQgLTMx +LjA0OCAxMy40OCA1Ljg0MSAxNC43NTIgMTEuMzUzQzE2LjAyNCAxNi44NjUgMTMuNDggNDIuMzA1 +IDEzLjQ4IDQyLjMwNUM0NC44ODQgMzMuMTQ1IDE3LjI5NiAzNS4wOTcgNDQuMDA4IDM4LjkxM0M3 +MC43MjEgNDIuNzI5IDk1LjMxMyA4LjM4NSA5Ny4wMDkgLTAuOTQ0Qzk4LjcwNSAtMTAuMjcyIDg4 +Ljk1MyAtMjEuNzIgODguOTUzIC0yMS43MkM5MC4yMjUgLTI0LjY4OCA4NS41NjEgLTM4LjI1NiA4 +MC40NzMgLTQ3LjE2Qzc1LjM4NSAtNTYuMDY0IDYwLjA2MyAtNTUuMTI1IDQzLjE2IC01Ni4wNjRD +MjcuODk2IC01Ni45MTIgMTAuMDg4IC0zNC40NCA4LjgxNiAtMzIuNzQ0eiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNmNGM2YTgiPgogIDxwYXRoIGQ9Ik05LjU0NCAtMzIuMDk2QzguMjk2IC0z +MC40MzIgMTQuMTIgNS43NjEgMTUuMzY4IDExLjE2OUMxNi42MTYgMTYuNTc3IDE0LjEyIDQxLjUz +NyAxNC4xMiA0MS41MzdDNDMuNTU2IDMyLjQ5NyAxNy44NjQgMzQuNDY1IDQ0LjA3MiAzOC4yMDlD +NzAuMjgxIDQxLjk1MyA5NC40MDkgOC4yNTcgOTYuMDczIC0wLjg5NUM5Ny43MzcgLTEwLjA0OCA4 +OC4xNjkgLTIxLjI4IDg4LjE2OSAtMjEuMjhDODkuNDE3IC0yNC4xOTIgODQuODQxIC0zNy41MDQg +NzkuODQ5IC00Ni4yNEM3NC44NTcgLTU0Ljk3NiA1OS44MjQgLTU0LjA1NSA0My4yNCAtNTQuOTc2 +QzI4LjI2NCAtNTUuODA4IDEwLjc5MiAtMzMuNzYgOS41NDQgLTMyLjA5NnoiLz4KIDwvZz4KIDxn +IHN0eWxlPSJmaWxsOiAjZjllMmQzIj4KICA8cGF0aCBkPSJNMTAuMjcyIC0zMS40NDhDOS4wNDgg +LTI5LjgxNiAxNC43NiA1LjY4MSAxNS45ODQgMTAuOTg1QzE3LjIwOCAxNi4yODkgMTQuNzYgNDAu +NzY5IDE0Ljc2IDQwLjc2OUM0Mi42MjggMzEuODQ5IDE4LjQzMiAzMy44MzMgNDQuMTM2IDM3LjUw +NUM2OS44NDEgNDEuMTc3IDkzLjUwNSA4LjEyOSA5NS4xMzcgLTAuODQ4Qzk2Ljc2OSAtOS44MjQg +ODcuMzg1IC0yMC44NCA4Ny4zODUgLTIwLjg0Qzg4LjYwOSAtMjMuNjk2IDg0LjEyMSAtMzYuNzUy +IDc5LjIyNSAtNDUuMzJDNzQuMzI5IC01My44ODggNTkuNTg1IC01Mi45ODUgNDMuMzIgLTUzLjg4 +OEMyOC42MzIgLTU0LjcwNCAxMS40OTYgLTMzLjA4IDEwLjI3MiAtMzEuNDQ4eiIvPgogPC9nPgog +PGcgc3R5bGU9ImZpbGw6ICNmZmZmZmYiPgogIDxwYXRoIGQ9Ik00NC4yIDM2LjhDNjkuNCA0MC40 +IDkyLjYwMSA4IDk0LjIwMSAtMC44Qzk1LjgwMSAtOS42IDg2LjYwMSAtMjAuNCA4Ni42MDEgLTIw +LjRDODcuODAxIC0yMy4yIDgzLjQgLTM2IDc4LjYgLTQ0LjRDNzMuOCAtNTIuOCA1OS4zNDYgLTUx +LjkxNCA0My40IC01Mi44QzI5IC01My42IDEyLjIgLTMyLjQgMTEgLTMwLjhDOS44IC0yOS4yIDE1 +LjQgNS42IDE2LjYgMTAuOEMxNy44IDE2IDE1LjQgNDAgMTUuNCA0MEM0MC45IDMxLjQgMTkgMzMu +MiA0NC4yIDM2Ljh6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGgg +ZD0iTTkwLjYwMSAyLjhDOTAuNjAxIDIuOCA2Mi44IDEwLjQgNTEuMiA4LjhDNTEuMiA4LjggMzUu +NCAyLjIgMjYuNiAyNEMyNi42IDI0IDIzIDMxLjIgMjEgMzMuMkMxOSAzNS4yIDkwLjYwMSAyLjgg +OTAuNjAxIDIuOHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBk +PSJNOTQuNDAxIDAuNkM5NC40MDEgMC42IDY1LjQgMTIuOCA1NS40IDEyLjRDNTUuNCAxMi40IDM5 +IDcuOCAzMC42IDIyLjRDMzAuNiAyMi40IDIyLjIgMzEuNiAxOSAzMy4yQzE5IDMzLjIgMTguNiAz +NC44IDI1IDMwLjhMMzUuNCAzNkMzNS40IDM2IDUwLjIgNDUuNiA1OS44IDI5LjZDNTkuOCAyOS42 +IDYzLjggMTguNCA2My44IDE2LjRDNjMuOCAxNC40IDg1IDguOCA4Ni42MDEgOC40Qzg4LjIwMSA4 +IDk0LjgwMSAzLjggOTQuNDAxIDAuNnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjOTljYzMy +Ij4KICA8cGF0aCBkPSJNNDcgMzYuNTE0QzQwLjEyOCAzNi41MTQgMzEuNzU1IDMyLjY0OSAzMS43 +NTUgMjYuNEMzMS43NTUgMjAuMTUyIDQwLjEyOCAxMy44ODcgNDcgMTMuODg3QzUzLjg3NCAxMy44 +ODcgNTkuNDQ2IDE4Ljk1MiA1OS40NDYgMjUuMkM1OS40NDYgMzEuNDQ5IDUzLjg3NCAzNi41MTQg +NDcgMzYuNTE0eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICM2NTk5MDAiPgogIDxwYXRoIGQ9 +Ik00My4zNzcgMTkuODNDMzguNTMxIDIwLjU1MiAzMy40NDIgMjIuMDU1IDMzLjUxNCAyMS44MzlD +MzUuMDU0IDE3LjIyIDQxLjQxNSAxMy44ODcgNDcgMTMuODg3QzUxLjI5NiAxMy44ODcgNTUuMDg0 +IDE1Ljg2NSA1Ny4zMiAxOC44NzVDNTcuMzIgMTguODc1IDUyLjAwNCAxOC41NDUgNDMuMzc3IDE5 +LjgzeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmYiPgogIDxwYXRoIGQ9Ik01NS40 +IDE5LjZDNTUuNCAxOS42IDUxIDE2LjQgNTEgMTguNkM1MSAxOC42IDU0LjYgMjMgNTUuNCAxOS42 +eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik00NS40IDI3 +LjcyNkM0Mi45MDEgMjcuNzI2IDQwLjg3NSAyNS43IDQwLjg3NSAyMy4yQzQwLjg3NSAyMC43MDEg +NDIuOTAxIDE4LjY3NSA0NS40IDE4LjY3NUM0Ny45IDE4LjY3NSA0OS45MjYgMjAuNzAxIDQ5Ljky +NiAyMy4yQzQ5LjkyNiAyNS43IDQ3LjkgMjcuNzI2IDQ1LjQgMjcuNzI2eiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNjYzcyMjYiPgogIDxwYXRoIGQ9Ik0tNTguNiAxNC40Qy01OC42IDE0LjQg +LTYxLjggLTYuOCAtNTkuNCAtMTEuMkMtNTkuNCAtMTEuMiAtNDguNiAtMjEuMiAtNDkgLTI0LjhD +LTQ5IC0yNC44IC00OS40IC00Mi44IC01MC42IC00My42Qy01MS44IC00NC40IC01OS40IC01MC40 +IC02NS40IC00NEMtNjUuNCAtNDQgLTc1LjggLTI2IC03NSAtMTkuNkwtNzUgLTE3LjZDLTc1IC0x +Ny42IC04Mi42IC0xOCAtODQuMiAtMTZDLTg0LjIgLTE2IC04NS40IC0xMC44IC04Ni42IC0xMC40 +Qy04Ni42IC0xMC40IC04OS40IC04IC04Ny40IC01LjJDLTg3LjQgLTUuMiAtODkuNCAtMi44IC04 +OSAxLjJMLTgxLjQgNS4yQy04MS40IDUuMiAtNzkuNCAxOS42IC02OC42IDI0LjhDLTYzLjc2NCAy +Ny4xMjkgLTYwLjYgMjAuNCAtNTguNiAxNC40eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNm +ZmZmZmYiPgogIDxwYXRoIGQ9Ik0tNTkuNiAxMi41NkMtNTkuNiAxMi41NiAtNjIuNDggLTYuNTIg +LTYwLjMyIC0xMC40OEMtNjAuMzIgLTEwLjQ4IC01MC42IC0xOS40OCAtNTAuOTYgLTIyLjcyQy01 +MC45NiAtMjIuNzIgLTUxLjMyIC0zOC45MiAtNTIuNCAtMzkuNjRDLTUzLjQ4IC00MC4zNiAtNjAu +MzIgLTQ1Ljc2IC02NS43MiAtNDBDLTY1LjcyIC00MCAtNzUuMDggLTIzLjggLTc0LjM2IC0xOC4w +NEwtNzQuMzYgLTE2LjI0Qy03NC4zNiAtMTYuMjQgLTgxLjIgLTE2LjYgLTgyLjY0IC0xNC44Qy04 +Mi42NCAtMTQuOCAtODMuNzIgLTEwLjEyIC04NC44IC05Ljc2Qy04NC44IC05Ljc2IC04Ny4zMiAt +Ny42IC04NS41MiAtNS4wOEMtODUuNTIgLTUuMDggLTg3LjMyIC0yLjkyIC04Ni45NiAwLjY4TC04 +MC4xMiA0LjI4Qy04MC4xMiA0LjI4IC03OC4zMiAxNy4yNCAtNjguNiAyMS45MkMtNjQuMjQ4IDI0 +LjAxNSAtNjEuNCAxNy45NiAtNTkuNiAxMi41NnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +ZWI5NTVjIj4KICA8cGF0aCBkPSJNLTUxLjA1IC00Mi42MUMtNTIuMTQgLTQzLjQ3IC01OS42MyAt +NDkuMjQgLTY1LjQ4IC00M0MtNjUuNDggLTQzIC03NS42MiAtMjUuNDUgLTc0Ljg0IC0xOS4yMUwt +NzQuODQgLTE3LjI2Qy03NC44NCAtMTcuMjYgLTgyLjI1IC0xNy42NSAtODMuODEgLTE1LjdDLTgz +LjgxIC0xNS43IC04NC45OCAtMTAuNjMgLTg2LjE1IC0xMC4yNEMtODYuMTUgLTEwLjI0IC04OC44 +OCAtNy45IC04Ni45MyAtNS4xN0MtODYuOTMgLTUuMTcgLTg4Ljg4IC0yLjgzIC04OC40OSAxLjA3 +TC04MS4wOCA0Ljk3Qy04MS4wOCA0Ljk3IC03OS4xMyAxOS4wMSAtNjguNiAyNC4wOEMtNjMuODg2 +IDI2LjM1IC02MC44IDE5Ljc5IC01OC44NSAxMy45NEMtNTguODUgMTMuOTQgLTYxLjk3IC02Ljcz +IC01OS42MyAtMTEuMDJDLTU5LjYzIC0xMS4wMiAtNDkuMSAtMjAuNzcgLTQ5LjQ5IC0yNC4yOEMt +NDkuNDkgLTI0LjI4IC00OS44OCAtNDEuODMgLTUxLjA1IC00Mi42MXoiLz4KIDwvZz4KIDxnIHN0 +eWxlPSJmaWxsOiAjZjJiODkyIj4KICA8cGF0aCBkPSJNLTUxLjUgLTQxLjYyQy01Mi40OCAtNDIu +NTQgLTU5Ljg2IC00OC4wOCAtNjUuNTYgLTQyQy02NS41NiAtNDIgLTc1LjQ0IC0yNC45IC03NC42 +OCAtMTguODJMLTc0LjY4IC0xNi45MkMtNzQuNjggLTE2LjkyIC04MS45IC0xNy4zIC04My40MiAt +MTUuNEMtODMuNDIgLTE1LjQgLTg0LjU2IC0xMC40NiAtODUuNyAtMTAuMDhDLTg1LjcgLTEwLjA4 +IC04OC4zNiAtNy44IC04Ni40NiAtNS4xNEMtODYuNDYgLTUuMTQgLTg4LjM2IC0yLjg2IC04Ny45 +OCAwLjk0TC04MC43NiA0Ljc0Qy04MC43NiA0Ljc0IC03OC44NiAxOC40MiAtNjguNiAyMy4zNkMt +NjQuMDA2IDI1LjU3MiAtNjEgMTkuMTggLTU5LjEgMTMuNDhDLTU5LjEgMTMuNDggLTYyLjE0IC02 +LjY2IC01OS44NiAtMTAuODRDLTU5Ljg2IC0xMC44NCAtNDkuNiAtMjAuMzQgLTQ5Ljk4IC0yMy43 +NkMtNDkuOTggLTIzLjc2IC01MC4zNiAtNDAuODYgLTUxLjUgLTQxLjYyeiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNmOGRjYzgiPgogIDxwYXRoIGQ9Ik0tNTEuOTUgLTQwLjYzQy01Mi44MiAt +NDEuNjEgLTYwLjA5IC00Ni45MiAtNjUuNjQgLTQxQy02NS42NCAtNDEgLTc1LjI2IC0yNC4zNSAt +NzQuNTIgLTE4LjQzTC03NC41MiAtMTYuNThDLTc0LjUyIC0xNi41OCAtODEuNTUgLTE2Ljk1IC04 +My4wMyAtMTUuMUMtODMuMDMgLTE1LjEgLTg0LjE0IC0xMC4yOSAtODUuMjUgLTkuOTJDLTg1LjI1 +IC05LjkyIC04Ny44NCAtNy43IC04NS45OSAtNS4xMUMtODUuOTkgLTUuMTEgLTg3Ljg0IC0yLjg5 +IC04Ny40NyAwLjgxTC04MC40NCA0LjUxQy04MC40NCA0LjUxIC03OC41OSAxNy44MyAtNjguNiAy +Mi42NEMtNjQuMTI3IDI0Ljc5NCAtNjEuMiAxOC41NyAtNTkuMzUgMTMuMDJDLTU5LjM1IDEzLjAy +IC02Mi4zMSAtNi41OSAtNjAuMDkgLTEwLjY2Qy02MC4wOSAtMTAuNjYgLTUwLjEgLTE5LjkxIC01 +MC40NyAtMjMuMjRDLTUwLjQ3IC0yMy4yNCAtNTAuODQgLTM5Ljg5IC01MS45NSAtNDAuNjN6Ii8+ +CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZiI+CiAgPHBhdGggZD0iTS01OS42IDEyLjQ2 +Qy01OS42IDEyLjQ2IC02Mi40OCAtNi41MiAtNjAuMzIgLTEwLjQ4Qy02MC4zMiAtMTAuNDggLTUw +LjYgLTE5LjQ4IC01MC45NiAtMjIuNzJDLTUwLjk2IC0yMi43MiAtNTEuMzIgLTM4LjkyIC01Mi40 +IC0zOS42NEMtNTMuMTYgLTQwLjY4IC02MC4zMiAtNDUuNzYgLTY1LjcyIC00MEMtNjUuNzIgLTQw +IC03NS4wOCAtMjMuOCAtNzQuMzYgLTE4LjA0TC03NC4zNiAtMTYuMjRDLTc0LjM2IC0xNi4yNCAt +ODEuMiAtMTYuNiAtODIuNjQgLTE0LjhDLTgyLjY0IC0xNC44IC04My43MiAtMTAuMTIgLTg0Ljgg +LTkuNzZDLTg0LjggLTkuNzYgLTg3LjMyIC03LjYgLTg1LjUyIC01LjA4Qy04NS41MiAtNS4wOCAt +ODcuMzIgLTIuOTIgLTg2Ljk2IDAuNjhMLTgwLjEyIDQuMjhDLTgwLjEyIDQuMjggLTc4LjMyIDE3 +LjI0IC02OC42IDIxLjkyQy02NC4yNDggMjQuMDE1IC02MS40IDE3Ljg2IC01OS42IDEyLjQ2eiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tNjIuNyA2LjJD +LTYyLjcgNi4yIC04NC4zIC00IC04NS4yIC00LjhDLTg1LjIgLTQuOCAtNzYuMSAzLjQgLTc1LjMg +My40Qy03NC41IDMuNCAtNjIuNyA2LjIgLTYyLjcgNi4yeiIvPgogPC9nPgogPGcgc3R5bGU9ImZp +bGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tNzkuOCAwQy03OS44IDAgLTYxLjQgMy42IC02MS40 +IDhDLTYxLjQgMTAuOTEyIC02MS42NDMgMjQuMzMxIC02NyAyMi44Qy03NS40IDIwLjQgLTcxLjgg +NiAtNzkuOCAweiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICM5OWNjMzIiPgogIDxwYXRoIGQ9 +Ik0tNzEuNCAzLjhDLTcxLjQgMy44IC02Mi40MjIgNS4yNzQgLTYxLjQgOEMtNjAuOCA5LjYgLTYw +LjEzNyAxNy45MDggLTY1LjYgMTlDLTcwLjE1MiAxOS45MTEgLTcyLjM4MiA5LjY5IC03MS40IDMu +OHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNMTQuNTk1 +IDQ2LjM0OUMxNC4wOTggNDQuNjA3IDE1LjQwOSA0NC43MzggMTcuMiA0NC4yQzE5LjIgNDMuNiAz +MS40IDM5LjggMzIuMiAzNy4yQzMzIDM0LjYgNDYuMiAzOSA0Ni4yIDM5QzQ4IDM5LjggNTIuNCA0 +Mi40IDUyLjQgNDIuNEM1Ny4yIDQzLjYgNjMuOCA0NCA2My44IDQ0QzY2LjIgNDUgNjkuNiA0Ny44 +IDY5LjYgNDcuOEM4NC4yIDU4IDk2LjYwMSA1MC44IDk2LjYwMSA1MC44QzExNi42MDEgNDQuMiAx +MTAuNjAxIDI3IDExMC42MDEgMjdDMTA3LjYwMSAxOCAxMTAuODAxIDE0LjYgMTEwLjgwMSAxNC42 +QzExMS4wMDEgMTAuOCAxMTguMjAxIDE3LjIgMTE4LjIwMSAxNy4yQzEyMC44MDEgMjEuNCAxMjEu +NjAxIDI2LjQgMTIxLjYwMSAyNi40QzEyOS42MDEgMzcuNiAxMjYuMjAxIDE5LjggMTI2LjIwMSAx +OS44QzEyNi40MDEgMTguOCAxMjMuNjAxIDE1LjIgMTIzLjYwMSAxNEMxMjMuNjAxIDEyLjggMTIx +LjgwMSA5LjQgMTIxLjgwMSA5LjRDMTE4LjgwMSA2IDEyMS4yMDEgLTEgMTIxLjIwMSAtMUMxMjMu +MDAxIC0xNC44IDEyMC44MDEgLTEzIDEyMC44MDEgLTEzQzExOS42MDEgLTE0LjggMTEwLjQwMSAt +NC44IDExMC40MDEgLTQuOEMxMDguMjAxIC0xLjQgMTAyLjIwMSAwLjIgMTAyLjIwMSAwLjJDOTku +NDAxIDIgOTYuMDAxIDAuNiA5Ni4wMDEgMC42QzkzLjQwMSAwLjIgODcuODAxIDcuMiA4Ny44MDEg +Ny4yQzkwLjYwMSA3IDkzLjAwMSAxMS40IDk1LjQwMSAxMS42Qzk3LjgwMSAxMS44IDk5LjYwMSA5 +LjIgMTAxLjIwMSA4LjZDMTAyLjgwMSA4IDEwNS42MDEgMTMuOCAxMDUuNjAxIDEzLjhDMTA2LjAw +MSAxNi40IDEwMC40MDEgMjEuMiAxMDAuNDAxIDIxLjJDMTAwLjAwMSAyNS44IDk4LjQwMSAyNC4y +IDk4LjQwMSAyNC4yQzk1LjQwMSAyMy42IDk0LjIwMSAyNy40IDkzLjIwMSAzMkM5Mi4yMDEgMzYu +NiA4OC4wMDEgMzcgODguMDAxIDM3Qzg2LjQwMSA0NC40IDg1LjIgNDEuNCA4NS4yIDQxLjRDODUg +MzUuOCA3OSA0MS42IDc5IDQxLjZDNzcuOCA0My42IDczLjIgNDEuNCA3My4yIDQxLjRDNjYuNCAz +OS40IDY4LjggMzcuNCA2OC44IDM3LjRDNzAuNiAzNS4yIDgxLjggMzcuNCA4MS44IDM3LjRDODQg +MzUuOCA3NiAzMS44IDc2IDMxLjhDNzUuNCAzMCA3Ni40IDI1LjYgNzYuNCAyNS42Qzc3LjYgMjIu +NCA4NC40IDE2LjggODQuNCAxNi44QzkzLjgwMSAxNS42IDkxLjAwMSAxNCA5MS4wMDEgMTRDODQu +ODAxIDguOCA3OSAxNi40IDc5IDE2LjRDNzYuOCAyMi42IDU5LjQgMzcuNiA1OS40IDM3LjZDNTQu +NiA0MSA1Ny4yIDM0LjIgNTMuMiAzNy42QzQ5LjIgNDEgMjguNiAzMiAyOC42IDMyQzE3LjAzOCAz +MC44MDcgMTQuMzA2IDQ2LjU0OSAxMC43NzcgNDMuNDI5QzEwLjc3NyA0My40MjkgMTYuMTk1IDUx +Ljk0OSAxNC41OTUgNDYuMzQ5eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgog +IDxwYXRoIGQ9Ik0yMDkuNDAxIC0xMjBDMjA5LjQwMSAtMTIwIDE4My44MDEgLTExMiAxODEuMDAx +IC05My4yQzE4MS4wMDEgLTkzLjIgMTc4LjYwMSAtNzAuNCAxOTkuMDAxIC01Mi44QzE5OS4wMDEg +LTUyLjggMTk5LjQwMSAtNDYuNCAyMDEuNDAxIC00My4yQzIwMS40MDEgLTQzLjIgMTk5LjgwMSAt +MzguNCAyMTguNjAxIC00NkwyNDUuODAxIC01NC40QzI0NS44MDEgLTU0LjQgMjUyLjIwMSAtNTYu +OCAyNTcuNDAxIC02NS42QzI2Mi42MDEgLTc0LjQgMjc3LjgwMSAtOTMuMiAyNzQuMjAxIC0xMTgu +NEMyNzQuMjAxIC0xMTguNCAyNzUuNDAxIC0xMjkuNiAyNjkuNDAxIC0xMzBDMjY5LjQwMSAtMTMw +IDI2MS4wMDEgLTEzMS42IDI1My44MDEgLTEyNEMyNTMuODAxIC0xMjQgMjQ3LjAwMSAtMTIwLjgg +MjQ0LjYwMSAtMTIxLjJMMjA5LjQwMSAtMTIweiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMw +MDAwMDAiPgogIDxwYXRoIGQ9Ik0yNjQuMDIyIC0xMjAuOTlDMjY0LjAyMiAtMTIwLjk5IDI2Ni4x +MjIgLTEyOS45MiAyNjEuMjgyIC0xMjUuMDhDMjYxLjI4MiAtMTI1LjA4IDI1NC4yNDIgLTExOS4z +NiAyNDYuNzYxIC0xMTkuMzZDMjQ2Ljc2MSAtMTE5LjM2IDIzMi4yNDEgLTExNy4xNiAyMjcuODQx +IC0xMDMuOTZDMjI3Ljg0MSAtMTAzLjk2IDIyMy44ODEgLTc3LjEyIDIzMS44MDEgLTcxLjRDMjMx +LjgwMSAtNzEuNCAyMzYuNjQxIC02My45MiAyNDMuNjgxIC03MC41MkMyNTAuNzIyIC03Ny4xMiAy +NjYuMjIyIC0xMDcuMzUgMjY0LjAyMiAtMTIwLjk5eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6 +ICMzMjMyMzIiPgogIDxwYXRoIGQ9Ik0yNjMuNjQ4IC0xMjAuNjMyQzI2My42NDggLTEyMC42MzIg +MjY1LjczOCAtMTI5LjM3NiAyNjAuOTg2IC0xMjQuNjI0QzI2MC45ODYgLTEyNC42MjQgMjU0LjA3 +NCAtMTE5LjAwOCAyNDYuNzI5IC0xMTkuMDA4QzI0Ni43MjkgLTExOS4wMDggMjMyLjQ3MyAtMTE2 +Ljg0OCAyMjguMTUzIC0xMDMuODg4QzIyOC4xNTMgLTEwMy44ODggMjI0LjI2NSAtNzcuNTM2IDIz +Mi4wNDEgLTcxLjkyQzIzMi4wNDEgLTcxLjkyIDIzNi43OTMgLTY0LjU3NiAyNDMuNzA1IC03MS4w +NTZDMjUwLjYxOCAtNzcuNTM2IDI2NS44MDggLTEwNy4yNCAyNjMuNjQ4IC0xMjAuNjMyeiIvPgog +PC9nPgogPGcgc3R5bGU9ImZpbGw6ICM2NjY2NjYiPgogIDxwYXRoIGQ9Ik0yNjMuMjc0IC0xMjAu +Mjc0QzI2My4yNzQgLTEyMC4yNzQgMjY1LjM1NCAtMTI4LjgzMiAyNjAuNjkgLTEyNC4xNjhDMjYw +LjY5IC0xMjQuMTY4IDI1My45MDYgLTExOC42NTYgMjQ2LjY5NyAtMTE4LjY1NkMyNDYuNjk3IC0x +MTguNjU2IDIzMi43MDUgLTExNi41MzYgMjI4LjQ2NSAtMTAzLjgxNkMyMjguNDY1IC0xMDMuODE2 +IDIyNC42NDkgLTc3Ljk1MiAyMzIuMjgxIC03Mi40NEMyMzIuMjgxIC03Mi40NCAyMzYuOTQ1IC02 +NS4yMzIgMjQzLjcyOSAtNzEuNTkyQzI1MC41MTQgLTc3Ljk1MiAyNjUuMzk0IC0xMDcuMTMgMjYz +LjI3NCAtMTIwLjI3NHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjOTk5OTk5Ij4KICA8cGF0 +aCBkPSJNMjYyLjkgLTExOS45MTZDMjYyLjkgLTExOS45MTYgMjY0Ljk3IC0xMjguMjg4IDI2MC4z +OTQgLTEyMy43MTJDMjYwLjM5NCAtMTIzLjcxMiAyNTMuNzM4IC0xMTguMzA0IDI0Ni42NjUgLTEx +OC4zMDRDMjQ2LjY2NSAtMTE4LjMwNCAyMzIuOTM3IC0xMTYuMjI0IDIyOC43NzcgLTEwMy43NDRD +MjI4Ljc3NyAtMTAzLjc0NCAyMjUuMDMzIC03OC4zNjggMjMyLjUyMSAtNzIuOTZDMjMyLjUyMSAt +NzIuOTYgMjM3LjA5NyAtNjUuODg4IDI0My43NTMgLTcyLjEyOEMyNTAuNDEgLTc4LjM2OCAyNjQu +OTggLTEwNy4wMiAyNjIuOSAtMTE5LjkxNnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2Nj +Y2NjIj4KICA8cGF0aCBkPSJNMjYyLjUyNiAtMTE5LjU1OEMyNjIuNTI2IC0xMTkuNTU4IDI2NC41 +ODYgLTEyNy43NDQgMjYwLjA5OCAtMTIzLjI1NkMyNjAuMDk4IC0xMjMuMjU2IDI1My41NjkgLTEx +Ny45NTIgMjQ2LjYzMyAtMTE3Ljk1MkMyNDYuNjMzIC0xMTcuOTUyIDIzMy4xNjkgLTExNS45MTIg +MjI5LjA4OSAtMTAzLjY3MkMyMjkuMDg5IC0xMDMuNjcyIDIyNS40MTcgLTc4Ljc4NCAyMzIuNzYx +IC03My40OEMyMzIuNzYxIC03My40OCAyMzcuMjQ5IC02Ni41NDQgMjQzLjc3NyAtNzIuNjY0QzI1 +MC4zMDUgLTc4Ljc4NCAyNjQuNTY2IC0xMDYuOTEgMjYyLjUyNiAtMTE5LjU1OHoiLz4KIDwvZz4K +IDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmIj4KICA8cGF0aCBkPSJNMjYyLjE1MSAtMTE5LjJDMjYy +LjE1MSAtMTE5LjIgMjY0LjIwMSAtMTI3LjIgMjU5LjgwMSAtMTIyLjhDMjU5LjgwMSAtMTIyLjgg +MjUzLjQwMSAtMTE3LjYgMjQ2LjYwMSAtMTE3LjZDMjQ2LjYwMSAtMTE3LjYgMjMzLjQwMSAtMTE1 +LjYgMjI5LjQwMSAtMTAzLjZDMjI5LjQwMSAtMTAzLjYgMjI1LjgwMSAtNzkuMiAyMzMuMDAxIC03 +NEMyMzMuMDAxIC03NCAyMzcuNDAxIC02Ny4yIDI0My44MDEgLTczLjJDMjUwLjIwMSAtNzkuMiAy +NjQuMTUxIC0xMDYuOCAyNjIuMTUxIC0xMTkuMnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +OTkyNjAwIj4KICA8cGF0aCBkPSJNNTAuNiA4NEM1MC42IDg0IDMwLjIgNjQuOCAyMi4yIDY0QzIy +LjIgNjQgLTEyLjIgNjAgLTI3IDc4Qy0yNyA3OCAtOS40IDU3LjYgMTguMiA2My4yQzE4LjIgNjMu +MiAtMy40IDU4LjggLTE1LjggNjJDLTE1LjggNjIgLTMyLjYgNjIgLTQyLjIgNzZMLTQ1IDgwLjhD +LTQ1IDgwLjggLTQxIDY2IC0yMi42IDYwQy0yMi42IDYwIDAuMiA1NS4yIDExIDYwQzExIDYwIC0x +MC42IDUzLjIgLTIwLjYgNTUuMkMtMjAuNiA1NS4yIC01MSA1Mi44IC02My44IDc5LjJDLTYzLjgg +NzkuMiAtNTkuOCA2NC44IC00NSA1Ny42Qy00NSA1Ny42IC0zMS40IDQ4LjggLTExIDUxLjZDLTEx +IDUxLjYgMy40IDU0LjggOC42IDU3LjJDMTMuOCA1OS42IDEyLjYgNTYuOCA0LjIgNTJDNC4yIDUy +IC0xLjQgNDIgLTE1LjQgNDIuNEMtMTUuNCA0Mi40IC01OC4yIDQ2IC02OC42IDU4Qy02OC42IDU4 +IC01NSA0Ni44IC00NC42IDQ0Qy00NC42IDQ0IC0yMi4yIDM2IC0xMy44IDM2LjhDLTEzLjggMzYu +OCAxMSAzNy44IDE4LjYgMzMuOEMxOC42IDMzLjggNy40IDM4LjggMTAuNiA0MkMxMy44IDQ1LjIg +MjAuNiA1Mi44IDIwLjYgNTRDMjAuNiA1NS4yIDQ0LjggNzcuMyA0OC40IDgxLjdMNTAuNiA4NHoi +Lz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNMTg5IDI3OEMx +ODkgMjc4IDE3My41IDI0MS41IDE2MSAyMzJDMTYxIDIzMiAxODcgMjQ4IDE5MC41IDI2NkMxOTAu +NSAyNjYgMTkwLjUgMjc2IDE4OSAyNzh6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2Nj +YyI+CiAgPHBhdGggZD0iTTIzNiAyODUuNUMyMzYgMjg1LjUgMjA5LjUgMjMwLjUgMTkxIDIwNi41 +QzE5MSAyMDYuNSAyMzQuNSAyNDQgMjM5LjUgMjcwLjVMMjQwIDI3NkwyMzcgMjczLjVDMjM3IDI3 +My41IDIzNi41IDI4Mi41IDIzNiAyODUuNXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2Nj +Y2NjIj4KICA8cGF0aCBkPSJNMjkyLjUgMjM3QzI5Mi41IDIzNyAyMzAgMTc3LjUgMjI4LjUgMTc1 +QzIyOC41IDE3NSAyODkgMjQxIDI5MiAyNDguNUMyOTIgMjQ4LjUgMjkwIDIzOS41IDI5Mi41IDIz +N3oiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNMTA0IDI4 +MC41QzEwNCAyODAuNSAxMjMuNSAyMjguNSAxNDIuNSAyNTFDMTQyLjUgMjUxIDE1Ny41IDI2MSAx +NTcgMjY0QzE1NyAyNjQgMTUzIDI1Ny41IDEzNSAyNThDMTM1IDI1OCAxMTYgMjU1IDEwNCAyODAu +NXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNMjk0LjUg +MTUzQzI5NC41IDE1MyAyNDkuNSAxMjQuNSAyNDIgMTIzQzIzMC4xOTMgMTIwLjYzOSAyOTEuNSAx +NTIgMjk2LjUgMTYyLjVDMjk2LjUgMTYyLjUgMjk4LjUgMTYwIDI5NC41IDE1M3oiLz4KIDwvZz4K +IDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNMTQzLjgwMSAyNTkuNjAxQzE0 +My44MDEgMjU5LjYwMSAxNjQuMjAxIDI1Ny42MDEgMTcxLjAwMSAyNTAuODAxTDE3NS40MDEgMjU0 +LjQwMUwxOTMuMDAxIDIxNi4wMDFMMTk2LjYwMSAyMjEuMjAxQzE5Ni42MDEgMjIxLjIwMSAyMTEu +MDAxIDIwNi40MDEgMjEwLjIwMSAxOTguNDAxQzIwOS40MDEgMTkwLjQwMSAyMjMuMDAxIDIwNC40 +MDEgMjIzLjAwMSAyMDQuNDAxQzIyMy4wMDEgMjA0LjQwMSAyMjIuMjAxIDE5Mi44MDEgMjI5LjQw +MSAxOTkuNjAxQzIyOS40MDEgMTk5LjYwMSAyMjcuMDAxIDE4NC4wMDEgMjM1LjQwMSAxOTIuMDAx +QzIzNS40MDEgMTkyLjAwMSAyMjQuODY0IDE2MS44NDQgMjQ3LjQwMSAxODcuNjAxQzI1My4wMDEg +MTk0LjAwMSAyNDguNjAxIDE4Ny4yMDEgMjQ4LjYwMSAxODcuMjAxQzI0OC42MDEgMTg3LjIwMSAy +MjIuNjAxIDEzOS4yMDEgMjQ0LjIwMSAxNTMuNjAxQzI0NC4yMDEgMTUzLjYwMSAyNDYuMjAxIDEz +MC44MDEgMjQ1LjAwMSAxMjYuNDAxQzI0My44MDEgMTIyLjAwMSAyNDEuODAxIDk5LjYgMjM3LjAw +MSA5NC40QzIzMi4yMDEgODkuMiAyMzcuNDAxIDg3LjYgMjQzLjAwMSA5Mi44QzI0My4wMDEgOTIu +OCAyMzEuODAxIDY4LjggMjQ1LjAwMSA4MC44QzI0NS4wMDEgODAuOCAyNDEuNDAxIDY1LjYgMjM3 +LjAwMSA2Mi44QzIzNy4wMDEgNjIuOCAyMzEuNDAxIDQ1LjYgMjQ2LjYwMSA1Ni40QzI0Ni42MDEg +NTYuNCAyNDIuMjAxIDQ0IDIzOS4wMDEgNDAuOEMyMzkuMDAxIDQwLjggMjI3LjQwMSAxMy4yIDIz +NC42MDEgMThMMjM5LjAwMSAyMS42QzIzOS4wMDEgMjEuNiAyMzIuMjAxIDcuNiAyMzguNjAxIDEy +QzI0NS4wMDEgMTYuNCAyNDUuMDAxIDE2IDI0NS4wMDEgMTZDMjQ1LjAwMSAxNiAyMjMuODAxIC0x +Ny4yIDI0NC4yMDEgMC40QzI0NC4yMDEgMC40IDIzNi4wNDIgLTEzLjUxOCAyMzIuNjAxIC0yMC40 +QzIzMi42MDEgLTIwLjQgMjEzLjgwMSAtNDAuOCAyMjguMjAxIC0zNC40TDIzMy4wMDEgLTMyLjhD +MjMzLjAwMSAtMzIuOCAyMjQuMjAxIC00Mi44IDIxNi4yMDEgLTQ0LjRDMjA4LjIwMSAtNDYgMjE4 +LjYwMSAtNTIuNCAyMjUuMDAxIC01MC40QzIzMS40MDEgLTQ4LjQgMjQ3LjAwMSAtNDAuOCAyNDcu +MDAxIC00MC44QzI0Ny4wMDEgLTQwLjggMjU5LjgwMSAtMjIgMjYzLjgwMSAtMjEuNkMyNjMuODAx +IC0yMS42IDI0My44MDEgLTI5LjIgMjQ5LjgwMSAtMjEuMkMyNDkuODAxIC0yMS4yIDI2NC4yMDEg +LTcuMiAyNTcuMDAxIC03LjZDMjU3LjAwMSAtNy42IDI1MS4wMDEgLTAuNCAyNTUuODAxIDguNEMy +NTUuODAxIDguNCAyMzcuMzQyIC05Ljk5MSAyNTIuMjAxIDE1LjZMMjU5LjAwMSAzMkMyNTkuMDAx +IDMyIDIzNC42MDEgNy4yIDI0NS44MDEgMjkuMkMyNDUuODAxIDI5LjIgMjYzLjAwMSA1Mi44IDI2 +NS4wMDEgNTMuMkMyNjcuMDAxIDUzLjYgMjcxLjQwMSA2Mi40IDI3MS40MDEgNjIuNEwyNjcuMDAx +IDYwLjRMMjcyLjIwMSA2OS4yQzI3Mi4yMDEgNjkuMiAyNjEuMDAxIDU3LjIgMjY3LjAwMSA3MC40 +TDI3Mi42MDEgODQuOEMyNzIuNjAxIDg0LjggMjUyLjIwMSA2Mi44IDI2NS44MDEgOTIuNEMyNjUu +ODAxIDkyLjQgMjQ5LjQwMSA4Ny4yIDI1OC4yMDEgMTA0LjRDMjU4LjIwMSAxMDQuNCAyNTYuNjAx +IDEyMC40MDEgMjU3LjAwMSAxMjUuNjAxQzI1Ny40MDEgMTMwLjgwMSAyNTguNjAxIDE1OS4yMDEg +MjU0LjIwMSAxNjcuMjAxQzI0OS44MDEgMTc1LjIwMSAyNjAuMjAxIDE5NC40MDEgMjYyLjIwMSAx +OTguNDAxQzI2NC4yMDEgMjAyLjQwMSAyNjcuODAxIDIxMy4yMDEgMjU5LjAwMSAyMDQuMDAxQzI1 +MC4yMDEgMTk0LjgwMSAyNTQuNjAxIDIwMC40MDEgMjU2LjYwMSAyMDkuMjAxQzI1OC42MDEgMjE4 +LjAwMSAyNjQuNjAxIDIzMy42MDEgMjYzLjgwMSAyMzkuMjAxQzI2My44MDEgMjM5LjIwMSAyNjIu +NjAxIDI0MC40MDEgMjU5LjQwMSAyMzYuODAxQzI1OS40MDEgMjM2LjgwMSAyNDQuNjAxIDIxNC4w +MDEgMjQ2LjIwMSAyMjguNDAxQzI0Ni4yMDEgMjI4LjQwMSAyNDUuMDAxIDIzNi40MDEgMjQxLjgw +MSAyNDUuMjAxQzI0MS44MDEgMjQ1LjIwMSAyMzguNjAxIDI1Ni4wMDEgMjM4LjYwMSAyNDcuMjAx +QzIzOC42MDEgMjQ3LjIwMSAyMzUuNDAxIDIzMC40MDEgMjMyLjYwMSAyMzguMDAxQzIyOS44MDEg +MjQ1LjYwMSAyMjYuMjAxIDI1MS42MDEgMjIzLjQwMSAyNTQuMDAxQzIyMC42MDEgMjU2LjQwMSAy +MTUuNDAxIDIzMy42MDEgMjE0LjIwMSAyNDQuMDAxQzIxNC4yMDEgMjQ0LjAwMSAyMDIuMjAxIDIz +MS42MDEgMTk3LjQwMSAyNDguMDAxTDE4NS44MDEgMjY0LjQwMUMxODUuODAxIDI2NC40MDEgMTg1 +LjQwMSAyNTIuMDAxIDE4NC4yMDEgMjU4LjAwMUMxODQuMjAxIDI1OC4wMDEgMTU0LjIwMSAyNjQu +MDAxIDE0My44MDEgMjU5LjYwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4K +ICA8cGF0aCBkPSJNMTA5LjQwMSAtOTcuMkMxMDkuNDAxIC05Ny4yIDk3LjgwMSAtMTA1LjIgOTMu +ODAxIC0xMDQuOEM4OS44MDEgLTEwNC40IDEyMS40MDEgLTExMy42IDE2Mi42MDEgLTg2QzE2Mi42 +MDEgLTg2IDE2Ny40MDEgLTgzLjIgMTcxLjAwMSAtODMuNkMxNzEuMDAxIC04My42IDE3NC4yMDEg +LTgxLjIgMTcxLjQwMSAtNzcuNkMxNzEuNDAxIC03Ny42IDE2Mi42MDEgLTY4IDE3My44MDEgLTU2 +LjhDMTczLjgwMSAtNTYuOCAxOTIuMjAxIC01MCAxODYuNjAxIC01OC44QzE4Ni42MDEgLTU4Ljgg +MTk3LjQwMSAtNTQuOCAxOTkuODAxIC01MC44QzIwMi4yMDEgLTQ2LjggMjAxLjAwMSAtNTAuOCAy +MDEuMDAxIC01MC44QzIwMS4wMDEgLTUwLjggMTk0LjYwMSAtNTggMTg4LjYwMSAtNjMuMkMxODgu +NjAxIC02My4yIDE4My40MDEgLTY1LjIgMTgwLjYwMSAtNzMuNkMxNzcuODAxIC04MiAxNzUuNDAx +IC05MiAxNzkuODAxIC05NS4yQzE3OS44MDEgLTk1LjIgMTc1LjgwMSAtOTAuOCAxNzYuNjAxIC05 +NC44QzE3Ny40MDEgLTk4LjggMTgxLjAwMSAtMTAyLjQgMTgyLjYwMSAtMTAyLjhDMTg0LjIwMSAt +MTAzLjIgMjAwLjYwMSAtMTE5IDIwNy40MDEgLTExOS40QzIwNy40MDEgLTExOS40IDE5OC4yMDEg +LTExOCAxOTUuMjAxIC0xMTlDMTkyLjIwMSAtMTIwIDE2NS42MDEgLTEzMS40IDE1OS42MDEgLTEz +Mi42QzE1OS42MDEgLTEzMi42IDE0Mi44MDEgLTEzOS4yIDE1NC44MDEgLTEzNy4yQzE1NC44MDEg +LTEzNy4yIDE5MC42MDEgLTEzMy40IDIwOC44MDEgLTEyMC4yQzIwOC44MDEgLTEyMC4yIDIwMS42 +MDEgLTEyOC42IDE4My4yMDEgLTEzNS42QzE4My4yMDEgLTEzNS42IDE2MS4wMDEgLTE0OC4yIDEy +NS44MDEgLTE0My4yQzEyNS44MDEgLTE0My4yIDEwOC4wMDEgLTE0MCAxMDAuMjAxIC0xMzguMkMx +MDAuMjAxIC0xMzguMiA5Ny42MDEgLTEzOC44IDk3LjAwMSAtMTM5LjJDOTYuNDAxIC0xMzkuNiA4 +NC42IC0xNDguNiA1NyAtMTQxLjZDNTcgLTE0MS42IDQwIC0xMzcgMzEuNCAtMTMyLjJDMzEuNCAt +MTMyLjIgMTYuMiAtMTMxIDEyLjYgLTEyNy44QzEyLjYgLTEyNy44IC02IC0xMTMuMiAtOCAtMTEy +LjRDLTEwIC0xMTEuNiAtMjEuNCAtMTA0IC0yMi4yIC0xMDMuNkMtMjIuMiAtMTAzLjYgMi40IC0x +MTAuMiA0LjggLTExMi42QzcuMiAtMTE1IDI0LjYgLTExNy42IDI3IC0xMTYuMkMyOS40IC0xMTQu +OCAzNy44IC0xMTUuNCAyOC4yIC0xMTQuOEMyOC4yIC0xMTQuOCAxMDMuODAxIC0xMDAgMTA0LjYw +MSAtOThDMTA1LjQwMSAtOTYgMTA5LjQwMSAtOTcuMiAxMDkuNDAxIC05Ny4yeiIvPgogPC9nPgog +PGcgc3R5bGU9ImZpbGw6ICNjYzcyMjYiPgogIDxwYXRoIGQ9Ik0xODAuODAxIC0xMDYuNEMxODAu +ODAxIC0xMDYuNCAxNzAuNjAxIC0xMTMuOCAxNjguNjAxIC0xMTMuOEMxNjYuNjAxIC0xMTMuOCAx +NTQuMjAxIC0xMjQgMTUwLjAwMSAtMTIzLjZDMTQ1LjgwMSAtMTIzLjIgMTMzLjYwMSAtMTMzLjIg +MTA2LjIwMSAtMTI1QzEwNi4yMDEgLTEyNSAxMDUuNjAxIC0xMjcgMTA5LjIwMSAtMTI3LjhDMTA5 +LjIwMSAtMTI3LjggMTE1LjYwMSAtMTMwIDExNi4wMDEgLTEzMC42QzExNi4wMDEgLTEzMC42IDEz +Ni4yMDEgLTEzNC44IDE0My40MDEgLTEzMS4yQzE0My40MDEgLTEzMS4yIDE1Mi42MDEgLTEyOC42 +IDE1OC44MDEgLTEyMi40QzE1OC44MDEgLTEyMi40IDE3MC4wMDEgLTExOS4yIDE3My4yMDEgLTEy +MC4yQzE3My4yMDEgLTEyMC4yIDE4Mi4wMDEgLTExOCAxODIuNDAxIC0xMTYuMkMxODIuNDAxIC0x +MTYuMiAxODguMjAxIC0xMTMuMiAxODYuNDAxIC0xMTAuNkMxODYuNDAxIC0xMTAuNiAxODYuODAx +IC0xMDkgMTgwLjgwMSAtMTA2LjR6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjNzIyNiI+ +CiAgPHBhdGggZD0iTTE2OC4zMyAtMTA4LjUwOUMxNjkuMTM3IC0xMDcuODc3IDE3MC4xNTYgLTEw +Ny43NzkgMTcwLjc2MSAtMTA2Ljk3QzE3MC45OTUgLTEwNi42NTYgMTcwLjcwNiAtMTA2LjMzIDE3 +MC4zOTEgLTEwNi4yMzNDMTY5LjM0OCAtMTA1LjkxNiAxNjguMjkyIC0xMDYuNDg2IDE2Ny4xNSAt +MTA1Ljg5OEMxNjYuNzQ4IC0xMDUuNjkxIDE2Ni4xMDYgLTEwNS44NzMgMTY1LjU1MyAtMTA2LjAy +MkMxNjMuOTIxIC0xMDYuNDYzIDE2Mi4wOTIgLTEwNi40ODggMTYwLjQwMSAtMTA1LjhDMTU4LjQx +NiAtMTA2LjkyOSAxNTYuMDU2IC0xMDYuMzQ1IDE1My45NzUgLTEwNy4zNDZDMTUzLjkxNyAtMTA3 +LjM3MyAxNTMuNjk1IC0xMDcuMDI3IDE1My42MjEgLTEwNy4wNTRDMTUwLjU3NSAtMTA4LjE5OSAx +NDYuODMyIC0xMDcuOTE2IDE0NC40MDEgLTExMC4yQzE0MS45NzMgLTExMC42MTIgMTM5LjYxNiAt +MTExLjA3NCAxMzcuMTg4IC0xMTEuNzU0QzEzNS4zNyAtMTEyLjI2MyAxMzMuOTYxIC0xMTMuMjUy +IDEzMi4zNDEgLTExNC4wODRDMTMwLjk2NCAtMTE0Ljc5MiAxMjkuNTA3IC0xMTUuMzE0IDEyNy45 +NzMgLTExNS42ODZDMTI2LjExIC0xMTYuMTM4IDEyNC4yNzkgLTExNi4wMjYgMTIyLjM4NiAtMTE2 +LjU0NkMxMjIuMjkzIC0xMTYuNTcxIDEyMi4xMDEgLTExNi4yMjcgMTIyLjAxOSAtMTE2LjI1NEMx +MjEuNjk1IC0xMTYuMzYyIDEyMS40MDUgLTExNi45NDUgMTIxLjIzNCAtMTE2Ljg5MkMxMTkuNTUz +IC0xMTYuMzcgMTE4LjA2NSAtMTE3LjM0MiAxMTYuNDAxIC0xMTdDMTE1LjIyMyAtMTE4LjIyNCAx +MTMuNDk1IC0xMTcuOTc5IDExMS45NDkgLTExOC40MjFDMTA4Ljk4NSAtMTE5LjI2OSAxMDUuODMx +IC0xMTcuOTk5IDEwMi44MDEgLTExOUMxMDYuOTE0IC0xMjAuODQyIDExMS42MDEgLTExOS42MSAx +MTUuNjYzIC0xMjEuNjc5QzExNy45OTEgLTEyMi44NjUgMTIwLjY1MyAtMTIxLjc2MyAxMjMuMjIz +IC0xMjIuNTIzQzEyMy43MSAtMTIyLjY2NyAxMjQuNDAxIC0xMjIuODY5IDEyNC44MDEgLTEyMi4y +QzEyNC45MzUgLTEyMi4zMzUgMTI1LjExNyAtMTIyLjU3NCAxMjUuMTc1IC0xMjIuNTQ2QzEyNy42 +MjUgLTEyMS4zODkgMTI5Ljk0IC0xMjAuMTE1IDEzMi40MjIgLTExOS4wNDlDMTMyLjc2MyAtMTE4 +LjkwMyAxMzMuMjk1IC0xMTkuMTM1IDEzMy41NDcgLTExOC45MzNDMTM1LjA2NyAtMTE3LjcxNyAx +MzcuMDEgLTExNy44MiAxMzguNDAxIC0xMTYuNkMxNDAuMDk5IC0xMTcuMTAyIDE0MS44OTIgLTEx +Ni43MjIgMTQzLjYyMSAtMTE3LjM0NkMxNDMuNjk4IC0xMTcuMzczIDE0My45MzIgLTExNy4wMzIg +MTQzLjk2NSAtMTE3LjA1NEMxNDUuMDk1IC0xMTcuODAyIDE0Ni4yNSAtMTE3LjUzMSAxNDcuMTQy +IC0xMTcuMjI3QzE0Ny40OCAtMTE3LjExMiAxNDguMTQzIC0xMTYuODY1IDE0OC40NDggLTExNi43 +OTFDMTQ5LjU3NCAtMTE2LjUxNSAxNTAuNDMgLTExNi4wMzUgMTUxLjYwOSAtMTE1Ljg1MkMxNTEu +NzIzIC0xMTUuODM0IDE1MS45MDggLTExNi4xNzQgMTUxLjk4IC0xMTYuMTQ2QzE1My4xMDMgLTEx +NS43MDggMTU0LjE0NSAtMTE1Ljc2NCAxNTQuODAxIC0xMTQuNkMxNTQuOTM2IC0xMTQuNzM1IDE1 +NS4xMDEgLTExNC45NzMgMTU1LjE4MyAtMTE0Ljk0NkMxNTYuMjEgLTExNC42MDggMTU2Ljg1OSAt +MTEzLjg1MyAxNTcuOTYgLTExMy42MTJDMTU4LjQ0NSAtMTEzLjUwNiAxNTkuMDU3IC0xMTIuODgg +MTU5LjYzMyAtMTEyLjcwNEMxNjIuMDI1IC0xMTEuOTczIDE2My44NjggLTExMC40NDQgMTY2LjA2 +MiAtMTA5LjU0OUMxNjYuODIxIC0xMDkuMjM5IDE2Ny42OTcgLTEwOS4wMDUgMTY4LjMzIC0xMDgu +NTA5eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjYzcyMjYiPgogIDxwYXRoIGQ9Ik05MS42 +OTYgLTEyMi43MzlDODkuMTc4IC0xMjQuNDY0IDg2LjgxIC0xMjUuNTcgODQuMzY4IC0xMjcuMzU2 +Qzg0LjE4NyAtMTI3LjQ4OSA4My44MjcgLTEyNy4zMTkgODMuNjI1IC0xMjcuNDQxQzgyLjYxOCAt +MTI4LjA1IDgxLjczIC0xMjguNjMxIDgwLjc0OCAtMTI5LjMyN0M4MC4yMDkgLTEyOS43MDkgNzku +Mzg4IC0xMjkuNjk4IDc4Ljg4IC0xMjkuOTU2Qzc2LjMzNiAtMTMxLjI0OCA3My43MDcgLTEzMS44 +MDYgNzEuMiAtMTMzQzcxLjg4MiAtMTMzLjYzOCA3My4wMDQgLTEzMy4zOTQgNzMuNiAtMTM0LjJD +NzMuNzk1IC0xMzMuOTIgNzQuMDMzIC0xMzMuNjM2IDc0LjM4NiAtMTMzLjgyN0M3Ni4wNjQgLTEz +NC43MzEgNzcuOTE0IC0xMzQuODg0IDc5LjU5IC0xMzQuNzk0QzgxLjI5NCAtMTM0LjcwMiA4My4w +MTQgLTEzNC4zOTcgODQuNzg5IC0xMzQuMTI1Qzg1LjA5NiAtMTM0LjA3OCA4NS4yOTUgLTEzMy41 +NTUgODUuNjE4IC0xMzMuNDU4Qzg3Ljg0NiAtMTMyLjc5NSA5MC4yMzUgLTEzMy4zMiA5Mi4zNTQg +LTEzMi40ODJDOTMuOTQ1IC0xMzEuODUzIDk1LjUxNSAtMTMxLjAzIDk2Ljc1NCAtMTI5Ljc1NUM5 +Ny4wMDYgLTEyOS40OTUgOTYuNjgxIC0xMjkuMTk0IDk2LjQwMSAtMTI5Qzk2Ljc4OSAtMTI5LjEw +OSA5Ny4wNjIgLTEyOC45MDMgOTcuMTczIC0xMjguNTlDOTcuMjU3IC0xMjguMzUxIDk3LjI1NyAt +MTI4LjA0OSA5Ny4xNzMgLTEyNy44MUM5Ny4wNjEgLTEyNy40OTggOTYuNzgyIC0xMjcuMzk3IDk2 +LjQwOCAtMTI3LjM0NkM5NS4wMDEgLTEyNy4xNTYgOTYuNzczIC0xMjguNTM2IDk2LjA3MyAtMTI4 +LjA4OEM5NC44IC0xMjcuMjc0IDk1LjU0NiAtMTI1Ljg2OCA5NC44MDEgLTEyNC42Qzk0LjUyMSAt +MTI0Ljc5NCA5NC4yOTEgLTEyNS4wMTIgOTQuNDAxIC0xMjUuNEM5NC42MzUgLTEyNC44NzggOTQu +MDMzIC0xMjQuNTg4IDkzLjg2NSAtMTI0LjI3MkM5My40OCAtMTIzLjU0NyA5Mi41ODEgLTEyMi4x +MzIgOTEuNjk2IC0xMjIuNzM5eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjYzcyMjYiPgog +IDxwYXRoIGQ9Ik01OS4xOTggLTExNS4zOTFDNTYuMDQ0IC0xMTYuMTg1IDUyLjk5NCAtMTE2LjA3 +IDQ5Ljk3OCAtMTE3LjM0NkM0OS45MTEgLTExNy4zNzQgNDkuNjg4IC0xMTcuMDI3IDQ5LjYyNCAt +MTE3LjA1NEM0OC4yNTggLTExNy42NDggNDcuMzQgLTExOC42MTQgNDYuMjY0IC0xMTkuNjZDNDUu +MzUxIC0xMjAuNTQ4IDQzLjY5MyAtMTIwLjE2MSA0Mi40MTkgLTEyMC42NDhDNDIuMDk1IC0xMjAu +NzcyIDQxLjg5MiAtMTIxLjI4NCA0MS41OTEgLTEyMS4zMjNDNDAuMzcyIC0xMjEuNDggMzkuNDQ1 +IC0xMjIuNDI5IDM4LjQgLTEyM0M0MC43MzYgLTEyMy43OTUgNDMuMTQ3IC0xMjMuNzY0IDQ1LjYw +OSAtMTI0LjE0OEM0NS43MjIgLTEyNC4xNjYgNDUuODY3IC0xMjMuODQ1IDQ2IC0xMjMuODQ1QzQ2 +LjEzNiAtMTIzLjg0NSA0Ni4yNjYgLTEyNC4wNjYgNDYuNCAtMTI0LjJDNDYuNTk1IC0xMjMuOTIg +NDYuODk3IC0xMjMuNTk0IDQ3LjE1NCAtMTIzLjg0OEM0Ny43MDIgLTEyNC4zODggNDguMjU4IC0x +MjQuMTk4IDQ4Ljc5OCAtMTI0LjE1OEM0OC45NDIgLTEyNC4xNDggNDkuMDY3IC0xMjMuODQ1IDQ5 +LjIgLTEyMy44NDVDNDkuMzM2IC0xMjMuODQ1IDQ5LjQ2NyAtMTI0LjE1NiA0OS42IC0xMjQuMTU2 +QzQ5LjczNiAtMTI0LjE1NSA0OS44NjcgLTEyMy44NDUgNTAgLTEyMy44NDVDNTAuMTM2IC0xMjMu +ODQ1IDUwLjI2NiAtMTI0LjA2NiA1MC40IC0xMjQuMkM1MS4wOTIgLTEyMy40MTggNTEuOTc3IC0x +MjMuOTcyIDUyLjc5OSAtMTIzLjc5M0M1My44MzcgLTEyMy41NjYgNTQuMTA0IC0xMjIuNDE4IDU1 +LjE3OCAtMTIyLjEyQzU5Ljg5MyAtMTIwLjgxNiA2NC4wMyAtMTE4LjY3MSA2OC4zOTMgLTExNi41 +ODRDNjguNyAtMTE2LjQzNyA2OC45MSAtMTE2LjE4OSA2OC44IC0xMTUuOEM2OS4wNjcgLTExNS44 +IDY5LjM4IC0xMTUuODg4IDY5LjU3IC0xMTUuNzU2QzcwLjYyOCAtMTE1LjAyNCA3MS42NjkgLTEx +NC40NzYgNzIuMzY2IC0xMTMuMzc4QzcyLjU4MiAtMTEzLjAzOSA3Mi4yNTMgLTExMi42MzIgNzIu +MDIgLTExMi42ODRDNjcuNTkxIC0xMTMuNjc5IDYzLjU4NSAtMTE0LjI4NyA1OS4xOTggLTExNS4z +OTF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjNzIyNiI+CiAgPHBhdGggZD0iTTQ1LjMz +OCAtNzEuMTc5QzQzLjc0NiAtNzIuMzk4IDQzLjE2MiAtNzQuNDI5IDQyLjAzNCAtNzYuMjIxQzQx +LjgyIC03Ni41NjEgNDIuMDk0IC03Ni44NzUgNDIuNDExIC03Ni45NjRDNDIuOTcxIC03Ny4xMjMg +NDMuNTE0IC03Ni42NDUgNDMuOTIzIC03Ni40NDNDNDUuNjY4IC03NS41ODEgNDcuMjAzIC03NC4z +MzkgNDkuMiAtNzQuMkM1MS4xOSAtNzEuOTY2IDU1LjQ1IC03MS41ODEgNTUuNDU3IC02OC4yQzU1 +LjQ1OCAtNjcuMzQxIDU0LjAzIC02OC4yNTkgNTMuNiAtNjcuNEM1MS4xNDkgLTY4LjQwMyA0OC43 +NiAtNjguMyA0Ni4zOCAtNjkuNzY3QzQ1Ljc2MyAtNzAuMTQ4IDQ2LjA5MyAtNzAuNjAxIDQ1LjMz +OCAtNzEuMTc5eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjYzcyMjYiPgogIDxwYXRoIGQ9 +Ik0xNy44IC0xMjMuNzU2QzE3LjkzNSAtMTIzLjc1NSAyNC45NjYgLTEyMy41MjIgMjQuOTQ5IC0x +MjMuNDA4QzI0LjkwNCAtMTIzLjA5OSAxNy4xNzQgLTEyMi4wNSAxNi44MSAtMTIyLjIyQzE2LjY0 +NiAtMTIyLjI5NiA5LjEzNCAtMTE5Ljg2NiA5IC0xMjBDOS4yNjggLTEyMC4xMzUgMTcuNTM0IC0x +MjMuNzU2IDE3LjggLTEyMy43NTZ6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+ +CiAgPHBhdGggZD0iTTMzLjIgLTExNEMzMy4yIC0xMTQgMTguNCAtMTEyLjIgMTQgLTExMUM5LjYg +LTEwOS44IC05IC0xMDIuMiAtMTIgLTEwMC4yQy0xMiAtMTAwLjIgLTI1LjQgLTk0LjggLTQyLjQg +LTc0LjhDLTQyLjQgLTc0LjggLTM0LjggLTc4LjIgLTMyLjYgLTgxQy0zMi42IC04MSAtMTkgLTkz +LjYgLTE5LjIgLTkxQy0xOS4yIC05MSAtNyAtOTkuNiAtNy42IC05Ny40Qy03LjYgLTk3LjQgMTYu +OCAtMTA4LjYgMTQuOCAtMTA1LjRDMTQuOCAtMTA1LjQgMzYuNCAtMTEwIDM1LjQgLTEwOEMzNS40 +IC0xMDggNTQuMiAtMTAzLjYgNTEuNCAtMTAzLjRDNTEuNCAtMTAzLjQgNDUuNiAtMTAyLjIgNTIg +LTk4LjZDNTIgLTk4LjYgNDguNiAtOTQuMiA0My4yIC05OC4yQzM3LjggLTEwMi4yIDQwLjggLTEw +MCAzNS44IC05OUMzNS44IC05OSAzMy4yIC05OC4yIDI4LjYgLTEwMi4yQzI4LjYgLTEwMi4yIDIz +IC0xMDYuOCAxNC4yIC0xMDMuMkMxNC4yIC0xMDMuMiAtMTYuNCAtOTAuNiAtMTguNCAtOTBDLTE4 +LjQgLTkwIC0yMiAtODcuMiAtMjQuNCAtODMuNkMtMjQuNCAtODMuNiAtMzAuMiAtNzkuMiAtMzMu +MiAtNzcuOEMtMzMuMiAtNzcuOCAtNDYgLTY2LjIgLTQ3LjIgLTY0LjhDLTQ3LjIgLTY0LjggLTUw +LjYgLTU5LjYgLTUxLjQgLTU5LjJDLTUxLjQgLTU5LjIgLTQ1IC02MyAtNDMgLTY1Qy00MyAtNjUg +LTI5IC03NSAtMjMuNiAtNzUuOEMtMjMuNiAtNzUuOCAtMTkuMiAtNzguOCAtMTguNCAtODAuMkMt +MTguNCAtODAuMiAtNCAtODkuNCAwLjIgLTg5LjRDMC4yIC04OS40IDkuNCAtODQuMiAxMS44IC05 +MS4yQzExLjggLTkxLjIgMTcuNiAtOTMgMjMuMiAtOTEuOEMyMy4yIC05MS44IDI2LjQgLTk0LjQg +MjUuNiAtOTYuNkMyNS42IC05Ni42IDI3LjIgLTk4LjQgMjguMiAtOTQuNkMyOC4yIC05NC42IDMx +LjYgLTkxIDM2LjQgLTkzQzM2LjQgLTkzIDQwLjQgLTkzLjIgMzguNCAtOTAuOEMzOC40IC05MC44 +IDM0IC04NyAyMi4yIC04Ni44QzIyLjIgLTg2LjggOS44IC04Ni4yIC02LjYgLTc4LjZDLTYuNiAt +NzguNiAtMzYuNCAtNjguMiAtNDUuNiAtNTcuOEMtNDUuNiAtNTcuOCAtNTIgLTQ5IC01Ny40IC00 +Ny44Qy01Ny40IC00Ny44IC02My4yIC00NyAtNjkuMiAtMzkuNkMtNjkuMiAtMzkuNiAtNTkuNCAt +NDUuNCAtNTAuNCAtNDUuNEMtNTAuNCAtNDUuNCAtNDYuNCAtNDcuOCAtNTAuMiAtNDQuMkMtNTAu +MiAtNDQuMiAtNTMuOCAtMzYuNiAtNTIuMiAtMzEuMkMtNTIuMiAtMzEuMiAtNTIuOCAtMjYgLTUz +LjYgLTI0LjRDLTUzLjYgLTI0LjQgLTYxLjQgLTExLjYgLTYxLjQgLTkuMkMtNjEuNCAtNi44IC02 +MC4yIDMgLTU5LjggMy42Qy01OS40IDQuMiAtNjAuOCAyIC01NyA0LjRDLTUzLjIgNi44IC01MC40 +IDguNCAtNDkuNiAxMS4yQy00OC44IDE0IC01MS42IDUuOCAtNTEuOCA0Qy01MiAyLjIgLTU2LjIg +LTUgLTU1LjQgLTcuNEMtNTUuNCAtNy40IC01NC40IC02LjQgLTUzLjYgLTVDLTUzLjYgLTUgLTU0 +LjIgLTUuNiAtNTMuNiAtOS4yQy01My42IC05LjIgLTUyLjggLTE0LjQgLTUxLjQgLTE3LjZDLTUw +IC0yMC44IC00OCAtMjQuNiAtNDcuNiAtMjUuNEMtNDcuMiAtMjYuMiAtNDcuMiAtMzIgLTQ1Ljgg +LTI5LjRMLTQyLjQgLTI2LjhDLTQyLjQgLTI2LjggLTQ1LjIgLTI5LjQgLTQzIC0zMS42Qy00MyAt +MzEuNiAtNDQgLTM3LjIgLTQyLjIgLTM5LjhDLTQyLjIgLTM5LjggLTM1LjIgLTQ4LjIgLTMzLjYg +LTQ5LjJDLTMyIC01MC4yIC0zMy40IC00OS44IC0zMy40IC00OS44Qy0zMy40IC00OS44IC0yNy40 +IC01NCAtMzMuMiAtNTIuNEMtMzMuMiAtNTIuNCAtMzcuMiAtNTAuOCAtNDAuMiAtNTAuOEMtNDAu +MiAtNTAuOCAtNDcuOCAtNDguOCAtNDMuOCAtNTNDLTM5LjggLTU3LjIgLTI5LjggLTYyLjYgLTI2 +IC02Mi40TC0yNS4yIC02MC44TC0xNCAtNjMuMkwtMTUuMiAtNjIuNEMtMTUuMiAtNjIuNCAtMTUu +NCAtNjIuNiAtMTEuMiAtNjNDLTcgLTYzLjQgLTEuMiAtNjIgMC4yIC02My44QzEuNiAtNjUuNiA1 +IC02Ni42IDQuNiAtNjUuMkM0LjIgLTYzLjggNCAtNjEuOCA0IC02MS44QzQgLTYxLjggOSAtNjcu +NiA4LjQgLTY1LjRDNy44IC02My4yIC0wLjQgLTU4IC0xLjggLTUxLjhMOC42IC02MEwxMi4yIC02 +M0MxMi4yIC02MyAxNS44IC02MC44IDE2IC02Mi40QzE2LjIgLTY0IDIwLjggLTY5LjggMjIgLTY5 +LjZDMjMuMiAtNjkuNCAyNS4yIC03Mi4yIDI1IC02OS42QzI0LjggLTY3IDMyLjQgLTYxLjYgMzIu +NCAtNjEuNkMzMi40IC02MS42IDM1LjYgLTYzLjQgMzcgLTYyQzM4LjQgLTYwLjYgNDIuNiAtODEu +OCA0Mi42IC04MS44TDY3LjYgLTkyLjRMMTExLjIwMSAtOTUuOEw5NC4yMDEgLTEwMi42TDMzLjIg +LTExNHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJzdHJva2U6IzRjMDAwMDsgc3Ryb2tlLXdpZHRoOjIi +PgogIDxwYXRoIGQ9Ik01MS40IDg1QzUxLjQgODUgMzYuNCA2OC4yIDI4IDY1LjZDMjggNjUuNiAx +NC42IDU4LjggLTEwIDY2LjYiLz4KIDwvZz4KIDxnIHN0eWxlPSJzdHJva2U6IzRjMDAwMDsgc3Ry +b2tlLXdpZHRoOjIiPgogIDxwYXRoIGQ9Ik0yNC44IDY0LjJDMjQuOCA2NC4yIC0wLjQgNTYuMiAt +MTUuOCA2MC40Qy0xNS44IDYwLjQgLTM0LjIgNjIuNCAtNDIuNiA3Ni4yIi8+CiA8L2c+CiA8ZyBz +dHlsZT0ic3Ryb2tlOiM0YzAwMDA7IHN0cm9rZS13aWR0aDoyIj4KICA8cGF0aCBkPSJNMjEuMiA2 +M0MyMS4yIDYzIDQuMiA1NS44IC0xMC42IDUzLjZDLTEwLjYgNTMuNiAtMjcuMiA1MSAtNDMuOCA1 +OC4yQy00My44IDU4LjIgLTU2IDY0LjIgLTYxLjQgNzQuNCIvPgogPC9nPgogPGcgc3R5bGU9InN0 +cm9rZTojNGMwMDAwOyBzdHJva2Utd2lkdGg6MiI+CiAgPHBhdGggZD0iTTIyLjIgNjMuNEMyMi4y +IDYzLjQgNi44IDUyLjQgNS44IDUxQzUuOCA1MSAtMS4yIDQwIC0xNC4yIDM5LjZDLTE0LjIgMzku +NiAtMzUuNiA0MC40IC01Mi44IDQ4LjQiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAw +Ij4KICA8cGF0aCBkPSJNMjAuODk1IDU0LjQwN0MyMi40MzcgNTUuODcgNDkuNCA4NC44IDQ5LjQg +ODQuOEM4NC42IDEyMS40MDEgNTYuNiA4Ny4yIDU2LjYgODcuMkM0OSA4Mi40IDM5LjggNjMuNiAz +OS44IDYzLjZDMzguNiA2MC44IDUzLjggNzAuOCA1My44IDcwLjhDNTcuOCA3MS42IDcxLjQgOTAu +OCA3MS40IDkwLjhDNjQuNiA4OC40IDY5LjQgOTUuNiA2OS40IDk1LjZDNzIuMiA5Ny42IDkyLjYw +MSAxMTMuMjAxIDkyLjYwMSAxMTMuMjAxQzk2LjIwMSAxMTcuMjAxIDEwMC4yMDEgMTE4LjgwMSAx +MDAuMjAxIDExOC44MDFDMTE0LjIwMSAxMTMuNjAxIDEwNy44MDEgMTI2LjgwMSAxMDcuODAxIDEy +Ni44MDFDMTEwLjIwMSAxMzMuNjAxIDExNS44MDEgMTIyLjAwMSAxMTUuODAxIDEyMi4wMDFDMTI3 +LjAwMSAxMDUuMiAxMTAuNjAxIDEwNy42MDEgMTEwLjYwMSAxMDcuNjAxQzgwLjYgMTEwLjQwMSA3 +My44IDk0LjQgNzMuOCA5NC40QzcxLjQgOTIgODAuMiA5NC40IDgwLjIgOTQuNEM4OC42MDEgOTYu +NCA3MyA4MiA3MyA4MkM3NS40IDgyIDg0LjYgODguOCA4NC42IDg4LjhDOTUuMDAxIDk4IDk3LjAw +MSA5NiA5Ny4wMDEgOTZDMTE1LjAwMSA4Ny4yIDEyNS40MDEgOTQuOCAxMjUuNDAxIDk0LjhDMTI3 +LjQwMSA5Ni40IDEyMS44MDEgMTAzLjIgMTIzLjQwMSAxMDguNDAxQzEyNS4wMDEgMTEzLjYwMSAx +MjkuODAxIDEyNi4wMDEgMTI5LjgwMSAxMjYuMDAxQzEyNy40MDEgMTI3LjYwMSAxMjcuODAxIDEz +OC40MDEgMTI3LjgwMSAxMzguNDAxQzE0NC42MDEgMTYxLjYwMSAxMzUuMDAxIDE1OS42MDEgMTM1 +LjAwMSAxNTkuNjAxQzExOS40MDEgMTU5LjIwMSAxMzQuMjAxIDE2Ni44MDEgMTM0LjIwMSAxNjYu +ODAxQzEzNy40MDEgMTY4LjgwMSAxNDYuMjAxIDE3Ni4wMDEgMTQ2LjIwMSAxNzYuMDAxQzE0My40 +MDEgMTc0LjgwMSAxNDEuODAxIDE4MC4wMDEgMTQxLjgwMSAxODAuMDAxQzE0Ni42MDEgMTg0LjAw +MSAxNDMuODAxIDE4OC44MDEgMTQzLjgwMSAxODguODAxQzEzNy44MDEgMTkwLjAwMSAxMzYuNjAx +IDE5NC4wMDEgMTM2LjYwMSAxOTQuMDAxQzE0My40MDEgMjAyLjAwMSAxMzMuNDAxIDIwMi40MDEg +MTMzLjQwMSAyMDIuNDAxQzEzNy4wMDEgMjA2LjgwMSAxMzIuMjAxIDIxOC44MDEgMTMyLjIwMSAy +MTguODAxQzEyNy40MDEgMjE4LjgwMSAxMjEuMDAxIDIyNC40MDEgMTIxLjAwMSAyMjQuNDAxQzEy +My40MDEgMjI5LjIwMSAxMTMuMDAxIDIzNC44MDEgMTEzLjAwMSAyMzQuODAxQzEwNC42MDEgMjM2 +LjQwMSAxMDcuNDAxIDI0My4yMDEgMTA3LjQwMSAyNDMuMjAxQzk5LjQwMSAyNDkuMjAxIDk3LjAw +MSAyNjUuMjAxIDk3LjAwMSAyNjUuMjAxQzk2LjIwMSAyNzUuNjAxIDkzLjgwMSAyNzguODAxIDk5 +LjAwMSAyNzYuODAxQzEwNC4yMDEgMjc0LjgwMSAxMDMuNDAxIDI2Mi40MDEgMTAzLjQwMSAyNjIu +NDAxQzk4LjYwMSAyNDYuODAxIDE0MS40MDEgMjMwLjgwMSAxNDEuNDAxIDIzMC44MDFDMTQ1LjQw +MSAyMjkuMjAxIDE0Ni4yMDEgMjI0LjAwMSAxNDYuMjAxIDIyNC4wMDFDMTQ4LjIwMSAyMjQuNDAx +IDE1Ny4wMDEgMjMyLjAwMSAxNTcuMDAxIDIzMi4wMDFDMTY0LjYwMSAyNDMuMjAxIDE2NS4wMDEg +MjM0LjAwMSAxNjUuMDAxIDIzNC4wMDFDMTY2LjIwMSAyMzAuNDAxIDE2NC42MDEgMjI0LjQwMSAx +NjQuNjAxIDIyNC40MDFDMTcwLjYwMSAyMDIuODAxIDE1Ni42MDEgMTk2LjQwMSAxNTYuNjAxIDE5 +Ni40MDFDMTQ2LjYwMSAxNjIuODAxIDE2MC42MDEgMTcxLjIwMSAxNjAuNjAxIDE3MS4yMDFDMTYz +LjQwMSAxNzYuODAxIDE3NC4yMDEgMTgyLjAwMSAxNzQuMjAxIDE4Mi4wMDFMMTc3LjgwMSAxNzku +NjAxQzE3Ni4yMDEgMTc0LjgwMSAxODQuNjAxIDE2OC44MDEgMTg0LjYwMSAxNjguODAxQzE4Ny40 +MDEgMTc1LjIwMSAxOTMuNDAxIDE2Ny4yMDEgMTkzLjQwMSAxNjcuMjAxQzE5Ny4wMDEgMTQyLjgw +MSAyMDkuNDAxIDE1Ny4yMDEgMjA5LjQwMSAxNTcuMjAxQzIxMy40MDEgMTU4LjQwMSAyMTQuNjAx +IDE1MS42MDEgMjE0LjYwMSAxNTEuNjAxQzIxOC4yMDEgMTQxLjIwMSAyMTQuNjAxIDEyNy42MDEg +MjE0LjYwMSAxMjcuNjAxQzIxOC4yMDEgMTI3LjIwMSAyMjcuODAxIDEzMy4yMDEgMjI3LjgwMSAx +MzMuMjAxQzIzMC42MDEgMTI5LjYwMSAyMjEuNDAxIDExMi44MDEgMjI1LjQwMSAxMTUuMjAxQzIy +OS40MDEgMTE3LjYwMSAyMzMuODAxIDExOS4yMDEgMjMzLjgwMSAxMTkuMjAxQzIzNC42MDEgMTE3 +LjIwMSAyMjQuNjAxIDEwNC44MDEgMjI0LjYwMSAxMDQuODAxQzIyMC4yMDEgMTAyIDIxNS4wMDEg +ODEuNiAyMTUuMDAxIDgxLjZDMjIyLjIwMSA4NS4yIDIxMi4yMDEgNzAgMjEyLjIwMSA3MEMyMTIu +MjAxIDY2LjggMjE4LjIwMSA1NS42IDIxOC4yMDEgNTUuNkMyMTcuNDAxIDQ4LjggMjE4LjIwMSA0 +OS4yIDIxOC4yMDEgNDkuMkMyMjEuMDAxIDUwLjQgMjI5LjAwMSA1MiAyMjIuMjAxIDQ1LjZDMjE1 +LjQwMSAzOS4yIDIyMy4wMDEgMzQuNCAyMjMuMDAxIDM0LjRDMjI3LjQwMSAzMS42IDIxMy44MDEg +MzIgMjEzLjgwMSAzMkMyMDguNjAxIDI3LjYgMjA5LjAwMSAyMy42IDIwOS4wMDEgMjMuNkMyMTcu +MDAxIDI1LjYgMjAyLjYwMSAxMS4yIDIwMC4yMDEgNy42QzE5Ny44MDEgNCAyMDcuNDAxIC0xLjIg +MjA3LjQwMSAtMS4yQzIyMC42MDEgLTQuOCAyMDkuMDAxIC04IDIwOS4wMDEgLThDMTg5LjQwMSAt +Ny42IDIwMC4yMDEgLTE4LjQgMjAwLjIwMSAtMTguNEMyMDYuMjAxIC0xOCAyMDQuNjAxIC0yMC40 +IDIwNC42MDEgLTIwLjRDMTk5LjQwMSAtMjEuNiAxODkuODAxIC0yOCAxODkuODAxIC0yOEMxODUu +ODAxIC0zMS42IDE4OS40MDEgLTMwLjggMTg5LjQwMSAtMzAuOEMyMDYuMjAxIC0yOS42IDE3Ny40 +MDEgLTQwLjggMTc3LjQwMSAtNDAuOEMxODUuNDAxIC00MC44IDE2Ny40MDEgLTUxLjIgMTY3LjQw +MSAtNTEuMkMxNjUuNDAxIC01Mi44IDE2Mi4yMDEgLTYwLjQgMTYyLjIwMSAtNjAuNEMxNTYuMjAx +IC02NS42IDE1MS40MDEgLTcyLjQgMTUxLjQwMSAtNzIuNEMxNTEuMDAxIC03Ni44IDE0Ni4yMDEg +LTgxLjYgMTQ2LjIwMSAtODEuNkMxMzQuNjAxIC05NS4yIDEyOS4wMDEgLTk0LjggMTI5LjAwMSAt +OTQuOEMxMTQuMjAxIC05OC40IDEwOS4wMDEgLTk3LjYgMTA5LjAwMSAtOTcuNkw1Ni4yIC05My4y +QzI5LjggLTgwLjQgMzcuNiAtNTkuNCAzNy42IC01OS40QzQ0IC01MSA1My4yIC01NC44IDUzLjIg +LTU0LjhDNTcuOCAtNjEgNjkuNCAtNTguOCA2OS40IC01OC44Qzg5LjgwMSAtNTUuNiA4Ny4yMDEg +LTU5LjIgODcuMjAxIC01OS4yQzg0LjgwMSAtNjMuOCA2OC42IC03MCA2OC40IC03MC42QzY4LjIg +LTcxLjIgNTkuNCAtNzQuNiA1OS40IC03NC42QzU2LjQgLTc1LjggNTIgLTg1IDUyIC04NUM0OC44 +IC04OC40IDY0LjYgLTgyLjYgNjQuNiAtODIuNkM2My40IC04MS42IDcwLjggLTc3LjYgNzAuOCAt +NzcuNkM4OC4yMDEgLTc4LjYgOTguODAxIC02Ny44IDk4LjgwMSAtNjcuOEMxMDkuNjAxIC01MS4y +IDEwOS44MDEgLTU5LjQgMTA5LjgwMSAtNTkuNEMxMTIuNjAxIC02OC44IDEwMC44MDEgLTkwIDEw +MC44MDEgLTkwQzEwMS4yMDEgLTkyIDEwOS40MDEgLTg1LjQgMTA5LjQwMSAtODUuNEMxMTAuODAx +IC04Ny40IDExMS42MDEgLTgxLjYgMTExLjYwMSAtODEuNkMxMTEuODAxIC03OS4yIDExNS42MDEg +LTcxLjIgMTE1LjYwMSAtNzEuMkMxMTguNDAxIC01OC4yIDEyMi4wMDEgLTY1LjYgMTIyLjAwMSAt +NjUuNkwxMjYuNjAxIC01Ni4yQzEyOC4wMDEgLTUzLjYgMTIyLjAwMSAtNDYgMTIyLjAwMSAtNDZD +MTIxLjgwMSAtNDMuMiAxMjIuNjAxIC00My40IDExNy4wMDEgLTM1LjhDMTExLjQwMSAtMjguMiAx +MTQuODAxIC0yMy44IDExNC44MDEgLTIzLjhDMTEzLjQwMSAtMTcuMiAxMjIuMjAxIC0xNy42IDEy +Mi4yMDEgLTE3LjZDMTI0LjgwMSAtMTUuNCAxMjguMjAxIC0xNS40IDEyOC4yMDEgLTE1LjRDMTMw +LjAwMSAtMTMuNCAxMzIuNDAxIC0xNCAxMzIuNDAxIC0xNEMxMzQuMDAxIC0xNy44IDE0MC4yMDEg +LTE1LjggMTQwLjIwMSAtMTUuOEMxNDEuNjAxIC0xOC4yIDE0OS44MDEgLTE4LjYgMTQ5LjgwMSAt +MTguNkMxNTAuODAxIC0yMS4yIDE1MS4yMDEgLTIyLjggMTU0LjYwMSAtMjMuNEMxNTguMDAxIC0y +NCAxMzMuNDAxIC02NyAxMzMuNDAxIC02N0MxMzkuODAxIC02Ny44IDEzMS42MDEgLTgwLjIgMTMx +LjYwMSAtODAuMkMxMjkuNDAxIC04Ni44IDE0MC44MDEgLTcyLjIgMTQzLjAwMSAtNzAuOEMxNDUu +MjAxIC02OS40IDE0Ni4yMDEgLTY3LjIgMTQ0LjYwMSAtNjcuNEMxNDMuMDAxIC02Ny42IDE0MS4y +MDEgLTY1LjQgMTQyLjYwMSAtNjUuMkMxNDQuMDAxIC02NSAxNTcuMDAxIC01MCAxNjAuNDAxIC0z +OS44QzE2My44MDEgLTI5LjYgMTY5LjgwMSAtMjUuNiAxNzYuMDAxIC0xOS42QzE4Mi4yMDEgLTEz +LjYgMTgxLjQwMSAxMC42IDE4MS40MDEgMTAuNkMxODEuMDAxIDE5LjQgMTg3LjAwMSAzMCAxODcu +MDAxIDMwQzE4OS4wMDEgMzMuOCAxODQuODAxIDUyIDE4NC44MDEgNTJDMTgyLjgwMSA1NC4yIDE4 +NC4yMDEgNTUgMTg0LjIwMSA1NUMxODUuMjAxIDU2LjIgMTkyLjAwMSA2OS40IDE5Mi4wMDEgNjku +NEMxOTAuMjAxIDY5LjIgMTkzLjgwMSA3Mi44IDE5My44MDEgNzIuOEMxOTkuMDAxIDc4LjggMTky +LjYwMSA3NS44IDE5Mi42MDEgNzUuOEMxODYuNjAxIDc0LjIgMTkzLjYwMSA4NCAxOTMuNjAxIDg0 +QzE5NC44MDEgODUuOCAxODUuODAxIDgxLjIgMTg1LjgwMSA4MS4yQzE3Ni42MDEgODAuNiAxODgu +MjAxIDg3LjggMTg4LjIwMSA4Ny44QzE5Ni44MDEgOTUgMTg1LjQwMSA5MC42IDE4NS40MDEgOTAu +NkMxODAuODAxIDg4LjggMTg0LjAwMSA5NS42IDE4NC4wMDEgOTUuNkMxODcuMjAxIDk3LjIgMjA0 +LjQwMSAxMDQuMiAyMDQuNDAxIDEwNC4yQzIwNC44MDEgMTA4LjAwMSAyMDEuODAxIDExMy4wMDEg +MjAxLjgwMSAxMTMuMDAxQzIwMi4yMDEgMTE3LjAwMSAyMDAuMDAxIDEyMC40MDEgMjAwLjAwMSAx +MjAuNDAxQzE5OC44MDEgMTI4LjYwMSAxOTguMjAxIDEyOS40MDEgMTk4LjIwMSAxMjkuNDAxQzE5 +NC4wMDEgMTI5LjYwMSAxODYuNjAxIDE0My40MDEgMTg2LjYwMSAxNDMuNDAxQzE4NC44MDEgMTQ2 +LjAwMSAxNzQuNjAxIDE1OC4wMDEgMTc0LjYwMSAxNTguMDAxQzE3Mi42MDEgMTY1LjAwMSAxNTQu +NjAxIDE1Ny44MDEgMTU0LjYwMSAxNTcuODAxQzE0OC4wMDEgMTYxLjIwMSAxNTAuMDAxIDE1Ny44 +MDEgMTUwLjAwMSAxNTcuODAxQzE0OS42MDEgMTU1LjYwMSAxNTQuNDAxIDE0OS42MDEgMTU0LjQw +MSAxNDkuNjAxQzE2MS40MDEgMTQ3LjAwMSAxNTguODAxIDEzNi4yMDEgMTU4LjgwMSAxMzYuMjAx +QzE2Mi44MDEgMTM0LjgwMSAxNTEuNjAxIDEzMi4wMDEgMTUxLjgwMSAxMzAuODAxQzE1Mi4wMDEg +MTI5LjYwMSAxNTcuODAxIDEyOC4yMDEgMTU3LjgwMSAxMjguMjAxQzE2NS44MDEgMTI2LjIwMSAx +NjEuNDAxIDEyMy44MDEgMTYxLjQwMSAxMjMuODAxQzE2MC44MDEgMTE5LjgwMSAxNjMuODAxIDEx +NC4yMDEgMTYzLjgwMSAxMTQuMjAxQzE3NS40MDEgMTEzLjQwMSAxNjMuODAxIDk3LjIgMTYzLjgw +MSA5Ny4yQzE1My4wMDEgODkuNiAxNTIuMDAxIDgzLjggMTUyLjAwMSA4My44QzE2NC42MDEgNzUu +NiAxNTYuNDAxIDYzLjIgMTU2LjYwMSA1OS42QzE1Ni44MDEgNTYgMTU4LjAwMSAzNC40IDE1OC4w +MDEgMzQuNEMxNTYuMDAxIDI4LjIgMTUzLjAwMSAxNC42IDE1My4wMDEgMTQuNkMxNTUuMjAxIDku +NCAxNjIuNjAxIC0zLjIgMTYyLjYwMSAtMy4yQzE2NS40MDEgLTcuNCAxNzQuMjAxIC0xMi4yIDE3 +Mi4wMDEgLTE1LjJDMTY5LjgwMSAtMTguMiAxNjIuMDAxIC0xNi40IDE2Mi4wMDEgLTE2LjRDMTU0 +LjIwMSAtMTcuOCAxNTQuODAxIC0xMi42IDE1NC44MDEgLTEyLjZDMTUzLjIwMSAtMTEuNiAxNTIu +NDAxIC02LjYgMTUyLjQwMSAtNi42QzE1MS42OCAxLjMzMyAxNDIuODAxIDcuNiAxNDIuODAxIDcu +NkMxMzEuNjAxIDEzLjggMTQwLjgwMSAxNy44IDE0MC44MDEgMTcuOEMxNDYuODAxIDI0LjQgMTM3 +LjAwMSAyNC42IDEzNy4wMDEgMjQuNkMxMjYuMDAxIDIyLjggMTM0LjIwMSAzMyAxMzQuMjAxIDMz +QzE0NS4wMDEgNDUuOCAxNDIuMDAxIDQ4LjYgMTQyLjAwMSA0OC42QzEzMS44MDEgNDkuNiAxNDQu +NDAxIDU4LjggMTQ0LjQwMSA1OC44QzE0NC40MDEgNTguOCAxNDMuNjAxIDU2LjggMTQzLjgwMSA1 +OC42QzE0NC4wMDEgNjAuNCAxNDcuMDAxIDY0LjYgMTQ3LjgwMSA2Ni42QzE0OC42MDEgNjguNiAx +NDQuNjAxIDY4LjggMTQ0LjYwMSA2OC44QzE0NS4yMDEgNzguNCAxMjkuODAxIDc0LjIgMTI5Ljgw +MSA3NC4yQzEyOS44MDEgNzQuMiAxMjkuODAxIDc0LjIgMTI4LjIwMSA3NC40QzEyNi42MDEgNzQu +NiAxMTUuNDAxIDczLjggMTA5LjYwMSA3MS42QzEwMy44MDEgNjkuNCA5Ny4wMDEgNjkuNCA5Ny4w +MDEgNjkuNEM5Ny4wMDEgNjkuNCA5My4wMDEgNzEuMiA4NS40IDcxQzc3LjggNzAuOCA2OS44IDcz +LjYgNjkuOCA3My42QzY1LjQgNzMuMiA3NCA2OC44IDc0LjIgNjlDNzQuNCA2OS4yIDgwIDYzLjYg +NzIgNjQuMkM1MC4yMDMgNjUuODM1IDM5LjQgNTUuNiAzOS40IDU1LjZDMzcuNCA1NC4yIDM0Ljgg +NTEuNCAzNC44IDUxLjRDMjQuOCA0OS40IDM2LjIgNjMuOCAzNi4yIDYzLjhDMzcuNCA2NS4yIDM2 +IDY2LjIgMzYgNjYuMkMzNS4yIDY0LjYgMjcuNCA1OS4yIDI3LjQgNTkuMkMyNC41ODkgNTguMjI3 +IDIzLjIyNiA1Ni44OTMgMjAuODk1IDU0LjQwN3oiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +NGMwMDAwIj4KICA8cGF0aCBkPSJNLTMgNDIuOEMtMyA0Mi44IDguNiA0OC40IDExLjIgNTEuMkMx +My44IDU0IDI3LjggNjUuNCAyNy44IDY1LjRDMjcuOCA2NS40IDIyLjQgNjMuNCAxOS44IDYxLjZD +MTcuMiA1OS44IDYuNCA1MS42IDYuNCA1MS42QzYuNCA1MS42IDIuNiA0NS42IC0zIDQyLjh6Ii8+ +CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzk5Y2MzMiI+CiAgPHBhdGggZD0iTS02MS4wMDkgMTEu +NjAzQy02MC42NzIgMTEuNDU1IC02MS4xOTYgOC43NDMgLTYxLjQgOC4yQy02Mi40MjIgNS40NzQg +LTcxLjQgNCAtNzEuNCA0Qy03MS42MjcgNS4zNjUgLTcxLjY4MiA2Ljk2MSAtNzEuNTc2IDguNTk5 +Qy03MS41NzYgOC41OTkgLTY2LjcwOCAxNC4xMTggLTYxLjAwOSAxMS42MDN6Ii8+CiA8L2c+CiA8 +ZyBzdHlsZT0iZmlsbDogIzY1OTkwMCI+CiAgPHBhdGggZD0iTS02MS4wMDkgMTEuNDAzQy02MS40 +NTggMTEuNTYxIC02MS4wMjQgOC42NjkgLTYxLjIgOC4yQy02Mi4yMjIgNS40NzQgLTcxLjQgMy45 +IC03MS40IDMuOUMtNzEuNjI3IDUuMjY1IC03MS42ODIgNi44NjEgLTcxLjU3NiA4LjQ5OUMtNzEu +NTc2IDguNDk5IC02Ny4zMDggMTMuNjE4IC02MS4wMDkgMTEuNDAzeiIvPgogPC9nPgogPGcgc3R5 +bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tNjUuNCAxMS41NDZDLTY2LjAyNSAxMS41 +NDYgLTY2LjUzMSAxMC40MDYgLTY2LjUzMSA5Qy02Ni41MzEgNy41OTUgLTY2LjAyNSA2LjQ1NSAt +NjUuNCA2LjQ1NUMtNjQuNzc1IDYuNDU1IC02NC4yNjggNy41OTUgLTY0LjI2OCA5Qy02NC4yNjgg +MTAuNDA2IC02NC43NzUgMTEuNTQ2IC02NS40IDExLjU0NnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJm +aWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNLTY1LjQgOXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJm +aWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNLTExMSAxMDkuNjAxQy0xMTEgMTA5LjYwMSAtMTE2 +LjYgMTE5LjYwMSAtOTEuOCAxMTMuNjAxQy05MS44IDExMy42MDEgLTc3LjggMTEyLjQwMSAtNzUu +NCAxMTAuMDAxQy03NC4yIDExMC44MDEgLTY1LjgzNCAxMTMuNzM0IC02MyAxMTQuNDAxQy01Ni4y +IDExNi4wMDEgLTQ3LjggMTA2IC00Ny44IDEwNkMtNDcuOCAxMDYgLTQzLjIgOTUuNSAtNDAuNCA5 +NS41Qy0zNy42IDk1LjUgLTQwLjggOTcuMSAtNDAuOCA5Ny4xQy00MC44IDk3LjEgLTQ3LjQgMTA3 +LjIwMSAtNDcgMTA4LjgwMUMtNDcgMTA4LjgwMSAtNTIuMiAxMjguODAxIC02OC4yIDEyOS42MDFD +LTY4LjIgMTI5LjYwMSAtODQuMzUgMTMwLjU1MSAtODMgMTM2LjQwMUMtODMgMTM2LjQwMSAtNzQu +MiAxMzQuMDAxIC03MS44IDEzNi40MDFDLTcxLjggMTM2LjQwMSAtNjEgMTM2LjAwMSAtNjkgMTQy +LjQwMUwtNzUuOCAxNTQuMDAxQy03NS44IDE1NC4wMDEgLTc1LjY2IDE1Ny45MTkgLTg1LjggMTU0 +LjQwMUMtOTUuNiAxNTEuMDAxIC0xMDUuOSAxMzguMTAxIC0xMDUuOSAxMzguMTAxQy0xMDUuOSAx +MzguMTAxIC0xMjEuODUgMTIzLjU1MSAtMTExIDEwOS42MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0i +ZmlsbDogI2U1OTk5OSI+CiAgPHBhdGggZD0iTS0xMTIuMiAxMTMuNjAxQy0xMTIuMiAxMTMuNjAx +IC0xMTQuMiAxMjMuMjAxIC03Ny40IDExMi44MDFDLTc3LjQgMTEyLjgwMSAtNzMgMTEyLjgwMSAt +NzAuNiAxMTMuNjAxQy02OC4yIDExNC40MDEgLTU2LjIgMTE3LjIwMSAtNTQuMiAxMTYuMDAxQy01 +NC4yIDExNi4wMDEgLTYxLjQgMTI5LjYwMSAtNzMgMTI4LjAwMUMtNzMgMTI4LjAwMSAtODYuMiAx +MjkuNjAxIC04NS44IDEzNC40MDFDLTg1LjggMTM0LjQwMSAtODEuOCAxNDEuNjAxIC03NyAxNDQu +MDAxQy03NyAxNDQuMDAxIC03NC4yIDE0Ni40MDEgLTc0LjYgMTQ5LjYwMUMtNzUgMTUyLjgwMSAt +NzcuOCAxNTQuNDAxIC03OS44IDE1NS4yMDFDLTgxLjggMTU2LjAwMSAtODUgMTUyLjgwMSAtODYu +NiAxNTIuODAxQy04OC4yIDE1Mi44MDEgLTk2LjYgMTQ2LjQwMSAtMTAxIDE0MS42MDFDLTEwNS40 +IDEzNi44MDEgLTExMy44IDEyNC44MDEgLTExMy40IDEyMi4wMDFDLTExMyAxMTkuMjAxIC0xMTIu +MiAxMTMuNjAxIC0xMTIuMiAxMTMuNjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNiMjY1 +NjUiPgogIDxwYXRoIGQ9Ik0tMTA5IDEzMS4wNTFDLTEwNi40IDEzNS4wMDEgLTEwMy4yIDEzOS4y +MDEgLTEwMSAxNDEuNjAxQy05Ni42IDE0Ni40MDEgLTg4LjIgMTUyLjgwMSAtODYuNiAxNTIuODAx +Qy04NSAxNTIuODAxIC04MS44IDE1Ni4wMDEgLTc5LjggMTU1LjIwMUMtNzcuOCAxNTQuNDAxIC03 +NSAxNTIuODAxIC03NC42IDE0OS42MDFDLTc0LjIgMTQ2LjQwMSAtNzcgMTQ0LjAwMSAtNzcgMTQ0 +LjAwMUMtODAuMDY2IDE0Mi40NjggLTgyLjgwNiAxMzguOTc2IC04NC4zODUgMTM2LjY1M0MtODQu +Mzg1IDEzNi42NTMgLTg0LjIgMTM5LjIwMSAtODkuNCAxMzguNDAxQy05NC42IDEzNy42MDEgLTk5 +LjggMTM0LjgwMSAtMTAxLjQgMTMxLjYwMUMtMTAzIDEyOC40MDEgLTEwNS40IDEyNi4wMDEgLTEw +My44IDEyOS42MDFDLTEwMi4yIDEzMy4yMDEgLTk5LjggMTM2LjgwMSAtOTguMiAxMzcuMjAxQy05 +Ni42IDEzNy42MDEgLTk3IDEzOC44MDEgLTk5LjQgMTM4LjQwMUMtMTAxLjggMTM4LjAwMSAtMTA0 +LjYgMTM3LjYwMSAtMTA5IDEzMi40MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzk5MjYw +MCI+CiAgPHBhdGggZD0iTS0xMTEuNiAxMTAuMDAxQy0xMTEuNiAxMTAuMDAxIC0xMDkuOCA5Ni40 +IC0xMDguNiA5Mi40Qy0xMDguNiA5Mi40IC0xMDkuNCA4NS42IC0xMDcgODEuNEMtMTA0LjYgNzcu +MiAtMTAyLjYgNzEgLTk5LjYgNjUuNkMtOTYuNiA2MC4yIC05Ni40IDU2LjIgLTkyLjQgNTQuNkMt +ODguNCA1MyAtODIuNCA0NC40IC03OS42IDQzLjRDLTc2LjggNDIuNCAtNzcgNDMuMiAtNzcgNDMu +MkMtNzcgNDMuMiAtNzAuMiAyOC40IC01Ni42IDMyLjRDLTU2LjYgMzIuNCAtNzIuOCAyOS42IC01 +NyAyMC4yQy01NyAyMC4yIC02MS44IDIxLjMgLTU4LjUgMTQuM0MtNTYuMjk5IDkuNjMyIC01Ni44 +IDE2LjQgLTY3LjggMjguMkMtNjcuOCAyOC4yIC03Mi44IDM2LjggLTc4IDM5LjhDLTgzLjIgNDIu +OCAtOTUuMiA0OS44IC05Ni40IDUzLjZDLTk3LjYgNTcuNCAtMTAwLjggNjMuMiAtMTAyLjggNjQu +OEMtMTA0LjggNjYuNCAtMTA3LjYgNzAuNiAtMTA4IDc0Qy0xMDggNzQgLTEwOS4yIDc4IC0xMTAu +NiA3OS4yQy0xMTIgODAuNCAtMTEyLjIgODMuNiAtMTEyLjIgODUuNkMtMTEyLjIgODcuNiAtMTE0 +LjIgOTAuNCAtMTE0IDkyLjhDLTExNCA5Mi44IC0xMTMuMiAxMTEuODAxIC0xMTMuNiAxMTMuODAx +TC0xMTEuNiAxMTAuMDAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmYiPgogIDxw +YXRoIGQ9Ik0tMTIwLjIgMTE0LjYwMUMtMTIwLjIgMTE0LjYwMSAtMTIyLjIgMTEzLjIwMSAtMTI2 +LjYgMTE5LjIwMUMtMTI2LjYgMTE5LjIwMSAtMTE5LjMgMTUyLjIwMSAtMTE5LjMgMTUzLjYwMUMt +MTE5LjMgMTUzLjYwMSAtMTE4LjIgMTUxLjUwMSAtMTE5LjUgMTQ0LjMwMUMtMTIwLjggMTM3LjEw +MSAtMTIxLjcgMTI0LjQwMSAtMTIxLjcgMTI0LjQwMUwtMTIwLjIgMTE0LjYwMXoiLz4KIDwvZz4K +IDxnIHN0eWxlPSJmaWxsOiAjOTkyNjAwIj4KICA8cGF0aCBkPSJNLTk4LjYgNTRDLTk4LjYgNTQg +LTExNi4yIDU3LjIgLTExNS44IDg2LjRMLTExNi42IDExMS4yMDFDLTExNi42IDExMS4yMDEgLTEx +Ny44IDg1LjYgLTExOSA4NEMtMTIwLjIgODIuNCAtMTE2LjIgNzEuMiAtMTE5LjQgNzcuMkMtMTE5 +LjQgNzcuMiAtMTMzLjQgOTEuMiAtMTI1LjQgMTEyLjQwMUMtMTI1LjQgMTEyLjQwMSAtMTIzLjkg +MTE1LjcwMSAtMTI2LjkgMTExLjEwMUMtMTI2LjkgMTExLjEwMSAtMTMxLjUgOTguNSAtMTMwLjQg +OTIuMUMtMTMwLjQgOTIuMSAtMTMwLjIgODkuOSAtMTI4LjMgODcuMUMtMTI4LjMgODcuMSAtMTE5 +LjcgNzUuNCAtMTE3IDczLjFDLTExNyA3My4xIC0xMTUuMiA1OC43IC05OS44IDUzLjVDLTk5Ljgg +NTMuNSAtOTQuMSA1MS4yIC05OC42IDU0eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAw +MDAiPgogIDxwYXRoIGQ9Ik00MC44IC0xMi4yQzQxLjQ2IC0xMi41NTQgNDEuNDUxIC0xMy41MjQg +NDIuMDMxIC0xMy42OTdDNDMuMTggLTE0LjA0MSA0My4zNDQgLTE1LjEwOCA0My44NjIgLTE1Ljg5 +MkM0NC43MzUgLTE3LjIxMSA0NC45MjggLTE4Ljc0NCA0NS41MSAtMjAuMjM1QzQ1Ljc4MiAtMjAu +OTM1IDQ1LjgwOSAtMjEuODkgNDUuNDk2IC0yMi41NUM0NC4zMjIgLTI1LjAzMSA0My42MiAtMjcu +NDggNDIuMTc4IC0yOS45MDZDNDEuOTEgLTMwLjM1NiA0MS42NDggLTMxLjE1IDQxLjQ0NyAtMzEu +NzQ4QzQwLjk4NCAtMzMuMTMyIDM5LjcyNyAtMzQuMTIzIDM4Ljg2NyAtMzUuNDQzQzM4LjU3OSAt +MzUuODg0IDM5LjEwNCAtMzYuODA5IDM4LjM4OCAtMzYuODkzQzM3LjQ5MSAtMzYuOTk4IDM2LjA0 +MiAtMzcuNTc4IDM1LjgwOSAtMzYuNTUyQzM1LjIyMSAtMzMuOTY1IDM2LjIzMiAtMzEuNDQyIDM3 +LjIgLTI5QzM2LjQxOCAtMjguMzA4IDM2Ljc1MiAtMjcuMzg3IDM2LjkwNCAtMjYuNjJDMzcuNjE0 +IC0yMy4wMTQgMzYuNDE2IC0xOS42NjIgMzUuNjU1IC0xNi4xODhDMzUuNjMyIC0xNi4wODQgMzUu +OTc0IC0xNS44ODYgMzUuOTQ2IC0xNS44MjRDMzQuNzI0IC0xMy4xMzggMzMuMjcyIC0xMC42OTMg +MzEuNDUzIC04LjMxMkMzMC42OTUgLTcuMzIgMjkuODIzIC02LjQwNCAyOS4zMjYgLTUuMzQxQzI4 +Ljk1OCAtNC41NTQgMjguNTUgLTMuNTg4IDI4LjggLTIuNkMyNS4zNjUgMC4xOCAyMy4xMTUgNC4w +MjUgMjAuNTA0IDcuODcxQzIwLjA0MiA4LjU1MSAyMC4zMzMgOS43NiAyMC44ODQgMTAuMDI5QzIx +LjY5NyAxMC40MjcgMjIuNjUzIDkuNDAzIDIzLjEyMyA4LjU1N0MyMy41MTIgNy44NTkgMjMuODY1 +IDcuMjA5IDI0LjM1NiA2LjU2NkMyNC40ODkgNi4zOTEgMjQuMzEgNS45NzIgMjQuNDQ1IDUuODUx +QzI3LjA3OCAzLjUwNCAyOC43NDcgMC41NjggMzEuMiAtMS44QzMzLjE1IC0yLjEyOSAzNC42ODcg +LTMuMTI3IDM2LjQzNSAtNC4xNEMzNi43NDMgLTQuMzE5IDM3LjI2NyAtNC4wNyAzNy41NTcgLTQu +MjY1QzM5LjMxIC01LjQ0MiAzOS4zMDggLTcuNDc4IDM5LjQxNCAtOS4zODhDMzkuNDY0IC0xMC4y +NzIgMzkuNjYgLTExLjU4OSA0MC44IC0xMi4yeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMw +MDAwMDAiPgogIDxwYXRoIGQ9Ik0zMS45NTkgLTE2LjY2NkMzMi4wODMgLTE2Ljc0MyAzMS45Mjgg +LTE3LjE2NiAzMi4wMzcgLTE3LjM4MkMzMi4xOTkgLTE3LjcwNiAzMi42MDIgLTE3Ljg5NCAzMi43 +NjQgLTE4LjIxOEMzMi44NzMgLTE4LjQzNCAzMi43MSAtMTguODE0IDMyLjg0NiAtMTguOTU2QzM1 +LjE3OSAtMjEuNDAzIDM1LjQzNiAtMjQuNDI3IDM0LjQgLTI3LjRDMzUuNDI0IC0yOC4wMiAzNS40 +ODUgLTI5LjI4MiAzNS4wNiAtMzAuMTI5QzM0LjIwNyAtMzEuODI5IDM0LjAxNCAtMzMuNzU1IDMz +LjAzOSAtMzUuMjk4QzMyLjIzNyAtMzYuNTY3IDMwLjY1OSAtMzcuODExIDI5LjI4OCAtMzYuNTA4 +QzI4Ljg2NyAtMzYuMTA4IDI4LjU0NiAtMzUuMzIxIDI4LjgyNCAtMzQuNjA5QzI4Ljg4OCAtMzQu +NDQ2IDI5LjE3MyAtMzQuMyAyOS4xNDYgLTM0LjIxOEMyOS4wMzkgLTMzLjg5NCAyOC40OTMgLTMz +LjY3IDI4LjQ4NyAtMzMuMzk4QzI4LjQ1NyAtMzEuOTAyIDI3LjUwMyAtMzAuMzkxIDI4LjEzMyAt +MjkuMDYyQzI4LjkwNSAtMjcuNDMzIDI5LjcyNCAtMjUuNTc2IDMwLjQgLTIzLjhDMjkuMTY2IC0y +MS42ODQgMzAuMTk5IC0xOS4yMzUgMjguNDQ2IC0xNy4zNThDMjguMzEgLTE3LjIxMiAyOC4zMTkg +LTE2LjgyNiAyOC40NDEgLTE2LjYyNEMyOC43MzMgLTE2LjEzOCAyOS4xMzkgLTE1LjczMiAyOS42 +MjUgLTE1LjQ0QzI5LjgyNyAtMTUuMzE5IDMwLjE3NSAtMTUuMzE3IDMwLjM3NSAtMTUuNDQxQzMw +Ljk1MyAtMTUuODAzIDMxLjM1MSAtMTYuMjkgMzEuOTU5IC0xNi42NjZ6Ii8+CiA8L2c+CiA8ZyBz +dHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTk0Ljc3MSAtMjYuOTc3Qzk2LjE2IC0y +NS4xODUgOTYuNDUgLTIyLjM5IDk0LjQwMSAtMjFDOTQuOTUxIC0xNy42OTEgOTguMzAyIC0xOS42 +NyAxMDAuNDAxIC0yMC4yQzEwMC4yOTIgLTIwLjU4OCAxMDAuNTE5IC0yMC45MzIgMTAwLjgwMiAt +MjAuOTM3QzEwMS44NTkgLTIwLjk1MiAxMDIuNTM5IC0yMS45ODQgMTAzLjYwMSAtMjEuOEMxMDQu +MDM1IC0yMy4zNTcgMTA1LjY3MyAtMjQuMDU5IDEwNi4zMTcgLTI1LjQzOUMxMDguMDQzIC0yOS4x +MzQgMTA3LjQ1MiAtMzMuNDA3IDEwNC44NjggLTM2LjY1M0MxMDQuNjY2IC0zNi45MDcgMTA0Ljg4 +MyAtMzcuNDI0IDEwNC43NTkgLTM3Ljc4NkMxMDQuMDAzIC0zOS45OTcgMTAxLjkzNSAtNDAuMzEy +IDEwMC4wMDEgLTQxQzk4LjgyNCAtNDQuODc1IDk4LjE2MyAtNDguOTA2IDk2LjQwMSAtNTIuNkM5 +NC43ODcgLTUyLjg1IDk0LjA4OSAtNTQuNTg5IDkyLjc1MiAtNTUuMzA5QzkxLjQxOSAtNTYuMDI4 +IDkwLjg1MSAtNTQuNDQ5IDkwLjg5MiAtNTMuNDAzQzkwLjg5OSAtNTMuMTk4IDkxLjM1MSAtNTIu +OTc0IDkxLjE4MSAtNTIuNjA5QzkxLjEwNSAtNTIuNDQ1IDkwLjg0NSAtNTIuMzM0IDkwLjg0NSAt +NTIuMkM5MC44NDYgLTUyLjA2NSA5MS4wNjcgLTUxLjkzNCA5MS4yMDEgLTUxLjhDOTAuMjgzIC01 +MC45OCA4OC44NiAtNTAuNTAzIDg4LjU2NSAtNDkuMzU4Qzg3LjYxMSAtNDUuNjQ4IDkwLjE4NCAt +NDIuNTIzIDkxLjg1MiAtMzkuMzIyQzkyLjQ0MyAtMzguMTg3IDkxLjcwNyAtMzYuOTE2IDkwLjk0 +NyAtMzUuNzA4QzkwLjUwOSAtMzUuMDEzIDkwLjYxNyAtMzMuODg2IDkwLjg5MyAtMzMuMDNDOTEu +NjQ1IC0zMC42OTkgOTMuMjM2IC0yOC45NiA5NC43NzEgLTI2Ljk3N3oiLz4KIDwvZz4KIDxnIHN0 +eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNNTcuNjExIC04LjU5MUM1Ni4xMjQgLTYu +NzQgNTIuNzEyIC00LjE3MSA1NS42MjkgLTIuMjQzQzU1LjgyMyAtMi4xMTQgNTYuMTkzIC0yLjEx +IDU2LjM2NiAtMi4yNDRDNTguMzg3IC0zLjgwOSA2MC4zOSAtNC43MTIgNjIuODI2IC01LjI5NEM2 +Mi45NSAtNS4zMjMgNjMuMjI0IC00Ljg1NiA2My41OTMgLTUuMDE3QzY1LjIwNiAtNS43MiA2Ny4y +MTYgLTUuNjYyIDY4LjQgLTdDNzIuMTY3IC02Ljc3NiA3NS43MzIgLTcuODkyIDc5LjEyMyAtOS4y +QzgwLjI4NCAtOS42NDggODEuNTU0IC0xMC4yMDcgODIuNzU1IC0xMC43MDlDODQuMTMxIC0xMS4y +ODUgODUuMzM1IC0xMi4yMTMgODYuNDQ3IC0xMy4zNTRDODYuNTggLTEzLjQ5IDg2LjkzNCAtMTMu +NCA4Ny4yMDEgLTEzLjRDODcuMTYxIC0xNC4yNjMgODguMTIzIC0xNC4zOSA4OC4zNyAtMTUuMDEy +Qzg4LjQ2MiAtMTUuMjQ0IDg4LjMxMiAtMTUuNjQgODguNDQ1IC0xNS43NDJDOTAuNTgzIC0xNy4z +NzIgOTEuNTAzIC0xOS4zOSA5MC4zMzQgLTIxLjc2N0M5MC4wNDkgLTIyLjM0NSA4OS44IC0yMi45 +NjMgODkuMjM0IC0yMy40MzlDODguMTQ5IC0yNC4zNSA4Ny4wNDcgLTIzLjQ5NiA4NiAtMjMuOEM4 +NS44NDEgLTIzLjE3MiA4NS4xMTIgLTIzLjM0NCA4NC43MjYgLTIzLjE0NkM4My44NjcgLTIyLjcw +NyA4Mi41MzQgLTIzLjI5MiA4MS42NzUgLTIyLjg1NEM4MC4zMTMgLTIyLjE1OSA3OS4wNzIgLTIx +Ljk5IDc3LjY1IC0yMS42MTNDNzcuMzM4IC0yMS41MzEgNzYuNTYgLTIxLjYyNyA3Ni40IC0yMUM3 +Ni4yNjYgLTIxLjEzNCA3Ni4xMTggLTIxLjM2OCA3Ni4wMTIgLTIxLjM0NkM3NC4xMDQgLTIwLjk1 +IDcyLjg0NCAtMjAuNzM2IDcxLjU0MyAtMTkuMDQ0QzcxLjQ0IC0xOC45MTEgNzAuOTk4IC0xOS4w +OSA3MC44MzkgLTE4Ljk1NUM2OS44ODIgLTE4LjE0NyA2OS40NzcgLTE2LjkxMyA2OC4zNzYgLTE2 +LjI0MUM2OC4xNzUgLTE2LjExOCA2Ny44MjMgLTE2LjI4NiA2Ny42MjkgLTE2LjE1N0M2Ni45ODMg +LTE1LjcyNiA2Ni42MTYgLTE1LjA4NSA2NS45NzQgLTE0LjYzOEM2NS42NDUgLTE0LjQwOSA2NS4y +NDUgLTE0LjczNCA2NS4yNzcgLTE0Ljk5QzY1LjUyMiAtMTYuOTM3IDY2LjE3NSAtMTguNzI0IDY1 +LjYgLTIwLjZDNjcuNjc3IC0yMy4xMiA3MC4xOTQgLTI1LjA2OSA3MiAtMjcuOEM3Mi4wMTUgLTI5 +Ljk2NiA3Mi43MDcgLTMyLjExMiA3Mi41OTQgLTM0LjE4OUM3Mi41ODQgLTM0LjM4MiA3Mi4yOTYg +LTM1LjExNSA3Mi4xNyAtMzUuNDYyQzcxLjg1OCAtMzYuMzE2IDcyLjc2NCAtMzcuMzgyIDcxLjky +IC0zOC4xMDZDNzAuNTE2IC0zOS4zMDkgNjkuMjI0IC0zOC40MzMgNjguNCAtMzdDNjYuNTYyIC0z +Ni42MSA2NC40OTYgLTM1LjkxNyA2Mi45MTggLTM3LjE1MUM2MS45MTEgLTM3LjkzOCA2MS4zMzMg +LTM4Ljg0NCA2MC41MzQgLTM5LjlDNTkuNTQ5IC00MS4yMDIgNTkuODg0IC00Mi42MzggNTkuOTU0 +IC00NC4yMDJDNTkuOTYgLTQ0LjMzIDU5LjY0NSAtNDQuNDY2IDU5LjY0NSAtNDQuNkM1OS42NDYg +LTQ0LjczNSA1OS44NjYgLTQ0Ljg2NiA2MCAtNDVDNTkuMjk0IC00NS42MjYgNTkuMDE5IC00Ni42 +ODQgNTggLTQ3QzU4LjMwNSAtNDguMDkyIDU3LjYyOSAtNDguOTc2IDU2Ljc1OCAtNDkuMjc4QzU0 +Ljc2MyAtNDkuOTY5IDUzLjA4NiAtNDguMDU3IDUxLjE5NCAtNDcuOTg0QzUwLjY4IC00Ny45NjUg +NTAuMjEzIC00OS4wMDMgNDkuNTY0IC00OS4zMjhDNDkuMTMyIC00OS41NDQgNDguNDI4IC00OS41 +NzcgNDguMDY2IC00OS4zMTFDNDcuMzc4IC00OC44MDcgNDYuNzg5IC00OC42OTMgNDYuMDMxIC00 +OC40ODhDNDQuNDE0IC00OC4wNTIgNDMuMTM2IC00Ni45NTggNDEuNjU2IC00Ni4xMDNDNDAuMTcx +IC00NS4yNDYgMzkuMjE2IC00My44MDkgMzguMTM2IC00Mi40ODlDMzcuMTk1IC00MS4zMzcgMzcu +MDU5IC0zOC45MjMgMzguNDc5IC0zOC40MjNDNDAuMzIyIC0zNy43NzMgNDEuNjI2IC00MC40NzYg +NDMuNTkyIC00MC4xNUM0My45MDQgLTQwLjA5OSA0NC4xMSAtMzkuNzg4IDQ0IC0zOS40QzQ0LjM4 +OSAtMzkuMjkxIDQ0LjYwNyAtMzkuNTIgNDQuOCAtMzkuOEM0NS42NTggLTM4Ljc4MSA0Ni44MjIg +LTM4LjQ0NCA0Ny43NiAtMzcuNTcxQzQ4LjczIC0zNi42NjcgNTAuNDc2IC0zNy4wODUgNTEuNDkx +IC0zNi4wODhDNTMuMDIgLTM0LjU4NiA1Mi40NjEgLTMxLjkwNSA1NC40IC0zMC42QzUzLjgxNCAt +MjkuMjg3IDUzLjIwNyAtMjguMDEgNTIuODcyIC0yNi41ODNDNTIuNTkgLTI1LjM3NyA1My41ODQg +LTI0LjE4IDU0Ljc5NSAtMjQuMjcxQzU2LjA1MyAtMjQuMzY1IDU2LjMxNSAtMjUuMTI0IDU2Ljgg +LTI2LjJDNTcuMDY3IC0yNS45MzMgNTcuNTM2IC0yNS42MzYgNTcuNDk1IC0yNS40MkM1Ny4wMzgg +LTIzLjAzMyA1Ni4wMTEgLTIxLjA0IDU1LjU1MyAtMTguNjA5QzU1LjQ5NCAtMTguMjkyIDU1LjE4 +OSAtMTguMDkgNTQuOCAtMTguMkM1NC4zMzIgLTE0LjA1MSA1MC4yOCAtMTEuNjU3IDQ3LjczNSAt +OC40OTJDNDcuMzMyIC03Ljk5IDQ3LjMyOCAtNi43NDEgNDcuNzM3IC02LjMzOEM0OS4xNCAtNC45 +NTEgNTEuMSAtNi40OTcgNTIuOCAtN0M1My4wMTMgLTguMjA2IDUzLjg3MiAtOS4xNDggNTUuMjA0 +IC05LjA5MkM1NS40NiAtOS4wODIgNTUuNjk1IC05LjYyNCA1Ni4wMTkgLTkuNzU0QzU2LjM2NyAt +OS44OTIgNTYuODY5IC05LjY2OCA1Ny4xNTUgLTkuODY2QzU4Ljg4NCAtMTEuMDYxIDYwLjI5MiAt +MTIuMTY3IDYyLjAzIC0xMy4zNTZDNjIuMjIyIC0xMy40ODcgNjIuNTY2IC0xMy4zMjggNjIuNzgy +IC0xMy40MzZDNjMuMTA3IC0xMy41OTggNjMuMjk0IC0xMy45ODUgNjMuNjE3IC0xNC4xN0M2My45 +NjUgLTE0LjM3IDY0LjIwNyAtMTQuMDggNjQuNCAtMTMuOEM2My43NTQgLTEzLjQ1MSA2My43NSAt +MTIuNDk0IDYzLjE2OCAtMTIuMjkyQzYyLjM5MyAtMTIuMDI0IDYxLjgzMiAtMTEuNTExIDYxLjE1 +OCAtMTEuMDY0QzYwLjg2NiAtMTAuODcxIDYwLjIwNyAtMTEuMTE5IDYwLjEwMyAtMTAuOTRDNTku +NTA1IC05LjkxMiA1OC4zMjEgLTkuNDc0IDU3LjYxMSAtOC41OTF6Ii8+CiA8L2c+CiA8ZyBzdHls +ZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTIuMiAtNThDMi4yIC01OCAtNy4wMzggLTYw +Ljg3MiAtMTguMiAtMzUuMkMtMTguMiAtMzUuMiAtMjAuNiAtMzAgLTIzIC0yOEMtMjUuNCAtMjYg +LTM2LjYgLTIyLjQgLTM4LjYgLTE4LjRMLTQ5IC0yLjRDLTQ5IC0yLjQgLTM0LjIgLTE4LjQgLTMx +IC0yMC44Qy0zMSAtMjAuOCAtMjMgLTI5LjIgLTI2LjIgLTIyLjRDLTI2LjIgLTIyLjQgLTQwLjIg +LTExLjYgLTM5IC0yLjRDLTM5IC0yLjQgLTQ0LjYgMTIgLTQ1LjQgMTRDLTQ1LjQgMTQgLTI5LjQg +LTE4IC0yNyAtMTkuMkMtMjQuNiAtMjAuNCAtMjMuNCAtMjAuNCAtMjQuNiAtMTYuOEMtMjUuOCAt +MTMuMiAtMjYuMiAzLjIgLTI5IDUuMkMtMjkgNS4yIC0yMSAtMTUuMiAtMjEuOCAtMTguNEMtMjEu +OCAtMTguNCAtMTguNiAtMjIgLTE2LjIgLTE2LjhMLTE3LjQgLTAuOEwtMTMgMTEuMkMtMTMgMTEu +MiAtMTUuNCAwIC0xMy44IC0xNS42Qy0xMy44IC0xNS42IC0xNS44IC0yNiAtMTEuOCAtMjAuNEMt +Ny44IC0xNC44IDEuOCAtOC44IDEuOCAtNEMxLjggLTQgLTMuNCAtMjEuNiAtMTIuNiAtMjYuNEwt +MTYuNiAtMjAuNEwtMTcuOCAtMjIuNEMtMTcuOCAtMjIuNCAtMjEuNCAtMjMuMiAtMTcgLTMwQy0x +Mi42IC0zNi44IC0xMyAtMzcuNiAtMTMgLTM3LjZDLTEzIC0zNy42IC02LjYgLTMwLjQgLTUgLTMw +LjRDLTUgLTMwLjQgOC4yIC0zOCA5LjQgLTEzLjZDOS40IC0xMy42IDE2LjIgLTI4IDcgLTM0LjhD +NyAtMzQuOCAtNy44IC0zNi44IC02LjYgLTQyTDAuNiAtNTQuNEM0LjIgLTU5LjYgMi42IC01Ni44 +IDIuNiAtNTYuOHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBk +PSJNLTE3LjggLTQxLjZDLTE3LjggLTQxLjYgLTMwLjYgLTQxLjYgLTMzLjggLTM2LjRMLTQxIC0y +Ni44Qy00MSAtMjYuOCAtMjMuOCAtMzYuOCAtMTkuOCAtMzhDLTE1LjggLTM5LjIgLTE3LjggLTQx +LjYgLTE3LjggLTQxLjZ6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBh +dGggZD0iTS01Ny44IC0zNS4yQy01Ny44IC0zNS4yIC01OS44IC0zNCAtNjAuMiAtMzEuMkMtNjAu +NiAtMjguNCAtNjMgLTI4IC02Mi4yIC0yNS4yQy02MS40IC0yMi40IC01OS40IC0yMCAtNTkuNCAt +MjRDLTU5LjQgLTI4IC01Ny44IC0zMCAtNTcgLTMxLjJDLTU2LjIgLTMyLjQgLTU0LjYgLTM2Ljgg +LTU3LjggLTM1LjJ6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGgg +ZD0iTS02Ni42IDI2Qy02Ni42IDI2IC03NSAyMiAtNzguMiAxOC40Qy04MS40IDE0LjggLTgwLjk0 +OCAxOS45NjYgLTg1LjggMTkuNkMtOTEuNjQ3IDE5LjE1OSAtOTAuNiAzLjIgLTkwLjYgMy4yTC05 +NC42IDEwLjhDLTk0LjYgMTAuOCAtOTUuOCAyNS4yIC04Ny44IDIyLjhDLTgzLjg5MyAyMS42Mjgg +LTgyLjYgMjMuMiAtODQuMiAyNEMtODUuOCAyNC44IC03OC42IDI1LjIgLTgxLjQgMjYuOEMtODQu +MiAyOC40IC02OS44IDIzLjIgLTcyLjIgMzMuNkwtNjYuNiAyNnoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNLTc5LjIgNDAuNEMtNzkuMiA0MC40IC05NC42 +IDQ0LjggLTk4LjIgMzUuMkMtOTguMiAzNS4yIC0xMDMgMzcuNiAtMTAwLjggNDAuNkMtOTguNiA0 +My42IC05Ny40IDQ0IC05Ny40IDQ0Qy05Ny40IDQ0IC05MiA0NS4yIC05Mi42IDQ2Qy05My4yIDQ2 +LjggLTk1LjYgNTAuMiAtOTUuNiA1MC4yQy05NS42IDUwLjIgLTg1LjQgNDQuMiAtNzkuMiA0MC40 +eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmYiPgogIDxwYXRoIGQ9Ik0xNDkuMjAx +IDExOC42MDFDMTQ4Ljc3NCAxMjAuNzM1IDE0Ny4xMDMgMTIxLjUzNiAxNDUuMjAxIDEyMi4yMDFD +MTQzLjI4NCAxMjEuMjQzIDE0MC42ODYgMTE4LjEzNyAxMzguODAxIDEyMC4yMDFDMTM4LjMyNyAx +MTkuNzIxIDEzNy41NDggMTE5LjY2MSAxMzcuMjA0IDExOC45OTlDMTM2LjczOSAxMTguMTAxIDEz +Ny4wMTEgMTE3LjA1NSAxMzYuNjY5IDExNi4yNTdDMTM2LjEyNCAxMTQuOTg1IDEzNS40MTUgMTEz +LjYxOSAxMzUuNjAxIDExMi4yMDFDMTM3LjQwNyAxMTEuNDg5IDEzOC4wMDIgMTA5LjU4MyAxMzcu +NTI4IDEwNy44MkMxMzcuNDU5IDEwNy41NjMgMTM3LjAzIDEwNy4zNjYgMTM3LjIzIDEwNy4wMTdD +MTM3LjQxNiAxMDYuNjk0IDEzNy43MzQgMTA2LjQ2NyAxMzguMDAxIDEwNi4yQzEzNy44NjYgMTA2 +LjMzNSAxMzcuNzIxIDEwNi41NjggMTM3LjYxIDEwNi41NDhDMTM3IDEwNi40NDIgMTM3LjEyNCAx +MDUuODA1IDEzNy4yNTQgMTA1LjQxOEMxMzcuODM5IDEwMy42NzIgMTM5Ljg1MyAxMDMuNDA4IDE0 +MS4yMDEgMTA0LjZDMTQxLjQ1NyAxMDQuMDM1IDE0MS45NjYgMTA0LjIyOSAxNDIuNDAxIDEwNC4y +QzE0Mi4zNTEgMTAzLjYyMSAxNDIuNzU5IDEwMy4wOTQgMTQyLjk1NyAxMDIuNjc0QzE0My40NzUg +MTAxLjU3NiAxNDUuMTA0IDEwMi42ODIgMTQ1LjkwMSAxMDIuMDdDMTQ2Ljk3NyAxMDEuMjQ1IDE0 +OC4wNCAxMDAuNTQ2IDE0OS4xMTggMTAxLjE0OUMxNTAuOTI3IDEwMi4xNjIgMTUyLjYzNiAxMDMu +Mzc0IDE1My44MzUgMTA1LjExNUMxNTQuNDEgMTA1Ljk0OSAxNTQuNjUgMTA3LjIzIDE1NC41OTIg +MTA4LjE4OEMxNTQuNTU0IDEwOC44MzUgMTUzLjE3MyAxMDguNDgzIDE1Mi44MyAxMDkuNDEyQzE1 +Mi4xODUgMTExLjE2IDE1NC4wMTYgMTExLjY3OSAxNTQuNzcyIDExMy4wMTdDMTU0Ljk3IDExMy4z +NjYgMTU0LjcwNiAxMTMuNjcgMTU0LjM5MSAxMTMuNzY4QzE1My45OCAxMTMuODk2IDE1My4xOTYg +MTEzLjcwNyAxNTMuMzM0IDExNC4xNkMxNTQuMzA2IDExNy4zNTMgMTUxLjU1IDExOC4wMzEgMTQ5 +LjIwMSAxMTguNjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmYiPgogIDxwYXRo +IGQ9Ik0xMzkuNiAxMzguMjAxQzEzOS41OTMgMTM2LjQ2MyAxMzcuOTkyIDEzNC43MDcgMTM5LjIw +MSAxMzMuMDAxQzEzOS4zMzYgMTMzLjEzNSAxMzkuNDY3IDEzMy4zNTYgMTM5LjYwMSAxMzMuMzU2 +QzEzOS43MzYgMTMzLjM1NiAxMzkuODY3IDEzMy4xMzUgMTQwLjAwMSAxMzMuMDAxQzE0MS40OTYg +MTM1LjIxNyAxNDUuMTQ4IDEzNi4xNDUgMTQ1LjAwNiAxMzguOTkxQzE0NC45ODQgMTM5LjQzOCAx +NDMuODk3IDE0MC4zNTYgMTQ0LjgwMSAxNDEuMDAxQzE0Mi45ODggMTQyLjM0OSAxNDIuOTMzIDE0 +NC43MTkgMTQyLjAwMSAxNDYuNjAxQzE0MC43NjMgMTQ2LjMxNSAxMzkuNTUxIDE0NS45NTIgMTM4 +LjQwMSAxNDUuNDAxQzEzOC43NTMgMTQzLjkxNSAxMzguNjM2IDE0Mi4yMzEgMTM5LjQ1NiAxNDAu +OTExQzEzOS44OSAxNDAuMjEzIDEzOS42MDMgMTM5LjEzNCAxMzkuNiAxMzguMjAxeiIvPgogPC9n +PgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tMjYuNiAxMjkuMjAxQy0y +Ni42IDEyOS4yMDEgLTQzLjQ1OCAxMzkuMzM3IC0yOS40IDEyNC4wMDFDLTIwLjYgMTE0LjQwMSAt +MTAuNiAxMDguODAxIC0xMC42IDEwOC44MDFDLTEwLjYgMTA4LjgwMSAtMC4yIDEwNC40IDMuNCAx +MDMuMkM3IDEwMiAyMi4yIDk2LjggMjUuNCA5Ni40QzI4LjYgOTYgMzguMiA5MiA0NSA5NkM1MS44 +IDEwMCA1OS44IDEwNC40IDU5LjggMTA0LjRDNTkuOCAxMDQuNCA0My40IDk2IDM5LjggOTguNEMz +Ni4yIDEwMC44IDI5IDEwMC40IDIzIDEwMy42QzIzIDEwMy42IDguMiAxMDguMDAxIDUgMTEwLjAw +MUMxLjggMTEyLjAwMSAtOC42IDEyMy42MDEgLTEwLjIgMTIyLjgwMUMtMTEuOCAxMjIuMDAxIC05 +LjggMTIxLjYwMSAtOC42IDExOC44MDFDLTcuNCAxMTYuMDAxIC05LjQgMTE0LjQwMSAtMTcuNCAx +MjAuODAxQy0yNS40IDEyNy4yMDEgLTI2LjYgMTI5LjIwMSAtMjYuNiAxMjkuMjAxeiIvPgogPC9n +PgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMTkuMTk1IDEyMy4yMzRD +LTE5LjE5NSAxMjMuMjM0IC0xNy43ODUgMTEwLjE5NCAtOS4zMDcgMTExLjg1OUMtOS4zMDcgMTEx +Ljg1OSAtMS4wODEgMTA3LjY4OSAxLjY0MSAxMDUuNzIxQzEuNjQxIDEwNS43MjEgOS43OCAxMDQu +MDE5IDExLjA5IDEwMy40MDJDMjkuNTY5IDk0LjcwMiA0NC4yODggOTkuMjIxIDQ0LjgzNSA5OC4x +MDFDNDUuMzgxIDk2Ljk4MiA2NS4wMDYgMTA0LjA5OSA2OC42MTUgMTA4LjE4NUM2OS4wMDYgMTA4 +LjYyOCA1OC4zODQgMTAyLjU4OCA0OC42ODYgMTAwLjY5N0M0MC40MTMgOTkuMDgzIDE4LjgxMSAx +MDAuOTQ0IDcuOTA1IDEwNi40OEM0LjkzMiAxMDcuOTg5IC00LjAxMyAxMTMuNzczIC02LjU0NCAx +MTMuNjYyQy05LjA3NSAxMTMuNTUgLTE5LjE5NSAxMjMuMjM0IC0xOS4xOTUgMTIzLjIzNHoiLz4K +IDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNLTIzIDE0OC44MDFD +LTIzIDE0OC44MDEgLTM4LjIgMTQ2LjQwMSAtMjEuNCAxNDQuODAxQy0yMS40IDE0NC44MDEgLTMu +NCAxNDIuODAxIDAuNiAxMzcuNjAxQzAuNiAxMzcuNjAxIDE0LjIgMTI4LjQwMSAxNyAxMjguMDAx +QzE5LjggMTI3LjYwMSA0OS44IDEyMC40MDEgNTAuMiAxMTguMDAxQzUwLjYgMTE1LjYwMSA1Ni4y +IDExNS42MDEgNTcuOCAxMTYuNDAxQzU5LjQgMTE3LjIwMSA1OC42IDExOC40MDEgNTUuOCAxMTku +MjAxQzUzIDEyMC4wMDEgMjEuOCAxMzYuNDAxIDE1LjQgMTM3LjYwMUM5IDEzOC44MDEgLTIuNiAx +NDYuNDAxIC03LjQgMTQ3LjYwMUMtMTIuMiAxNDguODAxIC0yMyAxNDguODAxIC0yMyAxNDguODAx +eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMy40OCAx +NDEuNDAzQy0zLjQ4IDE0MS40MDMgLTEyLjA2MiAxNDAuNTc0IC0zLjQ2MSAxMzkuNzU1Qy0zLjQ2 +MSAxMzkuNzU1IDUuMzU1IDEzNi4zMzEgNy40MDMgMTMzLjY2OEM3LjQwMyAxMzMuNjY4IDE0LjM2 +NyAxMjguOTU3IDE1LjggMTI4Ljc1M0MxNy4yMzQgMTI4LjU0OCAzMS4xOTQgMTI0Ljg2MSAzMS4z +OTkgMTIzLjYzM0MzMS42MDQgMTIyLjQwNCA2NS42NyAxMDkuODIzIDcwLjA5IDExMy4wMTNDNzMu +MDAxIDExNS4xMTQgNjMuMSAxMTMuNDM3IDUzLjQ2NiAxMTcuODQ3QzUyLjExMSAxMTguNDY3IDE4 +LjI1OCAxMzMuMDU0IDE0Ljk4MSAxMzMuNjY4QzExLjcwNCAxMzQuMjgzIDUuNzY1IDEzOC4xNzQg +My4zMDcgMTM4Ljc4OEMwLjg1IDEzOS40MDMgLTMuNDggMTQxLjQwMyAtMy40OCAxNDEuNDAzeiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMTEuNCAxNDMu +NjAxQy0xMS40IDE0My42MDEgLTYuMiAxNDMuMjAxIC03LjQgMTQ0LjgwMUMtOC42IDE0Ni40MDEg +LTExIDE0NS42MDEgLTExIDE0NS42MDFMLTExLjQgMTQzLjYwMXoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNLTE4LjYgMTQ1LjIwMUMtMTguNiAxNDUuMjAx +IC0xMy40IDE0NC44MDEgLTE0LjYgMTQ2LjQwMUMtMTUuOCAxNDguMDAxIC0xOC4yIDE0Ny4yMDEg +LTE4LjIgMTQ3LjIwMUwtMTguNiAxNDUuMjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMw +MDAwMDAiPgogIDxwYXRoIGQ9Ik0tMjkgMTQ2LjgwMUMtMjkgMTQ2LjgwMSAtMjMuOCAxNDYuNDAx +IC0yNSAxNDguMDAxQy0yNi4yIDE0OS42MDEgLTI4LjYgMTQ4LjgwMSAtMjguNiAxNDguODAxTC0y +OSAxNDYuODAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9 +Ik0tMzYuNiAxNDcuNjAxQy0zNi42IDE0Ny42MDEgLTMxLjQgMTQ3LjIwMSAtMzIuNiAxNDguODAx +Qy0zMy44IDE1MC40MDEgLTM2LjIgMTQ5LjYwMSAtMzYuMiAxNDkuNjAxTC0zNi42IDE0Ny42MDF6 +Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTEuOCAxMDgu +MDAxQzEuOCAxMDguMDAxIDYuMiAxMDguMDAxIDUgMTA5LjYwMUMzLjggMTExLjIwMSAwLjYgMTEw +LjgwMSAwLjYgMTEwLjgwMUwxLjggMTA4LjAwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +MDAwMDAwIj4KICA8cGF0aCBkPSJNLTguMiAxMTMuNjAxQy04LjIgMTEzLjYwMSAtMS42OTQgMTEx +LjQ2IC00LjIgMTE0LjgwMUMtNS40IDExNi40MDEgLTcuOCAxMTUuNjAxIC03LjggMTE1LjYwMUwt +OC4yIDExMy42MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGgg +ZD0iTS0xOS40IDExOC40MDFDLTE5LjQgMTE4LjQwMSAtMTQuMiAxMTguMDAxIC0xNS40IDExOS42 +MDFDLTE2LjYgMTIxLjIwMSAtMTkgMTIwLjQwMSAtMTkgMTIwLjQwMUwtMTkuNCAxMTguNDAxeiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMjcgMTI0LjQw +MUMtMjcgMTI0LjQwMSAtMjEuOCAxMjQuMDAxIC0yMyAxMjUuNjAxQy0yNC4yIDEyNy4yMDEgLTI2 +LjYgMTI2LjQwMSAtMjYuNiAxMjYuNDAxTC0yNyAxMjQuNDAxeiIvPgogPC9nPgogPGcgc3R5bGU9 +ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMzMuOCAxMjkuMjAxQy0zMy44IDEyOS4yMDEg +LTI4LjYgMTI4LjgwMSAtMjkuOCAxMzAuNDAxQy0zMSAxMzIuMDAxIC0zMy40IDEzMS4yMDEgLTMz +LjQgMTMxLjIwMUwtMzMuOCAxMjkuMjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAw +MDAiPgogIDxwYXRoIGQ9Ik01LjI4MiAxMzUuNTk4QzUuMjgyIDEzNS41OTggMTIuMjAzIDEzNS4w +NjYgMTAuNjA2IDEzNy4xOTVDOS4wMDkgMTM5LjMyNSA1LjgxNCAxMzguMjYgNS44MTQgMTM4LjI2 +TDUuMjgyIDEzNS41OTh6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBh +dGggZD0iTTE1LjY4MiAxMzAuNzk4QzE1LjY4MiAxMzAuNzk4IDIyLjYwMyAxMzAuMjY2IDIxLjAw +NiAxMzIuMzk1QzE5LjQwOSAxMzQuNTI1IDE2LjIxNCAxMzMuNDYgMTYuMjE0IDEzMy40NkwxNS42 +ODIgMTMwLjc5OHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBk +PSJNMjYuNDgyIDEyNi4zOThDMjYuNDgyIDEyNi4zOTggMzMuNDAzIDEyNS44NjYgMzEuODA2IDEy +Ny45OTVDMzAuMjA5IDEzMC4xMjUgMjcuMDE0IDEyOS4wNiAyNy4wMTQgMTI5LjA2TDI2LjQ4MiAx +MjYuMzk4eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0z +Ni44ODIgMTIxLjU5OEMzNi44ODIgMTIxLjU5OCA0My44MDMgMTIxLjA2NiA0Mi4yMDYgMTIzLjE5 +NUM0MC42MDkgMTI1LjMyNSAzNy40MTQgMTI0LjI2IDM3LjQxNCAxMjQuMjZMMzYuODgyIDEyMS41 +OTh6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTkuMjgy +IDEwMy41OThDOS4yODIgMTAzLjU5OCAxNi4yMDMgMTAzLjA2NiAxNC42MDYgMTA1LjE5NUMxMy4w +MDkgMTA3LjMyNSA5LjAxNCAxMDcuMDYgOS4wMTQgMTA3LjA2TDkuMjgyIDEwMy41OTh6Ii8+CiA8 +L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTE5LjI4MiAxMDAuMzk4 +QzE5LjI4MiAxMDAuMzk4IDI2LjIwMyA5OS44NjYgMjQuNjA2IDEwMS45OTVDMjMuMDA5IDEwNC4x +MjUgMTguNjE0IDEwMy44NiAxOC42MTQgMTAzLjg2TDE5LjI4MiAxMDAuMzk4eiIvPgogPC9nPgog +PGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMy40IDE0MC40MDFDLTMuNCAx +NDAuNDAxIDEuOCAxNDAuMDAxIDAuNiAxNDEuNjAxQy0wLjYgMTQzLjIwMSAtMyAxNDIuNDAxIC0z +IDE0Mi40MDFMLTMuNCAxNDAuNDAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICM5OTI2MDAi +PgogIDxwYXRoIGQ9Ik0tNzYuNiA0MS4yQy03Ni42IDQxLjIgLTgxIDUwIC04MS40IDUzLjJDLTgx +LjQgNTMuMiAtODAuNiA0NC40IC03OS40IDQyLjRDLTc4LjIgNDAuNCAtNzYuNiA0MS4yIC03Ni42 +IDQxLjJ6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzk5MjYwMCI+CiAgPHBhdGggZD0iTS05 +NSA1NS4yQy05NSA1NS4yIC05OC4yIDY5LjYgLTk3LjggNzIuNEMtOTcuOCA3Mi40IC05OSA2MC44 +IC05OC42IDU5LjZDLTk4LjIgNTguNCAtOTUgNTUuMiAtOTUgNTUuMnoiLz4KIDwvZz4KIDxnIHN0 +eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNLTc0LjIgLTE5LjRMLTc0LjQgLTE2LjJM +LTc2LjYgLTE2Qy03Ni42IC0xNiAtNjIuNCAtMy40IC02MS44IDQuMkMtNjEuOCA0LjIgLTYxIC00 +IC03NC4yIC0xOS40eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRo +IGQ9Ik0tNzAuMjE2IC0xOC4xMzVDLTcwLjY0NyAtMTguNTUxIC03MC40MjggLTE5LjI5NiAtNzAu +ODM2IC0xOS41NTZDLTcxLjY0NSAtMjAuMDcyIC02OS41MzggLTIwLjEyOSAtNjkuNzY2IC0yMC44 +NDVDLTcwLjE0OSAtMjIuMDUxIC02OS45NjIgLTIyLjA3MiAtNzAuMDg0IC0yMy4zNDhDLTcwLjE0 +MSAtMjMuOTQ2IC02OS41NTMgLTI1LjQ4NiAtNjkuMTY4IC0yNS45MjZDLTY3LjcyMiAtMjcuNTc4 +IC02OS4wNDYgLTMwLjUxIC02Ny40MDYgLTMyLjA2MUMtNjcuMTAyIC0zMi4zNSAtNjYuNzI2IC0z +Mi45MDIgLTY2LjQ0MSAtMzMuMzJDLTY1Ljc4MiAtMzQuMjgzIC02NC41OTggLTM0Ljc3MSAtNjMu +NjQ4IC0zNS41OTlDLTYzLjMzIC0zNS44NzUgLTYzLjUzMSAtMzYuNzAyIC02Mi45NjIgLTM2LjYx +Qy02Mi4yNDggLTM2LjQ5NSAtNjEuMDA3IC0zNi42MjUgLTYxLjA1MiAtMzUuNzg0Qy02MS4xNjUg +LTMzLjY2NCAtNjIuNDk0IC0zMS45NDQgLTYzLjc3NCAtMzAuMjc2Qy02My4zMjMgLTI5LjU3MiAt +NjMuNzgxIC0yOC45MzcgLTY0LjA2NSAtMjguMzhDLTY1LjQgLTI1Ljc2IC02NS4yMTEgLTIyLjkx +OSAtNjUuMzg1IC0yMC4wNzlDLTY1LjM5IC0xOS45OTQgLTY1LjY5NyAtMTkuOTE2IC02NS42ODkg +LTE5Ljg2M0MtNjUuMzM2IC0xNy41MjggLTY0Ljc1MiAtMTUuMzI5IC02My44NzMgLTEzLjFDLTYz +LjUwNyAtMTIuMTcgLTYzLjAzNiAtMTEuMjc1IC02Mi44ODYgLTEwLjM0OEMtNjIuNzc1IC05LjY2 +MiAtNjIuNjcyIC04LjgyOSAtNjMuMDggLTguMTI0Qy02MS4wNDUgLTUuMjM0IC02Mi4zNTQgLTIu +NTgzIC02MS4xODUgMC45NDhDLTYwLjk3OCAxLjU3MyAtNTkuMjg2IDMuNDg3IC01OS43NDkgMy4z +MjZDLTYyLjI2MiAyLjQ1NSAtNjIuMzc0IDIuMDU3IC02Mi41NTEgMS4zMDRDLTYyLjY5NyAwLjY4 +MSAtNjMuMDI3IC0wLjY5NiAtNjMuMjY0IC0xLjI5OEMtNjMuMzI4IC0xLjQ2MiAtNjMuNDk5IC0z +LjM0NiAtNjMuNTc3IC0zLjQ2OEMtNjUuMDkgLTUuODUgLTYzLjczMiAtNS42NzQgLTY1LjEwMiAt +OC4wMzJDLTY2LjUzIC04LjcxMiAtNjcuNDk2IC05LjgxNiAtNjguNjE5IC0xMC45NzhDLTY4Ljgx +NyAtMTEuMTgyIC02Ny42NzQgLTExLjkwNiAtNjcuODU1IC0xMi4xMTlDLTY4Ljk0NyAtMTMuNDA4 +IC03MC4xIC0xNC4xNzUgLTY5Ljc2NCAtMTUuNjY4Qy02OS42MDkgLTE2LjM1OCAtNjkuNDcyIC0x +Ny40MTUgLTcwLjIxNiAtMTguMTM1eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAi +PgogIDxwYXRoIGQ9Ik0tNzMuOCAtMTYuNEMtNzMuOCAtMTYuNCAtNzMuNCAtOS42IC03MSAtOEMt +NjguNiAtNi40IC02OS44IC03LjIgLTczIC04LjRDLTc2LjIgLTkuNiAtNzUgLTEwLjQgLTc1IC0x +MC40Qy03NSAtMTAuNCAtNzcuOCAtMTAgLTc1LjQgLThDLTczIC02IC02OS40IC0zLjYgLTcxIC0z +LjZDLTcyLjYgLTMuNiAtODAuMiAtNy42IC04MC4yIC0xMC40Qy04MC4yIC0xMy4yIC04MS4yIC0x +Ny4zIC04MS4yIC0xNy4zQy04MS4yIC0xNy4zIC04MC4xIC0xOC4xIC03NS4zIC0xOEMtNzUuMyAt +MTggLTczLjkgLTE3LjMgLTczLjggLTE2LjR6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2Zm +ZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0tNzQu +NiAyLjJDLTc0LjYgMi4yIC04My4xMiAtMC41OTEgLTEwMS42IDIuOEMtMTAxLjYgMi44IC05Mi41 +NjkgMC43MjIgLTczLjggM0MtNjMuNSA0LjI1IC03NC42IDIuMiAtNzQuNiAyLjJ6Ii8+CiA8L2c+ +CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDow +LjEiPgogIDxwYXRoIGQ9Ik0tNzIuNTAyIDIuMTI5Qy03Mi41MDIgMi4xMjkgLTgwLjc0OCAtMS4z +ODkgLTk5LjQ1MyAwLjM5MkMtOTkuNDUzIDAuMzkyIC05MC4yNzUgLTAuODk3IC03MS43NzQgMi45 +OTVDLTYxLjYyIDUuMTMxIC03Mi41MDIgMi4xMjkgLTcyLjUwMiAyLjEyOXoiLz4KIDwvZz4KIDxn +IHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+ +CiAgPHBhdGggZD0iTS03MC43MTQgMi4yMjJDLTcwLjcxNCAyLjIyMiAtNzguNjc2IC0xLjg5OSAt +OTcuNDYxIC0xLjUxNEMtOTcuNDYxIC0xLjUxNCAtODguMjEzIC0yLjExOCAtNzAuMDUyIDMuMTRD +LTYwLjA4NiA2LjAyNSAtNzAuNzE0IDIuMjIyIC03MC43MTQgMi4yMjJ6Ii8+CiA8L2c+CiA8ZyBz +dHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgog +IDxwYXRoIGQ9Ik0tNjkuNDQ0IDIuNDQ1Qy02OS40NDQgMi40NDUgLTc2LjI2OCAtMS44NjIgLTkz +LjE0MiAtMi45NkMtOTMuMTQyIC0yLjk2IC04NC44MDMgLTIuNzkgLTY4LjkyMiAzLjMxOUMtNjAu +MjA2IDYuNjcyIC02OS40NDQgMi40NDUgLTY5LjQ0NCAyLjQ0NXoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBh +dGggZD0iTTQ1Ljg0IDEyLjk2MUM0NS44NCAxMi45NjEgNDQuOTEgMTMuNjA1IDQ1LjEyNCAxMi40 +MjRDNDUuMzM5IDExLjI0MyA3My41NDcgLTEuOTI3IDc3LjE2MSAtMS42NzdDNzcuMTYxIC0xLjY3 +NyA0Ni45MTMgMTEuNTI5IDQ1Ljg0IDEyLjk2MXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +ZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTQy +LjQ0NiAxMy42QzQyLjQ0NiAxMy42IDQxLjU3IDE0LjMxNSA0MS42OTEgMTMuMTIxQzQxLjgxMiAx +MS45MjcgNjguODk5IC0zLjQxOCA3Mi41MjEgLTMuNDUyQzcyLjUyMSAtMy40NTIgNDMuNDA0IDEy +LjA4OSA0Mi40NDYgMTMuNnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJv +a2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTM5LjE2IDE0Ljk3NUMz +OS4xNiAxNC45NzUgMzguMzMyIDE1Ljc0NyAzOC4zNzQgMTQuNTQ3QzM4LjQxNiAxMy4zNDggNTgu +MjMzIC0yLjE0OSA2OC4wNDUgLTQuMDIzQzY4LjA0NSAtNC4wMjMgNTAuMDE1IDQuMTA0IDM5LjE2 +IDE0Ljk3NXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAw +MDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTM2LjI4NCAxNi44MzhDMzYuMjg0IDE2 +LjgzOCAzNS41MzkgMTcuNTMyIDM1LjU3NyAxNi40NTNDMzUuNjE1IDE1LjM3MyA1My40NDkgMS40 +MjYgNjIuMjggLTAuMjZDNjIuMjggLTAuMjYgNDYuMDU0IDcuMDU0IDM2LjI4NCAxNi44Mzh6Ii8+ +CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGggZD0iTTQuNiAxNjQuODAx +QzQuNiAxNjQuODAxIC0xMC42IDE2Mi40MDEgNi4yIDE2MC44MDFDNi4yIDE2MC44MDEgMjQuMiAx +NTguODAxIDI4LjIgMTUzLjYwMUMyOC4yIDE1My42MDEgNDEuOCAxNDQuNDAxIDQ0LjYgMTQ0LjAw +MUM0Ny40IDE0My42MDEgNjMuOCAxNDAuMDAxIDY0LjIgMTM3LjYwMUM2NC42IDEzNS4yMDEgNzAu +NiAxMzIuODAxIDcyLjIgMTMzLjYwMUM3My44IDEzNC40MDEgNzMuOCAxNDMuNjAxIDcxIDE0NC40 +MDFDNjguMiAxNDUuMjAxIDQ5LjQgMTUyLjQwMSA0MyAxNTMuNjAxQzM2LjYgMTU0LjgwMSAyNSAx +NjIuNDAxIDIwLjIgMTYzLjYwMUMxNS40IDE2NC44MDEgNC42IDE2NC44MDEgNC42IDE2NC44MDF6 +Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTc3LjYgMTI3 +LjQwMUM3Ny42IDEyNy40MDEgNzQuNiAxMjkuMDAxIDczLjQgMTMxLjYwMUM3My40IDEzMS42MDEg +NjcgMTQyLjIwMSA1Mi44IDE0NS40MDFDNTIuOCAxNDUuNDAxIDI5LjggMTU0LjQwMSAyMiAxNTYu +NDAxQzIyIDE1Ni40MDEgOC42IDE2MS40MDEgMS4yIDE2MC42MDFDMS4yIDE2MC42MDEgLTUuOCAx +NjAuODAxIDAuNCAxNjIuNDAxQzAuNCAxNjIuNDAxIDIwLjYgMTYwLjQwMSAyNCAxNTguNjAxQzI0 +IDE1OC42MDEgMzkuNiAxNTMuNDAxIDQyLjYgMTUwLjgwMUM0NS42IDE0OC4yMDEgNjMuOCAxNDMu +MjAxIDY2IDE0MS4yMDFDNjguMiAxMzkuMjAxIDc4IDEzMC44MDEgNzcuNiAxMjcuNDAxeiIvPgog +PC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0xOC44ODIgMTU4Ljkx +MUMxOC44ODIgMTU4LjkxMSAyNC4xMTEgMTU4LjY4NSAyMi45NTggMTYwLjIzNEMyMS44MDUgMTYx +Ljc4NCAxOS4zNTcgMTYwLjkxIDE5LjM1NyAxNjAuOTFMMTguODgyIDE1OC45MTF6Ii8+CiA8L2c+ +CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTTExLjY4IDE2MC4yNjNDMTEu +NjggMTYwLjI2MyAxNi45MDggMTYwLjAzNyAxNS43NTYgMTYxLjU4NkMxNC42MDMgMTYzLjEzNiAx +Mi4xNTUgMTYyLjI2MyAxMi4xNTUgMTYyLjI2M0wxMS42OCAxNjAuMjYzeiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0xLjI1MSAxNjEuNTExQzEuMjUxIDE2 +MS41MTEgNi40OCAxNjEuMjg0IDUuMzI3IDE2Mi44MzRDNC4xNzQgMTY0LjM4MyAxLjcyNiAxNjMu +NTEgMS43MjYgMTYzLjUxTDEuMjUxIDE2MS41MTF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDog +IzAwMDAwMCI+CiAgPHBhdGggZD0iTS02LjM4MyAxNjIuMDU1Qy02LjM4MyAxNjIuMDU1IC0xLjE1 +NCAxNjEuODI5IC0yLjMwNyAxNjMuMzc4Qy0zLjQ2IDE2NC45MjggLTUuOTA4IDE2NC4wNTQgLTUu +OTA4IDE2NC4wNTRMLTYuMzgzIDE2Mi4wNTV6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAw +MDAwMCI+CiAgPHBhdGggZD0iTTM1LjQxNSAxNTEuNTEzQzM1LjQxNSAxNTEuNTEzIDQyLjM3NSAx +NTEuMjEyIDQwLjg0IDE1My4yNzRDMzkuMzA2IDE1NS4zMzYgMzYuMDQ3IDE1NC4xNzQgMzYuMDQ3 +IDE1NC4xNzRMMzUuNDE1IDE1MS41MTN6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAw +MCI+CiAgPHBhdGggZD0iTTQ1LjczIDE0Ny4wODhDNDUuNzMgMTQ3LjA4OCA1MS42ODkgMTQzLjc4 +NyA1MS4xNTUgMTQ4Ljg0OUM1MC44ODUgMTUxLjQwNSA0Ni4zNjIgMTQ5Ljc0OSA0Ni4zNjIgMTQ5 +Ljc0OUw0NS43MyAxNDcuMDg4eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgog +IDxwYXRoIGQ9Ik01NC44NjIgMTQ0LjI3NEM1NC44NjIgMTQ0LjI3NCA2Mi4wMjEgMTQwLjU3MyA2 +MC4yODcgMTQ2LjAzNUM1OS41MDkgMTQ4LjQ4NSA1NS40OTMgMTQ2LjkzNSA1NS40OTMgMTQ2Ljkz +NUw1NC44NjIgMTQ0LjI3NHoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8 +cGF0aCBkPSJNNjQuMzc2IDEzOS40NDlDNjQuMzc2IDEzOS40NDkgNjguNzM1IDEzNC41NDggNjku +ODAxIDE0MS4yMUM3MC4yMDcgMTQzLjc0OCA2NS4wMDggMTQyLjExIDY1LjAwOCAxNDIuMTFMNjQu +Mzc2IDEzOS40NDl6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGgg +ZD0iTTI2LjgzNCAxNTUuOTk3QzI2LjgzNCAxNTUuOTk3IDMyLjA2MiAxNTUuNzcgMzAuOTEgMTU3 +LjMyQzI5Ljc1NyAxNTguODY5IDI3LjMwOCAxNTcuOTk2IDI3LjMwOCAxNTcuOTk2TDI2LjgzNCAx +NTUuOTk3eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAwMDAw +OyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNNjIuNDM0IDM0LjYwM0M2Mi40MzQgMzQu +NjAzIDYxLjcwOCAzNS4yNjggNjEuNzA3IDM0LjE5N0M2MS43MDcgMzMuMTI3IDc5LjE5MSAxOS44 +NjMgODguMDM0IDE4LjQ3OUM4OC4wMzQgMTguNDc5IDcxLjkzNSAyNS4yMDggNjIuNDM0IDM0LjYw +M3oiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNNjUuNCA5 +OC40QzY1LjQgOTguNCA4Ny40MDEgMTIwLjgwMSA5Ni42MDEgMTI0LjQwMUM5Ni42MDEgMTI0LjQw +MSAxMDUuODAxIDEzNS42MDEgMTAxLjgwMSAxNjEuNjAxQzEwMS44MDEgMTYxLjYwMSA5OC42MDEg +MTY5LjIwMSA5NS40MDEgMTQ4LjQwMUM5NS40MDEgMTQ4LjQwMSA5OC42MDEgMTIzLjIwMSA4Ny40 +MDEgMTM5LjIwMUM4Ny40MDEgMTM5LjIwMSA3OSAxMjkuMzAxIDg1LjQgMTI5LjYwMUM4NS40IDEy +OS42MDEgODguNjAxIDEzMS42MDEgODkuMDAxIDEzMC4wMDFDODkuNDAxIDEyOC40MDEgODEuNCAx +MTQuODAxIDY0LjIgMTAwLjRDNDcgODYgNjUuNCA5OC40IDY1LjQgOTguNHoiLz4KIDwvZz4KIDxn +IHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+ +CiAgPHBhdGggZD0iTTcgMTM3LjIwMUM3IDEzNy4yMDEgNi44IDEzNS40MDEgOC42IDEzNi4yMDFD +MTAuNCAxMzcuMDAxIDEwNC42MDEgMTQzLjIwMSAxMzYuMjAxIDE2Ny4yMDFDMTM2LjIwMSAxNjcu +MjAxIDkxLjAwMSAxNDQuMDAxIDcgMTM3LjIwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAj +ZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTE3 +LjQgMTMyLjgwMUMxNy40IDEzMi44MDEgMTcuMiAxMzEuMDAxIDE5IDEzMS44MDFDMjAuOCAxMzIu +NjAxIDE1Ny40MDEgMTMxLjYwMSAxODEuMDAxIDE2NC4wMDFDMTgxLjAwMSAxNjQuMDAxIDE1OS4w +MDEgMTM4LjgwMSAxNy40IDEzMi44MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZm +Zjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0yOSAxMjgu +ODAxQzI5IDEyOC44MDEgMjguOCAxMjcuMDAxIDMwLjYgMTI3LjgwMUMzMi40IDEyOC42MDEgMjA1 +LjgwMSAxMTUuNjAxIDIyOS40MDEgMTQ4LjAwMUMyMjkuNDAxIDE0OC4wMDEgMjE5LjgwMSAxMjIu +NDAxIDI5IDEyOC44MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tl +OiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0zOSAxMjQuMDAxQzM5IDEy +NC4wMDEgMzguOCAxMjIuMjAxIDQwLjYgMTIzLjAwMUM0Mi40IDEyMy44MDEgMTY0LjYwMSA4NS4y +IDE4OC4yMDEgMTE3LjYwMUMxODguMjAxIDExNy42MDEgMTc0LjgwMSA5MyAzOSAxMjQuMDAxeiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Ut +d2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNLTE5IDE0Ni44MDFDLTE5IDE0Ni44MDEgLTE5LjIgMTQ1 +LjAwMSAtMTcuNCAxNDUuODAxQy0xNS42IDE0Ni42MDEgMi4yIDE0OC44MDEgNC4yIDE4Ny42MDFD +NC4yIDE4Ny42MDEgLTMgMTQ1LjYwMSAtMTkgMTQ2LjgwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJm +aWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGgg +ZD0iTS0yNy44IDE0OC40MDFDLTI3LjggMTQ4LjQwMSAtMjggMTQ2LjYwMSAtMjYuMiAxNDcuNDAx +Qy0yNC40IDE0OC4yMDEgLTEwLjIgMTQzLjYwMSAtMTMgMTgyLjQwMUMtMTMgMTgyLjQwMSAtMTEu +OCAxNDcuMjAxIC0yNy44IDE0OC40MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZm +Zjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0tMzUuOCAx +NDguODAxQy0zNS44IDE0OC44MDEgLTM2IDE0Ny4wMDEgLTM0LjIgMTQ3LjgwMUMtMzIuNCAxNDgu +NjAxIC0xNyAxNDkuMjAxIC0yOS40IDE3MS42MDFDLTI5LjQgMTcxLjYwMSAtMTkuOCAxNDcuNjAx +IC0zNS44IDE0OC44MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tl +OiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0xMS41MjYgMTA0LjQ2NUMx +MS41MjYgMTA0LjQ2NSAxMS4wODIgMTA2LjQ2NCAxMi42MzEgMTA1LjI0N0MyOC42OTkgOTIuNjIy +IDYxLjE0MSAzMy43MiAxMTYuODI2IDI4LjA4NkMxMTYuODI2IDI4LjA4NiA3OC41MTggMTUuOTc2 +IDExLjUyNiAxMDQuNDY1eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9r +ZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNMjIuNzI2IDEwMi42NjVD +MjIuNzI2IDEwMi42NjUgMjEuMzYzIDEwMS40NzIgMjMuMjMxIDEwMC44NDdDMjUuMDk5IDEwMC4y +MjIgMTM3LjU0MSAyNy43MiAxNzYuODI2IDM1LjY4NkMxNzYuODI2IDM1LjY4NiAxNDkuNzE5IDI4 +LjE3NiAyMi43MjYgMTAyLjY2NXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBz +dHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTEuODg1IDEwOC43 +NjdDMS44ODUgMTA4Ljc2NyAxLjM3NiAxMTAuMzY2IDMuMDg3IDEwOS4zOUMxMi4wNjIgMTA0LjI3 +IDE1LjY3NyA0Ny4wNTkgNTkuMjU0IDQ1LjgwNEM1OS4yNTQgNDUuODA0IDI2Ljg0MyAzMS4wOSAx +Ljg4NSAxMDguNzY3eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZToj +MDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNLTE4LjAzOCAxMTkuNzkzQy0x +OC4wMzggMTE5Ljc5MyAtMTkuMTE1IDEyMS4wNzkgLTE3LjE2MiAxMjAuODI1Qy02LjkxNiAxMTku +NDkzIDE0LjQ4OSA3OC4yMjIgNTguOTI4IDgzLjMwMUM1OC45MjggODMuMzAxIDI2Ljk2MiA2OC45 +NTUgLTE4LjAzOCAxMTkuNzkzeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0 +cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNLTYuOCAxMTMuNjY3 +Qy02LjggMTEzLjY2NyAtNy42MTEgMTE1LjEzNiAtNS43NDIgMTE0LjUxMUM0LjA1NyAxMTEuMjM3 +IDE3LjE0MSA2Ni42MjUgNjEuNzI5IDYzLjA3OEM2MS43MjkgNjMuMDc4IDI3LjYwMyA1NS4xMzUg +LTYuOCAxMTMuNjY3eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZToj +MDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNLTI1LjA3OCAxMjQuOTEyQy0y +NS4wNzggMTI0LjkxMiAtMjUuOTUxIDEyNS45NTQgLTI0LjM2OSAxMjUuNzQ4Qy0xNi4wNyAxMjQu +NjY5IDEuMjY4IDkxLjI0IDM3LjI2NCA5NS4zNTRDMzcuMjY0IDk1LjM1NCAxMS4zNzEgODMuNzM0 +IC0yNS4wNzggMTI0LjkxMnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJv +a2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTS0zMi42NzcgMTMwLjgy +MUMtMzIuNjc3IDEzMC44MjEgLTMzLjY4MiAxMzEuODY2IC0zMi4wOTEgMTMxLjc0OEMtMjcuOTIz +IDEzMS40MzkgMi43MTUgOTguMzYgMjEuMTgzIDExMy44NjJDMjEuMTgzIDExMy44NjIgOS4xNjgg +OTUuMTM5IC0zMi42NzcgMTMwLjgyMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZm +OyBzdHJva2U6IzAwMDAwMDsgc3Ryb2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTM2Ljg1NSA5 +OC44OThDMzYuODU1IDk4Ljg5OCAzNS42NTQgOTcuNTQzIDM3LjU4NiA5Ny4xNThDMzkuNTE4IDk2 +Ljc3NCAxNjAuMjIxIDM5LjA2MSAxOTguMTg0IDUxLjkyN0MxOTguMTg0IDUxLjkyNyAxNzIuMjQz +IDQxLjA1MyAzNi44NTUgOTguODk4eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7 +IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNMy40IDE2My4y +MDFDMy40IDE2My4yMDEgMy4yIDE2MS40MDEgNSAxNjIuMjAxQzYuOCAxNjMuMDAxIDIyLjIgMTYz +LjYwMSA5LjggMTg2LjAwMUM5LjggMTg2LjAwMSAxOS40IDE2Mi4wMDEgMy40IDE2My4yMDF6Ii8+ +CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13 +aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0xMy44IDE2MS42MDFDMTMuOCAxNjEuNjAxIDEzLjYgMTU5 +LjgwMSAxNS40IDE2MC42MDFDMTcuMiAxNjEuNDAxIDM1IDE2My42MDEgMzcgMjAyLjQwMUMzNyAy +MDIuNDAxIDI5LjggMTYwLjQwMSAxMy44IDE2MS42MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmls +bDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9 +Ik0yMC42IDE2MC4wMDFDMjAuNiAxNjAuMDAxIDIwLjQgMTU4LjIwMSAyMi4yIDE1OS4wMDFDMjQg +MTU5LjgwMSA0OC42IDE2My4yMDEgNzIuMiAxOTUuNjAxQzcyLjIgMTk1LjYwMSAzNi42IDE1OC44 +MDEgMjAuNiAxNjAuMDAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9r +ZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNMjguMjI1IDE1Ny45NzJD +MjguMjI1IDE1Ny45NzIgMjcuNzg4IDE1Ni4yMTQgMjkuNjc4IDE1Ni43NjhDMzEuNTY4IDE1Ny4z +MjIgNTIuMDAyIDE1NS40MjMgOTAuMDk5IDE4OS41OTlDOTAuMDk5IDE4OS41OTkgNDMuOTI0IDE1 +NC42NTYgMjguMjI1IDE1Ny45NzJ6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsg +c3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik0zOC42MjUgMTUz +LjU3MkMzOC42MjUgMTUzLjU3MiAzOC4xODggMTUxLjgxNCA0MC4wNzggMTUyLjM2OEM0MS45Njgg +MTUyLjkyMiA3Ni44MDIgMTU3LjQyMyAxMjguNDk5IDE5Mi4zOTlDMTI4LjQ5OSAxOTIuMzk5IDU0 +LjMyNCAxNTAuMjU2IDM4LjYyNSAxNTMuNTcyeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNm +ZmZmZmY7IHN0cm9rZTojMDAwMDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNLTEu +OCAxNDIuMDAxQy0xLjggMTQyLjAwMSAtMiAxNDAuMjAxIC0wLjIgMTQxLjAwMUMxLjYgMTQxLjgw +MSA1NSAxNDQuNDAxIDg1LjQgMTcxLjIwMUM4NS40IDE3MS4yMDEgNTAuNDk5IDE0Ni40MjYgLTEu +OCAxNDIuMDAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAw +MDAwOyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNLTExLjggMTQ2LjAwMUMtMTEuOCAx +NDYuMDAxIC0xMiAxNDQuMjAxIC0xMC4yIDE0NS4wMDFDLTguNCAxNDUuODAxIDE2LjIgMTQ5LjIw +MSAzOS44IDE4MS42MDFDMzkuOCAxODEuNjAxIDQuMiAxNDQuODAxIC0xMS44IDE0Ni4wMDF6Ii8+ +CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2ZmZmZmZjsgc3Ryb2tlOiMwMDAwMDA7IHN0cm9rZS13 +aWR0aDowLjEiPgogIDxwYXRoIGQ9Ik00OS41MDMgMTQ4Ljk2MkM0OS41MDMgMTQ4Ljk2MiA0OC45 +MzggMTQ3LjI0MSA1MC44NjQgMTQ3LjY1NUM1Mi43OSAxNDguMDY4IDg3Ljg2IDE1MC4wMDQgMTQx +Ljk4MSAxODEuMDk4QzE0MS45ODEgMTgxLjA5OCA2NC4zMTcgMTQ2LjcwNCA0OS41MDMgMTQ4Ljk2 +MnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjZmZmZmZmOyBzdHJva2U6IzAwMDAwMDsgc3Ry +b2tlLXdpZHRoOjAuMSI+CiAgPHBhdGggZD0iTTU3LjkwMyAxNDYuNTYyQzU3LjkwMyAxNDYuNTYy +IDU3LjMzOCAxNDQuODQxIDU5LjI2NCAxNDUuMjU1QzYxLjE5IDE0NS42NjggOTYuMjYgMTQ3LjYw +NCAxNTAuMzgxIDE3OC42OThDMTUwLjM4MSAxNzguNjk4IDczLjMxNyAxNDMuOTA0IDU3LjkwMyAx +NDYuNTYyeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNmZmZmZmY7IHN0cm9rZTojMDAwMDAw +OyBzdHJva2Utd2lkdGg6MC4xIj4KICA8cGF0aCBkPSJNNjcuNTAzIDE0MS41NjJDNjcuNTAzIDE0 +MS41NjIgNjYuOTM4IDEzOS44NDEgNjguODY0IDE0MC4yNTVDNzAuNzkgMTQwLjY2OCAxMTMuODYg +MTQ1LjAwNCAyMDMuNTgyIDE3OS4yOThDMjAzLjU4MiAxNzkuMjk4IDgyLjkxNyAxMzguOTA0IDY3 +LjUwMyAxNDEuNTYyeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRo +IGQ9Ik0tNDMuOCAxNDguNDAxQy00My44IDE0OC40MDEgLTM4LjYgMTQ4LjAwMSAtMzkuOCAxNDku +NjAxQy00MSAxNTEuMjAxIC00My40IDE1MC40MDEgLTQzLjQgMTUwLjQwMUwtNDMuOCAxNDguNDAx +eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMTMgMTYy +LjQwMUMtMTMgMTYyLjQwMSAtNy44IDE2Mi4wMDEgLTkgMTYzLjYwMUMtMTAuMiAxNjUuMjAxIC0x +Mi42IDE2NC40MDEgLTEyLjYgMTY0LjQwMUwtMTMgMTYyLjQwMXoiLz4KIDwvZz4KIDxnIHN0eWxl +PSJmaWxsOiAjMDAwMDAwIj4KICA8cGF0aCBkPSJNLTIxLjggMTYyLjAwMUMtMjEuOCAxNjIuMDAx +IC0xNi42IDE2MS42MDEgLTE3LjggMTYzLjIwMUMtMTkgMTY0LjgwMSAtMjEuNCAxNjQuMDAxIC0y +MS40IDE2NC4wMDFMLTIxLjggMTYyLjAwMXoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjMDAw +MDAwIj4KICA8cGF0aCBkPSJNLTExNy4xNjkgMTUwLjE4MkMtMTE3LjE2OSAxNTAuMTgyIC0xMTIu +MTI0IDE1MS41MDUgLTExMy43ODIgMTUyLjYyNEMtMTE1LjQzOSAxNTMuNzQ0IC0xMTcuNDQ2IDE1 +Mi4yMDIgLTExNy40NDYgMTUyLjIwMkwtMTE3LjE2OSAxNTAuMTgyeiIvPgogPC9nPgogPGcgc3R5 +bGU9ImZpbGw6ICMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMTE1LjE2OSAxNDAuNTgyQy0xMTUuMTY5 +IDE0MC41ODIgLTExMC4xMjQgMTQxLjkwNSAtMTExLjc4MiAxNDMuMDI0Qy0xMTMuNDM5IDE0NC4x +NDQgLTExNS40NDYgMTQyLjYwMiAtMTE1LjQ0NiAxNDIuNjAyTC0xMTUuMTY5IDE0MC41ODJ6Ii8+ +CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogIzAwMDAwMCI+CiAgPHBhdGggZD0iTS0xMjIuMzY5IDEz +Ni4xODJDLTEyMi4zNjkgMTM2LjE4MiAtMTE3LjMyNCAxMzcuNTA1IC0xMTguOTgyIDEzOC42MjRD +LTEyMC42MzkgMTM5Ljc0NCAtMTIyLjY0NiAxMzguMjAyIC0xMjIuNjQ2IDEzOC4yMDJMLTEyMi4z +NjkgMTM2LjE4MnoiLz4KIDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBk +PSJNLTQyLjYgMjExLjIwMUMtNDIuNiAyMTEuMjAxIC00NC4yIDIxMS4yMDEgLTQ4LjIgMjEzLjIw +MUMtNTAuMiAyMTMuMjAxIC02MS40IDIxNi44MDEgLTY3IDIyNi44MDFDLTY3IDIyNi44MDEgLTU0 +LjYgMjE3LjIwMSAtNDIuNiAyMTEuMjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2Nj +Y2MiPgogIDxwYXRoIGQ9Ik00NS4xMTYgMzAzLjg0N0M0NS4yNTcgMzA0LjEwNSA0NS4zMTIgMzA0 +LjUyNSA0NS42MDQgMzA0LjU0MkM0Ni4yNjIgMzA0LjU4MiA0Ny40OTUgMzA0Ljg4MyA0Ny4zNyAz +MDQuMjQ3QzQ2LjUyMiAyOTkuOTQxIDQ1LjY0OCAyOTUuMDA0IDQxLjUxNSAyOTMuMTk3QzQwLjg3 +NiAyOTIuOTE4IDM5LjQzNCAyOTMuMzMxIDM5LjM2IDI5NC4yMTVDMzkuMjMzIDI5NS43MzkgMzku +MTE2IDI5Ny4wODggMzkuNDI1IDI5OC41NTRDMzkuNzI1IDI5OS45NzUgNDEuODgzIDI5OS45ODUg +NDIuOCAyOTguNjAxQzQzLjczNiAzMDAuMjczIDQ0LjE2OCAzMDIuMTE2IDQ1LjExNiAzMDMuODQ3 +eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0zNC4wMzgg +MzA4LjU4MUMzNC43ODYgMzA5Ljk5NCAzNC42NTkgMzExLjg1MyAzNi4wNzQgMzEyLjQxNkMzNi44 +MTQgMzEyLjcxIDM4LjY2NCAzMTEuNzM1IDM4LjI0NiAzMTAuNjYxQzM3LjQ0NCAzMDguNiAzNy4w +NTYgMzA2LjM2MSAzNS42NjcgMzA0LjU1QzM1LjQ2NyAzMDQuMjg4IDM1LjcwNyAzMDMuNzU1IDM1 +LjU0NyAzMDMuNDI3QzM0Ljk1MyAzMDIuMjA3IDMzLjgwOCAzMDEuNDcyIDMyLjQgMzAxLjgwMUMz +MS4yODUgMzA0LjAwNCAzMi40MzMgMzA2LjEzMyAzMy45NTUgMzA3Ljg0MkMzNC4wOTEgMzA3Ljk5 +NCAzMy45MjUgMzA4LjM3IDM0LjAzOCAzMDguNTgxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6 +ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tNS41NjQgMzAzLjM5MUMtNS42NzIgMzAzLjAxNCAtNS43 +MSAzMDIuNTUxIC01LjU0NSAzMDIuMjNDLTUuMDE0IDMwMS4xOTcgLTQuMjIxIDMwMC4wNzUgLTQu +NTU4IDI5OS4wNTNDLTQuOTA2IDI5Ny45OTcgLTYuMDIyIDI5OC4xNzkgLTYuNjcyIDI5OC43NDhD +LTcuODA3IDI5OS43NDIgLTcuODU2IDMwMS41NjggLTguNTQ3IDMwMi45MjdDLTguNzQzIDMwMy4z +MTMgLTguNjkyIDMwMy44ODYgLTkuMTMzIDMwNC4yNzdDLTkuNjA3IDMwNC42OTggLTEwLjA0NyAz +MDYuMjIyIC05Ljk1MSAzMDYuNzkzQy05Ljg5OCAzMDcuMTA2IC0xMC4wODEgMzE3LjAxNCAtOS44 +NTkgMzE2Ljc1MUMtOS4yNCAzMTYuMDE4IC02LjE5IDMwNi4yODQgLTYuMTIxIDMwNS4zOTJDLTYu +MDY0IDMwNC42NjEgLTUuMzMyIDMwNC4xOTYgLTUuNTY0IDMwMy4zOTF6Ii8+CiA8L2c+CiA8ZyBz +dHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGggZD0iTS0zMS4yMDIgMjk2LjU5OUMtMjguNTY4 +IDI5NC4xIC0yNS43NzggMjkxLjEzOSAtMjYuMjIgMjg3LjQyN0MtMjYuMzM2IDI4Ni40NTEgLTI4 +LjExMSAyODYuOTc4IC0yOC4yOTggMjg3LjgyNEMtMjkuMSAyOTEuNDQ5IC0zMS4xMzkgMjk0LjEx +IC0zMy43MDcgMjk2LjUwMkMtMzUuOTAzIDI5OC41NDkgLTM3Ljc2NSAzMDQuODkzIC0zOCAzMDUu +NDAxQy0zNC4zMDMgMzAwLjE0NSAtMzIuMDQ2IDI5Ny4zOTkgLTMxLjIwMiAyOTYuNTk5eiIvPgog +PC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tNDQuNzc2IDI5MC42 +MzVDLTQ0LjI1MyAyOTAuMjY1IC00NC41NTUgMjg5Ljc3NCAtNDQuMzM4IDI4OS40NDJDLTQzLjM4 +NSAyODcuOTg0IC00Mi4wODQgMjg2LjczOCAtNDIuMDY2IDI4NUMtNDIuMDYzIDI4NC43MjMgLTQy +LjQ0MSAyODQuNDE0IC00Mi43NzYgMjg0LjYzOEMtNDMuMDUzIDI4NC44MjIgLTQzLjM5NSAyODQu +OTUyIC00My41MDMgMjg1LjA4MkMtNDUuNTMzIDI4Ny41MzEgLTQ2LjkzMyAyOTAuMjAyIC00OC4z +NzYgMjkzLjAxNEMtNDguNTU5IDI5My4zNzEgLTQ5LjcwMyAyOTcuODYyIC00OS4zOSAyOTcuOTcz +Qy00OS4xNTEgMjk4LjA1OCAtNDcuNDMxIDI5My44NzcgLTQ3LjIyMSAyOTMuNzYzQy00NS45NTgg +MjkzLjA3NyAtNDUuOTQ2IDI5MS40NjIgLTQ0Ljc3NiAyOTAuNjM1eiIvPgogPC9nPgogPGcgc3R5 +bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tMjguMDQzIDMxMC4xNzlDLTI3LjU5OSAz +MDkuMzEgLTI2LjAyMyAzMDguMTA4IC0yNi4xMzYgMzA3LjIxOUMtMjYuMjU0IDMwNi4yOTEgLTI1 +Ljc4NiAzMDQuODQ4IC0yNi42OTggMzA1LjUzNkMtMjcuOTU1IDMwNi40ODQgLTMxLjQwNCAzMDcu +ODMzIC0zMS42NzQgMzEzLjY0MUMtMzEuNyAzMTQuMjEyIC0yOC43MjYgMzExLjUxOSAtMjguMDQz +IDMxMC4xNzl6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGggZD0i +TS0xMy42IDI5My4wMDFDLTEzLjIgMjkyLjMzMyAtMTIuNDkyIDI5Mi44MDYgLTEyLjAzMyAyOTIu +NTQzQy0xMS4zODUgMjkyLjE3MSAtMTAuNzc0IDI5MS42MTMgLTEwLjQ4MiAyOTAuOTY0Qy05LjUx +MiAyODguODE1IC03Ljc0MyAyODYuOTk1IC03LjYgMjg0LjYwMUMtOS4wOTEgMjgzLjE5NiAtOS43 +NyAyODUuMjM2IC0xMC40IDI4Ni4yMDFDLTExLjcyMyAyODQuNTU0IC0xMi43MjIgMjg2LjQyOCAt +MTQuMDIyIDI4Ni45NDdDLTE0LjA5MiAyODYuOTc1IC0xNC4zMDUgMjg2LjYyOCAtMTQuMzggMjg2 +LjY1NUMtMTUuNTU3IDI4Ny4wOTUgLTE2LjIzNyAyODguMTc2IC0xNy4yMzUgMjg4Ljk1N0MtMTcu +NDA2IDI4OS4wOTEgLTE3LjgxMSAyODguOTExIC0xNy45NTggMjg5LjA0N0MtMTguNjEgMjg5LjY1 +IC0xOS41ODMgMjg5Ljk3NSAtMTkuODYzIDI5MC42NTdDLTIwLjk3MyAyOTMuMzY0IC0yNC4xMTMg +Mjk1LjQ1OSAtMjYgMzAzLjAwMUMtMjUuNjE5IDMwMy45MSAtMjEuNDg4IDI5Ni4zNTkgLTIxLjAw +MSAyOTUuNjYxQy0yMC4xNjUgMjk0LjQ2NSAtMjAuMDQ3IDI5Ny4zMjIgLTE4Ljc3MSAyOTYuNjU2 +Qy0xOC43MiAyOTYuNjI5IC0xOC41MzQgMjk2Ljg2NyAtMTguNCAyOTcuMDAxQy0xOC4yMDYgMjk2 +LjcyMSAtMTcuOTg4IDI5Ni40OTIgLTE3LjYgMjk2LjYwMUMtMTcuNiAyOTYuMjAxIC0xNy43MzQg +Mjk1LjY0NSAtMTcuNTMzIDI5NS40ODZDLTE2LjI5NiAyOTQuNTA5IC0xNi4zOCAyOTMuNDQxIC0x +NS42IDI5Mi4yMDFDLTE1LjE0MiAyOTIuOTkgLTE0LjA4MSAyOTIuMjcxIC0xMy42IDI5My4wMDF6 +Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGggZD0iTTQ2LjIgMzQ3 +LjQwMUM0Ni4yIDM0Ny40MDEgNTMuNiAzMjcuMDAxIDQ5LjIgMzE1LjgwMUM0OS4yIDMxNS44MDEg +NjAuNiAzMzcuNDAxIDU2IDM0OC42MDFDNTYgMzQ4LjYwMSA1NS42IDMzOC4yMDEgNTEuNiAzMzMu +MjAxQzUxLjYgMzMzLjIwMSA0Ny42IDM0Ni4wMDEgNDYuMiAzNDcuNDAxeiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0zMS40IDM0NC44MDFDMzEuNCAzNDQu +ODAxIDM2LjggMzM2LjAwMSAyOC44IDMxNy42MDFDMjguOCAzMTcuNjAxIDI4IDMzOC4wMDEgMjEu +MiAzNDkuMDAxQzIxLjIgMzQ5LjAwMSAzNS40IDMyOC44MDEgMzEuNCAzNDQuODAxeiIvPgogPC9n +PgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0yMS40IDM0Mi44MDFDMjEu +NCAzNDIuODAxIDIxLjIgMzIyLjgwMSAyMS42IDMxOS44MDFDMjEuNiAzMTkuODAxIDE3LjggMzM2 +LjQwMSA3LjYgMzQ2LjAwMUM3LjYgMzQ2LjAwMSAyMiAzMzQuMDAxIDIxLjQgMzQyLjgwMXoiLz4K +IDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNMTEuOCAzMTAuODAx +QzExLjggMzEwLjgwMSAxNy44IDMyNC40MDEgNy44IDM0Mi44MDFDNy44IDM0Mi44MDEgMTQuMiAz +MzAuNjAxIDkuNCAzMjMuNjAxQzkuNCAzMjMuNjAxIDEyIDMyMC4yMDEgMTEuOCAzMTAuODAxeiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tNy40IDM0Mi40 +MDFDLTcuNCAzNDIuNDAxIC04LjQgMzI2LjgwMSAtNi42IDMyNC42MDFDLTYuNiAzMjQuNjAxIC02 +LjQgMzE4LjIwMSAtNi44IDMxNy4yMDFDLTYuOCAzMTcuMjAxIC0yLjggMzExLjAwMSAtMi42IDMx +OC40MDFDLTIuNiAzMTguNDAxIC0xLjIgMzI2LjIwMSAxLjYgMzMwLjgwMUMxLjYgMzMwLjgwMSA1 +LjIgMzM2LjIwMSA1IDM0Mi42MDFDNSAzNDIuNjAxIC01IDMxMi40MDEgLTcuNCAzNDIuNDAxeiIv +PgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tMTEgMzE0Ljgw +MUMtMTEgMzE0LjgwMSAtMTcuNiAzMjUuNjAxIC0xOS40IDM0NC42MDFDLTE5LjQgMzQ0LjYwMSAt +MjAuOCAzMzguNDAxIC0xNyAzMjQuMDAxQy0xNyAzMjQuMDAxIC0xMi44IDMwOC42MDEgLTExIDMx +NC44MDF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+CiAgPHBhdGggZD0iTS0z +Mi44IDMzNC42MDFDLTMyLjggMzM0LjYwMSAtMjcuOCAzMjkuMjAxIC0yNi40IDMyNC4yMDFDLTI2 +LjQgMzI0LjIwMSAtMjIuOCAzMDguNDAxIC0yOS4yIDMxNy4wMDFDLTI5LjIgMzE3LjAwMSAtMjkg +MzI1LjAwMSAtMzcuMiAzMzIuNDAxQy0zNy4yIDMzMi40MDEgLTMyLjQgMzMwLjAwMSAtMzIuOCAz +MzQuNjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0t +MzguNiAzMjkuNjAxQy0zOC42IDMyOS42MDEgLTM1LjIgMzEyLjIwMSAtMzQuNCAzMTEuNDAxQy0z +NC40IDMxMS40MDEgLTMyLjYgMzA4LjAwMSAtMzUuNCAzMTEuMjAxQy0zNS40IDMxMS4yMDEgLTQ0 +LjIgMzMwLjQwMSAtNDguMiAzMzcuMDAxQy00OC4yIDMzNy4wMDEgLTQwLjIgMzI3LjgwMSAtMzgu +NiAzMjkuNjAxeiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9 +Ik0tNDQuNCAzMTMuMDAxQy00NC40IDMxMy4wMDEgLTMyLjggMjkwLjYwMSAtNTQuNiAzMTYuNDAx +Qy01NC42IDMxNi40MDEgLTQzLjYgMzA2LjYwMSAtNDQuNCAzMTMuMDAxeiIvPgogPC9nPgogPGcg +c3R5bGU9ImZpbGw6ICNjY2NjY2MiPgogIDxwYXRoIGQ9Ik0tNTkuOCAyOTguNDAxQy01OS44IDI5 +OC40MDEgLTU1IDI3OS42MDEgLTUyLjQgMjc5LjgwMUMtNTIuNCAyNzkuODAxIC00NC4yIDI3MC44 +MDEgLTUwLjggMjgxLjQwMUMtNTAuOCAyODEuNDAxIC01Ni44IDI5MS4wMDEgLTU2LjIgMzAwLjgw +MUMtNTYuMiAzMDAuODAxIC01Ni44IDI5MS4yMDEgLTU5LjggMjk4LjQwMXoiLz4KIDwvZz4KIDxn +IHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNMjcwLjUgMjg3QzI3MC41IDI4NyAy +NTguNSAyNzcgMjU2IDI3My41QzI1NiAyNzMuNSAyNjkuNSAyOTIgMjY5LjUgMjk5QzI2OS41IDI5 +OSAyNzIgMjkxLjUgMjcwLjUgMjg3eiIvPgogPC9nPgogPGcgc3R5bGU9ImZpbGw6ICNjY2NjY2Mi +PgogIDxwYXRoIGQ9Ik0yNzYgMjY1QzI3NiAyNjUgMjU1IDI1MCAyNTEuNSAyNDIuNUMyNTEuNSAy +NDIuNSAyNzggMjcyIDI3OCAyNzYuNUMyNzggMjc2LjUgMjc4LjUgMjY3LjUgMjc2IDI2NXoiLz4K +IDwvZz4KIDxnIHN0eWxlPSJmaWxsOiAjY2NjY2NjIj4KICA8cGF0aCBkPSJNMjkzIDExMUMyOTMg +MTExIDI4MSAxMDMgMjc5LjUgMTA1QzI3OS41IDEwNSAyOTAgMTExLjUgMjkyLjUgMTIwQzI5Mi41 +IDEyMCAyOTEgMTExIDI5MyAxMTF6Ii8+CiA8L2c+CiA8ZyBzdHlsZT0iZmlsbDogI2NjY2NjYyI+ +CiAgPHBhdGggZD0iTTMwMS41IDE5MS41TDI4NCAxNzkuNUMyODQgMTc5LjUgMzAzIDE5Ni41IDMw +My41IDIwMC41TDMwMS41IDE5MS41eiIvPgogPC9nPgogPGcgc3R5bGU9InN0cm9rZTojMDAwMDAw +Ij4KICA8cGF0aCBkPSJNLTg5LjI1IDE2OUwtNjcuMjUgMTczLjc1Ii8+CiA8L2c+CiA8ZyBzdHls +ZT0ic3Ryb2tlOiMwMDAwMDAiPgogIDxwYXRoIGQ9Ik0tMzkgMzMxQy0zOSAzMzEgLTM5LjUgMzI3 +LjUgLTQ4LjUgMzM4Ii8+CiA8L2c+CiA8ZyBzdHlsZT0ic3Ryb2tlOiMwMDAwMDAiPgogIDxwYXRo +IGQ9Ik0tMzMuNSAzMzZDLTMzLjUgMzM2IC0zMS41IDMyOS41IC0zOCAzMzQiLz4KIDwvZz4KIDxn +IHN0eWxlPSJzdHJva2U6IzAwMDAwMCI+CiAgPHBhdGggZD0iTTIwLjUgMzQ0LjVDMjAuNSAzNDQu +NSAyMiAzMzMuNSAxMC41IDM0Ni41Ii8+CiA8L2c+CjwvZz4KPC9zdmc+ diff --git a/tests/resources/images/tiger.svg b/tests/resources/images/tiger.svg new file mode 100644 index 0000000000..28763f2264 --- /dev/null +++ b/tests/resources/images/tiger.svg @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-chart.xsd b/tests/resources/schema/ecma-376/dml-chart.xsd new file mode 100644 index 0000000000..7c2a42d718 --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-chart.xsd @@ -0,0 +1,3858 @@ + + + + + + + + + + + + Boolean Value + + + + + + + Floating Point Value + + + + + + + Integer Value + + + + + + + Relationship Reference + + + + + + String With Encoded Characters + + + + + + + + + + Uniform Resource Identifier + + + + + + + + Extension + + + + + + + + + Numeric Value + + + + + + Index + + + + + Number Format + + + + + + + + Format Code + + + + + Point Count + + + + + Numeric Point + + + + + + + + + + Formula + + + + + Number Cache + + + + + + + + + + + Number Reference + + + + + Number Literal + + + + + + + + + + Text Value + + + + + + Index + + + + + + + + + + + + + + + Formula + + + + + String Cache + + + + + + + + + + + String Reference + + + + + Rich Text + + + + + + + + Chart Language Tag + + + + + + + Language Code + + + + + + + + String Point + + + + + + + + + + Level + + + + + + + + + + Formula + + + + + Multi Level String Cache + + + + + + + + + + + Multi Level String Reference + + + + + Number Reference + + + + + Number Literal + + + + + + String Literal + + + + + + + + + + + + + + + + Layout Target + + + + + Inner + + + + + Outer + + + + + + + + Layout Target Value + + + + + + Layout Mode + + + + + Edge + + + + + Factor + + + + + + + + Layout Mode Value + + + + + + + + Layout Target + + + + + Left Mode + + + + + Top Mode + + + + + Width Mode + + + + + Height Mode + + + + + Left + + + + + Top + + + + + Width + + + + + Height + + + + + Chart Extensibility + + + + + + + + + Manual Layout + + + + + Chart Extensibility + + + + + + + + + Chart Text + + + + + Layout + + + + + Overlay + + + + + + + Chart Extensibility + + + + + + + X Rotation + + + + + + + + + + X Rotation Value + + + + + + Height Percent + + + + + + + + + + Height Percent Value + + + + + + Y Rotation + + + + + + + + + + Y Rotation Value + + + + + + Depth Percent + + + + + + + + + + Depth Percent Value + + + + + + Perspective + + + + + + + + + + Perspective Value + + + + + + + + X Rotation + + + + + Height Percent + + + + + Y Rotation + + + + + Depth Percent + + + + + Right Angle Axes + + + + + Perspective + + + + + Chart Extensibility + + + + + + + + + Thickness + + + + + + Picture Options + + + + + Chart Extensibility + + + + + + + + + Show Horizontal Border + + + + + Show Vertical Border + + + + + Show Outline Border + + + + + Show Legend Keys + + + + + + Text Properties + + + + + Chart Extensibility + + + + + + + Gap Amount + + + + + + + + + + Gap Size Value + + + + + + Overlap + + + + + + + + + + Overlap Value + + + + + + Bubble Scale + + + + + + + + + + Bubble Scale Value + + + + + + Size Represents + + + + + Bubble Size Represents Area + + + + + Bubble Size Represents Width + + + + + + + + Size Represents Value + + + + + + First Slice Angle + + + + + + + + + + First Slice Angle Value + + + + + + Hole Size + + + + + + + + + + Hole Size Value + + + + + + Split Type + + + + + Default Split + + + + + Custom Split + + + + + Split by Percentage + + + + + Split by Position + + + + + Split by Value + + + + + + + + Split Type Value + + + + + + + + Second Pie Point + + + + + + + Second Pie Size + + + + + + + + + + Second Pie Size Value + + + + + + + Number Format Code + + + + + Linked to Source + + + + + + Label Alignment + + + + + Center + + + + + Left + + + + + Right + + + + + + + + Label Alignment Value + + + + + + Data Label Position + + + + + Best Fit + + + + + Bottom + + + + + Center + + + + + Inside Base + + + + + Inside End + + + + + Left + + + + + Outside End + + + + + Right + + + + + Top + + + + + + + + Data Label Position Value + + + + + + + + Number Format + + + + + + + Data Label Position + + + + + Show Legend Key + + + + + Show Value + + + + + Show Category Name + + + + + Show Series Name + + + + + Show Percent + + + + + Show Bubble Size + + + + + Separator + + + + + + + + + Layout + + + + + + + + + + + Index + + + + + + Delete + + + + + + + Chart Extensibility + + + + + + + + + + Show Leader Lines + + + + + Leader Lines + + + + + + + + + Data Label + + + + + + Delete + + + + + + + Chart Extensibility + + + + + + + Marker Style + + + + + Circle + + + + + Dash + + + + + Diamond + + + + + Dot + + + + + None + + + + + Picture + + + + + Plus + + + + + Square + + + + + Star + + + + + Triangle + + + + + X + + + + + + + + Marker Style Value + + + + + + Marker Size + + + + + + + + + + Marker Size Value + + + + + + + + Symbol + + + + + Size + + + + + + Chart Extensibility + + + + + + + + + Index + + + + + Invert if Negative + + + + + Marker + + + + + 3D Bubble + + + + + Explosion + + + + + + + Chart Extensibility + + + + + + + Trendline Type + + + + + Exponential + + + + + Linear + + + + + Logarithmic + + + + + Moving Average + + + + + Polynomial + + + + + Power + + + + + + + + Trendline Type Value + + + + + + Order + + + + + + + + + + Order Value + + + + + + Period + + + + + + + + + + Period Value + + + + + + + + Layout + + + + + + Number Format + + + + + + + Chart Extensibility + + + + + + + + + Trendline Name + + + + + + Trendline Type + + + + + Polynomial Trendline Order + + + + + Period + + + + + Forward + + + + + Backward + + + + + Intercept + + + + + Display R Squared Value + + + + + Display Equation + + + + + Trendline Label + + + + + Chart Extensibility + + + + + + + Error Bar Direction + + + + + X + + + + + Y + + + + + + + + Error Bar Direction Value + + + + + + Error Bar Type + + + + + Both + + + + + Minus + + + + + Plus + + + + + + + + Error Bar Type Value + + + + + + Error Value Type + + + + + Custom Error Bars + + + + + Fixed Value + + + + + Percentage + + + + + Standard Deviation + + + + + Standard Error + + + + + + + + Error Bar Type Value + + + + + + + + Error Bar Direction + + + + + Error Bar Type + + + + + Error Bar Value Type + + + + + No End Cap + + + + + Plus + + + + + Minus + + + + + Error Bar Value + + + + + + Chart Extensibility + + + + + + + + + + + + + + Gap Width + + + + + Up Bars + + + + + Down Bars + + + + + Chart Extensibility + + + + + + + + + Index + + + + + Order + + + + + Series Text + + + + + + + + + + + Marker + + + + + Data Point + + + + + Data Labels + + + + + + Error Bars + + + + + Category Axis Data + + + + + + + Chart Extensibility + + + + + + + + + + Marker + + + + + Data Point + + + + + Data Labels + + + + + + Error Bars + + + + + + + Smoothing + + + + + Chart Extensibility + + + + + + + + + + Marker + + + + + Data Point + + + + + Data Labels + + + + + Category Axis Data + + + + + + Chart Extensibility + + + + + + + + + + Invert if Negative + + + + + + Data Point + + + + + Data Labels + + + + + Trendlines + + + + + Error Bars + + + + + Category Axis Data + + + + + + Shape + + + + + Chart Extensibility + + + + + + + + + + + Data Point + + + + + Data Labels + + + + + + Error Bars + + + + + Category Axis Data + + + + + Values + + + + + Chart Extensibility + + + + + + + + + + Explosion + + + + + Data Point + + + + + Data Labels + + + + + Category Axis Data + + + + + + Chart Extensibility + + + + + + + + + + Invert if Negative + + + + + Data Point + + + + + Data Labels + + + + + + Error Bars + + + + + X Values + + + + + Y Values + + + + + Bubble Size + + + + + 3D Bubble + + + + + Chart Extensibility + + + + + + + + + + Category Axis Data + + + + + + Chart Extensibility + + + + + + + Grouping + + + + + 100% Stacked + + + + + Standard + + + + + Stacked + + + + + + + + Grouping Value + + + + + + + + + + + + + Grouping + + + + + + + Data Labels + + + + + Drop Lines + + + + + + + + + + High Low Lines + + + + + + Show Marker + + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + + Gap Depth + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + Line Chart Series + + + + + Data Labels + + + + + + High Low Lines + + + + + Up/Down Bars + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + Scatter Style + + + + + None + + + + + Line + + + + + Line with Markers + + + + + Marker + + + + + Smooth + + + + + Smooth with Markers + + + + + + + + Scatter Style Value + + + + + + + + Scatter Style + + + + + Vary Colors by Point + + + + + Scatter Chart Series + + + + + Data Labels + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + Radar Style + + + + + Standard + + + + + Marker + + + + + Filled + + + + + + + + Radar Style Value + + + + + + + + Radar Style + + + + + + Radar Chart Series + + + + + Data Labels + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + Bar Grouping + + + + + 100% Stacked + + + + + Clustered + + + + + Standard + + + + + Stacked + + + + + + + + Bar Grouping Value + + + + + + Bar Direction + + + + + Bar + + + + + Column + + + + + + + + Bar Direction Value + + + + + + Shape + + + + + Cone + + + + + Cone to Max + + + + + Box + + + + + Cylinder + + + + + Pyramid + + + + + Pyramid to Maximum + + + + + + + + Shape Value + + + + + + + + Bar Direction + + + + + Bar Grouping + + + + + + Bar Chart Series + + + + + Data Labels + + + + + + + + + + Gap Width + + + + + Overlap + + + + + Series Lines + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + + Gap Width + + + + + Gap Depth + + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + Grouping + + + + + + Area Chart Series + + + + + Data Labels + + + + + Drop Lines + + + + + + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + + Gap Depth + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + + Pie Chart Series + + + + + Data Labels + + + + + + + + + + First Slice Angle + + + + + Chart Extensibility + + + + + + + + + + Chart Extensibility + + + + + + + + + + First Slice Angle + + + + + Hole Size + + + + + Chart Extensibility + + + + + + + Pie of Pie or Bar of Pie Type + + + + + Pie + + + + + Bar + + + + + + + + Pie of Pie or Bar of Pie Type Value + + + + + + + + Pie of Pie or Bar of Pie Type + + + + + + Gap Width + + + + + Split Type + + + + + Split Position + + + + + Custom Split + + + + + Second Pie Size + + + + + + Chart Extensibility + + + + + + + + + + Bubble Chart Series + + + + + Data Labels + + + + + 3D Bubble + + + + + Bubble Scale + + + + + Show Negative Bubbles + + + + + Size Represents + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + + + + + + + Band Format + + + + + + + + + Wireframe + + + + + Surface Chart Series + + + + + Band Formats + + + + + + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + + + + Axis ID + + + + + Chart Extensibility + + + + + + + Axis Position + + + + + Bottom + + + + + Left + + + + + Right + + + + + Top + + + + + + + + Axis Position Value + + + + + + Crosses + + + + + Axis Crosses at Zero + + + + + Maximum + + + + + Minimum + + + + + + + + Crosses Value + + + + + + Cross Between + + + + + Between + + + + + Midpoint of Category + + + + + + + + Cross Between Value + + + + + + Tick Mark + + + + + Cross + + + + + Inside + + + + + None + + + + + Outside + + + + + + + + Tick Mark Value + + + + + + Tick Label Position + + + + + High + + + + + Low + + + + + Next To + + + + + None + + + + + + + + Tick Label Position Value + + + + + + Skip + + + + + + + + + Tick Skip Value + + + + + + Time Unit + + + + + Days + + + + + Months + + + + + Years + + + + + + + + Time Unit Value + + + + + + Axis Unit + + + + + + + + + Major Unit Value + + + + + + Built-In Unit + + + + + Hundreds + + + + + Thousands + + + + + Ten Thousands + + + + + Hundred Thousands + + + + + Millions + + + + + Ten Millions + + + + + Hundred Millions + + + + + Billions + + + + + Trillions + + + + + + + + Built In Unit Value + + + + + + Picture Format + + + + + Stretch + + + + + Stack + + + + + Stack and Scale + + + + + + + + Picture Format Value + + + + + + Picture Stack Unit + + + + + + + + + Picture Stack Unit + + + + + + + + Apply To Front + + + + + Apply To Sides + + + + + Apply to End + + + + + Picture Format + + + + + Picture Stack Unit + + + + + + + + + Layout + + + + + + + + + + + + + Custom Display Unit + + + + + Built in Display Unit Value + + + + + + Display Units Label + + + + + Chart Extensibility + + + + + + + Orientation + + + + + Maximum to Minimum + + + + + Minimum to Maximum + + + + + + + + Orientation Value + + + + + + Logarithmic Base + + + + + + + + + + Logarithmic Base Value + + + + + + + + Logarithmic Base + + + + + Axis Orientation + + + + + Maximum + + + + + Minimum + + + + + Chart Extensibility + + + + + + + Label Offset + + + + + + + + + + Label Offset Value + + + + + + + + Axis ID + + + + + Scaling + + + + + Delete + + + + + Axis Position + + + + + Major Gridlines + + + + + Minor Gridlines + + + + + Title + + + + + Number Format + + + + + Major Tick Mark + + + + + Minor Tick Mark + + + + + Tick Label Position + + + + + + + Crossing Axis ID + + + + + + Crosses + + + + + Crossing Value + + + + + + + + + + + Automatic Category Axis + + + + + Label Alignment + + + + + Label Offset + + + + + + Tick Mark Skip + + + + + No Multi-level Labels + + + + + Chart Extensibility + + + + + + + + + + Automatic Category Axis + + + + + Label Offset + + + + + Base Time Unit + + + + + Major Unit + + + + + Major Time Unit + + + + + Minor Unit + + + + + Minor Time Unit + + + + + Chart Extensibility + + + + + + + + + + Tick Label Skip + + + + + + Chart Extensibility + + + + + + + + + + Cross Between + + + + + Major Unit + + + + + Minor Unit + + + + + Display Units + + + + + Chart Extensibility + + + + + + + + + Layout + + + + + + Area Charts + + + + + 3D Area Charts + + + + + Line Charts + + + + + 3D Line Charts + + + + + Stock Charts + + + + + Radar Charts + + + + + Scatter Charts + + + + + Pie Charts + + + + + 3D Pie Charts + + + + + Doughnut Charts + + + + + Bar Charts + + + + + 3D Bar Charts + + + + + Pie of Pie or Bar of Pie Charts + + + + + Surface Charts + + + + + 3D Surface Charts + + + + + Bubble Charts + + + + + + + Value Axis + + + + + Category Axis Data + + + + + Date Axis + + + + + Series Axis + + + + + + Data Table + + + + + + Chart Extensibility + + + + + + + + + Index + + + + + + + Marker + + + + + Data Label + + + + + Chart Extensibility + + + + + + + + + Pivot Format + + + + + + + Legend Position + + + + + Bottom + + + + + Top Right + + + + + Left + + + + + Right + + + + + Top + + + + + + + + Legend Position Value + + + + + + + + + + + + + Index + + + + + + Delete + + + + + + + Chart Extensibility + + + + + + + + + Legend Position + + + + + Legend Entry + + + + + Layout + + + + + Overlay + + + + + + + Chart Extensibility + + + + + + + Display Blanks As + + + + + Span + + + + + Gap + + + + + Zero + + + + + + + + Display Blanks As Value + + + + + + + + + Auto Title Is Deleted + + + + + Pivot Formats + + + + + View In 3D + + + + + Floor + + + + + Side Wall + + + + + Back Wall + + + + + Plot Area + + + + + Legend + + + + + Plot Visible Only + + + + + Display Blanks As + + + + + Show Data Labels over Maximum + + + + + Chart Extensibility + + + + + + + Style + + + + + + + + + + Style Type + + + + + + + + Pivot Name + + + + + Format ID + + + + + Chart Extensibility + + + + + + + + + Chart Object + + + + + Data Cannot Be Changed + + + + + Formatting + + + + + Selection + + + + + User Interface + + + + + + + + + Odd Header + + + + + Odd Footer + + + + + Even Header + + + + + Even Footer + + + + + First Header + + + + + First Footer + + + + + + Align With Margins + + + + + Different Odd Even + + + + + Different First + + + + + + + Left + + + + + Right + + + + + Top + + + + + Bottom + + + + + Header + + + + + Footer + + + + + + Printed Page Orientation + + + + + Default Page Orientation + + + + + Portrait Page + + + + + Landscape Page + + + + + + + + + Update Automatically + + + + + + Relationship Reference + + + + + + + Page Size + + + + + First Page Number + + + + + Orientation + + + + + Black and White + + + + + Draft + + + + + Use First Page Number + + + + + Horizontal DPI + + + + + Vertical DPI + + + + + Copies + + + + + + + + Header and Footer + + + + + Page Margins + + + + + Page Setup + + + + + Legacy Drawing for Headers and Footers + + + + + + + + + 1904 Date System + + + + + Editing Language + + + + + Rounded Corners + + + + + Style + + + + + Color Map Override + + + + + Pivot Source + + + + + Protection + + + + + Chart + + + + + Shape Properties + + + + + + External Data Relationship + + + + + Print Settings + + + + + Reference to Chart Drawing Part + + + + + Chart Extensibility + + + + + + + Chart Space + + + + + User Shapes + + + + + Reference to Chart Part + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-chartDrawing.xsd b/tests/resources/schema/ecma-376/dml-chartDrawing.xsd new file mode 100644 index 0000000000..ca1873367e --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-chartDrawing.xsd @@ -0,0 +1,338 @@ + + + + + + + + + + + + Chart Non Visual Properties + + + + + Non-Visual Shape Drawing Properties + + + + + + + + + Non-Visual Shape Properties + + + + + Shape Properties + + + + + Shape Style + + + + + Shape Text Body + + + + + + Reference to Custom Function + + + + + Text Link + + + + + Lock Text + + + + + Publish to Server + + + + + + + + Chart Non Visual Properties + + + + + Non-Visual Connection Shape Drawing Properties + + + + + + + + + Connector Non Visual Properties + + + + + Shape Properties + + + + + Connection Shape Style + + + + + + Reference to Custom Function + + + + + Publish to Server + + + + + + + + + Non-Visual Picture Drawing Properties + + + + + + + + + Non-Visual Picture Properties + + + + + Picture Fill + + + + + + + + Reference to Custom Function + + + + + Publish to Server + + + + + + + + Non-Visual Drawing Properties + + + + + Non-Visual Graphic Frame Drawing Properties + + + + + + + + + Non-Visual Graphic Frame Properties + + + + + Graphic Frame Transform + + + + + Graphical Object + + + + + + Reference to Custom Function + + + + + Publish To Server + + + + + + + + Chart Non Visual Properties + + + + + Non-Visual Group Shape Drawing Properties + + + + + + + + + Non-Visual Group Shape Properties + + + + + Group Shape Properties + + + + + + Shape + + + + + Group Shape + + + + + Graphic Frame + + + + + Connector Shape + + + + + Picture + + + + + + + + + + + Shape Definition + + + + + Group Shape + + + + + Graphic Frame + + + + + Connection Shape + + + + + + + + + Chart Marker Coordinate Value + + + + + + + + + + + Relative X Coordinate + + + + + Relative Y Coordinate + + + + + + + + + Starting Anchor Point + + + + + Ending Anchor Point + + + + + + + + + + + Shape Extent + + + + + + + + + + Relative Anchor Shape Size + + + + + Absolute Anchor Shape Size + + + + + + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-compatibility.xsd b/tests/resources/schema/ecma-376/dml-compatibility.xsd new file mode 100644 index 0000000000..dd8d5a6825 --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-compatibility.xsd @@ -0,0 +1,17 @@ + + + + + + + + Shape ID + + + + + + Legacy Drawing Object + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-diagram.xsd b/tests/resources/schema/ecma-376/dml-diagram.xsd new file mode 100644 index 0000000000..35ed75d2d3 --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-diagram.xsd @@ -0,0 +1,3635 @@ + + + + + + + + + + + + + Language + + + + + Description Value + + + + + + + Language + + + + + Description Value + + + + + + + Category Type + + + + + Priority + + + + + + + + Color Transform Category + + + + + + + Color Application Method Type + + + + + Span + + + + + Cycle + + + + + Repeat + + + + + + + Hue Direction + + + + + Clockwise Hue Direction + + + + + Counterclockwise Hue Direction + + + + + + + + + + + Color Application Method Type + + + + + Hue Direction + + + + + + + + Fill Color List + + + + + Line Color List + + + + + Effect Color List + + + + + Text Line Color List + + + + + Text Fill Color List + + + + + Text Effect Color List + + + + + + + Name + + + + + + + + Title + + + + + Description + + + + + Color Transform Category List + + + + + Style Label + + + + + + + Unique ID + + + + + Minimum Version + + + + + + Color Transform Definitions + + + + + + + Title + + + + + Description + + + + + Color Transform Category List + + + + + + + Unique ID + + + + + Minimum Version + + + + + Resource ID + + + + + + Color Transform Header + + + + + + + Color Transform Definition Header + + + + + + + Color Transform Header List + + + + + + + + + + + + Point Type + + + + + Node + + + + + Assistant Element + + + + + Document + + + + + Presentation + + + + + Parent Transition + + + + + Sibling Transition + + + + + + + + + Property Set + + + + + Shape Properties + + + + + Text Body + + + + + + + Model Identifier + + + + + Point Type + + + + + Connection Identifier + + + + + + + + Point + + + + + + + Connection Type + + + + + Parent Of + + + + + Presentation Of + + + + + Presentation Parent Of + + + + + Unknown Relationship + + + + + + + + + + + Model Identifier + + + + + Point Type + + + + + Source Identifier + + + + + Destination Identifier + + + + + Source Position + + + + + Destination Position + + + + + Parent Transition Identifier + + + + + Sibling Transition Identifier + + + + + Presentation Identifier + + + + + + + + Connection + + + + + + + + + Point List + + + + + Connection List + + + + + Background Formatting + + + + + Whole E2O Formatting + + + + + + + + Data Model + + + + + + + + + + + + + Axis + + + + + Data Point Type + + + + + Hide Last Transition + + + + + Start + + + + + Count + + + + + Step + + + + + + + Constraint Type + + + + + For + + + + + For Name + + + + + Data Point Type + + + + + + + Reference Type + + + + + Reference For + + + + + Reference For Name + + + + + Reference Point Type + + + + + + + + + + + + Operator + + + + + Value + + + + + Factor + + + + + + + + Constraint + + + + + + + + + + + + Value + + + + + Factor + + + + + Max Value + + + + + + + + Rule + + + + + + + + + + + + + Layout Shape Type + + + + + + 1-Based Index + + + + + + + + + Adjust Handle Index + + + + + Value + + + + + + + + Shape Adjust + + + + + + + + + Shape Adjust List + + + + + + + Rotation + + + + + Shape Type + + + + + Relationship to Image Part + + + + + Z-Order Offset + + + + + Hide Geometry + + + + + Prevent Text Editing + + + + + Image Placeholder + + + + + + + Parameter Type + + + + + Value + + + + + + + + Parameter + + + + + + + Algorithm Type + + + + + Revision Number + + + + + + + + Algorithm + + + + + Shape + + + + + Presentation Of + + + + + Constraint List + + + + + Rule List + + + + + Variable List + + + + + For Each + + + + + Layout Node + + + + + Choose Element + + + + + + + Name + + + + + Style Label + + + + + Child Order + + + + + Move With + + + + + + + + Algorithm + + + + + Shape + + + + + Presentation Of + + + + + Constraint List + + + + + Rule List + + + + + For Each + + + + + Layout Node + + + + + Choose Element + + + + + + + Name + + + + + Reference + + + + + + + + + Algorithm + + + + + Shape + + + + + Presentation Of + + + + + Constraint List + + + + + Rule List + + + + + For Each + + + + + Layout Node + + + + + Choose Element + + + + + + + Name + + + + + + Function + + + + + Argument + + + + + Operator + + + + + Value + + + + + + + + Algorithm + + + + + Shape + + + + + Presentation Of + + + + + Constraint List + + + + + Rule List + + + + + For Each + + + + + Layout Node + + + + + Choose Element + + + + + Extension List + + + + + + Name + + + + + + + + If + + + + + Else + + + + + + Name + + + + + + + + Data Model + + + + + + Use Default + + + + + + + Category Type + + + + + Priority + + + + + + + + Category + + + + + + + + Language + + + + + Value + + + + + + + Language + + + + + Value + + + + + + + + Title + + + + + Description + + + + + Category List + + + + + Sample Data + + + + + Style Data + + + + + Color Transform Sample Data + + + + + Layout Node + + + + + + + Unique Identifier + + + + + Minimum Version + + + + + Default Style + + + + + + Layout Definition + + + + + + + Title + + + + + Description + + + + + Category List + + + + + + + Unique Identifier + + + + + Minimum Version + + + + + Default Style + + + + + Resource Identifier + + + + + + Layout Definition Header + + + + + + + Layout Definition Header + + + + + + + Diagram Layout Header List + + + + + + Explicit Relationship to Diagram Data Part + + + + + Explicit Relationship to Diagram Layout Definition Part + + + + + Explicit Relationship to Style Definition Part + + + + + Explicit Relationship to Diagram Colors Part + + + + + + Explicit Relationships to Diagram Parts + + + + + Parameter Values + + + + + + + + + + + Model Identifier + + + + + + + + Presentation Layout Variables + + + + + Shape Style + + + + + + Presentation Element Identifier + + + + + Presentation Name + + + + + Presentation Style Label + + + + + Presentation Style Index + + + + + Presentation Style Count + + + + + Current Diagram Type + + + + + Current Diagram Category + + + + + Current Style Type + + + + + Current Style Category + + + + + Color Transform Type Identifier + + + + + Color Transform Category + + + + + Coherent 3D Behavior + + + + + Placeholder Text + + + + + Placeholder + + + + + Custom Rotation + + + + + Custom Vertical Flip + + + + + Custom Horizontal Flip + + + + + Fixed Width Override + + + + + Fixed Height Override + + + + + Width Scale + + + + + Height Scale + + + + + Text Changed + + + + + Custom Factor Width + + + + + Custom Factor Height + + + + + Neighbor Offset Width + + + + + Neighbor Offset Height + + + + + Radius Scale + + + + + Include Angle Scale + + + + + + + + Diagram Direction Definition + + + + + Normal Direction + + + + + Reversed Direction + + + + + + + Hierarchy Branch Style Definition + + + + + Left + + + + + Right + + + + + Hanging + + + + + Standard + + + + + Initial + + + + + + + One by One Animation Value Definition + + + + + Disable One-by-One + + + + + One By One + + + + + By Branch One By One + + + + + + + Animation Level String Definition + + + + + Disable Level At Once + + + + + By Level Animation + + + + + From Center Animation + + + + + + + + Show Organization Chart User Interface Value + + + + + + Number of Nodes Definition + + + + + + + + + Maximum Children Value + + + + + + + Preferred Number of CHildren Value + + + + + + + Show Insert Bullet Value + + + + + + + Diagram Direction Value + + + + + + + Organization Chart Branch Style Value + + + + + + + One By One Animation Value + + + + + + + Level Animation Value + + + + + + Resize Handle + + + + + Exact + + + + + Relative + + + + + + + + Shape Resize Style Type + + + + + + + + Show Organization Chart User Interface + + + + + Maximum Children + + + + + Preferred Number of Children + + + + + Show Insert Bullet + + + + + Diagram Direction + + + + + Organization Chart Branch Style + + + + + One by One Animation String + + + + + Level Animation + + + + + Shape Resize Style + + + + + + + + + + + + + + + + + + + Natural Language + + + + + Description Value + + + + + + + Natural Language + + + + + Description Value + + + + + + + Category Type + + + + + Priority + + + + + + + + Category + + + + + + + + + + + + + + 3-D Scene + + + + + 3-D Shape Properties + + + + + Text Properties + + + + + Shape Style + + + + + + + Style Name + + + + + + + + Title + + + + + Style Label Description + + + + + Category List + + + + + 3-D Scene + + + + + Style Label + + + + + + + Unique Style ID + + + + + Minimum Version + + + + + + Style Definition + + + + + + + Title + + + + + Style Label Description + + + + + Category List + + + + + + + Unique Style ID + + + + + Minimum Version + + + + + Resource ID + + + + + + Style Definition Header + + + + + + + Style Definition Header + + + + + + + List of Style Definition Headers + + + + + + + + Algorithm Types + + + + + Composite + + + + + Connector Algorithm + + + + + Cycle Algorithm + + + + + Hierarchy Child Algorithm + + + + + Hierarchy Root Algorithm + + + + + Pyramid Algorithm + + + + + Linear Algorithm + + + + + Space Algorithm + + + + + Text Algorithm + + + + + Snake Algorithm + + + + + + + Axis Type + + + + + Self + + + + + Child + + + + + Descendant + + + + + Descendant or Self + + + + + Parent + + + + + Ancestor + + + + + Ancestor or Self + + + + + Follow Sibling + + + + + Preceding Sibling + + + + + Follow + + + + + Preceding + + + + + Root + + + + + None + + + + + + + Axis Type List + + + + + + Boolean Constraint + + + + + None + + + + + Equal + + + + + Greater Than or Equal to + + + + + Less Than or Equal to + + + + + + + Child Order + + + + + Bottom + + + + + Top + + + + + + + Constraint Type + + + + + Unknown + + + + + Alignment Offset + + + + + Beginning Margin + + + + + Bending Distance + + + + + Beginning Padding + + + + + Bottom + + + + + Bottom Margin + + + + + Bottom Offset + + + + + Center Height + + + + + Center X Offset + + + + + Center Width + + + + + Center Y Offset + + + + + Connection Distance + + + + + Diameter + + + + + End Margin + + + + + End Padding + + + + + Height + + + + + Arrowhead Height + + + + + Height Offset + + + + + Left + + + + + Left Margin + + + + + Left Offset + + + + + Right + + + + + Right Margin + + + + + Right Offset + + + + + Primary Font Size + + + + + Pyramid Accent Ratio + + + + + Secondary Font Size + + + + + Sibling Spacing + + + + + Secondary Sibling Spacing + + + + + Spacing + + + + + Stem Thickness + + + + + Top + + + + + Top Margin + + + + + Top Offset + + + + + User Defined A + + + + + User Defined B + + + + + User Defined C + + + + + User Defined D + + + + + User Defined E + + + + + User Defined F + + + + + User Defined G + + + + + User Defined H + + + + + User Defined I + + + + + User Defined J + + + + + User Defined K + + + + + User Defined L + + + + + User Defined M + + + + + User Defined N + + + + + User Defined O + + + + + User Defined P + + + + + User Defined Q + + + + + User Defined R + + + + + User Defined S + + + + + User Defined T + + + + + User Defined U + + + + + User Defined V + + + + + User Defined W + + + + + User Defined X + + + + + User Defined Y + + + + + User Defined Z + + + + + Width + + + + + Arrowhead Width + + + + + Width Offset + + + + + + + Constraint Relationship + + + + + Self + + + + + Child + + + + + Descendant + + + + + + + Element Type + + + + + All + + + + + Document + + + + + Node + + + + + Normal + + + + + Non Normal + + + + + Assistant + + + + + Non Assistant + + + + + Parent Transition + + + + + Presentation + + + + + Sibling Transition + + + + + + + Element Type List + + + + + + Parameter Identifier + + + + + Horizontal Alignment + + + + + Vertical Alignment + + + + + Child Direction + + + + + Child Alignment + + + + + Secondary Child Alignment + + + + + Linear Direction + + + + + Secondary Linear Direction + + + + + Start Element + + + + + Bend Point + + + + + Connection Route + + + + + Beginning Arrowhead Style + + + + + End Style + + + + + Connector Dimension + + + + + Rotation Path + + + + + Center Shape Mapping + + + + + Node Horizontal Alignment + + + + + Node Vertical Alignment + + + + + Fallback Scale + + + + + Text Direction + + + + + Pyramid Accent Position + + + + + Pyramid Accent Text Margin + + + + + Text Block Direction + + + + + Text Anchor Horizontal + + + + + Text Anchor Vertical + + + + + Text Anchor Horizontal With Children + + + + + Text Anchor Vertical With Children + + + + + Parent Text Left-to-Right Alignment + + + + + Parent Text Right-to-Left Alignment + + + + + Shape Text Left-to-Right Alignment + + + + + Shape Text Right-to-Left Alignment + + + + + Auto Text Rotation + + + + + Grow Direction + + + + + Flow Direction + + + + + Continue Direction + + + + + Breakpoint + + + + + Offset + + + + + Hierarchy Alignment + + + + + Breakpoint Fixed Value + + + + + Start Bullets At Level + + + + + Start Angle + + + + + Span Angle + + + + + Aspect Ratio + + + + + Line Spacing Parent + + + + + Line Spacing After Parent Paragraph + + + + + Line Spacing Children + + + + + Line Spacing After Children Paragraph + + + + + Route Shortest Distance + + + + + Text Alignment + + + + + Pyramid Level Node + + + + + Pyramid Accent Background Node + + + + + Pyramid Accent Text Node + + + + + Source Node + + + + + Destination Node + + + + + Beginning Points + + + + + End Points + + + + + + + Integer List + + + + + + Unsigned Integer List + + + + + + Boolean List. + + + + + + Function Type + + + + + Count + + + + + Position + + + + + Reverse Position + + + + + Position Even + + + + + Position Odd + + + + + Variable + + + + + Depth + + + + + Max Depth + + + + + + + Function Operator + + + + + Equal + + + + + Not Equal To + + + + + Greater Than + + + + + Less Than + + + + + Greater Than or Equal to + + + + + Less Than or Equal to + + + + + + + Horizontal Alignment + + + + + Left + + + + + Center + + + + + Right + + + + + None + + + + + + + Vertical Alignment + + + + + Top + + + + + Middle + + + + + Bottom + + + + + None + + + + + + + Child Direction + + + + + Horizontal + + + + + Vertical + + + + + + + Child Alignment + + + + + Top + + + + + Bottom + + + + + Left + + + + + Right + + + + + + + Secondary Child Alignment + + + + + None + + + + + Top + + + + + Bottom + + + + + Left + + + + + Right + + + + + + + Linear Direction + + + + + From Left + + + + + From Right + + + + + From Top + + + + + From Bottom + + + + + + + Secondary Linear Direction + + + + + None + + + + + From Left + + + + + From Right + + + + + From Top + + + + + From Bottom + + + + + + + Starting Element + + + + + Node + + + + + Transition + + + + + + + Rotation Path + + + + + None + + + + + Along Path + + + + + + + Center Shape Mapping + + + + + None + + + + + First Node + + + + + + + Bend Point + + + + + Beginning + + + + + Default + + + + + End + + + + + + + Connector Routing + + + + + Straight + + + + + Bending + + + + + Curve + + + + + Long Curve + + + + + + + Arrowhead Styles + + + + + Auto + + + + + Arrowhead Present + + + + + No Arrowhead + + + + + + + Connector Dimension + + + + + 1 Dimension + + + + + 2 Dimensions + + + + + Custom + + + + + + + Connector Point + + + + + Auto + + + + + Bottom Center + + + + + Center + + + + + Middle Left + + + + + Middle Right + + + + + Top Center + + + + + Bottom Left + + + + + Bottom Right + + + + + Top Left + + + + + Top Right + + + + + Radial + + + + + + + Node Horizontal Alignment + + + + + Left + + + + + Center + + + + + Right + + + + + + + Node Vertical Alignment + + + + + Top + + + + + Middle + + + + + Bottom + + + + + + + Fallback Dimension + + + + + 1 Dimension + + + + + 2 Dimensions + + + + + + + Text Direction + + + + + From Top + + + + + From Bottom + + + + + + + Pyramid Accent Position + + + + + Before + + + + + Pyramid Accent After + + + + + + + Pyramid Accent Text Margin + + + + + Step + + + + + Stack + + + + + + + Text Block Direction + + + + + Horizontal + + + + + Vertical Direction + + + + + + + Text Anchor Horizontal + + + + + None + + + + + Center + + + + + + + Text Anchor Vertical + + + + + Top + + + + + Middle + + + + + Bottom + + + + + + + Text Alignment + + + + + Left + + + + + Center + + + + + Right + + + + + + + Auto Text Rotation + + + + + None + + + + + Upright + + + + + Gravity + + + + + + + Grow Direction + + + + + Top Left + + + + + Top Right + + + + + Bottom Left + + + + + Bottom Right + + + + + + + Flow Direction + + + + + Row + + + + + Column + + + + + + + Continue Direction + + + + + Reverse Direction + + + + + Same Direction + + + + + + + Breakpoint + + + + + End of Canvas + + + + + Balanced + + + + + Fixed + + + + + + + Offset + + + + + Center + + + + + Offset + + + + + + + Hierarchy Alignment + + + + + Top Left + + + + + Top Right + + + + + Top Center Children + + + + + Top Center Descendants + + + + + Bottom Left + + + + + Bottom Right + + + + + Bottom Center Child + + + + + Bottom Center Descendant + + + + + Left Top + + + + + Left Bottom + + + + + Left Center Child + + + + + Left Center Descendant + + + + + Right Top + + + + + Right Bottom + + + + + Right Center Children + + + + + Right Center Descendants + + + + + + + Function Value + + + + + + Variable Type + + + + + Unknown + + + + + Organizational Chart Algorithm + + + + + Child Max + + + + + Child Preference + + + + + Bullets Enabled + + + + + Direction + + + + + Hierarchy Branch + + + + + Animate One + + + + + Animation Level + + + + + Resize Handles + + + + + + + Function Argument + + + + + + Output Shape Type + + + + + None + + + + + Connection + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-lockedCanvas.xsd b/tests/resources/schema/ecma-376/dml-lockedCanvas.xsd new file mode 100644 index 0000000000..e464f7e5cc --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-lockedCanvas.xsd @@ -0,0 +1,10 @@ + + + + + + + Locked Canvas Container + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-main.xsd b/tests/resources/schema/ecma-376/dml-main.xsd new file mode 100644 index 0000000000..21361a8d38 --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-main.xsd @@ -0,0 +1,9464 @@ + + + + + + + + + + + + + + + + + + + + + Linked Relationship ID + + + + + + + + + + Linked Relationship ID + + + + + + + + + + Linked Relationship ID + + + + + + + Track + + + + + Time + + + + + + + + Audio Start Time + + + + + Audio End Time + + + + + + + + + + Audio from CD + + + + + Audio from WAV File + + + + + Audio from File + + + + + Video from File + + + + + QuickTime from File + + + + + + + + + + + + + + + Style Matrix Column Index + + + + + + Font Collection Index + + + + + Major Font + + + + + Minor Font + + + + + None + + + + + + + Theme Color Reference + + + + + Dark 1 + + + + + Light 1 + + + + + Dark 2 + + + + + Light 2 + + + + + Accent 1 + + + + + Accent 2 + + + + + Accent 3 + + + + + Accent 4 + + + + + Accent 5 + + + + + Accent 6 + + + + + Hyperlink + + + + + Followed Hyperlink + + + + + + + + + Dark 1 + + + + + Light 1 + + + + + Dark 2 + + + + + Light 2 + + + + + Accent 1 + + + + + Accent 2 + + + + + Accent 3 + + + + + Accent 4 + + + + + Accent 5 + + + + + Accent 6 + + + + + Hyperlink + + + + + Followed Hyperlink + + + + + + + Name + + + + + + + + + + Name + + + + + + + Script + + + + + Typeface + + + + + + + + Custom color + + + + + + + + + Latin Font + + + + + East Asian Font + + + + + Complex Script Font + + + + + Font + + + + + + + + + + + 3D Scene Properties + + + + + 3D properties + + + + + + + + + Major Font + + + + + Minor fonts + + + + + + + Name + + + + + + + + + + + + + + + + + + Effect Style + + + + + + + + + + + + + + Fill Style List + + + + + Line Style List + + + + + Effect Style List + + + + + Background Fill Style List + + + + + + Name + + + + + + + + + Font Scheme + + + + + Format Scheme + + + + + + + + + + + + + + + Uniform Resource Identifier + + + + + + Coordinate + + + + + + + + + Coordinate Point + + + + + + Positive Coordinate + + + + + + + + + Positive Coordinate Point + + + + + + + + Angle + + + + + + + Value + + + + + + Fixed Angle + + + + + + + + + Positive Fixed Angle + + + + + + + + + + Value + + + + + + Percentage + + + + + + + Value + + + + + + Positive Percentage + + + + + + + + + Value + + + + + + Fixed Percentage + + + + + + + + + + Value + + + + + + Positive Fixed Percentage + + + + + + + + + + Value + + + + + + + Numerator + + + + + Denominator + + + + + + + X-Axis Coordinate + + + + + Y-Axis Coordinate + + + + + + + Extent Length + + + + + Extent Width + + + + + + + + + + + + + Tint + + + + + Shade + + + + + Complement + + + + + Inverse + + + + + Gray + + + + + Alpha + + + + + Alpha Offset + + + + + Alpha Modulation + + + + + Hue + + + + + Hue Offset + + + + + Hue Modulate + + + + + Saturation + + + + + Saturation Offset + + + + + Saturation Modulation + + + + + Luminance + + + + + Luminance Offset + + + + + Luminance Modulation + + + + + Red + + + + + Red Offset + + + + + Red Modulation + + + + + Green + + + + + Green Offset + + + + + Green Modification + + + + + Blue + + + + + Blue Offset + + + + + Blue Modification + + + + + Gamma + + + + + Inverse Gamma + + + + + + + + + + + Red + + + + + Green + + + + + Blue + + + + + + Hex Binary of Length 3 + + + + + + + + + + + + Value + + + + + + + + + + Hue + + + + + Saturation + + + + + Luminance + + + + + + System Color Value + + + + + Scroll Bar System Color + + + + + Background System Color + + + + + Active Caption System Color + + + + + Inactive Caption System Color + + + + + Menu System Color + + + + + Window System Color + + + + + Window Frame System Color + + + + + Menu Text System Color + + + + + Window Text System Color + + + + + Caption Text System Color + + + + + Active Border System Color + + + + + Inactive Border System Color + + + + + Application Workspace System Color + + + + + Highlight System Color + + + + + Highlight Text System Color + + + + + Button Face System Color + + + + + Button Shadow System Color + + + + + Gray Text System Color + + + + + Button Text System Color + + + + + Inactive Caption Text System Color + + + + + Button Highlight System Color + + + + + 3D Dark System Color + + + + + 3D Light System Color + + + + + Info Text System Color + + + + + Info Back System Color + + + + + Hot Light System Color + + + + + Gradient Active Caption System Color + + + + + Gradient Inactive Caption System Color + + + + + Menu Highlight System Color + + + + + Menu Bar System Color + + + + + + + + + + + Value + + + + + Last Color + + + + + + Scheme Color + + + + + Background Color 1 + + + + + Text Color 1 + + + + + Background Color 2 + + + + + Text Color 2 + + + + + Accent Color 1 + + + + + Accent Color 2 + + + + + Accent Color 3 + + + + + Accent Color 4 + + + + + Accent Color 5 + + + + + Accent Color 6 + + + + + Hyperlink Color + + + + + Followed Hyperlink Color + + + + + Style Color + + + + + Dark Color 1 + + + + + Light Color 1 + + + + + Dark Color 2 + + + + + Light Color 2 + + + + + + + + + + + Value + + + + + + Preset Color Value + + + + + Alice Blue Preset Color + + + + + Antique White Preset Color + + + + + Aqua Preset Color + + + + + Aquamarine Preset Color + + + + + Azure Preset Color + + + + + Beige Preset Color + + + + + Bisque Preset Color + + + + + Black Preset Color + + + + + Blanched Almond Preset Color + + + + + Blue Preset Color + + + + + Blue Violet Preset Color + + + + + Brown Preset Color + + + + + Burly Wood Preset Color + + + + + Cadet Blue Preset Color + + + + + Chartreuse Preset Color + + + + + Chocolate Preset Color + + + + + Coral Preset Color + + + + + Cornflower Blue Preset Color + + + + + Cornsilk Preset Color + + + + + Crimson Preset Color + + + + + Cyan Preset Color + + + + + Dark Blue Preset Color + + + + + Dark Cyan Preset Color + + + + + Dark Goldenrod Preset Color + + + + + Dark Gray Preset Color + + + + + Dark Green Preset Color + + + + + Dark Khaki Preset Color + + + + + Dark Magenta Preset Color + + + + + Dark Olive Green Preset Color + + + + + Dark Orange Preset Color + + + + + Dark Orchid Preset Color + + + + + Dark Red Preset Color + + + + + Dark Salmon Preset Color + + + + + Dark Sea Green Preset Color + + + + + Dark Slate Blue Preset Color + + + + + Dark Slate Gray Preset Color + + + + + Dark Turquoise Preset Color + + + + + Dark Violet Preset Color + + + + + Deep Pink Preset Color + + + + + Deep Sky Blue Preset Color + + + + + Dim Gray Preset Color + + + + + Dodger Blue Preset Color + + + + + Firebrick Preset Color + + + + + Floral White Preset Color + + + + + Forest Green Preset Color + + + + + Fuchsia Preset Color + + + + + Gainsboro Preset Color + + + + + Ghost White Preset Color + + + + + Gold Preset Color + + + + + Goldenrod Preset Color + + + + + Gray Preset Color + + + + + Green Preset Color + + + + + Green Yellow Preset Color + + + + + Honeydew Preset Color + + + + + Hot Pink Preset Color + + + + + Indian Red Preset Color + + + + + Indigo Preset Color + + + + + Ivory Preset Color + + + + + Khaki Preset Color + + + + + Lavender Preset Color + + + + + Lavender Blush Preset Color + + + + + Lawn Green Preset Color + + + + + Lemon Chiffon Preset Color + + + + + Light Blue Preset Color + + + + + Light Coral Preset Color + + + + + Light Cyan Preset Color + + + + + Light Goldenrod Yellow Preset Color + + + + + Light Gray Preset Color + + + + + Light Green Preset Color + + + + + Light Pink Preset Color + + + + + Light Salmon Preset Color + + + + + Light Sea Green Preset Color + + + + + Light Sky Blue Preset Color + + + + + Light Slate Gray Preset Color + + + + + Light Steel Blue Preset Color + + + + + Light Yellow Preset Color + + + + + Lime Preset Color + + + + + Lime Green Preset Color + + + + + Linen Preset Color + + + + + Magenta Preset Color + + + + + Maroon Preset Color + + + + + Medium Aquamarine Preset Color + + + + + Medium Blue Preset Color + + + + + Medium Orchid Preset Color + + + + + Medium Purple Preset Color + + + + + Medium Sea Green Preset Color + + + + + Medium Slate Blue Preset Color + + + + + Medium Spring Green Preset Color + + + + + Medium Turquoise Preset Color + + + + + Medium Violet Red Preset Color + + + + + Midnight Blue Preset Color + + + + + Mint Cream Preset Color + + + + + Misty Rose Preset Color + + + + + Moccasin Preset Color + + + + + Navajo White Preset Color + + + + + Navy Preset Color + + + + + Old Lace Preset Color + + + + + Olive Preset Color + + + + + Olive Drab Preset Color + + + + + Orange Preset Color + + + + + Orange Red Preset Color + + + + + Orchid Preset Color + + + + + Pale Goldenrod Preset Color + + + + + Pale Green Preset Color + + + + + Pale Turquoise Preset Color + + + + + Pale Violet Red Preset Color + + + + + Papaya Whip Preset Color + + + + + Peach Puff Preset Color + + + + + Peru Preset Color + + + + + Pink Preset Color + + + + + Plum Preset Color + + + + + Powder Blue Preset Color + + + + + Purple Preset Color + + + + + Red Preset Color + + + + + Rosy Brown Preset Color + + + + + Royal Blue Preset Color + + + + + Saddle Brown Preset Color + + + + + Salmon Preset Color + + + + + Sandy Brown Preset Color + + + + + Sea Green Preset Color + + + + + Sea Shell Preset Color + + + + + Sienna Preset Color + + + + + Silver Preset Color + + + + + Sky Blue Preset Color + + + + + Slate Blue Preset Color + + + + + Slate Gray Preset Color + + + + + Snow Preset Color + + + + + Spring Green Preset Color + + + + + Steel Blue Preset Color + + + + + Tan Preset Color + + + + + Teal Preset Color + + + + + Thistle Preset Color + + + + + Tomato Preset Color + + + + + Turquoise Preset Color + + + + + Violet Preset Color + + + + + Wheat Preset Color + + + + + White Preset Color + + + + + White Smoke Preset Color + + + + + Yellow Preset Color + + + + + Yellow Green Preset Color + + + + + + + + + + + Value + + + + + + + + Extension + + + + + + + + + + + + + + Horizontal Ratio + + + + + Vertical Ratio + + + + + + + + + Offset + + + + + Extents + + + + + + Rotation + + + + + Horizontal Flip + + + + + Vertical Flip + + + + + + + + Offset + + + + + Extents + + + + + Child Offset + + + + + Child Extents + + + + + + Rotation + + + + + Horizontal Flip + + + + + Vertical Flip + + + + + + + X-Coordinate in 3D + + + + + Y-Coordinate in 3D + + + + + Z-Coordinate in 3D + + + + + + + Distance along X-axis in 3D + + + + + Distance along Y-axis in 3D + + + + + Distance along Z-axis in 3D + + + + + + + Latitude + + + + + Longitude + + + + + Revolution + + + + + + + Left Offset + + + + + Top Offset + + + + + Right Offset + + + + + Bottom Offset + + + + + + Rectangle Alignments + + + + + Rectangle Alignment Enum ( Top Left ) + + + + + Rectangle Alignment Enum ( Top ) + + + + + Rectangle Alignment Enum ( Top Right ) + + + + + Rectangle Alignment Enum ( Left ) + + + + + Rectangle Alignment Enum ( Center ) + + + + + Rectangle Alignment Enum ( Right ) + + + + + Rectangle Alignment Enum ( Bottom Left ) + + + + + Rectangle Alignment Enum ( Bottom ) + + + + + Rectangle Alignment Enum ( Bottom Right ) + + + + + + + GUID Method + + + + + + + + + + RGB Color Model - Percentage Variant + + + + + RGB Color Model - Hex Variant + + + + + Hue, Saturation, Luminance Color Model + + + + + System Color + + + + + Scheme Color + + + + + Preset Color + + + + + + + + + + + + + + + + + Black and White Mode + + + + + Color + + + + + Automatic + + + + + Gray + + + + + Light Gray + + + + + Inverse Gray + + + + + Gray and White + + + + + Black and Gray + + + + + Black and White + + + + + Black + + + + + White + + + + + Hidden + + + + + + + + Embedded Picture Reference + + + + + Linked Picture Reference + + + + + + + Embedded Audio File Relationship ID + + + + + Sound Name + + + + + Recognized Built-In Sound + + + + + + + + Hyperlink Sound + + + + + + + Drawing Object Hyperlink Target + + + + + Invalid URL + + + + + Action Setting + + + + + Target Frame + + + + + Hyperlink Tooltip + + + + + Add Hyperlink to Page History + + + + + Highlight Click + + + + + End Sounds + + + + + + Drawing Element ID + + + + + + + + + + + Disallow Shape Grouping + + + + + Disallow Shape Selection + + + + + Disallow Shape Rotation + + + + + Disallow Aspect Ratio Change + + + + + Disallow Shape Movement + + + + + Disallow Shape Resize + + + + + Disallow Shape Point Editing + + + + + Disallow Showing Adjust Handles + + + + + Disallow Arrowhead Changes + + + + + Disallow Shape Type Change + + + + + + + + + + + + + + + + + Disallow Shape Text Editing + + + + + + + + + + + Disallow Crop Changes + + + + + + + + + + Disallow Shape Grouping + + + + + Disallow Shape Ungrouping + + + + + Disallow Shape Selection + + + + + Disallow Shape Rotation + + + + + Disallow Aspect Ratio Change + + + + + Disallow Moving Shape + + + + + Disallow Shape Resizing + + + + + + + + + + Disallow Shape Grouping + + + + + Disallow Selection of Child Shapes + + + + + Disallow Shape Selection + + + + + Disallow Aspect Ratio Change + + + + + Disallow Shape Movement + + + + + Disallow Shape Resize + + + + + + + + Drawing Element On Click Hyperlink + + + + + Hyperlink for Hover + + + + + + + Unique Identifier + + + + + Name + + + + + Alternative Text for Object + + + + + Hidden + + + + + + + + Shape Locks + + + + + + + Text Box + + + + + + + + Connection Shape Locks + + + + + Connection Start + + + + + Connection End + + + + + + + + + + Picture Locks + + + + + + + Relative Resize Preferred + + + + + + + + Group Shape Locks + + + + + + + + + + Graphic Frame Locks + + + + + + + + + + + + + + Uniform Resource Identifier + + + + + + + + Graphic Object Data + + + + + + + Graphic Object + + + + + + + + Chart Animation Build Step + + + + + Category + + + + + Category Points + + + + + Series + + + + + Series Points + + + + + All Points + + + + + Grid and Legend + + + + + + + Diagram Animation Build Steps + + + + + Shape + + + + + Background + + + + + + + + Identifier + + + + + Animation Build Step + + + + + + + Series Index + + + + + Category Index + + + + + Animation Build Step + + + + + + + + Diagram to Animate + + + + + Chart to Animate + + + + + + + Animation Build Type + + + + + Animate At Once + + + + + + + Diagram only Animation Types + + + + + Elements One-by-One + + + + + Level One-by-One + + + + + Each Level at Once + + + + + + + Diagram Animation Build Type + + + + + + + Build + + + + + Reverse Animation + + + + + + Chart only Animation Types + + + + + Series + + + + + Catefory + + + + + Series Element + + + + + Category Element + + + + + + + Chart Animation Build Type + + + + + + + Build + + + + + Animate Background + + + + + + + + Build Diagram + + + + + Build Chart + + + + + + + + + + + + + + + + + + + Outline + + + + + + + + + + + + + + + + + + Shape Text Body + + + + + + Use Shape Text Rectangle + + + + + + + + + + + + + Non-Visual Shape Drawing Properties + + + + + + + + + Non-Visual Properties for a Shape + + + + + Visual Properties + + + + + Text Shape + + + + + Style + + + + + + + + + + Non-Visual Drawing Properties + + + + + Non-Visual Connector Shape Drawing Properties + + + + + + + + + Non-Visual Properties for a Connection Shape + + + + + Visual Properties + + + + + Shape Style + + + + + + + + + + + Non-Visual Picture Drawing Properties + + + + + + + + + Non-Visual Properties for a Picture + + + + + Picture Fill + + + + + Shape Properties + + + + + + + + + + + + Non-Visual Graphic Frame Drawing Properties + + + + + + + + + Non-Visual Properties for a Graphic Frame + + + + + + + + + + + + + Non-Visual Group Shape Drawing Properties + + + + + + + + + Non-Visual Properties for a Group Shape + + + + + Visual Group Shape Properties + + + + + + Text shape + + + + + Shape + + + + + Connection Shape + + + + + Picture + + + + + Graphic Frame + + + + + Group shape + + + + + + + + + + + + Preset Camera Type + + + + + Legacy Oblique Top Left + + + + + Legacy Oblique Top + + + + + Legacy Oblique Top Right + + + + + Legacy Oblique Left + + + + + Legacy Oblique Front + + + + + Legacy Oblique Right + + + + + Legacy Oblique Bottom Left + + + + + Legacy Oblique Bottom + + + + + Legacy Oblique Bottom Right + + + + + Legacy Perspective Top Left + + + + + Legacy Perspective Top + + + + + Legacy Perspective Top Right + + + + + Legacy Perspective Left + + + + + Legacy Perspective Front + + + + + Legacy Perspective Right + + + + + Legacy Perspective Bottom Left + + + + + Legacy Perspective Bottom + + + + + Legacy Perspective Bottom Right + + + + + Orthographic Front + + + + + Isometric Top Up + + + + + Isometric Top Down + + + + + Isometric Bottom Up + + + + + Isometric Bottom Down + + + + + Isometric Left Up + + + + + Isometric Left Down + + + + + Isometric Right Up + + + + + Isometric Right Down + + + + + Isometric Off Axis 1 Left + + + + + Isometric Off Axis 1 Right + + + + + Isometric Off Axis 1 Top + + + + + Isometric Off Axis 2 Left + + + + + Isometric Off Axis 2 Right + + + + + Isometric Off Axis 2 Top + + + + + Isometric Off Axis 3 Left + + + + + Isometric Off Axis 3 Right + + + + + Isometric Off Axis 3 Bottom + + + + + Isometric Off Axis 4 Left + + + + + Isometric Off Axis 4 Right + + + + + Isometric Off Axis 4 Bottom + + + + + Oblique Top Left + + + + + Oblique Top + + + + + Oblique Top Right + + + + + Oblique Left + + + + + Oblique Right + + + + + Oblique Bottom Left + + + + + Oblique Bottom + + + + + Oblique Bottom Right + + + + + Perspective Front + + + + + Perspective Left + + + + + Perspective Right + + + + + Orthographic Above + + + + + Perspective Below + + + + + Perspective Above Left Facing + + + + + Perspective Above Right Facing + + + + + Perspective Contrasting Left Facing + + + + + Perspective Contrasting Right Facing + + + + + Perspective Heroic Left Facing + + + + + Perspective Heroic Right Facing + + + + + Perspective Heroic Extreme Left Facing + + + + + Perspective Heroic Extreme Right Facing + + + + + Perspective Relaxed + + + + + Perspective Relaxed Moderately + + + + + + + Field of View Angle + + + + + + + + + + + Rotation + + + + + + Preset Camera Type + + + + + Field of View + + + + + Zoom + + + + + + + + + Light Rig Direction + + + + + Top Left + + + + + Top + + + + + Top Right + + + + + Left + + + + + Right + + + + + Bottom Left + + + + + Bottom + + + + + Bottom Right + + + + + + + Light Rig Type + + + + + Legacy Flat 1 + + + + + Legacy Flat 2 + + + + + Legacy Flat 3 + + + + + Legacy Flat 4 + + + + + Legacy Normal 1 + + + + + Legacy Normal 2 + + + + + Legacy Normal 3 + + + + + Legacy Normal 4 + + + + + Legacy Harsh 1 + + + + + Legacy Harsh 2 + + + + + Legacy Harsh 3 + + + + + Legacy Harsh 4 + + + + + Three Point + + + + + Light Rig Enum ( Balanced ) + + + + + Soft + + + + + Harsh + + + + + Flood + + + + + Contrasting + + + + + Morning + + + + + Sunrise + + + + + Sunset + + + + + Chilly + + + + + Freezing + + + + + Flat + + + + + Two Point + + + + + Glow + + + + + Bright Room + + + + + + + + + Rotation + + + + + + Rig Preset + + + + + Direction + + + + + + + + + + + + + Camera + + + + + Light Rig + + + + + Backdrop Plane + + + + + + + + + + + + + Anchor Point + + + + + Normal + + + + + Up Vector + + + + + + + + + + + Bevel Presets + + + + + Relaxed Inset + + + + + Circle + + + + + Slope + + + + + Cross + + + + + Angle + + + + + Soft Round + + + + + Convex + + + + + Cool Slant + + + + + Divot + + + + + Riblet + + + + + Hard Edge + + + + + Art Deco + + + + + + + + Width + + + + + Height + + + + + Preset Bevel + + + + + + Preset Material Type + + + + + Legacy Matte + + + + + Legacy Plastic + + + + + Legacy Metal + + + + + Legacy Wireframe + + + + + Matte + + + + + Plastic + + + + + Metal + + + + + Warm Matte + + + + + Translucent Powder + + + + + Powder + + + + + Dark Edge + + + + + Soft Edge + + + + + Clear + + + + + Flat + + + + + Soft Metal + + + + + + + + + Top Bevel + + + + + Bottom Bevel + + + + + Extrusion Color + + + + + Contour Color + + + + + + + Shape Depth + + + + + Extrusion Height + + + + + Contour Width + + + + + Preset Material Type + + + + + + + Z Coordinate + + + + + + + + Apply 3D shape properties + + + + + No text in 3D scene + + + + + + + + + + + Threshold + + + + + + + + + + + + + + Amount + + + + + + + Radius + + + + + + + Alpha + + + + + + + Threshold + + + + + + + Radius + + + + + Grow Bounds + + + + + + + + Change Color From + + + + + Change Color To + + + + + + Consider Alpha Values + + + + + + + + + + + + + + + + + + + + Radius + + + + + + + + Hue + + + + + Saturation + + + + + Luminance + + + + + + + + + + Blur Radius + + + + + Distance + + + + + Direction + + + + + + + Brightness + + + + + Contrast + + + + + + + + + + Blur Radius + + + + + Shadow Offset Distance + + + + + Shadow Direction + + + + + Horizontal Scaling Factor + + + + + Vertical Scaling Factor + + + + + Horizontal Skew + + + + + Vertical Skew + + + + + Shadow Alignment + + + + + Rotate With Shape + + + + + + Preset Shadow Type + + + + + Top Left Drop Shadow + + + + + Top Right Drop Shadow + + + + + Back Left Perspective Shadow + + + + + Back Right Perspective Shadow + + + + + Bottom Left Drop Shadow + + + + + Bottom Right Drop Shadow + + + + + Front Left Perspective Shadow + + + + + Front Right Perspective Shadow + + + + + Top Left Small Drop Shadow + + + + + Top Left Large Drop Shadow + + + + + Back Left Long Perspective Shadow + + + + + Back Right Long Perspective Shadow + + + + + Top Left Double Drop Shadow + + + + + Bottom Right Small Drop Shadow + + + + + Front Left Long Perspective Shadow + + + + + Front Right LongPerspective Shadow + + + + + 3D Outer Box Shadow + + + + + 3D Inner Box Shadow + + + + + Back Center Perspective Shadow + + + + + Front Bottom Shadow + + + + + + + + + + + Preset Shadow + + + + + Distance + + + + + Direction + + + + + + + Blur Radius + + + + + Start Opacity + + + + + Start Position + + + + + End Alpha + + + + + End Position + + + + + Distance + + + + + Direction + + + + + Fade Direction + + + + + Horizontal Ratio + + + + + Vertical Ratio + + + + + Horizontal Skew + + + + + Vertical Skew + + + + + Shadow Alignment + + + + + Rotate With Shape + + + + + + + Offset X + + + + + Offset Y + + + + + + + Radius + + + + + + + Hue + + + + + Amount + + + + + + + Horizontal Ratio + + + + + Vertical Ratio + + + + + Horizontal Skew + + + + + Vertical Skew + + + + + Horizontal Shift + + + + + Vertical Shift + + + + + + + + + + + + + Angle + + + + + Scaled + + + + + + Path Shade Type + + + + + Shape + + + + + Circle + + + + + Rectangle + + + + + + + + + Fill To Rectangle + + + + + + Gradient Fill Path + + + + + + + + Linear Gradient Fill + + + + + Path Gradient + + + + + + + Tile Flip Mode + + + + + None + + + + + Horizontal + + + + + Vertical + + + + + Horizontal and Vertical + + + + + + + + + + + Position + + + + + + + + Gradient stops + + + + + + + + + Gradient Stop List + + + + + + Tile Rectangle + + + + + + Tile Flip + + + + + Rotate With Shape + + + + + + + Horizontal Offset + + + + + Vertical Offset + + + + + Horizontal Ratio + + + + + Vertical Ratio + + + + + Tile Flipping + + + + + Alignment + + + + + + + + Fill Rectangle + + + + + + + + + Tile + + + + + Stretch + + + + + + + Blip Compression Type + + + + + Email Compression + + + + + Screen Viewing Compression + + + + + Printing Compression + + + + + High Quality Printing Compression + + + + + No Compression + + + + + + + + + + Alpha Bi-Level Effect + + + + + + + + + Alpha Modulate Fixed Effect + + + + + + Bi-Level (Black/White) Effect + + + + + + + Solid Color Replacement + + + + + + + + + Luminance Effect + + + + + Tint Effect + + + + + + + + + Compression State + + + + + + + + + Source Rectangle + + + + + + + DPI Setting + + + + + Rotate With Shape + + + + + + Preset Pattern Value + + + + + 5% + + + + + 10% + + + + + 20% + + + + + 25% + + + + + 30% + + + + + 40% + + + + + 50% + + + + + 60% + + + + + 70% + + + + + 75% + + + + + 80% + + + + + 90% + + + + + Horizontal + + + + + Vertical + + + + + Light Horizontal + + + + + Light Vertical + + + + + Dark Horizontal + + + + + Dark Vertical + + + + + Narrow Horizontal + + + + + Narrow Vertical + + + + + Dashed Horizontal + + + + + Dashed Vertical + + + + + Cross + + + + + Downward Diagonal + + + + + Upward Diagonal + + + + + Light Downward Diagonal + + + + + Light Upward Diagonal + + + + + Dark Downward Diagonal + + + + + Dark Upward Diagonal + + + + + Wide Downward Diagonal + + + + + Wide Upward Diagonal + + + + + Dashed Downward Diagonal + + + + + Dashed Upward DIagonal + + + + + Diagonal Cross + + + + + Small Checker Board + + + + + Large Checker Board + + + + + Small Grid + + + + + Large Grid + + + + + Dotted Grid + + + + + Small Confetti + + + + + Large Confetti + + + + + Horizontal Brick + + + + + Diagonal Brick + + + + + Solid Diamond + + + + + Open Diamond + + + + + Dotted Diamond + + + + + Plaid + + + + + Sphere + + + + + Weave + + + + + Divot + + + + + Shingle + + + + + Wave + + + + + Trellis + + + + + Zig Zag + + + + + + + + + Foreground color + + + + + Background color + + + + + + Preset Pattern + + + + + + + + + + + + + Pattern Fill + + + + + Group Fill + + + + + + + + + + + + + + + + + Blend Mode + + + + + Overlay + + + + + Multiply + + + + + Screen + + + + + Darken + + + + + Lighten + + + + + + + + + + + Blend + + + + + + + Reference + + + + + + + + Effect Container + + + + + Effect + + + + + + Alpha Ceiling Effect + + + + + Alpha Floor Effect + + + + + Alpha Inverse Effect + + + + + Alpha Modulate Effect + + + + + + Alpha Inset/Outset Effect + + + + + Alpha Replace Effect + + + + + + Blend Effect + + + + + + Color Change Effect + + + + + + Duotone Effect + + + + + Fill + + + + + Fill Overlay Effect + + + + + Glow Effect + + + + + Gray Scale Effect + + + + + Hue Saturation Luminance Effect + + + + + Inner Shadow Effect + + + + + Luminance + + + + + Outer Shadow Effect + + + + + Preset Shadow + + + + + Reflection Effect + + + + + Relative Offset Effect + + + + + Soft Edge Effect + + + + + + Transform Effect + + + + + + + Effect Container Type + + + + + Sibling + + + + + Tree + + + + + + + + + Effect Container Type + + + + + Name + + + + + + + + + + + + + Effect to blend + + + + + + Blend Mode + + + + + + + + Blur Effect + + + + + + + + + + + + + + + + Effect Container + + + + + Effect Container + + + + + + + + + + + + + + + + Preset Shape Types + + + + + Line Shape + + + + + Line Inverse Shape + + + + + Triangle Shape + + + + + Right Triangle Shape + + + + + Rectangle Shape + + + + + Diamond Shape + + + + + Parallelogram Shape + + + + + Trapezoid Shape + + + + + Non-Isosceles Trapezoid Shape + + + + + Pentagon Shape + + + + + Hexagon Shape + + + + + Heptagon Shape + + + + + Octagon Shape + + + + + Decagon Shape + + + + + Dodecagon Shape + + + + + Four Pointed Star Shape + + + + + Five Pointed Star Shape + + + + + Six Pointed Star Shape + + + + + Seven Pointed Star Shape + + + + + Eight Pointed Star Shape + + + + + Ten Pointed Star Shape + + + + + Twelve Pointed Star Shape + + + + + Sixteen Pointed Star Shape + + + + + Twenty Four Pointed Star Shape + + + + + Thirty Two Pointed Star Shape + + + + + Round Corner Rectangle Shape + + + + + One Round Corner Rectangle Shape + + + + + Two Same-side Round Corner Rectangle Shape + + + + + Two Diagonal Round Corner Rectangle Shape + + + + + One Snip One Round Corner Rectangle Shape + + + + + One Snip Corner Rectangle Shape + + + + + Two Same-side Snip Corner Rectangle Shape + + + + + Two Diagonal Snip Corner Rectangle Shape + + + + + Plaque Shape + + + + + Ellipse Shape + + + + + Teardrop Shape + + + + + Home Plate Shape + + + + + Chevron Shape + + + + + Pie Wedge Shape + + + + + Pie Shape + + + + + Block Arc Shape + + + + + Donut Shape + + + + + No Smoking Shape + + + + + Right Arrow Shape + + + + + Left Arrow Shape + + + + + Up Arrow Shape + + + + + Down Arrow Shape + + + + + Striped Right Arrow Shape + + + + + Notched Right Arrow Shape + + + + + Bent Up Arrow Shape + + + + + Left Right Arrow Shape + + + + + Up Down Arrow Shape + + + + + Left Up Arrow Shape + + + + + Left Right Up Arrow Shape + + + + + Quad-Arrow Shape + + + + + Callout Left Arrow Shape + + + + + Callout Right Arrow Shape + + + + + Callout Up Arrow Shape + + + + + Callout Down Arrow Shape + + + + + Callout Left Right Arrow Shape + + + + + Callout Up Down Arrow Shape + + + + + Callout Quad-Arrow Shape + + + + + Bent Arrow Shape + + + + + U-Turn Arrow Shape + + + + + Circular Arrow Shape + + + + + Left Circular Arrow Shape + + + + + Left Right Circular Arrow Shape + + + + + Curved Right Arrow Shape + + + + + Curved Left Arrow Shape + + + + + Curved Up Arrow Shape + + + + + Curved Down Arrow Shape + + + + + Swoosh Arrow Shape + + + + + Cube Shape + + + + + Can Shape + + + + + Lightning Bolt Shape + + + + + Heart Shape + + + + + Sun Shape + + + + + Moon Shape + + + + + Smiley Face Shape + + + + + Irregular Seal 1 Shape + + + + + Irregular Seal 2 Shape + + + + + Folded Corner Shape + + + + + Bevel Shape + + + + + Frame Shape + + + + + Half Frame Shape + + + + + Corner Shape + + + + + Diagonal Stripe Shape + + + + + Chord Shape + + + + + Curved Arc Shape + + + + + Left Bracket Shape + + + + + Right Bracket Shape + + + + + Left Brace Shape + + + + + Right Brace Shape + + + + + Bracket Pair Shape + + + + + Brace Pair Shape + + + + + Straight Connector 1 Shape + + + + + Bent Connector 2 Shape + + + + + Bent Connector 3 Shape + + + + + Bent Connector 4 Shape + + + + + Bent Connector 5 Shape + + + + + Curved Connector 2 Shape + + + + + Curved Connector 3 Shape + + + + + Curved Connector 4 Shape + + + + + Curved Connector 5 Shape + + + + + Callout 1 Shape + + + + + Callout 2 Shape + + + + + Callout 3 Shape + + + + + Callout 1 Shape + + + + + Callout 2 Shape + + + + + Callout 3 Shape + + + + + Callout 1 with Border Shape + + + + + Callout 2 with Border Shape + + + + + Callout 3 with Border Shape + + + + + Callout 1 with Border and Accent Shape + + + + + Callout 2 with Border and Accent Shape + + + + + Callout 3 with Border and Accent Shape + + + + + Callout Wedge Rectangle Shape + + + + + Callout Wedge Round Rectangle Shape + + + + + Callout Wedge Ellipse Shape + + + + + Callout Cloud Shape + + + + + Cloud Shape + + + + + Ribbon Shape + + + + + Ribbon 2 Shape + + + + + Ellipse Ribbon Shape + + + + + Ellipse Ribbon 2 Shape + + + + + Left Right Ribbon Shape + + + + + Vertical Scroll Shape + + + + + Horizontal Scroll Shape + + + + + Wave Shape + + + + + Double Wave Shape + + + + + Plus Shape + + + + + Process Flow Shape + + + + + Decision Flow Shape + + + + + Input Output Flow Shape + + + + + Predefined Process Flow Shape + + + + + Internal Storage Flow Shape + + + + + Document Flow Shape + + + + + Multi-Document Flow Shape + + + + + Terminator Flow Shape + + + + + Preparation Flow Shape + + + + + Manual Input Flow Shape + + + + + Manual Operation Flow Shape + + + + + Connector Flow Shape + + + + + Punched Card Flow Shape + + + + + Punched Tape Flow Shape + + + + + Summing Junction Flow Shape + + + + + Or Flow Shape + + + + + Collate Flow Shape + + + + + Sort Flow Shape + + + + + Extract Flow Shape + + + + + Merge Flow Shape + + + + + Offline Storage Flow Shape + + + + + Online Storage Flow Shape + + + + + Magnetic Tape Flow Shape + + + + + Magnetic Disk Flow Shape + + + + + Magnetic Drum Flow Shape + + + + + Display Flow Shape + + + + + Delay Flow Shape + + + + + Alternate Process Flow Shape + + + + + Off-Page Connector Flow Shape + + + + + Blank Button Shape + + + + + Home Button Shape + + + + + Help Button Shape + + + + + Information Button Shape + + + + + Forward or Next Button Shape + + + + + Back or Previous Button Shape + + + + + End Button Shape + + + + + Beginning Button Shape + + + + + Return Button Shape + + + + + Document Button Shape + + + + + Sound Button Shape + + + + + Movie Button Shape + + + + + Gear 6 Shape + + + + + Gear 9 Shape + + + + + Funnel Shape + + + + + Plus Math Shape + + + + + Minus Math Shape + + + + + Multiply Math Shape + + + + + Divide Math Shape + + + + + Equal Math Shape + + + + + Not Equal Math Shape + + + + + Corner Tabs Shape + + + + + Square Tabs Shape + + + + + Plaque Tabs Shape + + + + + Chart X Shape + + + + + Chart Star Shape + + + + + Chart Plus Shape + + + + + + + Preset Text Shape Types + + + + + No Text Shape + + + + + Plain Text Shape + + + + + Stop Sign Text Shape + + + + + Triangle Text Shape + + + + + Inverted Triangle Text Shape + + + + + Chevron Text Shape + + + + + Inverted Chevron Text Shape + + + + + Inside Ring Text Shape + + + + + Outside Ring Text Shape + + + + + Upward Arch Text Shape + + + + + Downward Arch Text Shape + + + + + Circle Text Shape + + + + + Button Text Shape + + + + + Upward Pour Arch Text Shape + + + + + Downward Pour Arch Text Shape + + + + + Circle Pour Text Shape + + + + + Button Pour Text Shape + + + + + Upward Curve Text Shape + + + + + Downward Curve Text Shape + + + + + Upward Can Text Shape + + + + + Downward Can Text Shape + + + + + Wave 1 Text Shape + + + + + Wave 2 Text Shape + + + + + Double Wave 1 Text Shape + + + + + Wave 4 Text Shape + + + + + Inflate Text Shape + + + + + Deflate Text Shape + + + + + Bottom Inflate Text Shape + + + + + Bottom Deflate Text Shape + + + + + Top Inflate Text Shape + + + + + Top Deflate Text Shape + + + + + Deflate-Inflate Text Shape + + + + + Deflate-Inflate-Deflate Text Shape + + + + + Right Fade Text Shape + + + + + Left Fade Text Shape + + + + + Upward Fade Text Shape + + + + + Downward Fade Text Shape + + + + + Upward Slant Text Shape + + + + + Downward Slant Text Shape + + + + + Upward Cascade Text Shape + + + + + Downward Cascade Text Shape + + + + + + + Geometry Guide Name Properties + + + + + + Geometry Guide Formula Properties + + + + + + + Shape Guide Name + + + + + Shape Guide Formula + + + + + + + + Shape Guide + + + + + + + Adjustable Coordinate Methods + + + + + + Adjustable Angle Methods + + + + + + + X-Coordinate + + + + + Y-Coordinate + + + + + + + Left + + + + + Top + + + + + Right + + + + + Bottom Position + + + + + + + + Position + + + + + + Horizontal Adjustment Guide + + + + + Minimum Horizontal Adjustment + + + + + Maximum Horizontal Adjustment + + + + + Vertical Adjustment Guide + + + + + Minimum Vertical Adjustment + + + + + Maximum Vertical Adjustment + + + + + + + + Shape Position Coordinate + + + + + + Radial Adjustment Guide + + + + + Minimum Radial Adjustment + + + + + Maximum Radial Adjustment + + + + + Angle Adjustment Guide + + + + + Minimum Angle Adjustment + + + + + Maximum Angle Adjustment + + + + + + + + Position + + + + + + Connection Site Angle + + + + + + + + XY Adjust Handle + + + + + Polar Adjust Handle + + + + + + + + + Shape Connection Site + + + + + + + + Identifier + + + + + Index + + + + + + + + Move end point + + + + + + + + + Line end point + + + + + + + + Shape Arc Width Radius + + + + + Shape Arc Height Radius + + + + + Shape Arc Start Angle + + + + + Shape Arc Swing Angle + + + + + + + + Shape Path Point + + + + + + + + + Control points and end point + + + + + + + + Path Fill Mode + + + + + No Path Fill + + + + + Normal Path Fill + + + + + Lighten Path Fill + + + + + Lighten Path Fill Less + + + + + Darken Path Fill + + + + + Darken Path Fill Less + + + + + + + + + Close Shape Path + + + + + Move Path To + + + + + Draw Line To + + + + + Draw Arc To + + + + + Draw Quadratic Bezier Curve To + + + + + Draw Cubic Bezier Curve To + + + + + + Path Width + + + + + Path Height + + + + + Path Fill + + + + + Path Stroke + + + + + 3D Extrusion Allowed + + + + + + + + Shape Path + + + + + + + + + List of Shape Adjust Values + + + + + + Preset Shape + + + + + + + + Adjust Value List + + + + + + Preset Warp Shape + + + + + + + + Adjust Value List + + + + + List of Shape Guides + + + + + List of Shape Adjust Handles + + + + + List of Shape Connection Sites + + + + + Shape Text Rectangle + + + + + List of Shape Paths + + + + + + + + + Custom geometry + + + + + Preset geometry + + + + + + + + + Custom Geometry + + + + + Preset Text Warp + + + + + + + + + + Line End Type + + + + + None + + + + + Triangle Arrow Head + + + + + Stealth Arrow + + + + + Diamond + + + + + Oval + + + + + Arrow Head + + + + + + + Line End Width + + + + + Small + + + + + Medium + + + + + Large + + + + + + + Line End Length + + + + + Small + + + + + Medium + + + + + Large + + + + + + + + Line Head/End Type + + + + + Width of Head/End + + + + + Length of Head/End + + + + + + + + No Fill + + + + + Solid Fill + + + + + Gradient Fill + + + + + + + + + + + Miter Join Limit + + + + + + + + Round Line Join + + + + + Line Join Bevel + + + + + Miter Line Join + + + + + + + Preset Line Dash Value + + + + + Solid + + + + + Dot + + + + + Dash + + + + + Large Dash + + + + + Dash Dot + + + + + Large Dash Dot + + + + + Large Dash Dot Dot + + + + + System Dash + + + + + System Dot + + + + + System Dash Dot + + + + + System Dash Dot Dot + + + + + + + + Value + + + + + + + Dash Length + + + + + Space Length + + + + + + + + Dash Stop + + + + + + + + + Preset Dash + + + + + Custom Dash + + + + + + + End Line Cap + + + + + Round Line Cap + + + + + Square Line Cap + + + + + Flat Line Cap + + + + + + + Line Width + + + + + + + + + Alignment Type + + + + + Center Alignment + + + + + Inset Alignment + + + + + + + Compound Line Type + + + + + Single Line + + + + + Double Lines + + + + + Thick Thin Double Lines + + + + + Thin Thick Double Lines + + + + + Thin Thick Thin Triple Lines + + + + + + + + + + + + Line Head/End Style + + + + + Tail line end style + + + + + + + Line Width + + + + + Line Ending Cap Type + + + + + Compound Line Type + + + + + Stroke Alignment + + + + + + + + + Shape ID + + + + + + + + + + + + + + + 2D Transform for Individual Objects + + + + + + + + + + + + + Black and White Mode + + + + + + + + 2D Transform for Grouped Objects + + + + + + + + + + Black and White Mode + + + + + + + + + + + + + Style Matrix Index + + + + + + + + + + Identifier + + + + + + + + + + + Font Reference + + + + + + + + + + + + + + Visual Properties + + + + + + + + + + + + + Shape Default + + + + + Line Default + + + + + Text Default + + + + + + + + + + + + + + + + + Background 1 + + + + + Text 1 + + + + + Background 2 + + + + + Text 2 + + + + + Accent 1 + + + + + Accent 2 + + + + + Accent 3 + + + + + Accent 4 + + + + + Accent 5 + + + + + Accent 6 + + + + + Hyperlink + + + + + Followed Hyperlink + + + + + + + + + Master Color Mapping + + + + + Override Color Mapping + + + + + + + + + + + + + + + + Extra Color Scheme + + + + + + + + + Theme Elements + + + + + Object Defaults + + + + + Extra Color Scheme List + + + + + Custom Color List + + + + + + + Name + + + + + + + + Color Scheme + + + + + + + + + + + + Color Map + + + + + + + Theme + + + + + Theme Override + + + + + Theme Manager + + + + + + + + + + + + + Left Border Line Properties + + + + + Right Border Line Properties + + + + + Top Border Line Properties + + + + + Bottom Border Line Properties + + + + + Top-Left to Bottom-Right Border Line Properties + + + + + Bottom-Left to Top-Right Border Line Properties + + + + + Cell 3-D + + + + + + + + Left Margin + + + + + Right Margin + + + + + Top Margin + + + + + Bottom Margin + + + + + Text Direction + + + + + Anchor + + + + + Anchor Center + + + + + Horizontal Overflow + + + + + + + + + + Width + + + + + + + + Table Grid Column + + + + + + + + + Text Body + + + + + Table Cell Properties + + + + + + + Row Span + + + + + Grid Span + + + + + Horizontal Merge + + + + + Vertical Merge + + + + + + + + Table Cell + + + + + + + Height + + + + + + + + + + + Table Style + + + + + Table Style ID + + + + + + Extension List + + + + + + Right-to-Left + + + + + First Row + + + + + First Column + + + + + Last Row + + + + + Last Column + + + + + Banded Rows + + + + + Banded Columns + + + + + + + + Table Properties + + + + + Table Grid + + + + + Table Row + + + + + + + Table + + + + + + + + + + + + + + Bevel + + + + + Light Rig + + + + + + + Preset Material + + + + + + + + Fill + + + + + Fill Reference + + + + + + + + + + Line Reference + + + + + + + + + Effect + + + + + Effect Reference + + + + + + + + + Font + + + + + + + + On/Off Style Type + + + + + On + + + + + Off + + + + + Default + + + + + + + + + + + + + Bold + + + + + Italic + + + + + + + + Left Border + + + + + Right Border + + + + + Top Border + + + + + Bottom Border + + + + + Inside Horizontal Border + + + + + Inside Vertical Border + + + + + Top Left to Bottom Right Border + + + + + Top Right to Bottom Left Border + + + + + + + + + + + + + + + + Table Cell Borders + + + + + + + + + + + Table Cell Text Style + + + + + Table Cell Style + + + + + + + + + Table Background + + + + + Whole Table + + + + + Band 1 Horizontal + + + + + Band 2 Horizontal + + + + + Band 1 Vertical + + + + + Band 2 Vertical + + + + + Last Column + + + + + First Column + + + + + Last Row + + + + + Southeast Cell + + + + + Southwest Cell + + + + + First Row + + + + + Northeast Cell + + + + + Northwest Cell + + + + + + + Style ID + + + + + Name + + + + + + + + Table Style + + + + + + Default + + + + + + Table Style List + + + + + + + + + + + + Text Paragraph Properties + + + + + + End Paragraph Run Properties + + + + + + + Text Anchoring Types + + + + + Text Anchoring Type Enum ( Top ) + + + + + Text Anchor Enum ( Center ) + + + + + Text Anchor Enum ( Bottom ) + + + + + Text Anchor Enum ( Justified ) + + + + + Text Anchor Enum ( Distributed ) + + + + + + + Text Vertical Overflow + + + + + Text Overflow Enum ( Overflow ) + + + + + Text Overflow Enum ( Ellipsis ) + + + + + Text Overflow Enum ( Clip ) + + + + + + + Text Horizontal Overflow Types + + + + + Text Horizontal Overflow Enum ( Overflow ) + + + + + Text Horizontal Overflow Enum ( Clip ) + + + + + + + Vertical Text Types + + + + + Vertical Text Type Enum ( Horizontal ) + + + + + Vertical Text Type Enum ( Vertical ) + + + + + Vertical Text Type Enum ( Vertical 270 ) + + + + + Vertical Text Type Enum ( WordArt Vertical ) + + + + + Vertical Text Type Enum ( East Asian Vertical ) + + + + + Vertical Text Type Enum ( Mongolian Vertical ) + + + + + Vertical WordArt Right to Left + + + + + + + Text Wrapping Types + + + + + Text Wrapping Type Enum ( None ) + + + + + Text Wrapping Type Enum ( Square ) + + + + + + + Text Column Count + + + + + + + + + + + Default Paragraph Style + + + + + List Level 1 Text Style + + + + + List Level 2 Text Style + + + + + List Level 3 Text Style + + + + + List Level 4 Text Style + + + + + List Level 5 Text Style + + + + + List Level 6 Text Style + + + + + List Level 7 Text Style + + + + + List Level 8 Text Style + + + + + List Level 9 Text Style + + + + + + + + Text Font Scale Percentage + + + + + + + + + + Font Scale + + + + + Line Space Reduction + + + + + + + + + + No AutoFit + + + + + Normal AutoFit + + + + + Shape AutoFit + + + + + + + + + Preset Text Shape + + + + + + 3D Scene Properties + + + + + + + + Rotation + + + + + Paragraph Spacing + + + + + Text Vertical Overflow + + + + + Text Horizontal Overflow + + + + + Vertical Text + + + + + Text Wrapping Type + + + + + Left Inset + + + + + Top Inset + + + + + Right Inset + + + + + Bottom Inset + + + + + Number of Columns + + + + + Space Between Columns + + + + + Columns Right-To-Left + + + + + From WordArt + + + + + Anchor + + + + + Anchor Center + + + + + Force Anti-Alias + + + + + Text Upright + + + + + Compatible Line Spacing + + + + + + + + Body Properties + + + + + Text List Styles + + + + + Text Paragraphs + + + + + + + + + + + + Start Bullet At Number + + + + + + + + + Text Auto-number Schemes + + + + + Autonumber Enum ( alphaLcParenBoth ) + + + + + Autonumbering Enum ( alphaUcParenBoth ) + + + + + Autonumbering Enum ( alphaLcParenR ) + + + + + Autonumbering Enum ( alphaUcParenR ) + + + + + Autonumbering Enum ( alphaLcPeriod ) + + + + + Autonumbering Enum ( alphaUcPeriod ) + + + + + Autonumbering Enum ( arabicParenBoth ) + + + + + Autonumbering Enum ( arabicParenR ) + + + + + Autonumbering Enum ( arabicPeriod ) + + + + + Autonumbering Enum ( arabicPlain ) + + + + + Autonumbering Enum ( romanLcParenBoth ) + + + + + Autonumbering Enum ( romanUcParenBoth ) + + + + + Autonumbering Enum ( romanLcParenR ) + + + + + Autonumbering Enum ( romanUcParenR ) + + + + + Autonumbering Enum ( romanLcPeriod ) + + + + + Autonumbering Enum ( romanUcPeriod ) + + + + + Autonumbering Enum ( circleNumDbPlain ) + + + + + Autonumbering Enum ( circleNumWdBlackPlain ) + + + + + Autonumbering Enum ( circleNumWdWhitePlain ) + + + + + Autonumbering Enum ( arabicDbPeriod ) + + + + + Autonumbering Enum ( arabicDbPlain ) + + + + + Autonumbering Enum ( ea1ChsPeriod ) + + + + + Autonumbering Enum ( ea1ChsPlain ) + + + + + Autonumbering Enum ( ea1ChtPeriod ) + + + + + Autonumbering Enum ( ea1ChtPlain ) + + + + + Autonumbering Enum ( ea1JpnChsDbPeriod ) + + + + + Autonumbering Enum ( ea1JpnKorPlain ) + + + + + Autonumbering Enum ( ea1JpnKorPeriod ) + + + + + Autonumbering Enum ( arabic1Minus ) + + + + + Autonumbering Enum ( arabic2Minus ) + + + + + Autonumbering Enum ( hebrew2Minus ) + + + + + Autonumbering Enum ( thaiAlphaPeriod ) + + + + + Autonumbering Enum ( thaiAlphaParenR ) + + + + + Autonumbering Enum ( thaiAlphaParenBoth ) + + + + + Autonumbering Enum ( thaiNumPeriod ) + + + + + Autonumbering Enum ( thaiNumParenR ) + + + + + Autonumbering Enum ( thaiNumParenBoth ) + + + + + Autonumbering Enum ( hindiAlphaPeriod ) + + + + + Autonumbering Enum ( hindiNumPeriod ) + + + + + Autonumbering Enum ( hindiNumParenR ) + + + + + Autonumbering Enum ( hindiAlpha1Period ) + + + + + + + + + + Follow Text + + + + + Color Specified + + + + + + + Bullet Size Percentage + + + + + + + + + + + Value + + + + + + + Value + + + + + + + + Bullet Size Follows Text + + + + + Bullet Size Percentage + + + + + Bullet Size Points + + + + + + + + + + Follow text + + + + + Specified + + + + + + + + Bullet Autonumbering Type + + + + + Start Numbering At + + + + + + + Bullet Character + + + + + + + + Blip + + + + + + + + + + No Bullet + + + + + Auto-Numbered Bullet + + + + + Character Bullet + + + + + Picture Bullet + + + + + + + + + + + + Text Point + + + + + + + + + Text Non-Negative Point + + + + + + + + + Text Font Size + + + + + + + + + Panose Type + + + + + + + + Text Typeface + + + + + + + Text Typeface + + + + + Panose Setting + + + + + Similar Font Family + + + + + Similar Character Set + + + + + + Language ID + + + + + + Text Underline Types + + + + + Text Underline Enum ( None ) + + + + + Text Underline Enum ( Words ) + + + + + Text Underline Enum ( Single ) + + + + + Text Underline Enum ( Double ) + + + + + Text Underline Enum ( Heavy ) + + + + + Text Underline Enum ( Dotted ) + + + + + Text Underline Enum ( Heavy Dotted ) + + + + + Text Underline Enum ( Dashed ) + + + + + Text Underline Enum ( Heavy Dashed ) + + + + + Text Underline Enum ( Long Dashed ) + + + + + Text Underline Enum ( Heavy Long Dashed ) + + + + + Text Underline Enum ( Dot Dash ) + + + + + Text Underline Enum ( Heavy Dot Dash ) + + + + + Text Underline Enum ( Dot Dot Dash ) + + + + + Text Underline Enum ( Heavy Dot Dot Dash ) + + + + + Text Underline Enum ( Wavy ) + + + + + Text Underline Enum ( Heavy Wavy ) + + + + + Text Underline Enum ( Double Wavy ) + + + + + + + + + + + + + + Underline Follows Text + + + + + Underline Stroke + + + + + + + + + Underline Fill Properties Follow Text + + + + + Underline Fill + + + + + + + Text Strike Type + + + + + Text Strike Enum ( No Strike ) + + + + + Text Strike Enum ( Single Strike ) + + + + + Text Strike Enum ( Double Strike ) + + + + + + + Text Cap Types + + + + + Text Caps Enum ( None ) + + + + + Text Caps Enum ( Small ) + + + + + Text Caps Enum ( All ) + + + + + + + + + Line + + + + + + + Highlight Color + + + + + + + Latin Font + + + + + East Asian Font + + + + + Complex Script Font + + + + + Symbol Font + + + + + Click Hyperlink + + + + + Mouse-Over Hyperlink + + + + + + + Kumimoji + + + + + Language ID + + + + + Alternative Language + + + + + Font Size + + + + + Bold + + + + + Italics + + + + + Underline + + + + + Strikethrough + + + + + Kerning + + + + + Capitalization + + + + + Spacing + + + + + Normalize Heights + + + + + Baseline + + + + + No Proofing + + + + + Dirty + + + + + Spelling Error + + + + + SmartTag Clean + + + + + SmartTag ID + + + + + Bookmark Link Target + + + + + + + + + + + + Text Spacing Point + + + + + + + + + Text Spacing Percent + + + + + + + + + + Value + + + + + + + Value + + + + + + Text Margin + + + + + + + + + Text Indentation + + + + + + + + + Text Tab Alignment Types + + + + + Text Tab Alignment Enum ( Left) + + + + + Text Tab Alignment Enum ( Center ) + + + + + Text Tab Alignment Enum ( Right ) + + + + + Text Tab Alignment Enum ( Decimal ) + + + + + + + + Tab Position + + + + + Tab Alignment + + + + + + + + Tab Stop + + + + + + + + + Text Run Properties + + + + + + + + + Spacing Percent + + + + + Spacing Points + + + + + + + Text Alignment Types + + + + + Text Alignment Enum ( Left ) + + + + + Text Alignment Enum ( Center ) + + + + + Text Alignment Enum ( Right ) + + + + + Text Alignment Enum ( Justified ) + + + + + Text Alignment Enum ( Justified Low ) + + + + + Text Alignment Enum ( Distributed ) + + + + + Text Alignment Enum ( Thai Distributed ) + + + + + + + Font Alignment Types + + + + + Font Alignment Enum ( Automatic ) + + + + + Font Alignment Enum ( Top ) + + + + + Font Alignment Enum ( Center ) + + + + + Font Alignment Enum ( Baseline ) + + + + + Font Alignment Enum ( Bottom ) + + + + + + + Text Indent Level Type + + + + + + + + + + + Line Spacing + + + + + Space Before + + + + + Space After + + + + + + + + + Tab List + + + + + Default Text Run Properties + + + + + + + Left Margin + + + + + Right Margin + + + + + Level + + + + + Indent + + + + + Alignment + + + + + Default Tab Size + + + + + Right To Left + + + + + East Asian Line Break + + + + + Font Alignment + + + + + Latin Line Break + + + + + Hanging Punctuation + + + + + + + + Text Character Properties + + + + + Text Paragraph Properties + + + + + + + Field ID + + + + + Field Type + + + + + + + + Text Run + + + + + Text Line Break + + + + + Text Field + + + + + + + + + + + + Text Character Properties + + + + + Text String + + + + + + + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-picture.xsd b/tests/resources/schema/ecma-376/dml-picture.xsd new file mode 100644 index 0000000000..9a8247e768 --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-picture.xsd @@ -0,0 +1,44 @@ + + + + + + + + + + Non-Visual Drawing Properties + + + + + Non-Visual Picture Drawing Properties + + + + + + + + + Non-Visual Picture Properties + + + + + Picture Fill + + + + + Shape Properties + + + + + + + Picture + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-spreadsheetDrawing.xsd b/tests/resources/schema/ecma-376/dml-spreadsheetDrawing.xsd new file mode 100644 index 0000000000..511fc23390 --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-spreadsheetDrawing.xsd @@ -0,0 +1,410 @@ + + + + + + + + + + + Locks With Sheet Flag + + + + + Prints With Sheet Flag + + + + + + + + Non-Visual Drawing Properties + + + + + Connection Non-Visual Shape Properties + + + + + + + + + Non-Visual Properties for a Shape + + + + + Shape Properties + + + + + + Shape Text Body + + + + + + Reference to Custom Function + + + + + Text Link + + + + + Lock Text Flag + + + + + Publish to Server Flag + + + + + + + + Connection Non-Visual Properties + + + + + Non-Visual Connector Shape Drawing Properties + + + + + + + + + Non-Visual Properties for a Connection Shape + + + + + Connector Shape Properties + + + + + + + Reference to Custom Function + + + + + Publish to Server Flag + + + + + + + + + Non-Visual Picture Drawing Properties + + + + + + + + + Non-Visual Properties for a Picture + + + + + Picture Fill + + + + + + Shape Style + + + + + + Reference To Custom Function + + + + + Publish to Server Flag + + + + + + + + Connection Non-Visual Properties + + + + + Non-Visual Graphic Frame Drawing Properties + + + + + + + + + Non-Visual Properties for a Graphic Frame + + + + + 2D Transform for Graphic Frames + + + + + + + Reference To Custom Function + + + + + Publish to Server Flag + + + + + + + + Connection Non-Visual Properties + + + + + Non-Visual Group Shape Drawing Properties + + + + + + + + + Non-Visual Properties for a Group Shape + + + + + Group Shape Properties + + + + + + Shape + + + + + Group Shape + + + + + + Connection Shape + + + + + Picture + + + + + + + + + + + Shape + + + + + Group Shape + + + + + Graphic Frame + + + + + Connection Shape + + + + + + + + + Column ID + + + + + + + + Row ID + + + + + + + + + + Column) + + + + + Column Offset + + + + + Row + + + + + Row Offset + + + + + + + Resizing Behaviors + + + + + Move and Resize With Anchor Cells + + + + + Move With Cells but Do Not Resize + + + + + Do Not Move or Resize With Underlying Rows/Columns + + + + + + + + + Starting Anchor Point + + + + + Ending Anchor Point + + + + + + Client Data + + + + + + Positioning and Resizing Behaviors + + + + + + + + + + + + + + + + Position + + + + + Shape Extent + + + + + + + + + + + Two Cell Anchor Shape Size + + + + + One Cell Anchor Shape Size + + + + + Absolute Anchor Shape Size + + + + + + + + + + + + Worksheet Drawing + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/dml-wordprocessingDrawing.xsd b/tests/resources/schema/ecma-376/dml-wordprocessingDrawing.xsd new file mode 100644 index 0000000000..3955cdf0cb --- /dev/null +++ b/tests/resources/schema/ecma-376/dml-wordprocessingDrawing.xsd @@ -0,0 +1,557 @@ + + + + + + + + Additional Extent on Left Edge + + + + + Additional Extent on Top Edge + + + + + Additional Extent on Right Edge + + + + + Additional Extent on Bottom Edge + + + + + + Distance from Text + + + + + + + + Drawing Object Size + + + + + Inline Wrapping Extent + + + + + Drawing Object Non-Visual Properties + + + + + Common DrawingML Non-Visual Properties + + + + + + + Distance From Text on Top Edge + + + + + Distance From Text on Bottom Edge + + + + + Distance From Text on Left Edge + + + + + Distance From Text on Right Edge + + + + + + Text Wrapping Location + + + + + Both Sides + + + + + Left Side Only + + + + + Right Side Only + + + + + Largest Side Only + + + + + + + + + Wrapping Polygon Start + + + + + Wrapping Polygon Line End Position + + + + + + Wrapping Points Modified + + + + + + + + + Object Extents Including Effects + + + + + + Text Wrapping Location + + + + + Distance From Text (Top) + + + + + Distance From Text on Bottom Edge + + + + + Distance From Text on Left Edge + + + + + Distance From Text on Right Edge + + + + + + + + Tight Wrapping Extents Polygon + + + + + + Text Wrapping Location + + + + + Distance From Test on Left Edge + + + + + Distance From Text on Right Edge + + + + + + + + Wrapping Polygon + + + + + + Text Wrapping Location + + + + + Distance From Text on Left Edge + + + + + Distance From Text on Right Edge + + + + + + + + Wrapping Boundaries + + + + + + Distance From Text on Top Edge + + + + + Distance From Text on Bottom Edge + + + + + + + + + No Text Wrapping + + + + + Square Wrapping + + + + + Tight Wrapping + + + + + Through Wrapping + + + + + Top and Bottom Wrapping + + + + + + + + Absolute Position Offset Value + + + + + + Relative Horizontal Alignment Positions + + + + + Left Alignment + + + + + Right Alignment + + + + + Center Alignment + + + + + Inside + + + + + Outside + + + + + + + Horizontal Relative Positioning + + + + + Page Margin + + + + + Page Edge + + + + + Column + + + + + Character + + + + + Left Margin + + + + + Right Margin + + + + + Inside Margin + + + + + Outside Margin + + + + + + + + + + Relative Horizontal Alignment + + + + + Absolute Position Offset + + + + + + + Horizontal Position Relative Base + + + + + + Vertical Alignment Definition + + + + + Top + + + + + Bottom + + + + + Center Alignment + + + + + Inside + + + + + Outside + + + + + + + Vertical Relative Positioning + + + + + Page Margin + + + + + Page Edge + + + + + Paragraph + + + + + Line + + + + + Top Margin + + + + + Bottom Margin + + + + + Inside Margin + + + + + Outside Margin + + + + + + + + + + Relative Vertical Alignment + + + + + + + + Vertical Position Relative Base + + + + + + + + Simple Positioning Coordinates + + + + + Horizontal Positioning + + + + + Vertical Positioning + + + + + Inline Drawing Object Extents + + + + + + + Drawing Object Non-Visual Properties + + + + + + + + Distance From Text on Top Edge + + + + + Distance From Text on Bottom Edge + + + + + Distance From Text on Left Edge + + + + + Distance From Text on Right Edge + + + + + Page Positioning + + + + + Relative Z-Ordering Position + + + + + Display Behind Document Text + + + + + Lock Anchor + + + + + Layout In Table Cell + + + + + Hidden + + + + + Allow Objects to Overlap + + + + + + Inline DrawingML Object + + + + + Anchor for Floating DrawingML Object + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/pml.xsd b/tests/resources/schema/ecma-376/pml.xsd new file mode 100644 index 0000000000..64f4b0aa5a --- /dev/null +++ b/tests/resources/schema/ecma-376/pml.xsd @@ -0,0 +1,4968 @@ + + + + + + + + + + + + + + + + + Transition Slide Direction Type + + + + + Transition Slide Direction Enum ( Left ) + + + + + Transition Slide Direction Enum ( Up ) + + + + + Transition Slide Direction ( Right ) + + + + + Transition Slide Direction Enum ( Down ) + + + + + + + Transition Corner Direction Type + + + + + Transition Corner Direction Enum ( Left-Up ) + + + + + Transition Corner Direction Enum ( Right-Up ) + + + + + Transition Corner Direction Enum ( Left-Down ) + + + + + Transition Corner Direction Enum ( Right-Down ) + + + + + + + Transition In/Out Direction Type + + + + + Transition In/Out Direction Enum ( Out ) + + + + + Transition In/Out Direction Enum ( In ) + + + + + + + + Direction + + + + + + + Direction + + + + + + Transition Eight Direction + + + + + + + Direction + + + + + + + Transition Direction + + + + + + + Direction + + + + + + + Transition Through Black + + + + + + + Orientation + + + + + Direction + + + + + + + Spokes + + + + + + + + Sound + + + + + + Loop Sound + + + + + + + + Start Sound Action + + + + + Stop Sound Action + + + + + + + Transition Speed + + + + + low + + + + + Medium + + + + + Fast + + + + + + + + + + Blinds Slide Transition + + + + + Checker Slide Transition + + + + + Circle Slide Transition + + + + + Dissolve Slide Transition + + + + + Comb Slide Transition + + + + + Cover Slide Transition + + + + + Cut Slide Transition + + + + + Diamond Slide Transition + + + + + Fade Slide Transition + + + + + Newsflash Slide Transition + + + + + Plus Slide Transition + + + + + Pull Slide Transition + + + + + Push Slide Transition + + + + + Random Slide Transition + + + + + Random Bar Slide Transition + + + + + Split Slide Transition + + + + + Strips Slide Transition + + + + + Wedge Slide Transition + + + + + Wheel Slide Transition + + + + + Wipe Slide Transition + + + + + Zoom Slide Transition + + + + + + Sound Action + + + + + + + Transition Speed + + + + + Advance on Click + + + + + Advance after time + + + + + + Indefinite Time Declaration + + + + + Indefinite Type Enum + + + + + + + Time + + + + + + Time Node ID + + + + + + + Time + + + + + + + Value + + + + + + Iterate Type + + + + + Element + + + + + Word + + + + + Letter + + + + + + + + + Time Absolute + + + + + Time Percentage + + + + + + Iterate Type + + + + + Backwards + + + + + + + Shape ID + + + + + + + + Character Range + + + + + Paragraph Text Range + + + + + + + Chart Subelement Type + + + + + Chart Build Element Type Enum ( Grid Legend ) + + + + + Chart Build Element Type Enum ( Series ) + + + + + Chart Build Element Type Enum ( Category ) + + + + + Chart Build Element Type Enum ( Point in Series ) + + + + + Chart Build Element Type Enum ( Point in Cat ) + + + + + + + + Type + + + + + Level + + + + + + + + Background + + + + + Subshape + + + + + OLE Chart Element + + + + + Text Element + + + + + Graphic Element + + + + + + Shape ID + + + + + + + + Slide Target + + + + + Sound Target + + + + + Shape Target + + + + + Ink Target + + + + + + + + Value + + + + + + Trigger RunTime Node + + + + + Trigger RunTime Node ( First ) + + + + + Trigger RunTime Node ( Last ) + + + + + Trigger RunTime Node Enum ( All ) + + + + + + + + Value + + + + + + Trigger Event + + + + + Trigger Event Enum ( On Begin ) + + + + + Trigger Event Enum ( On End ) + + + + + Trigger Event Enum ( Begin ) + + + + + Trigger Event Enum ( End ) + + + + + Trigger Event Enum ( On Click ) + + + + + Trigger Event Enum ( On Double Click ) + + + + + Trigger Event Enum ( On Mouse Over ) + + + + + Trigger Event Enum ( On Mouse Out ) + + + + + Trigger Event Enum ( On Next ) + + + + + Trigger Event Enum ( On Previous ) + + + + + Trigger Event Enum ( On Stop Audio ) + + + + + + + + + Target Element Trigger Choice + + + + + Time Node + + + + + Runtime Node Trigger Choice + + + + + + Trigger Event + + + + + Trigger Delay + + + + + + + + Condition + + + + + + + + + Parallel Time Node + + + + + Sequence Time Node + + + + + Exclusive + + + + + Animate + + + + + Animate Color Behavior + + + + + Animate Effect + + + + + Animate Motion + + + + + Animate Rotation + + + + + Animate Scale + + + + + Command + + + + + Set Time Node Behavior + + + + + Audio + + + + + Video + + + + + + + Time Node Preset Class Type + + + + + Preset Type Enum ( Entrance ) + + + + + Exit + + + + + Preset Type Enum ( Emphasis ) + + + + + Preset Type Enum ( Path ) + + + + + Preset Type Enum ( Verb ) + + + + + Preset Type Enum ( Media Call ) + + + + + + + Time Node Restart Type + + + + + Restart Enum ( Always ) + + + + + Restart Enum ( When Not Active ) + + + + + Restart Enum ( Never ) + + + + + + + Time Node Fill Type + + + + + Remove + + + + + Freeze + + + + + TimeNode Fill Type Enum ( Hold ) + + + + + Transition + + + + + + + Time Node Sync Type + + + + + TimeNode Sync Enum ( Can Slip ) + + + + + TimeNode Sync Enum ( Locked ) + + + + + + + Time Node Master Relation + + + + + TimeNode Master Relation Enum ( Same Click ) + + + + + TimeNode Master Relation Enum ( Last Click ) + + + + + TimeNode Master Relation Enum ( Next Click ) + + + + + + + Time Node Type + + + + + Node Type Enum ( Click Effect ) + + + + + Node Type Enum ( With Effect ) + + + + + Node Type Enum ( After Effect ) + + + + + Node Type Enum ( Main Sequence ) + + + + + Node Type Enum ( Interactive Sequence ) + + + + + Node Type Enum ( Click Paragraph ) + + + + + Node Type Enum ( With Group ) + + + + + Node Type Enum ( After Group ) + + + + + Node Type Enum ( Timing Root ) + + + + + + + + + Start Conditions List + + + + + End Conditions List + + + + + EndSync + + + + + Iterate + + + + + Children Time Node List + + + + + Sub-TimeNodes List + + + + + + ID + + + + + Preset ID + + + + + Preset Types + + + + + Preset SubType + + + + + Duration + + + + + Repeat Count + + + + + Repeat Duration + + + + + Speed + + + + + Acceleration + + + + + Deceleration + + + + + Auto Reverse + + + + + Restart + + + + + Fill + + + + + Synchronization Behavior + + + + + Time Filter + + + + + Event Filter + + + + + Display + + + + + Master Relation + + + + + Build level + + + + + Group ID + + + + + After Effect + + + + + Node Type + + + + + Node Placeholder + + + + + + + + Parallel TimeNode + + + + + + + Next Action Type + + + + + Next Action Type Enum ( None ) + + + + + Next Action Type Enum ( Seek ) + + + + + + + Previous Action Type + + + + + Previous Action Type Enum ( None ) + + + + + Previous Action Type Enum ( Skip Timed ) + + + + + + + + + Common TimeNode Properties + + + + + Previous Conditions List + + + + + Next Conditions List + + + + + + Concurrent + + + + + Previous Action + + + + + Next Action + + + + + + + + Common TimeNode Properties + + + + + + + + + Attribute Name + + + + + + + Behavior Additive Type + + + + + Additive Enum ( Base ) + + + + + Additive Enum ( Sum ) + + + + + Additive Enum ( Replace ) + + + + + Additive Enum ( Multiply ) + + + + + None + + + + + + + Behavior Accumulate Type + + + + + Accumulate Enum ( None ) + + + + + Accumulate Enum ( Always ) + + + + + + + Behavior Transform Type + + + + + Point + + + + + Image + + + + + + + Behavior Override Type + + + + + Override Enum ( Normal ) + + + + + Override Enum ( Child Style ) + + + + + + + + + + Target Element + + + + + Attribute Name List + + + + + + Additive + + + + + Accumulate + + + + + Transform Type + + + + + From + + + + + To + + + + + By + + + + + Runtime Context + + + + + Override + + + + + + + Value + + + + + + + Value + + + + + + + Value + + + + + + + Value + + + + + + + + Boolean Variant + + + + + Integer + + + + + Float Value + + + + + String Value + + + + + Color Value + + + + + + + Animation Time + + + + + + + + Value + + + + + + Time + + + + + Formula + + + + + + + + Time Animate Value + + + + + + + Time List Animate Behavior Calculate Mode + + + + + Calc Mode Enum ( Discrete ) + + + + + Calc Mode Enum ( Linear ) + + + + + Calc Mode Enum ( Formula ) + + + + + + + Time List Animate Behavior Value Types + + + + + Value Type Enum ( String ) + + + + + Value Type Enum ( Number ) + + + + + Value Type Enum ( Color ) + + + + + + + + + + Time Animated Value List + + + + + + By + + + + + From + + + + + To + + + + + Calculation Mode + + + + + Value Type + + + + + + + Red + + + + + Green + + + + + Blue + + + + + + + Hue + + + + + Saturation + + + + + Lightness + + + + + + + + RGB + + + + + HSL + + + + + + + Time List Animate Color Space + + + + + Color Space Enum ( RGB ) + + + + + Color Space Enum ( HSL ) + + + + + + + Time List Animate Color Direction + + + + + Direction Enum ( Clockwise ) + + + + + Counter-Clockwise + + + + + + + + + + By + + + + + From + + + + + To + + + + + + Color Space + + + + + Direction + + + + + + Time List Animate Effect Transition + + + + + Transition Enum ( In ) + + + + + Transition Enum ( Out ) + + + + + Transition Enum ( None ) + + + + + + + + + + Progress + + + + + + Transition + + + + + Filter + + + + + Property List + + + + + + Time List Animate Motion Behavior Origin + + + + + Origin Enum ( Parent ) + + + + + Origin Enum ( Layout ) + + + + + + + Time List Animate Motion Path Edit Mode + + + + + Path Edit Mode Enum ( Relative ) + + + + + Path Edit Mode Enum ( Fixed ) + + + + + + + + X coordinate + + + + + Y coordinate + + + + + + + + + + From + + + + + + Rotation Center + + + + + + Origin + + + + + Path + + + + + Path Edit Mode + + + + + Relative Angle + + + + + Points Types + + + + + + + + + + By + + + + + From + + + + + To + + + + + + + + + By + + + + + + To + + + + + + Zoom Content + + + + + + Command Type + + + + + Command Type Enum ( Event ) + + + + + Command Type Enum ( Call ) + + + + + Command Type Enum ( Verb ) + + + + + + + + + + + Command Type + + + + + Command + + + + + + + + Common Behavior + + + + + To + + + + + + + + + Common Time Node Properties + + + + + + + Volume + + + + + Mute + + + + + Number of Slides + + + + + Show When Stopped + + + + + + + + Common Media Node Properties + + + + + + Is Narration + + + + + + + + Common Media Node Properties + + + + + + Full Screen + + + + + + + Shape ID + + + + + Group ID + + + + + Expand UI + + + + + + + + Time Node List + + + + + + Level + + + + + + + + Template Effects + + + + + + + Paragraph Build Type + + + + + All At Once + + + + + Paragraph + + + + + Custom + + + + + Whole + + + + + + + + + Template effects + + + + + + + Build Types + + + + + Build Level + + + + + Animate Background + + + + + Auto Update Animation Background + + + + + Reverse + + + + + Auto Advance Time + + + + + + Diagram Build Types + + + + + Diagram Build Type Enum ( Whole ) + + + + + Diagram Build Type Enum ( Depth By Node ) + + + + + Diagram Build Type Enum ( Depth By Branch ) + + + + + Diagram Build Type Enum ( Breadth By Node ) + + + + + Diagram Build Type Enum ( Breadth By Level ) + + + + + Diagram Build Type Enum ( Clockwise ) + + + + + Diagram Build Type Enum ( Clockwise-In ) + + + + + Diagram Build Type Enum ( Clockwise-Out ) + + + + + Diagram Build Type Enum ( Counter-Clockwise ) + + + + + Diagram Build Type Enum ( Counter-Clockwise-In ) + + + + + Diagram Build Type Enum ( Counter-Clockwise-Out ) + + + + + Diagram Build Type Enum ( In-By-Ring ) + + + + + Diagram Build Type Enum ( Out-By-Ring ) + + + + + Diagram Build Type Enum ( Up ) + + + + + Diagram Build Type Enum ( Down ) + + + + + Diagram Build Type Enum ( All At Once ) + + + + + Diagram Build Type Enum ( Custom ) + + + + + + + + + Diagram Build Types + + + + + + OLE Chart Build Type + + + + + Chart Build Type Enum ( All At Once ) + + + + + Chart Build Type Enum ( Series ) + + + + + Chart Build Type Enum ( Category ) + + + + + Chart Build Type Enum ( Series Element ) + + + + + Chart Build Type Enum ( Category Element ) + + + + + + + + + Build + + + + + Animate Background + + + + + + + + Build As One + + + + + Build Sub Elements + + + + + + + + + + Build Paragraph + + + + + Build Diagram + + + + + Build OLE Chart + + + + + Build Graphics + + + + + + + + + + Build List + + + + + + + + + + + + Name string + + + + + + Direction + + + + + Horizontal + + + + + Vertical + + + + + + + Index + + + + + + + Start + + + + + End + + + + + + + Relationship ID + + + + + + + + Presentation Slide + + + + + + + + Custom Show Identifier + + + + + + + + All Slides + + + + + Slide Range + + + + + Custom Show + + + + + + + + Relationship ID + + + + + + + Relationship ID + + + + + + + + Customer Data + + + + + Customer Data Tags + + + + + + + + + + + Uniform Resource Identifier + + + + + + + + Extension + + + + + + + + + + + + + + + + Modify + + + + + + + + + + + + + + Comment Author ID + + + + + Comment Author Name + + + + + Comment Author Initials + + + + + Index of Comment Author's last comment + + + + + Comment Author Color Index + + + + + + + + Comment Author + + + + + + + List of Comment Authors + + + + + + + Comment Position + + + + + Comment's Text Content + + + + + + + Comment Author ID + + + + + Comment Date/Time + + + + + Comment Index + + + + + + + + Comment + + + + + + + Comment List + + + + + + + + + + + + OLE Object Shape ID + + + + + OLE Object Name + + + + + Show OLE Object As Icon + + + + + Relationship ID + + + + + Image Width + + + + + Image Height + + + + + + OLE Object to Follow Color Scheme + + + + + None + + + + + Full + + + + + Text and Background + + + + + + + + + + + Color Scheme Properties for OLE Object + + + + + + + + + + Update Linked OLE Objects Automatically + + + + + + + + Embedded OLE Object or Control + + + + + Linked OLE Object or Control + + + + + + + OLE ProgID + + + + + + Global Element for OLE Objects and Controls + + + + + + + + + + + + + Embedded Control + + + + + + + + + + + + + + Slide Identifier + + + + + + + + + + + + + Slide Identifier + + + + + Relationship Identifier + + + + + + + + Slide ID + + + + + + + Slide Master ID + + + + + + + + + + + + Slide Master Identifier + + + + + Relationship Identifier + + + + + + + + Slide Master ID + + + + + + + + + + + Relationship Identifier + + + + + + + + Notes Master ID + + + + + + + + + + + Relationship Identifier + + + + + + + + Handout Master ID + + + + + + + + Relationship Identifier + + + + + + + + Embedded Font Name + + + + + Regular Embedded Font + + + + + Bold Embedded Font + + + + + Italic Embedded Font + + + + + Bold Italic Embedded Font + + + + + + + + + Embedded Font + + + + + + + + Relationship Identifier + + + + + + + + List of Presentation Slides + + + + + + + Custom Show Name + + + + + Custom Show ID + + + + + + + + Custom Show + + + + + + + Photo Album Layout Definition + + + + + Fit Photos to Slide + + + + + 1 Photo per Slide + + + + + 2 Photos per Slide + + + + + 4 Photos per Slide + + + + + 1 Photo per Slide with Titles + + + + + 2 Photos per Slide with Titles + + + + + 4 Photos per Slide with Titles + + + + + + + Photo Album Shape for Photo Mask + + + + + Rectangle Photo Frame + + + + + Rounded Rectangle Photo Frame + + + + + Simple White Photo Frame + + + + + Simple Black Photo Frame + + + + + Compound Black Photo Frame + + + + + Center Shadow Photo Frame + + + + + Soft Edge Photo Frame + + + + + + + + + + + Black and White + + + + + Show/Hide Captions + + + + + Photo Album Layout + + + + + Frame Type + + + + + + Slide Size Coordinate + + + + + + + + + Slide Size Type + + + + + Screen 4x3 + + + + + Letter + + + + + A4 + + + + + 35mm Film + + + + + Overhead + + + + + Banner + + + + + Custom + + + + + Ledger + + + + + A3 + + + + + B4ISO + + + + + B5ISO + + + + + B4JIS + + + + + B5JIS + + + + + Hagaki Card + + + + + Screen 16x9 + + + + + Screen 16x10 + + + + + + + + Extent Length + + + + + Extent Width + + + + + Type of Size + + + + + + + Language + + + + + Invalid Kinsoku Start Characters + + + + + Invalid Kinsoku End Characters + + + + + + Bookmark ID Seed + + + + + + + + + Cryptographic Provider Type + + + + + RSA AES Encryption Scheme + + + + + RSA Full Encryption Scheme + + + + + Invalid Encryption Scheme + + + + + + + Cryptographic Algorithm Classes + + + + + Hash Algorithm Class + + + + + Invalid Algorithm Class + + + + + + + Cryptographic Algorithm Type + + + + + Any Algorithm Type + + + + + Invalid Algorithm Type + + + + + + + + Cryptographic Provider Type + + + + + Cryptographic Algorithm Class + + + + + Cryptographic Algorithm Type + + + + + Cryptographic Hashing Algorithm + + + + + Iterations to Run Hashing Algorithm + + + + + Salt for Password Verifier + + + + + Password Hash + + + + + Cryptographic Provider + + + + + Cryptographic Algorithm Extensibility + + + + + Algorithm Extensibility Source + + + + + Cryptographic Provider Type Extensibility + + + + + Provider Type Extensibility Source + + + + + + + + List of Slide Master IDs + + + + + List of Notes Master IDs + + + + + List of Handout Master IDs + + + + + List of Slide IDs + + + + + Presentation Slide Size + + + + + Notes Slide Size + + + + + Smart Tags + + + + + Embedded Font List + + + + + List of Custom Shows + + + + + Photo Album Information + + + + + List of Customer Data Buckets + + + + + Kinsoku Settings + + + + + Presentation Default Text Style + + + + + Modification Verifier + + + + + Extension List + + + + + + Server Zoom + + + + + First Slide Number + + + + + Show Header and Footer Placeholders on Titles + + + + + Right-To-Left Views + + + + + Remove Personal Information on Save + + + + + Compatibility Mode + + + + + Strict First and Last Characters + + + + + Embed True Type Fonts + + + + + Save Subset Fonts + + + + + Automatically Compress Pictures + + + + + Bookmark ID Seed + + + + + + Presentation + + + + + + + + + + Web browsers supported for HTML output + + + + + Browser v4 + + + + + Browser v3 + + + + + Browser v3v4 + + + + + + + + + + + + Show Speaker Notes + + + + + Browser Support Target + + + + + HTML Output Title + + + + + Publish Path + + + + + + HTML Slide Navigation Control Colors + + + + + Non-specific Colors + + + + + Browser Colors + + + + + Presentation Text Colors + + + + + Presentation Accent Colors + + + + + White Text on Black Colors + + + + + Black Text on White Colors + + + + + + + HTML/Web Screen Size Target + + + + + HTML/Web Size Enumeration 544x376 + + + + + HTML/Web Size Enumeration 640x480 + + + + + HTML/Web Size Enumeration 720x515 + + + + + HTML/Web Size Enumeration 800x600 + + + + + HTML/Web Size Enumeration 1024x768 + + + + + HTML/Web Size Enumeration 1152x882 + + + + + HTML/Web Size Enumeration 1152x900 + + + + + HTML/Web Size Enumeration 1280x1024 + + + + + HTML/Web Size Enumeration 1600x1200 + + + + + HTML/Web Size Enumeration 1800x1400 + + + + + HTML/Web Size Enumeration 1920x1200 + + + + + + + Web Encoding + + + + + + + + + + Show animation in HTML output + + + + + Resize graphics in HTML output + + + + + Allow PNG in HTML output + + + + + Rely on VML for HTML output + + + + + Organize HTML output in folders + + + + + Use long file names in HTML output + + + + + Image size for HTML output + + + + + Encoding for HTML output + + + + + Slide Navigation Colors for HTML output + + + + + + Default print output + + + + + Slides + + + + + 1 Slide / Handout Page + + + + + 2 Slides / Handout Page + + + + + 3 Slides / Handout Page + + + + + 4 Slides / Handout Page + + + + + 6 Slides / Handout Page + + + + + 9 Slides / Handout Page + + + + + Notes + + + + + Outline + + + + + + + Print Color Mode + + + + + Black and White Mode + + + + + Grayscale Mode + + + + + Color Mode + + + + + + + + + + + Print Output + + + + + Print Color Mode + + + + + Print Hidden Slides + + + + + Scale to Fit Paper when printing + + + + + Frame slides when printing + + + + + + + Show Scroll Bar in Window + + + + + + + Restart Show + + + + + + + + Presenter Slide Show Mode + + + + + Browse Slide Show Mode + + + + + Kiosk Slide Show Mode + + + + + + + + + + + Pen Color for Slide Show + + + + + + + Loop Slide Show + + + + + Show Narration in Slide Show + + + + + Show Animation in Slide Show + + + + + Use Timings in Slide Show + + + + + + + + HTML Publishing Properties + + + + + Web Properties + + + + + Printing Properties + + + + + Presentation-wide Show Properties + + + + + Color MRU + + + + + + + + Presentation-wide Properties + + + + + + + + + + + + + + + + + + + Slide Number Placeholder + + + + + Header Placeholder + + + + + Footer Placeholder + + + + + Date/Time Placeholder + + + + + + Placeholder IDs + + + + + Title + + + + + Body + + + + + Centered Title + + + + + Subtitle + + + + + Date and Time + + + + + Slide Number + + + + + Footer + + + + + Header + + + + + Object + + + + + Chart + + + + + Table + + + + + Clip Art + + + + + Diagram + + + + + Media + + + + + Slide Image + + + + + Picture + + + + + + + Placeholder Size + + + + + Full + + + + + Half + + + + + Quarter + + + + + + + + + + + Placeholder Type + + + + + Placeholder Orientation + + + + + Placeholder Size + + + + + Placeholder Index + + + + + Placeholder has custom prompt + + + + + + + + Placeholder Shape + + + + + + Customer Data List + + + + + + + Is a Photo Album + + + + + Is User Drawn + + + + + + + + Non-Visual Drawing Properties + + + + + Non-Visual Drawing Properties for a Shape + + + + + Application Non-Visual Drawing Properties + + + + + + + + + Non-Visual Properties for a Shape + + + + + + Shape Style + + + + + Shape Text Body + + + + + + + Use Background Fill + + + + + + + + Non-Visual Drawing Properties + + + + + Non-Visual Connector Shape Drawing Properties + + + + + Application Non-Visual Drawing Properties + + + + + + + + + Non-Visual Properties for a Connection Shape + + + + + Shape Properties + + + + + Connector Shape Style + + + + + + + + + + + Non-Visual Picture Drawing Properties + + + + + + + + + + Non-Visual Properties for a Picture + + + + + Picture Fill + + + + + + + + + + + + Non-Visual Drawing Properties + + + + + Non-Visual Graphic Frame Drawing Properties + + + + + Application Non-Visual Drawing Properties + + + + + + + + + Non-Visual Properties for a Graphic Frame + + + + + 2D Transform for Graphic Frame + + + + + + Extension List with Modification Flag + + + + + + + + + Non-visual Drawing Properties + + + + + Non-Visual Group Shape Drawing Properties + + + + + Non-Visual Properties + + + + + + + + + Non-Visual Properties for a Group Shape + + + + + Group Shape Properties + + + + + + Shape + + + + + Group Shape + + + + + Graphic Frame + + + + + Connection Shape + + + + + Picture + + + + + + + + + + + Color Scheme Map + + + + + + + + + Color Scheme Map Override + + + + + + + + Show Master Shapes + + + + + Show Master Placeholder Animations + + + + + + + + + + + + Shade to Title + + + + + + + + Background Properties + + + + + Background Style Reference + + + + + + + + + + + Black and White Mode + + + + + + + + Slide Background + + + + + Shape Tree + + + + + Customer Data List + + + + + List of controls + + + + + + + Name + + + + + + + + Common slide data for slides + + + + + + Slide Transition + + + + + Slide Timing Information for a Slide + + + + + + + + Show Slide in Slide Show + + + + + + Presentation Slide + + + + + Slide Layout Type + + + + + Slide Layout Type Enumeration ( Title ) + + + + + Slide Layout Type Enumeration ( Text ) + + + + + Slide Layout Type Enumeration ( Two Column Text ) + + + + + Slide Layout Type Enumeration ( Table ) + + + + + Slide Layout Type Enumeration ( Text and Chart ) + + + + + Slide Layout Type Enumeration ( Chart and Text ) + + + + + Slide Layout Type Enumeration ( Diagram ) + + + + + Chart + + + + + Text and Clip Art + + + + + Clip Art and Text + + + + + Slide Layout Type Enumeration ( Title Only ) + + + + + Slide Layout Type Enumeration ( Blank ) + + + + + Slide Layout Type Enumeration ( Text and Object ) + + + + + Slide Layout Type Enumeration ( Object and Text ) + + + + + Object + + + + + Title and Object + + + + + Slide Layout Type Enumeration ( Text and Media ) + + + + + Slide Layout Type Enumeration ( Media and Text ) + + + + + Slide Layout Type Enumeration ( Object over Text) + + + + + Slide Layout Type Enumeration ( Text over Object) + + + + + Text and Two Objects + + + + + Two Objects and Text + + + + + Two Objects over Text + + + + + Four Objects + + + + + Vertical Text + + + + + Clip Art and Vertical Text + + + + + Vertical Title and Text + + + + + Vertical Title and Text Over Chart + + + + + Two Objects + + + + + Object and Two Object + + + + + Two Objects and Object + + + + + Slide Layout Type Enumeration ( Custom ) + + + + + Section Header + + + + + Two Text and Two Objects + + + + + Title, Object, and Caption + + + + + Picture and Caption + + + + + + + + + Common slide data for slide layouts + + + + + + Slide Transition for a Slide Layout + + + + + Slide Timing Information for a Slide Layout + + + + + Header/Footer information for a slide layout + + + + + + + + Matching Name + + + + + Slide Layout Type + + + + + Preserve Slide Layout + + + + + Is User Drawn + + + + + + Slide Layout + + + + + + + Slide Master Title Text Style + + + + + Slide Master Body Text Style + + + + + Slide Master Other Text Style + + + + + + + + Slide Layout ID + + + + + + + + + + + + ID Tag + + + + + ID Tag + + + + + + + + Slide Layout Id + + + + + + + + + Common slide data for slide masters + + + + + + List of Slide Layouts + + + + + Slide Transition for a Slide Master + + + + + Slide Timing Information for Slide Masters + + + + + Header/Footer information for a slide master + + + + + Slide Master Text Styles + + + + + + + Preserve Slide Master + + + + + + Slide Master + + + + + + + Common slide data for handout master + + + + + + Header/Footer information for a handout master + + + + + + + + Handout Master + + + + + + + Common Slide Data + + + + + + Header/Footer Information for a Notes Master + + + + + Notes Text Style + + + + + + + + Notes Master + + + + + + + Common slide data for notes slides + + + + + + + + + + Notes Slide + + + + + + + + + + + + Server's Slide File ID + + + + + Server's Slide File's modification date/time + + + + + Client Slide Insertion date/time + + + + + + Slide Synchronization Properties + + + + + + + + Name + + + + + Value + + + + + + + + Programmable Extensibility Tag + + + + + + + Programmable Tab List + + + + + + + + + + Splitter Bar State + + + + + Min + + + + + Restored + + + + + Max + + + + + + + List of View Types + + + + + Normal Slide View + + + + + Slide Master View + + + + + Notes View + + + + + Handout View + + + + + Notes Master View + + + + + Outline View + + + + + Slide Sorter View + + + + + Slide Thumbnail View + + + + + + + + Normal View Dimension Size + + + + + Auto Adjust Normal View + + + + + + + + Normal View Restored Left Properties + + + + + Normal View Restored Top Properties + + + + + + + Show Outline Icons in Normal View + + + + + Snap Vertical Splitter + + + + + State of the Vertical Splitter Bar + + + + + State of the Horizontal Splitter Bar + + + + + Prefer Single View + + + + + + + + View Scale + + + + + View Origin + + + + + + Variable Scale + + + + + + + + Base properties for Notes View + + + + + + + + + Relationship Identifier + + + + + Collapsed + + + + + + + + Presentation Slide + + + + + + + + + Common View Properties + + + + + List of Presentation Slides + + + + + + + + + + Base properties for Slide Sorter View + + + + + + + Show Formatting + + + + + + + Guide Orientation + + + + + Guide Position + + + + + + + + A Guide + + + + + + + + + Base properties for Slide View + + + + + List of Guides + + + + + + Snap Objects to Grid + + + + + Snap Objects to Objects + + + + + Show Guides in View + + + + + + + + + + + + + + Common Slide View Properties + + + + + + + + + + Normal View Properties + + + + + Slide View Properties + + + + + Outline View Properties + + + + + Notes Text View Properties + + + + + Slide Sorter View Properties + + + + + Notes View Properties + + + + + Grid Spacing + + + + + + + Last View + + + + + Show Comments + + + + + + Presentation-wide View Properties + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/readme.md b/tests/resources/schema/ecma-376/readme.md new file mode 100644 index 0000000000..dfe9d8e26d --- /dev/null +++ b/tests/resources/schema/ecma-376/readme.md @@ -0,0 +1,16 @@ +# pml.xsd + +## How do I create the file ? +* Go to http://www.ecma-international.org/publications/standards/Ecma-376.htm +* Download the file "ECMA-376 1st edition Part 4" +* Extract the directory Office Open XML 1st edition Part 2 (DOCX).zip\OpenPackagingConventions-XMLSchema.zip +* From this, create files (dml-diagram.xsd, dml-main.xsd, pml.xsd, sml.xsd) + * Incorporate xsd files based on the order of **ECMA-376, Second Edition, Part 4 - Transitional Migration Features.zip\OfficeOpenXML-XMLSchema-Transitional.zip** files + * Try to avoid duplicate imprts + +## How do valid new created xsd ? +* Fetch some files from an PPTX files (theme1.xml, ...) +* Use xmllint : +``` +$ xmllint --noout --schema pml.xsd ../../../../samples/results/theme1.xml +``` \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-additionalCharacteristics.xsd b/tests/resources/schema/ecma-376/shared-additionalCharacteristics.xsd new file mode 100644 index 0000000000..b31d676d8c --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-additionalCharacteristics.xsd @@ -0,0 +1,71 @@ + + + + + + + Single Characteristic + + + + + + + + Name of Characteristic + + + + + Relationship of Value to Name + + + + + Characteristic Value + + + + + Characteristic Grammar + + + + + + Characteristic Relationship Types + + + + + Greater Than or Equal to + + + + + Less Than or Equal To + + + + + Greater Than + + + + + Less Than + + + + + Equal To + + + + + + + Set of Additional Characteristics + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-bibliography.xsd b/tests/resources/schema/ecma-376/shared-bibliography.xsd new file mode 100644 index 0000000000..c3c60fc7d0 --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-bibliography.xsd @@ -0,0 +1,534 @@ + + + + + String Value + + + + + + + + + Bibliographic Data Source Types + + + + + Article in a Periodical + + + + + Book + + + + + Book Section + + + + + Journal Article + + + + + Conference Proceedings + + + + + Reporter + + + + + Sound Recording + + + + + Performance + + + + + Art + + + + + Document from Internet Site + + + + + Internet Site + + + + + Film + + + + + Interview + + + + + Patent + + + + + Electronic Source + + + + + Case + + + + + Miscellaneous + + + + + + + + + Person + + + + + + + + + Person's Last, or Family, Name + + + + + Person's First, or Given, Name + + + + + Person's Middle, or Other, Name + + + + + + + + + Name List + + + + + + + + + + + Corporate Author + + + + + + + + + + + Artist + + + + + Author + + + + + Book Author + + + + + Compiler + + + + + Composer + + + + + Conductor + + + + + Counsel + + + + + Director + + + + + Editor + + + + + Interviewee + + + + + Interviewer + + + + + Inventor + + + + + Performer + + + + + Producer Name + + + + + Translator + + + + + Writer + + + + + + + + + + + Abbreviated Case Number + + + + + Album Title + + + + + Contributors List + + + + + Book Title + + + + + Broadcaster + + + + + Broadcast Title + + + + + Case Number + + + + + Chapter Number + + + + + City + + + + + Comments + + + + + Conference or Proceedings Name + + + + + Country or Region + + + + + Court + + + + + Day + + + + + Day Accessed + + + + + Department + + + + + Distributor + + + + + Editor + + + + + GUID + + + + + Institution + + + + + Internet Site Title + + + + + Issue + + + + + Journal Name + + + + + Locale ID + + + + + Medium + + + + + Month + + + + + Month Accessed + + + + + Number of Volumes + + + + + Pages + + + + + Patent Number + + + + + Periodical Title + + + + + Production Company + + + + + Publication Title + + + + + Publisher + + + + + Recording Number + + + + + Reference Order + + + + + Reporter + + + + + Source Type + + + + + Short Title + + + + + Standard Number + + + + + State or Province + + + + + Station + + + + + Tag + + + + + Theater + + + + + Thesis Type + + + + + Title + + + + + Type + + + + + URL + + + + + Version + + + + + Volume + + + + + Year + + + + + Year Accessed + + + + + + + + Sources + + + + + + + Source + + + + + + Selected Style + + + + + Documentation Style Name + + + + + Uniform Resource Identifier + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-commonSimpleTypes.xsd b/tests/resources/schema/ecma-376/shared-commonSimpleTypes.xsd new file mode 100644 index 0000000000..801fadf8e3 --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-commonSimpleTypes.xsd @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-customXmlDataProperties.xsd b/tests/resources/schema/ecma-376/shared-customXmlDataProperties.xsd new file mode 100644 index 0000000000..d2e7ce9362 --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-customXmlDataProperties.xsd @@ -0,0 +1,46 @@ + + + + + 128-Bit GUID Value + + + + + + + + + Target Namespace of Associated XML Schema + + + + + + + + Associated XML Schema + + + + + + + + + Set of Associated XML Schemas + + + + + + Custom XML Data ID + + + + + + Custom XML Data Properties + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-customXmlSchemaProperties.xsd b/tests/resources/schema/ecma-376/shared-customXmlSchemaProperties.xsd new file mode 100644 index 0000000000..19de7d36fd --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-customXmlSchemaProperties.xsd @@ -0,0 +1,34 @@ + + + + + + Custom XML Schema Namespace + + + + + Resource File Location + + + + + Custom XML Schema Location + + + + + + + + Custom XML Schema Reference + + + + + + + Embedded Custom XML Schema Supplementary Data + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-documentPropertiesCustom.xsd b/tests/resources/schema/ecma-376/shared-documentPropertiesCustom.xsd new file mode 100644 index 0000000000..a28208bf86 --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-documentPropertiesCustom.xsd @@ -0,0 +1,212 @@ + + + + + + Custom File Properties + + + + + + + Custom File Property + + + + + + + + + Vector + + + + + Array + + + + + Binary Blob + + + + + Binary Blob Object + + + + + Empty + + + + + Null + + + + + 1-Byte Signed Integer + + + + + 2-Byte Signed Integer + + + + + 4-Byte Signed Integer + + + + + 8-Byte Signed Integer + + + + + Integer + + + + + 1-Byte Unsigned Integer + + + + + 2-Byte Unsigned Integer + + + + + 4-Byte Unsigned Integer + + + + + 8-Byte Unsigned Integer + + + + + Unsigned Integer + + + + + 4-Byte Real Number + + + + + 8-Byte Real Number + + + + + Decimal + + + + + LPSTR + + + + + LPWSTR + + + + + Basic String + + + + + Date and Time + + + + + File Time + + + + + Boolean + + + + + Currency + + + + + Error Status Code + + + + + Binary Stream + + + + + Binary Stream Object + + + + + Binary Storage + + + + + Binary Storage Object + + + + + Binary Versioned Stream + + + + + Class ID + + + + + Clipboard Data + + + + + + Format ID + + + + + Property ID + + + + + Custom File Property Name + + + + + Bookmark Link Target + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-documentPropertiesExtended.xsd b/tests/resources/schema/ecma-376/shared-documentPropertiesExtended.xsd new file mode 100644 index 0000000000..eb094ef32e --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-documentPropertiesExtended.xsd @@ -0,0 +1,175 @@ + + + + + + Application Specific File Properties + + + + + + + Name of Document Template + + + + + Name of Manager + + + + + Name of Company + + + + + Total Number of Pages + + + + + Word Count + + + + + Total Number of Characters + + + + + Intended Format of Presentation + + + + + Number of Lines + + + + + Total Number of Paragraphs + + + + + Slides Metadata Element + + + + + Number of Slides Containing Notes + + + + + Total Edit Time Metadata Element + + + + + Number of Hidden Slides + + + + + Total Number of Multimedia Clips + + + + + Thumbnail Display Mode + + + + + Heading Pairs + + + + + Part Titles + + + + + Links Up-to-Date + + + + + Number of Characters (With Spaces) + + + + + Shared Document + + + + + Relative Hyperlink Base + + + + + Hyperlink List + + + + + Hyperlinks Changed + + + + + Digital Signature + + + + + Application Name + + + + + Application Version + + + + + Document Security + + + + + + + + + Vector + + + + + + + + + Vector + + + + + + + + + Binary Blob + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-documentPropertiesVariantTypes.xsd b/tests/resources/schema/ecma-376/shared-documentPropertiesVariantTypes.xsd new file mode 100644 index 0000000000..ad5914995b --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-documentPropertiesVariantTypes.xsd @@ -0,0 +1,844 @@ + + + + + Vector Base Type Simple Type + + + + + Variant Base Type + + + + + Vector Base Type Enumeration Value + + + + + 2-Byte Signed Integer Base Type + + + + + 4-Byte Signed Integer Base Type + + + + + 8-Byte Signed Integer Base Type + + + + + 1-Byte Unsigned Integer Base Type + + + + + 2-Byte Unisigned Integer Base Type + + + + + 4-Byte Unsigned Integer Base Type + + + + + 8-Byte Unsigned Integer Base Type + + + + + 4-Byte Real Number Base Type + + + + + 8-Byte Real Number Base Type + + + + + LPSTR Base Type + + + + + LPWSTR Base Type + + + + + Basic String Base Type + + + + + Date and Time Base Type + + + + + File Time Base Type + + + + + Boolean Base Type + + + + + Currency Base Type + + + + + Error Status Code Base Type + + + + + Class ID Base Type + + + + + Clipboard Data Base Type + + + + + + + Array Base Type Simple Type + + + + + Variant Base Type + + + + + 1-Byte Signed Integer Base Type + + + + + 2-Byte Signed Integer Base Type + + + + + 4-Byte Signed Integer Base Type + + + + + Integer Base Type + + + + + 1-Byte Unsigned Integer Base Type + + + + + 2-Byte Unsigned Integer Base Type + + + + + 4-Byte Unsigned Integer Base Type + + + + + Unsigned Integer Base Type + + + + + 4-Byte Real Number Base Type + + + + + 8-Byte Real Number Base Type + + + + + Decimal Base Type + + + + + Basic String Base Type + + + + + Date and Time Base Type + + + + + Boolean Base Type + + + + + Curency Base Type + + + + + Error Status Code Base Type + + + + + + + Currency Simple Type + + + + + + + + Error Status Code Simple Type + + + + + + + + Class ID Simple Type + + + + + + + + Format Simple Type + + + + + + + + + + + + + + + + Variant + + + + + 1-Byte Signed Integer + + + + + 2-Byte Signed Integer + + + + + 4-Byte Signed Integer + + + + + 8-Byte Signed Integer + + + + + 1-Byte Unsigned Integer + + + + + 2-Byte Unsigned Integer + + + + + 4-Byte Unsigned Integer + + + + + 8-Byte Unsigned Integer + + + + + 4-Byte Real Number + + + + + 8-Byte Real Number + + + + + LPSTR + + + + + LPWSTR + + + + + Basic String + + + + + Date and Time + + + + + File Time + + + + + Boolean + + + + + Currency + + + + + Error Status Code + + + + + Class ID + + + + + Clipboard Data + + + + + + Vector Base Type + + + + + Vector Size + + + + + + + + Variant + + + + + 1-Byte Signed Integer + + + + + 2-Byte Signed Integer + + + + + 4-Byte Signed Integer + + + + + Integer + + + + + 1-Byte Unsigned Integer + + + + + 2-Byte Unsigned Integer + + + + + 4-Byte Unsigned Integer + + + + + Unsigned Integer + + + + + 4-Byte Real Number + + + + + 8-Byte Real Number + + + + + Decimal + + + + + Basic String + + + + + Date and Time + + + + + Boolean + + + + + Error Status Code + + + + + Currency + + + + + + Array Lower Bounds Attribute + + + + + Array Upper Bounds Attribute + + + + + Array Base Type + + + + + + + + Variant + + + + + Vector + + + + + Array + + + + + Binary Blob + + + + + Binary Blob Object + + + + + Empty + + + + + Null + + + + + 1-Byte Signed Integer + + + + + 2-Byte Signed Integer + + + + + 4-Byte Signed Integer + + + + + 8-Byte Signed Integer + + + + + Integer + + + + + 1-Byte Unsigned Integer + + + + + 2-Byte Unsigned Integer + + + + + 4-Byte Unsigned Integer + + + + + 8-Byte Unsigned Integer + + + + + Unsigned Integer + + + + + 4-Byte Real Number + + + + + 8-Byte Real Number + + + + + Decimal + + + + + LPSTR + + + + + LPWSTR + + + + + Basic String + + + + + Date and Time + + + + + File Time + + + + + Boolean + + + + + Currency + + + + + Error Status Code + + + + + Binary Stream + + + + + Binary Stream Object + + + + + Binary Storage + + + + + Binary Storage Object + + + + + Binary Versioned Stream + + + + + Class ID + + + + + Clipboard Data + + + + + + + + + + VSTREAM Version Attribute + + + + + + + + + + + Format Attribute + + + + + + + + Variant + + + + + Vector + + + + + Array + + + + + Binary Blob + + + + + Binary Blob Object + + + + + Empty + + + + + Null + + + + + 1-Byte Signed Integer + + + + + 2-Byte Signed Integer + + + + + 4-Byte Signed Integer + + + + + 8-Byte Signed Integer + + + + + Integer + + + + + 1-Byte Unsigned Integer + + + + + 2-Byte Unsigned Integer + + + + + 4-Byte Unsigned Integer + + + + + 8-Byte Unsigned Integer + + + + + Unsigned Integer + + + + + 4-Byte Real Number + + + + + 8-Byte Real Number + + + + + Decimal + + + + + LPSTR + + + + + LPWSTR + + + + + Basic String + + + + + Date and Time + + + + + File Time + + + + + Boolean + + + + + Currency + + + + + Error Status Code + + + + + Binary Stream + + + + + Binary Stream Object + + + + + Binary Storage + + + + + Binary Storage Object + + + + + Binary Versioned Stream + + + + + Class ID + + + + + Clipboard Data + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-math.xsd b/tests/resources/schema/ecma-376/shared-math.xsd new file mode 100644 index 0000000000..1740e6fc56 --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-math.xsd @@ -0,0 +1,1528 @@ + + + + + + + Integer value (1 to 255) + + + + + + + + + + Value + + + + + + Integer value (-2 to 2) + + + + + + + + + + Value + + + + + + Spacing Rule + + + + + + + + + + Value + + + + + + Unsigned integer. + + + + + + + Value + + + + + + Character + + + + + + + + + value + + + + + + On Off + + + + + On + + + + + Off + + + + + + + + value + + + + + + String + + + + + + + value + + + + + + Horizontal Alignment + + + + + Left Justification + + + + + Center + + + + + Right + + + + + + + + Value + + + + + + Vertical Alignment + + + + + Top + + + + + Center (Function) + + + + + Bottom Alignment + + + + + + + + Value + + + + + + Shape (Delimiters) + + + + + Centered (Delimiters) + + + + + Match + + + + + + + + Value + + + + + + Fraction Type + + + + + Bar Fraction + + + + + Skewed + + + + + Linear Fraction + + + + + No-Bar Fraction (Stack) + + + + + + + + Value + + + + + + Limit Location + + + + + Under-Over location + + + + + Subscript-Superscript location + + + + + + + + Value + + + + + + Top-Bottom + + + + + Top + + + + + Bottom Alignment + + + + + + + + Value + + + + + + Script + + + + + Roman + + + + + Script + + + + + Fraktur + + + + + double-struck + + + + + Sans-Serif + + + + + Monospace + + + + + + + + Value + + + + + + Style + + + + + Plain + + + + + Bold + + + + + Italic + + + + + Bold-Italic + + + + + + + + Value + + + + + + + Index of Operator to Align To + + + + + + + + Script + + + + + style + + + + + + + + + Literal + + + + + + Normal Text + + + + + + + + + Break + + + + + Align + + + + + + + + + + Content Contains Significant Whitespace + + + + + + + + + + Run Properties + + + + + + + + Text + + + + + + + + + + + + + + + Accent Character + + + + + Control Properties + + + + + + + + + Accent Properties + + + + + Base + + + + + + + + + Position (Bar) + + + + + + + + + + Bar Properties + + + + + Base + + + + + + + + + Operator Emulator + + + + + No Break + + + + + Differential + + + + + Break + + + + + Alignment + + + + + + + + + + Box Properties + + + + + Base + + + + + + + + + Hide Top Edge + + + + + Hide Bottom Edge + + + + + Hide Left Edge + + + + + Hide Right Edge + + + + + Border Box Strikethrough Horizontal + + + + + Border Box Strikethrough Vertical + + + + + Border Box Strikethrough Bottom-Left to Top-Right + + + + + Border Box Strikethrough Top-Left to Bottom-Right + + + + + + + + + + Border Box Properties + + + + + Base + + + + + + + + + Delimiter Beginning Character + + + + + Delimiter Separator Character + + + + + Delimiter Ending Character + + + + + Delimiter Grow + + + + + Shape (Delimiters) + + + + + + + + + + Delimiter Properties + + + + + Base + + + + + + + + + Equation Array Base Justification + + + + + Maximum Distribution + + + + + Object Distribution + + + + + Row Spacing Rule + + + + + Row Spacing (Equation Array) + + + + + + + + + + Equation Array Properties + + + + + Element + + + + + + + + + Fraction type + + + + + + + + + + Fraction Properties + + + + + Numerator + + + + + Denominator + + + + + + + + + + + + + + Function Properties + + + + + Function Name + + + + + Base (Argument) + + + + + + + + + Group Character (Grouping Character) + + + + + Position (Group Character) + + + + + Vertical Justification + + + + + + + + + + Group-Character Properties + + + + + Base + + + + + + + + + + + + + + Lower Limit Properties + + + + + Base + + + + + Limit (Lower) + + + + + + + + + + + + + + Upper Limit Properties + + + + + Base + + + + + Limit (Upper) + + + + + + + + + Matrix Column Count + + + + + Matrix Column Justification + + + + + + + + + Matrix Column Properties + + + + + + + + + Matrix Column + + + + + + + + + Matrix Base Justification + + + + + Hide Placeholders (Matrix) + + + + + Row Spacing Rule + + + + + Matrix Column Gap Rule + + + + + Row Spacing (Matrix) + + + + + Matrix Column Spacing + + + + + Matrix Column Gap + + + + + Matrix Columns + + + + + + + + + + Element + + + + + + + + + Matrix Properties + + + + + Matrix Row + + + + + + + + + n-ary Operator Character + + + + + n-ary Limit Location + + + + + n-ary Grow + + + + + Hide Subscript (n-ary) + + + + + Hide Superscript (n-ary) + + + + + + + + + + n-ary Properties + + + + + Lower limit (n-ary) + + + + + Upper limit (n-ary) + + + + + Base (Argument) + + + + + + + + + Phantom Show + + + + + Phantom Zero Width + + + + + Phantom Zero Ascent + + + + + Phantom Zero Descent + + + + + Transparent (Phantom) + + + + + + + + + + Phantom Properties + + + + + Base + + + + + + + + + Hide Degree + + + + + + + + + + Radical Properties + + + + + Degree + + + + + Base + + + + + + + + + + + + + + Pre-Sub-Superscript Properties + + + + + Subscript (Pre-Sub-Superscript) + + + + + Superscript(Pre-Sub-Superscript function) + + + + + Base + + + + + + + + + + + + + + Subscript Properties + + + + + Base + + + + + Subscript (Subscript function) + + + + + + + + + Align Scripts + + + + + + + + + + Sub-Superscript Properties + + + + + Base + + + + + Subscript (Sub-Superscript) + + + + + Superscript (Sub-Superscript function) + + + + + + + + + + + + + + Superscript Properties + + + + + Base + + + + + Superscript (Superscript function) + + + + + + + + + Accent + + + + + Bar + + + + + Box Function + + + + + Border-Box Function + + + + + Delimiter Function + + + + + Equation-Array Function + + + + + Fraction Function + + + + + Function Apply Function + + + + + Group-Character Function + + + + + Lower-Limit Function + + + + + Upper-Limit Function + + + + + Matrix Function + + + + + n-ary Operator Function + + + + + Phantom Function + + + + + Radical Function + + + + + Pre-Sub-Superscript Function + + + + + Subscript Function + + + + + Sub-Superscript Function + + + + + Superscript Function + + + + + Run + + + + + + + + + + + + + + + Argument Size + + + + + + + + + Argument Properties + + + + + + + + + Justification + + + + + Left Justification + + + + + Right + + + + + Center (Equation) + + + + + Centered as Group (Equations) + + + + + + + + Value + + + + + + + + Justification + + + + + + + Twips measurement + + + + + + + Value + + + + + + Break Binary Operators + + + + + Before + + + + + After + + + + + Repeat + + + + + + + + Value + + + + + + Break on Binary Subtraction + + + + + Minus Minus + + + + + Minus Plus + + + + + Plus Minus + + + + + + + + Value + + + + + + + + Math Font + + + + + Break on Binary Operators + + + + + Break on Binary Subtraction + + + + + Small Fraction + + + + + Use Display Math Defaults + + + + + Left Margin + + + + + Right Margin + + + + + Default Justification + + + + + Pre-Equation Spacing + + + + + Post-Equation Spacing + + + + + Inter-Equation Spacing + + + + + Intra-Equation Spacing + + + + + + Wrap Indent + + + + + Wrap Right + + + + + + Integral Limit Locations + + + + + n-ary Limit Location + + + + + + + Math Properties + + + + + + + Office Math Paragraph Properties + + + + + Office Math + + + + + + + + + + + + + + + + + + + + Math Paragraph + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/shared-relationshipReference.xsd b/tests/resources/schema/ecma-376/shared-relationshipReference.xsd new file mode 100644 index 0000000000..938c422105 --- /dev/null +++ b/tests/resources/schema/ecma-376/shared-relationshipReference.xsd @@ -0,0 +1,31 @@ + + + + + Explicit Relationship ID + + + + + + Relationship ID + + + + + Embedded Image Relationship Target + + + + + + + + + + + + Hyperlink Target Relationship ID + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/sml.xsd b/tests/resources/schema/ecma-376/sml.xsd new file mode 100644 index 0000000000..6c0bcb301f --- /dev/null +++ b/tests/resources/schema/ecma-376/sml.xsd @@ -0,0 +1,15170 @@ + + + + + + + + + + + + + + + AutoFilter Column + + + + + Sort State for Auto Filter + + + + + + + Cell or Range Reference + + + + + + + + Filter Criteria + + + + + Top 10 + + + + + Custom Filters + + + + + Dynamic Filter + + + + + Color Filter Criteria + + + + + Icon Filter + + + + + + + Filter Column Data + + + + + Hidden AutoFilter Button + + + + + Show Filter Button + + + + + + + + Filter + + + + + Date Grouping + + + + + + Filter by Blank + + + + + Calendar Type + + + + + + + Filter Value + + + + + + + + Custom Filter Criteria + + + + + + And + + + + + + + Filter Comparison Operator + + + + + Top or Bottom Value + + + + + + + Top + + + + + Filter by Percent + + + + + Top or Bottom Value + + + + + Filter Value + + + + + + + Differential Format Record Id + + + + + Filter By Cell Color + + + + + + + Icon Set + + + + + Icon Id + + + + + + Filter Operator + + + + + Equal + + + + + Less Than + + + + + Less Than Or Equal + + + + + Not Equal + + + + + Greater Than Or Equal + + + + + Greater Than + + + + + + + + Dynamic filter type + + + + + Value + + + + + Max Value + + + + + + Dynamic Filter + + + + + Null + + + + + Above Average + + + + + Below Average + + + + + Tomorrow + + + + + Today + + + + + Yesterday + + + + + Next Week + + + + + This Week + + + + + Last Week + + + + + Next Month + + + + + This Month + + + + + Last Month + + + + + Next Quarter + + + + + This Quarter + + + + + Last Quarter + + + + + Next Year + + + + + This Year + + + + + Last Year + + + + + Year To Date + + + + + 1st Quarter + + + + + 2nd Quarter + + + + + 3rd Quarter + + + + + 4th Quarter + + + + + 1st Month + + + + + 2nd Month + + + + + 3rd Month + + + + + 4th Month + + + + + 5th Month + + + + + 6th Month + + + + + 7th Month + + + + + 8th Month + + + + + 9th Month + + + + + 10th Month + + + + + 11th Month + + + + + 12th Month + + + + + + + Icon Set Type + + + + + 3 Arrows + + + + + 3 Arrows (Gray) + + + + + 3 Flags + + + + + 3 Traffic Lights + + + + + 3 Traffic Lights Black + + + + + 3 Signs + + + + + 3 Symbols Circled + + + + + 3 Symbols + + + + + 4 Arrows + + + + + 4 Arrows (Gray) + + + + + 4 Red To Black + + + + + 4 Ratings + + + + + 4 Traffic Lights + + + + + 5 Arrows + + + + + 5 Arrows (Gray) + + + + + 5 Ratings Icon Set + + + + + 5 Quarters + + + + + + + + + Sort Condition + + + + + + + Sort by Columns + + + + + Case Sensitive + + + + + Sort Method + + + + + Sort Range + + + + + + + Descending + + + + + Sort By + + + + + Reference + + + + + Custom List + + + + + Format Id + + + + + Icon Set + + + + + Icon Id + + + + + + Sort By + + + + + Value + + + + + Sort by Cell Color + + + + + Sort by Font Color + + + + + Sort by Icon + + + + + + + Sort Method + + + + + Sort by Stroke + + + + + PinYin Sort + + + + + None + + + + + + + Calendar Type + + + + + No Calendar Type + + + + + Gregorian + + + + + Gregorian (U.S.) Calendar + + + + + Japanese Emperor Era Calendar + + + + + Taiwan Era Calendar + + + + + Korean Tangun Era Calendar + + + + + Hijri (Arabic Lunar) Calendar + + + + + Thai Calendar + + + + + Hebrew (Lunar) Calendar + + + + + Gregorian Middle East French Calendar + + + + + Gregorian Arabic Calendar + + + + + Gregorian Transliterated English Calendar + + + + + Gregorian Transliterated French Calendar + + + + + + + + Year + + + + + Month + + + + + Day + + + + + Hour + + + + + Minute + + + + + Second + + + + + Date Time Grouping + + + + + + Date Time Grouping + + + + + Group by Year + + + + + Month + + + + + Day + + + + + Group by Hour + + + + + Group by Minute + + + + + Second + + + + + + + + + Escaped String + + + + + + Cell Reference + + + + + + Cell References + + + + + + Single Cell Reference + + + + + + Reference Sequence + + + + + + Formula + + + + + + Hex Unsigned Integer + + + + + + + + Unsigned Short Hex + + + + + + + + Globally Unique Identifier + + + + + + + + + Value + + + + + + + + + + URI + + + + + + + + Extension + + + + + + + + + + + + + + + Calculation Chain Info + + + + + + + Cell + + + + + + + + + Cell Reference + + + + + Sheet Id + + + + + Child Chain + + + + + New Dependency Level + + + + + New Thread + + + + + Array + + + + + + + + + + Comments + + + + + + + Authors + + + + + List of Comments + + + + + + + + + + Author + + + + + + + + + Comment + + + + + + + + + Comment Text + + + + + + Cell Reference + + + + + Author Id + + + + + Unique Identifier for Comment + + + + + + + + XML Mapping + + + + + + + XML Schema + + + + + XML Mapping Properties + + + + + + Prefix Mappings for XPath Expressions + + + + + + + + + + Schema ID + + + + + Schema Reference + + + + + Schema Root Namespace + + + + + + + + XML Mapping + + + + + + XML Mapping ID + + + + + XML Mapping Name + + + + + Root Element Name + + + + + Schema Name + + + + + Show Validation Errors + + + + + AutoFit Table on Refresh + + + + + Append Data to Table + + + + + Preserve AutoFilter State + + + + + Preserve Cell Formatting + + + + + + + + + + Unique Identifer + + + + + Binding to External File + + + + + Reference to Connection ID + + + + + File Binding Name + + + + + XML Data Loading Behavior + + + + + + + + + + Connections + + + + + + + Connection + + + + + + + + + ODBC & OLE DB Properties + + + + + OLAP Properties + + + + + Web Query Properties + + + + + Text Import Settings + + + + + Query Parameters + + + + + Future Feature Data Storage + + + + + + Connection Id + + + + + Source Database File + + + + + Connection File + + + + + Keep Connection Open + + + + + Automatic Refresh Interval + + + + + Connection Name + + + + + Connection Description + + + + + Database Source Type + + + + + Reconnection Method + + + + + Last Refresh Version + + + + + Minimum Version Required for Refresh + + + + + Save Password + + + + + New Connection + + + + + Deleted Connection + + + + + Only Use Connection File + + + + + Background Refresh + + + + + Refresh on Open + + + + + Save Data + + + + + Reconnection Method + + + + + SSO Id + + + + + + Credentials Method + + + + + Integrated Authentication + + + + + No Credentials + + + + + Stored Credentials + + + + + Prompt Credentials + + + + + + + + Connection String + + + + + Command Text + + + + + Command Text + + + + + OLE DB Command Type + + + + + + + Local Cube + + + + + Local Cube Connection + + + + + Local Refresh + + + + + Send Locale to OLAP + + + + + Drill Through Count + + + + + OLAP Fill Formatting + + + + + OLAP Number Format + + + + + OLAP Server Font + + + + + OLAP Font Formatting + + + + + + + + Tables + + + + + + XML Source + + + + + Import XML Source Data + + + + + Parse PRE + + + + + Consecutive Delimiters + + + + + Use First Row + + + + + Created in Excel 97 + + + + + Dates as Text + + + + + Refreshed in Excel 2000 + + + + + URL + + + + + Web Post + + + + + HTML Tables Only + + + + + HTML Formatting Handling + + + + + Edit Query URL + + + + + + HTML Formatting Handling + + + + + No Formatting + + + + + Honor Rich Text + + + + + All + + + + + + + + + Parameter Properties + + + + + + Parameter Count + + + + + + + Parameter Name + + + + + SQL Data Type + + + + + Parameter Type + + + + + Refresh on Change + + + + + Parameter Prompt String + + + + + Boolean + + + + + Double + + + + + Integer + + + + + String + + + + + Cell Reference + + + + + + Parameter Type + + + + + Prompt on Refresh + + + + + Value + + + + + Parameter From Cell + + + + + + + + + No Value + + + + + Character Value + + + + + Index + + + + + + Count of Tables + + + + + + + + + Fields + + + + + + Prompt for File Name + + + + + File Type + + + + + Code Page + + + + + First Row + + + + + Source File Name + + + + + Delimited File + + + + + Decimal Separator + + + + + Thousands Separator + + + + + Tab as Delimiter + + + + + Space is Delimiter + + + + + Comma is Delimiter + + + + + Semicolon is Delimiter + + + + + Consecutive Delimiters + + + + + Qualifier + + + + + Custom Delimiter + + + + + + File Type + + + + + Macintosh + + + + + Windows (ANSI) + + + + + DOS + + + + + + + Qualifier + + + + + Double Quote + + + + + Single Quote + + + + + No Text Qualifier + + + + + + + + + Text Import Field Settings + + + + + + Count of Fields + + + + + + + Field Type + + + + + Position + + + + + + Text Field Datatype + + + + + General + + + + + Text + + + + + Month Day Year + + + + + Day Month Year + + + + + Year Month Day + + + + + Month Day Year + + + + + Day Year Month + + + + + Year Day Month + + + + + Skip Field + + + + + East Asian Year Month Day + + + + + + + + + + + + + + + PivotCache Definition + + + + + PivotCache Records + + + + + PivotTable Definition + + + + + + + PivotCache Source Description + + + + + PivotCache Fields + + + + + PivotCache Hierarchies + + + + + OLAP KPIs + + + + + Tuple Cache + + + + + Calculated Items + + + + + Calculated Members + + + + + OLAP Dimensions + + + + + OLAP Measure Groups + + + + + OLAP Measure Group + + + + + Future Feature Data Storage Area + + + + + + Relationship Identifier + + + + + Invalid Cache + + + + + Save Pivot Records + + + + + Refresh On Load + + + + + Optimize Cache for Memory + + + + + Enable PivotCache Refresh + + + + + Last Refreshed By + + + + + PivotCache Last Refreshed Date + + + + + Background Query + + + + + Missing Items Limit + + + + + PivotCache Created Version + + + + + PivotCache Last Refreshed Version + + + + + Minimum Version Required for Refresh + + + + + PivotCache Record Count + + + + + Upgrade PivotCache on Refresh + + + + + Stores Cache for OLAP Functions + + + + + Supports Subqueries + + + + + Supports Attribute Drilldown + + + + + + + + PivotCache Field + + + + + + Field Count + + + + + + + + Shared Items + + + + + Field Group Properties + + + + + Member Properties Map + + + + + Future Feature Data Storage Area + + + + + + PivotCache Field Name + + + + + PivotCache Field Caption + + + + + Property Name + + + + + Server-based Field + + + + + Unique List Retrieved + + + + + Number Format Id + + + + + Calculated Field Formula + + + + + SQL Data Type + + + + + Hierarchy + + + + + Hierarchy Level + + + + + Database Field + + + + + Member Property Count + + + + + Member Property Field + + + + + + + + Worksheet PivotCache Source + + + + + Consolidation Source + + + + + Future Feature Data Storage Area + + + + + + Cache Type + + + + + Connection Index + + + + + + PivotCache Type + + + + + Worksheet + + + + + External + + + + + Consolidation Ranges + + + + + Scenario Summary Report + + + + + + + + Reference + + + + + Named Range + + + + + Sheet Name + + + + + Relationship Id + + + + + + + + Page Item Values + + + + + Range Sets + + + + + + Auto Page + + + + + + + + Page Items + + + + + + Page Item String Count + + + + + + + + Page Item + + + + + + Page Item String Count + + + + + + + Page Item Name + + + + + + + + Range Set + + + + + + Reference and Page Item Count + + + + + + + Field Item Index Page 1 + + + + + Field Item Index Page 2 + + + + + Field Item index Page 3 + + + + + Field Item Index Page 4 + + + + + Reference + + + + + Named Range + + + + + Sheet Name + + + + + Relationship Id + + + + + + + + No Value + + + + + Numeric + + + + + Boolean + + + + + Error Value + + + + + Character Value + + + + + Date Time + + + + + + Contains Semi Mixed Data Types + + + + + Contains Non Date + + + + + Contains Date + + + + + Contains String + + + + + Contains Blank + + + + + Contains Mixed Data Types + + + + + Contains Numbers + + + + + Contains Integer + + + + + Minimum Numeric Value + + + + + Maximum Numeric Value + + + + + Minimum Date Time + + + + + Maximum Date Time Value + + + + + Shared Items Count + + + + + Long Text + + + + + + + + Tuples + + + + + Member Property Indexes + + + + + + Unused Item + + + + + Calculated Item + + + + + Caption + + + + + Member Property Count + + + + + Format Index + + + + + background Color + + + + + Foreground Color + + + + + Italic + + + + + Underline + + + + + Strikethrough + + + + + Bold + + + + + + + + OLAP Members + + + + + Member Property Index + + + + + + Value + + + + + Unused Item + + + + + Calculated Item + + + + + Caption + + + + + Member Property Count + + + + + Format Index + + + + + Background Color + + + + + Foreground Color + + + + + Italic + + + + + Underline + + + + + Strikethrough + + + + + Bold + + + + + + + + Member Property Indexes + + + + + + Value + + + + + Unused Item + + + + + Calculated Item + + + + + Caption + + + + + Member Property Count + + + + + + + + Tuples + + + + + Member Property Indexes + + + + + + Value + + + + + Unused Item + + + + + Calculated Item + + + + + Item Caption + + + + + Member Property Count + + + + + Format Index + + + + + background Color + + + + + Foreground Color + + + + + Italic + + + + + Underline + + + + + Strikethrough + + + + + Bold + + + + + + + + Tuples + + + + + Member Property Index + + + + + + Value + + + + + Unused Item + + + + + Calculated Item + + + + + Item Caption + + + + + Member Property Count + + + + + Format Index + + + + + Background Color + + + + + Foreground Color + + + + + Italic + + + + + Underline + + + + + Strikethrough + + + + + Bold + + + + + + + + Member Property Index + + + + + + Value + + + + + Unused Item + + + + + Calculated Item Value + + + + + Caption + + + + + Member Property Count + + + + + + + + Range Grouping Properties + + + + + Discrete Grouping Properties + + + + + OLAP Group Items + + + + + + Parent + + + + + Field Base + + + + + + + Source Data Set Beginning Range + + + + + Source Data Ending Range + + + + + Group By + + + + + Numeric Grouping Start Value + + + + + Numeric Grouping End Value + + + + + Date Grouping Start Value + + + + + Date Grouping End Value + + + + + Grouping Interval + + + + + + Values Group By + + + + + Group By Numeric Ranges + + + + + Seconds + + + + + Minutes + + + + + Hours + + + + + Days + + + + + Months + + + + + Quarters + + + + + Years + + + + + + + + + Element Group + + + + + + Mapping Index Count + + + + + + + + No Value + + + + + Numeric Value + + + + + Boolean + + + + + Error Value + + + + + Character Value + + + + + Date Time + + + + + + Items Created Count + + + + + + + + PivotCache Record + + + + + Future Feature Data Storage Area + + + + + + PivotCache Records Count + + + + + + + + No Value + + + + + Numeric Value + + + + + Boolean + + + + + Error Value + + + + + Character Value + + + + + Date Time + + + + + Shared Items Index + + + + + + + + + OLAP KPI + + + + + + KPI Count + + + + + + + KPI Unique Name + + + + + KPI Display Name + + + + + KPI Display Folder + + + + + KPI Measure Group Name + + + + + Parent KPI + + + + + KPI Value Unique Name + + + + + KPI Goal Unique Name + + + + + KPI Status Unique Name + + + + + KPI Trend Unique Name + + + + + KPI Weight Unique Name + + + + + Time Member KPI Unique Name + + + + + + + + PivotCache Hierarchy + + + + + + Hierarchy Count + + + + + + + + Fields Usage + + + + + OLAP Grouping Levels + + + + + Future Feature Data Storage Area + + + + + + Hierarchy Unique Name + + + + + Hierarchy Display Name + + + + + Measure Hierarchy + + + + + Set + + + + + Parent Set + + + + + KPI Icon Set + + + + + Attribute Hierarchy + + + + + Time + + + + + Key Attribute Hierarchy + + + + + Default Member Unique Name + + + + + Unique Name of 'All' + + + + + Display Name of 'All' + + + + + Dimension Unique Name + + + + + Display Folder + + + + + Measure Group Name + + + + + Measures + + + + + Levels Count + + + + + One Field + + + + + Member Value Data Type + + + + + Unbalanced + + + + + Unbalanced Group + + + + + Hidden + + + + + + + + PivotCache Field Id + + + + + + Field Count + + + + + + + Field Index + + + + + + + + OLAP Grouping Levels + + + + + + Grouping Level Count + + + + + + + + OLAP Level Groups + + + + + Future Feature Data Storage Area + + + + + + Unique Name + + + + + Grouping Level Display Name + + + + + User-Defined Group Level + + + + + Custom Roll Up + + + + + + + + OLAP Group + + + + + + Level Group Count + + + + + + + + OLAP Group Members + + + + + + Group Name + + + + + Unique Group Name + + + + + Group Caption + + + + + Parent Unique Name + + + + + Group Id + + + + + + + + OLAP Group Member + + + + + + Group Member Count + + + + + + + Group Member Unique Name + + + + + Group + + + + + + + + Entries + + + + + Sets + + + + + OLAP Query Cache + + + + + Server Formats + + + + + Future Feature Data Storage Area + + + + + + + + Culture + + + + + Format + + + + + + + + Server Format + + + + + + Format Count + + + + + + + + No Value + + + + + Numeric Value + + + + + Error Value + + + + + Character Value + + + + + + Tuple Count + + + + + + + + Tuple + + + + + + Member Name Count + + + + + + + Field Index + + + + + Hierarchy Index + + + + + Item Index + + + + + + + + OLAP Set + + + + + + Tuple Set Count + + + + + + + + Tuples + + + + + Sort By Tuple + + + + + + Number of Tuples + + + + + Maximum Rank Requested + + + + + MDX Set Definition + + + + + Set Sort Order + + + + + Query Failed + + + + + + Set Sort Order + + + + + None + + + + + Ascending + + + + + Descending + + + + + Ascending Alpha + + + + + Alphabetic Order Descending + + + + + Ascending Natural + + + + + Natural Order Descending + + + + + + + + + Query + + + + + + Cached Query Count + + + + + + + + Tuples + + + + + + MDX Query String + + + + + + + + Calculated Item + + + + + + Calculated Item Formula Count + + + + + + + + Calculated Item Location + + + + + Future Feature Data Storage Area + + + + + + Field Index + + + + + Calculated Item Formula + + + + + + + + Calculated Member + + + + + + Calculated Members Count + + + + + + + + Future Feature Data Storage Area + + + + + + Calculated Member Name + + + + + Calculated Member MDX Formula + + + + + OLAP Calculated Member Name + + + + + Hierarchy Name + + + + + Parent Name + + + + + Calculated Members Solve Order + + + + + Set + + + + + + + + PivotTable Location + + + + + PivotTable Fields + + + + + Row Fields + + + + + Row Items + + + + + Column Fields + + + + + Column Items + + + + + Page Field Items + + + + + Data Fields + + + + + PivotTable Formats + + + + + Conditional Formats + + + + + PivotChart Formats + + + + + PivotTable OLAP Hierarchies + + + + + PivotTable Style + + + + + Filters + + + + + Row OLAP Hierarchy References + + + + + Column OLAP Hierarchy References + + + + + Future Feature Data Storage Area + + + + + + Name + + + + + PivotCache Definition Id + + + + + Data On Rows + + + + + Default Data Field Position + + + + + + Data Field Header Name + + + + + Grand Totals Caption + + + + + Error Caption + + + + + Show Error + + + + + Caption for Missing Values + + + + + Show Missing + + + + + Page Header Style Name + + + + + Table Style Name + + + + + Vacated Style + + + + + PivotTable Custom String + + + + + PivotTable Last Updated Version + + + + + Minimum Refreshable Version + + + + + Asterisk Totals + + + + + Show Item Names + + + + + Allow Edit Data + + + + + Disable Field List + + + + + Show Calculated Members + + + + + Total Visual Data + + + + + Show Multiple Labels + + + + + Show Drop Down + + + + + Show Expand Collapse + + + + + Print Drill Indicators + + + + + Show Member Property ToolTips + + + + + Show ToolTips on Data + + + + + Enable PivotTable Wizard + + + + + Enable Drill Down + + + + + Enable Field Properties + + + + + Preserve Formatting + + + + + Auto Formatting + + + + + Page Wrap + + + + + Page Over Then Down + + + + + Subtotal Hidden Items + + + + + Row Grand Totals + + + + + Grand Totals On Columns + + + + + Field Print Titles + + + + + Item Print Titles + + + + + Merge Titles + + + + + Show Drop Zones + + + + + PivotCache Created Version + + + + + Indentation for Compact Axis + + + + + Show Empty Row + + + + + Show Empty Column + + + + + Show Field Headers + + + + + Compact New Fields + + + + + Outline New Fields + + + + + Outline Data Fields + + + + + Compact Data + + + + + Data Fields Published + + + + + Enable Drop Zones + + + + + Stop Immersive UI + + + + + Multiple Field Filters + + + + + Chart Format Id + + + + + Row Header Caption + + + + + Column Header Caption + + + + + Default Sort Order + + + + + MDX Subqueries Supported + + + + + Custom List AutoSort + + + + + + + Reference + + + + + First Header Row + + + + + PivotTable Data First Row + + + + + First Data Column + + + + + Rows Per Page Count + + + + + Columns Per Page + + + + + + + + PivotTable Field + + + + + + Field Count + + + + + + + + Field Items + + + + + AutoSort Scope + + + + + Future Feature Data Storage Area + + + + + + Field Name + + + + + Axis + + + + + Data Field + + + + + Custom Subtotal Caption + + + + + Show PivotField Header Drop Downs + + + + + Hidden Level + + + + + Unique Member Property + + + + + Compact + + + + + All Items Expanded + + + + + Number Format Id + + + + + Outline Items + + + + + Subtotals At Top + + + + + Drag To Row + + + + + Drag To Column + + + + + Multiple Field Filters + + + + + Drag Field to Page + + + + + Field Can Drag to Data + + + + + Drag Off + + + + + Show All Items + + + + + Insert Blank Row + + + + + Server-based Page Field + + + + + Insert Item Page Break + + + + + Auto Show + + + + + Top Auto Show + + + + + Hide New Items + + + + + Measure Filter + + + + + Inclusive Manual Filter + + + + + Items Per Page Count + + + + + Auto Sort Type + + + + + Data Source Sort + + + + + Auto Sort + + + + + Auto Show Rank By + + + + + Show Default Subtotal + + + + + Sum Subtotal + + + + + CountA + + + + + Average + + + + + Max Subtotal + + + + + Min Subtotal + + + + + Product Subtotal + + + + + Count + + + + + StdDev Subtotal + + + + + StdDevP Subtotal + + + + + Variance Subtotal + + + + + VarP Subtotal + + + + + Show Member Property in Cell + + + + + Show Member Property ToolTip + + + + + Show As Caption + + + + + Drill State + + + + + + + + Auto Sort Scope + + + + + + + + + PivotTable Field Item + + + + + + Field Count + + + + + + + Item User Caption + + + + + Item Type + + + + + Hidden + + + + + Character + + + + + Hide Details + + + + + Calculated Member + + + + + Missing + + + + + Child Items + + + + + Item Index + + + + + Expanded + + + + + Drill Across Attributes + + + + + + + + Page Field + + + + + + Page Item Count + + + + + + + + Future Feature Data Storage Area + + + + + + Field + + + + + Item Index + + + + + OLAP Hierarchy Index + + + + + Hierarchy Unique Name + + + + + Hierarchy Display Name + + + + + + + + Data Field Item + + + + + + Data Items Count + + + + + + + + Future Feature Data Storage Area + + + + + + Data Field Name + + + + + Field + + + + + Subtotal + + + + + Show Data As Display Format + + + + + 'Show Data As' Base Field + + + + + 'Show Data As' Base Setting + + + + + Number Format Id + + + + + + + + Row Items + + + + + + Items in a Row Count + + + + + + + + Column Items + + + + + + Column Item Count + + + + + + + + Row / Column Item Index + + + + + + Item Type + + + + + Repeated Items Count + + + + + Data Field Index + + + + + + + Shared Items Index + + + + + + + + Row Items + + + + + + Repeated Items Count + + + + + + + + Field + + + + + + Repeated Items Count + + + + + + + Field Index + + + + + + + + PivotTable Format + + + + + + Formats Count + + + + + + + + Pivot Table Location + + + + + Future Feature Data Storage Area + + + + + + Format Action + + + + + Format Id + + + + + + + + Conditional Formatting + + + + + + Conditional Format Count + + + + + + + + Pivot Areas + + + + + + + Conditional Formatting Scope + + + + + Conditional Formatting Rule Type + + + + + Priority + + + + + + + + Pivot Area + + + + + + Pivot Area Count + + + + + + Conditional Formatting Scope + + + + + Selection + + + + + Data Fields + + + + + Field Intersections + + + + + + + Top N Evaluation Type + + + + + Top N None + + + + + All + + + + + Row Top N + + + + + Column Top N + + + + + + + + + PivotChart Format + + + + + + Format Count + + + + + + + + Pivot Table Location Rule + + + + + + Chart Index + + + + + Pivot Format Id + + + + + Series Format + + + + + + + + OLAP Hierarchy + + + + + + OLAP Hierarchy Count + + + + + + + + OLAP Member Properties + + + + + Members + + + + + Future Feature Data Storage Area + + + + + + Outline New Levels + + + + + Multiple Field Filters + + + + + New Levels Subtotals At Top + + + + + Show In Field List + + + + + Drag To Row + + + + + Drag To Column + + + + + Drag to Page + + + + + Drag To Data + + + + + Drag Off + + + + + Inclusive Manual Filter + + + + + Hierarchy Caption + + + + + + + + Row OLAP Hierarchies + + + + + + Item Count + + + + + + + + Column OLAP Hierarchies + + + + + + Items Count + + + + + + + Hierarchy Usage + + + + + + + + OLAP Member Property + + + + + + OLAP Member Properties Count + + + + + + + OLAP Member Property Unique Name + + + + + Show Cell + + + + + Show Tooltip + + + + + Show As Caption + + + + + Name Length + + + + + Property Name Character Index + + + + + Property Name Length + + + + + Level Index + + + + + Field Index + + + + + + + + Member + + + + + + Item Count + + + + + Hierarchy Level + + + + + + + Hidden Item Name + + + + + + + + OLAP Dimension + + + + + + OLAP Dimensions Count + + + + + + + Measure + + + + + Dimension Name + + + + + Dimension Unique Name + + + + + Dimension Display Name + + + + + + + + OLAP Measure Group + + + + + + Measure Group Count + + + + + + + + OLAP Measure Group + + + + + + Measure Group Count + + + + + + + Measure Group Name + + + + + Measure Group Display Name + + + + + + + Measure Group Id + + + + + Dimension Id + + + + + + + Table Style Name + + + + + Show Row Header Formatting + + + + + Show Table Style Column Header Formatting + + + + + Show Row Stripes + + + + + Show Column Stripes + + + + + Show Last Column + + + + + + + + PivotTable Advanced Filter + + + + + + Pivot Filter Count + + + + + + + + Auto Filter + + + + + + + Field Index + + + + + Member Property Field Id + + + + + Pivot Filter Type + + + + + Evaluation Order + + + + + Pivot Filter Id + + + + + Measure Index + + + + + Measure Field Index + + + + + Pivot Filter Name + + + + + Pivot Filter Description + + + + + Label Pivot + + + + + Label Pivot Filter String Value 2 + + + + + + Show Data As + + + + + Normal Data Type + + + + + Difference + + + + + Percentage Of + + + + + Percentage Difference + + + + + Running Total + + + + + Percentage of Row + + + + + Percent of Column + + + + + Percentage of Total + + + + + Index + + + + + + + PivotItem Type + + + + + Data + + + + + Default + + + + + Sum + + + + + CountA + + + + + Average + + + + + Max + + + + + Min + + + + + Product + + + + + Count + + + + + stdDev + + + + + StdDevP + + + + + Var + + + + + VarP + + + + + Grand Total Item + + + + + Blank Pivot Item + + + + + + + PivotTable Format Types + + + + + Blank + + + + + Formatting + + + + + Drill Type + + + + + Formula Type + + + + + + + Field Sort Type + + + + + Manual Sort + + + + + Ascending + + + + + Descending + + + + + + + Pivot Filter Types + + + + + Unknown + + + + + Count + + + + + Percent + + + + + Sum + + + + + Caption Equals + + + + + Caption Not Equal + + + + + Caption Begins With + + + + + Caption Does Not Begin With + + + + + Caption Ends With + + + + + Caption Does Not End With + + + + + Caption Contains + + + + + Caption Does Not Contain + + + + + Caption Is Greater Than + + + + + Caption Is Greater Than Or Equal To + + + + + Caption Is Less Than + + + + + Caption Is Less Than Or Equal To + + + + + Caption Is Between + + + + + Caption Is Not Between + + + + + Value Equal + + + + + Value Not Equal + + + + + Value Greater Than + + + + + Value Greater Than Or Equal To + + + + + Value Less Than + + + + + Value Less Than Or Equal To + + + + + Value Between + + + + + Value Not Between + + + + + Date Equals + + + + + Date Does Not Equal + + + + + Date Older Than + + + + + Date Older Than Or Equal + + + + + Date Newer Than + + + + + Date Newer Than or Equal To + + + + + Date Between + + + + + Date Not Between + + + + + Tomorrow + + + + + Today + + + + + Yesterday + + + + + Next Week + + + + + This Week + + + + + Last Week + + + + + Next Month + + + + + This Month + + + + + Last Month + + + + + Next Quarter + + + + + This Quarter + + + + + Last Quarter + + + + + Next Year + + + + + This Year + + + + + Last Year + + + + + Year-To-Date + + + + + First Quarter + + + + + Second Quarter + + + + + Third Quarter + + + + + Fourth Quarter + + + + + January + + + + + Dates in February + + + + + Dates in March + + + + + Dates in April + + + + + Dates in May + + + + + Dates in June + + + + + Dates in July + + + + + Dates in August + + + + + Dates in September + + + + + Dates in October + + + + + Dates in November + + + + + Dates in December + + + + + + + + + + + + References + + + + + Future Feature Data Storage Area + + + + + + Field Index + + + + + Rule Type + + + + + Data Only + + + + + Labels Only + + + + + Include Row Grand Total + + + + + Include Column Grand Total + + + + + Cache Index + + + + + Outline + + + + + Offset Reference + + + + + Collapsed Levels Are Subtotals + + + + + Axis + + + + + Field Position + + + + + + Rule Type + + + + + None + + + + + Normal + + + + + Data + + + + + All + + + + + Origin + + + + + Field Button + + + + + Top Right + + + + + + + + + Reference + + + + + + Pivot Filter Count + + + + + + + + Field Item + + + + + + + Field Index + + + + + Item Index Count + + + + + Selected + + + + + Positional Reference + + + + + Relative Reference + + + + + Include Default Filter + + + + + Include Sum Filter + + + + + Include CountA Filter + + + + + Include Average Filter + + + + + Include Maximum Filter + + + + + Include Minimum Filter + + + + + Include Product Filter + + + + + Include Count Subtotal + + + + + Include StdDev Filter + + + + + Include StdDevP Filter + + + + + Include Var Filter + + + + + Include VarP Filter + + + + + + + Shared Items Index + + + + + + PivotTable Axis + + + + + Row Axis + + + + + Column Axis + + + + + Include Count Filter + + + + + Values Axis + + + + + + + + + + + + Query Table + + + + + + + QueryTable Refresh Information + + + + + Future Feature Data Storage Area + + + + + + QueryTable Name + + + + + First Row Column Titles + + + + + Row Numbers + + + + + Disable Refresh + + + + + Background Refresh + + + + + First Background Refresh + + + + + Refresh On Load + + + + + Grow Shrink Type + + + + + Fill Adjacent Formulas + + + + + Remove Data On Save + + + + + Disable Edit + + + + + Preserve Formatting On Refresh + + + + + Adjust Column Width On Refresh + + + + + Intermediate + + + + + Connection Id + + + + + + + + + Query table fields + + + + + Deleted Fields + + + + + Sort State + + + + + Future Feature Data Storage Area + + + + + + Preserve Sort & Filter Layout + + + + + Next Field Id Wrapped + + + + + Headers In Last Refresh + + + + + Minimum Refresh Version + + + + + Next field id + + + + + Columns Left + + + + + Columns Right + + + + + + + + Deleted Field + + + + + + Deleted Fields Count + + + + + + + Deleted Fields Name + + + + + + + + QueryTable Field + + + + + + Column Count + + + + + + + + Future Feature Data Storage Area + + + + + + Field Id + + + + + Name + + + + + Data Bound Column + + + + + Row Numbers + + + + + Fill This Formula On Refresh + + + + + Clipped Column + + + + + Table Column Id + + + + + + Grow Shrink Type + + + + + Insert & Delete On Refresh + + + + + Insert & Clear On Refresh + + + + + Overwrite & Clear On Refresh + + + + + + + + + + + Shared String Table + + + + + + + String Item + + + + + + + String Count + + + + + Unique String Count + + + + + + Phonetic Type + + + + + Half-Width Katakana + + + + + Full-Width Katakana + + + + + Hiragana + + + + + No Conversion + + + + + + + Phonetic Alignment Types + + + + + No Control + + + + + Left Alignment + + + + + Center Alignment + + + + + Distributed + + + + + + + + + Text + + + + + + Base Text Start Index + + + + + Base Text End Index + + + + + + + + Run Properties + + + + + Text + + + + + + + + + Font + + + + + Character Set + + + + + Font Family + + + + + Bold + + + + + Italic + + + + + Strike Through + + + + + Outline + + + + + Shadow + + + + + Condense + + + + + Extend + + + + + Text Color + + + + + Font Size + + + + + Underline + + + + + Vertical Alignment + + + + + Font Scheme + + + + + + + + + Text + + + + + Rich Text Run + + + + + Phonetic Run + + + + + Phonetic Properties + + + + + + + + Font Id + + + + + Character Type + + + + + Alignment + + + + + + + + + + + + Revision Headers + + + + + Revisions + + + + + + + Header + + + + + + Last Revision GUID + + + + + Last GUID + + + + + Shared Workbook + + + + + Disk Revisions + + + + + History + + + + + Track Revisions + + + + + Exclusive Mode + + + + + Revision Id + + + + + Version + + + + + Keep Change History + + + + + Protected + + + + + Preserve History + + + + + + + + Revision Row Column Insert Delete + + + + + Revision Cell Move + + + + + Revision Custom View + + + + + Revision Sheet Name + + + + + Revision Insert Sheet + + + + + Revision Cell Change + + + + + Revision Format + + + + + Revision AutoFormat + + + + + Revision Defined Name + + + + + Revision Cell Comment + + + + + Revision Query Table + + + + + Revision Merge Conflict + + + + + + + + Revision Id + + + + + Revision From Rejection + + + + + Revision Undo Rejected + + + + + + + + Sheet Id Map + + + + + Reviewed List + + + + + + + GUID + + + + + Date Time + + + + + Last Sheet Id + + + + + User Name + + + + + Relationship ID + + + + + Minimum Revision Id + + + + + Max Revision Id + + + + + + + + Sheet Id + + + + + + Sheet Count + + + + + + + Sheet Id + + + + + + + + Reviewed + + + + + + Reviewed Revisions Count + + + + + + + revision Id + + + + + + + Index + + + + + Expression + + + + + Reference 3D + + + + + Array Entered + + + + + Value Needed + + + + + Defined Name Formula + + + + + Cross Sheet Move + + + + + Range + + + + + Defined Name + + + + + Cell Reference + + + + + Sheet Id + + + + + + + + Undo + + + + + Revised Row Column + + + + + Revision Format + + + + + + + Sheet Id + + + + + End Of List + + + + + Reference + + + + + User Action + + + + + Edge Deleted + + + + + + + + Undo + + + + + Revision Cell Change + + + + + Revision Format + + + + + + + Sheet Id + + + + + Source + + + + + Destination + + + + + Source Sheet Id + + + + + + + GUID + + + + + User Action + + + + + + + + + + + Sheet Id + + + + + Old Sheet Name + + + + + New Sheet Name + + + + + + + + Sheet Id + + + + + Sheet Name + + + + + Sheet Position + + + + + + + + Old Cell Data + + + + + New Cell Data + + + + + Old Formatting Information + + + + + New Formatting Information + + + + + + + + Sheet Id + + + + + Old Formatting + + + + + Row Column Formatting Change + + + + + Style Revision + + + + + Formatting + + + + + Number Format Id + + + + + Quote Prefix + + + + + Old Quote Prefix + + + + + Phonetic Text + + + + + Old Phonetic Text + + + + + End of List Formula Update + + + + + + + + Formatting + + + + + + + Sheet Id + + + + + Row or Column Formatting Change + + + + + Style + + + + + Sequence Of References + + + + + Start index + + + + + Length + + + + + + + Sheet Id + + + + + + Reference + + + + + + + Sheet Id + + + + + Cell + + + + + GUID + + + + + User Action + + + + + Always Show Comment + + + + + Old Comment + + + + + Comment In Hidden Row + + + + + Hidden Column + + + + + Author + + + + + Original Comment Length + + + + + New Comment Length + + + + + + + + Formula + + + + + Old Formula + + + + + + + + Local Name Sheet Id + + + + + Custom View + + + + + Name + + + + + Function + + + + + Old Function + + + + + Function Group Id + + + + + Old Function Group Id + + + + + Shortcut Key + + + + + Old Short Cut Key + + + + + Named Range Hidden + + + + + Old Hidden + + + + + New Custom Menu + + + + + Old Custom Menu Text + + + + + Description + + + + + Old Description + + + + + New Help Topic + + + + + Old Help Topic + + + + + Status Bar + + + + + Old Status Bar + + + + + Name Comment + + + + + Old Name Comment + + + + + + + + Sheet Id + + + + + + + Sheet Id + + + + + QueryTable Reference + + + + + Field Id + + + + + + Row Column Action Type + + + + + Insert Row + + + + + Delete Row + + + + + Column Insert + + + + + Delete Column + + + + + + + Revision Action Types + + + + + Add + + + + + Delete + + + + + + + Formula Expression Type + + + + + Reference + + + + + Reference Is Error + + + + + Area + + + + + Area Error + + + + + Computed Area + + + + + + + + + + User List + + + + + + + User Information + + + + + + Active User Count + + + + + + + + + + User Revisions GUID + + + + + User Name + + + + + User Id + + + + + Date Time + + + + + + + + + + + + + + + Worksheet + + + + + Chart Sheet + + + + + Dialog Sheet + + + + + + + Sheet Properties + + + + + Macro Sheet Dimensions + + + + + Macro Sheet Views + + + + + Sheet Format Properties + + + + + Column Information + + + + + Sheet Data + + + + + Sheet Protection Options + + + + + AutoFilter + + + + + Sort State + + + + + Data Consolidation + + + + + Custom Sheet Views + + + + + Phonetic Properties + + + + + Conditional Formatting + + + + + Print Options + + + + + Page Margins + + + + + Page Setup Settings + + + + + Header Footer Settings + + + + + Horizontal Page Breaks (Row) + + + + + Vertical Page Breaks + + + + + Custom Properties + + + + + Drawing + + + + + Legacy Drawing Reference + + + + + Legacy Drawing Header Footer + + + + + Background Image + + + + + OLE Objects + + + + + Future Feature Data Storage Area + + + + + + + + + Sheet Properties + + + + + Dialog Sheet Views + + + + + Dialog Sheet Format Properties + + + + + Sheet Protection + + + + + Custom Sheet Views + + + + + Print Options + + + + + Page Margins + + + + + Page Setup Settings + + + + + Header & Footer Settings + + + + + Drawing + + + + + Legacy Drawing + + + + + Legacy Drawing Header Footer + + + + + + Future Feature Data Storage Area + + + + + + + + + Worksheet Properties + + + + + Worksheet Dimensions + + + + + Sheet Views + + + + + Sheet Format Properties + + + + + Column Information + + + + + Sheet Data + + + + + Sheet Calculation Properties + + + + + Sheet Protection + + + + + Protected Ranges + + + + + Scenarios + + + + + AutoFilter + + + + + Sort State + + + + + Data Consolidate + + + + + Custom Sheet Views + + + + + Merge Cells + + + + + Phonetic Properties + + + + + Conditional Formatting + + + + + Data Validations + + + + + Hyperlinks + + + + + Print Options + + + + + Page Margins + + + + + Page Setup Settings + + + + + Header and Footer Settings + + + + + Horizontal Page Breaks + + + + + Vertical Page Breaks + + + + + Custom Properties + + + + + Cell Watch Items + + + + + Ignored Errors + + + + + Smart Tags + + + + + Drawing + + + + + Legacy Drawing + + + + + Legacy Drawing Header Footer + + + + + Background Image + + + + + + Embedded Controls + + + + + Web Publishing Items + + + + + Table Parts + + + + + Future Feature Data Storage Area + + + + + + + + + Row + + + + + + + + Full Calculation On Load + + + + + + + Base Column Width + + + + + Default Column Width + + + + + Default Row Height + + + + + Custom Height + + + + + Hidden By Default + + + + + Thick Top Border + + + + + Thick Bottom Border + + + + + Maximum Outline Row + + + + + Column Outline Level + + + + + + + + Column Width & Formatting + + + + + + + + Minimum Column + + + + + Maximum Column + + + + + Column Width + + + + + Style + + + + + Hidden Columns + + + + + Best Fit Column Width + + + + + Custom Width + + + + + Show Phonetic Information + + + + + Outline Level + + + + + Collapsed + + + + + + Cell Span Type + + + + + + Cell Spans + + + + + + + + Cell + + + + + Future Feature Data Storage Area + + + + + + Row Index + + + + + Spans + + + + + Style Index + + + + + Custom Format + + + + + Row Height + + + + + Hidden + + + + + Custom Height + + + + + Outline Level + + + + + Collapsed + + + + + Thick Top Border + + + + + Thick Bottom + + + + + Show Phonetic + + + + + + + + Formula + + + + + Cell Value + + + + + Rich Text Inline + + + + + Future Feature Data Storage Area + + + + + + Reference + + + + + Style Index + + + + + Cell Data Type + + + + + Cell Metadata Index + + + + + Value Metadata Index + + + + + Show Phonetic + + + + + + Cell Type + + + + + Boolean + + + + + Number + + + + + Error + + + + + Shared String + + + + + String + + + + + Inline String + + + + + + + Formula Type + + + + + Normal + + + + + Array Entered + + + + + Table Formula + + + + + Shared Formula + + + + + + + + + Sheet Tab Color + + + + + Outline Properties + + + + + Page Setup Properties + + + + + + Synch Horizontal + + + + + Synch Vertical + + + + + Synch Reference + + + + + Transition Formula Evaluation + + + + + Transition Formula Entry + + + + + Published + + + + + Code Name + + + + + Filter Mode + + + + + Enable Conditional Formatting Calculations + + + + + + + Reference + + + + + + + + Worksheet View + + + + + Future Feature Data Storage Area + + + + + + + + + View Pane + + + + + Selection + + + + + PivotTable Selection + + + + + Future Feature Data Storage Area + + + + + + Window Protection + + + + + Show Formulas + + + + + Show Grid Lines + + + + + Show Headers + + + + + Show Zero Values + + + + + Right To Left + + + + + Sheet Tab Selected + + + + + Show Ruler + + + + + Show Outline Symbols + + + + + Default Grid Color + + + + + Show White Space + + + + + View Type + + + + + Top Left Visible Cell + + + + + Color Id + + + + + Zoom Scale + + + + + Zoom Scale Normal View + + + + + Zoom Scale Page Break Preview + + + + + Zoom Scale Page Layout View + + + + + Workbook View Index + + + + + + + Horizontal Split Position + + + + + Vertical Split Position + + + + + Top Left Visible Cell + + + + + Active Pane + + + + + Split State + + + + + + + + Pivot Area + + + + + + Pane + + + + + Show Header + + + + + Label + + + + + Data Selection + + + + + Extendable + + + + + Selection Count + + + + + Axis + + + + + Dimension + + + + + Start + + + + + Minimum + + + + + Maximum + + + + + Active Row + + + + + Active Column + + + + + Previous Row + + + + + Previous Column Selection + + + + + Click Count + + + + + Relationship Id + + + + + + + Pane + + + + + Active Cell Location + + + + + Active Cell Index + + + + + Sequence of References + + + + + + Pane Types + + + + + Bottom Right Pane + + + + + Top Right Pane + + + + + Bottom Left Pane + + + + + Top Left Pane + + + + + + + + + Break + + + + + + Page Break Count + + + + + Manual Break Count + + + + + + + Id + + + + + Minimum + + + + + Maximum + + + + + Manual Page Break + + + + + Pivot-Created Page Break + + + + + + Sheet View Type + + + + + Normal View + + + + + Page Break Preview + + + + + Page Layout View + + + + + + + + Apply Styles in Outline + + + + + Summary Below + + + + + Summary Right + + + + + Show Outline Symbols + + + + + + + Show Auto Page Breaks + + + + + Fit To Page + + + + + + + + Data Consolidation References + + + + + + Function Index + + + + + Use Left Column Labels + + + + + Labels In Top Row + + + + + Link + + + + + + Data Consolidation Functions + + + + + Average + + + + + Count + + + + + CountNums + + + + + Maximum + + + + + Minimum + + + + + Product + + + + + StdDev + + + + + StdDevP + + + + + Sum + + + + + Variance + + + + + VarP + + + + + + + + + Data Consolidation Reference + + + + + + Data Consolidation Reference Count + + + + + + + Reference + + + + + Named Range + + + + + Sheet Name + + + + + relationship Id + + + + + + + + Merged Cell + + + + + + Count + + + + + + + Reference + + + + + + + + Cell Smart Tags + + + + + + + + + Cell Smart Tag + + + + + + Reference + + + + + + + + Smart Tag Properties + + + + + + Smart Tag Type Index + + + + + Deleted + + + + + XML Based + + + + + + + Key Name + + + + + Value + + + + + + + Relationship id + + + + + + + Relationship Id + + + + + + + + Custom Sheet View + + + + + + + + + Pane Split Information + + + + + Selection + + + + + Horizontal Page Breaks + + + + + Vertical Page Breaks + + + + + Page Margins + + + + + Print Options + + + + + Page Setup Settings + + + + + Header Footer Settings + + + + + AutoFilter Settings + + + + + + + GUID + + + + + Print Scale + + + + + Color Id + + + + + Show Page Breaks + + + + + Show Formulas + + + + + Show Grid Lines + + + + + Show Headers + + + + + Show Outline Symbols + + + + + Show Zero Values + + + + + Fit To Page + + + + + Print Area Defined + + + + + Filtered List + + + + + Show AutoFitler Drop Down Controls + + + + + Hidden Rows + + + + + Hidden Columns + + + + + Visible State + + + + + Filter + + + + + View Type + + + + + Show Ruler + + + + + Top Left Visible Cell + + + + + + + + Data Validation + + + + + + Disable Prompts + + + + + Top Left Corner (X Coodrinate) + + + + + Top Left Corner (Y Coordinate) + + + + + Data Validation Item Count + + + + + + + + Formula 1 + + + + + Formula 2 + + + + + + Data Validation Type + + + + + Data Validation Error Style + + + + + IME Mode Enforced + + + + + Operator + + + + + Allow Blank + + + + + Show Drop Down + + + + + Show Input Message + + + + + Show Error Message + + + + + Error Alert Text + + + + + Error Message + + + + + Prompt Title + + + + + Input Prompt + + + + + Sequence of References + + + + + + Data Validation Type + + + + + None + + + + + Whole Number + + + + + Decimal + + + + + List + + + + + Date + + + + + Time + + + + + Text Length + + + + + Custom + + + + + + + Data Validation Operator + + + + + Between + + + + + Not Between + + + + + Equal + + + + + Not Equal + + + + + Less Than + + + + + Less Than Or Equal + + + + + Greater Than + + + + + Greater Than Or Equal + + + + + + + Data Validation Error Styles + + + + + Stop Icon + + + + + Warning Icon + + + + + Information Icon + + + + + + + Data Validation IME Mode + + + + + IME Mode Not Controlled + + + + + IME Off + + + + + IME On + + + + + Disabled IME Mode + + + + + Hiragana IME Mode + + + + + Full Katakana IME Mode + + + + + Half-Width Katakana + + + + + Full-Width Alpha-Numeric IME Mode + + + + + Half Alpha IME + + + + + Full Width Hangul + + + + + Half-Width Hangul IME Mode + + + + + + + Conditional Format Type + + + + + Expression + + + + + Cell Is + + + + + Color Scale + + + + + Data Bar + + + + + Icon Set + + + + + Top 10 + + + + + Unique Values + + + + + Duplicate Values + + + + + Contains Text + + + + + Does Not Contain Text + + + + + Begins With + + + + + Ends With + + + + + Contains Blanks + + + + + Contains No Blanks + + + + + Contains Errors + + + + + Contains No Errors + + + + + Time Period + + + + + Above or Below Average + + + + + + + Time Period Types + + + + + Today + + + + + Yesterday + + + + + Tomorrow + + + + + Last 7 Days + + + + + This Month + + + + + Last Month + + + + + Next Month + + + + + This Week + + + + + Last Week + + + + + Next Week + + + + + + + Conditional Format Operators + + + + + Less Than + + + + + Less Than Or Equal + + + + + Equal + + + + + Not Equal + + + + + Greater Than Or Equal + + + + + Greater Than + + + + + Between + + + + + Not Between + + + + + Contains + + + + + Does Not Contain + + + + + Begins With + + + + + Ends With + + + + + + + Conditional Format Value Object Type + + + + + Number + + + + + Percent + + + + + Maximum + + + + + Minimum + + + + + Formula + + + + + Percentile + + + + + + + + + Conditional Formatting Rule + + + + + + + PivotTable Conditional Formatting + + + + + Sequence of Refernces + + + + + + + + Formula + + + + + Color Scale + + + + + Data Bar + + + + + Icon Set + + + + + + + Type + + + + + Differential Formatting Id + + + + + Priority + + + + + Stop If True + + + + + Above Or Below Average + + + + + Top 10 Percent + + + + + Bottom N + + + + + Operator + + + + + Text + + + + + Time Period + + + + + Rank + + + + + StdDev + + + + + Equal Average + + + + + + + + Hyperlink + + + + + + + + Reference + + + + + Relationship Id + + + + + Location + + + + + Tool Tip + + + + + Display String + + + + + + + + + Formula Type + + + + + Always Calculate Array + + + + + Range of Cells + + + + + Data Table 2-D + + + + + Data Table Row + + + + + Input 1 Deleted + + + + + Input 2 Deleted + + + + + Data Table Cell 1 + + + + + Input Cell 2 + + + + + Calculate Cell + + + + + Shared Group Index + + + + + Assigns Value to Name + + + + + + + + + + Conditional Format Value Object + + + + + Color Gradiant Interpolation + + + + + + + + + Conditional Format Value Object + + + + + Data Bar Color + + + + + + Minimum Length + + + + + Maximum Length + + + + + Show Values + + + + + + + + Conditional Formatting Object + + + + + + Icon Set + + + + + Show Value + + + + + Percent + + + + + Reverse Icons + + + + + + + + + + Type + + + + + Value + + + + + Greater Than Or Equal + + + + + + + Left Page Margin + + + + + Right Page Margin + + + + + Top Page Margin + + + + + Bottom Page Margin + + + + + Header Page Margin + + + + + Footer Page Margin + + + + + + + Horizontal Centered + + + + + Vertical Centered + + + + + Print Headings + + + + + Print Grid Lines + + + + + Grid Lines Set + + + + + + + Paper Size + + + + + Print Scale + + + + + First Page Number + + + + + Fit To Width + + + + + Fit To Height + + + + + Page Order + + + + + Orientation + + + + + Use Printer Defaults + + + + + Black And White + + + + + Draft + + + + + Print Cell Comments + + + + + Use First Page Number + + + + + Print Error Handling + + + + + Horizontal DPI + + + + + Vertical DPI + + + + + Number Of Copies + + + + + Id + + + + + + Page Order + + + + + Down Then Over + + + + + Over Then Down + + + + + + + Orientation + + + + + Default + + + + + Portrait + + + + + Landscape + + + + + + + Cell Comments + + + + + None + + + + + Print Comments As Displayed + + + + + Print At End + + + + + + + + + Odd Header + + + + + Odd Page Footer + + + + + Even Page Header + + + + + Even Page Footer + + + + + First Page Header + + + + + First Page Footer + + + + + + Different Odd Even Header Footer + + + + + Different First Page + + + + + Scale Header & Footer With Document + + + + + Align Margins + + + + + + Print Errors + + + + + Display Cell Errors + + + + + Show Cell Errors As Blank + + + + + Dash Cell Errors + + + + + NA + + + + + + + + + Scenario + + + + + + Current Scenario + + + + + Last Shown Scenario + + + + + Sequence of References + + + + + + + Password + + + + + Sheet Locked + + + + + Objects Locked + + + + + Scenarios Locked + + + + + Format Cells Locked + + + + + Format Columns Locked + + + + + Format Rows Locked + + + + + Insert Columns Locked + + + + + Insert Rows Locked + + + + + Insert Hyperlinks Locked + + + + + Delete Columns Locked + + + + + Delete Rows Locked + + + + + Select Locked Cells Locked + + + + + Sort Locked + + + + + AutoFilter Locked + + + + + Pivot Tables Locked + + + + + Select Unlocked Cells Locked + + + + + + + + Protected Range + + + + + + + + Password + + + + + Sequence of References + + + + + Name + + + + + Security Descriptor + + + + + + + + Input Cells + + + + + + Scenario Name + + + + + Scenario Locked + + + + + Hidden Scenario + + + + + Changing Cell Count + + + + + User Name + + + + + Scenario Comment + + + + + + + Reference + + + + + Deleted + + + + + Undone + + + + + Value + + + + + Number Format Id + + + + + + + + Cell Watch Item + + + + + + + + Reference + + + + + + + + Chart Sheet Properties + + + + + Chart Sheet Views + + + + + Chart Sheet Protection + + + + + Custom Chart Sheet Views + + + + + + + + Drawing + + + + + + Legacy Drawing Reference in Header Footer + + + + + + + + + + + + + + Published + + + + + Code Name + + + + + + + + Chart Sheet View + + + + + + + + + + + + Sheet Tab Selected + + + + + Window Zoom Scale + + + + + Workbook View Id + + + + + Zoom To Fit + + + + + + + Password + + + + + Contents + + + + + Objects Locked + + + + + + + Paper Size + + + + + First Page Number + + + + + Orientation + + + + + Use Printer Defaults + + + + + Black And White + + + + + Draft + + + + + Use First Page Number + + + + + Horizontal DPI + + + + + Vertical DPI + + + + + Number Of Copies + + + + + Id + + + + + + + + Custom Chart Sheet View + + + + + + + + + + Chart Sheet Page Setup + + + + + + + GUID + + + + + Print Scale + + + + + Visible State + + + + + Zoom To Fit + + + + + + + + Custom Property + + + + + + + + Custom Property Name + + + + + Relationship Id + + + + + + + + OLE Object + + + + + + + + OLE ProgId + + + + + Data or View Aspect + + + + + OLE Link Moniker + + + + + OLE Update + + + + + Auto Load + + + + + Shape Id + + + + + Relationship Id + + + + + + Data View Aspect Type + + + + + Object Display Content + + + + + Object Display Icon + + + + + + + OLE Update Types + + + + + Always Update OLE + + + + + Update OLE On Call + + + + + + + + + Web Publishing Item + + + + + + Web Publishing Items Count + + + + + + + Id + + + + + Destination Bookmark + + + + + Web Source Type + + + + + Source Id + + + + + Source Object Name + + + + + Destination File Name + + + + + Title + + + + + Automatically Publish + + + + + + + + Embedded Control + + + + + + + + Shape Id + + + + + Relationship Id + + + + + Control Name + + + + + + Web Source Type + + + + + All Sheet Content + + + + + Print Area + + + + + AutoFilter + + + + + Range + + + + + Chart + + + + + PivotTable + + + + + QueryTable + + + + + Label + + + + + + + + + Ignored Error + + + + + + + + + Sequence of References + + + + + Evaluation Error + + + + + Two Digit Text Year + + + + + Number Stored As Text + + + + + Formula + + + + + Formula Range + + + + + Unlocked Formula + + + + + Empty Cell Reference + + + + + List Data Validation + + + + + Calculated Column + + + + + + Pane State + + + + + Split + + + + + Frozen + + + + + Frozen Split + + + + + + + + + Table Part + + + + + + Count + + + + + + + Relationship Id + + + + + + + + + Metadata + + + + + + + Metadata Types Collection + + + + + Metadata String Store + + + + + MDX Metadata Information + + + + + Future Metadata + + + + + Cell Metadata + + + + + Value Metadata + + + + + Future Feature Storage Area + + + + + + + + + Metadata Type Information + + + + + + Metadata Type Count + + + + + + + Metadata Type Name + + + + + Minimum Supported Version + + + + + Metadata Ghost Row + + + + + Metadata Ghost Column + + + + + Metadata Edit + + + + + Metadata Cell Value Delete + + + + + Metadata Copy + + + + + Metadata Paste All + + + + + Metadata Paste Formulas + + + + + Metadata Paste Special Values + + + + + Metadata Paste Formats + + + + + Metadata Paste Comments + + + + + Metadata Paste Data Validation + + + + + Metadata Paste Borders + + + + + Metadata Paste Column Widths + + + + + Metadata Paste Number Formats + + + + + Metadata Merge + + + + + Meatadata Split First + + + + + Metadata Split All + + + + + Metadata Insert Delete + + + + + Metadata Clear All + + + + + Metadata Clear Formats + + + + + Metadata Clear Contents + + + + + Metadata Clear Comments + + + + + Metadata Formula Assignment + + + + + Metadata Coercion + + + + + Adjust Metadata + + + + + Cell Metadata + + + + + + + + Metadata Block + + + + + + Metadata Block Count + + + + + + + + Metadata Record + + + + + + + + Metadata Record Type Index + + + + + Metadata Record Value Index + + + + + + + + Future Metadata Block + + + + + Future Feature Data Storage Area + + + + + + Metadata Type Name + + + + + Future Metadata Block Count + + + + + + + + Future Feature Storage Area + + + + + + + + + MDX Metadata Record + + + + + + MDX Metadata Record Count + + + + + + + + Tuple MDX Metadata + + + + + Set MDX Metadata + + + + + Member Property MDX Metadata + + + + + KPI MDX Metadata + + + + + + Connection Name Index + + + + + Cube Function Tag + + + + + + MDX Function Type + + + + + Cube Member + + + + + Cube Value + + + + + Cube Set + + + + + Cube Set Count + + + + + Cube Ranked Member + + + + + Cube Member Property + + + + + Cube KPI Member + + + + + + + + + Member Unique Name Index + + + + + + Member Index Count + + + + + Server Formatting Culture Currency + + + + + Server Formatting String Index + + + + + Server Formatting Built-In Number Format Index + + + + + Server Formatting Background Color + + + + + Server Formatting Foreground Color + + + + + Server Formatting Italic Font + + + + + Server Formatting Underline Font + + + + + Server Formatting Strikethrough Font + + + + + Server Formatting Bold Font + + + + + + + + Member Unique Name Index + + + + + + Set Definition Index + + + + + Sort By Member Index Count + + + + + Set Sort Order + + + + + + MDX Set Order + + + + + Unsorted + + + + + Ascending + + + + + Descending + + + + + Alpha Ascending Sort Order + + + + + Alpha Descending Sort Order + + + + + Natural Ascending + + + + + Natural Descending + + + + + + + + Member Unique Name Index + + + + + Property Name Index + + + + + + + Member Unique Name Index + + + + + KPI Index + + + + + KPI Property + + + + + + MDX KPI Property + + + + + Value + + + + + Goal + + + + + Status + + + + + Trend + + + + + Weight + + + + + Current Time Member + + + + + + + + Index Value + + + + + String is a Set + + + + + + + + MDX Metadata String + + + + + + MDX Metadata String Count + + + + + + + + + + Single Cells + + + + + + + Table Properties + + + + + + + + + Cell Properties + + + + + Future Feature Data Storage Area + + + + + + Table Id + + + + + Reference + + + + + Connection ID + + + + + + + + Column XML Properties + + + + + Future Feature Data Storage Area + + + + + + Table Field Id + + + + + Unique Table Name + + + + + + + + Future Feature Data Storage Area + + + + + + XML Map Id + + + + + XPath + + + + + XML Data Type + + + + + + + + + Style Sheet + + + + + + + Number Formats + + + + + Fonts + + + + + Fills + + + + + Borders + + + + + Formatting Records + + + + + Cell Formats + + + + + Cell Styles + + + + + Formats + + + + + Table Styles + + + + + Colors + + + + + Future Feature Data Storage Area + + + + + + + + Horizontal Alignment + + + + + Vertical Alignment + + + + + Text Rotation + + + + + Wrap Text + + + + + Indent + + + + + Relative Indent + + + + + Justify Last Line + + + + + Shrink To Fit + + + + + Reading Order + + + + + + Border Line Styles + + + + + None + + + + + Thin Border + + + + + Medium Border + + + + + Dashed + + + + + Dotted + + + + + Thick Line Border + + + + + Double Line + + + + + Hairline Border + + + + + Medium Dashed + + + + + Dash Dot + + + + + Medium Dash Dot + + + + + Dash Dot Dot + + + + + Medium Dash Dot Dot + + + + + Slant Dash Dot + + + + + + + + + Border + + + + + + Border Count + + + + + + + + Left Border + + + + + Right Border + + + + + Top Border + + + + + Bottom Border + + + + + Diagonal + + + + + Vertical Inner Border + + + + + Horizontal Inner Borders + + + + + + Diagonal Up + + + + + Diagonal Down + + + + + Outline + + + + + + + + Color + + + + + + Line Style + + + + + + + Cell Locked + + + + + Hidden Cell + + + + + + + + Font + + + + + + Font Count + + + + + + + + Fill + + + + + + Fill Count + + + + + + + + Pattern + + + + + Gradient + + + + + + + + + Foreground Color + + + + + Background Color + + + + + + Pattern Type + + + + + + + Automatic + + + + + Index + + + + + Alpha Red Green Blue Color Value + + + + + Theme Color + + + + + Tint + + + + + + Pattern Type + + + + + None + + + + + Solid + + + + + Medium Gray + + + + + Dary Gray + + + + + Light Gray + + + + + Dark Horizontal + + + + + Dark Vertical + + + + + Dark Down + + + + + Dark Up + + + + + Dark Grid + + + + + Dark Trellis + + + + + Light Horizontal + + + + + Light Vertical + + + + + Light Down + + + + + Light Up + + + + + Light Grid + + + + + Light Trellis + + + + + Gray 0.125 + + + + + Gray 0.0625 + + + + + + + + + Gradient Stop + + + + + + Gradient Fill Type + + + + + Linear Gradient Degree + + + + + Left Convergence + + + + + Right Convergence + + + + + Top Gradient Convergence + + + + + Bottom Convergence + + + + + + + + Color + + + + + + Gradient Stop Position + + + + + + Gradient Type + + + + + Linear Gradient + + + + + Path + + + + + + + Horizontal Alignment Type + + + + + General Horizontal Alignment + + + + + Left Horizontal Alignment + + + + + Centered Horizontal Alignment + + + + + Right Horizontal Alignment + + + + + Fill + + + + + Justify + + + + + Center Continuous Horizontal Alignment + + + + + Distributed Horizontal Alignment + + + + + + + Vertical Alignment Types + + + + + Align Top + + + + + Centered Vertical Alignment + + + + + Aligned To Bottom + + + + + Justified Vertically + + + + + Distributed Vertical Alignment + + + + + + + + + Number Formats + + + + + + Number Format Count + + + + + + + Number Format Id + + + + + Number Format Code + + + + + + + + Formatting Elements + + + + + + Style Count + + + + + + + + Format + + + + + + Format Count + + + + + + + + Alignment + + + + + Protection + + + + + Future Feature Data Storage Area + + + + + + Number Format Id + + + + + Font Id + + + + + Fill Id + + + + + Border Id + + + + + Format Id + + + + + Quote Prefix + + + + + Pivot Button + + + + + Apply Number Format + + + + + Apply Font + + + + + Apply Fill + + + + + Apply Border + + + + + Apply Alignment + + + + + Apply Protection + + + + + + + + Cell Style + + + + + + Style Count + + + + + + + + Future Feature Data Storage Area + + + + + + User Defined Cell Style + + + + + Format Id + + + + + Built-In Style Id + + + + + Outline Style + + + + + Hidden Style + + + + + Custom Built In + + + + + + + + Formatting + + + + + + Format Count + + + + + + + + Font Properties + + + + + Number Format + + + + + Fill + + + + + Alignment + + + + + Border Properties + + + + + Protection Properties + + + + + Future Feature Data Storage Area + + + + + + + Number Format Id + + + + + + Font Id + + + + + + Fill Id + + + + + + Border Id + + + + + + Cell Style Format Id + + + + + + Format Id + + + + + + + + Color Indexes + + + + + MRU Colors + + + + + + + + + RGB Color + + + + + + + + + Color + + + + + + + + Alpha Red Green Blue + + + + + + + + Table Style + + + + + + Table Style Count + + + + + Default Table Style + + + + + Default Pivot Style + + + + + + + + Table Style + + + + + + Table Style Name + + + + + Pivot Style + + + + + Table + + + + + Table Style Count + + + + + + + Table Style Type + + + + + Band Size + + + + + Formatting Id + + + + + + Table Style Type + + + + + Whole Table Style + + + + + Header Row Style + + + + + Total Row Style + + + + + First Column Style + + + + + Last Column Style + + + + + First Row Stripe Style + + + + + Second Row Stripe Style + + + + + First Column Stripe Style + + + + + Second Column Stipe Style + + + + + First Header Row Style + + + + + Last Header Style + + + + + First Total Row Style + + + + + Last Total Row Style + + + + + First Subtotal Column Style + + + + + Second Subtotal Column Style + + + + + Third Subtotal Column Style + + + + + First Subtotal Row Style + + + + + Second Subtotal Row Style + + + + + Third Subtotal Row Style + + + + + Blank Row Style + + + + + First Column Subheading Style + + + + + Second Column Subheading Style + + + + + Third Column Subheading Style + + + + + First Row Subheading Style + + + + + Second Row Subheading Style + + + + + Third Row Subheading Style + + + + + Page Field Labels Style + + + + + Page Field Values Style + + + + + + + + Value + + + + + + + Value + + + + + + + Value + + + + + + + String Value + + + + + + + Value + + + + + + Vertical Alignment Run Types + + + + + Baseline + + + + + Superscript + + + + + Subscript + + + + + + + + Font Scheme + + + + + + Font scheme Styles + + + + + None + + + + + Major Font + + + + + Minor Font + + + + + + + + Underline Value + + + + + + Underline Types + + + + + Single Underline + + + + + Double Underline + + + + + Accounting Single Underline + + + + + Accounting Double Underline + + + + + None + + + + + + + + + Font Name + + + + + Character Set + + + + + Font Family + + + + + Bold + + + + + Italic + + + + + Strike Through + + + + + Outline + + + + + Shadow + + + + + Condense + + + + + Extend + + + + + Text Color + + + + + Font Size + + + + + Underline + + + + + Text Vertical Alignment + + + + + Scheme + + + + + + + + Auto Format Id + + + + + Apply Number Formats + + + + + Apply Border Formats + + + + + Apply Font Formats + + + + + Apply Pattern Formats + + + + + Apply Alignment Formats + + + + + Apply Width / Height Formats + + + + + + + + + + + External Reference + + + + + + + External Workbook + + + + + DDE Connection + + + + + OLE Link + + + + + + + + + + Supporting Workbook Sheet Names + + + + + Named Links + + + + + Cached Worksheet Data + + + + + + Relationship to supporting book file path + + + + + + + + Sheet Name + + + + + + + + Sheet Name Value + + + + + + + + Defined Name + + + + + + + + Defined Name + + + + + Refers To + + + + + Sheet Id + + + + + + + + External Sheet Data Set + + + + + + + + + Row + + + + + + Sheet Id + + + + + Last Refresh Resulted in Error + + + + + + + + External Cell Data + + + + + + Row + + + + + + + + Value + + + + + + Reference + + + + + Type + + + + + Value Metadata + + + + + + + + DDE Items Collection + + + + + + Service name + + + + + Topic for DDE server + + + + + + + + DDE Item definition + + + + + + + + + DDE Name Values + + + + + + DDE Name + + + + + OLE + + + + + Advise + + + + + Data is an Image + + + + + + + + Value + + + + + + Rows + + + + + Columns + + + + + + + + DDE Link Value + + + + + + DDE Value Type + + + + + + DDE Value Types + + + + + Nil + + + + + Boolean + + + + + Real Number + + + + + Error + + + + + String + + + + + + + + + OLE Link Items + + + + + + OLE Link Relationship + + + + + OLE Link ProgID + + + + + + + + OLE Link Item + + + + + + + + OLE Name + + + + + Icon + + + + + Advise + + + + + Object is an Image + + + + + + + + + + + + Table + + + + + + + Table AutoFilter + + + + + Sort State + + + + + Table Columns + + + + + Table Style + + + + + Future Feature Data Storage Area + + + + + + Table Id + + + + + Name + + + + + Table Name + + + + + Table Comment + + + + + Reference + + + + + Table Type + + + + + Header Row Count + + + + + Insert Row Showing + + + + + Insert Row Shift + + + + + Totals Row Count + + + + + Totals Row Shown + + + + + Published + + + + + Header Row Format Id + + + + + Data Area Format Id + + + + + Totals Row Format Id + + + + + Header Row Border Format Id + + + + + Table Border Format Id + + + + + Totals Row Border Format Id + + + + + Header Row Style + + + + + Data Style Name + + + + + Totals Row Style + + + + + Connection ID + + + + + + Table Type + + + + + Worksheet + + + + + XML + + + + + Query Table + + + + + + + + Style Name + + + + + Show First Column + + + + + Show Last Column + + + + + Show Row Stripes + + + + + Show Column Stripes + + + + + + + + Table Column + + + + + + Column Count + + + + + + + + Calculated Column Formula + + + + + Totals Row Formula + + + + + XML Column Properties + + + + + Future Feature Data Storage Area + + + + + + Table Field Id + + + + + Unique Name + + + + + Column name + + + + + Totals Row Function + + + + + Totals Row Label + + + + + Query Table Field Id + + + + + Header Row Cell Format Id + + + + + Data & Insert Row Format Id + + + + + Totals Row Format Id + + + + + Header Row Cell Style + + + + + Data Area Style Name + + + + + Totals Row Style Name + + + + + + + + + Array + + + + + + + + Totals Row Function Types + + + + + None + + + + + Sum + + + + + Minimum + + + + + Maximum + + + + + Average + + + + + Non Empty Cell Count + + + + + Count Numbers + + + + + StdDev + + + + + Var + + + + + Custom Formula + + + + + + + + + Future Feature Data Storage Area + + + + + + XML Map Id + + + + + XPath + + + + + Denormalized + + + + + XML Data Type + + + + + + XML Data Types + + + + + String + + + + + Normalized String + + + + + Token + + + + + Byte + + + + + Unsigned Byte + + + + + Base 64 Encoded Binary + + + + + Hex Binary + + + + + Integer + + + + + Positive Integer + + + + + Negative Integer + + + + + Non Positive Integer + + + + + Non Negative Integer + + + + + Integer + + + + + Unsigned Integer + + + + + Long + + + + + Unsigned Long + + + + + Short + + + + + Unsigned Short + + + + + Decimal + + + + + Float + + + + + Double + + + + + Boolean + + + + + Time + + + + + Date Time + + + + + Duration + + + + + Date + + + + + gMonth + + + + + gYear + + + + + gYearMonth + + + + + gDay + + + + + gMonthDays + + + + + Name + + + + + Qname + + + + + NCName + + + + + Any URI + + + + + Language + + + + + ID + + + + + IDREF + + + + + IDREFS + + + + + ENTITY + + + + + ENTITIES + + + + + Notation + + + + + NMTOKEN + + + + + NMTOKENS + + + + + Any Type + + + + + + + + + + Volatile Dependency Types + + + + + + + Volatile Dependency Type + + + + + + + + + + Main + + + + + + Type + + + + + + + + Topic + + + + + + First String + + + + + + + + Topic Value + + + + + Strings in Subtopic + + + + + References + + + + + + Type + + + + + + + Reference + + + + + Sheet Id + + + + + + Volatile Dependency Types + + + + + Real Time Data + + + + + OLAP Formulas + + + + + + + Volatile Dependency Value Types + + + + + Boolean + + + + + Real Number + + + + + Error + + + + + String + + + + + + + + + + + Workbook + + + + + + + File Version + + + + + File Sharing + + + + + Workbook Properties + + + + + Workbook Protection + + + + + Workbook Views + + + + + Sheets + + + + + Function Groups + + + + + External References + + + + + Defined Names + + + + + Calculation Properties + + + + + OLE Size + + + + + Custom Workbook Views + + + + + PivotCaches + + + + + Smart Tag Properties + + + + + Smart Tag Types + + + + + Web Publishing Properties + + + + + File Recovery Properties + + + + + Web Publish Objects + + + + + Future Feature Data Storage Area + + + + + + + + Application Name + + + + + Last Edited Version + + + + + Lowest Edited Version + + + + + Build Version + + + + + Code Name + + + + + + + + Workbook View + + + + + + + + + + + Visibility + + + + + Minimized + + + + + Show Horizontal Scroll + + + + + Show Vertical Scroll + + + + + Show Sheet Tabs + + + + + Upper Left Corner (X Coordinate) + + + + + Upper Left Corner (Y Coordinate) + + + + + Window Width + + + + + Window Height + + + + + Sheet Tab Ratio + + + + + First Sheet + + + + + Active Sheet Index + + + + + AutoFilter Date Grouping + + + + + + Visibility Types + + + + + Visible + + + + + Hidden + + + + + Very Hidden + + + + + + + + + Custom Workbook View + + + + + + + + + + + Custom View Name + + + + + Custom View GUID + + + + + Auto Update + + + + + Merge Interval + + + + + Changes Saved Win + + + + + Only Synch + + + + + Personal View + + + + + Include Print Settings + + + + + Include Hidden Rows & Columns + + + + + Maximized + + + + + Minimized + + + + + Show Horizontal Scroll + + + + + Show Vertical Scroll + + + + + Show Sheet Tabs + + + + + Top Left Corner (X Coordinate) + + + + + Top Left Corner (Y Coordinate) + + + + + Window Width + + + + + Window Height + + + + + Sheet Tab Ratio + + + + + Active Sheet in Book View + + + + + Show Formula Bar + + + + + Show Status Bar + + + + + Show Comments + + + + + Show Objects + + + + + + Comment Display Types + + + + + No Comments + + + + + Show Comment Indicator + + + + + Show Comment & Indicator + + + + + + + Object Display Types + + + + + All + + + + + Show Placeholders + + + + + None + + + + + + + + + Sheet Information + + + + + + + + Sheet Name + + + + + Sheet Tab Id + + + + + Visible State + + + + + Relationship Id + + + + + + Sheet Visibility Types + + + + + Visible + + + + + Hidden + + + + + Very Hidden + + + + + + + + Date 1904 + + + + + Show Objects + + + + + Show Border Unselected Table + + + + + Filter Privacy + + + + + Prompted Solutions + + + + + Show Ink Annotations + + + + + Create Backup File + + + + + Save External Link Values + + + + + Update Links Behavior + + + + + Code Name + + + + + Hide Pivot Field List + + + + + Show Pivot Chart Filter + + + + + Allow Refresh Query + + + + + Publish Items + + + + + Check Compatibility On Save + + + + + Auto Compress Pictures + + + + + Refresh all Connections on Open + + + + + Default Theme Version + + + + + + Update Links Behavior Types + + + + + User Set + + + + + Never Update Links + + + + + Always Update Links + + + + + + + + Embed SmartTags + + + + + Show Smart Tags + + + + + + Smart Tag Display Types + + + + + All + + + + + None + + + + + No Smart Tag Indicator + + + + + + + + + Smart Tag Type + + + + + + + + SmartTag Namespace URI + + + + + Name + + + + + Smart Tag URL + + + + + + + Auto Recover + + + + + Crash Save + + + + + Data Extract Load + + + + + Repair Load + + + + + + + Calculation Id + + + + + Calculation Mode + + + + + Full Calculation On Load + + + + + Reference Mode + + + + + Calculation Iteration + + + + + Iteration Count + + + + + Iterative Calculation Delta + + + + + Full Precision Calculation + + + + + Calc Completed + + + + + Calculate On Save + + + + + Concurrent Calculations + + + + + Concurrent Thread Manual Count + + + + + Force Full Calculation + + + + + + Calculation Mode + + + + + Manual Calculation Mode + + + + + Automatic + + + + + Automatic Calculation (No Tables) + + + + + + + Reference Mode + + + + + A1 Mode + + + + + R1C1 Reference Mode + + + + + + + + + Defined Name + + + + + + + + + + Defined Name + + + + + Comment + + + + + Custom Menu Text + + + + + Description + + + + + Help + + + + + Status Bar + + + + + Local Name Sheet Id + + + + + Hidden Name + + + + + Function + + + + + Procedure + + + + + External Function + + + + + Function Group Id + + + + + Shortcut Key + + + + + Publish To Server + + + + + Workbook Parameter (Server) + + + + + + + + + + External Reference + + + + + + + + Relationship Id + + + + + + + Relationship Id + + + + + + + + PivotCache + + + + + + + + PivotCache Id + + + + + Relationship Id + + + + + + + Read Only Recommended + + + + + User Name + + + + + Write Reservation Password + + + + + + + Reference + + + + + + + Workbook Password + + + + + Revisions Password + + + + + Lock Structure + + + + + Lock Windows + + + + + Lock Revisions + + + + + + + Use CSS + + + + + Thicket + + + + + Enable Long File Names + + + + + VML in Browsers + + + + + Allow PNG + + + + + Target Screen Size + + + + + DPI + + + + + Code Page + + + + + + Target Screen Size Types + + + + + 544 x 376 Resolution + + + + + 640 x 480 Resolution + + + + + 720 x 512 Resolution + + + + + 800 x 600 Resolution + + + + + 1024 x 768 Resolution + + + + + 1152 x 882 Resolution + + + + + 1152 x 900 Resolution + + + + + 1280 x 1024 Resolution + + + + + 1600 x 1200 Resolution + + + + + 1800 x 1440 Resolution + + + + + 1920 x 1200 Resolution + + + + + + + + + Function Group + + + + + + Built-in Function Group Count + + + + + + + Name + + + + + + + + Web Publishing Object + + + + + + Count + + + + + + + Id + + + + + Div Id + + + + + Source Object + + + + + Destination File + + + + + Title + + + + + Auto Republish + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/vml-main.xsd b/tests/resources/schema/ecma-376/vml-main.xsd new file mode 100644 index 0000000000..784aee8f34 --- /dev/null +++ b/tests/resources/schema/ecma-376/vml-main.xsd @@ -0,0 +1,1733 @@ + + + + + + + + + + + + Unique Identifier + + + + + + + Shape Styling Properties + + + + + + + Shape Type Reference + + + + + + + Adjustment Parameters + + + + + + + Edge Path + + + + + + + Shape Fill Toggle + + + + + Fill Color + + + + + + + Image Transparency Color + + + + + + + VML Extension Handling Behavior + + + + + + + + + Hyperlink Target + + + + + Hyperlink Display Target + + + + + CSS Reference + + + + + Shape Title + + + + + Alternate Text + + + + + Coordinate Space Size + + + + + Coordinate Space Origin + + + + + Shape Bounding Polygon + + + + + Print Toggle + + + + + + + + + Fill Color Opacity + + + + + Shape Stroke Toggle + + + + + Shape Stroke Color + + + + + Shape Stroke Weight + + + + + Inset Border From Path + + + + + + + Optional String + + + + + Shape Handle Toggle + + + + + Regroup ID + + + + + Double-click Notification Toggle + + + + + Button Behavior Toggle + + + + + Hide Script Anchors + + + + + Graphical Bullet + + + + + Horizontal Rule Toggle + + + + + Horizontal Rule Standard Display Toggle + + + + + Horizontal Rule 3D Shading Toggle + + + + + Horizontal Rule Length Percentage + + + + + Horizontal Rule Alignment + + + + + Allow in Table Cell + + + + + Allow Shape Overlap + + + + + Exists In Master Slide + + + + + Border Top Color + + + + + Border Left Color + + + + + Bottom Border Color + + + + + Border Right Color + + + + + Diagram Node Layout Identifier + + + + + Diagram Node Identifier + + + + + Diagram Node Recent Layout Identifier + + + + + Text Inset Mode + + + + + + + Optional Number + + + + + Shape Connector Type + + + + + Black-and-White Mode + + + + + Pure Black-and-White Mode + + + + + Normal Black-and-White Mode + + + + + Force Dashed Outline + + + + + Embedded Object Icon Toggle + + + + + Embedded Object Toggle + + + + + Relative Resize Toggle + + + + + Clip to Wrapping Polygon + + + + + Clipping Toggle + + + + + + + + + + + + + + + Image Source + + + + + Image Left Crop + + + + + Image Top Crop + + + + + Image Right Crop + + + + + Image Bottom Crop + + + + + Image Intensity + + + + + Image Brightness + + + + + Image Gamma Correction + + + + + Image Grayscale Toggle + + + + + Image Bilevel Toggle + + + + + + + Stroke Toggle + + + + + Stroke Weight + + + + + Stroke Color + + + + + Stroke Opacity + + + + + Stroke Line Style + + + + + Miter Joint Limit + + + + + Line End Join Style + + + + + Line End Cap + + + + + Stroke Dash Pattern + + + + + Stroke Image Style + + + + + Stroke Image Location + + + + + Stroke Image Aspect Ratio + + + + + Stroke Image Size + + + + + Stoke Image Alignment + + + + + Stroke Alternate Pattern Color + + + + + Line Start Arrowhead + + + + + Line Start Arrowhead Width + + + + + Line Start Arrowhead Length + + + + + Line End Arrowhead + + + + + Line End Arrowhead Width + + + + + Line End Arrowhead Length + + + + + Original Image Reference + + + + + Alternate Image Reference + + + + + Stroke Title + + + + + Force Dashed Outline + + + + + Relationship + + + + + Inset Border From Path + + + + + Relationship to Part + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Shape Definition + + + + + Shape Template + + + + + Shape Group + + + + + Document Background + + + + + + + + + + + + + + + + Encoded Package + + + + + Storage for Alternate Math Content + + + + + + + + + + + + + + + Master Element Toggle + + + + + + + + + + + + + + + + + + + + + + + + Group Diagram Type + + + + + Table Properties + + + + + Table Row Height Limits + + + + + + + + + + + + Black-and-White Mode + + + + + Pure Black-and-White Mode + + + + + Normal Black-and-White Mode + + + + + Target Screen Size + + + + + + Shape Fill Properties + + + + + Set of Formulas + + + + + Set of Handles + + + + + Image Data + + + + + Shape Path + + + + + Text Box + + + + + Shadow Effect + + + + + Line Stroke Settings + + + + + Text Layout Path + + + + + + + + + + Fill Type + + + + + Fill Toggle + + + + + Primary Color + + + + + Primary Color Opacity + + + + + Secondary Color + + + + + Fill Image Source + + + + + Hyperlink Target + + + + + Alternate Image Reference Location + + + + + Fill Image Size + + + + + Fill Image Origin + + + + + Fill Image Position + + + + + Image Aspect Ratio + + + + + Intermediate Colors + + + + + Gradient Angle + + + + + Align Image With Shape + + + + + Gradient Center + + + + + Radial Gradient Size + + + + + Radial Gradient Center + + + + + Gradient Fill Method + + + + + Detect Mouse Click + + + + + Title + + + + + Secondary Color Opacity + + + + + Recolor Fill as Picture + + + + + Rotate Fill with Shape + + + + + Relationship to Part + + + + + Relationship to Part + + + + + + + + Single Formula + + + + + + + + Equation + + + + + + + + Shape Handle + + + + + + + + Handle Position + + + + + Handle Polar Center + + + + + Handle Coordinate Mapping + + + + + Invert Handle's X Position + + + + + Invert Handle's Y Position + + + + + Handle Inversion Toggle + + + + + Handle X Position Range + + + + + Handle Y Position Range + + + + + Handle Polar Radius Range + + + + + + + + + + Embossed Color + + + + + Black Recoloring Color + + + + + Original Image Reference + + + + + Alternate Image Reference + + + + + Image Data Title + + + + + Image Embedded Object ID + + + + + Detect Mouse Click + + + + + Movie Reference + + + + + Relationship to Part + + + + + Explicit Relationship to Image Data + + + + + Explicit Relationship to Alternate Image Data + + + + + Explicit Relationship to Hyperlink Target + + + + + + + + Path Definition + + + + + Limo Stretch Point + + + + + Text Box Bounding Box + + + + + Shape Fill Toggle + + + + + Stroke Toggle + + + + + Shadow Toggle + + + + + Arrowhead Display Toggle + + + + + Gradient Shape Toggle + + + + + Text Path Toggle + + + + + Inset Stroke From Path Flag + + + + + Connection Point Type + + + + + Connection Points + + + + + Connection Point Connect Angles + + + + + Extrusion Toggle + + + + + + + + Shadow Toggle + + + + + Shadow Type + + + + + Shadow Transparency + + + + + Shadow Primary Color + + + + + Shadow Opacity + + + + + Shadow Primary Offset + + + + + Shadow Secondary Color + + + + + Shadow Secondary Offset + + + + + Shadow Origin + + + + + Shadow Perspective Matrix + + + + + + + + + + + + + + + + + + + + + + + + Text Box Inset + + + + + Text Box Single-Click Selection Toggle + + + + + Text Inset Mode + + + + + + + + + Text Path Toggle + + + + + Shape Fit Toggle + + + + + Path Fit Toggle + + + + + Text Path Trim Toggle + + + + + Text X-Scaling + + + + + Text Path Text + + + + + + Arc Segment + + + + + Bezier Curve + + + + + Image File + + + + + Line + + + + + Oval + + + + + Multiple Path Line + + + + + Rectangle + + + + + Rounded Rectangle + + + + + + + + + + + Starting Angle + + + + + Ending Angle + + + + + + + + + + + + Curve Starting Point + + + + + First Curve Control Point + + + + + Second Curve Control Point + + + + + Curve Ending Point + + + + + + + + + + + + + + + + + + + + Line Start + + + + + Line End Point + + + + + + + + + + + + + + + + + + + + Points for Compound Line + + + + + + + + + + + + + + + + + + + Rounded Corner Arc Size + + + + + + VML Extension Handling Behaviors + + + + + Not renderable + + + + + Editable + + + + + Renderable + + + + + + + Boolean Value + + + + + True + + + + + False + + + + + True + + + + + False + + + + + + + Color Type + + + + + + Shape Fill Type + + + + + Solid Fill + + + + + Linear Gradient + + + + + Radial Gradient + + + + + Tiled Image + + + + + Image Pattern + + + + + Stretch Image to Fit + + + + + + + Gradient Fill Computation Type + + + + + No Gradient Fill + + + + + Linear Fill + + + + + Sigma Fill + + + + + Application Default Fill + + + + + Linear Sigma Fill + + + + + + + Shadow Type + + + + + Single Shadow + + + + + Double Shadow + + + + + Embossed Shadow + + + + + Perspective Shadow + + + + + + + Stroke Line Style + + + + + Single Line + + + + + Two Thin Lines + + + + + Thin Line Outside Thick Line + + + + + Thick Line Outside Thin Line + + + + + Thck Line Between Thin Lines + + + + + + + Line Join Type + + + + + Round Joint + + + + + Bevel Joint + + + + + Miter Joint + + + + + + + Stroke End Cap Type + + + + + Flat End + + + + + Square End + + + + + Round End + + + + + + + Stroke Arrowhead Length + + + + + Short Arrowhead + + + + + Medium Arrowhead + + + + + Long Arrowhead + + + + + + + Stroke Arrowhead Width + + + + + Narrow Arrowhead + + + + + Medium Arrowhead + + + + + Wide Arrowhead + + + + + + + Stroke Arrowhead Type + + + + + No Arrowhead + + + + + Block Arrowhead + + + + + Classic Arrowhead + + + + + Oval Arrowhead + + + + + Diamond Arrowhead + + + + + Open Arrowhead + + + + + + + Image Scaling Behavior + + + + + Ignore Aspect Ratio + + + + + At Most + + + + + At Least + + + + + + + Boolean Value with Blank [False] State + + + + + Logical True + + + + + Logical False + + + + + Logical True + + + + + Logical False + + + + + Blank – Logical False + + + + + + + Shape Grouping Types + + + + + Shape Canvas + + + + + Organization Chart Diagram + + + + + Radial Diagram + + + + + Cycle Diagram + + + + + Pyramid Diagram + + + + + Venn Diagram + + + + + Bullseye Diagram + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/vml-officeDrawing.xsd b/tests/resources/schema/ecma-376/vml-officeDrawing.xsd new file mode 100644 index 0000000000..fd2f2ce389 --- /dev/null +++ b/tests/resources/schema/ecma-376/vml-officeDrawing.xsd @@ -0,0 +1,1642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + New Shape Defaults + + + + + Shape Layout Properties + + + + + Digital Signature Line + + + + + Ink + + + + + VML Diagram + + + + + + + + + + + + + Callout + + + + + Shape Protections + + + + + Most Recently Used Colors + + + + + UI Default Colors + + + + + + + Shape ID Optional Storage + + + + + Shape Styling Properties + + + + + Shape Fill Toggle + + + + + Default Fill Color + + + + + Shape Stroke Toggle + + + + + Shape Stroke Color + + + + + Allow in Table Cell + + + + + + + + Ink Data + + + + + Annotation Flag + + + + + + + + Signature Line Flag + + + + + Unique ID + + + + + Signature Provider ID + + + + + Use Signing Instructions Flag + + + + + User-specified Comments Flag + + + + + Show Signed Date Flag + + + + + Suggested Signer Line 1 + + + + + Suggested Signer Line 2 + + + + + Suggested Signer E-mail Address + + + + + Instructions for Signing + + + + + Additional Signature Information + + + + + Signature Provider Download URL + + + + + + + + Shape ID Map + + + + + Shape Grouping History + + + + + Rule Set + + + + + + + + + + Shape IDs + + + + + + + + Regroup Entry + + + + + + + + + New Group ID + + + + + Old Group ID + + + + + + + + Rule + + + + + + + + + + Shape Reference + + + + + + Rule ID + + + + + Rule Type + + + + + Alignment Rule Type + + + + + Rule Shape Reference + + + + + + + Start Point Connection Flag + + + + + End Point Connection Flag + + + + + Proxy Shape Reference + + + + + Connection Location + + + + + + + + Diagram Relationship Table + + + + + + + Diagram Style Options + + + + + Diagram Automatic Format + + + + + Diagram Reverse Direction + + + + + Diagram Automatic Layout + + + + + Diagram Layout X Scale + + + + + Diagram Layout Y Scale + + + + + Diagram Font Size + + + + + Diagram Layout Extents + + + + + Diagram Base Font Size + + + + + + + + Diagram Relationship + + + + + + + + + + Diagram Relationship Source Shape + + + + + Diagram Relationship Destination Shape + + + + + Diagram Relationship Center Shape + + + + + + + + Recent colors + + + + + + + + Default stroke color + + + + + Default fill color + + + + + Default shadow color + + + + + Default extrusion color + + + + + + Skew Transform + + + + + 3D Extrusion + + + + + + + Embedded OLE Object + + + + + Complex + + + + + Text Box Left Stroke + + + + + Text Box Top Stroke + + + + + Text Box Right Stroke + + + + + Text Box Bottom Stroke + + + + + Text Box Interior Stroke + + + + + Shape Clipping Path + + + + + Shape Fill Extended Properties + + + + + + + Skew ID + + + + + Skew Toggle + + + + + Skew Offset + + + + + Skew Origin + + + + + Skew Perspective Matrix + + + + + + + + Extrusion Toggle + + + + + Extrusion Type + + + + + Extrusion Render Mode + + + + + Extrusion Viewpoint Origin + + + + + Extrusion Viewpoint + + + + + Extrusion Direction + + + + + Extrusion Skew Angle + + + + + Extrusion Skew + + + + + Forward Extrusion + + + + + Backward Extrusion Depth + + + + + Rotation Axis + + + + + Rotation Around Axis + + + + + Rotation Toggle + + + + + Center of Rotation Toggle + + + + + Rotation Center + + + + + X-Y Rotation Angle + + + + + Extrusion Color Mode + + + + + Extrusion Color + + + + + Shininess + + + + + Specularity + + + + + Diffuse Reflection + + + + + Metallic Surface Toggle + + + + + Simulated Bevel + + + + + Faceting Quality + + + + + Shape Face Lighting Toggle + + + + + Brightness + + + + + Primary Light Position + + + + + Primary Light Intensity + + + + + Primary Light Harshness Toggle + + + + + Secondary Light Position + + + + + Secondary Light Intensity + + + + + Secondary Light Harshness Toggle + + + + + + + + Callout toggle + + + + + Callout type + + + + + Callout gap + + + + + Callout angle + + + + + Callout automatic drop toggle + + + + + Callout drop position + + + + + Callout drop distance + + + + + Callout length toggle + + + + + Callout length + + + + + Callout accent bar toggle + + + + + Callout text border toggle + + + + + Callout flip x + + + + + Callout flip y + + + + + + + + Position Lock + + + + + Selection Lock + + + + + Grouping Lock + + + + + Ungrouping Lock + + + + + Rotation Lock + + + + + Cropping Lock + + + + + Vertices Lock + + + + + Handles Lock + + + + + Text Lock + + + + + Aspect Ratio Lock + + + + + AutoShape Type Lock + + + + + + + + Embedded Object Alternate Image Request + + + + + Embedded Object Cannot Be Refreshed + + + + + WordprocessingML Field Switches + + + + + + OLE Object Type + + + + + OLE Object Application + + + + + OLE Object Shape + + + + + OLE Object Representation + + + + + OLE Object Unique ID + + + + + Relationship + + + + + OLE Update Mode + + + + + + + + + + + Stroke Toggle + + + + + Stroke Weight + + + + + Stroke Color + + + + + Stroke Alternate Pattern Color + + + + + Stroke Opacity + + + + + Stroke Line Style + + + + + Miter Joint Limit + + + + + Line End Join Style) + + + + + Line End Cap + + + + + Stroke Dash Pattern + + + + + Inset Border From Path + + + + + Stroke Image Style + + + + + Stroke Image Location + + + + + Stroke Image Aspect Ratio + + + + + Stroke Image Size + + + + + Stoke Image Alignment + + + + + Line Start Arrowhead + + + + + Line Start Arrowhead Width + + + + + Line Start Arrowhead Length + + + + + Line End Arrowhead + + + + + Line End Arrowhead Width + + + + + Line End Arrowhead Length + + + + + Original Image Reference + + + + + Alternate Image Reference + + + + + Stroke Title + + + + + Force Dashed Outline + + + + + + + Path Definition + + + + + + + + Fill Type + + + + + + Rule Type + + + + + Arc Rule + + + + + Callout Rule + + + + + Connector Rule + + + + + Alignment Rule + + + + + + + Alignment Type + + + + + Top Alignment + + + + + Middle Alignment + + + + + Bottom Alignment + + + + + Left Alignment + + + + + Center Alignment + + + + + Right Alignment + + + + + + + Black And White Modes + + + + + Color + + + + + Automatic + + + + + Grayscale + + + + + Light grayscale + + + + + Inverse Grayscale + + + + + Gray Outlines + + + + + Black And White + + + + + Black + + + + + White + + + + + Hide Object When Displayed in Black and White + + + + + Do Not Show + + + + + Black Text And Lines + + + + + + + Screen Sizes Type + + + + + 544x376 pixels + + + + + 640x480 pixels + + + + + 720x512 pixels + + + + + 800x600 pixels + + + + + 1024x768 pixels + + + + + 1152x862 pixels + + + + + + + Inset Margin Type + + + + + Automatic Margins + + + + + Custom Margins + + + + + + + Extrusion Color Types + + + + + Use Shape Fill Color + + + + + Use Custom Color + + + + + + + Color Type + + + + + + Extrusion Type + + + + + Perspective Projection + + + + + Parallel Projection + + + + + + + Extrusion Rendering Types + + + + + Solid + + + + + Wireframe + + + + + Bounding Cube + + + + + + + Extrusion Planes + + + + + XY Plane + + + + + ZX Plane + + + + + YZ Plane + + + + + + + Callout Angles + + + + + Any Angle + + + + + 30 degrees + + + + + 45 degrees + + + + + 60 degrees + + + + + 90 degrees + + + + + Automatic Angle + + + + + + + Callout Drop Location + + + + + + Callout Placement + + + + + Top placement + + + + + Center placement + + + + + Bottom placement + + + + + User-defined placement + + + + + + + Connector Type + + + + + No Connector + + + + + Straight Connector + + + + + Elbow Connector + + + + + Curved Connector + + + + + + + Alignment Type + + + + + Left Alignment + + + + + Right Alignment + + + + + Center Alignment + + + + + + + Connection Locations Type + + + + + No + + + + + Four Connections + + + + + Edit Point Connections + + + + + Custom Connections + + + + + + + Embedded Object Alternate Image Request Types + + + + + Other Image + + + + + Bitmap Image + + + + + Enhanced Metafile Image + + + + + + + OLE Connection Type + + + + + Embedded Object + + + + + Linked Object + + + + + + + OLE Object Representations + + + + + Snapshot + + + + + Icon + + + + + + + OLE Update Method Type + + + + + Server Application Update + + + + + User Update + + + + + + + 128-Bit GUID + + + + + + + + Explicit Relationship ID + + + + + + Boolean Value + + + + + True + + + + + False + + + + + True + + + + + False + + + + + + + Boolean Value with Blank [False] State + + + + + Blank – Logical False + + + + + Logical True + + + + + Logical False + + + + + Logical True + + + + + Logical False + + + + + + + Shape Fill Type + + + + + Centered Radial Gradient + + + + + Solid Fill + + + + + Image Pattern + + + + + Tiled Image + + + + + Stretch Image to Fit + + + + + Unscaled Gradient + + + + + Radial Gradient + + + + + Linear Gradient + + + + + Use Background Fill + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/vml-presentationDrawing.xsd b/tests/resources/schema/ecma-376/vml-presentationDrawing.xsd new file mode 100644 index 0000000000..e431af9d47 --- /dev/null +++ b/tests/resources/schema/ecma-376/vml-presentationDrawing.xsd @@ -0,0 +1,21 @@ + + + + + Ink Annotation Flag + + + + + VML Diagram Text + + + + + + + Text Reference + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/vml-spreadsheetDrawing.xsd b/tests/resources/schema/ecma-376/vml-spreadsheetDrawing.xsd new file mode 100644 index 0000000000..3f04438b52 --- /dev/null +++ b/tests/resources/schema/ecma-376/vml-spreadsheetDrawing.xsd @@ -0,0 +1,518 @@ + + + + + Attached Object Data + + + + + + + Move with Cells + + + + + Resize with Cells + + + + + Anchor + + + + + Lock Toggle + + + + + Default Size Toggle + + + + + Print Toggle + + + + + Macro Disable Toggle + + + + + AutoFill + + + + + AutoLine + + + + + Automatically Size + + + + + Reference to Custom Function + + + + + Horizontal Text Alignment + + + + + Vertical Text Alignment + + + + + Text Lock + + + + + Far East Alignment Toggle + + + + + Password Edit + + + + + Default Button + + + + + Help Button + + + + + Cancel Button + + + + + Dismiss Button + + + + + Primary Keyboard Accelerator + + + + + Secondary Keyboard Accelerator + + + + + Comment Row Target + + + + + Comment Column Target + + + + + Comment Visibility Toggle + + + + + Comment's Row is Hidden + + + + + Comment's Column is Hidden + + + + + Validation Type + + + + + Multi-line + + + + + Vertical Scroll + + + + + Valid ID + + + + + List Items Source Range + + + + + Minimum Width + + + + + Selected Entry + + + + + Disable 3D + + + + + Selection Type + + + + + Multiple Selections + + + + + Callback Type + + + + + Non-linked List Item + + + + + Dropdown Style + + + + + Dropdown Color Toggle + + + + + Dropdown Maximum Lines + + + + + Checked + + + + + Linked Formula + + + + + Camera Source Range + + + + + Disable 3D + + + + + First Radio Button + + + + + Linked Formula - Group Box + + + + + Scroll bar position + + + + + Scroll Bar Minimum + + + + + Scroll Bar Maximum + + + + + Scroll Bar Increment + + + + + Scroll Bar Page Increment + + + + + Scroll Bar Orientation + + + + + Scroll Bar Width + + + + + ActiveX Control + + + + + Clipboard Format + + + + + Camera Tool + + + + + Recalculation Toggle + + + + + Font AutoScale + + + + + Dynamic Data Exchange + + + + + UI Object Toggle + + + + + HTML Script Text + + + + + HTML Script Attributes + + + + + HTML Script Language + + + + + HTML Script Location + + + + + Text Formula + + + + + + Object type + + + + + + Clipboard Format Type + + + + + WMF + + + + + EMF + + + + + Bitmap + + + + + Printer Picture + + + + + Screen Picture EMF + + + + + + + Object Type + + + + + Pushbutton + + + + + Checkbox + + + + + Dialog + + + + + Dropdown Box + + + + + Editable Text Field + + + + + Group Box + + + + + Label + + + + + Auditing Line + + + + + List Box + + + + + Movie + + + + + Comment + + + + + Image + + + + + Radio Button + + + + + Auditing Rectangle + + + + + Scroll Bar + + + + + Spin Button + + + + + Plain Shape + + + + + Group + + + + + Plain Rectangle + + + + + + + Boolean Value with Blank State + + + + + Logical True + + + + + Logical True + + + + + Logical False + + + + + Logical False + + + + + Blank - Default Value + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/vml-wordprocessingDrawing.xsd b/tests/resources/schema/ecma-376/vml-wordprocessingDrawing.xsd new file mode 100644 index 0000000000..8b2d266abb --- /dev/null +++ b/tests/resources/schema/ecma-376/vml-wordprocessingDrawing.xsd @@ -0,0 +1,355 @@ + + + + + Top Border + + + + + Left Border + + + + + Right Border + + + + + Bottom Border + + + + + + Border Style + + + + + Border Width + + + + + Border shadow + + + + + + Text Wrapping + + + + + + Wrapping type + + + + + Wrapping side + + + + + Horizontal Positioning Base + + + + + Vertical Positioning Base + + + + + + Anchor Location Is Locked + + + + + + Border Type + + + + + No Border + + + + + Single Line Border + + + + + Thick Line Border + + + + + Double Line Border + + + + + Hairline Border + + + + + Dotted Border + + + + + pecifies a line border consisting of a dashed line around the parent object. + + + + + Dot Dash Border + + + + + Dash Dot Dot Border + + + + + Triple Line Border + + + + + Thin Thick Small Gap Border + + + + + Small thick-thin lines border + + + + + Small thin-thick-thin Lines Border + + + + + Thin Thick Line Border + + + + + Thick Thin Line Border + + + + + Thin-thick-thin Border + + + + + Thin Thick Large Gap Border + + + + + Thick Thin Large Gap Border + + + + + Large thin-thick-thin Border + + + + + Wavy Border + + + + + Double Wavy Lines Border + + + + + Small Dash Border + + + + + Stroked Dash Dot Border + + + + + 3D Embossed Border + + + + + 3D Engraved Border + + + + + Outset Border + + + + + Inset Border + + + + + + + Border Shadow Type + + + + + True + + + + + True + + + + + False + + + + + False + + + + + + + Text Wrapping Type + + + + + Top and bottom wrapping + + + + + Square wrapping + + + + + No wrapping + + + + + Tight wrapping + + + + + Through wrapping + + + + + + + Text Wrapping Side + + + + + Both sides + + + + + Left side + + + + + Right side + + + + + Largest side + + + + + + + Horizontal Anchor Type + + + + + Margin + + + + + Page + + + + + Text + + + + + Character + + + + + + + Vertical Anchor Type + + + + + Margin + + + + + Page + + + + + Text + + + + + Line + + + + + \ No newline at end of file diff --git a/tests/resources/schema/ecma-376/wml.xsd b/tests/resources/schema/ecma-376/wml.xsd new file mode 100644 index 0000000000..737611f732 --- /dev/null +++ b/tests/resources/schema/ecma-376/wml.xsd @@ -0,0 +1,11334 @@ + + + + + + + + + + + On/Off Value + + + + + True + + + + + False + + + + + True + + + + + False + + + + + False + + + + + True + + + + + + + + On/Off Value + + + + + + Four Digit Hexadecimal Number Value + + + + + + + + + Long Hexadecimal Number Value + + + + + + Two Digit Hexadecimal Number Value + + + + + + + + + Two Digit Hexadecimal Value + + + + + + Two Digit Hexadecimal Number Value + + + + + + + + + Value + + + + + + Decimal Number Value + + + + + + + Decimal Number Value + + + + + + Unsigned Decimal Number Value + + + + + + Measurement in Twentieths of a Point + + + + + + + Measurement in Twentieths of a Point + + + + + + Signed Measurement in Twentieths of a Point + + + + + + + Positive or Negative Value in Twentieths of a Point + + + + + + Measurement in Pixels + + + + + + + Measurement in Pixels + + + + + + Measurement in Half-Points + + + + + + + Half Point Measurement + + + + + + Signed Measurement in Half-Points + + + + + + + Signed Half-Point Measurement + + + + + + Standard Date and Time Storage Format + + + + + + Script Subroutine Name Value + + + + + + + + + Name of Script Function + + + + + + Measurement in Eighths of a Point + + + + + + Measurement in Points + + + + + + String + + + + + + + String Value + + + + + + Text Expansion/Compression Percentage + + + + + + + + + + Text Expansion/Compression Value + + + + + + Text Highlight Colors + + + + + Black Highlighting Color + + + + + Blue Highlighting Color + + + + + Cyan Highlighting Color + + + + + Green Highlighting Color + + + + + Magenta Highlighting Color + + + + + Red Highlighting Color + + + + + Yellow Highlighting Color + + + + + White Highlighting Color + + + + + Dark Blue Highlighting Color + + + + + Dark Cyan Highlighting Color + + + + + Dark Green Highlighting Color + + + + + Dark Magenta Highlighting Color + + + + + Dark Red Highlighting Color + + + + + Dark Yellow Highlighting Color + + + + + Dark Gray Highlighting Color + + + + + Light Gray Highlighting Color + + + + + No Text Highlighting + + + + + + + + Highlighting Color + + + + + + ‘Automatic’ Color Value + + + + + Automatically Determined Color + + + + + + + Hexadecimal Color Value + + + + + + + + Color Value + + + + + + + Run Content Color + + + + + Run Content Theme Color + + + + + Run Content Theme Color Tint + + + + + Run Content Theme Color Shade + + + + + + Two Digit Hexadecimal Language Code + + + + + + + + Language Reference + + + + + + + Language Code + + + + + + 128-Bit GUID + + + + + + + + + GUID Value + + + + + + Underline Patterns + + + + + Single Underline + + + + + Underline Non-Space Characters Only + + + + + Double Underline + + + + + Thick Underline + + + + + Dotted Underline + + + + + Thick Dotted Underline + + + + + Dashed Underline + + + + + Thick Dashed Underline + + + + + Long Dashed Underline + + + + + Thick Long Dashed Underline + + + + + Dash-Dot Underline + + + + + Thick Dash-Dot Underline + + + + + Dash-Dot-Dot Underline + + + + + Thick Dash-Dot-Dot Underline + + + + + Wave Underline + + + + + Heavy Wave Underline + + + + + Double Wave Underline + + + + + No Underline + + + + + + + + Underline Style + + + + + Underline Color + + + + + Underline Theme Color + + + + + Underline Theme Color Tint + + + + + Underline Theme Color Shade + + + + + + Animated Text Effects + + + + + Blinking Background Animation + + + + + Colored Lights Animation + + + + + Black Dashed Line Animation + + + + + Marching Red Ants + + + + + Shimmer Animation + + + + + Sparkling Lights Animation + + + + + No Animation + + + + + + + + Animated Text Effect Type + + + + + + Border Styles + + + + + No Border + + + + + No Border + + + + + Single Line Border + + + + + Single Line Border + + + + + Double Line Border + + + + + Dotted Line Border + + + + + Dashed Line Border + + + + + Dot Dash Line Border + + + + + Dot Dot Dash Line Border + + + + + Triple Line Border + + + + + Thin, Thick Line Border + + + + + Thick, Thin Line Border + + + + + Thin, Thick, Thin Line Border + + + + + Thin, Thick Line Border + + + + + Thick, Thin Line Border + + + + + Thin, Thick, Thin Line Border + + + + + Thin, Thick Line Border + + + + + Thick, Thin Line Border + + + + + Thin, Thick, Thin Line Border + + + + + Wavy Line Border + + + + + Double Wave Line Border + + + + + Dashed Line Border + + + + + Dash Dot Strokes Line Border + + + + + 3D Embossed Line Border + + + + + 3D Engraved Line Border + + + + + Outset Line Border + + + + + Inset Line Border + + + + + Apples Art Border + + + + + Arched Scallops Art Border + + + + + Baby Pacifier Art Border + + + + + Baby Rattle Art Border + + + + + Three Color Balloons Art Border + + + + + Hot Air Balloons Art Border + + + + + Black Dash Art Border + + + + + Black Dot Art Border + + + + + Black Square Art Border + + + + + Thin Line Art Border + + + + + White Dash Art Border + + + + + White Dot Art Border + + + + + White Square Art Border + + + + + Wide Inline Art Border + + + + + Wide Midline Art Border + + + + + Wide Outline Art Border + + + + + Bats Art Border + + + + + Birds Art Border + + + + + Birds Flying Art Border + + + + + Cabin Art Border + + + + + Cake Art Border + + + + + Candy Corn Art Border + + + + + Knot Work Art Border + + + + + Certificate Banner Art Border + + + + + Chain Link Art Border + + + + + Champagne Bottle Art Border + + + + + Black and White Bar Art Border + + + + + Color Checked Bar Art Border + + + + + Checkerboard Art Border + + + + + Christmas Tree Art Border + + + + + Circles And Lines Art Border + + + + + Circles and Rectangles Art Border + + + + + Wave Art Border + + + + + Clocks Art Border + + + + + Compass Art Border + + + + + Confetti Art Border + + + + + Confetti Art Border + + + + + Confetti Art Border + + + + + Confetti Streamers Art Border + + + + + Confetti Art Border + + + + + Corner Triangle Art Border + + + + + Dashed Line Art Border + + + + + Dotted Line Art Border + + + + + Maze Art Border + + + + + Butterfly Art Border + + + + + Fish Art Border + + + + + Insects Art Border + + + + + Ladybug Art Border + + + + + Cross-stitch Art Border + + + + + Cupid Art Border + + + + + Archway Art Border + + + + + Color Archway Art Border + + + + + Blocks Art Border + + + + + Gray Diamond Art Border + + + + + Double D Art Border + + + + + Diamond Art Border + + + + + Earth Art Border + + + + + Earth Art Border + + + + + Shadowed Square Art Border + + + + + Shadowed Square Art Border + + + + + Painted Egg Art Border + + + + + Fans Art Border + + + + + Film Reel Art Border + + + + + Firecracker Art Border + + + + + Flowers Art Border + + + + + Daisy Art Border + + + + + Flowers Art Border + + + + + Flowers Art Border + + + + + Pansy Art Border + + + + + Red Rose Art Border + + + + + Roses Art Border + + + + + Flowers in a Teacup Art Border + + + + + Small Flower Art Border + + + + + Gems Art Border + + + + + Gingerbread Man Art Border + + + + + Triangle Gradient Art Border + + + + + Handmade Art Border + + + + + Handmade Art Border + + + + + Heart-Shaped Balloon Art Border + + + + + Gray Heart Art Border + + + + + Hearts Art Border + + + + + Pattern Art Border + + + + + Holly Art Border + + + + + House Art Border + + + + + Circular Art Border + + + + + Ice Cream Cone Art Border + + + + + Light Bulb Art Border + + + + + Lightning Art Border + + + + + Lightning Art Border + + + + + Map Pins Art Border + + + + + Maple Leaf Art Border + + + + + Muffin Art Border + + + + + Marquee Art Border + + + + + Marquee Art Border + + + + + Moon Art Border + + + + + Mosaic Art Border + + + + + Musical Note Art Border + + + + + Patterned Art Border + + + + + Oval Art Border + + + + + Package Art Border + + + + + Black Palm Tree Art Border + + + + + Color Palm Tree Art Border + + + + + Paper Clip Art Border + + + + + Papyrus Art Border + + + + + Party Favor Art Border + + + + + Party Glass Art Border + + + + + Pencils Art Border + + + + + Character Art Border + + + + + Waving Character Border + + + + + Character With Hat Art Border + + + + + Poinsettia Art Border + + + + + Postage Stamp Art Border + + + + + Pumpkin Art Border + + + + + Push Pin Art Border + + + + + Push Pin Art Border + + + + + Pyramid Art Border + + + + + Pyramid Art Border + + + + + Quadrants Art Border + + + + + Rings Art Border + + + + + Safari Art Border + + + + + Saw tooth Art Border + + + + + Gray Saw tooth Art Border + + + + + Scared Cat Art Border + + + + + Umbrella Art Border + + + + + Shadowed Squares Art Border + + + + + Shark Tooth Art Border + + + + + Bird Tracks Art Border + + + + + Rocket Art Border + + + + + Snowflake Art Border + + + + + Snowflake Art Border + + + + + Sombrero Art Border + + + + + Southwest-themed Art Border + + + + + Stars Art Border + + + + + Stars On Top Art Border + + + + + 3-D Stars Art Border + + + + + Stars Art Border + + + + + Stars With Shadows Art Border + + + + + Sun Art Border + + + + + Whirligig Art Border + + + + + Torn Paper Art Border + + + + + Black Torn Paper Art Border + + + + + Tree Art Border + + + + + Triangle Art Border + + + + + Triangles Art Border + + + + + Tribal Art Border One + + + + + Tribal Art Border Two + + + + + Tribal Art Border Three + + + + + Tribal Art Border Four + + + + + Tribal Art Border Five + + + + + Tribal Art Border Six + + + + + Twisted Lines Art Border + + + + + Twisted Lines Art Border + + + + + Vine Art Border + + + + + Wavy Line Art Border + + + + + Weaving Angles Art Border + + + + + Weaving Braid Art Border + + + + + Weaving Ribbon Art Border + + + + + Weaving Strips Art Border + + + + + White Flowers Art Border + + + + + Woodwork Art Border + + + + + Crisscross Art Border + + + + + Triangle Art Border + + + + + Zigzag Art Border + + + + + Zigzag stitch + + + + + + + + Border Style + + + + + Border Color + + + + + Border Theme Color + + + + + Border Theme Color Tint + + + + + Border Theme Color Shade + + + + + Border Width + + + + + Border Spacing Measurement + + + + + Border Shadow + + + + + Create Frame Effect + + + + + + Shading Patterns + + + + + No Pattern + + + + + No Pattern + + + + + 100% Fill Pattern + + + + + Horizontal Stripe Pattern + + + + + Vertical Stripe Pattern + + + + + Reverse Diagonal Stripe Pattern + + + + + Diagonal Stripe Pattern + + + + + Horizontal Cross Pattern + + + + + Diagonal Cross Pattern + + + + + Thin Horizontal Stripe Pattern + + + + + Thin Vertical Stripe Pattern + + + + + Thin Reverse Diagonal Stripe Pattern + + + + + Thin Diagonal Stripe Pattern + + + + + Thin Horizontal Cross Pattern + + + + + Thin Diagonal Cross Pattern + + + + + 5% Fill Pattern + + + + + 10% Fill Pattern + + + + + 12.5% Fill Pattern + + + + + 15% Fill Pattern + + + + + 20% Fill Pattern + + + + + 25% Fill Pattern + + + + + 30% Fill Pattern + + + + + 35% Fill Pattern + + + + + 37.5% Fill Pattern + + + + + 40% Fill Pattern + + + + + 45% Fill Pattern + + + + + 50% Fill Pattern + + + + + 55% Fill Pattern + + + + + 60% Fill Pattern + + + + + 62.5% Fill Pattern + + + + + 65% Fill Pattern + + + + + 70% Fill Pattern + + + + + 75% Fill Pattern + + + + + 80% Fill Pattern + + + + + 85% Fill Pattern + + + + + 87.5% Fill Pattern + + + + + 90% Fill Pattern + + + + + 95% Fill Pattern + + + + + + + + Shading Pattern + + + + + Shading Pattern Color + + + + + Shading Pattern Theme Color + + + + + Shading Pattern Theme Color Tint + + + + + Shading Pattern Theme Color Shade + + + + + Shading Background Color + + + + + Shading Background Theme Color + + + + + Shading Background Theme Color Tint + + + + + Shading Background Theme Color Shade + + + + + + Vertical Positioning Location + + + + + Regular Vertical Positioning + + + + + Superscript + + + + + Subscript + + + + + + + + Subscript/Superscript Value + + + + + + + Value + + + + + Fit Text Run ID + + + + + + Emphasis Mark Type + + + + + No Emphasis Mark + + + + + Dot Emphasis Mark Above Characters + + + + + Comma Emphasis Mark Above Characters + + + + + Circle Emphasis Mark Above Characters + + + + + Dot Emphasis Mark Below Characters + + + + + + + + Emphasis Mark Type + + + + + + + Latin Language + + + + + East Asian Language + + + + + Complex Script Language + + + + + + Two Lines in One Enclosing Character Type + + + + + No Enclosing Brackets + + + + + Round Brackets + + + + + Square Brackets + + + + + Angle Brackets + + + + + Curly Brackets + + + + + + + + East Asian Typography Run ID + + + + + Two Lines in One + + + + + Display Brackets Around Two Lines in One + + + + + Horizontal in Vertical (Rotate Text) + + + + + Compress Rotated Text to Line Height + + + + + + Horizontal Alignment Location + + + + + Left Aligned Horizontally + + + + + Centered Horizontally + + + + + Right Aligned Horizontally + + + + + Inside + + + + + Outside + + + + + + + Vertical Alignment Location + + + + + In line With Text + + + + + Top + + + + + Centered Vertically + + + + + Bottom + + + + + Inside Anchor Extents + + + + + Outside Anchor Extents + + + + + + + Height Rule + + + + + Determine Height Based On Contents + + + + + Exact Height + + + + + Minimum Height + + + + + + + Text Wrapping around Text Frame Type + + + + + Default Text Wrapping Around Frame + + + + + No Text Wrapping Beside Frame + + + + + Allow Text Wrapping Around Frame + + + + + Tight Text Wrapping Around Frame + + + + + Through Text Wrapping Around Frame + + + + + No Text Wrapping Around Frame + + + + + + + Vertical Anchor Location + + + + + Relative To Vertical Text Extents + + + + + Relative To Margin + + + + + Relative To Page + + + + + + + Horizontal Anchor Location + + + + + Relative to Text Extents + + + + + Relative To Margin + + + + + Relative to Page + + + + + + + Text Frame Drop Cap Location + + + + + Not Drop Cap + + + + + Drop Cap Inside Margin + + + + + Drop Cap Outside Margin + + + + + + + + Drop Cap Frame + + + + + Drop Cap Vertical Height in Lines + + + + + Frame Width + + + + + Frame Height + + + + + Vertical Frame Padding + + + + + Horizontal Frame Padding + + + + + Text Wrapping Around Frame + + + + + Frame Horizontal Positioning Base + + + + + Frame Vertical Positioning Base + + + + + Absolute Horizontal Position + + + + + Relative Horizontal Position + + + + + Absolute Vertical Position + + + + + Relative Vertical Position + + + + + Frame Height Type + + + + + Lock Frame Anchor to Paragraph + + + + + + Custom Tab Stop Type + + + + + No Tab Stop + + + + + Left Tab + + + + + Centered Tab + + + + + Right Tab + + + + + Decimal Tab + + + + + Bar Tab + + + + + List Tab + + + + + + + Custom Tab Stop Leader Character + + + + + No tab stop leader + + + + + Dotted leader line + + + + + Dashed tab stop leader line + + + + + Solid leader line + + + + + Heavy solid leader line + + + + + Middle dot leader line + + + + + + + + Tab Stop Type + + + + + Tab Leader Character + + + + + Tab Stop Position + + + + + + Line Spacing Rule + + + + + Automatically Determined Line Height + + + + + Exact Line Height + + + + + Minimum Line Height + + + + + + + + Spacing Above Paragraph + + + + + Spacing Above Paragraph IN Line Units + + + + + Automatically Determine Spacing Above Paragraph + + + + + Spacing Below Paragraph + + + + + Spacing Below Paragraph in Line Units + + + + + Automatically Determine Spacing Below Paragraph + + + + + Spacing Between Lines in Paragraph + + + + + Type of Spacing Between Lines + + + + + + + Left Indentation + + + + + Left Indentation in Character Units + + + + + Right Indentation + + + + + Right Indentation in Character Units + + + + + Indentation Removed from First Line + + + + + Indentation Removed From First Line in Character Units + + + + + Additional First Line Indentation + + + + + Additional First Line Indentation in Character Units + + + + + + Horizontal Alignment Type + + + + + Align Left + + + + + Align Center + + + + + Align Right + + + + + Justified + + + + + Medium Kashida Length + + + + + Distribute All Characters Equally + + + + + Align to List Tab + + + + + Widest Kashida Length + + + + + Low Kashida Length + + + + + Thai Language Justification + + + + + + + + Alignment Type + + + + + + Document View Values + + + + + Default View + + + + + Print Layout View + + + + + Outline View + + + + + Master Document View + + + + + Draft View + + + + + Web Page View + + + + + + + + Document View Setting Value + + + + + + Magnification Preset Values + + + + + No Preset Magnification + + + + + Display One Full Page + + + + + Display Page Width + + + + + Display Text Width + + + + + + + + Zoom Type + + + + + Zoom Percentage + + + + + + + Writing Style Language + + + + + Grammatical Engine ID + + + + + Grammatical Check Engine Version + + + + + Natural Language Grammar Check + + + + + Check Stylistic Rules With Grammar + + + + + Application Name + + + + + + Proofing State Values + + + + + Check Completed + + + + + Check Not Completed + + + + + + + + Spell Checking State + + + + + Grammatical Checking State + + + + + + Document Classification Values + + + + + Default Document + + + + + Letter + + + + + E-Mail Message + + + + + + + + Document Classification Value + + + + + + Document Protection Types + + + + + No Editing Restrictions + + + + + Allow No Editing + + + + + Allow Editing of Comments + + + + + Allow Editing With Revision Tracking + + + + + Allow Editing of Form Fields + + + + + + + Cryptographic Provider Types + + + + + AES Provider + + + + + Any Provider + + + + + + + Cryptographic Algorithm Classes + + + + + Hashing + + + + + + + Cryptographic Algorithm Types + + + + + Any Type + + + + + + + + Cryptographic Provider Type + + + + + Cryptographic Algorithm Class + + + + + Cryptographic Algorithm Type + + + + + Cryptographic Hashing Algorithm + + + + + Iterations to Run Hashing Algorithm + + + + + Cryptographic Provider + + + + + Cryptographic Algorithm Extensibility + + + + + Algorithm Extensibility Source + + + + + Cryptographic Provider Type Extensibility + + + + + Provider Type Extensibility Source + + + + + Password Hash + + + + + Salt for Password Verifier + + + + + + + Document Editing Restrictions + + + + + Only Allow Formatting With Unlocked Styles + + + + + Enforce Document Protection Settings + + + + + + + Source Document Types + + + + + Catalog Source Document + + + + + Envelope Source Document + + + + + Mailing Label Source Document + + + + + Form Letter Source Document + + + + + E-Mail Source Document + + + + + Fax Source Document + + + + + + + + Mail Merge Source Document Type + + + + + + Mail Merge Data Source Type Values + + + + + Text File Data Source + + + + + Database Data Source + + + + + Spreadsheet Data Source + + + + + Query Data Source + + + + + Open Database Connectivity Data Source + + + + + Office Data Source Object Data Source + + + + + + + + Value + + + + + + Merged Document Destination Types + + + + + Send Merged Documents to New Documents + + + + + Send Merged Documents to Printer + + + + + Send Merged Documents as E-mail Messages + + + + + Send Merged Documents as Faxes + + + + + + + + Mail Merge Merged Document Type + + + + + + Merge Field Mapping Types + + + + + Field Not Mapped + + + + + Field Mapping to Data Source Column + + + + + + + + Merge Field Mapping Type + + + + + + + Display Visual Indicator Of Markup Area + + + + + Display Comments + + + + + Display Content Revisions + + + + + Display Formatting Revisions + + + + + Display Ink Annotations + + + + + + + Language For Which Custom Line Breaking Rule Applies + + + + + Characters For Custom Line Breaking Rule + + + + + + Text Flow Direction + + + + + Left to Right, Top to Bottom + + + + + Top to Bottom, Right to Left + + + + + Bottom to Top, Left to Right + + + + + Left to Right, Top to Bottom Rotated + + + + + Top to Bottom, Right to Left Rotated + + + + + Top to Bottom, Left to Right Rotated + + + + + + + + Direction of Text Flow + + + + + + Vertical Text Alignment Types + + + + + Align Text at Top + + + + + Align Text at Center + + + + + Align Text at Baseline + + + + + Align Text at Bottom + + + + + Automatically Determine Alignment + + + + + + + + Vertical Character Alignment Position + + + + + + Location of Custom XML Markup Displacing an Annotation + + + + + Displaced by Next Custom XML Markup Tag + + + + + Displaced by Previous Custom XML Markup Tag + + + + + + + Table Cell Vertical Merge Revision Type + + + + + Vertically Merged Cell + + + + + Vertically Split Cell + + + + + + + + Annotation Identifier + + + + + + + + + Annotation Author + + + + + Annotation Date + + + + + + + + + + + Revised Vertical Merge Setting + + + + + Vertical Merge Setting Removed by Revision + + + + + + + + + + + Annotation Marker Displaced By Custom XML Markup + + + + + + + + + + + Annotation Marker Relocated For Custom XML Markup + + + + + + + + + + + First Table Column Covered By Bookmark + + + + + Last Table Column Covered By Bookmark + + + + + + + + + + + Bookmark Name + + + + + + + + + + + Annotation Author + + + + + Annotation Date + + + + + + + + + + + + + + Initials of Comment Author + + + + + + + + + + + Previous Numbering Value + + + + + + + + + + + + Previous Table-Level Property Exceptions + + + + + + + + + + + + + Previous Table Cell Properties + + + + + + + + + + + + + Previous Table Row Properties + + + + + + + + + + + + + Previous Table Grid + + + + + + + + + + + + + Previous Table Properties + + + + + + + + + + + + + Previous Section Properties + + + + + + + + + + + + + Previous Paragraph Properties + + + + + + + + + + + + + Previous Run Properties + + + + + + + + + + + + + Previous Run Properties for the Paragraph Mark + + + + + + + + + + + + + + + + + + + + + Table Cell Insertion + + + + + Table Cell Deletion + + + + + Vertically Merged/Split Table Cells + + + + + + + + + Bookmark Start + + + + + Bookmark End + + + + + Move Source Location Container - Start + + + + + Move Source Location Container - End + + + + + Move Destination Location Container - Start + + + + + Move Destination Location Container - End + + + + + Comment Anchor Range Start + + + + + Comment Anchor Range End + + + + + Custom XML Markup Insertion Start + + + + + Custom XML Markup Insertion End + + + + + Custom XML Markup Deletion Start + + + + + Custom XML Markup Deletion End + + + + + Custom XML Markup Move Source Start + + + + + Custom XML Markup Move Source End + + + + + Custom XML Markup Move Destination Location Start + + + + + Custom XML Markup Move Destination Location End + + + + + + + + + Numbering Level Reference + + + + + Numbering Definition Instance Reference + + + + + Previous Paragraph Numbering Properties + + + + + Inserted Numbering Properties + + + + + + + + + Paragraph Border Above Identical Paragraphs + + + + + Left Paragraph Border + + + + + Paragraph Border Between Identical Paragraphs + + + + + Right Paragraph Border + + + + + Paragraph Border Between Identical Paragraphs + + + + + Paragraph Border Between Facing Pages + + + + + + + + + Custom Tab Stop + + + + + + + Lines To Tight Wrap Within Text Box + + + + + Do Not Tight Wrap + + + + + Tight Wrap All Lines + + + + + Tight Wrap First and Last Lines + + + + + Tight Wrap First Line + + + + + Tight Wrap Last Line + + + + + + + + Lines to Tight Wrap to Paragraph Extents + + + + + + + + Referenced Paragraph Style + + + + + Keep Paragraph With Next Paragraph + + + + + Keep All Lines On One Page + + + + + Start Paragraph on Next Page + + + + + Text Frame Properties + + + + + Allow First/Last Line to Display on a Separate Page + + + + + Numbering Definition Instance Reference + + + + + Suppress Line Numbers for Paragraph + + + + + Paragraph Borders + + + + + Paragraph Shading + + + + + Set of Custom Tab Stops + + + + + Suppress Hyphenation for Paragraph + + + + + Use East Asian Typography Rules for First and Last Character per Line + + + + + Allow Line Breaking At Character Level + + + + + Allow Punctuation to Extent Past Text Extents + + + + + Compress Punctuation at Start of a Line + + + + + Automatically Adjust Spacing of Latin and East Asian Text + + + + + Automatically Adjust Spacing of East Asian Text and Numbers + + + + + Right to Left Paragraph Layout + + + + + Automatically Adjust Right Indent When Using Document Grid + + + + + Use Document Grid Settings for Inter-Line Paragraph Spacing + + + + + Spacing Between Lines and Above/Below Paragraph + + + + + Paragraph Indentation + + + + + Ignore Spacing Above and Below When Using Identical Styles + + + + + Use Left/Right Indents as Inside/Outside Indents + + + + + Prevent Text Frames From Overlapping + + + + + Paragraph Alignment + + + + + Paragraph Text Flow Direction + + + + + Vertical Character Alignment on Line + + + + + Allow Surrounding Paragraphs to Tight Wrap to Text Box Contents + + + + + Associated Outline Level + + + + + Associated HTML div ID + + + + + Paragraph Conditional Formatting + + + + + + + + + + + Run Properties for the Paragraph Mark + + + + + Section Properties + + + + + Revision Information for Paragraph Properties + + + + + + + + + + Unique Name for Embedded Control + + + + + Associated VML Data Reference + + + + + Embedded Control Properties Relationship Reference + + + + + + + + + Background Color + + + + + Background Theme Color + + + + + Border Theme Color Tint + + + + + Border Theme Color Shade + + + + + + + + + Relationship to Part + + + + + + + + + + + + + + + + Inline Embedded Control + + + + + + Original Image Width + + + + + Original Image Height + + + + + + + + + + + + Embedded Video + + + + + Floating Embedded Control + + + + + + + + + + + Drawing Element Anchor + + + + + Inline Drawing Object + + + + + + + + + Custom Field Data + + + + + + + Field Codes + + + + + Field Should Not Be Recalculated + + + + + Field Result Invalidated + + + + + + Complex Field Character Type + + + + + Start Character + + + + + Separator Character + + + + + End Character + + + + + + + Help or Status Text Type + + + + + Literal Text + + + + + Glossary Document Entry + + + + + + + Help Text Value + + + + + + + + Status Text Value + + + + + + + + Form Field Name Value + + + + + + + + Text Box Form Field Type Values + + + + + Text Box + + + + + Number + + + + + Date + + + + + Current Time Display + + + + + Current Date Display + + + + + Field Calculation + + + + + + + + Text Box Form Field Type Values + + + + + + + Form Field Name Value + + + + + + + + Custom Field Data + + + + + Form Field Properties + + + + + Previous Numbering Field Properties + + + + + + Field Character Type + + + + + Field Should Not Be Recalculated + + + + + Field Result Invalidated + + + + + + + + Hyperlink Target Frame + + + + + Associated String + + + + + Location in Target Document + + + + + Add To Viewed Hyperlinks + + + + + Hyperlink Anchor + + + + + Hyperlink Target + + + + + + + + Form Field Name + + + + + Form Field Enabled + + + + + Recalculate Fields When Current Field Is Modified + + + + + Script Function to Execute on Form Field Entry + + + + + Script Function to Execute on Form Field Exit + + + + + Associated Help Text + + + + + Associated Status Text + + + + + + Checkbox Form Field Properties + + + + + Drop-Down List Form Field Properties + + + + + Text Box Form Field Properties + + + + + + + + + Help Text Type + + + + + Help Text Value + + + + + + + Status Text Type + + + + + Status Text Value + + + + + + + + + Checkbox Form Field Size + + + + + Automatically Size Form Field + + + + + + Default Checkbox Form Field State + + + + + Checkbox Form Field State + + + + + + + + + Drop-Down List Selection + + + + + Default Drop-Down List Item Index + + + + + Drop-Down List Entry + + + + + + + + + Text Box Form Field Type + + + + + Default Text Box Form Field String + + + + + Text Box Form Field Maximum Length + + + + + Text Box Form Field Formatting + + + + + + + Section Type + + + + + Next Page Section Break + + + + + Column Section Break + + + + + Continuous Section Break + + + + + Even Page Section Break + + + + + Odd Page Section Break + + + + + + + + Section Type Setting + + + + + + + First Page Printer Tray Code + + + + + Non-First Page Printer Tray Code + + + + + + Numbering Format + + + + + Decimal Numbers + + + + + Uppercase Roman Numerals + + + + + Lowercase Roman Numerals + + + + + Uppercase Latin Alphabet + + + + + Lowercase Latin Alphabet + + + + + Ordinal + + + + + Cardinal Text + + + + + Ordinal Text + + + + + Hexadecimal Numbering + + + + + Chicago Manual of Style + + + + + Ideographs + + + + + Japanese Counting System + + + + + AIUEO Order Hiragana + + + + + Iroha Ordered Katakana + + + + + Double Byte Arabic Numerals + + + + + Single Byte Arabic Numerals + + + + + Japanese Legal Numbering + + + + + Japanese Digital Ten Thousand Counting System + + + + + Decimal Numbers Enclosed in a Circle + + + + + Double Byte Arabic Numerals Alternate + + + + + Full-Width AIUEO Order Hiragana + + + + + Full-Width Iroha Ordered Katakana + + + + + Initial Zero Arabic Numerals + + + + + Bullet + + + + + Korean Ganada Numbering + + + + + Korean Chosung Numbering + + + + + Decimal Numbers Followed by a Period + + + + + Decimal Numbers Enclosed in Parenthesis + + + + + Decimal Numbers Enclosed in a Circle + + + + + Ideographs Enclosed in a Circle + + + + + Traditional Ideograph Format + + + + + Zodiac Ideograph Format + + + + + Traditional Zodiac Ideograph Format + + + + + Taiwanese Counting System + + + + + Traditional Legal Ideograph Format + + + + + Taiwanese Counting Thousand System + + + + + Taiwanese Digital Counting System + + + + + Chinese Counting System + + + + + Chinese Legal Simplified Format + + + + + Chinese Counting Thousand System + + + + + Korean Digital Counting System + + + + + Korean Counting System + + + + + Korean Legal Numbering + + + + + Korean Digital Counting System Alternate + + + + + Vietnamese Numerals + + + + + Lowercase Russian Alphabet + + + + + Uppercase Russian Alphabet + + + + + No Numbering + + + + + Number With Dashes + + + + + Hebrew Numerals + + + + + Hebrew Alphabet + + + + + Arabic Alphabet + + + + + Arabic Abjad Numerals + + + + + Hindi Vowels + + + + + Hindi Consonants + + + + + Hindi Numbers + + + + + Hindi Counting System + + + + + Thai Letters + + + + + Thai Numerals + + + + + Thai Counting System + + + + + + + Page Orientation + + + + + Portrait Mode + + + + + Landscape Mode + + + + + + + + Page Width + + + + + Page Height + + + + + Page Orientation + + + + + Printer Paper Code + + + + + + + Top Margin Spacing + + + + + Right Margin Spacing + + + + + Page Bottom Spacing + + + + + Left Margin Spacing + + + + + Spacing to Top of Header + + + + + Spacing to Bottom of Footer + + + + + Page Gutter Spacing + + + + + + Page Border Z-Order + + + + + Page Border Ahead of Text + + + + + Page Border Behind Text + + + + + + + Page Border Display Options + + + + + Display Page Border on All Pages + + + + + Display Page Border on First Page + + + + + Display Page Border on All Pages Except First + + + + + + + Page Border Positioning Base + + + + + Page Border Is Positioned Relative to Page Edges + + + + + Page Border Is Positioned Relative to Text Extents + + + + + + + + + Top Border + + + + + Left Border + + + + + Bottom Border + + + + + Right Border + + + + + + Z-Ordering of Page Border + + + + + Pages to Display Page Borders + + + + + Page Border Positioning + + + + + + Chapter Separator Types + + + + + Hyphen Chapter Separator + + + + + Period Chapter Separator + + + + + Colon Chapter Separator + + + + + Em Dash Chapter Separator + + + + + En Dash Chapter Separator + + + + + + + Line Numbering Restart Position + + + + + Restart Line Numbering on Each Page + + + + + Restart Line Numbering for Each Section + + + + + Continue Line Numbering From Previous Section + + + + + + + + Line Number Increments to Display + + + + + Line Numbering Starting Value + + + + + Distance Between Text and Line Numbering + + + + + Line Numbering Restart Setting + + + + + + + Page Number Format + + + + + Starting Page Number + + + + + Chapter Heading Style + + + + + Chapter Separator Character + + + + + + + Column Width + + + + + Space Before Following Column + + + + + + + + Single Column Definition + + + + + + Equal Column Widths + + + + + Spacing Between Equal Width Columns + + + + + Number of Equal Width Columns + + + + + Draw Line Between Columns + + + + + + Vertical Alignment Type + + + + + Align Top + + + + + Align Center + + + + + Vertical Justification + + + + + Align Bottom + + + + + + + + Vertical Alignment Setting + + + + + + Document Grid Types + + + + + No Document Grid + + + + + Line Grid Only + + + + + Line and Character Grid + + + + + Character Grid Only + + + + + + + + Document Grid Type + + + + + Document Grid Line Pitch + + + + + Document Grid Character Pitch + + + + + + Header or Footer Type + + + + + Even Numbered Pages Only + + + + + Default Header or Footer + + + + + First Page Only + + + + + + + Footnote or Endnote Type + + + + + Normal Footnote/Endnote + + + + + Separator + + + + + Continuation Separator + + + + + Continuation Notice Separator + + + + + + + + + + Header or Footer Type + + + + + + + + + + Header Reference + + + + + Footer Reference + + + + + + + + + + + + Section-Wide Footnote Properties + + + + + Section-Wide Endnote Properties + + + + + Section Type + + + + + Page Size + + + + + Page Margins + + + + + Paper Source Information + + + + + Page Borders + + + + + Line Numbering Settings + + + + + Page Numbering Settings + + + + + Column Definitions + + + + + Only Allow Editing of Form Fields + + + + + Vertical Text Alignment on Page + + + + + Suppress Endnotes In Document + + + + + Different First Page Headers and Footers + + + + + Text Flow Direction + + + + + Right to Left Section Layout + + + + + Gutter on Right Side of Page + + + + + Document Grid + + + + + Reference to Printer Settings Data + + + + + + + + Physical Section Mark Character Revision ID + + + + + Section Deletion Revision ID + + + + + Section Addition Revision ID + + + + + Section Properties Revision ID + + + + + + + + + + + + + + + + Revision Information for Section Properties + + + + + + + + Break Types + + + + + Page Break + + + + + Column Break + + + + + Line Break + + + + + + + Line Break Text Wrapping Restart Location + + + + + Restart On Next Line + + + + + Restart In Next Text Region When In Leftmost Position + + + + + Restart In Next Text Region When In Rightmost Position + + + + + Restart On Next Full Line + + + + + + + + Break Type + + + + + Restart Location For Text Wrapping Break + + + + + + Absolute Position Tab Alignment + + + + + Left + + + + + Center + + + + + Right + + + + + + + Absolute Position Tab Positioning Base + + + + + Relative To Text Margins + + + + + Relative To Indents + + + + + + + Absolute Position Tab Leader Character + + + + + No Leader Character + + + + + Dot Leader Character + + + + + Hyphen Leader Character + + + + + Underscore Leader Character + + + + + Centered Dot Leader Character + + + + + + + + Positional Tab Stop Alignment + + + + + Positional Tab Base + + + + + Tab Leader Character + + + + + + + Symbol Character Font + + + + + Symbol Character Code + + + + + + Proofing Error Type + + + + + Start of Region Marked as Spelling Error + + + + + End of Region Marked as Spelling Error + + + + + Start of Region Marked as Grammatical Error + + + + + End of Region Marked as Grammatical Error + + + + + + + + Proofing Error Anchor Type + + + + + + Range Permision Editing Group + + + + + No Users Have Editing Permissions + + + + + All Users Have Editing Permissions + + + + + Administrator Group + + + + + Contributors Group + + + + + Editors Group + + + + + Owners Group + + + + + Current Group + + + + + + + + Annotation ID + + + + + Annotation Displaced By Custom XML Markup + + + + + + + + + Editor Group For Range Permission + + + + + Single User For Range Permission + + + + + First Table Column Covered By Range Permission + + + + + Last Table Column Covered By Range Permission + + + + + + + + + + + Content Contains Significant Whitespace + + + + + + + + + + Break + + + + + Text + + + + + Deleted Text + + + + + Field Code + + + + + Deleted Field Code + + + + + Non Breaking Hyphen Character + + + + + Optional Hyphen Character + + + + + Date Block - Short Day Format + + + + + Date Block - Short Month Format + + + + + Date Block - Short Year Format + + + + + Date Block - Long Day Format + + + + + Date Block - Long Month Format + + + + + Date Block - Long Year Format + + + + + Comment Information Block + + + + + Footnote Reference Mark + + + + + Endnote Reference Mark + + + + + Footnote/Endnote Separator Mark + + + + + Continuation Separator Mark + + + + + Symbol Character + + + + + Page Number Block + + + + + Carriage Return + + + + + Tab Character + + + + + Inline Embedded Object + + + + + VML Object + + + + + Complex Field Character + + + + + Phonetic Guide + + + + + Footnote Reference + + + + + Endnote Reference + + + + + Comment Content Reference Mark + + + + + DrawingML Object + + + + + Absolute Position Tab Character + + + + + Position of Last Calculated Page Break + + + + + + + + + + + + Revision Identifier for Run Properties + + + + + Revision Identifier for Run Deletion + + + + + Revision Identifier for Run + + + + + + Font Type Hint + + + + + High ANSI Font + + + + + East Asian Font + + + + + Complex Script Font + + + + + + + Theme Font + + + + + Major East Asian Theme Font + + + + + Major Complex Script Theme Font + + + + + Major ASCII Theme Font + + + + + Major High ANSI Theme Font + + + + + Minor East Asian Theme Font + + + + + Minor Complex Script Theme Font + + + + + Minor ASCII Theme Font + + + + + Minor High ANSI Theme Font + + + + + + + + Font Content Type + + + + + ASCII Font + + + + + High ANSI Font + + + + + East Asian Font + + + + + Complex Script Font + + + + + ASCII Theme Font + + + + + High ANSI Theme Font + + + + + East Asian Theme Font + + + + + Complex Script Theme Font + + + + + + + + Referenced Character Style + + + + + Run Fonts + + + + + Bold + + + + + Complex Script Bold + + + + + Italics + + + + + Complex Script Italics + + + + + Display All Characters As Capital Letters + + + + + Small Caps + + + + + Single Strikethrough + + + + + Double Strikethrough + + + + + Display Character Outline + + + + + Shadow + + + + + Embossing + + + + + Imprinting + + + + + Do Not Check Spelling or Grammar + + + + + Use Document Grid Settings For Inter-Character Spacing + + + + + Hidden Text + + + + + Web Hidden Text + + + + + Run Content Color + + + + + Character Spacing Adjustment + + + + + Expanded/Compressed Text + + + + + Font Kerning + + + + + Vertically Raised or Lowered Text + + + + + Font Size + + + + + Complex Script Font Size + + + + + Text Highlighting + + + + + Underline + + + + + Animated Text Effect + + + + + Text Border + + + + + Run Shading + + + + + Manual Run Width + + + + + Subscript/Superscript Text + + + + + Right To Left Text + + + + + Use Complex Script Formatting on Run + + + + + Emphasis Mark + + + + + Languages for Run Content + + + + + East Asian Typography Settings + + + + + Paragraph Mark Is Always Hidden + + + + + Office Open XML Math + + + + + + + + + + Revision Information for Run Properties + + + + + + + + + + + + + + Run Properties + + + + + + + + + + Inserted Math Control Character + + + + + Deleted Math Control Character + + + + + + + + + + + + + + + + + + + + + + Revision Information for Run Properties on the Paragraph Mark + + + + + + + + + Inserted Paragraph + + + + + Deleted Paragraph + + + + + Move Source Paragraph + + + + + Move Destination Paragraph + + + + + + + + + External Content Import Properties + + + + + + Relationship to Part + + + + + + + + Keep Source Formatting on Import + + + + + + + Phonetic Guide Text Alignment + + + + + Center + + + + + Distribute All Characters + + + + + Distribute all Characters w/ Additional Space On Either Side + + + + + Left Aligned + + + + + Right Aligned + + + + + Vertically Aligned to Right of Base Text + + + + + + + + Phonetic Guide Text Alignment Value + + + + + + + + Phonetic Guide Text Alignment + + + + + Phonetic Guide Text Font Size + + + + + Distance Between Phonetic Guide Text and Phonetic Guide Base Text + + + + + Phonetic Guide Base Text Font Size + + + + + Language ID for Phonetic Guide + + + + + Invalidated Field Cache + + + + + + + + + Phonetic Guide Text Run + + + + + + + + + + + + + Phonetic Guide Properties + + + + + Phonetic Guide Text + + + + + Phonetic Guide Base Text + + + + + + + Locking Types + + + + + SDT Cannot Be Deleted + + + + + Contents Cannot Be Edited At Runtime + + + + + No Locking + + + + + Contents Cannot Be Edited At Runtime And SDT Cannot Be Deleted + + + + + + + + Locking Type + + + + + + + List Entry Display Text + + + + + List Entry Value + + + + + + Date Storage Format Types + + + + + Same As Display + + + + + XML Schema Date Format + + + + + XML Schema DateTime Format + + + + + + + + Date Storage Type + + + + + + Calendar Types + + + + + Gregorian + + + + + Hijri + + + + + Hebrew + + + + + Taiwan + + + + + Japanese Emperor Era + + + + + Thai + + + + + Korean Tangun Era + + + + + Saka Era + + + + + Gregorian transliterated English + + + + + Gregorian transliterated French + + + + + + + + Calendar Type Value + + + + + + + + Date Display Mask + + + + + Date Picker Language ID + + + + + Custom XML Data Date Storage Format + + + + + Date Picker Calendar Type + + + + + + Last Known Date in XML Schema DateTime Format + + + + + + + + Combo Box List Item + + + + + + Combo Box Last Saved Value + + + + + + + + Document Part Gallery Filter + + + + + Document Part Category Filter + + + + + Built-In Document Part + + + + + + + + + Drop-Down List Item + + + + + + Drop-down List Last Saved Value + + + + + + + + Document Part Reference + + + + + + + + Allow Soft Line Breaks + + + + + + + XML Namespace Prefix Mappings + + + + + XPath + + + + + Custom XML Data Storage ID + + + + + + + + Run Properties For Structured Document Tag Contents + + + + + Friendly Name + + + + + Locking Setting + + + + + Structured Document Tag Placeholder Text + + + + + Current Contents Are Placeholder Text + + + + + XML Mapping + + + + + Remove Structured Document Tag When Contents Are Edited + + + + + Unique ID + + + + + Programmatic Tag + + + + + + Equation Structured Document Tag + + + + + Combo Box Structured Document Tag + + + + + Date Structured Document Tag + + + + + Built-In Document Part Structured Document Tag + + + + + Document Part Gallery Structured Document Tag + + + + + Drop-Down List Structured Document Tag + + + + + Picture Structured Document Tag + + + + + Rich Text Structured Document Tag + + + + + Plain Text Structured Document Tag + + + + + Citation Structured Document Tag + + + + + Group Structured Document Tag + + + + + Bibliography Structured Document Tag + + + + + + + + + + Structured Document Tag End Character Run Properties + + + + + + + + + Inline-Level Custom XML Element + + + + + Inline-Level Smart Tag + + + + + Inline-Level Structured Document Tag + + + + + Text Run + + + + + + + + + + + + + Block-Level Custom XML Element + + + + + Block-Level Structured Document Tag + + + + + Paragraph + + + + + Table + + + + + + + + + + + + + Table Row + + + + + Row-Level Custom XML Element + + + + + Row-Level Structured Document Tag + + + + + + + + + + + + + Table Cell + + + + + Cell-Level Custom XML Element + + + + + Cell-Level Structured Document Tag + + + + + + + + + + + + + Structured Document Tag Properties + + + + + Structured Document Tag End Character Properties + + + + + Block-Level Structured Document Tag Content + + + + + + + + + Structured Document Tag Properties + + + + + Structured Document Tag End Character Properties + + + + + Inline-Level Structured Document Tag Content + + + + + + + + + Structured Document Tag Properties + + + + + Structured Document Tag End Character Properties + + + + + Cell-Level Structured Document Tag Content + + + + + + + + + Structured Document Tag Properties + + + + + Structured Document Tag End Character Properties + + + + + Row-Level Structured Document Tag Content + + + + + + + + Namespace + + + + + Name + + + + + Value + + + + + + + + Custom XML Element Properties + + + + + + + Custom XML Markup Namespace + + + + + Element name + + + + + + + + Smart Tag Properties + + + + + + + Smart Tag Namespace + + + + + Smart Tag Name + + + + + + + + Custom XML Element Properties + + + + + + + Custom XML Element Namespace + + + + + Custom XML Element Name + + + + + + + + Custom XML Element Placeholder Text + + + + + Custom XML Attribute + + + + + + + + + Custom XML Element Properties + + + + + + + Custom XML Element Namespace + + + + + Custom XML Element Name + + + + + + + + Custom XML Element Properties + + + + + + + Custom XML Element Namespace + + + + + Custom XML Element Name + + + + + + + + Smart Tag Property + + + + + + + + + + Simple Field + + + + + Hyperlink + + + + + Anchor for Subdocument Location + + + + + + + + + Paragraph Properties + + + + + + + Revision Identifier for Paragraph Glyph Formatting + + + + + Revision Identifier for Paragraph + + + + + Revision Identifier for Paragraph Deletion + + + + + Revision Identifier for Paragraph Properties + + + + + Default Revision Identifier for Runs + + + + + + Table Width Units + + + + + No Width + + + + + Width in Fiftieths of a Percent + + + + + Width in Twentieths of a Point + + + + + Automatically Determined Width + + + + + + + + Table Row Height + + + + + Table Row Height Type + + + + + + + Table Width Value + + + + + Table Width Type + + + + + + + Grid Column Width + + + + + + + + Grid Column Definition + + + + + + + + + + + Revision Information for Table Grid Column Definitions + + + + + + + + + + + Table Cell Top Border + + + + + Table Cell Left Border + + + + + Table Cell Bottom Border + + + + + Table Cell Right Border + + + + + Table Cell Inside Horizontal Edges Border + + + + + Table Cell Inside Vertical Edges Border + + + + + Table Cell Top Left to Bottom Right Diagonal Border + + + + + Table Cell Top Right to Bottom Left Diagonal Border + + + + + + + + + Table Cell Top Margin Exception + + + + + Table Cell Left Margin Exception + + + + + Table Cell Bottom Margin Exception + + + + + Table Cell Right Margin Exception + + + + + + + Merged Cell Type + + + + + Continue Merged Region + + + + + Start/Restart Merged Region + + + + + + + + Vertical Merge Type + + + + + + + Horizontal Merge Type + + + + + + + + Table Cell Conditional Formatting + + + + + Preferred Table Cell Width + + + + + Grid Columns Spanned by Current Table Cell + + + + + Horizontally Merged Cell + + + + + Vertically Merged Cell + + + + + Table Cell Borders + + + + + Table Cell Shading + + + + + Don't Wrap Cell Content + + + + + Single Table Cell Margins + + + + + Table Cell Text Flow Direction + + + + + Fit Text Within Cell + + + + + Table Cell Vertical Alignment + + + + + Ignore End Of Cell Marker In Row Height Calculation + + + + + + + + + + + Revision Information for Table Cell Properties + + + + + + + + + + + + + + + + + + + + Table Cell Properties + + + + + + + + Conditional Formatting Bitmask + + + + + + + + + + Conditional Formatting Bit Mask + + + + + + + + Table Row Conditional Formatting + + + + + Associated HTML div ID + + + + + Grid Columns Before First Cell + + + + + Grid Columns After Last Cell + + + + + Preferred Width Before Table Row + + + + + Preferred Width After Table Row + + + + + Table Row Cannot Break Across Pages + + + + + Table Row Height + + + + + Repeat Table Row on Every New Page + + + + + Table Row Cell Spacing + + + + + Table Row Alignment + + + + + Hidden Table Row Marker + + + + + + + + + + + Inserted Table Row + + + + + Deleted Table Row + + + + + Revision Information for Table Row Properties + + + + + + + + + + + Table-Level Property Exceptions + + + + + Table Row Properties + + + + + + + Revision Identifier for Table Row Glyph Formatting + + + + + Revision Identifier for Table Row + + + + + Revision Identifier for Table Row Deletion + + + + + Revision Identifier for Table Row Properties + + + + + + Table Layout Type + + + + + Fixed Width Table Layout + + + + + AutoFit Table Layout + + + + + + + + Table Layout Setting + + + + + + Table Overlap Setting + + + + + Floating Table Cannot Overlap + + + + + Floating Table Can Overlap + + + + + + + + Floating Table Overlap Setting + + + + + + + Distance From Left of Table to Text + + + + + (Distance From Right of Table to Text + + + + + Distance From Top of Table to Text + + + + + Distance From Bottom of Table to Text + + + + + Table Vertical Anchor + + + + + Table Horizontal Anchor + + + + + Relative Horizontal Alignment From Anchor + + + + + Absolute Horizontal Distance From Anchor + + + + + Relative Vertical Alignment from Anchor + + + + + Absolute Vertical Distance From Anchor + + + + + + + + Table Cell Top Margin Default + + + + + Table Cell Left Margin Default + + + + + Table Cell Bottom Margin Default + + + + + Table Cell Right Margin Default + + + + + + + + + Table Top Border + + + + + Table Left Border + + + + + Table Bottom Border + + + + + Table Right Border + + + + + Table Inside Horizontal Edges Border + + + + + Table Inside Vertical Edges Border + + + + + + + + + Referenced Table Style + + + + + Floating Table Positioning + + + + + Floating Table Allows Other Tables to Overlap + + + + + Visually Right to Left Table + + + + + Number of Rows in Row Band + + + + + Number of Columns in Column Band + + + + + Preferred Table Width + + + + + Table Alignment + + + + + Table Cell Spacing Default + + + + + Table Indent from Leading Margin + + + + + Table Borders + + + + + Table Shading + + + + + Table Layout + + + + + Table Cell Margin Defaults + + + + + Table Style Conditional Formatting Settings + + + + + + + + + + + Revision Information for Table Properties + + + + + + + + + + + Preferred Table Width Exception + + + + + Table Alignment Exception + + + + + Table Cell Spacing Exception + + + + + Table Indent from Leading Margin Exception + + + + + Table Borders Exceptions + + + + + Table Shading Exception + + + + + Table Layout Exception + + + + + Table Cell Margin Exceptions + + + + + Table Style Conditional Formatting Settings Exception + + + + + + + + + + + Revision Information for Table-Level Property Exceptions + + + + + + + + + + + + Table Properties + + + + + Table Grid + + + + + + + + Footnote Positioning Location + + + + + Footnotes Positioned at Page Bottom + + + + + Footnotes Positioned Beneath Text + + + + + Footnotes Positioned At End of Section + + + + + Footnotes Positioned At End of Document + + + + + + + + Footnote Position Type + + + + + + Endnote Positioning Location + + + + + Endnotes Positioned at End of Section + + + + + Endnotes Positioned at End of Document + + + + + + + + Endnote Position Type + + + + + + + Numbering Format Type + + + + + + Footnote/Endnote Numbering Restart Locations + + + + + Continue Numbering From Previous Section + + + + + Restart Numbering For Each Section + + + + + Restart Numbering On Each Page + + + + + + + + Automatic Numbering Restart Value + + + + + + + Suppress Footnote/Endnote Reference Mark + + + + + Footnote/Endnote ID Reference + + + + + + + Footnote/Endnote ID + + + + + + + + + + Footnote/Endnote Type + + + + + Footnote/Endnote ID + + + + + + + + Footnote and Endnote Numbering Starting Value + + + + + Footnote and Endnote Numbering Restart Location + + + + + + + + + Footnote Placement + + + + + Footnote Numbering Format + + + + + + + + + + Endnote Placement + + + + + Endnote Numbering Format + + + + + + + + + + + + Special Footnote List + + + + + + + + + + + + + Special Endnote List + + + + + + + + + + + Record Is Included in Mail Merge + + + + + Index of Column Containing Unique Values for Record + + + + + Unique Value for Record + + + + + + + + + Data About Single Data Source Record + + + + + + + Inclusion/Exclusion Data for Data Source + + + + + + + Merge Field Mapping + + + + + Data Source Name for Column + + + + + Predefined Merge Field Name + + + + + Index of Column Being Mapped + + + + + Merge Field Name Language ID + + + + + Use Country-Based Address Field Ordering + + + + + + + Mail Merge ODSO Data Source Types + + + + + Database Data Source + + + + + Address Book Data Source + + + + + Alternate Document Format Data Source + + + + + Alternate Document Format Data Source Two + + + + + Text File Data Source + + + + + E-Mail Program Data Source + + + + + Native Data Souce + + + + + Legacy Document Format Data Source + + + + + Aggregate Data Source + + + + + + + + Data Source Type Value + + + + + + + + UDL Connection String + + + + + Data Source Table Name + + + + + ODSO Data Source File Path + + + + + Column Delimiter for Data Source + + + + + ODSO Data Source Type + + + + + First Row of Data Source Contains Column Names + + + + + External Data Source to Merge Field Mapping + + + + + Reference to Inclusion/Exclusion Data for Data Source + + + + + + + + + Source Document Type + + + + + Query Contains Link to External Query File + + + + + Data Source Type + + + + + Data Source Connection String + + + + + Query For Data Source Records To Merge + + + + + Data Source File Path + + + + + Header Definition File Path + + + + + Remove Blank Lines from Merged Documents + + + + + Merged Document Destination + + + + + Column Containing E-mail Address + + + + + Merged E-mail or Fax Subject Line + + + + + Merged Document To E-Mail Attachment + + + + + View Merged Data Within Document + + + + + Record Currently Displayed In Merged Document + + + + + Mail Merge Error Reporting Setting + + + + + Office Data Source Object Settings + + + + + + + Target Screen Sizes for Generated Web Pages + + + + + Optimize for 544x376 + + + + + Optimize for 640x480 + + + + + Optimize for 720x512 + + + + + Optimize for 800x600 + + + + + Optimize for 1024x768 + + + + + Optimize for 1152x882 + + + + + Optimize for 1152x900 + + + + + Optimize for 1280x1024 + + + + + Optimize for 1600x1200 + + + + + Optimize for 1800x1440 + + + + + Optimize for 1920x1200 + + + + + + + + Target Screen Size Value + + + + + + + + Use Simplified Rules For Table Border Conflicts + + + + + Emulate WordPerfect 6.x Paragraph Justification + + + + + Do Not Create Custom Tab Stop for Hanging Indent + + + + + Do Not Add Leading Between Lines of Text + + + + + Add Additional Space Below Baseline For Underlined East Asian Text + + + + + Do Not Balance Text Columns within a Section + + + + + Balance Single Byte and Double Byte Characters + + + + + Do Not Center Content on Lines With Exact Line Height + + + + + Convert Backslash To Yen Sign When Entered + + + + + Underline All Trailing Spaces + + + + + Don't Justify Lines Ending in Soft Line Break + + + + + Only Expand/Condense Text By Whole Points + + + + + Emulate Word 6.0 Line Wrapping for East Asian Text + + + + + Print Body Text before Header/Footer Contents + + + + + Print Colors as Black And White without Dithering + + + + + Space width + + + + + Display Page/Column Breaks Present in Frames + + + + + Increase Priority Of Font Size During Font Substitution + + + + + Ignore Exact Line Height for Last Line on Page + + + + + Ignore Minimum and Exact Line Height for First Line on Page + + + + + Ignore Minimum Line Height for First Line on Page + + + + + Emulate WordPerfect 5.x Line Spacing + + + + + Do Not Use Space Before On First Line After a Page Break + + + + + Swap Paragraph Borders on Odd Numbered Pages + + + + + Treat Backslash Quotation Delimiter as Two Quotation Marks + + + + + Emulate WordPerfect 6.x Font Height Calculation + + + + + Emulate Word 5.x for the Macintosh Small Caps Formatting + + + + + Use Printer Metrics To Display Documents + + + + + Do Not Suppress Paragraph Borders Next To Frames + + + + + Line Wrap Trailing Spaces + + + + + Emulate Word 6.x/95/97 Footnote Placement + + + + + Emulate Word 97 Text Wrapping Around Floating Objects + + + + + Align Table Rows Independently + + + + + Ignore Width of Last Tab Stop When Aligning Paragraph If It Is Not Left Aligned + + + + + Add Document Grid Line Pitch To Lines in Table Cells + + + + + Emulate Word 95 Full-Width Character Spacing + + + + + Do Not Increase Line Height for Raised/Lowered Text + + + + + Use Fixed Paragraph Spacing for HTML Auto Setting + + + + + Ignore Space Before Table When Deciding If Table Should Wrap Floating Object + + + + + Allow Table Rows to Wrap Inline Objects Independently + + + + + Emulate Word 97 East Asian Line Breaking + + + + + Do Not Allow Floating Tables To Break Across Pages + + + + + Do Not Snap to Document Grid in Table Cells with Objects + + + + + Select Field When First or Last Character Is Selected + + + + + Use Legacy Ethiopic and Amharic Line Breaking Rules + + + + + Do Not Allow Hanging Punctuation With Character Grid + + + + + Do Not Compress Compressible Characters When Using Document Grid + + + + + Emulate Word 2002 Table Style Rules + + + + + Allow Tables to AutoFit Into Page Margins + + + + + Do Not Bypass East Asian/Complex Script Layout Code + + + + + Do Not Automatically Apply List Paragraph Style To Bulleted/Numbered Text + + + + + Ignore Hanging Indent When Creating Tab Stop After Numbering + + + + + Use Alternate Set of East Asian Line Breaking Rules + + + + + Allow Contextual Spacing of Paragraphs in Tables + + + + + Do Not Ignore Floating Objects When Calculating Paragraph Indentation + + + + + Do Not AutoFit Tables To Fit Next To Wrapped Objects + + + + + Allow Table Columns To Exceed Preferred Widths of Constituent Cells + + + + + Underline Following Character Following Numbering + + + + + Always Use Fixed Width for Hangul Characters + + + + + Always Move Paragraph Mark to Page after a Page Break + + + + + Don't Vertically Align Cells Containing Floating Objects + + + + + Don't Break Table Rows Around Floating Tables + + + + + Ignore Vertical Alignment in Textboxes + + + + + Use ANSI Kerning Pairs from Fonts + + + + + Use Cached Paragraph Information for Column Balancing + + + + + + + + Document Variable Name + + + + + Document Variable Value + + + + + + + + Single Document Variable + + + + + + + + + Original Document Revision Save ID + + + + + Single Session Revision Save ID + + + + + + + Character-Level Whitespace Compression Settings + + + + + Do Not Compress Whitespace + + + + + Compress Whitespace From Punctuation Characters + + + + + Compress Whitespace From Both Japanese Kana And Punctuation Characters + + + + + + + + Value + + + + + + + XSL Transformation Location + + + + + Local Identifier for XSL Transform + + + + + + + + Run Properties + + + + + + + + + Paragraph Properties + + + + + + + + + Default Run Properties + + + + + Default Paragraph Properties + + + + + + + Theme Color Reference + + + + + Dark 1 Theme Color Reference + + + + + Light 1 Theme Color Reference + + + + + Dark 2 Theme Color Reference + + + + + Light 2 Theme Color Reference + + + + + Accent 1 Theme Color Reference + + + + + Accent 2 Theme Color Reference + + + + + Accent 3 Theme Color Reference + + + + + Accent4 Theme Color Reference + + + + + Accent5 Theme Color Reference + + + + + Accent 6 Theme Color Reference + + + + + Hyperlink Theme Color Reference + + + + + Followed Hyperlink Theme Color Reference + + + + + + + + Background 1 Theme Color Mapping + + + + + Text 1 Theme Color Mapping + + + + + Background 2 Theme Color Mapping + + + + + Text 2 Theme Color Mapping + + + + + Accent 1 Theme Color Mapping + + + + + Accent 2 Theme Color Mapping + + + + + Accent3 Theme Color Mapping + + + + + Accent4 Theme Color Mapping + + + + + Accent5 Theme Color Mapping + + + + + Accent6 Theme Color Mapping + + + + + Hyperlink Theme Color Mapping + + + + + Followed Hyperlink Theme Color Mapping + + + + + + + Use Actual Pages, Not Virtual Pages + + + + + Virtual Page Width + + + + + Virtual Page Height + + + + + Font Size Scaling + + + + + + + Recommend Write Protection in User Interface + + + + + + + + + Write Protection + + + + + Document View Setting + + + + + Magnification Setting + + + + + Remove Personal Information from Document Properties + + + + + Remove Date and Time from Annotations + + + + + Do Not Display Visual Boundary For Header/Footer or Between Pages + + + + + Display Background Objects When Displaying Document + + + + + Print PostScript Codes With Document Text + + + + + Print Fractional Character Widths + + + + + Only Print Form Field Content + + + + + Embed TrueType Fonts + + + + + Embed Common System Fonts + + + + + Subset Fonts When Embedding + + + + + Only Save Form Field Content + + + + + Mirror Page Margins + + + + + Align Paragraph and Table Borders with Page Border + + + + + Page Border Excludes Header + + + + + Page Border Excludes Footer + + + + + Position Gutter At Top of Page + + + + + Do Not Display Visual Indication of Spelling Errors + + + + + Do Not Display Visual Indication of Grammatical Errors + + + + + Grammar Checking Settings + + + + + Spelling and Grammatical Checking State + + + + + Structured Document Tag Placeholder Text Should be Resaved + + + + + Attached Document Template + + + + + Automatically Update Styles From Document Template + + + + + Suggested Filtering for List of Document Styles + + + + + Suggested Sorting for List of Document Styles + + + + + Document Classification + + + + + Mail Merge Settings + + + + + Visibility of Annotation Types + + + + + Track Revisions to Document + + + + + Do Not Use Move Syntax When Tracking Revisions + + + + + Do Not Track Formatting Revisions When Tracking Revisions + + + + + Document Editing Restrictions + + + + + Allow Automatic Formatting to Override Formatting Protection Settings + + + + + Prevent Modification of Themes Part + + + + + Prevent Replacement of Styles Part + + + + + Distance Between Automatic Tab Stops + + + + + Automatically Hyphenate Document Contents When Displayed + + + + + Maximum Number of Consecutively Hyphenated Lines + + + + + Hyphenation Zone + + + + + Do Not Hyphenate Words in ALL CAPITAL LETTERS + + + + + Show E-Mail Message Header + + + + + Percentage of Document to Use When Generating Summary + + + + + Paragraph Style Applied to Automatically Generated Paragraphs + + + + + Default Table Style for Newly Inserted Tables + + + + + Different Even/Odd Page Headers and Footers + + + + + Reverse Book Fold Printing + + + + + Book Fold Printing + + + + + Number of Pages Per Booklet + + + + + Drawing Grid Horizontal Grid Unit Size + + + + + Drawing Grid Vertical Grid Unit Size + + + + + Distance between Horizontal Gridlines + + + + + Distance between Vertical Gridlines + + + + + Do Not Use Margins for Drawing Grid Origin + + + + + Drawing Grid Horizontal Origin Point + + + + + Drawing Grid Vertical Origin Point + + + + + Do Not Show Visual Indicator For Form Fields + + + + + Never Kern Punctuation Characters + + + + + Character-Level Whitespace Compression + + + + + Print Two Pages Per Sheet + + + + + Use Strict Kinsoku Rules for Japanese Text + + + + + Custom Set of Characters Which Cannot End a Line + + + + + Custom Set Of Characters Which Cannot Begin A Line + + + + + Generate Thumbnail For Document On Save + + + + + Do Not Validate Custom XML Markup Against Schemas + + + + + Allow Saving Document As XML File When Custom XML Markup Is Invalid + + + + + Ignore Mixed Content When Validating Custom XML Markup + + + + + Use Custom XML Element Names as Default Placeholder Text + + + + + Do Not Show Visual Indicator For Invalid Custom XML Markup + + + + + Only Save Custom XML Markup + + + + + Save Document as XML File through Custom XSL Transform + + + + + Custom XSL Transform To Use When Saving As XML File + + + + + Show Visual Indicators for Custom XML Markup Start/End Locations + + + + + Do Not Mark Custom XML Elements With No Namespace As Invalid + + + + + Automatically Recalculate Fields on Open + + + + + Default Properties for VML Objects in Header and Footer + + + + + Document-Wide Footnote Properties + + + + + Document-Wide Endnote Properties + + + + + Compatibility Settings + + + + + Document Variables + + + + + Listing of All Revision Save ID Values + + + + + properties of math in the document + + + + + Disable Features Incompatible With Earlier Word Processing Formats + + + + + Attached Custom XML Schema + + + + + Theme Font Languages + + + + + Theme Color Mappings + + + + + Do Not Include Content in Text Boxes, Footnotes, and Endnotes in Document Statistics + + + + + Do Not Automatically Compress Images + + + + + Upgrade Document on Open + + + + + Caption Settings + + + + + Freeze Document Layout + + + + + Supplementary Smart Tag Information + + + + + Custom XML Schema List + + + + + Default Properties for VML Objects in Main Document + + + + + Remove Smart Tags When Saving + + + + + Radix Point for Field Code Evaluation + + + + + List Separator for Field Code Evaluation + + + + + + + + + Root Frameset Definition + + + + + Information about HTML div Elements + + + + + Output Encoding When Saving as Web Page + + + + + Disable Features Not Supported by Target Web Browser + + + + + Utilize VML When Saving as Web Page + + + + + Allow PNG as Graphic Format + + + + + Do Not Rely on CSS for Font Face Formatting + + + + + Recommend Web Page Format over Single File Web Page Format + + + + + Do Not Place Supporting Files in Subdirectory + + + + + Do Not Use File Names Longer than 8.3 Characters + + + + + Pixels per Inch for Graphics/Images + + + + + Target Screen Size for Web Page + + + + + Save Smart Tag Data in XML Property Bag + + + + + + + Frame Scrollbar Visibility + + + + + Always Show Scrollbar + + + + + Never Show Scrollbar + + + + + Automatically Show Scrollbar As Needed + + + + + + + + Scrollbar Display Option Value + + + + + + + + Frame Size + + + + + Frame Name + + + + + Source File for Frame + + + + + Left and Right Margin for Frame + + + + + Top and Bottom Margin for Frame + + + + + Scrollbar Display Option + + + + + Frame Cannot Be Resized + + + + + Maintain Link to Existing File + + + + + + + Frameset Layout Order + + + + + Stack Frames Vertically + + + + + Stack Frames Horizontally + + + + + Do Not Stack Frames + + + + + + + + Frameset Layout Value + + + + + + + + Frameset Splitter Width + + + + + Frameset Splitter Color + + + + + Do Not Display Frameset Splitters + + + + + Frameset Splitter Border Style + + + + + + + + + Nested Frameset Size + + + + + Frameset Splitter Properties + + + + + Frameset Layout + + + + + + Nested Frameset Definition + + + + + Single Frame Properties + + + + + + + + + + Picture Numbering Symbol Properties + + + + + + Picture Numbering Symbol ID + + + + + + Content Between Numbering Symbol and Paragraph Text + + + + + Tab Between Numbering and Text + + + + + Space Between Numbering and Text + + + + + Nothing Between Numbering and Text + + + + + + + + Character Type Between Numbering and Text + + + + + + + Level Text + + + + + Level Text Is Null Character + + + + + + + Use Legacy Numbering Properties + + + + + Legacy Spacing + + + + + Legacy Indent + + + + + + + + Starting Value + + + + + Numbering Format + + + + + Restart Numbering Level Symbol + + + + + Paragraph Style's Associated Numbering Level + + + + + Display All Levels Using Arabic Numerals + + + + + Content Between Numbering Symbol and Paragraph Text + + + + + Numbering Level Text + + + + + Picture Numbering Symbol Definition Reference + + + + + Legacy Numbering Level Properties + + + + + Justification + + + + + Numbering Level Associated Paragraph Properties + + + + + Numbering Symbol Run Properties + + + + + + Numbering Level + + + + + Template Code + + + + + Tentative Numbering + + + + + + Numbering Definition Type + + + + + Single Level Numbering Definition + + + + + Multilevel Numbering Definition + + + + + Hybrid Multilevel Numbering Definition + + + + + + + + Abstract Numbering Definition Type + + + + + + + + Abstract Numbering Definition Identifier + + + + + Abstract Numbering Definition Type + + + + + Numbering Template Code + + + + + Abstract Numbering Definition Name + + + + + Numbering Style Definition + + + + + Numbering Style Reference + + + + + Numbering Level Definition + + + + + + Abstract Numbering Definition ID + + + + + + + + Numbering Level Starting Value Override + + + + + Numbering Level Override Definition + + + + + + Numbering Level ID + + + + + + + + Abstract Numbering Definition Reference + + + + + Numbering Level Definition Override + + + + + + Numbering Definition Instance ID + + + + + + + + Picture Numbering Symbol Definition + + + + + Abstract Numbering Definition + + + + + Numbering Definition Instance + + + + + Last Reviewed Abstract Numbering Definition + + + + + + + Conditional Table Style Formatting Types + + + + + Whole table formatting + + + + + First Row Conditional Formatting + + + + + Last table row formatting + + + + + First Column Conditional Formatting + + + + + Last table column formatting + + + + + Banded Column Conditional Formatting + + + + + Even Column Stripe Conditional Formatting + + + + + Banded Row Conditional Formatting + + + + + Even Row Stripe Conditional Formatting + + + + + Top right table cell formatting + + + + + Top left table cell formatting + + + + + Bottom right table cell formatting + + + + + Bottom left table cell formatting + + + + + + + + + Table Style Conditional Formatting Paragraph Properties + + + + + Table Style Conditional Formatting Run Properties + + + + + Table Style Conditional Formatting Table Properties + + + + + Table Style Conditional Formatting Table Row Properties + + + + + Table Style Conditional Formatting Table Cell Properties + + + + + + Table Style Conditional Formatting Type + + + + + + Style Types + + + + + Paragraph Style + + + + + Character Style + + + + + Table Style + + + + + Numbering Style + + + + + + + + + Primary Style Name + + + + + Alternate Style Names + + + + + Parent Style ID + + + + + Style For Next Paragraph + + + + + Linked Style Reference + + + + + Automatically Merge User Formatting Into Style Definition + + + + + Hide Style From User Interface + + + + + Optional User Interface Sorting Order + + + + + Hide Style From Main User Interface + + + + + Remove Semi-Hidden Property When Style Is Used + + + + + Primary Style + + + + + Style Cannot Be Applied + + + + + E-Mail Message Text Style + + + + + E-Mail Message Composition Style + + + + + E-Mail Message Reply Style + + + + + Revision Identifier for Style Definition + + + + + Style Paragraph Properties + + + + + Run Properties + + + + + Style Table Properties + + + + + Style Table Row Properties + + + + + Style Table Cell Properties + + + + + Style Conditional Table Formatting Properties + + + + + + Style Type + + + + + Style ID + + + + + Default Style + + + + + User-Defined Style + + + + + + + Primary Style Name + + + + + Latent Style Locking Setting + + + + + Override default sorting order + + + + + Semi hidden text override + + + + + Unhide when used + + + + + Latent Style Primary Style Setting + + + + + + + + Latent Style Exception + + + + + + Default Style Locking Setting + + + + + Default User Interface Priority Setting + + + + + Default Semi-Hidden Setting + + + + + Default Hidden Until Used Setting + + + + + Default Primary Style Setting + + + + + Latent Style Count + + + + + + + + Document Default Paragraph and Run Properties + + + + + Latent Style Information + + + + + Style Definition + + + + + + + Panose-1 Number + + + + + + + + + Value + + + + + + Font Family Value + + + + + Novelty Font + + + + + Monospace Font + + + + + Proportional Font With Serifs + + + + + Script Font + + + + + Proportional Font Without Serifs + + + + + No Font Family + + + + + + + + Font Family Value + + + + + + Font Pitch Value + + + + + Fixed Width + + + + + Proportional Width + + + + + Default + + + + + + + + Value + + + + + + + First 32 Bits of Unicode Subset Bitfield + + + + + Second 32 Bits of Unicode Subset Bitfield + + + + + Third 32 Bits of Unicode Subset Bitfield + + + + + Fourth 32 Bits of Unicode Subset Bitfield + + + + + Lower 32 Bits of Code Page Bit Field + + + + + Upper 32 Bits of Code Page Bit Field + + + + + + + + + Embedded Font Obfuscation Key + + + + + Embedded Font Is Subsetted + + + + + + + + + + Alternate Names for Font + + + + + Pansose-1 Typeface Classification Number + + + + + Character Set Supported By Font + + + + + Font Family + + + + + Raster or Vector Font + + + + + Font Pitch + + + + + Supported Unicode Subranges and Code Pages + + + + + Regular Font Style Embedding + + + + + Bold Style Font Style Embedding + + + + + Italic Font Style Embedding + + + + + Bold Italic Font Style Embedding + + + + + + Primary Font Name + + + + + + + + Properties for a Single Font + + + + + + + + + Top Border for HTML div + + + + + Left Border for HTML div + + + + + Bottom Border for HTML div + + + + + Right Border for HTML div + + + + + + + + + Data for HTML blockquote Element + + + + + Data for HTML body Element + + + + + Left Margin for HTML div + + + + + Right Margin for HTML div + + + + + Top Margin for HTML div + + + + + Bottom Margin for HTML div + + + + + Set of Borders for HTML div + + + + + Child div Elements Contained within Current div + + + + + + div Data ID + + + + + + + + Information About Single HTML div Element + + + + + + + + + + Rich Text Box Content Container + + + + + + + + + + + + + + + + + + + Anchor for Imported External Content + + + + + + + + + Proofing Error Anchor + + + + + Range Permission Start + + + + + Range Permission End + + + + + + Inserted Run Content + + + + + Deleted Run Content + + + + + Move Source Run Content + + + + + Move Destination Run Content + + + + + + + + + + + Document Final Section Properties + + + + + + + + + + + + + + Comment Content + + + + + + + Comments Collection + + + + + + + Footnote Content + + + + + + + Document Footnotes + + + + + + + Endnote Content + + + + + + + Document Endnotes + + + + + Header + + + + + Footer + + + + + + Smart Tag Namespace + + + + + Smart Tag Name + + + + + Smart Tag Supplementary URL + + + + + + Theme Color + + + + + Dark 1 Theme Color + + + + + Light 1 Theme Color + + + + + Dark 2 Theme Color + + + + + Light 2 Theme Color + + + + + Accent 1 Theme Color + + + + + Accent 2 Theme Color + + + + + Accent 3 Theme Color + + + + + Accent 4 Theme Color + + + + + Accent 5 Theme Color + + + + + Accent 6 Theme Color + + + + + Hyperlink Theme Color + + + + + Followed Hyperlink Theme Color + + + + + No Theme Color + + + + + Background 1 Theme Color + + + + + Text 1 Theme Color + + + + + Background 2 Theme Color + + + + + Text 2 Theme Color + + + + + + + Insertion Behavior Types + + + + + Insert Content At Specified Location + + + + + Ensure Entry Is In New Paragraph + + + + + Ensure Entry Is On New Page + + + + + + + + Insertion Behavior Value + + + + + + + + Entry Insertion Behavior + + + + + + + Entry Types + + + + + No Type + + + + + Normal + + + + + Automatically Replace Name With Content + + + + + AutoText User Interface Entry + + + + + AutoCorrect Entry + + + + + Form Field Help Text + + + + + Structured Document Tag Placeholder Text + + + + + + + + Type Value + + + + + + + + Entry Type + + + + + + Entry Is Of All Types + + + + + + Entry Gallery Types + + + + + Structured Document Tag Placeholder Text Gallery + + + + + All Galleries + + + + + No Gallery Classification + + + + + Document Parts Gallery + + + + + Cover Page Gallery + + + + + Equations Gallery + + + + + Footers Gallery + + + + + Headers Gallery + + + + + Page Numbers Gallery + + + + + Table Gallery + + + + + Watermark Gallery + + + + + AutoText Gallery + + + + + Text Box Gallery + + + + + Page Numbers At Top Gallery + + + + + Page Numbers At Bottom Gallery + + + + + Page Numbers At Margins Gallery + + + + + Table of Contents Gallery + + + + + Bibliography Gallery + + + + + Custom Quick Parts Gallery + + + + + Custom Cover Page Gallery + + + + + Custom Equation Gallery + + + + + Custom Footer Gallery + + + + + Custom Header Gallery + + + + + Custom Page Number Gallery + + + + + Custom Table Gallery + + + + + Custom Watermark Gallery + + + + + Custom AutoText Gallery + + + + + Custom Text Box Gallery + + + + + Custom Page Number At Top Gallery + + + + + Custom Page Number At Bottom Gallery + + + + + Custom Page Number At Margins Gallery + + + + + Custom Table of Contents Gallery + + + + + Custom Bibliography Gallery + + + + + Custom 1 Gallery + + + + + Custom 2 Gallery + + + + + Custom 3 Gallery + + + + + Custom 4 Gallery + + + + + Custom 5 Gallery + + + + + + + + Gallery Value + + + + + + + + Category Associated With Entry + + + + + Gallery Associated With Entry + + + + + + + + Name Value + + + + + Built-In Entry + + + + + + + + Entry Name + + + + + Associated Paragraph Style Name + + + + + Entry Categorization + + + + + Entry Types + + + + + Entry Insertion Behaviors + + + + + Description for Entry + + + + + Entry ID + + + + + + + + + Glossary Document Entry Properties + + + + + Contents of Glossary Document Entry + + + + + + + + + Glossary Document Entry + + + + + + + Document Settings + + + + + Web Page Settings + + + + + Font Table Root Element + + + + + Numbering Definitions + + + + + Style Definitions + + + + + Automatic Caption Positioning Values + + + + + Position Caption Above Object + + + + + Position Caption Below Object + + + + + Position Caption Left Of Object + + + + + Position Caption Right Of Object + + + + + + + + Caption Type Name + + + + + Automatic Caption Placement + + + + + Include Chapter Number in Field for Caption + + + + + Style for Chapter Headings + + + + + Do Not Include Name In Caption + + + + + Caption Numbering Format + + + + + Chapter Number/Item Index Separator + + + + + + + Identifier of Object to be Automatically Captioned + + + + + Caption Used for Automatic Captioning + + + + + + + + Single Automatic Captioning Setting + + + + + + + + + Single Caption Type Definition + + + + + Automatic Captioning Settings + + + + + + + + + Document Background + + + + + + + + + + + Document Body + + + + + + + + + + + + + List of Glossary Document Entries + + + + + + + + + Document + + + + + Glossary Document Root Element + + + \ No newline at end of file diff --git a/tests/resources/schema/ooxml/dml-chart.xsd b/tests/resources/schema/ooxml/dml-chart.xsd index 91559f2ce6..958a897630 100644 --- a/tests/resources/schema/ooxml/dml-chart.xsd +++ b/tests/resources/schema/ooxml/dml-chart.xsd @@ -194,7 +194,7 @@ - + @@ -202,7 +202,7 @@ - + @@ -214,19 +214,13 @@ - + - - - - - - @@ -1164,7 +1158,7 @@ - + @@ -1172,7 +1166,7 @@ - + diff --git a/tests/resources/schema/opendocument/1.0/OpenDocument-manifest-schema-v1.0-os.rng b/tests/resources/schema/opendocument/1.0/OpenDocument-manifest-schema-v1.0-os.rng new file mode 100644 index 0000000000..97fe580eab --- /dev/null +++ b/tests/resources/schema/opendocument/1.0/OpenDocument-manifest-schema-v1.0-os.rng @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.0/OpenDocument-schema-v1.0-os.rng b/tests/resources/schema/opendocument/1.0/OpenDocument-schema-v1.0-os.rng new file mode 100644 index 0000000000..cf4ee51741 --- /dev/null +++ b/tests/resources/schema/opendocument/1.0/OpenDocument-schema-v1.0-os.rng @@ -0,0 +1,17666 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + boolean + short + int + long + double + string + datetime + base64Binary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + simple + + + + + replace + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + float + + + + + + date + + + + + + time + + + + + + boolean + + + + + + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + none + + + + + condition + + + + + + + + + + + + + + + + + + + + + simple + + + + + embed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + footnote + endnote + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + previous + current + next + + + + + + + + + + + + + + previous + next + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + name + number + number-and-name + plain-number-and-name + plain-number + + + + + + + + + + + + + + + + + + + full + path + name + name-and-extension + + + + + + + + + + + + + + + + + + full + path + name + name-and-extension + area + title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:page-count + text:paragraph-count + text:word-count + text:character-count + text:table-count + text:image-count + text:object-count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + command + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + table + text-box + image + object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:reference-ref + text:bookmark-ref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + page + chapter + direction + text + + + + + + + + + page + chapter + direction + text + category-and-value + caption + value + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + unit + gap + + + + + + + + + + + + + + + + + + + + + + + + + float + + + + + + + + percentage + + + + + + + + currency + + + + + + + + + + + + + date + + + + + + + + time + + + + + + + + boolean + + + + + + + + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + none + + + + + + + + + value + formula + none + + + + + + + + + value + formula + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:identifier + text:address + text:annote + text:author + text:booktitle + text:chapter + text:edition + text:editor + text:howpublished + text:institution + text:journal + text:month + text:note + text:number + text:organizations + text:pages + text:publisher + text:school + text:series + text:title + text:report-type + text:volume + text:year + text:url + text:custom1 + text:custom2 + text:custom3 + text:custom4 + text:custom5 + text:isbn + text:issn + + + + + + + + + + article + book + booklet + conference + custom1 + custom2 + custom3 + custom4 + custom5 + email + inbook + incollection + inproceedings + journal + manual + mastersthesis + misc + phdthesis + proceedings + techreport + unpublished + www + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + category-and-value + caption + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + separator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + name + number + number-and-name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + address + annote + author + bibliography-type + booktitle + chapter + custom1 + custom2 + custom3 + custom4 + custom5 + edition + editor + howpublished + identifier + institution + isbn + issn + journal + month + note + number + organizations + pages + publisher + report-type + school + series + title + url + volume + year + + + + + + + + + + + + + + + + + + + + + + + + right + + + + left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + collapse + filter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ($?([^\. ']+|'[^']+'))?\.$?[A-Z]+$?[0-9]+ + + + + + ($?([^\. ']+|'[^']+'))?\.$?[A-Z]+$?[0-9]+(:($?([^\. ']+|'[^']+'))?\.$?[A-Z]+$?[0-9]+)? + + + + + + + + + + + + + + + + + + + copy-all + copy-results-only + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + trace-dependents + remove-dependents + trace-precedents + remove-precedents + trace-errors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from-another-table + to-another-table + from-same-table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + enable + disable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + unsorted + sort-ascending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + stop + warning + information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column + row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + + print-range + filter + repeat-row + repeat-column + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column + row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + automatic + + + + + + + + + + ascending + descending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + automatic + + + + + + + + + + ascending + descending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + self + cell-range + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + data + hidden + + + + + page + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from-top + from-bottom + + + + + + + + + + + + + + data + + + + + + + + none + manual + name + + + + + + + + ascending + descending + + + + + + + + + + + + + tabular-layout + outline-subtotals-top + outline-subtotals-bottom + + + + + + + + + + + + + + + + + + + + + + + named + + + + + + + + previous + next + + + + + + + + none + member-difference + member-percentage + member-percentage-difference + running-total + row-percentage + column-percentage + total-percentage + index + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + auto + + + + + + + + + + auto + + + + + + auto + + + + + + + + + + + + + seconds + minutes + hours + days + months + quarters + years + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + accepted + rejected + pending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + always + screen + printer + none + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + full + section + cut + arc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + lines + line + curve + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + page + frame + paragraph + char + as-char + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top-left + top + top-right + left + center + right + bottom-left + bottom-right + + + + + + + auto + left + right + up + down + horizontal + vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scale + scale-min + + + + + + + + scale + scale-min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + onRequest + + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + nohref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parallel + perspective + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + phong + gouraud + draft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + non-primitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + phong + gouraud + draft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parallel + perspective + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + segments + rectangle + + + + + + + + + + + + + + + + + + + + + normal + path + shape + + + + + + + + + path + shape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + title + outline + subtitle + text + graphic + object + chart + table + orgchart + page + notes + handout + header + footer + date-time + page-number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + fade + move + stripes + open + close + dissolve + wavyline + random + lines + laser + appear + hide + move-short + checkerboard + rotate + stretch + + + + + + + + + + + + none + from-left + from-top + from-right + from-bottom + from-center + from-upper-left + from-upper-right + from-lower-left + from-lower-right + to-left + to-top + to-right + to-bottom + to-upper-left + to-upper-right + to-lower-right + to-lower-left + path + spiral-inward-left + spiral-inward-right + spiral-outward-left + spiral-outward-right + vertical + horizontal + to-center + clockwise + counter-clockwise + + + + + + + + + + + + slow + medium + fast + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + on-click + with-previous + after-previous + timing-root + main-sequence + interactive-sequence + + + + + + + + + + + + + + + + + + + + + + + custom + entrance + exit + emphasis + motion-path + ole-action + media-call + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + previous-page + next-page + first-page + last-page + hide + stop + execute + show + verb + fade-out + sound + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + current-date + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + enabled + disabled + + + + + + + + + enabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + start + end + top + bottom + + + + + + start + center + end + + + + + + + top-start + bottom-start + top-end + bottom-end + + + + + + + + + + + + + wide + high + balanced + + + + + custom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + y + z + + + + + + + + + + + + + + + + + + + + + + + + + + + major + minor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + get + post + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + command + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + current + parent + + + + + + + + + + + + + + + + + + + records + current + page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unchecked + checked + unknown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + submit + reset + push + url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + 3d + + + + + + + + + center + + + + + + start + end + top + bottom + + + + + + start + center + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + sql + sql-pass-through + value-list + table-fields + + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + + + + + + + float + + + + + + + + + + + + percentage + + + + + + + + + + + + currency + + + + + + + + + + + + + + + + + date + + + + + + + + + + + + time + + + + + + + + + + + + boolean + + + + + + + + + + + + string + + + + + + + + + + + void + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + i + I + + + + + + + + a + A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + into-default-style-data-style + into-english-number + keep-text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + + + + + + + + + + + rgb + hsl + + + + + + + + + clockwise + counter-clockwise + + + + + + + + + + + + + + + + + + translate + scale + rotate + skewX + skewY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward + reverse + + + + + + + + + forward + reverse + + + + + + + + + in + out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + + + + + + + + + + + + + none + sum + + + + + + + + + replace + sum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first + last + all + media + + + + + + + + + + + + + + + + + + + remove + freeze + hold + auto + default + transition + + + + + + + + + remove + freeze + hold + transition + auto + inherit + + + + + + + + + never + always + whenNotActive + default + + + + + + + + + never + always + whenNotActive + inherit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + left + right + mirrored + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + ultra-condensed + extra-condensed + condensed + semi-condensed + semi-expanded + expanded + extra-expanded + ultra-expanded + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + medium + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gregorian + gengou + ROC + hanja_yoil + hanja + hijri + jewish + buddhist + + + + + + + + + text + + + + + + + + + + paragraph + + + + + + + + + + + + + section + + + + + + + + + + ruby + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + rigth + inner + outer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + page + + + + + + + + + text + page + section + document + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + address + annote + author + bibliography-type + booktitle + chapter + custom1 + custom2 + custom3 + custom4 + custom5 + edition + editor + howpublished + identifier + institution + isbn + issn + journal + month + note + number + organizations + pages + publisher + report-type + school + series + title + url + volume + year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + + + + + + + + + + table-column + + + + + + + + + + table-row + + + + + + + + + + table-cell + + + + + + + + + + + + + + + + + graphic + presentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + drawing-page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + linear + axial + radial + ellipsoid + square + rectangular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + objectBoundingBox + + + + + + + + + + + pad + reflect + repeat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + single + double + triple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rect + round + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + chart + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + + + + + + + + + + portrait + landscape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + headers + grid + annotations + objects + charts + drawings + formulas + zero-values + + + + + + + + + + + ttb + ltr + + + + + + + + + + continue + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + both + none + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + + + + + + + + + + + + + + + none + line + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + small-caps + + + + + + + none + lowercase + uppercase + capitalize + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + super + sub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + roman + swiss + modern + decorative + script + system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + variable + + + + + + + + + + + + + [A-Za-z][A-Za-z0-9._\-]* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + latin + asian + complex + ignore + + + + + + + + + + normal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + italic + oblique + + + + + + + none + embossed + engraved + + + + + + + + + + + + + + + none + + + + + + + + + + + + + + + none + single + double + + + + + + + + + + + + + none + solid + dotted + dash + long-dash + dot-dash + dot-dot-dash + wave + + + + + + + + + + + + + auto + normal + bold + thin + dash + medium + thick + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + normal + bold + 100 + 200 + 300 + 400 + 500 + 600 + 700 + 800 + 900 + + + + + + + + + + + + + continuous + skip-white-space + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + letters + lines + + + + + + + + + + + + + + + + + + + + + none + + + none + accent + dot + circle + disc + + + above + below + + + + + + + + + + + + + + + + + + + + + + + + + fixed + line-height + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + none + + + + condition + + + none + + + + + + + + + + + + + + + + + + + + + + + + normal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + start + end + left + right + center + justify + + + + + + + + + start + center + justify + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + + char + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + page + + + + + + + + + no-limit + + + + + + + + + + + + + + + + + + + + + + word + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + column + page + + + + + + + auto + column + page + + + + + + + + + + + + + transparent + + + + + + + + + + + + + + + + + + + + + + + + + + no-repeat + repeat + stretch + + + + + + + + + left + center + right + top + bottom + + + + + + + + + + + + + + + + left + center + right + + + + + top + center + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + none + ideograph-alpha + + + + + + + + + simple + hanging + + + + + + + + + normal + strict + + + + + + + + + top + middle + bottom + auto + + + + + + + + + + + + + lr-tb + rl-tb + tb-rl + tb-lr + lr + rl + tb + page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + above + below + + + + + + + + + left + center + right + distribute-letter + distribute-space + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + solid + dotted + dashed + dot-dashed + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + margins + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + collapsing + separating + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + automatic + + + + + + + + + fix + value-type + + + + + + + + + + + + + ltr + ttb + + + + + + + + + auto + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-wrap + wrap + + + + + + + + + + + + + + + + + + + + none + bottom + top + center + + + + + + + + + none + hidden-and-protected + + + + protected + formula-hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + dash + solid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + + + + + + + + + + + miter + round + bevel + middle + none + inherit + + + + + + + + + none + solid + bitmap + gradient + hatch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-repeat + repeat + stretch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top-left + top + top-right + left + center + right + bottom-left + bottom + bottom-right + + + + + + + + + + + + + + + + + + + + + + + + + + + + nonzero + evenodd + + + + + + + + + + + + + + + + none + scroll + alternate + slide + + + + + + + + + left + right + up + down + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + justify + + + + + + + + + left + center + right + justify + + + + + + + + + no-wrap + wrap + + + + + + + + + + + + + + greyscale + mono + watermark + standard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + below + above + + + + + + + + + + + + + + + + automatic + left-outside + inside + right-outside + + + + + + + automatic + above + below + center + + + + + + + + + automatic + mm + cm + m + km + pt + pc + inch + ft + mi + + + + + + + + + + + + + + + + + + + + + + + straight-line + angled-line + angled-connector-line + + + + + + + + + fixed + free + + + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + correct + attractive + + + + + + + + + + + + + + + + + + + + + + + enabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + double-sided + + + + + + + + + object + flat + sphere + + + + + + + + + normal + inverse + + + + + + + + + object + parallel + sphere + + + + + + + object + parallel + sphere + + + + + + + + + luminance + intesity + color + + + + + + + + + enabled + disabled + + + + + + + + + replace + modulate + blend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + + content + position + size + + + + + + + + + + + + left + center + right + from-left + inside + outside + from-inside + + + + + + + + + + + + + + page + page-content + page-start-margin + page-end-margin + frame + frame-content + frame-start-margin + frame-end-margin + paragraph + paragraph-content + paragraph-start-margin + paragraph-end-margin + char + + + + + + + + + + + + + top + middle + bottom + from-top + below + + + + + + + + + + + + + + + + + + page + page-content + frame + frame-content + paragraph + paragraph-content + char + line + baseline + text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + left + right + parallel + dynamic + run-through + biggest + + + + + + + + + + + + + + + + no-limit + + + + + + + + + + + + + + + + + full + outside + + + + + + + + + foreground + background + + + + + + + + + + + + + + + + clip + auto-create-new-frame + + + + + + + + + none + vertical + + + vertical + + + + + vertical + + + + + + + + + horizontal + horizontal-on-odd + horizontal-on-even + + + + + + + + + + + + + + + iterative + once-concurrent + once-successive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)(px) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + automatic + + + + named-symbol + + + + square + diamond + arrow-down + arrow-up + arrow-right + arrow-left + bow-tie + hourglass + circle + star + x + plus + asterisk + horizontal-bar + vertical-bar + + + + + + image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + cubic-spline + b-spline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cuboid + cylinder + cone + pyramid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + side-by-side + stagger-even + stagger-odd + + + + + + + + + + + + + + + none + value + percentage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + variance + standard-deviation + percentage + error-margin + constant + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + columns + rows + + + + + + + + + none + linear + logarithmic + exponential + power + + + + + + + + + manual + automatic + semi-automatic + + + + + + + + + none + fade-from-left + fade-from-top + fade-from-right + fade-from-bottom + fade-from-upperleft + fade-from-upperright + fade-from-lowerleft + fade-from-lowerright + move-from-left + move-from-top + move-from-right + move-from-bottom + move-from-upperleft + move-from-upperright + move-from-lowerleft + move-from-lowerright + uncover-to-left + uncover-to-top + uncover-to-right + uncover-to-bottom + uncover-to-upperleft + uncover-to-upperright + uncover-to-lowerleft + uncover-to-lowerright + fade-to-center + fade-from-center + vertical-stripes + horizontal-stripes + clockwise + counterclockwise + open-vertical + open-horizontal + close-vertical + close-horizontal + wavyline-from-left + wavyline-from-top + wavyline-from-right + wavyline-from-bottom + spiralin-left + spiralin-right + spiralout-left + spiralout-right + roll-from-top + roll-from-left + roll-from-right + roll-from-bottom + stretch-from-left + stretch-from-top + stretch-from-right + stretch-from-bottom + + vertical-lines + horizontal-lines + dissolve + random + vertical-checkerboard + horizontal-checkerboard + interlocking-horizontal-left + interlocking-horizontal-right + interlocking-vertical-top + interlocking-vertical-bottom + fly-away + open + close + melt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward + reverse + + + + + + + + + forward + reverse + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + full + border + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + false + + + + + + + + + + + + + + + + + [A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})* + + + + + [A-Za-z0-9]{1,8} + + + + + [A-Za-z]{1,8} + + + + + 1 + + + + + -?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + + -?([0-9]+(\.[0-9]*)?|\.[0-9]+)% + + + + + [0-9]+\* + + + + + + + + + + + #[0-9a-fA-F]{6} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _self + _blank + _parent + _top + + + + + + + float + time + date + percentage + currency + boolean + string + + + + + + -?[0-9]+,-?[0-9]+([ ]+-?[0-9]+,-?[0-9]+)* + + + + + + + + + \([ ]*-?([0-9]+(\.[0-9]*)?|\.[0-9]+)([ ]+-?([0-9]+(\.[0-9]*)?|\.[0-9]+)){2}[ ]*\) + + + + + + + [0-9a-zA-Z_]+:[0-9a-zA-Z._\-]+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.0/OpenDocument-strict-schema-v1.0-os.rng b/tests/resources/schema/opendocument/1.0/OpenDocument-strict-schema-v1.0-os.rng new file mode 100644 index 0000000000..aa761dc880 --- /dev/null +++ b/tests/resources/schema/opendocument/1.0/OpenDocument-strict-schema-v1.0-os.rng @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.1/OpenDocument-manifest-schema-v1.1.rng b/tests/resources/schema/opendocument/1.1/OpenDocument-manifest-schema-v1.1.rng new file mode 100644 index 0000000000..4082d4ba95 --- /dev/null +++ b/tests/resources/schema/opendocument/1.1/OpenDocument-manifest-schema-v1.1.rng @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.1/OpenDocument-schema-v1.1.rng b/tests/resources/schema/opendocument/1.1/OpenDocument-schema-v1.1.rng new file mode 100644 index 0000000000..3ba6a687c4 --- /dev/null +++ b/tests/resources/schema/opendocument/1.1/OpenDocument-schema-v1.1.rng @@ -0,0 +1,17891 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + boolean + short + int + long + double + string + datetime + base64Binary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + simple + + + + + replace + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + float + + + + + + date + + + + + + time + + + + + + boolean + + + + + + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + none + + + + + condition + + + + + + + + + + + + + + + + + + + + + simple + + + + + embed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + footnote + endnote + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + previous + current + next + + + + + + + + + + + + + + previous + next + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + name + number + number-and-name + plain-number-and-name + plain-number + + + + + + + + + + + + + + + + + + + full + path + name + name-and-extension + + + + + + + + + + + + + + + + + + full + path + name + name-and-extension + area + title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:page-count + text:paragraph-count + text:word-count + text:character-count + text:table-count + text:image-count + text:object-count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + command + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + table + text-box + image + object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:reference-ref + text:bookmark-ref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + page + chapter + direction + text + + + + + + + + + page + chapter + direction + text + category-and-value + caption + value + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + unit + gap + + + + + + + + + + + + + + + + + + + + + + + + + float + + + + + + + + percentage + + + + + + + + currency + + + + + + + + + + + + + date + + + + + + + + time + + + + + + + + boolean + + + + + + + + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + none + + + + + + + + + value + formula + none + + + + + + + + + value + formula + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:identifier + text:address + text:annote + text:author + text:booktitle + text:chapter + text:edition + text:editor + text:howpublished + text:institution + text:journal + text:month + text:note + text:number + text:organizations + text:pages + text:publisher + text:school + text:series + text:title + text:report-type + text:volume + text:year + text:url + text:custom1 + text:custom2 + text:custom3 + text:custom4 + text:custom5 + text:isbn + text:issn + + + + + + + + + + article + book + booklet + conference + custom1 + custom2 + custom3 + custom4 + custom5 + email + inbook + incollection + inproceedings + journal + manual + mastersthesis + misc + phdthesis + proceedings + techreport + unpublished + www + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + category-and-value + caption + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + separator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + name + number + number-and-name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + address + annote + author + bibliography-type + booktitle + chapter + custom1 + custom2 + custom3 + custom4 + custom5 + edition + editor + howpublished + identifier + institution + isbn + issn + journal + month + note + number + organizations + pages + publisher + report-type + school + series + title + url + volume + year + + + + + + + + + + + + + + + + + + + + + + + + right + + + + left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + collapse + filter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+$?[0-9]+ + + + + + + ($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+$?[0-9]+(:($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+$?[0-9]+)? + + + + + + + + + + + + + + + + + + + copy-all + copy-results-only + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + trace-dependents + remove-dependents + trace-precedents + remove-precedents + trace-errors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from-another-table + to-another-table + from-same-table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + enable + disable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + unsorted + sort-ascending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + stop + warning + information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column + row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + + print-range + filter + repeat-row + repeat-column + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column + row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + automatic + + + + + + + + + + ascending + descending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + automatic + + + + + + + + + + ascending + descending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + self + cell-range + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + data + hidden + + + + + page + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from-top + from-bottom + + + + + + + + + + + + + + data + + + + + + + + none + manual + name + + + + + + + + ascending + descending + + + + + + + + + + + + + tabular-layout + outline-subtotals-top + outline-subtotals-bottom + + + + + + + + + + + + + + + + + + + + + + + named + + + + + + + + previous + next + + + + + + + + none + member-difference + member-percentage + member-percentage-difference + running-total + row-percentage + column-percentage + total-percentage + index + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + auto + + + + + + + + + + auto + + + + + + auto + + + + + + + + + + + + + seconds + minutes + hours + days + months + quarters + years + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + accepted + rejected + pending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + always + screen + printer + none + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + full + section + cut + arc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + lines + line + curve + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + page + frame + paragraph + char + as-char + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top-left + top + top-right + left + center + right + bottom-left + bottom-right + + + + + + + + auto + left + right + up + down + horizontal + vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scale + scale-min + + + + + + + + scale + scale-min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + onRequest + + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + nohref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parallel + perspective + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + phong + gouraud + draft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + non-primitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + phong + gouraud + draft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parallel + perspective + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + segments + rectangle + + + + + + + + + + + + + + + + + + + + + normal + path + shape + + + + + + + + + path + shape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + title + outline + subtitle + text + graphic + object + chart + table + orgchart + page + notes + handout + header + footer + date-time + page-number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + fade + move + stripes + open + close + dissolve + wavyline + random + lines + laser + appear + hide + move-short + checkerboard + rotate + stretch + + + + + + + + + + + + none + from-left + from-top + from-right + from-bottom + from-center + from-upper-left + from-upper-right + from-lower-left + from-lower-right + to-left + to-top + to-right + to-bottom + to-upper-left + to-upper-right + to-lower-right + to-lower-left + path + spiral-inward-left + spiral-inward-right + spiral-outward-left + spiral-outward-right + vertical + horizontal + to-center + clockwise + counter-clockwise + + + + + + + + + + + + slow + medium + fast + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + on-click + with-previous + after-previous + timing-root + main-sequence + interactive-sequence + + + + + + + + + + + + + + + + + + + + + + + custom + entrance + exit + emphasis + motion-path + ole-action + media-call + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + previous-page + next-page + first-page + last-page + hide + stop + execute + show + verb + fade-out + sound + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + current-date + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + enabled + disabled + + + + + + + + + enabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + start + end + top + bottom + + + + + + start + center + end + + + + + + + top-start + bottom-start + top-end + bottom-end + + + + + + + + + + + + + wide + high + balanced + + + + + custom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + y + z + + + + + + + + + + + + + + + + + + + + + + + + + + + major + minor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + get + post + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + command + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + current + parent + + + + + + + + + + + + + + + + + + + records + current + page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unchecked + checked + unknown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + submit + reset + push + url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + 3d + + + + + + + + + center + + + + + + start + end + top + bottom + + + + + + start + center + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + sql + sql-pass-through + value-list + table-fields + + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + + + + + + + float + + + + + + + + + + + + percentage + + + + + + + + + + + + currency + + + + + + + + + + + + + + + + + date + + + + + + + + + + + + time + + + + + + + + + + + + boolean + + + + + + + + + + + + string + + + + + + + + + + + void + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + i + I + + + + + + + + a + A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + into-default-style-data-style + into-english-number + keep-text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + + + + + + + + + + + rgb + hsl + + + + + + + + + clockwise + counter-clockwise + + + + + + + + + + + + + + + + + + translate + scale + rotate + skewX + skewY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward + reverse + + + + + + + + + forward + reverse + + + + + + + + + in + out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + + + + + + + + + + + + + none + sum + + + + + + + + + replace + sum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first + last + all + media + + + + + + + + + + + + + + + indefinite + + + + + + + + + remove + freeze + hold + auto + default + transition + + + + + + + + + remove + freeze + hold + transition + auto + inherit + + + + + + + + + never + always + whenNotActive + default + + + + + + + + + never + always + whenNotActive + inherit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + left + right + mirrored + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + ultra-condensed + extra-condensed + condensed + semi-condensed + semi-expanded + expanded + extra-expanded + ultra-expanded + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + medium + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gregorian + gengou + ROC + hanja_yoil + hanja + hijri + jewish + buddhist + + + + + + + + + text + + + + + + + + + + paragraph + + + + + + + + + + + + + section + + + + + + + + + + ruby + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + right + inner + outer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + page + + + + + + + + + text + page + section + document + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + address + annote + author + bibliography-type + booktitle + chapter + custom1 + custom2 + custom3 + custom4 + custom5 + edition + editor + howpublished + identifier + institution + isbn + issn + journal + month + note + number + organizations + pages + publisher + report-type + school + series + title + url + volume + year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + + + + + + + + + + table-column + + + + + + + + + + table-row + + + + + + + + + + table-cell + + + + + + + + + + + + + + + + + graphic + presentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + drawing-page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + linear + axial + radial + ellipsoid + square + rectangular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + objectBoundingBox + + + + + + + + + + + pad + reflect + repeat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + single + double + triple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rect + round + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + chart + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + + + + + + + + + + portrait + landscape + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + headers + grid + annotations + objects + charts + drawings + formulas + zero-values + + + + + + + + + + + ttb + ltr + + + + + + + + + + continue + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + both + none + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + + + + + + + + + + + + + + + none + line + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + small-caps + + + + + + + none + lowercase + uppercase + capitalize + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + super + sub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + roman + swiss + modern + decorative + script + system + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + variable + + + + + + + + + + + + + + + + + + + + + + + [A-Za-z][A-Za-z0-9._\-]* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + latin + asian + complex + ignore + + + + + + + + + + normal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + italic + oblique + + + + + + + none + embossed + engraved + + + + + + + + + + + + + + + none + + + + + + + + + + + + + + + none + single + double + + + + + + + + + + + + + none + solid + dotted + dash + long-dash + dot-dash + dot-dot-dash + wave + + + + + + + + + + + + + auto + normal + bold + thin + dash + medium + thick + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + normal + bold + 100 + 200 + 300 + 400 + 500 + 600 + 700 + 800 + 900 + + + + + + + + + + + + + continuous + skip-white-space + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + letters + lines + + + + + + + + + + + + + + + + + + + + + none + + + none + accent + dot + circle + disc + + + above + below + + + + + + + + + + + + + + + + + + + + + + + + + fixed + line-height + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + none + + + + condition + + + none + + + + + + + + + + + + + + + + + + + + + + + + normal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + start + end + left + right + center + justify + + + + + + + + + start + center + justify + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + + char + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + page + + + + + + + + + no-limit + + + + + + + + + + + + + + + + + + + + + + word + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + column + page + + + + + + + auto + column + page + + + + + + + + + + + + + transparent + + + + + + + + + + + + + + + + + + + + + + + + + + no-repeat + repeat + stretch + + + + + + + + + left + center + right + top + bottom + + + + + + + + + + + + + + + + left + center + right + + + + + top + center + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + none + ideograph-alpha + + + + + + + + + simple + hanging + + + + + + + + + normal + strict + + + + + + + + + top + middle + bottom + auto + baseline + + + + + + + + + + + + + lr-tb + rl-tb + tb-rl + tb-lr + lr + rl + tb + page + + + + + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + above + below + + + + + + + + + left + center + right + distribute-letter + distribute-space + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + solid + dotted + dashed + dot-dashed + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + margins + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + collapsing + separating + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + automatic + + + + + + + + + fix + value-type + + + + + + + + + + + + + ltr + ttb + + + + + + + + + auto + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-wrap + wrap + + + + + + + + + + + + + + + + + + + + none + bottom + top + center + + + + + + + + + none + hidden-and-protected + + + + protected + formula-hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + dash + solid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + + + + + + + + + + + miter + round + bevel + middle + none + inherit + + + + + + + + + none + solid + bitmap + gradient + hatch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-repeat + repeat + stretch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top-left + top + top-right + left + center + right + bottom-left + bottom + bottom-right + + + + + + + + + + + + + + + + + + + + + + + + + + + + nonzero + evenodd + + + + + + + + + + + + + + + + none + scroll + alternate + slide + + + + + + + + + left + right + up + down + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + justify + + + + + + + + + left + center + right + justify + + + + + + + + + no-wrap + wrap + + + + + + + + + + + + + + greyscale + mono + watermark + standard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + below + above + + + + + + + + + + + + + + + + automatic + left-outside + inside + right-outside + + + + + + + automatic + above + below + center + + + + + + + + + automatic + mm + cm + m + km + pt + pc + inch + ft + mi + + + + + + + + + + + + + + + + + + + + + + + straight-line + angled-line + angled-connector-line + + + + + + + + + fixed + free + + + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + correct + attractive + + + + + + + + + + + + + + + + + + + + + + + enabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + double-sided + + + + + + + + + object + flat + sphere + + + + + + + + + normal + inverse + + + + + + + + + object + parallel + sphere + + + + + + + object + parallel + sphere + + + + + + + + + luminance + intensity + color + + + + + + + + + enabled + disabled + + + + + + + + + replace + modulate + blend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + + content + position + size + + + + + + + + + + + + left + center + right + from-left + inside + outside + from-inside + + + + + + + + + + + + + + page + page-content + page-start-margin + page-end-margin + frame + frame-content + frame-start-margin + frame-end-margin + paragraph + paragraph-content + paragraph-start-margin + paragraph-end-margin + char + + + + + + + + + + + + + top + middle + bottom + from-top + below + + + + + + + + + + + + + + + + + + page + page-content + frame + frame-content + paragraph + paragraph-content + char + line + baseline + text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + left + right + parallel + dynamic + run-through + biggest + + + + + + + + + + + + + + + + no-limit + + + + + + + + + + + + + + + + + full + outside + + + + + + + + + foreground + background + + + + + + + + + + + + + + + + clip + auto-create-new-frame + + + + + + + + + none + vertical + + + vertical + + + + + vertical + + + + + + + + + horizontal + horizontal-on-odd + horizontal-on-even + + + + + + + + + + + + + + + iterative + once-concurrent + once-successive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)(px) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + automatic + + + + named-symbol + + + + square + diamond + arrow-down + arrow-up + arrow-right + arrow-left + bow-tie + hourglass + circle + star + x + plus + asterisk + horizontal-bar + vertical-bar + + + + + + image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + cubic-spline + b-spline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cuboid + cylinder + cone + pyramid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + side-by-side + stagger-even + stagger-odd + + + + + + + + + + + + + + + none + value + percentage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + variance + standard-deviation + percentage + error-margin + constant + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + columns + rows + + + + + + + + + none + linear + logarithmic + exponential + power + + + + + + + + + manual + automatic + semi-automatic + + + + + + + + + none + fade-from-left + fade-from-top + fade-from-right + fade-from-bottom + fade-from-upperleft + fade-from-upperright + fade-from-lowerleft + fade-from-lowerright + move-from-left + move-from-top + move-from-right + move-from-bottom + move-from-upperleft + move-from-upperright + move-from-lowerleft + move-from-lowerright + uncover-to-left + uncover-to-top + uncover-to-right + uncover-to-bottom + uncover-to-upperleft + uncover-to-upperright + uncover-to-lowerleft + uncover-to-lowerright + fade-to-center + fade-from-center + vertical-stripes + horizontal-stripes + clockwise + counterclockwise + open-vertical + open-horizontal + close-vertical + close-horizontal + wavyline-from-left + wavyline-from-top + wavyline-from-right + wavyline-from-bottom + spiralin-left + spiralin-right + spiralout-left + spiralout-right + roll-from-top + roll-from-left + roll-from-right + roll-from-bottom + stretch-from-left + stretch-from-top + stretch-from-right + stretch-from-bottom + + vertical-lines + horizontal-lines + dissolve + random + vertical-checkerboard + horizontal-checkerboard + interlocking-horizontal-left + interlocking-horizontal-right + interlocking-vertical-top + interlocking-vertical-bottom + fly-away + open + close + melt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + forward + reverse + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + full + border + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + false + + + + + + + + + + + + + + + + + + + + [A-Za-z0-9]{1,8} + + + + + [A-Za-z]{1,8} + + + + + 1 + + + + + -?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + + ([0-9]*[1-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + + -?([0-9]+(\.[0-9]*)?|\.[0-9]+)% + + + + + [0-9]+\* + + + + + + + + + + + #[0-9a-fA-F]{6} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _self + _blank + _parent + _top + + + + + + + float + time + date + percentage + currency + boolean + string + + + + + + -?[0-9]+,-?[0-9]+([ ]+-?[0-9]+,-?[0-9]+)* + + + + + + + + + \([ ]*-?([0-9]+(\.[0-9]*)?|\.[0-9]+)([ ]+-?([0-9]+(\.[0-9]*)?|\.[0-9]+)){2}[ ]*\) + + + + + + + [0-9a-zA-Z_]+:[0-9a-zA-Z._\-]+ + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.1/OpenDocument-strict-schema-v1.1.rng b/tests/resources/schema/opendocument/1.1/OpenDocument-strict-schema-v1.1.rng new file mode 100644 index 0000000000..e77fe4ba6e --- /dev/null +++ b/tests/resources/schema/opendocument/1.1/OpenDocument-strict-schema-v1.1.rng @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-dsig-schema.rng b/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-dsig-schema.rng new file mode 100644 index 0000000000..baab69981e --- /dev/null +++ b/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-dsig-schema.rng @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-manifest-schema.rng b/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-manifest-schema.rng new file mode 100644 index 0000000000..af13a26c71 --- /dev/null +++ b/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-manifest-schema.rng @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + edit + presentation-slide-show + read-only + + + + + + + + + + + + + + + + + + + + + + + + + + + SHA1/1K + + + + + + + + + + + + + + + + + + + Blowfish CFB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PBKDF2 + + + + + + + + + + + + + + + + + + + + + + + + + + + SHA1 + + + + + + + + + + + + + + + + [^:]+:[^:]+ + + + + + + + + + + + + diff --git a/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-schema.rng b/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-schema.rng new file mode 100644 index 0000000000..538c335b3b --- /dev/null +++ b/tests/resources/schema/opendocument/1.2/OpenDocument-v1.2-os-schema.rng @@ -0,0 +1,18127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + boolean + short + int + long + double + string + datetime + base64Binary + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + + + + + + + simple + + + + + + + replace + + + + + onLoad + + + + + + + + + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + float + + + + + + date + + + + + + time + + + + + + boolean + + + + + + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + none + + + + + condition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:page-count + text:paragraph-count + text:word-count + text:character-count + text:table-count + text:image-count + text:object-count + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:reference-ref + text:bookmark-ref + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + unit + gap + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:identifier + text:address + text:annote + text:author + text:booktitle + text:chapter + text:edition + text:editor + text:howpublished + text:institution + text:journal + text:month + text:note + text:number + text:organizations + text:pages + text:publisher + text:school + text:series + text:title + text:report-type + text:volume + text:year + text:url + text:custom1 + text:custom2 + text:custom3 + text:custom4 + text:custom5 + text:isbn + text:issn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + footnote + endnote + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + previous + current + next + + + + + + + + + + previous + next + + + + + + + + + + + + + + name + number + number-and-name + plain-number-and-name + plain-number + + + + + + + + + + + + + full + path + name + name-and-extension + + + + + + + + + + + full + path + name + name-and-extension + area + title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + command + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + table + text-box + image + object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + number-no-superior + number-all-superior + number + + + + + + + + + + + + + + + + + + + + + + category-and-value + caption + value + + + + + + + page + chapter + direction + text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + float + + + + + + + + percentage + + + + + + + + currency + + + + + + + + + + + + + date + + + + + + + + time + + + + + + + + boolean + + + + + + + + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + value + none + + + + + + + + + value + formula + none + + + + + + + + + value + formula + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + article + book + booklet + conference + custom1 + custom2 + custom3 + custom4 + custom5 + email + inbook + incollection + inproceedings + journal + manual + mastersthesis + misc + phdthesis + proceedings + techreport + unpublished + www + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + category-and-value + caption + + + + + + + + + + document + chapter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 2 + 3 + separator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + name + number + number-and-name + plain-number + plain-number-and-name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + address + annote + author + bibliography-type + booktitle + chapter + custom1 + custom2 + custom3 + custom4 + custom5 + edition + editor + howpublished + identifier + institution + isbn + issn + journal + month + note + number + organizations + pages + publisher + report-type + school + series + title + url + volume + year + + + + + + + + + + + + + + + + + + + + + + + + right + + + + left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + collapse + filter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+$?[0-9]+ + + + + + + ($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+$?[0-9]+(:($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+$?[0-9]+)? + + + ($?([^\. ']+|'([^']|'')+'))?\.$?[0-9]+:($?([^\. ']+|'([^']|'')+'))?\.$?[0-9]+ + + + ($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+:($?([^\. ']+|'([^']|'')+'))?\.$?[A-Z]+ + + + + + + Value is a space separated list of "cellRangeAddress" patterns + + + + + + + + + + + + + + copy-all + copy-results-only + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + trace-dependents + remove-dependents + trace-precedents + remove-precedents + trace-errors + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from-another-table + to-another-table + from-same-table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + date + + + + + + + + + + + + + + + + enable + disable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + unsorted + sort-ascending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + stop + warning + information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column + row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + + print-range + filter + repeat-row + repeat-column + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + column + row + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alpha-numeric + integer + double + + + + + + + + + + + + + + + + + + + + text + number + automatic + + + + + + + + ascending + descending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + automatic + + + + + + + + ascending + descending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + self + cell-range + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + number + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + data + hidden + + + + + page + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + from-top + from-bottom + + + + + + + + + + + + + + + + data + + + + + + + + none + manual + name + + + + + + ascending + descending + + + + + + + + + + + + + + + tabular-layout + outline-subtotals-top + outline-subtotals-bottom + + + + + + + + + + + + + + + + + + + + + named + + + + + + + + previous + next + + + + + + none + member-difference + member-percentage + member-percentage-difference + running-total + row-percentage + column-percentage + total-percentage + index + + + + + + + + + + + + + + + + + + + + + + auto + + + + + + auto + + + + + + + + auto + + + + + + auto + + + + + + + + + seconds + minutes + hours + days + months + quarters + years + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + average + count + countnums + max + min + product + stdev + stdevp + sum + var + varp + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + table + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + accepted + rejected + pending + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + always + screen + printer + none + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + full + section + cut + arc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + standard + lines + line + curve + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + page + frame + paragraph + char + as-char + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top-left + top + top-right + left + center + right + bottom-left + bottom-right + + + + + + auto + left + right + up + down + horizontal + vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + scale + scale-min + + + + + + + + scale + scale-min + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + new + replace + + + + + + + + + + + + nohref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parallel + perspective + + + + + + + + + + + + + + + + + + + + + + flat + phong + gouraud + draft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + phong + gouraud + draft + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parallel + perspective + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + segments + rectangle + + + + + + + + + + + + + + + + + normal + path + shape + + + + + + + path + shape + + + + + + + + + + + + + + + + + + non-primitive + + + + + + \([ ]*-?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc))([ ]+-?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc))){2}[ ]*\) + + + + + -0.5 + 0.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + title + outline + subtitle + text + graphic + object + chart + table + orgchart + page + notes + handout + header + footer + date-time + page-number + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + new + replace + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + fade + move + stripes + open + close + dissolve + wavyline + random + lines + laser + appear + hide + move-short + checkerboard + rotate + stretch + + + + + none + from-left + from-top + from-right + from-bottom + from-center + from-upper-left + from-upper-right + from-lower-left + from-lower-right + to-left + to-top + to-right + to-bottom + to-upper-left + to-upper-right + to-lower-right + to-lower-left + path + spiral-inward-left + spiral-inward-right + spiral-outward-left + spiral-outward-right + vertical + horizontal + to-center + clockwise + counter-clockwise + + + + + slow + medium + fast + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + on-click + with-previous + after-previous + timing-root + main-sequence + interactive-sequence + + + + + + + + + + + + + + + + + custom + entrance + exit + emphasis + motion-path + ole-action + media-call + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + previous-page + next-page + first-page + last-page + hide + stop + execute + show + verb + fade-out + sound + last-visited-page + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed + current-date + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + enabled + disabled + + + + + + + enabled + disabled + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + start + end + top + bottom + + + + + + start + center + end + + + + + + + top-start + bottom-start + top-end + bottom-end + + + + + + + + + wide + high + balanced + + + + + custom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + row + column + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + y + z + + + + + + + + + + + + + + + + + + + + + + major + minor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + none + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + equal-integer + is-boolean + equal-boolean + equal-use-only-zero + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + boolean + short + int + long + double + string + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + none + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-nulls + nullable + + + + + + + + + + + + + + + + + + + + bit + boolean + tinyint + smallint + integer + bigint + float + real + double + numeric + decimal + char + varchar + longvarchar + date + time + timestmp + binary + varbinary + longvarbinary + sqlnull + other + object + distinct + struct + array + blob + clob + ref + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + primary + unique + foreign + + + + + + + + + + + + + cascade + restrict + set-null + no-action + set-default + + + + + + + + cascade + restrict + set-null + no-action + set-default + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + + get + post + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + command + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + current + parent + + + + + records + current + page + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + selection + selection-indices + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + unchecked + checked + unknown + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + horizontal + vertical + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + submit + reset + push + url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + flat + 3d + + + + + + + + + center + + + + + + start + end + top + bottom + + + + + + start + center + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + table + query + sql + sql-pass-through + value-list + table-fields + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + float + + + + + + + + + + + + percentage + + + + + + + + + + + + currency + + + + + + + + + + + + + + + + + date + + + + + + + + + + + + time + + + + + + + + + + + + boolean + + + + + + + + + + + + string + + + + + + + + + + + void + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + i + I + + + + + + + + a + A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + + + To avoid inclusion of the complete MathML schema, anything is allowed within a math:math top-level element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + into-default-style-data-style + into-english-number + keep-text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + rgb + hsl + + + + + + + clockwise + counter-clockwise + + + + + + + + + translate + scale + rotate + skewX + skewY + + + + + + + + + + + + + + + + + forward + reverse + + + + + + + + + + + + in + out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + discrete + linear + paced + spline + + + + + + + + + + + + + + + + + + + + + + + + none + sum + + + + + + + replace + sum + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + first + last + all + media + + + + + + + + + + + + + + + + indefinite + + + + + + + 0.0 + + + + + + + remove + freeze + hold + auto + default + transition + + + + + + + + + remove + freeze + hold + transition + auto + inherit + + + + + + + + + never + always + whenNotActive + default + + + + + + + + + never + always + whenNotActive + inherit + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + left + right + mirrored + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + row + column + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + normal + ultra-condensed + extra-condensed + condensed + semi-condensed + semi-expanded + expanded + extra-expanded + ultra-expanded + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + onRequest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + short + long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + short + medium + long + + + + + + + + + + + + + + + + + fixed + language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gregorian + gengou + ROC + hanja_yoil + hanja + hijri + jewish + buddhist + + + + + + + + + + text + + + + + + + + paragraph + + + + + + + + + + + section + + + + + + + + ruby + + + + + + + + table + + + + + + + + table-column + + + + + + + + table-row + + + + + + + + table-cell + + + + + + + + + + + + + + + graphic + presentation + + + + + + + + + + + + + + + drawing-page + + + + + + + + chart + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + right + inner + outer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + document + chapter + page + + + + + + + text + page + section + document + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + address + annote + author + bibliography-type + booktitle + chapter + custom1 + custom2 + custom3 + custom4 + custom5 + edition + editor + howpublished + identifier + institution + isbn + issn + journal + month + note + number + organizations + pages + publisher + report-type + school + series + title + url + volume + year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + linear + axial + radial + ellipsoid + square + rectangular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + objectBoundingBox + + + + + + + + + + + pad + reflect + repeat + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + single + double + triple + + + + + + + + + + + + + + + + + + + + + + + + simple + + + + + + + embed + + + + + onLoad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + rect + round + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default + + + + + + + + portrait + landscape + + + + + + + + + + + + + + + + + + + + + + headers + grid + annotations + objects + charts + drawings + formulas + zero-values + + + + + + + + + ttb + ltr + + + + + + + + continue + + + + + + + + + + + + + + + + + horizontal + vertical + both + none + + + + + + + + + + + + + none + line + both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + lowercase + uppercase + capitalize + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + super + sub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + latin + asian + complex + ignore + + + + + + + + normal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + embossed + engraved + + + + + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + letters + lines + + + + + + + + + + + + + + + + + none + + + none + accent + dot + circle + disc + + + above + below + + + + + + + + + + + + + + + + + + + fixed + line-height + + + + + + + + + + + + + + + + + + + + + true + + + none + + + + condition + + + none + + + + + + + + + normal + small-caps + + + + + roman + swiss + modern + decorative + script + system + + + + + fixed + variable + + + + + [A-Za-z][A-Za-z0-9._\-]* + + + + + normal + italic + oblique + + + + + none + + + + + + none + single + double + + + + + none + solid + dotted + dash + long-dash + dot-dash + dot-dot-dash + wave + + + + + auto + normal + bold + thin + medium + thick + + + + + + + + normal + bold + 100 + 200 + 300 + 400 + 500 + 600 + 700 + 800 + 900 + + + + + continuous + skip-white-space + + + + + + + + + + + + + + + + + normal + + + + + + + + + + + + + + + + + + + + + + + + + start + center + justify + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + auto + page + + + + + + + no-limit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + ideograph-alpha + + + + + + + simple + hanging + + + + + + + normal + strict + + + + + + + top + middle + bottom + auto + baseline + + + + + + + + + + + + + + + + + + + + + + + start + end + left + right + center + justify + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + + char + + + + + + + + + + + + + + + + + + + + + + + font-color + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + word + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + column + page + + + + + + + auto + column + page + + + + + + + + + transparent + + + + + + + + + + + + + + + + + + + + + + + no-repeat + repeat + stretch + + + + + + + left + center + right + top + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + + + + + top + center + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + always + + + + + + + + + lr-tb + rl-tb + tb-rl + tb-lr + lr + rl + tb + page + + + + + + + + + + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + above + below + + + + + + + left + center + right + distribute-letter + distribute-space + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + solid + dotted + dashed + dot-dashed + + + + + + + + + + + + + + + top + middle + bottom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + left + center + right + margins + + + + + + + + + + + + + + + + + + + + collapsing + separating + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + auto + always + + + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + automatic + + + + + + + fix + value-type + + + + + + + + auto + 0 + 0deg + 0rad + 0grad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-wrap + wrap + + + + + + + + none + bottom + top + center + + + + + + + none + hidden-and-protected + + + + protected + formula-hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ltr + ttb + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + label-width-and-position + label-alignment + + + + + + + + + + + + + + + + + + + + + listtab + space + nothing + + + + + + + + + + + + + + + + + + + + + + + + + none + dash + solid + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + + + + + + + + + miter + round + bevel + middle + none + + + + + + + butt + square + round + + + + + + + + + + + + none + scroll + alternate + slide + + + + + + + left + right + up + down + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top + middle + bottom + justify + + + + + + + left + center + right + justify + + + + + + + no-wrap + wrap + + + + + + + + + + + + greyscale + mono + watermark + standard + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + below + above + + + + + + + + + + + + automatic + left-outside + inside + right-outside + + + + + + + automatic + above + below + center + + + + + + + automatic + mm + cm + m + km + pt + pc + inch + ft + mi + + + + + + + + + + + + + + + + + straight-line + angled-line + angled-connector-line + + + + + + + fixed + free + + + + + + + + + + + + + + + + + horizontal + vertical + auto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + correct + attractive + + + + + + + + + + + + + + + + + enabled + disabled + + + + + + + + + + + + + + + + + + + + + + standard + double-sided + + + + + + + object + flat + sphere + + + + + + + normal + inverse + + + + + + + object + parallel + sphere + + + + + + + object + parallel + sphere + + + + + + + luminance + intensity + color + + + + + + + enabled + disabled + + + + + + + replace + modulate + blend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + + content + position + size + + + + + + + + + + left + center + right + from-left + inside + outside + from-inside + + + + + + + + + + + + page + page-content + page-start-margin + page-end-margin + frame + frame-content + frame-start-margin + frame-end-margin + paragraph + paragraph-content + paragraph-start-margin + paragraph-end-margin + char + + + + + + + + + + + + + + + + + none + left + right + parallel + dynamic + run-through + biggest + + + + + + + + + + + + no-limit + + + + + + + + + + + + + full + outside + + + + + + + foreground + background + + + + + + + + + + + + clip + auto-create-new-frame + + + + + + + none + vertical + + + vertical + + + + + vertical + + + + + + + + auto + + + + + + + + iterative + once-concurrent + once-successive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + content + thumbnail + icon + print-view + + + + + + + + + + + + + + + + none + solid + bitmap + gradient + hatch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + no-repeat + repeat + stretch + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + top-left + top + top-right + left + center + right + bottom-left + bottom + bottom-right + + + + + + + + + horizontal + vertical + + + + + + + + + + + + + + + + + + nonzero + evenodd + + + + + + + + + + + + + + + + + + + top + middle + bottom + from-top + below + + + + + + + + + + + + + + page + page-content + frame + frame-content + paragraph + paragraph-content + char + line + baseline + text + + + + + + + + + + + + + + horizontal + horizontal-on-odd + horizontal-on-even + + + + + rect\([ ]*((-?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)))|(auto))([ ]*,[ ]*((-?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc))))|(auto)){3}[ ]*\) + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)(px) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + + + automatic + + + + named-symbol + + + + square + diamond + arrow-down + arrow-up + arrow-right + arrow-left + bow-tie + hourglass + circle + star + x + plus + asterisk + horizontal-bar + vertical-bar + + + + + + image + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + cubic-spline + b-spline + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cuboid + cylinder + cone + pyramid + + + + + + + + + + + + + + + + + use-zero + leave-gap + ignore + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + side-by-side + stagger-even + stagger-odd + + + + + + + + + none + value + percentage + value-and-percentage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + none + variance + standard-deviation + percentage + error-margin + constant + standard-error + cell-range + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + columns + rows + + + + + + + none + linear + logarithmic + exponential + power + + + + + + + start + end + + + + + + + + near-axis + near-axis-other-side + outside-start + outside-end + + + + + + + at-labels + at-axis + at-labels-and-axis + + + + + + + + + + + + + avoid-overlap + center + top + top-right + right + bottom-right + bottom + bottom-left + left + top-left + inside + outside + near-origin + + + + + + + + manual + automatic + semi-automatic + + + + + + + none + fade-from-left + fade-from-top + fade-from-right + fade-from-bottom + fade-from-upperleft + fade-from-upperright + fade-from-lowerleft + fade-from-lowerright + move-from-left + move-from-top + move-from-right + move-from-bottom + move-from-upperleft + move-from-upperright + move-from-lowerleft + move-from-lowerright + uncover-to-left + uncover-to-top + uncover-to-right + uncover-to-bottom + uncover-to-upperleft + uncover-to-upperright + uncover-to-lowerleft + uncover-to-lowerright + fade-to-center + fade-from-center + vertical-stripes + horizontal-stripes + clockwise + counterclockwise + open-vertical + open-horizontal + close-vertical + close-horizontal + wavyline-from-left + wavyline-from-top + wavyline-from-right + wavyline-from-bottom + spiralin-left + spiralin-right + spiralout-left + spiralout-right + roll-from-top + roll-from-left + roll-from-right + roll-from-bottom + stretch-from-left + stretch-from-top + stretch-from-right + stretch-from-bottom + vertical-lines + horizontal-lines + dissolve + random + vertical-checkerboard + horizontal-checkerboard + interlocking-horizontal-left + interlocking-horizontal-right + interlocking-vertical-top + interlocking-vertical-bottom + fly-away + open + close + melt + + + + + + + + + + + + + + + + + + + + + + forward + reverse + + + + + + + + + + + + + + + + + visible + hidden + + + + + + + full + border + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + false + + + + + + + + + + + + + + + + + + + + [A-Za-z0-9]{1,8} + + + + + [A-Za-z]{1,8} + + + + + [A-Za-z0-9]{1,8} + + + + + 1 + + + + + -?([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + ([0-9]+(\.[0-9]*)?|\.[0-9]+)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + ([0-9]*[1-9][0-9]*(\.[0-9]*)?|0+\.[0-9]*[1-9][0-9]*|\.[0-9]*[1-9][0-9]*)((cm)|(mm)|(in)|(pt)|(pc)|(px)) + + + + + -?([0-9]+(\.[0-9]*)?|\.[0-9]+)% + + + + + ([0-9]?[0-9](\.[0-9]*)?|100(\.0*)?|\.[0-9]+)% + + + + + -?([0-9]?[0-9](\.[0-9]*)?|100(\.0*)?|\.[0-9]+)% + + + + + [0-9]+\* + + + + + + + + + + + #[0-9a-fA-F]{6} + + + + + + + + (([\i-[:]][\c-[:]]*)?:)?.+ + 1 + + + + + + + + + + + + \[(([\i-[:]][\c-[:]]*)?:)?.+\] + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _self + _blank + _parent + _top + + + + + + float + time + date + percentage + currency + boolean + string + + + + + -?[0-9]+,-?[0-9]+([ ]+-?[0-9]+,-?[0-9]+)* + + + + + + + + \([ ]*-?([0-9]+(\.[0-9]*)?|\.[0-9]+)([ ]+-?([0-9]+(\.[0-9]*)?|\.[0-9]+)){2}[ ]*\) + + + + + [^:]+:[^:]+ + + + + + An IRI-reference as defined in [RFC3987]. See ODF 1.2 Part 1 section 18.3. + + + + + + + + + + + + + + + + + + + + +