From 12acc8661b2e9667c5eb2f1b913923686ec62fe4 Mon Sep 17 00:00:00 2001 From: David Juhasz Date: Thu, 7 Nov 2024 15:42:11 -0800 Subject: [PATCH] Add an activity to merge AIS metadata files Fixes #77. Concatenate the Arelda metadata file from the original package and the METS file created by Archivematica into a single "AIS" metadata file. [skip codecov] --- go.mod | 2 + go.sum | 5 + internal/ais/combinemd.go | 138 ++++ internal/ais/combinemd_test.go | 128 +++ internal/ais/workflow.go | 18 + .../AIS_1000_893_3251903 | 748 ++++++++++++++++++ 6 files changed, 1039 insertions(+) create mode 100644 internal/ais/combinemd.go create mode 100644 internal/ais/combinemd_test.go create mode 100644 internal/testdata/little-Test-AIP-Digitization/AIS_1000_893_3251903 diff --git a/go.mod b/go.mod index 40d8a9c3..5ef7402c 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/artefactual-sdps/preprocessing-sfa go 1.23.2 require ( + github.com/antchfx/xmlquery v1.4.2 github.com/artefactual-sdps/temporal-activities v0.0.0-20241018212855-8ea34d29bdf4 github.com/beevik/etree v1.4.0 github.com/deckarep/golang-set/v2 v2.6.0 @@ -22,6 +23,7 @@ require ( ) require ( + github.com/antchfx/xpath v1.3.2 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect diff --git a/go.sum b/go.sum index 7ab41d85..7f102ac9 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,10 @@ cloud.google.com/go/iam v1.1.13/go.mod h1:K8mY0uSXwEXS30KrnVb+j54LB/ntfZu1dr+4zF cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/antchfx/xmlquery v1.4.2 h1:MZKd9+wblwxfQ1zd1AdrTsqVaMjMCwow3IqkCSe00KA= +github.com/antchfx/xmlquery v1.4.2/go.mod h1:QXhvf5ldTuGqhd1SHNvvtlhhdQLks4dD0awIVhXIDTA= +github.com/antchfx/xpath v1.3.2 h1:LNjzlsSjinu3bQpw9hWMY9ocB80oLOWuQqFvO6xt51U= +github.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/artefactual-sdps/temporal-activities v0.0.0-20241018212855-8ea34d29bdf4 h1:WF95IOkZRVSCST/26SAqPYsUrtUuJpavBht6lvdeKl0= github.com/artefactual-sdps/temporal-activities v0.0.0-20241018212855-8ea34d29bdf4/go.mod h1:FVh79rCGNlUU1QnioAU+lrSjLqrA1PJFYKIhWPsmyug= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= @@ -307,6 +311,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= diff --git a/internal/ais/combinemd.go b/internal/ais/combinemd.go new file mode 100644 index 00000000..c7313726 --- /dev/null +++ b/internal/ais/combinemd.go @@ -0,0 +1,138 @@ +package ais + +import ( + "context" + "errors" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/antchfx/xmlquery" + + "github.com/artefactual-sdps/preprocessing-sfa/internal/fsutil" +) + +const CombineMDActivityName = "combine-metadata-files" + +type ( + CombineMDActivity struct{} + CombineMDActivityParams struct { + AreldaRelPath string + METSRelPath string + WorkingDir string + } + CombineMDActivityResult struct { + Path string + } +) + +func NewCombineMDActivity() *CombineMDActivity { + return &CombineMDActivity{} +} + +func (a *CombineMDActivity) Execute( + ctx context.Context, + params CombineMDActivityParams, +) (*CombineMDActivityResult, error) { + areldaPath := filepath.Join(params.WorkingDir, params.AreldaRelPath) + if !fsutil.FileExists(areldaPath) { + return nil, fmt.Errorf("missing Arelda file: %s", areldaPath) + } + + metsPath := filepath.Join(params.WorkingDir, params.METSRelPath) + if !fsutil.FileExists(metsPath) { + return nil, fmt.Errorf("missing METS file: %s", metsPath) + } + + aisName, err := aisFilename(areldaPath) + if err != nil { + return nil, fmt.Errorf("name AIS file: %v", err) + } + + dest := filepath.Join(params.WorkingDir, aisName) + + // Combine metadata files into AIS file. + w, err := os.Create(dest) // #nosec G304 -- generated path. + if err != nil { + return nil, fmt.Errorf("create AIS file: %v", err) + } + defer w.Close() + + if err := w.Chmod(os.FileMode(0o644)); err != nil { + return nil, fmt.Errorf("set AIS file permissions: %v", err) + } + + if err = concat(w, filepath.Join(areldaPath), filepath.Join(metsPath)); err != nil { + return nil, fmt.Errorf("concat: %v", err) + } + + // Delete original metadata files. + if err = removePaths(areldaPath, metsPath); err != nil { + return nil, fmt.Errorf("removePaths: %v", err) + } + + return &CombineMDActivityResult{Path: dest}, nil +} + +func aisFilename(mdpath string) (string, error) { + id, err := parseAccessionID(mdpath) + if err != nil { + return "", fmt.Errorf("get accession number: %v", err) + } + + id = strings.ReplaceAll(id, "/", "_") + + return fmt.Sprintf("AIS_%s", id), nil +} + +func parseAccessionID(path string) (string, error) { + f, err := os.Open(path) // #nosec G304 -- trusted path. + if err != nil { + return "", fmt.Errorf("open metadata file: %v", err) + } + defer f.Close() + + sp, err := xmlquery.CreateStreamParser(f, "//paket/ablieferung/ablieferungsnummer") + if err != nil { + return "", fmt.Errorf("create XML parser: %v", err) + } + + n, err := sp.Read() + if err == io.EOF { + return "", fmt.Errorf("can't find ablieferungsnummer in %q", filepath.Base(path)) + } + if err != nil { + return "", fmt.Errorf("read XML stream: %v", err) + } + return n.InnerText(), nil +} + +func concat(w io.Writer, paths ...string) error { + for i := range paths { + r, err := os.Open(paths[i]) // #nosec G304 -- trusted path. + if err != nil { + return fmt.Errorf("read: %v", err) + } + defer r.Close() + + if _, err := io.Copy(w, r); err != nil { + return fmt.Errorf("copy: %v", err) + } + _ = r.Close() + } + + return nil +} + +func removePaths(paths ...string) error { + var err error + for i := range paths { + if e := os.Remove(paths[i]); e != nil { + err = errors.Join(err, fmt.Errorf("remove: %v", e)) + } + } + + return err +} diff --git a/internal/ais/combinemd_test.go b/internal/ais/combinemd_test.go new file mode 100644 index 00000000..0274ed6c --- /dev/null +++ b/internal/ais/combinemd_test.go @@ -0,0 +1,128 @@ +package ais_test + +import ( + "strings" + "testing" + + temporalsdk_activity "go.temporal.io/sdk/activity" + temporalsdk_testsuite "go.temporal.io/sdk/testsuite" + "gotest.tools/v3/assert" + "gotest.tools/v3/fs" + + "github.com/artefactual-sdps/preprocessing-sfa/internal/ais" +) + +const ( + arelda = ` + + + + FILES + Bundesverwaltung (Bern) + 1000/893_3251903 + + +` + + mets = ` + + +` +) + +func testDir(t *testing.T) string { + td := fs.NewDir(t, "ppsfa", + fs.WithFile("arelda.xml", arelda), + fs.WithFile("mets.xml", mets), + ) + + return td.Path() +} + +func TestExecute(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + params ais.CombineMDActivityParams + want ais.CombineMDActivityResult + wantErr string + wantManifest fs.Manifest + }{ + { + name: "Returns the combined metadata", + params: ais.CombineMDActivityParams{ + AreldaRelPath: "arelda.xml", + METSRelPath: "mets.xml", + WorkingDir: testDir(t), + }, + want: ais.CombineMDActivityResult{Path: "{{wd}}/AIS_1000_893_3251903"}, + wantManifest: fs.Expected(t, + fs.WithFile("AIS_1000_893_3251903", arelda+mets, fs.WithMode(0o644)), + ), + }, + { + name: "Errors if the Arelda file doesn't exist", + params: ais.CombineMDActivityParams{ + AreldaRelPath: "missing.xml", + WorkingDir: testDir(t), + }, + wantErr: "activity error (type: combine-metadata-files, scheduledEventID: 0, startedEventID: 0, identity: ): missing Arelda file: {{wd}}/missing.xml", + }, + { + name: "Errors if the METS file doesn't exist", + params: ais.CombineMDActivityParams{ + AreldaRelPath: "arelda.xml", + METSRelPath: "missing.xml", + WorkingDir: testDir(t), + }, + wantErr: "activity error (type: combine-metadata-files, scheduledEventID: 0, startedEventID: 0, identity: ): missing METS file: {{wd}}/missing.xml", + }, + { + name: "Errors when the Arelda file is invalid", + params: ais.CombineMDActivityParams{ + AreldaRelPath: "mets.xml", + WorkingDir: testDir(t), + }, + wantErr: "activity error (type: combine-metadata-files, scheduledEventID: 0, startedEventID: 0, identity: ): name AIS file: get accession number: can't find ablieferungsnummer in \"mets.xml\"", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ts := &temporalsdk_testsuite.WorkflowTestSuite{} + env := ts.NewTestActivityEnvironment() + env.RegisterActivityWithOptions( + ais.NewCombineMDActivity().Execute, + temporalsdk_activity.RegisterOptions{Name: ais.CombineMDActivityName}, + ) + + tt.want.Path = strings.ReplaceAll(tt.want.Path, "{{wd}}", tt.params.WorkingDir) + tt.wantErr = strings.ReplaceAll(tt.wantErr, "{{wd}}", tt.params.WorkingDir) + + future, err := env.ExecuteActivity(ais.CombineMDActivityName, tt.params) + if tt.wantErr != "" { + if err == nil { + t.Errorf("error is nil, expecting: %q", tt.wantErr) + } else { + assert.ErrorContains(t, err, tt.wantErr) + } + + return + } + assert.NilError(t, err) + + var got ais.CombineMDActivityResult + future.Get(&got) + assert.DeepEqual(t, got, tt.want) + assert.Assert(t, fs.Equal(tt.params.WorkingDir, tt.wantManifest)) + }) + } +} diff --git a/internal/ais/workflow.go b/internal/ais/workflow.go index ebd1bc83..80e60926 100644 --- a/internal/ais/workflow.go +++ b/internal/ais/workflow.go @@ -188,6 +188,20 @@ func (w *Workflow) SessionHandler(ctx temporalsdk_workflow.Context, aipUUID, aip return "", e } + var combineMDResult CombineMDActivityResult + e = temporalsdk_workflow.ExecuteActivity( + withFilesystemActivityOpts(ctx), + CombineMDActivityName, + &CombineMDActivityParams{ + AreldaRelPath: metadataRelPath, + METSRelPath: metsPath, + WorkingDir: filepath.Join(localDir, filepath.Base(metadataRelPath)), + }, + ).Get(ctx, &combineMDResult) + if e != nil { + return "", e + } + var zipResult archivezip.Result e = temporalsdk_workflow.ExecuteActivity( withFilesystemActivityOpts(ctx), @@ -231,6 +245,10 @@ func RegisterWorkflow(ctx context.Context, tw temporalsdk_worker.Worker, config NewParseActivity().Execute, temporalsdk_activity.RegisterOptions{Name: ParseActivityName}, ) + tw.RegisterActivityWithOptions( + NewCombineMDActivity().Execute, + temporalsdk_activity.RegisterOptions{Name: CombineMDActivityName}, + ) tw.RegisterActivityWithOptions( archivezip.New().Execute, temporalsdk_activity.RegisterOptions{Name: archivezip.Name}, diff --git a/internal/testdata/little-Test-AIP-Digitization/AIS_1000_893_3251903 b/internal/testdata/little-Test-AIP-Digitization/AIS_1000_893_3251903 new file mode 100644 index 00000000..55212814 --- /dev/null +++ b/internal/testdata/little-Test-AIP-Digitization/AIS_1000_893_3251903 @@ -0,0 +1,748 @@ + + + AIP + 909c56e9-e334-4c0a-9736-f92c732149d9 + fa5fb285-fa45-44e4-8d85-77ec1d774403 + 1 + + + header + + old + + SIP + + metadata.xml + metadata.xml + MD5 + 29a08a4c20e931bf91079abb6951c79e + + + + + xsd + + ablieferung.xsd + ablieferung.xsd + MD5 + aa1f7ad13064e1643ac85478296165af + + + archivischeNotiz.xsd + archivischeNotiz.xsd + MD5 + 847911efbac472d0ecc6fe1e99873799 + + + archivischerVorgang.xsd + archivischerVorgang.xsd + MD5 + 4a237563fd2d40be9a9ecbf4c0bf946e + + + arelda.xsd + arelda.xsd + MD5 + f8454632e1ebf97e0aa8d9527ce2641f + + + base.xsd + base.xsd + MD5 + cb30854883c6d5640b0965dae5f34afd + + + datei.xsd + datei.xsd + MD5 + a4276f0c798ce6c497f0a03660ead0d9 + + + dokument.xsd + dokument.xsd + MD5 + 721965e5224766040bf0bcd03978809e + + + dossier.xsd + dossier.xsd + MD5 + f3f1141d95e92a291e84cfb30bb30e9a + + + ordner.xsd + ordner.xsd + MD5 + 83e0f91d1a232c7bdd7416970844af1c + + + ordnungssystem.xsd + ordnungssystem.xsd + MD5 + 4b64247b25362382d6c648ba8ff76ad6 + + + ordnungssystemposition.xsd + ordnungssystemposition.xsd + MD5 + 1e7f0a9b914c8baf1235740b133ec90e + + + paket.xsd + paket.xsd + MD5 + 9920c66b7066f645390e922ba803aadb + + + provenienz.xsd + provenienz.xsd + MD5 + 2d6dbc4665cb5169d62549dbbc3f19a7 + + + zusatzDaten.xsd + zusatzDaten.xsd + MD5 + a685887b7ad673ea2deac6f96cf3fb4f + + + + + content + + d_0000001 + + 00000001_PREMIS.xml + 00000001_PREMIS.xml + MD5 + 11f791c655cae7f4ab1dcaf613314151 + + + 00000002_PREMIS.xml + 00000002_PREMIS.xml + MD5 + 4ed338cc69d7635450b5332fb727d2d3 + + + Prozess_Digitalisierung_PREMIS.xml + Prozess_Digitalisierung_PREMIS.xml + MD5 + 8067daaa900eba6dace69572eea8f8f3 + + + 00000001.jp2 + 00000001.jp2 + MD5 + f7dc1f76a55cbdca0ae4a6dc8ae64644 + + + 00000002.jp2 + 00000002.jp2 + MD5 + 954d06be4a70c188b6b2e5fe4309fb2c + + + + + + FILES + Bundesverwaltung (Bern) + 1000/893_3251903 + + + Bundesverwaltung (k.A.) + + + Eisenbahnwesen + + 4. + Privatbahnen + + 4.2 + Normalspurbahnen + + 4.2.09 + Eisenbahnlinien Kanton Luzern + + 4.2.09.12 + Rigibahnen (Vitznau-Rigistaffel-Rigibahn) + + Beschwerde von Pfyffer-Zimmermann aus Witznau und Zurücknahme derselbigen + digital + + + + + + 1874-04-01 + + + + 1874-11-30 + + + + U_m_s_c_h_l_a_g_0000001 + digital + + + 000001 + + _miEf29GTkFR7ymi91IV4fO + _SRpeVgb4xGImymb23OH1od + _mOXw3hINt3zY6WvKQOfYmk + _MKhAIC639MxzyOn8ji3tN5 + _chYnT1OupaVua05V679qUi + _W4d0itDv1Grd0LDFAhwlmR + _vUbY87XIyeGLjNG5y3xndZ + _XUSIau5otTTxuIfouqUhn4 + _Qau7zrpSWxttPlj5ebexFJ + _Gve1UlcBNTPicVrGMpwFj3 + _AzXvLcHJZhBA9XiHtax3wL + _uyd7l0xiDaXnVtprqR2lQS + + + D_o_k_u_m_e_n_t_0000001 + digital + + + 000002 + + _g1rji2dQsuGpZLBIaAiMPA + _dUXhtGwNgH35GN2YJ8pyGj + _m9zFkHXuktC31o11YAkQ86 + _yeOC7WoQW2MvLRoJx9seg4 + _vjzJldkMgFjhC2x99KxX4C + _sAunvZiDt97hvfFKcuUAIp + _c0u3TfaCacJqAVcAQA1Vgt + _gOPGadEspA069T2N85DpVl + _xEGJY9P6wMIrYF5o4mNu1j + _mANLal5d2ams8uKVDWrZ6u + _MHMqEv92PQk5OGXPz4OdVC + _BLhDpBCdVv7XA8lPvYXgiM + _kaV2BGkXL0FRUMVSOs4JtG + _OQaXkOBY3ZdkDOaThk115U + _yUdWYvrUmwzzSx9Za6oGIY + _ns8VmWNaaqicac23Ve41wi + _8hJ6bqQxfPNvZYSQNiEM0X + _WDOTiSst00lZpCM3sU5hCr + _LUdtsyL44uJOQaH6jpa6F6 + _l6KWuZCLx1iKZ2aIB4doXK + _AhV2qVsjUaEYYHMqw0aAeM + _LqaXt7ItrSVoeFvbHDBLXQ + _vqe0NMPet3r3M2SceOawtc + _r6zP0gEmpz26iiYhh8GRG9 + _c9YCcja1BoebFloHrpzCmj + _jEW3tnlvkhF2Fzx1k2YvRF + _65DO2vjMnsF8s822IspEQL + _22poW8ITNRamPDrw9WW8l7 + _29aZ0BSA4qVep3IQg9EieM + _u5MaEjNn2Uz7j04gt3UnNQ + _CKkjeyNJ95RnEBAw0YWBno + _M1qm9saoSTpN75kfzVqkhg + _8eb0XsAYbviO9Xo3jI7U53 + _09TwnifWryQWrjs7hScdtd + _Cf655IAFrvhEC8EimMn1oa + _Ahjio1HDqF86v9yYcrOdb7 + _p88wAjggmlKTY2yqaLeqLO + _hnE15fb0ZBvcxvsM1Ma6P4 + _1bTsyHnoHuMyaWQWXxV6Ms + _7YzsOEQAFlg1nigqkj1ZCg + _SjnRjf96WKrtNnPPZGl07Z + _AqJz4iIE5eqN817DBuxT0E + _U8ihZE3VvCx6lIiqRv5dYO + _bkACPSns4u8viTC5bFWGiU + _K16qGRbMamzTTltdDAmJAn + _7XoZ0Szb5fjDnKa8sxbSEG + _Kzy1SSowwcrK4Ek0RGTmIG + _GMp4D9dmzUjsZHzOcsoMpQ + _QUlompkdLkrAEnLg2EjoNO + _Uo9EciU6ILcCg65yAH47uX + _t2ZFRhyi8nNaNy8hQ2t4L9 + _0D2xQ2tgEsbfv2n8701jCD + _RzGZcWlLHYHYHejEMtYJD1 + _ZWFNJKDstyjzV5AY7qteck + _ENEIr4hcozpDvVU0lTFFNR + _6jkE6ZiHpLF7JsqFtHJ6Rj + _GF3M4aavmw3A9fj6HTvtzQ + _iP9W74QLwsT4iySqXWe489 + _tCYK9lQ7Sfz1bd7hX7sbQ2 + _r1av2rPqUUcXdCAwK38N7k + _34nTAWDpIsjwIRqaKzIiA9 + _A0hWZZMTMWs0yOkVsfQIBu + _zIG4PT1xSfixgbIoIAiBLM + _WuExOQbpKcpVYiv0Zy0e6D + _k6oo1SW3RGkriZod3BK99p + _ryinWEtuwIpQNP9DyCbrbX + _s6EvFkDLbAvJQJNYctw0Ww + _tXLTqAespa6nLUIrcavkAr + _nwx8S8jRnOeggc1b2JFLM0 + _9MR0mmyKTu7lD1MOmZYMXw + _EwRpkPdle6xkbKXFMZW3IB + _TgaykLwdGRzII8teYbJAEm + _eUK5I37sOPMxnKsWm7AEvK + _TYwgpiUa3dp34fWeYUnJX0 + _u4MvnOdD3ziITgoB1U7Pzb + _UhXXXHpBFJu0W8w1dbvUwg + _xagaUMRyqSx77NnWTCyj9h + _IWFxD8uipl2XF44si89qdk + _0VKeh8UdAQ4QzTCf9DqoqU + _MK1pPyJ2VVKPrTmaIJ3WMu + _iKCifgultPZAicJf6L5Vtv + _mnVnAMZuJUx93XWR40mJLa + _4alkEjGRzdvT3zYZjmKqCU + _JdYHGXVQngMdqcsOQu6Ge8 + + + D_o_k_u_m_e_n_t_0000002 + digital + + + 000003 + + _5GbCxR3sghNXT8xA5s9HyZ + _TDIdElybgFikGkAIkTwqoh + _IMArz9cRs14LvlsMbiD8dg + _QqXM3KgJ6Cd5u5ZcZVLjwh + _HHN518svEimt6kKdODk5Hf + _TQiyhfZ7pij40uEWgzN9a9 + _lW3C2jttc1YSfjb94kPsuj + _GZnDQZu4tttgYJ3qRnZsIw + _9XTvqsaQ7n0h9jnhxCNlwC + _T2AHO9Ay2h6xDzQxVxGIQM + _erkbH23XUIhY6zYvAfnflZ + _FCUJfG1htM4ZjL9n60SbSG + _iAT86o61V4mUXrVWFN8TxJ + _x6BXCPWfBycjT23AqKXs6z + _UEJcxNRFUJCwDZh1saSJL0 + _ZXqfZ62rCifimFhGXYECU6 + _TsE8gzpiNSIQE3KermKmIx + _6XU2nW1l7uO2WWFPVlb6ds + _Ssw46IURTviV1n60ANariT + _QoLTixmqRpsl8NJlijTsob + _zS9BqPUGf5IXNDYYrIWoK4 + _JczB9iV7bzkO4XVPSOUhy1 + _cypvHQeLGC4zlXrpBcfgbE + _xcY0O1iSB9YrBeP9dWKxaB + _hmBomqIVtkLqZNOLPETgEv + _IJwBmAjHb5FqWo7Wq7Qf6R + + + D_o_k_u_m_e_n_t_0000003 + digital + + + 000004 + + _RO2p692zkgdsiRQMmkQArf + _2vljO2Bhh6leQYePmnzqED + _Xl1AqwKT6EEWwAPyyMz3bp + _2IO73BJXIP3N5kKDjZgImM + _y0qDEePHlePYYVdTB4sPZ8 + _0xPOqTgXDm6tA6V4EjuO26 + _HpQUjI8OpqkMCU5R2CyVqD + _6NCo6MZM5L0fpRKTQayfoE + _1xQ1vIulR4tjnEBAAoGO0Z + _SGKzK1JTc14hjyypFvod2d + _Z5FZCUArnATPRrenpduVWI + _L1bYrroT3aKdWYXP3AIVo9 + _IcpobVzeGK0lvwjYRfyQBa + _qG7sApsw35bYhrWpTXXhEz + _oGaZtFyiKiQqMzSeA13Kz2 + _Qe1TWhopShwLSSSsPmNtqR + _EHXkr0OsjGhZpik4z3IfK7 + _cJAogjjEq7R6RCtxEivL8L + _cdJNqJKOQVhxO9GFO01hWj + _GMSlFo0t5tdZYwarv50mCL + _itLKxrxYH2i5rslI7HHMxu + _czXg34nFEEtIeNEbBwBViM + _Gq45ShXWYVQB6FGL4eQ6KQ + _ohXDvtPkQT9gjavHMhE6s6 + _2e1DtZvIaWGol7TdeNs7mj + _0c7UKGRVoy9SKjluMj6iXM + _slVmhdd99ZM7iR1RSHYc23 + _FeiKFdMGoa0qQuqYOOXeJ2 + _NyuWZO4M2xpF5mkC5C4W21 + _vqNP5Wj14Jgo2dEGb82NN5 + _87PWsbAucVphK2i0GvuoK1 + _V5wdSfKnvvcHVWbvXxnM4V + _XCX4o1SeIkuvOHUTUK4SjK + _hsP0JP4t9dbhHZtSLicieI + + + D_o_k_u_m_e_n_t_0000004 + digital + + + 000005 + + _MMXDGhijq4qJC2aopeBET2 + _T64yDbMxHd4zOfiGsoFs4r + _KE02A0CGzT96EE5vF9Vkdv + _InXaEi8lKBdVMY2qsaBWIY + _mHtXnHF6nNaJPU9b2OsETC + _y9mcoxJZ6Y61TTtn3URphY + _YC1zWSNQ6SRiTgtFGuSogz + _kzWnFq4N6JWQSiPehb2GbZ + _XZbY1IizMF0WytFYyVm6Mh + _K67qrCY8ooGrAR0JKNJNqR + _wRRzwtYII1W5VuMvb9mTiF + _KS4ieDUVLMUAOTIS5cjkBu + _sDtU2QBmgbiypc9lkRsX73 + _8YO0xGYe4kTm2zwkuTUhsD + _WkYMoMj6YoZYe5dzlEl6UH + _rtjTAA789ADSKGFsTDQJWX + _vsP0fJdtAMMtVJfkr31biT + _ajpXoVoMzFfgZZppkaTtiG + _Qoj7vhZa7eoIMhSDcyh0o3 + _e4iXpHuX2MGTYmNMwlVzIF + _GNmwhWlzHTpU2c8GYVu3a8 + _Tfg1PiU4o0BuZLjcCcCcVC + _ffMVulAwTv5MBnB7KPPTmA + _LOst4IBCydIdX0ubzo3nqT + _3CDgIvoEtFU4wIsSBYr09R + _rKTEk5Hk6gpJhe10uvvpnJ + _HX1YwoXuUlupV5ZRiIzyWk + _zaoTYXgwS2noPioDE0mY4r + _GuoOJHUs8Yp80qpQ2RS5Te + _IkpFMsCq3pe9CRVlLocbs5 + + + D_o_k_u_m_e_n_t_0000005 + digital + + + 000006 + + _KZ4jMOlQzsRx7CaeDFivy5 + _IBo5JKFeEDTSNo8jeJEhi0 + _1U5ICwsUEWM9IVn8YQKd4x + _fYOPbYuQQzIuvBWi65PKa4 + _2QfWWCHlcQsKdZhqVObpMi + _evhPU333knVoQenmoxQp3p + _Dzcp26EY5q9tp8FY2qHVHd + _RKoI7lbfb02x0CI6tp5pet + _rNx0K1iEzAbZ42QtZpoNPp + _D47AgSXy1psDGSPvu8n3Ab + _VC3k7lRx4gwUYGIbsDHXmx + _WmutZZauwa0svTrKLojbfG + _xTNQNQq0LeFKFH7DTO0oqp + _W44KutzxgdYeJ1dnfei84t + _2jGV9dAtXIS6bbAwNy3y0v + _LesD7GLY0XU3xwQ3Qam5zt + _eHsdgzZhcMxKL4sWSLM3wA + _pSF7HwXXEuG4SFNkhsTOZE + _v6wfzOFe9ztQ3bRIO99KSv + _kp7i5MpgnUZz8Od8q8BlNk + _A6HU42E1oIpxNtnaaakSBX + _fd6f3iTPfkv0mDfCIBQOB3 + _9QNMH8PMBe4xKaMRyCS6Om + _lAdUCmfzik66AI6chJSlkG + _PWNGMrmal4Ot5TZmqB7ZYd + _9NcSm0FkkfcvCoiJjsRIgV + _NA8YTj85w888SqLKC7GUjy + _5ejgwi6M1HiOLIjKHV7Yh2 + _GLgX9BNnr8REfxjuvJjAt4 + _MwdwiJAKh9qnKVZTDwn8z0 + _eo6Un53FiJZcuuze12DZk0 + _CcRVDmsk1UT6yPoNWZai5D + _qhXvBpLc4vvUmwxiuK60zN + _IQH4a19oWdTYV6lnX2W60C + _IFuBFA9e5pYWgyhmJ0AW4c + _PARCvFSaN2WKsVO3euTyWg + _Ia3nJ4PRMlJDsRUChOzTf8 + _sUtsReqAfPndGMezxeCTiK + _fS7MPLkGHqBp7U6ND9YyKP + _kkerbTQ67I6R6iSKEdMRsb + _rvyYCI9FdSbzA0fQsKulE6 + _n7M0sIwOJL9Yk1gJFr21fB + _LHMWPwCslSzpp2IjZ25RWE + _fuy90NMhEjOIKrl1WDNsUq + + + D_o_k_u_m_e_n_t_0000006 + digital + + + 000007 + + _fqsPyR6gDpgU5Z3ArCJNeM + _2aOx3skcAZE17WZeZv5hZq + _iLaCg81G9JRb6NuWVePNpF + _RLcfryYHYI66uKhTMv4qHz + _mCdJazjFP1c6gUit9aKMjR + _IrRzPL6OkfOyctmo47bCxq + _ROfPPZvW6pvjO8TNzfKJ0M + _f4QB89a8ikn1fcWzWFWZez + _r8ClVGmpWAxabOq8JC9zL3 + _P08C99IZ3KFEjT7wgOGs6q + _YLiA0pG0Eil9fLj6Mb15Ce + _HNNLv4PqWh94DS8CLmI7et + _5Y5iAb70VuQLIp4TTRnIK7 + _WdQdTCXdlo9jZkfPQRFcWh + + + D_o_k_u_m_e_n_t_0000007 + digital + + + 000008 + + _RqkBRp1fesebvsPIEiUNQd + _pMI2DV3PWJfRkmgpAQZOhK + _5nQtK3pesuPnrebALdgAJp + _J3EBDE0Qb4NtQzy9Bqz6EP + + + D_o_k_u_m_e_n_t_0000008 + digital + + + 000009 + + _Xb7BEeQlYVD5iKjhN002VT + _ntrnETgjGq5ZkkqXfWhfrR + _HLiV6GpXlYzLYBmbQG70lR + _JvTp5wKJSrl0xYkbxOnrRH + _Ex74dZAnLGkEnn26OTvug7 + _ZnggZ8McxV0Zte6iN4FiiJ + _kJB5OvwTiRtaQadD87Cr4I + _8id5yJvFYTJt562PuQs8F7 + _yBqDEnTHEKd4OTnTwpWs3r + _jMklSwpXym77rS5f7wQSl6 + + + D_o_k_u_m_e_n_t_0000009 + digital + + + 000010 + + _kgiVYxgtd2scGDhIt8dozW + _MNJhXJMd6aGxXtT4KcVAwl + _mOEXfGMbComnFCEn7rY4JJ + _OTrhzDR1bOkVBnSODpJ8vm + _hH1cCBvux8nppZtw8P6Y5x + _ByqxIi7KrjbH9cg4VAJ0LV + _SFCHCNPWcdGmGg9xb4V35v + _Fq8w7T1SOXj62CObcXUrUG + _RGt4S8kcTAjnftlLOtdTed + _8JpG2bZ4uHfJvQ8evFpzFm + _u8wbaevKqvjDGGIL099UIR + _30uCRDgDRfx6unYVsoOtTq + _tNXTA6AU8a9C3gFZlLi4ue + _znw6633dR5JIvtBpREINzq + _9ea8XQ157z3wSdAOQofL6j + _U6OWSfan1QaUoFsHgIHt8T + _1PMnI74tQGziV2Ac7HPxDA + _mbXxIjD4Wf04zsrwAXjMGY + + + D_o_k_u_m_e_n_t_0000010 + digital + + + 000011 + + _TiPs089ulN6kLu00MwFiA5 + _9yiUkB1lIPSWhjMhQBpenn + _z1661TWaUL5ZslBqg3lezx + _kTO13Tip4ClGBOIsVXaY4Z + _lYT860phXPJJP12SlrhW7W + _O6tiqxLU7KapYy8VUL1NfS + + + D_o_k_u_m_e_n_t_0000011 + digital + + + 000012 + + _dxHJAQRH9faWPAy2SHGHkK + _iMua9Kcu3EXTkTanStTkQX + _OS7ocJFpaR9PHVMbEnrCRQ + _jqImgnt9qWQXKsFlIejtPj + _ZZcGoxi2beNyGA9lqipEOS + _P6xU6DgTXZob9HZDmU0XJc + _oDA7Qk2f8wL1UmS6hw6BSG + _IC6iMb5d5KanurFGtWQxyD + _qVDOwCxuC9i82QgRMcIrQu + _U8NnQkpVMQcNQTtLyNc39p + + + D_o_k_u_m_e_n_t_0000012 + digital + + + 000013 + + _YmgmI3c08DnHMLZNhjyq25 + _wtR8U6MzOz3thBU4s1CIY6 + _3HCURIx5sYfdsSXiNetOUF + _grqjylqzmA9ZdcVAEaZ2SY + _e9QUoUwvAAYNAIOcHCdVgn + _jWHcN1SqXQhkZAEyFpVB12 + _ZAxrrwnLQmyGnDFMUCoH34 + _FikviVe8pvRieFmC57WlRY + _9HvDTqJLRAr9e2PYyVIbJT + _q5yN8ixVJ1Q82sfASKFrm2 + + + D_o_k_u_m_e_n_t_0000013 + digital + + + 000014 + + _zNm1O32k4ujOrXNyxlTreS + _ll3DM2BEM2B10PAziKaSI9 + _ls1Nypyn4vcteoDjeAVbJN + _BGXS79BxBVD1odwUpTv6E6 + _7nd9FIuBDLgsFmF8qBLl6Y + _zg9JZsUIBwXwG0oFw2oGCq + _KHnOoHbnUMh4C5Szg2vyq5 + _t1A0k0NWhCCbtxiOXswMvs + _KEwotJieFXv7TspFOikWKR + _7EW6bwHe7cCrJAa5FAYnHi + _7c5F8YYaasRTPsu0AOXx0d + _KsYsTXZngBrdJJQ3JqbrE8 + _zC6lpqdRzNQl1BFBPEFy0T + _Re80mq9Psk4otRUJAKjrW2 + _uPShzQ4XHzKvyWYg1Vx12a + _q0OhAMl1owqvBvyyYpc3et + _fW7pGM0x5ZtHZd193VRY3x + _aH1mY7zyKnVmZRTKjLUWHK + _LT0ISE1KSSy55RuCFyLuGA + _V3glwnlSGywy82iCLZ3N5V + _5e7CJ88AMGziywDw1fAjWw + _yvp8lVYoYh31gAPkGY1wna + _iNVi3HL8osRWfGxljVSZIQ + _zeuQIbgcJIAyj7UX3UpeX5 + _1DTjvhyqIvklV7VFymJKKh + _hcEywtSuawS0ZjP2lFTEdF + _xtR2SqdyivU2JgFlDanRYx + _mBtxLpyAe7WDz60HifW8D5 + _6BKYFJBuvvQ0Dl77pvLZLS + _xyEdrQpxM61BeN6ZmLVq2R + _pg9NZbdLMGeLGkFoMO5ASq + _KsRi9Bzx6Ro9cjJ3yNSyWK + + + D_o_k_u_m_e_n_t_0000014 + digital + + + 000015 + + _BblSEzq4DYiBdsNmhCHVgC + _9YFtc0bslkVLZInZvnVrR2 + _aVV54EggtVulKdoLPzFL8U + _1FF9xChDJCKjSPDIM84oUE + _ohyOthTAk4aooIrojg0YKQ + _6c3OTNj6vrh2prG5A87JRL + _IwwCtk50jMU9H5N909OTYq + _BLlOwNRwRVYxIGMo7905q5 + _Ka9zQVJNk9ETDITX2r9kS6 + _svnHuG5fj6LKMvOBJPIWeE + + + D_o_k_u_m_e_n_t_0000015 + digital + + + 000016 + + _qvO2zsx328rTNX4bdzB06o + _dYtCZukGcGw5Dv9rpH7Phf + _qL6TWVbmxizhVqd7JTMlJr + _gnY2RtL225dXOzn34EsN0s + + + D_o_k_u_m_e_n_t_0000016 + digital + + + 000017 + + _FqoZqKtYsQn9iAdoqqv1cI + _riEcze9FkwXNAgtur3vhvB + _wrbiTSyMyT93k4b9yhnd8A + _QC7MZ9myhW7QgxL7ELdiQV + _EltAAZKE7xX72Nr4kNUT7f + _oSKAG9iswtYdLdEoZOgNZI + _MPUtT4LAN6k1X9i205JK4v + _JnLmA6SzL8PXhLuSAjD6BN + _RfwXpYysjDoYf1KN9ZDc9K + _t86rSQb97ckC4ZprJoDUqP + _aZTvmXomyNbDu78bf18jPb + _lCNbsKsl9D7BObhJtz81Sw + _ao6Adl1bXk9YAFXqcOgECY + _o8pOoPrSOEdgE8CMLlbOFq + _FDHQdkVRY6R3kiMBSVAkuj + _l3La0Qs6HdEVsmPEtnefcJ + + + D_o_k_u_m_e_n_t_0000017 + digital + + + 000018 + + _mknnbMIDwFwyyAhb0nNNAi + _bVWoiFVEofzRW0cjYiwZiU + _a3UQBD05UK5O75fbdz66oY + _MxAgCiLVHDdzLmFTqqJgvm + _c7FINosFeQtOUoVT1hHhTO + _jxDTghxxNxUFP0nh4DmCSF + _ehXSmIcDPXHcBRZRcEz93t + _QX9ItkC2VPpvB8rdhoLTXL + + _fZzi3dX2jvrwakvY6jeJS8 + + + + + + + + + Eingangsprüfung automatisiert + Automated tests run + + XML well formed and valid: + passed +Structural Integrity: + passed +File Names Correct: + passed +SIP content structure plausible: + passed +Virus Check: + passed +File Formats: + passed + + Comment: + + + 2023-08-31T15:36:11.239+02:00 + 2023-08-31T15:36:23.236+02:00 + + Andreas Christe + + + Eingangsprüfung manuell + SIP Approved for Ingest + + 2023-08-31T15:36:23.236+02:00 + 2023-08-31T15:36:23.236+02:00 + + Andreas Christe + +