From e8936bf8c97804a6151c3fc1f873e519c8304b0a Mon Sep 17 00:00:00 2001 From: Joana Bergsiek Date: Tue, 26 Mar 2024 21:21:59 +0100 Subject: [PATCH] Prettier correlation --- .../SBCorrelationCluster.class.st | 105 +++++----- .../SBCorrelationView.class.st | 189 ++++++++++++++---- .../SBCustomView.class.st | 4 +- .../SBExploriantsView.class.st | 13 +- .../SBHistoryView.class.st | 2 +- .../Sandblocks-Babylonian/SBLiveView.class.st | 2 +- .../SBPartialPermutationLabel.class.st | 57 ++++++ .../SBPartialPermutationLabel.extension.st | 7 + .../SBPermutationLabel.class.st | 2 +- .../SBSwitchableResultsView.class.st | 2 +- packages/Sandblocks-Core/SBComboBox.class.st | 6 + .../SBNilPermutation.class.st | 6 + .../Sandblocks-Utils/SBPermutation.class.st | 37 ++-- 13 files changed, 319 insertions(+), 113 deletions(-) create mode 100644 packages/Sandblocks-Babylonian/SBPartialPermutationLabel.class.st create mode 100644 packages/Sandblocks-Babylonian/SBPartialPermutationLabel.extension.st diff --git a/packages/Sandblocks-Babylonian/SBCorrelationCluster.class.st b/packages/Sandblocks-Babylonian/SBCorrelationCluster.class.st index e42be99f..43033d83 100644 --- a/packages/Sandblocks-Babylonian/SBCorrelationCluster.class.st +++ b/packages/Sandblocks-Babylonian/SBCorrelationCluster.class.st @@ -2,39 +2,48 @@ Class { #name : #SBCorrelationCluster, #superclass : #SBCluster, #instVars : [ - 'multiverse', 'displayedExample', 'displayedWatch', - 'opponentPermutations', - 'basePermutation' + 'baseUniverse', + 'basePermutation', + 'correlatingUniverses' ], #category : #'Sandblocks-Babylonian' } { #category : #'instance creation' } -SBCorrelationCluster class >> newForSize: aSBMorphResizer multiverse: aMultiverse example: anExample watch: aWatch basePermutation: base opponentPermutations: opponent [ +SBCorrelationCluster class >> newForSize: aSBMorphResizer example: anExample watch: aWatch basePermutation: aPermutation correlating: aCollectionOfUniverses [ ^ self new morphResizer: aSBMorphResizer; - multiverse: aMultiverse; displayedExample: anExample; displayedWatch: aWatch; - basePermutation: base; - opponentPermutations: opponent; + basePermutation: aPermutation; + correlatingUniverses: aCollectionOfUniverses; visualize; yourself ] { #category : #accessing } SBCorrelationCluster >> basePermutation [ - ^ basePermutation ] { #category : #accessing } -SBCorrelationCluster >> basePermutation: aSBPermutation [ +SBCorrelationCluster >> basePermutation: anObject [ + basePermutation := anObject +] - basePermutation := aSBPermutation +{ #category : #accessing } +SBCorrelationCluster >> baseUniverse [ + + ^ baseUniverse +] + +{ #category : #accessing } +SBCorrelationCluster >> baseUniverse: aUniverse [ + + baseUniverse := aUniverse ] { #category : #building } @@ -44,10 +53,10 @@ SBCorrelationCluster >> buildDisplayMatrix [ matrix := Matrix rows: 2 - columns: self opponentPermutations size + 1. + columns: self correlatingUniverses size + 1. matrix atRow: 1 put: ({TextMorph new contents: self basePermutation asVariantString}, - (self extractedTopHeadingsFrom: self opponentPermutations)). + (self extractedTopHeadingsFrom: self correlatingUniverses)). matrix at: 2 at: 1 put: (SBPermutationLabel newDisplaying: self basePermutation). @@ -56,6 +65,18 @@ SBCorrelationCluster >> buildDisplayMatrix [ ^ matrix ] +{ #category : #accessing } +SBCorrelationCluster >> correlatingUniverses [ + + ^ correlatingUniverses +] + +{ #category : #accessing } +SBCorrelationCluster >> correlatingUniverses: aCollectionOfUniverses [ + + correlatingUniverses := aCollectionOfUniverses +] + { #category : #accessing } SBCorrelationCluster >> displayedExample [ @@ -83,49 +104,37 @@ SBCorrelationCluster >> displayedWatch: anSBExampleWatch [ { #category : #building } SBCorrelationCluster >> extractRow [ - ^ self multiverse universes - select: [:aUniverse | (aUniverse activePermutation contains: self basePermutation)] - thenCollect: [:aUniverse | | display | + ^ self correlatingUniverses + collect: [:aUniverse | | display | display := ((aUniverse watches detect: [:aWatch | aWatch originalIdentifier = self displayedWatch identifier]) exampleToDisplay at: self displayedExample) value display. self compressedMorphsForDisplay: display] ] { #category : #building } -SBCorrelationCluster >> extractedLeftHeadingsFrom: aCollectionOfPermutations [ +SBCorrelationCluster >> extractedTopHeadingsFrom: aCollectionOfCorrelatingUniverses [ - ^ aCollectionOfPermutations collect: [:aPermutation | SBPermutationLabel newDisplaying: aPermutation] + ^ aCollectionOfCorrelatingUniverses collect: [:aCorrelatingUniverse | + SBPartialPermutationLabel + newDisplaying: (aCorrelatingUniverse activePermutation copyRemovingVariants: self basePermutation referencedVariants) + referingTo: aCorrelatingUniverse] ] -{ #category : #building } -SBCorrelationCluster >> extractedTopHeadingsFrom: aCollectionOfPermutations [ - - ^ aCollectionOfPermutations collect: [:aPermutation | - aPermutation isNilPermutation - ifTrue: [StringMorph new contents: ' / '] - ifFalse: [SBPermutationLabel newDisplaying: aPermutation]] -] - -{ #category : #accessing } -SBCorrelationCluster >> multiverse [ - - ^ multiverse -] - -{ #category : #accessing } -SBCorrelationCluster >> multiverse: aSBMultiverse [ - - multiverse := aSBMultiverse -] - -{ #category : #accessing } -SBCorrelationCluster >> opponentPermutations [ - - ^ opponentPermutations -] - -{ #category : #accessing } -SBCorrelationCluster >> opponentPermutations: aCollectionOfSBPermutations [ - - opponentPermutations := aCollectionOfSBPermutations +{ #category : #visualisation } +SBCorrelationCluster >> newTopRowFrom: aCollectionOfPermutationLabels [ + + "Width should be set, but height can vary" + ^ self newContainerMorph + listDirection: #leftToRight; + listCentering: #bottomRight; + cellPositioning: #topCenter; + hResizing: #spaceFill; + addAllMorphsBack: (aCollectionOfPermutationLabels collect: [:aLabel | + self newContainerMorph + addAllMorphsBack: { + (self + wrapInCell: aLabel + flexVertically: true + flexHorizontally: false) borderWidth: 0. + SBButton newApplyPermutationFor: (aLabel universe activePermutation).}]) ] diff --git a/packages/Sandblocks-Babylonian/SBCorrelationView.class.st b/packages/Sandblocks-Babylonian/SBCorrelationView.class.st index e4382c35..406f93ad 100644 --- a/packages/Sandblocks-Babylonian/SBCorrelationView.class.st +++ b/packages/Sandblocks-Babylonian/SBCorrelationView.class.st @@ -2,34 +2,23 @@ Class { #name : #SBCorrelationView, #superclass : #SBResizableResultsView, #instVars : [ - 'basePermutations' + 'variantSelection', + 'selectedVariants', + 'basePermutations', + 'groupedUniverses' ], #category : #'Sandblocks-Babylonian' } -{ #category : #accessing } -SBCorrelationView >> basePermutations [ - ^ basePermutations -] - -{ #category : #accessing } -SBCorrelationView >> basePermutations: anObject [ - basePermutations := anObject -] - { #category : #building } SBCorrelationView >> buildAllPossibleResults [ - | base thisVariant | self multiverse activeExamples ifEmpty: [gridContainer addMorph: (TextMorph new contents: 'No examples active'). gridContainer width: gridContainer firstSubmorph width + 5 "a bit of margin"]. - thisVariant := self multiverse universes first activePermutation referencedVariants third. - base := SBPermutation new referencedVariants: (self multiverse universes first activePermutation referencedVariants select: [:var | var = thisVariant]). - self multiverse universes first activePermutation associationsDo: [:idToNum | idToNum key = thisVariant id ifTrue: [base add: idToNum]]. - self halt. - self basePermutations: {base}. + groupedUniverses := self groupUniversesContainingAllVariantsIn: selectedVariants. + basePermutations := self collectAllPermutationsOfSelectedVariants asOrderedCollection. self multiverse activeExamples do: [:anExample | self multiverse watches do: [:aWatch | @@ -51,42 +40,142 @@ SBCorrelationView >> buildForExample: anExample watching: aWatch [ { #category : #building } SBCorrelationView >> buildGridsFor: anExample watching: aWatch [ - - ^ (self basePermutations collect: [:aBasePermutation | | split | - split := self getAllUniversesContainingPermutation: aBasePermutation. - {SBCorrelationCluster + + ^ (basePermutations collect: [:aBasePermutation | + SBCorrelationCluster newForSize: self selectedResizer - multiverse: self multiverse example: anExample watch: aWatch - basePermutation: aBasePermutation - opponentPermutations: split first }, - (split second collect: [:nonContainingPermutation | - SBCorrelationCluster - newForSize: self selectedResizer - multiverse: self multiverse - example: anExample - watch: aWatch - basePermutation: nonContainingPermutation - opponentPermutations: {SBNilPermutation new referencedVariants: {}}]) - ]) flatten + basePermutation: aBasePermutation + correlating: (self getUniversesContainingPermutation: aBasePermutation)]), + (groupedUniverses second collect: [:aNonCorrelatingUniverse | + SBCorrelationCluster + newForSize: self selectedResizer + example: anExample + watch: aWatch + basePermutation: aNonCorrelatingUniverse activePermutation + correlating: {aNonCorrelatingUniverse}]) +] + +{ #category : #building } +SBCorrelationView >> buildSelectionRow [ + + | container selectedString | + container := self containerRow. + self ensureVariantSelectionIn: container. + selectedString := 'Selected: '. + selectedVariants + ifEmpty: [ selectedString := selectedString, 'None' ] + ifNotEmpty: [ selectedString := selectedString, ((selectedVariants collect: #name) fold: [:a :b | a, ', ', Character cr, b ])]. + container addMorphBack: selectedString asMorph. + self block addMorph: container. ] { #category : #building } -SBCorrelationView >> getAllUniversesContainingPermutation: aPermutation [ +SBCorrelationView >> buildVariantSelection [ + + | options topLevelVariant | + options := self multiverse variants. + topLevelVariant := options detect: [:aVariant | aVariant parentVariant isNil] ifNone: [options first]. - | containsBase rest | - containsBase := OrderedCollection new. - rest := OrderedCollection new. + ^ SBComboBox new + prefix: 'Add or Remove'; + labels: (options collect: #name); + values: options; + object: topLevelVariant; + when: #selectionChanged send: #changeVariants to: self; + displayPrefixOnly +] + +{ #category : #accessing } +SBCorrelationView >> buttons [ + + ^ {} +] + +{ #category : #building } +SBCorrelationView >> changeVariants [ + + (selectedVariants includes: variantSelection object) + ifTrue: [selectedVariants remove: variantSelection object] + ifFalse: [selectedVariants add: variantSelection object]. + + self visualize +] + +{ #category : #building } +SBCorrelationView >> collectAllPermutationsOfSelectedVariants [ - self multiverse universes do: [:aUniverse | - ((aUniverse activePermutation contains: aPermutation)) - ifTrue: [containsBase add: (aUniverse activePermutation copyRemoving: {aPermutation}) ] - ifFalse: [rest add: aUniverse activePermutation]]. + | allPermutations | + selectedVariants ifEmpty: [^ {SBNilPermutation new referencedVariants: {}} asSet]. + allPermutations := Set new. + groupedUniverses first do: [:aUniverseContainingSelected | | base | + base := SBPermutation new referencedVariants: selectedVariants. + selectedVariants do: [:aVariant | base at: aVariant id put: (aUniverseContainingSelected activePermutation at: aVariant id)]. + allPermutations add: base]. + ^ allPermutations +] + +{ #category : #building } +SBCorrelationView >> ensureVariantSelection [ + + self multiverse variants ifEmpty: [selectedVariants := OrderedCollection new. ^ self]. + variantSelection := self buildVariantSelection. + self block addMorph: variantSelection. + + selectedVariants + ifNil: [selectedVariants := {variantSelection object} asOrderedCollection] + ifNotNil: [selectedVariants := selectedVariants select: [:aVariant | self multiverse variants includes: aVariant]]. + +] + +{ #category : #building } +SBCorrelationView >> ensureVariantSelectionIn: aMorph [ + + self multiverse variants ifEmpty: [selectedVariants := OrderedCollection new. ^ self]. + variantSelection := self buildVariantSelection. + aMorph addMorph: variantSelection. + + selectedVariants + ifNil: [selectedVariants := {variantSelection object} asOrderedCollection] + ifNotNil: [selectedVariants := selectedVariants select: [:aVariant | self multiverse variants includes: aVariant]]. + +] + +{ #category : #building } +SBCorrelationView >> getUniversesContainingPermutation: aPermutation [ + + ^ groupedUniverses first select: [:aUniverse | + aUniverse activePermutation contains: aPermutation] +] + +{ #category : #building } +SBCorrelationView >> groupUniversesContainingAllVariantsIn: aCollectionOfVariants [ + + | contains omits | + contains := OrderedCollection new. + omits := OrderedCollection new. + self multiverse universes do: [:aUniverse | + (aCollectionOfVariants allSatisfy: [:aVariant | aUniverse activePermutation referencedVariants includes: aVariant]) + ifTrue: [contains add: aUniverse] + ifFalse: [omits add: aUniverse]]. + + ^ {contains. omits.} +] + +{ #category : #building } +SBCorrelationView >> groupUniversesContainingPermutation: aPermutation [ + + | contains omits | + contains := OrderedCollection new. + omits := OrderedCollection new. + groupedUniverses first do: [:aUniverse | + (aUniverse activePermutation contains: aPermutation) + ifTrue: [contains add: aUniverse] + ifFalse: [omits add: aUniverse]]. - ^ {containsBase reject: [:aContainingPermutation | aContainingPermutation = aPermutation]. - rest ifEmpty: [{SBNilPermutation new referencedVariants: {}}]} + ^ {contains. omits.} ] { #category : #initialization } @@ -97,3 +186,17 @@ SBCorrelationView >> initialize [ self name: 'Correlation'. ] + +{ #category : #actions } +SBCorrelationView >> visualize [ + + self clean. + + self buildSelectionRow. + self block addMorph: dimensionOptions. + + self buildButtonRow. + + self buildAllPossibleResults . + self concludeContainerWidth. +] diff --git a/packages/Sandblocks-Babylonian/SBCustomView.class.st b/packages/Sandblocks-Babylonian/SBCustomView.class.st index 837c7fa4..13ec7048 100644 --- a/packages/Sandblocks-Babylonian/SBCustomView.class.st +++ b/packages/Sandblocks-Babylonian/SBCustomView.class.st @@ -35,7 +35,9 @@ SBCustomView >> initialize [ viewOptions := self buildViewOptions. self name: 'Results'. - self block addMorphFront: viewOptions. + self buildButtonRow. + + self block addMorphBack: viewOptions. self block addMorphBack: self selectedView ] diff --git a/packages/Sandblocks-Babylonian/SBExploriantsView.class.st b/packages/Sandblocks-Babylonian/SBExploriantsView.class.st index b164ef63..403ae16c 100644 --- a/packages/Sandblocks-Babylonian/SBExploriantsView.class.st +++ b/packages/Sandblocks-Babylonian/SBExploriantsView.class.st @@ -42,7 +42,7 @@ SBExploriantsView >> buildButtonRow [ { #category : #accessing } SBExploriantsView >> buttons [ - ^ {self updateButton. self resolveButton} + ^ {self updateButton. self resolveButton. self saveButton} ] { #category : #actions } @@ -110,6 +110,7 @@ SBExploriantsView >> multiverse: aSBMultiverse [ multiverse := aSBMultiverse. multiverse when: #updated send: #visualize to: self. + ^ multiverse ] { #category : #building } @@ -122,6 +123,16 @@ SBExploriantsView >> resolveButton [ cornerStyle: #squared ] +{ #category : #building } +SBExploriantsView >> saveButton [ + + ^ SBButton new + icon: SBIcon iconSave + label: 'Save As PNG' + do: [self block exportAsPNG]; + cornerStyle: #squared +] + { #category : #copying } SBExploriantsView >> snapshot [ diff --git a/packages/Sandblocks-Babylonian/SBHistoryView.class.st b/packages/Sandblocks-Babylonian/SBHistoryView.class.st index 7d857e08..3bc0216b 100644 --- a/packages/Sandblocks-Babylonian/SBHistoryView.class.st +++ b/packages/Sandblocks-Babylonian/SBHistoryView.class.st @@ -50,7 +50,7 @@ SBHistoryView >> buildSnapshotTabView [ { #category : #building } SBHistoryView >> buttons [ - ^ super buttons, {self clearButton. self changeTabsButton. self saveButton } + ^ super buttons, {self clearButton. self changeTabsButton. } ] { #category : #building } diff --git a/packages/Sandblocks-Babylonian/SBLiveView.class.st b/packages/Sandblocks-Babylonian/SBLiveView.class.st index b15b8716..111fd12e 100644 --- a/packages/Sandblocks-Babylonian/SBLiveView.class.st +++ b/packages/Sandblocks-Babylonian/SBLiveView.class.st @@ -65,7 +65,7 @@ SBLiveView >> buildSetUpRow [ { #category : #building } SBLiveView >> buttons [ - ^ super buttons, {self rebuildButton. self reloadLastSaveButton} + ^ {self rebuildButton. self reloadLastSaveButton} ] { #category : #actions } diff --git a/packages/Sandblocks-Babylonian/SBPartialPermutationLabel.class.st b/packages/Sandblocks-Babylonian/SBPartialPermutationLabel.class.st new file mode 100644 index 00000000..4320f5dd --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBPartialPermutationLabel.class.st @@ -0,0 +1,57 @@ +Class { + #name : #SBPartialPermutationLabel, + #superclass : #TextMorph, + #instVars : [ + 'permutation', + 'universe' + ], + #category : #'Sandblocks-Babylonian' +} + +{ #category : #'initialize-release' } +SBPartialPermutationLabel class >> newDisplaying: aSBPermutation referingTo: aUniverse [ + + ^ self new + universe: aUniverse; + permutation: aSBPermutation; + updateStyling; + yourself +] + +{ #category : #'*Sandblocks-Babylonian' } +SBPartialPermutationLabel >> listensToPermutations [ + + ^ true +] + +{ #category : #accessing } +SBPartialPermutationLabel >> permutation [ + + ^ permutation +] + +{ #category : #accessing } +SBPartialPermutationLabel >> permutation: aPermutation [ + + permutation := aPermutation +] + +{ #category : #accessing } +SBPartialPermutationLabel >> universe [ + + ^ universe +] + +{ #category : #accessing } +SBPartialPermutationLabel >> universe: aUniverse [ + + universe := aUniverse +] + +{ #category : #initialization } +SBPartialPermutationLabel >> updateStyling [ + + self contents: (self universe activePermutation isActive + ifTrue: [self permutation asStylizedText] + ifFalse: [self permutation asString]) +] diff --git a/packages/Sandblocks-Babylonian/SBPartialPermutationLabel.extension.st b/packages/Sandblocks-Babylonian/SBPartialPermutationLabel.extension.st new file mode 100644 index 00000000..a4e59e1e --- /dev/null +++ b/packages/Sandblocks-Babylonian/SBPartialPermutationLabel.extension.st @@ -0,0 +1,7 @@ +Extension { #name : #SBPartialPermutationLabel } + +{ #category : #'*Sandblocks-Babylonian' } +SBPartialPermutationLabel >> listensToPermutations [ + + ^ true +] diff --git a/packages/Sandblocks-Babylonian/SBPermutationLabel.class.st b/packages/Sandblocks-Babylonian/SBPermutationLabel.class.st index e1859677..b1a45868 100644 --- a/packages/Sandblocks-Babylonian/SBPermutationLabel.class.st +++ b/packages/Sandblocks-Babylonian/SBPermutationLabel.class.st @@ -7,7 +7,7 @@ Class { #category : #'Sandblocks-Babylonian' } -{ #category : #'as yet unclassified' } +{ #category : #'initialize-release' } SBPermutationLabel class >> newDisplaying: aSBPermutation [ ^ self new diff --git a/packages/Sandblocks-Babylonian/SBSwitchableResultsView.class.st b/packages/Sandblocks-Babylonian/SBSwitchableResultsView.class.st index a186cf87..f1482132 100644 --- a/packages/Sandblocks-Babylonian/SBSwitchableResultsView.class.st +++ b/packages/Sandblocks-Babylonian/SBSwitchableResultsView.class.st @@ -13,7 +13,7 @@ Class { { #category : #accessing } SBSwitchableResultsView >> buttons [ - ^ super buttons, {self toggleViewButton} + ^ {self toggleViewButton} ] { #category : #accessing } diff --git a/packages/Sandblocks-Core/SBComboBox.class.st b/packages/Sandblocks-Core/SBComboBox.class.st index b6259557..93a20f76 100644 --- a/packages/Sandblocks-Core/SBComboBox.class.st +++ b/packages/Sandblocks-Core/SBComboBox.class.st @@ -49,6 +49,12 @@ SBComboBox >> display: anObject [ ^ anObject printString ] +{ #category : #'as yet unclassified' } +SBComboBox >> displayPrefixOnly [ + + self contents: '' +] + { #category : #'as yet unclassified' } SBComboBox >> doubleClick: evt [ diff --git a/packages/Sandblocks-Utils/SBNilPermutation.class.st b/packages/Sandblocks-Utils/SBNilPermutation.class.st index cc56e502..fa33ef43 100644 --- a/packages/Sandblocks-Utils/SBNilPermutation.class.st +++ b/packages/Sandblocks-Utils/SBNilPermutation.class.st @@ -17,6 +17,12 @@ SBNilPermutation >> asString [ ^ 'No Variation' ] +{ #category : #converting } +SBNilPermutation >> asVariantString [ + + ^ 'No Variation' +] + { #category : #accessing } SBNilPermutation >> isActive [ diff --git a/packages/Sandblocks-Utils/SBPermutation.class.st b/packages/Sandblocks-Utils/SBPermutation.class.st index 807e4500..64cb68df 100644 --- a/packages/Sandblocks-Utils/SBPermutation.class.st +++ b/packages/Sandblocks-Utils/SBPermutation.class.st @@ -59,16 +59,6 @@ SBPermutation >> apply [ do: #sendNewPermutationNotification ] -{ #category : #converting } -SBPermutation >> asAlternativesString [ - - ^ (self referencedVariants collect: [:aVariant | - (aVariant blockAt: (self at: aVariant id)) nameToDisplay ]) - fold: [:a :b | a, ', ', Character cr, b ] - - -] - { #category : #converting } SBPermutation >> asString [ @@ -112,17 +102,32 @@ SBPermutation >> contains: anotherPermutation [ ] { #category : #'initialize-release' } -SBPermutation >> copyRemoving: aCollectionOfPermutations [ +SBPermutation >> copyRemovingPermutation: aPermutation [ | copy | copy := self veryDeepCopy. copy referencedVariants: (copy referencedVariants reject: [:aVariant | - aCollectionOfPermutations anySatisfy: [:aPermutation | aPermutation keys anySatisfy: [:id | id = aVariant id ]]]). + aPermutation includesKey: aVariant id]). - aCollectionOfPermutations do: [:aPermutation | - aPermutation associationsDo: [:idToNum | - copy at: idToNum key ifPresent: [:theValue | theValue = idToNum value - ifTrue: [copy removeKey: idToNum key]]]]. + aPermutation associationsDo: [:idToNum | + copy at: idToNum key ifPresent: [:theValue | theValue = idToNum value + ifTrue: [copy removeKey: idToNum key]]]. + ^ copy + +] + +{ #category : #'initialize-release' } +SBPermutation >> copyRemovingVariants: aCollectionOfVariants [ + + | copy | + copy := self class new. + copy referencedVariants: (self referencedVariants reject: [:aVariant | aCollectionOfVariants includes: aVariant]). + copy referencedVariants ifEmpty: [^ SBNilPermutation new referencedVariants: {}]. + "copy := self veryDeepCopy. + copy referencedVariants: (copy referencedVariants difference: aCollectionOfVariants)." + + self associationsDo: [:anAssc | copy add: anAssc]. + aCollectionOfVariants do: [:aVariant | copy removeKey: aVariant id ifAbsent: []]. ^ copy ]