/// <summary> 反转表文件 </summary> public void Rollback(string files) { List <string> fileNames = new List <string>(files.Split(';')); while (fileNames.Remove("")) { } if (fileNames.Count == 0) { Logger.info("请选择要转换的文件"); return; } Progress.Count = fileNames.Count; int Count = 0; for (int i = 0; i < fileNames.Count; ++i) { Progress.Current = (i + 1); try { byte[] buffer = FileUtil.GetFileBuffer(fileNames[i]); try { buffer = GZipUtil.Decompress(buffer); } catch (System.Exception) { } TableReader reader = new TableReader(buffer); Rollback_impl(reader, fileNames[i]); reader.Close(); Count++; } catch (System.Exception ex) { throw new Exception(string.Format("{0} 文件出错\r\n{1}", fileNames[i], ex.ToString())); } } if (Count > 0) { Logger.warn("转换结束"); } }
public static T BytesToData <T>(byte[] bytes, DataSerializerConfig config) { byte[] dataBytes = new byte[bytes.Length - 1]; Array.Copy(bytes, 1, dataBytes, 0, bytes.Length - 1); byte flag = bytes[0]; if (config.CryptKey != null && (flag & (byte)Flags.Crypt) == (byte)Flags.Crypt) { dataBytes = CryptoUtil.Decrypt(bytes, config.CryptKey, config.CryptIv); } #if ENABLE_COMPRESS_SERIALIZE_DATA if ((flag & (byte)Flags.Compress) == (byte)Flags.Compress) { dataBytes = GZipUtil.Uncompress(dataBytes); } #endif T data = default(T); BinaryFormatter bf = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream(dataBytes)) { data = (T)bf.Deserialize(ms); } return(data); }
public static byte[] DataToBytes(object data, DataSerializerConfig config, out byte flag) { byte[] bytes = null; flag = 0; using (MemoryStream ms = new MemoryStream()) { BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(ms, data); bytes = ms.ToArray(); #if ENABLE_COMPRESS_SERIALIZE_DATA if (config.EnableCompression) { bytes = GZipUtil.Compress(bytes); flag |= (byte)Flags.Compress; } #endif if (config.CryptKey != null) { bytes = CryptoUtil.Encrypt(bytes, config.CryptKey, config.CryptIv); flag |= (byte)Flags.Crypt; } } return(bytes); }
byte[] AcquireAudioBufferData() { byte[] audio = null; try { lock (audioBuffer) { if (audioBuffer.Count > 0) { audio = audioBuffer.ToArray(); audioBuffer.Clear(); } } if (audio != null) { audio = GZipUtil.Compress(audio); return(audio); } return(null); } catch (Exception) { return(null); } }
protected override IContent WritePage(ISource source, IPageData pageData, OutputData outputData) { IContent content = base.WritePage(source, pageData, outputData); if (!IsGZip && !IsEncrypt) { return(content); } byte[] data = content.ContentEncoding.GetBytes(content.Content); string contentType = content.ContentType; if (IsGZip) { MemoryStream stream = GZipUtil.GZipCompress(data); using (stream) { data = stream.ToArray(); } contentType = ContentTypeConst.GZIP; } if (IsEncrypt) { data = CryptoUtil.Encrypt(data); contentType = ContentTypeConst.BINARY; } return(new WebFileContent(new FileContent(contentType, data))); }
public byte[] GetBuffer(bool compress) { lock (this) { return(compress ? GZipUtil.Compress(FileUtil.GetFileBuffer(m_FileName)) : FileUtil.GetFileBuffer(m_FileName)); } }
public void Save(Action onComplete = null) { string path = WorldStateSavePath; File.WriteAllBytes(path, GZipUtil.Compress(_state.ToString())); Debug.Log($"saved WorldState data to {path}"); onComplete?.Invoke(); }
private void CheckFingerPrintWithServer(string json) { string url = "Assetbundle/CheckBundle"; JsonData tempData = new JsonData(); #if UNITY_ANDROID tempData["local_files"] = json; tempData["no_compression"] = "1"; #else tempData["local_files"] = Convert.ToBase64String(GZipUtil.Zip(json)); #endif byte[] Data = System.Text.Encoding.UTF8.GetBytes(tempData.ToJson()); StaticMonoBehaviour.Instance.StartCoroutine(HttpRequest.Instance.WebRequest(HttpRequest.HttpReqType.POST, url, Data, (string Json) => { JsonData tempJson = JsonMapper.ToObject(Json); JsonData data = tempJson["data"]; #if UNITY_ANDROID string filesUpdate = data ["file_to_update"].ToString(); string filesDelete = data ["file_to_delete"].ToString(); #else string filesUpdate = GZipUtil.UnZipToString(Convert.FromBase64String(data["file_to_update"].ToString())); string filesDelete = GZipUtil.UnZipToString(Convert.FromBase64String(data["file_to_delete"].ToString())); LogManager.Log("file_to_update: " + filesUpdate); LogManager.Log("file_to_delete: " + filesDelete); #endif FingerPrint.StartWriting(m_AssetBundlePath); if (!string.IsNullOrEmpty(filesDelete)) { JsonData jdFilesDelete = JsonMapper.ToObject(filesDelete); for (int i = 0; i < jdFilesDelete.Count; ++i) { var filePath = m_AssetBundlePath + jdFilesDelete[i].ToString(); if (File.Exists(filePath)) { File.Delete(filePath); } FingerPrint.DeleteItem(filePath, m_AssetBundlePath); } } FingerPrint.Flush(); //有需要更新的文件 if (!string.IsNullOrEmpty(filesUpdate)) { JsonData jdFilesUpdate = JsonMapper.ToObject(filesUpdate); string staticServer = data["static_server"].ToString(); string platformPath = data["platform_path"].ToString(); List <string> paths = GetPathFromJson(jdFilesUpdate, ""); if (paths.Count > 0) { DownloadFiles(paths, staticServer, platformPath); } else { Ready(); } } }, NetworkFail)); }
private void btnGZipUtil_Click(object sender, EventArgs e) { //压缩解压缩文本内容 string zippedContent = GZipUtil.Compress("wuhuacong"); string original = GZipUtil.Decompress(zippedContent); GZipUtil.Compress(Application.StartupPath, Application.StartupPath, "cityroad.zip"); GZipUtil.Decompress(Application.StartupPath, Path.Combine(Application.StartupPath, "cityroad"), "cityroad.zip"); MessageDxUtil.ShowTips("操作完成"); }
public static IdKeyData RouterReceive(this RouterSocket socket) { IdKeyData ikd = new IdKeyData(); NetMQMessage msg = socket.ReceiveMultipartMessage(); ikd.Id = msg[0].ConvertToString(); //socket.Options.Identity ikd.Key = msg[2].ConvertToString(); byte[] zipData = msg[3].Buffer; ikd.Data = GZipUtil.Decompress(zipData); return(ikd); }
void ReceivedAudio(byte[] buffer) { try { if (soundPlayer != null) { soundPlayer.Write(GZipUtil.Decompress(buffer)); } } catch (Exception) { } }
void ReceivedVideoCallback(object obj) { object[] objs = (object[])obj; AdHocDesktop_TcpCommand command = (AdHocDesktop_TcpCommand)objs[0]; byte[] buffer = (byte[])objs[1]; lock (this) { if (command == AdHocDesktop_TcpCommand.StreamingCamera) { using (Bitmap drawImage = ImageUtil.ByteToBitmap(buffer)) { using (Graphics g = videoPanel.CreateGraphics()) { g.DrawImage(drawImage, new Rectangle(new Point(0, 0), videoPanel.Size)); } } } else { try { byte[] image = null; if (previousBuffer == null) { previousBuffer = GZipUtil.Decompress(buffer); image = previousBuffer; } else { byte[] currentBuffer = GZipUtil.Decompress(buffer); image = ImageUtil.RecompareImage(previousBuffer, currentBuffer); } using (Bitmap drawImage = ImageUtil.ByteToBitmap(image))//, width, height, width * 3, PixelFormat.Format24bppRgb)) { using (Graphics g = videoPanel.CreateGraphics()) { g.DrawImage(drawImage, new Rectangle(new Point(0, 0), videoPanel.Size)); } } previousBuffer = null; previousBuffer = image; image = null; } catch (Exception) { } } } }
/// <summary> /// 选择并加载.backup备份数据库文件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void 无损加载数据库ToolStripMenuItem_Click(object sender, EventArgs e) { if (CanReadMdfFile() == false) { database.ResetConnection(); } OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Filter = "备份文件 (*.backup)|*.backup|所有文件 (*.*)|*.*"; if (fileDialog.ShowDialog() == DialogResult.OK) { GZipUtil.Decompress(new FileInfo(fileDialog.FileName), Properties.Resources.MdfFilename); MessageBox.Show("无损备份文件加载成功!", "加载成功", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } }
void AdHocDesktopThreadHandler() { Rectangle captureRectangle = Screen.PrimaryScreen.Bounds; //Rectangle captureRectangle = new Rectangle(0, 0, 240, 180); perviousBuffer = AllocateBuffer(captureRectangle); byte[] compressedBuffer = GZipUtil.Compress(perviousBuffer); user.Send(new AdHocDesktop_TcpObject(AdHocDesktop_TcpCommand.ProfileScreen, profile.Src, profile.Dest, captureRectangle.Size)); user.Send(new AdHocDesktop_TcpObject(AdHocDesktop_TcpCommand.StreamingScreen, profile.Src, profile.Dest, compressedBuffer)); while (isRunning) { try { if (isNextNewCapture) { isNextNewCapture = false; perviousBuffer = null; } byte[] currentBuffer = AllocateBuffer(captureRectangle); //currentBuffer = ImageUtil.TransformHSV(currentBuffer); if (perviousBuffer != null) { byte[] comparedBuffer = ImageUtil.CompareImage(perviousBuffer, currentBuffer); compressedBuffer = GZipUtil.Compress(comparedBuffer); } else { compressedBuffer = GZipUtil.Compress(currentBuffer); } user.Send(new AdHocDesktop_TcpObject(AdHocDesktop_TcpCommand.StreamingScreen, profile.Src, profile.Dest, compressedBuffer)); perviousBuffer = currentBuffer; Thread.Sleep(500); } catch (Exception e) { MessageBox.Show(e.ToString()); } } }
public byte[] Serialize <TObject>(TObject obj) { if (obj == null) { return(new byte[0]); } byte[] data = Encoding.UTF8.GetBytes(_jsonSerializer.Serialize(obj)); if (data.Length > NTKeyword.IntK) // 因为设计了_heade,这个值是可以改的 { data = GZipUtil.Compress(data); byte[] array = new byte[_head.Length + data.Length]; _head.CopyTo(array, 0); data.CopyTo(array, _head.Length); return(array); } else { return(data); } }
void SendStreaming(AdHocDesktop_TcpClient client, byte[] buffer, AdHocDesktop_TcpCommand command) { bandwidthInput += (buffer == null ? 0 : buffer.Length); List <AdHocDesktop_TcpClient> groups = groupTable[client.Identifier]; for (int i = 0; i < groups.Count; i++) { if (!groups[i].IsConnected) { groups.RemoveAt(i); i--; } } for (int i = 0; i < groups.Count; i++) { AdHocDesktop_TcpClient dest = groups[i]; if (winceClients.Contains(dest.Identifier)) { Size size = new Size(240, 180); if (command == AdHocDesktop_TcpCommand.StreamingCamera) { using (Bitmap b = ImageUtil.ByteToBitmap(buffer)) { buffer = ImageUtil.ResizeBitmapToJpegByte(b, size); } } else if (command == AdHocDesktop_TcpCommand.StreamingScreen) { using (Bitmap b = ImageUtil.ByteToBitmap(GZipUtil.Decompress(buffer))) { buffer = GZipUtil.Compress(ImageUtil.ResizeBitmapToByte(b, size)); } } } dest.Send(new AdHocDesktop_TcpObject(command, client.Identifier, dest.Identifier, buffer)); bandwidthOutput += (buffer == null ? 0 : buffer.Length); } }
public static void Load(Action <World> onComplete) { string path = WorldStateSavePath; World toReturn = null; if (File.Exists(path)) { string data = GZipUtil.Decompress(File.ReadAllBytes(path)).Trim(); try { WorldState worldState = Newtonsoft.Json.JsonConvert.DeserializeObject <WorldState>(data); Debug.Log($"loaded saved WorldState, seed: {worldState.seed}"); toReturn = new World(worldState); } catch { Debug.LogError("could not deserialize saved world state data"); onComplete?.Invoke(null); } } else { Debug.LogFormat($"Could not find file at {path}, so it will be created"); // check to make sure the directory exists before trying to write a file to it if (!Directory.Exists(Application.streamingAssetsPath)) { Directory.CreateDirectory(Application.streamingAssetsPath); } WorldState worldState = new WorldState(UnityEngine.Random.Range(int.MinValue, int.MaxValue)); toReturn = new World(worldState); } toReturn.Save(); onComplete(toReturn); }
private void Create_impl(byte[] buffer) { byte[] bytes = GZipUtil.Compress(buffer); foreach (var pair in mProgramInfos) { PROGRAM program = pair.Key; ProgramInfo info = pair.Value; if (!info.Create) { continue; } info.CreateData(mStrFiler, info.Compress ? bytes : buffer); CreateTable(info); CreateCustom(DataClassName, mPackage, mFields, info, true); foreach (var custom in mCustoms) { CreateCustom(custom.Key, mPackage, custom.Value, info, false); } foreach (var custom in mEnums) { info.CreateFile(custom.Key, info.GenerateEnum.Generate(custom.Key, mPackage, custom.Value)); } } }
private void MainForm_Load(object sender, EventArgs e) { if (this.需要重复开启软件检查) { // 检测后台是否运行同一程序 Process[] processes = Process.GetProcessesByName("关机助手"); if (processes.Length == 0) { processes = Process.GetProcessesByName("TimeManager"); } if (processes.Length > 1) { MessageBox.Show("检测到后台已经启动本程序,建议关闭其他窗口至只剩下本窗口。", "温馨提示"); } } // 检测数据库文件是否存在,不存在则解压缩空数据库 if (!File.Exists(Properties.Resources.MdfFilename)) { BinaryWriterUtil.WriteFileToDisk( GZipUtil.DecompressBytes(Properties.Resources.EmptyDB), Properties.Resources.MdfFilename); MessageBox.Show("检测到您第一次使用本软件,请点击数据管理进行初始化操作。", "欢迎!", MessageBoxButtons.OK, MessageBoxIcon.Information); ManagerForm.needInitialized = true; } comboBoxMode.SelectedIndex = 0; // 加载配置文件,执行相应的操作(调用已有的事件函数,以免造成与显示不同步的问题) if (ConfigManager.MainFormConfigLoaded) { if (ConfigManager.SafeModeBoot) { MainForm.DatabaseOffline = true; } if (ConfigManager.MainFormAutoDarkMode) { darkModeToolStripMenuItem_Click(null, null); } if (ConfigManager.MainFormOpacity != -1) { this.toolStripComboBox不透明度.Text = ConfigManager.MainFormOpacity.ToString() + "%"; } if (ConfigManager.MainDefaultComboBoxIndex != -1) { this.comboBoxMode.SelectedIndex = ConfigManager.MainDefaultComboBoxIndex; } if (ConfigManager.MainFormAutoShutdownSeconds != -1) { if (this.label设置倒计时.Text.Contains("分钟")) { this.comboBoxTime.Text = ((double)ConfigManager.MainFormAutoShutdownSeconds / 60).ToString(); } else { this.comboBoxTime.Text = ((double)ConfigManager.MainFormAutoShutdownSeconds / 3600).ToString(); } button确定_Click(sender, e); } if (ConfigManager.MainFormHideInTaskbar) { 任务栏隐匿ToolStripMenuItem_Click(null, null); } if (ConfigManager.MainFormHideNotifyIcon) { 隐藏右下角图标ToolStripMenuItem_Click(null, null); } } // 获取版本号并替换标题 this.Text = this.Text.Replace("{Version}", ProgramLauncher.Version()); // 给ComboBox添加选项 AddSelectOptionsInComboBoxTime(); // 添加鼠标滚动事件 this.MouseWheel += new MouseEventHandler(comboBoxTime_MouseWheel); // 添加时间并开启自动刷新时间线程 AddNowTimeToFormTitle(); FlushTitleInEvery10Second(); }
public static string ExportAsGzip(bool withEx) { string root = Path.GetFullPath(Application.dataPath + "/../../../"); // 获取本工程中git忽略的文件列表 List <string> gitIgnores = GetGitIgnores(root); if (gitIgnores == null) { return(""); } try { // 解析Framework配置文件 var configurations = ParseFrameworkConfiguration(root + "framework/framework.conf"); string version = configurations["version"][0]; var foldersCopyAll = configurations["folders_copy_all"]; var ignores = new List <string>(); var ignoresEx = new List <string>(); if (configurations.ContainsKey("ignore_public")) { ignores.AddRange(configurations["ignore_public"]); ignoresEx.AddRange(configurations["ignore_public"]); } if (configurations.ContainsKey("ignore_framework")) { ignores.AddRange(configurations["ignore_framework"]); } if (configurations.ContainsKey("ignore_framework_ex")) { ignoresEx.AddRange(configurations["ignore_framework_ex"]); } string fileMap = ""; bool hasRecordFileMap = false; UpkPack.Ignored ignoreFunc = (FileInfo fileInfo) => { bool ex = withEx && hasRecordFileMap; var relativePath = fileInfo.FullName.Replace(root, "").Replace('\\', '/'); // 过滤所有不在Framework文件夹中的文件 if (!IsInFrameworkFolder(relativePath, foldersCopyAll, ex)) { return(true); } // 过滤.gitignore中忽略的文件 if (IsIgnored(relativePath, gitIgnores)) { return(true); } // 过滤.frameworkignore中忽略的文件 if (IsIgnored(relativePath, ex ? ignoresEx : ignores)) { return(true); } // 过滤非本版本的文件地图文件 if (IsInvalidFileMap(relativePath, version)) { return(true); } if (!hasRecordFileMap) { fileMap += relativePath + "\n"; } return(false); }; // 记录文件地图 UpkPack.TraverseFolder(root, false, ignoreFunc); var fileMapPath = Path.Combine(root, "framework/filemap/" + GetFileMapName(version)); CheckCreateDirectory(fileMapPath); File.WriteAllText(fileMapPath, fileMap); hasRecordFileMap = true; // 合并为upk var upkPath = Path.Combine(root, "framework/output/v" + version + (withEx ? "_ex" : "") + ".upk"); CheckCreateDirectory(upkPath); UpkPack.PackFolder(root, upkPath, false, ignoreFunc); // 压缩为gzip var gzipPath = Path.Combine(root, "framework/output/v" + version + (withEx ? "_ex" : "") + ".upk.gz"); CheckCreateDirectory(gzipPath); File.WriteAllBytes(gzipPath, GZipUtil.Zip(File.ReadAllBytes(upkPath))); File.Delete(upkPath); return(gzipPath); } catch (System.Exception e) { Debug.LogError(e.Message + "\n" + e.StackTrace); return(""); } }
public static void DealerSend(this DealerSocket socket, KeyData kd) { byte[] zipData = GZipUtil.Compress(kd.Data); socket.SendMoreFrameEmpty().SendMoreFrame(kd.Key).SendFrame(zipData); }
public static FullRouteIPInfoCache CreateFromDownload(string url) { FullRouteIPInfoCache ret = new FullRouteIPInfoCache(); ret.TimeStamp = DateTime.Now; // Download CSV WebRequest req = HttpWebRequest.Create(url); WebResponse res = req.GetResponse(); try { Stream stream = res.GetResponseStream(); try { byte[] rawData = Util.ReadAllFromStream(stream); byte[] data = GZipUtil.Decompress(rawData); Csv csv = new Csv(new Buf(data)); foreach (CsvEntry?ce in csv.Items) { if (ce != null && ce.Count >= 7) { FullRouteIPInfoEntry e = new FullRouteIPInfoEntry(); e.From = Str.StrToUInt(ce[2]); e.To = Str.StrToUInt(ce[3]); //e.Registry = ce[2]; //e.Assigned = Str.StrToUInt(ce[3]); e.Country2 = ce[5]; //e.Country3 = ce[5]; e.CountryFull = DeleteSemi(ce[6]); if (e.From != 0 && e.To != 0) { ret.EntryList.Add(e); } } } ret.EntryList.Sort(); if (ret.EntryList.Count <= 70000) { throw new ApplicationException("ret.EntryList.Count <= 70000"); } } finally { stream.Close(); } } finally { res.Close(); } ret.build_country_code_to_name_db(); return(ret); }
static void ImportFromGzip(string root, bool withEx, bool generateGz) { string[] oldFileMap = null; var configurations = ParseFrameworkConfiguration(Path.Combine(root, "framework/framework.conf")); if (configurations.Count == 0) { configurations = ParseFrameworkConfiguration(Path.Combine(root, "framework/FRAMEWORK.md")); } string oldVersion = ""; if (configurations.ContainsKey("version")) { oldVersion = configurations["version"][0]; var fileMapPath = Path.Combine(root, "framework/filemap/v" + oldVersion + ".txt"); if (File.Exists(fileMapPath)) { oldFileMap = File.ReadAllLines(fileMapPath); } } bool import = false; if (oldFileMap == null) { if (EditorUtility.DisplayDialog("⚠️ 警告!", "目标工程并非基于某一个玩创Lab框架版本, 是否确定要导入?", "确认", "取消")) { import = true; } } else { import = true; } if (import) { List <string> pathList = null; bool success = false; var filePath = ""; if (!generateGz) { filePath = EditorUtility.OpenFilePanel("选择gz文件", Path.Combine(root, "../"), "gz"); } else { filePath = EditorFrameworkExport.ExportAsGzip(withEx); } if (!string.IsNullOrEmpty(filePath)) { var upkPath = Path.Combine(root, "framework/output/" + Path.GetFileNameWithoutExtension(filePath)); CheckCreateDirectory(upkPath); File.WriteAllBytes(upkPath, GZipUtil.UnZip(File.ReadAllBytes(filePath))); success = UPKExtra.ExtraUPK(upkPath, root, ref pathList); if (File.Exists(upkPath)) { File.Delete(upkPath); } } if (success) { if (oldFileMap != null && oldFileMap.Length > 0) { foreach (var oldFile in oldFileMap) { if (!pathList.Contains(oldFile)) { Debug.Log("Delete old version file: " + oldFile); if (File.Exists(Path.Combine(root, oldFile))) { File.Delete(Path.Combine(root, oldFile)); } } } } } AssetDatabase.Refresh(); } }
/// <summary> /// Decode the contents of the <paramref name="keyframeStream"/> and add packets to /// <paramref name="packets"/>. /// </summary> /// <param name="snapStream">The keyframe stream to decode</param> /// <param name="packets">The packet list to add to.</param> /// <returns></returns> private bool DecodeKeyframeStream(Stream snapStream, System.Collections.Generic.List <PacketBuffer> packets) { if (snapStream == null) { return(false); } bool ok = true; bool allowCompression = true; int bytesRead = 0; PacketHeader header = new PacketHeader(); byte[] headerBuffer = new byte[PacketHeader.Size]; uint queuedPacketCount = 0; try { do { if (allowCompression && GZipUtil.IsGZipStream(snapStream)) { allowCompression = false; snapStream = new GZipStream(snapStream, CompressionMode.Decompress); } bytesRead = snapStream.Read(headerBuffer, 0, headerBuffer.Length); // ok = false if done, true when we read something. ok = bytesRead == 0; if (bytesRead == headerBuffer.Length) { if (header.Read(new NetworkReader(new MemoryStream(headerBuffer, false)))) { // Read the header. Determine the expected size and read that much more data. int crcSize = ((header.Flags & (byte)PacketFlag.NoCrc) == 0) ? Crc16.CrcSize : 0; PacketBuffer packet = new PacketBuffer(header.PacketSize + crcSize); packet.Emplace(headerBuffer, bytesRead); packet.Emplace(snapStream, header.PacketSize + crcSize - bytesRead); if (packet.Status == PacketBufferStatus.Complete) { // Check for end of frame messages to yield on. packets.Add(packet); ok = true; ++queuedPacketCount; } else { switch (packet.Status) { case PacketBufferStatus.CrcError: Log.Error("Failed to decode packet CRC."); break; case PacketBufferStatus.Collating: Log.Error("Insufficient data for packet."); break; default: break; } } } } } while (ok && bytesRead != 0); Log.Diag("Decoded {0} packets from keyframe", queuedPacketCount); } catch (Exception e) { ok = false; Log.Exception(e); } return(ok); }