From dcc4fc562fee6c1cdee4dfbedf0d9a9af621f7f0 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 17 Aug 2026 11:57:41 +0200 Subject: [PATCH 1/5] Take the store screenshots during the release, and upload them The store copy beside these is written, so it lives in git and the release uploads what is committed. A screenshot is not written, it is taken: it is worth what the build it came off is worth. So these are taken during the release run, from the build going out, framed there, and handed to deliver from there. Nothing is committed. Six pictures per device - the folder, a text document, a spreadsheet, an edit under way, a pdf and a Word file - on a 6.9" iPhone and a 13" iPad, in the nine languages the app speaks. The app takes -ODRScreenshot in Debug builds and puts itself on the screen asked for, so nothing has to be tapped through Apple's document browser in eleven languages. The documents in them are written here too, in every language, and so is the framing: a coloured ground, a phone drawn to the dimensions Apple publishes for it, and a line of copy. Nothing comes from an image file except the font. One fix rode along, and it is not about screenshots: a pdf or a Word document opened part way down its own first page on a wide screen, with the heading cut off. The viewport was named before the web view had the width it would keep. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E6tn8P25cBDmrA67zrhfwN --- .gitattributes | 4 + .github/workflows/build_test.yml | 10 + .github/workflows/release.yml | 65 +- .gitignore | 2 + CHANGELOG.md | 11 +- OpenDocumentReader.xcodeproj/project.pbxproj | 117 ++ .../xcschemes/ODR Screenshots.xcscheme | 76 + OpenDocumentReader/AppDelegate.swift | 4 + .../DocumentBrowserViewController.swift | 52 + .../DocumentViewController.swift | 73 +- .../Samples/sample-cells-de.xlsx | Bin 0 -> 1874 bytes .../Samples/sample-cells-en.xlsx | Bin 0 -> 1867 bytes .../Samples/sample-cells-es.xlsx | Bin 0 -> 1874 bytes .../Samples/sample-cells-fr.xlsx | Bin 0 -> 1885 bytes .../Samples/sample-cells-it.xlsx | Bin 0 -> 1869 bytes .../Samples/sample-cells-pl.xlsx | Bin 0 -> 1898 bytes .../Samples/sample-cells-pt-BR.xlsx | Bin 0 -> 1885 bytes .../Samples/sample-cells-ru.xlsx | Bin 0 -> 1968 bytes .../Samples/sample-cells-tr.xlsx | Bin 0 -> 1898 bytes .../Samples/sample-deck-de.pptx | Bin 0 -> 1877 bytes .../Samples/sample-deck-en.pptx | Bin 0 -> 1860 bytes .../Samples/sample-deck-es.pptx | Bin 0 -> 1873 bytes .../Samples/sample-deck-fr.pptx | Bin 0 -> 1875 bytes .../Samples/sample-deck-it.pptx | Bin 0 -> 1864 bytes .../Samples/sample-deck-pl.pptx | Bin 0 -> 1868 bytes .../Samples/sample-deck-pt-BR.pptx | Bin 0 -> 1871 bytes .../Samples/sample-deck-ru.pptx | Bin 0 -> 1929 bytes .../Samples/sample-deck-tr.pptx | Bin 0 -> 1878 bytes .../Samples/sample-notes-de.txt | 72 + .../Samples/sample-notes-en.txt | 72 + .../Samples/sample-notes-es.txt | 72 + .../Samples/sample-notes-fr.txt | 72 + .../Samples/sample-notes-it.txt | 72 + .../Samples/sample-notes-pl.txt | 72 + .../Samples/sample-notes-pt-BR.txt | 72 + .../Samples/sample-notes-ru.txt | 72 + .../Samples/sample-notes-tr.txt | 72 + .../Samples/sample-paper-de.pdf | Bin 0 -> 4853 bytes .../Samples/sample-paper-en.pdf | Bin 0 -> 4806 bytes .../Samples/sample-paper-es.pdf | Bin 0 -> 4835 bytes .../Samples/sample-paper-fr.pdf | Bin 0 -> 4826 bytes .../Samples/sample-paper-it.pdf | Bin 0 -> 4836 bytes .../Samples/sample-paper-pl.pdf | Bin 0 -> 4806 bytes .../Samples/sample-paper-pt-BR.pdf | Bin 0 -> 4831 bytes .../Samples/sample-paper-ru.pdf | Bin 0 -> 4806 bytes .../Samples/sample-paper-tr.pdf | Bin 0 -> 4806 bytes OpenDocumentReader/Samples/sample-rows-de.csv | 7 + OpenDocumentReader/Samples/sample-rows-en.csv | 7 + OpenDocumentReader/Samples/sample-rows-es.csv | 7 + OpenDocumentReader/Samples/sample-rows-fr.csv | 7 + OpenDocumentReader/Samples/sample-rows-it.csv | 7 + OpenDocumentReader/Samples/sample-rows-pl.csv | 7 + .../Samples/sample-rows-pt-BR.csv | 7 + OpenDocumentReader/Samples/sample-rows-ru.csv | 7 + OpenDocumentReader/Samples/sample-rows-tr.csv | 7 + .../Samples/sample-sheet-de.ods | Bin 0 -> 2493 bytes .../Samples/sample-sheet-en.ods | Bin 0 -> 3669 bytes .../Samples/sample-sheet-es.ods | Bin 0 -> 2499 bytes .../Samples/sample-sheet-fr.ods | Bin 0 -> 2510 bytes .../Samples/sample-sheet-it.ods | Bin 0 -> 2483 bytes .../Samples/sample-sheet-pl.ods | Bin 0 -> 2514 bytes .../Samples/sample-sheet-pt-BR.ods | Bin 0 -> 2509 bytes .../Samples/sample-sheet-ru.ods | Bin 0 -> 2635 bytes .../Samples/sample-sheet-tr.ods | Bin 0 -> 2511 bytes .../Samples/sample-slides-de.odp | Bin 0 -> 1633 bytes .../Samples/sample-slides-en.odp | Bin 0 -> 1622 bytes .../Samples/sample-slides-es.odp | Bin 0 -> 1636 bytes .../Samples/sample-slides-fr.odp | Bin 0 -> 1650 bytes .../Samples/sample-slides-it.odp | Bin 0 -> 1630 bytes .../Samples/sample-slides-pl.odp | Bin 0 -> 1659 bytes .../Samples/sample-slides-pt-BR.odp | Bin 0 -> 1639 bytes .../Samples/sample-slides-ru.odp | Bin 0 -> 1743 bytes .../Samples/sample-slides-tr.odp | Bin 0 -> 1649 bytes OpenDocumentReader/Samples/sample-text-de.odt | Bin 0 -> 2136 bytes OpenDocumentReader/Samples/sample-text-en.odt | Bin 0 -> 2033 bytes OpenDocumentReader/Samples/sample-text-es.odt | Bin 0 -> 2097 bytes OpenDocumentReader/Samples/sample-text-fr.odt | Bin 0 -> 2134 bytes OpenDocumentReader/Samples/sample-text-it.odt | Bin 0 -> 2089 bytes OpenDocumentReader/Samples/sample-text-pl.odt | Bin 0 -> 2195 bytes .../Samples/sample-text-pt-BR.odt | Bin 0 -> 2102 bytes OpenDocumentReader/Samples/sample-text-ru.odt | Bin 0 -> 2401 bytes OpenDocumentReader/Samples/sample-text-tr.odt | Bin 0 -> 2092 bytes .../Samples/sample-word-de.docx | Bin 0 -> 2353 bytes .../Samples/sample-word-en.docx | Bin 0 -> 2258 bytes .../Samples/sample-word-es.docx | Bin 0 -> 2315 bytes .../Samples/sample-word-fr.docx | Bin 0 -> 2324 bytes .../Samples/sample-word-it.docx | Bin 0 -> 2302 bytes .../Samples/sample-word-pl.docx | Bin 0 -> 2391 bytes .../Samples/sample-word-pt-BR.docx | Bin 0 -> 2303 bytes .../Samples/sample-word-ru.docx | Bin 0 -> 2573 bytes .../Samples/sample-word-tr.docx | Bin 0 -> 2335 bytes .../Samples/screenshot-names.json | 290 +++ OpenDocumentReader/ScreenshotMode.swift | 243 +++ .../ScreenshotTests.swift | 132 ++ .../SnapshotHelper.swift | 320 ++++ README.md | 36 +- fastlane/Fastfile | 145 +- fastlane/README.md | 8 + fastlane/frames/Nunito[wght].ttf | Bin 0 -> 276932 bytes fastlane/frames/OFL.txt | 93 + fastlane/frames/frames.json | 359 ++++ fastlane/screenshots/README.md | 58 + fastlane/screenshots/README.txt | 7 - scripts/format.sh | 8 +- scripts/frame-screenshots.py | 691 ++++++++ scripts/make-screenshot-documents.py | 1559 +++++++++++++++++ scripts/store-screenshots.py | 246 +++ 107 files changed, 5296 insertions(+), 24 deletions(-) create mode 100644 .gitattributes create mode 100644 OpenDocumentReader.xcodeproj/xcshareddata/xcschemes/ODR Screenshots.xcscheme create mode 100644 OpenDocumentReader/Samples/sample-cells-de.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-en.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-es.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-fr.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-it.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-pl.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-pt-BR.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-ru.xlsx create mode 100644 OpenDocumentReader/Samples/sample-cells-tr.xlsx create mode 100644 OpenDocumentReader/Samples/sample-deck-de.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-en.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-es.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-fr.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-it.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-pl.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-pt-BR.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-ru.pptx create mode 100644 OpenDocumentReader/Samples/sample-deck-tr.pptx create mode 100644 OpenDocumentReader/Samples/sample-notes-de.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-en.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-es.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-fr.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-it.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-pl.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-pt-BR.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-ru.txt create mode 100644 OpenDocumentReader/Samples/sample-notes-tr.txt create mode 100644 OpenDocumentReader/Samples/sample-paper-de.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-en.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-es.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-fr.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-it.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-pl.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-pt-BR.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-ru.pdf create mode 100644 OpenDocumentReader/Samples/sample-paper-tr.pdf create mode 100644 OpenDocumentReader/Samples/sample-rows-de.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-en.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-es.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-fr.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-it.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-pl.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-pt-BR.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-ru.csv create mode 100644 OpenDocumentReader/Samples/sample-rows-tr.csv create mode 100644 OpenDocumentReader/Samples/sample-sheet-de.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-en.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-es.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-fr.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-it.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-pl.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-pt-BR.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-ru.ods create mode 100644 OpenDocumentReader/Samples/sample-sheet-tr.ods create mode 100644 OpenDocumentReader/Samples/sample-slides-de.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-en.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-es.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-fr.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-it.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-pl.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-pt-BR.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-ru.odp create mode 100644 OpenDocumentReader/Samples/sample-slides-tr.odp create mode 100644 OpenDocumentReader/Samples/sample-text-de.odt create mode 100644 OpenDocumentReader/Samples/sample-text-en.odt create mode 100644 OpenDocumentReader/Samples/sample-text-es.odt create mode 100644 OpenDocumentReader/Samples/sample-text-fr.odt create mode 100644 OpenDocumentReader/Samples/sample-text-it.odt create mode 100644 OpenDocumentReader/Samples/sample-text-pl.odt create mode 100644 OpenDocumentReader/Samples/sample-text-pt-BR.odt create mode 100644 OpenDocumentReader/Samples/sample-text-ru.odt create mode 100644 OpenDocumentReader/Samples/sample-text-tr.odt create mode 100644 OpenDocumentReader/Samples/sample-word-de.docx create mode 100644 OpenDocumentReader/Samples/sample-word-en.docx create mode 100644 OpenDocumentReader/Samples/sample-word-es.docx create mode 100644 OpenDocumentReader/Samples/sample-word-fr.docx create mode 100644 OpenDocumentReader/Samples/sample-word-it.docx create mode 100644 OpenDocumentReader/Samples/sample-word-pl.docx create mode 100644 OpenDocumentReader/Samples/sample-word-pt-BR.docx create mode 100644 OpenDocumentReader/Samples/sample-word-ru.docx create mode 100644 OpenDocumentReader/Samples/sample-word-tr.docx create mode 100644 OpenDocumentReader/Samples/screenshot-names.json create mode 100644 OpenDocumentReader/ScreenshotMode.swift create mode 100644 OpenDocumentReaderUITests/ScreenshotTests.swift create mode 100644 OpenDocumentReaderUITests/SnapshotHelper.swift create mode 100644 fastlane/frames/Nunito[wght].ttf create mode 100644 fastlane/frames/OFL.txt create mode 100644 fastlane/frames/frames.json create mode 100644 fastlane/screenshots/README.md delete mode 100644 fastlane/screenshots/README.txt create mode 100755 scripts/frame-screenshots.py create mode 100755 scripts/make-screenshot-documents.py create mode 100755 scripts/store-screenshots.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dbd6575 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# The sample pdfs are written with uncompressed content streams, so git reads +# them as text and puts a hundred and thirty lines of placed words in the diff +# for each one. They are generated files; nobody reads them as a diff. +*.pdf binary diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index 36f3ea5..d7a327f 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -45,6 +45,16 @@ jobs: - name: run tests run: bundle exec fastlane tests + # taking the pictures is a quarter hour of simulators and belongs to the + # release, but a screenshot target that no longer compiles should not wait + # for one to say so + - name: build the screenshot tests + run: > + xcodebuild build-for-testing + -project OpenDocumentReader.xcodeproj + -scheme "ODR Screenshots" + -destination 'generic/platform=iOS Simulator' + - uses: actions/upload-artifact@v7 if: always() with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e6ee562..98770f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -181,6 +181,62 @@ jobs: build/*.app.dSYM.zip if-no-files-found: warn + # Beside the build rather than behind it: it signs nothing and uploads nothing, + # it just drives simulators, and it takes about as long. On a dry run too - + # the artifact is the only way to look at the pictures before the store does. + screenshots: + runs-on: macos-26 + steps: + - name: checkout + uses: actions/checkout@v7 + + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ env.xcode_version }} + + # the framing draws with Pillow, which is the one thing the scripts here + # want that is not in the standard library + - uses: actions/setup-python@v6 + with: + python-version: "3.13" + - run: python3 -m pip install --quiet Pillow + + # the lane checks the set it produced, so a language that came out short + # fails here rather than half way up to App Store Connect + - name: photograph both devices in every locale + run: bundle exec fastlane ios screenshots + + # what the store is given + - name: archive the framed screenshots + uses: actions/upload-artifact@v7 + with: + name: framed + path: fastlane/framed + if-no-files-found: error + # png, so there is nothing left to squeeze out of them + compression-level: 0 + + # and what they were framed from, which is where to look when a picture + # comes out wrong + - name: archive the raw captures + uses: actions/upload-artifact@v7 + with: + name: screenshots + path: fastlane/screenshots + if-no-files-found: error + compression-level: 0 + + - uses: actions/upload-artifact@v7 + if: failure() + with: + name: screenshot-log + path: ~/Library/Logs/snapshot + if-no-files-found: warn + # a job per app, fail-fast off, so "Re-run failed jobs" can retry one half upload: needs: build @@ -219,7 +275,7 @@ jobs: # while a build cannot be uploaded twice. No macOS runner: this touches the # listing, not the app listing: - needs: upload + needs: [upload, screenshots] if: ${{ !inputs.dry_run }} runs-on: ubuntu-24.04 strategy: @@ -244,6 +300,13 @@ jobs: given: ${{ inputs.version }} run: .github/scripts/resolve-version.py --input "$given" --dry-run "$dry_run" + # where the lane looks for them, and the same set both apps are given + - name: fetch the screenshots + uses: actions/download-artifact@v8 + with: + name: framed + path: fastlane/framed + - name: write ${{ matrix.app }}'s listing env: ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }} diff --git a/.gitignore b/.gitignore index 08373d5..fc53004 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,8 @@ Carthage/Build fastlane/report.xml fastlane/Preview.html fastlane/screenshots/**/*.png +fastlane/screenshots/screenshots.html +fastlane/framed fastlane/test_output .DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md index f1a1017..085be0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,19 +21,20 @@ once the version tag exists. ### Changed -- The engine is odrcore 6.7.1, up from 6.6.0. A pdf, a text file and an archive - listing can be searched, not only a document. A pdf's text also sits where the - file puts it: words no longer drift to the right of where they belong, bold - and italic are bold and italic, and a hit is highlighted in one piece. +- The engine is odrcore 6.7.1, up from 6.6.0. Pdfs, text files and archive + listings can be searched too, and a pdf's text sits where the file puts it. - PDFs are rendered by odrcore instead of being handed to the web view, and a password protected one takes the prompt the other formats use. They can be - searched like a document, and a hit tints the text rather than covering it. + searched like a document. - The search button leaves the tool bar when the page cannot be searched, rather than greying out - the same as the edit button. - The pencil turns into a save button while editing, as on Android. Saving from the bar ends the edit and shows what was written; a save that failed stays in it. Saving has left the menu; discarding is still there and now leaves edit mode. +- The App Store screenshots are taken by the release run, from the build going + out, instead of being made by hand: six per device on an iPhone and an iPad, + in every language the app speaks. ### Fixed diff --git a/OpenDocumentReader.xcodeproj/project.pbxproj b/OpenDocumentReader.xcodeproj/project.pbxproj index 8f63183..ac7dab8 100644 --- a/OpenDocumentReader.xcodeproj/project.pbxproj +++ b/OpenDocumentReader.xcodeproj/project.pbxproj @@ -29,6 +29,13 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + A11E00000000000000000037 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = E2F7ED47220B54D600D63515 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E2F7ED4E220B54D600D63515; + remoteInfo = OpenDocumentReader; + }; E22B25312557F0E2001D0C52 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E2F7ED47220B54D600D63515 /* Project object */; @@ -49,6 +56,7 @@ A11E00000000000000000013 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; A11E00000000000000000014 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; A11E00000000000000000015 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; + A11E00000000000000000038 /* OpenDocumentReaderUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenDocumentReaderUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E1EB6C492C1A510D003EC5A0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E237952F2274844400BA7238 /* AdSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AdSupport.framework; path = System/Library/Frameworks/AdSupport.framework; sourceTree = SDKROOT; }; E26C39382250DC6E009C484A /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; @@ -77,9 +85,21 @@ path = OpenDocumentReaderTests; sourceTree = ""; }; + A11E00000000000000000030 /* OpenDocumentReaderUITests */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = OpenDocumentReaderUITests; + sourceTree = ""; + }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ + A11E00000000000000000034 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; A11E00000000000000000003 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -171,10 +191,12 @@ A11E00000000000000000009 /* Ads */, A11E0000000000000000000A /* NoAds */, A11E00000000000000000022 /* OpenDocumentReaderTests */, + A11E00000000000000000030 /* OpenDocumentReaderUITests */, E2BB4B64220EF4F20056176B /* Frameworks */, 52A348B12A9262D100DACAB9 /* OpenDocumentReader.app */, A11E00000000000000000008 /* OpenDocumentReader Lite.app */, 52A348B22A9262D100DACAB9 /* OpenDocumentReaderTests.xctest */, + A11E00000000000000000038 /* OpenDocumentReaderUITests.xctest */, ); sourceTree = ""; }; @@ -228,6 +250,27 @@ productReference = 52A348B22A9262D100DACAB9 /* OpenDocumentReaderTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + A11E00000000000000000031 /* OpenDocumentReaderUITests */ = { + isa = PBXNativeTarget; + buildConfigurationList = A11E00000000000000000032 /* Build configuration list for PBXNativeTarget "OpenDocumentReaderUITests" */; + buildPhases = ( + A11E00000000000000000033 /* Sources */, + A11E00000000000000000034 /* Frameworks */, + A11E00000000000000000035 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + A11E00000000000000000036 /* PBXTargetDependency */, + ); + fileSystemSynchronizedGroups = ( + A11E00000000000000000030 /* OpenDocumentReaderUITests */, + ); + name = OpenDocumentReaderUITests; + productName = OpenDocumentReaderUITests; + productReference = A11E00000000000000000038 /* OpenDocumentReaderUITests.xctest */; + productType = "com.apple.product-type.bundle.ui-testing"; + }; E2F7ED4E220B54D600D63515 /* OpenDocumentReader */ = { isa = PBXNativeTarget; buildConfigurationList = E2F7ED65220B54D700D63515 /* Build configuration list for PBXNativeTarget "OpenDocumentReader" */; @@ -266,6 +309,10 @@ A11E00000000000000000001 = { CreatedOnToolsVersion = 26.0; }; + A11E00000000000000000031 = { + CreatedOnToolsVersion = 26.0; + TestTargetID = E2F7ED4E220B54D600D63515; + }; E22B252B2557F0E2001D0C52 = { CreatedOnToolsVersion = 12.0; TestTargetID = E2F7ED4E220B54D600D63515; @@ -313,6 +360,7 @@ E2F7ED4E220B54D600D63515 /* OpenDocumentReader */, A11E00000000000000000001 /* OpenDocumentReader Lite */, E22B252B2557F0E2001D0C52 /* OpenDocumentReaderTests */, + A11E00000000000000000031 /* OpenDocumentReaderUITests */, ); }; /* End PBXProject section */ @@ -333,6 +381,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A11E00000000000000000035 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E2F7ED4D220B54D600D63515 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -358,6 +413,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + A11E00000000000000000033 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; E2F7ED4B220B54D600D63515 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -368,6 +430,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + A11E00000000000000000036 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E2F7ED4E220B54D600D63515 /* OpenDocumentReader */; + targetProxy = A11E00000000000000000037 /* PBXContainerItemProxy */; + }; E22B25322557F0E2001D0C52 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = E2F7ED4E220B54D600D63515 /* OpenDocumentReader */; @@ -423,6 +490,7 @@ ENABLE_BITCODE = NO; ENABLE_MODULE_VERIFIER = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; + EXCLUDED_SOURCE_FILE_NAMES = "sample-*"; INFOPLIST_FILE = configs/lite/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "OpenDocument Reader"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; @@ -441,6 +509,45 @@ }; name = Release; }; + A11E00000000000000000039 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = app.opendocument.OpenDocumentReaderUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = OpenDocumentReader; + }; + name = Debug; + }; + A11E0000000000000000003A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CODE_SIGN_STYLE = Automatic; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = app.opendocument.OpenDocumentReaderUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = OpenDocumentReader; + }; + name = Release; + }; E22B25342557F0E2001D0C52 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -648,6 +755,7 @@ ENABLE_BITCODE = NO; ENABLE_MODULE_VERIFIER = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; + EXCLUDED_SOURCE_FILE_NAMES = "sample-*"; INFOPLIST_FILE = configs/full/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "OpenDocument Reader"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; @@ -669,6 +777,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + A11E00000000000000000032 /* Build configuration list for PBXNativeTarget "OpenDocumentReaderUITests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A11E00000000000000000039 /* Debug */, + A11E0000000000000000003A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; A11E00000000000000000005 /* Build configuration list for PBXNativeTarget "OpenDocumentReader Lite" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/OpenDocumentReader.xcodeproj/xcshareddata/xcschemes/ODR Screenshots.xcscheme b/OpenDocumentReader.xcodeproj/xcshareddata/xcschemes/ODR Screenshots.xcscheme new file mode 100644 index 0000000..37c652d --- /dev/null +++ b/OpenDocumentReader.xcodeproj/xcshareddata/xcschemes/ODR Screenshots.xcscheme @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OpenDocumentReader/AppDelegate.swift b/OpenDocumentReader/AppDelegate.swift index b3104c7..8e1cb26 100644 --- a/OpenDocumentReader/AppDelegate.swift +++ b/OpenDocumentReader/AppDelegate.swift @@ -15,6 +15,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + // does nothing unless this launch was asked for a screenshot, and has to + // be ahead of anything that reads the defaults it settles + ScreenshotMode.prepare() + StoreReviewHelper.incrementAppOpenedCount() return true diff --git a/OpenDocumentReader/DocumentBrowserViewController.swift b/OpenDocumentReader/DocumentBrowserViewController.swift index 7b09e66..92b9b25 100644 --- a/OpenDocumentReader/DocumentBrowserViewController.swift +++ b/OpenDocumentReader/DocumentBrowserViewController.swift @@ -20,10 +20,62 @@ class DocumentBrowserViewController: UIDocumentBrowserViewController, UIDocument override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + // before anything that depends on how often the app has been opened: + // a screenshot run wants one screen and nothing over it + if let screen = ScreenshotMode.screen { + showForScreenshot(screen) + + return + } + StoreReviewHelper.checkAndAskForReview() + refreshPrivacyButton() } + /// Whether the screen `-ODRScreenshot` asked for is already up. + /// `viewDidAppear` runs again every time something over the browser goes + /// away, and a second document presented over the first would be the picture. + private var isShowingScreenshot = false + + private func showForScreenshot(_ screen: ScreenshotMode.Screen) { + guard !isShowingScreenshot else { return } + isShowingScreenshot = true + + // The browser is the picture. It opens on Recents, which is empty when + // the samples were laid out rather than opened, so each is revealed in + // turn to put it there. + guard screen != .browser else { + reveal(ScreenshotMode.browserDocuments) { [weak self] in + guard let self else { return } + + ScreenshotMode.markReady(self.view) + } + + return + } + + // nothing on a missing sample, so the test fails waiting for a document + // rather than photographing the browser + guard let document = ScreenshotMode.document(for: screen) else { return } + + presentDocument(at: document) + } + + /// Reveals each document in turn, one after the previous has landed, and + /// then says so. One call per document because revealing takes one URL. + private func reveal(_ documents: [URL], then finish: @escaping () -> Void) { + guard let next = documents.first else { + finish() + + return + } + + revealDocument(at: next, importIfNeeded: false) { [weak self] _, _ in + self?.reveal(Array(documents.dropFirst()), then: finish) + } + } + // MARK: - Privacy /// Brings consent up to date and then offers the way back to it. diff --git a/OpenDocumentReader/DocumentViewController.swift b/OpenDocumentReader/DocumentViewController.swift index 5477fff..37bb794 100644 --- a/OpenDocumentReader/DocumentViewController.swift +++ b/OpenDocumentReader/DocumentViewController.swift @@ -17,6 +17,9 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel private var browserTransition: DocumentBrowserTransitioningDelegate? private var hasStartedAds = false + /// The navigation that is putting a document on screen, as opposed to the + /// "loading" or the error page. Nothing but a screenshot asks. + private var documentNavigation: WKNavigation? public var transitionController: UIDocumentBrowserTransitionController? { didSet { if let controller = transitionController { @@ -250,6 +253,54 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { updateSearchButton() + + // the document is drawn, which is what a screenshot of it waits for - + // and only the document: the "loading" page finishes first, and a + // picture of it is a picture of the word "loading" + if let documentNavigation, navigation === documentNavigation { + stageScreenshot() + } + } + + /// Puts the document into the state its screenshot is of, and only then + /// says it is ready. A picture of a search is a picture of its hits. + private func stageScreenshot() { + switch ScreenshotMode.screen { + // The search is shown on the ODF document rather than on the pdf: as of + // odrcore 6.7.0 a hit in a pdf is drawn beside the word it found, not on + // it. Move this back to `.pdf` once a core lands that places it right. + case .text: + let query = ScreenshotMode.query + showSearchBar() + searchBar.text = query + // the hits are the picture, not a keyboard sitting over them + searchBar.resignFirstResponder() + + // Ready once the hits are drawn, not once they are asked for: the + // call is asynchronous, and a picture taken in between is a picture + // of the page unsearched. + callSearch("odr.search", with: query) { [weak self] in + guard let self else { return } + + ScreenshotMode.markReady(self.view) + } + + return + + case .edit: + // Entering an edit reloads the page as editable, so this comes back + // here a second time - and that pass is the one worth photographing. + guard document?.edit == true else { + editDocument() + + return + } + + default: + break + } + + ScreenshotMode.markReady(view) } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { @@ -521,7 +572,9 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel callSearch("odr.search", with: searchText) } - private func callSearch(_ function: String, with searchText: String) { + private func callSearch( + _ function: String, with searchText: String, then finish: (() -> Void)? = nil + ) { // an unescaped quote or backslash in the query would break the call // apart rather than search for itself let escaped = @@ -529,10 +582,18 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel .replacingOccurrences(of: "\\", with: "\\\\") .replacingOccurrences(of: "\"", with: "\\\"") - webview?.evaluateJavaScript("\(function)(\"\(escaped)\")") { _, error in + guard let webview else { + finish?() + + return + } + + webview.evaluateJavaScript("\(function)(\"\(escaped)\")") { _, error in if let error { CrashManager.shared.log(error) } + + finish?() } } @@ -701,6 +762,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel func documentUpdateContent(_ doc: Document) { guard let url = doc.result else { + documentNavigation = nil self.webview.loadHTMLString( "

\(NSLocalizedString("loading", comment: ""))

", baseURL: nil) @@ -712,9 +774,9 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel // pages come off the loopback server; a file URL needs read access // granted along with it if url.isFileURL { - self.webview.loadFileURL(url, allowingReadAccessTo: url) + documentNavigation = self.webview.loadFileURL(url, allowingReadAccessTo: url) } else { - self.webview.load(URLRequest(url: url)) + documentNavigation = self.webview.load(URLRequest(url: url)) } } @@ -760,7 +822,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel let fileName = doc.fileURL.absoluteString.lowercased() if systemRenderedExtensions.contains(where: fileName.hasSuffix) { // not odrcore's to render, but the web view knows the format - self.webview.loadFileURL(doc.fileURL, allowingReadAccessTo: doc.fileURL) + documentNavigation = self.webview.loadFileURL(doc.fileURL, allowingReadAccessTo: doc.fileURL) canEdit = false canSearch = false @@ -775,6 +837,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, UISearchBarDel return } + documentNavigation = nil self.webview.loadHTMLString( "

\(NSLocalizedString("error", comment: ""))

\(NSLocalizedString("toast_error_generic", comment: ""))", baseURL: nil) diff --git a/OpenDocumentReader/Samples/sample-cells-de.xlsx b/OpenDocumentReader/Samples/sample-cells-de.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..55ac228e59f0c5e07ea955b9e20c0a72e9badb7f GIT binary patch literal 1874 zcmZ{ldpJ~i7{|{TmkDFE%#vbEE>Gk(s$rYiwlEQ~?(3Q*qfkR*2$6}3N-phCm<*ao zMegNNa!c;H%rYp(C1n`7CX_wu*{7P_&Uwyx&-vr~ea`21-tYUfG=mCC0{{R6FEl`M ze+2&oK4}U7fD~Ar4gE+IB8lQ=8{$t4aMcPvc_J^d&7w|6^1NHaT2nMv z{~d^ezO?$w>tlgtD@*#`9IB{`e%@3H+s{*Ppvf`lsgde(@&iKKmQZBLY

?>3A0W z7_G*)pyp^xyh&K4cTi(Yz3JaJEz$JRJQ`D&vVXhL0^zLzIiUr!s2eGlX&hqL+iNYv z=$ugRz%6H&H%csFi=%U07@^7~_3W2T`o&HX7^ho`GOh|$pAP1>3tC;f5-lv{Z71$> zM7g!OgBrjq#~;>}V~a7@1oIz_d5)hk8Fhx;S`KfzketblHIVOll@yb4LvlAfhV58* znDca*HMG`nn7oA>p*2^!UL5W66!A<}SmtOgYZ%&UwXfFU`bqVw$2j%b;X?2A>M}xUYwE9^9};7! z_%>>$RZm>DjK8l|rIHSc>3v%@O2B@>GU?DMf~H~XvU^E7p*|R52wSQz{{!0ImE+l2 zZ(&SIMknV_*xx<0^!&YJ&@iu?3U8jYr`{Xb=1}akCX$oC6`6kMSFhci#<(^k+HEcd z=CC^=F^y+rBWE={EBk5DBc+NDEuwT~rW8cd0MX>Y8hk?g3*Biyvag4qpYKL5{7WiY zt0N8!ucl{>@rptu6IrfCeRi**G_6&4XXn(F;)f4|C6S19gP-P9)S6fEmv)9I+)qr% z*#gt;$40$XrgKMq#3G|~ucqEdZxX}MR+;*pOanUStiQ%~4+jHOzV##D^@oIPwNHST>#U_RmG4s?^!3r)i5y?~Tw| z&8MZ6t4w1%5^}7BVta=h<5$P{V2_Jj-BJTWqCi;07uatxuf`uD)#->69&Gn#Ja5X{ zAwIwsgjD$+G678=g{gyZDWHx8ArvXRrmy9dPTG zl`rp#k~XIg4(pF(U9UWV$If=3P_JmGm~bf^*0d&VS+95Yq%(sV+I6Pg+;j8-Y2-0x z-uXPGdP1sOkNmp!nnp;OG_AB)kOfyxY2)rg(f+>YQg@P1B6&P;?d6{(Vo2GTwmb$Byk8Rd@I_3X@cF^9J=BIpjBKv9#N zA=Ic&hZ^H+?#DYh?XVZL%1$a?+-1WkiN%8-m=c88fz9Ebj#?DSoY* z`4MVq1`&{k{&?_%ZSnbFf_?J8+W@}-|0w(-2LL8S8?^XlF!Bre2hCTZD7Xpzc&I9 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-cells-en.xlsx b/OpenDocumentReader/Samples/sample-cells-en.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c812d788847ba90357c78ce07940246a89720bbd GIT binary patch literal 1867 zcmWIWW@Zs#U|`??Vnv3$#2vizhU9!v?Mxi?wfN-po%izkM>Y z?0}2fk7?^&&q`K_ZuwYyI=;OBDsTFfgV`GnCZF#2sM(!acD&<=*R|l&?QGjy;<0jj{<*C@#}YWHyPZuqGn6MLPUXz0^9{xCcG~zDN!{dL@`q*JjwdNk zt34h^b1eQ*d$M)f!q+`cvRCd+?N~5Fz=XHsX5>bnhX;OKz5nN^Pm$#7dc99u|8H)O z*;oCUF#sjFj?a4Ex(OIe+Kdbg+(0_MC^e^8Uk^m~oYFV-jrQ z$%n2!U_KLQcPL_duGXHt)>f1B&pGqY?j{+!s;U~{%%Vc?a%W#R?ddb^bk zFTk-gd5@0)kXfv0u7 z(I+{zlEzgUoYE~vR?Ys#;CxI`*{CdqKOnDPGxhwb`l|Eqv(5Hb7Kw}a`sl8iCTg){ zUh<-3Zu|SYkE&bfHYUxOv7uF3D`(fUQ$|D#U3pF?NRqWK1lSi&D&|8zT}gM;2fuoAFP%|F3kRC_oBX3 zWK-)uqXXWDRxh;K_B&(AgC%~~PS~wGP~Kb5`L}!RZf3M3JC$|H4WKu>*cccj5MC|L zNKGv%)(2CDps4Mg8dy9>L7?G(*WqgB?&|z{-{c~ZTRdK78RgCaN-68VHP_@__9tU8 zdDzJ>wDoK1+Q-wjZw*`SV$Hw(*8KXK8w-z^WlVUiaJ2bqUadiH?(OqoKBn7pd(WTW z5&y{E>0|tkI~@C)54}Iy-}`}&t3G5}f4+IbbgvWYyg!#5;N*XGa^4QHXv?|f^0#{g zgC0NLx|iMLwDN_@fROM9z5Ze~MjFaz`;+c$I;ofbUZXcxEMU`(W6e6s4ZOT&A{%}l z`6{=H@9TQir>kt{Epg@9mD;^pI$;X?Vi|*9$G&!Nc&B|c=+xit%$UyItV>dJo-pca zC>&`LXqI~M+(tWhd&vy{=}R}Bi{Ef5@&AsEN-snT{__ZF_!nC4jk+5yxK8zw=Cnn4A-<6fXG&mY0~Gvwg%CaEaN6_r}?ty!hf0xxV%c&(@` zdr~@Q(*OAhryW%H{peX^_k;EAsy$s(#axP~9S!=Cb?5O1`%C|T37?Tkgc)~<4@?qZ zumqS!u$KSm2B4RL5bX>MOBnTmMj(}l=o-;W7=%VHVC{puyg@eyJ@X>W`3^A$IV+=U lK8}_h5Skw`gB=0VjFCA4yjg+Shk=0=2wj1`{J;w00RX3#|KI=s literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-cells-es.xlsx b/OpenDocumentReader/Samples/sample-cells-es.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e9a4dc35359a39ea86c8b70589692b3ffc57648f GIT binary patch literal 1874 zcmZ{lc{o&i7{`ysAj>dC)|)k38cQAt$$GO@Gm2y{DPxZb(`w1JWQ-{k$&#@&$X>~s zhRHC=&C(>9$(FrjP*b@_p8Ke|w{xCz-gEx=exLLCo%j3xkhTzRQ2+q=z)KzoJn=~A zJNUF~698-ltBZM1AjUfo<8c%l>>cWchzRg6BhU^#)e^bt(Y8>Vcqhb!Z^vv@j$*K? zaK)?JnepmgnnGAZ+sXc=o$HQ7IlvmQrEoqYH#cDoY>huW5_X(Xz zed1T~#H$l;b+H~DMu{ie^dISr%Ni+5CGucQ6f71kC(S}qI<;9k(NcK_unq$Q_RyT3 z3H5HnmBKm-Y)P*=?w)JTd8HaMeW*jf+8L(poG&Ntw!Pu|pZA_~qpn|zY{c>hR)R)+385p1&Cj{?>`znHFm*j#Dy<^!$EUHHU>{AIZ)ne(w#;4sSnP;Y27RR74RM6WhKu&nLM+}HD&kQ8Y| zi_AmyCKrka`yuKTwPcCt0_B)Zj*G}N>$8@-%)3@j)MQ(dBe=}@mdJI-AkY6UI@Loy zbRaNYKK=fLBguN{+4Au)#@x$DA?lQ4WXYh6Q?>I~-lF@`V%gUFPU|u$$ux`9f@y6& zC*3QA+jAC2q)?2H65m-TGa5M1uGD^+uLY4bKr|_^M)+&4(}f3x_?-+2@>}bLe@XdU zwFChMJNxeFToqP?(C23H%3&OmieR5`amoBr{qSLgh?sD;*_MSJYE-sS!cOe=QbJ0R zB%jV}y_iX*tmzS7f#?_=TxO~KW&!O~Hc`KaXqLsi9IT;m(#cFVdQiS<4(*ubd_XzO zdHRgl$tgpO4W6XvdWO#Pt)9!HxL9g)lW&L!>)m_VHxFiWCp}r-%3CkbwA^MXE?dao zrG|?tHP|F|rxc-}NdpWDo;}I|dpcjHqz;6X0bzyLVSmQN;jLjHp=J3NtgxDf2Q-Ue0cQnVqK6IKNubw+}X+csJ_aU-TLvrngEMLt<78+ogNz?p+A< zY?azxT;WTS?)?1hqMoEmS>9o^Mp@qj%6kk|(Y^_z(NkbV?U+)1->?*~1`Bf+6_9q5 zTTxA2!1IK=`JAQA?ocSe$1@oAdgYfS#4@M8nKt*OT%#|-SeBzoJ9Izm}a zRDe2rWJc5Z6Zfy(s$qps83hS%@Bo0s24$#^w>KtK^GDHM`>VLLo{%g#QIjie%tkIT zl%cP(o65_$B{lT0i$QT^?7RRsj8d+JCFIo!SpTYCcE%f@7gRI2v1f2L|D6iKzUSx{dqD%@J z?Yg?-u>HZ_SI1a_tWt>~kLW`9X+F3<3Slzf+J4^GXFwHelgg^dfBKn;fF_{1#1+M7 zo~Rl=KR0kIP^GQqw4$`nW1egZqk?=fvCXJZx;ngvPH&$vHgJ(LXcCUplgvSl@1`p3 zGcisFam4R+_w4bLqtZ!yey!ybj_%x5)eHG1Fh=s%S?{;82ovUDLkQ~R(D(y6Xp(+0$5T4&EEe6joKia6{HQ$kL&ooYY zYBRGf#UYOXc|?ZGzl*h61ZegdG=BI^M2Fd(X3qli@0DH!18Rx}%Mpnjxnp4afjScY-iT@K6q%9PT5&%HK(-NdyhOWK+1CXHw4FCWD literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-cells-fr.xlsx b/OpenDocumentReader/Samples/sample-cells-fr.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f70efbacd5e5ce84dfd9a5515d1d71c2194f30d1 GIT binary patch literal 1885 zcmZ{lc{o&S9LLWXhAhowiBOU?GK?#^kw;_fnJi_OC6ZlC8l_C+p^zm>_NmEM$V|jT zbJ0ZhY}qw#wvZ(mYutn9K5Fjmyw5qmbN={#pYwU&-(q3}W#tC|fCIe60UxI_o(=F# zfdv5gz-X)O>w|Ok!8x1@@^cNaN8-J`3gVlwZ

t9Nv8^xtH#*#Ub_ecBX`%Ec|6p zD(&9p$W^0NhMM~@fzwW{VES>dugi)4dh5U{jP!C+kxui0>jJOlZ#Ftyi|yiZORV;M zS$(lFRzJAHJ+Lm4X86&(F(U1AK_Ur;(>j9ruJZ-$AJ>RlR1Os;>II$e?lxn~Y#Wzr zRbS37uiMK|r9|Y}WnPzjMe7}`SEJbMMcF((ENFkIazi(-h1E16DgwsmexBRzf@D)e zDECG5KY?>QZLI$>280LjZsaj1K;;UIB{8t!GSY^WIP; zZuU9#v&G+$Ph&7aiJUs##<8$Xl-Rjk?@Cz1V&8uTq_orj%1{EAi0;jb;MT zwDW$ppr0qQLPAN5(_XM06YWD`%UU-!a#f#^y`dx%I++R6rbZbA|U%J^T@ie@}=Flzz?n;<)H4&39|MDs@p}2_ycb;TpeW zrD1eyT#hMQbT_>&c5Q?SmOF)%Tn$2sg0S!%*qICe}#2Wrk06~qS1a}%5Bso9tcC}nxt z8-Inp4^R+3@=<+%i8RUi+cB6nz%mDDph~6d_hW9 zC{NqnWn9p)qLzwd2o$Wb{hGCRRp%tfLDB>m00`~U23&S^#RVvC2h`T-#yqU{NmD{- zg|Mv*^$<`d5K|HU#SexL6BsjOWE6`kdC+*lVCDY0)tlrpk+80zz#kfOmue5?PkrhT zN>4r)Mn4`|goqTHr8&`W@=ymqQRTHrDx>TtIa@sDX#8b9`Fi4Fo$;uHkMV^bex28E z!HJXiy`D@OHbskkGk<^AW5JSP(wxxtmRBW4>2ze(-MykJUF45u#;Jz)>hy)-l)m(k z;KJ1-m2SzS_CMD>GG+>RA(2Xzf{<^=Y$Z-Tib?_B)Y$M6X`-J6_MUGFkH`>SpUq&G5 z{i8Ff#blX8#aP7?JdO4a8kxZbwi6h^mK+ZIV&WeUyf^g)`@ITUIp=EYSP~+F4ad!4 z!J2P0HXX@se4i^$$$KAdFm6R>l^j+;>&fbd)XA-GnwGYlcTv~+Fg8>qi=?z$+U#r5 zpERnDDuxd(kyfB4Mi3T$=ZIkdkHl>mP+9 B42J*! literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-cells-it.xlsx b/OpenDocumentReader/Samples/sample-cells-it.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..d1b57a392489a52ec935640d075e440de8782434 GIT binary patch literal 1869 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 APyhe` literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-cells-ru.xlsx b/OpenDocumentReader/Samples/sample-cells-ru.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1b51119ea13443885d7257d781801de44ee2770d GIT binary patch literal 1968 zcmWIWW@Zs#U|`??Vnv3$#2vizhU9!v?Mxi?wfN-po%izkM>Y z?0}2fk7?^&&q`K_ZuwYyI=;OBDsTFfgV`GnCZF#2sM(!acD&<=*R|l&?QGjy;<0jj{<*C@#}YWHyPZuqGn6MLPUXz0^9{xCcG~zDN!{dL@`q*JjwdNk zt34h^b1eQ*d$M)f!q+`cvRCd+?N~5Fz=XHsX5>bnhX;OKz5nN^Pm$#7dc99u|8H)O z*;oCUF#sjFj?a4Ex(OIe+Kdbg+(0_MC^e^8Uk^m~oYFV-jrQ z$%n2!U_KLQcPL_duGXHt)>f1B&pGqY?j{+!s;U~{%%Vc?a%W#R?ddb^bk zKRxkUNa&xcod!K2OuU%MfGVNN{ z?c@@x=YpE?R?}Vt$)#qOij>4v9}!{y9U|f_9jmZI$g8sDV61plO!05QiI+r`EOtye zn=S9wx@=d?g=o_!NoKZx{n}qz%sppsdFFrJ6MrvwFu|AkG1jX~zsTcbuJBYN!w-)55HzYDJ=ah7IUVp_r zL2UaGCf*6_?p?j>qHpr?n#<#3-0xq%yOw+AR{D%eWq(PT-3PABQ1i8}|M$@PzoqdH zcm2&Xw|Sh>(*5LM?iO)>5kICIj`t1D)xTWXx|HtNp)5j}4~R-D?$C5EZSDM>zoV#{~R z{W=>Za=q}y^rI`onAq3!mD|fn>4GRjrwjG-iW@bVq4XN9@Vn!(cPVNd$%47>nSbY$fYZ9J!{f0zkT3) z*WFFg|MFH`yKC2dVUfh|jE(UV1v*m8TRb@WwyWP!+^jNlsS5Kt)7^>JC!9^|IF&Uo zQQ*?jEY|5|D_asGBOF~-L<0kB6Yt-grvKBjAor%~l5gF)H>x`NIe6ZDOA_vSS<<>< ztHV4lr)Z&DT8GXXZ1p~o!^^yhao1`^vuJ?{c`nD-ChUqeQ50y`II%)yal2I&?|jn_ ze;E#46_6Aa4A|`b&Hcs1i}fW}C#IZhT=%K?pV%|so4(5{yRN@psvLdoV9_m=Q1=5< zBi3=f7QX$#oc9WE0=?=NI4b0Ka`<*c=KMpaBacaQL#o_zDGHJsulgm7U0duB*Kil zS^*|CFjxZ2Z&)iCbOX=}T8MTAh9!*pKqHWfU387;#TY^(7ckx9F4WM?K`$W?=6r{k ngIr#qYevsz2+i-A!HxiF#>jL5-mJiE$-ux0gswnehJtwj%Ahhs literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-cells-tr.xlsx b/OpenDocumentReader/Samples/sample-cells-tr.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..b26e2c4340fee0a1a5e31e6b120d368bb830f346 GIT binary patch literal 1898 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 b{9%ST2O}>8c(byBl(7P#574vkSwTDi2($FR literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-deck-fr.pptx b/OpenDocumentReader/Samples/sample-deck-fr.pptx new file mode 100644 index 0000000000000000000000000000000000000000..7e72b344917eb28db3691972345f57228e533338 GIT binary patch literal 1875 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 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-deck-pt-BR.pptx b/OpenDocumentReader/Samples/sample-deck-pt-BR.pptx new file mode 100644 index 0000000000000000000000000000000000000000..f1493dda91a8626436f3622249fd76d96ec990d8 GIT binary patch literal 1871 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 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-deck-tr.pptx b/OpenDocumentReader/Samples/sample-deck-tr.pptx new file mode 100644 index 0000000000000000000000000000000000000000..ac6d2d3a5267acff5ba0c6d4ccf258da28ed8a43 GIT binary patch literal 1878 zcmWIWW@Zs#U|`??Vnv3UbIA+816d|a3=G0RI@&ouuOv0EBtE3FAhkGFuOc^RZQx12 z!v+F>MNePXDm%rfIAsg_H01&fd4nRg&Q|lvJFEUyt9edj5ZzI*Dec~>!p*i->U=X! z9=mXA>#C&(5|YvnUpRIBZgQzIt0;%;4v7s@)m3)hHQ62PB(#S2%BhW0N>-cB6ttbt z#mTH(dq$3{zw!d-8EKvs>tFqfnk~WA7BuywbKb1#H;M1NDl9%#y_|S)qDVP+;i)Xu zB~R8g9@=5o@-Et|)GuJo97~g1F4}4ywT6jKb$k}D=lwLeS*8)EFkSt_nM<0YbB%;v zr>*;S_odU-8{e-bh@ZW;*`?O(^Sje4Y;J7$wV1~;?$W0<|978#^XsC+`ThGU*#l6* ziE|bE@r}UnF<@k1;0Dt1MX5Q(`g$O;_xxV2Lk0p25BB;C=55cEby>2pn)U`4&HPTs7O|#P-mwk3U{+ z5Itq3t5CL!?V3L0|AT)Ge7OAM?&|LPl6-uX@@XR}A0{Uc8YRacavdz-K<;?p6u4OWAyllFmj`IiqyY_<`HWj6FFD{k0wuoG8*lg4{gT?0Y>Zs|F z%=6Yikl+8d8!Z~I8?e^j26{3V=vh!E0C^VOo4pgxW&zWCOT6owy%Xo&IA%JnShLk3 zKUdzt<8{OW`z=|XzrIYJZNgIZGPiB+&l`6O>x-tE?dWc+kW0JF~~x$K%E3GfPi!9l0#Ps$+S)u{em^%5%2B#pyR?CQaUXqvXkV z+w`B?R$0AU^0Ac4*-z2bQw`L0Q5Xx*Z7Ot*I3+0@WNUCVaudz-)V{wdb#`nO+r zQDfd?%QEYuz<}7x!oVO34UFQP%#_q(eK2JRiuAJ~-g&nT1om?GQRq$! z7GZlM*C6P=P3oV4ip)y!7lFIZ?X!NKpsKk#Q)s(KgU&8N&$F}5^X2Ttr_Y^~!v7*_ zv9^`vX${6$>5H#&UH9kM)oExH&dWZy^kTq8IhnmNaW^h`Iy$W@Te|kex$0=6XRl;6 z-ks}Vl}+k(JX#y^Xj&u-`>kU6R~jcj>C84h8tvP!^2bz#>1V9KHx>J=mDht*e9M{{ z3YUGqo^idbRr62fey2-a7vxoEt-ipPdi;Rkv9={9iRUkEuXmUu+n~Sl^TevlRh;{O z`cLY=sn@&bjZ{dXiLdjnu5;a=mAIuZhHsf6w(#nSW8N=pRytQ~jCitHVm)($(M;dX zj0fd9b*$=n-6mSB)Np#6`RDxi`E%qKD64oDxjXLLZM3NW#B2k#gL|f&TVJcMsGIXg z<)VbtbQ?Kgj@>Wzg_el5PMDoheCXFxuCw6^W(VZnB?r#;daR%jDyO~a;_dy`HnOsP zlJ8Rs=81oPGoSBy_f3=k{xav>+c#f)c)0w9VBSeS789WjwuzskE!Xqe|9!~blHRDH zcU$gI?l e0tgfSFhiV!ks$)SS=m6!Sb@+7=-DrgrgZF zAHye66-~Jo6$ra4WUYQ-#ME2DJAz{M#}$0wjk1Pd72@q9qgA1&FIGXqMYF0^FI87@ zI8Q5~AK#1oi>R}88s5rvvB~5ve9q*xtTOYz>yUcQG45L-cl91IoW$^bRhJ??Oy*0Z z1d<3Xw}?-J2u*ncKbITy%ad5|Wg~a+Er~B9%zj17Pv~~pHo^$&Ml4E#_@vc!Q^8o& zBF}4-9uOu0`n{2v4$>QdCUHQ~l=0(h->3V0m6j-zQk45NU!gCBL=;{IgDg8C2*TJ2 z$Mjry+Qp4z-Oo5N{d{OZZi(I;R`;FgU3_NrJ(elp;9pu*0{Z7^GsQCv!CT_ z3tK%@xvzYGEUK)|imrC(s%9zS;8twm2N+e+kzmP$1(14{yv^iyk-wB8t9p4J;ZEc? zqDl{S2kkmS$Wid3*w$ZRlJv5a!^B0gg>f&%a1^cWjIz{aTFWYNVJ(2WwU|4C~-V7PTr^GX2eMc)80UJ=^YT)Z{TY1J zXxX8xR0GZ}#m5G`gZ7%E=Q?M`$;Eo#4-pwlGtM= zn;J83@}k-J6k5`klP(^CjmS_=>I&r0S>jWu=eS*NoB@Nwb}EPN@hu4K01nymC6pXHY}7E z|GIM$(6{a|*y*Ev4eUv#>U4v)O1zOd)c;DQVaWX(oxJa zzgr`1z+}j9C697zWLl1Cw5%^5UBrY2w4dayL>rHI^U2>UD(LfUMrn`tx+pNax*o{pD5up=yMEu6)iOfD{N|GJy}3&1CE2LJ#7 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-en.pdf b/OpenDocumentReader/Samples/sample-paper-en.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3540f171d9e138d429254737b9ff566ae4a72923 GIT binary patch literal 4806 zcmb7|T~pgQ6o&8fD|Exm?gh5>WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-es.pdf b/OpenDocumentReader/Samples/sample-paper-es.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bf14442c11c529e286d0e12b957293586608ef4d GIT binary patch literal 4835 zcmb7|%WmT~6o&VH3T^_li%8;47hn(|nc9;jn5+EO6N>2%&XtG+-F zDU-BZiE6#bMgB+~{`}A3<>LOA#U&2d45J8DPtUV=@50qzFEV^DTCuCP;l0?(1`+u7 z;p%E8%UnU~-&0sa;jcyBe5H!~7QU|zWs9(DqMn~OfzE3QnC?BilX)R-s_$PTKzYVd z%E-6yK{nN)UdsjoTU2GMeqqGaTfzlFvHIf*KJdn}h0YqpyGJHgg`U1xbrLQQPpulI z8Y&KNL?iX%Te*9cZLt>Nyj)j#QEtO8MR{E|h56qNNWJFR?LW(Gg>{P`KoJ!5!P*3L<4@(XudDn zA{R*R5GE*>==o3XJ%w~ho+S^`mlex_28)q=)M+!gJPm-Bn->bCc(#ma0HruDP-A$A$q5DOqJeB zX>i3_zO>aKODO^D1Qul*43imwxp3rtE!UtuOu$G3j#+?D8muZvr(V~60f~x41-z^_ z?VpeqgDmBcswlQF9;6tKg6xzcQ4~bcAj>fi(ld4#REoxt(e<$q&$90yGoWLT79E~c zhGR7pN3ro32@dE9%F>assNguvRHx*vsPhRW9ZUxY-6`oPJgKB(X*?#m4l^-I-ii7T zs5#|!FoI4@Zt0Oyp~Z9*i6Fs7MABk9G$kXPjxsi4E~}TSZhfxgmK}4Yns7()sR{3) zgW~Ag!=N9uK3h5p(}@@zN@9>32he_TAY9kHnj&h?m+B}!emDY{oWPim*`7ry9Jti7)9wC0K3>DQ_+r?5y0ANzMrq$qaF`_O zC``3WNn%d7ANP6}j0AcSTT%BqH*I*tf*83rIAvMCce91+I#(M^ee(NI!`dbq1g}8N z0j;ZYQ;711uqRTud^z4N9Is*2<;VZN+PJ)_cKLs}-}qk3%?vIrW|94%m~+a}2DxV$ z(%+)eJ>ziWqCO|ja0Is{XU_n+a literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-fr.pdf b/OpenDocumentReader/Samples/sample-paper-fr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e984ca1eef7bb731e18c626d010a3ee3e1f86cf GIT binary patch literal 4826 zcmb7|%WmT~6o&VH3T^_li%8;4vVcK=B#j%iV>C^SnZ;lhip6-CI#Q}jkm=KPJ8#jg zpP`!`QX*-k64iQ<3;pr%=g-6I$;}U|Qyj1bMiDCS9~bZ5g`2O>BD~C+Y+vren`|d) zMBv-ov$KULas{b>k6{gkKg+!SL>2itye!+ILD*GMyT=ukNaK}yXFgGI8NdFx~W9= zw7A$HC6GjD^MH5~L@41Y{M_W|yH&Pr+DgEeBtDHW`yOo`(bcA_gAvws7$X5Ys`Twi z)&lJX!UR3Gve30BYDPhV62|-H{zTPbw-*%xD{Dj}^az&LgQ^5!?1W-E5PCp=4Pc{C z_bN_JuhwndKqEgs-Cuj~rBQWLWq^ZQSq=Td#8W51y&fEapC6?t1~7^q3-16hzS|%P|j@Z`g5A*%?R1)DPuXwIYn7y-LfD4=GF& z)fY#>U`&Z5SdEiK*>a*YN*zy)m+P!KRN$pYq=V@w)miB%JZq(6X*|^(Ei*AzuCwYl zSZ#{ksDjQ+Zt00dLYwI*62bJEFiD%~&?TARw943+dDlKamsR7_XxXW>R0GZ}#pecm zfQ~k-S02ucldH0N${JY?mxbZvakMWj9fkQ!S~`?YIj)_g#>w|`D+<`jMtjr`w}q$D zQd{Y$I1b`uG+;NuxkWMds>H_2>%+aMcH#;4($ToRP|JJs(o#5{bJLh4kfY2NtPHVFZX4e z`xIKzmy|9ZNvD%iuR#u7rapz*O0|>Uifz?4b2-T@@5@O?(PVn9)VrfYVKMLtg_Bx$ z57CBBV^VdKuG%48$j$|uso6Pc+GOfKZyBIHQyJ896=IC=H@e8}a@&f{=j zUOEa6xdERTNIl>Vg=5O7J$k_D(pY)Z-tXab`R0^6OiM@m($Z1MoS6gEqcS#T!VRt# z(syd3mh~m2qnKxgcTU=X>6GJ29p%Q!btcs{b7t~5-j|n-N@+mHN#4n{?GtZa+KbBN zmkjpsderr9epAbOlhRVN+l~v!C+0WPdndJ*%R9J@o;K4LBv?@hayaHw+0G&ccNw+q zbnEKo!#P}zPeyy+9g7@GqvbG{;4(?nO<1KbMI^DeTX;9f;IShAdl1*)95lp7I9{@J z7}!iVJvWIuUFuuvT2xz!a)Dk-csM}YvUrdxy#mt=yt(vG3jOPgdh__-FB+#8Y|I`~ykfYD@qC literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-it.pdf b/OpenDocumentReader/Samples/sample-paper-it.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9dd1c5d7098fdda4e57e0918b70c438f71c193cb GIT binary patch literal 4836 zcmb7|OLN;c5XbNO6u5Y%Jy;}OlsJ>|jO|!)ruNjel;n`f0g@nMF#qZq06_sP3=(dw^P8QqFn>guRJwKR1ESO9`0iJ$jVeOx&m+Ut>Ud%F&#W zZ_%@?R8wwb1&%FLQR`nAF+EDOASls)T)_uMENbYiLcDFVzH0PzVBJZyY}U1&rJgE| zZbT(b^S#X9WSwn9bXRQDHY@hgm#nxhs?7fHC!~it_WK}LPc$UKVRb5K)GPzkH z?I4NKYKQo28lxFc;pb|Lep-mSZb|`PlH@YR>}Rz4j_y{i4My15FhZv3iP7DQtSW)B z9ASd?S+g&c=^$jx_;JMd0#zd4g5C&3DixwJ^r6Zk>zEUSvG*6#uD`WHqJvvk&GeGg zPVcd)YFVNWFYEgNKDWL-l>%^(O;nYH$pvg?_~;RiLD(;uEIKf_@8wRY7G2BzS#4x5 zM_D|j$b-MtfA@1~3`^m;r&1mc3N=MmPkRk`Jf9{f1}g=-sp~^mJ6P-1*QMIkf5I|# zy0t9juvJmwVBAYFY`papiQ{P;_p%)G>HM@uVEaKWW)eF|GqK-yW9Q6ChxV^0!-<}X zr(h|Dh9+3Al0(@%;37}0lJ}zAjwtD2+B@l1Nl)QXB|S@%q3LK1`OGT$D9S$|=M?*1 z584&?^gyaGVtR_iu(t+8GGcmkP6jyRWn#r#Hm|R$tX0TK2M>j%UUBXyKDOc=w0B^W zcQ~_BE>!s<4w))KyT{|9!1NU6BZ28rI;6SLl3FbvvW+YbK_4AE6qiOyPbJATne|I# zHaK@E#z7~s)$(3dV?pWIU{E>=Cu2f7G-08jjIEG&Z*Z1{k`Q-jFeDwt$e4?#XusZC zKsL8Be%kG_O%~cVo(;vLr!XDy(W4{@$jD|^#@k#q+uq5v*~gQiX!I0GhojMCACJz{ zkcVb_>jQi#b2+xJnWIDD=qWlI&XH!%cob4V$W3O2e31L0Q~s!=LqqY%9Hs9kLqoSp zo}#@=XjEau#^ZHWWgED9j;iS_f>G%xNGl_rI+TP?9EPo!P=LrXd@Oo+ATZ4p$Wvnp z$dfp9#h|HGbNLE2iQ4|eS znqxc28-#+>Qz@O&ev-F-ItNHFI9=8ANjn+3Wl)C(1JhBXCy(!t5A1OkGblHxD=c*# z9w?0UA=+W$nio za|K3Q_12u-gslmO`6bAk;5kdXo!d=k@-oqPOH-nL&?#A>S16lvfi^17#abQHv@0>; z_2u}uaD0c+uOI*WZR7Gr<=g-8!11G$y9vBnOk(#z3Fnlf9rA4{GT)-Yw{duK(Vvqx z9K&WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-pt-BR.pdf b/OpenDocumentReader/Samples/sample-paper-pt-BR.pdf new file mode 100644 index 0000000000000000000000000000000000000000..49a8c81beefc9a388c5c5de6e2596e0a03765a3f GIT binary patch literal 4831 zcmb7|&2Hm15XbL+3SI)Vhe+a=K7d7l&DL((Zn|mWW)F)!C>HJ2)|LW_O1FL89s(5T zsV~r>ERt3#QLPV&P5n3;{y9T(cy{y6>Kq4bfl-9&htG>wufp|jk0N}Nt9)PY!kc_2 z8bsjf?Zw4HRE380&r`UA!XL__`9L-KF?>_El|tBc(d{q0fN?1R>#T>@qA2sr`pbt1 zP@Zv=GV(FJ6;0jBjcCBJRb46l4o3qviV81tZ*bp&1+WSsqGN z7C90Jgb6AH`rKBZYW+o<88yLps!cH7zxG~K8=(!*2!Ynkpc6qDJ6ACsxLVZcF_-zE zgK@MQTb!A(UAK)A5`BAkxbons@##k9fP-dv(+C)ur%!@=pKt`KzAr^JfMEbm>zHcA zwbtJ$aTw(&&4Ls;@F!J_a~Til33nsKbB)@nRKY0EF$?eszpf#Z2INpVLV8c{>aF?} zGGdga9I_O}7RI9#!%>i(QY4CkC>mus=6d|jBCzA2mNJfvp!X##3Dq!o%!qm~EjvD) z499vbj$+eJ60F6yC`&y)^2|timCIsAN(a-?Q6Hsr6rPpRu{8Ec$rB^xbuNE_^`_d5 zdT zI1b`ubkxTbcLp)`dWnsiS9S9!3P|(e%K5@ii+cmpQaGLy)1oo+1!iQ#Tt4af_N_$R zvfjY76eDv!o}%NLYY|y$q+B)|S*pKf>5EH;`{L43n9jKAP!fBjWQmdT$M(rP*^cxD zrK3nT9hBWF{{u~9cEc?P+AHW7yrg{V$iqoFl>apY`0sXMn`j8 z&mB4umEGaSQFAMhBeCzCK{KP`N(%4B=ty5QItos<0iOu6E^QnN=aW%oy7;H5(eS2y z*q0k9917nC?s#83Ix3k{a)5gLjE#~|zBTP$)v_F~GL92YE$@p-M=?)!AN8~bvnk!R zhm;#Vuk)&fI`jDtUwS*-7nhF8Xh6qFe)Q75o_OQZ7Ck?!a^KB)Gpcb#uxBl0XGMW$bL}FIpt`J zTw8{^r>Jsm9By0m=cElsa8vT4jSz7EMH|Kc>dQDy90ykfgFE>IHQ)-~KQ W_18U(%BAWYXEBWyXJ^ZItHnPO)M#A* literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-ru.pdf b/OpenDocumentReader/Samples/sample-paper-ru.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3540f171d9e138d429254737b9ff566ae4a72923 GIT binary patch literal 4806 zcmb7|T~pgQ6o&8fD|Exm?gh5>WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-paper-tr.pdf b/OpenDocumentReader/Samples/sample-paper-tr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3540f171d9e138d429254737b9ff566ae4a72923 GIT binary patch literal 4806 zcmb7|T~pgQ6o&8fD|Exm?gh5>WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-rows-de.csv b/OpenDocumentReader/Samples/sample-rows-de.csv new file mode 100644 index 0000000..f42b5d1 --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-de.csv @@ -0,0 +1,7 @@ +Name,Rolle,E-Mail,Telefon +A. Bauer,Design,bauer@example.org,+43 1 234 5600 +M. Rossi,Support,rossi@example.org,+43 1 234 5610 +J. Novak,Vertrieb,novak@example.org,+43 1 234 5620 +L. Dubois,Entwicklung,dubois@example.org,+43 1 234 5630 +S. Meyer,Design,meyer@example.org,+43 1 234 5640 +K. Larsen,Support,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-en.csv b/OpenDocumentReader/Samples/sample-rows-en.csv new file mode 100644 index 0000000..4b3409b --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-en.csv @@ -0,0 +1,7 @@ +Name,Role,Email,Phone +A. Bauer,Design,bauer@example.org,+43 1 234 5600 +M. Rossi,Support,rossi@example.org,+43 1 234 5610 +J. Novak,Sales,novak@example.org,+43 1 234 5620 +L. Dubois,Engineering,dubois@example.org,+43 1 234 5630 +S. Meyer,Design,meyer@example.org,+43 1 234 5640 +K. Larsen,Support,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-es.csv b/OpenDocumentReader/Samples/sample-rows-es.csv new file mode 100644 index 0000000..1f89d28 --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-es.csv @@ -0,0 +1,7 @@ +Nombre,Puesto,Correo,Teléfono +A. Bauer,Diseño,bauer@example.org,+43 1 234 5600 +M. Rossi,Soporte,rossi@example.org,+43 1 234 5610 +J. Novak,Ventas,novak@example.org,+43 1 234 5620 +L. Dubois,Ingeniería,dubois@example.org,+43 1 234 5630 +S. Meyer,Diseño,meyer@example.org,+43 1 234 5640 +K. Larsen,Soporte,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-fr.csv b/OpenDocumentReader/Samples/sample-rows-fr.csv new file mode 100644 index 0000000..df84a66 --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-fr.csv @@ -0,0 +1,7 @@ +Nom,Rôle,E-mail,Téléphone +A. Bauer,Design,bauer@example.org,+43 1 234 5600 +M. Rossi,Support,rossi@example.org,+43 1 234 5610 +J. Novak,Ventes,novak@example.org,+43 1 234 5620 +L. Dubois,Développement,dubois@example.org,+43 1 234 5630 +S. Meyer,Design,meyer@example.org,+43 1 234 5640 +K. Larsen,Support,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-it.csv b/OpenDocumentReader/Samples/sample-rows-it.csv new file mode 100644 index 0000000..256b09c --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-it.csv @@ -0,0 +1,7 @@ +Nome,Ruolo,E-mail,Telefono +A. Bauer,Design,bauer@example.org,+43 1 234 5600 +M. Rossi,Supporto,rossi@example.org,+43 1 234 5610 +J. Novak,Vendite,novak@example.org,+43 1 234 5620 +L. Dubois,Sviluppo,dubois@example.org,+43 1 234 5630 +S. Meyer,Design,meyer@example.org,+43 1 234 5640 +K. Larsen,Supporto,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-pl.csv b/OpenDocumentReader/Samples/sample-rows-pl.csv new file mode 100644 index 0000000..846489c --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-pl.csv @@ -0,0 +1,7 @@ +Imię,Rola,E-mail,Telefon +A. Bauer,Design,bauer@example.org,+43 1 234 5600 +M. Rossi,Wsparcie,rossi@example.org,+43 1 234 5610 +J. Novak,Sprzedaż,novak@example.org,+43 1 234 5620 +L. Dubois,Rozwój,dubois@example.org,+43 1 234 5630 +S. Meyer,Design,meyer@example.org,+43 1 234 5640 +K. Larsen,Wsparcie,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-pt-BR.csv b/OpenDocumentReader/Samples/sample-rows-pt-BR.csv new file mode 100644 index 0000000..de0f727 --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-pt-BR.csv @@ -0,0 +1,7 @@ +Nome,Função,E-mail,Telefone +A. Bauer,Design,bauer@example.org,+43 1 234 5600 +M. Rossi,Suporte,rossi@example.org,+43 1 234 5610 +J. Novak,Vendas,novak@example.org,+43 1 234 5620 +L. Dubois,Engenharia,dubois@example.org,+43 1 234 5630 +S. Meyer,Design,meyer@example.org,+43 1 234 5640 +K. Larsen,Suporte,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-ru.csv b/OpenDocumentReader/Samples/sample-rows-ru.csv new file mode 100644 index 0000000..1d49415 --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-ru.csv @@ -0,0 +1,7 @@ +Имя,Роль,Почта,Телефон +A. Bauer,Дизайн,bauer@example.org,+43 1 234 5600 +M. Rossi,Поддержка,rossi@example.org,+43 1 234 5610 +J. Novak,Продажи,novak@example.org,+43 1 234 5620 +L. Dubois,Разработка,dubois@example.org,+43 1 234 5630 +S. Meyer,Дизайн,meyer@example.org,+43 1 234 5640 +K. Larsen,Поддержка,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-tr.csv b/OpenDocumentReader/Samples/sample-rows-tr.csv new file mode 100644 index 0000000..1380b79 --- /dev/null +++ b/OpenDocumentReader/Samples/sample-rows-tr.csv @@ -0,0 +1,7 @@ +Ad,Görev,E-posta,Telefon +A. Bauer,Tasarım,bauer@example.org,+43 1 234 5600 +M. Rossi,Destek,rossi@example.org,+43 1 234 5610 +J. Novak,Satış,novak@example.org,+43 1 234 5620 +L. Dubois,Geliştirme,dubois@example.org,+43 1 234 5630 +S. Meyer,Tasarım,meyer@example.org,+43 1 234 5640 +K. Larsen,Destek,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-sheet-de.ods b/OpenDocumentReader/Samples/sample-sheet-de.ods new file mode 100644 index 0000000000000000000000000000000000000000..db64526d360683b81ad0c2f20a32ee82d5e0def4 GIT binary patch literal 2493 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 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-sheet-es.ods b/OpenDocumentReader/Samples/sample-sheet-es.ods new file mode 100644 index 0000000000000000000000000000000000000000..2521bdec64317af286811bfbdf973d2145b3b4aa GIT binary patch literal 2499 zcmZ`*2{aUJ7akNoOJjx!O?KH0iHx+^ro~nv4Q67P8N`fb#?DX_reu#2*#?oV7<*-# z3?*T*M}@J2 zAIi&Cf;$064)VrfyuCf$T`**KFQSG&5exIeklaZyFK-+X>*eA{z!AwXlD97ogC)7) zaO6w>%lRXN3?NA-3(a7A-5dY_gl#PlHiqgKEYE5XFhqAejzoq95*Ny@<-x4^CYQRz{?q3;ca}F}`_ABge(?9Afx|$}FGB1m>%A4UvbK zIH|ALv7JD-7fzq9qMwOyW8c3-G%bKWIdJuzKjCoTDN_NfZaIB(@_7b0>FdkjFj9R$ z2H9FdFP(Q-$in~?(AT-461Cgs5b+#(& zT@2@}#Kp7=WfAMSiVHVIFApp`pza@$eHk;~|1xcj1^l&eH}H2E6L!%~JRtKiOC$ttdZ60(D(K=+sFIFs z)>z%Ksx(Dq8*0gh>FRy|dvGl)d>J|Kk|$}=s317eH6#+)IpZ&<-gH9|*J+Jf+wl8- z^0Vz$FZ}kUb6b-7oD7(&H%+_S;Eeb=ZRl+#9=$Q)y7w+TjzNv+d`Eh)^yd;RO_zqS zmN~MDq(pZ0jsqdYt=88c%PD|gdo8Iv(EfQp002b-0Q~G;yLb`FKc?xE3DFZG- zc~`#Ft*A0A7jQ}3>>Cs)gaLpG~()?qa%!p8nAA$ z*K~pUY**U%M0OltwKDf2GlL#{8MA4#F&}C@)n_w%#nG#_Q}S+Zz5V*Nh7wkQ#t@Mw zn**PD*nFYp(ST{0-%j8#ER-f?aj)T&+n#0pC&Aek>Xe=%_2aN@L1^Yw4Sxw5F8F9* zE;nd%L2#*=Y&{D~QxRs-cj&t(%=)KVe1Ue2^n3Py%V|bP34B#^V9}(-K_ea}<9TCD z;R#UC?w}i4=dhW|w3%c$I`tVW3IFsN3b`0{el*2l-r7zf_YsWN8&Xs8%~*f1=)#dz zwFix6jq+fB-ER{2@OOB4pL|)GsqU~%dsug0>*BEPr${}Y1cm0+X^IRaoO*Km;){%| zq>QT>BYDDlr-L8zEDX6QCy&q<=_rC}Qxl6OR17sy)E<7Bybw@xFg&*S^BW?gXz2bn zz0{#i8DE|^?Kk}FReEshN_|P#l9q*eeAD%=FV_2kvNLY6Du>q++;25a7MDV zU7K^>wj3U{R@FH*-_0!}US2$2Dr0?O5VK zVcjHOc?4ZCov;@_m~#I8NvYf!u=2w>18uY{g1^UsWLOb{q(WKZ zGB)Ber3~H#3g7luMXvts*fhsmy;oAK9~)wH^C12*{b&r3wGL)@%ed55-Nnd7wiZAp z%78Ubl?87g&veD9L7rgOPZg=2vTwTkM$O)8J*RjrmH<_1iS-k9>EL#1t>Ea!)_w8u z-}Ex<%3P7g$@FCCJ zYwez5*I0GP^$v?bCfN9|iQY~rEN1;^1qIaWV=O-#b4*2gPcQ5+zi>3b`AS;Vu81*3 zzVzc!>XdBF#9OCRI}yWC+ta2gZPUf@r7eH3t(Z1dyi(&pD%eMxg;9dNz3l^7%Bij2 zIeR$!CUh3$Ds9+2@t#jInNh(MhAT$EyxD`0vumfZs@4t8y3{?2<&0&viB-|U{MSU8 zVk8MHSijY~plZ{RRhKk1s@ofLeIL!pL=|!}@~=uf@U8`(qxQJ3=sZS@<8dIV^jO{* z8=XVhqz>(Ks zf%+?XuP#feHw|BI4_NLWeXY7IsvN)?jaCh4k9OQRrMJaqT@FqWuK&Npu<78xlF#Pi zpDWEz)W5GO|6l-sd=4A7`>#vO?@&-@tv|jF_z&O+Pvigq literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-sheet-fr.ods b/OpenDocumentReader/Samples/sample-sheet-fr.ods new file mode 100644 index 0000000000000000000000000000000000000000..265e44fbd09ecdb234079f44c981d6ac43623541 GIT binary patch literal 2510 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 W3#!>8IDz|%2Uvr_vV;3q2mA-^c~Fl4 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-sheet-it.ods b/OpenDocumentReader/Samples/sample-sheet-it.ods new file mode 100644 index 0000000000000000000000000000000000000000..3011475e71366f2a234a38cad3b0d7b832f5d13d GIT binary patch literal 2483 zcmZ`*2{aVy7a!EnWG4|LRF=W$X|Yt6sj+062xCb+CZoofF(cB*Fo~!vg_tN?sj)Qn zW#m~}#@LroF(RqKND(8;8}I$k>C}1u`<;94{mysp{l4El-?_hwuo2oK3;0)50Wlb( zcqo6fsUmz03l6S0cJQqo{It2QwY`O2pbs|S9Ew1Mh6Q3$lg;B> z_KU)ojNsiScz+kl^}aI>-9}`3>T7S7x+9G6!+Lw)IeE~mJ?!jUWDYjcnx2jSki`7U zvYxVwiQ4_iZ|p}H`k6P|^-P&8(66Tv-oTY&dkFPe8GDEqG1dKa?WdwYlvAZsJ~f6% z5b8pyfcxF9i!DJSQq+)0Pi2lzJYCDB6W9+-=@x$b%CVcQyASA(ig}Vjx@_|rD^%%e zQIXvhC&&Riq+6Ge7jreZ(K}BK&U<*K?Ne)vo9%B*Ul@@16*yXYP4xsH^so>B0OA8D z5HDd+giW+Jomkiw6-maFwq)qIdU}h+PJ`{jGfd6oP<360_vk#CuKZ)RWYDz1uNq7i zzDpqO4<8El(yr~9n84dCpETX2TXzh-ajT9k)?XmQI`B-owtU)_r_P#7v$ru6Gb}ZL zf8(wxj#1{T`sLFhG6UF^k_~m6{(;_k2{#7*miw|LAnL3NF|&BuG0D5tD<*kaE$pkP ziCWkFW{c3{o{mOm=a*mB-3duPSko5#nIx^Y=)|pXKxM=QGg3~@jr8IrMsPHX)b?_} z1+8r<8Mq@AOSlT;(deY}+jg_#FcAeY7xsP2kN76EUr)SmFNya?FMqs?9?KiApVX?2 zsIEL#oAkWroBkISW$lc2m4wjQ^B$bp;*zTfuyj`MKfu7c&*ouinSej$Q@DN3|b7 zx6OXYw1;fO4pms?Y?TqQtG3GFDPMi)k>3qF!Awd^xos`-;83v%Zf5C5>7c@79YqUS zg+(-j6vzdN`9HR~g}_*k&9?-|CpZ5IefRX?fUwD0GwZ5*`HI!<<<=E%U{pt3WsNgc z%KWxekNXYD;YZ!ACT?S|OBt)GceuHpE3%M!t>UtT2ea{_wu2s9T4JN$_kpe@D2b=L z-25R^gR-MZw1;~IRhOMk=|=*)k-&;;3Ou(8hH+F?Fl^?X8Q30kPyV<)U^-R?2Vsdd zcKMl416B0MX`QdarG#Bg-Z|b+b4|`Y&_f6UO(5cSeQ()n*e4W!`Hd|(mSLPY6uTgq zacta{Yyj^@4-fbXd`%1xJ1v=ugC2~V!kj>s<$g!D0C=3%s3OwDeimu2X zaNphXBr6V)4dKL&nC`4qkysBw3hg7pl-7@X3+U=l{e2IE#SX(?{P`vk&9N=AJ1;#7 z^DQKi+$Slk+A>QViT7YrSop1)6hY7fe`y!wSYP84NWyfA39SvGX-&IQ)cp0-r+FXm zhUKs~*Yes@HLnv+8_q4`+nnVW5)|-9#qDJ9`UAe2x*aRYYo_e@y%&g(z-$mVz|1px zONfIR?J}nB`C*4Kh9t0=50$Y}>{a|#r?bCt0|6a9x9xgIuYAQLb&r+U{u?~y;9Ct> zTAek@3OSy#OZV<{BDC7ksW5N4$!qR)dWRZ-4fn}=D`7CEt#`g4BlT!aSq3$B=6jo0QfIp=ySUXKDQs*oqpI&Y~2YPAI#%vzx%Ng}i;%3zduuFGw1G7}w>+&;! z(M>J|5|wS2o;sHc6*nv4oY{yAtw1lr!J%Dg0)r<+S8hbS@~>(!5m4e>@2$^5tloi- zL>5a&MhCM;A|3~`Nvm4y3Cae)^9u;d3jP0~h2Q@Fk$gV){v2U`M*a6#@^1_PkS}nW x@BZhI@_UNk3I1maJO0%_>Hhb)-^uD{T&>_Q)P=Cw3fw&0!e1P|E#G`P;BPJWT_ykk literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-sheet-pl.ods b/OpenDocumentReader/Samples/sample-sheet-pl.ods new file mode 100644 index 0000000000000000000000000000000000000000..61ba3894bef50de9b3e5da857b63e29fee0d5b98 GIT binary patch literal 2514 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 WiPT&iKz!dX_i;Ce>$|@{9q=E+B~O3= literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-sheet-ru.ods b/OpenDocumentReader/Samples/sample-sheet-ru.ods new file mode 100644 index 0000000000000000000000000000000000000000..0b466566304a6224c1c62ea1dd328b7481c8333b GIT binary patch literal 2635 zcmZ`*2{aUH8y?*3%h*!cMwU^`gsc^c$WCFpvS+=P zu~lRlAxqRRGEJ9k8M@Pd|8qKZ?*Dz~J@0bP^L*!h&v(xISi{(U5dr*jWB>{NS}9Ow z^36Dz7Jvyr2Zsfs-2(&tF`n+h7##Lo2-XXVb0=U3P+TAy>xJ{Y7J$YELkWR+w7VC< z7mW_K{vYQz1{uID^+Fd4GkU=S0EjZZrIDRJ#0+kHF2Eg&@kSGZp`ii(*;)E2y(+v$ zyIMwL7lV8p;*uv^tj4rr>$0g=MidYRgab343GWl!G`N8qJ*F5NV^&uf^fq&-+oUb- z)DT+wz1Pw~sBh<$MMsw>BJ5r-yNo(M3N9kqCQN@v^4AP0ctPN+*WcFX3*CC(6&^)+ zO3Vj57<1h2#c>MeUyDIWt-GhxopE@ylQvX5`rI67a|CVm8x%AyGNrsRHnPm5~hq8oi9L29R3(l?-N`Pd-k><#6mas=s89ZzKB zGt7!4hoHq0{IaN~Ie#PGQP658Qc?YM+zeu04?b1(JL>GmR-$td$~6pBx!!Yg3lTJ$ zcCP}@2kUpKy34NcCzbWNp;$3Q%x601{B4Zn5SRa2v=LccTC6}m$rtD!oH-%b2Yw>n zjJS!YGe;HatDcV1&^lzi`dk?E*JYY#sgz~A0^iEWj7aG4T8J#9g9Jto+oC@2Tsyq* z#$j(u5|GB_(!vlyL9U!Y631M!Au# zjQrN+=(v&bWdTv_Uhlx`$I*ZvXH5cif5or^0L4xK01tE4o;Ymqw_nK|HVp;C%^3qb z4;(q4IsMjJW@?ssA34UVQ_*32TAru;5~+;Qvj1{Gh6TS?Y&xf=_1U>9Ia@P*FEqueW>K{Y;(`NN7QCZn`B61GY6#NO~p@_`{y zMciJDPOfZtQm8V!g%_~G9XB!gh`mD$#GgCm*Su*9XBMKapwKW6tb4HXNfx>neT+0cYDuDF3s@24aHxow%g~9>qqEQ8n z2gAnZF@{%`&hzT5Uo#=WdIXV4vb##tA>^fj?e>ut5;iM0-3>QGqqmWCPib;Jjvlj< zYQdV&Uzvwb2}o!tHZwS>5Sm~ENI}l{mr*=hhTQsZL`q0gtX6!|(lFr2R=xPdy=nRA zVYkO4l@Y{vdg>;TcZy zY|%KaI76i^?7vnPG?+d-DVlYP>DKa0`JBrpE!1u+&@3FzR_H-65RMR*R$-O;0niZm z4jpHgFnxnv9&($jp-BHJ`Lvf(Lz2335I+RrY#}P9jDZ|;6|MxLdiFSh5ii{0D2Ibq zd+~UM;4*NqhmMVK@>Eh|n;p_4xuUP6QBL6r(p#!co~@%R4%se{7s7fp!UfvpdnaLM z1i4&3bv?)Tb&W(5O+l#SrclX*c~Z&+p=^h)528Usx2TAs-~JLze}iLv6~*&j^7gE) zVM8T*EzKBu5^`0kM5`8fpj+Y$ZgNbO(Ir7L9ss5Lb>na_x-@7vHl!)bNj9Al9OQn@ zx$ks;t_gi!@uT6dwXJfUf8rQ&M`!v!XzM9slq)cU^ogVn3%=*g#`g`!9wnWEVAZ`r z0(n%|lM38`=MsWNyl;<=3C@ssGpK5rwpJ4Qre*S9WE5(pJyMq4$IUqmlTYM;g=N9q z`DG{PV%}`YMdyHsb!jQD@k;PGeZTpu%U`Iz(~gge0uzomdw{&hDee|x$5fe9#JctA z0uTbe^2fQ9Y09PDq|3s|iML;R!_gGByu?jmXa3gA?DE6z0fyQD|GcFtO8wVf`_ifE z4tQtjYMip!6HK3tbP*ddU65do@)d=5qm zrBCJRsEZFrxnCX+$R`BC@5j75Nb{$x|p2#(4}=;vFnRKt zrTx{&beKHh~YJ$v&BOJrV%#j6I}Y?R`ZHZ*RBB>!}Vr!_PKKOM#PM8M51X8Q6-#DkdFJ zmrRY~{<6yj!K2rC9%iSPNV^nom!ci)Rqc>{o0G@qMOvLWF1G%r)0odOxt~Fvzq=!< zEvOg`%P018SLZ3_kfH23NcaAp1QgX{GgPT&DKri8es+;nNpv2OweZLB7h}Z>H74)7 zIlA07gCaBklbW#tCPwZZL`&UreaF^N9SyA4e5GMkByyuKMb-ox6ko0>WOIiqRz6$* zoNf;}bfF=}ry!Onnn80(;3LJpGu+xK1|*M_)>jnervAZZr;BE6qcH{|U!m{YwGZ~k z!nT&_N;vW%hc%3aRfO&Tiz((>`tK=YYJ%_5>O1P+<0;*XW{Xk n!jk#)cNy|C?&l@?9oNeG!%DS=9b@iV0N@wqU1xe2*SG9%1yqP4 literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-sheet-tr.ods b/OpenDocumentReader/Samples/sample-sheet-tr.ods new file mode 100644 index 0000000000000000000000000000000000000000..44fadad675f6527dd351b8d79f969d2b0c096a4e GIT binary patch literal 2511 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 RD;r3X1qfdO=|ol#4*;SMq1pfd literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-slides-en.odp b/OpenDocumentReader/Samples/sample-slides-en.odp new file mode 100644 index 0000000000000000000000000000000000000000..776db287cae2bdaf977e5e324dccb4f357aad00e GIT binary patch literal 1622 zcmWIWW@Zs#fB;1XW3@Fa^nn}@<^bZ{%-qzH%7WCyf`XjP8sezy>F1`O zo0ylGmRek*SCN}Db)sX}VFMo5@0P9?>^^Q;eelT3b?Pr<4p^M(IXKOC$&_c`9<$v_ z(`bF^CG@N6zjS%KH_ul|^>3X#Z*K9gm>45vQ!D+$N_Mut#g|ZV-JgPyU)HWXE&H+7 z#K3>a1y85p>L9xpDb%t;XJxlNe7Y9RK;dNnUef^vUZtXWo=8^VDx%<9I$wdCRGUqKd`_ z%~jkBPw~{%?ptWQ=SkoyOYtcWoi6(srB2-VeU{{dBc~p$oN;hnXoRpbPne5Qv+mJd ziCKaVC-fc<6E>Rlc545VfZUr2-@9zTdwTEtUM_cX;jWC6x$AEf-<{o7wC;Nsd$964 z!K<4T!`3V_sNMPd?XRL_qxH%bjml?~H{{ermB=V8*&JoXZYAHS-B@zV%h{_ftLXY% zR^dm>Pd+$a{mAzJqlL>#o41AS$bM9{>W)j|Y96`sA&1x_3wPKN~J9_v01+(~JD5fy%0%y}OHv zfx#9SqTIkhP0r6N0i{1+s9p{8&bw_OaQC?g%kD54>$QR$)0){_xl00BwiYu)NqOpM z1U)@Ie_hoyxwYyqJEpK4^$QNq5N~AcmO58GXQsJSX5sGjEH|6XVotXB>95ydoVlv! zw9-QU*WWMl?v0Jp37Pj<PwlQ-n~`M&V_ zz;o>m*MhaS>7wH8E!TWDJ8j;Tv!lB0p43&T!&j#@EAH&lUdFArxOY=Uh0}Vy=b5hR z&MC@I1T~J&>*4v|Rv2?W%e(qEUqxV2cg~a(drU)}UbgI;wd}LaZ1zV-Qzl&5?0L^p z@xZ^wEbH(8iEX<)d%4jRuW%oma}!PXFE5Vqsnai7{@*Q?y+8MTHZPkr*W9T*56$NG zc8WRt(GqzXw_1NfR1mjX=8Y9IHZE9v%$UpXy+XR*jew2QG_LP(-4OU#_I%FF3pcaZ z^q5b{opw1g{pRDc?RG7t53)|y@S11cm;C!UUbz0_OgHt~-7;?bX0RNY{~^~~r@rpL zqn(DD)K-&?suR}tWuB?xxj6SU*M^ppJxfkS7`HtZ&P!VCRNFMqCUC*E7pfe${HhA) zU#yxsZNkoHGwVIA$^-i~U#ANk;1SR}>8|b`lw7w3 zG>&<7+_ZhZN0LwNx~HiWC@FI{?2&gN&+$`Nw_e&7cx;+f!-A03!%e+O(b>nW7ZwKX zewCuvE4WMkpS$qh?d>P;-5WWJ^VXPn?0O%Bp AkpKVy literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-slides-es.odp b/OpenDocumentReader/Samples/sample-slides-es.odp new file mode 100644 index 0000000000000000000000000000000000000000..d86d2805c7ddb1e10e9efe8a82b804afdbf24cf2 GIT binary patch literal 1636 zcmWIWW@Zs#fB;1XW3@Fa^nn}@<^bZ{%-qzH%7WCyf`XjP8sezy>F1`O zo0ylGmRek*SCN}Db)sX}VFMo5@0P9?>^^Q;eelT3b?Pr<4p^M(IXKOC$&_c`9<$v_ z(`bF^CG@N6zjS%KH_ul|^>3X#Z*K9gm>45vQ!D+$N_Mut#g|ZV-JgPyU)HWXE&H+7 z#K3>a1y85p>L9xpDb%t;XJxlNe7Y9RK;dNnUef^vUZtXWo=8^VDx%<9I$wdCRGUqKd`_ z%~jkBPw~{%?ptWQ=SkoyOYtcWoi6(srB2-VeU{{dBc~p$oN;hnXoRpbPne5Qv+mJd ziCKaVC-fc<6E>Rlc545VfZUr2-@9zTdwTEtUM_cX;jWC6x$AEf-<{o7wC;Nsd$964 z!K<4T!`3V_sNMPd?XRL_qxH%bjml?~H{{ermB=V8*&JoXZYAHS-B@zV%h{_ftLXY% zR^dm>Pd+$a{mAzJqlL>#o41AS$bM9{>W)j|Y96`sA&1x_3wPKN~J9_v01+(~JD5f%;dgLTUyR z149}xM7e>1nw+0k0!n|tP`w)Fn0MPiV9#?=mg+DW>s$ejY0O(P*YVEUQXaJ^g-s+} zRrC0}mH99EyKEHgUwUs+Q4QUAIYhLGljp{jqVyfRH^)@gZPQeZEY4+F(c;J7uklc; z)n|p$!uWOii-N1RS!zfzH!g|Sjy|}xw%c}+TVEXinHP^5woKZ5%c=8U<`eGxg6=cTZ2xArY_&FB z7#@`JCo1A(X7c$+%_n9HMK7G+c6XBG>Cz{67C)#wR~+Uoed^kVr&8NF%Cc*; zjdpvzc%wV*xOABBs>_ktHy@PkzSmazAnQbp;`9xfy>)CMNB;jPS-kgI?3-5m`7Af~ zd(3(k@#o*i$u&{;3bd~!*i634q`&NH4bN58u)XWDjxgVxB(k9+P3HXHyKYk?f{yaM z3G|t#5t00563apLxsT499AH-~{9~XSH}g~dBe~%F>+`zq-Pf$?oHRSCSNZ3e>x+&n z9pAV^Ospa`@>bABrr&A(uUSq1|5z(_Rr|8_5u0TPo>z2-oW1+kY(m%H+a@hfxU?=z zv#u;Kkx(*foLnJtwN?7x+#3lG|6T9yxVu-i%&k71e|^Wh!tef%9z6h-3XDu5%(zQg zU@8WKCBU)*QRX6aVJ}7@dKeg%Fopt|SPNBjBhU*Zgb{u~s}aQ$x<2$ghtRhem=lq5 UV1PF(8%UA`2wwr|6jl%q0Q^L$_y7O^ literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-slides-fr.odp b/OpenDocumentReader/Samples/sample-slides-fr.odp new file mode 100644 index 0000000000000000000000000000000000000000..cde0944f2932baffb3855cabbdd0fa75a1094396 GIT binary patch literal 1650 zcmWIWW@Zs#fB;1XW3@Fa^nn}@<^bZ{%-qzH%7WCyf`XjP8sezy>F1`O zo0ylGmRek*SCN}Db)sX}VFMo5@0P9?>^^Q;eelT3b?Pr<4p^M(IXKOC$&_c`9<$v_ z(`bF^CG@N6zjS%KH_ul|^>3X#Z*K9gm>45vQ!D+$N_Mut#g|ZV-JgPyU)HWXE&H+7 z#K3>a1y85p>L9xpDb%t;XJxlNe7Y9RK;dNnUef^vUZtXWo=8^VDx%<9I$wdCRGUqKd`_ z%~jkBPw~{%?ptWQ=SkoyOYtcWoi6(srB2-VeU{{dBc~p$oN;hnXoRpbPne5Qv+mJd ziCKaVC-fc<6E>Rlc545VfZUr2-@9zTdwTEtUM_cX;jWC6x$AEf-<{o7wC;Nsd$964 z!K<4T!`3V_sNMPd?XRL_qxH%bjml?~H{{ermB=V8*&JoXZYAHS-B@zV%h{_ftLXY% zR^dm>Pd+$a{mAzJqlL>#o41AS$bM9{>W)j|Y96`sA&1x_3wPKN~J9_v01+(~JD5f%-=$yki*? z14Ak>M7e>1nw+0k0!n|tP`w)Fop;+n;O=h`mfbJB3g2vTREXf4z;@Hj;nKUz&Pka8 zOHTFM$CloX7PB`{Y9LS`r1i14(ff`^kUBL)Iyh_(-&7Y8qVXp;8&E?t8>u4x8{+l&qB`&2mUWM zC|j-eqj7VOozY>wm?obnFaG${gJatkt(oE6c}C^@9@D8Yt626+ES+9iCfT8W zI4r=Qtuoni`7?R;ijTkEE6K#p?F#S+71}4ST)6+Tp+C!hgBP4Z_d!-y-Brg6Ud}zO-%&oqp5L^9=^>26kcinG)$NAoG%Lbn>L9=#l;$}H_ z%R6&HLV?fUmnAVrM9|VmccH!6FFXo=HB+0qZyX-SIBw`S(@%`xX9OGA}6)(|0wZ)`FH|9V7#Nl?h60&bi&%6c(2FO85q?0c5rq}H fKJ*-j(6<8sezy>F1`O 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 LON?mFdRYAhOj(~v literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-text-en.odt b/OpenDocumentReader/Samples/sample-text-en.odt new file mode 100644 index 0000000000000000000000000000000000000000..1149cf7b0bfcbc036d9dab4906a7e11679f07858 GIT binary patch literal 2033 zcmZ`)2{0RI6b^AySGA}nL`#%PS|qM@q+2YiC9JE|mADf}613vzQdR0I;!04Z?rOCS zb=G~g;@G;jtIkzdQAcT&joqCwYj)p1Z{Ba((!{UiBA~uL<`cJb1 zC4LnRT!L04JEyM9%`HXn0j0j&s6$xMB%JSP;%THK~cG`2t_mN^nflH_Oel zSej~%u4FDTt~ypNAUv#@*g!HprBc2JrWEnlOWQFrVa4D*>4S08U=sCk&{Ge+_hbN zDz^Fi>KHzFE~aRwM7K-|EK$k}mX`0ksNtoOVCwhiF*P}LQCDV~hT3&;WnIfZeQn2C z^J1IIUTjv7Z+d8}<O{2?Qh5hW4ddpoW+|f6Y&#P(7Z?9oHDW$c1X7Pe@t!C{KKdt`=WFX*`^`Z zw?B$LR1|d^rYI+SfV#N7=R@_LNJxs(WTM>#y@`o~LaoqBi7Ip~`k9ekE=ox{L{7sY?)iW-iuJdl*lu&XjV;pmA0{og2h^fW4Yt9WtnDy2 z-vX6hT^(@)6^W=WSNpALw|z!fTzgD-H-nI|I=%`^Q!UUlhsdm3heq@aObML8Z?|;3 zuLwOd>j1n-AczeBFyIFOc$u?y@xc=h{vmVNTVI{cWMYTh#sEN@9aQ)KN zcNNBFw8JTu!f=t|GsSWX!-15PkQjzZc{7)=!P&H0P32mJ3hg=-+aHqGyE91vgiY9S zjQ@2x^YZ76ghu$dnrgv<@RPFmaa(pMt|ZN9IV^`Ib6&_@}n=NmVN(eCB>?CHs3(j+FVB!eB8o_~^+CG(w#WI8- zM~h4GycK);TvdU%&Mhyk;*uy0x}~TeqH3&$wAB(flS5ovxb=XMwex%OOt%^#N~gDH z^^aD*_1enntgJ~mU96Wneoc9>R*RDT>`BsB43E|DKI{Xnvg#+qSUlsjC698zJ`8LdZ|y>(Z(U4A9>lrJab4;^mRE^>#H06`0woSzBAb9= zcUplJ5(|@8k~hxY!q?GTDuhr7BB?d(d;NZWz%>8TOQjcm(J0`CH$fm55wYCyZNdEW z&bzM@4@K2YA@qD4oNjMsCg!q&yAN{a<^buFpRH#4|H9f}3XZ?CFH1H*f4Zx#JtU4) zo#@T0u5d=gSw3~0#j*c*o#AnN&v|jA@E!SWYUD%i%`!o74aLylRs)pt1BbZYUT3)4 zXBOPAP^6PAk2>|O&u(z{)UM76w()!@mf#7=MVda>d)?hgxzMLl zobpsTkt%@psyA|;wPN2w3O^Wef?6wdmU@C$s6Tp^Bmo%1=)5$glem`{SN%H9fauVrL<=DgwIop|YFS;=$EE9oF zSEszSKxl4uj4J|J=>Tw3vOaCbedR{!Ntbp;7BoyOCU2NWTTJr3g7wMQq6t)ai?g3jYa zT<(X9T1WFo$JUBS)!O@9bJ5fxKh@CtwB>`c8-HfHs)Di J#T?eIVNl>(;Dba`o5!5B=(kiK)qSjjS zEU^|X)fS~1>DY%V%1|cWymOp!=H36?bMHO>`R;$dd;W7jD|0SxAmDG42Do&p3qsk& zz8__~7sdf#EiT%csF+$_QuT7hVQ!;+{a^uJ*!wB1{B3H2(aU$^Q??Q7 zvS_N-6Jx0yzpS6fs!Ox#>qua2sLZU2^cHwybAX3;jykz(Mmp(_1gZWy!Mks zhNLhN5ol4%=vZ}Np95XW|RDij7N8OM*)TBxMv|pVhsinPf%C%g;``zhEpkO*Pp;-RAsCleoI& zrgxU1xl4HzfX@u=Krp94#0|hd8G9W6A$@_(c9aVM;Ab=T^$WzJefMc5*!1DrPm4Cq zD2bAokc?V+OPHPa{U8sc@SFH#!8@&Egx!|Sl=O}=)`FTwqh8~pFtzO0l3=wdpO+3s z*K)JTZT0E}pKdHKMoDgzobvFZF^_b2D#j>JJ+qFuP$>``{0cLDiuc%+DNB1XZ8PB- zALOyCqrviUnaEM=En~}(LR}}tKN?7m1Sglk(*^TwlyBCA!Gx@QA0cywb73YAr1c$V z|9Q|;6_ES;2O4RZQ$2jxxzLN{U?~t)F4jX7>z6!ytOHsFuCu0CSDHEHn5fHyXzBde z`LOml?5q6}Do@g)2_iJzHwp~so%27V(i{Or_u4qEZ4iIxe@1K$X-8XK-jvki?1Z`F zpJ@&l8=btY36Ac$?YuGVzBd?_&>0`zJLsFWGPwfF(0X>!Mq2KheQ0Fg5K}}9x7ptH z@pSzm`1)1A2ifHq+OK!81KlsC?A{~xl4U54z#jb8#z%qa0J{!)bk!8uK=!&{O$ z9e`2aIFPJZag=sO7O&Tq_n#aNz)50>)I!5~hg>PXj&o{QGuFp0of*T~(U`{0V$1ED zANnbj7o@16a#nABkV|mOZpdoOW<`L;^hj@dkRu^We2GcB1tQp0_`8l7Q9(V83N~u4 z^M!9*#rqWM#ta-SVhRd$5Mj`c1cNbsDM`o6A)qAqgBMq^n809GaDaz%;7fyd_5;7Y zeYzE&1aA@WuX3xHtOoYKP(Fv0>UT!c@l|OkE3OO%Ga)EF+nU8Q(`O1XoJx7PF3zGC z?*F3x!)l=I`GOt~nVTgcajhd%Nw*Z5ruOV+` zsRTE&QR4Xkf^6HWr=4@c#Z3+5qo3NhF|tj4@27M&ghun^vZ-N>!BR?h`3gtwcASVhqSM{?0iOaUn-dua#RVbdhua~-44z%oLR z8?it|Q~u{C_V97KT#{%JEuMsX-*t0`8z2{Rln{v!YRJ^hGte8Uis_S^z+d_hbjtdX zXk>(iy(qq(8z$twzzQ-?9d3Gq4i;n9`39O~*1Q}bqr>5yd7VQx($av~4RS?y*4qqP zlsD~pvk6l>J^MFc-tq9MhzRht@LDu7&M7sGhnN3jYVo}mUKC6gtRSy8ocTIDZwaZJ zl0#n$!bWE&y#cCu9;cEOT^QHT8AMkD)w(4vtTR8my|FCU1Wt1D%&ymGG>~(tPr8J!^)=MeNiXuorq=mY3eo+ve`h)rpYuPu`2Y=B4WqZ|32NCM%mL ziauSb+Z*!`PmP}wjQwe&I(NxvT6g8ldf9|)qIOZMlS#AYqtX*NTgYr>VoF$=qR;m% z`%a)1Q<)e4aj63P7BYCLAm&+E@!7bcPDz19`FryaOeWX1N6N<|g*iF>tzX8kILQ%p zXP@suxjrZc#!)FlpbQz_=+cE4&FzQT4VMKX^c{mxCK4lj@k_s?ukjy;Xu%eVF1R~B zo@IS-0j$H5qbmPFE6?iLEVR4b&6b2(&#E@Lz126%E+7&MX}I%qP)jtR6FzHT0JCG|63BXE-7k^B?az zQylqXswC)MF5uW`^ZuXgH$Fscq)n60Xj12$) literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-text-fr.odt b/OpenDocumentReader/Samples/sample-text-fr.odt new file mode 100644 index 0000000000000000000000000000000000000000..4258475bd7307de2264d496acb740da63cbcb6b1 GIT binary patch literal 2134 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 S1OyK+`MGC_8`XpktN#Ez&530I literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-text-pl.odt b/OpenDocumentReader/Samples/sample-text-pl.odt new file mode 100644 index 0000000000000000000000000000000000000000..2fa2c42e3bba589443dcd22745cd94c20b0e13d1 GIT binary patch literal 2195 zcmZ`)2{aV?8XseQSwbc;$Vhm~j4TnojH0rQVJt&TB+F!GjG2*rNj1W?WUMtqvS%+( zl;zq+mT)I>O^M8SM6yLD(H-x;b2_(k-}gV?`M&S`&+q%6-*^7!`yp)vh2#K#8U%o0 z>Pcwwi#-?PJ06SorGyiGy@^B|*2kNI4I;p<6RtvoyvbNHG>GU+xEkaWg7+m*pcLOQ z3i5x=_Mi~J(w8owc7E0?004ma(azGzT*nG=9)|ZOVEuf_6lfS8mvy&eU#G4FbvZKW z?zYQ@x-Y}10DkxZCGQ}+p(?NGX(-rOQ*B-c!fXG&zd|Z>c@2EMPsFiK$0+?s-U#}c zmT^I9kBU@?OSoNQPxqP|w5i-*zs8bjWGQ*J%*#!KRae(X&#DdRuLJ$Dh$7f8YgyVe4do)u}1B5PB z>6W=;(xEdNIgMHfsB=(OM1WbG7cpHTu!9}E+qQK#v%8wRsH^|n^!Z0AM)k$YDBWq& zGdDAbhxA*WO?qWhmzO`@R@tmn4!{@B2)|%zCmf$HalBzsFCG;&h~+4Y%GgdL&>&-L zsehAPW$Y)Sv<%g5PB`-5h_P}L5A9FQq3*#Rm~hpyh0f%4$Kc_Vyi$^+O^;`Ju82m* zYv9Xs@`XC`{^QyDG^}#pKX4ynENj4r91tEH6MeYIwm{TTYEe(*Heo& zI<@od_s{vUtLP=4A{Dz94N17f=|O{Wwkp=)~YA>Li~pXp9=!3qYsL1O>WfBX`<8N1?aBnI=`8i0JWI0m&^^b6lrduH7hUGH0^=!eFW=oKTP&20*nf$~>s>RjG-4r}zkJ#!@+^SOHE0_~(IbU7h^meKB%f3k6!_f9Sq zaXDxC`~)gf5&t~Wy3$S`k(kkAV*vixAGwyF!;HutdmE9z=tp5IM!hjsGv%p!^1|BN zyqOhaOCGg^`Wnvw`f%pev+-%8F65(grO9<|6{!mT>{0sIJnN{xGgC01ETS1|OV$8} zYQnhnTPA7MR1O%$^T3{ZF`G3g5Tn=39k^F}xFN$v{^}gL-X7nsARpCbec+d(25iOH zS99n@gLUvmefp?wdV6MGZ5?K+ieMS=+K5`R!D&S!3nif=IpeG|@5W)E&1aRsf(Uu5{fY`Ze!KqTHtoa$f6kT=$)$kB4B5K%UPh*F0s%+synDRgH2>5yic?1 zFGM{8%pYoq6=;HhTtowv959zukO%IfwcB)m_QYlj8O2h_GXK} zX@?Ij4CyDS8A?IBq;um(!J}mkPRJRjS$DlF`nob9&DbgoBsRWI$w?i5fPuY|0z7w7 z%ZO#sS!>x(a|d$sVj5aPkGJhGx; zuI)(cg)TI$HFu}dVRt1{aR}6OQQ+P!ve-F7d4+0QiEYVwz(S%2K?Ims>RN8*Ac_mj zr~dM!;?Z%T5xD(mLo;v9}2(W`X;pF|tehK3GD%PkSVv79Ut{WmS8`FodHc;)|2JCf`T; zWH;QGAZXWspE+BD^z-HJ<|g=9V?| zRV8V1@Up6qSEcIV@lB(~Bmg^2#(ziH!r5TNXWy#y`0D4gI0=(q)z}q~oSjrI!B3!+ zwN*tn@tm}zT$;B{dL;l8N{98ldP3MfF&JMl!yNv(< literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-text-pt-BR.odt b/OpenDocumentReader/Samples/sample-text-pt-BR.odt new file mode 100644 index 0000000000000000000000000000000000000000..42eeaca0825fef69d82f8d89ead125dea3bb42ff GIT binary patch literal 2102 zcmZ`)3p5ja8y~Z&#jK*yUc(}Cix6#!y~#D#kXuTOx$MHm5UP*#M#^}}*b?S`d)=aB zT7}X@smN_3l#pwTSMtvHe&=*v=l!1ldCv1Z=YM|B|NNfwKhMv>1}G*C_}i2K-tC7Z zRE5Q+ZxcEpkbt8`k#Rm`a!8=B4>gcPJQzXr()0x8-gGLGm+@(m~8h*WJVE|Ti- zzh;|ICBRp~W3g6Y)*%7_$OxnD31_U9m7V!Pf)6p!A4j2TM-oCZ=v>Gn9f`!*3rX}f z*Ck~f%P`ke;SQCtr@y{}(bPyo7^$Krw3Jp`H>66TwAlqj#51tdA6kZ~`xvj??yDK) z-e^NY!(F3n@3uWza33qU(cP^+fl0%v<|qf=w5p{mp$xd+kk`i7I80V1QRbX@cxLN& zkEuUomxkv0i5EU6m8_PTRwyD7 z)$?PgJUMLVCSzm` zZ3sKP)4nf8%>WhO=d@~S_r3(}r9N|y<`L@U9i>=2`6zkODYPqvQ4}U=({`pL3%sA( zBl_|JS>Eo`gZ3N)mlWOQ?gTywbvc&Aylm4 zk@fE%zTLh!@AlQV0BQSRzvSriKIzELFA@8+S}v>NI!}3hTMl109&ugiHcE7`SV3Y$ z+qDD8h5D~dP2?=}5sA2D8Y^iPF&W zCfQaVo&X+cesM$UtUrV>qTd(9h&A5uT~@!)f_7`FWs839m#M@e05HQQMoF1A?kLN@DhT zTCbDqS^uzW=7o*YhY^i}Nnj7Gx%xIU>2_p){?+KvcNRxmj_1?Di{@$z!7}eaA7*+Q z)X|dI`Bv`J>i*J8F3%S+Y}2->jBtcy+|c?eHw?N6-;O2)%#)c!B!x_6~|N{fi+C#G=t_9I{@_sin5U^0{hEj ztGi7W52#^7;j#*#MKPAZZ8g^!$gJeTKFDQ&c+65|sTY+ZoKKUo2kIa(*)>e>JjY7M zqBYf%Wy38H!f1@yxUT-IAn7xQufttLvh_w%)O*gEVz^!E;*Y0c#_2(=g6YxUzFzy& zB{gFBEf#dTU1K`N$eMwW-ro)WV8ELzzr`*&fdw%RtnjAJef3iXwG@qO| zS6}ByCO|T`tK#oz0#xXRs`*%qQ@{6@{ z^WrkkGJPliNWvp6mo5W{f|@ij4JPo!^7xTT&Fl=m6l#Kb9XKAEi_B7AtDd^5~=ZnS@1Mk#1-mLgH^>)#x>2X zUyRQ=Dj(@Xx1oxQf}=l+@CqB0Jr9wLJ5^MITk%s%>pVG5=vR)pWbb-!#mK^l{nPi{ ziw-s-qSCm#Z0N5h7!t`I|a%+pNiu1FDiSX&4`m+_c db$kBAm5cskmpa&hz?+w1!ZRt1hs8ImzW_d-j5PoN literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-text-ru.odt b/OpenDocumentReader/Samples/sample-text-ru.odt new file mode 100644 index 0000000000000000000000000000000000000000..727f2cfa2f4be226e8d1e1e74a9b13d3d97bf2bb GIT binary patch literal 2401 zcmZ`*2T&8r7EP!TP!fuO2qA`Mc!Xl26r~CX2qFJ3Hs@-a9*cj)f^ZhY;Xzg8{B~tMbXQ z7W)&#n%*AXSYjX^>x{>Hd0cZQdida!$T(M|kF%eLAJPYp#ku-iBY9(SL?jU#K(zQ@ zvVABF@NJ`mqlFdq0097DmNzrFq^oFbZm8t#jPr2A`Vo-<-d?FmZ9MJDe36SmF-hCj zYtq>4Q@J|OJYvS-@u!b78XNq@)#Q%ND#A8f_V~*V`7izuC--q#)+nB$z%$<3ypUJR zP3V$5M6wPvtMBUkab>z7VQ>&JtC_4TmnrR$X#6Azb`0INDtYhoc5_yC8cx`Wo0QhF zW4llzx<+3b#|3?fDcvmBc`PL4)|xq*9CTAXIa&bu>$}+tcv}JfnHd@{W9Y*G+c)i zxao@m*ndhky9~~FJMo6w#NL=?WoZ{^5MnwI^D6$McTgw|9{K|tV!3{ajFt-s_ zGdc9k_cG+dSg<_$*qt%UO&#;$QVn~=_vik$1pBLjQYG{4u`8B@f%uGK--D)I4y6yc zWZOpAUh9kGD~hs z7II2`cV~1pCv4f~+qD8ovnJVtOxl=GK>r*Wu1F1+!}eqBSJz3qr$1T$98`<6F#0K} z$<~c@#}}dA=xB=>p~NHm+#J@K?t24a@!c`E`Um_nmOd;Y(@zx{U|=#UHlcTDgH!y% zxSt(8lhvVr^qTKhvv52o0I&uD0C-uwzUG4??!QA;vny@rxG6)S<^fFH8)z+=`gVQj+w0ex<5$&d3bFUCTwhg78b% z&otazDNg-r)wG6WFi#EHHZar17@}G?GJ_s=N{BDdP3|&ai)Rm&bzdP;f)JN)@NY(2TIZ74yEe;$;GG?Pka7*CKh_ zp5fG5%_=RzBU;i_YgKIvY$`d^D90{pt>`H5K)Z} z*v2}S$Resqpps|g#}}W6&?OsY-K*qW(*Z&zsjlAl0Plp-&?&cdV4+F<%{XVmgF=CW zx=`0N)1e^8U$Rk8s>l1&L)5L#h?Oa9N=@5u&g;?TTWVfQHh+!JGj#V;XE#bZ+Sg3c zUs?lUFb^KI-Y?cr1<%`aDd#Xoqp0IGv*vFi_=eu~{wi)oLz=qgJZ+Hd0TW4rM@kh) zWptiln9`?_6F{ieK{aP>Dj~7y;WwM-4@q9bd0v$M>RHkCj@RtpR`4=lE!|QH5*Hax zia19mY6$)uDX^JP&e44mLXw@

j8Vhn>h(jU?*9pvSXyA}ykk{B1eKh5%Xi@-qow z$#_90HZ3SR29g3k8FVNmU9i!>Juw>9xKO?^E9M`Oyv*42eFbyR+F;u9*Q}Ovqj@+U zCdWpZ-Rhhmft|(j+_BH1itdbtf~w)b`qn+YR|FA!aN?3c;_-gzQV>+M7re6_ z{o!naMt!|<39ndU(j2E z8OqGgQuVb48=NP5EOwiW8@d?377Ej+|csdsBDg(dP$H*Z1@t(bGL@i~1fiq1=Duow zw6+-Tso`xw{p5q!Y2+OIIlAGmdGXBaa`oW^lGT zCNQ8>mH9n~Cf@g(lI!_XY?{@d(0!;{SoFY}eEuOD=T9NcNCD%Tj!T&-X|{sSw9>1w zJ)DjQ$_gf=?L(><6ae>fg1*-xvU(5NO5<|5aK1nc`1!{+&Xbb@Xql{uB2n(fr0$u>FH} UEKE7M_BT0LW1i)m_pc845AsG1zyJUM literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-text-tr.odt b/OpenDocumentReader/Samples/sample-text-tr.odt new file mode 100644 index 0000000000000000000000000000000000000000..e2a5862adfaeedd3d2e580cc4bde21072f4d85a7 GIT binary patch literal 2092 zcmZ`)2{0S#7LKL#p|J%eVkZQteZQ982H}Z_+BKzwq==B%)l#jtJX+c+B`vM(+AeB) zweL->Ppe8*Ep6>WseQTe?wc{!+;{#tbIzH6zVpv_=AZMSEm>GWfIm$VfbCM_f-;I@ zKg)1Gf*+0&M#8z1NWKIQcM8Fucp;eR3HNs=6UcCX5{~HU?-AsOBU0cLTqp(ozh=i! zNxt+G~1Q^i@aoI!}i88(5=T0Pe;m8ztsGslSlva*56|Q)CL_*4*{ZAPj zRr|TIcs3zLwW{p4=%0 z46+Zis_E?b;q>)o^3V`$PCwNInkhrLkE~3Ql+tY75WDwnuPKX~Mig*k4@zs^cU~+% z|MTU_jxI{t>T+AsZ1shb=^U=7E4tSZL_3-hcvFr@hWZ%P!c`aAedgq$H zYNy6wVrD2QJ*vZgdPXQ{6Yy8Yc)kP4OANN7EC2upgE5&B=8GdA(@e7MA+}5KG|VdU zgiOmlsgXy)?ff5yLPb(DTxR8g^$bmO3lO*4yT^Zz zIyGyv58r(pSpfiZAOOJ0n6-yLk#hVG8N)7h=p%kI3?yyLNhoAjN)%A9Jg9J1S%AF44ZEk9!EEzT^Q>ZE;iYG(!kj zbo1u>_SJDwaOC1w6>YaG%CtnNU0vqRf5t!eHtTsRcE_@prOpd~LZb4tIriSU%S=oO zfAl&p1)rLKZxF|ty|l5E+7&X~Q?m%^n=j=sp?=ES& zOjyvNo*k{z-E(jii3aKesf9Le!#{_hd)3yiy+Wk!-Zx5R`KBWJ$f&y9)e(q6lTORJ zRMS@0MenThQ}+*euwwUA8v9=@Hl6+Qv_wy};dyvl{jQ*aUx`#$)vcMt+2wljCKuXc zX){8;SWz8yPc~6p)i)GRC#+v3cNeBEzjl*o`M8DfSjuta*tR~^$2v`v z-STQ0m9Lo;9+0iQNVc~Kciah1n(Bp>ogw#i#an4A3@tl*cfg8Bl1T66-F+}ZsR@3K zJ{j8m2rD&;{sD%Y{8E09INk@z<^@hjx`@Utg`~cic6(Fl^lA-I!1S+NdV;dK7ev(j zi2L_Yx12byk^*LMxve3~x6zVl@jz+MR>4ORfvU4Hnp=9`B*3?OZ{5brdv^QQCuC~$ z;7ybYoL`u)l{4Qxc!tf}@1@Rm#t8RiRp1Q9K)5Rld>J{yncCoU!=!mxDyoX*y9qsQ z-*5=Qmq*HlTzb;#q*;X@S(OW)d#*y&1jw1T1XE75Va)AMmMDU z=UVP1hzK+!7a$E9FSR^GIM?=J$}@hmpz`teC$_zCem@*m?9jidK0Yg9eJSvwV{mG$v1~(WoW~pz?Lp!Xf)+@bP3*0TDsi>yrsS^rj1PSra|n`~s9;>o1 zni@Af4f(ko*hb+5%C>5u30mZM{llw+2{LC-h!#B_AmdI3g2Ua_W7$ER)(RKU54u&* z1)|t!4hH~M91-)<26VQTIm)=%MOm!0l_WqUU|WA|$Fmx~7vBesgFj&?V^CpVU&(UwfiAeR5HmW(a* zU(01kz=?LAp#EMK|HJ?QxlC4!^lwG-bc@qEbJD_y@$`x6oW`BrnJ2hn=D%!EwB;GL P<4ab?SztsZ_T%ag-`RLB literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-word-de.docx b/OpenDocumentReader/Samples/sample-word-de.docx new file mode 100644 index 0000000000000000000000000000000000000000..df39df22f803ae530d7755af0f03bdfa2c92eb44 GIT binary patch literal 2353 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 X-gT_adBEGZ@NjlL4qy!L_SJs?KVPz` literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-word-es.docx b/OpenDocumentReader/Samples/sample-word-es.docx new file mode 100644 index 0000000000000000000000000000000000000000..0d5b33548f3d6393b9c8e77a7db132d535411c3c GIT binary patch literal 2315 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 RzP%zUI86nBMPlEc{sOAe&g=jH literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-word-pl.docx b/OpenDocumentReader/Samples/sample-word-pl.docx new file mode 100644 index 0000000000000000000000000000000000000000..21c73b5a91933c78971f124b6a4772d1e51f785d GIT binary patch literal 2391 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 UI>>;&Zjlk6`^A98vR|M64O$h(ZU6uP literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-word-ru.docx b/OpenDocumentReader/Samples/sample-word-ru.docx new file mode 100644 index 0000000000000000000000000000000000000000..04a31771a80995be038162e8ece81f4a92ba9e00 GIT binary patch literal 2573 zcmaKuc|25q7sszo8WcmAktKyNcKI1=%91V1$XLcQq){gpB;A-|y*Fc|Ff_@9TTd{o|hVy6^Kkug~XLp;%Z2007v>IER51 z)7HpM#v6he0Qecv(I5aDg2slpp1}vAan46C`TLcn)LXnz5{PweKk1vMu5>6m_2QHY zvjLtUwGFFWF-KxC6XGN}F{^7az26ik73;^L*@Bl%{jPtSD#7aBw$nSP6S7iswFIjd zXk6Y4wiGjKt8l0tljBQFU8lC(!!_JV9W>#t<4(C^{q;7K7Hk%kR5THE2tTf>b{h1M zJSX2HR)Li$>d5JuS+#nSAr_B_dghvRtdu3GS2U(>KKRqRnrW!yfHZz>#apsGf$5!5 z>ti~n`g@nxFJSq9G`PR+nNL7PL=y|RedbK7zBSTXyD1ySy&5{T?E(VI8Ny*TNH}-0 z>rQplXV3WE$o9VNn2e4|mq=!--x|d-h>EUYG)RF705}-YH5l!OQ#|_pncUOJeO-wc zn93n}V>7NtDaW?Do7r0?nNsIr;2Ptw~GH2mk`n5h;8C9+H?)kwJNX*LVUMnT;1o|sUujh|JO>7!4$N(fDD*N7?$=a zA))n>Fnw_LGkW-K4JLQ@d`JtO`eY=vaD8ks3WC7LM*$_=QD8PRgp6LrS~eD z%{ZN1`#~Yg-#G<6jM)GNV;ke}{NTie;Qi3J?|f*hPR5k;($l;@4II7!F$yh(oQda{ z0VFDhE!@e9cyoiza6h%UlI&%XPj7Bs2-~bG)F?F>)#TpD5)yqMoiUmWotU%;?QFllmYIw{uR ztzc}K@$wLonpeUt8%(M4H<71Ztog9WXPe zT}g+!m^v2@O;buH*Wg!2oNw%6pYAgK-Yj(P$(A5i0N~{Xfc-z3_3Jnc+KpkyjCps` zKo7;N)1BLoBj(BiK#-?9fJ2@l0S1Bjs$H$}gvGkG7)LR4L10F%ew0ij*CgpLEj<8wNIn+S&=82x^i=E{PNfL3hemBRJ?1yu@6XA%8A3Grf-| z&gso76m%?ZhvKv}tXj5@Fh#Do`ADr-`PdRTSTwOqBSgg3Y-6qQ?1Eb&J4=qIxLdBR zFdxB$P%lz2`J$OugF+m@g817Wz|Hx;>DK1YFH(`bfr(G>3eU9*TMzUh`L21GWujz2 z!Lc=VEFY*g`8#Y%^>+fD9KC56eHnIr-TU(v=-NY_BFw|#ZANZqI%w>5to9~PSUC^N zOiRk>eo^q0V)Dymc9w*Vg?N!qdGSreH*l^+2TH-i?T1YfN^`~u=bl!Ip2yNH2b^J& zx=b{EYIIlg@-?QrK^!8$LNP!&GG;K)=e(J9kF?n(CPKK74yU~Y$>ot^OKcMM;?dfr{z)c%l`;J})Ns4EWu?xm3zFjn z8_!;rgI{lvjJKks?`7(bS_ECLFw|dII&wq2-4;Wdy)~;{ku%m8(3+Rbbq-h)8&q)r zfY#0_I8fMkZolP*sfE$4tmkM1%96v^SnDj$wRgVUSbKKjpB~zlnB>8h%`F=bx)-_b zqWEjvLXp9Kvv2E_4h{(;`^w33LPlW_KUZ?QS5;uFeh?crmH#0wKGXMD0+)=xT!VRX z|Bw!;eatpIkP!75Q=H=| zGLy}Zvft$9&L3HNAYl{{`o(4Si%l^IG2UaYNd361(zLB+g<@hBVENyR3qz#-zK9HY z|F3Jz-U53K{hxFIATr4@O8jE)dlUB>=FdcC#uD}a>~n9Wy_WQ|(&CRwKMiVc@?MGl fnJml@?!SNISHZSIfxzEC0Woe}24L;?{SWvHFiS|i literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/sample-word-tr.docx b/OpenDocumentReader/Samples/sample-word-tr.docx new file mode 100644 index 0000000000000000000000000000000000000000..548a3ddc83f52ce73767734f61d7a307e622e40c GIT binary patch literal 2335 zcmaKu3p|tiAIFDG%{3XN4Iz;+Bvi~T&O*X*k_;7diz#;zW46RBM9V>LvpFNNQ!BTW zODv|jb#s}!lF-RDx3m7|^s2o6|Nry6e$V%LUa#l-eLe5*>-+nB9y@D+ZBhULU^{Q^ z1I$@9#4hvhVEh2UE?#so55$C^F(K}bk(bcHu9^`6{&&-AY#X(t2=2{CFJ>BODI}za z4e9WkM`D#$l`H2?A~3##ax^ulT^zo11I~rl3_xIMm#j3>8qV2z=LMDQ2aKw_q%L*eQ#zdKWaipl=nb*t0)!e$GenUJ~D! zMMK$|h{3qq^G4;O6SWtfzj&8q9g{#Q7W135VrVcoT(?+$yPp~*&}*Gg!E2BP9{?cCi|#>a|6sW0*K5j)I8iSv1342RrH|8EbJ}sw%pMw>pa0nVo`- zzlz}s?Q0Y8Jir-iDQ^MK@dU=Usm4-E2z|3l{)=n)#g8-}k_@Gog4s6k5t zI8=9PC+49q^f<*=W@ok4RcxwT_qpE_P*SUlK$If{5=&Z**`P+jZVhOsf3h`kJ^h5E zW-Ln+L=n2Z#EI!4MfV2_u;3llOrH)P^mAj~Y!jFgXq28YvWD1#9F4$Y|p-HAdApakmGgX z5rBNfYugJfc;rd*?^++l5?J=>XY-!o?1oGPy$RO7?T%2QP zcAztYW&leXs^GGXiknsa82$Ff!M7biMjpy4=rlcqDwzwE*Px1wwtC5<6Wvq`r!k@* z-iEco{DhkAu6&{Z*L1Igi1#kz)#)v)n&a$#r5$&V7#4QQ+nak)i;C0;JkPm?b~SC{Z-?QhZck4^AfLX-%9P%_Dt)6RC# z=vxpsD_82vVGf-;uYUE7>$OeH{Y}1~n|03hPYg}~0APp!06V`m>&J2EC9_F=dJ-+} z=zME92_5yYBdl^z!BlcgGT)?ouw~?o;&FTa6Ormh$a{#HH)Nv~m5))O$TuHcm3@+W zjCM<_cFD%9d(F#FO|bLu@rU=QTh}F0M^9{{+;l+ZY8GbPHzl-lHY(LAs+!s|EY9;ccpeV%b6VS|3LIkD7dR$$3aIIGgcjuE!@%^#MA zwNYR0h)1`B*t@Iiw}Exzi6Uj3UZCL8gJQky#icID8fX-j#))6-c|lm3?y0>hp`&*r zG3~i`K_Bv6*nrVFfdQN?GF9K+Ojai&Dt{XMbS!ll-qdK{Cwx>Tj)iaa4BDr)@(czRd^F@Y>9IPbIjjD-R>Sl5 zBrZNgeEnIfG+%v>q{EwoRkKmjIq*~MD<7+wWdKpL)01ns>Jt~o_cveS#}iN;5d}|R z-fXO~XQSEYo8o?6>o!SAm=-!D-!Ct+`0cB`F&YL_Sqt`OVG~m*>}K?Zp;^{ZX`yRL zbctLyns~v$$2%;|)hD8Nb~jE64DL)MD>k4G>w)&dbu#8SF;DtkL{>5aI&kxAO%&sx zvZHW8hjDY2`|Yhq_9*rpFh2cmzn6a+gBrE4$Y_(5Z~C$;s-XyCyASTj-6iB`(VC4A ztoR_g=$bz$QR5TPI{A9hu(ckcy&}G{J*aHj$y;(Frqw^^{qcdoHTz56)zA+@s;qki zai@sOW)M-$xjWHEh5vf5MM1?{jddtgyISY$0fDL;>5b#(8G*;1I*brp9p4AWT#J64 zXB(TR}EdA}9^ y&rr5j+A7lDD@}c?^j)&ICT|t3@5wUT{{4&}CCtuR5cu^KLEdS?17rz(efk@jl;S}E literal 0 HcmV?d00001 diff --git a/OpenDocumentReader/Samples/screenshot-names.json b/OpenDocumentReader/Samples/screenshot-names.json new file mode 100644 index 0000000..93c52e7 --- /dev/null +++ b/OpenDocumentReader/Samples/screenshot-names.json @@ -0,0 +1,290 @@ +{ + "de": { + "files": { + "application": "Bewerbung", + "cells": "Umsatzzahlen", + "course": "Kursfolien", + "deck": "Teamtreffen", + "expenses": "Ausgaben", + "hours": "Arbeitszeiten", + "household": "Haushaltsbudget", + "inventory": "Bestand", + "kickoff": "Auftakt", + "lease": "Mietvertrag", + "letter": "Brief an den Vermieter", + "manual": "Anleitung", + "meeting": "Besprechungsnotizen", + "notes": "Notizen", + "paper": "Rechnung", + "reading": "Leseliste", + "resume": "Lebenslauf", + "review": "Quartalsrückblick", + "rows": "Kontakte", + "sheet": "Budget", + "slides": "Projektplan", + "stocktake": "Inventur", + "text": "Quartalsbericht", + "ticket": "Ticket", + "travel": "Reiseplan", + "warranty": "Garantie", + "word": "Vertrag" + }, + "search": "version" + }, + "en": { + "files": { + "application": "Application", + "cells": "Sales figures", + "course": "Course slides", + "deck": "Team offsite", + "expenses": "Expenses", + "hours": "Hours", + "household": "Household budget", + "inventory": "Inventory", + "kickoff": "Kickoff", + "lease": "Lease", + "letter": "Letter to the landlord", + "manual": "Manual", + "meeting": "Meeting notes", + "notes": "Notes", + "paper": "Invoice", + "reading": "Reading list", + "resume": "CV", + "review": "Quarterly review", + "rows": "Contacts", + "sheet": "Budget", + "slides": "Project plan", + "stocktake": "Stocktake", + "text": "Quarterly report", + "ticket": "Ticket", + "travel": "Travel plan", + "warranty": "Warranty", + "word": "Contract" + }, + "search": "release" + }, + "es": { + "files": { + "application": "Solicitud", + "cells": "Cifras de ventas", + "course": "Diapositivas del curso", + "deck": "Reunión de equipo", + "expenses": "Gastos", + "hours": "Horas", + "household": "Presupuesto doméstico", + "inventory": "Inventario", + "kickoff": "Inicio", + "lease": "Contrato de alquiler", + "letter": "Carta al casero", + "manual": "Manual", + "meeting": "Notas de reunión", + "notes": "Notas", + "paper": "Factura", + "reading": "Lista de lectura", + "resume": "Currículum", + "review": "Revisión trimestral", + "rows": "Contactos", + "sheet": "Presupuesto", + "slides": "Plan del proyecto", + "stocktake": "Recuento", + "text": "Informe trimestral", + "ticket": "Billete", + "travel": "Plan de viaje", + "warranty": "Garantía", + "word": "Contrato" + }, + "search": "versión" + }, + "fr": { + "files": { + "application": "Candidature", + "cells": "Chiffres de ventes", + "course": "Diapositives du cours", + "deck": "Réunion d'équipe", + "expenses": "Dépenses", + "hours": "Heures", + "household": "Budget familial", + "inventory": "Stock", + "kickoff": "Lancement", + "lease": "Bail", + "letter": "Lettre au propriétaire", + "manual": "Manuel", + "meeting": "Notes de réunion", + "notes": "Notes", + "paper": "Facture", + "reading": "Liste de lecture", + "resume": "CV", + "review": "Bilan trimestriel", + "rows": "Contacts", + "sheet": "Budget", + "slides": "Plan du projet", + "stocktake": "Inventaire", + "text": "Rapport trimestriel", + "ticket": "Billet", + "travel": "Plan de voyage", + "warranty": "Garantie", + "word": "Contrat" + }, + "search": "version" + }, + "it": { + "files": { + "application": "Candidatura", + "cells": "Dati di vendita", + "course": "Diapositive del corso", + "deck": "Riunione del team", + "expenses": "Spese", + "hours": "Ore", + "household": "Bilancio familiare", + "inventory": "Magazzino", + "kickoff": "Avvio", + "lease": "Contratto d'affitto", + "letter": "Lettera al locatore", + "manual": "Manuale", + "meeting": "Note della riunione", + "notes": "Note", + "paper": "Fattura", + "reading": "Lista di lettura", + "resume": "Curriculum", + "review": "Revisione trimestrale", + "rows": "Contatti", + "sheet": "Bilancio", + "slides": "Piano di progetto", + "stocktake": "Inventario", + "text": "Relazione trimestrale", + "ticket": "Biglietto", + "travel": "Piano di viaggio", + "warranty": "Garanzia", + "word": "Contratto" + }, + "search": "versione" + }, + "pl": { + "files": { + "application": "Podanie", + "cells": "Wyniki sprzedaży", + "course": "Slajdy kursu", + "deck": "Spotkanie zespołu", + "expenses": "Wydatki", + "hours": "Godziny", + "household": "Budżet domowy", + "inventory": "Stan magazynu", + "kickoff": "Rozpoczęcie", + "lease": "Umowa najmu", + "letter": "List do właściciela", + "manual": "Instrukcja", + "meeting": "Notatki ze spotkania", + "notes": "Notatki", + "paper": "Faktura", + "reading": "Lista lektur", + "resume": "CV", + "review": "Przegląd kwartalny", + "rows": "Kontakty", + "sheet": "Budżet", + "slides": "Plan projektu", + "stocktake": "Inwentaryzacja", + "text": "Raport kwartalny", + "ticket": "Bilet", + "travel": "Plan podróży", + "warranty": "Gwarancja", + "word": "Umowa" + }, + "search": "koszty" + }, + "pt-BR": { + "files": { + "application": "Inscrição", + "cells": "Números de vendas", + "course": "Slides do curso", + "deck": "Reunião da equipe", + "expenses": "Despesas", + "hours": "Horas", + "household": "Orçamento doméstico", + "inventory": "Estoque", + "kickoff": "Início", + "lease": "Contrato de aluguel", + "letter": "Carta ao locador", + "manual": "Manual", + "meeting": "Notas da reunião", + "notes": "Notas", + "paper": "Fatura", + "reading": "Lista de leitura", + "resume": "Currículo", + "review": "Revisão trimestral", + "rows": "Contatos", + "sheet": "Orçamento", + "slides": "Plano do projeto", + "stocktake": "Balanço", + "text": "Relatório trimestral", + "ticket": "Passagem", + "travel": "Plano de viagem", + "warranty": "Garantia", + "word": "Contrato" + }, + "search": "versão" + }, + "ru": { + "files": { + "application": "Заявление", + "cells": "Продажи", + "course": "Слайды курса", + "deck": "Встреча команды", + "expenses": "Расходы", + "hours": "Часы", + "household": "Домашний бюджет", + "inventory": "Склад", + "kickoff": "Старт проекта", + "lease": "Договор аренды", + "letter": "Письмо арендодателю", + "manual": "Инструкция", + "meeting": "Заметки со встречи", + "notes": "Заметки", + "paper": "Счёт", + "reading": "Список чтения", + "resume": "Резюме", + "review": "Квартальный обзор", + "rows": "Контакты", + "sheet": "Бюджет", + "slides": "План проекта", + "stocktake": "Инвентаризация", + "text": "Квартальный отчёт", + "ticket": "Билет", + "travel": "План поездки", + "warranty": "Гарантия", + "word": "Договор" + }, + "search": "расходы" + }, + "tr": { + "files": { + "application": "Başvuru", + "cells": "Satış rakamları", + "course": "Kurs slaytları", + "deck": "Ekip toplantısı", + "expenses": "Giderler", + "hours": "Çalışma saatleri", + "household": "Ev bütçesi", + "inventory": "Envanter", + "kickoff": "Başlangıç", + "lease": "Kira sözleşmesi", + "letter": "Ev sahibine mektup", + "manual": "Kılavuz", + "meeting": "Toplantı notları", + "notes": "Notlar", + "paper": "Fatura", + "reading": "Okuma listesi", + "resume": "Özgeçmiş", + "review": "Üç aylık değerlendirme", + "rows": "Kişiler", + "sheet": "Bütçe", + "slides": "Proje planı", + "stocktake": "Sayım", + "text": "Üç aylık rapor", + "ticket": "Bilet", + "travel": "Seyahat planı", + "warranty": "Garanti", + "word": "Sözleşme" + }, + "search": "sürüm" + } +} diff --git a/OpenDocumentReader/ScreenshotMode.swift b/OpenDocumentReader/ScreenshotMode.swift new file mode 100644 index 0000000..90153ce --- /dev/null +++ b/OpenDocumentReader/ScreenshotMode.swift @@ -0,0 +1,243 @@ +import UIKit + +/// The back door the App Store screenshots are taken through. +/// +/// `-ODRScreenshot text` puts the app on one screen and leaves it there, so +/// `fastlane snapshot` photographs the same thing in every language without +/// having to drive the document browser - which is Apple's own UI, in eleven +/// languages, and would be a different tap in each. +/// +/// Off in every build nobody passes that argument to, and compiled to nothing +/// outside Debug. The documents it opens are bundled the same way: written by +/// `scripts/make-screenshot-documents.py`, and kept out of the archive that +/// goes to the store by `EXCLUDED_SOURCE_FILE_NAMES`. +enum ScreenshotMode { + + /// What one launch shows. The screenshot test launches once per case and + /// takes one picture, so this list and the one in + /// `scripts/store-screenshots.py` are the same list. + enum Screen: String { + /// the document browser, with one of each format sitting in it + case browser + /// an ODF text document, read + case text + /// an ODF spreadsheet, with its sheet tabs + case sheet + /// the same reader on a Word file + case office + /// a pdf with a search under way + case pdf + /// a document being edited, keyboard up + case edit + + /// The sample this screen opens, `nil` where it opens none. + var sample: String? { + switch self { + case .browser: return nil + case .text, .edit: return "text" + case .sheet: return "sheet" + case .office: return "word" + case .pdf: return "paper" + } + } + } + + /// One entry in the folder, in the order the browser lists them. `source` is + /// the sample holding its bytes, which only a filler sets. + struct Sample { + let name: String + let format: String + let source: String + + init(name: String, format: String, from source: String? = nil) { + self.name = name + self.format = format + self.source = source ?? name + } + } + + static let folder = [ + Sample(name: "text", format: "odt"), + Sample(name: "sheet", format: "ods"), + Sample(name: "slides", format: "odp"), + Sample(name: "word", format: "docx"), + Sample(name: "cells", format: "xlsx"), + Sample(name: "deck", format: "pptx"), + Sample(name: "paper", format: "pdf"), + Sample(name: "rows", format: "csv"), + Sample(name: "notes", format: "txt"), + + // Fillers, so the folder looks like one somebody keeps things in. Each + // is a copy of a document above under a name of its own, never opened. + Sample(name: "meeting", format: "odt", from: "text"), + Sample(name: "letter", format: "odt", from: "text"), + Sample(name: "travel", format: "odt", from: "text"), + Sample(name: "reading", format: "odt", from: "text"), + Sample(name: "household", format: "ods", from: "sheet"), + Sample(name: "hours", format: "ods", from: "sheet"), + Sample(name: "stocktake", format: "ods", from: "sheet"), + Sample(name: "kickoff", format: "odp", from: "slides"), + Sample(name: "course", format: "odp", from: "slides"), + Sample(name: "lease", format: "docx", from: "word"), + Sample(name: "resume", format: "docx", from: "word"), + Sample(name: "application", format: "docx", from: "word"), + Sample(name: "expenses", format: "xlsx", from: "cells"), + Sample(name: "inventory", format: "xlsx", from: "cells"), + Sample(name: "review", format: "pptx", from: "deck"), + Sample(name: "ticket", format: "pdf", from: "paper"), + Sample(name: "warranty", format: "pdf", from: "paper"), + Sample(name: "manual", format: "pdf", from: "paper"), + ] + + /// Set on the view the picture is of, once it has something to show. The + /// test waits for it rather than for a fixed number of seconds, because + /// translating a document takes as long as the simulator takes. + static let readyIdentifier = "odr-screenshot-ready" + + /// `nil` unless this launch was asked for a screenshot. + /// + /// Read from `UserDefaults` rather than from the argument list, because + /// `-ODRScreenshot text` on the command line is a default: that is how + /// XCUITest's `launchArguments` arrive. + static var screen: Screen? { + #if DEBUG + guard let name = UserDefaults.standard.string(forKey: "ODRScreenshot") else { return nil } + + return Screen(rawValue: name) + #else + return nil + #endif + } + + /// Where each sample ended up, by name, once it was laid out. + private(set) static var laidOut: [String: URL] = [:] + + /// The browser's own picture, in the order it should reveal them. + /// + /// Revealing a document puts it in Recents, which is the tab the browser + /// opens on, and Recents shows the newest first - so this is back to front. + static var browserDocuments: [URL] { + folder.reversed().compactMap { laidOut[$0.name] } + } + + /// Lays the whole folder out before anything lists it. + /// + /// All of it on every screen, not just the one being photographed: the + /// browser is behind every other picture, and a folder holding one file + /// looks like a folder nobody uses. + static func prepare() { + guard screen != nil else { return } + + empty() + + let details = details() + query = details?.search ?? "" + + let titles = details?.files ?? [:] + laidOut = folder.reduce(into: [:]) { found, sample in + found[sample.name] = layOut(sample, called: titles[sample.name] ?? sample.name) + } + } + + /// Clears the folder first. A simulator is kept between runs and between + /// languages, so without this the picture is this run's documents plus + /// every run before it, under whatever names those used. + private static func empty() { + guard let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first, + let existing = try? FileManager.default.contentsOfDirectory( + at: documents, includingPropertiesForKeys: nil) + else { + return + } + + for file in existing { + try? FileManager.default.removeItem(at: file) + } + } + + /// What the folder is called and what the search screenshot looks for, in + /// the app's language. + /// + /// Written beside the samples by `make-screenshot-documents.py`, because + /// these are read by nobody but the screenshots and have no business in + /// `Localizable.strings`. + private struct Details: Decodable { + let files: [String: String] + let search: String + } + + private static func details() -> Details? { + guard + let url = Bundle.main.url(forResource: "screenshot-names", withExtension: "json"), + let data = try? Data(contentsOf: url), + let all = try? JSONDecoder().decode([String: Details].self, from: data) + else { + assertionFailure("no screenshot-names.json bundled - run scripts/make-screenshot-documents.py") + + return nil + } + + for language in Bundle.main.preferredLocalizations where all[language] != nil { + return all[language] + } + + return all["en"] + } + + /// The word the search screenshot types. Whatever the pdf it is looking at + /// actually says, which is not always this language. + private(set) static var query = "" + + /// The sample document of this screen, in the app's language, copied out of + /// the bundle into the documents directory - which is where the document + /// browser looks, and the only place the app may write. + /// + /// English where the language has no sample of its own, which is what that + /// storefront's screenshot would show anyway: the app has no UI in it either. + private static func layOut(_ sample: Sample, called title: String) -> URL? { + var source: URL? + for language in Bundle.main.preferredLocalizations + ["en"] { + source = Bundle.main.url( + forResource: "sample-\(sample.source)-\(language)", withExtension: sample.format) + + if source != nil { break } + } + + guard let source else { + assertionFailure("no \(sample.source) sample bundled - run scripts/make-screenshot-documents.py") + + return nil + } + + guard let documents = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { + return nil + } + + let destination = documents.appendingPathComponent("\(title).\(sample.format)") + + do { + try? FileManager.default.removeItem(at: destination) + try FileManager.default.copyItem(at: source, to: destination) + } catch { + assertionFailure("could not lay out \(destination.lastPathComponent): \(error)") + + return nil + } + + return destination + } + + /// The document this screen opens, once ``prepare()`` has laid it out. + static func document(for screen: Screen) -> URL? { + guard let sample = screen.sample else { return nil } + + return laidOut[sample] + } + + /// Marks the view the test waits for. Does nothing outside a screenshot run. + static func markReady(_ view: UIView) { + guard screen != nil else { return } + + view.accessibilityIdentifier = readyIdentifier + } +} diff --git a/OpenDocumentReaderUITests/ScreenshotTests.swift b/OpenDocumentReaderUITests/ScreenshotTests.swift new file mode 100644 index 0000000..fd85872 --- /dev/null +++ b/OpenDocumentReaderUITests/ScreenshotTests.swift @@ -0,0 +1,132 @@ +import XCTest + +/// The pictures the App Store shows. +/// +/// One launch per screen, each with `-ODRScreenshot `, which is the +/// app's own back door: it puts itself on that screen and stays there. Nothing +/// here taps anything, because everything there is to tap on the way - the +/// document browser - is Apple's UI in eleven languages. +/// +/// `fastlane snapshot` runs this once per language per device and collects what +/// it writes. `scripts/store-screenshots.py` then checks the set and stages it +/// for the release; the names below are the names it expects, and their order is +/// the order the store shows them in. +final class ScreenshotTests: XCTestCase { + + /// Long, because it covers translating a document on a simulator that is + /// also running eleven other languages' worth of tests today. + private let readyTimeout: TimeInterval = 180 + + override func setUpWithError() throws { + continueAfterFailure = false + } + + @MainActor + func testTakesTheStoreScreenshots() throws { + let app = XCUIApplication() + + // adds the language, the locale and fastlane's own arguments, once + setupSnapshot(app) + + // The keyboard offers to teach swipe typing the first time it comes up + // on a fresh simulator, over the keyboard the edit screenshot is of. + // Told here that it has already been shown, so nothing has to be tapped + // away in a language this test cannot read. + app.launchArguments += ["-DidShowContinuousPathIntroduction", "1"] + + let arguments = app.launchArguments + + for (index, screen) in ["browser", "text", "sheet", "edit", "pdf", "office"].enumerated() { + app.launchArguments = arguments + ["-ODRScreenshot", screen] + app.launch() + + let ready = app.descendants(matching: .any)["odr-screenshot-ready"] + XCTAssertTrue( + ready.waitForExistence(timeout: readyTimeout), + "\(screen) never finished coming up, so there is nothing to photograph") + + if screen == "browser" { + waitForTheFolderToFill(in: app) + } + + if screen == "edit" { + raiseTheKeyboard(in: app) + } + + snapshot(String(format: "%02d-%@", index + 1, screen)) + + // rather than leaving it running: the next launch has to go through + // didFinishLaunching again to be handed the next screen + app.terminate() + } + } + + /// Waits for the browser to have listed the documents. + /// + /// Recents is filled by the system a few at a time and the app cannot say + /// when it is done, so this waits for the count to stop growing. The first + /// cell is not the end of it. + @MainActor + private func waitForTheFolderToFill(in app: XCUIApplication) { + let cells = app.collectionViews.cells + + XCTAssertTrue( + cells.firstMatch.waitForExistence(timeout: 60), + "the browser never listed the documents") + + let deadline = Date().addingTimeInterval(60) + var listed = 0 + var stillFor = 0 + + // three seconds, not one and a half: it has been seen to pause for two + // beats and then hand over the last two files + while stillFor < 6, Date() < deadline { + Thread.sleep(forTimeInterval: 0.5) + + let count = cells.count + stillFor = count == listed ? stillFor + 1 : 0 + listed = count + } + } + + /// Taps into the text of the document being edited. + /// + /// A real tap, not a focus call from the app: WebKit only raises the + /// keyboard for a gesture it saw, so an edit staged entirely in code sets a + /// caret and nothing else. + /// + /// Where the text is depends on the page, and a tap into its margin reaches + /// nothing, so this works down the page until the keyboard answers rather + /// than betting the run on one offset. + @MainActor + private func raiseTheKeyboard(in app: XCUIApplication) { + let page = app.webViews.firstMatch + XCTAssertTrue(page.waitForExistence(timeout: 30), "the edit has no page to tap into") + + // near the top: the sample is a page of A4 with a few lines on it, so + // most of what is on screen is the blank rest of the sheet + for offset in [0.10, 0.14, 0.07, 0.18, 0.22, 0.28] { + page.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: offset)).tap() + + if app.keyboards.firstMatch.waitForExistence(timeout: 5) { + dismissTheKeyboardTutorial(in: app) + + return + } + } + + XCTFail("no tap down the page set a caret, so the keyboard never came up") + } + + /// Belt and braces for the swipe typing panel, in case the launch argument + /// stops being honoured. Only reaches an English keyboard, which is why it + /// is the second line of defence and not the first. + @MainActor + private func dismissTheKeyboardTutorial(in app: XCUIApplication) { + let continueButton = app.buttons["Continue"] + + if continueButton.waitForExistence(timeout: 2) { + continueButton.tap() + } + } +} diff --git a/OpenDocumentReaderUITests/SnapshotHelper.swift b/OpenDocumentReaderUITests/SnapshotHelper.swift new file mode 100644 index 0000000..fed8a2b --- /dev/null +++ b/OpenDocumentReaderUITests/SnapshotHelper.swift @@ -0,0 +1,320 @@ +// Copied verbatim from fastlane, which is where `snapshot` expects it, and MIT +// licensed like the rest of it - not our MPL 2.0. Update it by copying the file +// again rather than by editing it; the version marker at the bottom is what +// fastlane checks it against. +// +// https://github.com/fastlane/fastlane/blob/master/snapshot/lib/assets/SnapshotHelper.swift +// +// +// SnapshotHelper.swift +// Example +// +// Created by Felix Krause on 10/8/15. +// + +// ----------------------------------------------------- +// IMPORTANT: When modifying this file, make sure to +// increment the version number at the very +// bottom of the file to notify users about +// the new SnapshotHelper.swift +// ----------------------------------------------------- + +import Foundation +import XCTest + +@MainActor +func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) { + Snapshot.setupSnapshot(app, waitForAnimations: waitForAnimations) +} + +@MainActor +func snapshot(_ name: String, waitForLoadingIndicator: Bool) { + if waitForLoadingIndicator { + Snapshot.snapshot(name) + } else { + Snapshot.snapshot(name, timeWaitingForIdle: 0) + } +} + +/// - Parameters: +/// - name: The name of the snapshot +/// - timeout: Amount of seconds to wait until the network loading indicator disappears. Pass `0` if you don't want to wait. +@MainActor +func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { + Snapshot.snapshot(name, timeWaitingForIdle: timeout) +} + +enum SnapshotError: Error, CustomDebugStringConvertible { + case cannotFindSimulatorHomeDirectory + case cannotRunOnPhysicalDevice + + var debugDescription: String { + switch self { + case .cannotFindSimulatorHomeDirectory: + return "Couldn't find simulator home location. Please, check SIMULATOR_HOST_HOME env variable." + case .cannotRunOnPhysicalDevice: + return "Can't use Snapshot on a physical device." + } + } +} + +@objcMembers +@MainActor +open class Snapshot: NSObject { + static var app: XCUIApplication? + static var waitForAnimations = true + static var cacheDirectory: URL? + static var screenshotsDirectory: URL? { + return cacheDirectory?.appendingPathComponent("screenshots", isDirectory: true) + } + static var deviceLanguage = "" + static var currentLocale = "" + + open class func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) { + + Snapshot.app = app + Snapshot.waitForAnimations = waitForAnimations + + do { + let cacheDir = try getCacheDirectory() + Snapshot.cacheDirectory = cacheDir + setLanguage(app) + setLocale(app) + setLaunchArguments(app) + } catch let error { + NSLog(error.localizedDescription) + } + } + + class func setLanguage(_ app: XCUIApplication) { + guard let cacheDirectory = self.cacheDirectory else { + NSLog("CacheDirectory is not set - probably running on a physical device?") + return + } + + let path = cacheDirectory.appendingPathComponent("language.txt") + + do { + let trimCharacterSet = CharacterSet.whitespacesAndNewlines + deviceLanguage = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet) + app.launchArguments += ["-AppleLanguages", "(\(deviceLanguage))"] + } catch { + NSLog("Couldn't detect/set language...") + } + } + + class func setLocale(_ app: XCUIApplication) { + guard let cacheDirectory = self.cacheDirectory else { + NSLog("CacheDirectory is not set - probably running on a physical device?") + return + } + + let path = cacheDirectory.appendingPathComponent("locale.txt") + + do { + let trimCharacterSet = CharacterSet.whitespacesAndNewlines + currentLocale = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet) + } catch { + NSLog("Couldn't detect/set locale...") + } + + if currentLocale.isEmpty && !deviceLanguage.isEmpty { + currentLocale = Locale(identifier: deviceLanguage).identifier + } + + if !currentLocale.isEmpty { + app.launchArguments += ["-AppleLocale", "\"\(currentLocale)\""] + } + } + + class func setLaunchArguments(_ app: XCUIApplication) { + guard let cacheDirectory = self.cacheDirectory else { + NSLog("CacheDirectory is not set - probably running on a physical device?") + return + } + + let path = cacheDirectory.appendingPathComponent("snapshot-launch_arguments.txt") + app.launchArguments += ["-FASTLANE_SNAPSHOT", "YES", "-ui_testing"] + + do { + let launchArguments = try String(contentsOf: path, encoding: String.Encoding.utf8) + let regex = try NSRegularExpression(pattern: "(\\\".+?\\\"|\\S+)", options: []) + let matches = regex.matches(in: launchArguments, options: [], range: NSRange(location: 0, length: launchArguments.count)) + let results = matches.map { result -> String in + (launchArguments as NSString).substring(with: result.range) + } + app.launchArguments += results + } catch { + NSLog("Couldn't detect/set launch_arguments...") + } + } + + open class func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { + if timeout > 0 { + waitForLoadingIndicatorToDisappear(within: timeout) + } + + NSLog("snapshot: \(name)") // more information about this, check out https://docs.fastlane.tools/actions/snapshot/#how-does-it-work + + if Snapshot.waitForAnimations { + sleep(1) // Waiting for the animation to be finished (kind of) + } + + #if os(OSX) + guard let app = self.app else { + NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + return + } + + app.typeKey(XCUIKeyboardKeySecondaryFn, modifierFlags: []) + #else + + guard self.app != nil else { + NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + return + } + + let screenshot = XCUIScreen.main.screenshot() + #if os(iOS) && !targetEnvironment(macCatalyst) + let image = XCUIDevice.shared.orientation.isLandscape ? fixLandscapeOrientation(image: screenshot.image) : screenshot.image + #else + let image = screenshot.image + #endif + + guard var simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory else { return } + + do { + // The simulator name contains "Clone X of " inside the screenshot file when running parallelized UI Tests on concurrent devices + let regex = try NSRegularExpression(pattern: "Clone [0-9]+ of ") + let range = NSRange(location: 0, length: simulator.count) + simulator = regex.stringByReplacingMatches(in: simulator, range: range, withTemplate: "") + + let path = screenshotsDir.appendingPathComponent("\(simulator)-\(name).png") + #if swift(<5.0) + try UIImagePNGRepresentation(image)?.write(to: path, options: .atomic) + #else + try image.pngData()?.write(to: path, options: .atomic) + #endif + } catch let error { + NSLog("Problem writing screenshot: \(name) to \(screenshotsDir)/\(simulator)-\(name).png") + NSLog(error.localizedDescription) + } + #endif + } + + class func fixLandscapeOrientation(image: UIImage) -> UIImage { + #if os(watchOS) + return image + #else + if #available(iOS 10.0, *) { + let format = UIGraphicsImageRendererFormat() + format.scale = image.scale + let renderer = UIGraphicsImageRenderer(size: image.size, format: format) + return renderer.image { context in + image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) + } + } else { + return image + } + #endif + } + + class func waitForLoadingIndicatorToDisappear(within timeout: TimeInterval) { + #if os(tvOS) + return + #endif + + guard let app = self.app else { + NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + return + } + + let networkLoadingIndicator = app.otherElements.deviceStatusBars.networkLoadingIndicators.element + let networkLoadingIndicatorDisappeared = XCTNSPredicateExpectation(predicate: NSPredicate(format: "exists == false"), object: networkLoadingIndicator) + _ = XCTWaiter.wait(for: [networkLoadingIndicatorDisappeared], timeout: timeout) + } + + class func getCacheDirectory() throws -> URL { + let cachePath = "Library/Caches/tools.fastlane" + // on OSX config is stored in /Users//Library + // and on iOS/tvOS/WatchOS it's in simulator's home dir + #if os(OSX) + let homeDir = URL(fileURLWithPath: NSHomeDirectory()) + return homeDir.appendingPathComponent(cachePath) + #elseif arch(i386) || arch(x86_64) || arch(arm64) + guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else { + throw SnapshotError.cannotFindSimulatorHomeDirectory + } + let homeDir = URL(fileURLWithPath: simulatorHostHome) + return homeDir.appendingPathComponent(cachePath) + #else + throw SnapshotError.cannotRunOnPhysicalDevice + #endif + } +} + +private extension XCUIElementAttributes { + var isNetworkLoadingIndicator: Bool { + if hasAllowListedIdentifier { return false } + + let hasOldLoadingIndicatorSize = frame.size == CGSize(width: 10, height: 20) + let hasNewLoadingIndicatorSize = frame.size.width.isBetween(46, and: 47) && frame.size.height.isBetween(2, and: 3) + + return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize + } + + var hasAllowListedIdentifier: Bool { + let allowListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] + + return allowListedIdentifiers.contains(identifier) + } + + func isStatusBar(_ deviceWidth: CGFloat) -> Bool { + if elementType == .statusBar { return true } + guard frame.origin == .zero else { return false } + + let oldStatusBarSize = CGSize(width: deviceWidth, height: 20) + let newStatusBarSize = CGSize(width: deviceWidth, height: 44) + + return [oldStatusBarSize, newStatusBarSize].contains(frame.size) + } +} + +private extension XCUIElementQuery { + var networkLoadingIndicators: XCUIElementQuery { + let isNetworkLoadingIndicator = NSPredicate { (evaluatedObject, _) in + guard let element = evaluatedObject as? XCUIElementAttributes else { return false } + + return element.isNetworkLoadingIndicator + } + + return self.containing(isNetworkLoadingIndicator) + } + + @MainActor + var deviceStatusBars: XCUIElementQuery { + guard let app = Snapshot.app else { + fatalError("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") + } + + let deviceWidth = app.windows.firstMatch.frame.width + + let isStatusBar = NSPredicate { (evaluatedObject, _) in + guard let element = evaluatedObject as? XCUIElementAttributes else { return false } + + return element.isStatusBar(deviceWidth) + } + + return self.containing(isStatusBar) + } +} + +private extension CGFloat { + func isBetween(_ numberA: CGFloat, and numberB: CGFloat) -> Bool { + return numberA...numberB ~= self + } +} + +// Please don't remove the lines below +// They are used to detect outdated configuration files +// SnapshotHelperVersion [1.30] diff --git a/README.md b/README.md index 4afa177..ea41752 100644 --- a/README.md +++ b/README.md @@ -120,13 +120,14 @@ in App Store Connect: gh workflow run release.yml -f version=1.38 ``` -It runs as four jobs: +It runs as five jobs: | job | what it does | | --- | --- | | `build` | one run producing both signed `.ipa`s, archived on the run | +| `screenshots` | beside the build: photographs the app on two devices, in every locale | | `upload` | one job per app, uploading its `.ipa` | -| `listing` | one job per app, writing what the store says about it | +| `listing` | one job per app, writing what the store says and shows about it | | `record` | once both landed: tag the build, draft the GitHub release | Both apps always go out together, and nothing chooses one: Pro and Lite are the @@ -169,6 +170,32 @@ an app's name is unique in the store, and the one sentence about ads inside the description. `review_information` and the categories are left out. See `fastlane/metadata/README.md`. +### The screenshots + +Taken during the release run rather than committed, because a screenshot is only +worth what the build it was taken from is worth: + +```sh +bundle exec fastlane ios screenshots +``` + +Four pictures per device - the onboarding pages, a text document, a spreadsheet +and a presentation - on a 6.9" iPhone and a 13" iPad, in the nine store locales +the app is translated into. `hi` and `sv` are given the English set, which is +what those storefronts would show anyway. The documents in them are localized +too, and written by `scripts/make-screenshot-documents.py`. + +Nothing is tapped to get there. The app takes `-ODRScreenshot ` in Debug +builds and puts itself on that screen, so the same picture comes out in every +language without driving Apple's document browser in eleven of them - see +`OpenDocumentReader/ScreenshotMode.swift` and the `ODR Screenshots` scheme. +`scripts/store-screenshots.py` checks the set against the sizes App Store +Connect takes, and the `listing` job hands it to `deliver` alongside the text. +The same set goes to both apps. + +The run archives them as the `screenshots` artifact, on a dry run too - which is +how to look at them before the store does. See `fastlane/screenshots/README.md`. + Nothing has to be committed to cut a release, and a release leaves no commit behind either. Both halves of the version come from outside the tree: @@ -232,6 +259,11 @@ ODR_DRY_RUN=true bundle exec fastlane deployPro # build and sign only separate jobs. `uploadPro` takes the `.ipa` already in `build/` rather than making one, and `resolveBuildNumber` prints the number both apps would get. +`uploadListingPro` writes the text and, if `fastlane/screenshots` holds a set, +the pictures with it - so fixing a word in a description by hand does not cost a +quarter of an hour of simulators, while a release run, which always captures +first, sends both. + ### Tags Nothing is triggered by a tag, and no tag is pushed before a build: a version diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 825c34c..98f2a63 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -18,9 +18,25 @@ APPS = { # Resolved at parse time, which fastlane also does from fastlane/. IPA_DIR = File.expand_path("../build").freeze -# Absolute for the same reason. It resolves the repository from its own path, so -# it does not care which of the two it is called from. +# Absolute for the same reason. They resolve the repository from their own path, +# so they do not care which of the two they are called from. STORE_LISTING = File.expand_path("../scripts/store-listing.py").freeze +STORE_SCREENSHOTS = File.expand_path("../scripts/store-screenshots.py").freeze +FRAME_SCREENSHOTS = File.expand_path("../scripts/frame-screenshots.py").freeze + +# Where snapshot writes, and where the framed set goes. Neither is committed: +# a picture of the app is worth what the build it was taken from is. +SCREENSHOT_DIR = File.expand_path("screenshots").freeze +FRAMED_DIR = File.expand_path("framed").freeze + +# The two sizes App Store Connect asks an app that runs on both for, named by +# whatever the runner's Xcode calls them. Newest first, and the first one the +# runner actually has wins - a simulator's name changes with every Xcode, the +# number of pixels it has does not, and store-screenshots.py checks that. +SCREENSHOT_DEVICES = [ + ["iPhone 17 Pro Max", "iPhone 16 Pro Max", "iPhone 15 Pro Max"], + ["iPad Pro 13-inch (M5)", "iPad Pro 13-inch (M4)", "iPad Pro (12.9-inch) (6th generation)"], +].freeze def dry_run? ENV["ODR_DRY_RUN"].to_s.strip == "true" @@ -31,6 +47,62 @@ def github_output(name, value) File.open(output, "a") { |out| out.write("#{name}=#{value}\n") } if output end +# The simulators this machine has, by the iOS they run: the same model name +# usually exists on several, and which one a bare name resolves to is luck. +def simulators_by_ios + runtime = nil + + `xcrun simctl list devices available`.lines.each_with_object({}) do |line, found| + if (version = line[/^-- iOS ([0-9.]+) --/, 1]) + runtime = version + found[runtime] ||= [] + elsif runtime && (name = line[/^\s+(.+?) \([0-9A-F-]{36}\)/, 1]) + found[runtime] << name + end + end +end + +# The newest iOS installed. The store shows what the app looks like now, and a +# picture taken on last year's iOS is last year's buttons. +def screenshot_ios + given = ENV["ODR_SCREENSHOT_IOS"].to_s.strip + return given unless given.empty? + + newest = simulators_by_ios.keys.max_by { |version| Gem::Version.new(version) } + UI.user_error!("this machine has no iOS simulator runtime installed") unless newest + + newest +end + +# The locales to photograph. Every one the app is translated into, unless +# ODR_SCREENSHOT_LANGUAGES names fewer - which is how to look at one language's +# pictures without waiting out the other eight. +def screenshot_languages + given = ENV["ODR_SCREENSHOT_LANGUAGES"].to_s.strip + return given.split(",").map(&:strip) unless given.empty? + + sh(STORE_SCREENSHOTS, "--languages", log: false).split("\n").map(&:strip).reject(&:empty?) +end + +# One simulator per device the store wants, out of the ones that run the iOS +# being photographed, or a failure naming what is there instead - which beats +# xcodebuild spending twenty minutes not finding it. +def screenshot_devices(ios) + given = ENV["ODR_SCREENSHOT_DEVICES"].to_s.strip + return given.split(",").map(&:strip) unless given.empty? + + available = simulators_by_ios.fetch(ios, []) + + SCREENSHOT_DEVICES.map do |candidates| + candidates.find { |name| available.include?(name) } || + UI.user_error!( + "none of #{candidates.join(', ')} runs iOS #{ios}. That runtime has: " \ + "#{available.uniq.sort.join(', ')}. Set ODR_SCREENSHOT_DEVICES or " \ + "ODR_SCREENSHOT_IOS to pick by hand." + ) + end +end + platform :ios do desc "Build a signed .ipa of the paid app" lane :buildPro do @@ -62,6 +134,58 @@ platform :ios do upload_listing(APPS[:lite]) end + desc "Take the App Store screenshots of both devices, in every locale the app is translated into" + lane :screenshots do + languages = screenshot_languages + ios = screenshot_ios + devices = screenshot_devices(ios) + + UI.message("photographing #{devices.join(' and ')} on iOS #{ios} in #{languages.join(', ')}") + + # The Pro scheme, so no ad sdk is linked and no consent form can come up in + # front of a picture. The two apps are the same app, and what differs - the + # banner Lite carries - is not in a screenshot either way, so one set of + # pictures goes to both listings. + capture_ios_screenshots( + project: "OpenDocumentReader.xcodeproj", + scheme: "ODR Screenshots", + devices: devices, + # pinned, or the same model name on an older runtime answers instead and + # the store gets a picture of last year's iOS + ios_version: ios, + languages: languages, + output_directory: SCREENSHOT_DIR, + # 9:41 and a full battery, as Apple's own screenshots have. Spelled out + # because the default asks for "charged", which iOS 26 draws as a green + # charging battery - Apple's own pictures show a plain full one. + override_status_bar: true, + override_status_bar_arguments: + "--time 9:41 --dataNetwork wifi --wifiMode active --wifiBars 3 " \ + "--cellularMode active --cellularBars 4 --batteryState discharging --batteryLevel 100", + # a rerun replaces the set rather than adding to it + clear_previous_screenshots: true, + # the runner has no browser to open the summary in, and no one watching it + skip_open_summary: true, + stop_after_first_error: true + ) + + # A raw capture is not what the store shows. The framing is separate from the + # photography so that changing a headline costs a second of Pillow rather + # than a quarter hour of simulators - rerun this script alone after an edit + # to fastlane/frames/frames.json. + sh(FRAME_SCREENSHOTS) + + # what came out is what the store would be given, so it is checked here + # rather than at upload time on the other side of the run. A run narrowed to + # a few languages by hand has nothing to check against: half a set is what it + # was asked for. + if ENV["ODR_SCREENSHOT_LANGUAGES"].to_s.strip.empty? + sh(STORE_SCREENSHOTS, "--screenshots", FRAMED_DIR) + else + UI.important("only #{languages.join(', ')} were captured, so the set is not checked") + end + end + desc "Build and upload the paid app" lane :deployPro do build_ipa(APPS[:pro]) @@ -244,12 +368,22 @@ platform :ios do UI.user_error!("no version to write notes for: set ODR_VERSION (e.g. ODR_VERSION=1.41)") if version.empty? notes_dir = Dir.mktmpdir("release-notes") + shots_dir = Dir.mktmpdir("release-screenshots") key_path = nil begin # first, so a version some locale has no copy for fails before a key is # ever written to disk sh(STORE_LISTING, "--version", version, "--stage", notes_dir, "--app", options[:name]) + + # A run with nothing captured writes the text alone, so fixing a word in a + # description does not cost a quarter hour of simulators. A run with + # something captured has to have all of it: half a set is worse in the + # store than the set already up there. + captured = !Dir.glob(File.join(FRAMED_DIR, "*", "*.png")).empty? + sh(STORE_SCREENSHOTS, "--screenshots", FRAMED_DIR, "--stage", shots_dir) if captured + UI.important("no screenshots under #{FRAMED_DIR} - writing the text only") unless captured + key_path = api_key_file upload_to_app_store( @@ -259,9 +393,13 @@ platform :ios do # usual case: the build is still processing when this runs app_version: version, metadata_path: notes_dir, + screenshots_path: shots_dir, skip_binary_upload: true, - skip_screenshots: true, + skip_screenshots: !captured, skip_metadata: false, + # the set replaces what is up there rather than joining it, or a locale + # keeps whichever of last release's pictures this one has no answer to + overwrite_screenshots: captured, # deliver otherwise opens an HTML preview and waits to be told it is fine force: true, # same as the binary upload: precheck cannot read in-app purchases with @@ -272,6 +410,7 @@ platform :ios do ensure FileUtils.remove_entry(File.dirname(key_path), true) if key_path FileUtils.remove_entry(notes_dir, true) + FileUtils.remove_entry(shots_dir, true) end end end diff --git a/fastlane/README.md b/fastlane/README.md index cd8c419..a070310 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -63,6 +63,14 @@ Write the paid app's listing, and ODR_VERSION's release notes, to the store Write the ad supported app's listing, and ODR_VERSION's release notes, to the store +### ios screenshots + +```sh +[bundle exec] fastlane ios screenshots +``` + +Take the App Store screenshots of both devices, in every locale the app is translated into + ### ios deployPro ```sh diff --git a/fastlane/frames/Nunito[wght].ttf b/fastlane/frames/Nunito[wght].ttf new file mode 100644 index 0000000000000000000000000000000000000000..2ec1f4b0676c83ef33049db87b311171699e9192 GIT binary patch literal 276932 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%0Do|XJG1A?#Jml~?ZHg8;t1C9I zCM#Tle2g;FG_w~s=z3^yq&m>rT-elAQLf1O0CSsE-+1d6X|p_6t}q{SNa`Pb*qJsEojF7jq@qeL4fUN*YT&w zZ`wy*Zn-AVb1B3Jt!d%ymg~>P5nTAvlLQ<_Opt7qf`ZT%=|wnCJIRO_lNJeTfqp_{G{jidmvV2+nW~Z(5TJ!l<5ToH&?cwc zqvNQctu26?w&u3Lel%K;T6>L5E!SNI7@69dA6YWO(jTkd;T*6^4Y{;^t1bGsAP^m+13W9NL8x>4^Ui zZDZi2`>FJ{yWP&ez6)A6`H#tGSqA?j@nq0CA*CTk6-YE9TPN<0md0;6CA^3)*`L(Ud~$62dZH%7SAi(z31unlWia zdXueWMbtMFBMp=ctb}<%dzC)kbZVND{)j`G?}KCR0imjXC(%*Egcri{74}!6Uvq69 zk76qcXXk{AZP;G0H8=R9_aLPbRd(6P=%rK{at7^q@$A`G9YdWB@Ym>r4I5Me<09|I zP}mqB7%#axn$r&2Oz6 z5o6V1=7QGG!qv!;9EF+6nVTDbx416fmS0;Ee-UHA^TU3BuIR&XVKB?;W>wV#P%hCtQ%Y*ld|ffKQ}ddR zjzaj0peL?Kb$qfq3JC2*e+m;;{xq0a>g&bS;t~4TwMz^b=|ILcNYt_r(anA!@tN6TB$ht$k zkQIPWgyaiE`2~sc0+c_A@(V@zg;Wms;C<E=gF542jeW~nTD|_|JuW)#gzD)fL zYP(9I45+gap~(pj7?O{QJ{~pUjB=5q)g!1k`bcaKd@ozsq9FY!%Rm5XI=#rg>d^k| z^dcqApB)-{6@}$63aSBV%%of--UwDI7MF^VT8o(^w3K7IGWK%%94?n5uc_CwRsRUx z9?^Xn^JnGKZEkaqC(Cgm-G0iuU9TQ$JWlJXc>vz8WW8~%9GeT=bu|nv#ad9E_IM7Y zAmZ{>QYPQdTR}uxf5bjJVufj7lY_*YoV=rdSNObZH4xvF{>ojH!m%AT`lPkd(aru)zR@crwXsvXRksW-GS+l+1feLd|P zdIv{ow~_Y6cVpy~`)skW+hV;!8g5e)`*%Vnh6rZK$lzaUn79`p0;y0~uW(+X+2CtF z2kKNonM}HNQJkHx~;t@+|ic(c5a}vGuS=Mk95`NRy9X#m2FK0HDaGFMt&op!|*E- z`-8+≦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

MZ6ig%eU?U=Z}EJ{q=5OE-FqF6 zXD((_Jj@w`l|A|h=6^Idi)BgoYhtd{6w<;yBQuvwCJ#CnYR;wdc!>S&;GR#R>61y~ zk^U2ZF#o|mPP_9-c5aB`aeJrIjfCQ(ZpJ3)0JpDMn_#cR5y;Q%r&E}#Uu0uo2Xj$g zo>PN{JQFfa;pDW8jSFp7)_^woxcmxH=5`#GGyZDj1-Wnx zcmLj&mFE()*G7BxIEzO2ZAd13t{@G273SUm#pQcJX1&3>nW%e7WQp_|d0s{HXXHa4 z)>)Dj<%78l=`{J%83eup_@1Ik&+53HV-gSFyQF>iM4lw~29STSh7t|XPg`z^>*Pu4 z1|Qn{v*ijrL8LvfBj$`>Z^X5eVY1^IImzC|;#w+xzt{REy;}WhxGb+-c>e8iUalTR zKmA3*&Tbs5cFZ=ipZvfi_nsOD&W<0GqkG#9@(esldG_NKy&@5^zHpQ$Q|nt{p_+`Yudbtht`eE!*g%0cU`dlz#b#pVY{D2`>Gf_TzT2FQe9m; z?#AQ(MQPzoHhoZrc72co+~;;_ZP3}Vi`K;3I0fu=$LpTWQ-{Wo`W?z~P}@D0I_h|T z>igT@w(WJx@sFUb{e(ONTb7tF>m57;o>c2XyLUn1g$b$H^;v>&ZaZeI z>s&q?PI*%q62eHw?a#6b+P|`8qkKxVT?xVuB7yNMPR79=M8cRAJg02S<&=SKh&eaN zdkzWq%Jy9+?YKNCDH_XcyE{n-BQH{P@8`?|&~K94OeF2vUDiX|!ya0 z^(*_%25Lt~@9-YGnJJ3E-a#KrrX$h&@E+kI;?Cc@DYd7g&wl-9H|QBOO0nIV1ZPv&|FyQ~QRc?>xu*89x)I1Rk=3z9v7oIo zM#m`RJqcwD)-hI&F^(7&7dDaF-#I^Q?>oiV_e0(P>V6o${orI}4m xM$GzC~$G z{PyN6sfvno*v`{ZF|N2a2aoMr#NpDh811R(>uonC`jS2+`W=Y7qj&6}T){l&K++6& z6Xpiw->$CUarNBp>A?PJ+hgs_4cdEMxyono($%aQO50_D&7!Qag{DD!>@T32!z zY`Hp+5zEio2DiNX%fqHk?}DR`W4GJcHF{qX-Jb;y)rX$Hb(6RJeBX`k)zQ6Sx<~tV zjH^RAB+8HG$F$Ey@-urpc3g_3n401_I_?Dq>ssd-qQqE`UtC>mIM=g-vur`R?ECYa z_Yh+J!1so2T6_)K281;3|A`0BswrdH?lJZLL%%b?IKBWK9=>z@P zG0B|=w@U+SHoIRLy&<_Q+r=S|4)*3c)D>69-RCkAGoiVQ%bOV9fje3Luz?vArNjBL zO*3xZ1kc3#Mv37zUPjy9mZY-VJOjT@5J}5!&Q>Ib1v;E?4iNeB92oi+%nvDR+n+it z2A{^LSz7(S3fR+pWv(KA?FP4{~H16MZ{24~gCkJ4rH1=$Evn zvHK5{FX!#dKj?V@ZC`CE;;)<@*_tHpL*Vl{R+cuJV{^D4n;Ozy3GIVMpVejNvf{lW zR5p~Uy?wLkCA&IfOR`|M4LRKK)A`)QPq2?cJYAF9yu>wfVjBN6cPHLWL^4k-pY==B zTUtjEuU*>(@yuAm=TLBO7|(XFB;EdtzL6n9ZIAFc8$<*F+r<5b_E5O}k%zl>qkA8; zkDg*oMP5&Ea;}ZDeG=tr*VYanx2@T0WZOacZ_|aNEAq^UK8|M*lgP+c!S+?_rmOXX zJlL+;u%Q1woS;Yao)C&>`mg2h)RpWuy&HwjawYA*SR2yZB%$BOrA=+%_ERfAdcTV6 zPi1tT;pTOJLjR3R*Ep;^$QjuBU3~w8r5(lj02(W(4Qzb7XA{LUmwY~j=6Q+xR$pwz zdlhsHK4WXn401ls7+}-1*Pu_6hpnp(WIyEPj72DOaj-{d^~YYFc;Jh(*Zh1+g8bb4 zwEPlu!AZ|0t!$8o*)NQ(1L;f`%g>Qd^b5!K(|I#I!)M1|PM6x8p80e3LE`J|<{nSS z?Q5I9?{aWi>~rSyu30)SXUAXrY-KX}(fCB|Y-M(U01=AYj zH9h{g`+w9A?6^sBNRF0|-OgI1U7C&u^;^fuB+I~g)+sSOl{>IqW{)cwU)-GFBaHnW z^pm9VjgD!VZI#3mv@Ox*z7q8r4x@fe`bX;z=iCs&S?1u^e6as+-=Mf1eW1@Bu0Py0 z1lw{`Ppez5-Y4c``x^VFZ5`!?+xYB9x^MRHU7lpLy_W$wbZRbxG6eO5tP=J{bq)#g z6vg+(cNXoOvd%bEzNO^RQ&| zsoh)~MB}J=HxQ>~=7es#akSI!NEh}up$z6+I@?0pU$O0J?WLJ_aGF#e%0D3u3gh^0 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 z%0A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 is how the app is +asked to open one. See `OpenDocumentReader/ScreenshotMode.swift`. + +## Both apps get the same pictures + +Pro and Lite are one app built twice, and the one thing that differs on screen - +the banner Lite carries - is not in a screenshot either way. The set is taken +once, with the Pro scheme, which links no ad sdk and so cannot raise a consent +form in front of the camera. Both listings are then given it. diff --git a/fastlane/screenshots/README.txt b/fastlane/screenshots/README.txt deleted file mode 100644 index 8b015ec..0000000 --- a/fastlane/screenshots/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -Put all screenshots you want to use inside the folder of its language (e.g. en-US). -The device type will automatically be recognized using the image resolution. Apple TV screenshots -should be stored in a subdirectory named appleTV with language folders inside of it. iMessage -screenshots, like Apple TV screenshots, should also be stored in a subdirectory named iMessage -with language folders inside of it. - -The screenshots can be named whatever you want, but keep in mind they are sorted alphabetically. diff --git a/scripts/format.sh b/scripts/format.sh index 8a07f15..6c72cd7 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -27,6 +27,11 @@ if ! xcrun --find swift-format >/dev/null 2>&1; then exit 1 fi +# SnapshotHelper.swift is left out: it belongs to fastlane and is kept byte for +# byte as they ship it, so the next version can be copied over it. +# +# The comment stays out here. bash 3.2, which is the one macOS ships and the one +# CI runs, cannot parse an apostrophe in a comment inside a <( ). files=() while IFS= read -r -d '' file; do # tracked files can be staged for deletion and no longer exist on disk @@ -34,7 +39,8 @@ while IFS= read -r -d '' file; do files+=("$file") fi done < <( - git ls-files -z --cached --others --exclude-standard -- '*.swift' + git ls-files -z --cached --others --exclude-standard -- \ + '*.swift' ':!:OpenDocumentReaderUITests/SnapshotHelper.swift' ) if [ ${#files[@]} -eq 0 ]; then diff --git a/scripts/frame-screenshots.py b/scripts/frame-screenshots.py new file mode 100755 index 0000000..69af2c5 --- /dev/null +++ b/scripts/frame-screenshots.py @@ -0,0 +1,691 @@ +#!/usr/bin/env python3 +# +# Puts the captured screenshots into the picture the store shows: the app on a +# phone, on a coloured ground, under a line of copy in that locale's language. +# +# scripts/frame-screenshots.py frame the whole capture +# scripts/frame-screenshots.py --locale en-US one locale, for a look +# +# `fastlane ios screenshots` takes the raw captures into fastlane/screenshots; +# this reads them and writes the framed set to fastlane/framed, which is what +# `scripts/store-screenshots.py` then checks and stages. The raw set is left +# alone, so a framing change costs a rerun of this and not of the simulators. +# +# Nothing here is drawn from an image file. Every part of the design is a +# rounded rectangle, a plain rectangle or a line of text, so it is all in +# `fastlane/frames/frames.json` and in the numbers below - which is also what +# lets one canvas size become another. The only asset is the font. +# +# Needs Pillow, which is the one thing in this repository's scripts that is not +# in the standard library: +# +# python3 -m pip install Pillow + +import argparse +import bisect +import functools +import importlib.util +import json +import math +import shutil +import sys +from pathlib import Path + +try: + from PIL import Image, ImageChops, ImageDraw, ImageFilter, ImageFont +except ImportError: + sys.exit("this needs Pillow: python3 -m pip install Pillow") + +ROOT = Path(__file__).resolve().parent.parent +FRAMES = ROOT / "fastlane" / "frames" +CAPTURED = ROOT / "fastlane" / "screenshots" +FRAMED = ROOT / "fastlane" / "framed" + + +def load(path, name): + """Import a sibling script, whose file name is not an identifier.""" + spec = importlib.util.spec_from_file_location(name, path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +store = load(ROOT / "scripts" / "store-screenshots.py", "store_screenshots") + +# The design, as fractions of the canvas rather than pixels, because the canvas +# is whatever the capture is - 1320x2868 today and something else after the next +# device. +# +# How far down something sits is a fraction of the height; how big it is, and +# how far across, is a fraction of the width. So a taller canvas gives +# everything more room without stretching any of it. +# +# The proportions came off the 2020 artwork at 1242x2208. A phone is a good deal +# taller than that now, so the phone is anchored by its top left corner and left +# to run off the bottom and the right - which is what the original did too, only +# by less. +LAYOUT = { + "iphone": { + "headline_top": 0.068, + "headline_size": 0.070, # before it is shrunk to fit + "headline_width": 0.86, # what it is shrunk to fit inside + "headline_leading": 1.06, + "screen_left": 0.280, + "screen_top": 0.235, + "screen_width": 0.780, + # An iPhone 17 Pro Max, from its published dimensions: a 440pt screen + # inside a 78.0mm body, which leaves 2.54mm - 15.3pt - of black border + # and aluminium on every side, and a 62pt display corner. + "bezel": 0.0272, # screen edge to the outside of the body + "rim": 0.57, # how much of that is the black border + "corner": 0.141, # screen corner, of the screen's width + "island": (0.2826, 0.0811), # the Dynamic Island, of the screen's width + "island_top": 0.0334, + # The action button and the two volume keys: (how far down the body, + # how long), both of the body's height. Measured off Apple's own bezel + # artwork, which is also where the bezel, the island and the corner + # come from - so all of it is the device rather than a guess at it. + "buttons": [(0.189, 0.0423), (0.262, 0.0686), (0.349, 0.0686)], + # the side button, on the right edge, off the canvas where the phone + # sits today. Kept so the device is described whole: what is drawn + # follows from where it is placed, not the other way round. + "buttons_right": [(0.286, 0.1082)], + "chip_top": 0.440, + "chip_size": (0.240, 0.147), + "chip_step": 0.165, + "chip_text": 0.113, + "dash_stroke": 0.0056, + "dash_on": 0.0236, + "dash_off": 0.0098, + # Each decoration is a line that comes in from off the canvas, turns a + # corner and leaves again - one corner of a rounded rectangle far bigger + # than the picture. Points are (x, y) in canvas fractions, and a point + # past 1 is off the edge on purpose. A y of "chips" starts the line at + # the top of the tabs, so it runs behind however many there are and + # comes out underneath: anchored to a number instead, a screen with one + # tab leaves the line starting in mid air below it. + # The line crossing every screen. Each picture takes it in at the height + # the one before let it out at, steps it to a new height somewhere along + # the way, and hands it on - so no two screens carry the same line and + # the gallery still reads as one. There is one height per seam, which is + # one more than there are screens. + # + # Every height sits between the foot of the headline and the top of the + # device, the only band that is neither written on nor covered up. + "seams": [0.150, 0.200, 0.170, 0.215, 0.158, 0.195, 0.176], + # What the line does between the two seams it has to join. "in" is the + # height it arrived at and "out" the one it has to leave at; anything + # else is a height of its own. Only the left quarter is free below the + # band - the device covers the rest - so that is where a line can wander + # before it has to come back up and go. + # A step and, on some, a shallow dip into the left column before it. Kept + # shallow on purpose: the line is there to tie the pictures together, and + # one that wanders far down the page competes with what it is framing. + # One step, at a different place on each. Two of them dip a little + # further first, and only a little: the line is there to tie the + # pictures together, and anything more reads as decoration for its own + # sake across the top of every screen. + "routes": [ + [(0.34, "in"), (0.34, "out")], + [(0.17, "in"), (0.17, "out")], + [(0.52, "in"), (0.52, "out")], + [(0.12, "in"), (0.12, 0.248), (0.28, 0.248), (0.28, "out")], + [(0.26, "in"), (0.26, "out"), (0.60, "out")], + [(0.15, "in"), (0.15, 0.238), (0.33, 0.238), (0.33, "out")], + ], + "radii": [0.078, 0.066, 0.086, 0.062, 0.072, 0.070], + # The lower line. Some of these hang off the tabs, some come in from the + # left edge instead - picking up where the picture before let its own + # line disappear behind the device - and one leaves to the left again. + # A screen with no tabs takes one of the ones that does not need them. + "decorations": [ + [("chips", "chips"), ("chips", 0.930), (0.55, 0.930)], + [(-0.2, 0.700), (0.155, 0.700), (0.155, 0.930), (0.62, 0.930)], + [("chips", "chips"), ("chips", 0.880), (-0.2, 0.880)], + [(-0.2, 0.845), (0.185, 0.845), (0.185, 0.640), (0.58, 0.640)], + ], + }, + "ipad": { + "headline_top": 0.068, + "headline_size": 0.050, + "headline_width": 0.80, + "headline_leading": 1.06, + # Off the right edge by a little, as the phone is, but only a little: + # an iPad's status icons sit within a fiftieth of its own edge, so any + # more of a bleed takes the battery with it. The phone can afford 6% + # because the Dynamic Island pushes its icons well inboard. + "screen_left": 0.188, + "screen_top": 0.245, + "screen_width": 0.825, + # An iPad Pro 13-inch, likewise: a 1032pt screen in a 215.5mm body is + # 8.44mm - 43.8pt - of border, near three times the phone's, and the + # display corner is 18pt where the phone's is 62. Nothing on the left + # edge either: its buttons are all on the top one. + "bezel": 0.0350, + "rim": 0.86, + "corner": 0.0174, + "buttons": [], + "chip_top": 0.440, + "chip_size": (0.170, 0.0828), + "chip_step": 0.0935, + "chip_text": 0.080, + "dash_stroke": 0.0040, + "dash_on": 0.0147, + "dash_off": 0.0061, + "seams": [0.162, 0.208, 0.180, 0.224, 0.170, 0.202, 0.186], + "routes": [ + [(0.30, "in"), (0.30, "out")], + [(0.115, "in"), (0.115, "out")], + [(0.46, "in"), (0.46, "out")], + [(0.08, "in"), (0.08, 0.248), (0.19, 0.248), (0.19, "out")], + [(0.18, "in"), (0.18, "out"), (0.54, "out")], + [(0.10, "in"), (0.10, 0.238), (0.225, 0.238), (0.225, "out")], + ], + "radii": [0.060, 0.052, 0.068, 0.050, 0.056, 0.054], + "decorations": [ + [("chips", "chips"), ("chips", 0.930), (0.52, 0.930)], + [(-0.2, 0.620), (0.105, 0.620), (0.105, 0.930), (0.58, 0.930)], + [("chips", "chips"), ("chips", 0.880), (-0.2, 0.880)], + [(-0.2, 0.810), (0.125, 0.810), (0.125, 0.520), (0.54, 0.520)], + ], + }, +} + +# The phone, which is drawn rather than photographed. The rim is read across the +# body's width: bright where the edge turns towards the light, dark on the flat. +BODY = "#08080a" +RIM = ("#c9c9cf", "#6f7076", "#8e8f95", "#7c7d83", "#6a6b71", "#b6b7bd") +# The metal the device wears, off Apple's own bezel. They read as a step in the +# edge rather than as marks on it, which is what they are. +BUTTON = ("#d8d8d6", "#a9a9a7", "#c4c4c2") +GLASS = 96 # how brightly the screen's edge catches the light, of 255 + +# The shadow the device casts. Black rather than a colour of its own, which was +# mixed for the green ground and went muddy on the orange one, and offset down +# and right instead of sitting square behind the body, where the body covers it. +SHADOW = (0, 0, 0, 105) +SHADOW_OFFSET = (0.30, 0.65) # of the bezel, across and down +SHADOW_BLUR = 0.85 # of the bezel + + +@functools.lru_cache(maxsize=None) +def design(): + text = json.loads((FRAMES / "frames.json").read_text()) + text.pop("_comment", None) + return text + + +@functools.lru_cache(maxsize=None) +def font(size, weight): + """Nunito at one weight. It ships as a single variable file these days.""" + face = ImageFont.truetype(str(FRAMES / design()["font"]), size) + face.set_variation_by_name(weight) + return face + + +def gradient(size, top, bottom): + """The ground: the same colour top to bottom, a little darker at the foot.""" + width, height = size + strip = Image.new("RGB", (1, height)) + start = Image.new("RGB", (1, 1), top).getpixel((0, 0)) + end = Image.new("RGB", (1, 1), bottom).getpixel((0, 0)) + for y in range(height): + share = y / max(1, height - 1) + strip.putpixel((0, y), tuple(round(start[i] + (end[i] - start[i]) * share) for i in range(3))) + + return strip.resize((width, height)).convert("RGBA") + + +def rounded_path(points, radius, per_corner=24): + """A polyline with its corners rounded off, as points to walk along.""" + walk = [points[0]] + for before, corner, after in zip(points, points[1:], points[2:]): + into = math.hypot(corner[0] - before[0], corner[1] - before[1]) + out = math.hypot(after[0] - corner[0], after[1] - corner[1]) + r = min(radius, into / 2, out / 2) + start = (corner[0] + (before[0] - corner[0]) * r / into, + corner[1] + (before[1] - corner[1]) * r / into) + end = (corner[0] + (after[0] - corner[0]) * r / out, + corner[1] + (after[1] - corner[1]) * r / out) + walk.append(start) + for i in range(1, per_corner): + t = i / per_corner + # one quadratic bend, with the corner itself as the control point + walk.append(( + (1 - t) ** 2 * start[0] + 2 * (1 - t) * t * corner[0] + t ** 2 * end[0], + (1 - t) ** 2 * start[1] + 2 * (1 - t) * t * corner[1] + t ** 2 * end[1], + )) + walk.append(end) + walk.append(points[-1]) + + return walk + + +def dashed(canvas, points, stroke, on, off, colour=(255, 255, 255, 255), phase=0.0): + """Lays dashes along a path, so a dash carries on around a corner. + + Counted out from the start of the path rather than accumulated as it walks, + because a step that rounds to nothing next to a distance already travelled + is a step that never arrives. + """ + reached = [0.0] + for before, after in zip(points, points[1:]): + reached.append(reached[-1] + math.hypot(after[0] - before[0], after[1] - before[1])) + total = reached[-1] + if not total: + return + + def at(distance): + """The point that far along the path.""" + index = max(1, min(len(reached) - 1, bisect.bisect_left(reached, distance))) + span = reached[index] - reached[index - 1] + share = 0.0 if not span else (distance - reached[index - 1]) / span + before, after = points[index - 1], points[index] + + return (before[0] + (after[0] - before[0]) * share, + before[1] + (after[1] - before[1]) * share) + + draw = ImageDraw.Draw(canvas) + width = max(1, round(stroke)) + + period = on + off + phase = phase % period + for number in range(int((total + phase) // period) + 2): + start = number * period - phase + end = min(start + on, total) + if start >= total: + break + start = max(start, 0.0) + if start >= end: + continue + + # the path's own corners inside this dash, so a dash that lands on a + # bend is drawn bent rather than as a chord across it + run = [at(start)] + run += [point for point, so_far in zip(points, reached) if start < so_far < end] + run.append(at(end)) + draw.line(run, fill=colour, width=width, joint="curve") + + +def squircle(box, radius, exponent=5.0, per_corner=40): + """A rounded rectangle whose corners are superellipse quadrants. + + Apple's corners are a continuous curve rather than a circular arc: the + curvature eases into the straight edge instead of starting at full bend. A + circle reads as an Android phone, or as a 2015 one. Exponent 5 is close + enough that nobody looks twice. + """ + x0, y0, x1, y1 = box + r = min(radius, (x1 - x0) / 2, (y1 - y0) / 2) + points = [] + + # each corner as (centre, x sign, y sign), going clockwise from bottom right. + # Two of the four are walked backwards, so that every quadrant leaves off + # where the next one starts and the outline closes. + for (cx, cy), sx, sy in (((x1 - r, y1 - r), 1, 1), ((x0 + r, y1 - r), -1, 1), + ((x0 + r, y0 + r), -1, -1), ((x1 - r, y0 + r), 1, -1)): + for step in range(per_corner + 1): + share = step / per_corner if sx * sy > 0 else 1 - step / per_corner + angle = math.pi / 2 * share + points.append(( + cx + sx * r * math.cos(angle) ** (2 / exponent), + cy + sy * r * math.sin(angle) ** (2 / exponent), + )) + + return points + + +def outset(points, distance): + """The same outline, moved out by a fixed distance along its own normals. + + A squircle grown by raising its radius is not parallel to the one it grew + from: the gap between the two opens up around the corner and closes down + the sides. Drawn that way a bezel is visibly fatter at the corners than + along the edges, which is the first thing anybody who owns the phone sees. + """ + walked = list(zip(points, points[1:] + points[:1])) + facing = 1.0 if sum(x0 * y1 - x1 * y0 for (x0, y0), (x1, y1) in walked) > 0 else -1.0 + moved = [] + + for index, (x, y) in enumerate(points): + (ax, ay), (bx, by) = points[index - 1], points[(index + 1) % len(points)] + run, rise = bx - ax, by - ay + length = math.hypot(run, rise) or 1.0 + moved.append((x + facing * rise / length * distance, y - facing * run / length * distance)) + + return moved + + +def stencil(size, points, supersample=3): + """An antialiased mask of one shape. Pillow's polygon has hard edges, so it + is drawn large and shrunk, which is cheaper than it sounds on a mask.""" + big = Image.new("L", (size[0] * supersample, size[1] * supersample), 0) + ImageDraw.Draw(big).polygon([(x * supersample, y * supersample) for x, y in points], fill=255) + + return big.resize(size, Image.LANCZOS) + + +def chamfer(share): + """The metal's colour that far across the band, outside edge to black. + + Read off Apple's own bezel: the edge is turned, so it comes in at a middling + grey, climbs to a highlight about two thirds of the way in and falls away + again. Lit along its length like this it reads as a rolled edge; filled + flat, as a grey stripe. + """ + stops = ((0.00, 109), (0.19, 157), (0.40, 190), (0.64, 235), (0.79, 195), (1.00, 120)) + place = bisect.bisect_right([at for at, _ in stops], share) + if place == 0: + return (stops[0][1],) * 3 + if place == len(stops): + return (stops[-1][1],) * 3 + + (before, low), (after, high) = stops[place - 1], stops[place] + level = round(low + (high - low) * (share - before) / (after - before)) + + return (level,) * 3 + + +def brushed(size, colours): + """The rim: a metal that catches the light differently across its width.""" + width, height = size + strip = Image.new("RGB", (len(colours), 1)) + for index, colour in enumerate(colours): + strip.putpixel((index, 0), Image.new("RGB", (1, 1), colour).getpixel((0, 0))) + + return strip.resize((width, height), Image.BICUBIC) + + +def crossing(layout, order, size): + """The line this screen hands on: in at one height, out at the next.""" + width, height = size + seams = layout["seams"] + enters = seams[order % len(seams)] * height + leaves = seams[(order + 1) % len(seams)] * height + route = layout["routes"][order % len(layout["routes"])] + + def down(y): + return enters if y == "in" else leaves if y == "out" else y * height + + return ( + [(-0.2 * width, enters)] + + [(x * width, down(y)) for x, y in route] + + [(1.2 * width, leaves)] + ) + + +def walked(points): + """How far a path runs, so the next one can pick the dashes up.""" + return sum( + math.hypot(after[0] - before[0], after[1] - before[1]) + for before, after in zip(points, points[1:]) + ) + + +def phone(canvas, shot, layout): + """The device: the capture behind glass, in a metal body. + + Drawn rather than pasted from a mockup, so it is the shape of whatever was + captured. A frame downloaded for one device is the wrong shape for the next + one, and the sets on offer stop at a generation the store no longer asks for. + + Built in its own image and composited once, so the parts can be masked + against each other without the ground showing through the seams. + """ + width, height = canvas.size + screen_width = layout["screen_width"] * width + screen_height = screen_width * shot.height / shot.width + left, top = layout["screen_left"] * width, layout["screen_top"] * height + screen = (left, top, left + screen_width, top + screen_height) + + bezel = layout["bezel"] * width # screen edge to the outside of the body + rim = bezel * layout["rim"] # how much of that is metal + corner = layout["corner"] * screen_width + + body = (screen[0] - bezel, screen[1] - bezel, screen[2] + bezel, screen[3] + bezel) + + # its own canvas, with room to the left for the buttons that stand proud + margin = round(bezel * 3) + origin = (round(body[0]) - margin, round(body[1]) - margin) + size = (round(body[2]) - origin[0] + margin, round(body[3]) - origin[1] + margin) + here = lambda box: tuple(v - origin[i % 2] for i, v in enumerate(box)) + + device = Image.new("RGBA", size, (0, 0, 0, 0)) + + # the buttons first, so the body's own edge covers where they meet it + metal = brushed(size, BUTTON) + buttons = Image.new("L", size, 0) + draw = ImageDraw.Draw(buttons) + stand = screen_width * 0.0061 # how far a button stands proud, 2.7pt + tall_as = body[3] - body[1] + for edge, keys in ((here(body)[0], layout["buttons"]), + (here(body)[2], layout.get("buttons_right", []))): + for at_height, tall in keys: + y = here(body)[1] + tall_as * at_height + draw.rounded_rectangle((edge - stand, y, edge + stand, y + tall_as * tall), + radius=stand * 0.55, fill=255) + device.paste(metal, (0, 0), buttons) + + # Every edge is the screen's own outline moved out, so the black border and + # the metal around it are the same width the whole way round - which is what + # they are on the device, and not what a bigger squircle would give. + face = squircle(here(screen), corner) + outline = outset(face, bezel) + + # The metal, lit across the band's own width rather than the body's: the + # band is filled as rings, each the colour ``chamfer`` gives for how far in + # it sits, so the highlight follows the edge the whole way round. + band = bezel - rim + lit = Image.new("RGB", size, chamfer(1.0)) + rings = ImageDraw.Draw(lit) + steps = max(8, round(band)) + for step in range(steps + 1): + share = step / steps + rings.polygon(outset(face, bezel - band * share), fill=chamfer(share)) + + device.paste(lit, (0, 0), stencil(size, outline)) + + # the black surround the glass sits in, and then the glass + device.paste(Image.new("RGB", size, BODY), (0, 0), stencil(size, outset(face, rim))) + + fitted = shot.resize((round(screen_width), round(screen_height)), Image.LANCZOS).convert("RGBA") + inside = here(screen) + device.paste(fitted, (round(inside[0]), round(inside[1])), + stencil(size, face).crop( + (round(inside[0]), round(inside[1]), + round(inside[0]) + fitted.width, round(inside[1]) + fitted.height))) + + # The hairline where the glass meets the surround, which a real device + # catches the light along. Without it a screen that is dark at the top - the + # intro is - runs into the black bezel, and the two read as one fat border + # off a phone from 2016. + hair = max(1.0, screen_width * 0.0012) + halo = ImageChops.subtract( + stencil(size, face), stencil(size, outset(face, -hair)) + ).point(lambda level: level * GLASS // 255) + device.paste(Image.new("RGB", size, "white"), (0, 0), halo) + + # the pill the camera sits in, over the gap the status bar leaves for it + if layout.get("island"): + island_width, island_height = (share * screen_width for share in layout["island"]) + middle = (inside[0] + inside[2]) / 2 + island_top = inside[1] + layout["island_top"] * screen_width + ImageDraw.Draw(device).rounded_rectangle( + (middle - island_width / 2, island_top, middle + island_width / 2, island_top + island_height), + radius=island_height / 2, fill=BODY) + + shadow = Image.new("RGBA", size, (0, 0, 0, 0)) + shadow.paste(Image.new("RGB", size, SHADOW[:3]), (0, 0), + stencil(size, outline).point(lambda v: v * SHADOW[3] // 255)) + canvas.alpha_composite( + shadow.filter(ImageFilter.GaussianBlur(bezel * SHADOW_BLUR)), + (origin[0] + round(bezel * SHADOW_OFFSET[0]), origin[1] + round(bezel * SHADOW_OFFSET[1]))) + canvas.alpha_composite(device, origin) + + +def headline(canvas, lines, layout): + """Two lines, light over bold, centred and shrunk until they fit. + + Fitted rather than set at a fixed size because the same sentence is a third + longer in German than in English, and a line that runs off the picture is + worse than one set a little smaller. + """ + width, height = canvas.size + size = round(layout["headline_size"] * width) + allowed = layout["headline_width"] * width + weights = ("Regular", "Bold") + draw = ImageDraw.Draw(canvas) + + while size > 8: + faces = [font(size, weight) for weight in weights] + if max(draw.textlength(line, font=face) for line, face in zip(lines, faces)) <= allowed: + break + size -= 2 + + leading = size * layout["headline_leading"] + y = layout["headline_top"] * height + for line, face in zip(lines, faces): + draw.text((width / 2, y), line, font=face, fill="white", anchor="ma") + y += leading + + +def chips(canvas, names, palette, layout): + """The odt/ods/odp tabs, running off the left edge as the design has them.""" + width, height = canvas.size + least, chip_height = (share * width for share in layout["chip_size"]) + face = font(round(layout["chip_text"] * width), "Bold") + draw = ImageDraw.Draw(canvas) + + # As wide as the longest word in the whole design needs, and no narrower + # than the design's own tab: "odt" is three letters and "docx" is four, and + # a tab cut to fit the shorter one loses the end of the longer. + # + # Measured across every format rather than the two or three on this screen, + # so the tabs are one length through the gallery. Cut to fit each screen + # they step in and out as the reader swipes, which reads as the pictures + # having been made at different times. + padding = layout["chip_text"] * width * 0.42 + chip_width = max([least] + [draw.textlength(name, font=face) + 2 * padding for name in palette]) + + for index, name in enumerate(names): + top = layout["chip_top"] * height + layout["chip_step"] * width * index + draw.rectangle((-2, top, chip_width, top + chip_height), fill=palette[name]) + draw.text((chip_width / 2, top + chip_height / 2), name, font=face, fill="white", anchor="mm") + + return chip_width + + +def frame(shot, screen, locale, spec, order=0): + """One picture: ground, decorations, phone, tabs, headline.""" + kind = store.device(*shot.size) + if kind is None: + raise ValueError(f"{shot.size[0]}x{shot.size[1]} is no size the store takes") + + layout = LAYOUT[kind] + width, height = shot.size + canvas = gradient(shot.size, *spec["backgrounds"][screen["background"]]) + + on, off = layout["dash_on"] * width, layout["dash_off"] * width + stroke = layout["dash_stroke"] * width + radius = layout["radii"][order % len(layout["radii"])] * width + + # The crossing line, and the dash pattern picked up where the screens before + # it left off, so the dashes carry on across the gallery rather than + # restarting at every picture. + before = sum(walked(crossing(layout, index, shot.size)) for index in range(order)) + dashed( + canvas, rounded_path(crossing(layout, order, shot.size), radius), stroke, on, off, phase=before + ) + + lower = layout["decorations"][order % len(layout["decorations"])] + + # a line hanging off tabs that are not there reads as a line starting in mid + # air, so a screen without them takes one that comes in from the edge + if not screen["chips"] and any("chips" in point for point in lower): + lower = next( + points for points in layout["decorations"] if not any("chips" in p for p in points) + ) + + # "chips" is the middle of the tabs, so the line runs behind however many + # there are and comes out underneath + placed = [ + (layout["chip_size"][0] / 2 if x == "chips" else x, + layout["chip_top"] if y == "chips" else y) + for x, y in lower + ] + dashed( + canvas, + rounded_path([(x * width, y * height) for x, y in placed], radius), + stroke, on, off, + ) + + phone(canvas, shot, layout) + chips(canvas, screen["chips"], spec["chips"], layout) + headline(canvas, copy(screen, locale), layout) + + return canvas.convert("RGB") + + +def copy(screen, locale): + """This screen's two lines in that language, or the English if it has none.""" + lines = screen["headline"].get(locale) or screen["headline"][store.FALLBACK] + + return lines + + +def main(argv=None): + parser = argparse.ArgumentParser(description="Frame the captured App Store screenshots.") + parser.add_argument("--captured", metavar="DIR", default=CAPTURED, + help=f"where the capture run wrote (default {CAPTURED.relative_to(ROOT)})") + parser.add_argument("--framed", metavar="DIR", default=FRAMED, + help=f"where to write the framed set (default {FRAMED.relative_to(ROOT)})") + parser.add_argument("--locale", action="append", + help="only this locale, repeatable; default is everything captured") + args = parser.parse_args(argv) + + spec = design() + screens = {screen["name"]: screen for screen in spec["screens"]} + captured, framed = Path(args.captured), Path(args.framed) + + wanted = args.locale or store.languages() + written = 0 + + for locale in wanted: + folder = captured / locale + if not folder.is_dir(): + print(f"{locale}: no {folder}", file=sys.stderr) + continue + + # emptied rather than written over, so a screen that was renamed does + # not leave yesterday's picture behind for the release to find + out = framed / locale + shutil.rmtree(out, ignore_errors=True) + out.mkdir(parents=True, exist_ok=True) + + for path in sorted(folder.glob("*.png")): + name = next((n for n in screens if path.stem.endswith(n)), None) + if name is None: + continue + + with Image.open(path) as shot: + # a capture of a device the store does not ask for is left where + # it is; store-screenshots.py is what says the set is wrong + if store.device(*shot.size) is None: + print(f"{locale}: skipping {path.name}, {shot.width}x{shot.height} is no " + "size the store takes", file=sys.stderr) + continue + + picture = frame( + shot.convert("RGB"), screens[name], locale, spec, order=list(screens).index(name) + ) + + picture.save(out / path.name) + written += 1 + + print(f"framed {written} screenshots into {framed}") + + return 0 if written else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/make-screenshot-documents.py b/scripts/make-screenshot-documents.py new file mode 100755 index 0000000..86f8034 --- /dev/null +++ b/scripts/make-screenshot-documents.py @@ -0,0 +1,1559 @@ +#!/usr/bin/env python3 +"""Builds the documents the App Store screenshots are taken of. + +A reader's screenshots are mostly the document it is reading, so these are +written rather than borrowed: a short report, a small spreadsheet and a three +slide deck, in every language the app speaks and the store has a listing for. +The screenshot of the German store shows a German document. + +Kept small on purpose - a few kilobytes each, no images, no third party +material - because they are read once, on a simulator, to be photographed. +They are bundled in Debug builds only; `EXCLUDED_SOURCE_FILE_NAMES` keeps +`sample-*` out of the archive that goes to the store. + + python3 scripts/make-screenshot-documents.py + python3 scripts/make-screenshot-documents.py --language en one of them + +Rerun it when the wording changes, and commit what it writes. The packages are +byte for byte reproducible, so a rerun that changes nothing leaves no diff. +""" + +import argparse +import json +import re +import unicodedata +import zipfile +from pathlib import Path +from xml.sax.saxutils import escape + +# 1980-01-01, what zip stores when it is given nothing: a rerun with the same +# words has to produce the same bytes, or every run is a commit +EPOCH = (1980, 1, 1, 0, 0, 0) + +SAMPLES = Path(__file__).resolve().parent.parent / "OpenDocumentReader" / "Samples" + +NAMESPACES = " ".join( + [ + 'xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"', + 'xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"', + 'xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"', + 'xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"', + 'xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"', + 'xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"', + 'xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"', + ] +) + +MANIFEST = """ + + + + + +""" + +# A4 upright for the report and the sheet, 16:9 for the deck. +# +# A page is fitted to the width of the screen, so a page with little on it reads +# as a smudge in the top third of an empty sheet. The answer is words rather +# than smaller paper: these documents are written long enough to fill A4. +PAGE_LAYOUTS = { + "document": '', + "slide": '', +} + +# One accent, used for the report's headings and the slide titles, so the three +# documents read as one set. Blue, because the app's own tint is. +ACCENT = "#1c6fd6" +RULE = "#d4d9e0" + + +def styles(kind: str) -> str: + return f""" + + + + + {PAGE_LAYOUTS[kind]} + + + + + + +""" + + +def content(body: str, automatic: str = "") -> str: + return f""" + + +{automatic} + + +{body} + + +""" + + +def paragraph_style(name: str, *, size: str, weight: str = "normal", colour: str = "#1a1a1a", space: str = "0.4cm") -> str: + return f""" + + + """ + + +def report(words: dict) -> str: + """A page of text: a title, a lead, two headed sections and a closing line.""" + automatic = "\n".join( + [ + paragraph_style("Title", size="26pt", weight="bold", space="0.8cm"), + paragraph_style("Heading", size="16pt", weight="bold", colour=ACCENT, space="0.3cm"), + paragraph_style("Body", size="12pt", space="0.5cm"), + ] + ) + + lines = [ + f' {escape(words["title"])}', + f' {escape(words["lead"])}', + ] + for heading, paragraphs in words["sections"]: + lines.append( + f' {escape(heading)}' + ) + lines += [f' {escape(text)}' for text in paragraphs] + lines.append(f' {escape(words["closing"])}') + + return content(" \n" + "\n".join(lines) + "\n ", automatic) + + +def table(words: dict, columns: int = 4, rows: int = 0, scale: int = 1) -> tuple: + """The figures as rows of cells: a header, the items across as many periods + as are asked for with their totals, and a totals row under them. + + Narrowed and shortened for the files that are not the budget, so the .xlsx + and the invoice hold their own figures rather than the .ods twice. + + As wide as the header a language has words for, so one translated ahead of + the others comes out short rather than out of step. + """ + periods = words["periods"][:columns] + columns = len(periods) + taken = FIGURES[:rows] if rows else FIGURES + names = words["rows"][: len(taken)] + + head = [words["item"]] + periods + [words["total"]] + body = [ + [name] + [value * scale for value in figures[:columns]] + [sum(figures[:columns]) * scale] + for name, figures in zip(names, taken) + ] + foot = ( + [words["total"]] + + [sum(line[column + 1] for line in body) for column in range(len(periods))] + + [sum(line[-1] for line in body)] + ) + + return head, body, foot + + +def sheet(words: dict) -> str: + """Two sheets, so the tab bar under the document has something to show.""" + automatic = "\n".join( + [ + # two widths: eight at the label's width put half the sheet off + # the right edge, and a figure needs less room than its row's name + """ + + """, + """ + + """, + """ + + + """ % (RULE, ACCENT), + """ + + + """ % (RULE,), + ] + ) + + def row(cells: list, style: str | None = None) -> str: + marked = f' table:style-name="{style}"' if style else "" + out = [" "] + for cell in cells: + if isinstance(cell, int): + out.append( + f' ' + f"{cell}" + ) + else: + out.append( + f' ' + f"{escape(cell)}" + ) + out.append(" ") + + return "\n".join(out) + + head, body, foot = table(words, columns=6) + + overview = [row(head, "ceHead")] + [row(line) for line in body] + [row(foot, "ceTotal")] + costs = [row([words["item"], words["total"]], "ceHead")] + costs += [row([line[0], line[-1]]) for line in body] + + tables = [] + for name, rows, columns in ( + (words["sheets"][0], overview, len(head)), + (words["sheets"][1], costs, 2), + ): + # the label column, then a figure column for each of the rest + marks = "\n".join( + [' '] + + [' '] * (columns - 1) + ) + tables.append( + f' \n{marks}\n' + + "\n".join(rows) + + "\n " + ) + + return content(" \n" + "\n".join(tables) + "\n ", automatic) + + +def deck(words: dict) -> str: + """Three slides, each with a title and its bullets.""" + automatic = "\n".join( + [ + paragraph_style("SlideTitle", size="32pt", weight="bold", colour=ACCENT, space="0.6cm"), + paragraph_style("Bullet", size="18pt", space="0.35cm"), + ] + ) + + pages = [] + for title, bullets in words["slides"]: + lines = [f' {escape(title)}'] + lines += [ + f' \u2022 {escape(point)}' for point in bullets + ] + pages.append( + f' \n' + ' \n' + " \n" + "\n".join(lines) + "\n \n" + " \n " + ) + + return content(" \n" + "\n".join(pages) + "\n ", automatic) + + +# Short and plain on purpose: this is a document over someone's shoulder in a +# store screenshot, not copy that has to sell anything. +WORDS = { + "en": { + "title": "Quarterly report", + "lead": "The team met every goal of the second quarter, and the new release went out on time.", + "sections": [ + ["Highlights", [ + "Costs stayed below budget, and two new partners joined the project.", + "The new release reached more people in its first week than the last one did in a month.", + "Support answered nine of ten questions the same day.",]], + ["Costs and budget", [ + "Spending on software rose with the new licences, while travel fell again.", + "Hardware was replaced once, and support stayed steady through the quarter.", + "Two servers moved to the new provider without a day of downtime.",]], + ["Next quarter", [ + "The release in September is the last one planned this year.", + "Two positions open in support, and one in design.", + "The office moves in November, and the budget for it is agreed.", + ]], + ["The people", [ + "Six people worked on the release, two of them new this year.", + "Holiday cover was arranged in April and held through the summer.", + "Everyone has taken the training the new licence requires.", + ]], + ["Risks", [ + "The move in November is the one date nothing else can slip past.", + "One supplier has not signed the new terms, and is being chased.", + "Hosting costs rise in January unless the contract is renewed early.", + ]], + ], + "closing": "The next meeting is at the end of July.", + "sheets": ["Overview", "Costs"], + "item": "Item", + "total": "Total", + "periods": ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], + "rows": ["Software", "Travel", "Hardware", "Marketing", "Support", "Training", "Licences", "Hosting", "Events", "Office", "Cloud", "Recruiting", "Legal", "Insurance", "Catering", "Shipping", "Advertising", "Consulting", "Maintenance", "Utilities", "Equipment", "Subscriptions", "Telephony", "Internet", "Security", "Backups", "Domains", "Certificates", "Printing", "Stationery", "Postage", "Cleaning", "Repairs", "Furniture", "Storage", "Bank fees", "Memberships", "Conferences", "Translation", "Design"], + "slides": [ + ["Project plan", ["Goals for the quarter", "Budget and costs", "Next steps"]], + ["Schedule", ["Release in June", "Review in July", "Planning in August"]], + ["Team", ["Two new partners", "Support in three languages", "Training in autumn"]], + ], + }, + "de": { + "title": "Quartalsbericht", + "lead": "Das Team hat alle Ziele des zweiten Quartals erreicht, und die neue Version ist p\u00fcnktlich erschienen.", + "sections": [ + ["Das Wichtigste", [ + "Die Kosten blieben unter dem Budget, und zwei neue Partner sind zum Projekt gesto\u00dfen.", + "Die neue Version erreichte in der ersten Woche mehr Menschen als die letzte in einem Monat.", + "Der Support beantwortete neun von zehn Anfragen noch am selben Tag.",]], + ["Kosten und Budget", [ + "Die Ausgaben f\u00fcr Software stiegen mit den neuen Lizenzen, die Reisekosten sanken erneut.", + "Die Hardware wurde einmal ersetzt, der Support blieb \u00fcber das Quartal stabil.", + "Zwei Server sind ohne Ausfalltag zum neuen Anbieter umgezogen.",]], + ["N\xe4chstes Quartal", [ + "Die Version im September ist die letzte f\xfcr dieses Jahr.", + "Zwei Stellen im Support sind offen, eine im Design.", + "Der Umzug ins neue B\xfcro ist f\xfcr November geplant und budgetiert.", + ]], + ["Die Menschen", [ + "An der Version arbeiteten sechs Personen, zwei davon neu in diesem Jahr.", + "Die Urlaubsvertretung wurde im April geregelt und trug durch den Sommer.", + "Alle haben die Schulung absolviert, die die neue Lizenz verlangt.", + ]], + ["Risiken", [ + "Der Umzug im November ist der einzige Termin, an dem nichts vorbeigeht.", + "Ein Lieferant hat die neuen Bedingungen noch nicht unterschrieben.", + "Die Hostingkosten steigen im Januar, wenn der Vertrag nicht fr\xfcher erneuert wird.", + ]], + ], + "closing": "Das n\u00e4chste Treffen findet Ende Juli statt.", + "sheets": ["\u00dcbersicht", "Kosten"], + "item": "Position", + "total": "Gesamt", + "periods": ["Q1", "Q2", "Q3", "Q4"], + "rows": ["Software", "Reisen", "Hardware", "Marketing", "Support", "Schulung", "Lizenzen", "Hosting", "Veranstaltungen", "B\u00fcro", "Cloud", "Personalsuche", "Recht", "Versicherung", "Verpflegung", "Versand", "Werbung", "Beratung", "Wartung", "Nebenkosten"], + "slides": [ + ["Projektplan", ["Ziele f\u00fcr das Quartal", "Budget und Kosten", "N\u00e4chste Schritte"]], + ["Zeitplan", ["Version im Juni", "R\u00fcckblick im Juli", "Planung im August"]], + ["Team", ["Zwei neue Partner", "Support in drei Sprachen", "Schulung im Herbst"]], + ], + }, + "es": { + "title": "Informe trimestral", + "lead": "El equipo cumpli\u00f3 todos los objetivos del segundo trimestre y la nueva versi\u00f3n sali\u00f3 a tiempo.", + "sections": [ + ["Lo m\u00e1s destacado", [ + "Los costes se mantuvieron por debajo del presupuesto y dos nuevos socios se unieron al proyecto.", + "La nueva versi\u00f3n lleg\u00f3 a m\u00e1s gente en su primera semana que la anterior en un mes.", + "El soporte respondi\xf3 nueve de cada diez consultas el mismo d\xeda.",]], + ["Costes y presupuesto", [ + "El gasto en software subi\u00f3 con las nuevas licencias, mientras que los viajes volvieron a bajar.", + "El hardware se sustituy\u00f3 una vez y el soporte se mantuvo estable durante el trimestre.", + "Dos servidores pasaron al nuevo proveedor sin un d\xeda de ca\xedda.",]], + ["Pr\xf3ximo trimestre", [ + "La versi\xf3n de septiembre es la \xfaltima prevista este a\xf1o.", + "Hay dos vacantes en soporte y una en dise\xf1o.", + "La mudanza de oficina es en noviembre y ya tiene presupuesto.", + ]], + ["Las personas", [ + "En la versi\xf3n trabajaron seis personas, dos de ellas nuevas este a\xf1o.", + "La cobertura de vacaciones se organiz\xf3 en abril y aguant\xf3 todo el verano.", + "Todos han hecho la formaci\xf3n que exige la nueva licencia.", + ]], + ["Riesgos", [ + "La mudanza de noviembre es la \xfanica fecha que no puede moverse.", + "Un proveedor a\xfan no ha firmado las nuevas condiciones.", + "El alojamiento sube en enero si no se renueva antes el contrato.", + ]], + ], + "closing": "La pr\u00f3xima reuni\u00f3n es a finales de julio.", + "sheets": ["Resumen", "Costes"], + "item": "Concepto", + "total": "Total", + "periods": ["T1", "T2", "T3", "T4"], + "rows": ["Software", "Viajes", "Hardware", "Marketing", "Soporte", "Formaci\u00f3n", "Licencias", "Alojamiento", "Eventos", "Oficina", "Nube", "Contrataci\xf3n", "Legal", "Seguros", "Catering", "Env\xedos", "Publicidad", "Consultor\xeda", "Mantenimiento", "Suministros"], + "slides": [ + ["Plan del proyecto", ["Objetivos del trimestre", "Presupuesto y costes", "Pr\u00f3ximos pasos"]], + ["Calendario", ["Versi\u00f3n en junio", "Revisi\u00f3n en julio", "Planificaci\u00f3n en agosto"]], + ["Equipo", ["Dos nuevos socios", "Soporte en tres idiomas", "Formaci\u00f3n en oto\u00f1o"]], + ], + }, + "fr": { + "title": "Rapport trimestriel", + "lead": "L'\u00e9quipe a atteint tous les objectifs du deuxi\u00e8me trimestre et la nouvelle version est sortie \u00e0 temps.", + "sections": [ + ["Points forts", [ + "Les co\u00fbts sont rest\u00e9s sous le budget et deux nouveaux partenaires ont rejoint le projet.", + "La nouvelle version a touch\u00e9 plus de monde en une semaine que la pr\u00e9c\u00e9dente en un mois.", + "Le support a r\xe9pondu \xe0 neuf demandes sur dix le jour m\xeame.",]], + ["Co\u00fbts et budget", [ + "Les d\u00e9penses de logiciels ont augment\u00e9 avec les nouvelles licences, tandis que les voyages ont encore baiss\u00e9.", + "Le mat\u00e9riel a \u00e9t\u00e9 remplac\u00e9 une fois et le support est rest\u00e9 stable sur le trimestre.", + "Deux serveurs ont migr\xe9 vers le nouveau prestataire sans une journ\xe9e d'arr\xeat.",]], + ["Trimestre prochain", [ + "La version de septembre est la derni\xe8re pr\xe9vue cette ann\xe9e.", + "Deux postes sont ouverts au support, un au design.", + "Le d\xe9m\xe9nagement est pr\xe9vu en novembre, et le budget est valid\xe9.", + ]], + ["Les personnes", [ + "Six personnes ont travaill\xe9 sur la version, dont deux arriv\xe9es cette ann\xe9e.", + "Les remplacements d'\xe9t\xe9 ont \xe9t\xe9 organis\xe9s en avril et ont tenu.", + "Tout le monde a suivi la formation qu'exige la nouvelle licence.", + ]], + ["Risques", [ + "Le d\xe9m\xe9nagement de novembre est la seule date qui ne peut pas bouger.", + "Un prestataire n'a pas encore sign\xe9 les nouvelles conditions.", + "L'h\xe9bergement augmente en janvier sans renouvellement anticip\xe9.", + ]], + ], + "closing": "La prochaine r\u00e9union aura lieu fin juillet.", + "sheets": ["Aper\u00e7u", "Co\u00fbts"], + "item": "Poste", + "total": "Total", + "periods": ["T1", "T2", "T3", "T4"], + "rows": ["Logiciels", "Voyages", "Mat\u00e9riel", "Marketing", "Support", "Formation", "Licences", "H\u00e9bergement", "\u00c9v\u00e9nements", "Bureau", "Cloud", "Recrutement", "Juridique", "Assurance", "Traiteur", "Exp\xe9dition", "Publicit\xe9", "Conseil", "Maintenance", "Charges"], + "slides": [ + ["Plan du projet", ["Objectifs du trimestre", "Budget et co\u00fbts", "Prochaines \u00e9tapes"]], + ["Calendrier", ["Version en juin", "Bilan en juillet", "Planification en ao\u00fbt"]], + ["\u00c9quipe", ["Deux nouveaux partenaires", "Support en trois langues", "Formation \u00e0 l'automne"]], + ], + }, + "it": { + "title": "Relazione trimestrale", + "lead": "Il team ha raggiunto tutti gli obiettivi del secondo trimestre e la nuova versione \u00e8 uscita in tempo.", + "sections": [ + ["In evidenza", [ + "I costi sono rimasti sotto il budget e due nuovi partner si sono uniti al progetto.", + "La nuova versione ha raggiunto pi\u00f9 persone in una settimana di quante la precedente in un mese.", + "Il supporto ha risposto a nove richieste su dieci in giornata.",]], + ["Costi e budget", [ + "La spesa per il software \u00e8 cresciuta con le nuove licenze, mentre i viaggi sono di nuovo calati.", + "L'hardware \u00e8 stato sostituito una volta e il supporto \u00e8 rimasto stabile per tutto il trimestre.", + "Due server sono passati al nuovo fornitore senza un giorno di fermo.",]], + ["Prossimo trimestre", [ + "La versione di settembre \xe8 l'ultima prevista quest'anno.", + "Ci sono due posizioni aperte nel supporto e una nel design.", + "Il trasloco \xe8 a novembre e il budget \xe8 approvato.", + ]], + ["Le persone", [ + "Alla versione hanno lavorato sei persone, due delle quali nuove quest'anno.", + "Le sostituzioni estive sono state organizzate ad aprile e hanno retto.", + "Tutti hanno seguito il corso richiesto dalla nuova licenza.", + ]], + ["Rischi", [ + "Il trasloco di novembre \xe8 l'unica data che non pu\xf2 slittare.", + "Un fornitore non ha ancora firmato le nuove condizioni.", + "L'hosting aumenta a gennaio se il contratto non si rinnova prima.", + ]], + ], + "closing": "Il prossimo incontro \u00e8 a fine luglio.", + "sheets": ["Panoramica", "Costi"], + "item": "Voce", + "total": "Totale", + "periods": ["T1", "T2", "T3", "T4"], + "rows": ["Software", "Viaggi", "Hardware", "Marketing", "Supporto", "Formazione", "Licenze", "Hosting", "Eventi", "Ufficio", "Cloud", "Selezione", "Legale", "Assicurazione", "Catering", "Spedizioni", "Pubblicit\xe0", "Consulenza", "Manutenzione", "Utenze"], + "slides": [ + ["Piano di progetto", ["Obiettivi del trimestre", "Budget e costi", "Prossimi passi"]], + ["Calendario", ["Versione a giugno", "Revisione a luglio", "Pianificazione ad agosto"]], + ["Team", ["Due nuovi partner", "Supporto in tre lingue", "Formazione in autunno"]], + ], + }, + "pl": { + "title": "Raport kwartalny", + "lead": "Zesp\u00f3\u0142 osi\u0105gn\u0105\u0142 wszystkie cele drugiego kwarta\u0142u, a nowa wersja ukaza\u0142a si\u0119 na czas.", + "sections": [ + ["Najwa\u017cniejsze", [ + "Koszty pozosta\u0142y poni\u017cej bud\u017cetu, a do projektu do\u0142\u0105czy\u0142o dw\u00f3ch nowych partner\u00f3w.", + "Nowa wersja dotar\u0142a w pierwszym tygodniu do wi\u0119kszej liczby os\u00f3b ni\u017c poprzednia w miesi\u0105c.", + "Wsparcie odpowiedzia\u0142o na dziewi\u0119\u0107 z dziesi\u0119ciu zg\u0142osze\u0144 tego samego dnia.",]], + ["Koszty i bud\u017cet", [ + "Wydatki na oprogramowanie wzros\u0142y wraz z nowymi licencjami, a koszty podr\u00f3\u017cy zn\u00f3w spad\u0142y.", + "Sprz\u0119t wymieniono raz, a wsparcie by\u0142o stabilne przez ca\u0142y kwarta\u0142.", + "Dwa serwery przeniesiono do nowego dostawcy bez dnia przestoju.",]], + ["Nast\u0119pny kwarta\u0142", [ + "Wersja z wrze\u015bnia jest ostatni\u0105 zaplanowan\u0105 w tym roku.", + "Otwarte s\u0105 dwa etaty we wsparciu i jeden w dziale projektowym.", + "Przeprowadzka biura wypada w listopadzie i ma ju\u017c bud\u017cet.", + ]], + ["Ludzie", [ + "Nad wersj\u0105 pracowa\u0142o sze\u015b\u0107 os\xf3b, dwie z nich do\u0142\u0105czy\u0142y w tym roku.", + "Zast\u0119pstwa urlopowe ustalono w kwietniu i wytrzyma\u0142y ca\u0142e lato.", + "Wszyscy przeszli szkolenie wymagane przez now\u0105 licencj\u0119.", + ]], + ["Ryzyka", [ + "Przeprowadzka w listopadzie to jedyny termin, kt\xf3ry nie mo\u017ce si\u0119 przesun\u0105\u0107.", + "Jeden dostawca nie podpisa\u0142 jeszcze nowych warunk\xf3w.", + "Koszty hostingu rosn\u0105 w styczniu, je\u015bli umowa nie zostanie odnowiona wcze\u015bniej.", + ]], + ], + "closing": "Nast\u0119pne spotkanie odb\u0119dzie si\u0119 pod koniec lipca.", + "sheets": ["Przegl\u0105d", "Koszty"], + "item": "Pozycja", + "total": "Razem", + "periods": ["I kw.", "II kw.", "III kw.", "IV kw."], + "rows": ["Oprogramowanie", "Podr\u00f3\u017ce", "Sprz\u0119t", "Marketing", "Wsparcie", "Szkolenia", "Licencje", "Hosting", "Wydarzenia", "Biuro", "Chmura", "Rekrutacja", "Prawo", "Ubezpieczenie", "Catering", "Wysy\u0142ka", "Reklama", "Doradztwo", "Utrzymanie", "Media"], + "slides": [ + ["Plan projektu", ["Cele na kwarta\u0142", "Bud\u017cet i koszty", "Kolejne kroki"]], + ["Harmonogram", ["Wersja w czerwcu", "Podsumowanie w lipcu", "Planowanie w sierpniu"]], + ["Zesp\u00f3\u0142", ["Dw\u00f3ch nowych partner\u00f3w", "Wsparcie w trzech j\u0119zykach", "Szkolenia jesieni\u0105"]], + ], + }, + "pt-BR": { + "title": "Relat\u00f3rio trimestral", + "lead": "A equipe alcan\u00e7ou todas as metas do segundo trimestre e a nova vers\u00e3o saiu no prazo.", + "sections": [ + ["Destaques", [ + "Os custos ficaram abaixo do or\u00e7amento e dois novos parceiros entraram no projeto.", + "A nova vers\u00e3o alcan\u00e7ou mais pessoas na primeira semana do que a anterior em um m\u00eas.", + "O suporte respondeu nove de cada dez chamados no mesmo dia.",]], + ["Custos e or\u00e7amento", [ + "Os gastos com software subiram com as novas licen\u00e7as, enquanto as viagens ca\u00edram de novo.", + "O hardware foi substitu\u00eddo uma vez e o suporte se manteve est\u00e1vel no trimestre.", + "Dois servidores migraram para o novo provedor sem um dia de indisponibilidade.",]], + ["Pr\xf3ximo trimestre", [ + "A vers\xe3o de setembro \xe9 a \xfaltima prevista para este ano.", + "H\xe1 duas vagas no suporte e uma no design.", + "A mudan\xe7a de escrit\xf3rio \xe9 em novembro e j\xe1 tem or\xe7amento.", + ]], + ["As pessoas", [ + "Seis pessoas trabalharam na vers\xe3o, duas delas novas este ano.", + "A cobertura de f\xe9rias foi combinada em abril e durou o ver\xe3o todo.", + "Todos fizeram o treinamento que a nova licen\xe7a exige.", + ]], + ["Riscos", [ + "A mudan\xe7a de novembro \xe9 a \xfanica data que n\xe3o pode atrasar.", + "Um fornecedor ainda n\xe3o assinou as novas condi\xe7\xf5es.", + "A hospedagem sobe em janeiro se o contrato n\xe3o for renovado antes.", + ]], + ], + "closing": "A pr\u00f3xima reuni\u00e3o \u00e9 no fim de julho.", + "sheets": ["Vis\u00e3o geral", "Custos"], + "item": "Item", + "total": "Total", + "periods": ["T1", "T2", "T3", "T4"], + "rows": ["Software", "Viagens", "Hardware", "Marketing", "Suporte", "Treinamento", "Licen\u00e7as", "Hospedagem", "Eventos", "Escrit\u00f3rio", "Nuvem", "Recrutamento", "Jur\xeddico", "Seguros", "Buffet", "Frete", "Publicidade", "Consultoria", "Manuten\xe7\xe3o", "Utilidades"], + "slides": [ + ["Plano do projeto", ["Metas do trimestre", "Or\u00e7amento e custos", "Pr\u00f3ximos passos"]], + ["Cronograma", ["Vers\u00e3o em junho", "Revis\u00e3o em julho", "Planejamento em agosto"]], + ["Equipe", ["Dois novos parceiros", "Suporte em tr\u00eas idiomas", "Treinamento no outono"]], + ], + }, + "ru": { + "title": "\u041a\u0432\u0430\u0440\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0447\u0451\u0442", + "lead": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0430 \u0432\u0441\u0435 \u0446\u0435\u043b\u0438 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430, \u0438 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0432\u044b\u0448\u043b\u0430 \u0432 \u0441\u0440\u043e\u043a.", + "sections": [ + ["\u0413\u043b\u0430\u0432\u043d\u043e\u0435", [ + "\u0420\u0430\u0441\u0445\u043e\u0434\u044b \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0431\u044e\u0434\u0436\u0435\u0442\u0430, \u0430 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0438\u0441\u044c \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043f\u0430\u0440\u0442\u043d\u0451\u0440\u0430.", + "\u0417\u0430 \u043f\u0435\u0440\u0432\u0443\u044e \u043d\u0435\u0434\u0435\u043b\u044e \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043e\u0445\u0432\u0430\u0442\u0438\u043b\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u044e\u0434\u0435\u0439, \u0447\u0435\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0437\u0430 \u043c\u0435\u0441\u044f\u0446.", + "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043e\u0442\u0432\u0435\u0442\u0438\u043b\u0430 \u043d\u0430 \u0434\u0435\u0432\u044f\u0442\u044c \u0438\u0437 \u0434\u0435\u0441\u044f\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u0442 \u0436\u0435 \u0434\u0435\u043d\u044c.",]], + ["\u0420\u0430\u0441\u0445\u043e\u0434\u044b \u0438 \u0431\u044e\u0434\u0436\u0435\u0442", [ + "\u0417\u0430\u0442\u0440\u0430\u0442\u044b \u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432\u044b\u0440\u043e\u0441\u043b\u0438 \u0438\u0437-\u0437\u0430 \u043d\u043e\u0432\u044b\u0445 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0439, \u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u043f\u043e\u0435\u0437\u0434\u043a\u0438 \u0441\u043d\u043e\u0432\u0430 \u0441\u043d\u0438\u0437\u0438\u043b\u0438\u0441\u044c.", + "\u041e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u0435\u043d\u044f\u043b\u0438 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u0432\u0435\u0441\u044c \u043a\u0432\u0430\u0440\u0442\u0430\u043b.", + "\u0414\u0432\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u0435\u0445\u0430\u043b\u0438 \u043a \u043d\u043e\u0432\u043e\u043c\u0443 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0443 \u0431\u0435\u0437 \u0435\u0434\u0438\u043d\u043e\u0433\u043e \u0434\u043d\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u044f.",]], + ["\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u0432\u0430\u0440\u0442\u0430\u043b", [ + "\u0412\u0435\u0440\u0441\u0438\u044f \u0432 \u0441\u0435\u043d\u0442\u044f\u0431\u0440\u0435 \u2014 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0438\u0437 \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 \u044d\u0442\u043e\u043c \u0433\u043e\u0434\u0443.", + "\u041e\u0442\u043a\u0440\u044b\u0442\u044b \u0434\u0432\u0435 \u0432\u0430\u043a\u0430\u043d\u0441\u0438\u0438 \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0435 \u0438 \u043e\u0434\u043d\u0430 \u0432 \u0434\u0438\u0437\u0430\u0439\u043d\u0435.", + "\u041f\u0435\u0440\u0435\u0435\u0437\u0434 \u043e\u0444\u0438\u0441\u0430 \u043d\u0430\u043c\u0435\u0447\u0435\u043d \u043d\u0430 \u043d\u043e\u044f\u0431\u0440\u044c, \u0431\u044e\u0434\u0436\u0435\u0442 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0451\u043d.", + ]], + ["\u041b\u044e\u0434\u0438", [ + "\u041d\u0430\u0434 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0448\u0435\u0441\u0442\u044c \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u0434\u0432\u043e\u0435 \u0438\u0437 \u043d\u0438\u0445 \u043f\u0440\u0438\u0448\u043b\u0438 \u0432 \u044d\u0442\u043e\u043c \u0433\u043e\u0434\u0443.", + "\u0417\u0430\u043c\u0435\u043d\u044b \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043f\u0443\u0441\u043a\u043e\u0432 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043b\u0438 \u0432 \u0430\u043f\u0440\u0435\u043b\u0435, \u0438 \u043b\u0435\u0442\u043e\u043c \u0432\u0441\u0451 \u0441\u043e\u0448\u043b\u043e\u0441\u044c.", + "\u0412\u0441\u0435 \u043f\u0440\u043e\u0448\u043b\u0438 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u043e\u0432\u0430\u044f \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u044f.", + ]], + ["\u0420\u0438\u0441\u043a\u0438", [ + "\u041f\u0435\u0440\u0435\u0435\u0437\u0434 \u0432 \u043d\u043e\u044f\u0431\u0440\u0435 \u2014 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u0434\u0432\u0438\u043d\u0443\u0442\u044c.", + "\u041e\u0434\u0438\u043d \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043b \u043d\u043e\u0432\u044b\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f.", + "\u0425\u043e\u0441\u0442\u0438\u043d\u0433 \u043f\u043e\u0434\u043e\u0440\u043e\u0436\u0430\u0435\u0442 \u0432 \u044f\u043d\u0432\u0430\u0440\u0435, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u0440\u043e\u0434\u043b\u0438\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u0440\u0430\u043d\u0435\u0435.", + ]], + ], + "closing": "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0432\u0441\u0442\u0440\u0435\u0447\u0430 \u2014 \u0432 \u043a\u043e\u043d\u0446\u0435 \u0438\u044e\u043b\u044f.", + "sheets": ["\u041e\u0431\u0437\u043e\u0440", "\u0420\u0430\u0441\u0445\u043e\u0434\u044b"], + "item": "\u0421\u0442\u0430\u0442\u044c\u044f", + "total": "\u0418\u0442\u043e\u0433\u043e", + "periods": ["I \u043a\u0432.", "II \u043a\u0432.", "III \u043a\u0432.", "IV \u043a\u0432."], + "rows": ["\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b", "\u041f\u043e\u0435\u0437\u0434\u043a\u0438", "\u041e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435", "\u041c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430", "\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "\u041b\u0438\u0446\u0435\u043d\u0437\u0438\u0438", "\u0425\u043e\u0441\u0442\u0438\u043d\u0433", "\u041c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u044f", "\u041e\u0444\u0438\u0441", "\u041e\u0431\u043b\u0430\u043a\u043e", "\u041d\u0430\u0439\u043c", "\u042e\u0440\u0438\u0441\u0442\u044b", "\u0421\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u043d\u0438\u0435", "\u041a\u0435\u0439\u0442\u0435\u0440\u0438\u043d\u0433", "\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430", "\u0420\u0435\u043a\u043b\u0430\u043c\u0430", "\u041a\u043e\u043d\u0441\u0430\u043b\u0442\u0438\u043d\u0433", "\u041e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435", "\u041a\u043e\u043c\u043c\u0443\u043d\u0430\u043b\u044c\u043d\u044b\u0435"], + "slides": [ + ["\u041f\u043b\u0430\u043d \u043f\u0440\u043e\u0435\u043a\u0442\u0430", ["\u0426\u0435\u043b\u0438 \u043d\u0430 \u043a\u0432\u0430\u0440\u0442\u0430\u043b", "\u0411\u044e\u0434\u0436\u0435\u0442 \u0438 \u0440\u0430\u0441\u0445\u043e\u0434\u044b", "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438"]], + ["\u0413\u0440\u0430\u0444\u0438\u043a", ["\u0412\u0435\u0440\u0441\u0438\u044f \u0432 \u0438\u044e\u043d\u0435", "\u0418\u0442\u043e\u0433\u0438 \u0432 \u0438\u044e\u043b\u0435", "\u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u0430\u0432\u0433\u0443\u0441\u0442\u0435"]], + ["\u041a\u043e\u043c\u0430\u043d\u0434\u0430", ["\u0414\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043f\u0430\u0440\u0442\u043d\u0451\u0440\u0430", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043d\u0430 \u0442\u0440\u0451\u0445 \u044f\u0437\u044b\u043a\u0430\u0445", "\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u0441\u0435\u043d\u044c\u044e"]], + ], + }, + "tr": { + "title": "\u00dc\u00e7 ayl\u0131k rapor", + "lead": "Ekip ikinci \u00e7eyre\u011fin t\u00fcm hedeflerine ula\u015ft\u0131 ve yeni s\u00fcr\u00fcm zaman\u0131nda yay\u0131nland\u0131.", + "sections": [ + ["\u00d6ne \u00e7\u0131kanlar", [ + "Maliyetler b\u00fct\u00e7enin alt\u0131nda kald\u0131 ve projeye iki yeni ortak kat\u0131ld\u0131.", + "Yeni s\u00fcr\u00fcm ilk haftas\u0131nda, \u00f6ncekinin bir ayda ula\u015ft\u0131\u011f\u0131ndan daha fazla ki\u015fiye ula\u015ft\u0131.", + "Destek, on sorudan dokuzunu ayn\u0131 g\xfcn yan\u0131tlad\u0131.",]], + ["Maliyetler ve b\u00fct\u00e7e", [ + "Yeni lisanslarla yaz\u0131l\u0131m harcamalar\u0131 artt\u0131, seyahat giderleri yeniden d\u00fc\u015ft\u00fc.", + "Donan\u0131m bir kez yenilendi ve destek \u00e7eyrek boyunca istikrarl\u0131 kald\u0131.", + "\u0130ki sunucu, bir g\xfcn bile kesinti olmadan yeni sa\u011flay\u0131c\u0131ya ta\u015f\u0131nd\u0131.",]], + ["Gelecek \xe7eyrek", [ + "Eyl\xfcldeki s\xfcr\xfcm bu y\u0131l planlanan son s\xfcr\xfcm.", + "Destekte iki, tasar\u0131mda bir pozisyon a\xe7\u0131k.", + "Ofis ta\u015f\u0131nmas\u0131 kas\u0131mda ve b\xfct\xe7esi onayland\u0131.", + ]], + ["Ekip", [ + "S\xfcr\xfcm \xfczerinde alt\u0131 ki\u015fi \xe7al\u0131\u015ft\u0131, ikisi bu y\u0131l kat\u0131ld\u0131.", + "\u0130zin d\xf6nemi vekaletleri nisanda ayarland\u0131 ve yaz boyunca y\xfcr\xfcd\xfc.", + "Herkes yeni lisans\u0131n gerektirdi\u011fi e\u011fitimi tamamlad\u0131.", + ]], + ["Riskler", [ + "Kas\u0131mdaki ta\u015f\u0131nma, kayamayacak tek tarih.", + "Bir tedarik\xe7i yeni ko\u015fullar\u0131 hen\xfcz imzalamad\u0131.", + "S\xf6zle\u015fme erken yenilenmezse bar\u0131nd\u0131rma maliyeti ocakta art\u0131yor.", + ]], + ], + "closing": "Bir sonraki toplant\u0131 temmuz sonunda.", + "sheets": ["Genel bak\u0131\u015f", "Maliyetler"], + "item": "Kalem", + "total": "Toplam", + "periods": ["1. \u00c7", "2. \u00c7", "3. \u00c7", "4. \u00c7"], + "rows": ["Yaz\u0131l\u0131m", "Seyahat", "Donan\u0131m", "Pazarlama", "Destek", "E\u011fitim", "Lisanslar", "Bar\u0131nd\u0131rma", "Etkinlikler", "Ofis", "Bulut", "\u0130\u015fe al\u0131m", "Hukuk", "Sigorta", "\u0130kram", "Kargo", "Reklam", "Dan\u0131\u015fmanl\u0131k", "Bak\u0131m", "Faturalar"], + "slides": [ + ["Proje plan\u0131", ["\u00c7eyrek hedefleri", "B\u00fct\u00e7e ve maliyetler", "Sonraki ad\u0131mlar"]], + ["Takvim", ["Haziranda s\u00fcr\u00fcm", "Temmuzda de\u011ferlendirme", "A\u011fustosta planlama"]], + ["Ekip", ["\u0130ki yeni ortak", "\u00dc\u00e7 dilde destek", "Sonbaharda e\u011fitim"]], + ], + }, +} + +# What the sheets add up: forty rows over six periods, so there is enough of it +# to look like a spreadsheet. The first twenty keep the first four figures they +# had, because the invoice and the .xlsx take slices off the front. +FIGURES = [ + [1200, 1450, 1310, 1600, 1380, 1520], + [480, 620, 510, 470, 690, 540], + [3600, 900, 1200, 750, 830, 1150], + [820, 760, 930, 1010, 870, 940], + [540, 560, 580, 600, 610, 630], + [300, 450, 380, 520, 410, 470], + [1100, 1150, 1180, 1240, 1260, 1290], + [640, 640, 660, 680, 700, 700], + [420, 980, 350, 610, 1240, 380], + [260, 280, 270, 300, 290, 310], + [890, 910, 940, 980, 1000, 1030], + [1500, 400, 620, 350, 480, 390], + [340, 360, 350, 370, 380, 390], + [220, 220, 230, 230, 240, 240], + [180, 620, 210, 240, 190, 660], + [410, 430, 400, 450, 440, 460], + [760, 820, 690, 900, 850, 780], + [950, 480, 1100, 520, 560, 1180], + [280, 290, 300, 310, 320, 330], + [520, 540, 530, 560, 570, 590], + [1340, 1290, 1410, 1360, 1440, 1480], + [710, 730, 720, 750, 760, 780], + [190, 200, 190, 210, 200, 220], + [330, 330, 340, 340, 350, 350], + [860, 890, 1240, 910, 930, 960], + [240, 250, 260, 260, 270, 280], + [120, 130, 120, 140, 130, 150], + [460, 170, 180, 490, 180, 190], + [580, 610, 550, 640, 600, 670], + [150, 160, 170, 160, 180, 170], + [210, 230, 220, 250, 240, 260], + [390, 390, 400, 410, 410, 420], + [270, 1080, 310, 340, 290, 360], + [1620, 350, 380, 360, 400, 370], + [620, 650, 630, 680, 660, 700], + [110, 120, 110, 130, 120, 140], + [440, 450, 460, 470, 480, 490], + [980, 1020, 640, 1060, 1090, 720], + [560, 500, 590, 530, 610, 570], + [740, 770, 800, 790, 830, 860], +] + +# What the browser lists them as. Realistic rather than descriptive: the first +# screenshot is meant to look like somebody's folder, and the extensions do the +# talking about what the app opens. +FILE_NAMES = { + "en": {"text": "Quarterly report", "sheet": "Budget", "slides": "Project plan", + "word": "Contract", "cells": "Sales figures", "deck": "Team offsite", + "paper": "Invoice", "rows": "Contacts", "notes": "Notes"}, + "de": {"text": "Quartalsbericht", "sheet": "Budget", "slides": "Projektplan", + "word": "Vertrag", "cells": "Umsatzzahlen", "deck": "Teamtreffen", + "paper": "Rechnung", "rows": "Kontakte", "notes": "Notizen"}, + "es": {"text": "Informe trimestral", "sheet": "Presupuesto", "slides": "Plan del proyecto", + "word": "Contrato", "cells": "Cifras de ventas", "deck": "Reuni\u00f3n de equipo", + "paper": "Factura", "rows": "Contactos", "notes": "Notas"}, + "fr": {"text": "Rapport trimestriel", "sheet": "Budget", "slides": "Plan du projet", + "word": "Contrat", "cells": "Chiffres de ventes", "deck": "R\u00e9union d'\u00e9quipe", + "paper": "Facture", "rows": "Contacts", "notes": "Notes"}, + "it": {"text": "Relazione trimestrale", "sheet": "Bilancio", "slides": "Piano di progetto", + "word": "Contratto", "cells": "Dati di vendita", "deck": "Riunione del team", + "paper": "Fattura", "rows": "Contatti", "notes": "Note"}, + "pl": {"text": "Raport kwartalny", "sheet": "Bud\u017cet", "slides": "Plan projektu", + "word": "Umowa", "cells": "Wyniki sprzeda\u017cy", "deck": "Spotkanie zespo\u0142u", + "paper": "Faktura", "rows": "Kontakty", "notes": "Notatki"}, + "pt-BR": {"text": "Relat\u00f3rio trimestral", "sheet": "Or\u00e7amento", "slides": "Plano do projeto", + "word": "Contrato", "cells": "N\u00fameros de vendas", "deck": "Reuni\u00e3o da equipe", + "paper": "Fatura", "rows": "Contatos", "notes": "Notas"}, + "ru": {"text": "\u041a\u0432\u0430\u0440\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0447\u0451\u0442", "sheet": "\u0411\u044e\u0434\u0436\u0435\u0442", "slides": "\u041f\u043b\u0430\u043d \u043f\u0440\u043e\u0435\u043a\u0442\u0430", + "word": "\u0414\u043e\u0433\u043e\u0432\u043e\u0440", "cells": "\u041f\u0440\u043e\u0434\u0430\u0436\u0438", "deck": "\u0412\u0441\u0442\u0440\u0435\u0447\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b", + "paper": "\u0421\u0447\u0451\u0442", "rows": "\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u044b", "notes": "\u0417\u0430\u043c\u0435\u0442\u043a\u0438"}, + "tr": {"text": "\u00dc\u00e7 ayl\u0131k rapor", "sheet": "B\u00fct\u00e7e", "slides": "Proje plan\u0131", + "word": "S\u00f6zle\u015fme", "cells": "Sat\u0131\u015f rakamlar\u0131", "deck": "Ekip toplant\u0131s\u0131", + "paper": "Fatura", "rows": "Ki\u015filer", "notes": "Notlar"}, +} + +# The rest of the folder, so it does not read as a set of nine samples. Each is +# a copy of the sample named beside it, which only decides its icon: the browser +# shows a name and an icon, and none of them is ever opened. +FILLERS = { + "meeting": "text", + "letter": "text", + "travel": "text", + "reading": "text", + "household": "sheet", + "hours": "sheet", + "stocktake": "sheet", + "kickoff": "slides", + "course": "slides", + "lease": "word", + "resume": "word", + "application": "word", + "expenses": "cells", + "inventory": "cells", + "review": "deck", + "ticket": "paper", + "warranty": "paper", + "manual": "paper", +} + +# A language with none of its own falls back to English. +FILLER_NAMES = { + "en": { + "meeting": "Meeting notes", "letter": "Letter to the landlord", + "travel": "Travel plan", "reading": "Reading list", + "household": "Household budget", "hours": "Hours", "stocktake": "Stocktake", + "kickoff": "Kickoff", "course": "Course slides", + "lease": "Lease", "resume": "CV", "application": "Application", + "expenses": "Expenses", "inventory": "Inventory", + "review": "Quarterly review", + "ticket": "Ticket", "warranty": "Warranty", "manual": "Manual", + }, + "de": { + "meeting": "Besprechungsnotizen", "letter": "Brief an den Vermieter", + "travel": "Reiseplan", "reading": "Leseliste", + "household": "Haushaltsbudget", "hours": "Arbeitszeiten", "stocktake": "Inventur", + "kickoff": "Auftakt", "course": "Kursfolien", + "lease": "Mietvertrag", "resume": "Lebenslauf", "application": "Bewerbung", + "expenses": "Ausgaben", "inventory": "Bestand", + "review": "Quartalsr\u00fcckblick", + "ticket": "Ticket", "warranty": "Garantie", "manual": "Anleitung", + }, + "es": { + "meeting": "Notas de reuni\u00f3n", "letter": "Carta al casero", + "travel": "Plan de viaje", "reading": "Lista de lectura", + "household": "Presupuesto dom\u00e9stico", "hours": "Horas", "stocktake": "Recuento", + "kickoff": "Inicio", "course": "Diapositivas del curso", + "lease": "Contrato de alquiler", "resume": "Curr\u00edculum", "application": "Solicitud", + "expenses": "Gastos", "inventory": "Inventario", + "review": "Revisi\u00f3n trimestral", + "ticket": "Billete", "warranty": "Garant\u00eda", "manual": "Manual", + }, + "fr": { + "meeting": "Notes de r\u00e9union", "letter": "Lettre au propri\u00e9taire", + "travel": "Plan de voyage", "reading": "Liste de lecture", + "household": "Budget familial", "hours": "Heures", "stocktake": "Inventaire", + "kickoff": "Lancement", "course": "Diapositives du cours", + "lease": "Bail", "resume": "CV", "application": "Candidature", + "expenses": "D\u00e9penses", "inventory": "Stock", + "review": "Bilan trimestriel", + "ticket": "Billet", "warranty": "Garantie", "manual": "Manuel", + }, + "it": { + "meeting": "Note della riunione", "letter": "Lettera al locatore", + "travel": "Piano di viaggio", "reading": "Lista di lettura", + "household": "Bilancio familiare", "hours": "Ore", "stocktake": "Inventario", + "kickoff": "Avvio", "course": "Diapositive del corso", + "lease": "Contratto d'affitto", "resume": "Curriculum", "application": "Candidatura", + "expenses": "Spese", "inventory": "Magazzino", + "review": "Revisione trimestrale", + "ticket": "Biglietto", "warranty": "Garanzia", "manual": "Manuale", + }, + "pl": { + "meeting": "Notatki ze spotkania", "letter": "List do w\u0142a\u015bciciela", + "travel": "Plan podr\u00f3\u017cy", "reading": "Lista lektur", + "household": "Bud\u017cet domowy", "hours": "Godziny", "stocktake": "Inwentaryzacja", + "kickoff": "Rozpocz\u0119cie", "course": "Slajdy kursu", + "lease": "Umowa najmu", "resume": "CV", "application": "Podanie", + "expenses": "Wydatki", "inventory": "Stan magazynu", + "review": "Przegl\u0105d kwartalny", + "ticket": "Bilet", "warranty": "Gwarancja", "manual": "Instrukcja", + }, + "pt-BR": { + "meeting": "Notas da reuni\u00e3o", "letter": "Carta ao locador", + "travel": "Plano de viagem", "reading": "Lista de leitura", + "household": "Or\u00e7amento dom\u00e9stico", "hours": "Horas", "stocktake": "Balan\u00e7o", + "kickoff": "In\u00edcio", "course": "Slides do curso", + "lease": "Contrato de aluguel", "resume": "Curr\u00edculo", "application": "Inscri\u00e7\u00e3o", + "expenses": "Despesas", "inventory": "Estoque", + "review": "Revis\u00e3o trimestral", + "ticket": "Passagem", "warranty": "Garantia", "manual": "Manual", + }, + "ru": { + "meeting": "\u0417\u0430\u043c\u0435\u0442\u043a\u0438 \u0441\u043e \u0432\u0441\u0442\u0440\u0435\u0447\u0438", + "letter": "\u041f\u0438\u0441\u044c\u043c\u043e \u0430\u0440\u0435\u043d\u0434\u043e\u0434\u0430\u0442\u0435\u043b\u044e", + "travel": "\u041f\u043b\u0430\u043d \u043f\u043e\u0435\u0437\u0434\u043a\u0438", + "reading": "\u0421\u043f\u0438\u0441\u043e\u043a \u0447\u0442\u0435\u043d\u0438\u044f", + "household": "\u0414\u043e\u043c\u0430\u0448\u043d\u0438\u0439 \u0431\u044e\u0434\u0436\u0435\u0442", + "hours": "\u0427\u0430\u0441\u044b", + "stocktake": "\u0418\u043d\u0432\u0435\u043d\u0442\u0430\u0440\u0438\u0437\u0430\u0446\u0438\u044f", + "kickoff": "\u0421\u0442\u0430\u0440\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430", + "course": "\u0421\u043b\u0430\u0439\u0434\u044b \u043a\u0443\u0440\u0441\u0430", + "lease": "\u0414\u043e\u0433\u043e\u0432\u043e\u0440 \u0430\u0440\u0435\u043d\u0434\u044b", + "resume": "\u0420\u0435\u0437\u044e\u043c\u0435", + "application": "\u0417\u0430\u044f\u0432\u043b\u0435\u043d\u0438\u0435", + "expenses": "\u0420\u0430\u0441\u0445\u043e\u0434\u044b", + "inventory": "\u0421\u043a\u043b\u0430\u0434", + "review": "\u041a\u0432\u0430\u0440\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0431\u0437\u043e\u0440", + "ticket": "\u0411\u0438\u043b\u0435\u0442", + "warranty": "\u0413\u0430\u0440\u0430\u043d\u0442\u0438\u044f", + "manual": "\u0418\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f", + }, + "tr": { + "meeting": "Toplant\u0131 notlar\u0131", "letter": "Ev sahibine mektup", + "travel": "Seyahat plan\u0131", "reading": "Okuma listesi", + "household": "Ev b\u00fct\u00e7esi", "hours": "\u00c7al\u0131\u015fma saatleri", + "stocktake": "Say\u0131m", + "kickoff": "Ba\u015flang\u0131\u00e7", "course": "Kurs slaytlar\u0131", + "lease": "Kira s\u00f6zle\u015fmesi", "resume": "\u00d6zge\u00e7mi\u015f", + "application": "Ba\u015fvuru", + "expenses": "Giderler", "inventory": "Envanter", + "review": "\u00dc\u00e7 ayl\u0131k de\u011ferlendirme", + "ticket": "Bilet", "warranty": "Garanti", "manual": "K\u0131lavuz", + }, +} + + +# The word the search screenshot looks for. +# +# Counted out of the document rather than written down, so it is always a word +# that is really in there, and always one that is in there several times - a +# search that highlights a single hit does not look like a search. Short words +# are skipped because "the" and "and" say nothing about the document. +def query(words: dict) -> str: + """The most repeated long word of the report, which is what to search for.""" + text = " ".join( + [words["title"], words["lead"], words["closing"]] + + [heading for heading, _ in words["sections"]] + + [line for _, paragraphs in words["sections"] for line in paragraphs] + ) + + counted = {} + for word in re.findall(r"\w+", text.lower(), flags=re.UNICODE): + if len(word) >= 5 and not word.isdigit(): + counted[word] = counted.get(word, 0) + 1 + + # the most repeated, and the longest of those, so the choice is not a coin toss + return max(counted, key=lambda word: (counted[word], len(word))) + + +# The folder is not nine copies of one report. What each file is called says +# what it should hold, so the contract reads like a contract and the invoice +# like an invoice - a folder where every document has the same title is the one +# thing a picture of a folder must not be. +OTHERS = { + "en": { + "contract": ["Service agreement", + "This agreement is made between the two parties named below.", + ["The supplier provides the software described in the appendix for one year.", + "Payment is due within thirty days of each invoice.", + "Either party may end this agreement with three months' notice.", + "Changes to this agreement are valid only in writing.", + "The supplier keeps the service available on working days.", + "Both parties treat what they learn of each other as confidential.", + "Austrian law applies, and the court of Vienna has jurisdiction.", + "The supplier keeps a backup of the customer's data for thirty days.", + "Support requests are answered within one working day.", + "The customer names one person who may approve changes.", + "Prices hold for the first year and are reviewed each autumn.", + "Neither party may pass this agreement to a third party without consent.", + "The appendix lists the software covered and the version it starts at.", + "This agreement replaces every earlier arrangement between the parties."]], + "invoice": ["Invoice 2026-014", "Issued 12 June 2026", "Due within 30 days", "Billed to", "Subtotal", "VAT 20%", "Amount due", "Thank you for your business.", "Qty", "Unit price"], + "contacts": [["Name", "Role", "Email", "Phone"], + ["Design", "Support", "Sales", "Engineering"]], + }, + "de": { + "contract": ["Dienstleistungsvertrag", + "Dieser Vertrag wird zwischen den beiden unten genannten Parteien geschlossen.", + ["Der Anbieter stellt die im Anhang beschriebene Software f\u00fcr ein Jahr bereit.", + "Die Zahlung ist innerhalb von drei\u00dfig Tagen nach Rechnungsstellung f\u00e4llig.", + "Beide Parteien k\u00f6nnen den Vertrag mit einer Frist von drei Monaten k\u00fcndigen.", + "\u00c4nderungen dieses Vertrags bed\u00fcrfen der Schriftform.", + "Der Anbieter h\xe4lt den Dienst an Werktagen verf\xfcgbar.", + "Beide Parteien behandeln vertraulich, was sie voneinander erfahren.", + "Es gilt \xf6sterreichisches Recht; Gerichtsstand ist Wien.", + "Der Anbieter bewahrt eine Sicherung der Daten des Kunden drei\xdfig Tage lang auf.", + "Supportanfragen werden innerhalb eines Werktags beantwortet.", + "Der Kunde benennt eine Person, die \xc4nderungen freigeben darf.", + "Die Preise gelten im ersten Jahr und werden jeden Herbst \xfcberpr\xfcft.", + "Keine Partei darf diesen Vertrag ohne Zustimmung an Dritte weitergeben.", + "Der Anhang nennt die erfasste Software und die Version, ab der sie gilt.", + "Dieser Vertrag ersetzt alle fr\xfcheren Vereinbarungen zwischen den Parteien."]], + "invoice": ["Rechnung 2026-014", "Ausgestellt am 12. Juni 2026", "Zahlbar innerhalb von 30 Tagen", "Rechnung an", "Zwischensumme", "USt. 20%", "Zahlbetrag", "Vielen Dank f\xfcr Ihren Auftrag.", "Menge", "Einzelpreis"], + "contacts": [["Name", "Rolle", "E-Mail", "Telefon"], + ["Design", "Support", "Vertrieb", "Entwicklung"]], + }, + "es": { + "contract": ["Contrato de servicios", + "Este contrato se celebra entre las dos partes indicadas a continuaci\u00f3n.", + ["El proveedor facilita el software descrito en el anexo durante un a\u00f1o.", + "El pago vence a los treinta d\u00edas de cada factura.", + "Cualquiera de las partes puede rescindirlo con tres meses de preaviso.", + "Las modificaciones solo son v\u00e1lidas por escrito.", + "El proveedor mantiene el servicio disponible los d\xedas laborables.", + "Ambas partes tratan como confidencial lo que conozcan de la otra.", + "Se aplica la ley austriaca y el tribunal de Viena es competente.", + "El proveedor conserva una copia de los datos del cliente durante treinta d\xedas.", + "Las consultas de soporte se responden en un d\xeda laborable.", + "El cliente designa a una persona que puede aprobar los cambios.", + "Los precios se mantienen el primer a\xf1o y se revisan cada oto\xf1o.", + "Ninguna parte puede ceder este contrato a un tercero sin consentimiento.", + "El anexo enumera el software incluido y la versi\xf3n desde la que se aplica.", + "Este contrato sustituye cualquier acuerdo anterior entre las partes."]], + "invoice": ["Factura 2026-014", "Emitida el 12 de junio de 2026", "Vence en 30 d\u00edas", "Facturar a", "Subtotal", "IVA 20%", "Importe a pagar", "Gracias por su confianza.", "Cant.", "Precio unit."], + "contacts": [["Nombre", "Puesto", "Correo", "Tel\u00e9fono"], + ["Dise\u00f1o", "Soporte", "Ventas", "Ingenier\u00eda"]], + }, + "fr": { + "contract": ["Contrat de service", + "Ce contrat est conclu entre les deux parties d\u00e9sign\u00e9es ci-dessous.", + ["Le prestataire fournit le logiciel d\u00e9crit en annexe pendant un an.", + "Le paiement est d\u00fb dans les trente jours suivant chaque facture.", + "Chaque partie peut r\u00e9silier le contrat avec un pr\u00e9avis de trois mois.", + "Toute modification n'est valable que par \u00e9crit.", + "Le prestataire maintient le service disponible les jours ouvr\xe9s.", + "Chaque partie traite comme confidentiel ce qu'elle apprend de l'autre.", + "Le droit autrichien s'applique et le tribunal de Vienne est comp\xe9tent.", + "Le prestataire conserve une sauvegarde des donn\xe9es du client pendant trente jours.", + "Les demandes de support re\xe7oivent une r\xe9ponse sous un jour ouvr\xe9.", + "Le client d\xe9signe une personne habilit\xe9e \xe0 approuver les modifications.", + "Les prix sont fermes la premi\xe8re ann\xe9e et revus chaque automne.", + "Aucune partie ne peut c\xe9der ce contrat \xe0 un tiers sans accord.", + "L'annexe indique le logiciel couvert et la version \xe0 partir de laquelle il s'applique.", + "Ce contrat remplace tout accord ant\xe9rieur entre les parties."]], + "invoice": ["Facture 2026-014", "\u00c9mise le 12 juin 2026", "\u00c0 r\u00e9gler sous 30 jours", "Factur\xe9 \xe0", "Sous-total", "TVA 20%", "Montant d\xfb", "Merci de votre confiance.", "Qt\xe9", "Prix unitaire"], + "contacts": [["Nom", "R\u00f4le", "E-mail", "T\u00e9l\u00e9phone"], + ["Design", "Support", "Ventes", "D\u00e9veloppement"]], + }, + "it": { + "contract": ["Contratto di servizio", + "Il presente contratto \u00e8 stipulato tra le due parti indicate di seguito.", + ["Il fornitore mette a disposizione per un anno il software descritto in allegato.", + "Il pagamento \u00e8 dovuto entro trenta giorni da ogni fattura.", + "Ciascuna parte pu\u00f2 recedere con un preavviso di tre mesi.", + "Le modifiche sono valide solo in forma scritta.", + "Il fornitore mantiene il servizio disponibile nei giorni lavorativi.", + "Le parti trattano come riservato quanto apprendono l'una dell'altra.", + "Si applica il diritto austriaco e il foro competente \xe8 Vienna.", + "Il fornitore conserva una copia dei dati del cliente per trenta giorni.", + "Le richieste di supporto ricevono risposta entro un giorno lavorativo.", + "Il cliente indica una persona autorizzata ad approvare le modifiche.", + "I prezzi restano fermi il primo anno e sono rivisti ogni autunno.", + "Nessuna parte pu\xf2 cedere il contratto a terzi senza consenso.", + "L'allegato elenca il software coperto e la versione da cui decorre.", + "Il presente contratto sostituisce ogni accordo precedente tra le parti."]], + "invoice": ["Fattura 2026-014", "Emessa il 12 giugno 2026", "Da saldare entro 30 giorni", "Fatturato a", "Subtotale", "IVA 20%", "Importo dovuto", "Grazie per la collaborazione.", "Qt\xe0", "Prezzo unit."], + "contacts": [["Nome", "Ruolo", "E-mail", "Telefono"], + ["Design", "Supporto", "Vendite", "Sviluppo"]], + }, + "pl": { + "contract": ["Umowa o \u015bwiadczenie us\u0142ug", + "Niniejsza umowa zostaje zawarta mi\u0119dzy dwiema stronami wymienionymi poni\u017cej.", + ["Dostawca udost\u0119pnia oprogramowanie opisane w za\u0142\u0105czniku na okres roku.", + "P\u0142atno\u015b\u0107 jest wymagana w ci\u0105gu trzydziestu dni od ka\u017cdej faktury.", + "Ka\u017cda ze stron mo\u017ce rozwi\u0105za\u0107 umow\u0119 z trzymiesi\u0119cznym wypowiedzeniem.", + "Zmiany umowy wymagaj\u0105 formy pisemnej.", + "Dostawca utrzymuje dost\u0119pno\u015b\u0107 us\u0142ugi w dni robocze.", + "Obie strony traktuj\u0105 jako poufne to, czego dowiedz\u0105 si\u0119 o sobie.", + "Obowi\u0105zuje prawo austriackie, a s\u0105dem w\u0142a\u015bciwym jest s\u0105d w Wiedniu.", + "Dostawca przechowuje kopi\u0119 danych klienta przez trzydzie\u015bci dni.", + "Zg\u0142oszenia do wsparcia s\u0105 rozpatrywane w ci\u0105gu jednego dnia roboczego.", + "Klient wskazuje jedn\u0105 osob\u0119 uprawnion\u0105 do zatwierdzania zmian.", + "Ceny obowi\u0105zuj\u0105 przez pierwszy rok i s\u0105 weryfikowane ka\u017cdej jesieni.", + "\u017badna ze stron nie mo\u017ce przenie\u015b\u0107 umowy na osob\u0119 trzeci\u0105 bez zgody.", + "Za\u0142\u0105cznik wymienia obj\u0119te oprogramowanie i wersj\u0119, od kt\xf3rej obowi\u0105zuje.", + "Niniejsza umowa zast\u0119puje wszystkie wcze\u015bniejsze ustalenia stron."]], + "invoice": ["Faktura 2026-014", "Wystawiono 12 czerwca 2026", "P\u0142atne w ci\u0105gu 30 dni", "Nabywca", "Suma cz\u0119\u015bciowa", "VAT 20%", "Do zap\u0142aty", "Dzi\u0119kujemy za wsp\xf3\u0142prac\u0119.", "Ilo\u015b\u0107", "Cena jedn."], + "contacts": [["Imi\u0119", "Rola", "E-mail", "Telefon"], + ["Design", "Wsparcie", "Sprzeda\u017c", "Rozw\u00f3j"]], + }, + "pt-BR": { + "contract": ["Contrato de servi\u00e7o", + "Este contrato \u00e9 celebrado entre as duas partes indicadas abaixo.", + ["O fornecedor disponibiliza por um ano o software descrito no anexo.", + "O pagamento vence em trinta dias a contar de cada fatura.", + "Qualquer parte pode encerrar o contrato com tr\u00eas meses de aviso.", + "Altera\u00e7\u00f5es s\u00f3 s\u00e3o v\u00e1lidas por escrito.", + "O fornecedor mant\xe9m o servi\xe7o dispon\xedvel em dias \xfateis.", + "As partes tratam como confidencial o que souberem uma da outra.", + "Aplica-se a lei austr\xedaca e o foro competente \xe9 o de Viena.", + "O fornecedor mant\xe9m uma c\xf3pia dos dados do cliente por trinta dias.", + "Os chamados de suporte s\xe3o respondidos em um dia \xfatil.", + "O cliente indica uma pessoa autorizada a aprovar altera\xe7\xf5es.", + "Os pre\xe7os valem no primeiro ano e s\xe3o revistos a cada outono.", + "Nenhuma parte pode transferir este contrato a terceiros sem consentimento.", + "O anexo lista o software abrangido e a vers\xe3o a partir da qual vale.", + "Este contrato substitui qualquer acordo anterior entre as partes."]], + "invoice": ["Fatura 2026-014", "Emitida em 12 de junho de 2026", "Vence em 30 dias", "Faturado para", "Subtotal", "IVA 20%", "Valor a pagar", "Obrigado pela prefer\xeancia.", "Qtd", "Pre\xe7o unit."], + "contacts": [["Nome", "Fun\u00e7\u00e3o", "E-mail", "Telefone"], + ["Design", "Suporte", "Vendas", "Engenharia"]], + }, + "ru": { + "contract": ["\u0414\u043e\u0433\u043e\u0432\u043e\u0440 \u043e\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0443\u0441\u043b\u0443\u0433", + "\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u043a\u043b\u044e\u0447\u0451\u043d \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u043c\u0438, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0438\u0436\u0435.", + ["\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0434\u0438\u043d \u0433\u043e\u0434.", + "\u041e\u043f\u043b\u0430\u0442\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u0440\u0438\u0434\u0446\u0430\u0442\u0438 \u0434\u043d\u0435\u0439 \u0441 \u0434\u0430\u0442\u044b \u0441\u0447\u0451\u0442\u0430.", + "\u041a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0441\u0442\u043e\u0440\u0433\u043d\u0443\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440, \u0443\u0432\u0435\u0434\u043e\u043c\u0438\u0432 \u0437\u0430 \u0442\u0440\u0438 \u043c\u0435\u0441\u044f\u0446\u0430.", + "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0438\u0441\u044c\u043c\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435.", + "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 \u0440\u0430\u0431\u043e\u0447\u0438\u0435 \u0434\u043d\u0438.", + "\u0421\u0442\u043e\u0440\u043e\u043d\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442 \u0432 \u0442\u0430\u0439\u043d\u0435 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0434\u0440\u0443\u0433 \u043e \u0434\u0440\u0443\u0433\u0435.", + "\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0441\u0442\u0440\u0438\u0439\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e, \u0441\u043f\u043e\u0440\u044b \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442 \u0441\u0443\u0434 \u0412\u0435\u043d\u044b.", + "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u0445\u0440\u0430\u043d\u0438\u0442 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u0430 \u0442\u0440\u0438\u0434\u0446\u0430\u0442\u044c \u0434\u043d\u0435\u0439.", + "\u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0434\u043d\u044f.", + "\u0417\u0430\u043a\u0430\u0437\u0447\u0438\u043a \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430, \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e\u0449\u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.", + "\u0426\u0435\u043d\u044b \u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0433\u043e\u0434 \u0438 \u043f\u0435\u0440\u0435\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u0443\u044e \u043e\u0441\u0435\u043d\u044c.", + "\u041d\u0438 \u043e\u0434\u043d\u0430 \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u043d\u0435 \u0432\u043f\u0440\u0430\u0432\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0442\u0440\u0435\u0442\u044c\u0435\u043c\u0443 \u043b\u0438\u0446\u0443 \u0431\u0435\u0437 \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f.", + "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0438 \u0432\u0435\u0440\u0441\u0438\u044f, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043d\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442.", + "\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u043f\u0440\u0435\u0436\u043d\u0438\u0435 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0451\u043d\u043d\u043e\u0441\u0442\u0438 \u0441\u0442\u043e\u0440\u043e\u043d."]], + "invoice": ["\u0421\u0447\u0451\u0442 2026-014", "\u0412\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d 12 \u0438\u044e\u043d\u044f 2026", "\u041e\u043f\u043b\u0430\u0442\u0430 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 30 \u0434\u043d\u0435\u0439", "\u041f\u043b\u0430\u0442\u0435\u043b\u044c\u0449\u0438\u043a", "\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433", "\u041d\u0414\u0421 20%", "\u041a \u043e\u043f\u043b\u0430\u0442\u0435", "\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0437\u0430 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0435\u0441\u0442\u0432\u043e.", "\u041a\u043e\u043b-\u0432\u043e", "\u0426\u0435\u043d\u0430 \u0437\u0430 \u0435\u0434."], + "contacts": [["\u0418\u043c\u044f", "\u0420\u043e\u043b\u044c", "\u041f\u043e\u0447\u0442\u0430", "\u0422\u0435\u043b\u0435\u0444\u043e\u043d"], + ["\u0414\u0438\u0437\u0430\u0439\u043d", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430", "\u041f\u0440\u043e\u0434\u0430\u0436\u0438", "\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430"]], + }, + "tr": { + "contract": ["Hizmet s\u00f6zle\u015fmesi", + "Bu s\u00f6zle\u015fme a\u015fa\u011f\u0131da belirtilen iki taraf aras\u0131nda yap\u0131lm\u0131\u015ft\u0131r.", + ["Tedarik\u00e7i, ekte tan\u0131mlanan yaz\u0131l\u0131m\u0131 bir y\u0131l boyunca sa\u011flar.", + "\u00d6deme, her faturadan sonra otuz g\u00fcn i\u00e7inde yap\u0131l\u0131r.", + "Taraflardan biri s\u00f6zle\u015fmeyi \u00fc\u00e7 ay \u00f6nceden bildirerek sonland\u0131rabilir.", + "De\u011fi\u015fiklikler yaln\u0131zca yaz\u0131l\u0131 olarak ge\u00e7erlidir.", + "Tedarik\xe7i hizmeti i\u015f g\xfcnlerinde eri\u015filebilir tutar.", + "Taraflar birbirleri hakk\u0131nda \xf6\u011frendiklerini gizli tutar.", + "Avusturya hukuku uygulan\u0131r ve yetkili mahkeme Viyana'd\u0131r.", + "Tedarik\xe7i, m\xfc\u015fterinin verilerinin yede\u011fini otuz g\xfcn saklar.", + "Destek talepleri bir i\u015f g\xfcn\xfc i\xe7inde yan\u0131tlan\u0131r.", + "M\xfc\u015fteri, de\u011fi\u015fiklikleri onaylayabilecek bir ki\u015fi belirler.", + "Fiyatlar ilk y\u0131l sabittir ve her sonbahar g\xf6zden ge\xe7irilir.", + "Hi\xe7bir taraf s\xf6zle\u015fmeyi onay almadan \xfc\xe7\xfcnc\xfc ki\u015fiye devredemez.", + "Ek, kapsanan yaz\u0131l\u0131m\u0131 ve ge\xe7erli oldu\u011fu s\xfcr\xfcm\xfc listeler.", + "Bu s\xf6zle\u015fme, taraflar aras\u0131ndaki \xf6nceki t\xfcm d\xfczenlemelerin yerine ge\xe7er."]], + "invoice": ["Fatura 2026-014", "12 Haziran 2026 tarihli", "30 g\u00fcn i\u00e7inde \u00f6denir", "Fatura edilen", "Ara toplam", "KDV %20", "\xd6denecek tutar", "\u0130\u015f birli\u011finiz i\xe7in te\u015fekk\xfcrler.", "Adet", "Birim fiyat"], + "contacts": [["Ad", "G\u00f6rev", "E-posta", "Telefon"], + ["Tasar\u0131m", "Destek", "Sat\u0131\u015f", "Geli\u015ftirme"]], + }, +} + +# Names are names in every language, so these are not translated. +PEOPLE = ["A. Bauer", "M. Rossi", "J. Novak", "L. Dubois", "S. Meyer", "K. Larsen"] + + +# --- the other formats ------------------------------------------------------ +# +# The first screenshot is a folder, so the folder has to look like somebody's. +# What it holds is the quiet half of the message: an .odt beside an .xlsx beside +# a .pdf says what the app opens without a line of copy claiming it. +# +# These are written small and plain for the same reason the ODF ones are. They +# are read by odrcore, not by Word, so they carry the least markup that is still +# a valid package. + +OOXML_RELS = """ + + + +""" + +WORD_MAIN = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" + + +def docx_parts(words: dict, others: dict) -> dict: + """The Word file is the contract, not another copy of the report.""" + title, lead, clauses = others["contract"] + + def run(text: str, *, size: int, bold: bool = False, colour: str = "") -> str: + marks = ("" if bold else "") + (f'' if colour else "") + + return ( + f"{marks}" + f'{escape(text)}' + ) + + def para(runs: str, after: int) -> str: + return f'{runs}' + + # A clause is two sentences in one paragraph, numbered in line with the + # first. A number on a line of its own above a single sentence reads as a + # list of scraps rather than as a contract. + paragraphs = [ + para(run(title, size=72, bold=True), 640), + para(run(lead, size=22), 420), + ] + for number, index in enumerate(range(0, len(clauses) - 1, 2), start=1): + body = " ".join(clauses[index:index + 2]) + paragraphs.append( + para( + run(f"{number}. ", size=22, bold=True, colour=ACCENT[1:]) + run(body, size=22), + 300, + ) + ) + + # An empty paragraph between them, rather than trusting w:spacing: the + # renderer sets the clauses flush against each other whatever `w:after` + # says, and a contract whose clauses touch reads as one block of text. + body = ''.join(paragraphs) + + return { + "[Content_Types].xml": '' + '' + '' + '' + '' + '', + "_rels/.rels": OOXML_RELS.format(type=WORD_MAIN, target="word/document.xml"), + # Not optional. odrcore opens /word/styles.xml whether or not the + # document has a style in it, and a package without one is not read as a + # Word file at all: it falls through to the web view, which draws the + # text with no page around it and offers neither search nor editing. + "word/_rels/document.xml.rels": OOXML_RELS.format( + type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", + target="styles.xml", + ), + "word/styles.xml": '' + '' + "" + '' + "" + '' + "" + '' + '' + "", + "word/document.xml": '' + '' + # A4 with 2cm margins, in twentieths of a point. Without it there is no + # page for odrcore to lay the text on, and the document is drawn as a + # bare column of text rather than as a sheet of paper. + f"{body}" + '' + '' + "", + } + + +def xlsx_parts(words: dict) -> dict: + """A workbook of its own figures, so it is not the .ods twice.""" + head, body, foot = table(words, columns=2, rows=8, scale=3) + rows_of = [head] + body + [foot] + + def cell(column: int, row: int, value) -> str: + reference = f"{chr(ord('A') + column)}{row}" + if isinstance(value, int): + return f'{value}' + + return f'{escape(value)}' + + rows = "".join( + f'' + + "".join(cell(column, index + 1, value) for column, value in enumerate(line)) + + "" + for index, line in enumerate(rows_of) + ) + + return { + "[Content_Types].xml": '' + '' + '' + '' + '' + '', + "_rels/.rels": OOXML_RELS.format(type=WORD_MAIN, target="xl/workbook.xml"), + "xl/_rels/workbook.xml.rels": OOXML_RELS.format( + type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", + target="worksheets/sheet1.xml", + ), + "xl/workbook.xml": '' + '' + f'', + "xl/worksheets/sheet1.xml": '' + '' + f"{rows}", + } + + +def pptx_parts(words: dict) -> dict: + """One slide, titled and bulleted, so a deck opens on something.""" + drawing = 'xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"' + presentation = 'xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"' + + def shape(identifier: int, name: str, box: str, lines: list, size: int) -> str: + paragraphs = "".join( + f'' + f"{escape(line)}" + for line in lines + ) + + return ( + f'' + f"{box}" + '' + f"{paragraphs}" + ) + + slide = ( + f'' + "" + '' + + shape( + 2, + "Title", + '', + [words["slides"][0][0]], + 4000, + ) + + shape( + 3, + "Body", + '', + words["slides"][0][1], + 2000, + ) + + "" + ) + + return { + "[Content_Types].xml": '' + '' + '' + '' + '' + '', + "_rels/.rels": OOXML_RELS.format(type=WORD_MAIN, target="ppt/presentation.xml"), + "ppt/_rels/presentation.xml.rels": OOXML_RELS.format( + type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide", + target="slides/slide1.xml", + ), + "ppt/presentation.xml": f'' + f'' + '' + '', + "ppt/slides/slide1.xml": slide, + } + + +# Helvetica's own character widths, in thousandths of the point size, so the pdf +# can be set the way a real one is: each word placed where it belongs rather +# than a whole line handed over as one run. It is also what lets the lines wrap +# where the text actually reaches the margin. +HELVETICA = { + "regular": ( + "278 278 355 556 556 889 667 191 333 333 389 584 278 333 278 278 " + "556 556 556 556 556 556 556 556 556 556 278 278 584 584 584 556 " + "1015 667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 " + "667 778 722 667 611 722 667 944 667 667 611 278 278 278 469 556 " + "333 556 556 500 556 556 278 556 556 222 222 500 222 833 556 556 " + "556 556 333 500 278 556 500 722 500 500 500 334 260 334 584" + ), + "bold": ( + "278 333 474 556 556 889 722 238 333 333 389 584 278 333 278 278 " + "556 556 556 556 556 556 556 556 556 556 333 333 584 584 584 611 " + "975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 " + "667 778 722 667 611 722 667 944 667 667 611 333 278 333 584 556 " + "333 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 " + "611 611 389 556 333 611 556 778 556 556 500 389 280 389 584" + ), +} + +WIDTHS = { + weight: {chr(32 + index): int(value) for index, value in enumerate(table.split())} + for weight, table in HELVETICA.items() +} + + +def advance(text: str, weight: str, size: float) -> float: + """How wide that text is set in Helvetica at that size. + + An accented letter is as wide as the letter it is built on - true across + Helvetica's Latin range - so the table only has to hold the plain ones. + """ + table = WIDTHS[weight] + total = 0 + for character in text: + width = table.get(character) + if width is None: + plain = unicodedata.normalize("NFD", character)[0] + width = table.get(plain, 556) + total += width + + return total * size / 1000 + + +WINANSI = set(bytes(range(32, 256)).decode("cp1252", errors="ignore")) + + +def spellable(words: dict) -> bool: + """Whether Helvetica's encoding can write this language's wording.""" + return all( + character in WINANSI for line in (words["title"], words["closing"]) for character in line + ) + + +# A4 upright in points, with the same margin the ODF pages take. +PAGE = (595.0, 842.0) +MARGIN = 57.0 +COLUMN = PAGE[0] - 2 * MARGIN + + +def pdf_bytes(words: dict, others: dict) -> bytes: + """A one page PDF, written out by hand rather than through a library. + + Each word is placed at its own position, the way a real producer writes one. + Handed over as one run per line instead, a reader that marks a search hit + inside the run has nothing to measure the offset with, and the highlight + lands beside the word rather than on it. + + Helvetica and WinAnsi, so what it says is Latin text only - the languages + this cannot spell get the English wording, which is also what the search + screenshot then looks for. + """ + said = words if spellable(words) else WORDS["en"] + + def lay_out(text: str, weight: str, size: float) -> list: + """The text broken into lines of placed words.""" + lines, line, width = [], [], 0.0 + space = advance(" ", weight, size) + for word in text.split(): + reach = advance(word, weight, size) + if line and width + space + reach > COLUMN: + lines.append(line) + line, width = [], 0.0 + line.append((word, width)) + width += reach + space + if line: + lines.append(line) + + return lines + + def literal(text: str) -> str: + return text.replace("\\", r"\\").replace("(", r"\(").replace(")", r"\)") + + invoice = others["invoice"] if spellable(words) else OTHERS["en"]["invoice"] + number, issued, due, billed, subtotal, vat, due_label, thanks, quantity, unit = invoice + head, body, foot = table(said, columns=1, rows=20) + + money = foot[-1] + tax = round(money * 0.2) + right = PAGE[0] - MARGIN + + drawn = [] + + def put(text, x, y, weight="regular", size=10, align="left"): + """One line, placed. Numbers are hung off the right, which is what makes + a column of figures a column rather than a ragged list.""" + name = "F2" if weight == "bold" else "F1" + at = x - advance(text, weight, size) if align == "right" else x + drawn.append(f"BT /{name} {size:g} Tf {at:.1f} {y:.1f} Td ({literal(text)}) Tj ET") + + # the head: who it is from and when, against who it is to + y = PAGE[1] - MARGIN - 26 + put(number, MARGIN, y, "bold", 20) + put(issued, right, y, "regular", 10, "right") + put(due, right, y - 14, "regular", 10, "right") + + y -= 46 + put(billed, MARGIN, y, "bold", 11) + for line in ("Muster GmbH", "Praterstrasse 12", "1020 Wien"): + y -= 14 + put(line, MARGIN, y) + + # the table, in four columns across the width + columns = (MARGIN, MARGIN + 300, MARGIN + 390, right) + y -= 34 + put(head[0], columns[0], y, "bold", 10) + put(quantity, columns[1], y, "bold", 10, "right") + put(unit, columns[2], y, "bold", 10, "right") + put(head[-1], columns[3], y, "bold", 10, "right") + + for index, line in enumerate(body): + count = index % 4 + 1 + amount = line[-1] + y -= 15 + put(str(line[0]), columns[0], y) + put(str(count), columns[1], y, align="right") + put(f"{amount / count:.2f}", columns[2], y, align="right") + put(str(amount), columns[3], y, align="right") + + y -= 24 + for label, value, weight in ( + (subtotal, money, "regular"), (vat, tax, "regular"), (due_label, money + tax, "bold") + ): + put(label, columns[2], y, weight, 10 if weight == "regular" else 12, "right") + put(str(value), columns[3], y, weight, 10 if weight == "regular" else 12, "right") + y -= 17 + + y -= 12 + put(thanks, MARGIN, y) + + stream = ("\n".join(drawn) + "\n").encode("cp1252") + + objects = [ + b"<>", + b"<>", + b"<>>>/Contents 5 0 R>>", + b"<>", + b"<>\nstream\n" + stream + b"endstream", + b"<>", + ] + + out = bytearray(b"%PDF-1.4\n") + offsets = [] + for number, body in enumerate(objects, start=1): + offsets.append(len(out)) + out += f"{number} 0 obj\n".encode() + body + b"\nendobj\n" + + table_at = len(out) + out += f"xref\n0 {len(objects) + 1}\n".encode() + b"0000000000 65535 f \n" + for offset in offsets: + out += f"{offset:010d} 00000 n \n".encode() + out += f"trailer\n<>\nstartxref\n{table_at}\n%%EOF\n".encode() + + return bytes(out) + + +def csv_text(words: dict, others: dict) -> str: + """The contact list its name promises.""" + headers, roles = others["contacts"] + lines = [",".join(headers)] + for index, person in enumerate(PEOPLE): + handle = person.split(". ")[-1].lower() + lines.append( + ",".join([person, roles[index % len(roles)], f"{handle}@example.org", f"+43 1 234 56{index}0"]) + ) + + return "\n".join(lines) + "\n" + + +def txt_text(words: dict) -> str: + """The notes: the report in plain text, with the deck's points under it.""" + lines = [words["title"], "=" * len(words["title"]), "", words["lead"], ""] + for heading, paragraphs in words["sections"]: + lines += [heading, "-" * len(heading), ""] + for text in paragraphs: + lines += [text, ""] + for title, bullets in words["slides"]: + lines += [title, "-" * len(title), ""] + lines += [f"* {point}" for point in bullets] + lines.append("") + lines.append(words["closing"]) + + return "\n".join(lines) + "\n" + + +# What the app asks the bundle for. The first three are the documents the +# screenshots open; the rest sit in the folder the first screenshot is of. +DOCUMENTS = { + "text": ("odt", "application/vnd.oasis.opendocument.text", "document", report), + "sheet": ("ods", "application/vnd.oasis.opendocument.spreadsheet", "document", sheet), + "slides": ("odp", "application/vnd.oasis.opendocument.presentation", "slide", deck), +} + +PACKAGES = { + "word": ("docx", docx_parts), + "cells": ("xlsx", xlsx_parts), + "deck": ("pptx", pptx_parts), +} + +PLAIN = { + "rows": ("csv", csv_text), + "notes": ("txt", txt_text), +} + + +def package(path: Path, parts: dict) -> None: + """A zip of the given parts, reproducibly.""" + with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as archive: + for name, text in parts.items(): + info = zipfile.ZipInfo(name, date_time=EPOCH) + info.external_attr = 0o644 << 16 + archive.writestr(info, text, compress_type=zipfile.ZIP_DEFLATED) + + +def write(path: Path, mimetype: str, kind: str, content_xml: str) -> None: + with zipfile.ZipFile(path, "w", zipfile.ZIP_DEFLATED) as package: + def entry(name: str, text: str, stored: bool = False) -> None: + info = zipfile.ZipInfo(name, date_time=EPOCH) + info.external_attr = 0o644 << 16 + package.writestr( + info, text, compress_type=zipfile.ZIP_STORED if stored else zipfile.ZIP_DEFLATED + ) + + # first and uncompressed, or the package is only recognised by sniffing + entry("mimetype", mimetype, stored=True) + entry("META-INF/manifest.xml", MANIFEST.format(mimetype=mimetype)) + entry("styles.xml", styles(kind)) + entry("content.xml", content_xml) + + +def main(argv=None) -> None: + parser = argparse.ArgumentParser(description="Write the documents the store screenshots open.") + parser.add_argument( + "--language", action="append", choices=sorted(WORDS), + help="only this language, repeatable; default is all of them. What to reach for when a " + "change is worded in English first and the rest are to follow.") + args = parser.parse_args(argv) + + languages = args.language or list(WORDS) + + SAMPLES.mkdir(parents=True, exist_ok=True) + + written = 0 + for language in languages: + words = WORDS[language] + for name, (extension, mimetype, kind, build) in DOCUMENTS.items(): + path = SAMPLES / f"sample-{name}-{language}.{extension}" + write(path, mimetype, kind, build(words)) + written += 1 + + others = OTHERS[language] + + for name, (extension, build) in PACKAGES.items(): + parts = build(words, others) if name == "word" else build(words) + package(SAMPLES / f"sample-{name}-{language}.{extension}", parts) + written += 1 + + for name, (extension, build) in PLAIN.items(): + text = build(words, others) if name == "rows" else build(words) + (SAMPLES / f"sample-{name}-{language}.{extension}").write_text(text, encoding="utf-8") + written += 1 + + (SAMPLES / f"sample-paper-{language}.pdf").write_bytes(pdf_bytes(words, others)) + written += 1 + + details = { + language: { + "files": FILE_NAMES[language] + | { + key: FILLER_NAMES.get(language, {}).get(key, FILLER_NAMES["en"][key]) + for key in FILLERS + }, + "search": query(words), + } + for language, words in WORDS.items() + } + (SAMPLES / "screenshot-names.json").write_text( + json.dumps(details, ensure_ascii=False, indent=1, sort_keys=True) + "\n", encoding="utf-8" + ) + + print(f"wrote {written} documents in {len(languages)} languages to {SAMPLES}") + + +if __name__ == "__main__": + main() diff --git a/scripts/store-screenshots.py b/scripts/store-screenshots.py new file mode 100755 index 0000000..829496b --- /dev/null +++ b/scripts/store-screenshots.py @@ -0,0 +1,246 @@ +#!/usr/bin/env python3 +# +# The App Store screenshots: which ones there are, and the deliver tree built +# out of what a capture run wrote. +# +# Unlike the store copy, these are not committed. A picture of the app is only +# worth as much as the app it was taken from, so they are taken during the +# release run, from the build going out, and handed to deliver from there. +# `fastlane ios screenshots` takes them; this says what a full set is. +# +# scripts/store-screenshots.py --languages what to capture +# scripts/store-screenshots.py check what was captured +# scripts/store-screenshots.py --stage DIR check it and stage it +# +# The store has eleven locales and the app is translated into nine of them. +# The other two get the English pictures, which is what their storefront would +# show anyway: the app has no UI in Hindi or Swedish either. + +import argparse +import os +import shutil +import struct +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent +SCREENSHOTS = ROOT / "fastlane" / "screenshots" + +# Store locale -> the language the app is in when it is photographed for it. +# `None` means the app has none, so that locale reads the English pictures. +# The keys are the locales `fastlane/metadata` has; the values are what iOS +# resolves the locale to, which is why de-DE is one folder and pt-BR is another. +LOCALES = { + "de-DE": "de", + "en-US": "en", + "es-ES": "es", + "fr-FR": "fr", + "hi": None, + "it": "it", + "pl": "pl", + "pt-BR": "pt-BR", + "ru": "ru", + "sv": None, + "tr": "tr", +} + +FALLBACK = "en-US" + +# What one device shows, in the order the store shows them. The same names the +# screenshot test writes - see `OpenDocumentReaderUITests/ScreenshotTests.swift`. +SCREENS = ( + "01-browser", + "02-text", + "03-sheet", + "04-edit", + "05-pdf", + "06-office", +) + +# What App Store Connect accepts, upright, in pixels. An app that runs on both +# has to hand in both, and the store fits every smaller iPhone and iPad from +# these two. More than one size per device because which simulator a runner has +# depends on the Xcode it is running. +SIZES = { + "iphone": { + (1320, 2868), # 6.9", iPhone 16 Pro Max and later + (1290, 2796), # 6.9"/6.7", iPhone 15 Pro Max and 16 Plus + (1284, 2778), # 6.5", iPhone 12/13 Pro Max + (1242, 2688), # 6.5", iPhone 11 Pro Max + }, + "ipad": { + (2064, 2752), # 13", iPad Pro M4 + (2048, 2732), # 12.9", iPad Pro + }, +} + + +def languages(): + """The locales worth capturing: the ones the app can be photographed in.""" + return [locale for locale, language in LOCALES.items() if language] + + +def borrowed(): + """The locales that read another one's pictures.""" + return [locale for locale, language in LOCALES.items() if not language] + + +def size(path): + """The pixel size of a PNG, off its header rather than through a library.""" + with path.open("rb") as file: + header = file.read(24) + + if len(header) < 24 or header[:8] != b"\x89PNG\r\n\x1a\n" or header[12:16] != b"IHDR": + raise ValueError(f"{path.name} is not a PNG") + + return struct.unpack(">II", header[16:24]) + + +def device(width, height): + """Which device a picture that size belongs to, or None.""" + for name, sizes in SIZES.items(): + if (width, height) in sizes: + return name + + return None + + +def collect(directory): + """What one capture run wrote. Returns (files by locale and device, problems). + + snapshot names its output `-.png`, one folder per + language, so the simulator's name is read off the front and the size decides + which device it counts as - the name of a simulator changes with Xcode, the + number of pixels it has does not. + """ + directory = Path(directory) + found = {} + problems = [] + + for locale in languages(): + folder = directory / locale + if not folder.is_dir(): + problems.append(f"{locale}: no {folder}") + continue + + pictures = {} + for path in sorted(folder.glob("*.png")): + screen = next((name for name in SCREENS if path.stem.endswith(name)), None) + if screen is None: + problems.append(f"{locale}: {path.name} is not one of {', '.join(SCREENS)}") + continue + + try: + width, height = size(path) + except (OSError, ValueError) as reason: + problems.append(f"{locale}: {reason}") + continue + + kind = device(width, height) + if kind is None: + # Not ours to upload, and not a reason to stop: asked for one + # simulator, snapshot photographs every one whose name starts + # the same way, so a runner that has an iPhone 16 Pro as well as + # the Pro Max hands back a third set nobody asked for. What has + # to be there is still checked below, per device. + continue + + pictures.setdefault(kind, {})[screen] = path + + for kind in SIZES: + missing = [screen for screen in SCREENS if screen not in pictures.get(kind, {})] + if missing: + problems.append(f"{locale}: no {kind} {', '.join(missing)}") + + found[locale] = pictures + + return found, problems + + +def stage(found, directory): + """Write the screenshot tree deliver uploads. + + A folder per store locale, the borrowed ones copied from the English rather + than left out: what deliver does not upload for a locale, App Store Connect + keeps - which would be whatever was there before this release. + """ + directory = Path(directory) + + for locale, pictures in found.items(): + folder = directory / locale + folder.mkdir(parents=True, exist_ok=True) + for kind, screens in pictures.items(): + for screen, path in screens.items(): + shutil.copyfile(path, folder / f"{kind}-{screen}.png") + + for locale in borrowed(): + source = directory / FALLBACK + target = directory / locale + shutil.rmtree(target, ignore_errors=True) + shutil.copytree(source, target) + + return directory + + +def fail(message): + if os.environ.get("GITHUB_ACTIONS"): + # also surfaces as an annotation on the run, not only inside the step log + print(f"::error::{message}") + else: + print(message, file=sys.stderr) + return 1 + + +def main(argv=None): + parser = argparse.ArgumentParser( + description="Check a run of App Store screenshots, and stage it for deliver." + ) + parser.add_argument( + "--languages", + action="store_true", + help="print the locales to capture, one per line, and do nothing else", + ) + parser.add_argument( + "--screenshots", + metavar="DIR", + default=SCREENSHOTS, + help=f"where the capture run wrote (default {SCREENSHOTS.relative_to(ROOT)})", + ) + parser.add_argument( + "--stage", + metavar="DIR", + help="also write the deliver screenshot tree into DIR", + ) + args = parser.parse_args(argv) + + if args.languages: + print("\n".join(languages())) + return 0 + + found, problems = collect(args.screenshots) + + if problems: + return fail( + "no full set of screenshots to release with:\n " + + "\n ".join(problems) + + "\nRun `bundle exec fastlane ios screenshots` to take them." + ) + + if args.stage: + try: + stage(found, args.stage) + except OSError as reason: + return fail(str(reason)) + print( + f"staged {len(SCREENS)} screenshots per device for " + f"{len(found) + len(borrowed())} locales in {args.stage}" + ) + else: + pictures = sum(len(screens) for locale in found.values() for screens in locale.values()) + print(f"{pictures} screenshots in all {len(found)} captured locales: {', '.join(found)}") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 217f9cc98087c0951ade650bc2cd00fce5509ce0 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 17 Aug 2026 13:31:59 +0200 Subject: [PATCH 2/5] Write the sample documents rather than commit them Eighty-two files of build output, in a repository, kept in step with the script that writes them by hand. The lane runs the script before it builds instead. Before the build and not during it: the target picks its resources up off the disk as the build starts, so a file written by a build phase lands in the next one. Nothing else needs them. The app builds without them - only a screenshot run opens one - and CI compiles the screenshot target without them too, which is all it does with it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E6tn8P25cBDmrA67zrhfwN --- .gitattributes | 4 - .gitignore | 5 + .../Samples/sample-cells-de.xlsx | Bin 1874 -> 0 bytes .../Samples/sample-cells-en.xlsx | Bin 1867 -> 0 bytes .../Samples/sample-cells-es.xlsx | Bin 1874 -> 0 bytes .../Samples/sample-cells-fr.xlsx | Bin 1885 -> 0 bytes .../Samples/sample-cells-it.xlsx | Bin 1869 -> 0 bytes .../Samples/sample-cells-pl.xlsx | Bin 1898 -> 0 bytes .../Samples/sample-cells-pt-BR.xlsx | Bin 1885 -> 0 bytes .../Samples/sample-cells-ru.xlsx | Bin 1968 -> 0 bytes .../Samples/sample-cells-tr.xlsx | Bin 1898 -> 0 bytes .../Samples/sample-deck-de.pptx | Bin 1877 -> 0 bytes .../Samples/sample-deck-en.pptx | Bin 1860 -> 0 bytes .../Samples/sample-deck-es.pptx | Bin 1873 -> 0 bytes .../Samples/sample-deck-fr.pptx | Bin 1875 -> 0 bytes .../Samples/sample-deck-it.pptx | Bin 1864 -> 0 bytes .../Samples/sample-deck-pl.pptx | Bin 1868 -> 0 bytes .../Samples/sample-deck-pt-BR.pptx | Bin 1871 -> 0 bytes .../Samples/sample-deck-ru.pptx | Bin 1929 -> 0 bytes .../Samples/sample-deck-tr.pptx | Bin 1878 -> 0 bytes .../Samples/sample-notes-de.txt | 72 ----- .../Samples/sample-notes-en.txt | 72 ----- .../Samples/sample-notes-es.txt | 72 ----- .../Samples/sample-notes-fr.txt | 72 ----- .../Samples/sample-notes-it.txt | 72 ----- .../Samples/sample-notes-pl.txt | 72 ----- .../Samples/sample-notes-pt-BR.txt | 72 ----- .../Samples/sample-notes-ru.txt | 72 ----- .../Samples/sample-notes-tr.txt | 72 ----- .../Samples/sample-paper-de.pdf | Bin 4853 -> 0 bytes .../Samples/sample-paper-en.pdf | Bin 4806 -> 0 bytes .../Samples/sample-paper-es.pdf | Bin 4835 -> 0 bytes .../Samples/sample-paper-fr.pdf | Bin 4826 -> 0 bytes .../Samples/sample-paper-it.pdf | Bin 4836 -> 0 bytes .../Samples/sample-paper-pl.pdf | Bin 4806 -> 0 bytes .../Samples/sample-paper-pt-BR.pdf | Bin 4831 -> 0 bytes .../Samples/sample-paper-ru.pdf | Bin 4806 -> 0 bytes .../Samples/sample-paper-tr.pdf | Bin 4806 -> 0 bytes OpenDocumentReader/Samples/sample-rows-de.csv | 7 - OpenDocumentReader/Samples/sample-rows-en.csv | 7 - OpenDocumentReader/Samples/sample-rows-es.csv | 7 - OpenDocumentReader/Samples/sample-rows-fr.csv | 7 - OpenDocumentReader/Samples/sample-rows-it.csv | 7 - OpenDocumentReader/Samples/sample-rows-pl.csv | 7 - .../Samples/sample-rows-pt-BR.csv | 7 - OpenDocumentReader/Samples/sample-rows-ru.csv | 7 - OpenDocumentReader/Samples/sample-rows-tr.csv | 7 - .../Samples/sample-sheet-de.ods | Bin 2493 -> 0 bytes .../Samples/sample-sheet-en.ods | Bin 3669 -> 0 bytes .../Samples/sample-sheet-es.ods | Bin 2499 -> 0 bytes .../Samples/sample-sheet-fr.ods | Bin 2510 -> 0 bytes .../Samples/sample-sheet-it.ods | Bin 2483 -> 0 bytes .../Samples/sample-sheet-pl.ods | Bin 2514 -> 0 bytes .../Samples/sample-sheet-pt-BR.ods | Bin 2509 -> 0 bytes .../Samples/sample-sheet-ru.ods | Bin 2635 -> 0 bytes .../Samples/sample-sheet-tr.ods | Bin 2511 -> 0 bytes .../Samples/sample-slides-de.odp | Bin 1633 -> 0 bytes .../Samples/sample-slides-en.odp | Bin 1622 -> 0 bytes .../Samples/sample-slides-es.odp | Bin 1636 -> 0 bytes .../Samples/sample-slides-fr.odp | Bin 1650 -> 0 bytes .../Samples/sample-slides-it.odp | Bin 1630 -> 0 bytes .../Samples/sample-slides-pl.odp | Bin 1659 -> 0 bytes .../Samples/sample-slides-pt-BR.odp | Bin 1639 -> 0 bytes .../Samples/sample-slides-ru.odp | Bin 1743 -> 0 bytes .../Samples/sample-slides-tr.odp | Bin 1649 -> 0 bytes OpenDocumentReader/Samples/sample-text-de.odt | Bin 2136 -> 0 bytes OpenDocumentReader/Samples/sample-text-en.odt | Bin 2033 -> 0 bytes OpenDocumentReader/Samples/sample-text-es.odt | Bin 2097 -> 0 bytes OpenDocumentReader/Samples/sample-text-fr.odt | Bin 2134 -> 0 bytes OpenDocumentReader/Samples/sample-text-it.odt | Bin 2089 -> 0 bytes OpenDocumentReader/Samples/sample-text-pl.odt | Bin 2195 -> 0 bytes .../Samples/sample-text-pt-BR.odt | Bin 2102 -> 0 bytes OpenDocumentReader/Samples/sample-text-ru.odt | Bin 2401 -> 0 bytes OpenDocumentReader/Samples/sample-text-tr.odt | Bin 2092 -> 0 bytes .../Samples/sample-word-de.docx | Bin 2353 -> 0 bytes .../Samples/sample-word-en.docx | Bin 2258 -> 0 bytes .../Samples/sample-word-es.docx | Bin 2315 -> 0 bytes .../Samples/sample-word-fr.docx | Bin 2324 -> 0 bytes .../Samples/sample-word-it.docx | Bin 2302 -> 0 bytes .../Samples/sample-word-pl.docx | Bin 2391 -> 0 bytes .../Samples/sample-word-pt-BR.docx | Bin 2303 -> 0 bytes .../Samples/sample-word-ru.docx | Bin 2573 -> 0 bytes .../Samples/sample-word-tr.docx | Bin 2335 -> 0 bytes .../Samples/screenshot-names.json | 290 ------------------ README.md | 14 +- fastlane/Fastfile | 7 + fastlane/screenshots/README.md | 7 +- scripts/make-screenshot-documents.py | 5 +- 88 files changed, 28 insertions(+), 1015 deletions(-) delete mode 100644 .gitattributes delete mode 100644 OpenDocumentReader/Samples/sample-cells-de.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-en.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-es.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-fr.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-it.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-pl.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-pt-BR.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-ru.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-cells-tr.xlsx delete mode 100644 OpenDocumentReader/Samples/sample-deck-de.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-en.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-es.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-fr.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-it.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-pl.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-pt-BR.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-ru.pptx delete mode 100644 OpenDocumentReader/Samples/sample-deck-tr.pptx delete mode 100644 OpenDocumentReader/Samples/sample-notes-de.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-en.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-es.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-fr.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-it.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-pl.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-pt-BR.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-ru.txt delete mode 100644 OpenDocumentReader/Samples/sample-notes-tr.txt delete mode 100644 OpenDocumentReader/Samples/sample-paper-de.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-en.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-es.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-fr.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-it.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-pl.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-pt-BR.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-ru.pdf delete mode 100644 OpenDocumentReader/Samples/sample-paper-tr.pdf delete mode 100644 OpenDocumentReader/Samples/sample-rows-de.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-en.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-es.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-fr.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-it.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-pl.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-pt-BR.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-ru.csv delete mode 100644 OpenDocumentReader/Samples/sample-rows-tr.csv delete mode 100644 OpenDocumentReader/Samples/sample-sheet-de.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-en.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-es.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-fr.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-it.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-pl.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-pt-BR.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-ru.ods delete mode 100644 OpenDocumentReader/Samples/sample-sheet-tr.ods delete mode 100644 OpenDocumentReader/Samples/sample-slides-de.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-en.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-es.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-fr.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-it.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-pl.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-pt-BR.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-ru.odp delete mode 100644 OpenDocumentReader/Samples/sample-slides-tr.odp delete mode 100644 OpenDocumentReader/Samples/sample-text-de.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-en.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-es.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-fr.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-it.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-pl.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-pt-BR.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-ru.odt delete mode 100644 OpenDocumentReader/Samples/sample-text-tr.odt delete mode 100644 OpenDocumentReader/Samples/sample-word-de.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-en.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-es.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-fr.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-it.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-pl.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-pt-BR.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-ru.docx delete mode 100644 OpenDocumentReader/Samples/sample-word-tr.docx delete mode 100644 OpenDocumentReader/Samples/screenshot-names.json diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dbd6575..0000000 --- a/.gitattributes +++ /dev/null @@ -1,4 +0,0 @@ -# The sample pdfs are written with uncompressed content streams, so git reads -# them as text and puts a hundred and thirty lines of placed words in the diff -# for each one. They are generated files; nobody reads them as a diff. -*.pdf binary diff --git a/.gitignore b/.gitignore index fc53004..7ee2c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,11 @@ fastlane/Preview.html fastlane/screenshots/**/*.png fastlane/screenshots/screenshots.html fastlane/framed + +# The documents the screenshots are taken of, and the names the app lays +# them out under. Build output: `scripts/make-screenshot-documents.py` +# writes them, and the screenshot lane runs it before the build. +OpenDocumentReader/Samples/ fastlane/test_output .DS_Store diff --git a/OpenDocumentReader/Samples/sample-cells-de.xlsx b/OpenDocumentReader/Samples/sample-cells-de.xlsx deleted file mode 100644 index 55ac228e59f0c5e07ea955b9e20c0a72e9badb7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1874 zcmZ{ldpJ~i7{|{TmkDFE%#vbEE>Gk(s$rYiwlEQ~?(3Q*qfkR*2$6}3N-phCm<*ao zMegNNa!c;H%rYp(C1n`7CX_wu*{7P_&Uwyx&-vr~ea`21-tYUfG=mCC0{{R6FEl`M ze+2&oK4}U7fD~Ar4gE+IB8lQ=8{$t4aMcPvc_J^d&7w|6^1NHaT2nMv z{~d^ezO?$w>tlgtD@*#`9IB{`e%@3H+s{*Ppvf`lsgde(@&iKKmQZBLY

?>3A0W z7_G*)pyp^xyh&K4cTi(Yz3JaJEz$JRJQ`D&vVXhL0^zLzIiUr!s2eGlX&hqL+iNYv z=$ugRz%6H&H%csFi=%U07@^7~_3W2T`o&HX7^ho`GOh|$pAP1>3tC;f5-lv{Z71$> zM7g!OgBrjq#~;>}V~a7@1oIz_d5)hk8Fhx;S`KfzketblHIVOll@yb4LvlAfhV58* znDca*HMG`nn7oA>p*2^!UL5W66!A<}SmtOgYZ%&UwXfFU`bqVw$2j%b;X?2A>M}xUYwE9^9};7! z_%>>$RZm>DjK8l|rIHSc>3v%@O2B@>GU?DMf~H~XvU^E7p*|R52wSQz{{!0ImE+l2 zZ(&SIMknV_*xx<0^!&YJ&@iu?3U8jYr`{Xb=1}akCX$oC6`6kMSFhci#<(^k+HEcd z=CC^=F^y+rBWE={EBk5DBc+NDEuwT~rW8cd0MX>Y8hk?g3*Biyvag4qpYKL5{7WiY zt0N8!ucl{>@rptu6IrfCeRi**G_6&4XXn(F;)f4|C6S19gP-P9)S6fEmv)9I+)qr% z*#gt;$40$XrgKMq#3G|~ucqEdZxX}MR+;*pOanUStiQ%~4+jHOzV##D^@oIPwNHST>#U_RmG4s?^!3r)i5y?~Tw| z&8MZ6t4w1%5^}7BVta=h<5$P{V2_Jj-BJTWqCi;07uatxuf`uD)#->69&Gn#Ja5X{ zAwIwsgjD$+G678=g{gyZDWHx8ArvXRrmy9dPTG zl`rp#k~XIg4(pF(U9UWV$If=3P_JmGm~bf^*0d&VS+95Yq%(sV+I6Pg+;j8-Y2-0x z-uXPGdP1sOkNmp!nnp;OG_AB)kOfyxY2)rg(f+>YQg@P1B6&P;?d6{(Vo2GTwmb$Byk8Rd@I_3X@cF^9J=BIpjBKv9#N zA=Ic&hZ^H+?#DYh?XVZL%1$a?+-1WkiN%8-m=c88fz9Ebj#?DSoY* z`4MVq1`&{k{&?_%ZSnbFf_?J8+W@}-|0w(-2LL8S8?^XlF!Bre2hCTZD7Xpzc&I9 diff --git a/OpenDocumentReader/Samples/sample-cells-en.xlsx b/OpenDocumentReader/Samples/sample-cells-en.xlsx deleted file mode 100644 index c812d788847ba90357c78ce07940246a89720bbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1867 zcmWIWW@Zs#U|`??Vnv3$#2vizhU9!v?Mxi?wfN-po%izkM>Y z?0}2fk7?^&&q`K_ZuwYyI=;OBDsTFfgV`GnCZF#2sM(!acD&<=*R|l&?QGjy;<0jj{<*C@#}YWHyPZuqGn6MLPUXz0^9{xCcG~zDN!{dL@`q*JjwdNk zt34h^b1eQ*d$M)f!q+`cvRCd+?N~5Fz=XHsX5>bnhX;OKz5nN^Pm$#7dc99u|8H)O z*;oCUF#sjFj?a4Ex(OIe+Kdbg+(0_MC^e^8Uk^m~oYFV-jrQ z$%n2!U_KLQcPL_duGXHt)>f1B&pGqY?j{+!s;U~{%%Vc?a%W#R?ddb^bk zFTk-gd5@0)kXfv0u7 z(I+{zlEzgUoYE~vR?Ys#;CxI`*{CdqKOnDPGxhwb`l|Eqv(5Hb7Kw}a`sl8iCTg){ zUh<-3Zu|SYkE&bfHYUxOv7uF3D`(fUQ$|D#U3pF?NRqWK1lSi&D&|8zT}gM;2fuoAFP%|F3kRC_oBX3 zWK-)uqXXWDRxh;K_B&(AgC%~~PS~wGP~Kb5`L}!RZf3M3JC$|H4WKu>*cccj5MC|L zNKGv%)(2CDps4Mg8dy9>L7?G(*WqgB?&|z{-{c~ZTRdK78RgCaN-68VHP_@__9tU8 zdDzJ>wDoK1+Q-wjZw*`SV$Hw(*8KXK8w-z^WlVUiaJ2bqUadiH?(OqoKBn7pd(WTW z5&y{E>0|tkI~@C)54}Iy-}`}&t3G5}f4+IbbgvWYyg!#5;N*XGa^4QHXv?|f^0#{g zgC0NLx|iMLwDN_@fROM9z5Ze~MjFaz`;+c$I;ofbUZXcxEMU`(W6e6s4ZOT&A{%}l z`6{=H@9TQir>kt{Epg@9mD;^pI$;X?Vi|*9$G&!Nc&B|c=+xit%$UyItV>dJo-pca zC>&`LXqI~M+(tWhd&vy{=}R}Bi{Ef5@&AsEN-snT{__ZF_!nC4jk+5yxK8zw=Cnn4A-<6fXG&mY0~Gvwg%CaEaN6_r}?ty!hf0xxV%c&(@` zdr~@Q(*OAhryW%H{peX^_k;EAsy$s(#axP~9S!=Cb?5O1`%C|T37?Tkgc)~<4@?qZ zumqS!u$KSm2B4RL5bX>MOBnTmMj(}l=o-;W7=%VHVC{puyg@eyJ@X>W`3^A$IV+=U lK8}_h5Skw`gB=0VjFCA4yjg+Shk=0=2wj1`{J;w00RX3#|KI=s diff --git a/OpenDocumentReader/Samples/sample-cells-es.xlsx b/OpenDocumentReader/Samples/sample-cells-es.xlsx deleted file mode 100644 index e9a4dc35359a39ea86c8b70589692b3ffc57648f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1874 zcmZ{lc{o&i7{`ysAj>dC)|)k38cQAt$$GO@Gm2y{DPxZb(`w1JWQ-{k$&#@&$X>~s zhRHC=&C(>9$(FrjP*b@_p8Ke|w{xCz-gEx=exLLCo%j3xkhTzRQ2+q=z)KzoJn=~A zJNUF~698-ltBZM1AjUfo<8c%l>>cWchzRg6BhU^#)e^bt(Y8>Vcqhb!Z^vv@j$*K? zaK)?JnepmgnnGAZ+sXc=o$HQ7IlvmQrEoqYH#cDoY>huW5_X(Xz zed1T~#H$l;b+H~DMu{ie^dISr%Ni+5CGucQ6f71kC(S}qI<;9k(NcK_unq$Q_RyT3 z3H5HnmBKm-Y)P*=?w)JTd8HaMeW*jf+8L(poG&Ntw!Pu|pZA_~qpn|zY{c>hR)R)+385p1&Cj{?>`znHFm*j#Dy<^!$EUHHU>{AIZ)ne(w#;4sSnP;Y27RR74RM6WhKu&nLM+}HD&kQ8Y| zi_AmyCKrka`yuKTwPcCt0_B)Zj*G}N>$8@-%)3@j)MQ(dBe=}@mdJI-AkY6UI@Loy zbRaNYKK=fLBguN{+4Au)#@x$DA?lQ4WXYh6Q?>I~-lF@`V%gUFPU|u$$ux`9f@y6& zC*3QA+jAC2q)?2H65m-TGa5M1uGD^+uLY4bKr|_^M)+&4(}f3x_?-+2@>}bLe@XdU zwFChMJNxeFToqP?(C23H%3&OmieR5`amoBr{qSLgh?sD;*_MSJYE-sS!cOe=QbJ0R zB%jV}y_iX*tmzS7f#?_=TxO~KW&!O~Hc`KaXqLsi9IT;m(#cFVdQiS<4(*ubd_XzO zdHRgl$tgpO4W6XvdWO#Pt)9!HxL9g)lW&L!>)m_VHxFiWCp}r-%3CkbwA^MXE?dao zrG|?tHP|F|rxc-}NdpWDo;}I|dpcjHqz;6X0bzyLVSmQN;jLjHp=J3NtgxDf2Q-Ue0cQnVqK6IKNubw+}X+csJ_aU-TLvrngEMLt<78+ogNz?p+A< zY?azxT;WTS?)?1hqMoEmS>9o^Mp@qj%6kk|(Y^_z(NkbV?U+)1->?*~1`Bf+6_9q5 zTTxA2!1IK=`JAQA?ocSe$1@oAdgYfS#4@M8nKt*OT%#|-SeBzoJ9Izm}a zRDe2rWJc5Z6Zfy(s$qps83hS%@Bo0s24$#^w>KtK^GDHM`>VLLo{%g#QIjie%tkIT zl%cP(o65_$B{lT0i$QT^?7RRsj8d+JCFIo!SpTYCcE%f@7gRI2v1f2L|D6iKzUSx{dqD%@J z?Yg?-u>HZ_SI1a_tWt>~kLW`9X+F3<3Slzf+J4^GXFwHelgg^dfBKn;fF_{1#1+M7 zo~Rl=KR0kIP^GQqw4$`nW1egZqk?=fvCXJZx;ngvPH&$vHgJ(LXcCUplgvSl@1`p3 zGcisFam4R+_w4bLqtZ!yey!ybj_%x5)eHG1Fh=s%S?{;82ovUDLkQ~R(D(y6Xp(+0$5T4&EEe6joKia6{HQ$kL&ooYY zYBRGf#UYOXc|?ZGzl*h61ZegdG=BI^M2Fd(X3qli@0DH!18Rx}%Mpnjxnp4afjScY-iT@K6q%9PT5&%HK(-NdyhOWK+1CXHw4FCWD diff --git a/OpenDocumentReader/Samples/sample-cells-fr.xlsx b/OpenDocumentReader/Samples/sample-cells-fr.xlsx deleted file mode 100644 index f70efbacd5e5ce84dfd9a5515d1d71c2194f30d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1885 zcmZ{lc{o&S9LLWXhAhowiBOU?GK?#^kw;_fnJi_OC6ZlC8l_C+p^zm>_NmEM$V|jT zbJ0ZhY}qw#wvZ(mYutn9K5Fjmyw5qmbN={#pYwU&-(q3}W#tC|fCIe60UxI_o(=F# zfdv5gz-X)O>w|Ok!8x1@@^cNaN8-J`3gVlwZ

t9Nv8^xtH#*#Ub_ecBX`%Ec|6p zD(&9p$W^0NhMM~@fzwW{VES>dugi)4dh5U{jP!C+kxui0>jJOlZ#Ftyi|yiZORV;M zS$(lFRzJAHJ+Lm4X86&(F(U1AK_Ur;(>j9ruJZ-$AJ>RlR1Os;>II$e?lxn~Y#Wzr zRbS37uiMK|r9|Y}WnPzjMe7}`SEJbMMcF((ENFkIazi(-h1E16DgwsmexBRzf@D)e zDECG5KY?>QZLI$>280LjZsaj1K;;UIB{8t!GSY^WIP; zZuU9#v&G+$Ph&7aiJUs##<8$Xl-Rjk?@Cz1V&8uTq_orj%1{EAi0;jb;MT zwDW$ppr0qQLPAN5(_XM06YWD`%UU-!a#f#^y`dx%I++R6rbZbA|U%J^T@ie@}=Flzz?n;<)H4&39|MDs@p}2_ycb;TpeW zrD1eyT#hMQbT_>&c5Q?SmOF)%Tn$2sg0S!%*qICe}#2Wrk06~qS1a}%5Bso9tcC}nxt z8-Inp4^R+3@=<+%i8RUi+cB6nz%mDDph~6d_hW9 zC{NqnWn9p)qLzwd2o$Wb{hGCRRp%tfLDB>m00`~U23&S^#RVvC2h`T-#yqU{NmD{- zg|Mv*^$<`d5K|HU#SexL6BsjOWE6`kdC+*lVCDY0)tlrpk+80zz#kfOmue5?PkrhT zN>4r)Mn4`|goqTHr8&`W@=ymqQRTHrDx>TtIa@sDX#8b9`Fi4Fo$;uHkMV^bex28E z!HJXiy`D@OHbskkGk<^AW5JSP(wxxtmRBW4>2ze(-MykJUF45u#;Jz)>hy)-l)m(k z;KJ1-m2SzS_CMD>GG+>RA(2Xzf{<^=Y$Z-Tib?_B)Y$M6X`-J6_MUGFkH`>SpUq&G5 z{i8Ff#blX8#aP7?JdO4a8kxZbwi6h^mK+ZIV&WeUyf^g)`@ITUIp=EYSP~+F4ad!4 z!J2P0HXX@se4i^$$$KAdFm6R>l^j+;>&fbd)XA-GnwGYlcTv~+Fg8>qi=?z$+U#r5 zpERnDDuxd(kyfB4Mi3T$=ZIkdkHl>mP+9 B42J*! diff --git a/OpenDocumentReader/Samples/sample-cells-it.xlsx b/OpenDocumentReader/Samples/sample-cells-it.xlsx deleted file mode 100644 index d1b57a392489a52ec935640d075e440de8782434..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1869 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 APyhe` diff --git a/OpenDocumentReader/Samples/sample-cells-ru.xlsx b/OpenDocumentReader/Samples/sample-cells-ru.xlsx deleted file mode 100644 index 1b51119ea13443885d7257d781801de44ee2770d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1968 zcmWIWW@Zs#U|`??Vnv3$#2vizhU9!v?Mxi?wfN-po%izkM>Y z?0}2fk7?^&&q`K_ZuwYyI=;OBDsTFfgV`GnCZF#2sM(!acD&<=*R|l&?QGjy;<0jj{<*C@#}YWHyPZuqGn6MLPUXz0^9{xCcG~zDN!{dL@`q*JjwdNk zt34h^b1eQ*d$M)f!q+`cvRCd+?N~5Fz=XHsX5>bnhX;OKz5nN^Pm$#7dc99u|8H)O z*;oCUF#sjFj?a4Ex(OIe+Kdbg+(0_MC^e^8Uk^m~oYFV-jrQ z$%n2!U_KLQcPL_duGXHt)>f1B&pGqY?j{+!s;U~{%%Vc?a%W#R?ddb^bk zKRxkUNa&xcod!K2OuU%MfGVNN{ z?c@@x=YpE?R?}Vt$)#qOij>4v9}!{y9U|f_9jmZI$g8sDV61plO!05QiI+r`EOtye zn=S9wx@=d?g=o_!NoKZx{n}qz%sppsdFFrJ6MrvwFu|AkG1jX~zsTcbuJBYN!w-)55HzYDJ=ah7IUVp_r zL2UaGCf*6_?p?j>qHpr?n#<#3-0xq%yOw+AR{D%eWq(PT-3PABQ1i8}|M$@PzoqdH zcm2&Xw|Sh>(*5LM?iO)>5kICIj`t1D)xTWXx|HtNp)5j}4~R-D?$C5EZSDM>zoV#{~R z{W=>Za=q}y^rI`onAq3!mD|fn>4GRjrwjG-iW@bVq4XN9@Vn!(cPVNd$%47>nSbY$fYZ9J!{f0zkT3) z*WFFg|MFH`yKC2dVUfh|jE(UV1v*m8TRb@WwyWP!+^jNlsS5Kt)7^>JC!9^|IF&Uo zQQ*?jEY|5|D_asGBOF~-L<0kB6Yt-grvKBjAor%~l5gF)H>x`NIe6ZDOA_vSS<<>< ztHV4lr)Z&DT8GXXZ1p~o!^^yhao1`^vuJ?{c`nD-ChUqeQ50y`II%)yal2I&?|jn_ ze;E#46_6Aa4A|`b&Hcs1i}fW}C#IZhT=%K?pV%|so4(5{yRN@psvLdoV9_m=Q1=5< zBi3=f7QX$#oc9WE0=?=NI4b0Ka`<*c=KMpaBacaQL#o_zDGHJsulgm7U0duB*Kil zS^*|CFjxZ2Z&)iCbOX=}T8MTAh9!*pKqHWfU387;#TY^(7ckx9F4WM?K`$W?=6r{k ngIr#qYevsz2+i-A!HxiF#>jL5-mJiE$-ux0gswnehJtwj%Ahhs diff --git a/OpenDocumentReader/Samples/sample-cells-tr.xlsx b/OpenDocumentReader/Samples/sample-cells-tr.xlsx deleted file mode 100644 index b26e2c4340fee0a1a5e31e6b120d368bb830f346..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1898 zcmWIWW@Zs#U|`??Vnv3$#2vizhU9!v?Mxi?wfN-po%izkM>Y z?0}2fk7?^&&q`K_ZuwYyI=;OBDsTFfgV`GnCZF#2sM(!acD&<=*R|l&?QGjy;<0jj{<*C@#}YWHyPZuqGn6MLPUXz0^9{xCcG~zDN!{dL@`q*JjwdNk zt34h^b1eQ*d$M)f!q+`cvRCd+?N~5Fz=XHsX5>bnhX;OKz5nN^Pm$#7dc99u|8H)O z*;oCUF#sjFj?a4Ex(OIe+Kdbg+(0_MC^e^8Uk^m~oYFV-jrQ z$%n2!U_KLQcPL_duGXHt)>f1B&pGqY?j{+!s;U~{%%Vc?a%W#R?ddb^bk zFTk-gd5@9THifv0u7 z(WiNSrja{QK8s>n(St2X!B^ z%`xY-cogXLB$&USzdU^VgEb25K8LOxmX>_e_Rh7$vP);(t(#Rdyd$IE=g!ewoSUM$ z?v%=`jaP#G?}e%ImAXU=uVTOhq;#i8_thga{ak-D<@9#>+Mp?;}oUhmDl>MrZIFJj*- zRp!+9z?Fg`EudZ#MpV)r3?b5XH{@rd11J2ojiMyeROR_;ohsInXk@Y=-j8WOz&i7!UCA!Rz3CCt9wDze0ZkltyV7qo zMPBkeH`~4Ern3|%^`75lb&WGKr`&)Knd+VOp7;|(@H%;(W5 zHj_;H{PD+X)3=ZIZ2J7{Xin5j>8|w2zP^Y3ir?iF9eL)x+VK_Nl}Y|~`q#L88_u@q zJdjiiu~^6?xQngS=ET{L3#Rc0BvuEWacgTl)}(TrFTmx0?AkB(dYfJrEiGf4bMD_) z;jXSNALgnZ37YpK?8&2d>hBf@{Rid?MkWzv+!X>ap@6{>V9LQ-J)j$aUPMB)GcYV+ z)CU@YRA8cOL@$648o7X#6Yk;&-5m71jWFjs#2nMNePXDm%rfIAsg_H01&fd4nRg&Q|lvJFEUyt9edj5ZzI*Dec~>!p*i->U=X! z9=mXA>#C&(5|YvnUpRIBZgQzIt0;%;4v7s@)m3)hHQ62PB(#S2%BhW0N>-cB6ttbt z#mTH(dq$3{zw!d-8EKvs>tFqfnk~WA7BuywbKb1#H;M1NDl9%#y_|S)qDVP+;i)Xu zB~R8g9@=5o@-Et|)GuJo97~g1F4}4ywT6jKb$k}D=lwLeS*8)EFkSt_nM<0YbB%;v zr>*;S_odU-8{e-bh@ZW;*`?O(^Sje4Y;J7$wV1~;?$W0<|978#^XsC+`ThGU*#l6* ziE|bE@r}UnF<@k1;0Dt1MX5Q(`g$O;_xxV2Lk0p25BB;C=55cEby>2pn)U`4&HPTs7O|#P-mwk3U{+ z5Itq3t5CL!?V3L0|AT)Ge7OAM?&|LPl6-uX@@XR}A0{Uc8YRacavdz-K<;?p6u4OWAyllFmj`IiqyY_<`HWj6FFD{k0wuoG8*lg4{gT?0Y>Zs|F z%=6Yikl+8d8!Z~I8?e^j26{3V=vh!E0C^VOo4pgxW&zWCOT6owy%Xo&IA%JnShLk3 zKUdzt<8{OW`z=|XzrIYJZNgIZGPiB+&l`6O>x-tE?dWc+kW0JF~~x$K%E3GfPi!9l0#Ps$+S)u{em^%5%2B#pyR?CQaUXqvXkV z+w`B?R$0AU^0Ac4*-z2bQw`L0Q5Xx*Z7Ot*I3+0@WNUCVaudz-)V{wdb#`nO+r zQDgqkFBZNdz<}7t!oVO34UFQP%#_q(eK2JRiuAJ~r}J(b2>cOk`rfwb&8;Q@O9#HQ z3tb-^dbiZvE#_vH=A?*qu{-ZyKL0}3K5WvaS$2067>i!Gs%+i7dGq1pPebo#mN9%; zYbrWFCS^|J%C%W%w>^?K%a0SCQ#r}aGnY5y568TCUH#aXTay&8|F{%dQc;tFIWn_A{Y$R6rGsx<#-g)GD5lR2|^ zIX*f(xp0~HM&D7-qk>tFKJK^K^V!6~-DA=d|E3lDx4n{>Sf1$9l)BP(?aLL4x-oxL zE=ovUHI@t1!i|1ku3Gct)V<1X}paSsMd zfQbQX6@YF4dT9vJ&cLvQQ3GfMQrU>E5xuZMXk-FbKm>{&bi>dyGs3XMNePXDm%rfIAsg_H01&fd4nRg&Q|lvJFEUyt9edj5ZzI*Dec~>!p*i->U=X! z9=mXA>#C&(5|YvnUpRIBZgQzIt0;%;4v7s@)m3)hHQ62PB(#S2%BhW0N>-cB6ttbt z#mTH(dq$3{zw!d-8EKvs>tFqfnk~WA7BuywbKb1#H;M1NDl9%#y_|S)qDVP+;i)Xu zB~R8g9@=5o@-Et|)GuJo97~g1F4}4ywT6jKb$k}D=lwLeS*8)EFkSt_nM<0YbB%;v zr>*;S_odU-8{e-bh@ZW;*`?O(^Sje4Y;J7$wV1~;?$W0<|978#^XsC+`ThGU*#l6* ziE|bE@r}UnF<@k1;0Dt1MX5Q(`g$O;_xxV2Lk0p25BB;C=55cEby>2pn)U`4&HPTs7O|#P-mwk3U{+ z5Itq3t5CL!?V3L0|AT)Ge7OAM?&|LPl6-uX@@XR}A0{Uc8YRacavdz-K<;?p6u4OWAyllFmj`IiqyY_<`HWj6FFD{k0wuoG8*lg4{gT?0Y>Zs|F z%=6Yikl+8d8!Z~I8?e^j26{3V=vh!E0C^VOo4pgxW&zWCOT6owy%Xo&IA%JnShLk3 zKUdzt<8{OW`z=|XzrIYJZNgIZGPiB+&l`6O>x-tE?dWc+kW0JF~~x$K%E3GfPi!9l0#Ps$+S)u{em^%5%2B#pyR?CQaUXqvXkV z+w`B?R$0AU^0Ac4*-z2bQw`L0Q5Xx*Z7Ot*I3+0@WNUCVaudz-)V{wdb#`nO+r zQDgpR+tbUNfdR3Ng@Hj78W_bnnJKBo`e4cs6zOL}4(8o9;Q1@+_&v05vT9r4atHp? zsTxcwe;KZ(3Gr`Q(wXz@&1?6Qg}b*!Ze+B5ljQmA@#DvnU%sBb&-f7sV|2Q<<<3(} z7@~JC+xpwT zm+6(v`XTY{6uZNQC7rKJ+@407h0o1fYcu)9e#OkDe+Li6J#p9ldd$Rg@_n|39h;Ab zevsbJr&&`T!+z21&U}%u@;hxI&ksm0Yg@7N-CaiaXjd(^n&5h@5Ov951X$3KUMwv#+ybK{(UQCh3Xid z#%>Yk{G+;Q`~0S=dFiHoJG}nSeX1Ye&B!FejJu2nMl~2L0mePn5+B_F^uiCKoq=Hq zqXy6jq@oaABYN3_(8vU=ZwQn$=!T)^U4&upp@yO7WONhI6FkC%KgMNePXDm%rfIAsg_H01&fd4nRg&Q|lvJFEUyt9edj5ZzI*Dec~>!p*i->U=X! z9=mXA>#C&(5|YvnUpRIBZgQzIt0;%;4v7s@)m3)hHQ62PB(#S2%BhW0N>-cB6ttbt z#mTH(dq$3{zw!d-8EKvs>tFqfnk~WA7BuywbKb1#H;M1NDl9%#y_|S)qDVP+;i)Xu zB~R8g9@=5o@-Et|)GuJo97~g1F4}4ywT6jKb$k}D=lwLeS*8)EFkSt_nM<0YbB%;v zr>*;S_odU-8{e-bh@ZW;*`?O(^Sje4Y;J7$wV1~;?$W0<|978#^XsC+`ThGU*#l6* ziE|bE@r}UnF<@k1;0Dt1MX5Q(`g$O;_xxV2Lk0p25BB;C=55cEby>2pn)U`4&HPTs7O|#P-mwk3U{+ z5Itq3t5CL!?V3L0|AT)Ge7OAM?&|LPl6-uX@@XR}A0{Uc8YRacavdz-K<;?p6u4OWAyllFmj`IiqyY_<`HWj6FFD{k0wuoG8*lg4{gT?0Y>Zs|F z%=6Yikl+8d8!Z~I8?e^j26{3V=vh!E0C^VOo4pgxW&zWCOT6owy%Xo&IA%JnShLk3 zKUdzt<8{OW`z=|XzrIYJZNgIZGPiB+&l`6O>x-tE?dWc+kW0JF~~x$K%E3GfPi!9l0#Ps$+S)u{em^%5%2B#pyR?CQaUXqvXkV z+w`B?R$0AU^0Ac4*-z2bQw`L0Q5Xx*Z7Ot*I3+0@WNUCVaudz-)V{wdb#`nO+r zQDZ)L?s~riz<@Z$!oVO34UFQP%#_q(eK2JRiuAJ~-g&nT1ome#S;dN{A<_uxm@Nrw>9FI*FC|XL7HpcFSuOs z)Fz@&Hs*!NMBJt{dTnuQVWGuJP&PFcy)hgTE_|7e$NehyqBi2F=sw}tlr6Y zXUD~lGZ@}0)vbM^#3lGUqxjIJs>2Ky8xm#n5(M?amW9~&Xa)UTxn>s6zs+YqpL{ms zW02nS%8h6KWfkv>I`cU^so3u39AC5gTlbl_s<)ra=E`OFVAPxOcmEmbecSl|HNKo9 z;qrC@Lww7(-`n@Sjo5Jgg`T0Ez38itb*o>VTK$D@Z9PMPHzSh>GwuQ(81G=P1eg%8 z7XRo5pqGRY?Fg8qo_HghnP{b%uTcewRp863c b{9%ST2O}>8c(byBl(7P#574vkSwTDi2($FR diff --git a/OpenDocumentReader/Samples/sample-deck-fr.pptx b/OpenDocumentReader/Samples/sample-deck-fr.pptx deleted file mode 100644 index 7e72b344917eb28db3691972345f57228e533338..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1875 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 diff --git a/OpenDocumentReader/Samples/sample-deck-pt-BR.pptx b/OpenDocumentReader/Samples/sample-deck-pt-BR.pptx deleted file mode 100644 index f1493dda91a8626436f3622249fd76d96ec990d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1871 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 diff --git a/OpenDocumentReader/Samples/sample-deck-tr.pptx b/OpenDocumentReader/Samples/sample-deck-tr.pptx deleted file mode 100644 index ac6d2d3a5267acff5ba0c6d4ccf258da28ed8a43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1878 zcmWIWW@Zs#U|`??Vnv3UbIA+816d|a3=G0RI@&ouuOv0EBtE3FAhkGFuOc^RZQx12 z!v+F>MNePXDm%rfIAsg_H01&fd4nRg&Q|lvJFEUyt9edj5ZzI*Dec~>!p*i->U=X! z9=mXA>#C&(5|YvnUpRIBZgQzIt0;%;4v7s@)m3)hHQ62PB(#S2%BhW0N>-cB6ttbt z#mTH(dq$3{zw!d-8EKvs>tFqfnk~WA7BuywbKb1#H;M1NDl9%#y_|S)qDVP+;i)Xu zB~R8g9@=5o@-Et|)GuJo97~g1F4}4ywT6jKb$k}D=lwLeS*8)EFkSt_nM<0YbB%;v zr>*;S_odU-8{e-bh@ZW;*`?O(^Sje4Y;J7$wV1~;?$W0<|978#^XsC+`ThGU*#l6* ziE|bE@r}UnF<@k1;0Dt1MX5Q(`g$O;_xxV2Lk0p25BB;C=55cEby>2pn)U`4&HPTs7O|#P-mwk3U{+ z5Itq3t5CL!?V3L0|AT)Ge7OAM?&|LPl6-uX@@XR}A0{Uc8YRacavdz-K<;?p6u4OWAyllFmj`IiqyY_<`HWj6FFD{k0wuoG8*lg4{gT?0Y>Zs|F z%=6Yikl+8d8!Z~I8?e^j26{3V=vh!E0C^VOo4pgxW&zWCOT6owy%Xo&IA%JnShLk3 zKUdzt<8{OW`z=|XzrIYJZNgIZGPiB+&l`6O>x-tE?dWc+kW0JF~~x$K%E3GfPi!9l0#Ps$+S)u{em^%5%2B#pyR?CQaUXqvXkV z+w`B?R$0AU^0Ac4*-z2bQw`L0Q5Xx*Z7Ot*I3+0@WNUCVaudz-)V{wdb#`nO+r zQDfd?%QEYuz<}7x!oVO34UFQP%#_q(eK2JRiuAJ~-g&nT1om?GQRq$! z7GZlM*C6P=P3oV4ip)y!7lFIZ?X!NKpsKk#Q)s(KgU&8N&$F}5^X2Ttr_Y^~!v7*_ zv9^`vX${6$>5H#&UH9kM)oExH&dWZy^kTq8IhnmNaW^h`Iy$W@Te|kex$0=6XRl;6 z-ks}Vl}+k(JX#y^Xj&u-`>kU6R~jcj>C84h8tvP!^2bz#>1V9KHx>J=mDht*e9M{{ z3YUGqo^idbRr62fey2-a7vxoEt-ipPdi;Rkv9={9iRUkEuXmUu+n~Sl^TevlRh;{O z`cLY=sn@&bjZ{dXiLdjnu5;a=mAIuZhHsf6w(#nSW8N=pRytQ~jCitHVm)($(M;dX zj0fd9b*$=n-6mSB)Np#6`RDxi`E%qKD64oDxjXLLZM3NW#B2k#gL|f&TVJcMsGIXg z<)VbtbQ?Kgj@>Wzg_el5PMDoheCXFxuCw6^W(VZnB?r#;daR%jDyO~a;_dy`HnOsP zlJ8Rs=81oPGoSBy_f3=k{xav>+c#f)c)0w9VBSeS789WjwuzskE!Xqe|9!~blHRDH zcU$gI?l e0tgfSFhiV!ks$)SS=m6!Sb@+7=-DrgrgZF zAHye66-~Jo6$ra4WUYQ-#ME2DJAz{M#}$0wjk1Pd72@q9qgA1&FIGXqMYF0^FI87@ zI8Q5~AK#1oi>R}88s5rvvB~5ve9q*xtTOYz>yUcQG45L-cl91IoW$^bRhJ??Oy*0Z z1d<3Xw}?-J2u*ncKbITy%ad5|Wg~a+Er~B9%zj17Pv~~pHo^$&Ml4E#_@vc!Q^8o& zBF}4-9uOu0`n{2v4$>QdCUHQ~l=0(h->3V0m6j-zQk45NU!gCBL=;{IgDg8C2*TJ2 z$Mjry+Qp4z-Oo5N{d{OZZi(I;R`;FgU3_NrJ(elp;9pu*0{Z7^GsQCv!CT_ z3tK%@xvzYGEUK)|imrC(s%9zS;8twm2N+e+kzmP$1(14{yv^iyk-wB8t9p4J;ZEc? zqDl{S2kkmS$Wid3*w$ZRlJv5a!^B0gg>f&%a1^cWjIz{aTFWYNVJ(2WwU|4C~-V7PTr^GX2eMc)80UJ=^YT)Z{TY1J zXxX8xR0GZ}#m5G`gZ7%E=Q?M`$;Eo#4-pwlGtM= zn;J83@}k-J6k5`klP(^CjmS_=>I&r0S>jWu=eS*NoB@Nwb}EPN@hu4K01nymC6pXHY}7E z|GIM$(6{a|*y*Ev4eUv#>U4v)O1zOd)c;DQVaWX(oxJa zzgr`1z+}j9C697zWLl1Cw5%^5UBrY2w4dayL>rHI^U2>UD(LfUMrn`tx+pNax*o{pD5up=yMEu6)iOfD{N|GJy}3&1CE2LJ#7 diff --git a/OpenDocumentReader/Samples/sample-paper-en.pdf b/OpenDocumentReader/Samples/sample-paper-en.pdf deleted file mode 100644 index 3540f171d9e138d429254737b9ff566ae4a72923..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4806 zcmb7|T~pgQ6o&8fD|Exm?gh5>WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa diff --git a/OpenDocumentReader/Samples/sample-paper-es.pdf b/OpenDocumentReader/Samples/sample-paper-es.pdf deleted file mode 100644 index bf14442c11c529e286d0e12b957293586608ef4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4835 zcmb7|%WmT~6o&VH3T^_li%8;47hn(|nc9;jn5+EO6N>2%&XtG+-F zDU-BZiE6#bMgB+~{`}A3<>LOA#U&2d45J8DPtUV=@50qzFEV^DTCuCP;l0?(1`+u7 z;p%E8%UnU~-&0sa;jcyBe5H!~7QU|zWs9(DqMn~OfzE3QnC?BilX)R-s_$PTKzYVd z%E-6yK{nN)UdsjoTU2GMeqqGaTfzlFvHIf*KJdn}h0YqpyGJHgg`U1xbrLQQPpulI z8Y&KNL?iX%Te*9cZLt>Nyj)j#QEtO8MR{E|h56qNNWJFR?LW(Gg>{P`KoJ!5!P*3L<4@(XudDn zA{R*R5GE*>==o3XJ%w~ho+S^`mlex_28)q=)M+!gJPm-Bn->bCc(#ma0HruDP-A$A$q5DOqJeB zX>i3_zO>aKODO^D1Qul*43imwxp3rtE!UtuOu$G3j#+?D8muZvr(V~60f~x41-z^_ z?VpeqgDmBcswlQF9;6tKg6xzcQ4~bcAj>fi(ld4#REoxt(e<$q&$90yGoWLT79E~c zhGR7pN3ro32@dE9%F>assNguvRHx*vsPhRW9ZUxY-6`oPJgKB(X*?#m4l^-I-ii7T zs5#|!FoI4@Zt0Oyp~Z9*i6Fs7MABk9G$kXPjxsi4E~}TSZhfxgmK}4Yns7()sR{3) zgW~Ag!=N9uK3h5p(}@@zN@9>32he_TAY9kHnj&h?m+B}!emDY{oWPim*`7ry9Jti7)9wC0K3>DQ_+r?5y0ANzMrq$qaF`_O zC``3WNn%d7ANP6}j0AcSTT%BqH*I*tf*83rIAvMCce91+I#(M^ee(NI!`dbq1g}8N z0j;ZYQ;711uqRTud^z4N9Is*2<;VZN+PJ)_cKLs}-}qk3%?vIrW|94%m~+a}2DxV$ z(%+)eJ>ziWqCO|ja0Is{XU_n+a diff --git a/OpenDocumentReader/Samples/sample-paper-fr.pdf b/OpenDocumentReader/Samples/sample-paper-fr.pdf deleted file mode 100644 index 7e984ca1eef7bb731e18c626d010a3ee3e1f86cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4826 zcmb7|%WmT~6o&VH3T^_li%8;4vVcK=B#j%iV>C^SnZ;lhip6-CI#Q}jkm=KPJ8#jg zpP`!`QX*-k64iQ<3;pr%=g-6I$;}U|Qyj1bMiDCS9~bZ5g`2O>BD~C+Y+vren`|d) zMBv-ov$KULas{b>k6{gkKg+!SL>2itye!+ILD*GMyT=ukNaK}yXFgGI8NdFx~W9= zw7A$HC6GjD^MH5~L@41Y{M_W|yH&Pr+DgEeBtDHW`yOo`(bcA_gAvws7$X5Ys`Twi z)&lJX!UR3Gve30BYDPhV62|-H{zTPbw-*%xD{Dj}^az&LgQ^5!?1W-E5PCp=4Pc{C z_bN_JuhwndKqEgs-Cuj~rBQWLWq^ZQSq=Td#8W51y&fEapC6?t1~7^q3-16hzS|%P|j@Z`g5A*%?R1)DPuXwIYn7y-LfD4=GF& z)fY#>U`&Z5SdEiK*>a*YN*zy)m+P!KRN$pYq=V@w)miB%JZq(6X*|^(Ei*AzuCwYl zSZ#{ksDjQ+Zt00dLYwI*62bJEFiD%~&?TARw943+dDlKamsR7_XxXW>R0GZ}#pecm zfQ~k-S02ucldH0N${JY?mxbZvakMWj9fkQ!S~`?YIj)_g#>w|`D+<`jMtjr`w}q$D zQd{Y$I1b`uG+;NuxkWMds>H_2>%+aMcH#;4($ToRP|JJs(o#5{bJLh4kfY2NtPHVFZX4e z`xIKzmy|9ZNvD%iuR#u7rapz*O0|>Uifz?4b2-T@@5@O?(PVn9)VrfYVKMLtg_Bx$ z57CBBV^VdKuG%48$j$|uso6Pc+GOfKZyBIHQyJ896=IC=H@e8}a@&f{=j zUOEa6xdERTNIl>Vg=5O7J$k_D(pY)Z-tXab`R0^6OiM@m($Z1MoS6gEqcS#T!VRt# z(syd3mh~m2qnKxgcTU=X>6GJ29p%Q!btcs{b7t~5-j|n-N@+mHN#4n{?GtZa+KbBN zmkjpsderr9epAbOlhRVN+l~v!C+0WPdndJ*%R9J@o;K4LBv?@hayaHw+0G&ccNw+q zbnEKo!#P}zPeyy+9g7@GqvbG{;4(?nO<1KbMI^DeTX;9f;IShAdl1*)95lp7I9{@J z7}!iVJvWIuUFuuvT2xz!a)Dk-csM}YvUrdxy#mt=yt(vG3jOPgdh__-FB+#8Y|I`~ykfYD@qC diff --git a/OpenDocumentReader/Samples/sample-paper-it.pdf b/OpenDocumentReader/Samples/sample-paper-it.pdf deleted file mode 100644 index 9dd1c5d7098fdda4e57e0918b70c438f71c193cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4836 zcmb7|OLN;c5XbNO6u5Y%Jy;}OlsJ>|jO|!)ruNjel;n`f0g@nMF#qZq06_sP3=(dw^P8QqFn>guRJwKR1ESO9`0iJ$jVeOx&m+Ut>Ud%F&#W zZ_%@?R8wwb1&%FLQR`nAF+EDOASls)T)_uMENbYiLcDFVzH0PzVBJZyY}U1&rJgE| zZbT(b^S#X9WSwn9bXRQDHY@hgm#nxhs?7fHC!~it_WK}LPc$UKVRb5K)GPzkH z?I4NKYKQo28lxFc;pb|Lep-mSZb|`PlH@YR>}Rz4j_y{i4My15FhZv3iP7DQtSW)B z9ASd?S+g&c=^$jx_;JMd0#zd4g5C&3DixwJ^r6Zk>zEUSvG*6#uD`WHqJvvk&GeGg zPVcd)YFVNWFYEgNKDWL-l>%^(O;nYH$pvg?_~;RiLD(;uEIKf_@8wRY7G2BzS#4x5 zM_D|j$b-MtfA@1~3`^m;r&1mc3N=MmPkRk`Jf9{f1}g=-sp~^mJ6P-1*QMIkf5I|# zy0t9juvJmwVBAYFY`papiQ{P;_p%)G>HM@uVEaKWW)eF|GqK-yW9Q6ChxV^0!-<}X zr(h|Dh9+3Al0(@%;37}0lJ}zAjwtD2+B@l1Nl)QXB|S@%q3LK1`OGT$D9S$|=M?*1 z584&?^gyaGVtR_iu(t+8GGcmkP6jyRWn#r#Hm|R$tX0TK2M>j%UUBXyKDOc=w0B^W zcQ~_BE>!s<4w))KyT{|9!1NU6BZ28rI;6SLl3FbvvW+YbK_4AE6qiOyPbJATne|I# zHaK@E#z7~s)$(3dV?pWIU{E>=Cu2f7G-08jjIEG&Z*Z1{k`Q-jFeDwt$e4?#XusZC zKsL8Be%kG_O%~cVo(;vLr!XDy(W4{@$jD|^#@k#q+uq5v*~gQiX!I0GhojMCACJz{ zkcVb_>jQi#b2+xJnWIDD=qWlI&XH!%cob4V$W3O2e31L0Q~s!=LqqY%9Hs9kLqoSp zo}#@=XjEau#^ZHWWgED9j;iS_f>G%xNGl_rI+TP?9EPo!P=LrXd@Oo+ATZ4p$Wvnp z$dfp9#h|HGbNLE2iQ4|eS znqxc28-#+>Qz@O&ev-F-ItNHFI9=8ANjn+3Wl)C(1JhBXCy(!t5A1OkGblHxD=c*# z9w?0UA=+W$nio za|K3Q_12u-gslmO`6bAk;5kdXo!d=k@-oqPOH-nL&?#A>S16lvfi^17#abQHv@0>; z_2u}uaD0c+uOI*WZR7Gr<=g-8!11G$y9vBnOk(#z3Fnlf9rA4{GT)-Yw{duK(Vvqx z9K&WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa diff --git a/OpenDocumentReader/Samples/sample-paper-pt-BR.pdf b/OpenDocumentReader/Samples/sample-paper-pt-BR.pdf deleted file mode 100644 index 49a8c81beefc9a388c5c5de6e2596e0a03765a3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4831 zcmb7|&2Hm15XbL+3SI)Vhe+a=K7d7l&DL((Zn|mWW)F)!C>HJ2)|LW_O1FL89s(5T zsV~r>ERt3#QLPV&P5n3;{y9T(cy{y6>Kq4bfl-9&htG>wufp|jk0N}Nt9)PY!kc_2 z8bsjf?Zw4HRE380&r`UA!XL__`9L-KF?>_El|tBc(d{q0fN?1R>#T>@qA2sr`pbt1 zP@Zv=GV(FJ6;0jBjcCBJRb46l4o3qviV81tZ*bp&1+WSsqGN z7C90Jgb6AH`rKBZYW+o<88yLps!cH7zxG~K8=(!*2!Ynkpc6qDJ6ACsxLVZcF_-zE zgK@MQTb!A(UAK)A5`BAkxbons@##k9fP-dv(+C)ur%!@=pKt`KzAr^JfMEbm>zHcA zwbtJ$aTw(&&4Ls;@F!J_a~Til33nsKbB)@nRKY0EF$?eszpf#Z2INpVLV8c{>aF?} zGGdga9I_O}7RI9#!%>i(QY4CkC>mus=6d|jBCzA2mNJfvp!X##3Dq!o%!qm~EjvD) z499vbj$+eJ60F6yC`&y)^2|timCIsAN(a-?Q6Hsr6rPpRu{8Ec$rB^xbuNE_^`_d5 zdT zI1b`ubkxTbcLp)`dWnsiS9S9!3P|(e%K5@ii+cmpQaGLy)1oo+1!iQ#Tt4af_N_$R zvfjY76eDv!o}%NLYY|y$q+B)|S*pKf>5EH;`{L43n9jKAP!fBjWQmdT$M(rP*^cxD zrK3nT9hBWF{{u~9cEc?P+AHW7yrg{V$iqoFl>apY`0sXMn`j8 z&mB4umEGaSQFAMhBeCzCK{KP`N(%4B=ty5QItos<0iOu6E^QnN=aW%oy7;H5(eS2y z*q0k9917nC?s#83Ix3k{a)5gLjE#~|zBTP$)v_F~GL92YE$@p-M=?)!AN8~bvnk!R zhm;#Vuk)&fI`jDtUwS*-7nhF8Xh6qFe)Q75o_OQZ7Ck?!a^KB)Gpcb#uxBl0XGMW$bL}FIpt`J zTw8{^r>Jsm9By0m=cElsa8vT4jSz7EMH|Kc>dQDy90ykfgFE>IHQ)-~KQ W_18U(%BAWYXEBWyXJ^ZItHnPO)M#A* diff --git a/OpenDocumentReader/Samples/sample-paper-ru.pdf b/OpenDocumentReader/Samples/sample-paper-ru.pdf deleted file mode 100644 index 3540f171d9e138d429254737b9ff566ae4a72923..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4806 zcmb7|T~pgQ6o&8fD|Exm?gh5>WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa diff --git a/OpenDocumentReader/Samples/sample-paper-tr.pdf b/OpenDocumentReader/Samples/sample-paper-tr.pdf deleted file mode 100644 index 3540f171d9e138d429254737b9ff566ae4a72923..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4806 zcmb7|T~pgQ6o&8fD|Exm?gh5>WydoeW`M%dU6`_vZZA5$Fjxt0gPpN#TK3oPk!(o` zE6cmNAjEzoy?S-@b&hV|UmoL#Eig(@^YCr)?p?fk-HG_T=!$K#iEoRIkchzByOWcJ zs7nQ@pZlLGUo|j!4#-2}2pNUmH|y>POad=UIZRBH zS{QpNhP6~j5zw9_UY27XE%$2#)(YKs@)@6agHqW-~TI8|M76pX`E(*&y_ zvM5^yB=X!ic~!LKjFS$g-cAorIttG^=~$Xhbw_!~Gvnk<(SC;&rrvlJ3}!ldVqwr` zI*KGPu_jE?W;%39COEA!HD=!TyIs?EA&r)uib^%$+){jQzz<}nUlDWdK=ae$(F{(kL&f@ z4ZZQk_%RHn|TdB70 zJMq}|)l4`ti-*F|Q8b%gA@!E%P*?*(I+=0uT5Kk^_|ZvAhQg6qN}WumS{|I-N4-Nh zgd;KG_@S14Tfpk$g-4Z^4o0MF zXA7DeC-0xC-7c)r!J&wB6dY$GJ`reoxE%_|67LA=;igMt>wC$5%Xxa@$J%Iemm_8UYEh@k9 zzq1#|XU(?!4=IeFtynK0FR@7M2c?`-j@HOM%aMMIYWIvoQbm3Cp5X)%B5$4%0`lKH yqxfHC8Ha(e9ApKmt!Pyu>c0A0pe(*?8b~FLSsmFGZKs8^G~tV*ql=H1i+=#Pa$Eoa diff --git a/OpenDocumentReader/Samples/sample-rows-de.csv b/OpenDocumentReader/Samples/sample-rows-de.csv deleted file mode 100644 index f42b5d1..0000000 --- a/OpenDocumentReader/Samples/sample-rows-de.csv +++ /dev/null @@ -1,7 +0,0 @@ -Name,Rolle,E-Mail,Telefon -A. Bauer,Design,bauer@example.org,+43 1 234 5600 -M. Rossi,Support,rossi@example.org,+43 1 234 5610 -J. Novak,Vertrieb,novak@example.org,+43 1 234 5620 -L. Dubois,Entwicklung,dubois@example.org,+43 1 234 5630 -S. Meyer,Design,meyer@example.org,+43 1 234 5640 -K. Larsen,Support,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-en.csv b/OpenDocumentReader/Samples/sample-rows-en.csv deleted file mode 100644 index 4b3409b..0000000 --- a/OpenDocumentReader/Samples/sample-rows-en.csv +++ /dev/null @@ -1,7 +0,0 @@ -Name,Role,Email,Phone -A. Bauer,Design,bauer@example.org,+43 1 234 5600 -M. Rossi,Support,rossi@example.org,+43 1 234 5610 -J. Novak,Sales,novak@example.org,+43 1 234 5620 -L. Dubois,Engineering,dubois@example.org,+43 1 234 5630 -S. Meyer,Design,meyer@example.org,+43 1 234 5640 -K. Larsen,Support,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-es.csv b/OpenDocumentReader/Samples/sample-rows-es.csv deleted file mode 100644 index 1f89d28..0000000 --- a/OpenDocumentReader/Samples/sample-rows-es.csv +++ /dev/null @@ -1,7 +0,0 @@ -Nombre,Puesto,Correo,Teléfono -A. Bauer,Diseño,bauer@example.org,+43 1 234 5600 -M. Rossi,Soporte,rossi@example.org,+43 1 234 5610 -J. Novak,Ventas,novak@example.org,+43 1 234 5620 -L. Dubois,Ingeniería,dubois@example.org,+43 1 234 5630 -S. Meyer,Diseño,meyer@example.org,+43 1 234 5640 -K. Larsen,Soporte,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-fr.csv b/OpenDocumentReader/Samples/sample-rows-fr.csv deleted file mode 100644 index df84a66..0000000 --- a/OpenDocumentReader/Samples/sample-rows-fr.csv +++ /dev/null @@ -1,7 +0,0 @@ -Nom,Rôle,E-mail,Téléphone -A. Bauer,Design,bauer@example.org,+43 1 234 5600 -M. Rossi,Support,rossi@example.org,+43 1 234 5610 -J. Novak,Ventes,novak@example.org,+43 1 234 5620 -L. Dubois,Développement,dubois@example.org,+43 1 234 5630 -S. Meyer,Design,meyer@example.org,+43 1 234 5640 -K. Larsen,Support,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-it.csv b/OpenDocumentReader/Samples/sample-rows-it.csv deleted file mode 100644 index 256b09c..0000000 --- a/OpenDocumentReader/Samples/sample-rows-it.csv +++ /dev/null @@ -1,7 +0,0 @@ -Nome,Ruolo,E-mail,Telefono -A. Bauer,Design,bauer@example.org,+43 1 234 5600 -M. Rossi,Supporto,rossi@example.org,+43 1 234 5610 -J. Novak,Vendite,novak@example.org,+43 1 234 5620 -L. Dubois,Sviluppo,dubois@example.org,+43 1 234 5630 -S. Meyer,Design,meyer@example.org,+43 1 234 5640 -K. Larsen,Supporto,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-pl.csv b/OpenDocumentReader/Samples/sample-rows-pl.csv deleted file mode 100644 index 846489c..0000000 --- a/OpenDocumentReader/Samples/sample-rows-pl.csv +++ /dev/null @@ -1,7 +0,0 @@ -Imię,Rola,E-mail,Telefon -A. Bauer,Design,bauer@example.org,+43 1 234 5600 -M. Rossi,Wsparcie,rossi@example.org,+43 1 234 5610 -J. Novak,Sprzedaż,novak@example.org,+43 1 234 5620 -L. Dubois,Rozwój,dubois@example.org,+43 1 234 5630 -S. Meyer,Design,meyer@example.org,+43 1 234 5640 -K. Larsen,Wsparcie,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-pt-BR.csv b/OpenDocumentReader/Samples/sample-rows-pt-BR.csv deleted file mode 100644 index de0f727..0000000 --- a/OpenDocumentReader/Samples/sample-rows-pt-BR.csv +++ /dev/null @@ -1,7 +0,0 @@ -Nome,Função,E-mail,Telefone -A. Bauer,Design,bauer@example.org,+43 1 234 5600 -M. Rossi,Suporte,rossi@example.org,+43 1 234 5610 -J. Novak,Vendas,novak@example.org,+43 1 234 5620 -L. Dubois,Engenharia,dubois@example.org,+43 1 234 5630 -S. Meyer,Design,meyer@example.org,+43 1 234 5640 -K. Larsen,Suporte,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-ru.csv b/OpenDocumentReader/Samples/sample-rows-ru.csv deleted file mode 100644 index 1d49415..0000000 --- a/OpenDocumentReader/Samples/sample-rows-ru.csv +++ /dev/null @@ -1,7 +0,0 @@ -Имя,Роль,Почта,Телефон -A. Bauer,Дизайн,bauer@example.org,+43 1 234 5600 -M. Rossi,Поддержка,rossi@example.org,+43 1 234 5610 -J. Novak,Продажи,novak@example.org,+43 1 234 5620 -L. Dubois,Разработка,dubois@example.org,+43 1 234 5630 -S. Meyer,Дизайн,meyer@example.org,+43 1 234 5640 -K. Larsen,Поддержка,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-rows-tr.csv b/OpenDocumentReader/Samples/sample-rows-tr.csv deleted file mode 100644 index 1380b79..0000000 --- a/OpenDocumentReader/Samples/sample-rows-tr.csv +++ /dev/null @@ -1,7 +0,0 @@ -Ad,Görev,E-posta,Telefon -A. Bauer,Tasarım,bauer@example.org,+43 1 234 5600 -M. Rossi,Destek,rossi@example.org,+43 1 234 5610 -J. Novak,Satış,novak@example.org,+43 1 234 5620 -L. Dubois,Geliştirme,dubois@example.org,+43 1 234 5630 -S. Meyer,Tasarım,meyer@example.org,+43 1 234 5640 -K. Larsen,Destek,larsen@example.org,+43 1 234 5650 diff --git a/OpenDocumentReader/Samples/sample-sheet-de.ods b/OpenDocumentReader/Samples/sample-sheet-de.ods deleted file mode 100644 index db64526d360683b81ad0c2f20a32ee82d5e0def4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2493 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 diff --git a/OpenDocumentReader/Samples/sample-sheet-es.ods b/OpenDocumentReader/Samples/sample-sheet-es.ods deleted file mode 100644 index 2521bdec64317af286811bfbdf973d2145b3b4aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2499 zcmZ`*2{aUJ7akNoOJjx!O?KH0iHx+^ro~nv4Q67P8N`fb#?DX_reu#2*#?oV7<*-# z3?*T*M}@J2 zAIi&Cf;$064)VrfyuCf$T`**KFQSG&5exIeklaZyFK-+X>*eA{z!AwXlD97ogC)7) zaO6w>%lRXN3?NA-3(a7A-5dY_gl#PlHiqgKEYE5XFhqAejzoq95*Ny@<-x4^CYQRz{?q3;ca}F}`_ABge(?9Afx|$}FGB1m>%A4UvbK zIH|ALv7JD-7fzq9qMwOyW8c3-G%bKWIdJuzKjCoTDN_NfZaIB(@_7b0>FdkjFj9R$ z2H9FdFP(Q-$in~?(AT-461Cgs5b+#(& zT@2@}#Kp7=WfAMSiVHVIFApp`pza@$eHk;~|1xcj1^l&eH}H2E6L!%~JRtKiOC$ttdZ60(D(K=+sFIFs z)>z%Ksx(Dq8*0gh>FRy|dvGl)d>J|Kk|$}=s317eH6#+)IpZ&<-gH9|*J+Jf+wl8- z^0Vz$FZ}kUb6b-7oD7(&H%+_S;Eeb=ZRl+#9=$Q)y7w+TjzNv+d`Eh)^yd;RO_zqS zmN~MDq(pZ0jsqdYt=88c%PD|gdo8Iv(EfQp002b-0Q~G;yLb`FKc?xE3DFZG- zc~`#Ft*A0A7jQ}3>>Cs)gaLpG~()?qa%!p8nAA$ z*K~pUY**U%M0OltwKDf2GlL#{8MA4#F&}C@)n_w%#nG#_Q}S+Zz5V*Nh7wkQ#t@Mw zn**PD*nFYp(ST{0-%j8#ER-f?aj)T&+n#0pC&Aek>Xe=%_2aN@L1^Yw4Sxw5F8F9* zE;nd%L2#*=Y&{D~QxRs-cj&t(%=)KVe1Ue2^n3Py%V|bP34B#^V9}(-K_ea}<9TCD z;R#UC?w}i4=dhW|w3%c$I`tVW3IFsN3b`0{el*2l-r7zf_YsWN8&Xs8%~*f1=)#dz zwFix6jq+fB-ER{2@OOB4pL|)GsqU~%dsug0>*BEPr${}Y1cm0+X^IRaoO*Km;){%| zq>QT>BYDDlr-L8zEDX6QCy&q<=_rC}Qxl6OR17sy)E<7Bybw@xFg&*S^BW?gXz2bn zz0{#i8DE|^?Kk}FReEshN_|P#l9q*eeAD%=FV_2kvNLY6Du>q++;25a7MDV zU7K^>wj3U{R@FH*-_0!}US2$2Dr0?O5VK zVcjHOc?4ZCov;@_m~#I8NvYf!u=2w>18uY{g1^UsWLOb{q(WKZ zGB)Ber3~H#3g7luMXvts*fhsmy;oAK9~)wH^C12*{b&r3wGL)@%ed55-Nnd7wiZAp z%78Ubl?87g&veD9L7rgOPZg=2vTwTkM$O)8J*RjrmH<_1iS-k9>EL#1t>Ea!)_w8u z-}Ex<%3P7g$@FCCJ zYwez5*I0GP^$v?bCfN9|iQY~rEN1;^1qIaWV=O-#b4*2gPcQ5+zi>3b`AS;Vu81*3 zzVzc!>XdBF#9OCRI}yWC+ta2gZPUf@r7eH3t(Z1dyi(&pD%eMxg;9dNz3l^7%Bij2 zIeR$!CUh3$Ds9+2@t#jInNh(MhAT$EyxD`0vumfZs@4t8y3{?2<&0&viB-|U{MSU8 zVk8MHSijY~plZ{RRhKk1s@ofLeIL!pL=|!}@~=uf@U8`(qxQJ3=sZS@<8dIV^jO{* z8=XVhqz>(Ks zf%+?XuP#feHw|BI4_NLWeXY7IsvN)?jaCh4k9OQRrMJaqT@FqWuK&Npu<78xlF#Pi zpDWEz)W5GO|6l-sd=4A7`>#vO?@&-@tv|jF_z&O+Pvigq diff --git a/OpenDocumentReader/Samples/sample-sheet-fr.ods b/OpenDocumentReader/Samples/sample-sheet-fr.ods deleted file mode 100644 index 265e44fbd09ecdb234079f44c981d6ac43623541..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2510 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 W3#!>8IDz|%2Uvr_vV;3q2mA-^c~Fl4 diff --git a/OpenDocumentReader/Samples/sample-sheet-it.ods b/OpenDocumentReader/Samples/sample-sheet-it.ods deleted file mode 100644 index 3011475e71366f2a234a38cad3b0d7b832f5d13d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2483 zcmZ`*2{aVy7a!EnWG4|LRF=W$X|Yt6sj+062xCb+CZoofF(cB*Fo~!vg_tN?sj)Qn zW#m~}#@LroF(RqKND(8;8}I$k>C}1u`<;94{mysp{l4El-?_hwuo2oK3;0)50Wlb( zcqo6fsUmz03l6S0cJQqo{It2QwY`O2pbs|S9Ew1Mh6Q3$lg;B> z_KU)ojNsiScz+kl^}aI>-9}`3>T7S7x+9G6!+Lw)IeE~mJ?!jUWDYjcnx2jSki`7U zvYxVwiQ4_iZ|p}H`k6P|^-P&8(66Tv-oTY&dkFPe8GDEqG1dKa?WdwYlvAZsJ~f6% z5b8pyfcxF9i!DJSQq+)0Pi2lzJYCDB6W9+-=@x$b%CVcQyASA(ig}Vjx@_|rD^%%e zQIXvhC&&Riq+6Ge7jreZ(K}BK&U<*K?Ne)vo9%B*Ul@@16*yXYP4xsH^so>B0OA8D z5HDd+giW+Jomkiw6-maFwq)qIdU}h+PJ`{jGfd6oP<360_vk#CuKZ)RWYDz1uNq7i zzDpqO4<8El(yr~9n84dCpETX2TXzh-ajT9k)?XmQI`B-owtU)_r_P#7v$ru6Gb}ZL zf8(wxj#1{T`sLFhG6UF^k_~m6{(;_k2{#7*miw|LAnL3NF|&BuG0D5tD<*kaE$pkP ziCWkFW{c3{o{mOm=a*mB-3duPSko5#nIx^Y=)|pXKxM=QGg3~@jr8IrMsPHX)b?_} z1+8r<8Mq@AOSlT;(deY}+jg_#FcAeY7xsP2kN76EUr)SmFNya?FMqs?9?KiApVX?2 zsIEL#oAkWroBkISW$lc2m4wjQ^B$bp;*zTfuyj`MKfu7c&*ouinSej$Q@DN3|b7 zx6OXYw1;fO4pms?Y?TqQtG3GFDPMi)k>3qF!Awd^xos`-;83v%Zf5C5>7c@79YqUS zg+(-j6vzdN`9HR~g}_*k&9?-|CpZ5IefRX?fUwD0GwZ5*`HI!<<<=E%U{pt3WsNgc z%KWxekNXYD;YZ!ACT?S|OBt)GceuHpE3%M!t>UtT2ea{_wu2s9T4JN$_kpe@D2b=L z-25R^gR-MZw1;~IRhOMk=|=*)k-&;;3Ou(8hH+F?Fl^?X8Q30kPyV<)U^-R?2Vsdd zcKMl416B0MX`QdarG#Bg-Z|b+b4|`Y&_f6UO(5cSeQ()n*e4W!`Hd|(mSLPY6uTgq zacta{Yyj^@4-fbXd`%1xJ1v=ugC2~V!kj>s<$g!D0C=3%s3OwDeimu2X zaNphXBr6V)4dKL&nC`4qkysBw3hg7pl-7@X3+U=l{e2IE#SX(?{P`vk&9N=AJ1;#7 z^DQKi+$Slk+A>QViT7YrSop1)6hY7fe`y!wSYP84NWyfA39SvGX-&IQ)cp0-r+FXm zhUKs~*Yes@HLnv+8_q4`+nnVW5)|-9#qDJ9`UAe2x*aRYYo_e@y%&g(z-$mVz|1px zONfIR?J}nB`C*4Kh9t0=50$Y}>{a|#r?bCt0|6a9x9xgIuYAQLb&r+U{u?~y;9Ct> zTAek@3OSy#OZV<{BDC7ksW5N4$!qR)dWRZ-4fn}=D`7CEt#`g4BlT!aSq3$B=6jo0QfIp=ySUXKDQs*oqpI&Y~2YPAI#%vzx%Ng}i;%3zduuFGw1G7}w>+&;! z(M>J|5|wS2o;sHc6*nv4oY{yAtw1lr!J%Dg0)r<+S8hbS@~>(!5m4e>@2$^5tloi- zL>5a&MhCM;A|3~`Nvm4y3Cae)^9u;d3jP0~h2Q@Fk$gV){v2U`M*a6#@^1_PkS}nW x@BZhI@_UNk3I1maJO0%_>Hhb)-^uD{T&>_Q)P=Cw3fw&0!e1P|E#G`P;BPJWT_ykk diff --git a/OpenDocumentReader/Samples/sample-sheet-pl.ods b/OpenDocumentReader/Samples/sample-sheet-pl.ods deleted file mode 100644 index 61ba3894bef50de9b3e5da857b63e29fee0d5b98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2514 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 WiPT&iKz!dX_i;Ce>$|@{9q=E+B~O3= diff --git a/OpenDocumentReader/Samples/sample-sheet-ru.ods b/OpenDocumentReader/Samples/sample-sheet-ru.ods deleted file mode 100644 index 0b466566304a6224c1c62ea1dd328b7481c8333b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2635 zcmZ`*2{aUH8y?*3%h*!cMwU^`gsc^c$WCFpvS+=P zu~lRlAxqRRGEJ9k8M@Pd|8qKZ?*Dz~J@0bP^L*!h&v(xISi{(U5dr*jWB>{NS}9Ow z^36Dz7Jvyr2Zsfs-2(&tF`n+h7##Lo2-XXVb0=U3P+TAy>xJ{Y7J$YELkWR+w7VC< z7mW_K{vYQz1{uID^+Fd4GkU=S0EjZZrIDRJ#0+kHF2Eg&@kSGZp`ii(*;)E2y(+v$ zyIMwL7lV8p;*uv^tj4rr>$0g=MidYRgab343GWl!G`N8qJ*F5NV^&uf^fq&-+oUb- z)DT+wz1Pw~sBh<$MMsw>BJ5r-yNo(M3N9kqCQN@v^4AP0ctPN+*WcFX3*CC(6&^)+ zO3Vj57<1h2#c>MeUyDIWt-GhxopE@ylQvX5`rI67a|CVm8x%AyGNrsRHnPm5~hq8oi9L29R3(l?-N`Pd-k><#6mas=s89ZzKB zGt7!4hoHq0{IaN~Ie#PGQP658Qc?YM+zeu04?b1(JL>GmR-$td$~6pBx!!Yg3lTJ$ zcCP}@2kUpKy34NcCzbWNp;$3Q%x601{B4Zn5SRa2v=LccTC6}m$rtD!oH-%b2Yw>n zjJS!YGe;HatDcV1&^lzi`dk?E*JYY#sgz~A0^iEWj7aG4T8J#9g9Jto+oC@2Tsyq* z#$j(u5|GB_(!vlyL9U!Y631M!Au# zjQrN+=(v&bWdTv_Uhlx`$I*ZvXH5cif5or^0L4xK01tE4o;Ymqw_nK|HVp;C%^3qb z4;(q4IsMjJW@?ssA34UVQ_*32TAru;5~+;Qvj1{Gh6TS?Y&xf=_1U>9Ia@P*FEqueW>K{Y;(`NN7QCZn`B61GY6#NO~p@_`{y zMciJDPOfZtQm8V!g%_~G9XB!gh`mD$#GgCm*Su*9XBMKapwKW6tb4HXNfx>neT+0cYDuDF3s@24aHxow%g~9>qqEQ8n z2gAnZF@{%`&hzT5Uo#=WdIXV4vb##tA>^fj?e>ut5;iM0-3>QGqqmWCPib;Jjvlj< zYQdV&Uzvwb2}o!tHZwS>5Sm~ENI}l{mr*=hhTQsZL`q0gtX6!|(lFr2R=xPdy=nRA zVYkO4l@Y{vdg>;TcZy zY|%KaI76i^?7vnPG?+d-DVlYP>DKa0`JBrpE!1u+&@3FzR_H-65RMR*R$-O;0niZm z4jpHgFnxnv9&($jp-BHJ`Lvf(Lz2335I+RrY#}P9jDZ|;6|MxLdiFSh5ii{0D2Ibq zd+~UM;4*NqhmMVK@>Eh|n;p_4xuUP6QBL6r(p#!co~@%R4%se{7s7fp!UfvpdnaLM z1i4&3bv?)Tb&W(5O+l#SrclX*c~Z&+p=^h)528Usx2TAs-~JLze}iLv6~*&j^7gE) zVM8T*EzKBu5^`0kM5`8fpj+Y$ZgNbO(Ir7L9ss5Lb>na_x-@7vHl!)bNj9Al9OQn@ zx$ks;t_gi!@uT6dwXJfUf8rQ&M`!v!XzM9slq)cU^ogVn3%=*g#`g`!9wnWEVAZ`r z0(n%|lM38`=MsWNyl;<=3C@ssGpK5rwpJ4Qre*S9WE5(pJyMq4$IUqmlTYM;g=N9q z`DG{PV%}`YMdyHsb!jQD@k;PGeZTpu%U`Iz(~gge0uzomdw{&hDee|x$5fe9#JctA z0uTbe^2fQ9Y09PDq|3s|iML;R!_gGByu?jmXa3gA?DE6z0fyQD|GcFtO8wVf`_ifE z4tQtjYMip!6HK3tbP*ddU65do@)d=5qm zrBCJRsEZFrxnCX+$R`BC@5j75Nb{$x|p2#(4}=;vFnRKt zrTx{&beKHh~YJ$v&BOJrV%#j6I}Y?R`ZHZ*RBB>!}Vr!_PKKOM#PM8M51X8Q6-#DkdFJ zmrRY~{<6yj!K2rC9%iSPNV^nom!ci)Rqc>{o0G@qMOvLWF1G%r)0odOxt~Fvzq=!< zEvOg`%P018SLZ3_kfH23NcaAp1QgX{GgPT&DKri8es+;nNpv2OweZLB7h}Z>H74)7 zIlA07gCaBklbW#tCPwZZL`&UreaF^N9SyA4e5GMkByyuKMb-ox6ko0>WOIiqRz6$* zoNf;}bfF=}ry!Onnn80(;3LJpGu+xK1|*M_)>jnervAZZr;BE6qcH{|U!m{YwGZ~k z!nT&_N;vW%hc%3aRfO&Tiz((>`tK=YYJ%_5>O1P+<0;*XW{Xk n!jk#)cNy|C?&l@?9oNeG!%DS=9b@iV0N@wqU1xe2*SG9%1yqP4 diff --git a/OpenDocumentReader/Samples/sample-sheet-tr.ods b/OpenDocumentReader/Samples/sample-sheet-tr.ods deleted file mode 100644 index 44fadad675f6527dd351b8d79f969d2b0c096a4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2511 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 RD;r3X1qfdO=|ol#4*;SMq1pfd diff --git a/OpenDocumentReader/Samples/sample-slides-en.odp b/OpenDocumentReader/Samples/sample-slides-en.odp deleted file mode 100644 index 776db287cae2bdaf977e5e324dccb4f357aad00e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1622 zcmWIWW@Zs#fB;1XW3@Fa^nn}@<^bZ{%-qzH%7WCyf`XjP8sezy>F1`O zo0ylGmRek*SCN}Db)sX}VFMo5@0P9?>^^Q;eelT3b?Pr<4p^M(IXKOC$&_c`9<$v_ z(`bF^CG@N6zjS%KH_ul|^>3X#Z*K9gm>45vQ!D+$N_Mut#g|ZV-JgPyU)HWXE&H+7 z#K3>a1y85p>L9xpDb%t;XJxlNe7Y9RK;dNnUef^vUZtXWo=8^VDx%<9I$wdCRGUqKd`_ z%~jkBPw~{%?ptWQ=SkoyOYtcWoi6(srB2-VeU{{dBc~p$oN;hnXoRpbPne5Qv+mJd ziCKaVC-fc<6E>Rlc545VfZUr2-@9zTdwTEtUM_cX;jWC6x$AEf-<{o7wC;Nsd$964 z!K<4T!`3V_sNMPd?XRL_qxH%bjml?~H{{ermB=V8*&JoXZYAHS-B@zV%h{_ftLXY% zR^dm>Pd+$a{mAzJqlL>#o41AS$bM9{>W)j|Y96`sA&1x_3wPKN~J9_v01+(~JD5fy%0%y}OHv zfx#9SqTIkhP0r6N0i{1+s9p{8&bw_OaQC?g%kD54>$QR$)0){_xl00BwiYu)NqOpM z1U)@Ie_hoyxwYyqJEpK4^$QNq5N~AcmO58GXQsJSX5sGjEH|6XVotXB>95ydoVlv! zw9-QU*WWMl?v0Jp37Pj<PwlQ-n~`M&V_ zz;o>m*MhaS>7wH8E!TWDJ8j;Tv!lB0p43&T!&j#@EAH&lUdFArxOY=Uh0}Vy=b5hR z&MC@I1T~J&>*4v|Rv2?W%e(qEUqxV2cg~a(drU)}UbgI;wd}LaZ1zV-Qzl&5?0L^p z@xZ^wEbH(8iEX<)d%4jRuW%oma}!PXFE5Vqsnai7{@*Q?y+8MTHZPkr*W9T*56$NG zc8WRt(GqzXw_1NfR1mjX=8Y9IHZE9v%$UpXy+XR*jew2QG_LP(-4OU#_I%FF3pcaZ z^q5b{opw1g{pRDc?RG7t53)|y@S11cm;C!UUbz0_OgHt~-7;?bX0RNY{~^~~r@rpL zqn(DD)K-&?suR}tWuB?xxj6SU*M^ppJxfkS7`HtZ&P!VCRNFMqCUC*E7pfe${HhA) zU#yxsZNkoHGwVIA$^-i~U#ANk;1SR}>8|b`lw7w3 zG>&<7+_ZhZN0LwNx~HiWC@FI{?2&gN&+$`Nw_e&7cx;+f!-A03!%e+O(b>nW7ZwKX zewCuvE4WMkpS$qh?d>P;-5WWJ^VXPn?0O%Bp AkpKVy diff --git a/OpenDocumentReader/Samples/sample-slides-es.odp b/OpenDocumentReader/Samples/sample-slides-es.odp deleted file mode 100644 index d86d2805c7ddb1e10e9efe8a82b804afdbf24cf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1636 zcmWIWW@Zs#fB;1XW3@Fa^nn}@<^bZ{%-qzH%7WCyf`XjP8sezy>F1`O zo0ylGmRek*SCN}Db)sX}VFMo5@0P9?>^^Q;eelT3b?Pr<4p^M(IXKOC$&_c`9<$v_ z(`bF^CG@N6zjS%KH_ul|^>3X#Z*K9gm>45vQ!D+$N_Mut#g|ZV-JgPyU)HWXE&H+7 z#K3>a1y85p>L9xpDb%t;XJxlNe7Y9RK;dNnUef^vUZtXWo=8^VDx%<9I$wdCRGUqKd`_ z%~jkBPw~{%?ptWQ=SkoyOYtcWoi6(srB2-VeU{{dBc~p$oN;hnXoRpbPne5Qv+mJd ziCKaVC-fc<6E>Rlc545VfZUr2-@9zTdwTEtUM_cX;jWC6x$AEf-<{o7wC;Nsd$964 z!K<4T!`3V_sNMPd?XRL_qxH%bjml?~H{{ermB=V8*&JoXZYAHS-B@zV%h{_ftLXY% zR^dm>Pd+$a{mAzJqlL>#o41AS$bM9{>W)j|Y96`sA&1x_3wPKN~J9_v01+(~JD5f%;dgLTUyR z149}xM7e>1nw+0k0!n|tP`w)Fn0MPiV9#?=mg+DW>s$ejY0O(P*YVEUQXaJ^g-s+} zRrC0}mH99EyKEHgUwUs+Q4QUAIYhLGljp{jqVyfRH^)@gZPQeZEY4+F(c;J7uklc; z)n|p$!uWOii-N1RS!zfzH!g|Sjy|}xw%c}+TVEXinHP^5woKZ5%c=8U<`eGxg6=cTZ2xArY_&FB z7#@`JCo1A(X7c$+%_n9HMK7G+c6XBG>Cz{67C)#wR~+Uoed^kVr&8NF%Cc*; zjdpvzc%wV*xOABBs>_ktHy@PkzSmazAnQbp;`9xfy>)CMNB;jPS-kgI?3-5m`7Af~ zd(3(k@#o*i$u&{;3bd~!*i634q`&NH4bN58u)XWDjxgVxB(k9+P3HXHyKYk?f{yaM z3G|t#5t00563apLxsT499AH-~{9~XSH}g~dBe~%F>+`zq-Pf$?oHRSCSNZ3e>x+&n z9pAV^Ospa`@>bABrr&A(uUSq1|5z(_Rr|8_5u0TPo>z2-oW1+kY(m%H+a@hfxU?=z zv#u;Kkx(*foLnJtwN?7x+#3lG|6T9yxVu-i%&k71e|^Wh!tef%9z6h-3XDu5%(zQg zU@8WKCBU)*QRX6aVJ}7@dKeg%Fopt|SPNBjBhU*Zgb{u~s}aQ$x<2$ghtRhem=lq5 UV1PF(8%UA`2wwr|6jl%q0Q^L$_y7O^ diff --git a/OpenDocumentReader/Samples/sample-slides-fr.odp b/OpenDocumentReader/Samples/sample-slides-fr.odp deleted file mode 100644 index cde0944f2932baffb3855cabbdd0fa75a1094396..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1650 zcmWIWW@Zs#fB;1XW3@Fa^nn}@<^bZ{%-qzH%7WCyf`XjP8sezy>F1`O zo0ylGmRek*SCN}Db)sX}VFMo5@0P9?>^^Q;eelT3b?Pr<4p^M(IXKOC$&_c`9<$v_ z(`bF^CG@N6zjS%KH_ul|^>3X#Z*K9gm>45vQ!D+$N_Mut#g|ZV-JgPyU)HWXE&H+7 z#K3>a1y85p>L9xpDb%t;XJxlNe7Y9RK;dNnUef^vUZtXWo=8^VDx%<9I$wdCRGUqKd`_ z%~jkBPw~{%?ptWQ=SkoyOYtcWoi6(srB2-VeU{{dBc~p$oN;hnXoRpbPne5Qv+mJd ziCKaVC-fc<6E>Rlc545VfZUr2-@9zTdwTEtUM_cX;jWC6x$AEf-<{o7wC;Nsd$964 z!K<4T!`3V_sNMPd?XRL_qxH%bjml?~H{{ermB=V8*&JoXZYAHS-B@zV%h{_ftLXY% zR^dm>Pd+$a{mAzJqlL>#o41AS$bM9{>W)j|Y96`sA&1x_3wPKN~J9_v01+(~JD5f%-=$yki*? z14Ak>M7e>1nw+0k0!n|tP`w)Fop;+n;O=h`mfbJB3g2vTREXf4z;@Hj;nKUz&Pka8 zOHTFM$CloX7PB`{Y9LS`r1i14(ff`^kUBL)Iyh_(-&7Y8qVXp;8&E?t8>u4x8{+l&qB`&2mUWM zC|j-eqj7VOozY>wm?obnFaG${gJatkt(oE6c}C^@9@D8Yt626+ES+9iCfT8W zI4r=Qtuoni`7?R;ijTkEE6K#p?F#S+71}4ST)6+Tp+C!hgBP4Z_d!-y-Brg6Ud}zO-%&oqp5L^9=^>26kcinG)$NAoG%Lbn>L9=#l;$}H_ z%R6&HLV?fUmnAVrM9|VmccH!6FFXo=HB+0qZyX-SIBw`S(@%`xX9OGA}6)(|0wZ)`FH|9V7#Nl?h60&bi&%6c(2FO85q?0c5rq}H fKJ*-j(6<8sezy>F1`O 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 LON?mFdRYAhOj(~v diff --git a/OpenDocumentReader/Samples/sample-text-en.odt b/OpenDocumentReader/Samples/sample-text-en.odt deleted file mode 100644 index 1149cf7b0bfcbc036d9dab4906a7e11679f07858..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2033 zcmZ`)2{0RI6b^AySGA}nL`#%PS|qM@q+2YiC9JE|mADf}613vzQdR0I;!04Z?rOCS zb=G~g;@G;jtIkzdQAcT&joqCwYj)p1Z{Ba((!{UiBA~uL<`cJb1 zC4LnRT!L04JEyM9%`HXn0j0j&s6$xMB%JSP;%THK~cG`2t_mN^nflH_Oel zSej~%u4FDTt~ypNAUv#@*g!HprBc2JrWEnlOWQFrVa4D*>4S08U=sCk&{Ge+_hbN zDz^Fi>KHzFE~aRwM7K-|EK$k}mX`0ksNtoOVCwhiF*P}LQCDV~hT3&;WnIfZeQn2C z^J1IIUTjv7Z+d8}<O{2?Qh5hW4ddpoW+|f6Y&#P(7Z?9oHDW$c1X7Pe@t!C{KKdt`=WFX*`^`Z zw?B$LR1|d^rYI+SfV#N7=R@_LNJxs(WTM>#y@`o~LaoqBi7Ip~`k9ekE=ox{L{7sY?)iW-iuJdl*lu&XjV;pmA0{og2h^fW4Yt9WtnDy2 z-vX6hT^(@)6^W=WSNpALw|z!fTzgD-H-nI|I=%`^Q!UUlhsdm3heq@aObML8Z?|;3 zuLwOd>j1n-AczeBFyIFOc$u?y@xc=h{vmVNTVI{cWMYTh#sEN@9aQ)KN zcNNBFw8JTu!f=t|GsSWX!-15PkQjzZc{7)=!P&H0P32mJ3hg=-+aHqGyE91vgiY9S zjQ@2x^YZ76ghu$dnrgv<@RPFmaa(pMt|ZN9IV^`Ib6&_@}n=NmVN(eCB>?CHs3(j+FVB!eB8o_~^+CG(w#WI8- zM~h4GycK);TvdU%&Mhyk;*uy0x}~TeqH3&$wAB(flS5ovxb=XMwex%OOt%^#N~gDH z^^aD*_1enntgJ~mU96Wneoc9>R*RDT>`BsB43E|DKI{Xnvg#+qSUlsjC698zJ`8LdZ|y>(Z(U4A9>lrJab4;^mRE^>#H06`0woSzBAb9= zcUplJ5(|@8k~hxY!q?GTDuhr7BB?d(d;NZWz%>8TOQjcm(J0`CH$fm55wYCyZNdEW z&bzM@4@K2YA@qD4oNjMsCg!q&yAN{a<^buFpRH#4|H9f}3XZ?CFH1H*f4Zx#JtU4) zo#@T0u5d=gSw3~0#j*c*o#AnN&v|jA@E!SWYUD%i%`!o74aLylRs)pt1BbZYUT3)4 zXBOPAP^6PAk2>|O&u(z{)UM76w()!@mf#7=MVda>d)?hgxzMLl zobpsTkt%@psyA|;wPN2w3O^Wef?6wdmU@C$s6Tp^Bmo%1=)5$glem`{SN%H9fauVrL<=DgwIop|YFS;=$EE9oF zSEszSKxl4uj4J|J=>Tw3vOaCbedR{!Ntbp;7BoyOCU2NWTTJr3g7wMQq6t)ai?g3jYa zT<(X9T1WFo$JUBS)!O@9bJ5fxKh@CtwB>`c8-HfHs)Di J#T?eIVNl>(;Dba`o5!5B=(kiK)qSjjS zEU^|X)fS~1>DY%V%1|cWymOp!=H36?bMHO>`R;$dd;W7jD|0SxAmDG42Do&p3qsk& zz8__~7sdf#EiT%csF+$_QuT7hVQ!;+{a^uJ*!wB1{B3H2(aU$^Q??Q7 zvS_N-6Jx0yzpS6fs!Ox#>qua2sLZU2^cHwybAX3;jykz(Mmp(_1gZWy!Mks zhNLhN5ol4%=vZ}Np95XW|RDij7N8OM*)TBxMv|pVhsinPf%C%g;``zhEpkO*Pp;-RAsCleoI& zrgxU1xl4HzfX@u=Krp94#0|hd8G9W6A$@_(c9aVM;Ab=T^$WzJefMc5*!1DrPm4Cq zD2bAokc?V+OPHPa{U8sc@SFH#!8@&Egx!|Sl=O}=)`FTwqh8~pFtzO0l3=wdpO+3s z*K)JTZT0E}pKdHKMoDgzobvFZF^_b2D#j>JJ+qFuP$>``{0cLDiuc%+DNB1XZ8PB- zALOyCqrviUnaEM=En~}(LR}}tKN?7m1Sglk(*^TwlyBCA!Gx@QA0cywb73YAr1c$V z|9Q|;6_ES;2O4RZQ$2jxxzLN{U?~t)F4jX7>z6!ytOHsFuCu0CSDHEHn5fHyXzBde z`LOml?5q6}Do@g)2_iJzHwp~so%27V(i{Or_u4qEZ4iIxe@1K$X-8XK-jvki?1Z`F zpJ@&l8=btY36Ac$?YuGVzBd?_&>0`zJLsFWGPwfF(0X>!Mq2KheQ0Fg5K}}9x7ptH z@pSzm`1)1A2ifHq+OK!81KlsC?A{~xl4U54z#jb8#z%qa0J{!)bk!8uK=!&{O$ z9e`2aIFPJZag=sO7O&Tq_n#aNz)50>)I!5~hg>PXj&o{QGuFp0of*T~(U`{0V$1ED zANnbj7o@16a#nABkV|mOZpdoOW<`L;^hj@dkRu^We2GcB1tQp0_`8l7Q9(V83N~u4 z^M!9*#rqWM#ta-SVhRd$5Mj`c1cNbsDM`o6A)qAqgBMq^n809GaDaz%;7fyd_5;7Y zeYzE&1aA@WuX3xHtOoYKP(Fv0>UT!c@l|OkE3OO%Ga)EF+nU8Q(`O1XoJx7PF3zGC z?*F3x!)l=I`GOt~nVTgcajhd%Nw*Z5ruOV+` zsRTE&QR4Xkf^6HWr=4@c#Z3+5qo3NhF|tj4@27M&ghun^vZ-N>!BR?h`3gtwcASVhqSM{?0iOaUn-dua#RVbdhua~-44z%oLR z8?it|Q~u{C_V97KT#{%JEuMsX-*t0`8z2{Rln{v!YRJ^hGte8Uis_S^z+d_hbjtdX zXk>(iy(qq(8z$twzzQ-?9d3Gq4i;n9`39O~*1Q}bqr>5yd7VQx($av~4RS?y*4qqP zlsD~pvk6l>J^MFc-tq9MhzRht@LDu7&M7sGhnN3jYVo}mUKC6gtRSy8ocTIDZwaZJ zl0#n$!bWE&y#cCu9;cEOT^QHT8AMkD)w(4vtTR8my|FCU1Wt1D%&ymGG>~(tPr8J!^)=MeNiXuorq=mY3eo+ve`h)rpYuPu`2Y=B4WqZ|32NCM%mL ziauSb+Z*!`PmP}wjQwe&I(NxvT6g8ldf9|)qIOZMlS#AYqtX*NTgYr>VoF$=qR;m% z`%a)1Q<)e4aj63P7BYCLAm&+E@!7bcPDz19`FryaOeWX1N6N<|g*iF>tzX8kILQ%p zXP@suxjrZc#!)FlpbQz_=+cE4&FzQT4VMKX^c{mxCK4lj@k_s?ukjy;Xu%eVF1R~B zo@IS-0j$H5qbmPFE6?iLEVR4b&6b2(&#E@Lz126%E+7&MX}I%qP)jtR6FzHT0JCG|63BXE-7k^B?az zQylqXswC)MF5uW`^ZuXgH$Fscq)n60Xj12$) diff --git a/OpenDocumentReader/Samples/sample-text-fr.odt b/OpenDocumentReader/Samples/sample-text-fr.odt deleted file mode 100644 index 4258475bd7307de2264d496acb740da63cbcb6b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2134 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 S1OyK+`MGC_8`XpktN#Ez&530I diff --git a/OpenDocumentReader/Samples/sample-text-pl.odt b/OpenDocumentReader/Samples/sample-text-pl.odt deleted file mode 100644 index 2fa2c42e3bba589443dcd22745cd94c20b0e13d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2195 zcmZ`)2{aV?8XseQSwbc;$Vhm~j4TnojH0rQVJt&TB+F!GjG2*rNj1W?WUMtqvS%+( zl;zq+mT)I>O^M8SM6yLD(H-x;b2_(k-}gV?`M&S`&+q%6-*^7!`yp)vh2#K#8U%o0 z>Pcwwi#-?PJ06SorGyiGy@^B|*2kNI4I;p<6RtvoyvbNHG>GU+xEkaWg7+m*pcLOQ z3i5x=_Mi~J(w8owc7E0?004ma(azGzT*nG=9)|ZOVEuf_6lfS8mvy&eU#G4FbvZKW z?zYQ@x-Y}10DkxZCGQ}+p(?NGX(-rOQ*B-c!fXG&zd|Z>c@2EMPsFiK$0+?s-U#}c zmT^I9kBU@?OSoNQPxqP|w5i-*zs8bjWGQ*J%*#!KRae(X&#DdRuLJ$Dh$7f8YgyVe4do)u}1B5PB z>6W=;(xEdNIgMHfsB=(OM1WbG7cpHTu!9}E+qQK#v%8wRsH^|n^!Z0AM)k$YDBWq& zGdDAbhxA*WO?qWhmzO`@R@tmn4!{@B2)|%zCmf$HalBzsFCG;&h~+4Y%GgdL&>&-L zsehAPW$Y)Sv<%g5PB`-5h_P}L5A9FQq3*#Rm~hpyh0f%4$Kc_Vyi$^+O^;`Ju82m* zYv9Xs@`XC`{^QyDG^}#pKX4ynENj4r91tEH6MeYIwm{TTYEe(*Heo& zI<@od_s{vUtLP=4A{Dz94N17f=|O{Wwkp=)~YA>Li~pXp9=!3qYsL1O>WfBX`<8N1?aBnI=`8i0JWI0m&^^b6lrduH7hUGH0^=!eFW=oKTP&20*nf$~>s>RjG-4r}zkJ#!@+^SOHE0_~(IbU7h^meKB%f3k6!_f9Sq zaXDxC`~)gf5&t~Wy3$S`k(kkAV*vixAGwyF!;HutdmE9z=tp5IM!hjsGv%p!^1|BN zyqOhaOCGg^`Wnvw`f%pev+-%8F65(grO9<|6{!mT>{0sIJnN{xGgC01ETS1|OV$8} zYQnhnTPA7MR1O%$^T3{ZF`G3g5Tn=39k^F}xFN$v{^}gL-X7nsARpCbec+d(25iOH zS99n@gLUvmefp?wdV6MGZ5?K+ieMS=+K5`R!D&S!3nif=IpeG|@5W)E&1aRsf(Uu5{fY`Ze!KqTHtoa$f6kT=$)$kB4B5K%UPh*F0s%+synDRgH2>5yic?1 zFGM{8%pYoq6=;HhTtowv959zukO%IfwcB)m_QYlj8O2h_GXK} zX@?Ij4CyDS8A?IBq;um(!J}mkPRJRjS$DlF`nob9&DbgoBsRWI$w?i5fPuY|0z7w7 z%ZO#sS!>x(a|d$sVj5aPkGJhGx; zuI)(cg)TI$HFu}dVRt1{aR}6OQQ+P!ve-F7d4+0QiEYVwz(S%2K?Ims>RN8*Ac_mj zr~dM!;?Z%T5xD(mLo;v9}2(W`X;pF|tehK3GD%PkSVv79Ut{WmS8`FodHc;)|2JCf`T; zWH;QGAZXWspE+BD^z-HJ<|g=9V?| zRV8V1@Up6qSEcIV@lB(~Bmg^2#(ziH!r5TNXWy#y`0D4gI0=(q)z}q~oSjrI!B3!+ zwN*tn@tm}zT$;B{dL;l8N{98ldP3MfF&JMl!yNv(< diff --git a/OpenDocumentReader/Samples/sample-text-pt-BR.odt b/OpenDocumentReader/Samples/sample-text-pt-BR.odt deleted file mode 100644 index 42eeaca0825fef69d82f8d89ead125dea3bb42ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmZ`)3p5ja8y~Z&#jK*yUc(}Cix6#!y~#D#kXuTOx$MHm5UP*#M#^}}*b?S`d)=aB zT7}X@smN_3l#pwTSMtvHe&=*v=l!1ldCv1Z=YM|B|NNfwKhMv>1}G*C_}i2K-tC7Z zRE5Q+ZxcEpkbt8`k#Rm`a!8=B4>gcPJQzXr()0x8-gGLGm+@(m~8h*WJVE|Ti- zzh;|ICBRp~W3g6Y)*%7_$OxnD31_U9m7V!Pf)6p!A4j2TM-oCZ=v>Gn9f`!*3rX}f z*Ck~f%P`ke;SQCtr@y{}(bPyo7^$Krw3Jp`H>66TwAlqj#51tdA6kZ~`xvj??yDK) z-e^NY!(F3n@3uWza33qU(cP^+fl0%v<|qf=w5p{mp$xd+kk`i7I80V1QRbX@cxLN& zkEuUomxkv0i5EU6m8_PTRwyD7 z)$?PgJUMLVCSzm` zZ3sKP)4nf8%>WhO=d@~S_r3(}r9N|y<`L@U9i>=2`6zkODYPqvQ4}U=({`pL3%sA( zBl_|JS>Eo`gZ3N)mlWOQ?gTywbvc&Aylm4 zk@fE%zTLh!@AlQV0BQSRzvSriKIzELFA@8+S}v>NI!}3hTMl109&ugiHcE7`SV3Y$ z+qDD8h5D~dP2?=}5sA2D8Y^iPF&W zCfQaVo&X+cesM$UtUrV>qTd(9h&A5uT~@!)f_7`FWs839m#M@e05HQQMoF1A?kLN@DhT zTCbDqS^uzW=7o*YhY^i}Nnj7Gx%xIU>2_p){?+KvcNRxmj_1?Di{@$z!7}eaA7*+Q z)X|dI`Bv`J>i*J8F3%S+Y}2->jBtcy+|c?eHw?N6-;O2)%#)c!B!x_6~|N{fi+C#G=t_9I{@_sin5U^0{hEj ztGi7W52#^7;j#*#MKPAZZ8g^!$gJeTKFDQ&c+65|sTY+ZoKKUo2kIa(*)>e>JjY7M zqBYf%Wy38H!f1@yxUT-IAn7xQufttLvh_w%)O*gEVz^!E;*Y0c#_2(=g6YxUzFzy& zB{gFBEf#dTU1K`N$eMwW-ro)WV8ELzzr`*&fdw%RtnjAJef3iXwG@qO| zS6}ByCO|T`tK#oz0#xXRs`*%qQ@{6@{ z^WrkkGJPliNWvp6mo5W{f|@ij4JPo!^7xTT&Fl=m6l#Kb9XKAEi_B7AtDd^5~=ZnS@1Mk#1-mLgH^>)#x>2X zUyRQ=Dj(@Xx1oxQf}=l+@CqB0Jr9wLJ5^MITk%s%>pVG5=vR)pWbb-!#mK^l{nPi{ ziw-s-qSCm#Z0N5h7!t`I|a%+pNiu1FDiSX&4`m+_c db$kBAm5cskmpa&hz?+w1!ZRt1hs8ImzW_d-j5PoN diff --git a/OpenDocumentReader/Samples/sample-text-ru.odt b/OpenDocumentReader/Samples/sample-text-ru.odt deleted file mode 100644 index 727f2cfa2f4be226e8d1e1e74a9b13d3d97bf2bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2401 zcmZ`*2T&8r7EP!TP!fuO2qA`Mc!Xl26r~CX2qFJ3Hs@-a9*cj)f^ZhY;Xzg8{B~tMbXQ z7W)&#n%*AXSYjX^>x{>Hd0cZQdida!$T(M|kF%eLAJPYp#ku-iBY9(SL?jU#K(zQ@ zvVABF@NJ`mqlFdq0097DmNzrFq^oFbZm8t#jPr2A`Vo-<-d?FmZ9MJDe36SmF-hCj zYtq>4Q@J|OJYvS-@u!b78XNq@)#Q%ND#A8f_V~*V`7izuC--q#)+nB$z%$<3ypUJR zP3V$5M6wPvtMBUkab>z7VQ>&JtC_4TmnrR$X#6Azb`0INDtYhoc5_yC8cx`Wo0QhF zW4llzx<+3b#|3?fDcvmBc`PL4)|xq*9CTAXIa&bu>$}+tcv}JfnHd@{W9Y*G+c)i zxao@m*ndhky9~~FJMo6w#NL=?WoZ{^5MnwI^D6$McTgw|9{K|tV!3{ajFt-s_ zGdc9k_cG+dSg<_$*qt%UO&#;$QVn~=_vik$1pBLjQYG{4u`8B@f%uGK--D)I4y6yc zWZOpAUh9kGD~hs z7II2`cV~1pCv4f~+qD8ovnJVtOxl=GK>r*Wu1F1+!}eqBSJz3qr$1T$98`<6F#0K} z$<~c@#}}dA=xB=>p~NHm+#J@K?t24a@!c`E`Um_nmOd;Y(@zx{U|=#UHlcTDgH!y% zxSt(8lhvVr^qTKhvv52o0I&uD0C-uwzUG4??!QA;vny@rxG6)S<^fFH8)z+=`gVQj+w0ex<5$&d3bFUCTwhg78b% z&otazDNg-r)wG6WFi#EHHZar17@}G?GJ_s=N{BDdP3|&ai)Rm&bzdP;f)JN)@NY(2TIZ74yEe;$;GG?Pka7*CKh_ zp5fG5%_=RzBU;i_YgKIvY$`d^D90{pt>`H5K)Z} z*v2}S$Resqpps|g#}}W6&?OsY-K*qW(*Z&zsjlAl0Plp-&?&cdV4+F<%{XVmgF=CW zx=`0N)1e^8U$Rk8s>l1&L)5L#h?Oa9N=@5u&g;?TTWVfQHh+!JGj#V;XE#bZ+Sg3c zUs?lUFb^KI-Y?cr1<%`aDd#Xoqp0IGv*vFi_=eu~{wi)oLz=qgJZ+Hd0TW4rM@kh) zWptiln9`?_6F{ieK{aP>Dj~7y;WwM-4@q9bd0v$M>RHkCj@RtpR`4=lE!|QH5*Hax zia19mY6$)uDX^JP&e44mLXw@

j8Vhn>h(jU?*9pvSXyA}ykk{B1eKh5%Xi@-qow z$#_90HZ3SR29g3k8FVNmU9i!>Juw>9xKO?^E9M`Oyv*42eFbyR+F;u9*Q}Ovqj@+U zCdWpZ-Rhhmft|(j+_BH1itdbtf~w)b`qn+YR|FA!aN?3c;_-gzQV>+M7re6_ z{o!naMt!|<39ndU(j2E z8OqGgQuVb48=NP5EOwiW8@d?377Ej+|csdsBDg(dP$H*Z1@t(bGL@i~1fiq1=Duow zw6+-Tso`xw{p5q!Y2+OIIlAGmdGXBaa`oW^lGT zCNQ8>mH9n~Cf@g(lI!_XY?{@d(0!;{SoFY}eEuOD=T9NcNCD%Tj!T&-X|{sSw9>1w zJ)DjQ$_gf=?L(><6ae>fg1*-xvU(5NO5<|5aK1nc`1!{+&Xbb@Xql{uB2n(fr0$u>FH} UEKE7M_BT0LW1i)m_pc845AsG1zyJUM diff --git a/OpenDocumentReader/Samples/sample-text-tr.odt b/OpenDocumentReader/Samples/sample-text-tr.odt deleted file mode 100644 index e2a5862adfaeedd3d2e580cc4bde21072f4d85a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2092 zcmZ`)2{0S#7LKL#p|J%eVkZQteZQ982H}Z_+BKzwq==B%)l#jtJX+c+B`vM(+AeB) zweL->Ppe8*Ep6>WseQTe?wc{!+;{#tbIzH6zVpv_=AZMSEm>GWfIm$VfbCM_f-;I@ zKg)1Gf*+0&M#8z1NWKIQcM8Fucp;eR3HNs=6UcCX5{~HU?-AsOBU0cLTqp(ozh=i! zNxt+G~1Q^i@aoI!}i88(5=T0Pe;m8ztsGslSlva*56|Q)CL_*4*{ZAPj zRr|TIcs3zLwW{p4=%0 z46+Zis_E?b;q>)o^3V`$PCwNInkhrLkE~3Ql+tY75WDwnuPKX~Mig*k4@zs^cU~+% z|MTU_jxI{t>T+AsZ1shb=^U=7E4tSZL_3-hcvFr@hWZ%P!c`aAedgq$H zYNy6wVrD2QJ*vZgdPXQ{6Yy8Yc)kP4OANN7EC2upgE5&B=8GdA(@e7MA+}5KG|VdU zgiOmlsgXy)?ff5yLPb(DTxR8g^$bmO3lO*4yT^Zz zIyGyv58r(pSpfiZAOOJ0n6-yLk#hVG8N)7h=p%kI3?yyLNhoAjN)%A9Jg9J1S%AF44ZEk9!EEzT^Q>ZE;iYG(!kj zbo1u>_SJDwaOC1w6>YaG%CtnNU0vqRf5t!eHtTsRcE_@prOpd~LZb4tIriSU%S=oO zfAl&p1)rLKZxF|ty|l5E+7&X~Q?m%^n=j=sp?=ES& zOjyvNo*k{z-E(jii3aKesf9Le!#{_hd)3yiy+Wk!-Zx5R`KBWJ$f&y9)e(q6lTORJ zRMS@0MenThQ}+*euwwUA8v9=@Hl6+Qv_wy};dyvl{jQ*aUx`#$)vcMt+2wljCKuXc zX){8;SWz8yPc~6p)i)GRC#+v3cNeBEzjl*o`M8DfSjuta*tR~^$2v`v z-STQ0m9Lo;9+0iQNVc~Kciah1n(Bp>ogw#i#an4A3@tl*cfg8Bl1T66-F+}ZsR@3K zJ{j8m2rD&;{sD%Y{8E09INk@z<^@hjx`@Utg`~cic6(Fl^lA-I!1S+NdV;dK7ev(j zi2L_Yx12byk^*LMxve3~x6zVl@jz+MR>4ORfvU4Hnp=9`B*3?OZ{5brdv^QQCuC~$ z;7ybYoL`u)l{4Qxc!tf}@1@Rm#t8RiRp1Q9K)5Rld>J{yncCoU!=!mxDyoX*y9qsQ z-*5=Qmq*HlTzb;#q*;X@S(OW)d#*y&1jw1T1XE75Va)AMmMDU z=UVP1hzK+!7a$E9FSR^GIM?=J$}@hmpz`teC$_zCem@*m?9jidK0Yg9eJSvwV{mG$v1~(WoW~pz?Lp!Xf)+@bP3*0TDsi>yrsS^rj1PSra|n`~s9;>o1 zni@Af4f(ko*hb+5%C>5u30mZM{llw+2{LC-h!#B_AmdI3g2Ua_W7$ER)(RKU54u&* z1)|t!4hH~M91-)<26VQTIm)=%MOm!0l_WqUU|WA|$Fmx~7vBesgFj&?V^CpVU&(UwfiAeR5HmW(a* zU(01kz=?LAp#EMK|HJ?QxlC4!^lwG-bc@qEbJD_y@$`x6oW`BrnJ2hn=D%!EwB;GL P<4ab?SztsZ_T%ag-`RLB diff --git a/OpenDocumentReader/Samples/sample-word-de.docx b/OpenDocumentReader/Samples/sample-word-de.docx deleted file mode 100644 index df39df22f803ae530d7755af0f03bdfa2c92eb44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2353 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 X-gT_adBEGZ@NjlL4qy!L_SJs?KVPz` diff --git a/OpenDocumentReader/Samples/sample-word-es.docx b/OpenDocumentReader/Samples/sample-word-es.docx deleted file mode 100644 index 0d5b33548f3d6393b9c8e77a7db132d535411c3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2315 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 RzP%zUI86nBMPlEc{sOAe&g=jH diff --git a/OpenDocumentReader/Samples/sample-word-pl.docx b/OpenDocumentReader/Samples/sample-word-pl.docx deleted file mode 100644 index 21c73b5a91933c78971f124b6a4772d1e51f785d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2391 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 UI>>;&Zjlk6`^A98vR|M64O$h(ZU6uP diff --git a/OpenDocumentReader/Samples/sample-word-ru.docx b/OpenDocumentReader/Samples/sample-word-ru.docx deleted file mode 100644 index 04a31771a80995be038162e8ece81f4a92ba9e00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2573 zcmaKuc|25q7sszo8WcmAktKyNcKI1=%91V1$XLcQq){gpB;A-|y*Fc|Ff_@9TTd{o|hVy6^Kkug~XLp;%Z2007v>IER51 z)7HpM#v6he0Qecv(I5aDg2slpp1}vAan46C`TLcn)LXnz5{PweKk1vMu5>6m_2QHY zvjLtUwGFFWF-KxC6XGN}F{^7az26ik73;^L*@Bl%{jPtSD#7aBw$nSP6S7iswFIjd zXk6Y4wiGjKt8l0tljBQFU8lC(!!_JV9W>#t<4(C^{q;7K7Hk%kR5THE2tTf>b{h1M zJSX2HR)Li$>d5JuS+#nSAr_B_dghvRtdu3GS2U(>KKRqRnrW!yfHZz>#apsGf$5!5 z>ti~n`g@nxFJSq9G`PR+nNL7PL=y|RedbK7zBSTXyD1ySy&5{T?E(VI8Ny*TNH}-0 z>rQplXV3WE$o9VNn2e4|mq=!--x|d-h>EUYG)RF705}-YH5l!OQ#|_pncUOJeO-wc zn93n}V>7NtDaW?Do7r0?nNsIr;2Ptw~GH2mk`n5h;8C9+H?)kwJNX*LVUMnT;1o|sUujh|JO>7!4$N(fDD*N7?$=a zA))n>Fnw_LGkW-K4JLQ@d`JtO`eY=vaD8ks3WC7LM*$_=QD8PRgp6LrS~eD z%{ZN1`#~Yg-#G<6jM)GNV;ke}{NTie;Qi3J?|f*hPR5k;($l;@4II7!F$yh(oQda{ z0VFDhE!@e9cyoiza6h%UlI&%XPj7Bs2-~bG)F?F>)#TpD5)yqMoiUmWotU%;?QFllmYIw{uR ztzc}K@$wLonpeUt8%(M4H<71Ztog9WXPe zT}g+!m^v2@O;buH*Wg!2oNw%6pYAgK-Yj(P$(A5i0N~{Xfc-z3_3Jnc+KpkyjCps` zKo7;N)1BLoBj(BiK#-?9fJ2@l0S1Bjs$H$}gvGkG7)LR4L10F%ew0ij*CgpLEj<8wNIn+S&=82x^i=E{PNfL3hemBRJ?1yu@6XA%8A3Grf-| z&gso76m%?ZhvKv}tXj5@Fh#Do`ADr-`PdRTSTwOqBSgg3Y-6qQ?1Eb&J4=qIxLdBR zFdxB$P%lz2`J$OugF+m@g817Wz|Hx;>DK1YFH(`bfr(G>3eU9*TMzUh`L21GWujz2 z!Lc=VEFY*g`8#Y%^>+fD9KC56eHnIr-TU(v=-NY_BFw|#ZANZqI%w>5to9~PSUC^N zOiRk>eo^q0V)Dymc9w*Vg?N!qdGSreH*l^+2TH-i?T1YfN^`~u=bl!Ip2yNH2b^J& zx=b{EYIIlg@-?QrK^!8$LNP!&GG;K)=e(J9kF?n(CPKK74yU~Y$>ot^OKcMM;?dfr{z)c%l`;J})Ns4EWu?xm3zFjn z8_!;rgI{lvjJKks?`7(bS_ECLFw|dII&wq2-4;Wdy)~;{ku%m8(3+Rbbq-h)8&q)r zfY#0_I8fMkZolP*sfE$4tmkM1%96v^SnDj$wRgVUSbKKjpB~zlnB>8h%`F=bx)-_b zqWEjvLXp9Kvv2E_4h{(;`^w33LPlW_KUZ?QS5;uFeh?crmH#0wKGXMD0+)=xT!VRX z|Bw!;eatpIkP!75Q=H=| zGLy}Zvft$9&L3HNAYl{{`o(4Si%l^IG2UaYNd361(zLB+g<@hBVENyR3qz#-zK9HY z|F3Jz-U53K{hxFIATr4@O8jE)dlUB>=FdcC#uD}a>~n9Wy_WQ|(&CRwKMiVc@?MGl fnJml@?!SNISHZSIfxzEC0Woe}24L;?{SWvHFiS|i diff --git a/OpenDocumentReader/Samples/sample-word-tr.docx b/OpenDocumentReader/Samples/sample-word-tr.docx deleted file mode 100644 index 548a3ddc83f52ce73767734f61d7a307e622e40c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2335 zcmaKu3p|tiAIFDG%{3XN4Iz;+Bvi~T&O*X*k_;7diz#;zW46RBM9V>LvpFNNQ!BTW zODv|jb#s}!lF-RDx3m7|^s2o6|Nry6e$V%LUa#l-eLe5*>-+nB9y@D+ZBhULU^{Q^ z1I$@9#4hvhVEh2UE?#so55$C^F(K}bk(bcHu9^`6{&&-AY#X(t2=2{CFJ>BODI}za z4e9WkM`D#$l`H2?A~3##ax^ulT^zo11I~rl3_xIMm#j3>8qV2z=LMDQ2aKw_q%L*eQ#zdKWaipl=nb*t0)!e$GenUJ~D! zMMK$|h{3qq^G4;O6SWtfzj&8q9g{#Q7W135VrVcoT(?+$yPp~*&}*Gg!E2BP9{?cCi|#>a|6sW0*K5j)I8iSv1342RrH|8EbJ}sw%pMw>pa0nVo`- zzlz}s?Q0Y8Jir-iDQ^MK@dU=Usm4-E2z|3l{)=n)#g8-}k_@Gog4s6k5t zI8=9PC+49q^f<*=W@ok4RcxwT_qpE_P*SUlK$If{5=&Z**`P+jZVhOsf3h`kJ^h5E zW-Ln+L=n2Z#EI!4MfV2_u;3llOrH)P^mAj~Y!jFgXq28YvWD1#9F4$Y|p-HAdApakmGgX z5rBNfYugJfc;rd*?^++l5?J=>XY-!o?1oGPy$RO7?T%2QP zcAztYW&leXs^GGXiknsa82$Ff!M7biMjpy4=rlcqDwzwE*Px1wwtC5<6Wvq`r!k@* z-iEco{DhkAu6&{Z*L1Igi1#kz)#)v)n&a$#r5$&V7#4QQ+nak)i;C0;JkPm?b~SC{Z-?QhZck4^AfLX-%9P%_Dt)6RC# z=vxpsD_82vVGf-;uYUE7>$OeH{Y}1~n|03hPYg}~0APp!06V`m>&J2EC9_F=dJ-+} z=zME92_5yYBdl^z!BlcgGT)?ouw~?o;&FTa6Ormh$a{#HH)Nv~m5))O$TuHcm3@+W zjCM<_cFD%9d(F#FO|bLu@rU=QTh}F0M^9{{+;l+ZY8GbPHzl-lHY(LAs+!s|EY9;ccpeV%b6VS|3LIkD7dR$$3aIIGgcjuE!@%^#MA zwNYR0h)1`B*t@Iiw}Exzi6Uj3UZCL8gJQky#icID8fX-j#))6-c|lm3?y0>hp`&*r zG3~i`K_Bv6*nrVFfdQN?GF9K+Ojai&Dt{XMbS!ll-qdK{Cwx>Tj)iaa4BDr)@(czRd^F@Y>9IPbIjjD-R>Sl5 zBrZNgeEnIfG+%v>q{EwoRkKmjIq*~MD<7+wWdKpL)01ns>Jt~o_cveS#}iN;5d}|R z-fXO~XQSEYo8o?6>o!SAm=-!D-!Ct+`0cB`F&YL_Sqt`OVG~m*>}K?Zp;^{ZX`yRL zbctLyns~v$$2%;|)hD8Nb~jE64DL)MD>k4G>w)&dbu#8SF;DtkL{>5aI&kxAO%&sx zvZHW8hjDY2`|Yhq_9*rpFh2cmzn6a+gBrE4$Y_(5Z~C$;s-XyCyASTj-6iB`(VC4A ztoR_g=$bz$QR5TPI{A9hu(ckcy&}G{J*aHj$y;(Frqw^^{qcdoHTz56)zA+@s;qki zai@sOW)M-$xjWHEh5vf5MM1?{jddtgyISY$0fDL;>5b#(8G*;1I*brp9p4AWT#J64 zXB(TR}EdA}9^ y&rr5j+A7lDD@}c?^j)&ICT|t3@5wUT{{4&}CCtuR5cu^KLEdS?17rz(efk@jl;S}E diff --git a/OpenDocumentReader/Samples/screenshot-names.json b/OpenDocumentReader/Samples/screenshot-names.json deleted file mode 100644 index 93c52e7..0000000 --- a/OpenDocumentReader/Samples/screenshot-names.json +++ /dev/null @@ -1,290 +0,0 @@ -{ - "de": { - "files": { - "application": "Bewerbung", - "cells": "Umsatzzahlen", - "course": "Kursfolien", - "deck": "Teamtreffen", - "expenses": "Ausgaben", - "hours": "Arbeitszeiten", - "household": "Haushaltsbudget", - "inventory": "Bestand", - "kickoff": "Auftakt", - "lease": "Mietvertrag", - "letter": "Brief an den Vermieter", - "manual": "Anleitung", - "meeting": "Besprechungsnotizen", - "notes": "Notizen", - "paper": "Rechnung", - "reading": "Leseliste", - "resume": "Lebenslauf", - "review": "Quartalsrückblick", - "rows": "Kontakte", - "sheet": "Budget", - "slides": "Projektplan", - "stocktake": "Inventur", - "text": "Quartalsbericht", - "ticket": "Ticket", - "travel": "Reiseplan", - "warranty": "Garantie", - "word": "Vertrag" - }, - "search": "version" - }, - "en": { - "files": { - "application": "Application", - "cells": "Sales figures", - "course": "Course slides", - "deck": "Team offsite", - "expenses": "Expenses", - "hours": "Hours", - "household": "Household budget", - "inventory": "Inventory", - "kickoff": "Kickoff", - "lease": "Lease", - "letter": "Letter to the landlord", - "manual": "Manual", - "meeting": "Meeting notes", - "notes": "Notes", - "paper": "Invoice", - "reading": "Reading list", - "resume": "CV", - "review": "Quarterly review", - "rows": "Contacts", - "sheet": "Budget", - "slides": "Project plan", - "stocktake": "Stocktake", - "text": "Quarterly report", - "ticket": "Ticket", - "travel": "Travel plan", - "warranty": "Warranty", - "word": "Contract" - }, - "search": "release" - }, - "es": { - "files": { - "application": "Solicitud", - "cells": "Cifras de ventas", - "course": "Diapositivas del curso", - "deck": "Reunión de equipo", - "expenses": "Gastos", - "hours": "Horas", - "household": "Presupuesto doméstico", - "inventory": "Inventario", - "kickoff": "Inicio", - "lease": "Contrato de alquiler", - "letter": "Carta al casero", - "manual": "Manual", - "meeting": "Notas de reunión", - "notes": "Notas", - "paper": "Factura", - "reading": "Lista de lectura", - "resume": "Currículum", - "review": "Revisión trimestral", - "rows": "Contactos", - "sheet": "Presupuesto", - "slides": "Plan del proyecto", - "stocktake": "Recuento", - "text": "Informe trimestral", - "ticket": "Billete", - "travel": "Plan de viaje", - "warranty": "Garantía", - "word": "Contrato" - }, - "search": "versión" - }, - "fr": { - "files": { - "application": "Candidature", - "cells": "Chiffres de ventes", - "course": "Diapositives du cours", - "deck": "Réunion d'équipe", - "expenses": "Dépenses", - "hours": "Heures", - "household": "Budget familial", - "inventory": "Stock", - "kickoff": "Lancement", - "lease": "Bail", - "letter": "Lettre au propriétaire", - "manual": "Manuel", - "meeting": "Notes de réunion", - "notes": "Notes", - "paper": "Facture", - "reading": "Liste de lecture", - "resume": "CV", - "review": "Bilan trimestriel", - "rows": "Contacts", - "sheet": "Budget", - "slides": "Plan du projet", - "stocktake": "Inventaire", - "text": "Rapport trimestriel", - "ticket": "Billet", - "travel": "Plan de voyage", - "warranty": "Garantie", - "word": "Contrat" - }, - "search": "version" - }, - "it": { - "files": { - "application": "Candidatura", - "cells": "Dati di vendita", - "course": "Diapositive del corso", - "deck": "Riunione del team", - "expenses": "Spese", - "hours": "Ore", - "household": "Bilancio familiare", - "inventory": "Magazzino", - "kickoff": "Avvio", - "lease": "Contratto d'affitto", - "letter": "Lettera al locatore", - "manual": "Manuale", - "meeting": "Note della riunione", - "notes": "Note", - "paper": "Fattura", - "reading": "Lista di lettura", - "resume": "Curriculum", - "review": "Revisione trimestrale", - "rows": "Contatti", - "sheet": "Bilancio", - "slides": "Piano di progetto", - "stocktake": "Inventario", - "text": "Relazione trimestrale", - "ticket": "Biglietto", - "travel": "Piano di viaggio", - "warranty": "Garanzia", - "word": "Contratto" - }, - "search": "versione" - }, - "pl": { - "files": { - "application": "Podanie", - "cells": "Wyniki sprzedaży", - "course": "Slajdy kursu", - "deck": "Spotkanie zespołu", - "expenses": "Wydatki", - "hours": "Godziny", - "household": "Budżet domowy", - "inventory": "Stan magazynu", - "kickoff": "Rozpoczęcie", - "lease": "Umowa najmu", - "letter": "List do właściciela", - "manual": "Instrukcja", - "meeting": "Notatki ze spotkania", - "notes": "Notatki", - "paper": "Faktura", - "reading": "Lista lektur", - "resume": "CV", - "review": "Przegląd kwartalny", - "rows": "Kontakty", - "sheet": "Budżet", - "slides": "Plan projektu", - "stocktake": "Inwentaryzacja", - "text": "Raport kwartalny", - "ticket": "Bilet", - "travel": "Plan podróży", - "warranty": "Gwarancja", - "word": "Umowa" - }, - "search": "koszty" - }, - "pt-BR": { - "files": { - "application": "Inscrição", - "cells": "Números de vendas", - "course": "Slides do curso", - "deck": "Reunião da equipe", - "expenses": "Despesas", - "hours": "Horas", - "household": "Orçamento doméstico", - "inventory": "Estoque", - "kickoff": "Início", - "lease": "Contrato de aluguel", - "letter": "Carta ao locador", - "manual": "Manual", - "meeting": "Notas da reunião", - "notes": "Notas", - "paper": "Fatura", - "reading": "Lista de leitura", - "resume": "Currículo", - "review": "Revisão trimestral", - "rows": "Contatos", - "sheet": "Orçamento", - "slides": "Plano do projeto", - "stocktake": "Balanço", - "text": "Relatório trimestral", - "ticket": "Passagem", - "travel": "Plano de viagem", - "warranty": "Garantia", - "word": "Contrato" - }, - "search": "versão" - }, - "ru": { - "files": { - "application": "Заявление", - "cells": "Продажи", - "course": "Слайды курса", - "deck": "Встреча команды", - "expenses": "Расходы", - "hours": "Часы", - "household": "Домашний бюджет", - "inventory": "Склад", - "kickoff": "Старт проекта", - "lease": "Договор аренды", - "letter": "Письмо арендодателю", - "manual": "Инструкция", - "meeting": "Заметки со встречи", - "notes": "Заметки", - "paper": "Счёт", - "reading": "Список чтения", - "resume": "Резюме", - "review": "Квартальный обзор", - "rows": "Контакты", - "sheet": "Бюджет", - "slides": "План проекта", - "stocktake": "Инвентаризация", - "text": "Квартальный отчёт", - "ticket": "Билет", - "travel": "План поездки", - "warranty": "Гарантия", - "word": "Договор" - }, - "search": "расходы" - }, - "tr": { - "files": { - "application": "Başvuru", - "cells": "Satış rakamları", - "course": "Kurs slaytları", - "deck": "Ekip toplantısı", - "expenses": "Giderler", - "hours": "Çalışma saatleri", - "household": "Ev bütçesi", - "inventory": "Envanter", - "kickoff": "Başlangıç", - "lease": "Kira sözleşmesi", - "letter": "Ev sahibine mektup", - "manual": "Kılavuz", - "meeting": "Toplantı notları", - "notes": "Notlar", - "paper": "Fatura", - "reading": "Okuma listesi", - "resume": "Özgeçmiş", - "review": "Üç aylık değerlendirme", - "rows": "Kişiler", - "sheet": "Bütçe", - "slides": "Proje planı", - "stocktake": "Sayım", - "text": "Üç aylık rapor", - "ticket": "Bilet", - "travel": "Seyahat planı", - "warranty": "Garanti", - "word": "Sözleşme" - }, - "search": "sürüm" - } -} diff --git a/README.md b/README.md index ea41752..d1e0754 100644 --- a/README.md +++ b/README.md @@ -179,11 +179,15 @@ worth what the build it was taken from is worth: bundle exec fastlane ios screenshots ``` -Four pictures per device - the onboarding pages, a text document, a spreadsheet -and a presentation - on a 6.9" iPhone and a 13" iPad, in the nine store locales -the app is translated into. `hi` and `sv` are given the English set, which is -what those storefronts would show anyway. The documents in them are localized -too, and written by `scripts/make-screenshot-documents.py`. +Six pictures per device - the folder, a text document, a spreadsheet, an edit +under way, a pdf and a Word file - on a 6.9" iPhone and a 13" iPad, in the nine +store locales the app is translated into. `hi` and `sv` are given the English +set, which is what those storefronts would show anyway. + +The documents in them are localized too. They are not committed: the lane runs +`scripts/make-screenshot-documents.py` before the build, because they are build +output and nothing but a screenshot run opens them. Building the app needs +none of it. Nothing is tapped to get there. The app takes `-ODRScreenshot ` in Debug builds and puts itself on that screen, so the same picture comes out in every diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 98f2a63..2032f7d 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -23,6 +23,7 @@ IPA_DIR = File.expand_path("../build").freeze STORE_LISTING = File.expand_path("../scripts/store-listing.py").freeze STORE_SCREENSHOTS = File.expand_path("../scripts/store-screenshots.py").freeze FRAME_SCREENSHOTS = File.expand_path("../scripts/frame-screenshots.py").freeze +MAKE_DOCUMENTS = File.expand_path("../scripts/make-screenshot-documents.py").freeze # Where snapshot writes, and where the framed set goes. Neither is committed: # a picture of the app is worth what the build it was taken from is. @@ -142,6 +143,12 @@ platform :ios do UI.message("photographing #{devices.join(' and ')} on iOS #{ios} in #{languages.join(', ')}") + # The documents in the pictures, written rather than committed: they are + # build output, and the only thing that opens them is the run below. Ahead + # of the build, because the target picks its resources up off the disk as + # it starts - a file written later lands in the next build, not this one. + sh(MAKE_DOCUMENTS) + # The Pro scheme, so no ad sdk is linked and no consent form can come up in # front of a picture. The two apps are the same app, and what differs - the # banner Lite carries - is not in a screenshot either way, so one set of diff --git a/fastlane/screenshots/README.md b/fastlane/screenshots/README.md index 86f6d5c..aa73e1f 100644 --- a/fastlane/screenshots/README.md +++ b/fastlane/screenshots/README.md @@ -46,9 +46,10 @@ Eleven in the store, nine in the app. `de-DE`, `en-US`, `es-ES`, `fr-FR`, `it`, either - that is what those storefronts would show whatever we upload. The documents in the pictures are localized too, which is most of what a reader -has to show: `scripts/make-screenshot-documents.py` writes them, they are -bundled into Debug builds only, and `-ODRScreenshot ` is how the app is -asked to open one. See `OpenDocumentReader/ScreenshotMode.swift`. +has to show. The lane writes them with `scripts/make-screenshot-documents.py` +before it builds, rather than keeping them in git: they are build output, and +they are bundled into Debug builds only. `-ODRScreenshot ` is how the +app is asked to open one. See `OpenDocumentReader/ScreenshotMode.swift`. ## Both apps get the same pictures diff --git a/scripts/make-screenshot-documents.py b/scripts/make-screenshot-documents.py index 86f8034..350440c 100755 --- a/scripts/make-screenshot-documents.py +++ b/scripts/make-screenshot-documents.py @@ -14,8 +14,9 @@ python3 scripts/make-screenshot-documents.py python3 scripts/make-screenshot-documents.py --language en one of them -Rerun it when the wording changes, and commit what it writes. The packages are -byte for byte reproducible, so a rerun that changes nothing leaves no diff. +What it writes is not committed - the screenshot lane runs this before it +builds. The packages are byte for byte reproducible, so a rerun that changes +no wording writes the same bytes. """ import argparse From ae5c66b35dc42ce3c8c635209f7e6d9f77396ab6 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 17 Aug 2026 13:57:39 +0200 Subject: [PATCH 3/5] Have the sample wording read by someone who speaks it Eight native reviewers, one per language, against the English. They came back with 87 corrections: calques that read as broken sentences, dropped clauses, wrong register in the contract, European Portuguese in the Brazilian one, a European VAT label on a Brazilian invoice, and a missing dotless i in Turkish. Three of them were the same fault in every language rather than eight separate slips. A clause of the risks paragraph - "and is being chased" - had been dropped from five. The lowercase second sentence of the first headline, which is deliberate in English, reads as a typo in French, Russian and Polish. And "Billed to" was calqued on three invoices. One was ours: the contacts column headed "Role" holds Design, Support, Sales and Engineering, which are departments. Every language had translated the mistake faithfully. It says Team now, and the three languages that used a first-name-only word for a column of full names say the full-name one. Every language also gets the six months and forty rows English has, so the spreadsheet is the same document everywhere. Their labels are the reviewers' own, and no language repeats a row or a file name. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E6tn8P25cBDmrA67zrhfwN --- fastlane/frames/frames.json | 48 ++++---- scripts/make-screenshot-documents.py | 176 +++++++++++++-------------- 2 files changed, 112 insertions(+), 112 deletions(-) diff --git a/fastlane/frames/frames.json b/fastlane/frames/frames.json index 98096a0..c8637bb 100644 --- a/fastlane/frames/frames.json +++ b/fastlane/frames/frames.json @@ -52,11 +52,11 @@ ], "es-ES": [ "Todos tus documentos,", - "en cualquier momento." + "donde y cuando quieras." ], "fr-FR": [ "Tous vos documents,", - "partout. à tout moment." + "partout, à tout moment." ], "hi": [ "आपके सभी दस्तावेज़,", @@ -64,19 +64,19 @@ ], "it": [ "Tutti i tuoi documenti,", - "ovunque. sempre." + "sempre e ovunque." ], "pl": [ "Wszystkie dokumenty,", - "wszędzie. zawsze." + "zawsze i wszędzie." ], "pt-BR": [ "Todos os seus documentos,", "em qualquer lugar. sempre." ], "ru": [ - "Все ваши документы,", - "везде. всегда." + "Все ваши документы —", + "везде и всегда." ], "sv": [ "Alla dina dokument,", @@ -100,16 +100,16 @@ "read and searchable." ], "de-DE": [ - "Textdokumente,", + "Textdokumente:", "lesen und durchsuchen." ], "es-ES": [ "Documentos de texto,", - "leer y buscar." + "léelos y búscalos." ], "fr-FR": [ "Documents texte,", - "lire et rechercher." + "lecture et recherche." ], "hi": [ "टेक्स्ट दस्तावेज़,", @@ -117,19 +117,19 @@ ], "it": [ "Documenti di testo,", - "leggi e cerca." + "da leggere e cercare." ], "pl": [ "Dokumenty tekstowe,", - "czytaj i wyszukuj." + "czytaj i przeszukuj." ], "pt-BR": [ "Documentos de texto,", "leia e pesquise." ], "ru": [ - "Текстовые документы,", - "читайте и ищите." + "Текстовые документы —", + "чтение и поиск." ], "sv": [ "Textdokument,", @@ -137,7 +137,7 @@ ], "tr": [ "Metin belgeleri,", - "okuyun ve arayin." + "okuyun ve arayın." ] } }, @@ -153,7 +153,7 @@ "sheet by sheet." ], "de-DE": [ - "Tabellenkalkulationen,", + "Tabellen,", "Blatt für Blatt." ], "es-ES": [ @@ -178,7 +178,7 @@ ], "pt-BR": [ "Planilhas,", - "planilha por planilha." + "aba por aba." ], "ru": [ "Электронные таблицы,", @@ -207,7 +207,7 @@ ], "de-DE": [ "Ein Tippfehler?", - "Gleich hier ausbessern." + "Gleich hier korrigieren." ], "es-ES": [ "¿Una errata?", @@ -234,8 +234,8 @@ "Corrija aqui mesmo." ], "ru": [ - "Опечатка?", - "Исправьте здесь." + "Нашли опечатку?", + "Исправьте прямо здесь." ], "sv": [ "Ett stavfel?", @@ -264,11 +264,11 @@ ], "es-ES": [ "Abre cualquier PDF,", - "aquí mismo." + "sin salir de la app." ], "fr-FR": [ - "Ouvrez tout PDF,", - "directement dans l'app." + "Tous vos PDF,", + "directement dans l'appli." ], "hi": [ "कोई भी PDF खोलें,", @@ -279,7 +279,7 @@ "direttamente nell'app." ], "pl": [ - "Otwórz każdy PDF,", + "Otwórz dowolny PDF,", "od razu w aplikacji." ], "pt-BR": [ @@ -322,7 +322,7 @@ ".docx, .xlsx y .pptx." ], "fr-FR": [ - "Aussi les fichiers Office :", + "Les fichiers Office aussi :", ".docx, .xlsx et .pptx." ], "hi": [ diff --git a/scripts/make-screenshot-documents.py b/scripts/make-screenshot-documents.py index 350440c..2ae07cd 100755 --- a/scripts/make-screenshot-documents.py +++ b/scripts/make-screenshot-documents.py @@ -303,30 +303,30 @@ def deck(words: dict) -> str: "Der Support beantwortete neun von zehn Anfragen noch am selben Tag.",]], ["Kosten und Budget", [ "Die Ausgaben f\u00fcr Software stiegen mit den neuen Lizenzen, die Reisekosten sanken erneut.", - "Die Hardware wurde einmal ersetzt, der Support blieb \u00fcber das Quartal stabil.", - "Zwei Server sind ohne Ausfalltag zum neuen Anbieter umgezogen.",]], + "Die Hardware wurde einmal ersetzt, der Support blieb das ganze Quartal \u00fcber stabil.", + "Zwei Server sind ohne einen Tag Ausfall zum neuen Anbieter umgezogen.",]], ["N\xe4chstes Quartal", [ "Die Version im September ist die letzte f\xfcr dieses Jahr.", "Zwei Stellen im Support sind offen, eine im Design.", "Der Umzug ins neue B\xfcro ist f\xfcr November geplant und budgetiert.", ]], - ["Die Menschen", [ + ["Das Team", [ "An der Version arbeiteten sechs Personen, zwei davon neu in diesem Jahr.", - "Die Urlaubsvertretung wurde im April geregelt und trug durch den Sommer.", + "Die Urlaubsvertretung wurde im April geregelt und hat den ganzen Sommer über gehalten.", "Alle haben die Schulung absolviert, die die neue Lizenz verlangt.", ]], ["Risiken", [ - "Der Umzug im November ist der einzige Termin, an dem nichts vorbeigeht.", - "Ein Lieferant hat die neuen Bedingungen noch nicht unterschrieben.", - "Die Hostingkosten steigen im Januar, wenn der Vertrag nicht fr\xfcher erneuert wird.", + "Der Umzug im November ist der einzige Termin, der sich nicht verschieben lässt.", + "Ein Lieferant hat die neuen Bedingungen noch nicht unterschrieben; wir haken nach.", + "Die Hostingkosten steigen im Januar, wenn der Vertrag nicht vorzeitig verl\xe4ngert wird.", ]], ], "closing": "Das n\u00e4chste Treffen findet Ende Juli statt.", "sheets": ["\u00dcbersicht", "Kosten"], "item": "Position", "total": "Gesamt", - "periods": ["Q1", "Q2", "Q3", "Q4"], - "rows": ["Software", "Reisen", "Hardware", "Marketing", "Support", "Schulung", "Lizenzen", "Hosting", "Veranstaltungen", "B\u00fcro", "Cloud", "Personalsuche", "Recht", "Versicherung", "Verpflegung", "Versand", "Werbung", "Beratung", "Wartung", "Nebenkosten"], + "periods": ["Jan", "Feb", "M\u00e4r", "Apr", "Mai", "Jun"], + "rows": ["Software", "Reisen", "Hardware", "Marketing", "Support", "Schulung", "Lizenzen", "Hosting", "Veranstaltungen", "B\u00fcro", "Cloud", "Personalsuche", "Recht", "Versicherung", "Verpflegung", "Versand", "Werbung", "Beratung", "Wartung", "Nebenkosten", "Ausstattung", "Abonnements", "Telefonie", "Internet", "Sicherheit", "Backups", "Domains", "Zertifikate", "Druck", "B\u00fcromaterial", "Porto", "Reinigung", "Reparaturen", "M\u00f6bel", "Lager", "Bankgeb\u00fchren", "Mitgliedschaften", "Konferenzen", "\u00dcbersetzung", "Design"], "slides": [ ["Projektplan", ["Ziele f\u00fcr das Quartal", "Budget und Kosten", "N\u00e4chste Schritte"]], ["Zeitplan", ["Version im Juni", "R\u00fcckblick im Juli", "Planung im August"]], @@ -344,7 +344,7 @@ def deck(words: dict) -> str: ["Costes y presupuesto", [ "El gasto en software subi\u00f3 con las nuevas licencias, mientras que los viajes volvieron a bajar.", "El hardware se sustituy\u00f3 una vez y el soporte se mantuvo estable durante el trimestre.", - "Dos servidores pasaron al nuevo proveedor sin un d\xeda de ca\xedda.",]], + "Dos servidores pasaron al nuevo proveedor sin una sola interrupci\xf3n del servicio.",]], ["Pr\xf3ximo trimestre", [ "La versi\xf3n de septiembre es la \xfaltima prevista este a\xf1o.", "Hay dos vacantes en soporte y una en dise\xf1o.", @@ -357,7 +357,7 @@ def deck(words: dict) -> str: ]], ["Riesgos", [ "La mudanza de noviembre es la \xfanica fecha que no puede moverse.", - "Un proveedor a\xfan no ha firmado las nuevas condiciones.", + "Un proveedor a\xfan no ha firmado las nuevas condiciones y se le est\xe1 reclamando.", "El alojamiento sube en enero si no se renueva antes el contrato.", ]], ], @@ -365,8 +365,8 @@ def deck(words: dict) -> str: "sheets": ["Resumen", "Costes"], "item": "Concepto", "total": "Total", - "periods": ["T1", "T2", "T3", "T4"], - "rows": ["Software", "Viajes", "Hardware", "Marketing", "Soporte", "Formaci\u00f3n", "Licencias", "Alojamiento", "Eventos", "Oficina", "Nube", "Contrataci\xf3n", "Legal", "Seguros", "Catering", "Env\xedos", "Publicidad", "Consultor\xeda", "Mantenimiento", "Suministros"], + "periods": ["Ene", "Feb", "Mar", "Abr", "May", "Jun"], + "rows": ["Software", "Viajes", "Hardware", "Marketing", "Soporte", "Formaci\u00f3n", "Licencias", "Alojamiento", "Eventos", "Oficina", "Nube", "Contrataci\u00f3n", "Legal", "Seguros", "Catering", "Env\u00edos", "Publicidad", "Consultor\u00eda", "Mantenimiento", "Suministros", "Equipamiento", "Suscripciones", "Telefon\u00eda", "Internet", "Seguridad", "Copias de seguridad", "Dominios", "Certificados", "Impresi\u00f3n", "Papeler\u00eda", "Franqueo", "Limpieza", "Reparaciones", "Mobiliario", "Almacenamiento", "Comisiones bancarias", "Cuotas", "Congresos", "Traducci\u00f3n", "Dise\u00f1o"], "slides": [ ["Plan del proyecto", ["Objetivos del trimestre", "Presupuesto y costes", "Pr\u00f3ximos pasos"]], ["Calendario", ["Versi\u00f3n en junio", "Revisi\u00f3n en julio", "Planificaci\u00f3n en agosto"]], @@ -378,13 +378,13 @@ def deck(words: dict) -> str: "lead": "L'\u00e9quipe a atteint tous les objectifs du deuxi\u00e8me trimestre et la nouvelle version est sortie \u00e0 temps.", "sections": [ ["Points forts", [ - "Les co\u00fbts sont rest\u00e9s sous le budget et deux nouveaux partenaires ont rejoint le projet.", + "Les co\u00fbts sont rest\u00e9s dans le budget et deux nouveaux partenaires ont rejoint le projet.", "La nouvelle version a touch\u00e9 plus de monde en une semaine que la pr\u00e9c\u00e9dente en un mois.", "Le support a r\xe9pondu \xe0 neuf demandes sur dix le jour m\xeame.",]], ["Co\u00fbts et budget", [ - "Les d\u00e9penses de logiciels ont augment\u00e9 avec les nouvelles licences, tandis que les voyages ont encore baiss\u00e9.", + "Les d\u00e9penses en logiciels ont augment\u00e9 avec les nouvelles licences, tandis que les d\u00e9placements ont encore baiss\u00e9.", "Le mat\u00e9riel a \u00e9t\u00e9 remplac\u00e9 une fois et le support est rest\u00e9 stable sur le trimestre.", - "Deux serveurs ont migr\xe9 vers le nouveau prestataire sans une journ\xe9e d'arr\xeat.",]], + "Deux serveurs ont migr\xe9 vers le nouveau prestataire sans la moindre interruption de service.",]], ["Trimestre prochain", [ "La version de septembre est la derni\xe8re pr\xe9vue cette ann\xe9e.", "Deux postes sont ouverts au support, un au design.", @@ -392,21 +392,21 @@ def deck(words: dict) -> str: ]], ["Les personnes", [ "Six personnes ont travaill\xe9 sur la version, dont deux arriv\xe9es cette ann\xe9e.", - "Les remplacements d'\xe9t\xe9 ont \xe9t\xe9 organis\xe9s en avril et ont tenu.", + "Les remplacements pour les cong\xe9s ont \xe9t\xe9 organis\xe9s en avril et ont tenu tout l'\xe9t\xe9.", "Tout le monde a suivi la formation qu'exige la nouvelle licence.", ]], ["Risques", [ "Le d\xe9m\xe9nagement de novembre est la seule date qui ne peut pas bouger.", "Un prestataire n'a pas encore sign\xe9 les nouvelles conditions.", - "L'h\xe9bergement augmente en janvier sans renouvellement anticip\xe9.", + "Le co\xfbt de l'h\xe9bergement augmente en janvier sans renouvellement anticip\xe9.", ]], ], "closing": "La prochaine r\u00e9union aura lieu fin juillet.", "sheets": ["Aper\u00e7u", "Co\u00fbts"], "item": "Poste", "total": "Total", - "periods": ["T1", "T2", "T3", "T4"], - "rows": ["Logiciels", "Voyages", "Mat\u00e9riel", "Marketing", "Support", "Formation", "Licences", "H\u00e9bergement", "\u00c9v\u00e9nements", "Bureau", "Cloud", "Recrutement", "Juridique", "Assurance", "Traiteur", "Exp\xe9dition", "Publicit\xe9", "Conseil", "Maintenance", "Charges"], + "periods": ["Janv.", "F\u00e9vr.", "Mars", "Avr.", "Mai", "Juin"], + "rows": ["Logiciels", "D\u00e9placements", "Mat\u00e9riel", "Marketing", "Support", "Formation", "Licences", "H\u00e9bergement", "\u00c9v\u00e9nements", "Bureau", "Cloud", "Recrutement", "Juridique", "Assurance", "Traiteur", "Exp\u00e9dition", "Publicit\u00e9", "Conseil", "Maintenance", "Charges", "\u00c9quipement", "Abonnements", "T\u00e9l\u00e9phonie", "Internet", "S\u00e9curit\u00e9", "Sauvegardes", "Domaines", "Certificats", "Impression", "Fournitures", "Affranchissement", "Nettoyage", "R\u00e9parations", "Mobilier", "Stockage", "Frais bancaires", "Cotisations", "Conf\u00e9rences", "Traduction", "Design"], "slides": [ ["Plan du projet", ["Objectifs du trimestre", "Budget et co\u00fbts", "Prochaines \u00e9tapes"]], ["Calendrier", ["Version en juin", "Bilan en juillet", "Planification en ao\u00fbt"]], @@ -419,10 +419,10 @@ def deck(words: dict) -> str: "sections": [ ["In evidenza", [ "I costi sono rimasti sotto il budget e due nuovi partner si sono uniti al progetto.", - "La nuova versione ha raggiunto pi\u00f9 persone in una settimana di quante la precedente in un mese.", + "La nuova versione ha raggiunto in una settimana pi\u00f9 persone di quante ne avesse raggiunte la precedente in un mese.", "Il supporto ha risposto a nove richieste su dieci in giornata.",]], ["Costi e budget", [ - "La spesa per il software \u00e8 cresciuta con le nuove licenze, mentre i viaggi sono di nuovo calati.", + "La spesa per il software \u00e8 cresciuta con le nuove licenze, mentre quella per i viaggi è di nuovo calata.", "L'hardware \u00e8 stato sostituito una volta e il supporto \u00e8 rimasto stabile per tutto il trimestre.", "Due server sono passati al nuovo fornitore senza un giorno di fermo.",]], ["Prossimo trimestre", [ @@ -438,15 +438,15 @@ def deck(words: dict) -> str: ["Rischi", [ "Il trasloco di novembre \xe8 l'unica data che non pu\xf2 slittare.", "Un fornitore non ha ancora firmato le nuove condizioni.", - "L'hosting aumenta a gennaio se il contratto non si rinnova prima.", + "I costi di hosting aumentano a gennaio se il contratto non viene rinnovato in anticipo.", ]], ], "closing": "Il prossimo incontro \u00e8 a fine luglio.", "sheets": ["Panoramica", "Costi"], "item": "Voce", "total": "Totale", - "periods": ["T1", "T2", "T3", "T4"], - "rows": ["Software", "Viaggi", "Hardware", "Marketing", "Supporto", "Formazione", "Licenze", "Hosting", "Eventi", "Ufficio", "Cloud", "Selezione", "Legale", "Assicurazione", "Catering", "Spedizioni", "Pubblicit\xe0", "Consulenza", "Manutenzione", "Utenze"], + "periods": ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu"], + "rows": ["Software", "Viaggi", "Hardware", "Marketing", "Supporto", "Formazione", "Licenze", "Hosting", "Eventi", "Ufficio", "Cloud", "Selezione", "Legale", "Assicurazione", "Catering", "Spedizioni", "Pubblicit\u00e0", "Consulenza", "Manutenzione", "Utenze", "Attrezzature", "Abbonamenti", "Telefonia", "Internet", "Sicurezza", "Backup", "Domini", "Certificati", "Stampa", "Cancelleria", "Affrancature", "Pulizie", "Riparazioni", "Arredi", "Archiviazione", "Spese bancarie", "Quote associative", "Conferenze", "Traduzioni", "Design"], "slides": [ ["Piano di progetto", ["Obiettivi del trimestre", "Budget e costi", "Prossimi passi"]], ["Calendario", ["Versione a giugno", "Revisione a luglio", "Pianificazione ad agosto"]], @@ -464,29 +464,29 @@ def deck(words: dict) -> str: ["Koszty i bud\u017cet", [ "Wydatki na oprogramowanie wzros\u0142y wraz z nowymi licencjami, a koszty podr\u00f3\u017cy zn\u00f3w spad\u0142y.", "Sprz\u0119t wymieniono raz, a wsparcie by\u0142o stabilne przez ca\u0142y kwarta\u0142.", - "Dwa serwery przeniesiono do nowego dostawcy bez dnia przestoju.",]], + "Dwa serwery przeniesiono do nowego dostawcy bez ani jednego dnia przestoju.",]], ["Nast\u0119pny kwarta\u0142", [ "Wersja z wrze\u015bnia jest ostatni\u0105 zaplanowan\u0105 w tym roku.", "Otwarte s\u0105 dwa etaty we wsparciu i jeden w dziale projektowym.", "Przeprowadzka biura wypada w listopadzie i ma ju\u017c bud\u017cet.", ]], ["Ludzie", [ - "Nad wersj\u0105 pracowa\u0142o sze\u015b\u0107 os\xf3b, dwie z nich do\u0142\u0105czy\u0142y w tym roku.", - "Zast\u0119pstwa urlopowe ustalono w kwietniu i wytrzyma\u0142y ca\u0142e lato.", + "Nad wersj\u0105 pracowa\u0142o sze\u015b\u0107 os\xf3b, z czego dwie do\u0142\u0105czy\u0142y w tym roku.", + "Zast\u0119pstwa urlopowe ustalono w kwietniu i utrzyma\u0142y si\u0119 przez ca\u0142e lato.", "Wszyscy przeszli szkolenie wymagane przez now\u0105 licencj\u0119.", ]], ["Ryzyka", [ "Przeprowadzka w listopadzie to jedyny termin, kt\xf3ry nie mo\u017ce si\u0119 przesun\u0105\u0107.", - "Jeden dostawca nie podpisa\u0142 jeszcze nowych warunk\xf3w.", - "Koszty hostingu rosn\u0105 w styczniu, je\u015bli umowa nie zostanie odnowiona wcze\u015bniej.", + "Jeden dostawca nie podpisa\u0142 jeszcze nowych warunk\xf3w i jest ponaglany.", + "Koszty hostingu wzrosn\u0105 w styczniu, je\u015bli umowa nie zostanie odnowiona wcze\u015bniej.", ]], ], "closing": "Nast\u0119pne spotkanie odb\u0119dzie si\u0119 pod koniec lipca.", "sheets": ["Przegl\u0105d", "Koszty"], "item": "Pozycja", "total": "Razem", - "periods": ["I kw.", "II kw.", "III kw.", "IV kw."], - "rows": ["Oprogramowanie", "Podr\u00f3\u017ce", "Sprz\u0119t", "Marketing", "Wsparcie", "Szkolenia", "Licencje", "Hosting", "Wydarzenia", "Biuro", "Chmura", "Rekrutacja", "Prawo", "Ubezpieczenie", "Catering", "Wysy\u0142ka", "Reklama", "Doradztwo", "Utrzymanie", "Media"], + "periods": ["sty", "lut", "mar", "kwi", "maj", "cze"], + "rows": ["Oprogramowanie", "Podr\u00f3\u017ce", "Sprz\u0119t", "Marketing", "Wsparcie", "Szkolenia", "Licencje", "Hosting", "Wydarzenia", "Biuro", "Chmura", "Rekrutacja", "Prawo", "Ubezpieczenie", "Catering", "Wysy\u0142ka", "Reklama", "Doradztwo", "Utrzymanie", "Media", "Wyposa\u017cenie", "Subskrypcje", "Telefonia", "Internet", "Bezpiecze\u0144stwo", "Kopie zapasowe", "Domeny", "Certyfikaty", "Druk", "Artyku\u0142y biurowe", "Op\u0142aty pocztowe", "Sprz\u0105tanie", "Naprawy", "Meble", "Magazyn", "Op\u0142aty bankowe", "Sk\u0142adki cz\u0142onkowskie", "Konferencje", "T\u0142umaczenia", "Projektowanie"], "slides": [ ["Plan projektu", ["Cele na kwarta\u0142", "Bud\u017cet i koszty", "Kolejne kroki"]], ["Harmonogram", ["Wersja w czerwcu", "Podsumowanie w lipcu", "Planowanie w sierpniu"]], @@ -512,7 +512,7 @@ def deck(words: dict) -> str: ]], ["As pessoas", [ "Seis pessoas trabalharam na vers\xe3o, duas delas novas este ano.", - "A cobertura de f\xe9rias foi combinada em abril e durou o ver\xe3o todo.", + "A escala de f\xe9rias foi definida em abril e valeu o ver\xe3o todo.", "Todos fizeram o treinamento que a nova licen\xe7a exige.", ]], ["Riscos", [ @@ -525,8 +525,8 @@ def deck(words: dict) -> str: "sheets": ["Vis\u00e3o geral", "Custos"], "item": "Item", "total": "Total", - "periods": ["T1", "T2", "T3", "T4"], - "rows": ["Software", "Viagens", "Hardware", "Marketing", "Suporte", "Treinamento", "Licen\u00e7as", "Hospedagem", "Eventos", "Escrit\u00f3rio", "Nuvem", "Recrutamento", "Jur\xeddico", "Seguros", "Buffet", "Frete", "Publicidade", "Consultoria", "Manuten\xe7\xe3o", "Utilidades"], + "periods": ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun"], + "rows": ["Software", "Viagens", "Hardware", "Marketing", "Suporte", "Treinamento", "Licen\u00e7as", "Hospedagem", "Eventos", "Escrit\u00f3rio", "Nuvem", "Recrutamento", "Jur\u00eddico", "Seguros", "Buffet", "Frete", "Publicidade", "Consultoria", "Manuten\u00e7\u00e3o", "\u00c1gua e luz", "Equipamentos", "Assinaturas", "Telefonia", "Internet", "Seguran\u00e7a", "Backups", "Dom\u00ednios", "Certificados", "Impress\u00e3o", "Papelaria", "Correios", "Limpeza", "Reparos", "M\u00f3veis", "Armazenamento", "Tarifas banc\u00e1rias", "Associa\u00e7\u00f5es", "Confer\u00eancias", "Tradu\u00e7\u00e3o", "Design"], "slides": [ ["Plano do projeto", ["Metas do trimestre", "Or\u00e7amento e custos", "Pr\u00f3ximos passos"]], ["Cronograma", ["Vers\u00e3o em junho", "Revis\u00e3o em julho", "Planejamento em agosto"]], @@ -535,14 +535,14 @@ def deck(words: dict) -> str: }, "ru": { "title": "\u041a\u0432\u0430\u0440\u0442\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0447\u0451\u0442", - "lead": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043b\u0430 \u0432\u0441\u0435 \u0446\u0435\u043b\u0438 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430, \u0438 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0432\u044b\u0448\u043b\u0430 \u0432 \u0441\u0440\u043e\u043a.", + "lead": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043e\u0441\u0442\u0438\u0433\u043b\u0430 \u0432\u0441\u0435\u0445 \u0446\u0435\u043b\u0435\u0439 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043a\u0432\u0430\u0440\u0442\u0430\u043b\u0430, \u0438 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0432\u044b\u0448\u043b\u0430 \u0432 \u0441\u0440\u043e\u043a.", "sections": [ ["\u0413\u043b\u0430\u0432\u043d\u043e\u0435", [ "\u0420\u0430\u0441\u0445\u043e\u0434\u044b \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u0431\u044e\u0434\u0436\u0435\u0442\u0430, \u0430 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443 \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043b\u0438\u0441\u044c \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043f\u0430\u0440\u0442\u043d\u0451\u0440\u0430.", "\u0417\u0430 \u043f\u0435\u0440\u0432\u0443\u044e \u043d\u0435\u0434\u0435\u043b\u044e \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u043e\u0445\u0432\u0430\u0442\u0438\u043b\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u044e\u0434\u0435\u0439, \u0447\u0435\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u0437\u0430 \u043c\u0435\u0441\u044f\u0446.", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043e\u0442\u0432\u0435\u0442\u0438\u043b\u0430 \u043d\u0430 \u0434\u0435\u0432\u044f\u0442\u044c \u0438\u0437 \u0434\u0435\u0441\u044f\u0442\u0438 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u0432 \u0442\u043e\u0442 \u0436\u0435 \u0434\u0435\u043d\u044c.",]], ["\u0420\u0430\u0441\u0445\u043e\u0434\u044b \u0438 \u0431\u044e\u0434\u0436\u0435\u0442", [ - "\u0417\u0430\u0442\u0440\u0430\u0442\u044b \u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432\u044b\u0440\u043e\u0441\u043b\u0438 \u0438\u0437-\u0437\u0430 \u043d\u043e\u0432\u044b\u0445 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0439, \u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u043f\u043e\u0435\u0437\u0434\u043a\u0438 \u0441\u043d\u043e\u0432\u0430 \u0441\u043d\u0438\u0437\u0438\u043b\u0438\u0441\u044c.", + "\u0417\u0430\u0442\u0440\u0430\u0442\u044b \u043d\u0430 \u041f\u041e \u0432\u044b\u0440\u043e\u0441\u043b\u0438 \u0438\u0437-\u0437\u0430 \u043d\u043e\u0432\u044b\u0445 \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0439, \u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u044b \u043d\u0430 \u043f\u043e\u0435\u0437\u0434\u043a\u0438 \u0441\u043d\u043e\u0432\u0430 \u0441\u043d\u0438\u0437\u0438\u043b\u0438\u0441\u044c.", "\u041e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u0435\u043d\u044f\u043b\u0438 \u043e\u0434\u0438\u043d \u0440\u0430\u0437, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e \u0432\u0435\u0441\u044c \u043a\u0432\u0430\u0440\u0442\u0430\u043b.", "\u0414\u0432\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0435\u0440\u0435\u0435\u0445\u0430\u043b\u0438 \u043a \u043d\u043e\u0432\u043e\u043c\u0443 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0443 \u0431\u0435\u0437 \u0435\u0434\u0438\u043d\u043e\u0433\u043e \u0434\u043d\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u044f.",]], ["\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u0432\u0430\u0440\u0442\u0430\u043b", [ @@ -552,12 +552,12 @@ def deck(words: dict) -> str: ]], ["\u041b\u044e\u0434\u0438", [ "\u041d\u0430\u0434 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u0448\u0435\u0441\u0442\u044c \u0447\u0435\u043b\u043e\u0432\u0435\u043a, \u0434\u0432\u043e\u0435 \u0438\u0437 \u043d\u0438\u0445 \u043f\u0440\u0438\u0448\u043b\u0438 \u0432 \u044d\u0442\u043e\u043c \u0433\u043e\u0434\u0443.", - "\u0417\u0430\u043c\u0435\u043d\u044b \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043f\u0443\u0441\u043a\u043e\u0432 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043b\u0438 \u0432 \u0430\u043f\u0440\u0435\u043b\u0435, \u0438 \u043b\u0435\u0442\u043e\u043c \u0432\u0441\u0451 \u0441\u043e\u0448\u043b\u043e\u0441\u044c.", + "\u0417\u0430\u043c\u0435\u043d\u044b \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043f\u0443\u0441\u043a\u043e\u0432 \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u043b\u0438 \u0432 \u0430\u043f\u0440\u0435\u043b\u0435, \u0438 \u0433\u0440\u0430\u0444\u0438\u043a \u043f\u0440\u043e\u0434\u0435\u0440\u0436\u0430\u043b\u0441\u044f \u0432\u0441\u0451 \u043b\u0435\u0442\u043e.", "\u0412\u0441\u0435 \u043f\u0440\u043e\u0448\u043b\u0438 \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043d\u043e\u0432\u0430\u044f \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u044f.", ]], ["\u0420\u0438\u0441\u043a\u0438", [ "\u041f\u0435\u0440\u0435\u0435\u0437\u0434 \u0432 \u043d\u043e\u044f\u0431\u0440\u0435 \u2014 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u0434\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u0441\u0434\u0432\u0438\u043d\u0443\u0442\u044c.", - "\u041e\u0434\u0438\u043d \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043b \u043d\u043e\u0432\u044b\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f.", + "\u041e\u0434\u0438\u043d \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0442\u0430\u043a \u0438 \u043d\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043b \u043d\u043e\u0432\u044b\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f, \u0435\u043c\u0443 \u043d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442.", "\u0425\u043e\u0441\u0442\u0438\u043d\u0433 \u043f\u043e\u0434\u043e\u0440\u043e\u0436\u0430\u0435\u0442 \u0432 \u044f\u043d\u0432\u0430\u0440\u0435, \u0435\u0441\u043b\u0438 \u043d\u0435 \u043f\u0440\u043e\u0434\u043b\u0438\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u0440\u0430\u043d\u0435\u0435.", ]], ], @@ -565,8 +565,8 @@ def deck(words: dict) -> str: "sheets": ["\u041e\u0431\u0437\u043e\u0440", "\u0420\u0430\u0441\u0445\u043e\u0434\u044b"], "item": "\u0421\u0442\u0430\u0442\u044c\u044f", "total": "\u0418\u0442\u043e\u0433\u043e", - "periods": ["I \u043a\u0432.", "II \u043a\u0432.", "III \u043a\u0432.", "IV \u043a\u0432."], - "rows": ["\u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b", "\u041f\u043e\u0435\u0437\u0434\u043a\u0438", "\u041e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435", "\u041c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430", "\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "\u041b\u0438\u0446\u0435\u043d\u0437\u0438\u0438", "\u0425\u043e\u0441\u0442\u0438\u043d\u0433", "\u041c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u044f", "\u041e\u0444\u0438\u0441", "\u041e\u0431\u043b\u0430\u043a\u043e", "\u041d\u0430\u0439\u043c", "\u042e\u0440\u0438\u0441\u0442\u044b", "\u0421\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u043d\u0438\u0435", "\u041a\u0435\u0439\u0442\u0435\u0440\u0438\u043d\u0433", "\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430", "\u0420\u0435\u043a\u043b\u0430\u043c\u0430", "\u041a\u043e\u043d\u0441\u0430\u043b\u0442\u0438\u043d\u0433", "\u041e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435", "\u041a\u043e\u043c\u043c\u0443\u043d\u0430\u043b\u044c\u043d\u044b\u0435"], + "periods": ["\u042f\u043d\u0432.", "\u0424\u0435\u0432\u0440.", "\u041c\u0430\u0440\u0442", "\u0410\u043f\u0440.", "\u041c\u0430\u0439", "\u0418\u044e\u043d\u044c"], + "rows": ["\u041f\u041e", "\u041f\u043e\u0435\u0437\u0434\u043a\u0438", "\u041e\u0431\u043e\u0440\u0443\u0434\u043e\u0432\u0430\u043d\u0438\u0435", "\u041c\u0430\u0440\u043a\u0435\u0442\u0438\u043d\u0433", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430", "\u041e\u0431\u0443\u0447\u0435\u043d\u0438\u0435", "\u041b\u0438\u0446\u0435\u043d\u0437\u0438\u0438", "\u0425\u043e\u0441\u0442\u0438\u043d\u0433", "\u041c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u044f", "\u041e\u0444\u0438\u0441", "\u041e\u0431\u043b\u0430\u043a\u043e", "\u041d\u0430\u0451\u043c", "\u042e\u0440\u0438\u0441\u0442\u044b", "\u0421\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u043d\u0438\u0435", "\u041a\u0435\u0439\u0442\u0435\u0440\u0438\u043d\u0433", "\u0414\u043e\u0441\u0442\u0430\u0432\u043a\u0430", "\u0420\u0435\u043a\u043b\u0430\u043c\u0430", "\u041a\u043e\u043d\u0441\u0430\u043b\u0442\u0438\u043d\u0433", "\u041e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0435", "\u041a\u043e\u043c\u043c\u0443\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0443\u0441\u043b\u0443\u0433\u0438", "\u041e\u0441\u043d\u0430\u0449\u0435\u043d\u0438\u0435", "\u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0438", "\u0422\u0435\u043b\u0435\u0444\u043e\u043d\u0438\u044f", "\u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442", "\u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c", "\u0420\u0435\u0437\u0435\u0440\u0432\u043d\u043e\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", "\u0414\u043e\u043c\u0435\u043d\u044b", "\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u044b", "\u041f\u0435\u0447\u0430\u0442\u044c", "\u041a\u0430\u043d\u0446\u0442\u043e\u0432\u0430\u0440\u044b", "\u041f\u043e\u0447\u0442\u043e\u0432\u044b\u0435 \u0440\u0430\u0441\u0445\u043e\u0434\u044b", "\u0423\u0431\u043e\u0440\u043a\u0430", "\u0420\u0435\u043c\u043e\u043d\u0442", "\u041c\u0435\u0431\u0435\u043b\u044c", "\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435", "\u0411\u0430\u043d\u043a\u043e\u0432\u0441\u043a\u0438\u0435 \u043a\u043e\u043c\u0438\u0441\u0441\u0438\u0438", "\u0427\u043b\u0435\u043d\u0441\u043a\u0438\u0435 \u0432\u0437\u043d\u043e\u0441\u044b", "\u041a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0438", "\u041f\u0435\u0440\u0435\u0432\u043e\u0434", "\u0414\u0438\u0437\u0430\u0439\u043d"], "slides": [ ["\u041f\u043b\u0430\u043d \u043f\u0440\u043e\u0435\u043a\u0442\u0430", ["\u0426\u0435\u043b\u0438 \u043d\u0430 \u043a\u0432\u0430\u0440\u0442\u0430\u043b", "\u0411\u044e\u0434\u0436\u0435\u0442 \u0438 \u0440\u0430\u0441\u0445\u043e\u0434\u044b", "\u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438"]], ["\u0413\u0440\u0430\u0444\u0438\u043a", ["\u0412\u0435\u0440\u0441\u0438\u044f \u0432 \u0438\u044e\u043d\u0435", "\u0418\u0442\u043e\u0433\u0438 \u0432 \u0438\u044e\u043b\u0435", "\u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u0430\u0432\u0433\u0443\u0441\u0442\u0435"]], @@ -592,21 +592,21 @@ def deck(words: dict) -> str: ]], ["Ekip", [ "S\xfcr\xfcm \xfczerinde alt\u0131 ki\u015fi \xe7al\u0131\u015ft\u0131, ikisi bu y\u0131l kat\u0131ld\u0131.", - "\u0130zin d\xf6nemi vekaletleri nisanda ayarland\u0131 ve yaz boyunca y\xfcr\xfcd\xfc.", + "\u0130zin d\xf6nemi vekaletleri nisanda belirlendi ve yaz boyunca sorunsuz i\u015fledi.", "Herkes yeni lisans\u0131n gerektirdi\u011fi e\u011fitimi tamamlad\u0131.", ]], ["Riskler", [ - "Kas\u0131mdaki ta\u015f\u0131nma, kayamayacak tek tarih.", - "Bir tedarik\xe7i yeni ko\u015fullar\u0131 hen\xfcz imzalamad\u0131.", - "S\xf6zle\u015fme erken yenilenmezse bar\u0131nd\u0131rma maliyeti ocakta art\u0131yor.", + "Kas\u0131mdaki ta\u015f\u0131nma, ertelenemeyecek tek tarih.", + "Bir tedarik\xe7i yeni ko\u015fullar\u0131 hen\xfcz imzalamad\u0131, takibi s\xfcr\xfcyor.", + "S\xf6zle\u015fme erken yenilenmezse bar\u0131nd\u0131rma maliyeti ocakta artacak.", ]], ], "closing": "Bir sonraki toplant\u0131 temmuz sonunda.", "sheets": ["Genel bak\u0131\u015f", "Maliyetler"], "item": "Kalem", "total": "Toplam", - "periods": ["1. \u00c7", "2. \u00c7", "3. \u00c7", "4. \u00c7"], - "rows": ["Yaz\u0131l\u0131m", "Seyahat", "Donan\u0131m", "Pazarlama", "Destek", "E\u011fitim", "Lisanslar", "Bar\u0131nd\u0131rma", "Etkinlikler", "Ofis", "Bulut", "\u0130\u015fe al\u0131m", "Hukuk", "Sigorta", "\u0130kram", "Kargo", "Reklam", "Dan\u0131\u015fmanl\u0131k", "Bak\u0131m", "Faturalar"], + "periods": ["Oca", "\u015eub", "Mar", "Nis", "May", "Haz"], + "rows": ["Yaz\u0131l\u0131m", "Seyahat", "Donan\u0131m", "Pazarlama", "Destek", "E\u011fitim", "Lisanslar", "Bar\u0131nd\u0131rma", "Etkinlikler", "Ofis", "Bulut", "\u0130\u015fe al\u0131m", "Hukuk", "Sigorta", "\u0130kram", "Kargo", "Reklam", "Dan\u0131\u015fmanl\u0131k", "Bak\u0131m", "Faturalar", "Ekipman", "Abonelikler", "Telefon", "\u0130nternet", "G\u00fcvenlik", "Yedekleme", "Alan adlar\u0131", "Sertifikalar", "Bask\u0131", "K\u0131rtasiye", "Posta", "Temizlik", "Onar\u0131m", "Mobilya", "Depolama", "Banka masraflar\u0131", "\u00dcyelikler", "Konferanslar", "\u00c7eviri", "Tasar\u0131m"], "slides": [ ["Proje plan\u0131", ["\u00c7eyrek hedefleri", "B\u00fct\u00e7e ve maliyetler", "Sonraki ad\u0131mlar"]], ["Takvim", ["Haziranda s\u00fcr\u00fcm", "Temmuzda de\u011ferlendirme", "A\u011fustosta planlama"]], @@ -672,13 +672,13 @@ def deck(words: dict) -> str: "word": "Vertrag", "cells": "Umsatzzahlen", "deck": "Teamtreffen", "paper": "Rechnung", "rows": "Kontakte", "notes": "Notizen"}, "es": {"text": "Informe trimestral", "sheet": "Presupuesto", "slides": "Plan del proyecto", - "word": "Contrato", "cells": "Cifras de ventas", "deck": "Reuni\u00f3n de equipo", + "word": "Contrato", "cells": "Cifras de ventas", "deck": "Jornada de equipo", "paper": "Factura", "rows": "Contactos", "notes": "Notas"}, "fr": {"text": "Rapport trimestriel", "sheet": "Budget", "slides": "Plan du projet", - "word": "Contrat", "cells": "Chiffres de ventes", "deck": "R\u00e9union d'\u00e9quipe", + "word": "Contrat", "cells": "Chiffres des ventes", "deck": "R\u00e9union d'\u00e9quipe", "paper": "Facture", "rows": "Contacts", "notes": "Notes"}, - "it": {"text": "Relazione trimestrale", "sheet": "Bilancio", "slides": "Piano di progetto", - "word": "Contratto", "cells": "Dati di vendita", "deck": "Riunione del team", + "it": {"text": "Relazione trimestrale", "sheet": "Budget", "slides": "Piano di progetto", + "word": "Contratto", "cells": "Dati di vendita", "deck": "Ritiro del team", "paper": "Fattura", "rows": "Contatti", "notes": "Note"}, "pl": {"text": "Raport kwartalny", "sheet": "Bud\u017cet", "slides": "Plan projektu", "word": "Umowa", "cells": "Wyniki sprzeda\u017cy", "deck": "Spotkanie zespo\u0142u", @@ -690,7 +690,7 @@ def deck(words: dict) -> str: "word": "\u0414\u043e\u0433\u043e\u0432\u043e\u0440", "cells": "\u041f\u0440\u043e\u0434\u0430\u0436\u0438", "deck": "\u0412\u0441\u0442\u0440\u0435\u0447\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u044b", "paper": "\u0421\u0447\u0451\u0442", "rows": "\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u044b", "notes": "\u0417\u0430\u043c\u0435\u0442\u043a\u0438"}, "tr": {"text": "\u00dc\u00e7 ayl\u0131k rapor", "sheet": "B\u00fct\u00e7e", "slides": "Proje plan\u0131", - "word": "S\u00f6zle\u015fme", "cells": "Sat\u0131\u015f rakamlar\u0131", "deck": "Ekip toplant\u0131s\u0131", + "word": "S\u00f6zle\u015fme", "cells": "Sat\u0131\u015f rakamlar\u0131", "deck": "Ekip \u00e7al\u0131\u015ftay\u0131", "paper": "Fatura", "rows": "Ki\u015filer", "notes": "Notlar"}, } @@ -744,15 +744,15 @@ def deck(words: dict) -> str: "meeting": "Notas de reuni\u00f3n", "letter": "Carta al casero", "travel": "Plan de viaje", "reading": "Lista de lectura", "household": "Presupuesto dom\u00e9stico", "hours": "Horas", "stocktake": "Recuento", - "kickoff": "Inicio", "course": "Diapositivas del curso", - "lease": "Contrato de alquiler", "resume": "Curr\u00edculum", "application": "Solicitud", + "kickoff": "Arranque del proyecto", "course": "Diapositivas del curso", + "lease": "Alquiler del piso", "resume": "Curr\u00edculum", "application": "Solicitud", "expenses": "Gastos", "inventory": "Inventario", "review": "Revisi\u00f3n trimestral", "ticket": "Billete", "warranty": "Garant\u00eda", "manual": "Manual", }, "fr": { "meeting": "Notes de r\u00e9union", "letter": "Lettre au propri\u00e9taire", - "travel": "Plan de voyage", "reading": "Liste de lecture", + "travel": "Itinéraire", "reading": "Liste de lecture", "household": "Budget familial", "hours": "Heures", "stocktake": "Inventaire", "kickoff": "Lancement", "course": "Diapositives du cours", "lease": "Bail", "resume": "CV", "application": "Candidature", @@ -771,10 +771,10 @@ def deck(words: dict) -> str: "ticket": "Biglietto", "warranty": "Garanzia", "manual": "Manuale", }, "pl": { - "meeting": "Notatki ze spotkania", "letter": "List do w\u0142a\u015bciciela", + "meeting": "Notatki ze spotkania", "letter": "List do w\u0142a\u015bciciela mieszkania", "travel": "Plan podr\u00f3\u017cy", "reading": "Lista lektur", "household": "Bud\u017cet domowy", "hours": "Godziny", "stocktake": "Inwentaryzacja", - "kickoff": "Rozpocz\u0119cie", "course": "Slajdy kursu", + "kickoff": "Spotkanie startowe", "course": "Slajdy kursu", "lease": "Umowa najmu", "resume": "CV", "application": "Podanie", "expenses": "Wydatki", "inventory": "Stan magazynu", "review": "Przegl\u0105d kwartalny", @@ -784,7 +784,7 @@ def deck(words: dict) -> str: "meeting": "Notas da reuni\u00e3o", "letter": "Carta ao locador", "travel": "Plano de viagem", "reading": "Lista de leitura", "household": "Or\u00e7amento dom\u00e9stico", "hours": "Horas", "stocktake": "Balan\u00e7o", - "kickoff": "In\u00edcio", "course": "Slides do curso", + "kickoff": "Kickoff", "course": "Slides do curso", "lease": "Contrato de aluguel", "resume": "Curr\u00edculo", "application": "Inscri\u00e7\u00e3o", "expenses": "Despesas", "inventory": "Estoque", "review": "Revis\u00e3o trimestral", @@ -815,7 +815,7 @@ def deck(words: dict) -> str: "travel": "Seyahat plan\u0131", "reading": "Okuma listesi", "household": "Ev b\u00fct\u00e7esi", "hours": "\u00c7al\u0131\u015fma saatleri", "stocktake": "Say\u0131m", - "kickoff": "Ba\u015flang\u0131\u00e7", "course": "Kurs slaytlar\u0131", + "kickoff": "Proje ba\u015flang\u0131c\u0131", "course": "Kurs slaytlar\u0131", "lease": "Kira s\u00f6zle\u015fmesi", "resume": "\u00d6zge\u00e7mi\u015f", "application": "Ba\u015fvuru", "expenses": "Giderler", "inventory": "Envanter", @@ -871,7 +871,7 @@ def query(words: dict) -> str: "The appendix lists the software covered and the version it starts at.", "This agreement replaces every earlier arrangement between the parties."]], "invoice": ["Invoice 2026-014", "Issued 12 June 2026", "Due within 30 days", "Billed to", "Subtotal", "VAT 20%", "Amount due", "Thank you for your business.", "Qty", "Unit price"], - "contacts": [["Name", "Role", "Email", "Phone"], + "contacts": [["Name", "Team", "Email", "Phone"], ["Design", "Support", "Sales", "Engineering"]], }, "de": { @@ -892,7 +892,7 @@ def query(words: dict) -> str: "Der Anhang nennt die erfasste Software und die Version, ab der sie gilt.", "Dieser Vertrag ersetzt alle fr\xfcheren Vereinbarungen zwischen den Parteien."]], "invoice": ["Rechnung 2026-014", "Ausgestellt am 12. Juni 2026", "Zahlbar innerhalb von 30 Tagen", "Rechnung an", "Zwischensumme", "USt. 20%", "Zahlbetrag", "Vielen Dank f\xfcr Ihren Auftrag.", "Menge", "Einzelpreis"], - "contacts": [["Name", "Rolle", "E-Mail", "Telefon"], + "contacts": [["Name", "Team", "E-Mail", "Telefon"], ["Design", "Support", "Vertrieb", "Entwicklung"]], }, "es": { @@ -913,7 +913,7 @@ def query(words: dict) -> str: "El anexo enumera el software incluido y la versi\xf3n desde la que se aplica.", "Este contrato sustituye cualquier acuerdo anterior entre las partes."]], "invoice": ["Factura 2026-014", "Emitida el 12 de junio de 2026", "Vence en 30 d\u00edas", "Facturar a", "Subtotal", "IVA 20%", "Importe a pagar", "Gracias por su confianza.", "Cant.", "Precio unit."], - "contacts": [["Nombre", "Puesto", "Correo", "Tel\u00e9fono"], + "contacts": [["Nombre", "Equipo", "Correo", "Tel\u00e9fono"], ["Dise\u00f1o", "Soporte", "Ventas", "Ingenier\u00eda"]], }, "fr": { @@ -930,11 +930,11 @@ def query(words: dict) -> str: "Les demandes de support re\xe7oivent une r\xe9ponse sous un jour ouvr\xe9.", "Le client d\xe9signe une personne habilit\xe9e \xe0 approuver les modifications.", "Les prix sont fermes la premi\xe8re ann\xe9e et revus chaque automne.", - "Aucune partie ne peut c\xe9der ce contrat \xe0 un tiers sans accord.", - "L'annexe indique le logiciel couvert et la version \xe0 partir de laquelle il s'applique.", + "Aucune des parties ne peut c\xe9der ce contrat \xe0 un tiers sans accord.", + "L'annexe indique le logiciel couvert et la version \xe0 partir de laquelle la couverture s'applique.", "Ce contrat remplace tout accord ant\xe9rieur entre les parties."]], - "invoice": ["Facture 2026-014", "\u00c9mise le 12 juin 2026", "\u00c0 r\u00e9gler sous 30 jours", "Factur\xe9 \xe0", "Sous-total", "TVA 20%", "Montant d\xfb", "Merci de votre confiance.", "Qt\xe9", "Prix unitaire"], - "contacts": [["Nom", "R\u00f4le", "E-mail", "T\u00e9l\u00e9phone"], + "invoice": ["Facture 2026-014", "\u00c9mise le 12 juin 2026", "\u00c0 r\u00e9gler sous 30 jours", "Factur\xe9 \xe0", "Sous-total", "TVA 20 %", "Montant d\xfb", "Merci de votre confiance.", "Qt\xe9", "Prix unitaire"], + "contacts": [["Nom", "\u00c9quipe", "E-mail", "T\u00e9l\u00e9phone"], ["Design", "Support", "Ventes", "D\u00e9veloppement"]], }, "it": { @@ -952,39 +952,39 @@ def query(words: dict) -> str: "Il cliente indica una persona autorizzata ad approvare le modifiche.", "I prezzi restano fermi il primo anno e sono rivisti ogni autunno.", "Nessuna parte pu\xf2 cedere il contratto a terzi senza consenso.", - "L'allegato elenca il software coperto e la versione da cui decorre.", + "L'allegato elenca il software coperto e la versione di partenza.", "Il presente contratto sostituisce ogni accordo precedente tra le parti."]], - "invoice": ["Fattura 2026-014", "Emessa il 12 giugno 2026", "Da saldare entro 30 giorni", "Fatturato a", "Subtotale", "IVA 20%", "Importo dovuto", "Grazie per la collaborazione.", "Qt\xe0", "Prezzo unit."], - "contacts": [["Nome", "Ruolo", "E-mail", "Telefono"], + "invoice": ["Fattura 2026-014", "Emessa il 12 giugno 2026", "Da saldare entro 30 giorni", "Intestato a", "Subtotale", "IVA 20%", "Importo dovuto", "Grazie per la collaborazione.", "Qt\xe0", "Prezzo unit."], + "contacts": [["Nome", "Reparto", "E-mail", "Telefono"], ["Design", "Supporto", "Vendite", "Sviluppo"]], }, "pl": { "contract": ["Umowa o \u015bwiadczenie us\u0142ug", "Niniejsza umowa zostaje zawarta mi\u0119dzy dwiema stronami wymienionymi poni\u017cej.", ["Dostawca udost\u0119pnia oprogramowanie opisane w za\u0142\u0105czniku na okres roku.", - "P\u0142atno\u015b\u0107 jest wymagana w ci\u0105gu trzydziestu dni od ka\u017cdej faktury.", + "P\u0142atno\u015b\u0107 jest wymagalna w terminie trzydziestu dni od daty ka\u017cdej faktury.", "Ka\u017cda ze stron mo\u017ce rozwi\u0105za\u0107 umow\u0119 z trzymiesi\u0119cznym wypowiedzeniem.", "Zmiany umowy wymagaj\u0105 formy pisemnej.", "Dostawca utrzymuje dost\u0119pno\u015b\u0107 us\u0142ugi w dni robocze.", - "Obie strony traktuj\u0105 jako poufne to, czego dowiedz\u0105 si\u0119 o sobie.", + "Obie strony traktuj\u0105 jako poufne to, czego dowiedz\u0105 si\u0119 o sobie nawzajem.", "Obowi\u0105zuje prawo austriackie, a s\u0105dem w\u0142a\u015bciwym jest s\u0105d w Wiedniu.", "Dostawca przechowuje kopi\u0119 danych klienta przez trzydzie\u015bci dni.", "Zg\u0142oszenia do wsparcia s\u0105 rozpatrywane w ci\u0105gu jednego dnia roboczego.", "Klient wskazuje jedn\u0105 osob\u0119 uprawnion\u0105 do zatwierdzania zmian.", "Ceny obowi\u0105zuj\u0105 przez pierwszy rok i s\u0105 weryfikowane ka\u017cdej jesieni.", "\u017badna ze stron nie mo\u017ce przenie\u015b\u0107 umowy na osob\u0119 trzeci\u0105 bez zgody.", - "Za\u0142\u0105cznik wymienia obj\u0119te oprogramowanie i wersj\u0119, od kt\xf3rej obowi\u0105zuje.", + "Za\u0142\u0105cznik wymienia oprogramowanie obj\u0119te umow\u0105 oraz wersj\u0119 pocz\u0105tkow\u0105.", "Niniejsza umowa zast\u0119puje wszystkie wcze\u015bniejsze ustalenia stron."]], - "invoice": ["Faktura 2026-014", "Wystawiono 12 czerwca 2026", "P\u0142atne w ci\u0105gu 30 dni", "Nabywca", "Suma cz\u0119\u015bciowa", "VAT 20%", "Do zap\u0142aty", "Dzi\u0119kujemy za wsp\xf3\u0142prac\u0119.", "Ilo\u015b\u0107", "Cena jedn."], - "contacts": [["Imi\u0119", "Rola", "E-mail", "Telefon"], - ["Design", "Wsparcie", "Sprzeda\u017c", "Rozw\u00f3j"]], + "invoice": ["Faktura 2026-014", "Wystawiono 12 czerwca 2026", "P\u0142atne w ci\u0105gu 30 dni", "Nabywca", "Warto\u015b\u0107 netto", "VAT 20%", "Do zap\u0142aty", "Dzi\u0119kujemy za wsp\xf3\u0142prac\u0119.", "Ilo\u015b\u0107", "Cena jedn."], + "contacts": [["Imi\u0119 i nazwisko", "Dział", "E-mail", "Telefon"], + ["Projektowanie", "Wsparcie", "Sprzeda\u017c", "Rozw\u00f3j"]], }, "pt-BR": { "contract": ["Contrato de servi\u00e7o", "Este contrato \u00e9 celebrado entre as duas partes indicadas abaixo.", ["O fornecedor disponibiliza por um ano o software descrito no anexo.", "O pagamento vence em trinta dias a contar de cada fatura.", - "Qualquer parte pode encerrar o contrato com tr\u00eas meses de aviso.", + "Qualquer parte pode encerrar o contrato com aviso pr\u00e9vio de tr\u00eas meses.", "Altera\u00e7\u00f5es s\u00f3 s\u00e3o v\u00e1lidas por escrito.", "O fornecedor mant\xe9m o servi\xe7o dispon\xedvel em dias \xfateis.", "As partes tratam como confidencial o que souberem uma da outra.", @@ -992,18 +992,18 @@ def query(words: dict) -> str: "O fornecedor mant\xe9m uma c\xf3pia dos dados do cliente por trinta dias.", "Os chamados de suporte s\xe3o respondidos em um dia \xfatil.", "O cliente indica uma pessoa autorizada a aprovar altera\xe7\xf5es.", - "Os pre\xe7os valem no primeiro ano e s\xe3o revistos a cada outono.", + "Os pre\xe7os ficam fixos no primeiro ano e s\xe3o revisados todo outono.", "Nenhuma parte pode transferir este contrato a terceiros sem consentimento.", - "O anexo lista o software abrangido e a vers\xe3o a partir da qual vale.", + "O anexo lista o software abrangido e a vers\xe3o inicial coberta.", "Este contrato substitui qualquer acordo anterior entre as partes."]], - "invoice": ["Fatura 2026-014", "Emitida em 12 de junho de 2026", "Vence em 30 dias", "Faturado para", "Subtotal", "IVA 20%", "Valor a pagar", "Obrigado pela prefer\xeancia.", "Qtd", "Pre\xe7o unit."], - "contacts": [["Nome", "Fun\u00e7\u00e3o", "E-mail", "Telefone"], + "invoice": ["Fatura 2026-014", "Emitida em 12 de junho de 2026", "Vence em 30 dias", "Faturado para", "Subtotal", "Impostos 20%", "Valor a pagar", "Obrigado pela prefer\xeancia.", "Qtd", "Pre\xe7o unit."], + "contacts": [["Nome", "Equipe", "E-mail", "Telefone"], ["Design", "Suporte", "Vendas", "Engenharia"]], }, "ru": { "contract": ["\u0414\u043e\u0433\u043e\u0432\u043e\u0440 \u043e\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0443\u0441\u043b\u0443\u0433", "\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u043a\u043b\u044e\u0447\u0451\u043d \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u0430\u043c\u0438, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0438\u0436\u0435.", - ["\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0434\u0438\u043d \u0433\u043e\u0434.", + ["\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438, \u0441\u0440\u043e\u043a\u043e\u043c \u043d\u0430 \u043e\u0434\u0438\u043d \u0433\u043e\u0434.", "\u041e\u043f\u043b\u0430\u0442\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u0440\u0438\u0434\u0446\u0430\u0442\u0438 \u0434\u043d\u0435\u0439 \u0441 \u0434\u0430\u0442\u044b \u0441\u0447\u0451\u0442\u0430.", "\u041a\u0430\u0436\u0434\u0430\u044f \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0441\u0442\u043e\u0440\u0433\u043d\u0443\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440, \u0443\u0432\u0435\u0434\u043e\u043c\u0438\u0432 \u0437\u0430 \u0442\u0440\u0438 \u043c\u0435\u0441\u044f\u0446\u0430.", "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0438\u0441\u044c\u043c\u0435\u043d\u043d\u043e\u043c \u0432\u0438\u0434\u0435.", @@ -1012,13 +1012,13 @@ def query(words: dict) -> str: "\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0441\u0442\u0440\u0438\u0439\u0441\u043a\u043e\u0435 \u043f\u0440\u0430\u0432\u043e, \u0441\u043f\u043e\u0440\u044b \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u0442 \u0441\u0443\u0434 \u0412\u0435\u043d\u044b.", "\u0418\u0441\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c \u0445\u0440\u0430\u043d\u0438\u0442 \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u0443\u044e \u043a\u043e\u043f\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043a\u0430\u0437\u0447\u0438\u043a\u0430 \u0442\u0440\u0438\u0434\u0446\u0430\u0442\u044c \u0434\u043d\u0435\u0439.", "\u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0434\u043d\u044f.", - "\u0417\u0430\u043a\u0430\u0437\u0447\u0438\u043a \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u0430, \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u044e\u0449\u0435\u0433\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.", - "\u0426\u0435\u043d\u044b \u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u0439 \u0433\u043e\u0434 \u0438 \u043f\u0435\u0440\u0435\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u0443\u044e \u043e\u0441\u0435\u043d\u044c.", + "\u0417\u0430\u043a\u0430\u0437\u0447\u0438\u043a \u043d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043e\u0434\u043d\u043e\u0433\u043e \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043f\u0440\u0430\u0432\u0435 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.", + "\u0426\u0435\u043d\u044b \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0433\u043e\u0434 \u0438 \u043f\u0435\u0440\u0435\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u0443\u044e \u043e\u0441\u0435\u043d\u044c.", "\u041d\u0438 \u043e\u0434\u043d\u0430 \u0438\u0437 \u0441\u0442\u043e\u0440\u043e\u043d \u043d\u0435 \u0432\u043f\u0440\u0430\u0432\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0442\u0440\u0435\u0442\u044c\u0435\u043c\u0443 \u043b\u0438\u0446\u0443 \u0431\u0435\u0437 \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f.", - "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0438 \u0432\u0435\u0440\u0441\u0438\u044f, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043e\u043d\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442.", + "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0438 \u0441 \u043a\u0430\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438.", "\u041d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0434\u043e\u0433\u043e\u0432\u043e\u0440 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u043f\u0440\u0435\u0436\u043d\u0438\u0435 \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0451\u043d\u043d\u043e\u0441\u0442\u0438 \u0441\u0442\u043e\u0440\u043e\u043d."]], - "invoice": ["\u0421\u0447\u0451\u0442 2026-014", "\u0412\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d 12 \u0438\u044e\u043d\u044f 2026", "\u041e\u043f\u043b\u0430\u0442\u0430 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 30 \u0434\u043d\u0435\u0439", "\u041f\u043b\u0430\u0442\u0435\u043b\u044c\u0449\u0438\u043a", "\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433", "\u041d\u0414\u0421 20%", "\u041a \u043e\u043f\u043b\u0430\u0442\u0435", "\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0437\u0430 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0435\u0441\u0442\u0432\u043e.", "\u041a\u043e\u043b-\u0432\u043e", "\u0426\u0435\u043d\u0430 \u0437\u0430 \u0435\u0434."], - "contacts": [["\u0418\u043c\u044f", "\u0420\u043e\u043b\u044c", "\u041f\u043e\u0447\u0442\u0430", "\u0422\u0435\u043b\u0435\u0444\u043e\u043d"], + "invoice": ["\u0421\u0447\u0451\u0442 2026-014", "\u0412\u044b\u0441\u0442\u0430\u0432\u043b\u0435\u043d 12 \u0438\u044e\u043d\u044f 2026 \u0433.", "\u041e\u043f\u043b\u0430\u0442\u0430 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 30 \u0434\u043d\u0435\u0439", "\u041f\u043b\u0430\u0442\u0435\u043b\u044c\u0449\u0438\u043a", "\u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u044b\u0439 \u0438\u0442\u043e\u0433", "\u041d\u0414\u0421 20%", "\u041a \u043e\u043f\u043b\u0430\u0442\u0435", "\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u0438\u043c \u0437\u0430 \u0441\u043e\u0442\u0440\u0443\u0434\u043d\u0438\u0447\u0435\u0441\u0442\u0432\u043e.", "\u041a\u043e\u043b-\u0432\u043e", "\u0426\u0435\u043d\u0430 \u0437\u0430 \u0435\u0434."], + "contacts": [["\u0424\u0418\u041e", "\u041e\u0442\u0434\u0435\u043b", "\u041f\u043e\u0447\u0442\u0430", "\u0422\u0435\u043b\u0435\u0444\u043e\u043d"], ["\u0414\u0438\u0437\u0430\u0439\u043d", "\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430", "\u041f\u0440\u043e\u0434\u0430\u0436\u0438", "\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430"]], }, "tr": { @@ -1038,8 +1038,8 @@ def query(words: dict) -> str: "Hi\xe7bir taraf s\xf6zle\u015fmeyi onay almadan \xfc\xe7\xfcnc\xfc ki\u015fiye devredemez.", "Ek, kapsanan yaz\u0131l\u0131m\u0131 ve ge\xe7erli oldu\u011fu s\xfcr\xfcm\xfc listeler.", "Bu s\xf6zle\u015fme, taraflar aras\u0131ndaki \xf6nceki t\xfcm d\xfczenlemelerin yerine ge\xe7er."]], - "invoice": ["Fatura 2026-014", "12 Haziran 2026 tarihli", "30 g\u00fcn i\u00e7inde \u00f6denir", "Fatura edilen", "Ara toplam", "KDV %20", "\xd6denecek tutar", "\u0130\u015f birli\u011finiz i\xe7in te\u015fekk\xfcrler.", "Adet", "Birim fiyat"], - "contacts": [["Ad", "G\u00f6rev", "E-posta", "Telefon"], + "invoice": ["Fatura 2026-014", "12 Haziran 2026 tarihli", "30 g\u00fcn i\u00e7inde \u00f6denir", "Alıcı", "Ara toplam", "KDV %20", "\xd6denecek tutar", "\u0130\u015f birli\u011finiz i\xe7in te\u015fekk\xfcrler.", "Adet", "Birim fiyat"], + "contacts": [["Ad Soyad", "Ekip", "E-posta", "Telefon"], ["Tasar\u0131m", "Destek", "Sat\u0131\u015f", "Geli\u015ftirme"]], }, } From 953b1b4ae48b721962901e3ba4a1bb5a880f4aff Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 17 Aug 2026 14:29:50 +0200 Subject: [PATCH 4/5] Write our own hand-off to snapshot instead of carrying fastlane's Three hundred and twenty lines of theirs, kept byte for byte so it could be replaced wholesale, and held out of the formatter for the same reason. A hundred and fifteen of ours, which the formatter now covers like every other source here. What it does is the part we use: read the language and the region fastlane left in its cache directory, put them on the app's arguments, and write the screen back there under the name the release expects - including taking "Clone 2 of" off a device name, which xcodebuild adds when it runs several at once. What went: the macOS, tvOS and watchOS branches, the landscape correction for pictures we only ever take upright, a Swift 4 fallback, and sixty lines waiting on the network activity indicator, which iOS stopped drawing at 13 and which the test replaces with a marker of its own. It no longer forwards launch arguments from the lane either, because the lane sets none. The lane now skips snapshot's helper version check. That check does not read the helper - it refuses to start unless a file called SnapshotHelper.swift exists somewhere and carries a version marker at the bottom. The file was a token as much as a helper. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E6tn8P25cBDmrA67zrhfwN --- .../ScreenshotTests.swift | 6 +- .../SnapshotHelper.swift | 320 ------------------ OpenDocumentReaderUITests/Snapshots.swift | 115 +++++++ fastlane/Fastfile | 5 + scripts/format.sh | 8 +- 5 files changed, 124 insertions(+), 330 deletions(-) delete mode 100644 OpenDocumentReaderUITests/SnapshotHelper.swift create mode 100644 OpenDocumentReaderUITests/Snapshots.swift diff --git a/OpenDocumentReaderUITests/ScreenshotTests.swift b/OpenDocumentReaderUITests/ScreenshotTests.swift index fd85872..969be0b 100644 --- a/OpenDocumentReaderUITests/ScreenshotTests.swift +++ b/OpenDocumentReaderUITests/ScreenshotTests.swift @@ -25,8 +25,8 @@ final class ScreenshotTests: XCTestCase { func testTakesTheStoreScreenshots() throws { let app = XCUIApplication() - // adds the language, the locale and fastlane's own arguments, once - setupSnapshot(app) + // the language and the region this run is for, once + Snapshots.prepare(app) // The keyboard offers to teach swipe typing the first time it comes up // on a fresh simulator, over the keyboard the edit screenshot is of. @@ -53,7 +53,7 @@ final class ScreenshotTests: XCTestCase { raiseTheKeyboard(in: app) } - snapshot(String(format: "%02d-%@", index + 1, screen)) + Snapshots.take(String(format: "%02d-%@", index + 1, screen)) // rather than leaving it running: the next launch has to go through // didFinishLaunching again to be handed the next screen diff --git a/OpenDocumentReaderUITests/SnapshotHelper.swift b/OpenDocumentReaderUITests/SnapshotHelper.swift deleted file mode 100644 index fed8a2b..0000000 --- a/OpenDocumentReaderUITests/SnapshotHelper.swift +++ /dev/null @@ -1,320 +0,0 @@ -// Copied verbatim from fastlane, which is where `snapshot` expects it, and MIT -// licensed like the rest of it - not our MPL 2.0. Update it by copying the file -// again rather than by editing it; the version marker at the bottom is what -// fastlane checks it against. -// -// https://github.com/fastlane/fastlane/blob/master/snapshot/lib/assets/SnapshotHelper.swift -// -// -// SnapshotHelper.swift -// Example -// -// Created by Felix Krause on 10/8/15. -// - -// ----------------------------------------------------- -// IMPORTANT: When modifying this file, make sure to -// increment the version number at the very -// bottom of the file to notify users about -// the new SnapshotHelper.swift -// ----------------------------------------------------- - -import Foundation -import XCTest - -@MainActor -func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) { - Snapshot.setupSnapshot(app, waitForAnimations: waitForAnimations) -} - -@MainActor -func snapshot(_ name: String, waitForLoadingIndicator: Bool) { - if waitForLoadingIndicator { - Snapshot.snapshot(name) - } else { - Snapshot.snapshot(name, timeWaitingForIdle: 0) - } -} - -/// - Parameters: -/// - name: The name of the snapshot -/// - timeout: Amount of seconds to wait until the network loading indicator disappears. Pass `0` if you don't want to wait. -@MainActor -func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { - Snapshot.snapshot(name, timeWaitingForIdle: timeout) -} - -enum SnapshotError: Error, CustomDebugStringConvertible { - case cannotFindSimulatorHomeDirectory - case cannotRunOnPhysicalDevice - - var debugDescription: String { - switch self { - case .cannotFindSimulatorHomeDirectory: - return "Couldn't find simulator home location. Please, check SIMULATOR_HOST_HOME env variable." - case .cannotRunOnPhysicalDevice: - return "Can't use Snapshot on a physical device." - } - } -} - -@objcMembers -@MainActor -open class Snapshot: NSObject { - static var app: XCUIApplication? - static var waitForAnimations = true - static var cacheDirectory: URL? - static var screenshotsDirectory: URL? { - return cacheDirectory?.appendingPathComponent("screenshots", isDirectory: true) - } - static var deviceLanguage = "" - static var currentLocale = "" - - open class func setupSnapshot(_ app: XCUIApplication, waitForAnimations: Bool = true) { - - Snapshot.app = app - Snapshot.waitForAnimations = waitForAnimations - - do { - let cacheDir = try getCacheDirectory() - Snapshot.cacheDirectory = cacheDir - setLanguage(app) - setLocale(app) - setLaunchArguments(app) - } catch let error { - NSLog(error.localizedDescription) - } - } - - class func setLanguage(_ app: XCUIApplication) { - guard let cacheDirectory = self.cacheDirectory else { - NSLog("CacheDirectory is not set - probably running on a physical device?") - return - } - - let path = cacheDirectory.appendingPathComponent("language.txt") - - do { - let trimCharacterSet = CharacterSet.whitespacesAndNewlines - deviceLanguage = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet) - app.launchArguments += ["-AppleLanguages", "(\(deviceLanguage))"] - } catch { - NSLog("Couldn't detect/set language...") - } - } - - class func setLocale(_ app: XCUIApplication) { - guard let cacheDirectory = self.cacheDirectory else { - NSLog("CacheDirectory is not set - probably running on a physical device?") - return - } - - let path = cacheDirectory.appendingPathComponent("locale.txt") - - do { - let trimCharacterSet = CharacterSet.whitespacesAndNewlines - currentLocale = try String(contentsOf: path, encoding: .utf8).trimmingCharacters(in: trimCharacterSet) - } catch { - NSLog("Couldn't detect/set locale...") - } - - if currentLocale.isEmpty && !deviceLanguage.isEmpty { - currentLocale = Locale(identifier: deviceLanguage).identifier - } - - if !currentLocale.isEmpty { - app.launchArguments += ["-AppleLocale", "\"\(currentLocale)\""] - } - } - - class func setLaunchArguments(_ app: XCUIApplication) { - guard let cacheDirectory = self.cacheDirectory else { - NSLog("CacheDirectory is not set - probably running on a physical device?") - return - } - - let path = cacheDirectory.appendingPathComponent("snapshot-launch_arguments.txt") - app.launchArguments += ["-FASTLANE_SNAPSHOT", "YES", "-ui_testing"] - - do { - let launchArguments = try String(contentsOf: path, encoding: String.Encoding.utf8) - let regex = try NSRegularExpression(pattern: "(\\\".+?\\\"|\\S+)", options: []) - let matches = regex.matches(in: launchArguments, options: [], range: NSRange(location: 0, length: launchArguments.count)) - let results = matches.map { result -> String in - (launchArguments as NSString).substring(with: result.range) - } - app.launchArguments += results - } catch { - NSLog("Couldn't detect/set launch_arguments...") - } - } - - open class func snapshot(_ name: String, timeWaitingForIdle timeout: TimeInterval = 20) { - if timeout > 0 { - waitForLoadingIndicatorToDisappear(within: timeout) - } - - NSLog("snapshot: \(name)") // more information about this, check out https://docs.fastlane.tools/actions/snapshot/#how-does-it-work - - if Snapshot.waitForAnimations { - sleep(1) // Waiting for the animation to be finished (kind of) - } - - #if os(OSX) - guard let app = self.app else { - NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") - return - } - - app.typeKey(XCUIKeyboardKeySecondaryFn, modifierFlags: []) - #else - - guard self.app != nil else { - NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") - return - } - - let screenshot = XCUIScreen.main.screenshot() - #if os(iOS) && !targetEnvironment(macCatalyst) - let image = XCUIDevice.shared.orientation.isLandscape ? fixLandscapeOrientation(image: screenshot.image) : screenshot.image - #else - let image = screenshot.image - #endif - - guard var simulator = ProcessInfo().environment["SIMULATOR_DEVICE_NAME"], let screenshotsDir = screenshotsDirectory else { return } - - do { - // The simulator name contains "Clone X of " inside the screenshot file when running parallelized UI Tests on concurrent devices - let regex = try NSRegularExpression(pattern: "Clone [0-9]+ of ") - let range = NSRange(location: 0, length: simulator.count) - simulator = regex.stringByReplacingMatches(in: simulator, range: range, withTemplate: "") - - let path = screenshotsDir.appendingPathComponent("\(simulator)-\(name).png") - #if swift(<5.0) - try UIImagePNGRepresentation(image)?.write(to: path, options: .atomic) - #else - try image.pngData()?.write(to: path, options: .atomic) - #endif - } catch let error { - NSLog("Problem writing screenshot: \(name) to \(screenshotsDir)/\(simulator)-\(name).png") - NSLog(error.localizedDescription) - } - #endif - } - - class func fixLandscapeOrientation(image: UIImage) -> UIImage { - #if os(watchOS) - return image - #else - if #available(iOS 10.0, *) { - let format = UIGraphicsImageRendererFormat() - format.scale = image.scale - let renderer = UIGraphicsImageRenderer(size: image.size, format: format) - return renderer.image { context in - image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)) - } - } else { - return image - } - #endif - } - - class func waitForLoadingIndicatorToDisappear(within timeout: TimeInterval) { - #if os(tvOS) - return - #endif - - guard let app = self.app else { - NSLog("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") - return - } - - let networkLoadingIndicator = app.otherElements.deviceStatusBars.networkLoadingIndicators.element - let networkLoadingIndicatorDisappeared = XCTNSPredicateExpectation(predicate: NSPredicate(format: "exists == false"), object: networkLoadingIndicator) - _ = XCTWaiter.wait(for: [networkLoadingIndicatorDisappeared], timeout: timeout) - } - - class func getCacheDirectory() throws -> URL { - let cachePath = "Library/Caches/tools.fastlane" - // on OSX config is stored in /Users//Library - // and on iOS/tvOS/WatchOS it's in simulator's home dir - #if os(OSX) - let homeDir = URL(fileURLWithPath: NSHomeDirectory()) - return homeDir.appendingPathComponent(cachePath) - #elseif arch(i386) || arch(x86_64) || arch(arm64) - guard let simulatorHostHome = ProcessInfo().environment["SIMULATOR_HOST_HOME"] else { - throw SnapshotError.cannotFindSimulatorHomeDirectory - } - let homeDir = URL(fileURLWithPath: simulatorHostHome) - return homeDir.appendingPathComponent(cachePath) - #else - throw SnapshotError.cannotRunOnPhysicalDevice - #endif - } -} - -private extension XCUIElementAttributes { - var isNetworkLoadingIndicator: Bool { - if hasAllowListedIdentifier { return false } - - let hasOldLoadingIndicatorSize = frame.size == CGSize(width: 10, height: 20) - let hasNewLoadingIndicatorSize = frame.size.width.isBetween(46, and: 47) && frame.size.height.isBetween(2, and: 3) - - return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize - } - - var hasAllowListedIdentifier: Bool { - let allowListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] - - return allowListedIdentifiers.contains(identifier) - } - - func isStatusBar(_ deviceWidth: CGFloat) -> Bool { - if elementType == .statusBar { return true } - guard frame.origin == .zero else { return false } - - let oldStatusBarSize = CGSize(width: deviceWidth, height: 20) - let newStatusBarSize = CGSize(width: deviceWidth, height: 44) - - return [oldStatusBarSize, newStatusBarSize].contains(frame.size) - } -} - -private extension XCUIElementQuery { - var networkLoadingIndicators: XCUIElementQuery { - let isNetworkLoadingIndicator = NSPredicate { (evaluatedObject, _) in - guard let element = evaluatedObject as? XCUIElementAttributes else { return false } - - return element.isNetworkLoadingIndicator - } - - return self.containing(isNetworkLoadingIndicator) - } - - @MainActor - var deviceStatusBars: XCUIElementQuery { - guard let app = Snapshot.app else { - fatalError("XCUIApplication is not set. Please call setupSnapshot(app) before snapshot().") - } - - let deviceWidth = app.windows.firstMatch.frame.width - - let isStatusBar = NSPredicate { (evaluatedObject, _) in - guard let element = evaluatedObject as? XCUIElementAttributes else { return false } - - return element.isStatusBar(deviceWidth) - } - - return self.containing(isStatusBar) - } -} - -private extension CGFloat { - func isBetween(_ numberA: CGFloat, and numberB: CGFloat) -> Bool { - return numberA...numberB ~= self - } -} - -// Please don't remove the lines below -// They are used to detect outdated configuration files -// SnapshotHelperVersion [1.30] diff --git a/OpenDocumentReaderUITests/Snapshots.swift b/OpenDocumentReaderUITests/Snapshots.swift new file mode 100644 index 0000000..0a18b0c --- /dev/null +++ b/OpenDocumentReaderUITests/Snapshots.swift @@ -0,0 +1,115 @@ +import Foundation +import XCTest + +/// The hand-off to `fastlane snapshot`, which is a directory and a file name. +/// +/// Nothing is passed in process. `capture_ios_screenshots` writes what the run +/// is for into a cache directory on the host, launches this bundle once per +/// language, and afterwards collects whatever PNGs it finds there. That is the +/// whole protocol: two files read, one directory written. +/// +/// fastlane ships a `SnapshotHelper.swift` to do this, and it used to sit here +/// verbatim - three hundred lines carrying macOS, tvOS and watchOS branches, a +/// landscape correction, and a wait on the network activity indicator that iOS +/// has not drawn since 13. None of it applied to this app, and none of it could +/// be read or formatted like the rest of these sources, because a copied file +/// has to stay byte for byte theirs to be replaceable. This is the part we use, +/// written as ours. +/// +/// One thing theirs does that this does not: it passes on the `launch_arguments` +/// from the lane, through a third file. The lane sets none, and the app takes +/// the only argument it cares about from ``ScreenshotTests`` directly. +/// +/// https://docs.fastlane.tools/actions/snapshot/ +enum Snapshots { + + /// Where fastlane leaves what it wants, and looks for what it gets back. + /// Absent off a simulator, which is the one place this cannot run. + private static var handOff: URL? { + guard let host = ProcessInfo.processInfo.environment["SIMULATOR_HOST_HOME"] else { + return nil + } + + return URL(fileURLWithPath: host).appendingPathComponent("Library/Caches/tools.fastlane") + } + + private static var pictures: URL? { + handOff?.appendingPathComponent("screenshots", isDirectory: true) + } + + /// Puts the language and region this run is for on the app's arguments. + /// + /// One launch of this bundle is one language. The app cannot work out which + /// on its own - the simulator is the same one every time - so fastlane names + /// it in a file and it is handed over here. + @MainActor + static func prepare(_ app: XCUIApplication) { + guard let handOff else { + XCTFail("no SIMULATOR_HOST_HOME: screenshots are taken on a simulator, by fastlane") + + return + } + + let language = read(handOff.appendingPathComponent("language.txt")) + if let language { + app.launchArguments += ["-AppleLanguages", "(\(language))"] + } + + // The region decides how a date and a number are written, which is half + // of what a spreadsheet screenshot shows. It follows the language when + // the lane does not name one of its own. + let region = + read(handOff.appendingPathComponent("locale.txt")) + ?? language.map { Locale(identifier: $0).identifier } + if let region { + app.launchArguments += ["-AppleLocale", "\"\(region)\""] + } + } + + /// Writes the screen under the name the release expects to find. + /// + /// `scripts/store-screenshots.py` reads these back by name, so the shape of + /// it - the device, then the screen - is a promise to that script. + @MainActor + static func take(_ name: String) { + guard let pictures, + let simulator = ProcessInfo.processInfo.environment["SIMULATOR_DEVICE_NAME"] + else { + XCTFail("nowhere to write \(name): fastlane did not set this run up") + + return + } + + // whatever is still easing into place, which no element can be waited on + // for - the tab bar settling, a keyboard finishing its way up + Thread.sleep(forTimeInterval: 0.5) + + let file = pictures.appendingPathComponent("\(model(of: simulator))-\(name).png") + + do { + try FileManager.default.createDirectory(at: pictures, withIntermediateDirectories: true) + try XCUIScreen.main.screenshot().pngRepresentation.write(to: file, options: .atomic) + } catch { + XCTFail("could not write \(file.lastPathComponent): \(error.localizedDescription)") + } + } + + /// The model's own name. xcodebuild calls a device "Clone 2 of iPhone 17 Pro + /// Max" when it runs several at once, and the release expects the plain one. + private static func model(of simulator: String) -> String { + guard simulator.hasPrefix("Clone "), let of = simulator.range(of: " of ") else { + return simulator + } + + return String(simulator[of.upperBound...]) + } + + /// A line fastlane left, or `nil` where it left nothing to say. + private static func read(_ file: URL) -> String? { + guard let text = try? String(contentsOf: file, encoding: .utf8) else { return nil } + + let line = text.trimmingCharacters(in: .whitespacesAndNewlines) + + return line.isEmpty ? nil : line + } +} diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 2032f7d..404c183 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -171,6 +171,11 @@ platform :ios do "--cellularMode active --cellularBars 4 --batteryState discharging --batteryLevel 100", # a rerun replaces the set rather than adding to it clear_previous_screenshots: true, + # snapshot refuses to start without a file named SnapshotHelper.swift, + # and checks its version marker. We do not carry theirs - the hand-off is + # OpenDocumentReaderUITests/Snapshots.swift, which is ours - so there is + # nothing for it to find and nothing for it to check. + skip_helper_version_check: true, # the runner has no browser to open the summary in, and no one watching it skip_open_summary: true, stop_after_first_error: true diff --git a/scripts/format.sh b/scripts/format.sh index 6c72cd7..8a07f15 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -27,11 +27,6 @@ if ! xcrun --find swift-format >/dev/null 2>&1; then exit 1 fi -# SnapshotHelper.swift is left out: it belongs to fastlane and is kept byte for -# byte as they ship it, so the next version can be copied over it. -# -# The comment stays out here. bash 3.2, which is the one macOS ships and the one -# CI runs, cannot parse an apostrophe in a comment inside a <( ). files=() while IFS= read -r -d '' file; do # tracked files can be staged for deletion and no longer exist on disk @@ -39,8 +34,7 @@ while IFS= read -r -d '' file; do files+=("$file") fi done < <( - git ls-files -z --cached --others --exclude-standard -- \ - '*.swift' ':!:OpenDocumentReaderUITests/SnapshotHelper.swift' + git ls-files -z --cached --others --exclude-standard -- '*.swift' ) if [ ${#files[@]} -eq 0 ]; then From d0c4ab59b987a8925c97a32e69cc5c0be4ffcf38 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Mon, 17 Aug 2026 15:02:16 +0200 Subject: [PATCH 5/5] Import the store description rather than load it by hand The framing script needs to know which locales there are and what size a picture has to be, and it was reaching for that by reading the other script off disk and running it. A plain import does the same thing, once the file is named something Python can say. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01E6tn8P25cBDmrA67zrhfwN --- README.md | 2 +- fastlane/Fastfile | 4 ++-- fastlane/screenshots/README.md | 2 +- scripts/frame-screenshots.py | 18 ++++-------------- ...ore-screenshots.py => store_screenshots.py} | 9 ++++++--- 5 files changed, 14 insertions(+), 21 deletions(-) rename scripts/{store-screenshots.py => store_screenshots.py} (96%) diff --git a/README.md b/README.md index d1e0754..fabb71f 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ Nothing is tapped to get there. The app takes `-ODRScreenshot ` in Debug builds and puts itself on that screen, so the same picture comes out in every language without driving Apple's document browser in eleven of them - see `OpenDocumentReader/ScreenshotMode.swift` and the `ODR Screenshots` scheme. -`scripts/store-screenshots.py` checks the set against the sizes App Store +`scripts/store_screenshots.py` checks the set against the sizes App Store Connect takes, and the `listing` job hands it to `deliver` alongside the text. The same set goes to both apps. diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 404c183..6b2ea02 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -21,7 +21,7 @@ IPA_DIR = File.expand_path("../build").freeze # Absolute for the same reason. They resolve the repository from their own path, # so they do not care which of the two they are called from. STORE_LISTING = File.expand_path("../scripts/store-listing.py").freeze -STORE_SCREENSHOTS = File.expand_path("../scripts/store-screenshots.py").freeze +STORE_SCREENSHOTS = File.expand_path("../scripts/store_screenshots.py").freeze FRAME_SCREENSHOTS = File.expand_path("../scripts/frame-screenshots.py").freeze MAKE_DOCUMENTS = File.expand_path("../scripts/make-screenshot-documents.py").freeze @@ -33,7 +33,7 @@ FRAMED_DIR = File.expand_path("framed").freeze # The two sizes App Store Connect asks an app that runs on both for, named by # whatever the runner's Xcode calls them. Newest first, and the first one the # runner actually has wins - a simulator's name changes with every Xcode, the -# number of pixels it has does not, and store-screenshots.py checks that. +# number of pixels it has does not, and store_screenshots.py checks that. SCREENSHOT_DEVICES = [ ["iPhone 17 Pro Max", "iPhone 16 Pro Max", "iPhone 15 Pro Max"], ["iPad Pro 13-inch (M5)", "iPad Pro 13-inch (M4)", "iPad Pro (12.9-inch) (6th generation)"], diff --git a/fastlane/screenshots/README.md b/fastlane/screenshots/README.md index aa73e1f..9320b2a 100644 --- a/fastlane/screenshots/README.md +++ b/fastlane/screenshots/README.md @@ -33,7 +33,7 @@ shows them: | `04-slides` | a presentation | Two devices, because an app that runs on iPhone and iPad has to hand in both: a -6.9" iPhone and a 13" iPad. `scripts/store-screenshots.py` holds the sizes App +6.9" iPhone and a 13" iPad. `scripts/store_screenshots.py` holds the sizes App Store Connect accepts and checks the set against them; `Fastfile` holds the simulators to look for, newest first, because what a simulator is called changes with every Xcode and what it is worth does not. diff --git a/scripts/frame-screenshots.py b/scripts/frame-screenshots.py index 69af2c5..b0886ca 100755 --- a/scripts/frame-screenshots.py +++ b/scripts/frame-screenshots.py @@ -8,7 +8,7 @@ # # `fastlane ios screenshots` takes the raw captures into fastlane/screenshots; # this reads them and writes the framed set to fastlane/framed, which is what -# `scripts/store-screenshots.py` then checks and stages. The raw set is left +# `scripts/store_screenshots.py` then checks and stages. The raw set is left # alone, so a framing change costs a rerun of this and not of the simulators. # # Nothing here is drawn from an image file. Every part of the design is a @@ -24,13 +24,14 @@ import argparse import bisect import functools -import importlib.util import json import math import shutil import sys from pathlib import Path +import store_screenshots as store + try: from PIL import Image, ImageChops, ImageDraw, ImageFilter, ImageFont except ImportError: @@ -41,17 +42,6 @@ CAPTURED = ROOT / "fastlane" / "screenshots" FRAMED = ROOT / "fastlane" / "framed" - -def load(path, name): - """Import a sibling script, whose file name is not an identifier.""" - spec = importlib.util.spec_from_file_location(name, path) - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module - - -store = load(ROOT / "scripts" / "store-screenshots.py", "store_screenshots") - # The design, as fractions of the canvas rather than pixels, because the canvas # is whatever the capture is - 1320x2868 today and something else after the next # device. @@ -669,7 +659,7 @@ def main(argv=None): with Image.open(path) as shot: # a capture of a device the store does not ask for is left where - # it is; store-screenshots.py is what says the set is wrong + # it is; store_screenshots.py is what says the set is wrong if store.device(*shot.size) is None: print(f"{locale}: skipping {path.name}, {shot.width}x{shot.height} is no " "size the store takes", file=sys.stderr) diff --git a/scripts/store-screenshots.py b/scripts/store_screenshots.py similarity index 96% rename from scripts/store-screenshots.py rename to scripts/store_screenshots.py index 829496b..e454636 100755 --- a/scripts/store-screenshots.py +++ b/scripts/store_screenshots.py @@ -8,9 +8,12 @@ # release run, from the build going out, and handed to deliver from there. # `fastlane ios screenshots` takes them; this says what a full set is. # -# scripts/store-screenshots.py --languages what to capture -# scripts/store-screenshots.py check what was captured -# scripts/store-screenshots.py --stage DIR check it and stage it +# scripts/store_screenshots.py --languages what to capture +# scripts/store_screenshots.py check what was captured +# scripts/store_screenshots.py --stage DIR check it and stage it +# +# Named with an underscore, unlike its neighbours, because frame-screenshots.py +# imports it and a hyphen is not an identifier. # # The store has eleven locales and the app is translated into nine of them. # The other two get the English pictures, which is what their storefront would