コード例 #1
0
ファイル: StatisticsHandler.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Executes 'GetStats' command.
        /// </summary>
        private string GetStats(SimpleHttpContext context)
        {
            StringBuilder json = new StringBuilder();

            try
            {
                using (SimpleJsonWriter writer = new SimpleJsonWriter(json))
                {
                    writer.WriteStartObject();
                    WriteServiceObject(writer, true);
                    WriteDeviceObject(writer);
                    WriteRequestObject(writer, context);
                    foreach (IStatsWriter stats in _statsWriters)
                    {
                        stats.WriteRuntimeStatistics(writer);
                    }
                    writer.WriteEndObject();
                }
            }
            catch (Exception ex)
            {
                _errorHandler?.LogError(ex);
                return(WriteFatalResponse(context, ex));
            }
            return(json.ToString());
        }
コード例 #2
0
        /// <summary>
        /// Writes runtime statistics.
        /// </summary>
        public void WriteRuntimeStatistics(SimpleJsonWriter writer)
        {
            try
            {
                List <ErrorCacheItem> errorStats = GetErrorReport();

                writer.WriteStartArray("errorStats");
                foreach (ErrorCacheItem errorItem in errorStats)
                {
                    writer.WriteStartObject();
                    writer.WritePropertyValue("count", errorItem.Count);
                    writer.WritePropertyValue("cpm", Math.Round(errorItem.CountPerMinute, 1));
                    writer.WritePropertyValue("type", errorItem.Error.Type ?? "");
                    writer.WritePropertyValue("message", errorItem.Error.Message ?? "");
                    writer.WritePropertyValue("stackTrace", errorItem.Error.StackTrace ?? "");
                    writer.WriteEndObject();
                }
                writer.WriteEndArray();
            }
            catch (Exception ex)
            {
                if (_errorHandler != null)
                {
                    _errorHandler.LogError(ex);
                }
            }
        }
コード例 #3
0
        public static void SetupBondJson(
            out Action <object, ChunkedMemoryStream> serialize,
            out Func <ChunkedMemoryStream, Type, object> deserialize)
        {
            var serializers   = new Dictionary <Type, Bond.Serializer <SimpleJsonWriter> >();
            var deserializers = new Dictionary <Type, Bond.Deserializer <SimpleJsonReader> >();

            serialize = (obj, stream) =>
            {
                var jsonWriter = new SimpleJsonWriter(stream);
                var type       = obj.GetType();
                Bond.Serializer <SimpleJsonWriter> serializer;
                if (!serializers.TryGetValue(type, out serializer))
                {
                    serializers[type] = serializer = new Bond.Serializer <SimpleJsonWriter>(type);
                }
                serializer.Serialize(obj, jsonWriter);
                jsonWriter.Flush();
            };
            deserialize = (stream, type) =>
            {
                var reader = new SimpleJsonReader(stream);
                Bond.Deserializer <SimpleJsonReader> deserializer;
                if (!deserializers.TryGetValue(type, out deserializer))
                {
                    deserializers[type] = deserializer = new Bond.Deserializer <SimpleJsonReader>(type);
                }
                return(deserializer.Deserialize(reader));
            };
        }
コード例 #4
0
ファイル: Heartbeat.cs プロジェクト: jon-hyland/rpi
            public string ToJson()
            {
                StringBuilder sb = new StringBuilder();

                using (SimpleJsonWriter writer = new SimpleJsonWriter(sb, true))
                {
                    writer.WriteStartObject();
                    writer.WritePropertyValue("serial", Serial);
                    writer.WritePropertyValue("name", Name);
                    writer.WritePropertyValue("version", Version);
                    writer.WritePropertyValue("httpPort", HttpPort);
                    writer.WritePropertyValue("runningSecs", (int)RunningTime.TotalSeconds);
                    writer.WritePropertyValue("serviceState", ServiceState);
                    writer.WriteStartArray("interfaces");
                    foreach (Interface i in Interfaces)
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyValue("name", i.Name);
                        writer.WritePropertyValue("physical", i.PhysicalAddress);
                        writer.WritePropertyValue("internet", i.InternetAddress);
                        writer.WriteEndObject();
                    }
                    writer.WriteEndArray();
                    writer.WriteEndObject();
                }
                return(sb.ToString());
            }
コード例 #5
0
ファイル: GpioHandler.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Executes 'Read' command.
        /// </summary>
        private string Read(SimpleHttpContext context)
        {
            StringBuilder json = new StringBuilder();

            try
            {
                string input1 = _gpio.GetBank(BankType.Input1);
                string input2 = _gpio.GetBank(BankType.Input2);
                string output = _gpio.GetBank(BankType.Output);

                using (SimpleJsonWriter writer = new SimpleJsonWriter(json))
                {
                    writer.WriteStartObject();
                    WriteServiceObject(writer, true);
                    WriteDeviceObject(writer);
                    WriteRequestObject(writer, context);
                    writer.WriteStartObject("output");
                    writer.WritePropertyValue("success", 1);
                    writer.WritePropertyValue("input1", input1);
                    writer.WritePropertyValue("input2", input2);
                    writer.WritePropertyValue("output", output);
                    writer.WriteEndObject();
                    writer.WriteEndObject();
                }
            }
            catch (Exception ex)
            {
                _errorHandler?.LogError(ex);
                return(WriteFatalResponse(context, ex));
            }
            return(json.ToString());
        }
コード例 #6
0
ファイル: GpioHandler.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Executes 'Write' command.
        /// </summary>
        private string Write(SimpleHttpContext context)
        {
            StringBuilder json = new StringBuilder();

            try
            {
                string output = context.Query.Get("output");
                if (String.IsNullOrWhiteSpace(output))
                {
                    throw new Exception("Parameter 'output' missing or invalid");
                }
                _gpio.SetBank(BankType.Output, output);

                using (SimpleJsonWriter writer = new SimpleJsonWriter(json))
                {
                    writer.WriteStartObject();
                    WriteServiceObject(writer, true);
                    WriteDeviceObject(writer);
                    WriteRequestObject(writer, context);
                    writer.WriteStartObject("output");
                    writer.WritePropertyValue("success", 1);
                    writer.WriteEndObject();
                    writer.WriteEndObject();
                }
            }
            catch (Exception ex)
            {
                _errorHandler?.LogError(ex);
                return(WriteFatalResponse(context, ex));
            }
            return(json.ToString());
        }
コード例 #7
0
        public override void Serialize(object serializable, Stream outputStream)
        {
            Initialize();
            var writer = new SimpleJsonWriter(outputStream);

            _serializer.Serialize(serializable, writer);
        }
コード例 #8
0
ファイル: HandlerBase.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Writes fatal error response as JSON if command execution failed completely.
        /// </summary>
        protected string WriteFatalResponse(SimpleHttpContext context, Exception ex)
        {
            StringBuilder json = new StringBuilder();

            try
            {
                using (SimpleJsonWriter writer = new SimpleJsonWriter(json))
                {
                    writer.WriteStartObject();
                    WriteServiceObject(writer);
                    WriteDeviceObject(writer);
                    WriteRequestObject(writer, context);
                    writer.WriteStartObject("output");
                    writer.WritePropertyValue("success", 0);
                    writer.WritePropertyValue("code", 1);
                    writer.WritePropertyValue("message", ex.Message ?? "A fatal error occurred");
                    writer.WriteEndObject();
                    WriteErrorsObject(writer, new List <Exception>()
                    {
                        ex
                    });
                    writer.WriteEndObject();
                }
            }
            catch (Exception exx)
            {
                _errorHandler?.LogError(exx);
            }
            return(json.ToString());
        }
コード例 #9
0
ファイル: Program.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Saves entries file.
        /// </summary>
        private static void WriteEntriesFile()
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                using (SimpleJsonWriter writer = new SimpleJsonWriter(sb))
                {
                    writer.WriteStartObject();
                    writer.WriteStartArray("entries");
                    foreach (Entry entry in _entries)
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyValue("ip", entry.IP);
                        writer.WritePropertyValue("host", entry.Host);
                        writer.WritePropertyValue("mac", entry.Mac);
                        writer.WriteEndObject();
                    }
                    writer.WriteEndArray();
                    writer.WriteEndObject();
                }

                Console.WriteLine($"Writing file {EntriesFile}");
                File.WriteAllText(EntriesFile, sb.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception($"Unable to save file {EntriesFile}", ex);
            }
        }
コード例 #10
0
ファイル: PiInfo.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Writes runtime stats.
        /// </summary>
        public void WriteRuntimeStatistics(SimpleJsonWriter writer)
        {
            if (!_config.IsLinux)
            {
                return;
            }

            writer.WriteStartObject("pi");
            writer.WritePropertyValue("boardModel", Pi.Info.BoardModel.ToString());
            writer.WritePropertyValue("boardRevision", Pi.Info.BoardRevision);
            writer.WritePropertyValue("cpuArchitecture", Pi.Info.CpuArchitecture);
            writer.WritePropertyValue("cpuImplementer", Pi.Info.CpuImplementer);
            writer.WritePropertyValue("cpuPart", Pi.Info.CpuPart);
            writer.WritePropertyValue("cpuRevision", Pi.Info.CpuRevision);
            writer.WritePropertyValue("cpuVariant", Pi.Info.CpuVariant);
            writer.WritePropertyValue("features", String.Join(", ", Pi.Info.Features));
            writer.WritePropertyValue("hardware", Pi.Info.Hardware);
            writer.WritePropertyValue("installedRam", Pi.Info.InstalledRam);
            writer.WritePropertyValue("isLittleEndian", Pi.Info.IsLittleEndian ? 1 : 0);
            writer.WritePropertyValue("libraryVersion", Pi.Info.LibraryVersion?.ToString());
            writer.WritePropertyValue("manufacturer", Pi.Info.Manufacturer.ToString());
            writer.WritePropertyValue("memorySize", Pi.Info.MemorySize.ToString());
            writer.WritePropertyValue("modelName", Pi.Info.ModelName);
            writer.WritePropertyValue("operatingSystem", Pi.Info.OperatingSystem?.ToString());
            writer.WritePropertyValue("processorModel", Pi.Info.ProcessorModel.ToString());
            writer.WritePropertyValue("processorModel", Pi.Info.ProcessorModel.ToString());
            writer.WritePropertyValue("raspberryPiVersion", Pi.Info.RaspberryPiVersion.ToString());
            writer.WritePropertyValue("revision", Pi.Info.Revision);
            writer.WritePropertyValue("revisionNumber", Pi.Info.RevisionNumber);
            writer.WritePropertyValue("serial", Pi.Info.Serial);
            writer.WritePropertyValue("uptimeSecs", Pi.Info.Uptime);
            writer.WriteEndObject();
        }
コード例 #11
0
        public static void SerializeJson <T>(T obj, Stream stream)
        {
            var writer = new SimpleJsonWriter(stream);

            Serialize.To(writer, obj);
            writer.Flush();
        }
コード例 #12
0
        /// <summary>
        /// Executes 'Set Device Name' command.
        /// </summary>
        private string SetDeviceName(SimpleHttpContext context)
        {
            StringBuilder json = new StringBuilder();

            try
            {
                string name = context.Query.Get("name");
                if (String.IsNullOrWhiteSpace(name))
                {
                    throw new Exception("Parameter 'name' is missing or invalid");
                }

                _config.DeviceName = name;
                using (SimpleJsonWriter writer = new SimpleJsonWriter(json))
                {
                    writer.WriteStartObject();
                    WriteServiceObject(writer, true);
                    WriteDeviceObject(writer);
                    WriteRequestObject(writer, context);
                    writer.WriteStartObject("output");
                    writer.WritePropertyValue("success", 1);
                    writer.WritePropertyValue("code", 0);
                    writer.WriteEndObject();
                    writer.WriteEndObject();
                }
            }
            catch (Exception ex)
            {
                _errorHandler?.LogError(ex);
                return(WriteFatalResponse(context, ex));
            }
            return(json.ToString());
        }
コード例 #13
0
        public string Get(string str)
        {
            /*if (str == "foo")
             *  return "bar";
             * else
             *  return "no bar";
             */

            // Convert string to json
            var reader = new SimpleJsonReader(new StringReader(str));

            // Deserialize the json to record
            var readRecord = Deserialize <Record> .From(reader);

            // Change record
            readRecord.Name = "Changed";

            // Convert json back to string
            var jsonString = new StringBuilder();
            var jsonWriter = new SimpleJsonWriter(new StringWriter(jsonString));

            //Reserialize
            Serialize.To(jsonWriter, readRecord);
            jsonWriter.Flush();

            // Send response
            return(jsonString.ToString());
        }
コード例 #14
0
ファイル: StatisticsHandler.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Executes 'Ping' command.
        /// </summary>
        private string Ping(SimpleHttpContext context)
        {
            StringBuilder json = new StringBuilder();

            try
            {
                using (var writer = new SimpleJsonWriter(json))
                {
                    writer.WriteStartObject();
                    WriteServiceObject(writer, true);
                    WriteDeviceObject(writer);
                    _statsWriters
                    .Where(sw => sw is ServiceState)
                    .FirstOrDefault()?
                    .WriteRuntimeStatistics(writer);
                    writer.WriteEndObject();
                }
            }
            catch (Exception ex)
            {
                _errorHandler?.LogError(ex);
                return(WriteFatalResponse(context, ex));
            }
            return(json.ToString());
        }
コード例 #15
0
 public override string Serialize(object serializable)
 {
     Initialize();
     using (var tw = new StringWriter())
     {
         var writer = new SimpleJsonWriter(tw);
         _serializer.Serialize(serializable, writer);
         return(tw.ToString());
     }
 }
コード例 #16
0
        /// <summary>
        /// Serializes an EntryPointOperation object to its JSON representation.
        /// </summary>
        public static void SerializeToJson(EntryPointOperation entryPoint, Stream stream)
        {
            var writer     = new SimpleJsonWriter(stream);
            var serializer = new Serializer <SimpleJsonWriter>(typeof(EntryPointOperation));

            serializer.Serialize(entryPoint, writer);
            writer.Flush();
            stream.Flush();
            stream.Position = 0;
        }
コード例 #17
0
        public static void TranscodeCBJson <From>(Stream from, Stream to)
        {
            var input  = new InputStream(from, 11);
            var reader = new CompactBinaryReader <InputStream>(input);

            var writer = new SimpleJsonWriter(to);

            Transcode <From> .FromTo(reader, writer);

            writer.Flush();
        }
コード例 #18
0
ファイル: HandlerBase.cs プロジェクト: jon-hyland/rpi
 /// <summary>
 /// Writes the 'device' object for all commands.
 /// </summary>
 public void WriteDeviceObject(SimpleJsonWriter writer)
 {
     writer.WriteStartObject("device");
     writer.WritePropertyValue("serial", _config.DeviceSerial ?? "");
     writer.WritePropertyValue("name", _config.DeviceName ?? "");
     writer.WritePropertyValue("interfaceName", _config.PrimaryInterface?.Name ?? "");
     writer.WritePropertyValue("macAddress", _config.PrimaryInterface?.PhysicalAddress ?? "");
     writer.WritePropertyValue("ipAddress", _config.PrimaryInterface?.InternetAddress ?? "");
     writer.WritePropertyValue("os", _config.GetOS());
     writer.WriteEndObject();
 }
コード例 #19
0
            public void SaveSettings()
            {
                StringBuilder sb = new StringBuilder();

                using (SimpleJsonWriter writer = new SimpleJsonWriter(sb))
                {
                    writer.WriteStartObject();
                    writer.WritePropertyValue("deviceName", DeviceName);
                    writer.WriteEndObject();
                }
                File.WriteAllText(FilePath, sb.ToString(), Encoding.UTF8);
            }
コード例 #20
0
        /// <summary>
        /// Writes runtime statistics.
        /// </summary>
        public void WriteRuntimeStatistics(SimpleJsonWriter writer)
        {
            try
            {
                var          now    = DateTime.Now;
                var          state  = ServiceStateType.Up;
                var          health = ServiceHealthType.Good;
                List <Alert> alerts = null;
                lock (_lock)
                {
                    state = _state;
                    foreach (Alert a in _alerts)
                    {
                        if (a.Type > health)
                        {
                            health = a.Type;
                        }
                    }
                    if (health > ServiceHealthType.Good)
                    {
                        alerts = new List <Alert>();
                        foreach (Alert a in _alerts)
                        {
                            alerts.Add(a);
                        }
                    }
                }

                writer.WriteStartObject("serviceState");
                writer.WritePropertyValue("state", ((Int32)state) + "-" + state.ToString());
                writer.WritePropertyValue("health", ((Int32)health) + "-" + health.ToString());
                if (alerts != null)
                {
                    writer.WriteStartArray("alerts");
                    foreach (Alert a in alerts)
                    {
                        writer.WriteStartObject();
                        writer.WritePropertyValue("type", ((Int32)a.Type) + "-" + a.Type.ToString());
                        writer.WritePropertyValue("message", a.Message ?? "");
                        writer.WritePropertyValue("time", a.Time.ToString());
                        writer.WritePropertyValue("expiration", a.Expiration == DateTime.MaxValue ? "max" : ((Int32)(((TimeSpan)(a.Expiration - now)).TotalMinutes)).ToString());
                        writer.WriteEndObject();
                    }
                    writer.WriteEndArray();
                }
                writer.WriteEndObject();
            }
            catch (Exception ex)
            {
                _errorHandler?.LogError(ex);
            }
        }
コード例 #21
0
ファイル: HandlerBase.cs プロジェクト: jon-hyland/rpi
 /// <summary>
 /// Writes the 'service' object for all commands.
 /// </summary>
 public void WriteServiceObject(SimpleJsonWriter writer, bool isStatistics = false)
 {
     writer.WriteStartObject("service");
     writer.WritePropertyValue("name", _config.ServiceName);
     writer.WritePropertyValue("version", _config.ServiceVersion);
     if (isStatistics)
     {
         writer.WritePropertyValue("now", DateTime.Now.ToString());
         writer.WritePropertyValue("runningTime", _config.RunningTime.ToShortString());
         writer.WritePropertyValue("memoryUsageMB", _config.GetMegabytesUsedByProcess());
     }
     writer.WriteEndObject();
 }
コード例 #22
0
ファイル: HandlerBase.cs プロジェクト: jon-hyland/rpi
        /// <summary>
        /// Writes the 'request' object for all commands.
        /// </summary>
        public void WriteRequestObject(SimpleJsonWriter writer, SimpleHttpContext context)
        {
            IDictionary <string, string[]> qs = context.Query.GetAll();

            writer.WriteStartObject("request");
            writer.WritePropertyValue("handler", context.Handler);
            writer.WritePropertyValue("command", context.Command);
            foreach (string key in qs.Keys)
            {
                writer.WritePropertyValue(key, qs[key].Length > 0 ? qs[key][0] : null);
            }
            writer.WritePropertyValue("elapsedMS", context.Stopwatch.ElapsedMilliseconds);
            writer.WriteEndObject();
        }
コード例 #23
0
        /// <inheritdoc/>
        public override byte[] Serialize <T>(T value)
        {
            var serializer = _cache.GetSerializer(value.GetType());
            var buffer     = StringBuilderPool.Lease();

            using (var stringWriter = new StringWriter(buffer))
            {
                var writer = new SimpleJsonWriter(stringWriter);
                serializer.Serialize(value, writer);

                var bytes = Encoding.UTF8.GetBytes(buffer.ToString());
                StringBuilderPool.Return(buffer);
                return(bytes);
            }
        }
コード例 #24
0
        public void JsonSerialization_NullNonNullableString_Throws()
        {
            var ser    = new Serializer <SimpleJsonWriter>(typeof(BasicTypes));
            var stream = new StringWriter();
            var jw     = new SimpleJsonWriter(stream);

            var nullString = new BasicTypes {
                _str = null
            };

            Assert.Throws <NullReferenceException>(() => ser.Serialize(nullString, jw));

            var nullWString = new BasicTypes {
                _wstr = null
            };

            Assert.Throws <NullReferenceException>(() => ser.Serialize(nullWString, jw));
        }
コード例 #25
0
        private static ByteArrayContent CreateWriteBody(IEnumerable <CounterWriteOperation> operations)
        {
            var writeBody = new CounterWriteRequest {
                Writes = operations.ToList()
            };

            using (var ms = new MemoryStream())
            {
                var writer = new SimpleJsonWriter(ms);
                writer.Write(writeBody);

                var bytes = new byte[ms.Length];
                Buffer.BlockCopy(ms.GetBuffer(), 0, bytes, 0, bytes.Length);

                var content = new ByteArrayContent(bytes);
                content.Headers.ContentType = new MediaTypeHeaderValue(Protocol.ApplicationJsonMimeType);
                return(content);
            }
        }
コード例 #26
0
        static void Main()
        {
            var config = new Config
            {
                Variant = "Simple",
                Enabled = true,
                Urls    = { "http://example.com", "http://www.example.com" }
            };

            var jsonString = new StringBuilder();
            var jsonWriter = new SimpleJsonWriter(new StringWriter(jsonString));

            Serialize.To(jsonWriter, config);
            jsonWriter.Flush();
            Console.WriteLine(jsonString);

            var reader = new SimpleJsonReader(new StringReader(jsonString.ToString()));

            config = Deserialize <Config> .From(reader);
        }
コード例 #27
0
ファイル: HandlerBase.cs プロジェクト: jon-hyland/rpi
 /// <summary>
 /// Writes the 'errors' object for all commands.
 /// </summary>
 public void WriteErrorsObject(SimpleJsonWriter writer, List <Exception> errors)
 {
     writer.WriteStartArray("errors");
     if ((errors != null) && (errors.Count > 0))
     {
         for (int i = 0; i < errors.Count; i++)
         {
             Exception ex = errors[i];
             if (!String.IsNullOrEmpty(ex.Message))
             {
                 writer.WriteStartObject();
                 writer.WritePropertyValue("type", ex.GetType().ToString());
                 writer.WritePropertyValue("message", CleanErrorString(ex.Message));
                 writer.WritePropertyValue("stack", CleanErrorString(ex.StackTrace ?? ""));
                 writer.WriteEndObject();
             }
         }
     }
     writer.WriteEndArray();
 }
コード例 #28
0
        private void Write <TData>(TData data)
        {
            var acceptTypes = this.HttpRequest.AcceptTypes;

            if (acceptTypes != null && acceptTypes.Contains(Protocol.BondCompactBinaryMimeType, StringComparer.Ordinal))
            {
                this.ContentType = Protocol.BondCompactBinaryMimeType;
                using (var writerStream = new WriterStream(this.responseBody))
                {
                    var writer = writerStream.CreateCompactBinaryWriter();
                    writer.Write(data);
                }
            }
            else
            {
                this.ContentType = Protocol.ApplicationJsonMimeType;
                var writer = new SimpleJsonWriter(this.responseBody);
                writer.Write(data);
            }
        }
コード例 #29
0
        /// <summary>
        /// Writes runtime stats.
        /// </summary>
        public void WriteRuntimeStatistics(SimpleJsonWriter writer)
        {
            string input1, input2, output;

            _lock.EnterReadLock();
            try
            {
                input1 = BankToString(_input1);
                input2 = BankToString(_input2);
                output = BankToString(_outputRead);
            }
            finally
            {
                _lock.ExitReadLock();
            }

            writer.WriteStartObject("gpio");
            writer.WritePropertyValue("input1", input1);
            writer.WritePropertyValue("input2", input2);
            writer.WritePropertyValue("output", output);
            writer.WritePropertyValue("cps", _cps != null ? _cps.CPS.ToString("0.0") : "0.0");
            writer.WriteEndObject();
        }
コード例 #30
0
        public static string Serializer(string name, string uni, double year)
        {
            var src = new Record
            {
                Name        = name,
                University  = uni,
                GraduationY = year
            };

            // Inspect the Record
            Console.WriteLine(src.Name + " " + src.University + " " + src.GraduationY);
            Console.ReadLine();

            //Serialize the Record into Json format
            var jsonString = new StringBuilder();
            var jsonWriter = new SimpleJsonWriter(new StringWriter(jsonString));

            Serialize.To(jsonWriter, src);
            jsonWriter.Flush();

            //Return the serialized Record
            return(jsonString.ToString());
        }