PageSourceSearch

https://alpition.ch/script-top.js

js alpition.ch collected 2026-10-02 00:27:03 UTC 5,960 bytes, 182 lines download raw bytes

1(() => {
2    const OFFER_QUERY_KEY = 'utm_term';
3    const OFFER_STORAGE_KEY = 'site_offer';
4    const MIN_OFFER_PREFIX = 4;
5    
6    // Legacy aliases that may still be used in campaigns.
7    const STATIC_ALLOWED_OFFERS = ['AI Trade', 'Kizuna', 'Arbinio'];
8
9    const sanitizeOffer = (value) => {
10        if (typeof value !== 'string') return null;
11        const normalized = value.trim();
12
13        if (!normalized || normalized.length > 60) return null;
14        if (!/^[A-Za-z0-9][A-Za-z0-9 ._-]{0,59}$/.test(normalized)) return null;
15
16        return normalized;
17    };
18
19    const normalizeToken = (value) => (value || '').toLowerCase().replace(/[^a-z0-9]/g, '');
20
21    const replaceLiteral = (value, from, to) => {
22        if (typeof value !== 'string' || !from || from === to || !value.includes(from)) {
23            return value;
24        }
25
26        return value.split(from).join(to);
27    };
28
29    const detectServerOffer = () => {
30        const selectors = ['a.logo', '.logo', '.uk-navbar-left .uk-active a'];
31        for (const selector of selectors) {
32            const node = document.querySelector(selector);
33            const candidate = sanitizeOffer(node && node.textContent ? node.textContent : '');
34            if (candidate) return candidate;
35        }
36
37        const titleCandidate = sanitizeOffer((document.title || '').split('|')[0].split('™')[0]);
38        return titleCandidate;
39    };
40
41    const buildAllowedOffers = (serverOffer) => {
42        const offers = [];
43        const seen = new Set();
44
45        [serverOffer, ...STATIC_ALLOWED_OFFERS].forEach((offer) => {
46            const safeOffer = sanitizeOffer(offer);
47            const normalizedOffer = normalizeToken(safeOffer);
48
49            if (!safeOffer || !normalizedOffer || seen.has(normalizedOffer)) {
50                return;
51            }
52
53            seen.add(normalizedOffer);
54            offers.push(safeOffer);
55        });
56
57        return offers;
58    };
59
60    const resolveAllowedOffer = (rawValue, allowedOffers) => {
61        const safeRaw = sanitizeOffer(rawValue);
62        if (!safeRaw) {
63            return null;
64        }
65
66        const normalizedRaw = normalizeToken(safeRaw);
67        if (!normalizedRaw) {
68            return null;
69        }
70
71        // 1) Exact match by normalized token.
72        for (const offer of allowedOffers) {
73            if (normalizeToken(offer) === normalizedRaw) {
74                return offer;
75            }
76        }
77
78        // 2) Fuzzy: if utm_term contains first 4 chars of approved offer.
79        for (const offer of allowedOffers) {
80            const normalizedOffer = normalizeToken(offer);
81            if (normalizedOffer.length < MIN_OFFER_PREFIX) {
82                continue;
83            }
84
85            const offerPrefix = normalizedOffer.slice(0, MIN_OFFER_PREFIX);
86            if (normalizedRaw.includes(offerPrefix)) {
87                return offer;
88            }
89        }
90
91        return null;
92    };
93
94    const replaceInTextNodes = (sourceOffer, targetOffer) => {
95        const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
96        const blockedParents = new Set(['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA']);
97        let node = walker.nextNode();
98
99        while (node) {
100            const parentTag = node.parentElement ? node.parentElement.tagName : '';
101            if (!blockedParents.has(parentTag) && node.nodeValue && node.nodeValue.includes(sourceOffer)) {
102                node.nodeValue = replaceLiteral(node.nodeValue, sourceOffer, targetOffer);
103            }
104            node = walker.nextNode();
105        }
106    };
107
108    const replaceInAttributes = (sourceOffer, targetOffer) => {
109        const attrs = ['content', 'placeholder', 'title', 'aria-label', 'alt', 'value'];
110        const selector = attrs.map((attr) => `[${attr}*="${sourceOffer}"]`).join(',');
111        const nodes = document.querySelectorAll(selector);
112
113        nodes.forEach((el) => {
114            attrs.forEach((attr) => {
115                const current = el.getAttribute(attr);
116                if (current && current.includes(sourceOffer)) {
117                    el.setAttribute(attr, replaceLiteral(current, sourceOffer, targetOffer));
118                }
119            });
120        });
121    };
122
123    const applyOffer = (sourceOffer, targetOffer) => {
124        if (!sourceOffer || !targetOffer || sourceOffer === targetOffer) {
125            return;
126        }
127
128        document.title = replaceLiteral(document.title, sourceOffer, targetOffer);
129        replaceInAttributes(sourceOffer, targetOffer);
130
131        if (document.body) {
132            replaceInTextNodes(sourceOffer, targetOffer);
133        }
134    };
135
136    const getQueryOffer = () => {
137        try {
138            const params = new URLSearchParams(location.search);
139            return params.has(OFFER_QUERY_KEY) ? params.get(OFFER_QUERY_KEY) : null;
140        } catch (e) {
141            return null;
142        }
143    };
144
145    const getStoredOffer = (allowedOffers) => {
146        try {
147            return resolveAllowedOffer(localStorage.getItem(OFFER_STORAGE_KEY), allowedOffers);
148        } catch (e) {
149            return null;
150        }
151    };
152
153    const initOfferRotation = () => {
154        const sourceOffer = detectServerOffer();
155        const allowedOffers = buildAllowedOffers(sourceOffer);
156        const rawQueryOffer = getQueryOffer();
157
158        let targetOffer = null;
159
160        if (rawQueryOffer) {
161            targetOffer = resolveAllowedOffer(rawQueryOffer, allowedOffers);
162
163            if (targetOffer) {
164                try {
165                    localStorage.setItem(OFFER_STORAGE_KEY, targetOffer);
166                } catch (e) {}
167            }
168        }
169
170        if (!targetOffer) {
171            targetOffer = getStoredOffer(allowedOffers);
172        }
173
174        applyOffer(sourceOffer, targetOffer);
175    };
176
177    if (document.readyState === 'loading') {
178        document.addEventListener('DOMContentLoaded', initOfferRotation);
179    } else {
180        initOfferRotation();
181    }
182})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.