예제 #1
0
        /// <summary>
        /// Validates an XML file againts the XesExt schema
        /// </summary>
        /// <returns>The validate.</returns>
        /// <param name="location">A file name or a URI.</param>
        protected bool Validate(string location)
        {
            XmlDocument doc = new XmlDocument();

            doc.Load(location);
            doc.Schemas.Add(schema);
            try
            {
                doc.Validate((sender, evt) =>
                {
                    if (evt.Severity == XmlSeverityType.Error)
                    {
                        XLogging.Log(String.Format("XML validation error: {0}", evt.Message), XLogging.Importance.ERROR);
                    }
                    else
                    {
                        XLogging.Log(String.Format("XML validation warning: {0}", evt.Message), XLogging.Importance.WARNING);
                    }
                });
                return(true);
            }
            catch (Exception e)
            {
                XLogging.Log(e.Message, XLogging.Importance.ERROR);
                return(false);
            }
        }
예제 #2
0
        protected async System.Threading.Tasks.Task CacheExtensionAsync(Uri uri)
        {
            String uriStr = uri.ToString().ToLower();

            if (uriStr.EndsWith("/", StringComparison.Ordinal))
            {
                uriStr = uriStr.Substring(0, uriStr.Length - 1);
            }
            String fileName = uriStr.Substring(uriStr.LastIndexOf("/", StringComparison.Ordinal));

            if (!(fileName.EndsWith(".xesext", StringComparison.CurrentCulture)))
            {
                fileName = fileName + ".xesext";
            }
            FileStream cacheFile = File.Create(Path.Combine(XRuntimeUtils.GetExtensionCacheFolder(), fileName));
            Stream     fs;

            try
            {
                HttpClient client = new HttpClient();
                fs = await client.GetStreamAsync(uri).ConfigureAwait(false);

                await fs.CopyToAsync(cacheFile);

                cacheFile.Flush();
            }
            catch (Exception e)
            {
                XLogging.Log(e.Message, XLogging.Importance.ERROR);
                throw e;
            }
        }
예제 #3
0
 public DateTime?ExtractTimestamp(XEvent evt)
 {
     try{
         return(((XAttributeTimestamp)evt.GetAttributes()[QualifiedName(KEY_TIMESTAMP)]).Value);
     }catch (KeyNotFoundException) {
         XLogging.Log("Key '" + QualifiedName(KEY_TIMESTAMP) + "' not available", XLogging.Importance.WARNING);
         return(null);
     }
 }
예제 #4
0
        public XExtension GetByUri(Uri uri)
        {
            if (!this.extensionMap.ContainsKey(uri))
            {
                XLogging.Log(String.Format("Extension with uri '{0}' not regiesterd. Attempting download...", uri), XLogging.Importance.INFO);
                this.Register(XExtensionParser.Instance.Parse(uri));
            }
            XExtension extension = this.extensionMap[uri];

            return(extension);
        }
예제 #5
0
 public XID ExtractID(IXAttributable element)
 {
     try
     {
         return(((XAttributeID)element.GetAttributes()[QualifiedName(KEY_ID)]).Value);
     }
     catch (KeyNotFoundException)
     {
         XLogging.Log("Key '" + QualifiedName(KEY_ID) + "' not available", XLogging.Importance.WARNING);
         return(null);
     }
 }
예제 #6
0
 public string ExtractInstance(XEvent evt)
 {
     try
     {
         return(((XAttributeLiteral)evt.GetAttributes()[QualifiedName(KEY_INSTANCE)]).Value);
     }
     catch (KeyNotFoundException)
     {
         XLogging.Log("Key '" + QualifiedName(KEY_INSTANCE) + "' not available", XLogging.Importance.WARNING);
         return(null);
     }
 }
예제 #7
0
 public string ExtractName(IXElement element)
 {
     try
     {
         return(((XAttributeLiteral)element.GetAttributes()[QualifiedName(KEY_NAME)]).Value);
     }
     catch (KeyNotFoundException)
     {
         XLogging.Log("Key '" + KEY_NAME + "' not available", XLogging.Importance.WARNING);
         return(null);
     }
 }
예제 #8
0
 public string Get(string key)
 {
     try
     {
         return(this[key]);
     }
     catch (KeyNotFoundException)
     {
         XLogging.Log(String.Format("The key '{0}' is nor registered", key), XLogging.Importance.WARNING);
         return(null);
     }
 }
예제 #9
0
 /// <summary>
 /// Registers a mapping for a given attribute.
 /// </summary>
 /// <param name="attributeKey">Attribute key for which to register a mapping.</param>
 /// <param name="alias">Alias string to map the attribute to.</param>
 public void RegisterMapping(string attributeKey, string alias)
 {
     lock (this)
     {
         try
         {
             this.Add(attributeKey, alias);
         }
         catch (ArgumentException)
         {
             XLogging.Log(String.Format("Mapping '{0}->{1}'already exists. Skipping register process", attributeKey, alias), XLogging.Importance.WARNING);
         }
     }
 }
예제 #10
0
        protected void LoadExtensionCache()
        {
            long          minModified = DateTime.Now.Ticks - 2592000000L;
            DirectoryInfo extFolder   = Directory.CreateDirectory(XRuntimeUtils.GetExtensionCacheFolder());

            FileInfo[] extFiles = extFolder.GetFiles();
            if (extFiles == null)
            {
                XLogging.Log("Extension caching disabled (Could not access cache directory)!", XLogging.Importance.WARNING);

                return;
            }
            foreach (FileInfo extFile in extFiles)
            {
                if (!(extFile.FullName.ToLower().EndsWith(".xesext", StringComparison.Ordinal)))
                {
                    continue;
                }

                if (extFile.LastWriteTime.Ticks < minModified)
                {
                    extFile.Delete();
                }
                else
                {
                    try
                    {
                        XExtension extension = XExtensionParser.Instance.Parse(extFile);
                        if (!(this.extensionMap.ContainsKey(extension.Uri)))
                        {
                            this.extensionMap.Add(extension.Uri, extension);
                            this.extensionList.Add(extension);
                            XLogging.Log("Loaded XES extension '" + extension.Uri + "' from cache",
                                         XLogging.Importance.DEBUG);
                        }
                        else
                        {
                            XLogging.Log("Skipping cached XES extension '" + extension.Uri + "' (already defined)",
                                         XLogging.Importance.DEBUG);
                        }
                    }
                    catch (Exception e)
                    {
                        XLogging.Log(e.Message, XLogging.Importance.ERROR);
                        throw e;
                    }
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Creates a clone of this ID.
        /// </summary>
        /// <returns>The clone.</returns>
        public object Clone()
        {
            XID clone;

            try
            {
                clone = (XID)MemberwiseClone();
            }
            catch (NotSupportedException e)
            {
                XLogging.Log(e.Message, XLogging.Importance.ERROR);
                clone = null;
            }
            return(clone);
        }
예제 #12
0
 public object Clone()
 {
     try
     {
         XAttributeMapLazy <T> clone = (XAttributeMapLazy <T>)MemberwiseClone();
         if (this.backingStore != null)
         {
             clone.backingStore = ((T)this.backingStore.Clone());
         }
         return(clone);
     }
     catch (NotSupportedException e)
     {
         XLogging.Log(e.Message, XLogging.Importance.ERROR);
     }
     return(null);
 }
예제 #13
0
        /// <summary>
        /// Parse the specified datetimeString.
        /// </summary>
        /// <returns>The object containing the value of the specified datetime.</returns>
        /// <param name="datetimeString">Datetime string.</param>
        public static DateTime Parse(string datetimeString)
        {
            string[] formats = { "yyyy-MM-ddTHH:mm:ss.FFFFFZ", "yyyy-MM-ddTHH:mm:ss.FFFFFK",
                                 "yyyy-MM-ddTHH:mm:ss:FFFFFZ", "yyyy-MM-ddTHH:mm:ss:FFFFFK" };
            DateTime d;

            try
            {
                d = XmlConvert.ToDateTime(datetimeString, formats).ToUniversalTime();
            }
            catch (Exception e)
            {
                XLogging.Log("Could not parse the string '" + datetimeString + "'", XLogging.Importance.WARNING);
                throw e;
            }

            return(d);
        }
예제 #14
0
        public void Serialize(IXLog log, Stream stream)
        {
            XLogging.Log("Start serializing log to XES.XML", XLogging.Importance.DEBUG);

            long        start = DateTime.Now.Ticks;
            XmlDocument doc   = new XmlDocument();

            doc.AppendChild(doc.CreateComment("This file has been generated with the OpenXES.Net library. It conforms"));
            doc.AppendChild(doc.CreateComment("to the XML serialization of the XES standard for log storage and management."));
            doc.AppendChild(doc.CreateComment("XES standard version: 2.0"));
            doc.AppendChild(doc.CreateComment(String.Format("OpenXES.Net library version: {0}", openXesNetVersion)));
            doc.AppendChild(doc.CreateComment("OpenXES is available from http://www.openxes.org/")); // TODO: update this string

            XmlNode logNode = doc.CreateElement("log");

            doc.AppendChild(logNode);

            // Log metadata
            XmlAttribute xesNetVersion = doc.CreateAttribute("openxesnet.version");

            xesNetVersion.Value = String.Format("{0}", openXesNetVersion);
            logNode.Attributes.Append(xesNetVersion);

            XmlAttribute xesVersion = doc.CreateAttribute("xes.version");

            xesVersion.Value = ((XLog)log).Version;
            logNode.Attributes.Append(xesVersion);

            XmlAttribute xesFeatures = doc.CreateAttribute("xes.features");

            xesFeatures.Value = ((XLog)log).Features;
            logNode.Attributes.Append(xesFeatures);

            // Log extensions
            foreach (XExtension extension in log.Extensions)
            {
                XmlNode extNode = doc.CreateElement("extension");

                XmlAttribute name = doc.CreateAttribute("name");
                name.Value = extension.Name;
                extNode.Attributes.Append(name);

                XmlAttribute prefix = doc.CreateAttribute("prefix");
                prefix.Value = extension.Prefix;
                extNode.Attributes.Append(prefix);

                XmlAttribute uri = doc.CreateAttribute("uri");
                uri.Value = extension.Uri.ToString();
                extNode.Attributes.Append(uri);

                logNode.AppendChild(extNode);
            }

            // Global attributes: we add this tag and subtags only if present

            /*
             * if (log.GlobalEventAttributes.Count > 0 || log.GlobalTraceAttributes.Count > 0)
             * {
             *  XmlNode globalNode = doc.CreateElement("global");
             *  logNode.AppendChild(globalNode);
             *
             *  if (log.GlobalTraceAttributes.Count > 0)
             *  {
             *      XmlNode globalTraceNode = doc.CreateElement("trace");
             *      globalNode.AppendChild(globalTraceNode);
             *      AddAttributes(doc, globalTraceNode, log.GlobalTraceAttributes);
             *  }
             *
             *  if (log.GlobalEventAttributes.Count > 0)
             *  {
             *      XmlNode globalEventNode = doc.CreateElement("event");
             *      globalNode.AppendChild(globalEventNode);
             *      AddAttributes(doc, globalEventNode, log.GlobalEventAttributes);
             *  }
             * }*/

            if (log.GlobalEventAttributes.Count > 0)
            {
                XmlNode      globalEventNode = doc.CreateElement("global");
                XmlAttribute scope           = doc.CreateAttribute("scope");
                scope.Value = "event";
                globalEventNode.Attributes.Append(scope);

                logNode.AppendChild(globalEventNode);
                AddAttributes(doc, globalEventNode, log.GlobalEventAttributes);
            }

            if (log.GlobalTraceAttributes.Count > 0)
            {
                XmlNode      globalTraceNode = doc.CreateElement("global");
                XmlAttribute scope           = doc.CreateAttribute("scope");
                scope.Value = "trace";
                globalTraceNode.Attributes.Append(scope);

                logNode.AppendChild(globalTraceNode);
                AddAttributes(doc, globalTraceNode, log.GlobalTraceAttributes);
            }

            foreach (IXEventClassifier classifier in log.Classifiers)
            {
                if (classifier is XEventAttributeClassifier)
                {
                    XEventAttributeClassifier attrClass = (XEventAttributeClassifier)classifier;
                    XmlNode      clsNode = doc.CreateElement("classifier");
                    XmlAttribute name    = doc.CreateAttribute("name");
                    name.Value = ((XEventAttributeClassifier)classifier).Name;
                    clsNode.Attributes.Append(name);
                    XmlAttribute keys = doc.CreateAttribute("keys");
                    keys.Value = XTokenHelper.FormatTokenString(new List <string>(attrClass.DefiningAttributeKeys));
                    clsNode.Attributes.Append(keys);
                }
            }

            // Log attributes
            AddAttributes(doc, logNode, log.GetAttributes().AsList());

            // Log traces
            foreach (XTrace trace in log)
            {
                XmlNode traceNode = doc.CreateElement("trace");
                logNode.AppendChild(traceNode);

                // Trace attributes
                AddAttributes(doc, traceNode, trace.GetAttributes().AsList());

                // Trace events
                foreach (XEvent evt in trace)
                {
                    // Event attributes
                    XmlNode eventNode = doc.CreateElement("event");
                    traceNode.AppendChild(eventNode);
                    AddAttributes(doc, eventNode, evt.GetAttributes().AsList());
                }
            }

            // Save the doc
            doc.Save(stream);

            string duration = " (" + (new TimeSpan(DateTime.Now.Ticks - start)).TotalMilliseconds + " msec.)";

            XLogging.Log("Finished serializing log" + duration, XLogging.Importance.DEBUG);
        }
예제 #15
0
        protected XExtension Parse(XmlReader reader)
        {
            XExtension extension        = null;
            XAttribute currentAttribute = null;
            Dictionary <string, XAttribute> xAttributes = null;
            IXFactory factory = XFactoryRegistry.Instance.CurrentDefault;

            while (reader.Read())
            {
                // When a start tag is found
                if (reader.IsStartElement())
                {
                    string tagName = reader.LocalName;
                    if (tagName.Equals("", StringComparison.CurrentCultureIgnoreCase))
                    {
                        tagName = reader.Name;
                    }

                    if (tagName.Equals("xesextension", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string xName   = reader.GetAttribute("name");
                        string xPrefix = reader.GetAttribute("prefix");
                        Uri    xUri    = null;
                        try
                        {
                            xUri = new Uri(reader.GetAttribute("uri"));
                        }
                        catch (UriFormatException e)
                        {
                            XLogging.Log(e.Message, XLogging.Importance.ERROR);
                            throw e;
                        }
                        extension = new XExtension(xName, xPrefix, xUri);
                    }
                    else if (tagName.Equals("log", StringComparison.CurrentCultureIgnoreCase))
                    {
                        xAttributes = extension.LogAttributes;
                    }
                    else if (tagName.Equals("trace", StringComparison.CurrentCultureIgnoreCase))
                    {
                        xAttributes = extension.TraceAttributes;
                    }
                    else if (tagName.Equals("event", StringComparison.CurrentCultureIgnoreCase))
                    {
                        xAttributes = extension.EventAttributes;
                    }
                    else if (tagName.Equals("meta", StringComparison.CurrentCultureIgnoreCase))
                    {
                        xAttributes = extension.MetaAttributes;
                    }
                    else if (tagName.Equals("string", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string key = reader.GetAttribute("key");
                        currentAttribute = factory.CreateAttributeLiteral(key, "DEFAULT", extension);
                        xAttributes.Add(key, currentAttribute);
                    }
                    else if (tagName.Equals("date", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string key = reader.GetAttribute("key");
                        currentAttribute = factory.CreateAttributeTimestamp(key, 0L, extension);
                        xAttributes.Add(key, currentAttribute);
                    }
                    else if (tagName.Equals("int", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string key = reader.GetAttribute("key");
                        currentAttribute = factory.CreateAttributeDiscrete(key, 0L, extension);
                        xAttributes.Add(key, currentAttribute);
                    }
                    else if (tagName.Equals("float", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string key = reader.GetAttribute("key");
                        currentAttribute = factory.CreateAttributeContinuous(key, 0.0D, extension);
                        xAttributes.Add(key, currentAttribute);
                    }
                    else if (tagName.Equals("boolean", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string key = reader.GetAttribute("key");
                        currentAttribute = factory.CreateAttributeBoolean(key, false, extension);
                        xAttributes.Add(key, currentAttribute);
                    }
                    else if (tagName.Equals("id", StringComparison.CurrentCultureIgnoreCase))
                    {
                        string key = reader.GetAttribute("key");
                        currentAttribute = factory.CreateAttributeID(key, XIDFactory.Instance.CreateId(),
                                                                     extension);
                        xAttributes.Add(key, currentAttribute);
                    }
                    else if (tagName.Equals("alias", StringComparison.CurrentCultureIgnoreCase) && currentAttribute != null)
                    {
                        string mapping = reader.GetAttribute("mapping");
                        string name    = reader.GetAttribute("name");
                        XGlobalAttributeNameMap.Instance.RegisterMapping(mapping, currentAttribute.Key, name);
                    }
                    else
                    {
                        // non supported tag
                        XLogging.Log(String.Format("Non-supported tag '{0}' found. Ignoring it.", tagName), XLogging.Importance.TRACE);
                    }
                }
                // When a close tag is found (including empty elements)
                if (reader.IsEmptyElement || !reader.IsStartElement())
                {
                    string tagName = reader.LocalName;
                    if (tagName.Equals("", StringComparison.InvariantCultureIgnoreCase))
                    {
                        tagName = reader.Name;
                    }
                    if (ATTRIBUTE_TYPES.Contains(tagName.Trim().ToLower()))
                    {
                        currentAttribute = null;
                    }
                }
            }
            return(extension);
        }
예제 #16
0
        public override IXLog Parse(Stream stream)
        {
            Stack <IXAttributable> attributableStack = new Stack <IXAttributable>();
            Stack <XAttribute>     attributeStack    = new Stack <XAttribute>();
            IXEvent           evt     = null;
            IXLog             log     = null;
            IXTrace           trace   = null;
            List <XAttribute> globals = null;

            using (XmlReader reader = XmlReader.Create(stream))
            {
                List <string> ATTR_TYPE_TAGS = new List <string>(new string[] { "string", "date", "int", "float", "boolean", "id", "list", "container" });
                ATTR_TYPE_TAGS.Sort();

                while (reader.Read())
                {
                    if (reader.IsStartElement())
                    {
                        // start tag found
                        string tagName = reader.LocalName.Trim();
                        if (tagName.Length == 0)
                        {
                            tagName = reader.Name.Trim(); // <= qualified name
                        }


                        if (ATTR_TYPE_TAGS.Contains(tagName.ToLower()))
                        {
                            // The tag is an attribute
                            string     key        = reader.GetAttribute("key") ?? "";
                            string     val        = reader.GetAttribute("value") ?? "";
                            XExtension ext        = null;
                            int        colonindex = key.IndexOf(":", StringComparison.InvariantCultureIgnoreCase);
                            if (colonindex > 0)
                            {
                                string prefix = key.Substring(0, colonindex);
                                ext = XExtensionManager.Instance.GetByPrefix(prefix);
                            }

                            XAttribute attr = null;
                            switch (tagName)
                            {
                            case "string":
                                attr = factory.CreateAttributeLiteral(key, val, ext);
                                break;

                            case "int":
                                attr = factory.CreateAttributeDiscrete(key, long.Parse(val), ext);
                                break;

                            case "boolean":
                                attr = factory.CreateAttributeBoolean(key, bool.Parse(val), ext);
                                break;

                            case "date":
                                DateTime d = XAttributeTimestamp.Parse(val);
                                attr = factory.CreateAttributeTimestamp(key, d, ext);
                                break;

                            case "float":
                                attr = factory.CreateAttributeContinuous(key, double.Parse(val), ext);
                                break;

                            case "id":
                                attr = factory.CreateAttributeID(key, XID.Parse(val), ext);
                                break;

                            case "list":
                                attr = factory.CreateAttributeList(key, ext);
                                break;

                            case "container":
                                attr = factory.CreateAttributeContainer(key, ext);
                                break;

                            default:
                                XLogging.Log("Unknown tag '" + tagName + "'", XLogging.Importance.WARNING);
                                break;
                            }
                            if (reader.IsEmptyElement)
                            {
                                // No child nodes, we can directly store it
                                if (globals != null)
                                {
                                    // attribute is global
                                    globals.Add(attr);
                                }
                                else
                                {
                                    attributableStack.Peek().GetAttributes().Add(attr.Key, attr);

                                    if ((!(attributeStack.Count == 0)) &&
                                        (attributeStack.Peek() is XAttributeCollection))
                                    {
                                        ((XAttributeCollection)attributeStack.Peek()).AddToCollection(attr);
                                    }
                                }
                            }
                            else if (attr != null)
                            {
                                attributeStack.Push(attr);
                                attributableStack.Push((IXAttributable)attr);
                            }
                        }
                        else if ("event".Equals(tagName.ToLower()))
                        {
                            // Parse an event
                            evt = factory.CreateEvent();
                            attributableStack.Push(evt);
                        }
                        else if ("trace".Equals(tagName.ToLower()))
                        {
                            trace = factory.CreateTrace();
                            attributableStack.Push(trace);
                        }
                        else if ("log".Equals(tagName.ToLower()))
                        {
                            log = factory.CreateLog();
                            ((XLog)log).Version  = reader.GetAttribute("xes.version") ?? "2.0";
                            ((XLog)log).Features = reader.GetAttribute("xes.features") ?? "";
                            attributableStack.Push(log);
                        }
                        else if ("extension".Equals(tagName.ToLower()))
                        {
                            XExtension extension = null;
                            String     uriString = reader.GetAttribute("uri");
                            if (uriString != null)
                            {
                                extension = XExtensionManager.Instance.GetByUri(new UriBuilder(uriString).Uri);
                            }
                            else
                            {
                                string prefixString = reader.GetAttribute("prefix");
                                if (prefixString != null)
                                {
                                    extension = XExtensionManager.Instance.GetByPrefix(prefixString);
                                }
                            }

                            if (extension != null)
                            {
                                log.Extensions.Add(extension);
                            }
                            else
                            {
                                XLogging.Log("Unknown extension: " + uriString, XLogging.Importance.ERROR);
                            }
                        }
                        else if ("global".Equals(tagName.ToLower()))
                        {
                            string scope = reader.GetAttribute("scope");
                            if (scope.Equals("trace"))
                            {
                                globals = log.GlobalTraceAttributes;
                            }
                            else if (scope.Equals("event"))
                            {
                                globals = log.GlobalEventAttributes;
                            }
                        }
                        else if ("classifier".Equals(tagName.ToLower()))
                        {
                            string name = reader.GetAttribute("name");
                            string keys = reader.GetAttribute("keys");
                            if ((name == null) || (keys == null) || (name.Length <= 0) || (keys.Length <= 0))
                            {
                                continue;
                            }
                            IList <string> keysList = FixKeys(log, XTokenHelper.ExtractTokens(keys));

                            string[] keysArray = new string[keysList.Count];
                            int      i         = 0;
                            foreach (string key in keysList)
                            {
                                keysArray[(i++)] = key;
                            }
                            IXEventClassifier classifier = new XEventAttributeClassifier(name, keysArray);

                            log.Classifiers.Add(classifier);
                        }
                    }
                    else
                    {
                        // end tag found
                        string tagName = reader.LocalName.Trim().ToLower();
                        if (tagName.Length == 0)
                        {
                            tagName = reader.Name.Trim().ToLower(); // <= qualified name
                        }

                        if ("global".Equals(tagName))
                        {
                            globals = null;
                        }
                        else if (ATTR_TYPE_TAGS.Contains(tagName))
                        {
                            XAttribute attribute = attributeStack.Pop();
                            attributableStack.Pop();
                            if (globals != null)
                            {
                                globals.Add(attribute);
                            }
                            else
                            {
                                attributableStack.Peek().GetAttributes().Add(attribute.Key, attribute);

                                if ((!(attributeStack.Count == 0)) &&
                                    (attributeStack.Peek() is XAttributeCollection))
                                {
                                    ((XAttributeCollection)attributeStack.Peek()).AddToCollection(attribute);
                                }
                            }
                        }
                        else if ("event".Equals(tagName))
                        {
                            trace.Add(evt);
                            evt = null;
                            attributableStack.Pop();
                        }
                        else if ("trace".Equals(tagName))
                        {
                            log.Add(trace);
                            trace = null;
                            attributableStack.Pop();
                        }
                        else if ("log".Equals(tagName))
                        {
                            attributableStack.Pop();
                        }
                    }
                }
            }
            return(log);
        }