From 6bdf35e20f5e05062ab4667d755bb1575572f466 Mon Sep 17 00:00:00 2001 From: "Artem V. Ageev" Date: Sat, 4 Jan 2025 15:42:07 +0200 Subject: [PATCH 1/2] add github-actions --- .github/dependabot.yml | 7 ++ .github/workflows/make.ps1 | 167 +++++++++++++++++++++++++++++++++++++ .github/workflows/make.sh | 98 ++++++++++++++++++++++ .github/workflows/make.yml | 49 +++++++++++ 4 files changed, 321 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/make.ps1 create mode 100644 .github/workflows/make.sh create mode 100644 .github/workflows/make.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..64284b9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +--- +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/make.ps1 b/.github/workflows/make.ps1 new file mode 100644 index 0000000..e69eecd --- /dev/null +++ b/.github/workflows/make.ps1 @@ -0,0 +1,167 @@ +#!/usr/bin/env pwsh +############################################################################################################## + +Function Show-Usage { + " +vagrant = 'it-gro/win10-ltsc-eval' +download = 'https://microsoft.com/en-us/evalcenter' +package = 'https://learn.microsoft.com/en-us/mem/configmgr/develop/apps/how-to-create-the-windows-installer-file-msi' +shell = 'https://learn.microsoft.com/en-us/powershell' + +Usage: pwsh -File $($PSCommandPath) [OPTIONS] +Options: + build + lint +" | Out-Host +} + +Function Build-Project { + New-Variable -Option Constant -Name VAR -Value @{ + Src = 'examples' + Use = 'package' + Pkg = 'package\components.txt' + } + If (! (Test-Path -Path $Var.Src)) { + "$([char]27)[31m.... Source do not find!$([char]27)[0m" | Out-Host + Exit 1 + } + If (Test-Path -Path '.gitmodules') { + & git submodule update --init --recursive --force --remote | Out-Host + "$([char]27)[33m.... [[$($LastExitCode)]] git submodule update$([char]27)[0m" | Out-Host + } + @( + @{ + Cmd = 'lazbuild' + Url = 'https://fossies.org/windows/misc/lazarus-3.6-fpc-3.2.2-win64.exe' + Path = "C:\Lazarus" + } + ) | Where-Object { ! (Test-Path -Path $_.Path) } | + ForEach-Object { + $_.Url | Request-File | Install-Program + $Env:PATH+=";$($_.Path)" + (Get-Command $_.Cmd).Source | Out-Host + } + If (Test-Path -Path $VAR.Use) { + If (Test-Path -Path $VAR.Pkg) { + Get-Content -Path $VAR.Pkg | + Where-Object { + ! (Test-Path -Path "$($VAR.Use)\$($_)") && + ! (& lazbuild --verbose-pkgsearch $_ ) && + ! (& lazbuild --add-package $_) + } | ForEach-Object { + Return @{ + Uri = "https://packages.lazarus-ide.org/$($_).zip" + Path = "$($VAR.Use)\$($_)" + OutFile = (New-TemporaryFile).FullName + } + } | ForEach-Object -Parallel { + Invoke-WebRequest -OutFile $_.OutFile -Uri $_.Uri + Expand-Archive -Path $_.OutFile -DestinationPath $_.Path + Remove-Item $_.OutFile + Return "$([char]27)[33m.... download $($_.Uri)$([char]27)[0m" + } | Out-Host + } + (Get-ChildItem -Filter '*.lpk' -Recurse -File –Path $VAR.Use).FullName | + ForEach-Object { + & lazbuild --add-package-link $_ | Out-Null + Return "$([char]27)[33m.... [$($LastExitCode)] add package link $($_)$([char]27)[0m" + } | Out-Host + } + Exit ( + (Get-ChildItem -Filter '*.lpi' -Recurse -File –Path $Var.Src).FullName | + Sort-Object | + ForEach-Object { + $Output = (& lazbuild --build-all --recursive --no-write-project $_) + $Result = @("$([char]27)[32m.... [$($LastExitCode)] build project $($_)$([char]27)[0m") + $exitCode = Switch ($LastExitCode) { + 0 { + $Result += $Output | Select-String -Pattern 'Linking' + 0 + } + Default { + $Result += $Output | Select-String -Pattern 'Error:', 'Fatal:' + 1 + } + } + $Result | Out-Host + Return $exitCode + } | Measure-Object -Sum + ).Sum +} + +Function Request-File { + While ($Input.MoveNext()) { + New-Variable -Option Constant -Name VAR -Value @{ + Uri = $Input.Current + OutFile = (Split-Path -Path $Input.Current -Leaf).Split('?')[0] + } + Invoke-WebRequest @VAR + Return $VAR.OutFile + } +} + +Function Install-Program { + While ($Input.MoveNext()) { + Switch ((Split-Path -Path $Input.Current -Leaf).Split('.')[-1]) { + 'msi' { + & msiexec /passive /package $Input.Current | Out-Null + } + Default { + & ".\$($Input.Current)" /SP- /VERYSILENT /SUPPRESSMSGBOXES /NORESTART | Out-Null + } + } + Remove-Item $Input.Current + } +} + +Function Request-URL([Switch] $Post) { + $VAR = Switch ($Post) { + True { + Return @{ + Method = 'POST' + Headers = @{ + ContentType = 'application/json' + } + Uri = 'https://postman-echo.com/post' + Body = @{ + One = '1' + } | ConvertTo-Json + } + } + False { + Return @{ + Uri = 'https://postman-echo.com/get' + } + } + } + Return (Invoke-WebRequest @VAR | ConvertFrom-Json).Headers +} + +Function Switch-Action { + $ErrorActionPreference = 'stop' + Set-PSDebug -Strict #-Trace 1 + Invoke-ScriptAnalyzer -EnableExit -Path $PSCommandPath + If ($args.count -gt 0) { + Switch ($args[0]) { + 'lint' { + Invoke-ScriptAnalyzer -EnableExit -Recurse -Path '.' + (Get-ChildItem -Filter '*.ps1' -Recurse -Path '.').FullName | + ForEach-Object { + Invoke-Formatter -ScriptDefinition $(Get-Content -Path $_ | Out-String) | + Set-Content -Path $_ + } + } + 'build' { + Build-Project + } + Default { + Show-Usage + } + } + } Else { + Show-Usage + } +} + +############################################################################################################## +Switch-Action @args diff --git a/.github/workflows/make.sh b/.github/workflows/make.sh new file mode 100644 index 0000000..2aae097 --- /dev/null +++ b/.github/workflows/make.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +############################################################################################################## + +function priv_clippit +( + cat <&2 + fi + declare -i errors=0 + while read -r; do + declare -A TMP=( + [out]=$(mktemp) + ) + if (lazbuild --build-all --recursive --no-write-project "${REPLY}" > "${TMP[out]}"); then + printf '\x1b[32m\t[%s]\t%s\x1b[0m\n' "${?}" "${REPLY}" + grep --color='always' 'Linking' "${TMP[out]}" + else + printf '\x1b[31m\t[%s]\t%s\x1b[0m\n' "${?}" "${REPLY}" + grep --color='always' --extended-regexp '(Error|Fatal):' "${TMP[out]}" + ((errors+=1)) + fi 1>&2 + rm "${TMP[out]}" + done < <(find "${VAR[src]}" -type 'f' -name '*.lpi' | sort) + exit "${errors}" +) + +function priv_main +( + set -euo pipefail + if ((${#})); then + case ${1} in + build) priv_lazbuild ;; + *) priv_clippit ;; + esac + else + priv_clippit + fi +) + +############################################################################################################## +priv_main "${@}" >/dev/null diff --git a/.github/workflows/make.yml b/.github/workflows/make.yml new file mode 100644 index 0000000..006d55c --- /dev/null +++ b/.github/workflows/make.yml @@ -0,0 +1,49 @@ +--- +name: Make + +on: + schedule: + - cron: '0 0 1 * *' + push: + branches: + - "**" + pull_request: + branches: + - master + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ${{ matrix.os }} + timeout-minutes: 120 + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: true + + - name: Build on Linux + if: runner.os == 'Linux' + shell: bash + run: bash .github/workflows/make.sh build + + - name: Build on Windows + if: runner.os == 'Windows' + shell: powershell + run: pwsh -File .github/workflows/make.ps1 build + + - name: Archive + if: runner.os == 'Windows' + uses: actions/upload-artifact@v4 + with: + retention-days: 1 + path: src\bin\*.exe From dba7afb09e939bf427fa6124ac0f91b4dc8b4a20 Mon Sep 17 00:00:00 2001 From: "Artem V. Ageev" Date: Tue, 7 Jan 2025 16:27:01 +0200 Subject: [PATCH 2/2] add github-actions --- .github/workflows/make.json | 7 ++ .github/workflows/make.ps1 | 104 ++++++++++++++--------- .github/workflows/make.sh | 82 ++++++++++-------- examples/BoldText/OdtBoldTextExample.lpi | 11 ++- examples/BoldText/OdtBoldTextExample.lps | 24 ++++-- examples/ImprovedDemo/ImprovedDemo.res | Bin 1779 -> 1825 bytes examples/fpcTestfpOdf/fpcTestfpOdf.res | Bin 139052 -> 139100 bytes 7 files changed, 140 insertions(+), 88 deletions(-) create mode 100644 .github/workflows/make.json diff --git a/.github/workflows/make.json b/.github/workflows/make.json new file mode 100644 index 0000000..07372d8 --- /dev/null +++ b/.github/workflows/make.json @@ -0,0 +1,7 @@ +{ + "app" : "examples", + "lib" : "package", + "tst" : "test/fpOdfTest.lpi", + "pkg" : [ + ] +} diff --git a/.github/workflows/make.ps1 b/.github/workflows/make.ps1 index e69eecd..5458c87 100644 --- a/.github/workflows/make.ps1 +++ b/.github/workflows/make.ps1 @@ -16,13 +16,9 @@ Options: } Function Build-Project { - New-Variable -Option Constant -Name VAR -Value @{ - Src = 'examples' - Use = 'package' - Pkg = 'package\components.txt' - } - If (! (Test-Path -Path $Var.Src)) { - "$([char]27)[31m.... Source do not find!$([char]27)[0m" | Out-Host + New-Variable -Option Constant -Name VAR -Value (Get-Content -Path $PSCommandPath.Replace('ps1', 'json') | ConvertFrom-Json) + If (! (Test-Path -Path $Var.app)) { + "$([char]27)[31m.... $($Var.app) did not find!$([char]27)[0m" | Out-Host Exit 1 } If (Test-Path -Path '.gitmodules') { @@ -35,45 +31,69 @@ Function Build-Project { Url = 'https://fossies.org/windows/misc/lazarus-3.6-fpc-3.2.2-win64.exe' Path = "C:\Lazarus" } - ) | Where-Object { ! (Test-Path -Path $_.Path) } | - ForEach-Object { - $_.Url | Request-File | Install-Program - $Env:PATH+=";$($_.Path)" - (Get-Command $_.Cmd).Source | Out-Host - } - If (Test-Path -Path $VAR.Use) { - If (Test-Path -Path $VAR.Pkg) { - Get-Content -Path $VAR.Pkg | - Where-Object { - ! (Test-Path -Path "$($VAR.Use)\$($_)") && - ! (& lazbuild --verbose-pkgsearch $_ ) && - ! (& lazbuild --add-package $_) - } | ForEach-Object { - Return @{ - Uri = "https://packages.lazarus-ide.org/$($_).zip" - Path = "$($VAR.Use)\$($_)" - OutFile = (New-TemporaryFile).FullName - } - } | ForEach-Object -Parallel { - Invoke-WebRequest -OutFile $_.OutFile -Uri $_.Uri - Expand-Archive -Path $_.OutFile -DestinationPath $_.Path - Remove-Item $_.OutFile - Return "$([char]27)[33m.... download $($_.Uri)$([char]27)[0m" - } | Out-Host + ) | Where-Object { + ! (Test-Path -Path $_.Path) + } | ForEach-Object { + $_.Url | Request-File | Install-Program + $Env:PATH+=";$($_.Path)" + Return (Get-Command $_.Cmd).Source + } | Out-Host + $VAR.Pkg | ForEach-Object { + @{ + Name = $_ + Uri = "https://packages.lazarus-ide.org/$($_).zip" + Path = "$($Env:HOME)\.lazarus\onlinepackagemanager\packages\$($_)" + OutFile = (New-TemporaryFile).FullName } - (Get-ChildItem -Filter '*.lpk' -Recurse -File –Path $VAR.Use).FullName | + } | Where-Object { + ! (Test-Path -Path $_.Path) && + ! (& lazbuild --verbose-pkgsearch $_.Name ) && + ! (& lazbuild --add-package $_.Name) + } | ForEach-Object -Parallel { + Invoke-WebRequest -OutFile $_.OutFile -Uri $_.Uri + New-Item -Type Directory -Path $_.Path | Out-Null + Expand-Archive -Path $_.OutFile -DestinationPath $_.Path + Remove-Item $_.OutFile + (Get-ChildItem -Filter '*.lpk' -Recurse -File –Path $_.Path).FullName | + ForEach-Object { + & lazbuild --add-package-link $_ | Out-Null + Return "$([char]27)[33m.... [$($LastExitCode)] add package link $($_)$([char]27)[0m" + } + } | Out-Host + If (Test-Path -Path $VAR.lib) { + (Get-ChildItem -Filter '*.lpk' -Recurse -File –Path $VAR.lib).FullName | ForEach-Object { & lazbuild --add-package-link $_ | Out-Null Return "$([char]27)[33m.... [$($LastExitCode)] add package link $($_)$([char]27)[0m" } | Out-Host } - Exit ( - (Get-ChildItem -Filter '*.lpi' -Recurse -File –Path $Var.Src).FullName | - Sort-Object | + Exit $(Switch (Test-Path -Path $Var.tst) { + true { + $Output = ( + & lazbuild --build-all --recursive --no-write-project $VAR.tst | + Where-Object { + $_.Contains('Linking') + } | ForEach-Object { + $_.Split(' ')[2].Replace('bin', 'bin\.') + } + ) + $Output = (& $Output --all --format=plain --progress) + $exitCode = Switch ($LastExitCode) { + 0 {0} + Default { + 1 + } + } + $Output | Out-Host + Return $exitCode +K } + Default {0} + }) + ( + (Get-ChildItem -Filter '*.lpi' -Recurse -File –Path $Var.app).FullName | ForEach-Object { $Output = (& lazbuild --build-all --recursive --no-write-project $_) $Result = @("$([char]27)[32m.... [$($LastExitCode)] build project $($_)$([char]27)[0m") - $exitCode = Switch ($LastExitCode) { + $exitCode = $(Switch ($LastExitCode) { 0 { $Result += $Output | Select-String -Pattern 'Linking' 0 @@ -82,7 +102,7 @@ Function Build-Project { $Result += $Output | Select-String -Pattern 'Error:', 'Fatal:' 1 } - } + }) $Result | Out-Host Return $exitCode } | Measure-Object -Sum @@ -116,8 +136,8 @@ Function Install-Program { Function Request-URL([Switch] $Post) { $VAR = Switch ($Post) { - True { - Return @{ + true { + @{ Method = 'POST' Headers = @{ ContentType = 'application/json' @@ -128,8 +148,8 @@ Function Request-URL([Switch] $Post) { } | ConvertTo-Json } } - False { - Return @{ + false { + @{ Uri = 'https://postman-echo.com/get' } } diff --git a/.github/workflows/make.sh b/.github/workflows/make.sh index 2aae097..04643b4 100644 --- a/.github/workflows/make.sh +++ b/.github/workflows/make.sh @@ -17,19 +17,22 @@ EOF function priv_lazbuild ( + mapfile -t < "${0//sh/json}" declare -rA VAR=( - [src]='examples' - [use]='package' - [pkg]='package/components.txt' + [app]=$(jq --raw-output --exit-status '.app' <<< "${MAPFILE[@]}") + [lib]=$(jq --raw-output --exit-status '.lib' <<< "${MAPFILE[@]}") + [tst]=$(jq --raw-output --exit-status '.tst' <<< "${MAPFILE[@]}") + [opt]=$(jq --raw-output --exit-status '.opt' <<< "${MAPFILE[@]}") ) - if ! [[ -d "${VAR[src]}" ]]; then - printf '\x1b[31m\tSource do not find!\x1b[0m\n' + if ! [[ -d "${VAR[app]}" ]]; then + printf '\x1b[32m\t[%s] did not find!\x1b[0m\n' "${VAR[app]}" exit 1 - fi + fi >&2 if [[ -f '.gitmodules' ]]; then git submodule update --init --recursive --force --remote & fi if ! (command -v lazbuild); then + # shellcheck source=/dev/null source '/etc/os-release' case ${ID:?} in debian | ubuntu) @@ -37,33 +40,44 @@ function priv_lazbuild sudo apt-get install -y lazarus{-ide-qt5,} & ;; esac - fi + fi &>/dev/null + wait + while read -r; do + ( + declare -rA TMP=( + [url]="https://packages.lazarus-ide.org/${REPLY}.zip" + [dir]="${HOME}/.lazarus/onlinepackagemanager/packages/${REPLY}" + [out]=$(mktemp) + ) + if ! [[ -d "${TMP[dir]}" ]] && + ! (lazbuild --verbose-pkgsearch "${REPLY}") && + ! (lazbuild --add-package "${REPLY}"); then + wget --quiet --output-document "${TMP[out]}" "${TMP[url]}" + mkdir --parents "${TMP[dir]}" + unzip -o "${TMP[out]}" -d "${TMP[dir]}" + rm --verbose "${TMP[out]}" + find "${TMP[dir]}" -type 'f' -name '*.lpk' -printf '\033[33m\tadd package link\t%p\033[0m\n' -exec \ + lazbuild --add-package-link {} + >&2 + fi + ) & + done < <(jq --raw-output --exit-status '.pkg[]' <<< "${MAPFILE[@]}") wait - if [[ -d "${VAR[use]}" ]]; then - if [[ -f "${VAR[pkg]}" ]]; then - while read -r; do - if [[ -n "${REPLY}" ]] && - ! [[ -d "${VAR[use]}/${REPLY}" ]] && - ! (lazbuild --verbose-pkgsearch "${REPLY}") && - ! (lazbuild --add-package "${REPLY}"); then - ( - declare -A TMP=( - [url]="https://packages.lazarus-ide.org/${REPLY}.zip" - [dir]="${VAR[use]}/${REPLY}" - [out]=$(mktemp) - ) - wget --quiet --output-document "${TMP[out]}" "${TMP[url]}" - unzip -o "${TMP[out]}" -d "${TMP[dir]}" - rm --verbose "${TMP[out]}" - ) & - fi - done < "${VAR[pkg]}" - wait + if [[ -d "${VAR[lib]}" ]]; then + find "${VAR[lib]}" -type 'f' -name '*.lpk' -printf '\033[33m\tadd package link\t%p\033[0m\n' -exec \ + lazbuild --add-package-link {} + >&2 + fi + declare -i exitCode=0 + if [[ -f "${VAR[tst]}" ]]; then + declare -A TMP=( + [tst]=$( + lazbuild --build-all --recursive --no-write-project "${VAR[tst]}" | + awk '/Linking/{print $3}' + ) + ) + if ! ("${TMP[tst]}" --all --format=plain --progress >&2); then + ((exitCode+=1)) fi - find "${VAR[use]}" -type 'f' -name '*.lpk' -printf '\033[33m\tadd package link\t%p\033[0m\n' -exec \ - lazbuild --add-package-link {} + 1>&2 fi - declare -i errors=0 while read -r; do declare -A TMP=( [out]=$(mktemp) @@ -74,11 +88,11 @@ function priv_lazbuild else printf '\x1b[31m\t[%s]\t%s\x1b[0m\n' "${?}" "${REPLY}" grep --color='always' --extended-regexp '(Error|Fatal):' "${TMP[out]}" - ((errors+=1)) - fi 1>&2 + ((exitCode+=1)) + fi >&2 rm "${TMP[out]}" - done < <(find "${VAR[src]}" -type 'f' -name '*.lpi' | sort) - exit "${errors}" + done < <(find "${VAR[app]}" -type 'f' -name '*.lpi') + exit "${exitCode}" ) function priv_main diff --git a/examples/BoldText/OdtBoldTextExample.lpi b/examples/BoldText/OdtBoldTextExample.lpi index 2643e79..a1fccff 100644 --- a/examples/BoldText/OdtBoldTextExample.lpi +++ b/examples/BoldText/OdtBoldTextExample.lpi @@ -1,16 +1,16 @@ - + + - <UseAppBundle Value="False"/> <ResourceType Value="res"/> @@ -31,10 +31,13 @@ <Mode0 Name="default"/> </Modes> </RunParams> - <RequiredPackages Count="1"> + <RequiredPackages Count="2"> <Item1> - <PackageName Value="fpOdf"/> + <PackageName Value="LCL"/> </Item1> + <Item2> + <PackageName Value="fpOdf"/> + </Item2> </RequiredPackages> <Units Count="1"> <Unit0> diff --git a/examples/BoldText/OdtBoldTextExample.lps b/examples/BoldText/OdtBoldTextExample.lps index 8664117..82f7f33 100644 --- a/examples/BoldText/OdtBoldTextExample.lps +++ b/examples/BoldText/OdtBoldTextExample.lps @@ -1,21 +1,20 @@ <?xml version="1.0" encoding="UTF-8"?> <CONFIG> <ProjectSession> - <Version Value="11"/> + <Version Value="12"/> <BuildModes Active="Default"/> - <Units Count="3"> + <Units Count="4"> <Unit0> <Filename Value="OdtBoldTextExample.lpr"/> <IsPartOfProject Value="True"/> - <IsVisibleTab Value="True"/> - <TopLine Value="5"/> - <CursorPos X="60" Y="39"/> + <TopLine Value="24"/> + <CursorPos X="24" Y="29"/> <UsageCount Value="60"/> <Loaded Value="True"/> </Unit0> <Unit1> <Filename Value="../../odf_xmlutils.pas"/> - <EditorIndex Value="2"/> + <EditorIndex Value="3"/> <TopLine Value="44"/> <CursorPos X="74" Y="52"/> <UsageCount Value="10"/> @@ -23,16 +22,25 @@ </Unit1> <Unit2> <Filename Value="../../odf_types.pas"/> - <EditorIndex Value="1"/> + <EditorIndex Value="2"/> <TopLine Value="975"/> <CursorPos X="31" Y="995"/> <UsageCount Value="10"/> <Loaded Value="True"/> </Unit2> + <Unit3> + <Filename Value="/usr/lib64/lazarus/lcl/graphics.pp"/> + <UnitName Value="Graphics"/> + <IsVisibleTab Value="True"/> + <EditorIndex Value="1"/> + <TopLine Value="13"/> + <UsageCount Value="10"/> + <Loaded Value="True"/> + </Unit3> </Units> <RunParams> <FormatVersion Value="2"/> - <Modes Count="0" ActiveMode="default"/> + <Modes ActiveMode="default"/> </RunParams> </ProjectSession> </CONFIG> diff --git a/examples/ImprovedDemo/ImprovedDemo.res b/examples/ImprovedDemo/ImprovedDemo.res index 0ad004b9d97928b9d3a42fa745f31fc0da4dfdb5..631a2cc1cb6087996c140ff6cf34669a29cb9801 100644 GIT binary patch delta 53 ycmey&yO3{!0^`GtiqqIs6l`+x^U?znOEMhG6N^&q(h_ruQ*HE71ShX$a{~Yqa}&w{ delta 16 YcmZ3;_nCKs0^{b5iqqI8KV`E405+}$JOBUy diff --git a/examples/fpcTestfpOdf/fpcTestfpOdf.res b/examples/fpcTestfpOdf/fpcTestfpOdf.res index f6e8499568f21121986c715951291349244aeef3..55653795630f092e02e316c1398baeab0ab25dbd 100644 GIT binary patch delta 70 zcmZ3pkK@ihjtL5k4>u}KV^dME$;r=44@fM@a4b(OO0`Q%%qdQ_(MJ)Syq3+Kk)ioB PTl;4=#_gZkm@Fj##&Q}l delta 31 ncmcb!k7La~jtL5kn>Q*>W1IYx&9+&Ey<LT!ak~mTlZ6BT$Ds;0