cryptonobler revised this gist . Go to revision
1 file changed, 364 insertions
blum.js(file created)
@@ -0,0 +1,364 @@ | |||
1 | + | // ==UserScript== | |
2 | + | // @name Blum Autoclicker | |
3 | + | // @version 1.0 | |
4 | + | // @namespace Nobler's | |
5 | + | // @author https://twitter.com/cryptonobler | |
6 | + | // @match https://telegram.blum.codes/* | |
7 | + | // @grant none | |
8 | + | // @icon https://img.bitgetimg.com/multiLang/web/6a914e6e4aa70f6fd2bdf790f0f8401f.png | |
9 | + | // @downloadURL https://twitter.com/cryptonobler | |
10 | + | // @updateURL https://twitter.com/cryptonobler | |
11 | + | // @homepage https://twitter.com/cryptonobler | |
12 | + | // ==/UserScript== | |
13 | + | ||
14 | + | let GAME_SETTINGS = { | |
15 | + | minBombHits: Math.floor(Math.random() * 2), | |
16 | + | minIceHits: Math.floor(Math.random() * 2) + 2, | |
17 | + | flowerSkipPercentage: Math.floor(Math.random() * 11) + 15, | |
18 | + | minDelayMs: 1500, | |
19 | + | maxDelayMs: 4500, | |
20 | + | autoClickPlay: false, | |
21 | + | }; | |
22 | + | let isGamePaused = false; | |
23 | + | try { | |
24 | + | let gameStats = { | |
25 | + | score: 0, | |
26 | + | bombHits: 0, | |
27 | + | iceHits: 0, | |
28 | + | flowersSkipped: 0, | |
29 | + | isGameOver: false, | |
30 | + | }; | |
31 | + | const originalPush = Array.prototype.push; | |
32 | + | Array.prototype.push = function (...items) { | |
33 | + | if (!isGamePaused) { | |
34 | + | items.forEach((item) => handleGameElement(item)); | |
35 | + | } | |
36 | + | return originalPush.apply(this, items); | |
37 | + | }; | |
38 | + | function handleGameElement(element) { | |
39 | + | if (!element || !element.item) return; | |
40 | + | const { type } = element.item; | |
41 | + | switch (type) { | |
42 | + | case "CLOVER": | |
43 | + | processFlower(element); | |
44 | + | break; | |
45 | + | case "BOMB": | |
46 | + | processBomb(element); | |
47 | + | break; | |
48 | + | case "FREEZE": | |
49 | + | processIce(element); | |
50 | + | break; | |
51 | + | } | |
52 | + | } | |
53 | + | function processFlower(element) { | |
54 | + | const shouldSkip = Math.random() < GAME_SETTINGS.flowerSkipPercentage / 100; | |
55 | + | if (shouldSkip) { | |
56 | + | gameStats.flowersSkipped++; | |
57 | + | } else { | |
58 | + | gameStats.score++; | |
59 | + | clickElement(element); | |
60 | + | } | |
61 | + | } | |
62 | + | function processBomb(element) { | |
63 | + | if (gameStats.bombHits < GAME_SETTINGS.minBombHits) { | |
64 | + | gameStats.score = 0; | |
65 | + | clickElement(element); | |
66 | + | gameStats.bombHits++; | |
67 | + | } | |
68 | + | } | |
69 | + | function processIce(element) { | |
70 | + | if (gameStats.iceHits < GAME_SETTINGS.minIceHits) { | |
71 | + | clickElement(element); | |
72 | + | gameStats.iceHits++; | |
73 | + | } | |
74 | + | } | |
75 | + | function clickElement(element) { | |
76 | + | element.onClick(element); | |
77 | + | element.isExplosion = true; | |
78 | + | element.addedAt = performance.now(); | |
79 | + | } | |
80 | + | function checkGameCompletion() { | |
81 | + | const rewardElement = document.querySelector( | |
82 | + | "#app > div > div > div.content > div.reward" | |
83 | + | ); | |
84 | + | if (rewardElement && !gameStats.isGameOver) { | |
85 | + | gameStats.isGameOver = true; | |
86 | + | resetGameStats(); | |
87 | + | } | |
88 | + | } | |
89 | + | function resetGameStats() { | |
90 | + | gameStats = { | |
91 | + | score: 0, | |
92 | + | bombHits: 0, | |
93 | + | iceHits: 0, | |
94 | + | flowersSkipped: 0, | |
95 | + | isGameOver: false, | |
96 | + | }; | |
97 | + | } | |
98 | + | function getNewGameDelay() { | |
99 | + | return Math.floor( | |
100 | + | Math.random() * | |
101 | + | (GAME_SETTINGS.maxDelayMs - GAME_SETTINGS.minDelayMs + 1) + | |
102 | + | GAME_SETTINGS.minDelayMs | |
103 | + | ); | |
104 | + | } | |
105 | + | function checkAndClickPlayButton() { | |
106 | + | const playButtons = document.querySelectorAll( | |
107 | + | 'button.kit-button.is-large.is-primary, a.play-btn[href="/game"], button.kit-button.is-large.is-primary' | |
108 | + | ); | |
109 | + | playButtons.forEach((button) => { | |
110 | + | if ( | |
111 | + | !isGamePaused && | |
112 | + | GAME_SETTINGS.autoClickPlay && | |
113 | + | (/Play/.test(button.textContent) || /Continue/.test(button.textContent)) | |
114 | + | ) { | |
115 | + | setTimeout(() => { | |
116 | + | button.click(); | |
117 | + | gameStats.isGameOver = false; | |
118 | + | }, getNewGameDelay()); | |
119 | + | } | |
120 | + | }); | |
121 | + | } | |
122 | + | function continuousPlayButtonCheck() { | |
123 | + | checkAndClickPlayButton(); | |
124 | + | setTimeout(continuousPlayButtonCheck, 1000); | |
125 | + | } | |
126 | + | const observer = new MutationObserver((mutations) => { | |
127 | + | for (const mutation of mutations) { | |
128 | + | if (mutation.type === "childList") { | |
129 | + | checkGameCompletion(); | |
130 | + | } | |
131 | + | } | |
132 | + | }); | |
133 | + | const appElement = document.querySelector("#app"); | |
134 | + | if (appElement) { | |
135 | + | observer.observe(appElement, { childList: true, subtree: true }); | |
136 | + | } | |
137 | + | continuousPlayButtonCheck(); | |
138 | + | const settingsMenu = document.createElement("div"); | |
139 | + | settingsMenu.className = "settings-menu"; | |
140 | + | settingsMenu.style.display = "none"; | |
141 | + | const menuTitle = document.createElement("h3"); | |
142 | + | menuTitle.className = "settings-title"; | |
143 | + | menuTitle.textContent = "Blum Autoclicker"; | |
144 | + | const closeButton = document.createElement("button"); | |
145 | + | closeButton.className = "settings-close-button"; | |
146 | + | closeButton.textContent = "×"; | |
147 | + | closeButton.onclick = () => { | |
148 | + | settingsMenu.style.display = "none"; | |
149 | + | }; | |
150 | + | menuTitle.appendChild(closeButton); | |
151 | + | settingsMenu.appendChild(menuTitle); | |
152 | + | function updateSettingsMenu() { | |
153 | + | document.getElementById("flowerSkipPercentage").value = | |
154 | + | GAME_SETTINGS.flowerSkipPercentage; | |
155 | + | document.getElementById("flowerSkipPercentageDisplay").textContent = | |
156 | + | GAME_SETTINGS.flowerSkipPercentage; | |
157 | + | document.getElementById("minIceHits").value = GAME_SETTINGS.minIceHits; | |
158 | + | document.getElementById("minIceHitsDisplay").textContent = | |
159 | + | GAME_SETTINGS.minIceHits; | |
160 | + | document.getElementById("minBombHits").value = GAME_SETTINGS.minBombHits; | |
161 | + | document.getElementById("minBombHitsDisplay").textContent = | |
162 | + | GAME_SETTINGS.minBombHits; | |
163 | + | document.getElementById("minDelayMs").value = GAME_SETTINGS.minDelayMs; | |
164 | + | document.getElementById("minDelayMsDisplay").textContent = | |
165 | + | GAME_SETTINGS.minDelayMs; | |
166 | + | document.getElementById("maxDelayMs").value = GAME_SETTINGS.maxDelayMs; | |
167 | + | document.getElementById("maxDelayMsDisplay").textContent = | |
168 | + | GAME_SETTINGS.maxDelayMs; | |
169 | + | document.getElementById("autoClickPlay").checked = | |
170 | + | GAME_SETTINGS.autoClickPlay; | |
171 | + | } | |
172 | + | settingsMenu.appendChild( | |
173 | + | createSettingElement( | |
174 | + | "Flower Skip (%)", | |
175 | + | "flowerSkipPercentage", | |
176 | + | "range", | |
177 | + | 0, | |
178 | + | 100, | |
179 | + | 1, | |
180 | + | "Percentage probability of missing a flower" | |
181 | + | ) | |
182 | + | ); | |
183 | + | settingsMenu.appendChild( | |
184 | + | createSettingElement( | |
185 | + | "Min Freeze Hits", | |
186 | + | "minIceHits", | |
187 | + | "range", | |
188 | + | 1, | |
189 | + | 10, | |
190 | + | 1, | |
191 | + | "Minimum number of clicks per freeze" | |
192 | + | ) | |
193 | + | ); | |
194 | + | settingsMenu.appendChild( | |
195 | + | createSettingElement( | |
196 | + | "Min Bomb Hits", | |
197 | + | "minBombHits", | |
198 | + | "range", | |
199 | + | 0, | |
200 | + | 10, | |
201 | + | 1, | |
202 | + | "Minimum number of clicks per bomb" | |
203 | + | ) | |
204 | + | ); | |
205 | + | settingsMenu.appendChild( | |
206 | + | createSettingElement( | |
207 | + | "Min Delay (ms)", | |
208 | + | "minDelayMs", | |
209 | + | "range", | |
210 | + | 10, | |
211 | + | 10000, | |
212 | + | 10, | |
213 | + | "Minimum delay between clicks" | |
214 | + | ) | |
215 | + | ); | |
216 | + | settingsMenu.appendChild( | |
217 | + | createSettingElement( | |
218 | + | "Max Delay (ms)", | |
219 | + | "maxDelayMs", | |
220 | + | "range", | |
221 | + | 10, | |
222 | + | 10000, | |
223 | + | 10, | |
224 | + | "Maximum delay between clicks" | |
225 | + | ) | |
226 | + | ); | |
227 | + | settingsMenu.appendChild( | |
228 | + | createSettingElement( | |
229 | + | "Auto Click Play", | |
230 | + | "autoClickPlay", | |
231 | + | "checkbox", | |
232 | + | null, | |
233 | + | null, | |
234 | + | null, | |
235 | + | "Automatically start the next game" | |
236 | + | ) | |
237 | + | ); | |
238 | + | const pauseResumeButton = document.createElement("button"); | |
239 | + | pauseResumeButton.textContent = "Pause"; | |
240 | + | pauseResumeButton.className = "pause-resume-btn"; | |
241 | + | pauseResumeButton.onclick = toggleGamePause; | |
242 | + | settingsMenu.appendChild(pauseResumeButton); | |
243 | + | const socialButtons = document.createElement("div"); | |
244 | + | socialButtons.className = "social-buttons"; | |
245 | + | const twitterButton = document.createElement("a"); | |
246 | + | twitterButton.href = "https://twitter.com/CryptoNobler"; | |
247 | + | twitterButton.target = "_blank"; | |
248 | + | twitterButton.className = "social-button"; | |
249 | + | twitterButton.innerHTML = | |
250 | + | '<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIiB2aWV3Qm94PSIwIDAgMjQgMjQiPgogIDxwYXRoIGZpbGw9ImN1cnJlbnRDb2xvciIgZD0iTTE4LjkwMSAxLjE1M2gzLjY4bC04LjA0IDkuMTlMMjQgMjIuODQ2aC03LjQwNmwtNS44LTcuNTg0bC02LjYzOCA3LjU4NEguNDc0bDguNi05LjgzTDAgMS4xNTRoNy41OTRsNS4yNDMgNi45MzJaTTE3LjYxIDIwLjY0NGgyLjAzOUw2LjQ4NiAzLjI0SDQuMjk4WiIvPgo8L3N2Zz4=">Twitter'; | |
251 | + | socialButtons.appendChild(twitterButton); | |
252 | + | const telegramButton = document.createElement("a"); | |
253 | + | telegramButton.href = "https://t.me/shopalenka"; | |
254 | + | telegramButton.target = "_blank"; | |
255 | + | telegramButton.className = "social-button"; | |
256 | + | telegramButton.innerHTML = | |
257 | + | '<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIiB2aWV3Qm94PSIwIDAgMjU2IDI1NiI+CiAgPGRlZnM+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImxvZ29zVGVsZWdyYW0wIiB4MT0iNTAlIiB4Mj0iNTAlIiB5MT0iMCUiIHkyPSIxMDAlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzJBQUJFRSIvPgogICAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMyMjlFRDkiLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxwYXRoIGZpbGw9InVybCgjbG9nb3NUZWxlZ3JhbTApIiBkPSJNMTI4IDBDOTQuMDYgMCA2MS40OCAxMy40OTQgMzcuNSAzNy40OUExMjguMDM4IDEyOC4wMzggMCAwIDAgMCAxMjhjMCAzMy45MzQgMTMuNSA2Ni41MTQgMzcuNSA5MC41MUM2MS40OCAyNDIuNTA2IDk0LjA2IDI1NiAxMjggMjU2czY2LjUyLTEzLjQ5NCA5MC41LTM3LjQ5YzI0LTIzLjk5NiAzNy41LTU2LjU3NiAzNy41LTkwLjUxYzAtMzMuOTM0LTEzLjUtNjYuNTE0LTM3LjUtOTAuNTFDMTk0LjUyIDEzLjQ5NCAxNjEuOTQgMCAxMjggMFoiLz4KICA8cGF0aCBmaWxsPSIjRkZGIiBkPSJNNTcuOTQgMTI2LjY0OGMzNy4zMi0xNi4yNTYgNjIuMi0yNi45NzQgNzQuNjQtMzIuMTUyYzM1LjU2LTE0Ljc4NiA0Mi45NC0xNy4zNTQgNDcuNzYtMTcuNDQxYzEuMDYtLjAxNyAzLjQyLjI0NSA0Ljk2IDEuNDljMS4yOCAxLjA1IDEuNjQgMi40NyAxLjgyIDMuNDY3Yy4xNi45OTYuMzggMy4yNjYuMiA1LjAzOGMtMS45MiAyMC4yNC0xMC4yNiA2OS4zNTYtMTQuNSA5Mi4wMjZjLTEuNzggOS41OTItNS4zMiAxMi44MDgtOC43NCAxMy4xMjJjLTcuNDQuNjg0LTEzLjA4LTQuOTEyLTIwLjI4LTkuNjNjLTExLjI2LTcuMzg2LTE3LjYyLTExLjk4Mi0yOC41Ni0xOS4xODhjLTEyLjY0LTguMzI4LTQuNDQtMTIuOTA2IDIuNzYtMjAuMzg2YzEuODgtMS45NTggMzQuNjQtMzEuNzQ4IDM1LjI2LTM0LjQ1Yy4wOC0uMzM4LjE2LTEuNTk4LS42LTIuMjYyYy0uNzQtLjY2Ni0xLjg0LS40MzgtMi42NC0uMjU4Yy0xLjE0LjI1Ni0xOS4xMiAxMi4xNTItNTQgMzUuNjg2Yy01LjEgMy41MDgtOS43MiA1LjIxOC0xMy44OCA1LjEyOGMtNC41Ni0uMDk4LTEzLjM2LTIuNTg0LTE5LjktNC43MDhjLTgtMi42MDYtMTQuMzgtMy45ODQtMTMuODItOC40MWMuMjgtMi4zMDQgMy40Ni00LjY2MiA5LjUyLTcuMDcyWiIvPgo8L3N2Zz4=">Telegram Channel'; | |
258 | + | socialButtons.appendChild(telegramButton); | |
259 | + | settingsMenu.appendChild(socialButtons); | |
260 | + | document.body.appendChild(settingsMenu); | |
261 | + | const settingsButton = document.createElement("button"); | |
262 | + | settingsButton.className = "settings-button"; | |
263 | + | settingsButton.textContent = "⚙️"; | |
264 | + | settingsButton.onclick = () => { | |
265 | + | settingsMenu.style.display = | |
266 | + | settingsMenu.style.display === "block" ? "none" : "block"; | |
267 | + | }; | |
268 | + | document.body.appendChild(settingsButton); | |
269 | + | const style = document.createElement("style"); | |
270 | + | style.textContent = ` .settings-menu { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgba(40, 44, 52, 0.95); border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); color: #abb2bf; font-family: 'Arial', sans-serif; z-index: 10000; padding: 20px; width: 300px; } .settings-title { color: #61afef; font-size: 18px; font-weight: bold; margin-bottom: 15px; display: flex; align-items: center; justify-content: space-between; } .settings-close-button { background: none; border: none; color: #e06c75; font-size: 20px; cursor: pointer; padding: 0; } .setting-item { margin-bottom: 12px; } .setting-label { display: flex; align-items: center; margin-bottom: 4px; } .setting-label-text { color: #e5c07b; margin-right: 5px; } .help-icon { cursor: help; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 50%; background-color: #61afef; color: #282c34; font-size: 10px; font-weight: bold; } .setting-input { display: flex; align-items: center; } .setting-slider { flex-grow: 1; margin-right: 8px; } .setting-value { min-width: 30px; text-align: right; font-size: 11px; } .tooltip { position: relative; } .tooltip .tooltiptext { visibility: hidden; width: 200px; background-color: #4b5263; color: #fff; text-align: center; border-radius: 6px; padding: 5px; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -100px; opacity: 0; transition: opacity 0.3s; font-size: 11px; box-shadow: 0 2px 4px rgba(0,0,0,0.2); } .tooltip:hover .tooltiptext { visibility: visible; opacity: 1; } .pause-resume-btn { display: block; width: calc(100% - 10px); padding: 8px; margin: 15px 5px; background-color: #98c379; color: #282c34; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; font-size: 14px; transition: background-color 0.3s; } .pause-resume-btn:hover { background-color: #7cb668; } .social-buttons { margin-top: 15px; display: flex; justify-content: space-between; white-space: nowrap; } .social-button { display: inline-flex; align-items: center; padding: 5px 8px; border-radius: 4px; background-color: #282c34; color: #abb2bf; text-decoration: none; font-size: 12px; transition: background-color 0.3s; } .social-button:hover { background-color: #4b5263; } .social-button img { width: 16px; height: 16px; margin-right: 5px; } .settings-button { position: fixed; bottom: 20px; right: 20px; background-color: rgba(36, 146, 255, 0.8); color: #fff; border: none; border-radius: 50%; width: 40px; height: 40px; font-size: 18px; cursor: pointer; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); z-index: 9999; } `; | |
271 | + | document.head.appendChild(style); | |
272 | + | function createSettingElement(label, id, type, min, max, step, tooltipText) { | |
273 | + | const container = document.createElement("div"); | |
274 | + | container.className = "setting-item"; | |
275 | + | const labelContainer = document.createElement("div"); | |
276 | + | labelContainer.className = "setting-label"; | |
277 | + | const labelElement = document.createElement("span"); | |
278 | + | labelElement.className = "setting-label-text"; | |
279 | + | labelElement.textContent = label; | |
280 | + | const helpIcon = document.createElement("span"); | |
281 | + | helpIcon.textContent = "?"; | |
282 | + | helpIcon.className = "help-icon tooltip"; | |
283 | + | const tooltipSpan = document.createElement("span"); | |
284 | + | tooltipSpan.className = "tooltiptext"; | |
285 | + | tooltipSpan.innerHTML = tooltipText; | |
286 | + | helpIcon.appendChild(tooltipSpan); | |
287 | + | labelContainer.appendChild(labelElement); | |
288 | + | labelContainer.appendChild(helpIcon); | |
289 | + | const inputContainer = document.createElement("div"); | |
290 | + | inputContainer.className = "setting-input"; | |
291 | + | setInterval(() => { | |
292 | + | const claimButton = document.querySelector( | |
293 | + | "button.kit-button.is-large.is-drop.is-fill.button.is-done" | |
294 | + | ); | |
295 | + | const startFarmingButton = document.querySelector( | |
296 | + | "button.kit-button.is-large.is-primary.is-fill.button" | |
297 | + | ); | |
298 | + | if (claimButton) { | |
299 | + | claimButton.click(); | |
300 | + | } else if (startFarmingButton) { | |
301 | + | startFarmingButton.click(); | |
302 | + | } | |
303 | + | }, Math.floor(Math.random() * 5000) + 5000); | |
304 | + | let input; | |
305 | + | if (type === "checkbox") { | |
306 | + | input = document.createElement("input"); | |
307 | + | input.type = "checkbox"; | |
308 | + | input.id = id; | |
309 | + | input.checked = GAME_SETTINGS[id]; | |
310 | + | input.addEventListener("change", (e) => { | |
311 | + | GAME_SETTINGS[id] = e.target.checked; | |
312 | + | saveSettings(); | |
313 | + | }); | |
314 | + | inputContainer.appendChild(input); | |
315 | + | } else { | |
316 | + | input = document.createElement("input"); | |
317 | + | input.type = type; | |
318 | + | input.id = id; | |
319 | + | input.min = min; | |
320 | + | input.max = max; | |
321 | + | input.step = step; | |
322 | + | input.value = GAME_SETTINGS[id]; | |
323 | + | input.className = "setting-slider"; | |
324 | + | const valueDisplay = document.createElement("span"); | |
325 | + | valueDisplay.id = `${id}Display`; | |
326 | + | valueDisplay.textContent = GAME_SETTINGS[id]; | |
327 | + | valueDisplay.className = "setting-value"; | |
328 | + | input.addEventListener("input", (e) => { | |
329 | + | GAME_SETTINGS[id] = parseFloat(e.target.value); | |
330 | + | valueDisplay.textContent = e.target.value; | |
331 | + | saveSettings(); | |
332 | + | }); | |
333 | + | inputContainer.appendChild(input); | |
334 | + | inputContainer.appendChild(valueDisplay); | |
335 | + | } | |
336 | + | container.appendChild(labelContainer); | |
337 | + | container.appendChild(inputContainer); | |
338 | + | return container; | |
339 | + | } | |
340 | + | function saveSettings() { | |
341 | + | localStorage.setItem( | |
342 | + | "BlumAutoclickerSettings", | |
343 | + | JSON.stringify(GAME_SETTINGS) | |
344 | + | ); | |
345 | + | } | |
346 | + | function loadSettings() { | |
347 | + | const savedSettings = localStorage.getItem("BlumAutoclickerSettings"); | |
348 | + | if (savedSettings) { | |
349 | + | const parsedSettings = JSON.parse(savedSettings); | |
350 | + | GAME_SETTINGS = { ...GAME_SETTINGS, ...parsedSettings }; | |
351 | + | } | |
352 | + | } | |
353 | + | loadSettings(); | |
354 | + | updateSettingsMenu(); | |
355 | + | function toggleGamePause() { | |
356 | + | isGamePaused = !isGamePaused; | |
357 | + | pauseResumeButton.textContent = isGamePaused ? "Resume" : "Pause"; | |
358 | + | pauseResumeButton.style.backgroundColor = isGamePaused | |
359 | + | ? "#e5c07b" | |
360 | + | : "#98c379"; | |
361 | + | } | |
362 | + | } catch (e) { | |
363 | + | console.error("Blum Autoclicker error:", e); | |
364 | + | } |
Newer
Older