binary-collections 2.0.9 → 2.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/.puppeterrc.cjs +25 -0
  2. package/binaries/binary-executor.cjs +178 -0
  3. package/{bin → binaries}/clean-nodemodule +0 -0
  4. package/binaries/clean-nodemodule.cjs +178 -0
  5. package/binaries/clean-nodemodule.cmd +4 -0
  6. package/{bin → binaries}/clean-nodemodules +0 -0
  7. package/binaries/clean-nodemodules.cjs +178 -0
  8. package/binaries/clean-nodemodules.cmd +5 -0
  9. package/{bin → binaries}/dev +0 -0
  10. package/binaries/dev.cjs +178 -0
  11. package/{bin → binaries}/empty +0 -0
  12. package/binaries/empty.cjs +178 -0
  13. package/{bin → binaries}/git-reduce-size +0 -0
  14. package/binaries/git-reduce-size.cjs +178 -0
  15. package/binaries/javakill.cjs +178 -0
  16. package/{bin → binaries}/javakill.cmd +0 -0
  17. package/binaries/kill-night-crows.bat +7 -0
  18. package/binaries/kill-night-crows.ps1 +172 -0
  19. package/{bin → binaries}/kill-process +0 -0
  20. package/binaries/kill-process.cjs +178 -0
  21. package/binaries/nodekill.cjs +178 -0
  22. package/{bin → binaries}/nodekill.ps1 +0 -0
  23. package/{bin → binaries}/prod +0 -0
  24. package/binaries/prod.cjs +178 -0
  25. package/binaries/py +111 -0
  26. package/binaries/py.cjs +178 -0
  27. package/binaries/py.cmd +49 -0
  28. package/{bin → binaries}/rmfind +0 -0
  29. package/binaries/rmfind.cjs +178 -0
  30. package/{bin → binaries}/rmx +0 -0
  31. package/binaries/rmx.cjs +178 -0
  32. package/{bin → binaries}/submodule-token +0 -0
  33. package/binaries/submodule-token.cjs +178 -0
  34. package/binaries/test-cjs +10 -0
  35. package/binaries/test-cjs.cjs +178 -0
  36. package/binaries/test-cjs.cmd +11 -0
  37. package/binaries/yarn-clean +32 -0
  38. package/binaries/yarn-clean.cjs +178 -0
  39. package/binaries/yarn-clean.cmd +30 -0
  40. package/binaries/yarn-clean.py +148 -0
  41. package/docs-src/clean-github-actions-caches.md +26 -0
  42. package/docs-src/free-chatgpt.md +26 -0
  43. package/lib/binary-collections-config.cjs +3 -2
  44. package/lib/binary-collections-config.mjs +2 -2
  45. package/lib/binary-collections.cjs +513 -105
  46. package/lib/binary-collections.mjs +178 -117
  47. package/lib/changelog.cjs +64 -16
  48. package/lib/changelog.mjs +177 -171
  49. package/lib/{chunk-VVEZVNIV.mjs → chunk-2CBJCW7E.mjs} +3 -3
  50. package/lib/chunk-34IQDTLZ.mjs +27 -0
  51. package/lib/chunk-3HFFECCI.mjs +27 -0
  52. package/lib/chunk-4UHL4WVN.mjs +136 -0
  53. package/lib/{chunk-4BYBVEYC.mjs → chunk-66PAU5PS.mjs} +5 -4
  54. package/lib/chunk-6HHJRKFB.mjs +59 -0
  55. package/lib/chunk-6S4NXESK.mjs +26 -0
  56. package/lib/chunk-7XTEJHOE.mjs +193 -0
  57. package/lib/{chunk-ZYAQRPUL.mjs → chunk-7YD7IPFF.mjs} +2 -2
  58. package/lib/{chunk-SH3L6HHV.mjs → chunk-A2JQXI5Z.mjs} +2 -2
  59. package/lib/{chunk-EGSSKVDH.mjs → chunk-A3VUZEJK.mjs} +1 -1
  60. package/lib/chunk-AJDD5DZM.mjs +109 -0
  61. package/lib/chunk-BZWVHODJ.mjs +62 -0
  62. package/lib/chunk-FCDQGYBF.mjs +136 -0
  63. package/lib/chunk-FKI7IEB5.mjs +172 -0
  64. package/lib/chunk-GEYA2USY.mjs +207 -0
  65. package/lib/chunk-GJTGHXRA.mjs +356 -0
  66. package/lib/{chunk-YV7DO3YV.mjs → chunk-HLGOWBEO.mjs} +1 -1
  67. package/lib/chunk-ID2WBTE2.mjs +80 -0
  68. package/lib/chunk-JXFOHKDM.mjs +239 -0
  69. package/lib/{chunk-YX5U7XDR.mjs → chunk-M3YIYRHT.mjs} +6 -5
  70. package/lib/chunk-N436BNBK.mjs +514 -0
  71. package/lib/chunk-NCXAP7AA.mjs +31 -0
  72. package/lib/chunk-PDN26I7O.mjs +188 -0
  73. package/lib/{chunk-JGR2NW6D.mjs → chunk-PDSXF5HY.mjs} +3 -3
  74. package/lib/{chunk-AASHBCRW.mjs → chunk-QQ4A6DLD.mjs} +8 -0
  75. package/lib/{chunk-ONIBBBQ3.mjs → chunk-RWLXRTYP.mjs} +4 -3
  76. package/lib/chunk-TOIVAQF7.mjs +136 -0
  77. package/lib/chunk-V5SKYJUB.mjs +136 -0
  78. package/lib/chunk-WSRETQCA.mjs +59 -0
  79. package/lib/chunk-XA3SNBPA.mjs +184 -0
  80. package/lib/chunk-XVBFFVCJ.mjs +209 -0
  81. package/lib/chunk-YYLIQQKF.mjs +31 -0
  82. package/lib/{chunk-APBWENF6.mjs → chunk-Z6JLYU2J.mjs} +63 -16
  83. package/lib/chunk-ZDMWBSYF.mjs +81 -0
  84. package/lib/clean-github-actions-caches.cjs +291 -148
  85. package/lib/clean-github-actions-caches.mjs +4 -3
  86. package/lib/del-gradle.cjs +63 -15
  87. package/lib/del-gradle.js +2 -1
  88. package/lib/del-gradle.mjs +2 -2
  89. package/lib/del-node-modules.cjs +143 -148
  90. package/lib/del-node-modules.js +210 -14
  91. package/lib/del-node-modules.mjs +149 -18
  92. package/lib/del-ps.cjs +90 -21
  93. package/lib/del-ps.js +3 -2
  94. package/lib/del-ps.mjs +7 -5
  95. package/lib/del-yarn-caches.cjs +87 -18
  96. package/lib/del-yarn-caches.js +38 -3
  97. package/lib/del-yarn-caches.mjs +6 -6
  98. package/lib/find-node-modules-cli.cjs +5 -4
  99. package/lib/find-node-modules-cli.js +2 -1
  100. package/lib/find-node-modules-cli.mjs +2 -2
  101. package/lib/find-node-modules.cjs +4 -3
  102. package/lib/{find-node-modules.d.ts → find-node-modules.d.cts} +1 -1
  103. package/lib/find-node-modules.mjs +2 -2
  104. package/lib/free-chatgpt.cjs +754 -0
  105. package/lib/free-chatgpt.js +51 -0
  106. package/lib/free-chatgpt.mjs +50 -0
  107. package/lib/git/gitattributes.cjs +2 -1
  108. package/lib/git/{gitattributes.d.ts → gitattributes.d.cts} +7 -2
  109. package/lib/git/gitattributes.mjs +2 -2
  110. package/lib/git/line-endings.cjs +298 -64
  111. package/lib/git/line-endings.mjs +4 -4
  112. package/lib/git/normalize.cjs +26 -36
  113. package/lib/git/normalize.mjs +2 -2
  114. package/lib/git/permissions.cjs +77 -11
  115. package/lib/git/permissions.mjs +3 -3
  116. package/lib/git/pull-strategy.cjs +76 -9
  117. package/lib/git/pull-strategy.mjs +3 -3
  118. package/lib/git/undo-commit-cli.cjs +110 -0
  119. package/lib/git/undo-commit-cli.d.ts +1 -0
  120. package/lib/git/undo-commit-cli.js +4 -0
  121. package/lib/git/undo-commit-cli.mjs +14 -0
  122. package/lib/git/undo-commit.cjs +81 -0
  123. package/lib/git/undo-commit.d.cts +1 -0
  124. package/lib/git/undo-commit.mjs +7 -0
  125. package/lib/git/undo-staged-cli.cjs +110 -0
  126. package/lib/git/undo-staged-cli.d.ts +1 -0
  127. package/lib/git/undo-staged-cli.js +4 -0
  128. package/lib/git/undo-staged-cli.mjs +14 -0
  129. package/lib/git/undo-staged.cjs +81 -0
  130. package/lib/git/undo-staged.d.cts +1 -0
  131. package/lib/git/undo-staged.mjs +7 -0
  132. package/lib/git/user-config.cjs +313 -83
  133. package/lib/git/user-config.mjs +4 -4
  134. package/lib/git/utils.cjs +40 -60
  135. package/lib/git/utils.mjs +2 -2
  136. package/lib/git-diff-cli.cjs +857 -0
  137. package/lib/git-diff-cli.js +16 -0
  138. package/lib/git-diff-cli.mjs +17 -0
  139. package/lib/git-diff.cjs +862 -58
  140. package/lib/git-diff.d.ts +38 -83
  141. package/lib/git-diff.js +152 -0
  142. package/lib/git-diff.mjs +23 -85
  143. package/lib/git-fix.cjs +733 -97
  144. package/lib/git-fix.mjs +10 -9
  145. package/lib/git-purge.cjs +64 -16
  146. package/lib/git-purge.d.cts +1 -0
  147. package/lib/git-purge.mjs +43 -37
  148. package/lib/index.cjs +7 -6
  149. package/lib/index.d.ts +1 -1
  150. package/lib/index.js +2 -5
  151. package/lib/index.mjs +4 -4
  152. package/lib/kill-night-crows.cjs +87 -0
  153. package/lib/kill-night-crows.d.mts +1 -0
  154. package/lib/kill-night-crows.mjs +65 -0
  155. package/lib/npm-run-series.cjs +63 -16
  156. package/lib/npm-run-series.mjs +42 -36
  157. package/lib/package-resolutions-updater-cli.cjs +560 -0
  158. package/lib/package-resolutions-updater-cli.d.mts +1 -0
  159. package/lib/package-resolutions-updater-cli.mjs +124 -0
  160. package/lib/package-resolutions-updater.cjs +178 -158
  161. package/lib/package-resolutions-updater.d.mts +32 -1
  162. package/lib/package-resolutions-updater.mjs +17 -338
  163. package/lib/php-cs-fixer-staged.cjs +105 -0
  164. package/lib/php-cs-fixer-staged.d.cts +2 -0
  165. package/lib/php-cs-fixer-staged.mjs +117 -0
  166. package/lib/print-directory-tree.cjs +320 -207
  167. package/lib/print-directory-tree.mjs +3 -3
  168. package/lib/ps/connected-domain.cjs +25 -2
  169. package/lib/ps/connected-domain.d.ts +10 -2
  170. package/lib/ps/connected-domain.js +5 -2
  171. package/lib/ps/connected-domain.mjs +8 -4
  172. package/lib/ps/index.cjs +345 -322
  173. package/lib/ps/index.d.mjs +1 -1
  174. package/lib/ps/index.js +2 -1
  175. package/lib/ps/index.mjs +179 -182
  176. package/lib/ps/isWin.cjs +24 -1
  177. package/lib/ps/isWin.d.ts +1 -1
  178. package/lib/ps/isWin.js +3 -1
  179. package/lib/ps/isWin.mjs +8 -4
  180. package/lib/ps/table-parser.cjs +167 -159
  181. package/lib/ps/table-parser.d.ts +5 -0
  182. package/lib/ps/table-parser.js +10 -4
  183. package/lib/ps/table-parser.mjs +9 -5
  184. package/lib/remove-module.cjs +310 -0
  185. package/lib/remove-module.d.mts +1 -0
  186. package/lib/remove-module.mjs +111 -0
  187. package/lib/rmpath.cjs +322 -0
  188. package/lib/rmpath.d.mts +3 -0
  189. package/lib/rmpath.mjs +108 -0
  190. package/lib/submodule-install.cjs +311 -86
  191. package/lib/submodule-install.mjs +53 -5
  192. package/lib/submodule-remove-cli.cjs +107 -0
  193. package/lib/submodule-remove-cli.d.ts +1 -0
  194. package/lib/submodule-remove-cli.js +31 -0
  195. package/lib/submodule-remove-cli.mjs +28 -0
  196. package/lib/submodule-remove.cjs +46 -0
  197. package/lib/submodule-remove.d.cts +2 -0
  198. package/lib/submodule-remove.mjs +6 -0
  199. package/lib/utils/chatgpt.cjs +541 -0
  200. package/lib/utils/chatgpt.d.ts +31 -0
  201. package/lib/utils/chatgpt.js +708 -0
  202. package/lib/utils/chatgpt.mjs +8 -0
  203. package/lib/utils/findEnvFiles.cjs +107 -0
  204. package/lib/utils/findEnvFiles.d.ts +8 -0
  205. package/lib/utils/findEnvFiles.js +121 -0
  206. package/lib/utils/findEnvFiles.mjs +8 -0
  207. package/lib/utils/findWorkspaceRoot.cjs +70 -0
  208. package/lib/utils/findWorkspaceRoot.d.ts +9 -0
  209. package/lib/utils/findWorkspaceRoot.js +57 -0
  210. package/lib/utils/findWorkspaceRoot.mjs +40 -0
  211. package/lib/{utils.cjs → utils/index.cjs} +61 -14
  212. package/lib/{utils.mjs → utils/index.mjs} +2 -2
  213. package/lib/utils/isGithubTokenValid.cjs +64 -0
  214. package/lib/utils/isGithubTokenValid.d.ts +7 -0
  215. package/lib/utils/isGithubTokenValid.js +48 -0
  216. package/lib/utils/isGithubTokenValid.mjs +36 -0
  217. package/lib/yarn-reinstall.cjs +220 -38
  218. package/lib/yarn-reinstall.mjs +2 -2
  219. package/package.json +138 -104
  220. package/readme.md +48 -75
  221. package/releases/readme.md +36 -0
  222. package/requirements.txt +1 -0
  223. package/test/README.md +101 -0
  224. package/test/package.json +2 -1
  225. package/test-project/readme.md +26 -0
  226. package/tmp/test-repo/README.md +35 -0
  227. package/tmp/test-repo/package.json +1 -1
  228. package/tmp/typedoc/readme.md +320 -0
  229. package/bin/bash-dummy +0 -56
  230. package/bin/bash-dummy.cmd +0 -25
  231. package/bin/dir-tree.cmd +0 -7
  232. package/bin/git-diff +0 -4
  233. package/bin/git-diff.cmd +0 -7
  234. package/bin/git-fix +0 -36
  235. package/bin/git-fix.cmd +0 -7
  236. package/bin/rmpath +0 -70
  237. package/bin/submodule-install.txt +0 -118
  238. package/bin/submodule-remove +0 -46
  239. package/bin/submodule.txt +0 -172
  240. package/lib/binary-collections-config.d.mts +0 -18
  241. package/lib/binary-collections-config.js +0 -39
  242. package/lib/binary-collections.d.mts +0 -137
  243. package/lib/binary-collections.d.ts +0 -137
  244. package/lib/changelog.d.mts +0 -2
  245. package/lib/changelog.js +0 -226
  246. package/lib/chunk-DPKAJKFO.mjs +0 -171
  247. package/lib/chunk-G3THLIDT.mjs +0 -200
  248. package/lib/chunk-W3ENOM53.mjs +0 -18
  249. package/lib/clean-github-actions-caches.d.mts +0 -169
  250. package/lib/clean-github-actions-caches.d.ts +0 -169
  251. package/lib/del-gradle.d.mts +0 -2
  252. package/lib/del-node-modules.d.mts +0 -2
  253. package/lib/del-ps.d.mts +0 -2
  254. package/lib/del-yarn-caches.d.mts +0 -2
  255. package/lib/find-node-modules-cli.d.mts +0 -1
  256. package/lib/find-node-modules.d.mts +0 -13
  257. package/lib/find-node-modules.js +0 -53
  258. package/lib/git/gitattributes.d.mts +0 -35
  259. package/lib/git/gitattributes.js +0 -223
  260. package/lib/git/line-endings.d.mts +0 -83
  261. package/lib/git/line-endings.d.ts +0 -83
  262. package/lib/git/normalize.d.mts +0 -43
  263. package/lib/git/normalize.d.ts +0 -43
  264. package/lib/git/permissions.d.mts +0 -17
  265. package/lib/git/permissions.d.ts +0 -17
  266. package/lib/git/pull-strategy.d.mts +0 -15
  267. package/lib/git/pull-strategy.d.ts +0 -15
  268. package/lib/git/user-config.d.mts +0 -105
  269. package/lib/git/user-config.d.ts +0 -105
  270. package/lib/git/utils.d.mts +0 -69
  271. package/lib/git/utils.d.ts +0 -69
  272. package/lib/git-diff.d.mts +0 -84
  273. package/lib/git-fix.d.mts +0 -141
  274. package/lib/git-fix.d.ts +0 -141
  275. package/lib/git-purge.d.mts +0 -2
  276. package/lib/git-purge.js +0 -59
  277. package/lib/index.d.mts +0 -1
  278. package/lib/npm-run-series.d.mts +0 -1
  279. package/lib/npm-run-series.js +0 -86
  280. package/lib/package-resolutions-updater.d.ts +0 -352
  281. package/lib/print-directory-tree.d.mts +0 -234
  282. package/lib/print-directory-tree.d.ts +0 -234
  283. package/lib/ps/connected-domain.d.mts +0 -3
  284. package/lib/ps/index.d.d.mts +0 -26
  285. package/lib/ps/index.d.d.ts +0 -26
  286. package/lib/ps/index.d.mts +0 -26
  287. package/lib/ps/isWin.d.mts +0 -3
  288. package/lib/ps/table-parser.d.mts +0 -3
  289. package/lib/submodule-install.d.mts +0 -121
  290. package/lib/submodule-install.d.ts +0 -121
  291. package/lib/utils.d.mts +0 -40
  292. package/lib/utils.js +0 -181
  293. package/lib/yarn-reinstall.d.mts +0 -49
  294. package/lib/yarn-reinstall.d.ts +0 -49
  295. package/src/package-resolutions-updater.mjs +0 -350
  296. package/src/print-directory-tree.cjs +0 -234
  297. package/src/ps/index.js +0 -286
  298. package/src/yarn-reinstall.cjs +0 -49
  299. /package/{bin → binaries}/nodekill +0 -0
  300. /package/{bin → binaries}/nodekill.cmd +0 -0
  301. /package/lib/{binary-collections-config.d.ts → binary-collections-config.d.cts} +0 -0
  302. /package/lib/{changelog.d.ts → changelog.d.cts} +0 -0
  303. /package/lib/{git-purge.d.ts → free-chatgpt.d.ts} +0 -0
  304. /package/lib/{git-diff.d.cts → git-diff-cli.d.ts} +0 -0
  305. /package/lib/{npm-run-series.d.ts → npm-run-series.d.cts} +0 -0
  306. /package/lib/{utils.d.ts → utils/index.d.cts} +0 -0
@@ -0,0 +1,356 @@
1
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ init_esm_shims
4
+ } from "./chunk-QQ4A6DLD.mjs";
5
+
6
+ // src/utils/chatgpt.js
7
+ init_esm_shims();
8
+ import fs from "fs-extra";
9
+ import puppeteer from "puppeteer-extra";
10
+ import StealthPlugin from "puppeteer-extra-plugin-stealth";
11
+ import path from "upath";
12
+ var COOKIE_DIR = path.join(process.cwd(), "tmp", "cookies");
13
+ var DEFAULT_COOKIE_PATH = path.join(COOKIE_DIR, "cookies.json");
14
+ fs.ensureDirSync(COOKIE_DIR);
15
+ async function saveCookies(page, path2 = DEFAULT_COOKIE_PATH) {
16
+ const cookies = await page.cookies();
17
+ fs.writeFileSync(path2, JSON.stringify(cookies, null, 2));
18
+ }
19
+ function getCookiePathForUrl(url) {
20
+ try {
21
+ const { hostname } = new URL(url);
22
+ return path.join(COOKIE_DIR, `cookies_${hostname}.json`);
23
+ } catch {
24
+ return DEFAULT_COOKIE_PATH;
25
+ }
26
+ }
27
+ async function navigatePage(page, url) {
28
+ const cookiePath = getCookiePathForUrl(url);
29
+ const cookies = loadCookies(cookiePath);
30
+ if (cookies) {
31
+ await page.setCookie(...cookies);
32
+ }
33
+ await page.goto(url, { waitUntil: "networkidle0" });
34
+ await page.evaluate(() => {
35
+ window.__domStillUpdating = true;
36
+ if (window.__domObserver) {
37
+ window.__domObserver.disconnect();
38
+ }
39
+ window.__domObserver = new MutationObserver(() => {
40
+ window.__lastDomMutation = Date.now();
41
+ });
42
+ window.__lastDomMutation = Date.now();
43
+ window.__domObserver.observe(document.body, {
44
+ childList: true,
45
+ subtree: true,
46
+ attributes: true,
47
+ characterData: true
48
+ });
49
+ setTimeout(() => {
50
+ window.__domStillUpdating = false;
51
+ window.__domObserver.disconnect();
52
+ }, 3e4);
53
+ });
54
+ const waitForDomIdle = async (idleMs = 1e3, timeout = 1e4) => {
55
+ const start = Date.now();
56
+ while (Date.now() - start < timeout) {
57
+ const lastMutation = await page.evaluate(() => window.__lastDomMutation);
58
+ const idle = Date.now() - lastMutation;
59
+ if (idle >= idleMs) {
60
+ return true;
61
+ }
62
+ await new Promise((r) => setTimeout(r, 200));
63
+ }
64
+ throw new Error("DOM did not stabilize within timeout");
65
+ };
66
+ return { waitForDomIdle };
67
+ }
68
+ function loadCookies(cookieFilePath = DEFAULT_COOKIE_PATH) {
69
+ if (!fs.existsSync(cookieFilePath)) return null;
70
+ return JSON.parse(fs.readFileSync(cookieFilePath));
71
+ }
72
+ async function writeQuestion(page, question) {
73
+ const questions = question.split("\n");
74
+ const promptTextarea = await page.waitForSelector("#prompt-textarea", { timeout: 3e4 });
75
+ if (!promptTextarea) {
76
+ console.log(
77
+ "Cannot find the prompt input on the webpage. Please check whether you have access to chat.openai.com without logging in via your browser."
78
+ );
79
+ }
80
+ await page.evaluate(() => {
81
+ document.querySelector("#prompt-textarea").innerHTML = `<p></p>`;
82
+ });
83
+ if (questions.length === 1) {
84
+ await page.type("#prompt-textarea", questions[0], { delay: 100 });
85
+ return;
86
+ }
87
+ for (const q of questions) {
88
+ await page.type("#prompt-textarea", q, { delay: 100 });
89
+ if (q !== questions[questions.length - 1]) {
90
+ await page.keyboard.down("Shift");
91
+ await page.keyboard.press("Enter");
92
+ await page.keyboard.up("Shift");
93
+ }
94
+ }
95
+ }
96
+ async function clickSubmitButton(page) {
97
+ try {
98
+ const fruitjuiceSendButton = await page.evaluate(() => {
99
+ return document.querySelector('[data-testid="fruitjuice-send-button"]') !== null;
100
+ });
101
+ const sendButton = await page.evaluate(() => {
102
+ return document.querySelector('[data-testid="send-button"]') !== null;
103
+ });
104
+ if (fruitjuiceSendButton) {
105
+ await page.click('[data-testid="fruitjuice-send-button"]');
106
+ } else if (sendButton) {
107
+ await page.click('[data-testid="send-button"]');
108
+ } else {
109
+ console.log("Neither send button is present");
110
+ }
111
+ } catch (e) {
112
+ console.log(`Failed to click the send button: ${e}`);
113
+ }
114
+ }
115
+ var lastMessageId = null;
116
+ var messageCount = 0;
117
+ var is_streaming = false;
118
+ function sleep(ms) {
119
+ return new Promise((resolve) => setTimeout(resolve, ms));
120
+ }
121
+ async function waitForInitialResponse(page, timeout = 3e4) {
122
+ const startTime = Date.now();
123
+ while (Date.now() - startTime < timeout) {
124
+ const assistantMessages = await page.$$('[data-message-author-role="assistant"]');
125
+ const currentMessageCount = assistantMessages.length;
126
+ if (currentMessageCount > messageCount) {
127
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
128
+ const isThinking = await lastMessage.$(".result-thinking");
129
+ if (!isThinking) {
130
+ lastMessageId = await page.evaluate((element) => element.getAttribute("data-message-id"), lastMessage);
131
+ messageCount = currentMessageCount;
132
+ return;
133
+ }
134
+ }
135
+ await sleep(100);
136
+ }
137
+ console.log("Timed out waiting for the initial response.");
138
+ }
139
+ async function handleStreamingResponse(page, outputFile = path.join(process.cwd(), "tmp/response.txt")) {
140
+ let previousText = "";
141
+ let completeResponse = "";
142
+ let newContentDetected = false;
143
+ while (!newContentDetected) {
144
+ const assistantMessages = await page.$$('[data-message-author-role="assistant"]');
145
+ if (assistantMessages.length > 0) {
146
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
147
+ const currentMessageId = await page.evaluate((element) => element.getAttribute("data-message-id"), lastMessage);
148
+ if (currentMessageId === lastMessageId) {
149
+ const currentText = await page.evaluate((element) => element.textContent, lastMessage);
150
+ console.log(`Current text: ${currentText}`);
151
+ if (currentText !== previousText) {
152
+ if (is_streaming) {
153
+ process.stdout.write(currentText.slice(previousText.length));
154
+ } else {
155
+ completeResponse += currentText.slice(previousText.length);
156
+ }
157
+ }
158
+ previousText = currentText;
159
+ const isStreaming = await lastMessage.$(".result-streaming");
160
+ if (!isStreaming) {
161
+ newContentDetected = true;
162
+ }
163
+ } else {
164
+ lastMessageId = currentMessageId;
165
+ }
166
+ }
167
+ await sleep(100);
168
+ }
169
+ if (!is_streaming) {
170
+ console.log(completeResponse.trim());
171
+ console.log("\n\n");
172
+ fs.ensureDirSync(path.dirname(outputFile));
173
+ fs.writeFileSync(outputFile, completeResponse.trim());
174
+ console.log(`Response saved to ${outputFile}`);
175
+ }
176
+ }
177
+ async function isLoggedIn(page) {
178
+ const result = await page.evaluate(() => {
179
+ const loginButton = document.querySelector('[data-testid="login-button"]');
180
+ return !(loginButton && loginButton.offsetParent !== null);
181
+ });
182
+ return result === true;
183
+ }
184
+ async function createBrowser(browserOptions = {}) {
185
+ const defaultOptions = {
186
+ headless: false,
187
+ userDataDir: path.join(process.cwd(), "tmp/puppeteer-profile"),
188
+ // Windows-specific options to handle browser launch issues
189
+ args: [
190
+ "--no-sandbox",
191
+ "--disable-setuid-sandbox",
192
+ "--disable-dev-shm-usage",
193
+ "--disable-accelerated-2d-canvas",
194
+ "--no-first-run",
195
+ "--no-zygote",
196
+ "--disable-gpu",
197
+ "--disable-background-timer-throttling",
198
+ "--disable-backgrounding-occluded-windows",
199
+ "--disable-renderer-backgrounding"
200
+ ],
201
+ ignoreDefaultArgs: ["--disable-extensions"],
202
+ ...process.platform === "win32" && {
203
+ // Additional Windows-specific options
204
+ executablePath: void 0
205
+ // Let Puppeteer find Chrome automatically
206
+ }
207
+ };
208
+ try {
209
+ return await puppeteer.use(StealthPlugin()).launch({ ...defaultOptions, ...browserOptions });
210
+ } catch (_error) {
211
+ console.error("Failed to launch browser with default options. Trying fallback options...");
212
+ try {
213
+ return await puppeteer.use(StealthPlugin()).launch({
214
+ headless: browserOptions.headless || false,
215
+ args: ["--no-sandbox", "--disable-setuid-sandbox"],
216
+ ignoreDefaultArgs: false,
217
+ ...browserOptions
218
+ });
219
+ } catch (fallbackError) {
220
+ console.error("Browser launch failed completely. Common solutions:");
221
+ console.error("1. Install Google Chrome if not installed");
222
+ console.error("2. Update Node.js to the latest version");
223
+ console.error("3. Try running: npm install puppeteer --force");
224
+ console.error("4. Check if antivirus is blocking browser launch");
225
+ throw new Error(`Browser launch failed: ${fallbackError.message}`);
226
+ }
227
+ }
228
+ }
229
+ async function loginToChatGpt() {
230
+ const browser = await createBrowser({ headless: false });
231
+ const page = (await browser.pages()).length > 0 ? (await browser.pages())[0] : await browser.newPage();
232
+ const url = "https://chat.openai.com";
233
+ const navigate = await navigatePage(page, url);
234
+ await navigate.waitForDomIdle(2e3, 1e4);
235
+ const loginButtonExists = await page.evaluate(() => {
236
+ return document.querySelector('[data-testid="login-button"]') !== null;
237
+ });
238
+ if (loginButtonExists) {
239
+ console.log("Login button found, clicking to log in...");
240
+ await page.click('[data-testid="login-button"]');
241
+ await page.waitForNavigation({ waitUntil: "networkidle0" });
242
+ console.log("Login process completed.");
243
+ } else {
244
+ console.log("No login required - user appears to be already logged in.");
245
+ }
246
+ }
247
+ async function runChatGpt(chatgptOptions = {}) {
248
+ const headless = chatgptOptions.headless !== void 0 ? chatgptOptions.headless : true;
249
+ const questionFile = chatgptOptions.questionFile;
250
+ let question = chatgptOptions.question;
251
+ const responseFile = chatgptOptions.responseFile || path.join(process.cwd(), "tmp", "response.txt");
252
+ const noInputProvided = !question && !questionFile;
253
+ const questionIsEmpty = question && question.trim().length === 0;
254
+ const questionFileIsEmpty = questionFile && questionFile.trim().length === 0;
255
+ if (noInputProvided || questionIsEmpty || questionFileIsEmpty) {
256
+ throw new Error("You must provide a question or a question file.");
257
+ }
258
+ let browser;
259
+ try {
260
+ browser = await createBrowser({ headless });
261
+ } catch (error) {
262
+ console.error("Error running ChatGPT:", error);
263
+ console.error("\nTroubleshooting steps:");
264
+ console.error("1. Make sure Google Chrome is installed");
265
+ console.error("2. Try running: yarn add puppeteer --force");
266
+ console.error("3. Check if your antivirus is blocking the browser");
267
+ console.error("4. Close any running Chrome instances and try again");
268
+ throw error;
269
+ }
270
+ const page = (await browser.pages()).length > 0 ? (await browser.pages())[0] : await browser.newPage();
271
+ try {
272
+ const url = "https://chat.openai.com";
273
+ const navigate = await navigatePage(page, url);
274
+ await navigate.waitForDomIdle(2e3, 15e3);
275
+ try {
276
+ const tempChatButton = await page.$('button[aria-label="Turn on temporary chat"]');
277
+ if (tempChatButton) {
278
+ await page.evaluate((el) => el.click(), tempChatButton);
279
+ console.log("Successfully clicked temporary chat button");
280
+ await navigate.waitForDomIdle(1e3, 1e4);
281
+ } else {
282
+ console.log("Temporary chat button not found, proceeding without it.");
283
+ }
284
+ } catch (error) {
285
+ console.log(`Failed to click temporary chat button: ${error.message}`);
286
+ }
287
+ if (question) {
288
+ await writeQuestion(page, question);
289
+ await clickSubmitButton(page);
290
+ await navigate.waitForDomIdle(1e3, 3e4);
291
+ await waitForInitialResponse(page);
292
+ await handleStreamingResponse(page, responseFile);
293
+ await saveCookies(page, getCookiePathForUrl(url));
294
+ } else if (questionFile) {
295
+ await navigate.waitForDomIdle(2e3, 1e4);
296
+ const isUserLoggedIn = await isLoggedIn(page);
297
+ console.log(`Login status: ${isUserLoggedIn ? "Logged in" : "Not logged in"}`);
298
+ if (!isUserLoggedIn) {
299
+ console.log(
300
+ "Not logged in. Please log in to ChatGPT in the browser window, then close it and run the command again."
301
+ );
302
+ return loginToChatGpt();
303
+ }
304
+ const plusButtonExists = await page.evaluate(() => {
305
+ const button = document.querySelector('[data-testid="composer-plus-btn"]');
306
+ return button !== null;
307
+ });
308
+ if (plusButtonExists) {
309
+ await page.click('[data-testid="composer-plus-btn"]');
310
+ await sleep(500);
311
+ const menuItems = await page.$$('[role="menuitem"]');
312
+ let clicked = false;
313
+ for (const item of menuItems) {
314
+ const text = await page.evaluate((el) => el.innerText, item);
315
+ if (text && text.includes("Add photos") && text.includes("files")) {
316
+ await item.hover();
317
+ clicked = true;
318
+ break;
319
+ }
320
+ }
321
+ if (!clicked) {
322
+ console.log('Could not find the "Add photos & files" menu item.');
323
+ return;
324
+ }
325
+ try {
326
+ await sleep(1e3);
327
+ const fileInput = await page.waitForSelector('input[type="file"]', { timeout: 1e4 });
328
+ if (fileInput) {
329
+ console.log(`Uploading file: ${questionFile}`);
330
+ await fileInput.uploadFile(questionFile);
331
+ await navigate.waitForDomIdle(2e3, 15e3);
332
+ console.log("File uploaded successfully");
333
+ await clickSubmitButton(page);
334
+ await navigate.waitForDomIdle(1e3, 3e4);
335
+ await waitForInitialResponse(page);
336
+ await handleStreamingResponse(page, responseFile);
337
+ } else {
338
+ console.log("Could not find file input element");
339
+ }
340
+ } catch (error) {
341
+ console.log(`Error uploading file: ${error.message}`);
342
+ }
343
+ } else {
344
+ console.log('Could not find the [data-testid="composer-plus-btn"] button.');
345
+ }
346
+ }
347
+ } finally {
348
+ if (browser) {
349
+ await browser.close();
350
+ }
351
+ }
352
+ }
353
+
354
+ export {
355
+ runChatGpt
356
+ };
@@ -3,7 +3,7 @@ import {
3
3
  __commonJS,
4
4
  __require,
5
5
  init_esm_shims
6
- } from "./chunk-AASHBCRW.mjs";
6
+ } from "./chunk-QQ4A6DLD.mjs";
7
7
 
8
8
  // src/git/normalize.cjs
9
9
  var require_normalize = __commonJS({
@@ -0,0 +1,80 @@
1
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ init_esm_shims
4
+ } from "./chunk-QQ4A6DLD.mjs";
5
+
6
+ // src/utils/findEnvFiles.js
7
+ init_esm_shims();
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import * as glob from "glob";
11
+ var DEFAULT_IGNORES = [
12
+ "**/node_modules/**",
13
+ "**/.git/**",
14
+ "**/.yarn/**",
15
+ "**/.pnpm/**",
16
+ "**/dist/**",
17
+ "**/build/**",
18
+ "**/coverage/**",
19
+ "**/vendor/**",
20
+ "**/tmp/**",
21
+ "**/.cache/**",
22
+ "**/assets/**",
23
+ "**/logs/**",
24
+ "**/output/**",
25
+ "**/public/**",
26
+ "**/static/**",
27
+ "**/temp/**",
28
+ "**/backup/**",
29
+ "**/backups/**",
30
+ "**/examples/**",
31
+ "**/docs/**",
32
+ "**/tests/**",
33
+ "**/__tests__/**",
34
+ "**/spec/**",
35
+ "**/__specs__/**",
36
+ "**/scripts/**",
37
+ "**/bin/**",
38
+ "**/hooks/**",
39
+ "**/config/**",
40
+ "**/configs/**",
41
+ "**/settings/**",
42
+ "**/.vscode/**",
43
+ "**/.idea/**"
44
+ ];
45
+ function findEnvFiles(startDir = process.cwd(), filter) {
46
+ const found = /* @__PURE__ */ new Set();
47
+ function addFile(file) {
48
+ const normalized = path.normalize(file);
49
+ if (typeof filter === "function" && !filter(normalized)) {
50
+ return;
51
+ }
52
+ found.add(normalized);
53
+ }
54
+ let current = path.resolve(startDir);
55
+ while (true) {
56
+ const envPath = path.join(current, ".env");
57
+ if (fs.existsSync(envPath)) {
58
+ addFile(envPath);
59
+ }
60
+ const parent = path.dirname(current);
61
+ if (parent === current) {
62
+ break;
63
+ }
64
+ current = parent;
65
+ }
66
+ const files = glob.globSync("**/.env*", {
67
+ cwd: startDir,
68
+ absolute: true,
69
+ nodir: true,
70
+ ignore: DEFAULT_IGNORES
71
+ });
72
+ for (const file of files) {
73
+ addFile(file);
74
+ }
75
+ return [...found];
76
+ }
77
+
78
+ export {
79
+ findEnvFiles
80
+ };
@@ -0,0 +1,239 @@
1
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ findEnvFiles
4
+ } from "./chunk-ID2WBTE2.mjs";
5
+ import {
6
+ require_utils
7
+ } from "./chunk-Z6JLYU2J.mjs";
8
+ import {
9
+ __toESM,
10
+ init_esm_shims
11
+ } from "./chunk-QQ4A6DLD.mjs";
12
+
13
+ // src/package-resolutions-updater.mjs
14
+ init_esm_shims();
15
+ var utils = __toESM(require_utils(), 1);
16
+ import * as dotenv from "dotenv";
17
+ import fs from "fs";
18
+ import https from "https";
19
+ import os from "os";
20
+ import path from "path";
21
+ var projectDir = process.cwd();
22
+ var envPath = path.join(projectDir, ".env");
23
+ var args = utils.getArgs();
24
+ if (!fs.existsSync(envPath)) {
25
+ const envFiles = findEnvFiles(projectDir, (file) => {
26
+ const content = fs.readFileSync(file, "utf-8");
27
+ return /GITHUB_TOKEN|ACCESS_TOKEN/.test(content);
28
+ });
29
+ if (envFiles.length > 0) {
30
+ envPath = envFiles[0];
31
+ }
32
+ }
33
+ if (fs.existsSync(envPath)) {
34
+ dotenv.config({ path: envPath, quiet: true, override: true });
35
+ }
36
+ var ACCESS_TOKEN = process.env.GITHUB_TOKEN || process.env.ACCESS_TOKEN;
37
+ if (args.help || args.h) {
38
+ showHelp();
39
+ }
40
+ function showHelp() {
41
+ const helpText = `
42
+ GitHub Package Resolutions Updater
43
+ Usage:
44
+ node src/package-resolutions-updater.mjs [options]
45
+ Options:
46
+ --help, -h Show this help message
47
+ Description:
48
+ Updates the commit hashes in package.json's 'resolutions' field for GitHub tarball URLs to point to the latest commit SHA of the corresponding repository and branch.
49
+ Features:
50
+ - Parses GitHub URLs to extract repository owner, name, and branch.
51
+ - Fetches the latest commit SHA across all branches using GitHub's API.
52
+ - Replaces the old branch or commit in the URL with the latest SHA.
53
+ - Overwrites package.json with the updated URLs.
54
+ Requirements:
55
+ - GitHub Personal Access Token (GITHUB_TOKEN) via .env
56
+ - ESM support (type: "module" in package.json)
57
+ - Node.js v18+ recommended
58
+ Dependencies:
59
+ - ansi-colors \u2013 for styled terminal output
60
+ - dotenv \u2013 to load GitHub token from .env
61
+ Examples:
62
+ node src/package-resolutions-updater.mjs
63
+ node src/package-resolutions-updater.mjs --help
64
+
65
+ `;
66
+ console.log(helpText);
67
+ process.exit(0);
68
+ }
69
+ var GITHUB_USER_AGENTS = [
70
+ "octokit-rest.js/19.0.7",
71
+ "GitHub CLI/2.40.0",
72
+ "Mozilla/5.0 (compatible; GitHubCopilot/1.0)",
73
+ "PostmanRuntime/7.32.3",
74
+ "binary-collections-resolver/1.0 (+https://github.com/dimaslanjaka/bin)"
75
+ ];
76
+ var userAgentDir = path.join(os.tmpdir(), "nodejs");
77
+ var userAgentFile = path.join(userAgentDir, "useragent.txt");
78
+ var selectedUserAgent;
79
+ try {
80
+ if (!fs.existsSync(userAgentDir)) fs.mkdirSync(userAgentDir, { recursive: true });
81
+ if (fs.existsSync(userAgentFile)) {
82
+ const fileAgent = fs.readFileSync(userAgentFile, "utf-8").trim();
83
+ if (GITHUB_USER_AGENTS.includes(fileAgent)) {
84
+ selectedUserAgent = fileAgent;
85
+ }
86
+ }
87
+ if (!selectedUserAgent) {
88
+ selectedUserAgent = GITHUB_USER_AGENTS[Math.floor(Math.random() * GITHUB_USER_AGENTS.length)];
89
+ fs.writeFileSync(userAgentFile, selectedUserAgent, "utf-8");
90
+ }
91
+ } catch (_e) {
92
+ selectedUserAgent = GITHUB_USER_AGENTS[Math.floor(Math.random() * GITHUB_USER_AGENTS.length)];
93
+ }
94
+ function fetchJson(url) {
95
+ const headers = {
96
+ "User-Agent": selectedUserAgent,
97
+ Accept: "application/vnd.github.v3+json",
98
+ "X-GitHub-Api-Version": "2022-11-28",
99
+ ...ACCESS_TOKEN ? { Authorization: `token ${ACCESS_TOKEN}` } : {}
100
+ };
101
+ return new Promise((resolve, reject) => {
102
+ https.get(url, { headers }, (res) => {
103
+ let data = "";
104
+ res.on("data", (chunk) => data += chunk);
105
+ res.on("end", () => {
106
+ try {
107
+ const json = JSON.parse(data);
108
+ if (res.statusCode < 200 || res.statusCode >= 300) {
109
+ return reject(
110
+ new Error(`GitHub API Error ${res.statusCode}: ${json.message || "Unknown error"}
111
+ URL: ${url}`)
112
+ );
113
+ }
114
+ resolve(json);
115
+ } catch {
116
+ reject(new Error(`Invalid JSON from: ${url}`));
117
+ }
118
+ });
119
+ }).on("error", reject);
120
+ });
121
+ }
122
+ async function getLatestCommit(owner, repo, branch = "main") {
123
+ var _a, _b, _c, _d;
124
+ const url = `https://api.github.com/repos/${owner}/${repo}/commits/${branch}`;
125
+ const json = await fetchJson(url);
126
+ const sha = json.sha;
127
+ const dateStr = ((_b = (_a = json.commit) == null ? void 0 : _a.committer) == null ? void 0 : _b.date) || ((_d = (_c = json.commit) == null ? void 0 : _c.author) == null ? void 0 : _d.date);
128
+ if (!sha || !dateStr) {
129
+ console.log(json);
130
+ throw new Error(`Missing SHA or date for ${owner}/${repo}@${branch}`);
131
+ }
132
+ return {
133
+ owner,
134
+ repo,
135
+ branch,
136
+ sha,
137
+ date: new Date(dateStr).toISOString()
138
+ };
139
+ }
140
+ async function getLatestCommitAcrossBranches(owner, repo) {
141
+ const branches = await fetchJson(`https://api.github.com/repos/${owner}/${repo}/branches`);
142
+ const commits = await Promise.all(
143
+ branches.map(async ({ name, commit }) => {
144
+ var _a, _b, _c, _d;
145
+ const commitSha = commit == null ? void 0 : commit.sha;
146
+ if (!commitSha) {
147
+ console.warn(`No commit SHA for '${owner}/${repo}' branch: ${name}`);
148
+ return { branch: name, sha: "", date: /* @__PURE__ */ new Date(0) };
149
+ }
150
+ try {
151
+ const commitData = await fetchJson(`https://api.github.com/repos/${owner}/${repo}/commits/${commitSha}`);
152
+ const dateStr = ((_b = (_a = commitData.commit) == null ? void 0 : _a.committer) == null ? void 0 : _b.date) || ((_d = (_c = commitData.commit) == null ? void 0 : _c.author) == null ? void 0 : _d.date);
153
+ const date = dateStr ? new Date(dateStr) : /* @__PURE__ */ new Date(0);
154
+ return { branch: name, sha: commitData.sha, date };
155
+ } catch (e) {
156
+ console.warn(`Failed to fetch commit for ${name}: ${e.message}`);
157
+ return { branch: name, sha: commitSha, date: /* @__PURE__ */ new Date(0) };
158
+ }
159
+ })
160
+ );
161
+ const latest = commits.reduce((a, b) => a.date > b.date ? a : b, { date: /* @__PURE__ */ new Date(0) });
162
+ return {
163
+ owner,
164
+ repo,
165
+ branch: latest.branch,
166
+ sha: latest.sha,
167
+ date: latest.date.toISOString()
168
+ };
169
+ }
170
+ function replaceRawWithLatestHash(url, latestHash) {
171
+ const match = url.match(/^https:\/\/github\.com\/([^/]+)\/([^/]+)\/raw\/([^/]+)\/(.+)$/);
172
+ if (!match) throw new Error("Invalid GitHub raw URL");
173
+ const [, owner, repo, _oldHash, path2] = match;
174
+ return `https://github.com/${owner}/${repo}/raw/${latestHash}/${path2}`;
175
+ }
176
+ function splitGitHubRefPath(refPath) {
177
+ const segments = refPath.split("/").filter(Boolean);
178
+ if (segments.length === 0) {
179
+ return { branch: "", remainder: null };
180
+ }
181
+ if (segments[0] === "refs" && segments[1] === "heads" && segments.length >= 3) {
182
+ return {
183
+ branch: segments[2],
184
+ remainder: segments.slice(3).join("/") || null
185
+ };
186
+ }
187
+ let branchSegmentCount = 1;
188
+ if (segments[0] === "refs") {
189
+ if ((segments[1] === "tags" || segments[1] === "remotes" || segments[1] === "pull") && segments.length >= 3) {
190
+ branchSegmentCount = segments[1] === "tags" ? 3 : 4;
191
+ }
192
+ }
193
+ const branch = segments.slice(0, branchSegmentCount).join("/");
194
+ const remainder = segments.slice(branchSegmentCount).join("/");
195
+ return {
196
+ branch,
197
+ remainder: remainder || null
198
+ };
199
+ }
200
+ function parseGitHubUrl(url) {
201
+ const ghRepoRoot = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/?$/;
202
+ const ghTreeOrBlob = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/(tree|blob)\/([^/]+(?:\/[^/]+)*)/;
203
+ const ghRaw = /^https:\/\/raw\.githubusercontent\.com\/([^/]+)\/([^/]+)\/(.+)$/;
204
+ const ghDotComRaw = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/raw\/(.+)$/;
205
+ let match;
206
+ if (match = url.match(ghRaw)) {
207
+ const [, owner, repo, rawPath] = match;
208
+ const { branch, remainder } = splitGitHubRefPath(rawPath);
209
+ return {
210
+ owner,
211
+ repo,
212
+ branch,
213
+ url: `https://raw.githubusercontent.com/${owner}/${repo}/${branch}${remainder ? `/${remainder}` : ""}`
214
+ };
215
+ }
216
+ if (match = url.match(ghDotComRaw)) {
217
+ const [, owner, repo, rawPath] = match;
218
+ const { branch } = splitGitHubRefPath(rawPath);
219
+ return { owner, repo, branch, url };
220
+ }
221
+ if (match = url.match(ghTreeOrBlob)) {
222
+ const [, owner, repo, , branchPath] = match;
223
+ const { branch } = splitGitHubRefPath(branchPath);
224
+ return { owner, repo, branch, url };
225
+ }
226
+ if (match = url.match(ghRepoRoot)) {
227
+ const [, owner, repo] = match;
228
+ return { owner, repo, url };
229
+ }
230
+ throw new Error(`Unsupported GitHub URL: ${url}`);
231
+ }
232
+
233
+ export {
234
+ fetchJson,
235
+ getLatestCommit,
236
+ getLatestCommitAcrossBranches,
237
+ replaceRawWithLatestHash,
238
+ parseGitHubUrl
239
+ };