Skip to content

Commit

Permalink
streamline
Browse files Browse the repository at this point in the history
  • Loading branch information
mandelsoft committed Dec 27, 2024
1 parent ee98829 commit 1f5f031
Show file tree
Hide file tree
Showing 33 changed files with 156 additions and 127 deletions.
1 change: 1 addition & 0 deletions api/helper/builder/ocm_hint.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/mandelsoft/goutils/sliceutils"
"github.com/modern-go/reflect2"

"ocm.software/ocm/api/ocm/refhints"
)

Expand Down
6 changes: 3 additions & 3 deletions api/ocm/compdesc/norm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ var CD3 = `
referenceName: vasu1124/introspect:1.0.0
type: localBlob
referenceHints:
- type: OCI
- type: oci
reference: vasu1124/introspect:1.0.0
digest:
hashAlgorithm: SHA-256
Expand All @@ -193,7 +193,7 @@ var CD3 = `
repository: github.com/vasu1124/introspect
type: git
referenceHints:
- type: OCI
- type: oci
reference: vasu1124/introspect:1.0.0
name: introspect
type: git
Expand Down Expand Up @@ -235,7 +235,7 @@ var _ = Describe("Normalization", func() {
It("hashes referenceHints", func() {
n, err := compdesc.Normalize(cd3, compdesc.JsonNormalisationV2)
Expect(err).To(Succeed())
Expect(string(n)).To(Equal("{\"component\":{\"componentReferences\":[],\"name\":\"github.com/vasu1124/introspect\",\"provider\":{\"name\":\"internal\"},\"resources\":[{\"digest\":{\"hashAlgorithm\":\"SHA-256\",\"normalisationAlgorithm\":\"ociArtifactDigest/v1\",\"value\":\"6a1c7637a528ab5957ab60edf73b5298a0a03de02a96be0313ee89b22544840c\"},\"labels\":[{\"name\":\"label2\",\"signing\":true,\"value\":\"bar\"}],\"name\":\"introspect-image\",\"referenceHints\":[{\"reference\":\"vasu1124/introspect:1.0.0\",\"type\":\"OCI\"}],\"relation\":\"local\",\"type\":\"ociImage\",\"version\":\"1.0.0\"}],\"sources\":[{\"name\":\"introspect\",\"referenceHints\":[{\"reference\":\"vasu1124/introspect:1.0.0\",\"type\":\"OCI\"}],\"type\":\"git\",\"version\":\"1.0.0\"}],\"version\":\"1.0.0\"}}"))
Expect(string(n)).To(Equal("{\"component\":{\"componentReferences\":[],\"name\":\"github.com/vasu1124/introspect\",\"provider\":{\"name\":\"internal\"},\"resources\":[{\"digest\":{\"hashAlgorithm\":\"SHA-256\",\"normalisationAlgorithm\":\"ociArtifactDigest/v1\",\"value\":\"6a1c7637a528ab5957ab60edf73b5298a0a03de02a96be0313ee89b22544840c\"},\"labels\":[{\"name\":\"label2\",\"signing\":true,\"value\":\"bar\"}],\"name\":\"introspect-image\",\"referenceHints\":[{\"reference\":\"vasu1124/introspect:1.0.0\",\"type\":\"oci\"}],\"relation\":\"local\",\"type\":\"ociImage\",\"version\":\"1.0.0\"}],\"sources\":[{\"name\":\"introspect\",\"referenceHints\":[{\"reference\":\"vasu1124/introspect:1.0.0\",\"type\":\"oci\"}],\"type\":\"git\",\"version\":\"1.0.0\"}],\"version\":\"1.0.0\"}}"))
})

It("hashes v1 with none access", func() {
Expand Down
44 changes: 29 additions & 15 deletions api/ocm/compdesc/versions/ocm.software/v3alpha1/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package v3alpha1

import (
"github.com/mandelsoft/goutils/errors"
"github.com/mandelsoft/goutils/sliceutils"

"ocm.software/ocm/api/ocm/compdesc"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
"ocm.software/ocm/api/ocm/compdesc/versions/ocm.software/v3alpha1/jsonscheme"
"ocm.software/ocm/api/ocm/refhints"
"ocm.software/ocm/api/utils/runtime"
)

Expand Down Expand Up @@ -107,11 +109,16 @@ func convertReferencesTo(in []Reference) compdesc.References {
return out
}

func convertHintsTo(in []refhints.DefaultReferenceHint) refhints.ReferenceHints {
return sliceutils.Convert[refhints.ReferenceHint](in)
}

func convertSourceTo(in Source) compdesc.Source {
return compdesc.Source{
SourceMeta: compdesc.SourceMeta{
ElementMeta: convertElementmetaTo(in.ElementMeta),
Type: in.Type,
ElementMeta: convertElementmetaTo(in.ElementMeta),
Type: in.Type,
ReferenceHints: convertHintsTo(in.ReferenceHints),
},
Access: compdesc.GenericAccessSpec(in.Access.DeepCopy()),
}
Expand Down Expand Up @@ -144,11 +151,12 @@ func convertResourceTo(in Resource) compdesc.Resource {
}
return compdesc.Resource{
ResourceMeta: compdesc.ResourceMeta{
ElementMeta: convertElementmetaTo(in.ElementMeta),
Type: in.Type,
Relation: in.Relation,
SourceRefs: srcRefs,
Digest: in.Digest.Copy(),
ElementMeta: convertElementmetaTo(in.ElementMeta),
Type: in.Type,
ReferenceHints: convertHintsTo(in.ReferenceHints),
Relation: in.Relation,
SourceRefs: srcRefs,
Digest: in.Digest.Copy(),
},
Access: compdesc.GenericAccessSpec(in.Access),
}
Expand Down Expand Up @@ -231,15 +239,20 @@ func convertReferencesFrom(in []compdesc.Reference) []Reference {
return out
}

func convertHintsFrom(in refhints.ReferenceHints) []refhints.DefaultReferenceHint {
return sliceutils.Transform(in, refhints.AsDefault)
}

func convertSourceFrom(in compdesc.Source) Source {
acc, err := runtime.ToUnstructuredTypedObject(in.Access)
if err != nil {
compdesc.ThrowConversionError(err)
}
return Source{
SourceMeta: SourceMeta{
ElementMeta: convertElementmetaFrom(in.ElementMeta),
Type: in.Type,
ElementMeta: convertElementmetaFrom(in.ElementMeta),
Type: in.Type,
ReferenceHints: convertHintsFrom(in.ReferenceHints),
},
Access: acc,
}
Expand Down Expand Up @@ -271,12 +284,13 @@ func convertResourceFrom(in compdesc.Resource) Resource {
compdesc.ThrowConversionError(err)
}
return Resource{
ElementMeta: convertElementmetaFrom(in.ElementMeta),
Type: in.Type,
Relation: in.Relation,
SourceRefs: convertSourcerefsFrom(in.SourceRefs),
Access: acc,
Digest: in.Digest.Copy(),
ElementMeta: convertElementmetaFrom(in.ElementMeta),
Type: in.Type,
ReferenceHints: convertHintsFrom(in.ReferenceHints),
Relation: in.Relation,
SourceRefs: convertSourcerefsFrom(in.SourceRefs),
Access: acc,
Digest: in.Digest.Copy(),
}
}

Expand Down
20 changes: 3 additions & 17 deletions api/ocm/compdesc/versions/v2/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"

"github.com/mandelsoft/goutils/errors"
"github.com/mandelsoft/goutils/sliceutils"

"ocm.software/ocm/api/ocm/compdesc"
metav1 "ocm.software/ocm/api/ocm/compdesc/meta/v1"
Expand Down Expand Up @@ -118,15 +119,7 @@ func convertComponentReferencesTo(in []ComponentReference) compdesc.References {
}

func convertHintsTo(in []refhints.DefaultReferenceHint) refhints.ReferenceHints {
if in == nil {
return nil
}
hints := make(refhints.ReferenceHints, len(in))

for i, h := range in {
hints[i] = h
}
return hints
return sliceutils.Convert[refhints.ReferenceHint](in)
}

func convertSourceTo(in Source) compdesc.Source {
Expand Down Expand Up @@ -269,14 +262,7 @@ func convertComponentReferencesFrom(in []compdesc.Reference) []ComponentReferenc
}

func convertHintsFrom(in refhints.ReferenceHints) []refhints.DefaultReferenceHint {
if in == nil {
return nil
}
hints := make([]refhints.DefaultReferenceHint, len(in))
for i, h := range in {
hints[i] = h.AsDefault()
}
return hints
return sliceutils.Transform(in, refhints.AsDefault)
}

func convertSourceFrom(in compdesc.Source) Source {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ var _ = Describe("dir tree resource access", func() {

acc := Must(me.ResourceAccess(env.OCMContext(), compdesc.NewResourceMeta("test", resourcetypes.OCI_IMAGE, compdesc.LocalRelation), spec))

Expect(acc.ReferenceHintForAccess()).To(Equal(refhints.NewHints(techoci.ReferenceHint, OCINAMESPACE+":"+OCIVERSION, true)))
Expect(acc.ReferenceHintForAccess()).To(Equal(refhints.DefaultList(techoci.ReferenceHint, OCINAMESPACE+":"+OCIVERSION, true)))
Expect(acc.GlobalAccess()).To(BeNil())
Expect(acc.Meta().Type).To(Equal(resourcetypes.OCI_IMAGE))

Expand Down
2 changes: 1 addition & 1 deletion api/ocm/elements/artifactblob/dirtreeblob/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ var _ = Describe("dir tree resource access", func() {
me.WithGlobalAccess(global),
)

Expect(acc.ReferenceHintForAccess()).To(Equal(refhints.NewHints(refhints.DefaultHint, "demo")))
Expect(acc.ReferenceHintForAccess()).To(Equal(refhints.DefaultList(refhints.DefaultHint, "demo")))
Expect(acc.GlobalAccess()).To(Equal(global))
Expect(acc.Meta().Type).To(Equal(resourcetypes.DIRECTORY_TREE))

Expand Down
2 changes: 1 addition & 1 deletion api/ocm/elements/artifactblob/dockerdaemonblob/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func Access[M any, P compdesc.ArtifactMetaPointer[M]](ctx ocm.Context, meta P, n
h := eff.Hint.GetReferenceHint(techoci.ReferenceHintType, "")
hint := ociartifact.Hint(optionutils.AsValue(eff.Blob.Origin), locator, h.GetReference(), version)
blobprov := dockerdaemon.Provider(name, &eff.Blob)
accprov := cpi.NewAccessProviderForBlobAccessProvider(ctx, blobprov, refhints.ReferenceHints{techoci.ReferenceHint(hint)}, eff.Global)
accprov := cpi.NewAccessProviderForBlobAccessProvider(ctx, blobprov, refhints.DefaultList(techoci.ReferenceHint, hint), eff.Global)
// strange type cast is required by Go compiler, meta has the correct type.
return cpi.NewArtifactAccessForProvider[M, P](generics.Cast[*M](meta), accprov)
}
Expand Down
2 changes: 1 addition & 1 deletion api/ocm/elements/artifactblob/mavenblob/access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ var _ = Describe("blobaccess for maven", func() {
coords := maven.NewCoordinates("com.sap.cloud.sdk", "sdk-modules-bom", "5.7.0")

a := me.ResourceAccessForMavenCoords(env.OCMContext(), Must(elements.ResourceMeta("mavenblob", resourcetypes.OCM_JSON, elements.WithLocalRelation())), repo, coords, me.WithCachingFileSystem(env.FileSystem()))
Expect(a.ReferenceHintForAccess()).To(Equal(refhints.NewHints(maven.ReferenceHint, coords.GAV())))
Expect(a.ReferenceHintForAccess()).To(Equal(refhints.DefaultList(maven.ReferenceHint, coords.GAV())))
})
})
})
2 changes: 1 addition & 1 deletion api/ocm/elements/artifactblob/mavenblob/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const TYPE = resourcetypes.MAVEN_PACKAGE
func Access[M any, P compdesc.ArtifactMetaPointer[M]](ctx ocm.Context, meta P, repo *maven.Repository, groupId, artifactId, version string, opts ...Option) cpi.ArtifactAccess[M] {
eff := optionutils.EvalOptions(optionutils.WithDefaults(opts, WithCredentialContext(ctx))...)
if eff.Blob.IsPackage() && eff.Hint == nil {
eff.Hint = refhints.NewHints(techmaven.ReferenceHint, maven.NewCoordinates(groupId, artifactId, version).GAV())
eff.Hint = refhints.DefaultList(techmaven.ReferenceHint, maven.NewCoordinates(groupId, artifactId, version).GAV())
}

if meta.GetType() == "" {
Expand Down
2 changes: 1 addition & 1 deletion api/ocm/elements/artifactblob/ociartifactblob/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func Access[M any, P compdesc.ArtifactMetaPointer[M]](ctx ocm.Context, meta P, r
if hint == nil {
ref, err := oci.ParseRef(refname)
if err == nil {
hint = refhints.NewHints(techoci.ReferenceHint, ref.String())
hint = refhints.DefaultList(techoci.ReferenceHint, ref.String())
}
}

Expand Down
2 changes: 1 addition & 1 deletion api/ocm/extensions/accessmethods/maven/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (a *AccessSpec) GlobalAccessSpec(_ accspeccpi.Context) accspeccpi.AccessSpe
// GetReferenceHint returns the reference hint for the Maven (mvn) artifact.
func (a *AccessSpec) GetReferenceHint(_ accspeccpi.ComponentVersionAccess) refhints.ReferenceHints {
if a.IsPackage() {
return refhints.NewHints(maven.ReferenceHint, a.GAV(), true)
return refhints.DefaultList(maven.ReferenceHint, a.GAV(), true)
}
return nil
}
Expand Down
2 changes: 1 addition & 1 deletion api/ocm/extensions/accessmethods/npm/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (a *AccessSpec) GlobalAccessSpec(_ accspeccpi.Context) accspeccpi.AccessSpe
}

func (a *AccessSpec) GetReferenceHint(_ accspeccpi.ComponentVersionAccess) refhints.ReferenceHints {
return refhints.NewHints(npm.ReferenceHint, a.Package+":"+a.Version, true)
return refhints.DefaultList(npm.ReferenceHint, a.Package+":"+a.Version, true)
}

func (_ *AccessSpec) GetType() string {
Expand Down
2 changes: 1 addition & 1 deletion api/ocm/extensions/accessmethods/ociartifact/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (a *AccessSpec) GetReferenceHint(cv accspeccpi.ComponentVersionAccess) refh
if ref.Tag != nil {
hint += grammar.TagSeparator + *ref.Tag
}
return refhints.NewHints(techoci.ReferenceHint, hint, true)
return refhints.DefaultList(techoci.ReferenceHint, hint, true)
}

func (a *AccessSpec) GetOCIReference(cv accspeccpi.ComponentVersionAccess) (string, error) {
Expand Down
6 changes: 3 additions & 3 deletions api/ocm/extensions/accessmethods/ociartifact/method_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var _ = Describe("Method", func() {
spec := ociartifact.New(oci.StandardOCIRef(OCIHOST+".alias", OCINAMESPACE, OCIVERSION))

hint := spec.GetReferenceHint(&cpi.DummyComponentVersionAccess{env.OCMContext()})
Expect(hint).To(Equal(refhints.NewHints(techoci.ReferenceHint, "ocm/value:v2.0", true)))
Expect(hint).To(Equal(refhints.DefaultList(techoci.ReferenceHint, "ocm/value:v2.0", true)))
})
})

Expand All @@ -81,7 +81,7 @@ var _ = Describe("Method", func() {
spec := ociartifact.New(oci.StandardOCIRef(OCIHOST+".alias", OCINAMESPACE, OCIVERSION+"@sha256:"+D_OCIMANIFEST1))

hint := spec.GetReferenceHint(&cpi.DummyComponentVersionAccess{env.OCMContext()})
Expect(hint).To(Equal(refhints.NewHints(techoci.ReferenceHint, "ocm/value:v2.0", true)))
Expect(hint).To(Equal(refhints.DefaultList(techoci.ReferenceHint, "ocm/value:v2.0", true)))
})
})

Expand All @@ -107,7 +107,7 @@ var _ = Describe("Method", func() {
spec := ociartifact.New(oci.StandardOCIRef(OCIHOST+".alias", OCINAMESPACE, "@sha256:"+D_OCIMANIFEST1))

hint := spec.GetReferenceHint(&cpi.DummyComponentVersionAccess{env.OCMContext()})
Expect(hint).To(Equal(refhints.NewHints(techoci.ReferenceHint, "ocm/value", true)))
Expect(hint).To(Equal(refhints.DefaultList(techoci.ReferenceHint, "ocm/value", true)))
})
})
})
2 changes: 1 addition & 1 deletion api/ocm/extensions/accessmethods/relativeociref/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (a *AccessSpec) GetDigest() (string, bool) {
}

func (a *AccessSpec) GetReferenceHint(cv internal.ComponentVersionAccess) refhints.ReferenceHints {
return refhints.NewHints(techoci.ReferenceHint, a.Reference, true)
return refhints.DefaultList(techoci.ReferenceHint, a.Reference, true)
}

func (a *AccessSpec) GetOCIReference(cv accspeccpi.ComponentVersionAccess) (string, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var _ = Describe("blobhandler generic maven tests", func() {
ocmrepo := composition.NewRepository(env)
defer Close(ocmrepo)
cv := composition.NewComponentVersion(env, "acme.org/test", "1.0.0")
MustBeSuccessful(cv.SetResourceBlob(Must(elements.ResourceMeta("test", resourcetypes.MAVEN_PACKAGE)), bacc, refhints.NewHints(maven.ReferenceHint, coords.GAV(), true), nil))
MustBeSuccessful(cv.SetResourceBlob(Must(elements.ResourceMeta("test", resourcetypes.MAVEN_PACKAGE)), bacc, refhints.DefaultList(maven.ReferenceHint, coords.GAV(), true), nil))
MustBeSuccessful(ocmrepo.AddComponentVersion(cv))
l := sliceutils.Transform(Must(vfs.ReadDir(env.FileSystem(), "target/com/sap/cloud/sdk/sdk-modules-bom/5.7.0")),
func(info os.FileInfo) string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ var _ = Describe("explicit hint upload", func() {

tgt := composition.NewComponentVersion(ctx, COMP, VERS)
defer Close(tgt, "tgt")
MustBeSuccessful(tgt.SetResourceBlob(ra.Meta(), blob, refhints.NewHints(refhints.DefaultHint, OCINAMESPACE+":"+OCIVERSION+"-beta", true), nil))
MustBeSuccessful(tgt.SetResourceBlob(ra.Meta(), blob, refhints.DefaultList(refhints.DefaultHint, OCINAMESPACE+":"+OCIVERSION+"-beta", true), nil))

// close pending handler config
MustBeSuccessful(ctx.Finalize())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ var _ = Describe("upload", func() {

tgt := composition.NewComponentVersion(ctx, COMP, VERS)
defer Close(tgt, "tgt")
MustBeSuccessful(tgt.SetResourceBlob(ra.Meta(), blob, refhints.NewHints(refhints.DefaultHint, OCINAMESPACE+":"+OCIVERSION+"-beta", true), nil))
MustBeSuccessful(tgt.SetResourceBlob(ra.Meta(), blob, refhints.DefaultList(refhints.DefaultHint, OCINAMESPACE+":"+OCIVERSION+"-beta", true), nil))

// close pending handler config
MustBeSuccessful(ctx.Finalize())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,5 @@ func (b *pluginHandler) StoreBlob(blob cpi.BlobAccess, artType string, hints met
r := accessio.NewOndemandReader(blob)
defer errors.PropagateError(&err, r.Close)

return b.plugin.Put(b.name, r, artType, blob.MimeType(), hint, creddata, target)
return b.plugin.Put(b.name, r, artType, blob.MimeType(), hints, creddata, target)
}
4 changes: 2 additions & 2 deletions api/ocm/extensions/repositories/genericocireg/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ var _ = Describe("component repository mapping", func() {
blob := blobaccess.ForFile(mime, "test.tgz", tempfs)

fmt.Printf("physical digest: %s\n", blob.Digest())
acc := Must(vers.AddBlob(blob, "", refhints.NewHints(refhints.DefaultHint, "artifact1", true), nil))
acc := Must(vers.AddBlob(blob, "", refhints.DefaultList(refhints.DefaultHint, "artifact1", true), nil))
MustBeSuccessful(vers.SetResource(cpi.NewResourceMeta("image", resourcetypes.OCI_IMAGE, metav1.LocalRelation), acc))
MustBeSuccessful(comp.AddVersion(vers))

Expand All @@ -412,7 +412,7 @@ var _ = Describe("component repository mapping", func() {
o := acc.(*ociartifact.AccessSpec)
Expect(o.ImageReference).To(Equal(TESTBASE + "/artifact1@sha256:" + testhelper.DIGEST_MANIFEST))

acc = Must(vers.AddBlob(blob, "", refhints.NewHints(refhints.DefaultHint, "artifact2:v1", true), nil))
acc = Must(vers.AddBlob(blob, "", refhints.DefaultList(refhints.DefaultHint, "artifact2:v1", true), nil))
MustBeSuccessful(vers.SetResource(cpi.NewResourceMeta("image2", resourcetypes.OCI_IMAGE, metav1.LocalRelation), acc, cpi.ModifyResource()))
MustBeSuccessful(comp.AddVersion(vers))

Expand Down
4 changes: 3 additions & 1 deletion api/ocm/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"ocm.software/ocm/api/ocm/plugin/ppi/cmds/valueset"
vscompose "ocm.software/ocm/api/ocm/plugin/ppi/cmds/valueset/compose"
vsval "ocm.software/ocm/api/ocm/plugin/ppi/cmds/valueset/validate"
"ocm.software/ocm/api/ocm/refhints"
"ocm.software/ocm/api/ocm/valuemergehandler"
"ocm.software/ocm/api/utils/cobrautils/flagsets"
"ocm.software/ocm/api/utils/cobrautils/logopts/logging"
Expand Down Expand Up @@ -293,9 +294,10 @@ func (p *pluginImpl) Get(w io.Writer, creds, spec json.RawMessage) error {
return err
}

func (p *pluginImpl) Put(name string, r io.Reader, artType, mimeType, hint string, creds, target json.RawMessage) (ocm.AccessSpec, error) {
func (p *pluginImpl) Put(name string, r io.Reader, artType, mimeType string, hints []refhints.ReferenceHint, creds, target json.RawMessage) (ocm.AccessSpec, error) {
args := []string{upload.Name, put.Name, name, string(target)}

hint := refhints.Serialize(hints, true)
if creds != nil {
args = append(args, "--"+put.OptCreds, string(creds))
}
Expand Down
Loading

0 comments on commit 1f5f031

Please sign in to comment.