Exemple #1
0
        /// <summary>
        /// Internal prepare
        /// </summary>
        /// <param name="readService"></param>
        /// <param name="data"></param>
        /// <param name="subOps"></param>
        unsafe void PrepareInternal(IReadService readService, List <DeleteChild> subOps)
        {
            // We inspect children.
            ulong childrenTS;
            Block block = readService.Read(BlockType.NodeHeaderBlock, commonAddress);

            fixed(byte *p = block.Data)
            {
                NodeCommonHeader *header = (NodeCommonHeader *)p;

                childrenTS = header->ChildrenBTree;
            }

            // We check children count.
            BPlusTree         tree    = new BPlusTree(childrenTS);
            List <ObjectInfo> objects = tree.ListAll(readService);

            // We update stage index/count.
            for (int j = 0; j < objects.Count; j++)
            {
                BlockStream childTagStream = BlockStream.FromBase(objects[j].Address, readService);
                ChildTag    childTag       = Common.DeserializeFromArray(childTagStream.Read(objects[j].Size)) as ChildTag;

                foreach (KeyValuePair <string, ulong> child in childTag.Children)
                {
                    DeleteChild subOp = new DeleteChild(child.Value, childrenTS, child.Key);
                    subOps.Add(subOp);
                }
            }

            subOps.Add(this);
        }
Exemple #2
0
        public void Execute(uint stage, SharpMedia.Database.Physical.Journalling.IService service)
        {
            // 1) We read previous object placement and change it.
            ObjectInfo  info     = childrenTree.Find(service, (uint)prevName.GetHashCode());
            BlockStream stream   = BlockStream.FromBase(info.Address, service);
            ChildTag    childTag = Common.DeserializeFromArray(stream.Read(info.Size)) as ChildTag;

            childTag.Remove(prevName);

            // Remove it if empty.
            if (childTag.IsEmpty)
            {
                childrenTree.Remove(service, (uint)prevName.GetHashCode(), 1, false);
            }
            else
            {
                // Update the entry (now without this child).
                byte[] childTagData = Common.SerializeToArray(childTag);
                stream = service.AllocationContext.CreateBlockStream((ulong)childTagData.LongLength);
                stream.Write(childTagData);

                childrenTree.Replace(service,
                                     new ObjectInfo((uint)prevName.GetHashCode(), (ulong)childTagData.LongLength, stream.BaseAddress));
            }

            // 3) We create new and insert it into tree.
            ObjectInfo info2 = childrenTree.Find(service, (uint)newName.GetHashCode());

            if (info2 == null)
            {
                // We create new tag.
                childTag = new ChildTag();
                childTag.Add(newName, info.Address);
                byte[] childTagData = Common.SerializeToArray(childTag);
                stream = service.AllocationContext.CreateBlockStream((ulong)childTagData.LongLength);
                stream.Write(childTagData);

                // And we add child.
                childrenTree.Add(service,
                                 new ObjectInfo((uint)newName.GetHashCode(), (ulong)childTagData.LongLength, stream.BaseAddress));
            }
            else
            {
                // We append it and release previous tag.
                stream   = BlockStream.FromBase(info2.Address, service);
                childTag = Common.DeserializeFromArray(stream.Read(info2.Size)) as ChildTag;
                stream.Deallocate();

                // We modify and rewrite it.
                childTag.Add(newName, info.Address);
                byte[] childTagData = Common.SerializeToArray(childTag);
                stream = service.AllocationContext.CreateBlockStream((ulong)childTagData.LongLength);
                stream.Write(childTagData);

                // We insert into children tree.
                childrenTree.Replace(service,
                                     new ObjectInfo((uint)newName.GetHashCode(), (ulong)childTagData.LongLength, info.Address));
            }
        }
Exemple #3
0
        public string PrintProperty(PropertyInfo prop, ChildTag child)
        {
            var output = "";

            if (prop.GetValue(child) == null)
            {
                return(output);
            }
            if (prop.GetValue(child).GetType() != typeof(List <ChildTag>))   // If property is not a list of childtags, aka, not a set of children for a component
            {
                if (prop.GetValue(child).GetType() != typeof(bool))
                {
                    if (prop.Name != "useTextTexture")
                    {
                        if (prop.Name != "Tag")
                        {
                            if (Char.IsUpper(prop.Name[0]) == false)    // If the first letter of the property name is not a capital, then it is a header property
                            {
                                output += (FormatNewline(FormatTag(prop.Name) + "\n" + prop.GetValue(child) + "\n"));
                            }
                            else
                            {
                                if (prop.GetValue(child).ToString() != "-999")
                                {
                                    output += (prop.GetValue(child) + "\n");
                                }
                            }
                        }
                        else
                        {
                            output += (FormatNewline(FormatTag(prop.GetValue(child).ToString()) + "\n"));
                        }
                    }
                    else
                    {
                        output += FormatTag(prop.Name) + "\n" + GetTextTextureID(prop.GetValue(child).ToString(), TextTextures) + "\n";
                    }
                }
                else if (bool.Parse(prop.GetValue(child).ToString()))
                {
                    output += (FormatNewline(FormatTag(prop.Name) + "\n\n"));
                }
            }
            else
            {
                output += (UnpackChildList(prop, child));
            }

            return(output);
        }
Exemple #4
0
        public void Compile(ChildTag child, string compInputPath, string outputPath = @"C:\Temp\ConfigOut.cfg")
        {
            InputPath = compInputPath;
            var textTextureOutput = CompileTextTextures(TextTextures);
            var outputString      = UnpackProperties(child);

            if (File.Exists(outputPath))
            {
                File.AppendAllText(outputPath, outputString);
            }
            else
            {
                File.WriteAllText(outputPath, textTextureOutput + outputString);
                //File.WriteAllText(outputPath, outputString);
            }
        }
Exemple #5
0
        //private int getMeshStart(string opString)
        //{
        //    Match match = Regex.Match(opString, @"\[mesh\]");
        //    return match.Index;
        //}

        public string UnpackProperties(ChildTag child)
        {
            var outputString = "";

            foreach (var prop in child.GetType().GetProperties())
            {
                if (prop.PropertyType != typeof(List <ChildTag>))
                {
                    outputString += PrintProperty(prop, child);
                }
                else
                {
                    outputString += UnpackChildList(prop, child);
                }
            }

            return(outputString);
        }
Exemple #6
0
        public string UnpackChildList(PropertyInfo prop, ChildTag child)
        {
            var output   = "";
            var property = prop.GetValue(child);

            if (!(property is List <ChildTag> propertyList))
            {
                return(output);
            }
            foreach (var item in propertyList)
            {
                foreach (var itemProp in item.GetType().GetProperties())
                {
                    output += PrintProperty(itemProp, item);
                }
            }

            return(output);
        }
Exemple #7
0
        /// <summary>
        /// Executes the operation.
        /// </summary>
        /// <param name="service">Service for operation.</param>
        unsafe void ExecuteInternal(IService service)
        {
            ulong childrenTS;
            ulong versionTS;

            // 1) We extract child TS and version TS
            Block block = service.Read(BlockType.NodeHeaderBlock, commonAddress);

            fixed(byte *p = block.Data)
            {
                NodeCommonHeader *header = (NodeCommonHeader *)p;

                childrenTS = header->ChildrenBTree;
                versionTS  = header->VersionsBTree;
            }

            // 2) Can get rid of node.
            service.DeAllocate(commonAddress);

            // 3) We delete children TS, it should be empty (since deletes were already called on nodes).
            service.DeAllocate(childrenTS);

            // 4) We go through versions.
            BPlusTree         versionsTree = new BPlusTree(versionTS);
            List <ObjectInfo> versions     = versionsTree.ListAll(service);

            // 5) We delete each version.
            foreach (ObjectInfo info in versions)
            {
                // a) Read version tag.
                BlockStream versionTagStream = BlockStream.FromBase(info.Address, service);
                VersionTag  versionTag       = Common.DeserializeFromArray(versionTagStream.Read(info.Size)) as VersionTag;
                versionTagStream.Deallocate();

                foreach (KeyValuePair <ulong, ulong> versionToNode in versionTag.VersionAddress)
                {
                    block = service.Read(BlockType.NodeHeaderBlock, versionToNode.Value);

                    List <ulong> typedStreams = NodeVersionHelper.ListAllTypedStreamsAsAddresses(block, service);

                    // b) Delete all typed streams.
                    for (int i = 0; i < typedStreams.Count; i++)
                    {
                        // 1) We delete the typed stream object.
                        block = service.Read(BlockType.TypedStreamHeader, typedStreams[i]);
                        fixed(byte *p = block.Data)
                        {
                            TypedStreamHeader *header = (TypedStreamHeader *)p;

                            // We delete single object.
                            if ((header->Options & StreamOptions.SingleObject) != 0)
                            {
                                if (header->ObjectsAddress != 0)
                                {
                                    BlockStream stream = BlockStream.FromBase(header->ObjectsAddress, service);
                                    stream.Deallocate();
                                }
                            }
                            else
                            {
                                // We delete all children.
                                BPlusTree tree = new BPlusTree(header->ObjectsAddress);
                                foreach (ObjectInfo info2 in tree.ListAll(service))
                                {
                                    BlockStream stream = BlockStream.FromBase(info2.Address, service);
                                    stream.Deallocate();
                                }
                            }
                        }

                        // 2) We also delete the header itself.
                        service.DeAllocate(typedStreams[i]);
                    }

                    // c) We deallocate version block.
                    service.DeAllocate(versionToNode.Value);
                }
            }

            // 6) We delete the tree.
            versionsTree.DeallocateTree(service);

            // 7) We must erase the node from root.
            ObjectInfo  childInfo      = parentChildTree.Find(service, (uint)childName.GetHashCode());
            BlockStream childTagStream = BlockStream.FromBase(childInfo.Address, service);

            byte[]   childTagData = childTagStream.Read(childInfo.Size);
            ChildTag childTag     = Common.DeserializeFromArray(childTagData) as ChildTag;

            childTagStream.Deallocate();

            if (childTag.Children.Count == 1)
            {
                // Simply delete it.
                parentChildTree.Remove(service, (uint)childName.GetHashCode(), 1, false);
            }
            else
            {
                // We have to replace it.
                childTag.Remove(childName);
                childTagData   = Common.SerializeToArray(childTag);
                childTagStream = service.AllocationContext.CreateBlockStream((ulong)childTagData.LongLength);
                childTagStream.Write(childTagData);

                parentChildTree.Replace(service, new ObjectInfo((uint)childName.GetHashCode(),
                                                                (ulong)childTagData.LongLength, childTagStream.BaseAddress));
            }
        }
Exemple #8
0
        public unsafe void Execute(uint stage, IService service)
        {
            // 1) We create the node common block.
            versionAddress = service.AllocationContext.AllocateBlock();
            commonAddress  = service.AllocationContext.AllocateBlock();
            BPlusTree versionTS = new BPlusTree(service.AllocationContext.CreateEmptyBTree());

            // Fill common block and write.
            Block commonBlock = new Block(service.BlockSize);

            fixed(byte *p = commonBlock.Data)
            {
                NodeCommonHeader *header = (NodeCommonHeader *)p;

                header->ChildrenBTree         = service.AllocationContext.CreateEmptyBTree();
                header->CurrentVersionAddress = versionAddress;
                header->CurrentVersionNumber  = 0;
                header->HeaderMagic           = NodeCommonHeader.Magic;
                header->ParentAddress         = parentAddress;
                header->VersionsBTree         = versionTS.RootAddress;
            }

            service.Write(BlockType.NodeHeaderBlock, commonAddress, commonBlock);

            // 2) We create the node default typed stream.
            Block tsblock = new Block(service.BlockSize);

            ulong tsBlock = service.AllocationContext.AllocateBlock();

            fixed(byte *p = tsblock.Data)
            {
                TypedStreamHeader *header = (TypedStreamHeader *)p;

                header->ObjectsAddress = (defaultTSOptions & StreamOptions.SingleObject) == 0 ?
                                         service.AllocationContext.CreateEmptyBTree() : 0;
                header->Options    = defaultTSOptions;
                header->ObjectSize = 0;

                int i;

                for (i = 0; i < defaultTSType.Length; i++)
                {
                    header->Type[i] = defaultTSType[i];
                }

                // Null terminate it.
                header->Type[i] = '\0';
            }

            service.Write(BlockType.TypedStreamHeader, tsBlock, tsblock);

            // 3) We create the node version block.
            // Fill version block and write.
            Block versionBlock = new Block(service.BlockSize);

            fixed(byte *pp = versionBlock.Data)
            {
                NodeVersionHeader *header = (NodeVersionHeader *)pp;

                header->CreationTime       = DateTime.Now;
                header->DefaultTypedStream = 0;
                header->HeaderMagic        = NodeVersionHeader.Magic;
                header->ModifiedTime       = DateTime.Now;
                header->NodeCommonAddress  = commonAddress;
                header->StreamCount        = 0; //< Is actually one but NodeHelper changes this.
                header->VersionNumber      = 0;
            }

            // We must add default typed stream to block.
            NodeVersionHelper.AddTypedStream(tsBlock, defaultTSType, versionBlock);
            service.Write(BlockType.NodeHeaderBlock, versionAddress, versionBlock);

            // 4) We add to children tree.
            ObjectInfo info = childrenTree.Find(service, (uint)childName.GetHashCode());

            if (info == null)
            {
                // We simply create a new object at address.
                ChildTag childTag = new ChildTag();
                childTag.HashCode = childName.GetHashCode();
                childTag.Add(childName, commonAddress);
                byte[] childData = Common.SerializeToArray(childTag);

                // We write it to block stream.
                BlockStream stream = service.AllocationContext.CreateBlockStream((ulong)childData.LongLength);
                stream.Write(childData);

                // We now add it to B+ tree.
                childrenTree.Add(service, new ObjectInfo((uint)childName.GetHashCode(), (ulong)childData.LongLength, stream.BaseAddress));
            }
            else
            {
                // The index at hash already exists, we must add it, first read it.
                BlockStream stream   = BlockStream.FromBase(info.Address, service);
                ChildTag    childTag = Common.DeserializeFromArray(stream.Read(info.Size)) as ChildTag;

                // Steam not used anymore.
                stream.Deallocate();

                // We modify child tag.
                childTag.Add(childName, commonAddress);
                byte[] childData = Common.SerializeToArray(childTag);

                // We must write it to new address.
                stream = service.AllocationContext.CreateBlockStream((ulong)childData.LongLength);
                stream.Write(childData);

                // Now we replace the data in tree.
                childrenTree.Replace(service,
                                     new ObjectInfo((uint)childName.GetHashCode(), (ulong)childData.LongLength, stream.BaseAddress));
            }

            // 5) Add version to typed stream.
            VersionTag versionTag = new VersionTag((0).GetHashCode());

            versionTag.Add(0, versionAddress);
            byte[] versionTagData = Common.SerializeToArray(versionTag);

            // Write to stream.
            BlockStream versionTagStream = service.AllocationContext.CreateBlockStream((ulong)versionTagData.LongLength);

            versionTagStream.Write(versionTagData);

            versionTS.Add(service, new ObjectInfo((uint)(0).GetHashCode(),
                                                  (ulong)versionTagData.LongLength, versionTagStream.BaseAddress));
        }
Exemple #9
0
        public static async Task <Document> ParseXmlAsync(XmlDocument xmlFile, string fileName)
        {
            XmlNode        root     = xmlFile.DocumentElement;
            XmlNodeList    nodes    = root.ChildNodes;
            Document       document = new Document();
            List <SqlData> SqlData  = new List <SqlData>();

            document.Tags = new List <Tag>();

            document.GlobalResources = null;
            //Dictionary<string, Dictionary<string,string>> nodeMap = new Dictionary<string, Dictionary<string, string>>();
            //Dictionary<Dictionary<string, string>, Dictionary<string, string>> childNodeMap = new Dictionary<Dictionary<string, string>, Dictionary<string, string>>();
            if (fileName.Contains("global"))
            {
                document.IsGlobal                         = true;
                document.GlobalResources                  = new GlobalResources();
                document.GlobalResources.DbConfig         = new List <DbConfig>();
                document.GlobalResources.WebServiceConfig = new List <WebServiceConfig>();
            }

            foreach (XmlNode node in nodes)
            {
                //nodeMap[node.Name] = new Dictionary<string, string>();
                Tag tag = new Tag();
                Console.WriteLine(node.Name);
                tag.tagName = node.Name;
                Console.WriteLine("----------------------");
                if (node.Attributes != null)
                {
                    XmlAttributeCollection attributes = node.Attributes;
                    tag.attributeKeyValue = new Dictionary <string, string>();
                    bool             addNameToNode   = false;
                    bool             dbConfigCreated = false;
                    bool             wsConfigCreated = false;
                    DbConfig         dbConfig        = null;
                    WebServiceConfig wsConfig        = null;
                    var AttributeCount = attributes.Count;

                    var i = 0;
                    foreach (XmlAttribute attribute in attributes)
                    {
                        i++;
                        tag.attributeKeyValue.Add(attribute.Name, attribute.Value);

                        if (node.Name.Equals("flow") || node.Name.Equals("sub-flow"))
                        {
                            if (!addNameToNode && attribute.Name.Equals("name"))
                            {
                                tag.tagName   = node.Name + " (" + attribute.Value + ")";
                                addNameToNode = true;
                            }
                        }
                        else if (fileName.Contains("global"))
                        {
                            //ADDITIONAL CONDITION FOR GLOBAL.XML FILE
                            if (!addNameToNode && attribute.Name.Equals("name"))
                            {
                                tag.tagName   = node.Name + " (" + attribute.Value + ")";
                                addNameToNode = true;
                            }

                            if (node.Name.StartsWith("db:"))
                            {
                                if (!dbConfigCreated)
                                {
                                    dbConfig        = new DbConfig();
                                    dbConfigCreated = true;
                                    dbConfig.DbType = node.Name;
                                }

                                if (attribute.Name.Equals("name"))
                                {
                                    dbConfig.Dbname = attribute.Value;
                                }
                                else if (attribute.Name.Equals("url"))
                                {
                                    dbConfig.DbUrl = attribute.Value;
                                }
                            }
                            if (node.Name.StartsWith("ws:"))
                            {
                                if (!wsConfigCreated)
                                {
                                    wsConfig        = new WebServiceConfig();
                                    wsConfigCreated = true;
                                }

                                if (attribute.Name.Equals("name"))
                                {
                                    wsConfig.WsName = attribute.Value;
                                }
                                else if (attribute.Name.Equals("service"))
                                {
                                    wsConfig.WsService = attribute.Value;
                                }
                                else if (attribute.Name.Equals("port"))
                                {
                                    wsConfig.WsPort = attribute.Value;
                                }
                                else if (attribute.Name.Equals("wsdlLocation"))
                                {
                                    wsConfig.wsdlLocation = attribute.Value;
                                }
                                else if (attribute.Name.Equals("connectorConfig"))
                                {
                                    wsConfig.WsconnectorConfig = attribute.Value;
                                }
                            }
                        }
                        else if (!fileName.Contains("global") && !fileName.Contains("api"))
                        {
                            continue;
                        }
                        Console.WriteLine(attribute.Name + " -> " + attribute.Value);
                        //nodeMap[node.Name][attribute.Name] = attribute.Value;
                        if (i == AttributeCount && node.Name.StartsWith("db:"))
                        {
                            document.GlobalResources.DbConfig.Add(dbConfig);
                        }

                        if (i == AttributeCount && node.Name.StartsWith("ws:"))
                        {
                            document.GlobalResources.WebServiceConfig.Add(wsConfig);
                        }
                    }

                    if (node.HasChildNodes)
                    {
                        tag.hasChildTag = true;

                        tag.childTagList = new List <ChildTag>();

                        XmlNodeList childNodes = node.ChildNodes;

                        foreach (XmlNode childNode in childNodes)
                        {
                            ChildTag childTag = new ChildTag();
                            XmlAttributeCollection childAttributes = childNode.Attributes;
                            if (childAttributes != null)
                            {
                                Console.WriteLine("\n");

                                if (childAttributes.Count == 0)
                                {
                                    break;
                                }

                                childTag.childTagname = childNode.Name;

                                // Console.WriteLine("Child node name: " + childNode.Name);
                                //Console.WriteLine("+++++++++++++++");

                                childTag.childTagCount = childAttributes.Count;
                                //else
                                //{
                                childTag.childAttributeKeyValue = new Dictionary <string, string>();
                                foreach (XmlAttribute attribute in childAttributes)
                                {
                                    Console.WriteLine(attribute.Name + " -> " + attribute.Value);
                                    childTag.childAttributeKeyValue.Add(attribute.Name, attribute.Value);



                                    //ADDITIONAL CHILD NODE CONDITION FOR GLOBAL.XML FILE
                                    if (attribute.Name.Equals("name") && fileName.Contains("global"))
                                    {
                                        childTag.childTagname = childNode.Name + " (" + attribute.Value + ")";
                                    }

                                    if (childNode.Name.Equals("db:select"))
                                    {
                                        if (attribute.Name.Equals("config-ref") && attribute.Value.Equals("Oracle_Configuration_BANNER", StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            if (childNode.HasChildNodes)
                                            {
                                                if (!childNode.InnerText.Equals("#[payload]", StringComparison.InvariantCultureIgnoreCase))
                                                {
                                                    XmlNodeList childOfChildNodes = childNode.ChildNodes;
                                                    foreach (XmlNode childofChildNode in childOfChildNodes)
                                                    {
                                                        //Console.WriteLine(childofChildNode.InnerText);
                                                        //Console.WriteLine(childofChildNode.Name);
                                                        if (childofChildNode.Name.Equals("db:parameterized-query"))
                                                        {
                                                            var     sqlQuery = childNode.InnerText;
                                                            SqlData sqlData  = await Run(sqlQuery);

                                                            sqlData.databaseType = attribute.Value;
                                                            sqlData.operation    = childNode.Name;
                                                            SqlData.Add(sqlData);
                                                            //Task.Run(() => Run(sqlQuery)).Wait();
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    else if (childNode.Name.Equals("db:stored-procedure") && attribute.Name.Equals("config-ref") && attribute.Value.Equals("Oracle_Configuration_BANNER", StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        if (childNode.HasChildNodes && !childNode.InnerText.Equals("#[payload]", StringComparison.InvariantCultureIgnoreCase))
                                        {
                                            XmlNodeList childOfChildNodes = childNode.ChildNodes;
                                            foreach (XmlNode childofChildNode in childOfChildNodes)
                                            {
                                                if (childofChildNode.Name.Equals("db:parameterized-query"))
                                                {
                                                    SqlData sqlData = new SqlData();
                                                    sqlData.isStoredProcedure = true;
                                                    sqlData.storedProcedure   = childNode.InnerText;
                                                    sqlData.databaseType      = attribute.Value;
                                                    sqlData.operation         = childNode.Name;
                                                    SqlData.Add(sqlData);
                                                }
                                            }
                                        }
                                    }

                                    //CONDITION FOR CHILD NODES
                                    if (childNode.HasChildNodes)
                                    {
                                        childTag.hasGrandchildTag = true;

                                        childTag.grandchildTagList = new List <GrandchildTag>();

                                        XmlNodeList grandchildNodes = childNode.ChildNodes;

                                        foreach (XmlNode grandchildNode in grandchildNodes)
                                        {
                                            GrandchildTag          grandchildTag        = new GrandchildTag();
                                            XmlAttributeCollection grandchildAttributes = grandchildNode.Attributes;
                                            if (grandchildAttributes != null)
                                            {
                                                Console.WriteLine("\n");

                                                if (grandchildAttributes.Count == 0)
                                                {
                                                    break;
                                                }

                                                grandchildTag.grandchildTagname = grandchildNode.Name;

                                                // Console.WriteLine("Child node name: " + childNode.Name);
                                                //Console.WriteLine("+++++++++++++++");

                                                grandchildTag.grandchildTagCount = grandchildAttributes.Count;
                                                //else
                                                //{
                                                grandchildTag.grandchildAttributeKeyValue = new Dictionary <string, string>();
                                                foreach (XmlAttribute gcAttribute in grandchildAttributes)
                                                {
                                                    Console.WriteLine(gcAttribute.Name + " -> " + gcAttribute.Value);
                                                    grandchildTag.grandchildAttributeKeyValue.Add(gcAttribute.Name, gcAttribute.Value);
                                                }
                                            }
                                            childTag.grandchildTagList.Add(grandchildTag);
                                        }
                                    }
                                }
                                document.SqlData = SqlData;
                            }
                            tag.childTagList.Add(childTag);
                        }
                    }

                    Console.WriteLine("\n");
                    if (tag.attributeKeyValue.Count > 0)
                    {
                        document.Tags.Add(tag);
                    }
                }
            }
            return(document);
        }