Пример #1
0
        protected override object ResolveReference(object partReference)
        {
            var entityComponentReference = partReference as EntityComponent;

            if (entityComponentReference != null)
            {
                var containingEntity = entityComponentReference.Entity;
                if (containingEntity == null)
                {
                    throw new InvalidOperationException("Found a reference to a component which doesn't have any entity");
                }

                var realEntity = (Entity)base.ResolveReference(containingEntity);
                if (realEntity == null)
                {
                    return(null);
                }

                var componentId   = IdentifiableHelper.GetId(entityComponentReference);
                var realComponent = realEntity.Components.FirstOrDefault(c => IdentifiableHelper.GetId(c) == componentId);
                return(realComponent);
            }

            return(base.ResolveReference(partReference));
        }
Пример #2
0
        private static void FixupEntityReferences(object rootToVisit, EntityHierarchyData entityHierarchy)
        {
            var entityAnalysisResult = Visit(rootToVisit);

            // Reverse the list, so that we can still properly update everything
            // (i.e. if we have a[0], a[1], a[1].Test, we have to do it from back to front to be valid at each step)
            entityAnalysisResult.EntityReferences.Reverse();

            // Updates Entity/EntityComponent references
            foreach (var entityLink in entityAnalysisResult.EntityReferences)
            {
                object obj = null;

                if (entityLink.EntityComponent != null)
                {
                    var containingEntity = entityLink.EntityComponent.Entity;
                    if (containingEntity == null)
                    {
                        throw new InvalidOperationException("Found a reference to a component which doesn't have any entity");
                    }

                    EntityDesign realEntity;
                    if (entityHierarchy.Entities.TryGetValue(containingEntity.Id, out realEntity))
                    {
                        var componentId = IdentifiableHelper.GetId(entityLink.EntityComponent);
                        obj = realEntity.Entity.Components.FirstOrDefault(c => IdentifiableHelper.GetId(c) == componentId);
                        if (obj == entityLink.EntityComponent)
                        {
                            continue;
                        }
                    }
                }
                else
                {
                    EntityDesign realEntity;
                    if (entityHierarchy.Entities.TryGetValue(entityLink.Entity.Id, out realEntity))
                    {
                        obj = realEntity.Entity;

                        // If we already have the proper item, let's skip
                        if (obj == entityLink.Entity)
                        {
                            continue;
                        }
                    }
                }

                if (obj != null)
                {
                    // We could find the referenced item, let's use it
                    entityLink.Path.Apply(rootToVisit, MemberPathAction.ValueSet, obj);
                }
                else
                {
                    // Item could not be found, let's null it
                    entityLink.Path.Apply(rootToVisit, MemberPathAction.ValueClear, null);
                }
            }
        }
Пример #3
0
 public EntityComponentReference(EntityComponent entityComponent)
 {
     this.Entity = new EntityReference()
     {
         Id = entityComponent.Entity.Id
     };
     this.Id    = IdentifiableHelper.GetId(entityComponent);
     this.Value = entityComponent;
 }
Пример #4
0
        public void FillFromPart(object assetPart)
        {
            var component = (EntityComponent)assetPart;

            Entity = new EntityReference {
                Id = component.Entity.Id
            };
            Id = IdentifiableHelper.GetId(component);
        }
Пример #5
0
        public override string ConvertTo(ref ObjectContext objectContext)
        {
            var attachedReference = AttachedReferenceManager.GetAttachedReference(objectContext.Instance);

            if (attachedReference == null)
            {
                throw new YamlException($"Unable to extract asset reference from object [{objectContext.Instance}]");
            }

            var referenceId = IdentifiableHelper.GetId(objectContext.Instance);

            return($"{referenceId}/{attachedReference.Id}:{attachedReference.Url}");
        }
Пример #6
0
        private void DiffValue(Diff3Node diff3, ref NodeDescription baseNodeDesc, ref NodeDescription asset1NodeDesc, ref NodeDescription asset2NodeDesc)
        {
            var node            = diff3.Asset1Node ?? diff3.Asset2Node ?? diff3.BaseNode;
            var dataVisitMember = node as DataVisitMember;

            if (dataVisitMember != null)
            {
                var diffMember = dataVisitMember.MemberDescriptor.GetCustomAttributes <DiffMemberAttribute>(true).FirstOrDefault();
                if (diffMember != null)
                {
                    if (diffMember.PreferredChange.HasValue)
                    {
                        diff3.ChangeType = diffMember.PreferredChange.Value;
                    }

                    diff3.Weight = diffMember.Weight;
                }
            }

            var instanceType = asset1NodeDesc.Instance?.GetType() ?? asset2NodeDesc.Instance?.GetType();

            object baseInstance   = baseNodeDesc.Instance;
            object asset1Instance = asset1NodeDesc.Instance;
            object asset2Instance = asset2NodeDesc.Instance;

            // If this is an identifiable type (but we are for example not visiting its member), compare only the Ids instead
            if (UseOverrideMode && instanceType != null && IdentifiableHelper.IsIdentifiable(instanceType))
            {
                baseInstance   = IdentifiableHelper.GetId(baseInstance);
                asset1Instance = IdentifiableHelper.GetId(asset1Instance);
                asset2Instance = IdentifiableHelper.GetId(asset2Instance);
            }

            var baseAsset1Equals = Equals(baseInstance, asset1Instance);
            var baseAsset2Equals = Equals(baseInstance, asset2Instance);
            var asset1And2Equals = Equals(asset1Instance, asset2Instance);

            diff3.ChangeType = baseAsset1Equals && baseAsset2Equals
                ? Diff3ChangeType.None
                : baseAsset2Equals ? Diff3ChangeType.MergeFromAsset1 : baseAsset1Equals ? Diff3ChangeType.MergeFromAsset2 : asset1And2Equals ? Diff3ChangeType.MergeFromAsset1And2 : Diff3ChangeType.Conflict;
        }
Пример #7
0
        /// <inheritdoc/>
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            if (!AreCollectionItemsIdentifiable(ref objectContext))
            {
                base.TransformObjectAfterRead(ref objectContext);
                return;
            }

            var info = (InstanceInfo)objectContext.Properties[InstanceInfoKey];

            // This is to be backward compatible with previous serialization. We fetch ids from the ~Id member of each item
            if (info.Instance != null)
            {
                ICollection <ItemId> deletedItems;
                objectContext.Properties.TryGetValue(DeletedItemsKey, out deletedItems);
                TransformAfterDeserialization((IDictionary)objectContext.Instance, info.Descriptor, info.Instance, deletedItems);
            }
            objectContext.Instance = info.Instance;

            var enumerable = objectContext.Instance as IEnumerable;

            if (enumerable != null)
            {
                var ids        = CollectionItemIdHelper.GetCollectionItemIds(objectContext.Instance);
                var descriptor = (DictionaryDescriptor)info.Descriptor;
                foreach (var item in descriptor.GetEnumerator(objectContext.Instance))
                {
                    ItemId id;
                    if (ids.TryGet(item.Key, out id) && id != ItemId.Empty)
                    {
                        continue;
                    }

                    var guid = item.Value != null?IdentifiableHelper.GetId(item.Value) : Guid.NewGuid();

                    ids[item.Key] = guid != Guid.Empty ? new ItemId(guid.ToByteArray()) : ItemId.New();
                }
            }

            base.TransformObjectAfterRead(ref objectContext);
        }
Пример #8
0
 public override void Serialize(ref MaterialNull obj, ArchiveMode mode, SerializationStream stream)
 {
     if (stream.Context.SerializerSelector.HasProfile("AssetClone"))
     {
         // At design time, when performing a clone, we keep the associated id of this instance.
         if (mode == ArchiveMode.Serialize)
         {
             var id = IdentifiableHelper.GetId(obj);
             stream.Write(id);
         }
         else
         {
             var id = stream.Read <Guid>();
             obj = new MaterialNull();
             IdentifiableHelper.SetId(obj, id);
         }
     }
     else
     {
         // For runtime serialization, a MaterialNull becomes null
         obj = null;
     }
 }
Пример #9
0
        /// <inheritdoc/>
        protected override void TransformObjectAfterRead(ref ObjectContext objectContext)
        {
            InstanceInfo info;

            if (!objectContext.Properties.TryGetValue(InstanceInfoKey, out info))
            {
                base.TransformObjectAfterRead(ref objectContext);

                if (AreCollectionItemsIdentifiable(ref objectContext))
                {
                    // This is to be backward compatible with previous serialization. We fetch ids from the ~Id member of each item
                    var enumerable = objectContext.Instance as IEnumerable;
                    if (enumerable != null)
                    {
                        var ids = CollectionItemIdHelper.GetCollectionItemIds(objectContext.Instance);
                        var i   = 0;
                        foreach (var item in enumerable)
                        {
                            var id = item != null?IdentifiableHelper.GetId(item) : Guid.NewGuid();

                            ids[i] = id != Guid.Empty ? new ItemId(id.ToByteArray()) : ItemId.New();
                            ++i;
                        }
                    }
                }
                return;
            }

            var instance = info.Instance ?? objectContext.SerializerContext.ObjectFactory.Create(info.Descriptor.Type);
            ICollection <ItemId> deletedItems;

            objectContext.Properties.TryGetValue(DeletedItemsKey, out deletedItems);
            TransformAfterDeserialization((IDictionary)objectContext.Instance, info.Descriptor, instance, deletedItems);
            objectContext.Instance = instance;

            base.TransformObjectAfterRead(ref objectContext);
        }
Пример #10
0
        public override object ConvertFrom(ref ObjectContext context, Scalar fromScalar)
        {
            Guid  guid;
            UFile location;
            Guid  referenceId;

            if (!AssetReference.TryParse(fromScalar.Value, out referenceId, out guid, out location))
            {
                throw new YamlException(fromScalar.Start, fromScalar.End, "Unable to decode asset reference [{0}]. Expecting format GUID:LOCATION".ToFormat(fromScalar.Value));
            }

            var instance = AttachedReferenceManager.CreateProxyObject(context.Descriptor.Type, guid, location);

            // If the referenceId is empty, force its creation, else attach it to the reference
            if (referenceId == Guid.Empty)
            {
                IdentifiableHelper.GetId(instance);
            }
            else
            {
                IdentifiableHelper.SetId(instance, referenceId);
            }
            return(instance);
        }
Пример #11
0
        public void TestIdentifierHelper()
        {
            // Has IdentifierHelper is using ShadowObject, we will test it here
            ShadowObject.Enable = true;
            var obj = new object();

            var id = IdentifiableHelper.GetId(obj);

            Assert.AreNotEqual(Guid.Empty, id);

            var id1 = IdentifiableHelper.GetId(obj);

            Assert.AreEqual(id, id1);

            // We should not get an id for a collection
            var idCollection = IdentifiableHelper.GetId(new List <object>());

            Assert.AreEqual(Guid.Empty, idCollection);

            // We should not get an id for a dictionary
            var idDict = IdentifiableHelper.GetId(new MyDictionary());

            Assert.AreEqual(Guid.Empty, idDict);
        }
Пример #12
0
            public override void VisitObjectMember(object container, ObjectDescriptor containerDescriptor, IMemberDescriptor member, object value)
            {
                base.VisitObjectMember(container, containerDescriptor, member, value);
                var assetReference    = value as AssetReference;
                var assetBase         = value as AssetBase;
                var attachedReference = AttachedReferenceManager.GetAttachedReference(value);

                if (assetReference != null)
                {
                    AddLink(assetReference,
                            (guid, location) =>
                    {
                        var newValue = AssetReference.New(member.Type, guid ?? assetReference.Id, location);
                        member.Set(container, newValue);
                        return(newValue);
                    });
                }
                else if (assetBase != null)
                {
                    AddLink(assetBase,
                            (guid, location) =>
                    {
                        var newValue = new AssetBase(location, assetBase.Asset);
                        member.Set(container, newValue);
                        return(newValue);
                    });
                }
                else if (attachedReference != null)
                {
                    AddLink(attachedReference,
                            (guid, location) =>
                    {
                        object newValue = guid.HasValue && guid.Value != Guid.Empty ? AttachedReferenceManager.CreateProxyObject(member.Type, guid.Value, location) : null;
                        if (newValue != null)
                        {
                            IdentifiableHelper.SetId(newValue, IdentifiableHelper.GetId(value));
                        }
                        member.Set(container, newValue);
                        return(newValue);
                    });
                }
                else if (value is UFile)
                {
                    AddLink(value,
                            (guid, location) =>
                    {
                        var newValue = new UFile(location);
                        member.Set(container, newValue);
                        return(newValue);
                    });
                }
                else if (value is UDirectory)
                {
                    AddLink(value,
                            (guid, location) =>
                    {
                        var newValue = new UDirectory(location);
                        member.Set(container, newValue);
                        return(newValue);
                    });
                }
            }
Пример #13
0
 public override object Get(object thisObject)
 {
     return(IdentifiableHelper.GetId(thisObject));
 }
Пример #14
0
        private void FixReferencesToEntities(EntityDesign newEntityDesign, Dictionary <GroupPartKey, Guid> mapBaseIdToNewId)
        {
            var newEntity = newEntityDesign.Entity;

            // We need to visit all references to entities/components in order to fix references
            // (e.g entities removed, entity added from base referencing an entity from base that we have to redirect to the new child entity...)
            // Suppose for example that:
            //
            // base   newBase                                      newAsset
            // EA       EA                                           EA'
            // EB       EB                                           EB'
            // EC       EC                                           EC'
            //          ED (+link to EA via script or whather)       ED' + link to EA' (we need to change from EA to EA')
            //
            // So in the example above, when merging ED into newAsset, all references to entities declared in newBase are not automatically
            // remapped to the new entities in newAsset. This is the purpose of this whole method

            var entityVisitor          = new SingleLevelVisitor(typeof(Entity), true);
            var entityComponentVisitor = new SingleLevelVisitor(typeof(EntityComponent), true);

            DataVisitNodeBuilder.Run(TypeDescriptorFactory.Default, newEntity, new List <IDataCustomVisitor>()
            {
                entityVisitor,
                entityComponentVisitor
            });

            // Fix Entity and EntityComponent references
            foreach (var idNodes in entityVisitor.References.Concat(entityComponentVisitor.References))
            {
                var id    = idNodes.Key;
                var nodes = idNodes.Value;

                // If entity id is not in the current list, it is more likely that it was a link to a base entity
                if (!newAsset.Hierarchy.Parts.ContainsKey(id))
                {
                    var groupKey = new GroupPartKey(newEntityDesign.BasePartInstanceId, id);

                    // We are trying to remap the base id to the new id from known entities from newAsset
                    Guid newId;
                    if (mapBaseIdToNewId.TryGetValue(groupKey, out newId))
                    {
                        var linkedEntity = newAsset.Hierarchy.Parts[newId].Entity;
                        foreach (var node in nodes)
                        {
                            var entityComponent = node.Instance as EntityComponent;
                            if (entityComponent != null)
                            {
                                var entityComponentId = IdentifiableHelper.GetId(entityComponent);
                                // TODO: In case of a DataVisitMember node, we need to set an OverrideType to New if we are actually removing a base value
                                var newEntityComponent = (EntityComponent)linkedEntity.Components.FirstOrDefault(t => IdentifiableHelper.GetId(t) == entityComponentId);
                                node.SetValue(newEntityComponent);
                            }
                            else
                            {
                                // TODO: In case of a DataVisitMember node, we need to set an OverrideType to New if we are actually removing a base value
                                // Else the node applies to an entity
                                node.SetValue(linkedEntity);
                            }
                        }
                    }
                    else
                    {
                        // TODO: In case of a DataVisitMember node, we need to set an OverrideType to New if we are actually removing a base value
                        // If we are trying to link to an entity/component that was removed, we need to remove it
                        foreach (var node in nodes)
                        {
                            node.RemoveValue();
                        }
                    }
                }
            }
        }
Пример #15
0
        public override string ConvertTo(ref ObjectContext objectContext)
        {
            var materialNull = ((MaterialNull)objectContext.Instance);

            return(IdentifiableHelper.GetId(materialNull).ToString());
        }
Пример #16
0
            public override void VisitArrayItem(Array array, ArrayDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
            {
                base.VisitArrayItem(array, descriptor, index, item, itemDescriptor);
                var assetReference    = item as AssetReference;
                var assetBase         = item as AssetBase;
                var attachedReference = AttachedReferenceManager.GetAttachedReference(item);

                if (assetReference != null)
                {
                    AddLink(item,
                            (guid, location) =>
                    {
                        var newValue = AssetReference.New(descriptor.ElementType, guid ?? assetReference.Id, location);
                        array.SetValue(newValue, index);
                        return(newValue);
                    });
                }
                else if (assetBase != null)
                {
                    AddLink(item,
                            (guid, location) =>
                    {
                        var newValue = new AssetBase(location, assetBase.Asset);
                        array.SetValue(newValue, index);
                        return(newValue);
                    });
                }
                else if (attachedReference != null)
                {
                    AddLink(attachedReference,
                            (guid, location) =>
                    {
                        object newValue = guid.HasValue && guid.Value != Guid.Empty ? AttachedReferenceManager.CreateProxyObject(descriptor.ElementType, guid.Value, location) : null;
                        if (newValue != null)
                        {
                            IdentifiableHelper.SetId(newValue, IdentifiableHelper.GetId(item));
                        }
                        array.SetValue(newValue, index);
                        return(newValue);
                    });
                }
                else if (item is UFile)
                {
                    AddLink(item,
                            (guid, location) =>
                    {
                        var newValue = new UFile(location);
                        array.SetValue(newValue, index);
                        return(newValue);
                    });
                }
                else if (item is UDirectory)
                {
                    AddLink(item,
                            (guid, location) =>
                    {
                        var newValue = new UFile(location);
                        array.SetValue(newValue, index);
                        return(newValue);
                    });
                }
            }
Пример #17
0
        public void Test()
        {
            var prefab = new PrefabAsset();

            var modelComponent = new ModelComponent();
            var entity         = new Entity()
            {
                modelComponent
            };

            prefab.Hierarchy.Parts.Add(new EntityDesign(entity));
            prefab.Hierarchy.RootPartIds.Add(entity.Id);

            var material1 = new MaterialNull();

            IdentifiableHelper.SetId(material1, new Guid("39E2B226-8752-4678-8E93-76FFBFBA337B"));
            var material2 = new MaterialNull();

            IdentifiableHelper.SetId(material2, new Guid("CC4F1B31-FBB7-4360-A3E7-060BDFDA0695"));
            modelComponent.Materials.Add(material1);
            modelComponent.Materials.Add(material2);

            Action <PrefabAsset> checkPrefab = (newPrefab) =>
            {
                var previousEntityDesign = newPrefab.Hierarchy.Parts.FirstOrDefault();

                Assert.NotNull(previousEntityDesign);

                var previousEntity = previousEntityDesign.Entity;


                var component = previousEntity.Get <ModelComponent>();
                Assert.NotNull(component);

                Assert.AreEqual(2, component.Materials.Count);

                var newMaterial1 = component.Materials[0];
                Assert.AreEqual(IdentifiableHelper.GetId(material1), IdentifiableHelper.GetId(newMaterial1));
                var newMaterial2 = component.Materials[1];
                Assert.AreEqual(IdentifiableHelper.GetId(material2), IdentifiableHelper.GetId(newMaterial2));
            };

            // Test yaml serialization
            {
                using (var stream = new MemoryStream())
                {
                    AssetSerializer.Save(stream, prefab);

                    stream.Position = 0;
                    var serializedVersion = Encoding.UTF8.GetString(stream.ToArray());
                    Console.WriteLine(serializedVersion);

                    stream.Position = 0;
                    var newPrefab = (PrefabAsset)AssetSerializer.Load(stream, "myentity");
                    checkPrefab(newPrefab);
                }
            }

            // Test cloning
            var newPrefabClone = (PrefabAsset)AssetCloner.Clone(prefab);

            checkPrefab(newPrefabClone);

            // Test runtime serialization (runtime serialization is removing MaterialNull and replacing it by a null)
            {
                var stream = new MemoryStream();
                var writer = new BinarySerializationWriter(stream)
                {
                    Context = { SerializerSelector = SerializerSelector.AssetWithReuse }
                };
                writer.SerializeExtended(entity, ArchiveMode.Serialize);
                writer.Flush();
                stream.Position = 0;

                var reader = new BinarySerializationReader(stream)
                {
                    Context = { SerializerSelector = SerializerSelector.AssetWithReuse }
                };

                Entity newEntity = null;
                reader.SerializeExtended(ref newEntity, ArchiveMode.Deserialize);

                Assert.NotNull(newEntity);

                var component = newEntity.Get <ModelComponent>();
                Assert.NotNull(component);

                Assert.AreEqual(2, component.Materials.Count);

                Assert.Null(component.Materials[0]);
                Assert.Null(component.Materials[1]);
            }
        }
Пример #18
0
            public override void VisitCollectionItem(IEnumerable collection, CollectionDescriptor descriptor, int index, object item, ITypeDescriptor itemDescriptor)
            {
                base.VisitCollectionItem(collection, descriptor, index, item, itemDescriptor);
                var assetReference    = item as AssetReference;
                var assetBase         = item as AssetBase;
                var attachedReference = AttachedReferenceManager.GetAttachedReference(item);

                // We cannot set links if we do not have indexer accessor
                if (!descriptor.HasIndexerAccessors)
                {
                    return;
                }

                if (assetReference != null)
                {
                    AddLink(assetReference, (guid, location) =>
                    {
                        var link = AssetReference.New(descriptor.ElementType, guid ?? assetReference.Id, location);
                        descriptor.SetValue(collection, index, link);
                        return(link);
                    });
                }
                else if (assetBase != null)
                {
                    AddLink(assetBase, (guid, location) =>
                    {
                        var link = new AssetBase(location, assetBase.Asset);
                        descriptor.SetValue(collection, index, link);
                        return(link);
                    });
                }
                else if (attachedReference != null)
                {
                    AddLink(attachedReference, (guid, location) =>
                    {
                        var link = guid.HasValue && guid.Value != Guid.Empty ? AttachedReferenceManager.CreateProxyObject(descriptor.ElementType, guid.Value, location) : null;
                        if (link != null)
                        {
                            IdentifiableHelper.SetId(link, IdentifiableHelper.GetId(item));
                        }
                        descriptor.SetValue(collection, index, link);
                        return(link);
                    });
                }
                else if (item is UFile)
                {
                    AddLink(item, (guid, location) =>
                    {
                        var link = new UFile(location);
                        descriptor.SetValue(collection, index, link);
                        return(link);
                    });
                }
                else if (item is UDirectory)
                {
                    AddLink(item, (guid, location) =>
                    {
                        var link = new UDirectory(location);
                        descriptor.SetValue(collection, index, link);
                        return(link);
                    });
                }
            }
Пример #19
0
            public override void VisitDictionaryKeyValue(object dictionaryObj, DictionaryDescriptor descriptor, object key, ITypeDescriptor keyDescriptor, object value, ITypeDescriptor valueDescriptor)
            {
                base.VisitDictionaryKeyValue(dictionaryObj, descriptor, key, keyDescriptor, value, valueDescriptor);
                var assetReference    = value as AssetReference;
                var assetBase         = value as AssetBase;
                var attachedReference = AttachedReferenceManager.GetAttachedReference(value);

                if (assetReference != null)
                {
                    AddLink(assetReference,
                            (guid, location) =>
                    {
                        var newValue = AssetReference.New(descriptor.ValueType, guid ?? assetReference.Id, location);
                        descriptor.SetValue(dictionaryObj, key, newValue);
                        return(newValue);
                    });
                }
                else if (assetBase != null)
                {
                    AddLink(assetBase,
                            (guid, location) =>
                    {
                        var newValue = new AssetBase(location, assetBase.Asset);
                        descriptor.SetValue(dictionaryObj, key, newValue);
                        return(newValue);
                    });
                }
                else if (attachedReference != null)
                {
                    AddLink(attachedReference,
                            (guid, location) =>
                    {
                        object newValue = guid.HasValue && guid.Value != Guid.Empty ? AttachedReferenceManager.CreateProxyObject(descriptor.ValueType, guid.Value, location) : null;
                        if (newValue != null)
                        {
                            IdentifiableHelper.SetId(newValue, IdentifiableHelper.GetId(value));
                        }
                        descriptor.SetValue(dictionaryObj, key, newValue);
                        return(newValue);
                    });
                }
                else if (value is UFile)
                {
                    AddLink(value,
                            (guid, location) =>
                    {
                        var newValue = new UFile(location);
                        descriptor.SetValue(dictionaryObj, key, newValue);
                        return(newValue);
                    });
                }
                else if (value is UDirectory)
                {
                    AddLink(value,
                            (guid, location) =>
                    {
                        var newValue = new UDirectory(location);
                        descriptor.SetValue(dictionaryObj, key, newValue);
                        return(newValue);
                    });
                }
            }