[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CBBAGJ0CHCSNMNV53WX982":3,"skill-same:01M6CBBAGJ0CHCSNMNV53WX982":44},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":21,"frontMatter":22,"refName":23,"commitSha":24,"skillDirectory":25,"forksCount":13,"repositoryHtmlUrl":26,"repositoryHomepageUrl":6,"ownerHtmlUrl":27,"ownerBlogUrl":6,"ownerDescription":28,"updatedAt":29,"install":30,"resources":43},"01M6CBBAGJ0CHCSNMNV53WX982","13-asset-manager",null,"devwinsoft\u002Fdevian","devwinsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F22570160?v=4","01M6C6RR8W05NH8NPKQNCE3Q72","maoshy","01M6C6RRDJ5TJJCZXRTY801YDH",0,"MIT","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian-unity\u002F20-common-package\u002F13-asset-manager\u002FSKILL.md",[],[18],"13 asset manager","2026-11-10 10:12:30",false,"# 13-asset-manager\n\nStatus: ACTIVE  \nAppliesTo: v10\n\n## SSOT\n\n이 문서는 `AssetManager` 컴포넌트의 **API, 정책, 검증 규칙**을 정의한다.\n\n---\n\n## 목적\u002F범위\n\n**Addressables 기반 로딩\u002F캐시 + Resources 로딩(옵션) + Scene 로딩(Addressables + Build Profile fallback) + Editor Find를 제공하는 Unity 전용 컴포넌트.**\n\n- **런타임(필수)**: Addressables로 라벨\u002F키 기반 에셋 로드 → 캐시에 등록 → 이름으로 조회\n- **런타임(씬)**: Addressables 키 우선, Build Profile(SceneManager) fallback으로 씬 로드\n- **런타임(옵션)**: Resources 로드\u002F언로드 (캐시 포함)\n- **에디터**: `UNITY_EDITOR` 전용 Find 메서드 (AssetDatabase 기반)\n\n> **Note:** 이 문서에서 \"Bundle\"은 **파일 기반 AssetBundle이 아니라 Addressables의 label\u002Fkey 묶음**을 의미한다.\n\n---\n\n## 소스 경로\n\n| 위치 | 경로 |\n|------|------|\n| UPM 소스 | `framework-cs\u002Fupm\u002Fcom.devian.foundation\u002FRuntime\u002FUnity\u002FAssetManager\u002FAssetManager.cs` |\n| UnityExample | `framework-cs\u002Fapps\u002FUnityExample\u002FPackages\u002Fcom.devian.foundation\u002FRuntime\u002FUnity\u002FAssetManager\u002FAssetManager.cs` |\n\n---\n\n## API\n\n```csharp\nnamespace Devian\n{\n    public static class AssetManager\n    {\n        \u002F\u002F ====================================================================\n        \u002F\u002F Addressables (Bundle 의미 = Label\u002FKey)\n        \u002F\u002F ====================================================================\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F Addressables에서 단일 에셋을 로드하고 캐시한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static async Task\u003CCommonResult> LoadBundleAsset\u003CT>(string key) where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F Addressables에서 label\u002Fkey에 해당하는 모든 에셋을 로드하고 캐시한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static async Task\u003CCommonResult> LoadBundleAssets\u003CT>(string key) where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F Addressables에서 key AND lang (intersection)에 해당하는 에셋을 로드하고 캐시한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static async Task\u003CCommonResult> LoadBundleAssets\u003CT>(string key, SystemLanguage lang) where T : UnityEngine.Object;\n\n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F Addressables에서 key에 해당하는 에셋을 로드하고 지정된 Component를 캐시한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static async Task\u003CCommonResult> LoadBundleComponents\u003CT>(string key) where T : Component;\n\n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 지정된 key로 로드된 에셋들을 캐시에서 제거하고 Addressables handle을 해제한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static IEnumerable\u003Cstring> UnloadBundleAssets(string key);\n\n        \u002F\u002F ====================================================================\n        \u002F\u002F Scene Load\u002FUnload (Addressables + Build Profile fallback)\n        \u002F\u002F ====================================================================\n\n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 씬을 로드한다. Addressables 키가 존재하면 Addressables로, 없으면 Build Profile(SceneManager) fallback.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static async Task\u003CCommonResult> LoadSceneAsync(\n            string key,\n            UnityEngine.SceneManagement.LoadSceneMode mode = UnityEngine.SceneManagement.LoadSceneMode.Single,\n            bool activateOnLoad = true,\n            int priority = 100);\n\n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F LoadSceneAsync로 로드한 씬을 언로드한다. Addressables\u002FBuild Profile 자동 분기.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static async Task\u003CCommonResult> UnloadSceneAsync(string key, bool autoReleaseHandle = true);\n        \n        \u002F\u002F ====================================================================\n        \u002F\u002F Cache Access (즉시 반환)\n        \u002F\u002F ====================================================================\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 파일명으로 캐시된 에셋을 가져온다 (확장자 제거, 대소문자 무시).\n        \u002F\u002F\u002F 탐색 순서: Bundle 캐시 → Resource 캐시\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static T? GetAsset\u003CT>(string fileName) where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F GetAsset의 별칭 (기존 코드 호환용).\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static T? LoadAsset\u003CT>(string fileName) where T : UnityEngine.Object;\n        \n        \u002F\u002F ====================================================================\n        \u002F\u002F Resources (옵션)\n        \u002F\u002F ====================================================================\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F Resources 폴더에서 에셋을 로드하고 캐시한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static T? LoadResourceAsset\u003CT>(string filePath, SystemLanguage lang = SystemLanguage.Unknown)\n            where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F Resources 폴더 하위 디렉토리에서 모든 에셋을 로드하고 캐시한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static T[] LoadResourceAssets\u003CT>(string searchDir, SystemLanguage lang = SystemLanguage.Unknown)\n            where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 캐시된 Resource 에셋을 언로드한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static void UnloadResourceAsset\u003CT>(string fileName) where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 디렉토리에 해당하는 캐시된 Resource 에셋들을 언로드한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static IEnumerable\u003Cstring> UnloadResourceAssets\u003CT>(string searchDir) where T : UnityEngine.Object;\n        \n        \u002F\u002F ====================================================================\n        \u002F\u002F Cleanup\n        \u002F\u002F ====================================================================\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 모든 캐시된 번들과 리소스를 정리한다.\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static void ClearAll();\n        \n        \u002F\u002F ====================================================================\n        \u002F\u002F Editor-Only Find Methods (UNITY_EDITOR)\n        \u002F\u002F ====================================================================\n        \n#if UNITY_EDITOR\n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 프로젝트에서 파일명으로 에셋을 검색한다 (에디터 전용).\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static T[] FindAssets\u003CT>(string fileName, params string[] searchDirs) \n            where T : UnityEngine.Object;\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 프로젝트에서 모든 프리팹을 검색한다 (에디터 전용).\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static GameObject[] FindPrefabs(params string[] searchDirs);\n        \n        \u002F\u002F\u002F \u003Csummary>\n        \u002F\u002F\u002F 특정 컴포넌트를 가진 프리팹을 검색한다 (에디터 전용).\n        \u002F\u002F\u002F \u003C\u002Fsummary>\n        public static GameObject[] FindPrefabs\u003CT>(params string[] searchDirs) \n            where T : Component;\n#endif\n    }\n}\n```\n\n---\n\n## Hard Rules (정책)\n\n### 1. Addressables 기반 (필수)\n\n**`LoadBundleAsset(s)`는 Addressables API를 사용한다.**\n\n- `LoadBundleAssets\u003CT>(key)`: `Addressables.LoadAssetsAsync\u003CT>(key, onEachLoaded)` 사용\n- `LoadBundleAssets\u003CT>(key, lang)`: `Addressables.MergeMode.Intersection`으로 key + lang 교집합 로드\n- `UnloadBundleAssets(key)`: 해당 key의 handle을 `Addressables.Release`로 해제\n\n### 2. 캐시 키 규칙 (NormalizeAssetName)\n\n**에셋 키는 `NormalizeAssetName(name)` = `Path.GetFileNameWithoutExtension(name).ToLowerInvariant()`로 정규화한다.**\n\n```csharp\nprivate static string NormalizeAssetName(string name)\n{\n    return Path.GetFileNameWithoutExtension(name).ToLowerInvariant();\n}\n\n\u002F\u002F 예시\n\"TestSheet.json\" → \"testsheet\"\n\"Cube.prefab\" → \"cube\"\n```\n\n- 대소문자 무시 (case-insensitive)\n- 확장자 제거\n- 중복 이름(type별)은 오류 로그 후 등록 거부 (기존 에셋 우선, handle leak 방지)\n\n### 3. 네이밍 예외 (@로 시작하는 에셋)\n\n**에셋의 원본 이름(`asset.name`)이 `@`로 시작하면 캐시에 등록하지 않고 handle을 즉시 해제한다.**\n\n```csharp\n\u002F\u002F 정규화 전 원본 asset.name 기준으로 체크\nif (asset.name.StartsWith(\"@\"))\n{\n    Addressables.Release(handle);\n    yield break; \u002F\u002F skip registration\n}\n```\n\n> **Note:** `assetKey`(정규화 후)가 아니라 `asset.name`(원본) 기준이다. 정규화는 캐시 등록 직전에만 수행된다.\n\n### 4. Resources 허용 범위\n\n**Resources는 명시 API(`LoadResourceAsset(s)` \u002F `UnloadResourceAsset(s)`)로만 로드\u002F정리한다.**\n\n- `GetAsset\u003CT>` 탐색 순서: **Bundle(Addressables) 캐시 → Resource 캐시**\n- 무분별한 `Resources.Load` 직접 호출은 권장하지 않음\n\n### 5. 파일 AssetBundle 로딩 제거\n\n**파일 경로 기반 AssetBundle 로딩(`AssetBundle.LoadFromFileAsync`)은 지원하지 않는다.**\n\n- `LoadBundle(key, bundleFilePath)` 형태의 API 없음\n- Addressables가 카탈로그\u002F그룹을 통해 번들을 관리함\n\n### 6. 동일 key 재로드 정책 (Handle Leak 방지)\n\n**이미 로드된 key로 `LoadBundleAsset` 또는 `LoadBundleAssets`를 다시 호출하면 경고만 출력하고 무시한다.**\n\n```csharp\n\u002F\u002F 이미 로드된 key인 경우\nif (mBundles.ContainsKey(key))\n{\n    Debug.LogWarning($\"[AssetManager] Bundle '{key}' already loaded.\");\n    return CommonResult.Ok();  \u002F\u002F 중복 로드 방지 → handle leak 방지\n}\n```\n\n**중복 asset name(type별) 발견 시:**\n\n```csharp\nif (typeDict.ContainsKey(assetKey))\n{\n    Debug.LogError($\"[AssetManager] Duplicate asset name '{assetKey}' for type {type.Name}. Ignoring.\");\n    Addressables.Release(handle);  \u002F\u002F 기존 에셋 우선, 새 handle 해제\n    yield break;\n}\n\n### 7. Scene 로딩 분기 정책\n\n**Scene 로딩은 Addressables 우선, Build Profile fallback으로 동작한다.**\n\n- `LoadSceneAsync(key)` 호출 시 `Addressables.LoadResourceLocationsAsync`로 키 존재 여부를 확인\n- Addressables 키 존재 → `Addressables.LoadSceneAsync` 사용 (기존 동작)\n- Addressables 키 미존재 → `SceneManager.LoadSceneAsync` fallback (Build Profile 씬)\n- Addressables 씬은 `mScenes` (handle cache), Build Profile 씬은 `mBuildProfileScenes` (HashSet)로 별도 추적\n- `UnloadSceneAsync(key)` 호출 시 Build Profile\u002FAddressables 자동 분기\n\n### 8. Scene handle cache 정리 정책\n\n**Scene cache는 `Scene.isLoaded == false` 인 stale handle을 자동 정리해야 한다.**\n\n- `LoadSceneAsync()` 진입 전 stale scene handle prune 수행\n- `LoadSceneMode.Single` 로드 성공 후 stale scene handle prune 재수행\n- `UnloadSceneAsync()` 호출 시 invalid\u002Funloaded handle이면 캐시에서 제거하고 handle release\n- stale handle 검사\u002F해제 중 예외가 발생해도 로드 흐름은 계속 진행하고, 캐시만 안전하게 정리\n- Build Profile 씬도 stale 정리 대상 (`SceneManager.GetSceneByName`으로 확인)\n```\n\n> **Note:** `LoadBundleAssets(key, lang)` 오버로드도 동일하게 `key`로 중복 체크 및 저장한다. 언로드는 항상 `UnloadBundleAssets(key)`로 수행.\n\n---\n\n## 사용 예시\n\n### BundleManager + AssetManager 연동\n\n```csharp\nusing Devian;\nusing UnityEngine;\n\npublic class BootSequence : MonoBehaviour\n{\n    async Task Start()\n    {\n        \u002F\u002F 1. bootstrap prefab\u002Fscene object에 미리 부착된 BundleManager로 다운로드 정책 수행\n        var dm = BundleManager.Instance;\n\n        var patchResult = await dm.InitializeAsync(labels);\n        if (patchResult.IsSuccess)\n            Debug.Log($\"Total: {patchResult.Value!.TotalSize} bytes\");\n\n        var downloadResult = await dm.DownloadAsync(\n            labels,\n            progress => Debug.Log($\"Progress: {progress * 100:F1}%\")\n        );\n        \n        \u002F\u002F 2. AssetManager로 Addressables 에셋 로드\n        await AssetManager.LoadBundleAssets\u003CGameObject>(\"prefabs\");\n        await AssetManager.LoadBundleAssets\u003CTextAsset>(\"table-ndjson\");\n        \n        \u002F\u002F 3. 캐시에서 즉시 조회\n        var cube = AssetManager.LoadAsset\u003CGameObject>(\"Cube\");\n        var testSheet = AssetManager.GetAsset\u003CTextAsset>(\"TestSheet\");\n        \n        if (cube != null)\n        {\n            Instantiate(cube);\n        }\n        \n        if (testSheet != null)\n        {\n            Debug.Log(testSheet.text);\n        }\n    }\n    \n    void OnDestroy()\n    {\n        \u002F\u002F 정리\n        AssetManager.ClearAll();\n    }\n}\n```\n\n### Resources 로딩 (옵션)\n\n```csharp\n\u002F\u002F Resources 폴더에서 로드 (Addressables가 아닌 경우)\nvar config = AssetManager.LoadResourceAsset\u003CTextAsset>(\"Config\u002Fsettings\");\n\n\u002F\u002F 캐시에서 조회 (Bundle + Resources 모두 탐색)\nvar asset = AssetManager.GetAsset\u003CTextAsset>(\"settings\");\n\n\u002F\u002F 정리\nAssetManager.UnloadResourceAsset\u003CTextAsset>(\"settings\");\n```\n\n---\n\n## String Table Caveat (Hard Rule)\n\n**AssetManager는 에셋을 \"이름(fileName)\" 기준으로 캐시한다.**\n\nString Table은 언어별로 같은 TableName 파일이 존재하므로, AssetManager 캐시를 직접 재사용하면 **언어 충돌**이 발생한다.\n\n### 금지 패턴\n\n```csharp\n\u002F\u002F FAIL: AssetManager로 String Table 로드\nyield return AssetManager.LoadBundleAsset\u003CTextAsset>(\"string\u002Fndjson\u002FKorean\u002FUIText\");\nvar text = AssetManager.GetAsset\u003CTextAsset>(\"UIText\"); \u002F\u002F 언어 충돌!\n```\n\n### 올바른 패턴\n\n**String Table은 `TableManager` + `ST_{TableName}`을 사용하고, `(format, language, tableName)` 키로 별도 캐시한다.**\n\n```csharp\n\u002F\u002F CORRECT: TableManager \u002F ST_ 사용\nyield return ST_UIText.PreloadAsync(\"ndjson\", SystemLanguage.Korean);\nvar text = ST_UIText.Get(\"ndjson\", SystemLanguage.Korean, \"greeting\");\n```\n\n> **Reference**: `skills\u002Fdevian-unity\u002F20-common-package\u002F31-table-manager\u002FSKILL.md`\n\n---\n\n## DoD (검증 가능)\n\n### PASS 조건\n\n- [ ] `AssetManager\u002FAssetManager.cs` (UPM + UnityExample) 최상단 SSOT가 이 문서를 가리킴\n- [ ] `AssetManager\u002FAssetManager.cs`가 `Addressables.LoadAssetsAsync`를 사용\n- [ ] `AssetManager\u002FAssetManager.cs`가 `Addressables.Release(handle)`로 언로드\n- [ ] `LoadAsset\u003CT>`가 `GetAsset\u003CT>`의 alias로 존재\n- [ ] 파일 AssetBundle 로딩 코드(`AssetBundle.LoadFromFileAsync`) 없음\n\n### FAIL 조건\n\n- `AssetBundle.LoadFromFileAsync` 코드가 존재\n- `LoadBundle(key, bundleFilePath)` 형태의 API가 존재\n- SSOT 주석이 다른 문서를 가리킴\n\n---\n\n## Reference\n\n- Related: `skills\u002Fdevian\u002F10-module\u002F03-ssot\u002FSKILL.md` (Foundation Package SSOT)\n- Related: `skills\u002Fdevian-unity\u002F20-common-package\u002F19-bundle-manager\u002FSKILL.md` (다운로드 정책)\n- Related: `skills\u002Fdevian-unity\u002F01-policy\u002FSKILL.md` (component policy)\n",{},"main","8cb5bd877a3a7004867d2f55697cb9e4ff2f1734","skills\u002Fdevian-unity\u002F20-common-package\u002F13-asset-manager","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft","Kim Hyong Joon","2026-04-12 18:44:10",{"source":7,"skillName":5,"commands":31,"prompt":41,"zipAvailable":42},[32,35,38],{"tool":33,"command":34},"npx","npx skills add devwinsoft\u002Fdevian --skill 13-asset-manager",{"tool":36,"command":37},"bunx","bunx skills add devwinsoft\u002Fdevian --skill 13-asset-manager",{"tool":39,"command":40},"pnpm","pnpm dlx skills add devwinsoft\u002Fdevian --skill 13-asset-manager","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian-unity\u002F20-common-package\u002F13-asset-manager\u002FSKILL.md",true,[],[45,51,59,67,76,83],{"skillNo":46,"name":47,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":48,"categories":49,"keywords":50,"publishedAt":19},"01M6CBX3K2JJV38ANHVGCAT8A0","devian","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002FSKILL.md",[],[47],{"skillNo":52,"name":53,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":54,"categories":55,"keywords":56,"publishedAt":19},"01M6CBX210BFMM8AMN770J9WY8","90-project-archive","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F90-project-archive\u002FSKILL.md",[],[57,58],"archive","90 project archive",{"skillNo":60,"name":61,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":62,"categories":63,"keywords":64,"publishedAt":19},"01M6CBWZSGRR9R3YJZB3177667","30-env-management","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F30-env-management\u002FSKILL.md",[],[65,66],"management","30 env management",{"skillNo":68,"name":69,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":70,"categories":71,"keywords":72,"publishedAt":19},"01M6CBWYD3TGWBQV7V35551THF","19-page-push-send","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F19-page-push-send\u002FSKILL.md",[],[73,74,75],"push","page","19 page push send",{"skillNo":77,"name":78,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":79,"categories":80,"keywords":81,"publishedAt":19},"01M6CBWWRQ05A7604GHJKTPJTF","18-page-savedata","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F18-page-savedata\u002FSKILL.md",[],[74,82],"18 page savedata",{"skillNo":84,"name":85,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":88,"publishedAt":19},"01M6CBWVH4S2VF1V7B2GBTESCT","17-page-deobfuscate","https:\u002F\u002Fgithub.com\u002Fdevwinsoft\u002Fdevian\u002Fblob\u002Fmain\u002Fskills\u002Fdevian\u002F80-tools\u002F20-operation\u002F17-page-deobfuscate\u002FSKILL.md",[],[74,89],"17 page deobfuscate"]