mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 06:09:23 +00:00
Initial commit of Merge UI
This commit is contained in:
parent
23d86deae7
commit
86831928c7
59
frontend/src/components/tools/merge/MergeSettings.tsx
Normal file
59
frontend/src/components/tools/merge/MergeSettings.tsx
Normal file
@ -0,0 +1,59 @@
|
||||
import React from 'react';
|
||||
import { Stack, Select, Checkbox, Text } from '@mantine/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MergeParameters } from '../../../hooks/tools/merge/useMergeParameters';
|
||||
|
||||
interface MergeSettingsProps {
|
||||
parameters: MergeParameters;
|
||||
onParameterChange: <K extends keyof MergeParameters>(key: K, value: MergeParameters[K]) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const MergeSettings: React.FC<MergeSettingsProps> = ({
|
||||
parameters,
|
||||
onParameterChange,
|
||||
disabled = false,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const mergeOrderOptions = [
|
||||
{ value: 'orderProvided', label: t('merge.orderBy.orderProvided', 'Dragging Files') },
|
||||
{ value: 'byFileName', label: t('merge.orderBy.byFileName', 'By File Name') },
|
||||
{ value: 'byDateModified', label: t('merge.orderBy.byDateModified', 'By Date Modified') },
|
||||
{ value: 'byDateCreated', label: t('merge.orderBy.byDateCreated', 'By Date Created') },
|
||||
{ value: 'byPDFTitle', label: t('merge.orderBy.byPDFTitle', 'By PDF Title') },
|
||||
];
|
||||
|
||||
return (
|
||||
<Stack gap="md">
|
||||
<div>
|
||||
<Text size="sm" fw={500} mb="xs">
|
||||
{t('merge.orderBy.title', 'Merge Order')}
|
||||
</Text>
|
||||
<Select
|
||||
data={mergeOrderOptions}
|
||||
value={parameters.mergeOrder}
|
||||
onChange={(value) => onParameterChange('mergeOrder', value as MergeParameters['mergeOrder'])}
|
||||
disabled={disabled}
|
||||
placeholder={t('merge.orderBy.placeholder', 'Select merge order')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Checkbox
|
||||
label={t('merge.removeDigitalSignature', 'Remove digital signature in the merged file?')}
|
||||
checked={parameters.removeDigitalSignature}
|
||||
onChange={(event) => onParameterChange('removeDigitalSignature', event.currentTarget.checked)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<Checkbox
|
||||
label={t('merge.generateTableOfContents', 'Generate table of contents in the merged file?')}
|
||||
checked={parameters.generateTableOfContents}
|
||||
onChange={(event) => onParameterChange('generateTableOfContents', event.currentTarget.checked)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default MergeSettings;
|
35
frontend/src/hooks/tools/merge/useMergeOperation.ts
Normal file
35
frontend/src/hooks/tools/merge/useMergeOperation.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useToolOperation, ResponseHandler } from '../shared/useToolOperation';
|
||||
import { createStandardErrorHandler } from '../../../utils/toolErrorHandler';
|
||||
import { MergeParameters } from './useMergeParameters';
|
||||
|
||||
const buildFormData = (parameters: MergeParameters, files: File[]): FormData => {
|
||||
const formData = new FormData();
|
||||
|
||||
files.forEach((file) => {
|
||||
formData.append("fileInput", file);
|
||||
});
|
||||
formData.append("sortType", parameters.mergeOrder);
|
||||
formData.append("removeCertSign", parameters.removeDigitalSignature.toString());
|
||||
formData.append("generateToc", parameters.generateTableOfContents.toString());
|
||||
|
||||
return formData;
|
||||
};
|
||||
|
||||
const mergeResponseHandler: ResponseHandler = (blob: Blob, originalFiles: File[]): File[] => {
|
||||
return [new File([blob], 'merged.pdf', { type: 'application/pdf' })];
|
||||
};
|
||||
|
||||
export const useMergeOperation = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useToolOperation<MergeParameters>({
|
||||
operationType: 'merge',
|
||||
endpoint: '/api/v1/general/merge-pdfs',
|
||||
buildFormData,
|
||||
filePrefix: 'merged_',
|
||||
multiFileEndpoint: true, // Single API call with all files
|
||||
responseHandler: mergeResponseHandler, // Handle single PDF response
|
||||
getErrorMessage: createStandardErrorHandler(t('merge.error.failed', 'An error occurred while merging the PDFs.'))
|
||||
});
|
||||
};
|
39
frontend/src/hooks/tools/merge/useMergeParameters.ts
Normal file
39
frontend/src/hooks/tools/merge/useMergeParameters.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
|
||||
export interface MergeParameters {
|
||||
mergeOrder: 'orderProvided' | 'byFileName' | 'byDateModified' | 'byDateCreated' | 'byPDFTitle';
|
||||
removeDigitalSignature: boolean;
|
||||
generateTableOfContents: boolean;
|
||||
}
|
||||
|
||||
export const defaultMergeParameters: MergeParameters = {
|
||||
mergeOrder: 'orderProvided',
|
||||
removeDigitalSignature: false,
|
||||
generateTableOfContents: false,
|
||||
};
|
||||
|
||||
export const useMergeParameters = () => {
|
||||
const [parameters, setParameters] = useState<MergeParameters>(defaultMergeParameters);
|
||||
|
||||
const updateParameter = useCallback(<K extends keyof MergeParameters>(
|
||||
key: K,
|
||||
value: MergeParameters[K]
|
||||
) => {
|
||||
setParameters(prev => ({ ...prev, [key]: value }));
|
||||
}, []);
|
||||
|
||||
const validateParameters = useCallback((): boolean => {
|
||||
return true; // Merge has no required parameters
|
||||
}, []);
|
||||
|
||||
const resetParameters = useCallback(() => {
|
||||
setParameters(defaultMergeParameters);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
parameters,
|
||||
updateParameter,
|
||||
validateParameters,
|
||||
resetParameters,
|
||||
};
|
||||
};
|
@ -2,6 +2,7 @@ import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useFlatToolRegistry } from "../data/useTranslatedToolRegistry";
|
||||
import { getAllEndpoints, type ToolRegistryEntry } from "../data/toolsTaxonomy";
|
||||
import MergeIcon from "@mui/icons-material/Merge";
|
||||
import { useMultipleEndpointsEnabled } from "./useEndpointConfig";
|
||||
|
||||
interface ToolManagementResult {
|
||||
|
95
frontend/src/tools/Merge.tsx
Normal file
95
frontend/src/tools/Merge.tsx
Normal file
@ -0,0 +1,95 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
|
||||
import { useFileContext } from "../contexts/FileContext";
|
||||
import { useToolFileSelection } from "../contexts/FileSelectionContext";
|
||||
|
||||
import { createToolFlow } from "../components/tools/shared/createToolFlow";
|
||||
import MergeSettings from "../components/tools/merge/MergeSettings";
|
||||
|
||||
import { useMergeParameters } from "../hooks/tools/merge/useMergeParameters";
|
||||
import { useMergeOperation } from "../hooks/tools/merge/useMergeOperation";
|
||||
import { BaseToolProps } from "../types/tool";
|
||||
|
||||
const Merge = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { setCurrentMode } = useFileContext();
|
||||
const { selectedFiles } = useToolFileSelection();
|
||||
|
||||
const mergeParams = useMergeParameters();
|
||||
const mergeOperation = useMergeOperation();
|
||||
|
||||
// Endpoint validation
|
||||
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled("merge-pdfs");
|
||||
|
||||
useEffect(() => {
|
||||
mergeOperation.resetResults();
|
||||
onPreviewFile?.(null);
|
||||
}, [mergeParams.parameters]);
|
||||
|
||||
const handleMerge = async () => {
|
||||
try {
|
||||
await mergeOperation.executeOperation(mergeParams.parameters, selectedFiles);
|
||||
if (mergeOperation.files && onComplete) {
|
||||
onComplete(mergeOperation.files);
|
||||
}
|
||||
} catch (error) {
|
||||
if (onError) {
|
||||
onError(error instanceof Error ? error.message : "Merge operation failed");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleThumbnailClick = (file: File) => {
|
||||
onPreviewFile?.(file);
|
||||
sessionStorage.setItem("previousMode", "merge");
|
||||
setCurrentMode("viewer");
|
||||
};
|
||||
|
||||
const handleSettingsReset = () => {
|
||||
mergeOperation.resetResults();
|
||||
onPreviewFile?.(null);
|
||||
setCurrentMode("merge");
|
||||
};
|
||||
|
||||
const hasFiles = selectedFiles.length > 1; // Merge requires at least 2 files
|
||||
const hasResults = mergeOperation.files.length > 0 || mergeOperation.downloadUrl !== null;
|
||||
const settingsCollapsed = !hasFiles || hasResults;
|
||||
|
||||
return createToolFlow({
|
||||
files: {
|
||||
selectedFiles,
|
||||
isCollapsed: hasFiles && !hasResults,
|
||||
placeholder: "Select multiple PDF files to merge",
|
||||
},
|
||||
steps: [
|
||||
{
|
||||
title: "Settings",
|
||||
isCollapsed: settingsCollapsed,
|
||||
onCollapsedClick: settingsCollapsed ? handleSettingsReset : undefined,
|
||||
content: (
|
||||
<MergeSettings
|
||||
parameters={mergeParams.parameters}
|
||||
onParameterChange={mergeParams.updateParameter}
|
||||
disabled={endpointLoading}
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
executeButton: {
|
||||
text: t("merge.submit", "Merge PDFs"),
|
||||
isVisible: !hasResults,
|
||||
loadingText: t("loading"),
|
||||
onClick: handleMerge,
|
||||
disabled: !mergeParams.validateParameters() || !hasFiles || !endpointEnabled,
|
||||
},
|
||||
review: {
|
||||
isVisible: hasResults,
|
||||
operation: mergeOperation,
|
||||
title: t("merge.title", "Merge Results"),
|
||||
onFileClick: handleThumbnailClick,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export default Merge;
|
74
testing/test_pdf_1.pdf
Normal file
74
testing/test_pdf_1.pdf
Normal file
@ -0,0 +1,74 @@
|
||||
%PDF-1.3
|
||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||
>>
|
||||
stream
|
||||
GarW00abco&4HDcidm(mI,3'DZY:^WQ,7!K+Bf&Mo_p+bJu"KZ.3A(M3%pEBpBe"=Bb3[h-Xt2ROZoe^Q)8NH>;#5qqB`Oee86NZp2V9^`:9`Y'Dq([aoCS4Veh*jH9C%+DV`*GHUK^ngc-TW~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 9
|
||||
0000000000 65535 f
|
||||
0000000073 00000 n
|
||||
0000000114 00000 n
|
||||
0000000221 00000 n
|
||||
0000000333 00000 n
|
||||
0000000526 00000 n
|
||||
0000000594 00000 n
|
||||
0000000890 00000 n
|
||||
0000000949 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<cb35d644a26f0c9be3597a7f8189b123><cb35d644a26f0c9be3597a7f8189b123>]
|
||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||
|
||||
/Info 6 0 R
|
||||
/Root 5 0 R
|
||||
/Size 9
|
||||
>>
|
||||
startxref
|
||||
1186
|
||||
%%EOF
|
74
testing/test_pdf_2.pdf
Normal file
74
testing/test_pdf_2.pdf
Normal file
@ -0,0 +1,74 @@
|
||||
%PDF-1.3
|
||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||
>>
|
||||
stream
|
||||
GarW00abco&4HDcidm(mI,3'DZY:^WQ,7!K+Bf&Mo_p+bJu"KZ.3A(M3%pEBpBe"=Bb3[h-Xt2ROZoe^Q)8NH>;#5qqB`Oee86NZp3Iif`:9`Y'Dq([aoCS4Veh*jH9C%+DV`*GHUK^ngmo`i~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 9
|
||||
0000000000 65535 f
|
||||
0000000073 00000 n
|
||||
0000000114 00000 n
|
||||
0000000221 00000 n
|
||||
0000000333 00000 n
|
||||
0000000526 00000 n
|
||||
0000000594 00000 n
|
||||
0000000890 00000 n
|
||||
0000000949 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<46f6a3460762da2956d1d3fc19ab996f><46f6a3460762da2956d1d3fc19ab996f>]
|
||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||
|
||||
/Info 6 0 R
|
||||
/Root 5 0 R
|
||||
/Size 9
|
||||
>>
|
||||
startxref
|
||||
1186
|
||||
%%EOF
|
74
testing/test_pdf_3.pdf
Normal file
74
testing/test_pdf_3.pdf
Normal file
@ -0,0 +1,74 @@
|
||||
%PDF-1.3
|
||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||
>>
|
||||
stream
|
||||
GarW0YmS?5&4HDC`<2TCEOpM_A^cO6ZEVtG&1rQ7k5R.W5uPe>'T[Ma*9KfZqZs*-57""%'<u)dPtNs!.p_7Cem+LKojd:CaF,4$g:S_<`9sPL'Dq([aoCSX;_^WU4Wa'KgNd255,.iQh#\m&~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 9
|
||||
0000000000 65535 f
|
||||
0000000073 00000 n
|
||||
0000000114 00000 n
|
||||
0000000221 00000 n
|
||||
0000000333 00000 n
|
||||
0000000526 00000 n
|
||||
0000000594 00000 n
|
||||
0000000890 00000 n
|
||||
0000000949 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<8c4eba11c30780ded30147f80c0aa46f><8c4eba11c30780ded30147f80c0aa46f>]
|
||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||
|
||||
/Info 6 0 R
|
||||
/Root 5 0 R
|
||||
/Size 9
|
||||
>>
|
||||
startxref
|
||||
1186
|
||||
%%EOF
|
74
testing/test_pdf_4.pdf
Normal file
74
testing/test_pdf_4.pdf
Normal file
@ -0,0 +1,74 @@
|
||||
%PDF-1.3
|
||||
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
|
||||
1 0 obj
|
||||
<<
|
||||
/F1 2 0 R /F2 3 0 R
|
||||
>>
|
||||
endobj
|
||||
2 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
3 0 obj
|
||||
<<
|
||||
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||
>>
|
||||
endobj
|
||||
4 0 obj
|
||||
<<
|
||||
/Contents 8 0 R /MediaBox [ 0 0 612 792 ] /Parent 7 0 R /Resources <<
|
||||
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||
>> /Rotate 0 /Trans <<
|
||||
|
||||
>>
|
||||
/Type /Page
|
||||
>>
|
||||
endobj
|
||||
5 0 obj
|
||||
<<
|
||||
/PageMode /UseNone /Pages 7 0 R /Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
6 0 obj
|
||||
<<
|
||||
/Author (anonymous) /CreationDate (D:20250819094504+01'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20250819094504+01'00') /Producer (ReportLab PDF Library - www.reportlab.com)
|
||||
/Subject (unspecified) /Title (untitled) /Trapped /False
|
||||
>>
|
||||
endobj
|
||||
7 0 obj
|
||||
<<
|
||||
/Count 1 /Kids [ 4 0 R ] /Type /Pages
|
||||
>>
|
||||
endobj
|
||||
8 0 obj
|
||||
<<
|
||||
/Filter [ /ASCII85Decode /FlateDecode ] /Length 147
|
||||
>>
|
||||
stream
|
||||
GarW00abco&4HDcidm(mI,3'DZY:^WQ,7!K+Bf&Mo_p+bJu"KZ.3A(M3%pEBpBe"=Bb3[h-Xt2ROZoe^Q)8NH>;#5qqB`Oee86NZp3%Qb`:9`Y'Dq([aoCS4Veh*jH9C%+DV`*GHUK^nh.J$8~>endstream
|
||||
endobj
|
||||
xref
|
||||
0 9
|
||||
0000000000 65535 f
|
||||
0000000073 00000 n
|
||||
0000000114 00000 n
|
||||
0000000221 00000 n
|
||||
0000000333 00000 n
|
||||
0000000526 00000 n
|
||||
0000000594 00000 n
|
||||
0000000890 00000 n
|
||||
0000000949 00000 n
|
||||
trailer
|
||||
<<
|
||||
/ID
|
||||
[<ade40b97468692afaf20f74813f90619><ade40b97468692afaf20f74813f90619>]
|
||||
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
|
||||
|
||||
/Info 6 0 R
|
||||
/Root 5 0 R
|
||||
/Size 9
|
||||
>>
|
||||
startxref
|
||||
1186
|
||||
%%EOF
|
Loading…
x
Reference in New Issue
Block a user