GreasyFork Search

使用谷歌搜索GreasyFork和SleazyFork上的脚本

当前为 2024-09-10 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name GreasyFork Search
  3. // @name:zh-CN GreasyFork Search
  4. // @description:zh-CN 使用谷歌搜索GreasyFork和SleazyFork上的脚本
  5. // @name:ar GreasyFork Search
  6. // @description:ar البحث باستخدام جوجلGreasyForkوSleazyForkالنص العلوي
  7. // @name:bg GreasyFork Search
  8. // @description:bg Търсете с GoogleGreasyForkиSleazyForkгорен скрипт
  9. // @name:cs GreasyFork Search
  10. // @description:cs Hledejte pomocí GoogleGreasyForkaSleazyForkhorní písmo
  11. // @name:da GreasyFork Search
  12. // @description:da Søg ved hjælp af GoogleGreasyForkogSleazyForkøverste skrift
  13. // @name:de GreasyFork Search
  14. // @description:de Suchen Sie mit GoogleGreasyForkUndSleazyForkOberschrift
  15. // @name:el GreasyFork Search
  16. // @description:el Αναζήτηση χρησιμοποιώντας το GoogleGreasyForkκαιSleazyForkπάνω σενάριο
  17. // @name:en GreasyFork Search
  18. // @description:en Search using GoogleGreasyForkandSleazyForkupper script
  19. // @name:eo GreasyFork Search
  20. // @description:eo Serĉu per GugloGreasyForkkajSleazyForksupra manuskripto
  21. // @name:es GreasyFork Search
  22. // @description:es Buscar usando GoogleGreasyForkySleazyForkguión superior
  23. // @name:fi GreasyFork Search
  24. // @description:fi Hae Googlen avullaGreasyForkjaSleazyForkylempi kirjoitus
  25. // @name:fr GreasyFork Search
  26. // @description:fr Rechercher avec GoogleGreasyForketSleazyForkécriture supérieure
  27. // @name:he GreasyFork Search
  28. // @description:he חפש באמצעות גוגלGreasyForkוSleazyForkכתב עליון
  29. // @name:hr GreasyFork Search
  30. // @description:hr Pretražujte pomoću GoogleaGreasyForkiSleazyForkgornja skripta
  31. // @name:hu GreasyFork Search
  32. // @description:hu Keressen a Google segítségévelGreasyForkésSleazyForkfelső szkript
  33. // @name:id GreasyFork Search
  34. // @description:id Cari menggunakan GoogleGreasyForkDanSleazyForkskrip atas
  35. // @name:it GreasyFork Search
  36. // @description:it Cerca utilizzando GoogleGreasyForkESleazyForkscrittura superiore
  37. // @name:ja GreasyFork Search
  38. // @description:ja Googleを使って検索するGreasyForkそしてSleazyFork上的脚本
  39. // @name:ka GreasyFork Search
  40. // @description:ka ძიება Google-ის გამოყენებითGreasyForkდაSleazyForkზედა დამწერლობა
  41. // @name:ko GreasyFork Search
  42. // @description:ko Google을 사용하여 검색GreasyFork그리고SleazyFork상적 각본
  43. // @name:nl GreasyFork Search
  44. // @description:nl Zoek met GoogleGreasyForkEnSleazyForkbovenste schrift
  45. // @name:nb GreasyFork Search
  46. // @description:nb Søk med GoogleGreasyForkogSleazyForkøvre skrift
  47. // @name:pl GreasyFork Search
  48. // @description:pl Szukaj za pomocą GoogleGreasyForkISleazyForkgórny skrypt
  49. // @name:pt-BR GreasyFork Search
  50. // @description:pt-BR Pesquise usando o GoogleGreasyForkeSleazyForkscript superior
  51. // @name:ro GreasyFork Search
  52. // @description:ro Căutați folosind GoogleGreasyForkşiSleazyForkscriptul superior
  53. // @name:ru GreasyFork Search
  54. // @description:ru Поиск с помощью GoogleGreasyForkиSleazyForkверхний сценарий
  55. // @name:sk GreasyFork Search
  56. // @description:sk Hľadajte pomocou GoogleGreasyForkaSleazyForkhorné písmo
  57. // @name:sr GreasyFork Search
  58. // @description:sr Претражујте помоћу Гоогле-аGreasyForkиSleazyForkгорње писмо
  59. // @name:sv GreasyFork Search
  60. // @description:sv Sök med GoogleGreasyForkochSleazyForkövre skrift
  61. // @name:th GreasyFork Search
  62. // @description:th ค้นหาโดยใช้ GoogleGreasyForkและSleazyForkสคริปต์ด้านบน
  63. // @name:tr GreasyFork Search
  64. // @description:tr Google’ı kullanarak arama yapınGreasyForkVeSleazyForküst yazı
  65. // @name:ug GreasyFork Search
  66. // @description:ug Google نى ئىشلىتىپ ئىزدەشGreasyForkۋەSleazyForkئۈستى قوليازما
  67. // @name:uk GreasyFork Search
  68. // @description:uk Пошук за допомогою GoogleGreasyForkіSleazyForkверхній скрипт
  69. // @name:vi GreasyFork Search
  70. // @description:vi Tìm kiếm bằng GoogleGreasyForkVàSleazyForkchữ viết trên
  71. // @name:zh-TW GreasyFork Search
  72. // @description:zh-TW 使用谷歌搜尋GreasyFork和SleazyFork上體文字
  73. // @name:zh-HK GreasyFork Search
  74. // @description:zh-HK 使用谷歌搜尋GreasyFork和SleazyFork上體文字
  75. // @name:fr-CA GreasyFork Search
  76. // @description:fr-CA Rechercher avec GoogleGreasyForketSleazyForkécriture supérieure
  77. // @namespace https://greasyfork.org/zh-CN/users/1169082
  78. // @version 0.6.5.21
  79. // @description To search scripts using Google Search
  80. // @author CY Fung , 人民的勤务员 <toniaiwanowskiskr47@gmail.com>
  81. // @match https://greasyfork.org/*
  82. // @match https://sleazyfork.org/*
  83. // @icon https://greasyfork.org/vite/assets/blacklogo96-CxYTSM_T.png
  84. // @require https://fastly.jsdelivr.net/npm/jstat@1.9.6/dist/jstat.min.js
  85. // @grant none
  86. // @license MIT
  87.  
  88. // ==/UserScript==
  89.  
  90.  
  91.  
  92. (() => {
  93.  
  94.  
  95.  
  96. function jacobi(a) {
  97. var n = a.length
  98. var trial = n * n * 2
  99. var e = jStat.identity(n, n)
  100. var ev = []
  101. var i, j, p, q, maxim, s
  102. let vaildResult = false
  103. outer: while (trial-- > 0) {
  104. maxim = a[0][1]
  105. p = 0
  106. q = 1
  107. for (i = 0; i < n; i++) {
  108. for (j = 0; j < n; j++) {
  109. if (i != j) {
  110. let t = Math.abs(a[i][j])
  111. if (maxim < t) {
  112. maxim = t
  113. p = i
  114. q = j
  115. }
  116. }
  117. }
  118. }
  119.  
  120. s = jStat.identity(n, n)
  121.  
  122. let tanValue = 2 * a[p][q] / (a[p][p] - a[q][q])
  123.  
  124. let cosTwoTheta = Math.sqrt(1 / (1 + tanValue * tanValue))
  125. let cosTheta = Math.sqrt(.5 * (1 + cosTwoTheta))
  126. let sinTheta = Math.sqrt(.5 * (1 - cosTwoTheta))
  127.  
  128. s[p][p] = cosTheta
  129. s[p][q] = -sinTheta
  130. s[q][p] = sinTheta
  131. s[q][q] = cosTheta
  132.  
  133. e = jStat.multiply(e, s)
  134. a = jStat.multiply(jStat.multiply(jStat.transpose(s), a), s)
  135.  
  136. for (i = 0; i < n; i++) {
  137. for (j = i + 1; j < n; j++) {
  138. if (Math.abs(a[i][j]) > .0004) {
  139. continue outer
  140. }
  141. }
  142. }
  143.  
  144. vaildResult = true
  145. break
  146. }
  147. if (!vaildResult) {
  148. console.warn("The matrix is not symmetric.")
  149. return null
  150. }
  151. for (i = 0; i < n; i++) ev.push(a[i][i])
  152. //returns both the eigenvalue and eigenmatrix
  153. return [e, ev]
  154. }
  155.  
  156.  
  157.  
  158. function getVN(A) {
  159. // normalized the matrix values such that det(A) will be a finite value close to 1.0
  160. // vn = sqrt( ( column_vector_1 ^2 + column_vector_2 ^2 + ... + column_vector_n ^2 ) / n )
  161. let vn = 0
  162. const AT = jStat.transpose(A)
  163. let N = AT.length
  164. for (let i = 0; i < N; i++) {
  165. vn += jStat.dot(AT[i], AT[i])
  166. }
  167. vn = Math.sqrt(vn / N)
  168. return vn
  169. }
  170.  
  171. function subtractLambdaFromDiagonal(matrix, lambda) {
  172. // A - lambda I
  173. return matrix.map((row, rowIndex) => row.map((val, colIndex) => rowIndex === colIndex ? val - lambda : val))
  174. }
  175.  
  176.  
  177. function eigenvalueNewton(A, lambda0) {
  178. const N = A.length
  179. const epsilon = 1e-5 // epsilon is applied on the normalized scale of lambda
  180. const maxTrial = 8
  181.  
  182. function f(lambda) {
  183. return jStat.det(subtractLambdaFromDiagonal(A, lambda))
  184. }
  185.  
  186. function fPrime(lambda) {
  187. return (f(lambda + epsilon) - f(lambda)) / epsilon
  188. }
  189.  
  190. let x_k = lambda0
  191. let positiveSign = 0
  192. let negativeSign = 0
  193. for (let i = 0; i < maxTrial; i++) {
  194. const fx = f(x_k)
  195. const fxPrime = fPrime(x_k)
  196. const diff = fx / fxPrime
  197. if (isNaN(diff)) return x_k // ignore f/f'
  198. const x_k1 = x_k - diff
  199. if ((diff > 0 ? diff : -diff) < epsilon) {
  200. return x_k1
  201. }
  202. x_k = x_k1
  203. if (fx > 0) positiveSign = 1
  204. else if (fx < 0) negativeSign = 1
  205. }
  206. return positiveSign && negativeSign ? x_k : lambda0 // avoid diverging iterations
  207. }
  208.  
  209. function vectorNorm(v) {
  210. // Math.sqrt(v dot v), same as jStat.norm(jStat.transpose(v))
  211. let s = 0
  212. for (const k of v) s += k[0] * k[0]
  213. return Math.sqrt(s)
  214. }
  215.  
  216. function isUnitVector(v, tol = 0.01) {
  217. // Check if it is likely a unit vector
  218. let s = 0
  219. for (const k of v) {
  220. s += k[0] * k[0]
  221. if (s > 1 + tol) return false
  222. }
  223. return s > 1 - tol
  224. }
  225.  
  226. jStat.jacobiOri = jStat.jacobi
  227. // https://www.statskingdom.com/pca-calculator.html
  228. jStat.jacobi = function (C) {
  229.  
  230. const vn = getVN(C)
  231. C = jStat.multiply(C, 1 / vn)
  232. let r1 = jacobi(C)
  233. // let r0 = JSON.parse(JSON.stringify(r1))
  234. // r0[1] = r0[1].map(v => vn * v);
  235. let A = C
  236. let eigenvectors = r1[0]
  237. let eigenvalues = r1[1]
  238. const iterationCount = 4
  239.  
  240. for (let i = 0; i < eigenvalues.length; i++) {
  241. let q, m
  242. q = jStat.transpose(eigenvectors[i])
  243. if (!isUnitVector(q)) break
  244. eigenvalues[i] = eigenvalueNewton(A, eigenvalues[i]) // refine eigenvalues obtained in jacobiOri
  245.  
  246. // inverse power method (A-lambda I) y_k = b_{k-1}
  247. // b_k = y_k / norm(y_k)
  248. let M = subtractLambdaFromDiagonal(A, eigenvalues[i])
  249. for (let j = 0; j < iterationCount; j++) {
  250. m = jStat.transpose(jStat.gauss_elimination(M, q))
  251. m = jStat.multiply(m, 1 / vectorNorm(m))
  252. if (!isUnitVector(m)) break // avoid Inf / NaN error
  253. q = m
  254. }
  255. eigenvectors[i] = jStat.transpose(q)
  256.  
  257. }
  258. r1[1] = r1[1].map(v => vn * v)
  259. return r1
  260. }
  261.  
  262.  
  263.  
  264. })()
  265.  
  266.  
  267. jStat.PCA = function PCA(X) {
  268. var m = X.length
  269. var n = X[0].length
  270. var i = 0
  271. var j, temp1
  272. var u = []
  273. var D = []
  274. var result = []
  275. var temp2 = []
  276. var Y = []
  277. var Bt = []
  278. var B = []
  279. var C = []
  280. var V = []
  281. var Vt = []
  282. for (i = 0; i < m; i++) {
  283. u[i] = jStat.sum(X[i]) / n
  284. }
  285. for (i = 0; i < n; i++) {
  286. B[i] = []
  287. for (j = 0; j < m; j++) {
  288. B[i][j] = X[j][i] - u[j]
  289. }
  290. }
  291. B = jStat.transpose(B)
  292. for (i = 0; i < m; i++) {
  293. C[i] = []
  294. for (j = 0; j < m; j++) {
  295. C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1)
  296. }
  297. }
  298. result = jStat.jacobi(C)
  299. V = result[0]
  300. D = result[1]
  301.  
  302. Vt = jStat.transpose(V)
  303.  
  304.  
  305. let vd = []
  306. for (i = 0; i < D.length; i++) {
  307. vd[i] = {
  308. Vt: Vt[i],
  309. D: D[i],
  310. k: D[i] * D[i]
  311. }
  312. }
  313.  
  314. vd.sort((a, b) => {
  315. return b.k - a.k
  316. })
  317.  
  318. Vt = vd.map(e => e.Vt)
  319. D = vd.map(e => e.D)
  320.  
  321.  
  322.  
  323. V = null
  324.  
  325.  
  326. Bt = jStat.transpose(B)
  327.  
  328. let pcs_11 = []
  329. let pt_11 = [1, 1]
  330. for (i = 0; i < m; i++) {
  331.  
  332.  
  333. pcs_11[i] = jStat.dot([Vt[i]], [pt_11])
  334. if (pcs_11[i] < 0) Vt[i] = jStat.multiply(Vt[i], -1)
  335. pcs_11[i] = jStat.dot([Vt[i]], [pt_11])
  336. }
  337.  
  338.  
  339.  
  340.  
  341.  
  342. for (i = 0; i < m; i++) {
  343. Y[i] = []
  344. for (j = 0; j < Bt.length; j++) {
  345. Y[i][j] = jStat.dot([Vt[i]], [Bt[j]])
  346. }
  347. }
  348. return [X, D, Vt, Y]
  349. };
  350.  
  351. (function () {
  352. 'use strict'
  353.  
  354. let input = document.querySelector('form input[name="q"]')
  355. if (!(input instanceof HTMLInputElement)) return
  356. let form = input.closest('form')
  357. if (!(form instanceof HTMLFormElement)) return
  358.  
  359.  
  360. let locales = [...document.querySelectorAll('select#language-selector-locale > option')].map(x => x.value)
  361.  
  362. document.head.appendChild(document.createElement('style')).textContent = `
  363.  
  364.  
  365. @keyframes rs1tmAnimation {
  366. 0% {
  367. background-position-x: 3px;
  368. }
  369. 100% {
  370. background-position-x: 4px;
  371. }
  372. }
  373.  
  374. form.rs1tm{
  375. position: fixed;
  376. top:-300px;
  377. left:-300px;
  378. width: 1px;
  379. height: 1px;
  380. contain: strict;
  381. display: flex;
  382. overflow: hidden;
  383. animation: rs1tmAnimation 1ms linear 1ms 1 normal forwards;
  384. }
  385.  
  386. `
  387. document.addEventListener('animationstart', (evt) => {
  388.  
  389. if (evt.animationName === 'rs1tmAnimation') {
  390. const target = evt.target
  391. target && target.parentNode && target.remove()
  392. }
  393.  
  394. }, true)
  395.  
  396. window.callback947 = function (rainijpolynomialRegressionJs) {
  397. if (!rainijpolynomialRegressionJs) return
  398. const { PolynomialFeatures, PolynomialRegressor, RegressionError } = rainijpolynomialRegressionJs
  399. if (!PolynomialFeatures || !PolynomialRegressor || !RegressionError) return
  400.  
  401. console.log(rainijpolynomialRegressionJs)
  402. }
  403.  
  404. form.addEventListener('submit', function (evt) {
  405.  
  406. try {
  407.  
  408.  
  409. let form = evt.target
  410. if (!(form instanceof HTMLFormElement)) return
  411. let input = form.querySelector('input[name="q"]')
  412. if (!(input instanceof HTMLInputElement)) return
  413.  
  414. if (form.classList.contains('rs1tm')) return
  415.  
  416. let value = input.value
  417. const lang = document.documentElement.lang || ''
  418.  
  419. let useLang = false
  420.  
  421.  
  422. let u = 0
  423. let isGoogleSearch = false
  424.  
  425. let sites = []
  426.  
  427. const split = value.split(/\s+/)
  428. let forceLang = 'all'
  429. let reformedSplit = []
  430. for (const s of split) {
  431.  
  432. if (!isGoogleSearch && /^[a-z][a-z0-9_-]{2,}(\.[a-z][a-z0-9_-]{2,})*(\.[a-z-]{2,4})+$/.test(s)) {
  433. if (/\.(js|css|html|htm|xml|img|svg|txt|php|cgi|xhtml|ini|vue|xhr|ajax)$/.test(s)) {
  434. reformedSplit.push(s)
  435. } else {
  436. sites.push(s)
  437. }
  438. } else if (s === 'js') {
  439. forceLang = 'js'; reformedSplit.push(s)
  440. } else if (s === 'css') {
  441. forceLang = 'css'; reformedSplit.push(s)
  442. } else if (s === 'user.js') {
  443. forceLang = 'js'
  444. } else if (s === 'user.css') {
  445. forceLang = 'css'
  446. } else if (s === '"js"') {
  447. reformedSplit.push('js')
  448. } else if (s === '"css"') {
  449. reformedSplit.push('css')
  450. } else if (u === 0 && s === 'g') {
  451. isGoogleSearch = true
  452. } else if (locales.indexOf(s) >= 0 || s === lang) {
  453. useLang = s
  454. } else {
  455. reformedSplit.push(s)
  456. }
  457. u++
  458. }
  459. console.log(sites)
  460.  
  461. value = reformedSplit.join(' ')
  462.  
  463. let onlySite = ''
  464.  
  465. if (sites.length === 1 && sites[0]) {
  466. onlySite = sites[0]
  467. }
  468.  
  469. /*
  470. if (!isGoogleSearch && onlySite && /\.\w+\.\w+/.test(onlySite)) {
  471. alert('Greasy Fork only lists eTLD+1.');
  472. evt.preventDefault();
  473. evt.stopImmediatePropagation();
  474. evt.stopPropagation();
  475. return;
  476. }
  477. */
  478.  
  479.  
  480. if (isGoogleSearch && value) {
  481. let q = value.replace('g ', '')
  482.  
  483. let m = "-inurl%3A%22%2Fusers%2F%22+-inurl%3A%22%2Fdiscussions%22-inurl%3A%22%2Fstats%22+-inurl%3A%22%2Ffeedback%22+-inurl%3A%22%2Fcode%22+-inurl%3A%22q%3D%22+-inurl%3A%22%2Fby-site%2F%22+inurl%3A%22%2Fscripts%2F%22+site%3A"
  484. var currentUrl = window.location.origin
  485. var index1 = currentUrl.indexOf("sleazyfork")
  486. var index2 = currentUrl.indexOf("greasyfork")//搜索
  487. if (index2 !== -1) {
  488. m = m + "greasyfork.org"
  489. }
  490. if (index1 !== -1) {
  491. m = m + "sleazyfork.org"
  492. }
  493. let lr = useLang ? `&lr=lang_${useLang}` : ''
  494. evt.preventDefault()
  495. evt.stopImmediatePropagation()
  496. evt.stopPropagation()
  497.  
  498. location.href = `https://www.google.com/search?q=${encodeURIComponent(q)}+${m}${lr}`
  499.  
  500. } else if (!isGoogleSearch && (value || onlySite)) {
  501.  
  502.  
  503. let newForm = document.createElement('form')
  504. newForm.className = 'rs1tm'
  505. const copyAttr = (x) => {
  506. let t = form.getAttribute(x)
  507. if (typeof t === 'string') newForm.setAttribute(x, t)
  508. }
  509. copyAttr('action')
  510. copyAttr('accept-charset')
  511. copyAttr('method')
  512. newForm.innerHTML = `<input name="q" type="hidden" value="" /><input name="site" type="hidden" /><input name="language" type="hidden" value="all" /><input name="sort" type="hidden" />`
  513.  
  514.  
  515. const nq = newForm.querySelector('input[name="q"]')
  516. const language = newForm.querySelector('input[name="language"]')
  517. const site = newForm.querySelector('input[name="site"]')
  518. const sort = newForm.querySelector('input[name="sort"]')
  519.  
  520. value = value.replace(/\s+/g, ' ')
  521. site.value = onlySite
  522.  
  523. if (form.getAttribute('action') === `/${lang}/scripts` && useLang && useLang !== lang) {
  524. form.setAttribute('action', `/${useLang}/scripts`)
  525. }
  526.  
  527.  
  528. if (site.value === '') site.remove()
  529.  
  530. nq.value = value
  531.  
  532. language.value = forceLang
  533.  
  534. if (language.value === '') language.remove()
  535.  
  536.  
  537. sort.value = 'updated'
  538.  
  539. let sorting = document.querySelector('#script-list-sort')
  540. if (sorting) {
  541. let sorts1 = {
  542. nil: 0,
  543. daily_installs: 0,
  544. total_installs: 0,
  545. ratings: 0,
  546. created: 0,
  547. updated: 0,
  548. name: 0
  549. }
  550. let sorts2 = {
  551. daily_installs: 0,
  552. total_installs: 0,
  553. ratings: 0,
  554. created: 0,
  555. updated: 0,
  556. name: 0
  557. }
  558. const allOptions = sorting.querySelectorAll('.list-option')
  559. const sorts = allOptions.length === 6 ? (sorts2) : (sorts1)
  560. const keys = Object.keys(sorts)
  561.  
  562. if (allOptions.length === keys.length) {
  563.  
  564.  
  565. for (const key of keys) {
  566. let e = `.list-option:not(.list-current) a[href$="sort=${key}"]`
  567. if (key === 'nil') {
  568. e = `.list-option:not(.list-current) a[href]:not([href*="sort="])`
  569. e = sorting.querySelector(e)
  570. } else {
  571. e = sorting.querySelector(e)
  572. }
  573.  
  574. if (e) {
  575. sorts[key] = 1
  576. }
  577.  
  578. }
  579.  
  580.  
  581.  
  582. let p = Object.entries(sorts).filter(r => !r[1])
  583. if (p.length === 1) {
  584. sort.value = p[0][0]
  585. }
  586.  
  587. }
  588.  
  589. }
  590.  
  591.  
  592.  
  593.  
  594. if (sort.value === '') sort.remove()
  595.  
  596. evt.preventDefault()
  597. evt.stopImmediatePropagation()
  598. evt.stopPropagation()
  599.  
  600. form.parentNode.insertBefore(newForm, form)
  601. newForm.submit()
  602. Promise.resolve().then(() => {
  603. newForm.remove()
  604. })
  605.  
  606.  
  607. } else {
  608. evt.preventDefault()
  609. evt.stopImmediatePropagation()
  610. evt.stopPropagation()
  611. }
  612.  
  613. } catch (e) {
  614. console.log(e)
  615.  
  616. evt.preventDefault()
  617. evt.stopImmediatePropagation()
  618. evt.stopPropagation()
  619. }
  620.  
  621. })
  622.  
  623. // Your code here...
  624. })();
  625.  
  626. (() => {
  627.  
  628. function prettyMatrix(A) {
  629. let w = ''
  630. for (let i = 0; i < A.length; i++) {
  631. for (let j = 0; j < A[i].length; j++) {
  632. w += A[i][j].toFixed(4) + '\t'
  633. }
  634. w += '\n\t'
  635. }
  636. return '[\n\t' + w.trim() + '\n]'
  637. }
  638.  
  639.  
  640. requestAnimationFrame(() => {
  641.  
  642. setTimeout(() => {
  643.  
  644. if ((location.search.includes('sort=updated') || location.search.includes('sort=created')) && location.pathname.endsWith('/scripts')) { } else return
  645. let items = document.querySelectorAll('[data-script-id][data-script-daily-installs][data-script-total-installs]')
  646.  
  647. let data = [...items].map(e => ({
  648. id: parseInt(e.getAttribute('data-script-id')),
  649. daily: parseInt(e.getAttribute('data-script-daily-installs')),
  650. total: parseInt(e.getAttribute('data-script-total-installs'))
  651. })).filter(e => e.id && !isNaN(e.daily) && !isNaN(e.total))
  652.  
  653. const daily = data.map(d => d.daily)
  654. const total = data.map(d => d.total)
  655. dailyMean = jStat.mean(daily)
  656. dailySD = jStat.stdev(daily, true)
  657. totalMean = jStat.mean(total)
  658. totalSD = jStat.stdev(total, true)
  659.  
  660. const uDaily = jStat.multiply(jStat.subtract(daily, dailyMean), 1 / dailySD)
  661. const uTotal = jStat.multiply(jStat.subtract(total, totalMean), 1 / totalSD)
  662.  
  663. let dataA = data.map((d, i) => [uDaily[i], uTotal[i]])
  664.  
  665. // dataA = dataA.slice(0, 4)
  666. // console.log(dataA)
  667.  
  668. let matrixA = jStat.transpose(dataA)
  669.  
  670.  
  671. const result = jStat.PCA(matrixA)
  672. const [X, D, Vt, Y] = result
  673.  
  674.  
  675.  
  676. let q = null
  677. let qSet = null
  678. if (location.search.includes('q=')) {
  679. q = new URLSearchParams(location.search)
  680. q = q.get('q')
  681.  
  682. }
  683.  
  684. function makeQA(q) {
  685. let qSet = new Set()
  686. q.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
  687. qSet.add(_.toLowerCase())
  688. })
  689. return qSet
  690. }
  691.  
  692. if (q) {
  693. qSet = makeQA(q)
  694. }
  695.  
  696. let mr = new Map()
  697. let u = 0
  698. for (const d of data) {
  699. d.pcaScore = Y[0][u++]
  700. let elm = document.querySelector(`[data-script-id="${d.id}"]`)
  701. if (elm) {
  702.  
  703. let order = 0
  704. order -= Math.floor(d.pcaScore * 1000)
  705.  
  706. let u1 = 0, u2 = 0
  707.  
  708. if (qSet) {
  709.  
  710. const pSet = qSet
  711.  
  712. let elp = elm.querySelector('.script-link')
  713. if (elp) {
  714. let t = elp.textContent
  715.  
  716. t.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
  717. if (pSet.has(_.toLowerCase())) u1++
  718. })
  719.  
  720.  
  721. }
  722.  
  723.  
  724.  
  725. let elq = elm.querySelector('.script-description')
  726.  
  727. if (elq) {
  728. let t = elq.textContent
  729.  
  730. t.replace(/_-/g, ' ').replace(/\b\S+\b/g, (_) => {
  731. if (pSet.has(_.toLowerCase())) u2++
  732. })
  733.  
  734.  
  735. }
  736.  
  737.  
  738. }
  739.  
  740.  
  741. if (u1 && u2) order -= 30000
  742. else if (u1) order -= 20000
  743. else if (u2) order -= 10000
  744.  
  745.  
  746. mr.set(d.id, order)
  747. // elm.style.order = order;
  748. // elm.parentNode.style.display = 'flex';
  749.  
  750.  
  751. // elm.parentNode.style.flexDirection = 'column';
  752.  
  753.  
  754. }
  755. }
  756.  
  757. /*
  758. let lists = [...new Set([...document.querySelectorAll(`[data-script-id]`)].map(p => p.parentNode))];
  759. for (const list of lists) {
  760. let m = [...list.childNodes].map(e => ({
  761. element: e,
  762. order: mr.get(e instanceof HTMLElement ? (+e.getAttribute('data-script-id') || '') : '') || 0
  763. }));
  764. m.sort((a, b) => {
  765. return Math.round(a.order - b.order)
  766. });
  767. let newNodes = m.map(e => e.element);
  768. list.replaceChildren(...newNodes);
  769. }
  770. */
  771.  
  772. // console.log(prettyMatrix(X))
  773.  
  774. // console.log(prettyMatrix(Y))
  775.  
  776.  
  777.  
  778.  
  779.  
  780. }, 300)
  781.  
  782. })
  783.  
  784.  
  785.  
  786. })()