mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-11-01 01:21:18 +01:00 
			
		
		
		
	Merge pull request #1307 from Stirling-Tools/upgrades
Tomcat to Jetty and other changes
This commit is contained in:
		
						commit
						4781fd515b
					
				
							
								
								
									
										8
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							@ -3,14 +3,8 @@ name: "Build repo"
 | 
				
			|||||||
on:
 | 
					on:
 | 
				
			||||||
  push:
 | 
					  push:
 | 
				
			||||||
    branches: ["main"]
 | 
					    branches: ["main"]
 | 
				
			||||||
    paths-ignore:
 | 
					 | 
				
			||||||
      - ".github/**"
 | 
					 | 
				
			||||||
      - "**/*.md"
 | 
					 | 
				
			||||||
  pull_request:
 | 
					  pull_request:
 | 
				
			||||||
    branches: ["main"]
 | 
					    branches: ["main"]
 | 
				
			||||||
    paths-ignore:
 | 
					 | 
				
			||||||
      - ".github/**"
 | 
					 | 
				
			||||||
      - "**/*.md"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
@ -36,7 +30,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - uses: gradle/actions/setup-gradle@v3
 | 
					      - uses: gradle/actions/setup-gradle@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          gradle-version: 7.6
 | 
					          gradle-version: 8.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Build with Gradle
 | 
					      - name: Build with Gradle
 | 
				
			||||||
        run: ./gradlew build --no-build-cache
 | 
					        run: ./gradlew build --no-build-cache
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/push-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/push-docker.yml
									
									
									
									
										vendored
									
									
								
							@ -24,7 +24,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - uses: gradle/actions/setup-gradle@v3
 | 
					      - uses: gradle/actions/setup-gradle@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          gradle-version: 7.6
 | 
					          gradle-version: 8.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Run Gradle Command
 | 
					      - name: Run Gradle Command
 | 
				
			||||||
        run: ./gradlew clean build
 | 
					        run: ./gradlew clean build
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								.github/workflows/releaseArtifacts.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/releaseArtifacts.yml
									
									
									
									
										vendored
									
									
								
							@ -29,7 +29,7 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - uses: gradle/actions/setup-gradle@v3
 | 
					      - uses: gradle/actions/setup-gradle@v3
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          gradle-version: 7.6
 | 
					          gradle-version: 8.7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Generate jar (With Security=${{ matrix.enable_security }})
 | 
					      - name: Generate jar (With Security=${{ matrix.enable_security }})
 | 
				
			||||||
        run: ./gradlew clean createExe
 | 
					        run: ./gradlew clean createExe
 | 
				
			||||||
 | 
				
			|||||||
@ -94,7 +94,13 @@ dependencies {
 | 
				
			|||||||
    implementation("io.github.pixee:java-security-toolkit:1.1.3")
 | 
					    implementation("io.github.pixee:java-security-toolkit:1.1.3")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    implementation 'org.yaml:snakeyaml:2.2'
 | 
					    implementation 'org.yaml:snakeyaml:2.2'
 | 
				
			||||||
    implementation 'org.springframework.boot:spring-boot-starter-web:3.2.4'
 | 
					    
 | 
				
			||||||
 | 
					    // Exclude Tomcat and include Jetty
 | 
				
			||||||
 | 
					    implementation('org.springframework.boot:spring-boot-starter-web:3.2.4') {
 | 
				
			||||||
 | 
					        exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    implementation 'org.springframework.boot:spring-boot-starter-jetty:3.2.4'
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.4'
 | 
					    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.4'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
 | 
					    if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.docx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.docx
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.odp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.odp
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.odt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.odt
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.pptx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								cucumber/exampleFiles/example.pptx
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										158
									
								
								cucumber/exampleFiles/example.rtf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								cucumber/exampleFiles/example.rtf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					{\rtf1\ansi\ansicpg1252\uc0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deff0\adeff0{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f2\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}}{\colortbl;\red0\green0\blue0;\red67\green67\blue67;
 | 
				
			||||||
 | 
					\red102\green102\blue102;}{\stylesheet{\s0\snext0\sqformat\spriority0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1 Normal;}{\s1\sbasedon0\snext0\styrsid15694742
 | 
				
			||||||
 | 
					\sqformat\spriority0\keep\keepn\fi0\sb400\sa120\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs40\ltrch\b0\i0\fs40\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1 heading 1;}{\s2\sbasedon0\snext0\styrsid15694742
 | 
				
			||||||
 | 
					\sqformat\spriority0\keep\keepn\fi0\sb360\sa120\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs32\ltrch\b0\i0\fs32\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1 heading 2;}{\s3\sbasedon0\snext0\styrsid15694742
 | 
				
			||||||
 | 
					\sqformat\spriority0\keep\keepn\fi0\sb320\sa80\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs28\ltrch\b0\i0\fs28\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf2 heading 3;}{\s4\sbasedon0\snext0\styrsid15694742
 | 
				
			||||||
 | 
					\sqformat\spriority0\keep\keepn\fi0\sb280\sa80\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs24\ltrch\b0\i0\fs24\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf3 heading 4;}{\s5\sbasedon0\snext0\styrsid15694742
 | 
				
			||||||
 | 
					\sqformat\spriority0\keep\keepn\fi0\sb240\sa80\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf3 heading 5;}{\s6\sbasedon0\snext0\styrsid15694742
 | 
				
			||||||
 | 
					\sqformat\spriority0\keep\keepn\fi0\sb240\sa80\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai\af2\afs22\ltrch\b0\i\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf3 heading 6;}{\*\cs10\additive\ssemihidden\spriority0 Default Paragraph Font;
 | 
				
			||||||
 | 
					}{\*\ts11\tsrowd\snext11\ssemihidden\spriority0\aspalpha\aspnum\adjustright\ltrpar\li0\lin0\ri0\rin0\ql\faauto\tsvertalt\tsbrdrl\tsbrdrr\tsbrdrt\tsbrdrb\tsbrdrdgr\tsbrdrdgl\tsbrdrh\tsbrdrv\trpaddl108\trpaddfl3\trwWidthB0\trftsWidthB3\trpaddt0\trpaddft3\trpaddb0
 | 
				
			||||||
 | 
					\trpaddfb3\trpaddr108\trpaddfr3 Normal Table;}{\s15\sbasedon0\snext15\styrsid15694742\sqformat\spriority0\keep\keepn\fi0\sb0\sa60\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs52\ltrch\b0\i0\fs52\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\strike0\ulnone\cf1 Title;}{\s16\sbasedon0\snext16\styrsid15694742\sqformat\spriority0\keep\keepn\fi0\sb0\sa320\aspalpha\aspnum\adjustright\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl240\slmult1\rtlch\ab0\ai0\af2\afs30\ltrch\b0\i0\fs30
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf3 Subtitle;}}{\*\rsidtbl\rsid10976062\rsid13249109}{\*\generator Aspose.Words for Java 23.4.0;}{\info\version1\edmins0\nofpages1\nofwords0\nofchars0\nofcharsws0}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0{
 | 
				
			||||||
 | 
					\mmathPr\mbrkBin0\mbrkBinSub0\mdefJc1\mdispDef1\minterSp0\mintLim0\mintraSp0\mlMargin0\mmathFont0\mnaryLim1\mpostSp0\mpreSp0\mrMargin0\msmallFrac0\mwrapIndent1440\mwrapRight0}\deflang1033\deflangfe2052\adeflang1025\jexpand\showxmlerrors1\validatexml1{
 | 
				
			||||||
 | 
					\*\wgrffmtfilter 013f}\viewkind1\viewscale100\fet0\ftnbj\aenddoc\ftnrstcont\aftnrstcont\ftnnar\aftnnrlc\widowctrl\nospaceforul\nolnhtadjtbl\alntblind\lyttblrtgr\dntblnsbdb\noxlattoyen\wrppunct\nobrkwrptbl\expshrtn\snaptogridincell\asianbrkrule\htmautsp\noultrlspc
 | 
				
			||||||
 | 
					\useltbaln\splytwnine\ftnlytwnine\lytcalctblwd\allowfieldendsel\lnbrkrule\nouicompat\nofeaturethrottle1\utinl\formshade\nojkernpunct\dghspace180\dgvspace180\dghorigin1800\dgvorigin1440\dghshow1\dgvshow1\dgmargin\pgbrdrhead\pgbrdrfoot\rsidroot10976062\sectd\sectlinegrid360\pgwsxn12240\pghsxn15840\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\guttersxn0\headery720\footery720\colsx720\ltrsect\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar
 | 
				
			||||||
 | 
					\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\alang1025\afs22\ltrch\b0\i0\fs22\lang1033\langnp1033\langfe1033\langfenp1033\loch\af2\dbch\af2
 | 
				
			||||||
 | 
					\hich\f2\strike0\ulnone\cf1 A}{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar
 | 
				
			||||||
 | 
					\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\alang1025\afs22\ltrch\b0\i0\fs22\lang1033\langnp1033\langfe1033\langfenp1033\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\strike0\ulnone\cf1 B}{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar
 | 
				
			||||||
 | 
					\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard
 | 
				
			||||||
 | 
					\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0
 | 
				
			||||||
 | 
					\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0
 | 
				
			||||||
 | 
					\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0
 | 
				
			||||||
 | 
					\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2
 | 
				
			||||||
 | 
					\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw
 | 
				
			||||||
 | 
					\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}
 | 
				
			||||||
 | 
					\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22
 | 
				
			||||||
 | 
					\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}\pard\plain\itap0\s0\ilvl0\fi0\sb0\sa0\aspalpha\aspnum\adjustright\brdrt\brdrl\brdrb
 | 
				
			||||||
 | 
					\brdrr\brdrbtw\brdrbar\widctlpar\ltrpar\li0\lin0\ri0\rin0\ql\faauto\sl276\slmult1\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1{\rtlch\ab0\ai0\af2\alang1025\afs22\ltrch\b0\i0\fs22\lang1033\langnp1033\langfe1033\langfenp1033
 | 
				
			||||||
 | 
					\loch\af2\dbch\af2\hich\f2\strike0\ulnone\cf1 C}{\rtlch\ab0\ai0\af2\afs22\ltrch\b0\i0\fs22\loch\af2\dbch\af2\hich\f2\insrsid10976062\strike0\ulnone\cf1\par}{
 | 
				
			||||||
 | 
					\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef0{\lsdlockedexcept\lsdqformat1 Normal;\lsdqformat1 heading 1;\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 2;\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 3;
 | 
				
			||||||
 | 
					\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 4;\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 5;\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 6;\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 7;\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 8;
 | 
				
			||||||
 | 
					\lsdsemihidden1\lsdunhideused1\lsdqformat1 heading 9;\lsdsemihidden1\lsdunhideused1\lsdqformat1 caption;\lsdqformat1 Title;\lsdqformat1 Subtitle;\lsdqformat1 Strong;\lsdqformat1 Emphasis;\lsdsemihidden1\lsdpriority99 Placeholder Text;\lsdqformat1\lsdpriority1 No Spacing;
 | 
				
			||||||
 | 
					\lsdpriority60 Light Shading;\lsdpriority61 Light List;\lsdpriority62 Light Grid;\lsdpriority63 Medium Shading 1;\lsdpriority64 Medium Shading 2;\lsdpriority65 Medium List 1;\lsdpriority66 Medium List 2;\lsdpriority67 Medium Grid 1;\lsdpriority68 Medium Grid 2;
 | 
				
			||||||
 | 
					\lsdpriority69 Medium Grid 3;\lsdpriority70 Dark List;\lsdpriority71 Colorful Shading;\lsdpriority72 Colorful List;\lsdpriority73 Colorful Grid;\lsdpriority60 Light Shading Accent 1;\lsdpriority61 Light List Accent 1;\lsdpriority62 Light Grid Accent 1;\lsdpriority63 Medium Shading 1 Accent 1;
 | 
				
			||||||
 | 
					\lsdpriority64 Medium Shading 2 Accent 1;\lsdpriority65 Medium List 1 Accent 1;\lsdsemihidden1\lsdpriority99 Revision;\lsdqformat1\lsdpriority34 List Paragraph;\lsdqformat1\lsdpriority29 Quote;\lsdqformat1\lsdpriority30 Intense Quote;\lsdpriority66 Medium List 2 Accent 1;
 | 
				
			||||||
 | 
					\lsdpriority67 Medium Grid 1 Accent 1;\lsdpriority68 Medium Grid 2 Accent 1;\lsdpriority69 Medium Grid 3 Accent 1;\lsdpriority70 Dark List Accent 1;\lsdpriority71 Colorful Shading Accent 1;\lsdpriority72 Colorful List Accent 1;\lsdpriority73 Colorful Grid Accent 1;
 | 
				
			||||||
 | 
					\lsdpriority60 Light Shading Accent 2;\lsdpriority61 Light List Accent 2;\lsdpriority62 Light Grid Accent 2;\lsdpriority63 Medium Shading 1 Accent 2;\lsdpriority64 Medium Shading 2 Accent 2;\lsdpriority65 Medium List 1 Accent 2;\lsdpriority66 Medium List 2 Accent 2;
 | 
				
			||||||
 | 
					\lsdpriority67 Medium Grid 1 Accent 2;\lsdpriority68 Medium Grid 2 Accent 2;\lsdpriority69 Medium Grid 3 Accent 2;\lsdpriority70 Dark List Accent 2;\lsdpriority71 Colorful Shading Accent 2;\lsdpriority72 Colorful List Accent 2;\lsdpriority73 Colorful Grid Accent 2;
 | 
				
			||||||
 | 
					\lsdpriority60 Light Shading Accent 3;\lsdpriority61 Light List Accent 3;\lsdpriority62 Light Grid Accent 3;\lsdpriority63 Medium Shading 1 Accent 3;\lsdpriority64 Medium Shading 2 Accent 3;\lsdpriority65 Medium List 1 Accent 3;\lsdpriority66 Medium List 2 Accent 3;
 | 
				
			||||||
 | 
					\lsdpriority67 Medium Grid 1 Accent 3;\lsdpriority68 Medium Grid 2 Accent 3;\lsdpriority69 Medium Grid 3 Accent 3;\lsdpriority70 Dark List Accent 3;\lsdpriority71 Colorful Shading Accent 3;\lsdpriority72 Colorful List Accent 3;\lsdpriority73 Colorful Grid Accent 3;
 | 
				
			||||||
 | 
					\lsdpriority60 Light Shading Accent 4;\lsdpriority61 Light List Accent 4;\lsdpriority62 Light Grid Accent 4;\lsdpriority63 Medium Shading 1 Accent 4;\lsdpriority64 Medium Shading 2 Accent 4;\lsdpriority65 Medium List 1 Accent 4;\lsdpriority66 Medium List 2 Accent 4;
 | 
				
			||||||
 | 
					\lsdpriority67 Medium Grid 1 Accent 4;\lsdpriority68 Medium Grid 2 Accent 4;\lsdpriority69 Medium Grid 3 Accent 4;\lsdpriority70 Dark List Accent 4;\lsdpriority71 Colorful Shading Accent 4;\lsdpriority72 Colorful List Accent 4;\lsdpriority73 Colorful Grid Accent 4;
 | 
				
			||||||
 | 
					\lsdpriority60 Light Shading Accent 5;\lsdpriority61 Light List Accent 5;\lsdpriority62 Light Grid Accent 5;\lsdpriority63 Medium Shading 1 Accent 5;\lsdpriority64 Medium Shading 2 Accent 5;\lsdpriority65 Medium List 1 Accent 5;\lsdpriority66 Medium List 2 Accent 5;
 | 
				
			||||||
 | 
					\lsdpriority67 Medium Grid 1 Accent 5;\lsdpriority68 Medium Grid 2 Accent 5;\lsdpriority69 Medium Grid 3 Accent 5;\lsdpriority70 Dark List Accent 5;\lsdpriority71 Colorful Shading Accent 5;\lsdpriority72 Colorful List Accent 5;\lsdpriority73 Colorful Grid Accent 5;
 | 
				
			||||||
 | 
					\lsdpriority60 Light Shading Accent 6;\lsdpriority61 Light List Accent 6;\lsdpriority62 Light Grid Accent 6;\lsdpriority63 Medium Shading 1 Accent 6;\lsdpriority64 Medium Shading 2 Accent 6;\lsdpriority65 Medium List 1 Accent 6;\lsdpriority66 Medium List 2 Accent 6;
 | 
				
			||||||
 | 
					\lsdpriority67 Medium Grid 1 Accent 6;\lsdpriority68 Medium Grid 2 Accent 6;\lsdpriority69 Medium Grid 3 Accent 6;\lsdpriority70 Dark List Accent 6;\lsdpriority71 Colorful Shading Accent 6;\lsdpriority72 Colorful List Accent 6;\lsdpriority73 Colorful Grid Accent 6;
 | 
				
			||||||
 | 
					\lsdqformat1\lsdpriority19 Subtle Emphasis;\lsdqformat1\lsdpriority21 Intense Emphasis;\lsdqformat1\lsdpriority31 Subtle Reference;\lsdqformat1\lsdpriority32 Intense Reference;\lsdqformat1\lsdpriority33 Book Title;\lsdsemihidden1\lsdunhideused1\lsdpriority37 Bibliography;
 | 
				
			||||||
 | 
					\lsdsemihidden1\lsdunhideused1\lsdqformat1\lsdpriority39 TOC Heading;}}}
 | 
				
			||||||
@ -1,5 +1,7 @@
 | 
				
			|||||||
 | 
					@example
 | 
				
			||||||
Feature: API Validation
 | 
					Feature: API Validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @positive @password
 | 
				
			||||||
  Scenario: Remove password 
 | 
					  Scenario: Remove password 
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the pdf contains 3 pages
 | 
					    And the pdf contains 3 pages
 | 
				
			||||||
@ -13,6 +15,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response PDF is not passworded
 | 
					    And the response PDF is not passworded
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @negative @password
 | 
				
			||||||
  Scenario: Remove password wrong password
 | 
					  Scenario: Remove password wrong password
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the pdf contains 3 pages
 | 
					    And the pdf contains 3 pages
 | 
				
			||||||
@ -24,6 +27,7 @@ Feature: API Validation
 | 
				
			|||||||
    Then the response status code should be 500
 | 
					    Then the response status code should be 500
 | 
				
			||||||
    And the response should contain error message "Internal Server Error"
 | 
					    And the response should contain error message "Internal Server Error"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @positive @info
 | 
				
			||||||
  Scenario: Get info
 | 
					  Scenario: Get info
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/security/get-info-on-pdf"
 | 
					    When I send the API request to the endpoint "/api/v1/security/get-info-on-pdf"
 | 
				
			||||||
@ -31,6 +35,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response file should have size greater than 100
 | 
					    And the response file should have size greater than 100
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @positive @password
 | 
				
			||||||
  Scenario: Add password
 | 
					  Scenario: Add password
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the pdf contains 3 pages
 | 
					    And the pdf contains 3 pages
 | 
				
			||||||
@ -43,6 +48,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response PDF is passworded
 | 
					    And the response PDF is passworded
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
					  @positive @password
 | 
				
			||||||
  Scenario: Add password with other params 
 | 
					  Scenario: Add password with other params 
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the pdf contains 3 pages
 | 
					    And the pdf contains 3 pages
 | 
				
			||||||
@ -59,7 +65,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response PDF is passworded
 | 
					    And the response PDF is passworded
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	
 | 
					  @positive @watermark
 | 
				
			||||||
  Scenario: Add watermark
 | 
					  Scenario: Add watermark
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the pdf contains 3 pages
 | 
					    And the pdf contains 3 pages
 | 
				
			||||||
@ -77,17 +83,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response file should have size greater than 100
 | 
					    And the response file should have size greater than 100
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @positive
 | 
				
			||||||
 | 
					 | 
				
			||||||
  Scenario: Repair PDF
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/misc/repair"
 | 
					 | 
				
			||||||
    Then the response content type should be "application/pdf"
 | 
					 | 
				
			||||||
    And the response file should have size greater than 0
 | 
					 | 
				
			||||||
	And the response status code should be 200
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Scenario: Remove blank pages
 | 
					  Scenario: Remove blank pages
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
	And the pdf contains 3 blank pages
 | 
						And the pdf contains 3 blank pages
 | 
				
			||||||
@ -101,79 +97,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response PDF should contain 0 pages
 | 
					    And the response PDF should contain 0 pages
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ocr
 | 
					  @positive @flatten
 | 
				
			||||||
  Scenario: Process PDF with OCR
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value       |
 | 
					 | 
				
			||||||
      | languages        | eng         |
 | 
					 | 
				
			||||||
      | sidecar          | false        |
 | 
					 | 
				
			||||||
      | deskew           | true        |
 | 
					 | 
				
			||||||
      | clean            | true        |
 | 
					 | 
				
			||||||
      | cleanFinal       | true        |
 | 
					 | 
				
			||||||
      | ocrType          | Normal      |
 | 
					 | 
				
			||||||
      | ocrRenderType    | hocr        |
 | 
					 | 
				
			||||||
      | removeImagesAfter| false       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
					 | 
				
			||||||
    Then the response content type should be "application/pdf"
 | 
					 | 
				
			||||||
    And the response file should have size greater than 0
 | 
					 | 
				
			||||||
	And the response status code should be 200
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @ocr
 | 
					 | 
				
			||||||
  Scenario: Process PDF with text and OCR with type normal 
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the pdf contains 3 pages with random text
 | 
					 | 
				
			||||||
    And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value       |
 | 
					 | 
				
			||||||
      | languages        | eng         |
 | 
					 | 
				
			||||||
      | sidecar          | false        |
 | 
					 | 
				
			||||||
      | deskew           | true        |
 | 
					 | 
				
			||||||
      | clean            | true        |
 | 
					 | 
				
			||||||
      | cleanFinal       | true        |
 | 
					 | 
				
			||||||
      | ocrType          | Normal      |
 | 
					 | 
				
			||||||
      | ocrRenderType    | hocr        |
 | 
					 | 
				
			||||||
      | removeImagesAfter| false       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
					 | 
				
			||||||
	Then the response status code should be 500
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
  @ocr
 | 
					 | 
				
			||||||
  Scenario: Process PDF with OCR
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value       |
 | 
					 | 
				
			||||||
      | languages        | eng         |
 | 
					 | 
				
			||||||
      | sidecar          | false        |
 | 
					 | 
				
			||||||
      | deskew           | true        |
 | 
					 | 
				
			||||||
      | clean            | true        |
 | 
					 | 
				
			||||||
      | cleanFinal       | true        |
 | 
					 | 
				
			||||||
      | ocrType          | Force      |
 | 
					 | 
				
			||||||
      | ocrRenderType    | hocr        |
 | 
					 | 
				
			||||||
      | removeImagesAfter| false       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
					 | 
				
			||||||
    Then the response content type should be "application/pdf"
 | 
					 | 
				
			||||||
    And the response file should have size greater than 0
 | 
					 | 
				
			||||||
	And the response status code should be 200
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
  @ocr
 | 
					 | 
				
			||||||
  Scenario: Process PDF with OCR with sidecar
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value       |
 | 
					 | 
				
			||||||
      | languages        | eng         |
 | 
					 | 
				
			||||||
      | sidecar          | true        |
 | 
					 | 
				
			||||||
      | deskew           | true        |
 | 
					 | 
				
			||||||
      | clean            | true        |
 | 
					 | 
				
			||||||
      | cleanFinal       | true        |
 | 
					 | 
				
			||||||
      | ocrType          | Force      |
 | 
					 | 
				
			||||||
      | ocrRenderType    | hocr        |
 | 
					 | 
				
			||||||
      | removeImagesAfter| false       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
					 | 
				
			||||||
    Then the response content type should be "application/octet-stream"
 | 
					 | 
				
			||||||
	And the response file should have extension ".zip"
 | 
					 | 
				
			||||||
    And the response file should have size greater than 0
 | 
					 | 
				
			||||||
	And the response status code should be 200
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
  Scenario: Flatten PDF
 | 
					  Scenario: Flatten PDF
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the request data includes
 | 
					    And the request data includes
 | 
				
			||||||
@ -184,6 +108,7 @@ Feature: API Validation
 | 
				
			|||||||
    And the response file should have size greater than 0
 | 
					    And the response file should have size greater than 0
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
					  @positive @metadata
 | 
				
			||||||
  Scenario: Update metadata
 | 
					  Scenario: Update metadata
 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
    And the request data includes
 | 
					    And the request data includes
 | 
				
			||||||
@ -202,41 +127,4 @@ Feature: API Validation
 | 
				
			|||||||
	And the response PDF metadata should include "Title" as "Sample Title"
 | 
						And the response PDF metadata should include "Title" as "Sample Title"
 | 
				
			||||||
	And the response status code should be 200
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @libre
 | 
					 | 
				
			||||||
  Scenario: Convert PDF to DOCX
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the pdf contains 3 pages with random text
 | 
					 | 
				
			||||||
	And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value      |
 | 
					 | 
				
			||||||
      | outputFormat     | docx       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/convert/pdf/word"
 | 
					 | 
				
			||||||
	Then the response status code should be 200
 | 
					 | 
				
			||||||
    And the response file should have size greater than 100
 | 
					 | 
				
			||||||
    And the response file should have extension ".docx"
 | 
					 | 
				
			||||||
#    And the response DOCX should contain 3 pages
 | 
					 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  @libre
 | 
					 | 
				
			||||||
  Scenario: Convert PDF to ODT
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the pdf contains 3 pages with random text
 | 
					 | 
				
			||||||
	And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value     |
 | 
					 | 
				
			||||||
      | outputFormat     | odt       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/convert/pdf/word"
 | 
					 | 
				
			||||||
	Then the response status code should be 200
 | 
					 | 
				
			||||||
    And the response file should have size greater than 100
 | 
					 | 
				
			||||||
    And the response file should have extension ".odt"
 | 
					 | 
				
			||||||
#   And the response ODT should contain 3 pages
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  @libre
 | 
					 | 
				
			||||||
  Scenario: Convert PDF to DOC
 | 
					 | 
				
			||||||
    Given I generate a PDF file as "fileInput"
 | 
					 | 
				
			||||||
    And the pdf contains 3 pages with random text
 | 
					 | 
				
			||||||
	And the request data includes
 | 
					 | 
				
			||||||
      | parameter        | value     |
 | 
					 | 
				
			||||||
      | outputFormat     | doc       |
 | 
					 | 
				
			||||||
    When I send the API request to the endpoint "/api/v1/convert/pdf/word"
 | 
					 | 
				
			||||||
	Then the response status code should be 200
 | 
					 | 
				
			||||||
    And the response file should have extension ".doc"
 | 
					 | 
				
			||||||
    And the response file should have size greater than 100
 | 
					 | 
				
			||||||
#    And the response DOC should contain 3 pages
 | 
					 | 
				
			||||||
							
								
								
									
										228
									
								
								cucumber/features/external.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								cucumber/features/external.feature
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,228 @@
 | 
				
			|||||||
 | 
					Feature: API Validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @libre @positive
 | 
				
			||||||
 | 
					  Scenario: Repair PDF
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/repair"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 0
 | 
				
			||||||
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ocr @positive
 | 
				
			||||||
 | 
					  Scenario: Process PDF with OCR
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value       |
 | 
				
			||||||
 | 
					      | languages        | eng         |
 | 
				
			||||||
 | 
					      | sidecar          | false        |
 | 
				
			||||||
 | 
					      | deskew           | true        |
 | 
				
			||||||
 | 
					      | clean            | true        |
 | 
				
			||||||
 | 
					      | cleanFinal       | true        |
 | 
				
			||||||
 | 
					      | ocrType          | Normal      |
 | 
				
			||||||
 | 
					      | ocrRenderType    | hocr        |
 | 
				
			||||||
 | 
					      | removeImagesAfter| false       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 0
 | 
				
			||||||
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ocr @positive
 | 
				
			||||||
 | 
					  Scenario: Extract Image Scans
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
						And the pdf contains 3 images on 2 pages
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value       |
 | 
				
			||||||
 | 
					      | angleThreshold        | 5         |
 | 
				
			||||||
 | 
					      | tolerance          | 20        |
 | 
				
			||||||
 | 
					      | minArea           | 8000        |
 | 
				
			||||||
 | 
					      | minContourArea            | 500        |
 | 
				
			||||||
 | 
					      | borderSize       | 1        |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/extract-image-scans"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/octet-stream"
 | 
				
			||||||
 | 
						And the response file should have extension ".zip"
 | 
				
			||||||
 | 
						And the response ZIP should contain 2 files
 | 
				
			||||||
 | 
					    And the response file should have size greater than 0
 | 
				
			||||||
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @ocr @negative
 | 
				
			||||||
 | 
					  Scenario: Process PDF with text and OCR with type normal 
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value       |
 | 
				
			||||||
 | 
					      | languages        | eng         |
 | 
				
			||||||
 | 
					      | sidecar          | false        |
 | 
				
			||||||
 | 
					      | deskew           | true        |
 | 
				
			||||||
 | 
					      | clean            | true        |
 | 
				
			||||||
 | 
					      | cleanFinal       | true        |
 | 
				
			||||||
 | 
					      | ocrType          | Normal      |
 | 
				
			||||||
 | 
					      | ocrRenderType    | hocr        |
 | 
				
			||||||
 | 
					      | removeImagesAfter| false       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
				
			||||||
 | 
						Then the response status code should be 500
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @ocr @positive
 | 
				
			||||||
 | 
					  Scenario: Process PDF with OCR
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value       |
 | 
				
			||||||
 | 
					      | languages        | eng         |
 | 
				
			||||||
 | 
					      | sidecar          | false        |
 | 
				
			||||||
 | 
					      | deskew           | true        |
 | 
				
			||||||
 | 
					      | clean            | true        |
 | 
				
			||||||
 | 
					      | cleanFinal       | true        |
 | 
				
			||||||
 | 
					      | ocrType          | Force      |
 | 
				
			||||||
 | 
					      | ocrRenderType    | hocr        |
 | 
				
			||||||
 | 
					      | removeImagesAfter| false       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 0
 | 
				
			||||||
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @ocr @positive
 | 
				
			||||||
 | 
					  Scenario: Process PDF with OCR with sidecar
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value       |
 | 
				
			||||||
 | 
					      | languages        | eng         |
 | 
				
			||||||
 | 
					      | sidecar          | true        |
 | 
				
			||||||
 | 
					      | deskew           | true        |
 | 
				
			||||||
 | 
					      | clean            | true        |
 | 
				
			||||||
 | 
					      | cleanFinal       | true        |
 | 
				
			||||||
 | 
					      | ocrType          | Force      |
 | 
				
			||||||
 | 
					      | ocrRenderType    | hocr        |
 | 
				
			||||||
 | 
					      | removeImagesAfter| false       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/ocr-pdf"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/octet-stream"
 | 
				
			||||||
 | 
						And the response file should have extension ".zip"
 | 
				
			||||||
 | 
						And the response ZIP should contain 2 files
 | 
				
			||||||
 | 
					    And the response file should have size greater than 0
 | 
				
			||||||
 | 
						And the response status code should be 200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @libre @positive
 | 
				
			||||||
 | 
					  Scenario Outline: Convert PDF to various word formats
 | 
				
			||||||
 | 
					  Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					  And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
					  And the request data includes
 | 
				
			||||||
 | 
					    | parameter    | value       |
 | 
				
			||||||
 | 
					    | outputFormat | <format>    |
 | 
				
			||||||
 | 
					  When I send the API request to the endpoint "/api/v1/convert/pdf/word"
 | 
				
			||||||
 | 
					  Then the response status code should be 200
 | 
				
			||||||
 | 
					  And the response file should have size greater than 100
 | 
				
			||||||
 | 
					  And the response file should have extension "<extension>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					    | format | extension |
 | 
				
			||||||
 | 
					    | docx   | .docx     |
 | 
				
			||||||
 | 
					    | odt    | .odt      |
 | 
				
			||||||
 | 
					    | doc    | .doc      |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @ocr
 | 
				
			||||||
 | 
					  Scenario: PDFA
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
						And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value     |
 | 
				
			||||||
 | 
					      | outputFormat     | pdfa       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/convert/pdf/pdfa"
 | 
				
			||||||
 | 
						Then the response status code should be 200
 | 
				
			||||||
 | 
					    And the response file should have extension ".pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 100
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @ocr
 | 
				
			||||||
 | 
					  Scenario: PDFA1
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
						And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value     |
 | 
				
			||||||
 | 
					      | outputFormat     | pdfa-1       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/convert/pdf/pdfa"
 | 
				
			||||||
 | 
						Then the response status code should be 200
 | 
				
			||||||
 | 
					    And the response file should have extension ".pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 100
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @compress @ghostscript @positive
 | 
				
			||||||
 | 
					  Scenario: Compress
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
						And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value     |
 | 
				
			||||||
 | 
					      | optimizeLevel     | 4       |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/compress-pdf"
 | 
				
			||||||
 | 
						Then the response status code should be 200
 | 
				
			||||||
 | 
					    And the response file should have extension ".pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 100
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @compress @ghostscript @positive
 | 
				
			||||||
 | 
					  Scenario: Compress
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
						And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value     |
 | 
				
			||||||
 | 
					      | optimizeLevel     | 1       |
 | 
				
			||||||
 | 
						  | expectedOutputSize | 5KB |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/compress-pdf"
 | 
				
			||||||
 | 
						Then the response status code should be 200
 | 
				
			||||||
 | 
					    And the response file should have extension ".pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 100
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @compress @ghostscript @positive
 | 
				
			||||||
 | 
					  Scenario: Compress
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
						And the request data includes
 | 
				
			||||||
 | 
					      | parameter        | value     |
 | 
				
			||||||
 | 
					      | optimizeLevel     | 1       |
 | 
				
			||||||
 | 
						  | expectedOutputSize | 5KB |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/misc/compress-pdf"
 | 
				
			||||||
 | 
						Then the response status code should be 200
 | 
				
			||||||
 | 
					    And the response file should have extension ".pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 100	
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @libre @positive
 | 
				
			||||||
 | 
					  Scenario Outline: Convert PDF to various types
 | 
				
			||||||
 | 
					  Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					  And the pdf contains 3 pages with random text
 | 
				
			||||||
 | 
					  And the request data includes
 | 
				
			||||||
 | 
					    | parameter    | value       |
 | 
				
			||||||
 | 
					    | outputFormat | <format>    |
 | 
				
			||||||
 | 
					  When I send the API request to the endpoint "/api/v1/convert/pdf/<type>"
 | 
				
			||||||
 | 
					  Then the response status code should be 200
 | 
				
			||||||
 | 
					  And the response file should have size greater than 100
 | 
				
			||||||
 | 
					  And the response file should have extension "<extension>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					   | type | format | extension |
 | 
				
			||||||
 | 
					   |  text   | rtf   | .rtf     |
 | 
				
			||||||
 | 
					   |  text   | txt    | .txt      |
 | 
				
			||||||
 | 
					   |  presentation   | ppt   | .ppt     |
 | 
				
			||||||
 | 
					   |  presentation   | pptx    | .pptx      |
 | 
				
			||||||
 | 
					   |  presentation   | odp   | .odp     |
 | 
				
			||||||
 | 
					   |  html   | html    | .zip      |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @libre @positive @topdf
 | 
				
			||||||
 | 
					  Scenario Outline: Convert PDF to various types
 | 
				
			||||||
 | 
					  Given I use an example file at "exampleFiles/example<extension>" as parameter "fileInput"
 | 
				
			||||||
 | 
					  When I send the API request to the endpoint "/api/v1/convert/file/pdf"
 | 
				
			||||||
 | 
					  Then the response status code should be 200
 | 
				
			||||||
 | 
					  And the response file should have size greater than 100
 | 
				
			||||||
 | 
					  And the response file should have extension ".pdf"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					   | extension | 
 | 
				
			||||||
 | 
					   |   .docx  |
 | 
				
			||||||
 | 
					   |  .odp   |
 | 
				
			||||||
 | 
					   |  .odt   | 
 | 
				
			||||||
 | 
					   |  .pptx   | 
 | 
				
			||||||
 | 
					   |  .rtf   | 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							
 | 
				
			||||||
							
								
								
									
										96
									
								
								cucumber/features/general.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								cucumber/features/general.feature
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					@general
 | 
				
			||||||
 | 
					Feature: API Validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					  @split-pdf-by-sections @positive
 | 
				
			||||||
 | 
					  Scenario Outline: split-pdf-by-sections with different parameters
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 2 pages
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter           | value       |
 | 
				
			||||||
 | 
					      | horizontalDivisions | <horizontalDivisions> |
 | 
				
			||||||
 | 
					      | verticalDivisions   | <verticalDivisions> |
 | 
				
			||||||
 | 
					      | merge               | true |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/general/split-pdf-by-sections"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 200
 | 
				
			||||||
 | 
					    And the response status code should be 200
 | 
				
			||||||
 | 
					    And the response PDF should contain <page_count> pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					    | horizontalDivisions | verticalDivisions | page_count |
 | 
				
			||||||
 | 
					    | 0                   | 1                 | 4          |
 | 
				
			||||||
 | 
					    | 1                   | 1                 | 8          |
 | 
				
			||||||
 | 
					    | 1                   | 2                 | 12          |
 | 
				
			||||||
 | 
					    | 2                   | 2                 | 18          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @split-pdf-by-sections @positive
 | 
				
			||||||
 | 
					  Scenario Outline: split-pdf-by-sections with different parameters
 | 
				
			||||||
 | 
					    Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					    And the pdf contains 2 pages
 | 
				
			||||||
 | 
					    And the request data includes
 | 
				
			||||||
 | 
					      | parameter           | value       |
 | 
				
			||||||
 | 
					      | horizontalDivisions | <horizontalDivisions> |
 | 
				
			||||||
 | 
					      | verticalDivisions   | <verticalDivisions> |
 | 
				
			||||||
 | 
					      | merge               | true |
 | 
				
			||||||
 | 
					    When I send the API request to the endpoint "/api/v1/general/split-pdf-by-sections"
 | 
				
			||||||
 | 
					    Then the response content type should be "application/pdf"
 | 
				
			||||||
 | 
					    And the response file should have size greater than 200
 | 
				
			||||||
 | 
					    And the response status code should be 200
 | 
				
			||||||
 | 
					    And the response PDF should contain <page_count> pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					    | horizontalDivisions | verticalDivisions | page_count |
 | 
				
			||||||
 | 
					    | 0                   | 1                 | 4          |
 | 
				
			||||||
 | 
					    | 1                   | 1                 | 8          |
 | 
				
			||||||
 | 
					    | 1                   | 2                 | 12          |
 | 
				
			||||||
 | 
					    | 2                   | 2                 | 18          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @split-pdf-by-pages @positive
 | 
				
			||||||
 | 
					  Scenario Outline: split-pdf-by-pages with different parameters
 | 
				
			||||||
 | 
					  Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					  And the pdf contains 20 pages
 | 
				
			||||||
 | 
					  And the request data includes
 | 
				
			||||||
 | 
					    | parameter     | value         |
 | 
				
			||||||
 | 
					    | fileInput     | fileInput     |
 | 
				
			||||||
 | 
					    | pageNumbers   | <pageNumbers> |
 | 
				
			||||||
 | 
					  When I send the API request to the endpoint "/api/v1/general/split-pages"
 | 
				
			||||||
 | 
					  Then the response content type should be "application/octet-stream"
 | 
				
			||||||
 | 
					  And the response status code should be 200
 | 
				
			||||||
 | 
					  And the response file should have size greater than 200
 | 
				
			||||||
 | 
					  And the response ZIP should contain <file_count> files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					    | pageNumbers | file_count |
 | 
				
			||||||
 | 
					    | 1,3,5-9     | 8          |
 | 
				
			||||||
 | 
					    | all         | 20         |
 | 
				
			||||||
 | 
					    | 2n+1        | 11         |
 | 
				
			||||||
 | 
					    | 3n          | 7          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @split-pdf-by-size-or-count @positive
 | 
				
			||||||
 | 
					  Scenario Outline: split-pdf-by-size-or-count with different parameters
 | 
				
			||||||
 | 
					  Given I generate a PDF file as "fileInput"
 | 
				
			||||||
 | 
					  And the pdf contains 20 pages
 | 
				
			||||||
 | 
					  And the request data includes
 | 
				
			||||||
 | 
					    | parameter  | value          |
 | 
				
			||||||
 | 
					    | fileInput  | fileInput      |
 | 
				
			||||||
 | 
					    | splitType  | <splitType>    |
 | 
				
			||||||
 | 
					    | splitValue | <splitValue>   |
 | 
				
			||||||
 | 
					  When I send the API request to the endpoint "/api/v1/general/split-by-size-or-count"
 | 
				
			||||||
 | 
					  Then the response content type should be "application/octet-stream"
 | 
				
			||||||
 | 
					  And the response status code should be 200
 | 
				
			||||||
 | 
					  And the response file should have size greater than 200
 | 
				
			||||||
 | 
					  And the response ZIP file should contain <doc_count> documents each having <pages_per_doc> pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Examples:
 | 
				
			||||||
 | 
					    | splitType | splitValue | doc_count | pages_per_doc |
 | 
				
			||||||
 | 
					    | 1         | 5          | 4         | 5             |
 | 
				
			||||||
 | 
					    | 2         | 2          | 2         | 10            |
 | 
				
			||||||
 | 
					    | 2         | 4          | 4         | 5             |
 | 
				
			||||||
 | 
					    | 1         | 10         | 2         | 10            |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,6 +9,8 @@ from reportlab.lib.pagesizes import letter
 | 
				
			|||||||
from reportlab.pdfgen import canvas
 | 
					from reportlab.pdfgen import canvas
 | 
				
			||||||
import mimetypes
 | 
					import mimetypes
 | 
				
			||||||
import requests
 | 
					import requests
 | 
				
			||||||
 | 
					import zipfile
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#########
 | 
					#########
 | 
				
			||||||
# GIVEN #
 | 
					# GIVEN #
 | 
				
			||||||
@ -26,6 +28,23 @@ def step_generate_pdf(context, fileInput):
 | 
				
			|||||||
        context.files = {}
 | 
					        context.files = {}
 | 
				
			||||||
    context.files[context.param_name] = open(context.file_name, 'rb')
 | 
					    context.files[context.param_name] = open(context.file_name, 'rb')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@given('I use an example file at "{filePath}" as parameter "{fileInput}"')
 | 
				
			||||||
 | 
					def step_use_example_file(context, filePath, fileInput):
 | 
				
			||||||
 | 
					    context.param_name = fileInput
 | 
				
			||||||
 | 
					    context.file_name = filePath.split('/')[-1]
 | 
				
			||||||
 | 
					    if not hasattr(context, 'files'):
 | 
				
			||||||
 | 
					        context.files = {}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    # Ensure the file exists before opening
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        example_file = open(filePath, 'rb')
 | 
				
			||||||
 | 
					        context.files[context.param_name] = example_file
 | 
				
			||||||
 | 
					    except FileNotFoundError:
 | 
				
			||||||
 | 
					        raise FileNotFoundError(f"The example file '{filePath}' does not exist.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@given('the pdf contains {page_count:d} pages')
 | 
					@given('the pdf contains {page_count:d} pages')
 | 
				
			||||||
def step_pdf_contains_pages(context, page_count):
 | 
					def step_pdf_contains_pages(context, page_count):
 | 
				
			||||||
    writer = PdfWriter()
 | 
					    writer = PdfWriter()
 | 
				
			||||||
@ -47,6 +66,59 @@ def step_pdf_contains_blank_pages(context, page_count):
 | 
				
			|||||||
    context.files[context.param_name].close()
 | 
					    context.files[context.param_name].close()
 | 
				
			||||||
    context.files[context.param_name] = open(context.file_name, 'rb')
 | 
					    context.files[context.param_name] = open(context.file_name, 'rb')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_black_box_image(file_name, size):
 | 
				
			||||||
 | 
					    can = canvas.Canvas(file_name, pagesize=size)
 | 
				
			||||||
 | 
					    width, height = size
 | 
				
			||||||
 | 
					    can.setFillColorRGB(0, 0, 0)
 | 
				
			||||||
 | 
					    can.rect(0, 0, width, height, fill=1)
 | 
				
			||||||
 | 
					    can.showPage()
 | 
				
			||||||
 | 
					    can.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_pdf_with_black_boxes(file_name, image_count, page_count):
 | 
				
			||||||
 | 
					    page_width, page_height = letter
 | 
				
			||||||
 | 
					    box_size = 72  # 1 inch by 1 inch black box
 | 
				
			||||||
 | 
					    boxes_per_page = image_count // page_count + (1 if image_count % page_count != 0 else 0)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    writer = PdfWriter()
 | 
				
			||||||
 | 
					    box_counter = 0
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    for page in range(page_count):
 | 
				
			||||||
 | 
					        packet = io.BytesIO()
 | 
				
			||||||
 | 
					        can = canvas.Canvas(packet, pagesize=letter)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for i in range(boxes_per_page):
 | 
				
			||||||
 | 
					            if box_counter >= image_count:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            x = (i % (page_width // box_size)) * box_size
 | 
				
			||||||
 | 
					            y = page_height - ((i // (page_width // box_size) + 1) * box_size)
 | 
				
			||||||
 | 
					            can.setFillColorRGB(0, 0, 0)
 | 
				
			||||||
 | 
					            can.rect(x, y, box_size, box_size, fill=1)
 | 
				
			||||||
 | 
					            box_counter += 1
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        can.showPage()
 | 
				
			||||||
 | 
					        can.save()
 | 
				
			||||||
 | 
					        packet.seek(0)
 | 
				
			||||||
 | 
					        new_pdf = PdfReader(packet)
 | 
				
			||||||
 | 
					        writer.add_page(new_pdf.pages[0])
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    with open(file_name, 'wb') as f:
 | 
				
			||||||
 | 
					        writer.write(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@given('the pdf contains {image_count:d} images on {page_count:d} pages')
 | 
				
			||||||
 | 
					def step_pdf_contains_images(context, image_count, page_count):
 | 
				
			||||||
 | 
					    if not hasattr(context, 'param_name'):
 | 
				
			||||||
 | 
					        context.param_name = "default"
 | 
				
			||||||
 | 
					    context.file_name = "genericNonCustomisableName.pdf"
 | 
				
			||||||
 | 
					    create_pdf_with_black_boxes(context.file_name, image_count, page_count)
 | 
				
			||||||
 | 
					    if not hasattr(context, 'files'):
 | 
				
			||||||
 | 
					        context.files = {}
 | 
				
			||||||
 | 
					    if context.param_name in context.files:
 | 
				
			||||||
 | 
					        context.files[context.param_name].close()
 | 
				
			||||||
 | 
					    context.files[context.param_name] = open(context.file_name, 'rb')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
@given('the pdf contains {page_count:d} pages with random text')
 | 
					@given('the pdf contains {page_count:d} pages with random text')
 | 
				
			||||||
def step_pdf_contains_pages_with_random_text(context, page_count):
 | 
					def step_pdf_contains_pages_with_random_text(context, page_count):
 | 
				
			||||||
    buffer = io.BytesIO()
 | 
					    buffer = io.BytesIO()
 | 
				
			||||||
@ -129,7 +201,7 @@ def step_send_api_request(context, endpoint):
 | 
				
			|||||||
    for key, file in files.items():
 | 
					    for key, file in files.items():
 | 
				
			||||||
        mime_type, _ = mimetypes.guess_type(file.name)
 | 
					        mime_type, _ = mimetypes.guess_type(file.name)
 | 
				
			||||||
        mime_type = mime_type or 'application/octet-stream'
 | 
					        mime_type = mime_type or 'application/octet-stream'
 | 
				
			||||||
        print("form_data " + file.name + " with " + mime_type)
 | 
					        print(f"form_data {file.name} with {mime_type}")
 | 
				
			||||||
        form_data.append((key, (file.name, file, mime_type)))
 | 
					        form_data.append((key, (file.name, file, mime_type)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    response = requests.post(url, files=form_data)
 | 
					    response = requests.post(url, files=form_data)
 | 
				
			||||||
@ -205,3 +277,31 @@ def step_save_response_file(context, filename):
 | 
				
			|||||||
    with open(filename, 'wb') as f:
 | 
					    with open(filename, 'wb') as f:
 | 
				
			||||||
        f.write(context.response.content)
 | 
					        f.write(context.response.content)
 | 
				
			||||||
    print(f"Saved response content to {filename}")
 | 
					    print(f"Saved response content to {filename}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@then('the response PDF should contain {page_count:d} pages')
 | 
				
			||||||
 | 
					def step_check_response_pdf_page_count(context, page_count):
 | 
				
			||||||
 | 
					    response_file = io.BytesIO(context.response.content)
 | 
				
			||||||
 | 
					    reader = PdfReader(io.BytesIO(response_file.getvalue()))
 | 
				
			||||||
 | 
					    actual_page_count = len(reader.pages)
 | 
				
			||||||
 | 
					    assert actual_page_count == page_count, f"Expected {page_count} pages but got {actual_page_count} pages"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@then('the response ZIP should contain {file_count:d} files')
 | 
				
			||||||
 | 
					def step_check_response_zip_file_count(context, file_count):
 | 
				
			||||||
 | 
					    response_file = io.BytesIO(context.response.content)
 | 
				
			||||||
 | 
					    with zipfile.ZipFile(io.BytesIO(response_file.getvalue())) as zip_file:
 | 
				
			||||||
 | 
					      actual_file_count = len(zip_file.namelist())
 | 
				
			||||||
 | 
					    assert actual_file_count == file_count, f"Expected {file_count} files but got {actual_file_count} files"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@then('the response ZIP file should contain {doc_count:d} documents each having {pages_per_doc:d} pages')
 | 
				
			||||||
 | 
					def step_check_response_zip_doc_page_count(context, doc_count, pages_per_doc):
 | 
				
			||||||
 | 
					    response_file = io.BytesIO(context.response.content)
 | 
				
			||||||
 | 
					    with zipfile.ZipFile(io.BytesIO(response_file.getvalue())) as zip_file:
 | 
				
			||||||
 | 
					        actual_doc_count = len(zip_file.namelist())
 | 
				
			||||||
 | 
					        assert actual_doc_count == doc_count, f"Expected {doc_count} documents but got {actual_doc_count} documents"
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for file_name in zip_file.namelist():
 | 
				
			||||||
 | 
					            with zip_file.open(file_name) as pdf_file:
 | 
				
			||||||
 | 
					                reader = PdfReader(pdf_file)
 | 
				
			||||||
 | 
					                actual_pages_per_doc = len(reader.pages)
 | 
				
			||||||
 | 
					                assert actual_pages_per_doc == pages_per_doc, f"Expected {pages_per_doc} pages per document but got {actual_pages_per_doc} pages in document {file_name}"
 | 
				
			||||||
 | 
				
			|||||||
@ -135,7 +135,9 @@ public class MergeController {
 | 
				
			|||||||
            throw ex;
 | 
					            throw ex;
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            for (File file : filesToDelete) {
 | 
					            for (File file : filesToDelete) {
 | 
				
			||||||
                file.delete();
 | 
					                if (file != null) {
 | 
				
			||||||
 | 
					                    Files.deleteIfExists(file.toPath());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -87,12 +87,12 @@ public class PdfOverlayController {
 | 
				
			|||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            for (File overlayPdfFile : overlayPdfFiles) {
 | 
					            for (File overlayPdfFile : overlayPdfFiles) {
 | 
				
			||||||
                if (overlayPdfFile != null) {
 | 
					                if (overlayPdfFile != null) {
 | 
				
			||||||
                    overlayPdfFile.delete();
 | 
					                    Files.deleteIfExists(overlayPdfFile.toPath());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            for (File tempFile : tempFiles) { // Delete temporary files
 | 
					            for (File tempFile : tempFiles) { // Delete temporary files
 | 
				
			||||||
                if (tempFile != null) {
 | 
					                if (tempFile != null) {
 | 
				
			||||||
                    tempFile.delete();
 | 
					                    Files.deleteIfExists(tempFile.toPath());
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -121,7 +121,7 @@ public class SplitPDFController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
 | 
					        logger.info("Successfully created zip file with split documents: {}", zipFile.toString());
 | 
				
			||||||
        byte[] data = Files.readAllBytes(zipFile);
 | 
					        byte[] data = Files.readAllBytes(zipFile);
 | 
				
			||||||
        Files.delete(zipFile);
 | 
					        Files.deleteIfExists(zipFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // return the Resource in the response
 | 
					        // return the Resource in the response
 | 
				
			||||||
        return WebResponseUtils.bytesToWebResponse(
 | 
					        return WebResponseUtils.bytesToWebResponse(
 | 
				
			||||||
 | 
				
			|||||||
@ -63,10 +63,7 @@ public class SplitPdfBySectionsController {
 | 
				
			|||||||
            MergeController mergeController = new MergeController();
 | 
					            MergeController mergeController = new MergeController();
 | 
				
			||||||
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
					            ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
				
			||||||
            mergeController.mergeDocuments(splitDocuments).save(baos);
 | 
					            mergeController.mergeDocuments(splitDocuments).save(baos);
 | 
				
			||||||
            return WebResponseUtils.bytesToWebResponse(
 | 
					            return WebResponseUtils.bytesToWebResponse(baos.toByteArray(), filename + "_split.pdf");
 | 
				
			||||||
                    baos.toByteArray(),
 | 
					 | 
				
			||||||
                    filename + "_split.pdf",
 | 
					 | 
				
			||||||
                    MediaType.APPLICATION_OCTET_STREAM);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        for (PDDocument doc : splitDocuments) {
 | 
					        for (PDDocument doc : splitDocuments) {
 | 
				
			||||||
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
					            ByteArrayOutputStream baos = new ByteArrayOutputStream();
 | 
				
			||||||
@ -98,7 +95,7 @@ public class SplitPdfBySectionsController {
 | 
				
			|||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            data = Files.readAllBytes(zipFile);
 | 
					            data = Files.readAllBytes(zipFile);
 | 
				
			||||||
            Files.delete(zipFile);
 | 
					            Files.deleteIfExists(zipFile);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return WebResponseUtils.bytesToWebResponse(
 | 
					        return WebResponseUtils.bytesToWebResponse(
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,6 @@ package stirling.software.SPDF.controller.api.converters;
 | 
				
			|||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
import java.nio.file.Path;
 | 
					import java.nio.file.Path;
 | 
				
			||||||
import java.nio.file.StandardCopyOption;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@ -41,34 +40,35 @@ public class ConvertOfficeController {
 | 
				
			|||||||
        // Save the uploaded file to a temporary location
 | 
					        // Save the uploaded file to a temporary location
 | 
				
			||||||
        Path tempInputFile =
 | 
					        Path tempInputFile =
 | 
				
			||||||
                Files.createTempFile("input_", "." + FilenameUtils.getExtension(originalFilename));
 | 
					                Files.createTempFile("input_", "." + FilenameUtils.getExtension(originalFilename));
 | 
				
			||||||
        Files.copy(inputFile.getInputStream(), tempInputFile, StandardCopyOption.REPLACE_EXISTING);
 | 
					        inputFile.transferTo(tempInputFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Prepare the output file path
 | 
					        // Prepare the output file path
 | 
				
			||||||
        Path tempOutputFile = Files.createTempFile("output_", ".pdf");
 | 
					        Path tempOutputFile = Files.createTempFile("output_", ".pdf");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Run the LibreOffice command
 | 
					        try {
 | 
				
			||||||
        List<String> command =
 | 
					            // Run the LibreOffice command
 | 
				
			||||||
                new ArrayList<>(
 | 
					            List<String> command =
 | 
				
			||||||
                        Arrays.asList(
 | 
					                    new ArrayList<>(
 | 
				
			||||||
                                "unoconv",
 | 
					                            Arrays.asList(
 | 
				
			||||||
                                "-vvv",
 | 
					                                    "unoconv",
 | 
				
			||||||
                                "-f",
 | 
					                                    "-vvv",
 | 
				
			||||||
                                "pdf",
 | 
					                                    "-f",
 | 
				
			||||||
                                "-o",
 | 
					                                    "pdf",
 | 
				
			||||||
                                tempOutputFile.toString(),
 | 
					                                    "-o",
 | 
				
			||||||
                                tempInputFile.toString()));
 | 
					                                    tempOutputFile.toString(),
 | 
				
			||||||
        ProcessExecutorResult returnCode =
 | 
					                                    tempInputFile.toString()));
 | 
				
			||||||
                ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE)
 | 
					            ProcessExecutorResult returnCode =
 | 
				
			||||||
                        .runCommandWithOutputHandling(command);
 | 
					                    ProcessExecutor.getInstance(ProcessExecutor.Processes.LIBRE_OFFICE)
 | 
				
			||||||
 | 
					                            .runCommandWithOutputHandling(command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Read the converted PDF file
 | 
					            // Read the converted PDF file
 | 
				
			||||||
        byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
					            byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
				
			||||||
 | 
					            return pdfBytes;
 | 
				
			||||||
        // Clean up the temporary files
 | 
					        } finally {
 | 
				
			||||||
        Files.delete(tempInputFile);
 | 
					            // Clean up the temporary files
 | 
				
			||||||
        Files.delete(tempOutputFile);
 | 
					            if (tempInputFile != null) Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
 | 
					            Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
        return pdfBytes;
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private boolean isValidFileExtension(String fileExtension) {
 | 
					    private boolean isValidFileExtension(String fileExtension) {
 | 
				
			||||||
 | 
				
			|||||||
@ -61,8 +61,8 @@ public class ConvertPDFToPDFA {
 | 
				
			|||||||
        byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
					        byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Clean up the temporary files
 | 
					        // Clean up the temporary files
 | 
				
			||||||
        Files.delete(tempInputFile);
 | 
					        Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
        Files.delete(tempOutputFile);
 | 
					        Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Return the optimized PDF as a response
 | 
					        // Return the optimized PDF as a response
 | 
				
			||||||
        String outputFilename =
 | 
					        String outputFilename =
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,7 @@ public class ConvertWebsiteToPDF {
 | 
				
			|||||||
            pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
					            pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            // Clean up the temporary files
 | 
					            // Clean up the temporary files
 | 
				
			||||||
            Files.delete(tempOutputFile);
 | 
					            Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        // Convert URL to a safe filename
 | 
					        // Convert URL to a safe filename
 | 
				
			||||||
        String outputFilename = convertURLToFileName(URL);
 | 
					        String outputFilename = convertURLToFileName(URL);
 | 
				
			||||||
 | 
				
			|||||||
@ -118,7 +118,7 @@ public class AutoSplitPdfController {
 | 
				
			|||||||
            e.printStackTrace();
 | 
					            e.printStackTrace();
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            data = Files.readAllBytes(zipFile);
 | 
					            data = Files.readAllBytes(zipFile);
 | 
				
			||||||
            Files.delete(zipFile);
 | 
					            Files.deleteIfExists(zipFile);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return WebResponseUtils.bytesToWebResponse(
 | 
					        return WebResponseUtils.bytesToWebResponse(
 | 
				
			||||||
 | 
				
			|||||||
@ -136,10 +136,10 @@ public class CompressController {
 | 
				
			|||||||
                    // Increase optimization level for next iteration
 | 
					                    // Increase optimization level for next iteration
 | 
				
			||||||
                    optimizeLevel++;
 | 
					                    optimizeLevel++;
 | 
				
			||||||
                    if (autoMode && optimizeLevel > 4) {
 | 
					                    if (autoMode && optimizeLevel > 4) {
 | 
				
			||||||
                        System.out.println("Skipping level 5 due to bad results in auto mode");
 | 
					                        logger.info("Skipping level 5 due to bad results in auto mode");
 | 
				
			||||||
                        sizeMet = true;
 | 
					                        sizeMet = true;
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        System.out.println(
 | 
					                        logger.info(
 | 
				
			||||||
                                "Increasing ghostscript optimisation level to " + optimizeLevel);
 | 
					                                "Increasing ghostscript optimisation level to " + optimizeLevel);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -230,10 +230,10 @@ public class CompressController {
 | 
				
			|||||||
                            if (currentSize > expectedOutputSize) {
 | 
					                            if (currentSize > expectedOutputSize) {
 | 
				
			||||||
                                // Log the current file size and scaleFactor
 | 
					                                // Log the current file size and scaleFactor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                System.out.println(
 | 
					                                logger.info(
 | 
				
			||||||
                                        "Current file size: "
 | 
					                                        "Current file size: "
 | 
				
			||||||
                                                + FileUtils.byteCountToDisplaySize(currentSize));
 | 
					                                                + FileUtils.byteCountToDisplaySize(currentSize));
 | 
				
			||||||
                                System.out.println("Current scale factor: " + scaleFactor);
 | 
					                                logger.info("Current scale factor: " + scaleFactor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                // The file is still too large, reduce scaleFactor and try again
 | 
					                                // The file is still too large, reduce scaleFactor and try again
 | 
				
			||||||
                                scaleFactor *= 0.9f; // reduce scaleFactor by 10%
 | 
					                                scaleFactor *= 0.9f; // reduce scaleFactor by 10%
 | 
				
			||||||
@ -256,7 +256,6 @@ public class CompressController {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Read the optimized PDF file
 | 
					            // Read the optimized PDF file
 | 
				
			||||||
            pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
					            pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -269,17 +268,18 @@ public class CompressController {
 | 
				
			|||||||
                // Read the original file again
 | 
					                // Read the original file again
 | 
				
			||||||
                pdfBytes = Files.readAllBytes(tempInputFile);
 | 
					                pdfBytes = Files.readAllBytes(tempInputFile);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            // Return the optimized PDF as a response
 | 
				
			||||||
 | 
					            String outputFilename =
 | 
				
			||||||
 | 
					                    Filenames.toSimpleFileName(inputFile.getOriginalFilename())
 | 
				
			||||||
 | 
					                                    .replaceFirst("[.][^.]+$", "")
 | 
				
			||||||
 | 
					                            + "_Optimized.pdf";
 | 
				
			||||||
 | 
					            return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            // Clean up the temporary files
 | 
					            // Clean up the temporary files
 | 
				
			||||||
            Files.delete(tempInputFile);
 | 
					            // deleted by multipart file handler deu to transferTo?
 | 
				
			||||||
            Files.delete(tempOutputFile);
 | 
					            // Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
 | 
					            Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Return the optimized PDF as a response
 | 
					 | 
				
			||||||
        String outputFilename =
 | 
					 | 
				
			||||||
                Filenames.toSimpleFileName(inputFile.getOriginalFilename())
 | 
					 | 
				
			||||||
                                .replaceFirst("[.][^.]+$", "")
 | 
					 | 
				
			||||||
                        + "_Optimized.pdf";
 | 
					 | 
				
			||||||
        return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,6 @@ import java.io.FileOutputStream;
 | 
				
			|||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
import java.nio.file.Path;
 | 
					import java.nio.file.Path;
 | 
				
			||||||
import java.nio.file.StandardCopyOption;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@ -103,10 +102,7 @@ public class ExtractImageScansController {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                tempInputFile = Files.createTempFile("input_", "." + extension);
 | 
					                tempInputFile = Files.createTempFile("input_", "." + extension);
 | 
				
			||||||
                Files.copy(
 | 
					                form.getFileInput().transferTo(tempInputFile);
 | 
				
			||||||
                        form.getFileInput().getInputStream(),
 | 
					 | 
				
			||||||
                        tempInputFile,
 | 
					 | 
				
			||||||
                        StandardCopyOption.REPLACE_EXISTING);
 | 
					 | 
				
			||||||
                // Add input file path to images list
 | 
					                // Add input file path to images list
 | 
				
			||||||
                images.add(tempInputFile.toString());
 | 
					                images.add(tempInputFile.toString());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -176,11 +172,14 @@ public class ExtractImageScansController {
 | 
				
			|||||||
                byte[] zipBytes = Files.readAllBytes(tempZipFile);
 | 
					                byte[] zipBytes = Files.readAllBytes(tempZipFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Clean up the temporary zip file
 | 
					                // Clean up the temporary zip file
 | 
				
			||||||
                Files.delete(tempZipFile);
 | 
					                Files.deleteIfExists(tempZipFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return WebResponseUtils.bytesToWebResponse(
 | 
					                return WebResponseUtils.bytesToWebResponse(
 | 
				
			||||||
                        zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
					                        zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
				
			||||||
            } else {
 | 
					            } if (processedImageBytes.size() == 0) { 
 | 
				
			||||||
 | 
					            	throw new IllegalArgumentException("No images detected");
 | 
				
			||||||
 | 
					            }else {
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
                // Return the processed image as a response
 | 
					                // Return the processed image as a response
 | 
				
			||||||
                byte[] imageBytes = processedImageBytes.get(0);
 | 
					                byte[] imageBytes = processedImageBytes.get(0);
 | 
				
			||||||
                return WebResponseUtils.bytesToWebResponse(
 | 
					                return WebResponseUtils.bytesToWebResponse(
 | 
				
			||||||
@ -201,7 +200,7 @@ public class ExtractImageScansController {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (tempZipFile != null && Files.exists(tempZipFile)) {
 | 
					            if (tempZipFile != null && Files.exists(tempZipFile)) {
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    Files.delete(tempZipFile);
 | 
					                    Files.deleteIfExists(tempZipFile);
 | 
				
			||||||
                } catch (IOException e) {
 | 
					                } catch (IOException e) {
 | 
				
			||||||
                    logger.error("Failed to delete temporary zip file: " + tempZipFile, e);
 | 
					                    logger.error("Failed to delete temporary zip file: " + tempZipFile, e);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,6 @@ import java.io.FileOutputStream;
 | 
				
			|||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
import java.nio.file.Path;
 | 
					import java.nio.file.Path;
 | 
				
			||||||
import java.nio.file.StandardCopyOption;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.Collections;
 | 
					import java.util.Collections;
 | 
				
			||||||
@ -91,139 +90,145 @@ public class OCRController {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        // Save the uploaded file to a temporary location
 | 
					        // Save the uploaded file to a temporary location
 | 
				
			||||||
        Path tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
					        Path tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
				
			||||||
        Files.copy(inputFile.getInputStream(), tempInputFile, StandardCopyOption.REPLACE_EXISTING);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Prepare the output file path
 | 
					 | 
				
			||||||
        Path tempOutputFile = Files.createTempFile("output_", ".pdf");
 | 
					        Path tempOutputFile = Files.createTempFile("output_", ".pdf");
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Prepare the output file path
 | 
					 | 
				
			||||||
        Path sidecarTextPath = null;
 | 
					        Path sidecarTextPath = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Run OCR Command
 | 
					        try {
 | 
				
			||||||
        String languageOption = String.join("+", selectedLanguages);
 | 
					            inputFile.transferTo(tempInputFile.toFile());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List<String> command =
 | 
					            // Run OCR Command
 | 
				
			||||||
                new ArrayList<>(
 | 
					            String languageOption = String.join("+", selectedLanguages);
 | 
				
			||||||
                        Arrays.asList(
 | 
					 | 
				
			||||||
                                "ocrmypdf",
 | 
					 | 
				
			||||||
                                "--verbose",
 | 
					 | 
				
			||||||
                                "2",
 | 
					 | 
				
			||||||
                                "--output-type",
 | 
					 | 
				
			||||||
                                "pdf",
 | 
					 | 
				
			||||||
                                "--pdf-renderer",
 | 
					 | 
				
			||||||
                                ocrRenderType));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sidecar != null && sidecar) {
 | 
					            List<String> command =
 | 
				
			||||||
            sidecarTextPath = Files.createTempFile("sidecar", ".txt");
 | 
					                    new ArrayList<>(
 | 
				
			||||||
            command.add("--sidecar");
 | 
					                            Arrays.asList(
 | 
				
			||||||
            command.add(sidecarTextPath.toString());
 | 
					                                    "ocrmypdf",
 | 
				
			||||||
        }
 | 
					                                    "--verbose",
 | 
				
			||||||
 | 
					                                    "2",
 | 
				
			||||||
        if (deskew != null && deskew) {
 | 
					                                    "--output-type",
 | 
				
			||||||
            command.add("--deskew");
 | 
					                                    "pdf",
 | 
				
			||||||
        }
 | 
					                                    "--pdf-renderer",
 | 
				
			||||||
        if (clean != null && clean) {
 | 
					                                    ocrRenderType));
 | 
				
			||||||
            command.add("--clean");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (cleanFinal != null && cleanFinal) {
 | 
					 | 
				
			||||||
            command.add("--clean-final");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (ocrType != null && !"".equals(ocrType)) {
 | 
					 | 
				
			||||||
            if ("skip-text".equals(ocrType)) {
 | 
					 | 
				
			||||||
                command.add("--skip-text");
 | 
					 | 
				
			||||||
            } else if ("force-ocr".equals(ocrType)) {
 | 
					 | 
				
			||||||
                command.add("--force-ocr");
 | 
					 | 
				
			||||||
            } else if ("Normal".equals(ocrType)) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (sidecar != null && sidecar) {
 | 
				
			||||||
 | 
					                sidecarTextPath = Files.createTempFile("sidecar", ".txt");
 | 
				
			||||||
 | 
					                command.add("--sidecar");
 | 
				
			||||||
 | 
					                command.add(sidecarTextPath.toString());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        command.addAll(
 | 
					            if (deskew != null && deskew) {
 | 
				
			||||||
                Arrays.asList(
 | 
					                command.add("--deskew");
 | 
				
			||||||
                        "--language",
 | 
					            }
 | 
				
			||||||
                        languageOption,
 | 
					            if (clean != null && clean) {
 | 
				
			||||||
                        tempInputFile.toString(),
 | 
					                command.add("--clean");
 | 
				
			||||||
                        tempOutputFile.toString()));
 | 
					            }
 | 
				
			||||||
 | 
					            if (cleanFinal != null && cleanFinal) {
 | 
				
			||||||
 | 
					                command.add("--clean-final");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (ocrType != null && !"".equals(ocrType)) {
 | 
				
			||||||
 | 
					                if ("skip-text".equals(ocrType)) {
 | 
				
			||||||
 | 
					                    command.add("--skip-text");
 | 
				
			||||||
 | 
					                } else if ("force-ocr".equals(ocrType)) {
 | 
				
			||||||
 | 
					                    command.add("--force-ocr");
 | 
				
			||||||
 | 
					                } else if ("Normal".equals(ocrType)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Run CLI command
 | 
					                }
 | 
				
			||||||
        ProcessExecutorResult result =
 | 
					            }
 | 
				
			||||||
                ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF)
 | 
					
 | 
				
			||||||
                        .runCommandWithOutputHandling(command);
 | 
					            command.addAll(
 | 
				
			||||||
        if (result.getRc() != 0
 | 
					                    Arrays.asList(
 | 
				
			||||||
                && result.getMessages().contains("multiprocessing/synchronize.py")
 | 
					                            "--language",
 | 
				
			||||||
                && result.getMessages().contains("OSError: [Errno 38] Function not implemented")) {
 | 
					                            languageOption,
 | 
				
			||||||
            command.add("--jobs");
 | 
					                            tempInputFile.toString(),
 | 
				
			||||||
            command.add("1");
 | 
					                            tempOutputFile.toString()));
 | 
				
			||||||
            result =
 | 
					
 | 
				
			||||||
 | 
					            // Run CLI command
 | 
				
			||||||
 | 
					            ProcessExecutorResult result =
 | 
				
			||||||
                    ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF)
 | 
					                    ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF)
 | 
				
			||||||
                            .runCommandWithOutputHandling(command);
 | 
					                            .runCommandWithOutputHandling(command);
 | 
				
			||||||
        }
 | 
					            if (result.getRc() != 0
 | 
				
			||||||
 | 
					                    && result.getMessages().contains("multiprocessing/synchronize.py")
 | 
				
			||||||
        // Remove images from the OCR processed PDF if the flag is set to true
 | 
					                    && result.getMessages()
 | 
				
			||||||
        if (removeImagesAfter != null && removeImagesAfter) {
 | 
					                            .contains("OSError: [Errno 38] Function not implemented")) {
 | 
				
			||||||
            Path tempPdfWithoutImages = Files.createTempFile("output_", "_no_images.pdf");
 | 
					                command.add("--jobs");
 | 
				
			||||||
 | 
					                command.add("1");
 | 
				
			||||||
            List<String> gsCommand =
 | 
					                result =
 | 
				
			||||||
                    Arrays.asList(
 | 
					                        ProcessExecutor.getInstance(ProcessExecutor.Processes.OCR_MY_PDF)
 | 
				
			||||||
                            "gs",
 | 
					                                .runCommandWithOutputHandling(command);
 | 
				
			||||||
                            "-sDEVICE=pdfwrite",
 | 
					 | 
				
			||||||
                            "-dFILTERIMAGE",
 | 
					 | 
				
			||||||
                            "-o",
 | 
					 | 
				
			||||||
                            tempPdfWithoutImages.toString(),
 | 
					 | 
				
			||||||
                            tempOutputFile.toString());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
 | 
					 | 
				
			||||||
                    .runCommandWithOutputHandling(gsCommand);
 | 
					 | 
				
			||||||
            tempOutputFile = tempPdfWithoutImages;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // Read the OCR processed PDF file
 | 
					 | 
				
			||||||
        byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
					 | 
				
			||||||
        // Clean up the temporary files
 | 
					 | 
				
			||||||
        Files.delete(tempInputFile);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Return the OCR processed PDF as a response
 | 
					 | 
				
			||||||
        String outputFilename =
 | 
					 | 
				
			||||||
                Filenames.toSimpleFileName(inputFile.getOriginalFilename())
 | 
					 | 
				
			||||||
                                .replaceFirst("[.][^.]+$", "")
 | 
					 | 
				
			||||||
                        + "_OCR.pdf";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (sidecar != null && sidecar) {
 | 
					 | 
				
			||||||
            // Create a zip file containing both the PDF and the text file
 | 
					 | 
				
			||||||
            String outputZipFilename =
 | 
					 | 
				
			||||||
                    Filenames.toSimpleFileName(inputFile.getOriginalFilename())
 | 
					 | 
				
			||||||
                                    .replaceFirst("[.][^.]+$", "")
 | 
					 | 
				
			||||||
                            + "_OCR.zip";
 | 
					 | 
				
			||||||
            Path tempZipFile = Files.createTempFile("output_", ".zip");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            try (ZipOutputStream zipOut =
 | 
					 | 
				
			||||||
                    new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) {
 | 
					 | 
				
			||||||
                // Add PDF file to the zip
 | 
					 | 
				
			||||||
                ZipEntry pdfEntry = new ZipEntry(outputFilename);
 | 
					 | 
				
			||||||
                zipOut.putNextEntry(pdfEntry);
 | 
					 | 
				
			||||||
                Files.copy(tempOutputFile, zipOut);
 | 
					 | 
				
			||||||
                zipOut.closeEntry();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // Add text file to the zip
 | 
					 | 
				
			||||||
                ZipEntry txtEntry = new ZipEntry(outputFilename.replace(".pdf", ".txt"));
 | 
					 | 
				
			||||||
                zipOut.putNextEntry(txtEntry);
 | 
					 | 
				
			||||||
                Files.copy(sidecarTextPath, zipOut);
 | 
					 | 
				
			||||||
                zipOut.closeEntry();
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            byte[] zipBytes = Files.readAllBytes(tempZipFile);
 | 
					            // Remove images from the OCR processed PDF if the flag is set to true
 | 
				
			||||||
 | 
					            if (removeImagesAfter != null && removeImagesAfter) {
 | 
				
			||||||
 | 
					                Path tempPdfWithoutImages = Files.createTempFile("output_", "_no_images.pdf");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Clean up the temporary zip file
 | 
					                List<String> gsCommand =
 | 
				
			||||||
            Files.delete(tempZipFile);
 | 
					                        Arrays.asList(
 | 
				
			||||||
            Files.delete(tempOutputFile);
 | 
					                                "gs",
 | 
				
			||||||
            Files.delete(sidecarTextPath);
 | 
					                                "-sDEVICE=pdfwrite",
 | 
				
			||||||
 | 
					                                "-dFILTERIMAGE",
 | 
				
			||||||
 | 
					                                "-o",
 | 
				
			||||||
 | 
					                                tempPdfWithoutImages.toString(),
 | 
				
			||||||
 | 
					                                tempOutputFile.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
 | 
				
			||||||
 | 
					                        .runCommandWithOutputHandling(gsCommand);
 | 
				
			||||||
 | 
					                tempOutputFile = tempPdfWithoutImages;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // Read the OCR processed PDF file
 | 
				
			||||||
 | 
					            byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Return the zip file containing both the PDF and the text file
 | 
					 | 
				
			||||||
            return WebResponseUtils.bytesToWebResponse(
 | 
					 | 
				
			||||||
                    zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            // Return the OCR processed PDF as a response
 | 
					            // Return the OCR processed PDF as a response
 | 
				
			||||||
            Files.delete(tempOutputFile);
 | 
					            String outputFilename =
 | 
				
			||||||
            return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					                    Filenames.toSimpleFileName(inputFile.getOriginalFilename())
 | 
				
			||||||
 | 
					                                    .replaceFirst("[.][^.]+$", "")
 | 
				
			||||||
 | 
					                            + "_OCR.pdf";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (sidecar != null && sidecar) {
 | 
				
			||||||
 | 
					                // Create a zip file containing both the PDF and the text file
 | 
				
			||||||
 | 
					                String outputZipFilename =
 | 
				
			||||||
 | 
					                        Filenames.toSimpleFileName(inputFile.getOriginalFilename())
 | 
				
			||||||
 | 
					                                        .replaceFirst("[.][^.]+$", "")
 | 
				
			||||||
 | 
					                                + "_OCR.zip";
 | 
				
			||||||
 | 
					                Path tempZipFile = Files.createTempFile("output_", ".zip");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                try (ZipOutputStream zipOut =
 | 
				
			||||||
 | 
					                        new ZipOutputStream(new FileOutputStream(tempZipFile.toFile()))) {
 | 
				
			||||||
 | 
					                    // Add PDF file to the zip
 | 
				
			||||||
 | 
					                    ZipEntry pdfEntry = new ZipEntry(outputFilename);
 | 
				
			||||||
 | 
					                    zipOut.putNextEntry(pdfEntry);
 | 
				
			||||||
 | 
					                    Files.copy(tempOutputFile, zipOut);
 | 
				
			||||||
 | 
					                    zipOut.closeEntry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Add text file to the zip
 | 
				
			||||||
 | 
					                    ZipEntry txtEntry = new ZipEntry(outputFilename.replace(".pdf", ".txt"));
 | 
				
			||||||
 | 
					                    zipOut.putNextEntry(txtEntry);
 | 
				
			||||||
 | 
					                    Files.copy(sidecarTextPath, zipOut);
 | 
				
			||||||
 | 
					                    zipOut.closeEntry();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                byte[] zipBytes = Files.readAllBytes(tempZipFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Clean up the temporary zip file
 | 
				
			||||||
 | 
					                Files.deleteIfExists(tempZipFile);
 | 
				
			||||||
 | 
					                Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
 | 
					                Files.deleteIfExists(sidecarTextPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Return the zip file containing both the PDF and the text file
 | 
				
			||||||
 | 
					                return WebResponseUtils.bytesToWebResponse(
 | 
				
			||||||
 | 
					                        zipBytes, outputZipFilename, MediaType.APPLICATION_OCTET_STREAM);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                // Return the OCR processed PDF as a response
 | 
				
			||||||
 | 
					                Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
 | 
					                return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            // Clean up the temporary files
 | 
				
			||||||
 | 
					            Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
 | 
					            // Comment out as transferTo makes multipart handle cleanup
 | 
				
			||||||
 | 
					            // Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
 | 
					            if (sidecarTextPath != null) {
 | 
				
			||||||
 | 
					                Files.deleteIfExists(sidecarTextPath);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -41,28 +41,24 @@ public class RepairController {
 | 
				
			|||||||
        MultipartFile inputFile = request.getFileInput();
 | 
					        MultipartFile inputFile = request.getFileInput();
 | 
				
			||||||
        // Save the uploaded file to a temporary location
 | 
					        // Save the uploaded file to a temporary location
 | 
				
			||||||
        Path tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
					        Path tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
				
			||||||
        inputFile.transferTo(tempInputFile.toFile());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Prepare the output file path
 | 
					 | 
				
			||||||
        Path tempOutputFile = Files.createTempFile("output_", ".pdf");
 | 
					        Path tempOutputFile = Files.createTempFile("output_", ".pdf");
 | 
				
			||||||
 | 
					        byte[] pdfBytes = null;
 | 
				
			||||||
 | 
					        inputFile.transferTo(tempInputFile.toFile());
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List<String> command = new ArrayList<>();
 | 
					            List<String> command = new ArrayList<>();
 | 
				
			||||||
        command.add("gs");
 | 
					            command.add("gs");
 | 
				
			||||||
        command.add("-o");
 | 
					            command.add("-o");
 | 
				
			||||||
        command.add(tempOutputFile.toString());
 | 
					            command.add(tempOutputFile.toString());
 | 
				
			||||||
        command.add("-sDEVICE=pdfwrite");
 | 
					            command.add("-sDEVICE=pdfwrite");
 | 
				
			||||||
        command.add(tempInputFile.toString());
 | 
					            command.add(tempInputFile.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ProcessExecutorResult returnCode =
 | 
					            ProcessExecutorResult returnCode =
 | 
				
			||||||
                ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
 | 
					                    ProcessExecutor.getInstance(ProcessExecutor.Processes.GHOSTSCRIPT)
 | 
				
			||||||
                        .runCommandWithOutputHandling(command);
 | 
					                            .runCommandWithOutputHandling(command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Read the optimized PDF file
 | 
					            // Read the optimized PDF file
 | 
				
			||||||
        byte[] pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
					            pdfBytes = Files.readAllBytes(tempOutputFile);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Clean up the temporary files
 | 
					 | 
				
			||||||
        Files.delete(tempInputFile);
 | 
					 | 
				
			||||||
        Files.delete(tempOutputFile);
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        // Return the optimized PDF as a response
 | 
					        // Return the optimized PDF as a response
 | 
				
			||||||
        String outputFilename =
 | 
					        String outputFilename =
 | 
				
			||||||
@ -70,5 +66,11 @@ public class RepairController {
 | 
				
			|||||||
                                .replaceFirst("[.][^.]+$", "")
 | 
					                                .replaceFirst("[.][^.]+$", "")
 | 
				
			||||||
                        + "_repaired.pdf";
 | 
					                        + "_repaired.pdf";
 | 
				
			||||||
        return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
					        return WebResponseUtils.bytesToWebResponse(pdfBytes, outputFilename);
 | 
				
			||||||
 | 
					        } finally {
 | 
				
			||||||
 | 
					            // Clean up the temporary files
 | 
				
			||||||
 | 
					            Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
 | 
					            Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -185,10 +185,12 @@ public class StampController {
 | 
				
			|||||||
            try (InputStream is = classPathResource.getInputStream();
 | 
					            try (InputStream is = classPathResource.getInputStream();
 | 
				
			||||||
                    FileOutputStream os = new FileOutputStream(tempFile)) {
 | 
					                    FileOutputStream os = new FileOutputStream(tempFile)) {
 | 
				
			||||||
                IOUtils.copy(is, os);
 | 
					                IOUtils.copy(is, os);
 | 
				
			||||||
 | 
					                font = PDType0Font.load(document, tempFile);
 | 
				
			||||||
 | 
					            } finally {
 | 
				
			||||||
 | 
					                if (tempFile != null) {
 | 
				
			||||||
 | 
					                    Files.deleteIfExists(tempFile.toPath());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            font = PDType0Font.load(document, tempFile);
 | 
					 | 
				
			||||||
            tempFile.deleteOnExit();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        contentStream.setFont(font, fontSize);
 | 
					        contentStream.setFont(font, fontSize);
 | 
				
			||||||
 | 
				
			|||||||
@ -150,10 +150,10 @@ public class WatermarkController {
 | 
				
			|||||||
            try (InputStream is = classPathResource.getInputStream();
 | 
					            try (InputStream is = classPathResource.getInputStream();
 | 
				
			||||||
                    FileOutputStream os = new FileOutputStream(tempFile)) {
 | 
					                    FileOutputStream os = new FileOutputStream(tempFile)) {
 | 
				
			||||||
                IOUtils.copy(is, os);
 | 
					                IOUtils.copy(is, os);
 | 
				
			||||||
 | 
					                font = PDType0Font.load(document, tempFile);
 | 
				
			||||||
 | 
					            } finally {
 | 
				
			||||||
 | 
					                if (tempFile != null) Files.deleteIfExists(tempFile.toPath());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
            font = PDType0Font.load(document, tempFile);
 | 
					 | 
				
			||||||
            tempFile.deleteOnExit();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        contentStream.setFont(font, fontSize);
 | 
					        contentStream.setFont(font, fontSize);
 | 
				
			||||||
 | 
				
			|||||||
@ -79,8 +79,8 @@ public class FileToPdf {
 | 
				
			|||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Clean up temporary files
 | 
					            // Clean up temporary files
 | 
				
			||||||
            Files.delete(tempOutputFile);
 | 
					            Files.deleteIfExists(tempOutputFile);
 | 
				
			||||||
            Files.delete(tempInputFile);
 | 
					            Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return pdfBytes;
 | 
					        return pdfBytes;
 | 
				
			||||||
 | 
				
			|||||||
@ -38,14 +38,14 @@ public class GeneralUtils {
 | 
				
			|||||||
                    @Override
 | 
					                    @Override
 | 
				
			||||||
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
 | 
					                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
 | 
				
			||||||
                            throws IOException {
 | 
					                            throws IOException {
 | 
				
			||||||
                        Files.delete(file);
 | 
					                        Files.deleteIfExists(file);
 | 
				
			||||||
                        return FileVisitResult.CONTINUE;
 | 
					                        return FileVisitResult.CONTINUE;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    @Override
 | 
					                    @Override
 | 
				
			||||||
                    public FileVisitResult postVisitDirectory(Path dir, IOException exc)
 | 
					                    public FileVisitResult postVisitDirectory(Path dir, IOException exc)
 | 
				
			||||||
                            throws IOException {
 | 
					                            throws IOException {
 | 
				
			||||||
                        Files.delete(dir);
 | 
					                        Files.deleteIfExists(dir);
 | 
				
			||||||
                        return FileVisitResult.CONTINUE;
 | 
					                        return FileVisitResult.CONTINUE;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,6 @@ import java.io.FileInputStream;
 | 
				
			|||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.nio.file.Files;
 | 
					import java.nio.file.Files;
 | 
				
			||||||
import java.nio.file.Path;
 | 
					import java.nio.file.Path;
 | 
				
			||||||
import java.nio.file.StandardCopyOption;
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
import java.util.Arrays;
 | 
					import java.util.Arrays;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.List;
 | 
				
			||||||
@ -47,8 +46,7 @@ public class PDFToFile {
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // Save the uploaded file to a temporary location
 | 
					            // Save the uploaded file to a temporary location
 | 
				
			||||||
            tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
					            tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
				
			||||||
            Files.copy(
 | 
					            inputFile.transferTo(tempInputFile);
 | 
				
			||||||
                    inputFile.getInputStream(), tempInputFile, StandardCopyOption.REPLACE_EXISTING);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Prepare the output directory
 | 
					            // Prepare the output directory
 | 
				
			||||||
            tempOutputDir = Files.createTempDirectory("output_");
 | 
					            tempOutputDir = Files.createTempDirectory("output_");
 | 
				
			||||||
@ -85,7 +83,7 @@ public class PDFToFile {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            // Clean up the temporary files
 | 
					            // Clean up the temporary files
 | 
				
			||||||
            if (tempInputFile != null) Files.delete(tempInputFile);
 | 
					            if (tempInputFile != null) Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
            if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile());
 | 
					            if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -127,8 +125,7 @@ public class PDFToFile {
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
            // Save the uploaded file to a temporary location
 | 
					            // Save the uploaded file to a temporary location
 | 
				
			||||||
            tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
					            tempInputFile = Files.createTempFile("input_", ".pdf");
 | 
				
			||||||
            Files.copy(
 | 
					            inputFile.transferTo(tempInputFile);
 | 
				
			||||||
                    inputFile.getInputStream(), tempInputFile, StandardCopyOption.REPLACE_EXISTING);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Prepare the output directory
 | 
					            // Prepare the output directory
 | 
				
			||||||
            tempOutputDir = Files.createTempDirectory("output_");
 | 
					            tempOutputDir = Files.createTempDirectory("output_");
 | 
				
			||||||
@ -180,7 +177,7 @@ public class PDFToFile {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        } finally {
 | 
					        } finally {
 | 
				
			||||||
            // Clean up the temporary files
 | 
					            // Clean up the temporary files
 | 
				
			||||||
            if (tempInputFile != null) Files.delete(tempInputFile);
 | 
					            Files.deleteIfExists(tempInputFile);
 | 
				
			||||||
            if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile());
 | 
					            if (tempOutputDir != null) FileUtils.deleteDirectory(tempOutputDir.toFile());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        System.out.println("fileBytes=" + fileBytes.length);
 | 
					        System.out.println("fileBytes=" + fileBytes.length);
 | 
				
			||||||
 | 
				
			|||||||
@ -232,7 +232,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                // Step 3: Apply the function to your labels
 | 
					                // Step 3: Apply the function to your labels
 | 
				
			||||||
                document.addEventListener('DOMContentLoaded', () => {
 | 
					                document.addEventListener('DOMContentLoaded', () => {
 | 
				
			||||||
                  const labels = document.querySelectorAll('#languages .form-check-label');
 | 
					                  const labels = document.querySelectorAll('#languages label');
 | 
				
			||||||
                  labels.forEach(label => {
 | 
					                  labels.forEach(label => {
 | 
				
			||||||
                    const languageCode = label.getAttribute('for').split('-')[1];
 | 
					                    const languageCode = label.getAttribute('for').split('-')[1];
 | 
				
			||||||
                    label.textContent = getFullLanguageName(languageCode);
 | 
					                    label.textContent = getFullLanguageName(languageCode);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user