Something went wrong. Try again.
this post sux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197/* * sux shared logic — pure functions, no extension APIs. * Loaded as a classic script in the background page, content script, and sidebar, * and require()-able from Node for the unit tests. */(function (global) { "use strict";
var TEXT_CAP = 2000; var WORD_CAP = 80;
function cleanWord(w) { if (typeof w !== "string") return ""; return w.trim().toLowerCase().slice(0, WORD_CAP); }
function normalizeSettings(s) { s = s || {}; var ruleA = s.ruleA || {}; var ruleB = s.ruleB || {}; return { enabled: !!s.enabled, apiKey: typeof s.apiKey === "string" ? s.apiKey : "", combine: s.combine === "or" ? "or" : "and", ruleA: { enabled: !!ruleA.enabled, word1: cleanWord(ruleA.word1), word2: cleanWord(ruleA.word2), }, ruleB: { enabled: !!ruleB.enabled, word: cleanWord(ruleB.word), above: ruleB.above !== false, }, }; }
function defaults() { return normalizeSettings(null); }
// Rule A needs two distinct usable words. "neither" is reserved as the Choice's // third option, so a word colliding with it would silently overwrite that option. function ruleAValid(st) { var a = st.ruleA; return !!a.word1 && !!a.word2 && a.word1 !== a.word2 && a.word1 !== "neither" && a.word2 !== "neither"; }
function ruleBValid(st) { return !!st.ruleB.word; }
// True when the filter should actually run: master on AND at least one usable rule. function isActive(st) { return st.enabled && ((st.ruleA.enabled && ruleAValid(st)) || (st.ruleB.enabled && ruleBValid(st))); }
// FNV-1a — small, fast, dependency-free; collisions only cause a shared verdict, // which identical config+content would produce anyway with overwhelming likelihood. function hash(str) { var h = 0x811c9dc5; for (var i = 0; i < str.length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 0x01000193); } return (h >>> 0).toString(16); }
// Cache key = rule config + post content. Changing any word or the combinator // invalidates old verdicts; reposts with identical text share one key (and one // API call) because the post id is deliberately not part of the key. function cacheKey(st, text, alt) { var cfg = [ st.ruleA.enabled && ruleAValid(st) ? "A:" + st.ruleA.word1 + "|" + st.ruleA.word2 : "", st.ruleB.enabled && ruleBValid(st) ? "B:" + st.ruleB.word + "|" + (st.ruleB.above ? "above" : "below") : "", st.combine, ].join(";"); return hash(cfg) + ":" + hash((text || "") + "\n" + (alt || "")); }
function isJudgeable(post) { return !!((post.text && post.text.trim()) || (post.alt && post.alt.trim())); }
// Jev questions, one per enabled rule. Wording follows the jev skill: one property // per question, named state path in backticks, contrastive criteria, no policy // in the question (thresholds live in decideFromAnswers). function buildQuestions(st) { var q = {}; if (st.ruleA.enabled && ruleAValid(st)) { var w1 = st.ruleA.word1; var w2 = st.ruleA.word2; var c = { type: "choice", instructions: "Which option best describes the main topic or overall vibe of the post in `post`? Judge the post's own words only.", }; c.criteria = {}; c.criteria[w1] = "The post is mainly about " + w1 + ", or mainly expresses " + w1 + "."; c.criteria[w2] = "The post is mainly about " + w2 + ", or mainly expresses " + w2 + "."; c.criteria.neither = "The post is about neither " + w1 + " nor " + w2 + ", is about both equally, or it is too unclear to tell."; q.compare = c; } if (st.ruleB.enabled && ruleBValid(st)) { var w = st.ruleB.word; q.single = { type: "noul", instructions: "Does the post in `post` read as \"" + w + "\"? Judge the post's own words only.", criteria: { true: "The post is mainly about " + w + " or clearly expresses " + w + ".", false: "The post is not about " + w + ", or only mentions it in passing.", }, }; } return q; }
function buildRequest(st, post) { return { state: { post: { text: (post.text || "").slice(0, TEXT_CAP), alt: (post.alt || "").slice(0, TEXT_CAP), }, }, model: "jev-latest", questions: buildQuestions(st), }; }
// Turn Jev's answers into "show" | "hide" | null. Null means the response did not // contain a usable answer (transient/malformed) — callers fail open in that case. function decideFromAnswers(st, answers) { var results = []; if (st.ruleA.enabled && ruleAValid(st)) { var cmp = answers && answers.compare; var probs = cmp && cmp.probabilities; var p = probs && typeof probs[st.ruleA.word1] === "number" ? probs[st.ruleA.word1] : null; if (p === null) return null; results.push(p >= 0.5); // "at least 50% word1" } if (st.ruleB.enabled && ruleBValid(st)) { var single = answers && answers.single; var n = single && typeof single.noul === "number" ? single.noul : null; if (n === null) return null; results.push(st.ruleB.above ? n > 0.5 : n < 0.5); // strict: exactly 0.5 fails both ways } if (results.length === 0) return null; var pass = st.combine === "or" ? results.some(function (x) { return x; }) : results.every(function (x) { return x; }); return pass ? "show" : "hide"; }
// Score details behind a verdict — telemetry for tuning and for explaining // near-threshold behavior. Keys: p = P(word1) for rule A, n = Noul for rule B. function answerDetails(st, answers) { var d = {}; if (st.ruleA.enabled && ruleAValid(st)) { var probs = answers && answers.compare && answers.compare.probabilities; var p = probs && typeof probs[st.ruleA.word1] === "number" ? probs[st.ruleA.word1] : null; if (p !== null) d.p = Math.round(p * 1000) / 1000; } if (st.ruleB.enabled && ruleBValid(st)) { var single = answers && answers.single; var n = single && typeof single.noul === "number" ? single.noul : null; if (n !== null) d.n = Math.round(n * 1000) / 1000; } return d; }
var SuxShared = { TEXT_CAP: TEXT_CAP, WORD_CAP: WORD_CAP, defaults: defaults, normalizeSettings: normalizeSettings, ruleAValid: ruleAValid, ruleBValid: ruleBValid, isActive: isActive, hash: hash, cacheKey: cacheKey, isJudgeable: isJudgeable, buildQuestions: buildQuestions, buildRequest: buildRequest, decideFromAnswers: decideFromAnswers, answerDetails: answerDetails, };
global.SuxShared = SuxShared; if (typeof module !== "undefined" && module.exports) { module.exports = SuxShared; }})(typeof globalThis !== "undefined" ? globalThis : this);