From 7f2c3bce87ebd12821214cf56daf231dc615b321 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Fri, 20 Jun 2025 09:25:58 +0000 Subject: [PATCH 01/51] doc: clearer explanation of `.user.js` url support --- README.md | 10 +++++++--- src/app/_locales/en/quick-start-guide-ios.md | 7 +++++-- src/app/_locales/en/quick-start-guide-mac.md | 10 +++++++++- src/app/_locales/zh/quick-start-guide-ios.md | 7 +++++-- src/app/_locales/zh/quick-start-guide-mac.md | 10 +++++++++- src/app/_locales/zh_Hant/quick-start-guide-ios.md | 7 +++++-- src/app/_locales/zh_Hant/quick-start-guide-mac.md | 10 +++++++++- 7 files changed, 49 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index b000d558..9c163dc2 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,9 @@ After installing the iOS App, you need two main steps to make the extension work There are two main ways to install a user script from the iOS version: -- Visit any `.user.js` URL in Safari, then open the extension `popup` and you will see an installation prompt -- You can also save `.user.js` files directly to the Userscripts directory you set above +- Visit a `.user.js` URL in Safari, then open the extension `popup` and you will see an installation prompt +- The URL should ending with `.user.js` in `PATH` part, not the `?QUERY` or `#HASH` parts +- You could also save files that extension with `.user.js` directly to the Userscripts directory you set above > [!TIP] > @@ -177,10 +178,13 @@ Userscripts Safari currently supports the following userscript metadata: - when paired with `@updateURL`, this will allow the user to update a userscript from a remote source, if the version on their machine is `<` version at the update URL - `@version` does nothing by itself, it needs to be paired with` @updateURL` for remote updating to function properly - `@updateURL` - - the remote url to check version against + - the remote url to check version against, the url `PATH` should ending with `.meta.js` and contains the Metadata block - if the version of the file located at the update URL is `>` the version on the local machine, the file will be updated - `@updateURL` does nothing by itself, it needs to be paired with `@version` for remote updating to function properly + - Read this [link](https://stackoverflow.com/questions/38023717/) for more details + - _Note: The extension does not correctly implement the entire update process, tracking in issue [#248](https://github.com/quoid/userscripts/issues/248)_ - `@downloadURL` + - the url `PATH` should ending with `.user.js`, that is, it cannot be in `?QUERY` or `#HASH` parts - optional download location for a remotely updateable file (\*i.e. a file that has both `@version` and `@updateURL`) - when paired with `@version` and `@updateURL`, if the local version is `<` the version of the file that `@updateURL` points to, the extension will attempt to update the file's code with the contents of the file located at the `@downloadURL` - `@downloadURL` does nothing by itself, it needs `@version` and `@updateURL` to present in order to function properly diff --git a/src/app/_locales/en/quick-start-guide-ios.md b/src/app/_locales/en/quick-start-guide-ios.md index 7f0c38f3..3f134782 100644 --- a/src/app/_locales/en/quick-start-guide-ios.md +++ b/src/app/_locales/en/quick-start-guide-ios.md @@ -14,8 +14,11 @@ ### How to you install a user script -- Visit any `.user.js` URL in Safari, then open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. -- You can also save `.user.js` files directly to the Userscripts directory. The script file must contain a valid metadata block to match the page and be displayed in the extension popup. +- The mobile extension does not currently have a built-in script editor, but you could still write your own scripts and install them. +- You could save files that extension with `.user.js` directly to the Userscripts directory. + - The script file must contain a valid metadata block to match the web pages and be displayed in the extension popup. +- When you visit a `.user.js` URL in Safari, open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. + - The URL should ending with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. ### That’s it, start improving your quality of life now! diff --git a/src/app/_locales/en/quick-start-guide-mac.md b/src/app/_locales/en/quick-start-guide-mac.md index 27623afa..5f0b26eb 100644 --- a/src/app/_locales/en/quick-start-guide-mac.md +++ b/src/app/_locales/en/quick-start-guide-mac.md @@ -12,6 +12,14 @@ - Enable Userscripts in Safari extensions list. - For an optimal experience it's recommended that you "Always Allow" Userscripts for "All Websites", but you could also allow only the sites you want, but please don't forget your settings if your script doesn't work. -That’s it, start improving your quality of life now! +### How to you install a user script + +- The preferred method is of course to create your own scripts, open the extension page and click on the plus sign in the editor to create a new JS, write code and save it. +- You could also save files that extension with `.user.js` directly to the Userscripts directory. + - The script file must contain a valid metadata block to match the web pages and be displayed in the extension popup. +- When you visit a `.user.js` URL in Safari, open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. + - The URL should ending with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. + +### That’s it, start improving your quality of life now! _Hey, don't forget to read our detailed documentation to learn more._ diff --git a/src/app/_locales/zh/quick-start-guide-ios.md b/src/app/_locales/zh/quick-start-guide-ios.md index 8817c19f..4ee730d4 100644 --- a/src/app/_locales/zh/quick-start-guide-ios.md +++ b/src/app/_locales/zh/quick-start-guide-ios.md @@ -13,8 +13,11 @@ ### 那么,如何安装用户脚本? -- 在 Safari 中访问任何 `.user.js` 网址,然后打开扩展弹出窗口,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 -- 您还可以将 `.user.js` 文件直接保存到您上面设置的 Userscripts 目录中,脚本文件必须包含有效的元数据块以匹配页面并显示在扩展弹出窗口中。 +- 移动版扩展目前不包含内置的脚本编辑器,但您仍然可以编写您自己的脚本并安装它们。 +- 您可以直接保存扩展名为 `.user.js` 的文件到您上面设置的 Userscripts 目录中。 + - 您的脚本文件必须包含有效的元数据块以匹配网站页面并正确显示在扩展的弹出窗口中。 +- 当您在 Safari 中访问一个 `.user.js` 网址,然后打开扩展弹出窗口,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 + - 请注意该网址的 `/路径` 部分应该以 `.user.js` 结尾,而不是 `?查询` 或 `#锚点` 部分,否则该网址将不会被视为有效的用户脚本。 ### 就这样,现在就开始改善您的生活质量吧! diff --git a/src/app/_locales/zh/quick-start-guide-mac.md b/src/app/_locales/zh/quick-start-guide-mac.md index e0ffc0d0..ad86d6db 100644 --- a/src/app/_locales/zh/quick-start-guide-mac.md +++ b/src/app/_locales/zh/quick-start-guide-mac.md @@ -11,6 +11,14 @@ - 在 Safari 扩展列表中启用 Userscripts 条目。 - 为了获得最佳体验,建议您“始终允许” Userscripts 为“所有网站”,但您也可以仅允许您想要的网站,但当您的脚本不起作用时,请不要忘记您的设置。 -就这样,现在就开始改善您的生活质量吧! +### 那么,如何安装用户脚本? + +- 首选的方法当然是撰写您自己的用户脚本,打开扩展页面点击加号创建新脚本,编辑和保存它。 +- 您还可以直接保存扩展名为 `.user.js` 的文件到您上面设置的 Userscripts 目录中。 + - 您的脚本文件必须包含有效的元数据块以匹配网站页面并正确显示在扩展的弹出窗口中。 +- 当您在 Safari 中访问一个 `.user.js` 网址,然后打开扩展弹出窗口,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 + - 请注意该网址的 `/路径` 部分应该以 `.user.js` 结尾,而不是 `?查询` 或 `#锚点` 部分,否则该网址将不会被视为有效的用户脚本。 + +### 就这样,现在就开始改善您的生活质量吧! _嘿,不要忘记阅读我们的详细文档以了解更多信息。_ diff --git a/src/app/_locales/zh_Hant/quick-start-guide-ios.md b/src/app/_locales/zh_Hant/quick-start-guide-ios.md index 7bd6876d..8564e25f 100644 --- a/src/app/_locales/zh_Hant/quick-start-guide-ios.md +++ b/src/app/_locales/zh_Hant/quick-start-guide-ios.md @@ -13,8 +13,11 @@ ### 那麼,如何安裝使用者腳本? -- 在 Safari 中訪問任何 `.user.js` 網址,然後開啟延伸功能彈出視窗,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 -- 您還可以將 `.user.js` 檔案直接儲存到您上面設定的 Userscripts 目錄中,腳本檔案必須包含有效的元資料塊以匹配頁面並顯示在延伸功能彈出視窗中。 +- 移動版延伸功能目前不包含內建的腳本編輯器,但您仍然可以編寫您自己的腳本並安裝它們。 +- 您可以直接儲存副檔名為 `.user.js` 的檔案到您上面設定的 Userscripts 目錄中。 + - 您的腳本檔案必須包含有效的元資料塊以匹配網站頁面並正確顯示在延伸功能的彈出視窗中。 +- 當您在 Safari 中訪問一個 `.user.js` 網址,然後開啟延伸功能彈出視窗,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 + - 請注意該網址的 `/路徑` 部分應該以 `.user.js` 結尾,而不是 `?查詢` 或 `#錨點` 部分,否則該網址將不會被視為有效的使用者腳本。 ### 就這樣,現在就開始改善您的生活質量吧! diff --git a/src/app/_locales/zh_Hant/quick-start-guide-mac.md b/src/app/_locales/zh_Hant/quick-start-guide-mac.md index 74902b9c..611d40c2 100644 --- a/src/app/_locales/zh_Hant/quick-start-guide-mac.md +++ b/src/app/_locales/zh_Hant/quick-start-guide-mac.md @@ -11,6 +11,14 @@ - 在 Safari 延伸功能列表中啟用 Userscripts 條目。 - 為了獲得最佳體驗,建議您“始終允許” Userscripts 為“所有網站”,但您也可以僅允許您想要的網站,但當您的腳本不起作用時,請不要忘記您的設定。 -就這樣,現在就開始改善您的生活質量吧! +### 那麼,如何安裝使用者腳本? + +- 首選的方法當然是撰寫您自己的使用者腳本,開啟延伸功能頁面點選加號建立新腳本,編輯和儲存它。 +- 您還可以直接儲存副檔名為 `.user.js` 的檔案到您上面設定的 Userscripts 目錄中。 + - 您的腳本檔案必須包含有效的元資料塊以匹配網站頁面並正確顯示在延伸功能的彈出視窗中。 +- 當您在 Safari 中訪問一個 `.user.js` 網址,然後開啟延伸功能彈出視窗,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 + - 請注意該網址的 `/路徑` 部分應該以 `.user.js` 結尾,而不是 `?查詢` 或 `#錨點` 部分,否則該網址將不會被視為有效的使用者腳本。 + +### 就這樣,現在就開始改善您的生活質量吧! _嘿,不要忘記閱讀我們的詳細文件以瞭解更多資訊。_ From 624f523595d40e8c91284bef05430ec49d792f88 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Fri, 20 Jun 2025 09:34:43 +0000 Subject: [PATCH 02/51] fix: consistent in different code paths --- xcode/Ext-Safari/Functions.swift | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/xcode/Ext-Safari/Functions.swift b/xcode/Ext-Safari/Functions.swift index 77431ac9..7163c9eb 100644 --- a/xcode/Ext-Safari/Functions.swift +++ b/xcode/Ext-Safari/Functions.swift @@ -59,10 +59,12 @@ func validateUrl(_ urlString: String) -> Bool { logger?.error("\(#function, privacy: .public) - Invalid URL: \(urlString, privacy: .public)") return false } - if - (ptcl != "https:" && ptcl != "http:") - || (!path.hasSuffix(".css") && !path.hasSuffix(".js")) - { + if ptcl != "https:" && ptcl != "http:" { + logger?.error("\(#function, privacy: .public) - Invalid URL protocol: \(urlString, privacy: .public)") + return false + } + if !path.hasSuffix(".css") && !path.hasSuffix(".js") { + logger?.error("\(#function, privacy: .public) - Invalid URL suffix: \(urlString, privacy: .public)") return false } return true @@ -829,7 +831,7 @@ func checkForRemoteUpdates(_ optionalFilesArray: [[String: Any]] = []) -> [[Stri let currentVersion = metadata["version"]![0] let updateUrl = metadata["updateURL"]![0] // before fetching remote contents, ensure it points to a file of the same type - if !updateUrl.hasSuffix(type) {continue} + if !validateUrl(updateUrl) {continue} guard let remoteFileContents = getRemoteFileContents(updateUrl), let remoteFileContentsParsed = parse(remoteFileContents), @@ -1812,7 +1814,7 @@ func getFileRemoteUpdate(_ content: String) -> [String: String] { return ["error": "Update failed, couldn't parse remote file contents"] } // check if update is needed - if version >= remoteVersion { + if !isVersionNewer(version, remoteVersion) { return ["info": "No updates found"] } // at this point it is known an update is available, get new code from downloadURL From 52b257bdf44ff57b4797177221a20a5ce24587cf Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Fri, 20 Jun 2025 10:15:45 +0000 Subject: [PATCH 03/51] chore: apply suggestions from code review --- README.md | 8 ++++---- src/app/_locales/en/quick-start-guide-ios.md | 2 +- src/app/_locales/en/quick-start-guide-mac.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 9c163dc2..d0601bfc 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ After installing the iOS App, you need two main steps to make the extension work There are two main ways to install a user script from the iOS version: - Visit a `.user.js` URL in Safari, then open the extension `popup` and you will see an installation prompt -- The URL should ending with `.user.js` in `PATH` part, not the `?QUERY` or `#HASH` parts -- You could also save files that extension with `.user.js` directly to the Userscripts directory you set above + - The URL should end with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts +- You could also save files with the extension `.user.js` directly to the Userscripts directory you set above > [!TIP] > @@ -178,13 +178,13 @@ Userscripts Safari currently supports the following userscript metadata: - when paired with `@updateURL`, this will allow the user to update a userscript from a remote source, if the version on their machine is `<` version at the update URL - `@version` does nothing by itself, it needs to be paired with` @updateURL` for remote updating to function properly - `@updateURL` - - the remote url to check version against, the url `PATH` should ending with `.meta.js` and contains the Metadata block + - the remote url to check version against, the url `/PATH` should end with `.meta.js` and contains the Metadata block - if the version of the file located at the update URL is `>` the version on the local machine, the file will be updated - `@updateURL` does nothing by itself, it needs to be paired with `@version` for remote updating to function properly - Read this [link](https://stackoverflow.com/questions/38023717/) for more details - _Note: The extension does not correctly implement the entire update process, tracking in issue [#248](https://github.com/quoid/userscripts/issues/248)_ - `@downloadURL` - - the url `PATH` should ending with `.user.js`, that is, it cannot be in `?QUERY` or `#HASH` parts + - the url `/PATH` should end with `.user.js`, that is, it cannot be in `?QUERY` or `#HASH` parts - optional download location for a remotely updateable file (\*i.e. a file that has both `@version` and `@updateURL`) - when paired with `@version` and `@updateURL`, if the local version is `<` the version of the file that `@updateURL` points to, the extension will attempt to update the file's code with the contents of the file located at the `@downloadURL` - `@downloadURL` does nothing by itself, it needs `@version` and `@updateURL` to present in order to function properly diff --git a/src/app/_locales/en/quick-start-guide-ios.md b/src/app/_locales/en/quick-start-guide-ios.md index 3f134782..976eeb37 100644 --- a/src/app/_locales/en/quick-start-guide-ios.md +++ b/src/app/_locales/en/quick-start-guide-ios.md @@ -18,7 +18,7 @@ - You could save files that extension with `.user.js` directly to the Userscripts directory. - The script file must contain a valid metadata block to match the web pages and be displayed in the extension popup. - When you visit a `.user.js` URL in Safari, open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. - - The URL should ending with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. + - The URL should end with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. ### That’s it, start improving your quality of life now! diff --git a/src/app/_locales/en/quick-start-guide-mac.md b/src/app/_locales/en/quick-start-guide-mac.md index 5f0b26eb..aefe28fb 100644 --- a/src/app/_locales/en/quick-start-guide-mac.md +++ b/src/app/_locales/en/quick-start-guide-mac.md @@ -18,7 +18,7 @@ - You could also save files that extension with `.user.js` directly to the Userscripts directory. - The script file must contain a valid metadata block to match the web pages and be displayed in the extension popup. - When you visit a `.user.js` URL in Safari, open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. - - The URL should ending with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. + - The URL should end with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. ### That’s it, start improving your quality of life now! From b2dc7f5049bf5d168648c771a0cc2568f354c234 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sat, 21 Jun 2025 04:05:47 +0000 Subject: [PATCH 04/51] doc: adjust guide text --- src/app/_locales/en/quick-start-guide-ios.md | 4 +++- src/app/_locales/en/quick-start-guide-mac.md | 6 ++++-- src/app/_locales/zh/quick-start-guide-ios.md | 10 ++++++---- src/app/_locales/zh/quick-start-guide-mac.md | 10 ++++++---- src/app/_locales/zh_Hant/quick-start-guide-ios.md | 10 ++++++---- src/app/_locales/zh_Hant/quick-start-guide-mac.md | 10 ++++++---- 6 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/app/_locales/en/quick-start-guide-ios.md b/src/app/_locales/en/quick-start-guide-ios.md index 976eeb37..4bc2316b 100644 --- a/src/app/_locales/en/quick-start-guide-ios.md +++ b/src/app/_locales/en/quick-start-guide-ios.md @@ -12,13 +12,15 @@ - Manage extensions from the Settings App (Settings > Safari > Extensions) or Safari App (`AA` button on iPhone, `extension-icon` on iPad, the same location where you open the extension's `popup` interface). - For an optimal experience it's recommended that you "Always Allow" Userscripts for "All Websites", but you could also allow only the sites you want, but please don't forget your settings if your script doesn't work. -### How to you install a user script +### How to install and inject a user script and some things to note: - The mobile extension does not currently have a built-in script editor, but you could still write your own scripts and install them. - You could save files that extension with `.user.js` directly to the Userscripts directory. - The script file must contain a valid metadata block to match the web pages and be displayed in the extension popup. - When you visit a `.user.js` URL in Safari, open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. - The URL should end with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. +- When you enabled the extension and write the metadata correctly especially like `@match`, it will automatically complete the injection when you visit a matching web page. + - You could temporarily disable individual user scripts or all of them, just open the extension popup interface to toggle them. ### That’s it, start improving your quality of life now! diff --git a/src/app/_locales/en/quick-start-guide-mac.md b/src/app/_locales/en/quick-start-guide-mac.md index aefe28fb..c6ae6ef7 100644 --- a/src/app/_locales/en/quick-start-guide-mac.md +++ b/src/app/_locales/en/quick-start-guide-mac.md @@ -9,16 +9,18 @@ - **Enable the extension in Safari** - - Enable Userscripts in Safari extensions list. + - Enable Userscripts in Safari > Settings... > Extensions list. - For an optimal experience it's recommended that you "Always Allow" Userscripts for "All Websites", but you could also allow only the sites you want, but please don't forget your settings if your script doesn't work. -### How to you install a user script +### How to install and inject a user script and some things to note: - The preferred method is of course to create your own scripts, open the extension page and click on the plus sign in the editor to create a new JS, write code and save it. - You could also save files that extension with `.user.js` directly to the Userscripts directory. - The script file must contain a valid metadata block to match the web pages and be displayed in the extension popup. - When you visit a `.user.js` URL in Safari, open the extension popup and you will see an installation prompt, or it will pop up automatically if you have enhanced prompts turned on. - The URL should end with `.user.js` in `/PATH` part, not the `?QUERY` or `#HASH` parts, otherwise it will not be considered a valid user script URL by the extension. +- When you enabled the extension and write the metadata correctly especially like `@match`, it will automatically complete the injection when you visit a matching web page. + - You could temporarily disable individual user scripts or all of them, just open the extension popup interface to toggle them. ### That’s it, start improving your quality of life now! diff --git a/src/app/_locales/zh/quick-start-guide-ios.md b/src/app/_locales/zh/quick-start-guide-ios.md index 4ee730d4..d24bda16 100644 --- a/src/app/_locales/zh/quick-start-guide-ios.md +++ b/src/app/_locales/zh/quick-start-guide-ios.md @@ -8,16 +8,18 @@ - **在 Safari 中启用扩展** - - 从设置应用程序(设置 > Safari > 扩展程序)或 Safari 应用程序(iPhone 上的“AA”按钮,iPad 上的“扩展图标”,也是您打开扩展程序的“弹出”界面的位置)管理扩展程序。 + - 从 `设置` 应用(设置 > Safari > 扩展)或 `Safari` 应用(iPhone 上的“AA”按钮,iPad 上的“扩展图标”,也是您打开扩展的“弹出界面”的位置)管理扩展。 - 为了获得最佳体验,建议您“始终允许” Userscripts 为“所有网站”,但您也可以仅允许您想要的网站,但当您的脚本不起作用时,请不要忘记您的设置。 -### 那么,如何安装用户脚本? +### 那么,如何安装和注入用户脚本,以及一些注意事项? - 移动版扩展目前不包含内置的脚本编辑器,但您仍然可以编写您自己的脚本并安装它们。 - 您可以直接保存扩展名为 `.user.js` 的文件到您上面设置的 Userscripts 目录中。 - - 您的脚本文件必须包含有效的元数据块以匹配网站页面并正确显示在扩展的弹出窗口中。 -- 当您在 Safari 中访问一个 `.user.js` 网址,然后打开扩展弹出窗口,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 + - 您的脚本文件必须包含有效的元数据块以匹配网站页面并正确显示在扩展的弹出界面中。 +- 当您在 Safari 中访问一个 `.user.js` 网址,然后打开扩展弹出界面,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 - 请注意该网址的 `/路径` 部分应该以 `.user.js` 结尾,而不是 `?查询` 或 `#锚点` 部分,否则该网址将不会被视为有效的用户脚本。 +- 当您启用该扩展并正确编写元数据尤其是像 `@match` 后,当您访问匹配的网页时,它将自动完成注入。 + - 您可以暂时禁用单个用户脚本或所有用户脚本,只需打开扩展弹出界面即可切换它们。 ### 就这样,现在就开始改善您的生活质量吧! diff --git a/src/app/_locales/zh/quick-start-guide-mac.md b/src/app/_locales/zh/quick-start-guide-mac.md index ad86d6db..f9983ced 100644 --- a/src/app/_locales/zh/quick-start-guide-mac.md +++ b/src/app/_locales/zh/quick-start-guide-mac.md @@ -8,16 +8,18 @@ - **在 Safari 中启用扩展** - - 在 Safari 扩展列表中启用 Userscripts 条目。 + - 在 Safari > 设置... > 扩展列表中启用 Userscripts 条目。 - 为了获得最佳体验,建议您“始终允许” Userscripts 为“所有网站”,但您也可以仅允许您想要的网站,但当您的脚本不起作用时,请不要忘记您的设置。 -### 那么,如何安装用户脚本? +### 那么,如何安装和注入用户脚本,以及一些注意事项? - 首选的方法当然是撰写您自己的用户脚本,打开扩展页面点击加号创建新脚本,编辑和保存它。 - 您还可以直接保存扩展名为 `.user.js` 的文件到您上面设置的 Userscripts 目录中。 - - 您的脚本文件必须包含有效的元数据块以匹配网站页面并正确显示在扩展的弹出窗口中。 -- 当您在 Safari 中访问一个 `.user.js` 网址,然后打开扩展弹出窗口,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 + - 您的脚本文件必须包含有效的元数据块以匹配网站页面并正确显示在扩展的弹出界面中。 +- 当您在 Safari 中访问一个 `.user.js` 网址,然后打开扩展弹出界面,您将看到安装提示;如果您启用了增强提示,它会自动弹出。 - 请注意该网址的 `/路径` 部分应该以 `.user.js` 结尾,而不是 `?查询` 或 `#锚点` 部分,否则该网址将不会被视为有效的用户脚本。 +- 当您启用该扩展并正确编写元数据尤其是像 `@match` 后,当您访问匹配的网页时,它将自动完成注入。 + - 您可以暂时禁用单个用户脚本或所有用户脚本,只需打开扩展弹出界面即可切换它们。 ### 就这样,现在就开始改善您的生活质量吧! diff --git a/src/app/_locales/zh_Hant/quick-start-guide-ios.md b/src/app/_locales/zh_Hant/quick-start-guide-ios.md index 8564e25f..0d7f5e51 100644 --- a/src/app/_locales/zh_Hant/quick-start-guide-ios.md +++ b/src/app/_locales/zh_Hant/quick-start-guide-ios.md @@ -8,16 +8,18 @@ - **在 Safari 中啟用延伸功能** - - 從設定應用程式(設定 > Safari > 延伸功能程式)或 Safari 應用程式(iPhone 上的“AA”按鈕,iPad 上的“延伸功能圖示”,也是您開啟延伸功能程式的“彈出”介面的位置)管理延伸功能程式。 + - 從 `設定` 應用(設定 > Safari > 延伸功能)或 `Safari` 應用(iPhone 上的“AA”按鈕,iPad 上的“延伸功能圖示”,也是您開啟延伸功能的“彈出介面”的位置)管理延伸功能。 - 為了獲得最佳體驗,建議您“始終允許” Userscripts 為“所有網站”,但您也可以僅允許您想要的網站,但當您的腳本不起作用時,請不要忘記您的設定。 -### 那麼,如何安裝使用者腳本? +### 那麼,如何安裝和注入使用者腳本,以及一些注意事項? - 移動版延伸功能目前不包含內建的腳本編輯器,但您仍然可以編寫您自己的腳本並安裝它們。 - 您可以直接儲存副檔名為 `.user.js` 的檔案到您上面設定的 Userscripts 目錄中。 - - 您的腳本檔案必須包含有效的元資料塊以匹配網站頁面並正確顯示在延伸功能的彈出視窗中。 -- 當您在 Safari 中訪問一個 `.user.js` 網址,然後開啟延伸功能彈出視窗,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 + - 您的腳本檔案必須包含有效的元資料塊以匹配網站頁面並正確顯示在延伸功能的彈出介面中。 +- 當您在 Safari 中訪問一個 `.user.js` 網址,然後開啟延伸功能彈出介面,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 - 請注意該網址的 `/路徑` 部分應該以 `.user.js` 結尾,而不是 `?查詢` 或 `#錨點` 部分,否則該網址將不會被視為有效的使用者腳本。 +- 當您啟用該延伸功能並正確編寫元資料尤其是像 `@match` 後,當您訪問匹配的網頁時,它將自動完成注入。 + - 您可以暫時禁用單個使用者腳本或所有使用者腳本,只需開啟延伸功能彈出介面即可切換它們。 ### 就這樣,現在就開始改善您的生活質量吧! diff --git a/src/app/_locales/zh_Hant/quick-start-guide-mac.md b/src/app/_locales/zh_Hant/quick-start-guide-mac.md index 611d40c2..3331a109 100644 --- a/src/app/_locales/zh_Hant/quick-start-guide-mac.md +++ b/src/app/_locales/zh_Hant/quick-start-guide-mac.md @@ -8,16 +8,18 @@ - **在 Safari 中啟用延伸功能** - - 在 Safari 延伸功能列表中啟用 Userscripts 條目。 + - 在 Safari > 設定... > 延伸功能列表中啟用 Userscripts 條目。 - 為了獲得最佳體驗,建議您“始終允許” Userscripts 為“所有網站”,但您也可以僅允許您想要的網站,但當您的腳本不起作用時,請不要忘記您的設定。 -### 那麼,如何安裝使用者腳本? +### 那麼,如何安裝和注入使用者腳本,以及一些注意事項? - 首選的方法當然是撰寫您自己的使用者腳本,開啟延伸功能頁面點選加號建立新腳本,編輯和儲存它。 - 您還可以直接儲存副檔名為 `.user.js` 的檔案到您上面設定的 Userscripts 目錄中。 - - 您的腳本檔案必須包含有效的元資料塊以匹配網站頁面並正確顯示在延伸功能的彈出視窗中。 -- 當您在 Safari 中訪問一個 `.user.js` 網址,然後開啟延伸功能彈出視窗,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 + - 您的腳本檔案必須包含有效的元資料塊以匹配網站頁面並正確顯示在延伸功能的彈出介面中。 +- 當您在 Safari 中訪問一個 `.user.js` 網址,然後開啟延伸功能彈出介面,您將看到安裝提示;如果您啟用了增強提示,它會自動彈出。 - 請注意該網址的 `/路徑` 部分應該以 `.user.js` 結尾,而不是 `?查詢` 或 `#錨點` 部分,否則該網址將不會被視為有效的使用者腳本。 +- 當您啟用該延伸功能並正確編寫元資料尤其是像 `@match` 後,當您訪問匹配的網頁時,它將自動完成注入。 + - 您可以暫時禁用單個使用者腳本或所有使用者腳本,只需開啟延伸功能彈出介面即可切換它們。 ### 就這樣,現在就開始改善您的生活質量吧! From c9c7333f18f2b9985e1cee42cca885f207d0d18e Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sat, 28 Jun 2025 23:07:37 +0000 Subject: [PATCH 05/51] fix: add light theme color for console log --- src/ext/content-scripts/entry-userscripts.js | 19 ++++++++++--------- src/shared/colors.js | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 9 deletions(-) create mode 100644 src/shared/colors.js diff --git a/src/ext/content-scripts/entry-userscripts.js b/src/ext/content-scripts/entry-userscripts.js index e0b0f7fb..5c0f79e7 100644 --- a/src/ext/content-scripts/entry-userscripts.js +++ b/src/ext/content-scripts/entry-userscripts.js @@ -1,4 +1,5 @@ import USAPI from "./api.js"; +import { getColor } from "@shared/colors.js"; // code received from background page will be stored in this variable // code referenced again when strict CSPs block initial injection attempt @@ -62,13 +63,13 @@ ${userscript.code} } const world = injectInto === "content" ? "content" : "page"; if (window.self === window.top) { - console.info(`Injecting: ${name} %c(js/${world})`, "color: #fff600"); + console.info(`Injecting: ${name} %c(js/${world})`, getColor("yellow")); } else { console.info( `Injecting: ${name} %c(js/${world})%c - %cframe(${label})(${window.location})`, - "color: #fff600", - "color: inherit", - "color: #006fff", + getColor("yellow"), + getColor(), + getColor("blue"), ); } if (world === "page") { @@ -94,13 +95,13 @@ ${userscript.code} function injectCSS(name, code) { if (window.self === window.top) { - console.info(`Injecting ${name} %c(css)`, "color: #60f36c"); + console.info(`Injecting ${name} %c(css)`, getColor("green")); } else { console.info( `Injecting ${name} %c(css)%c - %cframe(${label})(${window.location})`, - "color: #60f36c", - "color: inherit", - "color: #006fff", + getColor("green"), + getColor(), + getColor("blue"), ); } // Safari lacks full support for tabs.insertCSS @@ -246,7 +247,7 @@ function listeners() { for (let i = 0; i < data.files.menu.length; i++) { const item = data.files.menu[i]; if (item.scriptObject.filename === filename) { - console.info(`Injecting ${filename} %c(js)`, "color: #fff600"); + console.info(`Injecting ${filename} %c(js)`, getColor("yellow")); injectJS(item); return; } diff --git a/src/shared/colors.js b/src/shared/colors.js new file mode 100644 index 00000000..a6204eef --- /dev/null +++ b/src/shared/colors.js @@ -0,0 +1,20 @@ +/** + * Get theme colors for console log css + * @param {string=} color + */ +export function getColor(color) { + if (!color) return "color: inherit"; + const isDark = matchMedia("(prefers-color-scheme: dark)").matches; + /** @type {string} */ + let hex; + if (color === "blue") { + hex = isDark ? "#006fff" : "#317eff"; + } else if (color === "green") { + hex = isDark ? "#60f36c" : "#2bb239"; + } else if (color === "yellow") { + hex = isDark ? "#fff600" : "#b8722c"; + } else { + return ""; + } + return `color: ${hex}`; +} From 3469a4f399084c538672f35357f11f8c928b9853 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sat, 28 Jun 2025 23:25:47 +0000 Subject: [PATCH 06/51] refactor: reduce repetition and simplify syntax --- src/shared/colors.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/shared/colors.js b/src/shared/colors.js index a6204eef..4d309cc9 100644 --- a/src/shared/colors.js +++ b/src/shared/colors.js @@ -5,16 +5,14 @@ export function getColor(color) { if (!color) return "color: inherit"; const isDark = matchMedia("(prefers-color-scheme: dark)").matches; - /** @type {string} */ - let hex; - if (color === "blue") { - hex = isDark ? "#006fff" : "#317eff"; - } else if (color === "green") { - hex = isDark ? "#60f36c" : "#2bb239"; - } else if (color === "yellow") { - hex = isDark ? "#fff600" : "#b8722c"; - } else { - return ""; + const colors = { + blue: { dark: "#006fff", light: "#317eff" }, + green: { dark: "#60f36c", light: "#2bb239" }, + yellow: { dark: "#fff600", light: "#b8722c" }, + }; + if (color in colors) { + const hex = isDark ? colors[color].dark : colors[color].light; + return `color: ${hex}`; } - return `color: ${hex}`; + return ""; } From 8572b54926c914a89a269cf433547241b6fe2bf4 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sat, 28 Jun 2025 23:40:37 +0000 Subject: [PATCH 07/51] perf: use media query change event --- src/shared/colors.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shared/colors.js b/src/shared/colors.js index 4d309cc9..f7162e40 100644 --- a/src/shared/colors.js +++ b/src/shared/colors.js @@ -1,10 +1,17 @@ +const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)"); + +let isDark = darkModeQuery.matches; + +darkModeQuery.addEventListener("change", () => { + isDark = darkModeQuery.matches; +}); + /** * Get theme colors for console log css * @param {string=} color */ export function getColor(color) { if (!color) return "color: inherit"; - const isDark = matchMedia("(prefers-color-scheme: dark)").matches; const colors = { blue: { dark: "#006fff", light: "#317eff" }, green: { dark: "#60f36c", light: "#2bb239" }, From 040a3a00ef96162894cf072abe3b1cedbb12a963 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sun, 29 Jun 2025 00:55:36 +0000 Subject: [PATCH 08/51] feat: new app icon with icon composer --- xcode/App-Shared/AppIcon.icon/Assets/icon.svg | 9 ++ xcode/App-Shared/AppIcon.icon/icon.json | 94 +++++++++++++++++++ xcode/Userscripts.xcodeproj/project.pbxproj | 6 ++ 3 files changed, 109 insertions(+) create mode 100644 xcode/App-Shared/AppIcon.icon/Assets/icon.svg create mode 100644 xcode/App-Shared/AppIcon.icon/icon.json diff --git a/xcode/App-Shared/AppIcon.icon/Assets/icon.svg b/xcode/App-Shared/AppIcon.icon/Assets/icon.svg new file mode 100644 index 00000000..f19d064d --- /dev/null +++ b/xcode/App-Shared/AppIcon.icon/Assets/icon.svg @@ -0,0 +1,9 @@ + + + icon + + + + + + \ No newline at end of file diff --git a/xcode/App-Shared/AppIcon.icon/icon.json b/xcode/App-Shared/AppIcon.icon/icon.json new file mode 100644 index 00000000..a5558deb --- /dev/null +++ b/xcode/App-Shared/AppIcon.icon/icon.json @@ -0,0 +1,94 @@ +{ + "fill-specializations" : [ + { + "value" : "automatic" + }, + { + "appearance" : "dark", + "value" : "automatic" + } + ], + "groups" : [ + { + "blend-mode-specializations" : [ + { + "value" : "plus-darker" + }, + { + "appearance" : "dark", + "value" : "plus-lighter" + }, + { + "appearance" : "tinted", + "value" : "normal" + } + ], + "blur-material" : 0.5, + "hidden" : false, + "layers" : [ + { + "blend-mode" : "normal", + "fill-specializations" : [ + { + "value" : "automatic" + }, + { + "appearance" : "dark", + "value" : { + "linear-gradient" : [ + "extended-gray:1.00000,0.80000", + "extended-gray:1.00000,0.70000" + ] + } + }, + { + "appearance" : "tinted", + "value" : { + "linear-gradient" : [ + "extended-gray:1.00000,0.80000", + "extended-gray:1.00000,0.70000" + ] + } + } + ], + "glass" : true, + "hidden" : false, + "image-name" : "icon.svg", + "name" : "icon", + "opacity" : 1 + } + ], + "lighting" : "individual", + "position" : { + "scale" : 1, + "translation-in-points" : [ + 0, + 0 + ] + }, + "shadow-specializations" : [ + { + "value" : { + "kind" : "neutral", + "opacity" : 0.5 + } + }, + { + "appearance" : "light", + "value" : { + "kind" : "layer-color", + "opacity" : 0.5 + } + } + ], + "specular" : true, + "translucency" : { + "enabled" : true, + "value" : 0.2 + } + } + ], + "supported-platforms" : { + "squares" : "shared" + } +} \ No newline at end of file diff --git a/xcode/Userscripts.xcodeproj/project.pbxproj b/xcode/Userscripts.xcodeproj/project.pbxproj index 10708e48..8708c6b7 100644 --- a/xcode/Userscripts.xcodeproj/project.pbxproj +++ b/xcode/Userscripts.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 007596BF2E10B67F008F8C04 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 007596BE2E10B67F008F8C04 /* AppIcon.icon */; }; + 007596C02E10B67F008F8C04 /* AppIcon.icon in Resources */ = {isa = PBXBuildFile; fileRef = 007596BE2E10B67F008F8C04 /* AppIcon.icon */; }; 030C64F62AC62CC900548FBD /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 030C64F52AC62CC900548FBD /* Settings.bundle */; }; 030C64FC2AD0B24C00548FBD /* Initialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030C64FB2AD0B24C00548FBD /* Initialization.swift */; }; 030FCAD42B182008004D13CD /* UrlCodecTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030FCAD32B182008004D13CD /* UrlCodecTests.swift */; }; @@ -112,6 +114,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 007596BE2E10B67F008F8C04 /* AppIcon.icon */ = {isa = PBXFileReference; lastKnownFileType = folder.iconcomposer.icon; path = AppIcon.icon; sourceTree = ""; }; 030C64F52AC62CC900548FBD /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; 030C64FB2AD0B24C00548FBD /* Initialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Initialization.swift; sourceTree = ""; }; 030FCAD32B182008004D13CD /* UrlCodecTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlCodecTests.swift; sourceTree = ""; }; @@ -204,6 +207,7 @@ isa = PBXGroup; children = ( 039F59512AD95485002E9977 /* Resources */, + 007596BE2E10B67F008F8C04 /* AppIcon.icon */, 03D405482CC66DC90091FE6F /* Shared.xcassets */, 4A4CF6E9270A38BD00111584 /* ViewController.swift */, 039F59552ADA2FE2002E9977 /* USchemeHandler.swift */, @@ -501,6 +505,7 @@ 4A4CF6F0270A38BD00111584 /* Main.storyboard in Resources */, 4A4CF6ED270A38BD00111584 /* LaunchScreen.storyboard in Resources */, 03D4054B2CC66DC90091FE6F /* Shared.xcassets in Resources */, + 007596BF2E10B67F008F8C04 /* AppIcon.icon in Resources */, 030C64F62AC62CC900548FBD /* Settings.bundle in Resources */, 4A4CF710270A38BF00111584 /* Assets.xcassets in Resources */, 039F59532AD9591C002E9977 /* dist in Resources */, @@ -523,6 +528,7 @@ files = ( 4A57B9F9227235CE008A9763 /* Assets.xcassets in Resources */, 032CBD3C2CBCF19A00B31D5E /* dist in Resources */, + 007596C02E10B67F008F8C04 /* AppIcon.icon in Resources */, 03D4054D2CC66DC90091FE6F /* Shared.xcassets in Resources */, 4A57B9F5227235CD008A9763 /* Main.storyboard in Resources */, ); From 58aa9a25b7fc884ea3f0702e3171846bb9f3698f Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sun, 29 Jun 2025 03:25:42 +0000 Subject: [PATCH 09/51] feat: replace png with svg of adaptive colors --- src/app/App.svelte | 21 +++++++-------------- src/shared/Components/LogoIcon.svelte | 18 ++++++++++++++++++ src/shared/img/logo-icon.png | Bin 24309 -> 0 bytes 3 files changed, 25 insertions(+), 14 deletions(-) create mode 100644 src/shared/Components/LogoIcon.svelte delete mode 100644 src/shared/img/logo-icon.png diff --git a/src/app/App.svelte b/src/app/App.svelte index 7e6c5c5b..bbfe8df8 100644 --- a/src/app/App.svelte +++ b/src/app/App.svelte @@ -1,7 +1,7 @@ + + + + + + diff --git a/src/shared/img/logo-icon.png b/src/shared/img/logo-icon.png deleted file mode 100644 index 9fe96182de0e89765ffbef258c50c5a7d2d8b767..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24309 zcmdSBX7nh{@(T9y<(uh#sBByohKrg3Rgg&3!p21T>SH~ z*kZ#^AH5Mb+J_Acp6)(;!us|pu}cSc?fO~AbpK1!zTbatK793;UmqX+{cTzH{Ilim0(FBD)?@ao<`w)%YCx7PG1EX`#4-M84Gj&kG;drIehWv|*f9STGSk zNwbkVsp$S>KCb|5_;7r^ON%I|v&kM=aY#4K>qs2_^m@SY0e{uI+d}0JKd!&c5JkM( z0O|DHc>ks1A8oEmk0s4MwnI+Ay`y z9*dHmIB$Zhr+=h+;oUP>?@%A`BSO1!(1=CTF|e4=qsAja_kRp(A_*xfpS138?CFLO zJJ^bWVxIG(#f^7(kv9$B}Qvpx+7 zy=~h?kYSEbfx$N4$E0*#$=lt;o+4bIm=2>T>gC6&Aq%q6TPux2Xb48TultEP|NFRI zPai6F5`$E%5FTOkZcfQ~myklFRZO}0Med6amhT(NCTX;$;`)}@M=Gl| zGAnqy(aceLzw}E5lfP(&KFsvzN(wTfcv-iQ1ha~i$nGDG-$Ytf1**6)#;RpO_7kRS z#z-pn^OXfv`pTiYxFg^5JK3{Sje;31(X9}`^;E2*e>cOZavRUC>|VJmJM5K z^`o%B-vhr=sx&zB3#Jxkyr$XPDrW|9s3v<#YGXQgYbAJ~{0n7h@z;cjx+KiNJ5JDx zC%zACeotKy-ep@e*N;x&EJJ)n!#;@6A_>>g z`@v!3>#sINVYbV~WBgfS?zM;YfXSYqAIJ)q+xG-T+0 zLBr&09Nm52#?+qi3nr^&g9^gFz%^*4^0y4+$}P(COywNRJvH>ZrRfJUeGwh;RehWe zONjZf;hhrq#YVYvM&DT9)ab3mY+(&nj`!KM@ftpC;C@MW=r4+1d|_ehiYv$)t1En zsN9iOCp?y>=RkSvp9k@_49G9VUH0nk)AevGlpc=HEM$QboY}9j*Awl0f@~>A- z6Y{ziPz6DN4wUm|yvU8{2IrzQ=VC|Kaffh4+d>k1dy(_hPLD9FwJY?APg$Heersgb z)(=1a#1*-8NDZ186me5IL;0qJ)6&;yUK)Xz?kBBeMn+!IX5`29Tc+5st*^~aF#&?S^f4Jxx z*trE-j}{IrokPQ;?XH-Gmn%{Q!{i!$`AE3yk5r}_>2~pkX&SoNCUkOudOn{Y=`UAg zW=AzP=ad*t+eyJ?6ni%%aTy}VVb^eJLJzu>Eo(FDG50m(-P=p0hv-FdpgIji$bjhY zz%}CA#r37>0xgwmR_COCww(0rj273eo+NEvLA`0cgPqi)8^YgA>NQgIEw5NJ)I8WR zx)$mlQ(NAs*UU7nWCA~lbh=F!aoIqkFq`L@RtCEtZEuPSfAr68>hzUGbrwD=WQhQ! zKR~y$uXX1{F1JZupcS)wOqLO4kMcAca`iS_z0Y-jIbu%DdV1E^dm;5KK_5m8v?82Kh3M%QO6(T>UyIPtSV!u&W$CIKYzxD_@iBJx)Tx?LUi$`07X*RLdpk z5i}RyOb>vkil5(^qkpU(>pc1D?5Q|(l{8N=beski@hBpxUn2Co7JeeoG(ql(E-l#i zX0tdio;~b;qmk;!p%Evm5$|DWZ5&KvNVi1_bv*%&ZiND zT~5@uXA5IrH9Bg7Mmt2`~;qBP1uT#J^lH>GhMm+eoI_q#n5p>H2M zG@vURCXM5^&_0iGO50sA2Ft8)6KDFjo~4%Vi;SK_WmRns)Ko}z@y=D;vh_eFB}Z#7 zj;h#OVM}_s**|ucSXJbvkE1RZWntGFQ%8%Ttj&H~=#voRhrYnA#&u-!h^U{OgFQ4L zSth1r$SSUos!qh0xvBWCRiFYSZe-;5KDHp;j><84S(u~MlRE7Ho|OMm^5R5(Y$v`t z^A^+G^w%=ef!4nGP;PHBs$Sr%%1iE+j&mbm%cm`%LxRN+4cddLGWu$4(29nGCC0lU z!&&rb99r6NW9_R3jMqttfCNo`p08CM{LXlJH(S`sn0H3b9X$@yWN9E5k9{WHw-YF8 zF$N{J>}Pbg@NUe`&Y}ia;l{~#vmTpuv~8SAL)TE?^bO~Czjo#D_Jt*inli@L^I26j zTiKJw?A(eD?zgJ=)|rlz77N!7ghquEoHH_W+VDu*EZ&TgW0i2)IxAaALr~oEc4;V} zyKp&hdofisFO8Wq4}I_&wX(81^K1I__s^h@tujgX_Qb#~+uQgfW^shtF_U+jQ z3A!Beq5qG4N0$>V`@g)@8+?$D^LzMQ(ey*x8frQsO8TVMA=svB*wSyCwe4n0xj<9R zFMXarFyj5%pMU?nVhi^}P>+!T#-xi+O)z&AVHq_rOXT+O1Z5Pl9A7^#@|gBp4m0EG zl?5LldNgd%#HkpuTX>bw^&Ieaj*W-(^LRBECU@laoRoC9LKIP2x6BHjgyF3r$XEsi z{ayo@IkphXTebXivz}OzcY%me76nt8xh#~Sn6j;x4)Rh8t02F@X7~JEzln&auN2kPjc&-qL5%G0a7Unlp3{;ll%Uf1lt=GMdrQ{)LvuhHK)8XS06qH*fuwbzK4 z*0y5TJZx@V)wGzSWqvk?+`fG9hb=f2DAk&dGr#tgAf*lyRgpKr)&G5l5*G7XAhDCy>B zMxIaXVHiU#J6IkOt;0szR&`(Za$j#nmYM>62N{a@k+L^qx9K<%d*$*TGxpCjj`r)q z&agQeG1p%qdS3hfv)i8Om@loedaS2a*KzxruphkkI%1@(t(24LrY7%L{oLU5!~rn* znU6w(#U0&mZ8802arrLd?$9U7@)4AD=5%_Tom8IOs^@>3(5562;~&%M2J)O+T11Z6C<^p+hr52YtXBpEP=G9^2%Oos=?$m4n zWAcY(Ur3ED1=iGCMmY~hJ!RE_9=57@<1!y6n@G=lIlT5fueR7@_$WuK{DYz@7<RfEI-_;-J%=tE zu#?8q{9>{HDNrry(&D_eUW>pskHzG0d6eVB-)R0~w+^i+newI+ml-4XUfb+4uQ6gy z%3E41&(j>IK6%01w=Z)VYh7q^!Bt2%>iNCox8TAtSx1%vTzOF;MK4ASl}ntwPphMT ziVckE;*-LhO}0Jd5!=8kwukgIS&HJP9QkcJJ^ZRtZGKfu#Z78^#A341;%HdC{;=eQ zWcSF%SV@o!^jo$FR%q5v$cd`Hn8p5fCCkQ2Y4oDCvU3qX!4C5hv5%78+IOAzBU#28 z^Ri$vNg^ZFI6)dV6yTczMV_F4;!VVB(6o|A=C)$!MinZXm)r}Gd;EweLfNyBO#;m) z7-?icyVz^C>+u*nJE*?;TT!`F#zmCe;K4`btvfB8A)^UnZoQxzskX=7Ed|>?smk&{ z&z-rG&Fmaqz%gT-cW`WpGiq9l*yX+yuz92=*-{KRaY~=R$M`-9l8t%P{wI0wF?qg0 zaa)c4;WWbB&{y=T8iHw=fw%RFTZpX93hWt*I-w^|)d#0NA^kno<#sOINb#nqB=~Xv z=5IuHKxwHKjox^y%i(U1O*)}LDV`Cz1U&wrXrJ+RO8~Gd_9-}FKJEWdmOQt{*YPgv`?Fhh=}Ml!6LoOn zX?(x9PXYwyW*Te2MHegt+r0y`Js+uOUbz31%U_T zu=nceq&TsPhOhZ-Z>7=oz$F~N2z;Z-f?0sUHu2p`4S3(gt|neZZ+WsM$e?jG#*T91 z@ww@rJ`kmUIOdgG2@2t}V$Zt=C;|cmeG++fwCZN439AOzck2!YeHTv`L=SceMvqUC zc#<>5eMwzTMAIFH9g~6eHr;hEif|~V^14+yme zlTTip+pL|EYUwX_DyY}LN}&G4>%}u$-|bYuA8zHXM*0kYj^s&)_1A!3#*y00HjR1Wcl9iiysh; zP7Ic#Le4Lg%wwbf?9S^evj&?^nrB8LN`YtZY|;eu5Ud_=Y)sIHLR7yNoywOVUKk5%Z;Av9mJ@N#sG! zNrpo2Kh;FbtaNHyLFox8_xomfk7d8168&q-+g|r2Uo|;t6vd5{R|uGI@A3InP{L4; zp`b1^^SW+$fKt6{!ZxZ&4AI~HUUlz|ebxw=8`ma$=b6dfE@Q86CQ*PhPEF z>&*MW7=yCTtThLTo~#uU#|PGemUeu@Tf6-s4Y$u0hZam8k12k7b}&Dl+4tQ7(N}k?b^2@Q>Z|@be%s9V>eyQSgj6MJdPIL+S|aDc$S2;6 z@lAk}SxPS=@v!J^MCMk2w}_RM&+AGqY6Lwh6RT`}a+= zzHebka0vFojpG1fkkvqz?14Y->Z_pzQtM8S;nmR`YN!xFk|(0%y{%{kj;db;=;)3cfLxbnTdCu6>=F{F5P8cxGMg;w0}d#F}FRq4Y$m~BFm+t;mlY3$i_ zmjb5Fp9(X8vO0p#W&pGpCtUCoZTQtxF76zuc>8(xLZn^jWbt+#yO+C|hqNCWcAI_O zn88`TBn*r0#Rb2}oD{XRhL`HfMfpwi%R`3!$&OQkbt)*WxWt<i|)vHPX#*PA}T#Q!cUiIb2Tatc#A?+mUpA5|9fEq1cnRxgoE zHm+_-9|*|TjF79|sjQmV%j(_)3wkc9TasP@ZKJpDmbtjf)HIG$1T*_(Y{D;Oc-RZS zy@04$KPHnI;%WW_3@xWVjPV@sRIg|xL>`zANg{R|;CCrOw8M{lG7nXj1?4mPz1g?A zcy%oUZ}$i3)R~;tei&gydaCA?X^+n%8jd{fnsaZ`;`}L9~ID)UoA4kJf#wDFNN!g zHtwyOv^R7@H+DTt%oxc`%7C(pG#s0k1%=&nQ&tPAVBS}Y@yy{O z56*`Q7C@<8AIN7{HC1=vd2PZ6a;~x3w%Q(8%auBnZ946&>aWeZSqLulJsaHAA76+t zW3QUDR{oI42Nz~@+aVj;4iYonepq%70vqr$EfaEX`!d?!Q--Dm`Lk#;K(&aH-ccbX zoKCW{9!9HtkzW3D*Uj@g7-uL$78LX{AgXU&32&5tr}Hkl#*{yLIDtyG@tX4d+JJ@J?dkd z4$OMc;X&ayMkJx{gKL!X>Xi$!`z|&!^=^>IwT-t z(e{TU=(n?t`23aNR0z}MYV4cV4l!S#AY>7R8b9`;wLsKk-&`?a>-+N<)QQ6-Zzj1rqW+y9pO8n=(alM&xMC`z3b^|5zdLl%q{XiWnBhg$xX z-mc;0TMEU5L=w9>D_15@I39Hj78}U)MJ}wKr|;D;5Km8VA}LJuwDdS_oA=*OO90wTKVNxmnukhVONE`rd#pQ^qely?yz|&k8xk4 zt>l=dWfk&s@QtN6c;kmlf6)o{@OnXtd*I-L44%8Y5GA1nGOkgmRTLIiF*(DEMyw|r zhlwb+BsWe}SVl^DV?JVvquTFWS$*K^bL;3-r8F&%au-Kpt?3Z;5Y6InVv7s=ql*FR zlShoJKGAK52P1%)o)*yAP`3=q{h{DFfX@E4B~VpsdoDIwtO(t#<1uWAxvZUw-V%6H zt%eo2O7jve`nE97;fWOZjevgHFyApvm3gn{`>q-Ew7o*AMi%Cf^0Gqz?@F1Bb;Ft* zzSe2xcz&!x#*UDdBtajL24SWQu<$(kCyz{%3AM5w$zmx_=4D7|f3;?Bw_I+WKSpo* zM7|Wet;olnP!&nnBr0_!APJy>gR)U%3orB5_{cc-hm1s31QX8dz8I^#m4sW648zER zXx4FkNvydYMiS|~A%vZTvfXE#+5xz#a3RtAmtOH4&of8x=ERNT_e)I%L+|Wx5VWD? zBStbx0&X~a0J-WzeUGe8*5S2(-ZKDL4S_L$9rE(Z*GTixp@4pZT!xUG^an8zf1Z-w z*%`U`S!b_1-Y~(xl4symUN;O(qSfb9@}_OSSqypKrN^Gsj3~c#Lk(8yq5YH@8ardKI+Zs_vbU|)9`TB~8b_qrBH^U0Q9fuKiicF9fl z3hHJ3@ii?b<+#X26SQ%YI>RMz_cUCV1tvofMJix z>4AC7$O!?-Hb-}CkJEX+Ca7zi0@0P2ZM+8|rQ2l_I<;8_FbJw@_KIgWz*Ptjguy7q zDc7z&VW(>QuiRz#CFyIU)=zq6LUN5EKIPv2vKp$tZ2jQS5{5F z(#8#?LM`p7^<({`Ws!G%Ns*hk`wL>+e#He8Tfw^aG@bhXeyF&z-@Vx6_hI9&>xCI{ zcVrCgOxfMXZYo1n*#@swg91ruT6T;m`5Y}DG$H!Cg+d|(jroU>lyjcOU?jpUL9GZZ zlRq8*TuvLlo>yXP+LC$zIYmufFJzg2icD1Zif*jzpV77W-;N-vBN;>X^_Ar5iyu6* z+9#{mv={M%jGxUZH3CLogdkXn9SY}B0P%c~2+USJJ&>)1K~8Br#*IW8+hG* z+1pFY!lebktE6YDbz+u7=!15GRy*<#^wMU}{i_e<$a<{Jd5ql2CR7Qtb6sNQ2Vzh~o2n+39e zJAwTk0yLjUn-Qngw=TafPu1MCLQj65Ipp}tQDwUWQSz#!(*qbQ9rd>q-~M9Yn||JG|)c3XW|ZFys_>2zSW2(b+j z$~LaNKxv&?#%|Ul0M%F50KqWLq~*h7J#E3bEPOR5$@#gQ|N7hOsN`niOXOFgb?8}H zkV58x$_c9@xkNvI`3SJk8)%Mv3_w>**O0SoY0XgIlB>wEaV=>H2Rh=v#S?X2v@w7jCy$U~ ziGnU-X2Zf=t>MGjs6H`<(0($}(RntxdX-8x_SCZoH4sqWR{NEPQUqnrB`!M!B`^5SE%@Wn<`ZTQ!q zuSE+*HVZnu8IL44V61r!W!9yxPgOL_J8CbGe`qbm{-{o_)z@L&qZzU?99j8LR=*)@ z?Ew~ZV`RuYA!Jg*bX+WJxGvyW$ytlP{Q=Q0WMNNO4X6S_pe9N3nj|0(11mB{_ixTM zyN3IPPAS&3syR}FmM%XuNZ1N!EqUs5;E^T2ng8HqwJmnG_BTSZD$aQA#IG!vtptkD-vm(}vr zfsVa)W4P|J0i4&07U5UtVkjO=<)U)Dm;#r&n% z!c>!P+j*MDiT1TFIOYzcGY6az$AL`zWM??(5J1}KaIiB&Z}b&Fsh&O1Zbcm3|4diH4QWTR#oKCn}Cm8{?ey}+GD8`d?%^X~ZIcV9V zC|~C5LwFtVQr_GLGe`ZmQkt1kv!6bs2{M=bly)YcIsNf2DpJNA;WQkY_n7qPCx7^v zgLV1|p#(;MZwjGL#!>_*<%U}?VB8mj!2Gj^e0>TC$1K_A@(tXaQ+^*x!l`tmhTzt= zvPE48%;Gdr$SI?nDUbWLlBCA0LMLVL1Kaw|I(%q2%}6Gyv_Y2JPR7+}BkMr}1ID+d zR4^)+Ti@5Kwtj50XWB*5HP-=ICfCfrXTl+0JeTyeU|w-b>k{={c6RI z+3G6wgqGCdStr_Yh{Y z>pyW!aJi_UvxJ+WLwsFFvI3WX4z+$?wY$H7oO)v(Nd)z^eL5#w3@Dnm(W%<}-kWOK zx5?pE{zz+nALrO$YsW9T7O)}antSMK+i1}?9PFD&6J814;I>1tf%U_qzBED4ciz#g zsZ`0P`2zeHCWK-d&|MP4ZhC;;yETnX+vcRll%NCc_V!DOE zG7w%tjqI#ACrNf7e5u}96g-<{z^vK_1Knv1P!0Nmqt%b0H&WY8y~cXuR#x?9cCMSH zG3~*##J0i~xe8JDMHL@mW|s~pClGKdR9ZV*-R>-XY;DrDgMss<)3E5f9Qg7Z(I5r8 zu>jy0iIWy_mZp=3DndqC9vQ1-WP#v_HY_6@zO)^=x#zajyCqzNG%^-@( z#>WWGivyma%`Yj|E1FN?1p+|h=}*F7XYtys$)JX!H^BKAxRw{ylHW1troB4y)Bl+P zH*sx6fKh$w?e(>0Y3#}Z(2(i9G&~A^ob0#Ya2PD+jo3z)C*k#kE7GEe2QrXs6YVO-0z^0C(m25v+*C*p3<$p#Jz_v$a zzqSHe=^5%CWWk?mDTdzRhet!#jdi5J)pGV&f1@|kPEc*+9C#}WJE?4XhVhn&&a$)e zY+rG$=*(1W)Fz5O{*f{Eh@`Q}(3~vGyzgqhe`^AunhV*Rp9{X7=2h1;lx#6_Id7s8 zkV=8R#Xf4=u+}16fq+qFUpljEycw?QZ75mPcqyvNB1ZAcmSH$I>uO2X#z6{Q&`pmP z+7daBZ!eU`VZ0IcK?VYIc7o&;@+=TXk@u@Os{j#{`NJPSh}9=}Z_s5;IdSnO+h@fd zIAUktmTeIIN-zVd!CmnzSSz%8$#;?(AolRtnSs5>QALfFJ|5KTuoE+?n#fZIPdIrt zz9r&}fu$gR$5crf6K6g0InhQ*^g6QbM3;O3C=)T7G-4wkp#))TFl{lhwEx@U( zz^wP#?D6pM70i$=#uMdVW2Qnd_GzeN8Z82;Jj^+_JICR)_gA~Knp5VDt+l)Q{HK^GQ zG43=dAod5F@NA)!l3>@aGEV1<%4#`4sQ`=>k6{=0rnhn*wU$c+DhThZP5$9o_-!ZM9A(qR`V{+L9Ow^_SBN-XxlGM%R|7O|}J9`mp#JRzv+v znc2gVai$e5I!_?r zuGY;ks^Y1>1rUmxm#N@GF*P+@gd3p*x!<0wxBoUnt}N!fBiMeF!*)v(iMgFWVkWBb zrOLP9QJroqXL0;M8Y0_hi-#BS_QT$@&mSeY;XIxHD1``H$=V)@_cI|tBD02kbyVS2 z8eY5T8}K1+O`iF7VE9tqLvOTTKU}{!#`Ql&r)~Z}uposZx40;HzehGqa5D4mO1;#b z9-C2K*GXFeK-fgl{A0bBD59CKLrgxO+ZJ7DG{8^Q5??R}^S^~_uO;KICtsDaZ=3!G z=-hvj?zu{&LD1}Y?@2}^qR~h`3g-^@0p^}LDsA5p)BK-EeS0&?!1qx<)JiFj;jhi7 zGKjp42sg{|9eJ&8wj8n$-tObhqFjl=tWW+(BHN5&W9D()!%KW##-m1sYuu=+kR@{4(sNGG z&ygvIng|ZqpSo#1Kz=8(u#Oj5k43830DJ@#h4?6h%gNlyfpb zgh6VoFW!IIkJJYD{%eyS*tP=VplQ0fsDu?Y<$|ohp=)0c8Tu)%C5{Wu8=8B}1akj1 zP&=<`H9YE*42x0`(gy~Cot?c&&gK*&e6s(z6}7j_b>*@K(e<`ZE+>f} z&fMU&*?(|NdGb$>_ldxr4y@qQo!E0+aqB{;B(VjQm@ad$0ZB}oGf#idC&O( z4zad|jRlrhxq$-g%_SATbf9PD;Vng!+UcTyL!p|cpB;PDsNDTq1I>2N*<<=(m%^5z zU+sod7fW&E7Tn`C<*?}+5qKNyNvuCSA{Y4{i`()ezvy%mo_itfTrSP$?gY44XA`D7 zr-tJ9uNKF7k0%9T9T6ozjK{&9_QO=UZF*T-c%rV!7f5ITMKCtUX_?-}$hF6efB z6ME~F=$f1fw-Jay(82FRhn%|zPj6tSbWUkcC2?PNAHegzM(d5G_pA9fZWvDk=LFph zKk~qu;RSCVeUQ_n3q>9*D$}wfr;-<^X6v^FSThQ=T}rr{J#UBOAA$xr6W%*&`{cUL z?4j_sZr+Kxnj!N_>x_{O0Li*yid*C!PU(<_ZV7}?yBNW?C|a>MxD2m#pr2^1i!~82 zj-t-?lzRf{pt}cHcd*o^GT>0&r!7REc0P&ECqOwa?!I*lT|S^!>N${>B79Zg&RR;w z4*?<%eF)24wE_ zsA<(>K1Q;uiH@^-NbR^_*<0Vg27warrYvJwpU_qXn7;shuw}gMnujzG5H=mm_xj+> zUJ^P94#E@V$xc=7vc27@=oOQ)8(*tnpd)9$i2spx;HD+BK*c!qiPdV4(IlzP%IL}s zOQu8$9!9_b+T~B@p9nZG5of_pIBlmtRZ{dO5yUx$^&~sQZvS+SE_TjNy+B~K9dNiH z+x|03rEcQVwWT)Rh;X2}K)~%f-{@MN#o1hS?5R5<@SJv4&BFp>x<;D@Vu<9TahFu` zI~@hI$M9Tj{Q~Cs7P&`)G)dAqT#HL+hTd-lRc|nY&4y)6y>#vwFJqC5p#WTB~EncGLc^$=LD|7K^ejAj7~2MX9pKe(M*jaCF8I^jy2AW_=} zZaq{ijeTVK(z(ktPxz))Q$Y`0PrdA|LUe0ogC7Hl$A%Xc9kXW3!4);c?M3(E%wcEZ z3C3EsG2Pth{Ms1ZZN`_Y;a6J54_^QSS2TVUNQ%vmknekoBA7Qu(#PjYhifmf)M8VW zsx0^)8ebAgTEiagd%}!hORdO?rhj0;0V}f0R|UuNXdBpM*JMpTYSIq6lk59Q>&=Kc zWJ;bg2a!U?EEdCdp@M~W-IrQ|KxFd|%i;9KFBH{GAbie=%Ky|R+R@ZD!X!-p&bZp6 z{yZRi663_VubNd5Y=s%{O-rfMYa-i`oiIa}r`FYVy>9U9G(j0DU+bKXFrMv50+EOQ zkpx=*Pst}U9+w?wGBP3c6QEADW!uTEDLG3W4*UY$5Wm3Nca#v==Bv$*6ieIY!ZRfNJ|%91nC* zro$4{hd6CA^?Ff>w3fK_!Li}N29TTY)5$qO*<{tL2dLJxz)(fDc!R>2^LO`);gyQLl%PQ-OrBEKwpA33DxL;&XRbC@bDK8H+ zOxlh6@(L#e-{sL5^VC{i+N@B`>-$lC)Ydx0`}*iz9stwsC7Mkhy5RFJ=5T?!XW{IZ zRozcdJxO{0AO*L7GFMbR2|&lv`_Zm8z$_Eb&^^J+Rf1l`E)iyZH;%(+tgzbxxu5Xm zu=8u%INE*pyvH+Fa5EDW<7{AA%+1H8n2h0({4L@i(CcZO?-5+&b#~J~@_^F6fx|RZo~H1l{itS7!oB|@ij3!f0uDHtR(2kM@STn-w9FM|A&Vmxmh~KZnkbw~@8AF8JQ@CO=2>OKy~$VzyPrXo!RZM@4hY| zAjDKS^NZndz-6cmPc{8tT?TVecoiqvMM`w+o(Vt@%#6SpGai_ibbegwO!*vN z=|n}~ZCr}p>_m`Iev<3I|J^VXwyW}xdsC)jhO>G2O0+I1e5xz!UAEDU8j_Rg6nO@^ zt7gk}*GLZg7te(TW~wBJ#Zd+^sxvqhwkjnnE|&CVeS-qEPP+o_w@Iv0&a9Q+n zOE1(;jfVa*V-fq9q2`$7O5)68R)=Sni|W01xK#DZ(yj{*-XFTJ-GmLD88TgOWKiY2 z_Xd*?Ho-~#Db?t@XN#mKL!Fs$PoT8KF?6nGyY3PwuF|(h=`oXFl-Rf;n&XiYJY3;s z$1H8v`wh2MgA3`yNh?qsUmNjQqLZC|N&)+Eq|}V6fU$AHOk+o8aZWb6_4Rare3gzC zAx0ZkPjz|G0O;|qT!tzrBkWO;qgX|;Ogp;SH%;*CfxVv`#6tiBrkbN;z`W+6r&LqI|K{2#1;@43xDAijO=Ee zw2`W#8#=hG;ZKVIoEyp=78-`yk&k~Iy)v{^{HnlbzftV^^V_uASGVi?l^$A>!usoO z$(OkU9yGbGreV>i=JT43@N@IomEd5aCq7T~?XxV3G+6I; zO#FPC&*=WDLi6I)f0w-6ZhSlx@T|}=yMAOwGh-R!3ctMen-N&EGd^@2t_3m`snG<+ zWz*Nx@}<_=g;t;F^P4S}U6T|ef{Hfn#UouW;%a^V-44JSH*BiQA$h5?F9b-GpY}gl zJ}l2rpUDm91NpdT=I-jV$A!!M(q*O)6;>Pk9M`yt37DGxVzG02j|Y(C5syxOy`9Y{ z_+>d$++dn**C^DWTyP4Sm?R3h2Smn*;MSx`bG_ym8~5l?WNx2dEW|(0(BHhpNx-xM z)B}5>5x+IbJhSV|4ujP8)s*Xa=YG2P)M?!#81gyVkTVqhK>m57BG#y+FxM*}KU;f_ z%SB{JK)KDS4bMX;5m3Q|CHFTGFzB^@U%PjF_Kxz&KlpJ+4>WNtq5SU^Z$);~&swxj ztzLm56AEH0V*~01tr^J0Vy%c&?X}dX#d9|moy*A%HPz*St)x#t! zuJreKO%(Z)3eHRHcUQd9Xw&0Tm{^cS7>9=&wZ22D7Ix+Pn(;o^C;>A-h)}S3K}yAw zeNi4O0gVW~H8-0TlB{Yq~j%0*QlziZ%VIy^D_+-h*B zv&86IO^Mp_LbYT9ycVf!)D~|tLHv=m)VIw)08B)PR^G}%=!-VhFyl;Uf)9CCR5&3S z#z2fh&TJPdM%|erZ11?pO8`@N{g<>U&mX?FfMi5EJK{G?@1IF1iM_O~hJ~_e9A6qB zEd7mnJhR6C+#fj<8g$|@IC&LqiL9^Cg|b{!?~*=fYz3@#Ae4PDX>`XH(>tUOs`Ika zKUfXw5MFUkj2}RE)x_(beeJ^A2h_@}4l!x$#MR*4gLu^u7R($d0#KJ{(`qMUtEk z>*$XHUr2(@i0LZXKn=dC%m3K;cxt^v+(UaYy`s5RI1B`91N3|v6e)4uRzAC%^-sza z`R?a2Nw=cZi=;D0;7P#yk4JAXiMTrn7^~678~4fO1ERW{KD6kP##fxK8e2lOWSCl} zO>TT7VeZx73WQkxZ=~&3ND>|WTNW{})ZD!T?7i~qM1g!dVE!vT-+ zGUQ?f%M_&y2zK7eE5R&-rF)&gJmsS50**DEh)7R7(7|{H^i0{B31HDpZOV5c2&Ce$ z^Irgc71cbhvggpe_>Z_hWm7EO)c;4Y?J}Cz4*0aJh==4drB=gr`3(Ckr$?SZ9MvD` z>`JWG@kh1Ve@KkbjN1_c*7jdvuVknu+h-X*+PSEy$FXDQ{5;5?LV*ZSF-d#c5o_*ugpXe|Op$T4XmOxoF!Fpj_q;{Y|fHKhR zlDiFd@0G5LmUlU*eV!IBQ&8%6J?oh0U^Xh=yyxzk8s+tpQX<_c6s`#}XqdN&AIKx?HEXf%!i_%!02?^JVOW zZe`o&s;Si;d}MTEaZ+%H&;DLxc@3{_ri=k>*mNps(nundp{h&e77rI>#Ffo}8)*xY z9*3(-C7Y7lrhi8%51xnrmLKz|OJQzjiH$$MGD#j`-Buaz%g|^B78h*)r%)X8NENrB z2Es^O=y{VQ32Xb9mN7D4ldKIy0BByHb*7>VQ>%7f6w|yERbIVn<*B@*z*B9A1kx?V z0>5ms%NivL7VZa3q1^<=@jWcha->_^$IZLVgqj0D*H?%oc4z+Ht6HZ&jbJ=&dLnS7zDeI*g8 z^rS?LbQB1{x%#k)gJ1~~U>=X0N!^)#)UKC3srqTN9j zl&rnlZw7CnbFpxr^jiDR8paRd#Z~s5Kjp_38?6EVZSK1327;lheDWooCfS&~ zY&94d*S2w5G)bEIJ?MQIYuCfUZ-M{>AaM_Bt31S*bfoijfDw9M${$$nv;Ae69&y$M zN#E1NS(@e0wu$ehN%dY+DOI8pgA?s5FyJpGqD0i-m$wvmls6y9b6HUO#Ko7ss5jX! zi#vctH3Tmdu)Mq^5CLq*dp z(u<@E8^K(b-`?q=KAyN#BYwH=|ElK9!;;STJ+3uI9V^B>g@sGyB-7Mn=E{iD#(A@u&ZN6=!4em9xpd@js0XO9K_Ab7SiEf}@?v7rqH;RXOq< z_9#QYLSCwU){TD~db^59H;EH91DS}vMm0uKb%l$M$)(bbbZ_qNgMNKey?f#LIPKTX z4|^dFxBZ=4p5r{yT9PTa^%WU!qzy|u(da7VVqx8=BpW1cZW=7##O*HOxwz6+3LI-L zMNJpF5DmhDUw|#Ye$80+i?Cd~$*{W=POX~RaI=3-Rr_P3yqWHmP#1%~%~vhUOPk(z zV~A_D=Qz`i_vYZdajuO*l}G=oG?b~#{<&zKhX$NFAU_~ilIE6^7zH9xF4S;Gf?>^IcCufTpcY$w zO-&ox>k_W?==zto!%h@n3j(z;QpT|YoclP)Xkey4NDG!E@7h3cqH@+_JP^-9T@DTa zK8j%N6M6dZAI$^vHBMgx(_q>Ret#{@qAKXagd_D8bOFvCl1`aJyDw+&sQy8*gL+>@ zesmG*?zRZBgMDY-#}#{oC-56VX!MNj;H072^W7&>LDsmPy#PZhSjlF z_qGboZshtou;{({&>)w>sb5{A^SCGDT?gq*U1#~;EThH@oUN?UtoA{UiO9% zSl(#XwscXVx~V1LFcFwyzl7)jPEnd@!LxS5pwXvib&SK+OXx5diE2E7f5cohXjmc7|_@#ZRMxix~G6%gRCYv6hPdrdVbcHLUH8=vlygX|}>nuA+Ko>QN@ zzm9<G^ByKm*B3Gp3=p}nBuBCt(?>d36 z?>mG`SLVj=lb$@m85zx2+f%!?h_kBm$BB5XY&_Q2VfdVHVYk^4Y}r3K%&8KI10N#PL;(9RIdf2af* zrY>Sd&9EWY2oowWT>|3M*ah`;no9jeY$)Ar@j>sShJ`ZM6D66R`nqHc>D@8roUsIu zzmZ~ci6%bJ&haj!7h zzlU3wCf&a%j63z0)Y#6U2u-jk-pf4*h2auO{y~3`82OXqrp#(WguxWm#ax*y;oqUv z`-zzW3e+l>D3TQ=+%O9K@BJDjKI!F4=EgV!+zn!f?@Q#?RBPCfZeER5X&es*;LC;j zwz>0XUV%1?Y7f7-L3s6-hQ1pk~D~WvX%H;D-*JNo$jnTFHfBjVJUIXyGGfU1l@e?D>Yq$}1UP1wxhPciS;a z%Tn>5#LNpTY3EDifEOsF0c0t-8(+*!1>vA36{y*hE^?X^-hM!V7T|`xZz_lIOhTY5 zgtq4TNjJ3t#IRG0k#RV1>_yDkwvLaXFB`K9vJZsqx2n+Ty8W};#$8B2$ZT8YCT>HJ zQXcndIAPAf0iAh~n}K)Yyv9GPa04escv|_0?sUglPO7VI^;@St>GGDugwwINZ)U@n zJ;uY5Itntc4^`#FSoDgaj&oOAb_H;DzOFi*`N-Nyb%<-c4l=KOE59@hVe!Mh< z7!A9ey%O3#D%hutr!B{ay&buxZgt6H^+26k7O13wmD5TiZf|%6`Pt$mNcDL|BCXF5!R$W5*z;Q z&f$9>)c4tA6R7P!BlQ`+05%DM2;Gv+{kHzP)C$Rw%(eC2D)@}^@#zpWWAC!)C zzO_8Qa-&E@E9UMQT_TKzQN;CIsmK*t0Ov zE|ZX+fvc_PV< zlE0IepAWu|@;Md^%9&po(f z#Tf^Gk-UK!rAOdV2Hx}=TfPYvdD>?xoygK2o^pn%NT4W#)yK3N-Wy1}AuYg0a-&D> zNY?OJd}(hpO=4s2pwq3_y2I&73o&!-V|!zs8sjZd@qvsTo7~~Zg}EYSe9f%l4Y$P@ zK>F~M$T%{o6|k6&O1=d~VH2;}z|vQAlfh;;Ch%2@uluY@o1}Y4-eYXjvp*f}BCCG?qkmRVSrD`1!X!)O!lE8UUpBK+t#TO;A2Fbrh}SQDVENafH9 zw#TAl!>qizY>3sfrpT*^@3qLtf_uC`-fRHrYa z#igWr=?-Xk+Xr@5RsUsM8FnE3;p2_ICWD& z9A4olRj?uf#As>Ve5(zbq*k|tW!ouR1`|WDY7-Zq*6nILJNKum$?O(cT0oZG6_+$1 z2i-DfZYD$icDIW(Z25a|N-WAhyr@vsPq2^`YwP#?x6vPoK>hVklLi0wh{xi|km&1E zv$C}DmOha)8+8rebfXvab45*Y*p}Yt(V;9^)@rJ#zelvuHaGI^nlQ%DaG0Y8YwiiQ zYoD4j6r_0N9;&*?bru~{-0!;6mvwCLy~AJ_?iRVC310C&jCWhgqP?Wa(#g(z_lsog z-sd$Uu(nU9+mk~HMwvXR z5Ff7MqQ|vJ%eB8t>Xf%$7?ej6r$WsP)US1MwHIf1&es5%W=7>0!-l}1k#7vs(LSXY zS!)<(6oKn`uV<9Li8wvL)|+U2caXWEh-5HSI=ak@D($aUJZm0R?+po%8Nkn3;W8SLHglf&h#!yO$Lzs>l{VmGe*%O4x2ntomY~ zfXe84gm`eH`K^skVxf6qfNpTxWqv|&hPVl&d?_}?q2lXDD=WWHGQ>D3S>#k1+RUoN zjs}CTDj&m&CuS{2L8eXwa5N6i$tx|MA^Xge`r>0sNO!rKw>Xj5iXCh{$dg(GJ2aV>3P23z<)n_jLQ)7GoanmTXb% zU`qTxJ;VDh+V};5S1jLu=^O||6D5=B*ku5GEFVM5yU}uK3!l!cNB@MNjf$4^juU{ml5~n60k7>A6Pj4^bhL zO*EOJ)?gSS-sb9FeP6-kD5o(rX*I%jA&x`@)Lk?2!UUaZM|6k=Z?4BtVUa%j)FPO& zUSC?KH)`RbGoep5-ncM6c9z|J(}~5+Cw^wr8fr>#}+*^fzP$AN9gYkN{Mag9+*}V_=p#1JnKF`Wl57ji2?*sV9s|c zLeDc+QumL4Y*M0Jcyxa zUK_{nxWGBoz)ZwSR4<+G7|H4e#bseN-Ex-Z-G1MJsiY5j-zWJ@+)S4K9=2@Z_abNO zIEct3O`LRBCbvH>xLj9t#-PI6I%{fs*`;ZMNiPj6VcRGq{K^&O3wgH)TQ4dOoNVHL z!}TC*=Wu05M>$OHN-TV26=-n$hJ6A*ovA7G;h1Y0YydAtee6)D&9;XAoQ+wX(LNKQ zOF+(}@r*31>FzAoSj3cizn2Ah1*1Ef`v6iFaaSh;5jFE}w;;$-f)GkDz%&c_iyWI@&->5Kj~zd@9bxipT<^x` z7H#)ORNLY6U$jre5ywZvm9BI90u4UOy;cIKc$Ha0dW$ZS99*fHg|OB!_bgL2(-5{y z5pvMxOKJ7?`D^4V0)D)*I@B8t>UpY!Q#+Gks~jTq)hAjGH)yIm?igsd?#wx$8%6>F z;`4m?z5MdP?Kz%;cykgSjRVA3t{*5UJ<{u zbJd1pZil9XUS0Xc1%dR%f9qVj7>KFt+adiC_Ux+!hd>4U$X-d{m-`!9?7W{I$u3s} zce(d{_pBQpJ*Ya_^bGpCe3T)`eFZj%*dksT%+h1b}c)-PKqu9_zAq}Z+M;wp)iymfG;lfFCaeSLv z*eai;&*RB?TO{ij2{uXPtNTSa-s}|SiF0Gx6Ln@181V=D{5&&B>t7|=B#Ocsv`uzJ z;6}V7ySyX43j0&_hERT`KZSQLiRSMN_Q&gFM3wyLc)`)%F*IuWeS)Lj5B~Pkz;jF; zB0zq3uw8ignU&La+#xzjMWD0?lrVn!+}i%xI)?P9IqmMm`Q8U-VJC*pc(K}m*`7*e zZJapvgOk^E+p8r{f_ak>^8Z^|`f$jY60)kZ>gje*? Date: Sun, 29 Jun 2025 03:33:26 +0000 Subject: [PATCH 10/51] ci: update xcode version --- .github/workflows/deployment.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index 1d6cdf02..192c7f3f 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -9,7 +9,7 @@ jobs: strategy: matrix: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs platform: [mac, ios] - runs-on: macos-latest # https://github.com/actions/runner-images + runs-on: macos-15 # https://github.com/actions/runner-images steps: - uses: actions/checkout@v4 # https://github.com/actions/checkout with: @@ -38,7 +38,7 @@ jobs: - run: npm run build:${{ matrix.platform }}-safari-15 if: ${{ ! github.event.release.prerelease }} - name: Set xcode version - run: sudo xcode-select -s "/Applications/Xcode_16.2.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md#xcode + run: sudo xcode-select -s "/Applications/Xcode_26.0.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md#xcode - name: Run fastlane id: fastlane working-directory: ./fastlane From dc5a1dd077ea2fdde473b6f0f40612d35c3bb4fb Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Sun, 29 Jun 2025 03:59:03 +0000 Subject: [PATCH 11/51] chore: clean up some redundant codes --- src/shared/Components/LogoIcon.svelte | 4 ---- src/shared/Components/LogoText.svelte | 3 --- 2 files changed, 7 deletions(-) diff --git a/src/shared/Components/LogoIcon.svelte b/src/shared/Components/LogoIcon.svelte index ff9991cc..7b5f74df 100644 --- a/src/shared/Components/LogoIcon.svelte +++ b/src/shared/Components/LogoIcon.svelte @@ -1,11 +1,7 @@ - - diff --git a/src/shared/Components/LogoText.svelte b/src/shared/Components/LogoText.svelte index 849b023d..e5ad9068 100644 --- a/src/shared/Components/LogoText.svelte +++ b/src/shared/Components/LogoText.svelte @@ -1,8 +1,5 @@ - - Date: Sun, 29 Jun 2025 04:03:29 +0000 Subject: [PATCH 12/51] chore: update ci comment link --- .github/workflows/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index 192c7f3f..ef193cf6 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -38,7 +38,7 @@ jobs: - run: npm run build:${{ matrix.platform }}-safari-15 if: ${{ ! github.event.release.prerelease }} - name: Set xcode version - run: sudo xcode-select -s "/Applications/Xcode_26.0.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-14-arm64-Readme.md#xcode + run: sudo xcode-select -s "/Applications/Xcode_26.0.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md#xcode - name: Run fastlane id: fastlane working-directory: ./fastlane From 02965ed20e9070a366e24b56c0fd2b8158249025 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Mon, 7 Jul 2025 06:28:15 +0000 Subject: [PATCH 13/51] ci: avoid use xcode symbolic links --- .github/workflows/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index ef193cf6..f63d7243 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -38,7 +38,7 @@ jobs: - run: npm run build:${{ matrix.platform }}-safari-15 if: ${{ ! github.event.release.prerelease }} - name: Set xcode version - run: sudo xcode-select -s "/Applications/Xcode_26.0.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md#xcode + run: sudo xcode-select -s "/Applications/Xcode_26_beta.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md#xcode - name: Run fastlane id: fastlane working-directory: ./fastlane From 1bd811ebfb8bebb657fe0871ceecf17be024ac2a Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Mon, 7 Jul 2025 06:56:03 +0000 Subject: [PATCH 14/51] ci: try manually install ios component --- .github/workflows/deployment.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index f63d7243..86855b3f 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -39,6 +39,7 @@ jobs: if: ${{ ! github.event.release.prerelease }} - name: Set xcode version run: sudo xcode-select -s "/Applications/Xcode_26_beta.app" # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-arm64-Readme.md#xcode + - run: xcodebuild -downloadPlatform iOS # Temporary fix for Xcode_26_beta - name: Run fastlane id: fastlane working-directory: ./fastlane From 178782a9f748b397229b5333655efa4dfb97ac1b Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Mon, 7 Jul 2025 16:44:12 +0000 Subject: [PATCH 15/51] build(gem): update fastlane --- fastlane/Gemfile.lock | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/fastlane/Gemfile.lock b/fastlane/Gemfile.lock index 989cb342..a8ba4db2 100644 --- a/fastlane/Gemfile.lock +++ b/fastlane/Gemfile.lock @@ -9,26 +9,26 @@ GEM public_suffix (>= 2.0.2, < 7.0) artifactory (3.0.17) atomos (0.1.3) - aws-eventstream (1.3.2) - aws-partitions (1.1106.0) - aws-sdk-core (3.224.0) + aws-eventstream (1.4.0) + aws-partitions (1.1125.0) + aws-sdk-core (3.226.2) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) base64 jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.101.0) - aws-sdk-core (~> 3, >= 3.216.0) + aws-sdk-kms (1.106.0) + aws-sdk-core (~> 3, >= 3.225.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.186.1) - aws-sdk-core (~> 3, >= 3.216.0) + aws-sdk-s3 (1.192.0) + aws-sdk-core (~> 3, >= 3.225.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) - aws-sigv4 (1.11.0) + aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) - base64 (0.2.0) + base64 (0.3.0) claide (1.1.0) colored (1.2) colored2 (3.1.2) @@ -57,10 +57,10 @@ GEM faraday (>= 0.8.0) http-cookie (~> 1.0.0) faraday-em_http (1.0.0) - faraday-em_synchrony (1.0.0) + faraday-em_synchrony (1.0.1) faraday-excon (1.1.0) faraday-httpclient (1.0.1) - faraday-multipart (1.1.0) + faraday-multipart (1.1.1) multipart-post (~> 2.0) faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) @@ -70,7 +70,7 @@ GEM faraday_middleware (1.2.1) faraday (~> 1.0) fastimage (2.4.0) - fastlane (2.227.2) + fastlane (2.228.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -157,8 +157,8 @@ GEM httpclient (2.9.0) mutex_m jmespath (1.6.2) - json (2.12.0) - jwt (2.10.1) + json (2.12.2) + jwt (2.10.2) base64 logger (1.7.0) mini_magick (4.13.2) @@ -167,13 +167,13 @@ GEM multipart-post (2.4.1) mutex_m (0.3.0) nanaimo (0.4.0) - naturally (2.2.1) + naturally (2.3.0) nkf (0.2.0) optparse (0.6.0) os (1.1.4) plist (3.7.2) public_suffix (6.0.2) - rake (13.2.1) + rake (13.3.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) From 12f00e40ed7319ed16cced574e52460467ab3820 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:30:22 +0000 Subject: [PATCH 16/51] docs: notes icloud folder guide --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0601bfc..9f563559 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ After installing the iOS App, you need two main steps to make the extension work > > The App cannot detect whether you have enabled the extension in Safari, therefore, the App prompt will not change after you enable the extension. Currently the App interface is only used to set or change the userscripts directory. > -> You could select an iCloud folder for syncing scripts between macOS and iOS, but please note that there may be delays in synchronization, and you may encounter files be evictioned due to iCloud optimization, please refer to [#424](https://github.com/quoid/userscripts/issues/424). +> You could select an iCloud folder for syncing scripts between macOS and iOS, but please note that there may be delays in synchronization, and you may encounter files be evictioned due to iCloud optimization, please refer to [#424](https://github.com/quoid/userscripts/issues/424). (**Since macOS 15 / iOS 18, please set "keep downloaded" for the folder to avoid eviction**) There are two main ways to install a user script from the iOS version: From 7e4276042e1784a3c0747ad865cabfa760370566 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:37:16 +0000 Subject: [PATCH 17/51] docs: update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f563559..269aa89b 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ After installing the iOS App, you need two main steps to make the extension work > [!NOTE] > -> The App cannot detect whether you have enabled the extension in Safari, therefore, the App prompt will not change after you enable the extension. Currently the App interface is only used to set or change the userscripts directory. +> The iOS App cannot detect whether you have enabled the extension in Safari, therefore, the App prompt will not change after you enable the extension. Currently the App interface is only used to set or change the userscripts directory. > > You could select an iCloud folder for syncing scripts between macOS and iOS, but please note that there may be delays in synchronization, and you may encounter files be evictioned due to iCloud optimization, please refer to [#424](https://github.com/quoid/userscripts/issues/424). (**Since macOS 15 / iOS 18, please set "keep downloaded" for the folder to avoid eviction**) From bb9437b5fde33e8f01ae4497e9cb77265aaea194 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:49:08 +0000 Subject: [PATCH 18/51] chore: update year information --- README.md | 2 +- docs/contributing.md | 2 +- docs/dev.md | 2 +- docs/structure.md | 2 +- xcode/xcconfig/Userscripts-Release.xcconfig | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 269aa89b..09cdc78a 100644 --- a/README.md +++ b/README.md @@ -386,6 +386,6 @@ Userscripts does not collect any data from its users nor monitor activities or a ## License -Copyright (c) 2018-2024 Justin Wasack +Copyright © 2018-2025 Justin Wasack Licensed under the [GNU General Public License v3.0](/LICENSE) license for all open source applications. A commercial license is required for all other applications. diff --git a/docs/contributing.md b/docs/contributing.md index 7d09d9d4..3cb92e9d 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -117,4 +117,4 @@ If you are not a member of the project, first you need to fork the master branch # About -[Userscripts](https://github.com/quoid/userscripts) @ 2018-2023 +[Userscripts](https://github.com/quoid/userscripts) diff --git a/docs/dev.md b/docs/dev.md index 2bfa7681..262aac05 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -79,4 +79,4 @@ Note that all existing `.xcconfig` files already include `.dev.xcconfig` files o # About -[Userscripts](https://github.com/quoid/userscripts) @ 2018-2024 +[Userscripts](https://github.com/quoid/userscripts) diff --git a/docs/structure.md b/docs/structure.md index d493c3b7..1a0cd320 100644 --- a/docs/structure.md +++ b/docs/structure.md @@ -38,4 +38,4 @@ Build the project from here to extension bundled app # About -[Userscripts](https://github.com/quoid/userscripts) @ 2018-2023 +[Userscripts](https://github.com/quoid/userscripts) diff --git a/xcode/xcconfig/Userscripts-Release.xcconfig b/xcode/xcconfig/Userscripts-Release.xcconfig index 886f5a47..8c52d66b 100644 --- a/xcode/xcconfig/Userscripts-Release.xcconfig +++ b/xcode/xcconfig/Userscripts-Release.xcconfig @@ -1,6 +1,6 @@ #include "Userscripts-Base.xcconfig" -INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2018–2024 Justin Wasack. All rights reserved. +INFOPLIST_KEY_NSHumanReadableCopyright = Copyright © 2018–2025 Justin Wasack. All rights reserved. CURRENT_PROJECT_VERSION = 1 MARKETING_VERSION = 1.0.0 From e03d49edfc621c8f43a4cab5fa28213d3d2ab975 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:55:02 +0000 Subject: [PATCH 19/51] refactor: use light-dark for console log colors --- src/ext/content-scripts/entry-userscripts.js | 20 ++++++------- src/shared/colors.js | 31 +++++--------------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/ext/content-scripts/entry-userscripts.js b/src/ext/content-scripts/entry-userscripts.js index 5c0f79e7..5721dd90 100644 --- a/src/ext/content-scripts/entry-userscripts.js +++ b/src/ext/content-scripts/entry-userscripts.js @@ -1,5 +1,5 @@ import USAPI from "./api.js"; -import { getColor } from "@shared/colors.js"; +import { colors } from "@shared/colors.js"; // code received from background page will be stored in this variable // code referenced again when strict CSPs block initial injection attempt @@ -63,13 +63,13 @@ ${userscript.code} } const world = injectInto === "content" ? "content" : "page"; if (window.self === window.top) { - console.info(`Injecting: ${name} %c(js/${world})`, getColor("yellow")); + console.info(`Injecting: ${name} %c(js/${world})`, colors.yellow); } else { console.info( `Injecting: ${name} %c(js/${world})%c - %cframe(${label})(${window.location})`, - getColor("yellow"), - getColor(), - getColor("blue"), + colors.yellow, + colors.inherit, + colors.blue, ); } if (world === "page") { @@ -95,13 +95,13 @@ ${userscript.code} function injectCSS(name, code) { if (window.self === window.top) { - console.info(`Injecting ${name} %c(css)`, getColor("green")); + console.info(`Injecting ${name} %c(css)`, colors.green); } else { console.info( `Injecting ${name} %c(css)%c - %cframe(${label})(${window.location})`, - getColor("green"), - getColor(), - getColor("blue"), + colors.green, + colors.inherit, + colors.blue, ); } // Safari lacks full support for tabs.insertCSS @@ -247,7 +247,7 @@ function listeners() { for (let i = 0; i < data.files.menu.length; i++) { const item = data.files.menu[i]; if (item.scriptObject.filename === filename) { - console.info(`Injecting ${filename} %c(js)`, getColor("yellow")); + console.info(`Injecting ${filename} %c(js)`, colors.yellow); injectJS(item); return; } diff --git a/src/shared/colors.js b/src/shared/colors.js index f7162e40..71a2412f 100644 --- a/src/shared/colors.js +++ b/src/shared/colors.js @@ -1,25 +1,10 @@ -const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)"); - -let isDark = darkModeQuery.matches; - -darkModeQuery.addEventListener("change", () => { - isDark = darkModeQuery.matches; -}); - /** - * Get theme colors for console log css - * @param {string=} color + * Theme colors for console log css + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output} */ -export function getColor(color) { - if (!color) return "color: inherit"; - const colors = { - blue: { dark: "#006fff", light: "#317eff" }, - green: { dark: "#60f36c", light: "#2bb239" }, - yellow: { dark: "#fff600", light: "#b8722c" }, - }; - if (color in colors) { - const hex = isDark ? colors[color].dark : colors[color].light; - return `color: ${hex}`; - } - return ""; -} +export const colors = { + inherit: "color: inherit", + blue: "color: light-dark( #317eff, #006fff);", + green: "color: light-dark( #2bb239, #60f36c);", + yellow: "color: light-dark( #b8722c, #fff600);", +}; From 599cc7bdc5c5cdda1a04a8b830248aa80135631b Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 8 Jul 2025 21:59:41 +0000 Subject: [PATCH 20/51] chore: add a trailing semicolon --- src/shared/colors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/colors.js b/src/shared/colors.js index 71a2412f..73d9001f 100644 --- a/src/shared/colors.js +++ b/src/shared/colors.js @@ -3,7 +3,7 @@ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/console#styling_console_output} */ export const colors = { - inherit: "color: inherit", + inherit: "color: inherit;", blue: "color: light-dark( #317eff, #006fff);", green: "color: light-dark( #2bb239, #60f36c);", yellow: "color: light-dark( #b8722c, #fff600);", From f618f01d4a46de20870134467455fc83027490ef Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:47:19 +0000 Subject: [PATCH 21/51] chore: fix dev public dir --- scripts/dev-safari.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/dev-safari.js b/scripts/dev-safari.js index 34943850..c9236b9f 100644 --- a/scripts/dev-safari.js +++ b/scripts/dev-safari.js @@ -186,6 +186,7 @@ async function serverCheck(url) { /** run development server */ const server = await createServer({ ...sharedConfig, + publicDir: "public/ext/vendor/", plugins: [svelte()], server: { host: true, From c4aee6442024780fd13ed4e21eb898026320e8a2 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Mon, 21 Jul 2025 16:51:40 +0000 Subject: [PATCH 22/51] fix: editor tab key restores default behavior --- src/ext/extension-page/Components/Editor/CodeMirror.svelte | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ext/extension-page/Components/Editor/CodeMirror.svelte b/src/ext/extension-page/Components/Editor/CodeMirror.svelte index f097189b..b2cbacda 100644 --- a/src/ext/extension-page/Components/Editor/CodeMirror.svelte +++ b/src/ext/extension-page/Components/Editor/CodeMirror.svelte @@ -150,11 +150,6 @@ "Cmd-S": () => saveHandler(), "Cmd-F": () => activateSearch(), Esc: () => (searchActive = false), - Tab: (cm) => { - // convert tabs to spaces and add invisible elements - const s = Array(cm.getOption("indentUnit") + 1).join(" "); - cm.replaceSelection(s); - }, }, }); From 649157a4bbcb3e2fa5d06c5cf56d98e050258b8a Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:33:30 +0000 Subject: [PATCH 23/51] style: avoid the button being shrink --- src/shared/Components/IconButton.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/Components/IconButton.svelte b/src/shared/Components/IconButton.svelte index 99751f97..52ec42cc 100644 --- a/src/shared/Components/IconButton.svelte +++ b/src/shared/Components/IconButton.svelte @@ -28,6 +28,7 @@ color: inherit; cursor: pointer; display: flex; + flex-shrink: 0; height: 1.5rem; justify-content: center; overflow: visible; From 546fdf5f0f7a48049c229d7e528e2f7f5f96e04d Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:35:42 +0000 Subject: [PATCH 24/51] fix: add truncate to couple element --- src/ext/extension-page/Components/Editor/Editor.svelte | 2 +- src/ext/extension-page/Components/Sidebar/SidebarItem.svelte | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ext/extension-page/Components/Editor/Editor.svelte b/src/ext/extension-page/Components/Editor/Editor.svelte index 0bdd3507..adcd67dd 100644 --- a/src/ext/extension-page/Components/Editor/Editor.svelte +++ b/src/ext/extension-page/Components/Editor/Editor.svelte @@ -173,7 +173,7 @@
{name}
-
+
{#if $v4state.includes("saving")} Saving... {:else if $v4state.includes("trashing")} diff --git a/src/ext/extension-page/Components/Sidebar/SidebarItem.svelte b/src/ext/extension-page/Components/Sidebar/SidebarItem.svelte index 266d68bc..c7c27bc7 100644 --- a/src/ext/extension-page/Components/Sidebar/SidebarItem.svelte +++ b/src/ext/extension-page/Components/Sidebar/SidebarItem.svelte @@ -42,7 +42,10 @@
{#if description} -
+
{description}
{/if} From 22b3b516e480dd1241fc0f6aa857b194b60b6603 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:39:56 +0000 Subject: [PATCH 25/51] feat: activate the first script on mount --- src/ext/extension-page/Components/Sidebar/Sidebar.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ext/extension-page/Components/Sidebar/Sidebar.svelte b/src/ext/extension-page/Components/Sidebar/Sidebar.svelte index cbc62445..2c38d359 100644 --- a/src/ext/extension-page/Components/Sidebar/Sidebar.svelte +++ b/src/ext/extension-page/Components/Sidebar/Sidebar.svelte @@ -30,6 +30,8 @@ $: if (list.find((a) => a.active)) { const active = list.find((a) => a.active); scrollToEl(active.filename); + } else { + activate(list[0]); } /** From d652e573893aa58ae5c7afa79c4dfc87a9d46884 Mon Sep 17 00:00:00 2001 From: ACTCD <101378590+ACTCD@users.noreply.github.com> Date: Tue, 22 Jul 2025 12:42:51 +0000 Subject: [PATCH 26/51] refactor: split class attributes for clearer --- src/ext/extension-page/Components/Sidebar/Sidebar.svelte | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ext/extension-page/Components/Sidebar/Sidebar.svelte b/src/ext/extension-page/Components/Sidebar/Sidebar.svelte index 2c38d359..bdab0149 100644 --- a/src/ext/extension-page/Components/Sidebar/Sidebar.svelte +++ b/src/ext/extension-page/Components/Sidebar/Sidebar.svelte @@ -206,9 +206,8 @@