diff --git a/extra/beta/update-version.js b/extra/beta/update-version.js index d8e626d03..9ab00155b 100644 --- a/extra/beta/update-version.js +++ b/extra/beta/update-version.js @@ -5,7 +5,7 @@ const util = require("../../src/util"); util.polyfill(); -const version = process.env.VERSION; +const version = process.env.RELEASE_BETA_VERSION; console.log("Beta Version: " + version); diff --git a/extra/env2arg.js b/extra/env2arg.js deleted file mode 100644 index f89a91e43..000000000 --- a/extra/env2arg.js +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env node - -const childProcess = require("child_process"); -let env = process.env; - -let cmd = process.argv[2]; -let args = process.argv.slice(3); -let replacedArgs = []; - -for (let arg of args) { - for (let key in env) { - arg = arg.replaceAll(`$${key}`, env[key]); - } - replacedArgs.push(arg); -} - -let child = childProcess.spawn(cmd, replacedArgs); -child.stdout.pipe(process.stdout); -child.stderr.pipe(process.stderr); diff --git a/extra/exe-builder/.gitignore b/extra/exe-builder/.gitignore deleted file mode 100644 index d52874b6c..000000000 --- a/extra/exe-builder/.gitignore +++ /dev/null @@ -1 +0,0 @@ -packages/ diff --git a/extra/exe-builder/App.config b/extra/exe-builder/App.config deleted file mode 100644 index 97eb34aff..000000000 --- a/extra/exe-builder/App.config +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extra/exe-builder/DownloadForm.Designer.cs b/extra/exe-builder/DownloadForm.Designer.cs deleted file mode 100644 index 26a474e9c..000000000 --- a/extra/exe-builder/DownloadForm.Designer.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.ComponentModel; - -namespace UptimeKuma { - partial class DownloadForm { - /// - /// Required designer variable. - /// - private IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) { - if (disposing && (components != null)) { - components.Dispose(); - } - - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DownloadForm)); - this.progressBar = new System.Windows.Forms.ProgressBar(); - this.label = new System.Windows.Forms.Label(); - this.labelData = new System.Windows.Forms.Label(); - this.SuspendLayout(); - // - // progressBar - // - this.progressBar.Location = new System.Drawing.Point(12, 12); - this.progressBar.Name = "progressBar"; - this.progressBar.Size = new System.Drawing.Size(472, 41); - this.progressBar.TabIndex = 0; - // - // label - // - this.label.Location = new System.Drawing.Point(12, 59); - this.label.Name = "label"; - this.label.Size = new System.Drawing.Size(472, 23); - this.label.TabIndex = 1; - this.label.Text = "Preparing..."; - // - // labelData - // - this.labelData.Location = new System.Drawing.Point(12, 82); - this.labelData.Name = "labelData"; - this.labelData.Size = new System.Drawing.Size(472, 23); - this.labelData.TabIndex = 2; - // - // DownloadForm - // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(496, 117); - this.Controls.Add(this.labelData); - this.Controls.Add(this.label); - this.Controls.Add(this.progressBar); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); - this.MaximizeBox = false; - this.Name = "DownloadForm"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Uptime Kuma"; - this.Load += new System.EventHandler(this.DownloadForm_Load); - this.ResumeLayout(false); - } - - private System.Windows.Forms.Label labelData; - - private System.Windows.Forms.Label label; - - private System.Windows.Forms.ProgressBar progressBar; - - #endregion - } -} - diff --git a/extra/exe-builder/DownloadForm.cs b/extra/exe-builder/DownloadForm.cs deleted file mode 100644 index 28a57c527..000000000 --- a/extra/exe-builder/DownloadForm.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.IO.Compression; -using System.Net; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using Newtonsoft.Json; - -namespace UptimeKuma { - public partial class DownloadForm : Form { - private readonly Queue downloadQueue = new(); - private readonly WebClient webClient = new(); - private DownloadItem currentDownloadItem; - - public DownloadForm() { - InitializeComponent(); - } - - private void DownloadForm_Load(object sender, EventArgs e) { - webClient.DownloadProgressChanged += DownloadProgressChanged; - webClient.DownloadFileCompleted += DownloadFileCompleted; - - label.Text = "Reading latest version..."; - - // Read json from https://uptime.kuma.pet/version - var versionJson = new WebClient().DownloadString("https://uptime.kuma.pet/version"); - var versionObj = JsonConvert.DeserializeObject(versionJson); - - var nodeVersion = versionObj.nodejs; - var uptimeKumaVersion = versionObj.latest; - var hasUpdateFile = File.Exists("update"); - - if (!Directory.Exists("node")) { - downloadQueue.Enqueue(new DownloadItem { - URL = $"https://nodejs.org/dist/v{nodeVersion}/node-v{nodeVersion}-win-x64.zip", - Filename = "node.zip", - TargetFolder = "node" - }); - } - - if (!Directory.Exists("core") || hasUpdateFile) { - - // It is update, rename the core folder to core.old - if (Directory.Exists("core")) { - // Remove the old core.old folder - if (Directory.Exists("core.old")) { - Directory.Delete("core.old", true); - } - - Directory.Move("core", "core.old"); - } - - downloadQueue.Enqueue(new DownloadItem { - URL = $"https://github.com/louislam/uptime-kuma/archive/refs/tags/{uptimeKumaVersion}.zip", - Filename = "core.zip", - TargetFolder = "core" - }); - - File.WriteAllText("version.json", versionJson); - - // Delete the update file - if (hasUpdateFile) { - File.Delete("update"); - } - } - - DownloadNextFile(); - } - - void DownloadNextFile() { - if (downloadQueue.Count > 0) { - var item = downloadQueue.Dequeue(); - - currentDownloadItem = item; - - // Download if the zip file is not existing - if (!File.Exists(item.Filename)) { - label.Text = item.URL; - webClient.DownloadFileAsync(new Uri(item.URL), item.Filename); - } else { - progressBar.Value = 100; - label.Text = "Use local " + item.Filename; - DownloadFileCompleted(null, null); - } - } else { - npmSetup(); - } - } - - void npmSetup() { - labelData.Text = ""; - - var npm = "..\\node\\npm.cmd"; - var cmd = $"{npm} ci --production & {npm} run download-dist & exit"; - - var startInfo = new ProcessStartInfo { - FileName = "cmd.exe", - Arguments = $"/k \"{cmd}\"", - RedirectStandardOutput = false, - RedirectStandardError = false, - RedirectStandardInput = true, - UseShellExecute = false, - CreateNoWindow = false, - WorkingDirectory = "core" - }; - - var process = new Process(); - process.StartInfo = startInfo; - process.EnableRaisingEvents = true; - process.Exited += (_, e) => { - progressBar.Value = 100; - - if (process.ExitCode == 0) { - Task.Delay(2000).ContinueWith(_ => { - Application.Restart(); - }); - label.Text = "Done"; - } else { - label.Text = "Failed, exit code: " + process.ExitCode; - } - - }; - process.Start(); - label.Text = "Installing dependencies and download dist files"; - progressBar.Value = 50; - process.WaitForExit(); - } - - void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { - progressBar.Value = e.ProgressPercentage; - var total = e.TotalBytesToReceive / 1024; - var current = e.BytesReceived / 1024; - - if (total > 0) { - labelData.Text = $"{current}KB/{total}KB"; - } - } - - void DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { - Extract(currentDownloadItem); - DownloadNextFile(); - } - - void Extract(DownloadItem item) { - if (Directory.Exists(item.TargetFolder)) { - var dir = new DirectoryInfo(item.TargetFolder); - dir.Delete(true); - } - - if (Directory.Exists("temp")) { - var dir = new DirectoryInfo("temp"); - dir.Delete(true); - } - - labelData.Text = $"Extracting {item.Filename}..."; - - ZipFile.ExtractToDirectory(item.Filename, "temp"); - - string[] dirList; - - // Move to the correct level - dirList = Directory.GetDirectories("temp"); - - - - if (dirList.Length > 0) { - var dir = dirList[0]; - - // As sometime ExtractToDirectory is still locking the directory, loop until ok - while (true) { - try { - Directory.Move(dir, item.TargetFolder); - break; - } catch (Exception exception) { - Thread.Sleep(1000); - } - } - - } else { - MessageBox.Show("Unexcepted Error: Cannot move extracted files, folder not found."); - } - - labelData.Text = $"Extracted"; - - if (Directory.Exists("temp")) { - var dir = new DirectoryInfo("temp"); - dir.Delete(true); - } - - File.Delete(item.Filename); - } - } - - public class DownloadItem { - public string URL { get; set; } - public string Filename { get; set; } - public string TargetFolder { get; set; } - } -} - diff --git a/extra/exe-builder/DownloadForm.resx b/extra/exe-builder/DownloadForm.resx deleted file mode 100644 index e87e0c0d4..000000000 --- a/extra/exe-builder/DownloadForm.resx +++ /dev/null @@ -1,377 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - AAABAAMAMDAAAAEAIACoJQAANgAAACAgAAABACAAqBAAAN4lAAAQEAAAAQAgAGgEAACGNgAAKAAAADAA - AABgAAAAAQAgAAAAAAAAJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA////BPT09Bfu7u4e8fHxJPPz8yv19fUy9fX1M/Pz8yvx8fEk9vb2HPPz8xXMzMwFAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP// - /wHv7+8f7u7uPPPz81Tx8fFs8fHxgPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGB8fHxcfHx8V3x8fFI9PT0MOvr6w0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADy8vIU8fHxS/Dw8Hbx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fFr9PT0R/Dw8CIAAAABAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA8vLyFPHx8Vnx8fGB8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fFs9fX1Mb+/vwQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAICAgALy8vI88fHxfvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvLy8nby8vI8gICAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAzMzMBfHx8Vrx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8vLyYf///wwAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwF8vLyYPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8W/z8/MWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADv7+9R8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLw8PB26urqDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLy8ijx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgu7w7Ifj79ud2u7PtNLrw83P677dzeu85c3r - u+rM67rwzOu68c7rverQ68Dj0uvD3NbuyM3b7c+64u7apujv5ZPx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxXgAAAAEAAAAAAAAAAAAAAAAAAAAA4+PjCfDw - 8Hfx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLd7tSmzeu92MbqsvvG6bH/xumy/8fq - s//H6rP/yOq0/8jqtf/J6rb/yeq2/8rrt//K67j/y+u4/8vruf/M67r/zOu7/83ru//Q7MDx1u7Kz9/t - 163s8OuJ8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgu/v7y8AAAAAAAAAAAAA - AAAAAAAA7u7uPfHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC5PDdl8jqtuTE6a7/xOmv/8Xp - sP/G6bH/xumx/8bpsv/H6rP/x+qz/8jqtP/I6rX/yeq2/8nqtv/K67f/yuu4/8vruP/L67n/zOu6/8zr - u//N67v/zey8/87svf/P67742e3Mx+jv5ZLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvDw - 8HWAgIACAAAAAAAAAACqqqoD8vLyc/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLf7degxOiu+cPo - rf/D6a7/xOmu/8Xpr//F6bD/xumx/8bpsf/G6bL/x+qz/8fqs//I6rT/yOq1/8nqtv/J6rb/yuu3/8rr - uP/L67j/y+u5/8zruv/M67v/zeu7/83svP/O7L3/zuy9/87svfzc7tK28fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fEkAAAAAAAAAADz8/Mq8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgunv - 5o3D6a/0wuis/8Lorf/D6K3/xOmu/8Tprv/F6a//xemw/8bpsf/G6bH/xumy/8fqs//H6rP/yOq0/8jq - tf/J6rb/yeq2/8rrt//K67j/y+u4/8vruf/M67r/zOu7/83ru//N7Lz/zuy9/87svf/O7L3/3e/TtPHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLy8vJNAAAAAAAAAADy8vJM8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgszqutDB6Kv/weir/8LorP/D6K3/w+it/8Tprv/E6a7/xemv/8XpsP/G6bH/xumx/8bp - sv/H6rP/x+qz/8jqtP/I6rX/yeq2/8nqtv/K67f/yuu4/8vruP/L67n/zOu6/8zru//N67v/zey8/87s - vf/O7L3/zuy++u3w6Yzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLy8vJ1AAAAAAAAAADx8fFr8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC6O/kjsDoqvzA6Kr/weir/8Loq//C6Kz/w+it/8Porf/E6a7/xOmu/8Xp - r//F6bD/xumx/8bpsf/G6bL/x+qz/8fqtP/I6rT/yOq1/8nqtv/J6rb/yuu3/8rruP/L67n/y+u5/8zr - uv/M67v/zeu7/83svP/O7L3/zuy9/93u07Xx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC////Bv// - /wfx8fGB8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC1ezJsr/nqf/A56n/weiq/8Hoq//C6Kv/wuis/8Po - rf/D6K3/xOmu/8Pprv+856T/uOed/7bmmv+05Zf/teWZ/7jnnf+86KP/wOio/8fqs//J6rb/yeq2/8rr - t//K67j/y+u5/8vruf/M67r/zOu7/83ru//N7Lz/zuy9/9buyNLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8vLyE/Ly8hPx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCy+q6zr/nqP/A56n/wOep/8Ho - qv/B6Kv/wuir/8LorP+u5Y//neF2/5bgav+V4Gr/luBr/5fhbP+Y4W7/meFv/5rhcf+b4nL/nOJ0/53i - dv+j5H//reaM/7nnnf/E6q//y+y4/8vruf/L67n/zOu6/8zru//N67v/zey8/9Lsxd/x8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC7+/vIPb29hzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCx+m03L/n - qP+/56j/wOep/8Dnqf/B6Kr/weir/7nmn/+R32T/kt9l/5PfZ/+U4Gj/leBq/5bga/+X4W3/mOFu/5nh - b/+a4XH/m+Jy/5zidP+d4nX/nuN3/5/jeP+f4nn/weqq/8rruP/L67n/y+u5/8zruv/M67v/zeu7/9Ls - w+Lx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8PDwI/Hx8SXx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGCxeix5L/nqP+/56j/v+eo/8Dnqf/A56n/weiq/7Pllv+Q3mP/kd9k/5LfZf+T32f/lOBo/5Xg - av+W4Gv/l+Ft/5jhbv+Z4W//muFx/5vicv+c4nT/neJ1/57jd/+f43j/xOmu/8rrt//K67j/y+u5/8vr - uf/M67r/zOu7/9Tsxtfx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC9PT0GO/v7yDx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGCx+m037/nqP+/56j/v+eo/7/nqP/A56n/wOip/7TmmP+P3mH/kN5j/5Hf - ZP+S32b/k99n/5TgaP+V4Gr/luBr/5fhbf+Y4W7/meFw/5rhcf+b4nL/nOJ0/53idf+h5Hz/yuu2/8nq - t//K67f/yuu4/8vruf/L67n/zOu6/9ftysrx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC7e3tDvT0 - 9Bfx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCyOq117/nqP+/56j/v+eo/7/nqP+/56j/wOep/7vn - of+O3mD/j95h/5DeY/+R32T/kt9m/5PfZ/+U4Gj/leBq/5bga/+X4W3/mOFu/5nhcP+a4nH/m+Jy/5zi - dP+r5Yr/yOq1/8nqtv/J6rf/yuu3/8rruP/L67n/y+u5/9zu1LHx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLz8/OA////A+7u7g/x8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCz+q+xb/nqP+/56j/v+eo/7/n - qP+/56j/v+eo/8Dnqf+S4Gb/jt5g/4/eYf+Q3mP/kd9k/5LfZv+T32f/lOBo/5Xgav+W4Gv/l+Ft/5jh - bv+Z4XD/muJx/5vic/+4553/yOq0/8jqtf/J6rb/yeq3/8rrt//K67j/y+u5/+bw4Zfx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fFrAAAAAP///wHz8/N88fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC1+zMrr/n - qP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+f4Xn/jd5f/47eYP+P3mH/kN5j/5HfZP+S32b/k99n/5Tg - af+V4Gr/luBr/5fhbf+Y4W7/meFw/5vic//F6rD/x+q0/8jqtP/I6rX/yeq2/8nqt//K67f/zOu88u/x - 74Px8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLv7+9QAAAAAAAAAADw8PBm8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC5e7gk7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+u5I//jN1d/43eX/+O3mD/j95h/5De - Y/+R32T/kt9m/5PfZ/+U4Gn/leBq/5bga/+X4W3/mOFu/6rliP/G6rL/x+qz/8fqtP/I6rT/yOq1/8nq - tv/J6rf/1OzGy/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YL19fUzAAAAAAAAAADy8vJO8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgsPoru2/56j/v+eo/7/nqP+/56j/v+eo/7/nqP++6Kf/j95i/4zd - Xf+N3l//jt5g/4/eYv+Q3mP/kd9k/5LfZv+T32f/lOBp/5Xgav+W4Gz/l+Ft/7voov/G6bL/xuqy/8fq - s//H6rT/yOq1/8jqtf/J6rb/4e/Zo/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLw8PARAAAAAAAA - AADu7u4u8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgszpvMm/56j/v+eo/7/nqP+/56j/v+eo/7/n - qP+/56j/q+SL/4vdXP+M3V3/jd5f/47eYP+P3mL/kN9j/5HfZP+S32b/k99n/5Tgaf+V4Gr/qOOH/8Xp - sP/G6bH/xumy/8bqsv/H6rP/x+q0/8jqtf/K67jy8PHwhPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8WoAAAAAAAAAAAAAAADo6OgL8fHxgfHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxguDv2J2/56j/v+eo/7/n - qP+/56j/v+eo/7/nqP+/56j/v+eo/6Xjgv+L3Vz/jN1d/43eX/+O3mD/j95i/5DfY/+R32T/kt9m/5Pf - Z/+k44D/xOmu/8XpsP/F6bD/xumx/8bpsv/G6rL/x+qz/8fqtP/W7cnB8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvPz80AAAAAAAAAAAAAAAAAAAAAA8PDwZ/Hx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLD6K/rv+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+u5I//kt5n/4zdXf+N3l//jt5g/4/e - Yv+Q32P/luFs/67kj//D6K3/xOmu/8Tpr//F6bD/xemw/8bpsf/G6bL/xuqy/8fqtP7o7+WR8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz8xYAAAAAAAAAAAAAAAAAAAAA8vLyPPHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLV7ci0v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/wOio/7Xl - mv+u5I7/rOSM/67kj/+35pz/wumr/8Lorf/D6K3/w+it/8Tprv/E6a//xemw/8XpsP/G6bH/xumy/9Ds - wNPx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8vLyZQAAAAAAAAAAAAAAAAAAAAAAAAAA////DPHx - 8YDx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGCx+m03L/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/n - qP+/56j/v+eo/7/nqP+/56j/wOep/8Doqv/B6Kr/weir/8LorP/C6K3/w+it/8Porv/E6a7/xOmv/8Xp - sP/F6bD/yOq18uvw6Yvx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC7+/vMQAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAPHx8Vzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC6O/ij8LorPG/56j/v+eo/7/n - qP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/8Dnqf/A6Kr/weiq/8Hoq//C6Kz/wuit/8Po - rf/D6K7/xOmu/8Tpr//F6bH74u/anvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLw8PB6////BQAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPPz8yrx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxguHu - 2pnB56v2v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP/A56n/wOiq/8Ho - q//B6Kv/wuis/8Lorf/D6K3/w+mu/8Tprv3b7dKq8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fFJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHy8vJf8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLi7tyXwumt8L/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/n - qP+/56j/wOep/8Doqv/B6Kv/weir/8LorP/C6K3/xOiv+d7u1aTx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvLy8nb///8KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADv7+8Q8/Pze/Hx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC6/Dpiszqu82/56j/v+eo/7/nqP+/56j/v+eo/7/n - qP+/56j/v+eo/7/nqP+/56j/v+eo/8Dnqf/A6Kr/weir/8Hoq//H6bTj5e7elfHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz8yoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA9fX1MvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLe7tShx+mz3r/n - qP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/v+eo/7/nqP/A56n/xumy5drtz6rv8e+D8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8vLyTgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPHx8Unx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgubv45DU68e2y+q6z8XoseTD6a7uweir9MPpru7F6bHly+q50tLsxLrl796U8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLy8vJh////AwAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wHx8fFZ8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8Wzf398IAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8D8/PzVfHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8PDwZujo - 6AsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA////AfHx8Ujx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fFa////BQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADz8/Mp8vLydvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8/PzfPHx8TcAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CvLy8lDz8/N/8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvPz84Hx8fFa8PDwEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADw8PAR8vLyTvHx8X3x8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fF/8/PzVvT09BgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wXz8/Mq8/PzU/Hx8XDx8fGB8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLy8vJz8fHxWO/v7y////8IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8G7e3tHfLy - 8ifu7u4u8PDwNPT09C/y8vIo7+/vH+Pj4wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAP///////wAA////////AAD///////8AAP//gAf//wAA//gAAD//AAD/wAAAB/8AAP+A - AAAB/wAA/gAAAAB/AAD8AAAAAD8AAPgAAAAAHwAA8AAAAAAPAADwAAAAAAcAAOAAAAAABwAA4AAAAAAD - AADAAAAAAAMAAMAAAAAAAwAAwAAAAAABAACAAAAAAAEAAIAAAAAAAQAAgAAAAAABAACAAAAAAAEAAIAA - AAAAAQAAgAAAAAABAACAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADAAAAAAAMAAMAAAAAABwAAwAAAAAAH - AADgAAAAAAcAAOAAAAAADwAA4AAAAAAPAADwAAAAAB8AAPAAAAAAHwAA+AAAAAA/AAD8AAAAAD8AAPwA - AAAAfwAA/gAAAAD/AAD/AAAAAf8AAP+AAAAD/wAA/8AAAAf/AAD/8AAAH/8AAP/8AAA//wAA//8AAf// - AAD//+AP//8AAP///////wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAgICAAu/v7xD09PQX7u7uHvDw8CP29vYb8vLyFOrq6gwAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAICA - gALy8vIm7+/vT/Pz82fz8/N98fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvDw8Hrw8PBm7+/vUPT0 - 9C3o6OgLAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOPj - 4wnz8/NC8vLydPHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YHy8vJj8/PzKoCAgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADx8fEl8vLydfHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxcfHx8SUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA9PT0LfHx8YDx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8/PzgPLy8j0AAAABAAAAAAAA - AAAAAAAAAAAAAO3t7Rzx8fGA8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLr8OmM5O7emeTv - 3Z7h79mj5fDem+nv45Tu8u6H8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvLy - 8joAAAAAAAAAAAAAAAD///8E8fHxbvHx8YLx8fGC8fHxgvHx8YLx8fGC7vDshtns0K7N67zayeq288fq - s//I6rT/yOq1/8nqtv/K67f/y+u4/8vruf/P7L7w0+zF29vv0Lrn8OKX8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8/PzfvPz8xUAAAAAAAAAAPX19TLx8fGC8fHxgvHx8YLx8fGC8fHxgt3u1KXF6rHzxOmv/8Xp - sP/G6bH/xumy/8fqs//I6rT/yOq1/8nqtv/K67f/y+u4/8vruf/M67v/zey8/87svf/S7MPj4u7Zp/Hx - 8YLx8fGC8fHxgvHx8YLx8fGC8/PzVQAAAAAAAAAA8fHxavHx8YLx8fGC8fHxgvHx8YLf7defwuis/cPo - rf/E6a7/xOmv/8XpsP/G6bH/xumy/8fqs//I6rT/yOq1/8nqtv/K67f/y+u4/8vruv/M67v/zey8/87s - vf/N67z/3e7SufHx8YLx8fGC8fHxgvHx8YLz8/N8////Bf///w3x8fGC8fHxgvHx8YLx8fGC8fHxgsXp - sOnB6Kv/wuis/8Porf/E6a7/xOmv/8XpsP/G6bH/xumy/8fqs//I6rT/yOq1/8nqtv/K67f/y+u4/8vr - uv/M67v/zey8/87svf/O67z96/Hoj/Hx8YLx8fGC8fHxgvHx8YLy8vIm8/PzK/Hx8YLx8fGC8fHxgvHx - 8YLg79icwOep/8Hoqv/B6Kv/wuis/8Porf/E6a7/wuit/73opP+76KL/u+eh/77opv/D6a3/yeu1/8nq - tv/K67f/y+u5/8zruv/M67v/zey8/87svf/d7tSz8fHxgvHx8YLx8fGC8fHxgvHx8Tby8vI68fHxgvHx - 8YLx8fGC8fHxgtTrxre/56j/wOep/8Hoqv/B6Kv/uOad/53idv+V4Gn/leBq/5fhbP+Y4W//muFx/5vi - c/+e4Xb/puWD/7PmlP/D6a3/y+u5/8zruv/M67v/zey8/9rtzsHx8fGC8fHxgvHx8YLx8fGC8/PzQfPz - 80Lx8fGC8fHxgvHx8YLx8fGC0OvAwr/nqP+/56j/wOep/8Hoqv+o44b/kd9k/5LfZv+U4Gj/leBq/5fh - bf+Y4W//muFx/5vic/+d4nX/n+N3/7fnm//K67j/y+u5/8zruv/M67v/2u3QvPHx8YLx8fGC8fHxgvHx - 8YLy8vI98/PzP/Hx8YLx8fGC8fHxgvHx8YLQ6sK/v+eo/7/nqP+/56j/wOep/6jjhv+P3mL/kd9k/5Lf - Zv+U4Gj/leBr/5fhbf+Y4W//muFx/5zic/+d4nX/v+mm/8nqt//K67j/y+u5/8zruv/f79au8fHxgvHx - 8YLx8fGC8fHxgvX19TLx8fE38fHxgvHx8YLx8fGC8fHxgtTrybO/56j/v+eo/7/nqP+/56j/sOSS/47e - YP+P3mL/kd9k/5LfZv+U4Gj/leBr/5fhbf+Z4W//muJx/5/jd//H6bP/yeq2/8nqt//K67j/y+u5/+nv - 45Tx8fGC8fHxgvHx8YLx8fGC7+/vIPHx8SXx8fGC8fHxgvHx8YLx8fGC4e/Zm7/nqP+/56j/v+eo/7/n - qP+956X/jt5h/47eYP+P3mL/kd9k/5LfZv+U4Gn/luBr/5fhbf+Z4W//q+aK/8fqs//I6rT/yeq2/8nq - t//N7Lvw8fHxgvHx8YLx8fGC8fHxgvPz84D///8G6+vrDfHx8YLx8fGC8fHxgvHx8YLv8e+Dweis87/n - qP+/56j/v+eo/7/nqP+d4XX/jN1e/47eYP+P3mL/kd9k/5PfZ/+U4Gn/luBr/5fhbf+86KP/xuqy/8fq - s//I6rX/yeq2/9Tsx8nx8fGC8fHxgvHx8YLx8fGC8PDwaAAAAAAAAAAA8fHxbPHx8YLx8fGC8fHxgvHx - 8YLM6rrMv+eo/7/nqP+/56j/v+eo/7blmv+N3V//jN1e/47eYP+Q3mL/kd9k/5PfZ/+U4Gn/qeSH/8Xp - sP/G6bH/xuqy/8fqs//I6rX/5fDem/Hx8YLx8fGC8fHxgvHx8YLz8/M/AAAAAAAAAADz8/NB8fHxgvHx - 8YLx8fGC8fHxgt3s06O/56j/v+eo/7/nqP+/56j/v+eo/7Xmmf+U32n/jN1e/47eYP+Q3mL/k99o/6zk - i//D6a7/xemv/8XpsP/G6bH/xuqy/8vqu+jx8fGC8fHxgvHx8YLx8fGC8fHxgvPz8xUAAAAAAAAAAPT0 - 9Bfx8fGC8fHxgvHx8YLx8fGC8fHvg8Tpsee/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+35pz/suWV/7Xm - mf/A6Kj/wuit/8Porf/E6a7/xemv/8XpsP/G6bH/3e3UqvHx8YLx8fGC8fHxgvHx8YLw8PBmAAAAAAAA - AAAAAAAAAAAAAPHx8W7x8fGC8fHxgvHx8YLx8fGC4u7cmMHnqvm/56j/v+eo/7/nqP+/56j/v+eo/7/n - qP+/56j/wOep/8Hoqv/C6Kz/wuit/8Porf/E6a7/xemv/9Hrwszx8fGC8fHxgvHx8YLx8fGC8fHxgvX1 - 9TEAAAAAAAAAAAAAAAAAAAAA7u7uO/Hx8YLx8fGC8fHxgvHx8YLx8fGC3e7SpMHoqfq/56j/v+eo/7/n - qP+/56j/v+eo/7/nqP+/56j/wOip/8Hoq//C6Kz/wuit/8Porf/O67zV8PHwhPHx8YLx8fGC8fHxgvHx - 8YLy8vJ2////BQAAAAAAAAAAAAAAAAAAAACqqqoD8PDwafHx8YLx8fGC8fHxgvHx8YLx8fGC4O/YnMTo - ruy/56j/v+eo/7/nqP+/56j/v+eo/7/nqP+/56j/wOip/8Hoq//C6Kz90uvEwe/x74Px8fGC8fHxgvHx - 8YLx8fGC8fHxgvPz8ykAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADz8/MW8fHxfPHx8YLx8fGC8fHxgvHx - 8YLx8fGC8PLuhdXtyLXF6bHlv+eo/7/nqP+/56j/v+eo/7/nqP/B6Kv0zeq8zOXv4JTx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLy8vJNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADy8vIm8fHxgPHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLs8OmJ4e/Zm93u06Pf7def5+/hkvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxXf///wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AADy8vIo8/PzffHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8VnMzMwFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAD29vYb8fHxbvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz83/v7+9BgICAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzMwF8/PzQPLy8nnx8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgvPz84Hx8fFc9PT0GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////B/X19TLx8fFc8PDwevHx - 8YLx8fGC8fHxgvHx8YLx8fGC8fHxgPHx8Wv09PRE9PT0FwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAA7+/vEPb29hvw8PAj7+/vH/T09Be/v78EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////8B///wAA//wAAD/wAAAP4AAAB+AA - AAfAAAADwAAAA4AAAAGAAAABgAAAAYAAAAGAAAABgAAAAYAAAAGAAAADwAAAA8AAAAPAAAAH4AAAB+AA - AA/wAAAP+AAAH/gAAD/+AAB//wAB///AA///+B////////////8oAAAAEAAAACAAAAABACAAAAAAAAAE - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////CfDw8BH///8GAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAAu7u7i7x8fFe8PDwevHx8YLx8fGC8fHxgvDw - 8Hvx8fFs7+/vT/Dw8CMAAAABAAAAAAAAAAAAAAAA5ubmCvLy8l/x8fGC8fHxgvHx8YLx8fGC8fHxgvHx - 8YLx8fGC8fHxgvHx8YLx8fGC8/PzZu7u7g8AAAAAAAAAAPHx8V3x8fGC8fHxgunv5o7Z7c200+vFytTs - xc7W7cnH2+7QueLu2qbu8OyH8fHxgvHx8YLx8fFu////BfHx8STx8fGC8fHxgtrtzq3D6a/8xemw/8bp - sv/I6rT/yeq2/8vruP/M67v/z+u++Nzu0bjx8fGC8fHxgu/v7zDx8fFI8fHxguzw6ojC56z3wuis/8Tp - rv/E6q3/weiq/8fqsv/J6rb/y+u5/8zru//N67z/6/HpjfHx8YLy8vJN8fHxXPHx8YLg79icv+eo/8Ho - qv+k4n//lOBo/5fhbf+a4XH/n+J5/7Pmlv/L67n/zOu7/+Xw353x8fGC8fHxXvHx8Vrx8fGC4O3Zm7/n - qP+/56j/nuF3/5HfZP+U4Gj/l+Ft/5ricf+x5pL/yeq3/8vruf/r8emN8fHxgu/v70/x8fFK8fHxguzw - 6ojA6Kn8v+eo/6njiP+O3mD/kd9k/5Tgaf+X4W3/vuim/8jqtP/N67zr8fHxgvHx8YLy8vI68/PzK/Hx - 8YLx8fGCx+m03L/nqP++6Kb/meBw/47eYP+S32X/q+SL/8XpsP/G6rL/1+zLvvHx8YLz8/OB8PDwEdXV - 1Qbx8fF98fHxgt/t1Z/A56j9v+eo/7/nqP+656H/vuim/8Lorf/E6a7/yOq18Ovw6Yvx8fGC8vLyYwAA - AAAAAAAA8fHxR/Hx8YLx8fGC2O3NrMDnqfq/56j/v+eo/7/nqP/B6Kv/xumy7OTu3Zfx8fGC8/PzgfLy - 8icAAAAAAAAAAP///wPz8/Nm8fHxgvHx8YLo7+SO0+zFuczquszM6bzJ1+zMru7w7Ibx8fGC8fHxgvHx - 8UcAAAAAAAAAAAAAAAAAAAAA4+PjCfHx8Vzx8fGC8fHxgvHx8YLx8fGC8fHxgvHx8YLx8fGC8fHxgfPz - 80D///8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8/PzK/Ly8mDz8/N+8fHxgvHx8YLy8vJ68vLyUezs - 7BsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAevr6w3j4+MJAAAAAAAA - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAD8fwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIAB - AADAAwAAwAMAAOAHAADwDwAA/n8AAP//AAA= - - - \ No newline at end of file diff --git a/extra/exe-builder/FodyWeavers.xml b/extra/exe-builder/FodyWeavers.xml deleted file mode 100644 index 0b37e4ef4..000000000 --- a/extra/exe-builder/FodyWeavers.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/extra/exe-builder/FodyWeavers.xsd b/extra/exe-builder/FodyWeavers.xsd deleted file mode 100644 index ff119f713..000000000 --- a/extra/exe-builder/FodyWeavers.xsd +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks - - - - - A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. - - - - - A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks - - - - - A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. - - - - - A list of unmanaged 32 bit assembly names to include, delimited with line breaks. - - - - - A list of unmanaged 64 bit assembly names to include, delimited with line breaks. - - - - - The order of preloaded assemblies, delimited with line breaks. - - - - - - This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. - - - - - Controls if .pdbs for reference assemblies are also embedded. - - - - - Controls if runtime assemblies are also embedded. - - - - - Controls whether the runtime assemblies are embedded with their full path or only with their assembly name. - - - - - Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. - - - - - As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. - - - - - Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. - - - - - Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. - - - - - A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | - - - - - A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. - - - - - A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with | - - - - - A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |. - - - - - A list of unmanaged 32 bit assembly names to include, delimited with |. - - - - - A list of unmanaged 64 bit assembly names to include, delimited with |. - - - - - The order of preloaded assemblies, delimited with |. - - - - - - - - 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. - - - - - A comma-separated list of error codes that can be safely ignored in assembly verification. - - - - - 'false' to turn off automatic generation of the XML Schema file. - - - - - \ No newline at end of file diff --git a/extra/exe-builder/Program.cs b/extra/exe-builder/Program.cs deleted file mode 100644 index d9db4d001..000000000 --- a/extra/exe-builder/Program.cs +++ /dev/null @@ -1,262 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; -using Microsoft.Win32; -using Newtonsoft.Json; -using UptimeKuma.Properties; - -namespace UptimeKuma { - static class Program { - /// - /// The main entry point for the application. - /// - [STAThread] - static void Main(string[] args) { - var cwd = Path.GetDirectoryName(Application.ExecutablePath); - - if (cwd != null) { - Environment.CurrentDirectory = cwd; - } - - bool isIntranet = args.Contains("--intranet"); - - if (isIntranet) { - Console.WriteLine("The --intranet argument was provided, so we will not try to access the internet. The first time this application runs you'll need to run it without the --intranet param or copy the result from another machine to the intranet server."); - } - - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new UptimeKumaApplicationContext(isIntranet)); - } - } - - public class UptimeKumaApplicationContext : ApplicationContext - { - private static Mutex mutex = null; - - const string appName = "Uptime Kuma"; - - private NotifyIcon trayIcon; - private Process process; - - private MenuItem statusMenuItem; - private MenuItem runWhenStarts; - private MenuItem openMenuItem; - - private RegistryKey registryKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); - - private readonly bool intranetOnly; - - public UptimeKumaApplicationContext(bool intranetOnly) { - - // Single instance only - bool createdNew; - mutex = new Mutex(true, appName, out createdNew); - if (!createdNew) { - return; - } - - this.intranetOnly = intranetOnly; - - var startingText = "Starting server..."; - trayIcon = new NotifyIcon(); - trayIcon.Text = startingText; - - runWhenStarts = new MenuItem("Run when system starts", RunWhenStarts); - runWhenStarts.Checked = registryKey.GetValue(appName) != null; - - statusMenuItem = new MenuItem(startingText); - statusMenuItem.Enabled = false; - - openMenuItem = new MenuItem("Open", Open); - openMenuItem.Enabled = false; - - trayIcon.Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location); - trayIcon.ContextMenu = new ContextMenu(new MenuItem[] { - statusMenuItem, - openMenuItem, - //new("Debug Console", DebugConsole), - runWhenStarts, - new("Check for Update...", CheckForUpdate), - new("Visit GitHub...", VisitGitHub), - new("About", About), - new("Exit", Exit), - }); - - trayIcon.MouseDoubleClick += new MouseEventHandler(Open); - trayIcon.Visible = true; - - var hasUpdateFile = File.Exists("update"); - - if (!hasUpdateFile && Directory.Exists("core") && Directory.Exists("node") && Directory.Exists("core/node_modules") && Directory.Exists("core/dist")) { - // Go go go - StartProcess(); - } else { - DownloadFiles(); - } - } - - void DownloadFiles() { - if (intranetOnly) { - return; - } - - var form = new DownloadForm(); - form.Closed += Exit; - form.Show(); - } - - private void RunWhenStarts(object sender, EventArgs e) { - if (registryKey == null) { - MessageBox.Show("Error: Unable to set startup registry key."); - return; - } - - if (runWhenStarts.Checked) { - registryKey.DeleteValue(appName, false); - runWhenStarts.Checked = false; - } else { - registryKey.SetValue(appName, Application.ExecutablePath); - runWhenStarts.Checked = true; - } - } - - void StartProcess() { - var startInfo = new ProcessStartInfo { - FileName = "node/node.exe", - Arguments = "server/server.js --data-dir=\"../data/\"", - RedirectStandardOutput = false, - RedirectStandardError = false, - UseShellExecute = false, - CreateNoWindow = true, - WorkingDirectory = "core" - }; - - process = new Process(); - process.StartInfo = startInfo; - process.EnableRaisingEvents = true; - process.Exited += ProcessExited; - - try { - process.Start(); - //Open(null, null); - - // Async task to check if the server is ready - Task.Run(() => { - var runningText = "Server is running"; - using TcpClient tcpClient = new TcpClient(); - while (true) { - try { - tcpClient.Connect("127.0.0.1", 3001); - statusMenuItem.Text = runningText; - openMenuItem.Enabled = true; - trayIcon.Text = runningText; - break; - } catch (Exception) { - System.Threading.Thread.Sleep(2000); - } - } - }); - - } catch (Exception e) { - MessageBox.Show("Startup failed: " + e.Message, "Uptime Kuma Error"); - } - } - - void StopProcess() { - process?.Kill(); - } - - void Open(object sender, EventArgs e) { - Process.Start("http://localhost:3001"); - } - - void DebugConsole(object sender, EventArgs e) { - - } - - void CheckForUpdate(object sender, EventArgs e) { - if (intranetOnly) { - return; - } - - // Check version.json exists - if (File.Exists("version.json")) { - // Load version.json and compare with the latest version from GitHub - var currentVersionObj = JsonConvert.DeserializeObject(File.ReadAllText("version.json")); - - var versionJson = new WebClient().DownloadString("https://uptime.kuma.pet/version"); - var latestVersionObj = JsonConvert.DeserializeObject(versionJson); - - // Compare version, if the latest version is newer, then update - if (new System.Version(latestVersionObj.latest).CompareTo(new System.Version(currentVersionObj.latest)) > 0) { - var result = MessageBox.Show("A new version is available. Do you want to update?", "Update", MessageBoxButtons.YesNo); - if (result == DialogResult.Yes) { - // Create a empty file `update`, so the app will download the core files again at startup - File.Create("update").Close(); - - trayIcon.Visible = false; - process?.Kill(); - - // Restart the app, it will download the core files again at startup - Application.Restart(); - } - } else { - MessageBox.Show("You are using the latest version."); - } - } - - - } - - void VisitGitHub(object sender, EventArgs e) { - if (intranetOnly) { - MessageBox.Show("You have parsed in --intranet so we will not try to access the internet or visit github.com, please go to https://github.com/louislam/uptime-kuma if you want to visit github."); - return; - } - - Process.Start("https://github.com/louislam/uptime-kuma"); - } - - void About(object sender, EventArgs e) - { - MessageBox.Show("Uptime Kuma Windows Runtime v1.0.0" + Environment.NewLine + "© 2023 Louis Lam", "Info"); - } - - void Exit(object sender, EventArgs e) - { - // Hide tray icon, otherwise it will remain shown until user mouses over it - trayIcon.Visible = false; - process?.Kill(); - Application.Exit(); - } - - void ProcessExited(object sender, EventArgs e) { - - if (process.ExitCode != 0) { - var line = ""; - while (!process.StandardOutput.EndOfStream) - { - line += process.StandardOutput.ReadLine(); - } - - MessageBox.Show("Uptime Kuma exited unexpectedly. Exit code: " + process.ExitCode + " " + line); - } - - trayIcon.Visible = false; - Application.Exit(); - } - - } -} - diff --git a/extra/exe-builder/Properties/AssemblyInfo.cs b/extra/exe-builder/Properties/AssemblyInfo.cs deleted file mode 100644 index aa35ef812..000000000 --- a/extra/exe-builder/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Uptime Kuma")] -[assembly: AssemblyDescription("A portable executable for running Uptime Kuma")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Uptime Kuma")] -[assembly: AssemblyProduct("Uptime Kuma")] -[assembly: AssemblyCopyright("Copyright © 2023 Louis Lam")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("86B40AFB-61FC-433D-8C31-650B0F32EA8F")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.2.0")] -[assembly: AssemblyFileVersion("1.0.2.0")] diff --git a/extra/exe-builder/Properties/Resources.Designer.cs b/extra/exe-builder/Properties/Resources.Designer.cs deleted file mode 100644 index 8c8e559c5..000000000 --- a/extra/exe-builder/Properties/Resources.Designer.cs +++ /dev/null @@ -1,62 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace UptimeKuma.Properties { - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", - "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", - "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState - .Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if ((resourceMan == null)) { - global::System.Resources.ResourceManager temp = - new global::System.Resources.ResourceManager("UptimeKuma.Properties.Resources", - typeof(Resources).Assembly); - resourceMan = temp; - } - - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState - .Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { return resourceCulture; } - set { resourceCulture = value; } - } - } -} \ No newline at end of file diff --git a/extra/exe-builder/Properties/Resources.resx b/extra/exe-builder/Properties/Resources.resx deleted file mode 100644 index ffecec851..000000000 --- a/extra/exe-builder/Properties/Resources.resx +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/extra/exe-builder/Properties/Settings.Designer.cs b/extra/exe-builder/Properties/Settings.Designer.cs deleted file mode 100644 index 6c63b395b..000000000 --- a/extra/exe-builder/Properties/Settings.Designer.cs +++ /dev/null @@ -1,23 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace UptimeKuma.Properties { - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute( - "Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - private static Settings defaultInstance = - ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { return defaultInstance; } - } - } -} \ No newline at end of file diff --git a/extra/exe-builder/Properties/Settings.settings b/extra/exe-builder/Properties/Settings.settings deleted file mode 100644 index abf36c5d3..000000000 --- a/extra/exe-builder/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/extra/exe-builder/UptimeKuma.csproj b/extra/exe-builder/UptimeKuma.csproj deleted file mode 100644 index a2ce892ba..000000000 --- a/extra/exe-builder/UptimeKuma.csproj +++ /dev/null @@ -1,203 +0,0 @@ - - - - - Debug - AnyCPU - {2DB53988-1D93-4AC0-90C4-96ADEAAC5C04} - WinExe - UptimeKuma - uptime-kuma - v4.7.2 - 512 - true - true - ..\..\public\favicon.ico - 9 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - app.manifest - - - COPY "$(SolutionDir)bin\Debug\uptime-kuma.exe" "%UserProfile%\Desktop\uptime-kuma-win64\" - - - - packages\Microsoft.Win32.Primitives.4.3.0\lib\net46\Microsoft.Win32.Primitives.dll - - - - packages\Newtonsoft.Json.13.0.2\lib\net45\Newtonsoft.Json.dll - - - - packages\System.AppContext.4.3.0\lib\net463\System.AppContext.dll - - - packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll - - - - packages\System.Console.4.3.1\lib\net46\System.Console.dll - - - - packages\System.Diagnostics.DiagnosticSource.7.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll - - - packages\System.Diagnostics.Tracing.4.3.0\lib\net462\System.Diagnostics.Tracing.dll - - - packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll - - - packages\System.IO.4.3.0\lib\net462\System.IO.dll - - - packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll - - - - packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll - - - packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll - - - packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll - - - packages\System.Linq.4.3.0\lib\net463\System.Linq.dll - - - packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll - - - packages\System.Memory.4.5.5\lib\net461\System.Memory.dll - - - packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll - - - packages\System.Net.Sockets.4.3.0\lib\net46\System.Net.Sockets.dll - - - - packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - - - packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll - - - packages\System.Runtime.4.3.1\lib\net462\System.Runtime.dll - - - packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll - - - packages\System.Runtime.Extensions.4.3.1\lib\net462\System.Runtime.Extensions.dll - - - packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll - - - packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll - - - packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net463\System.Security.Cryptography.Algorithms.dll - - - packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll - - - packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - - - packages\System.Security.Cryptography.X509Certificates.4.3.2\lib\net461\System.Security.Cryptography.X509Certificates.dll - - - packages\System.Text.RegularExpressions.4.3.1\lib\net463\System.Text.RegularExpressions.dll - - - - - - - - - - - packages\System.Xml.ReaderWriter.4.3.1\lib\net46\System.Xml.ReaderWriter.dll - - - - - Form - - - DownloadForm.cs - - - - - - DownloadForm.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - favicon.ico - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105.The missing file is {0}. - - - - - \ No newline at end of file diff --git a/extra/exe-builder/UptimeKuma.sln b/extra/exe-builder/UptimeKuma.sln deleted file mode 100644 index 201d7e234..000000000 --- a/extra/exe-builder/UptimeKuma.sln +++ /dev/null @@ -1,16 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UptimeKuma", "UptimeKuma.csproj", "{2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2DB53988-1D93-4AC0-90C4-96ADEAAC5C04}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/extra/exe-builder/UptimeKuma.sln.DotSettings.user b/extra/exe-builder/UptimeKuma.sln.DotSettings.user deleted file mode 100644 index b4ca9dadf..000000000 --- a/extra/exe-builder/UptimeKuma.sln.DotSettings.user +++ /dev/null @@ -1,3 +0,0 @@ - - True - True \ No newline at end of file diff --git a/extra/exe-builder/Version.cs b/extra/exe-builder/Version.cs deleted file mode 100644 index 896c7a244..000000000 --- a/extra/exe-builder/Version.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace UptimeKuma { - public class Version { - public string latest { get; set; } - public string slow { get; set; } - public string beta { get; set; } - public string nodejs { get; set; } - public string exe { get; set; } - } -} diff --git a/extra/exe-builder/app.manifest b/extra/exe-builder/app.manifest deleted file mode 100644 index 4a48528fc..000000000 --- a/extra/exe-builder/app.manifest +++ /dev/null @@ -1,28 +0,0 @@ - - - - - true - PerMonitorV2 - - - - - - - - - - - diff --git a/extra/exe-builder/packages.config b/extra/exe-builder/packages.config deleted file mode 100644 index 579e2b7ff..000000000 --- a/extra/exe-builder/packages.config +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extra/mark-as-nightly.js b/extra/mark-as-nightly.js index ada2aca81..d2cb8cb4b 100644 --- a/extra/mark-as-nightly.js +++ b/extra/mark-as-nightly.js @@ -15,7 +15,6 @@ if (newVersion) { // Process package.json pkg.version = newVersion; pkg.scripts.setup = pkg.scripts.setup.replaceAll(oldVersion, newVersion); - pkg.scripts["build-docker"] = pkg.scripts["build-docker"].replaceAll(oldVersion, newVersion); fs.writeFileSync("package.json", JSON.stringify(pkg, null, 4) + "\n"); // Process README.md diff --git a/extra/press-any-key.js b/extra/press-any-key.js deleted file mode 100644 index 42fc363cd..000000000 --- a/extra/press-any-key.js +++ /dev/null @@ -1,6 +0,0 @@ -console.log("Git Push and Publish the release note on github, then press any key to continue"); - -process.stdin.setRawMode(true); -process.stdin.resume(); -process.stdin.on("data", process.exit.bind(process, 0)); - diff --git a/extra/release/beta.mjs b/extra/release/beta.mjs new file mode 100644 index 000000000..ec3be7c68 --- /dev/null +++ b/extra/release/beta.mjs @@ -0,0 +1,65 @@ +import "dotenv/config"; +import { + ver, + buildDist, + buildImage, + checkDocker, + checkTagExists, + checkVersionFormat, + dryRun, + getRepoName, + pressAnyKey, + execSync, uploadArtifacts, +} from "./lib.mjs"; +import semver from "semver"; + +const repoName = getRepoName(); +const version = process.env.RELEASE_BETA_VERSION; +const githubToken = process.env.RELEASE_GITHUB_TOKEN; + +console.log("RELEASE_BETA_VERSION:", version); + +if (!githubToken) { + console.error("GITHUB_TOKEN is required"); + process.exit(1); +} + +// Check if the version is a valid semver +checkVersionFormat(version); + +// Check if the semver identifier is "beta" +const semverIdentifier = semver.prerelease(version); +console.log("Semver identifier:", semverIdentifier); +if (semverIdentifier[0] !== "beta") { + console.error("VERSION should have a semver identifier of 'beta'"); + process.exit(1); +} + +// Check if docker is running +checkDocker(); + +// Check if the tag exists +await checkTagExists(repoName, version); + +// node extra/beta/update-version.js +execSync("node ./extra/beta/update-version.js"); + +// Build frontend dist +buildDist(); + +// Build slim image (rootless) +buildImage(repoName, [ "beta-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); + +// Build full image (rootless) +buildImage(repoName, [ "beta-rootless", ver(version, "rootless") ], "rootless"); + +// Build slim image +buildImage(repoName, [ "beta-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); + +// Build full image +buildImage(repoName, [ "beta", version ], "release"); + +await pressAnyKey(); + +// npm run upload-artifacts +uploadArtifacts(version, githubToken); diff --git a/extra/release/final.mjs b/extra/release/final.mjs new file mode 100644 index 000000000..b4435064f --- /dev/null +++ b/extra/release/final.mjs @@ -0,0 +1,57 @@ +import "dotenv/config"; +import { + ver, + buildDist, + buildImage, + checkDocker, + checkTagExists, + checkVersionFormat, + getRepoName, + pressAnyKey, execSync, uploadArtifacts +} from "./lib.mjs"; + +const repoName = getRepoName(); +const version = process.env.RELEASE_VERSION; +const githubToken = process.env.RELEASE_GITHUB_TOKEN; + +console.log("RELEASE_VERSION:", version); + +if (!githubToken) { + console.error("GITHUB_TOKEN is required"); + process.exit(1); +} + +// Check if the version is a valid semver +checkVersionFormat(version); + +// Check if docker is running +checkDocker(); + +// Check if the tag exists +await checkTagExists(repoName, version); + +// node extra/beta/update-version.js +execSync("node extra/update-version.js"); + +// Build frontend dist +buildDist(); + +// Build slim image (rootless) +buildImage(repoName, [ "2-slim-rootless", ver(version, "slim-rootless") ], "rootless", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); + +// Build full image (rootless) +buildImage(repoName, [ "2-rootless", ver(version, "rootless") ], "rootless"); + +// Build slim image +buildImage(repoName, [ "next-slim", "2-slim", ver(version, "slim") ], "release", "BASE_IMAGE=louislam/uptime-kuma:base2-slim"); + +// Build full image +buildImage(repoName, [ "next", "2", version ], "release"); + +await pressAnyKey(); + +// npm run upload-artifacts +uploadArtifacts(version, githubToken); + +// node extra/update-wiki-version.js +execSync("node extra/update-wiki-version.js"); diff --git a/extra/release/lib.mjs b/extra/release/lib.mjs new file mode 100644 index 000000000..49391900a --- /dev/null +++ b/extra/release/lib.mjs @@ -0,0 +1,224 @@ +import "dotenv/config"; +import * as childProcess from "child_process"; +import semver from "semver"; + +export const dryRun = process.env.RELEASE_DRY_RUN === "1"; + +if (dryRun) { + console.info("Dry run enabled."); +} + +/** + * Check if docker is running + * @returns {void} + */ +export function checkDocker() { + try { + childProcess.execSync("docker ps"); + } catch (error) { + console.error("Docker is not running. Please start docker and try again."); + process.exit(1); + } +} + +/** + * Get Docker Hub repository name + */ +export function getRepoName() { + return process.env.RELEASE_REPO_NAME || "louislam/uptime-kuma"; +} + +/** + * Build frontend dist + * @returns {void} + */ +export function buildDist() { + if (!dryRun) { + childProcess.execSync("npm run build", { stdio: "inherit" }); + } else { + console.info("[DRY RUN] npm run build"); + } +} + +/** + * Build docker image and push to Docker Hub + * @param {string} repoName Docker Hub repository name + * @param {string[]} tags Docker image tags + * @param {string} target Dockerfile's target name + * @param {string} buildArgs Docker build args + * @param {string} dockerfile Path to Dockerfile + * @param {string} platform Build platform + * @returns {void} + */ +export function buildImage(repoName, tags, target, buildArgs = "", dockerfile = "docker/dockerfile", platform = "linux/amd64,linux/arm64,linux/arm/v7") { + let args = [ + "buildx", + "build", + "-f", + dockerfile, + "--platform", + platform, + ]; + + // Add tags + for (let tag of tags) { + args.push("-t", `${repoName}:${tag}`); + } + + args = [ + ...args, + "--target", + target, + ]; + + // Add build args + if (buildArgs) { + args.push("--build-arg", buildArgs); + } + + args = [ + ...args, + ".", + "--push", + ]; + + if (!dryRun) { + childProcess.spawnSync("docker", args, { stdio: "inherit" }); + } else { + console.log(`[DRY RUN] docker ${args.join(" ")}`); + } +} + +/** + * Check if the version already exists on Docker Hub + * TODO: use semver to compare versions if it is greater than the previous? + * @param {string} repoName Docker Hub repository name + * @param {string} version Version to check + * @returns {void} + */ +export async function checkTagExists(repoName, version) { + console.log(`Checking if version ${version} exists on Docker Hub`); + + // Get a list of tags from the Docker Hub repository + let tags = []; + + // It is mainly to check my careless mistake that I forgot to update the release version in .env, so `page_size` is set to 100 is enough, I think. + const response = await fetch(`https://hub.docker.com/v2/repositories/${repoName}/tags/?page_size=100`); + if (response.ok) { + const data = await response.json(); + tags = data.results.map((tag) => tag.name); + } else { + console.error("Failed to get tags from Docker Hub"); + process.exit(1); + } + + // Check if the version already exists + if (tags.includes(version)) { + console.error(`Version ${version} already exists`); + process.exit(1); + } +} + +/** + * Check the version format + * @param {string} version Version to check + * @returns {void} + */ +export function checkVersionFormat(version) { + if (!version) { + console.error("VERSION is required"); + process.exit(1); + } + + // Check the version format, it should be a semver and must be like this: "2.0.0-beta.0" + if (!semver.valid(version)) { + console.error("VERSION is not a valid semver version"); + process.exit(1); + } +} + +/** + * Press any key to continue + * @returns {Promise} + */ +export function pressAnyKey() { + console.log("Git Push and Publish the release note on github, then press any key to continue"); + process.stdin.setRawMode(true); + process.stdin.resume(); + return new Promise(resolve => process.stdin.once("data", data => { + process.stdin.setRawMode(false); + process.stdin.pause(); + resolve(); + })); +} + +/** + * Append version identifier + * @param {string} version Version + * @param {string} identifier Identifier + * @returns {string} Version with identifier + */ +export function ver(version, identifier) { + const obj = semver.parse(version); + + if (obj.prerelease.length === 0) { + obj.prerelease = [ identifier ]; + } else { + obj.prerelease[0] = [ obj.prerelease[0], identifier ].join("-"); + } + return obj.format(); +} + +/** + * Upload artifacts to GitHub + * docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain + * @param {string} version Version + * @param {string} githubToken GitHub token + * @returns {void} + */ +export function uploadArtifacts(version, githubToken) { + let args = [ + "buildx", + "build", + "-f", + "docker/dockerfile", + "--platform", + "linux/amd64", + "-t", + "louislam/uptime-kuma:upload-artifact", + "--build-arg", + `VERSION=${version}`, + "--build-arg", + "GITHUB_TOKEN", + "--target", + "upload-artifact", + ".", + "--progress", + "plain", + ]; + + if (!dryRun) { + childProcess.spawnSync("docker", args, { + stdio: "inherit", + env: { + ...process.env, + GITHUB_TOKEN: githubToken, + }, + }); + } else { + console.log(`[DRY RUN] docker ${args.join(" ")}`); + } +} + +/** + * Execute a command + * @param {string} cmd Command to execute + * @returns {void} + */ +export function execSync(cmd) { + if (!dryRun) { + childProcess.execSync(cmd, { stdio: "inherit" }); + } else { + console.info(`[DRY RUN] ${cmd}`); + } +} diff --git a/extra/release/nightly.mjs b/extra/release/nightly.mjs new file mode 100644 index 000000000..c6641bad7 --- /dev/null +++ b/extra/release/nightly.mjs @@ -0,0 +1,16 @@ +import { buildDist, buildImage, checkDocker, getRepoName } from "./lib.mjs"; + +// Docker Hub repository name +const repoName = getRepoName(); + +// Check if docker is running +checkDocker(); + +// Build frontend dist (it will build on the host machine, TODO: build on a container?) +buildDist(); + +// Build full image (rootless) +buildImage(repoName, [ "nightly2-rootless" ], "nightly-rootless"); + +// Build full image +buildImage(repoName, [ "nightly2" ], "nightly"); diff --git a/extra/release/upload-artifacts-beta.mjs b/extra/release/upload-artifacts-beta.mjs new file mode 100644 index 000000000..2897097e6 --- /dev/null +++ b/extra/release/upload-artifacts-beta.mjs @@ -0,0 +1,6 @@ +import { uploadArtifacts } from "./lib.mjs"; + +const version = process.env.RELEASE_BETA_VERSION; +const githubToken = process.env.RELEASE_GITHUB_TOKEN; + +uploadArtifacts(version, githubToken); diff --git a/extra/release/upload-artifacts.mjs b/extra/release/upload-artifacts.mjs new file mode 100644 index 000000000..cd34bd7d4 --- /dev/null +++ b/extra/release/upload-artifacts.mjs @@ -0,0 +1,6 @@ +import { uploadArtifacts } from "./lib.mjs"; + +const version = process.env.RELEASE_VERSION; +const githubToken = process.env.RELEASE_GITHUB_TOKEN; + +uploadArtifacts(version, githubToken); diff --git a/extra/test-docker.js b/extra/test-docker.js deleted file mode 100644 index d7926fcca..000000000 --- a/extra/test-docker.js +++ /dev/null @@ -1,9 +0,0 @@ -// Check if docker is running -const { exec } = require("child_process"); - -exec("docker ps", (err, stdout, stderr) => { - if (err) { - console.error("Docker is not running. Please start docker and try again."); - process.exit(1); - } -}); diff --git a/extra/update-version.js b/extra/update-version.js index 2bc13a78e..f9aead09d 100644 --- a/extra/update-version.js +++ b/extra/update-version.js @@ -5,7 +5,7 @@ const util = require("../src/util"); util.polyfill(); -const newVersion = process.env.VERSION; +const newVersion = process.env.RELEASE_VERSION; console.log("New Version: " + newVersion); diff --git a/extra/update-wiki-version.js b/extra/update-wiki-version.js index 003deec01..f6c961213 100644 --- a/extra/update-wiki-version.js +++ b/extra/update-wiki-version.js @@ -1,7 +1,7 @@ const childProcess = require("child_process"); const fs = require("fs"); -const newVersion = process.env.VERSION; +const newVersion = process.env.RELEASE_VERSION; if (!newVersion) { console.log("Missing version"); diff --git a/package.json b/package.json index ad9aac913..4f8eef138 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "2.0.0-dev", + "version": "2.0.0-beta.0", "license": "MIT", "repository": { "type": "git", @@ -34,20 +34,14 @@ "playwright-show-report": "playwright show-report ./private/playwright-report", "tsc": "tsc", "vite-preview-dist": "vite preview --host --config ./config/vite.config.js", - "build-docker": "npm run build && npm run build-docker-full && npm run build-docker-slim", "build-docker-base": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2 --target base2 . --push", "build-docker-base-slim": "docker buildx build -f docker/debian-base.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:base2-slim --target base2-slim . --push", "build-docker-builder-go": "docker buildx build -f docker/builder-go.dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:builder-go . --push", - "build-docker-slim": "node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:next-slim -t louislam/uptime-kuma:2-slim -t louislam/uptime-kuma:$VERSION-slim --target release --build-arg BASE_IMAGE=louislam/uptime-kuma:base2-slim . --push", - "build-docker-full": "node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:next -t louislam/uptime-kuma:2 -t louislam/uptime-kuma:$VERSION --target release . --push", - "build-docker-nightly": "node ./extra/test-docker.js && npm run build && docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly2 --target nightly . --push", - "build-docker-slim-rootless": "node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:2-slim-rootless -t louislam/uptime-kuma:$VERSION-slim-rootless --target rootless --build-arg BASE_IMAGE=louislam/uptime-kuma:base2-slim . --push", - "build-docker-full-rootless": "node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:2-rootless -t louislam/uptime-kuma:$VERSION-rootless --target rootless . --push", - "build-docker-nightly-rootless": "node ./extra/test-docker.js && npm run build && docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly2-rootless --target nightly-rootless . --push", "build-docker-nightly-local": "npm run build && docker build -f docker/dockerfile -t louislam/uptime-kuma:nightly2 --target nightly .", "build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push", - "upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain", - "setup": "git checkout 1.23.14 && npm ci --production && npm run download-dist", + "upload-artifacts": "node extra/release/upload-artifacts.mjs", + "upload-artifacts-beta": "node extra/release/upload-artifacts-beta.mjs", + "setup": "git checkout 1.23.15 && npm ci --production && npm run download-dist", "download-dist": "node extra/download-dist.js", "mark-as-nightly": "node extra/mark-as-nightly.js", "reset-password": "node extra/reset-password.js", @@ -58,8 +52,9 @@ "simple-postgres": "docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres", "simple-mariadb": "docker run --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mariadb# mariadb", "update-language-files": "cd extra/update-language-files && node index.js && cross-env-shell eslint ../../src/languages/$npm_config_language.js --fix", - "release-final": "node ./extra/test-docker.js && node extra/update-version.js && npm run build-docker && node ./extra/press-any-key.js && npm run upload-artifacts && node ./extra/update-wiki-version.js", - "release-beta": "node ./extra/test-docker.js && node extra/beta/update-version.js && npm run build && node ./extra/env2arg.js docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:$VERSION -t louislam/uptime-kuma:beta . --target release --push && node ./extra/press-any-key.js && npm run upload-artifacts", + "release-final": "node ./extra/release/final.mjs", + "release-beta": "node ./extra/release/beta.mjs", + "release-nightly": "node ./extra/release/nightly.mjs", "git-remove-tag": "git tag -d", "build-dist-and-restart": "npm run build && npm run start-server-dev", "start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev", diff --git a/src/components/notifications/Slack.vue b/src/components/notifications/Slack.vue index dc07bf373..9fa9f34be 100644 --- a/src/components/notifications/Slack.vue +++ b/src/components/notifications/Slack.vue @@ -4,6 +4,9 @@ +
+ {{ $t("aboutSlackUsername") }} +
diff --git a/src/lang/bg-BG.json b/src/lang/bg-BG.json index d52c1b498..372ded2a2 100644 --- a/src/lang/bg-BG.json +++ b/src/lang/bg-BG.json @@ -1088,5 +1088,14 @@ "From": "От", "Can be found on:": "Можте да се откриете на: {0}", "The phone number of the recipient in E.164 format.": "Телефонният номер на получателя във формат E.164.", - "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Идентификационен номер на подателя на текста или телефонен номер във формат E.164, в случай, че желаете да получавате отговори." + "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Идентификационен номер на подателя на текста или телефонен номер във формат E.164, в случай, че желаете да получавате отговори.", + "rabbitmqNodesRequired": "Моля, задайте възлите за този монитор.", + "rabbitmqNodesInvalid": "Моля, използвайте пълния URL адрес (започващ с 'http') за RabbitMQ възли.", + "RabbitMQ Password": "RabbitMQ парола", + "RabbitMQ Username": "RabbitMQ потребител", + "SendGrid API Key": "SendGrid API ключ", + "Separate multiple email addresses with commas": "Разделяйте отделните имейл адреси със запетаи", + "RabbitMQ Nodes": "Възли за управление на RabbitMQ", + "rabbitmqNodesDescription": "Въведете URL адреса на възлите за управление на RabbitMQ, включително протокол и порт. Пример: {0}", + "rabbitmqHelpText": "За да използвате монитора, ще трябва да активирате добавката за управление във вашата настройка на RabbitMQ. За повече информация моля, вижте {rabitmq_documentation}." } diff --git a/src/lang/cs-CZ.json b/src/lang/cs-CZ.json index 8fbebdc5c..ebcd2ebfd 100644 --- a/src/lang/cs-CZ.json +++ b/src/lang/cs-CZ.json @@ -1051,5 +1051,9 @@ "Client ID": "ID klienta", "Client Secret": "Tajemství klienta", "OAuth Scope": "OAuth rozsah", - "Optional: Space separated list of scopes": "Volitelné: seznam rozsahů oddělte mezerami" + "Optional: Space separated list of scopes": "Volitelné: seznam rozsahů oddělte mezerami", + "Debug": "Ladění", + "CopyToClipboardError": "Nelze zkopírovat do schránky: {error}", + "ignoredTLSError": "Chyby TLS/SSL byly ignorovány", + "Copy": "Kopírovat" } diff --git a/src/lang/de-CH.json b/src/lang/de-CH.json index 0c9ffe917..15b60519f 100644 --- a/src/lang/de-CH.json +++ b/src/lang/de-CH.json @@ -1085,5 +1085,15 @@ "Can be found on:": "Ist zu finden auf: {0}", "From": "Von", "Arcade": "Spielhalle", - "Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.": "Zeitkritische Benachrichtigungen werden sofort zugestellt, auch wenn sich das Gerät im Nicht stören-Modus befindet." + "Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.": "Zeitkritische Benachrichtigungen werden sofort zugestellt, auch wenn sich das Gerät im Nicht stören-Modus befindet.", + "RabbitMQ Nodes": "RabbitMQ-Verwaltungsknoten", + "rabbitmqNodesDescription": "Gib die URL für die RabbitMQ-Verwaltungsknoten einschliesslich Protokoll und Port ein. Beispiel: {0}", + "rabbitmqNodesRequired": "Setze die Knoten für diesen Monitor.", + "RabbitMQ Username": "RabbitMQ Benutzername", + "RabbitMQ Password": "RabbitMQ Passwort", + "SendGrid API Key": "SendGrid-API-Schlüssel", + "Separate multiple email addresses with commas": "Mehrere E-Mail-Adressen mit Kommas trennen", + "rabbitmqNodesInvalid": "Benutze eine vollständig qualifizierte URL (beginnend mit 'http') für RabbitMQ-Knoten.", + "rabbitmqHelpText": "Um den Monitor zu benutzen, musst du das Management Plugin in deinem RabbitMQ-Setup aktivieren. Weitere Informationen siehe {rabitmq_documentation}.", + "aboutSlackUsername": "Ändert den Anzeigenamen des Absenders. Wenn du jemanden erwähnen möchtest, füge ihn stattdessen in den Namen ein." } diff --git a/src/lang/de-DE.json b/src/lang/de-DE.json index 086740da3..9102d8e94 100644 --- a/src/lang/de-DE.json +++ b/src/lang/de-DE.json @@ -1088,5 +1088,15 @@ "Bubble": "Blase", "Clear": "Klar", "Pop": "Pop", - "Arcade": "Spielhalle" + "Arcade": "Spielhalle", + "rabbitmqNodesRequired": "Setze die Knoten für diesen Monitor.", + "RabbitMQ Username": "RabbitMQ Benutzername", + "RabbitMQ Password": "RabbitMQ Passwort", + "SendGrid API Key": "SendGrid-API-Schlüssel", + "Separate multiple email addresses with commas": "Mehrere E-Mail-Adressen mit Kommas trennen", + "RabbitMQ Nodes": "RabbitMQ-Verwaltungsknoten", + "rabbitmqNodesDescription": "Gib die URL für die RabbitMQ-Verwaltungsknoten einschließlich Protokoll und Port ein. Beispiel: {0}", + "rabbitmqNodesInvalid": "Benutze eine vollständig qualifizierte URL (beginnend mit 'http') für RabbitMQ-Knoten.", + "rabbitmqHelpText": "Um den Monitor zu benutzen, musst du das Management Plugin in deinem RabbitMQ-Setup aktivieren. Weitere Informationen siehe {rabitmq_documentation}.", + "aboutSlackUsername": "Ändert den Anzeigenamen des Absenders. Wenn du jemanden erwähnen möchtest, füge ihn stattdessen in den Namen ein." } diff --git a/src/lang/en.json b/src/lang/en.json index 38cf77452..970bdf2ff 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -721,6 +721,7 @@ "Icon Emoji": "Icon Emoji", "signalImportant": "IMPORTANT: You cannot mix groups and numbers in recipients!", "aboutWebhooks": "More info about Webhooks on: {0}", + "aboutSlackUsername": "Changes the display name of the message sender. If you want to mention someone, include it in the friendly name instead.", "aboutChannelName": "Enter the channel name on {0} Channel Name field if you want to bypass the Webhook channel. Ex: #other-channel", "aboutKumaURL": "If you leave the Uptime Kuma URL field blank, it will default to the Project GitHub page.", "smtpDkimSettings": "DKIM Settings", diff --git a/src/lang/fi.json b/src/lang/fi.json index d5a9f1c0a..75286226c 100644 --- a/src/lang/fi.json +++ b/src/lang/fi.json @@ -1086,5 +1086,14 @@ "The phone number of the recipient in E.164 format.": "Vastaanottajan puhelinnumero E.164-muodossa.", "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Joko lähettäjätunnus (sender ID) tai puhelinnumero E-164-muodossa jos haluat pystyä vastaanottamaan vastausviestejä.", "Scifi": "Tieteisseikkailu", - "Pop": "Poksahdus" + "Pop": "Poksahdus", + "rabbitmqNodesRequired": "Aseta tämän seuraimen solmut.", + "rabbitmqNodesInvalid": "Käytä RabbitMQ-solmuille täysin hyväksyttyä ('http' alkavaa) URL-osoitetta.", + "RabbitMQ Username": "RabbitMQ Käyttäjänimi", + "RabbitMQ Password": "RabbitMQ Salasana", + "SendGrid API Key": "SendGrid API-avain", + "Separate multiple email addresses with commas": "Erottele useammat sähköpostiosoitteet pilkuilla", + "RabbitMQ Nodes": "RabbitMQ-hallintasolmut", + "rabbitmqNodesDescription": "Anna URL RabbitMQ-hallintasolmuille sisältäen protokollan ja portin. Esimerkki: {0}", + "rabbitmqHelpText": "Jotta voit käyttää seurainta, sinun on otettava hallintalaajennus käyttöön RabbitMQ-asetuksissa. Lisätietoja saat osoitteesta {rabitmq_documentation}." } diff --git a/src/lang/fr-FR.json b/src/lang/fr-FR.json index f1163a06f..babb45c8d 100644 --- a/src/lang/fr-FR.json +++ b/src/lang/fr-FR.json @@ -1088,5 +1088,14 @@ "From": "De", "Can be found on:": "Disponible sur : {0}", "The phone number of the recipient in E.164 format.": "Le numéro de téléphone du destinataire au format E.164.", - "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Soit un identifiant d'expéditeur de texte, soit un numéro de téléphone au format E.164 si vous souhaitez pouvoir recevoir des réponses." + "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Soit un identifiant d'expéditeur de texte, soit un numéro de téléphone au format E.164 si vous souhaitez pouvoir recevoir des réponses.", + "RabbitMQ Nodes": "Nœuds de gestion RabbitMQ", + "rabbitmqNodesDescription": "Entrez l'URL des nœuds de gestion RabbitMQ, y compris le protocole et le port. Exemple : {0}", + "rabbitmqNodesRequired": "Veuillez définir les nœuds pour cette sonde.", + "rabbitmqNodesInvalid": "Veuillez utiliser une URL complète (commençant par « http ») pour les nœuds RabbitMQ.", + "RabbitMQ Username": "Nom d'utilisateur RabbitMQ", + "RabbitMQ Password": "Mot de passe RabbitMQ", + "rabbitmqHelpText": "Pour utiliser la sonde, vous devrez activer le plug-in de gestion dans votre configuration RabbitMQ. Pour plus d'informations, veuillez consulter la {rabitmq_documentation}.", + "SendGrid API Key": "Clé API SendGrid", + "Separate multiple email addresses with commas": "Séparez plusieurs adresses e-mail par des virgules" } diff --git a/src/lang/hi.json b/src/lang/hi.json index 6eda19a5c..101cb3a85 100644 --- a/src/lang/hi.json +++ b/src/lang/hi.json @@ -58,5 +58,53 @@ "Cert Exp.": "प्रमाणपत्र अनुभव.", "dbName": "डेटाबेस का नाम", "now": "अभी", - "-year": "-वर्ष" + "-year": "-वर्ष", + "Not available, please setup.": "उपलब्ध नहीं है, कृपया सेट अप करें।", + "Auto": "स्वतः", + "styleElapsedTime": "हार्टबीट बार के नीचे बीता हुआ समय", + "Setup Notification": "सूचना सेट अप करें", + "Light": "प्रकाश", + "Dark": "अंधकार", + "Theme - Heartbeat Bar": "थीम - हार्टबीट बार", + "Host URL": "होस्ट यूआरएल", + "Request Timeout": "अनुरोध समय सीमा", + "Accepted Status Codes": "स्वीकृत स्थिति कोड", + "Response": "प्रतिक्रिया", + "locally configured mail transfer agent": "स्थानीय रूप से कॉन्फ़िगर किया गया मेल ट्रांसफर एजेंट", + "Heartbeat Interval": "हार्टबीट अंतराल", + "Retries": "पुनः प्रयासों की संख्या", + "Heartbeat Retry Interval": "हार्टबीट पुनः प्रयास अंतराल", + "Port": "पोर्ट", + "checkEverySecond": "हर {0} सेकंड में जांच करें", + "retryCheckEverySecond": "हर {0} सेकंड में पुनः प्रयास करें", + "ignoreTLSErrorGeneral": "कनेक्शन के लिए TLS/SSL त्रुटि को अनदेखा करें", + "needPushEvery": "आपको हर {0} सेकंड में इस URL को कॉल करना चाहिए।", + "pushOptionalParams": "वैकल्पिक पैरामीटर: {0}", + "Save": "सहेजें", + "retriesDescription": "सेवा को डाउन के रूप में चिह्नित करने और सूचना भेजने से पहले अधिकतम पुनः प्रयासों की संख्या", + "Notifications": "सूचनाएँ", + "Check Update On GitHub": "गिटहब पर अपडेट जांचें", + "timeoutAfter": "{0} सेकंड के बाद समय सीमा समाप्त", + "upsideDownModeDescription": "स्थिति को उल्टा करें। यदि सेवा पहुंच योग्य है, तो यह DOWN है।", + "Upside Down Mode": "उल्टा मोड", + "Max. Redirects": "अधिकतम पुनर्निर्देश", + "Push URL": "पुश यूआरएल", + "Monitor": "मॉनिटर | मॉनिटर्स", + "maxRedirectDescription": "अनुसरण करने के लिए अधिकतम पुनर्निर्देशनों की संख्या। पुनर्निर्देशनों को अक्षम करने के लिए 0 पर सेट करें।", + "Advanced": "उन्नत", + "Invert Keyword": "कीवर्ड उलटें", + "Json Query Expression": "JSON क्वेरी अभिव्यक्ति", + "URL": "यूआरएल", + "Hostname": "होस्टनेम", + "Either enter the hostname of the server you want to connect to or localhost if you intend to use a locally configured mail transfer agent": "या तो उस सर्वर का होस्टनेम दर्ज करें जिससे आप कनेक्ट करना चाहते हैं या {localhost} यदि आप {local_mta} का उपयोग करना चाहते हैं", + "Resend Notification if Down X times consecutively": "यदि लगातार X बार डाउन हो, तो पुनः सूचना भेजें", + "resendEveryXTimes": "हर {0} बार में पुनः भेजें", + "resendDisabled": "पुनः भेजना निष्क्रिय किया गया है", + "ignoredTLSError": "TLS/SSL त्रुटियों को अनदेखा किया गया है", + "pushOthers": "अन्य", + "programmingLanguages": "प्रोग्रामिंग भाषाएँ", + "styleElapsedTimeShowNoLine": "दिखाएँ (कोई रेखा नहीं)", + "Expected Value": "अपेक्षित मान", + "ignoreTLSError": "HTTPS वेबसाइटों के लिए TLS/SSL त्रुटियों को अनदेखा करें", + "pushViewCode": "पुश मॉनिटर का उपयोग कैसे करें? (कोड देखें)" } diff --git a/src/lang/hr-HR.json b/src/lang/hr-HR.json index c00c1bf5d..ddde66c34 100644 --- a/src/lang/hr-HR.json +++ b/src/lang/hr-HR.json @@ -1082,5 +1082,14 @@ "Can be found on:": "Može se pronaći na: {0}", "The phone number of the recipient in E.164 format.": "Telefonski broj primatelja u formatu E.164.", "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Ili identifikator pošiljatelja tekstualne poruke ili telefonski broj u formatu E.164 ako želite primati odgovore.", - "jsonQueryDescription": "Izvršite JSON upit nad primljenim odgovorom i provjerite očekivanu povratnu vrijednost. Koristite \"$\" za zahtjeve u kojima ne očekujete JSON odgovor. Povratna vrijednost će se za usporedbu pretvoriti u niz znakova (string). Pogledajte stranicu {0} za dokumentaciju o jeziku upita. Testno okruženje možete pronaći na {1}." + "jsonQueryDescription": "Izvršite JSON upit nad primljenim odgovorom i provjerite očekivanu povratnu vrijednost. Koristite \"$\" za zahtjeve u kojima ne očekujete JSON odgovor. Povratna vrijednost će se za usporedbu pretvoriti u niz znakova (string). Pogledajte stranicu {0} za dokumentaciju o jeziku upita. Testno okruženje možete pronaći na {1}.", + "rabbitmqNodesRequired": "Postavite čvorove za ovaj Monitor.", + "rabbitmqNodesInvalid": "Koristite potpuni URL (onaj koji počinje s 'http') za RabbitMQ čvorove.", + "RabbitMQ Username": "RabbitMQ korisničko ime", + "RabbitMQ Password": "RabbitMQ lozinka", + "SendGrid API Key": "SendGrid API ključ", + "Separate multiple email addresses with commas": "Više adresa e-pošte potrebno je odvojiti zarezima", + "RabbitMQ Nodes": "RabbitMQ upravljački čvorovi", + "rabbitmqNodesDescription": "Unesite URL za upravljačke čvorove RabbitMQ uključujući protokol i port. Primjer: {0}", + "rabbitmqHelpText": "Za korištenje ovog Monitora morat ćete omogućiti dodatak \"Management Plugin\" u svom RabbitMQ-u. Za više informacija pogledajte {rabitmq_documentation}." } diff --git a/src/lang/id-ID.json b/src/lang/id-ID.json index 1f2676a3d..52cb59a75 100644 --- a/src/lang/id-ID.json +++ b/src/lang/id-ID.json @@ -119,7 +119,7 @@ "Password": "Sandi", "Remember me": "Ingat saya", "Login": "Masuk", - "No Monitors, please": "Tolong, jangan ada Monitor", + "No Monitors, please": "Tidak ada monitor, silakan", "add one": "tambahkan satu", "Notification Type": "Tipe Notifikasi", "Email": "Surel", @@ -1052,5 +1052,41 @@ "Copy": "Salin", "CopyToClipboardError": "Tidak bisa menyalin ke papan klip: {galat}", "CopyToClipboardSuccess": "Tersalin!", - "CurlDebugInfo": "Untuk pengawakutuan monitor, Anda bisa menempelkan ini ke terminal mesin Anda sendiri atau ke terminal mesin di mana uptime kuma sedang berjalan dan melihat apa yang Anda harapkan. Mohon perhatikan perbedaan jaringan seperti {firewalls}, {dns_resolvers}, atau {docker_networks}." + "CurlDebugInfo": "Untuk pengawakutuan monitor, Anda bisa menempelkan ini ke terminal mesin Anda sendiri atau ke terminal mesin di mana uptime kuma sedang berjalan dan melihat apa yang Anda harapkan. Mohon perhatikan perbedaan jaringan seperti {firewalls}, {dns_resolvers}, atau {docker_networks}.", + "aboutSlackUsername": "Mengubah nama tampilan pengirim pesan. Jika Anda ingin menyebut seseorang, sertakan dalam nama yang mudah diingat.", + "Message format": "Format pesan", + "Sound": "Suara", + "Alphanumerical string and hyphens only": "Hanya string alfanumerik dan tanda hubung", + "Elevator": "Pengundak", + "Custom sound to override default notification sound": "Suara khusus untuk mengganti suara notifikasi bawaan", + "Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.": "Pemberitahuan yang sensitif terhadap waktu akan segera dikirimkan, meskipun perangkat dalam mode jangan ganggu.", + "RabbitMQ Nodes": "RabbitMQ Management Nodes", + "rabbitmqNodesDescription": "Masukkan URL untuk node manajemen RabbitMQ termasuk protokol dan port. Contoh: {0}", + "RabbitMQ Password": "Kata kunci RabbitMQ", + "rabbitmqHelpText": "Untuk menggunakan monitor, Anda perlu mengaktifkan Plugin Manajemen di pengaturan RabbitMQ Anda. Untuk informasi lebih lanjut, silakan baca {rabitmq_documentation}.", + "rabbitmqNodesRequired": "Harap atur node untuk monitor ini.", + "rabbitmqNodesInvalid": "Harap gunakan URL yang memenuhi syarat (dimulai dengan 'http') untuk node RabbitMQ.", + "RabbitMQ Username": "Nama pengguna RabbitMQ", + "Notification Channel": "Notifikasi Kanal", + "Send rich messages": "Kirim rich messages", + "Arcade": "Arkade", + "Correct": "Benar", + "Fail": "Gagal", + "Harp": "Harpa", + "Reveal": "Mengungkap", + "Bubble": "Gelembung", + "Doorbell": "Bel pintu", + "Flute": "Seruling", + "Money": "Uang", + "Scifi": "Fiksi ilmiah", + "Clear": "Jernih", + "Guitar": "Gitar", + "Pop": "Letupan", + "Time Sensitive (iOS Only)": "Sensitif terhadap Waktu (Khusus iOS)", + "From": "Dari", + "Can be found on:": "Bisa ditemukan di: {0}", + "The phone number of the recipient in E.164 format.": "Nomor telepon penerima dalam format E.164.", + "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Antara ID pengirim teks atau nomor telepon dalam format E.164 jika Anda ingin menerima balasan.", + "SendGrid API Key": "Kunci API SendGrid", + "Separate multiple email addresses with commas": "Pisahkan beberapa alamat email dengan koma" } diff --git a/src/lang/tr-TR.json b/src/lang/tr-TR.json index 077919fae..812e44175 100644 --- a/src/lang/tr-TR.json +++ b/src/lang/tr-TR.json @@ -1088,5 +1088,14 @@ "ignoredTLSError": "TLS/SSL hataları göz ardı edildi", "CurlDebugInfo": "Monitörü hata ayıklamak için, bunu kendi makinenizin terminaline veya uptime kuma'nın çalıştığı makinenin terminaline yapıştırabilir ve ne istediğinizi görebilirsiniz.{newiline}Lütfen {firewalls}, {dns_resolvers} veya {docker_networks} gibi ağ farklılıklarına dikkat edin.", "Time sensitive notifications will be delivered immediately, even if the device is in do not disturb mode.": "Cihaz rahatsız etmeyin modunda olsa bile, zaman açısından hassas bildirimler anında iletilecek.", - "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Cevap alabilmek istiyorsanız E.164 formatında bir kısa mesaj gönderici kimliği veya bir telefon numarası." + "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Cevap alabilmek istiyorsanız E.164 formatında bir kısa mesaj gönderici kimliği veya bir telefon numarası.", + "rabbitmqNodesRequired": "Lütfen bu monitör için sunucuları ayarlayın.", + "rabbitmqNodesInvalid": "Lütfen RabbitMQ düğümleri için tam nitelikli ('http' ile başlayan) bir URL kullanın.", + "RabbitMQ Username": "RabbitMQ Kullanıcı Adı", + "RabbitMQ Password": "RabbitMQ Şifresi", + "SendGrid API Key": "SendGrid API Anahtarı", + "Separate multiple email addresses with commas": "Birden fazla e-posta adresini virgülle ayırın", + "RabbitMQ Nodes": "RabbitMQ Yönetim Sunucuları", + "rabbitmqNodesDescription": "Protokol ve port dahil olmak üzere RabbitMQ yönetim düğümleri için URL'yi girin. Örnek: {0}", + "rabbitmqHelpText": "Monitörü kullanmak için, RabbitMQ kurulumunuzda Yönetim Eklentisini etkinleştirmeniz gerekecektir. Daha fazla bilgi için lütfen {rabitmq_documentation}'a bakın." } diff --git a/src/lang/uk-UA.json b/src/lang/uk-UA.json index 24dddf657..913e856c9 100644 --- a/src/lang/uk-UA.json +++ b/src/lang/uk-UA.json @@ -1094,5 +1094,14 @@ "CurlDebugInfo": "Для налагодження монітора ви можете вставити цей файл у термінал вашої власної машини або у термінал машини, на якій запущено uptime kuma, і подивитися, що ви запитуєте.{newline}Зверніть увагу на мережеві відмінності, такі як {firewalls}, {dns_resolvers} або {docker_networks}.", "CurlDebugInfoOAuth2CCUnsupported": "Повний потік облікових даних клієнта oauth не підтримується в {curl}.{newline}Потрібно отримати bearer-токен і передати його за допомогою опції {oauth2_bearer}.", "Can be found on:": "Можна знайти на: {0}", - "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Або ідентифікатор відправника тексту, або номер телефону у форматі E.164, якщо ви хочете отримувати відповіді." + "Either a text sender ID or a phone number in E.164 format if you want to be able to receive replies.": "Або ідентифікатор відправника тексту, або номер телефону у форматі E.164, якщо ви хочете отримувати відповіді.", + "rabbitmqNodesRequired": "Будь ласка, встановіть вузли для цього монітора.", + "RabbitMQ Username": "Ім'я користувача RabbitMQ", + "RabbitMQ Password": "Пароль RabbitMQ", + "SendGrid API Key": "API-ключ SendGrid", + "Separate multiple email addresses with commas": "Розділяйте кілька адрес комами", + "RabbitMQ Nodes": "Вузли керування RabbitMQ", + "rabbitmqNodesDescription": "Введіть URL-адресу для вузлів керування RabbitMQ, включаючи протокол і порт. Приклад: {0}", + "rabbitmqNodesInvalid": "Будь ласка, використовуйте повну URL-адресу (починаючи з 'http') для вузлів RabbitMQ.", + "rabbitmqHelpText": "Щоб використовувати монітор, вам потрібно увімкнути плагін керування у налаштуваннях RabbitMQ. Для отримання додаткової інформації, будь ласка, зверніться до {rabitmq_documentation}." } diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index 8b14e6c5d..945c9f00b 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -1090,5 +1090,15 @@ "Money": "Money(钱)", "CurlDebugInfoOAuth2CCUnsupported": "{curl} 不支持完整的 oauth 客户端凭证流。{newline}请获取承载令牌(bearer token)并通过 {oauth2_bearer} 选项传递。", "CurlDebugInfo": "要调试监控项,您可以将该命令粘贴到您自己的或 uptime kuma 正在运行的机器的命令行终端中,并查看结果。{newiline}请注意网络差异,例如 {firewalls}、{dns_resolvers} 或 {docker_networks}。", - "ignoredTLSError": "TLS/SSL 错误已被忽略" + "ignoredTLSError": "TLS/SSL 错误已被忽略", + "SendGrid API Key": "SendGrid API 密钥", + "RabbitMQ Password": "RabbitMQ 密码", + "RabbitMQ Username": "RabbitMQ 用户名", + "rabbitmqNodesInvalid": "请使用 RabbitMQ 节点的完整 URL(即完全限定 URL,以 http 开头)。", + "rabbitmqNodesRequired": "请设置此监视项的节点。", + "rabbitmqNodesDescription": "输入 RabbitMQ 管理节点的 URL,包括协议和端口。例如:{0}", + "RabbitMQ Nodes": "RabbitMQ 管理节点", + "Separate multiple email addresses with commas": "用逗号分隔多个电子邮件地址", + "rabbitmqHelpText": "要使用此监控项,您需要在 RabbitMQ 设置中启用管理插件。有关更多信息,请参阅 {rabitmq_documentation}。", + "aboutSlackUsername": "更改消息发件人的显示名称。如果您想提及某人,请另行将其包含在友好名称中。" }