hownz
Version:
Safely clean the copied text of hidden surprises. Checks for invisible code, hidden watermarks, and tracking symbols.
597 lines (559 loc) • 49.8 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Remove hidden code, secret symbols, and AI marks and earn Dopamine Dash Coins.</title>
<meta name="description" content="Learn how the coin reward system works. Earn Dopamine Dash Coins by cleaning text, customizing your experience, and for work on AI output, coin will be on the Solana network.">
<meta name="keywords" content="earn bonus, crypto coin, protect from hackers, Solana, Dopamine, Dash, coin rewards, new currency, get safe, rewards, Solana clean, remove hidden">
<meta name="theme-color" content="#1E1E1E">
<link rel="manifest" href="manifest.json">
<meta name="msapplication-config" content="browserconfig.xml">
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#c5b358">
<link rel="icon" href="favicon.ico" sizes="any">
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
<link rel="icon" type="image/png" sizes="48x48" href="favicon-48x48.png">
<link rel="icon" type="image/png" sizes="96x96" href="favicon-96x96.png">
<link rel="icon" type="image/png" sizes="192x192" href="android-chrome-192x192.png">
<link rel="icon" type="image/png" sizes="512x512" href="android-chrome-512x512.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="httpss://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="index.css" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Article",
"headline": "How to Earn Dopamine Dash Coins",
"description": "Learn how the coin reward system works. Earn Dopamine Dash Coins by cleaning text, customizing your experience, and for work on AI output, coin will be on the Solana network.",
"image": "https://hownz.com/android-chrome-512x512.png",
"keywords": "earn bonus, crypto coin, protect from hackers, Solana, Dopamine, Dash, coin rewards, new currency, get safe, rewards, Solana clean, remove hidden",
"author": {
"@type": "Organization",
"name": "hownz.com",
"url": "https://hownz.com/"
},
"publisher": {
"@type": "Organization",
"name": "hownz.com",
"logo": {
"@type": "ImageObject",
"url": "https://hownz.com/android-chrome-512x512.png"
}
},
"datePublished": "2024-07-26",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://hownz.com/coins.html"
}
},
{
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Clean chat, Remove hidden code",
"item": "https://hownz.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Dopamine Dash Coin Earnings",
"item": "https://hownz.com/coins.html"
}
]
}
]
}
</script>
</head>
<body>
<div id="root">
<header class="site-header">
<div class="site-header-container">
<div class="header-left-side">
<div class="site-logo">
<a href="index.html">hownz.com</a>
</div>
<a href="hello.html" id="btn-hello-world" class="btn btn-special">Hello World!</a>
</div>
<div id="nav-wrapper" class="nav-wrapper">
<div class="header-actions">
<a href="coins.html" class="btn btn-rewards-info">Rewards info</a>
<div id="logged-in-controls" class="hidden">
<div class="coin-balance" title="Coins">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="24" height="24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-12h2v2h-2v-2zm-2 4h6v2H9v-2zm8-2c0-2.21-1.79-4-4-4s-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2h-2c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4h-2c0 1.1-.9 2-2 2s-2-.9-2-2h4c0-2.21-1.79-4-4-4z" /></svg>
<span id="coin-balance-display">0</span>
</div>
<button id="btn-logout" class="btn-logout">Logout</button>
</div>
<div id="logged-out-controls" class="header-login-container">
<form id="header-login-form" class="header-login-form">
<input
type="text"
id="login-username"
placeholder="account"
required
maxLength="5"
autoCapitalize="none"
/>
<input
type="password"
id="login-password"
placeholder="password"
required
maxLength="5"
autoCapitalize="none"
/>
<button type="submit" class="btn-login-register">Login/Register</button>
<a href="index.html#settings" class="settings-icon" title="Settings">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
<path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61-.25-1.17.59-1.69-.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24-.42-.12-.64l2 3.46c.12-.22.39.3.61-.22l2.49 1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49.42l.38-2.65c.61-.25 1.17.59 1.69.98l2.49 1c.23-.09.49 0 .61.22l2-3.46c.12-.22-.07.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/>
</svg>
</a>
</form>
<p class="login-hint">Account & Password: 5 small English letters.</p>
</div>
</div>
</div>
</div>
</header>
<div class="app-container">
<header class="app-header">
<h1><span role="img" aria-label="Rocket">🚀</span> Your Guide to Earning Dopamine Dash Coins</h1>
<h2>Learn how the coin reward system works. Earn Dopamine Dash Coins by cleaning text, customizing your experience, and for work on AI output, as the coin will be on the Solana network.</h2>
<p class="login-to-earn-note"><strong>Note:</strong> You must be logged in to earn coins. Rewards are only given for actions performed while signed into your account.</p>
</header>
<section class="coin-guide-section">
<h2 class="section-title">Your Quest to Earn</h2>
<ol class="quest-timeline">
<li class="quest-step" data-icon="1">
<h4 class="quest-step-title">The Spark</h4>
<p class="quest-step-desc">Your journey begins. Simply paste and process any text to instantly earn your first reward. Every action, no matter how small, has value.</p>
<div class="quest-step-reward">+1 Coin</div>
</li>
<li class="quest-step" data-icon="2">
<h4 class="quest-step-title">The Architect</h4>
<p class="quest-step-desc">Shape your tool. Customize the 'Approved' or 'Condense' character lists to fit your workflow and earn a constructor's bonus.</p>
<div class="quest-step-reward">+2 Coin Bonus</div>
</li>
<li class="quest-step" data-icon="3">
<h4 class="quest-step-title">The Artist</h4>
<p class="quest-step-desc">Personalize your experience. Change the font, size, or color of the output text to make the tool truly yours. A touch of class deserves a reward.</p>
<div class="quest-step-reward">+1 Coin Bonus</div>
</li>
<li class="quest-step" data-icon="4">
<h4 class="quest-step-title">The Investigator</h4>
<p class="quest-step-desc">Unlock the ultimate reward. Use the "Mark unrecognized characters" feature to see exactly what's being filtered. This is how you master the tool and earn big.</p>
<div class="quest-step-reward">+5 Coin Total Reward</div>
</li>
<li class="quest-step" data-icon="5">
<h4 class="quest-step-title">The Ambassador</h4>
<p class="quest-step-desc">Spread the word about safe text practices. Generate a unique referral link from the main page and earn a special reward.</p>
<div class="quest-step-reward">+10 Coins</div>
</li>
<li class="quest-step" data-icon="6">
<h4 class="quest-step-title">The Developer</h4>
<p class="quest-step-desc">For those who code. Install the tool globally via NPM from the main page to integrate it into your workflow and claim a significant reward for the installation.</p>
<div class="quest-step-reward">+15 Coins</div>
</li>
</ol>
</section>
<section class="cli-usage-section">
<h3><span role="img" aria-label="Terminal">💻</span> Command-Line Usage Guide</h3>
<p class="cli-usage-subheading">After completing the 'Developer' quest by installing the tool, you can use it from your command line. Here’s how:</p>
<div class="cli-commands-grid">
<div class="cli-command-item"><code>hownz "text"</code><p>Cleans a string → console output.</p></div>
<div class="cli-command-item"><code>hownz -a "text"</code><p>Cleans a string → random .txt file.</p></div>
<div class="cli-command-item"><code>echo "text" | hownz</code><p>Cleans piped text → random .txt file.</p></div>
<div class="cli-command-item"><code>hownz < in.txt --here</code><p>Redirects a file's content and forces output to the console, making it easy to pipe to other tools.</p></div>
<div class="cli-command-item"><code>hownz -s < file.txt</code><p>Sends a file's content to the Gemini API for summarization, saving the result to a new file automatically.</p></div>
<div class="cli-command-item"><code>hownz -m "text"</code><p>Marks unrecognized characters with '#'.</p></div>
<div class="cli-command-item"><code>hownz -l "text"</code><p>Includes language characters.</p></div>
<div class="cli-command-item"><code>hownz -e "text"</code><p>Includes emoji characters.</p></div>
<div class="cli-command-item"><code>hownz -le "ñ & 😀"</code><p>Combines flags for languages and emojis.</p></div>
<div class="cli-command-item"><code>hownz -sm < article.txt</code><p>Summarizes and marks a file's content.</p></div>
<div class="cli-command-item"><code>hownz -h</code><p>Displays the detailed help guide.</p></div>
</div>
</section>
<section class="coin-guide-section solana-horizon-section">
<h2><span role="img" aria-label="Galaxy">🌌</span> The Solana Horizon: From Our Tool to the Blockchain</h2>
<p>Every Dopamine Dash Coin you earn today is a step towards an exciting future. We're building a bridge to the <strong>Solana network</strong>, one of the fastest and most innovative blockchains. Your coins are more than just points-they're your stake in a growing ecosystem. The more you earn, the more you'll be a part of what comes next. Don't wait, the future is being built now.</p>
</section>
<section class="cta-quest-section">
<h2>Ready to Start Your Quest?</h2>
<p class="contact-subheading">Your journey to earning Dopamine Dash Coins begins with a single click. Go back to the tool, clean some text, and claim your first reward. Don't be patient, act!</p>
<a href="index.html" class="btn-cta-quest">Start Earning Now!</a>
</section>
<section class="internal-links-section">
<h2 class="internal-links-heading">Explore Our Network</h2>
<nav class="site-nav">
<ul id="nav-links-container" class="nav-links-relocated">
</ul>
</nav>
</section>
<section id="ctcs" class="contact-section">
<h2 class="contact-heading"><span role="img" aria-label="Mailbox">📫</span> Contact Us</h2>
<p class="contact-subheading">Have a suggestion, a question, or want to report an issue? We'd love to hear from you!</p>
<div class="contact-card">
<h3><span role="img" aria-label="New Zealand Flag">🇳🇿</span> Get in Touch</h3>
<p class="contact-link"><span role="img" aria-label="Email">📧</span> <strong>Email:</strong> <a href="mailto:dailybuddyapp.com@gmail.com">dailybuddyapp.com@gmail.com</a></p>
<p class="contact-link"><span role="img" aria-label="Telegram">✈️</span> <strong>Telegram:</strong> <a href="https://t.me/MeetUpNZ" target="_blank" rel="noopener noreferrer">@MeetUpNZ</a></p>
</div>
</section>
</div>
<footer class="site-footer-main">
<div id="footer-links-container" class="footer-links">
</div>
<button id="btn-claim-install" class="btn btn-claim-install">Explore</button>
<div class="site-search-container">
<form id="site-search-form" class="site-search-form">
<input type="search" id="site-search-input" class="site-search-input" placeholder="Search across our network...">
<button type="submit" class="site-search-button" aria-label="Search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M15.5 14h-.79l-.28-.27C14.41 12.59 15 11.11 15 9.5 15 5.91 12.09 3 8.5 3S2 5.91 2 9.5 4.91 16 8.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L19.49 19l-4.99-5zm-7 0C6.01 14 4 11.99 4 9.5S6.01 5 8.5 5 13 7.01 13 9.5 10.99 14 8.5 14z"/></svg>
</button>
</form>
</div>
<div class="footer-banner">
<div class="footer-v-stack">
<div id="date-time-display">
<span id="time-display" class="time"></span>
<span id="date-display" class="date"></span>
</div>
<a href="https://mfatnz.com" id="ip-ad-link">
<img src="https://ip.im/img" alt="My IP Address" width="185" height="50" />
</a>
</div>
<div class="footer-banner-text-content" style="text-align: left;">
<p style="margin: 0 0 0.5rem 0;"><span role="img" aria-label="Coin">🟡</span> Your progress is worth celebrating. Earn <strong>Dopamine Dash Coins</strong> as part of a fair system designed to support your <strong>motivation</strong>.</p>
<p style="margin: 0;">A free, non-commercial tool created in support of mfatnz.com Independent Initiative. A simple tool for the developer community.</p>
</div>
</div>
<div class="coin-logo-container">
<div class="coin-logo-animated">
<img src="logo.png" alt="Dopamine Dash Coin Logo" />
</div>
<h3>The Official Dopamine Dash Coin</h3>
<p>A dynamic reward for a dynamic user. This is what you earn. This is what you'll hold. Watch it grow.</p>
</div>
</footer>
</div>
<script type="module">
// This script contains the logic for the main page and other shared functionality.
// NOTE: This script is shared across multiple pages. It uses feature detection (e.g., if(element){...})
// to run page-specific code only when needed.
import { GoogleGenAI } from 'https://esm.sh/@google/genai';
document.addEventListener('DOMContentLoaded', async () => {
const updateDateTime = () => {
const timeDisplay = document.getElementById('time-display');
const dateDisplay = document.getElementById('date-display');
if (!timeDisplay || !dateDisplay) return;
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
timeDisplay.textContent = `${hours}:${minutes}`;
const options = { year: 'numeric', month: 'long', day: 'numeric' };
dateDisplay.textContent = now.toLocaleDateString(undefined, options);
};
updateDateTime();
setInterval(updateDateTime, 60000);
let currencyMap = [];
try {
const response = await fetch('usd.json');
if (!response.ok) throw new Error('Network response was not ok');
currencyMap = await response.json();
} catch (error) {
console.error('Failed to load currency data from usd.json:', error);
currencyMap = [
{"symbol": "£", "abbreviation": "GBP"}, {"symbol": "$", "abbreviation": "USD"},
{"symbol": "€", "abbreviation": "EUR"}, {"symbol": "¥", "abbreviation": "JPY"},
{"symbol": "₹", "abbreviation": "INR"}, {"symbol": "₽", "abbreviation": "RUB"},
{"symbol": "₩", "abbreviation": "KRW"}, {"symbol": "A$", "abbreviation": "AUD"},
{"symbol": "C$", "abbreviation": "CAD"}, {"symbol": "NZ$", "abbreviation": "NZD"}
];
}
const DEFAULT_APPROVED_CHARS = `'\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:,-.*[]!<>()?;&$@~/%^{}|\\-_=\t \r\nбвгджзклмнпрстфхцчшщаеёиоуыэюяБВГДЗКЛМНПРСТФХЙЧЩАЭЫОУЯЕИЁЮіўІЎґєєїҐЄЇāēīōūĀĒĪŌŪαβγδεζηθικλμνξοπρσςτυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ+-*/=≠<>≤≥≈∑∫∂π∞√∈∉∀∃∝∧∨¬⇒⇔≡∪∩⊂⊃⊆⊇∅∇×÷±∓∏∛∜∠⊥∥∋∌⊄⊅∊∉iːɪeæʌɑːɒɔːʊuːəɜːeɪaɪɔɪəʊaʊɪəeəʊəpbtbd tʃdʒkgfvθðszʃʒhmnŋlrwjIVXLCDMivxlcdm`;
const DEFAULT_CONDENSE_CHARS = "*?!,-:;#`\t";
const DEFAULT_FONT_FAMILY = "'Roboto', sans-serif";
const DEFAULT_FONT_SIZE = "1";
const DEFAULT_FONT_COLOR = "#E0E0E0";
const DEFAULT_IS_BOLD = !1;
const DEFAULT_MARK_UNRECOGNIZED = !1;
const LS_KEY_MARK = 'clearedTextMarkUnrecognized';
const LS_KEY_CHARS = 'clearedTextApprovedChars';
const LS_KEY_CONDENSE = 'clearedTextCondenseChars';
const LS_KEY_FONT_FAMILY = 'clearedTextFontFamily';
const LS_KEY_FONT_SIZE = 'clearedTextFontSize';
const LS_KEY_FONT_COLOR = 'clearedTextFontColor';
const LS_KEY_IS_BOLD = 'clearedTextIsBold';
const LS_KEY_USERS = 'clearedTextUsers';
const LS_KEY_CURRENT_USER = 'clearedTextCurrentUser';
const LS_KEY_PERSONAL_API_KEY = 'clearedTextPersonalApiKey';
const RATE_LIMIT_KEY = 'hownzApiTimestamps';
const MAX_CALLS_PER_MINUTE = 20;
const ONE_MINUTE_MS = 60 * 1000;
const navLinks = [{href: "https://actnz.com/", text: "Planner", target: "_blank"}, {href: "https://mfatnz.com/", text: "Token Counter", target: "_blank"}, {href: "https://actnz.com/coins.html", text: "Coins", target: "_blank"}, {href: "https://irdnz.com/", text: "NZ Finances", target: "_blank"}, {href: "https://irdnz.com/bonds.html", text: "Bond Market Tips", target: "_blank"}];
const footerLinks = [{href: "https://mfatnz.com/", text: "mfatnz.com"}, {href: "https://actnz.com", text: "actnz.com"}, {href: "https://irdnz.com", text: "irdnz.com"}, {href: "https://hownz.com", text: "hownz.com"}, {href: "coins.html", text: "Rewards info"}];
const dom = {
navLinksContainer: document.getElementById('nav-links-container') || document.querySelector('.nav-links-relocated'),
footerLinksContainer: document.getElementById('footer-links-container'),
loggedInControls: document.getElementById('logged-in-controls'),
loggedOutControls: document.getElementById('logged-out-controls'),
loginForm: document.getElementById('header-login-form'),
loginUsernameInput: document.getElementById('login-username'),
loginPasswordInput: document.getElementById('login-password'),
logoutButton: document.getElementById('btn-logout'),
coinBalanceDisplay: document.getElementById('coin-balance-display'),
siteSearchForm: document.getElementById('site-search-form'),
siteSearchInput: document.getElementById('site-search-input'),
// Page-specific elements (will be null on pages where they don't exist)
markUnrecognizedCheck: document.getElementById('mark-unrecognized'),
textInput: document.getElementById('text-input'),
clearedOutput: document.getElementById('cleared-output'),
btnCollectCoins: document.getElementById('btn-collect-coins'),
approvedCharsInput: document.getElementById('approved-chars-input'),
condenseCharsInput: document.getElementById('condense-chars-input'),
saveConfigButton: document.getElementById('btn-save-config'),
resetDefaultsButton: document.getElementById('btn-reset-defaults'),
saveFeedback: document.getElementById('save-feedback'),
fontFamilySelect: document.getElementById('font-family-select'),
fontSizeInput: document.getElementById('font-size-input'),
fontColorInput: document.getElementById('font-color-input'),
isBoldCheck: document.getElementById('font-weight-bold'),
facebookShareBtn: document.getElementById('facebook-share-btn'),
telegramShareBtn: document.getElementById('telegram-share-btn'),
btnGenerateReferral: document.getElementById('btn-generate-referral'),
referralLinkWrapper: document.getElementById('referral-link-wrapper'),
referralLinkInput: document.getElementById('referral-link-input'),
btnCopyReferral: document.getElementById('btn-copy-referral'),
referralFeedback: document.getElementById('referral-feedback'),
btnSaveTxt: document.getElementById('btn-save-txt'),
btnHelloWorld: document.getElementById('btn-hello-world'),
btnClaimInstall: document.getElementById('btn-claim-install'),
btnSummarize: document.getElementById('btn-summarize'),
apiKeyForm: document.getElementById('api-key-form'),
personalApiKeyInput: document.getElementById('personal-api-key-input'),
apiKeyFeedback: document.getElementById('api-key-feedback'),
btnCopyNpmCommand: document.getElementById('btn-copy-npm-command'),
btnCopyDirectCommand: document.getElementById('btn-copy-direct-command')
};
const getStoredValue = (key, fallback, isBoolean = !1) => {const value = localStorage.getItem(key); if (value === null) return fallback; if (isBoolean) return value === 'true'; if (typeof fallback === 'number') { const num = parseFloat(value); return isNaN(num) ? fallback : num } return value };
const _getUsersData = () => { const data = localStorage.getItem(LS_KEY_USERS); return data ? JSON.parse(data) : {} };
const _saveUsersData = data => { localStorage.setItem(LS_KEY_USERS, JSON.stringify(data)) };
let _currentUser = getStoredValue(LS_KEY_CURRENT_USER, null);
const authManager = {
isAuthenticated: () => !!_currentUser,
getCurrentUser: () => _currentUser,
loginOrRegister: (username, password) => {
if (!username || !password) return { success: !1, message: 'Username and password required.' };
const usersData = _getUsersData();
if (usersData[username]) {
if (usersData[username].password === password) { _currentUser = username; localStorage.setItem(LS_KEY_CURRENT_USER, username); return { success: !0, message: 'Login successful.', isNewUser: !1 } }
else { return { success: !1, message: 'Incorrect password.' } }
} else {
usersData[username] = { password: password, coins: 0 };
_saveUsersData(usersData);
_currentUser = username;
localStorage.setItem(LS_KEY_CURRENT_USER, username);
return { success: !0, message: 'Registration successful.', isNewUser: !0 }
}
},
logout: () => { _currentUser = null; localStorage.removeItem(LS_KEY_CURRENT_USER); updateUI(); }
};
const coinManager = {
getBalance: () => { if (!authManager.isAuthenticated()) return 0; const usersData = _getUsersData(); const currentUser = authManager.getCurrentUser(); return usersData[currentUser]?.coins || 0 },
addCoins: amount => { if (!authManager.isAuthenticated() || amount <= 0) return; const usersData = _getUsersData(); const currentUser = authManager.getCurrentUser(); if (usersData[currentUser]) { usersData[currentUser].coins = (usersData[currentUser].coins || 0) + amount; _saveUsersData(usersData) } }
};
let state = {
inputText: '',
markUnrecognized: getStoredValue(LS_KEY_MARK, DEFAULT_MARK_UNRECOGNIZED, !0),
approvedChars: getStoredValue(LS_KEY_CHARS, DEFAULT_APPROVED_CHARS),
condenseChars: getStoredValue(LS_KEY_CONDENSE, DEFAULT_CONDENSE_CHARS),
fontFamily: getStoredValue(LS_KEY_FONT_FAMILY, DEFAULT_FONT_FAMILY),
fontSize: getStoredValue(LS_KEY_FONT_SIZE, DEFAULT_FONT_SIZE),
fontColor: getStoredValue(LS_KEY_FONT_COLOR, DEFAULT_FONT_COLOR),
isBold: getStoredValue(LS_KEY_IS_BOLD, DEFAULT_IS_BOLD, !0),
rewardGivenForInput: !1,
appearanceChanged: !1,
configChanged: !1,
referralLinkGenerated: !1,
pendingReward: 0,
helloClicked: sessionStorage.getItem('helloClicked') === 'true',
txtSaved: sessionStorage.getItem('txtSaved') === 'true',
installClaimed: sessionStorage.getItem('installClaimed') === 'true',
isSummarizing: false,
personalApiKey: getStoredValue(LS_KEY_PERSONAL_API_KEY, '')
};
const checkRateLimit = () => {
const now = Date.now();
const timestamps = JSON.parse(sessionStorage.getItem(RATE_LIMIT_KEY) || '[]');
const recentTimestamps = timestamps.filter(ts => now - ts < ONE_MINUTE_MS);
if (recentTimestamps.length >= MAX_CALLS_PER_MINUTE) {
return false;
}
recentTimestamps.push(now);
sessionStorage.setItem(RATE_LIMIT_KEY, JSON.stringify(recentTimestamps));
return true;
};
const generateRandomString = () => { const digits = '012356789'; return digits.charAt(Math.floor(Math.random() * digits.length)); };
const showCollectFeedback = amount => { const feedbackEl = document.createElement('span'); feedbackEl.textContent = `+${amount} Coins!`; feedbackEl.className = 'collect-feedback-animation'; const container = dom.clearedOutput ? dom.clearedOutput.parentElement : document.body; if (container) { container.style.position = 'relative'; container.appendChild(feedbackEl); setTimeout(() => { feedbackEl.remove() }, 1500) } };
const calculateAndSetPendingReward = () => { if (!authManager.isAuthenticated() || !dom.textInput || state.inputText.length === 0 || state.rewardGivenForInput) { state.pendingReward = 0; return } let reward = 1; if (state.appearanceChanged) reward += 1; if (state.configChanged) reward += 2; if (state.markUnrecognized) reward += 4; state.pendingReward = reward };
const handleCurrencySymbols = (text) => {
if (!currencyMap || currencyMap.length === 0) return text;
const escapeRegex = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
const sortedCurrencies = [...currencyMap].sort((a, b) => b.symbol.length - a.symbol.length);
let processedText = text;
sortedCurrencies.forEach(({ symbol }) => {
const escapedSymbol = escapeRegex(symbol);
const consecutiveRegex = new RegExp(`(?:${escapedSymbol}){2,}`, 'g');
processedText = processedText.replace(consecutiveRegex, '');
});
sortedCurrencies.forEach(({ symbol, abbreviation }) => {
const escapedSymbol = escapeRegex(symbol);
const singleRegex = new RegExp(escapedSymbol, 'g');
processedText = processedText.replace(singleRegex, abbreviation);
});
return processedText;
};
const expandContractions = text => {
const contractions = { "couldn't've": "could not have", "mightn't've": "might not have", "mustn't've": "must not have", "shouldn't've": "should not have", "wouldn't've": "would not have", "i'm": "i am", "you're": "you are", "he's": "he is", "she's": "she is", "it's": "it is", "we're": "we are", "they're": "they are", "i've": "i have", "you've": "you have", "we've": "we have", "they've": "they have", "i'd": "i would", "you'd": "you would", "he'd": "he would", "she'd": "she would", "it'd": "it would", "we'd": "we would", "they'd": "they would", "i'll": "i will", "you'll": "you will", "he'll": "he will", "she'll": "she will", "it'll": "it will", "we'll": "we will", "they'll": "they will", "don't": "do not", "doesn't": "does not", "didn't": "did not", "isn't": "is not", "aren't": "are not", "wasn't": "was not", "weren't": "were not", "haven't": "have not", "hasn't": "has not", "hadn't": "had not", "won't": "will not", "wouldn't": "would not", "can't": "cannot", "couldn't": "could not", "shouldn't": "should not", "mightn't": "might not", "mustn't": "must not", "shan't": "shall not", "let's": "let us", "that's": "that is", "there's": "there is", "here's": "here is", "what's": "what is", "where's": "where is", "when's": "when is", "why's": "why is", "how's": "how is", "who's": "who is", "gonna": "going to", "wanna": "want to", "gotcha": "got you", "kinda": "kind of", "sorta": "sort of", "dunno": "don't know" };
let processedText = text.replace(/[’]/g, "'");
const contractionKeys = Object.keys(contractions).sort((a, b) => b.length - a.length);
const regex = new RegExp(`\\b(${contractionKeys.join("|")})\\b`, "gi");
return processedText.replace(regex, match => { const expansion = contractions[match.toLowerCase()]; if (match === match.toUpperCase()) { return expansion.toUpperCase(); } if (match[0] === match[0].toUpperCase()) { return expansion.charAt(0).toUpperCase() + expansion.slice(1); } return expansion; });
};
const updateClearedText = () => { if (!dom.clearedOutput) return; let textToProcess = state.inputText; textToProcess = handleCurrencySymbols(textToProcess); textToProcess = expandContractions(textToProcess); const phrasesToRemoveRegex = /\b(Here is|Let me know|you are)\b/gi; textToProcess = textToProcess.replace(phrasesToRemoveRegex, ''); textToProcess = textToProcess.replace(/—/g, ' - '); textToProcess = textToProcess.replace(/['"]{2,}/g, ''); const approvedSet = new Set(Array.from(state.approvedChars)); let result = ''; for (const char of textToProcess) { if (approvedSet.has(char)) { result += char } else if (state.markUnrecognized) { result += '#' } } if (state.condenseChars) { const escapedChars = state.condenseChars.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); if (escapedChars) { const condenseRegex = new RegExp(`([${escapedChars}])\\1+`, 'g'); result = result.replace(condenseRegex, '$1') } } result = result.replace(/ {2,}/g, ' '); result = result.replace(/#{2,}/g, '#'); dom.clearedOutput.value = result.trim(); calculateAndSetPendingReward(); updateUI(); };
const updateUI = () => {
const isAuthenticated = authManager.isAuthenticated();
if(dom.loggedInControls) dom.loggedInControls.classList.toggle('hidden', !isAuthenticated);
if(dom.loggedOutControls) dom.loggedOutControls.classList.toggle('hidden', isAuthenticated);
if(dom.coinBalanceDisplay) dom.coinBalanceDisplay.textContent = coinManager.getBalance();
if (dom.btnCollectCoins) { if (isAuthenticated && state.pendingReward > 0) { dom.btnCollectCoins.disabled = !1; dom.btnCollectCoins.textContent = `Collect +${state.pendingReward}` } else { dom.btnCollectCoins.disabled = !0; dom.btnCollectCoins.textContent = 'Collect Coins' } }
if(dom.markUnrecognizedCheck) dom.markUnrecognizedCheck.checked = state.markUnrecognized;
if(dom.textInput) dom.textInput.value = state.inputText;
if(dom.approvedCharsInput) dom.approvedCharsInput.value = state.approvedChars;
if(dom.condenseCharsInput) dom.condenseCharsInput.value = state.condenseChars;
if(dom.fontFamilySelect) dom.fontFamilySelect.value = state.fontFamily;
if(dom.fontSizeInput) dom.fontSizeInput.value = state.fontSize;
if(dom.fontColorInput) dom.fontColorInput.value = state.fontColor;
if(dom.isBoldCheck) dom.isBoldCheck.checked = state.isBold;
if (dom.clearedOutput) { dom.clearedOutput.style.fontFamily = state.fontFamily; dom.clearedOutput.style.fontSize = `${state.fontSize}rem`; dom.clearedOutput.style.color = state.fontColor; dom.clearedOutput.style.fontWeight = state.isBold ? 'bold' : 'normal' }
if (dom.personalApiKeyInput) { dom.personalApiKeyInput.value = state.personalApiKey; }
if (dom.btnSummarize) {
if(state.isSummarizing) {
dom.btnSummarize.innerHTML = `<span class="spinner"></span> Summarizing...`;
dom.btnSummarize.disabled = true;
} else {
dom.btnSummarize.innerHTML = `✨ Summarize with AI`;
dom.btnSummarize.disabled = !dom.clearedOutput || !dom.clearedOutput.value.trim();
}
}
};
const handleAppearanceChange = updateAction => { updateAction(); state.appearanceChanged = !0; if (dom.textInput) updateClearedText(); updateUI() };
const generateContent = () => {
if (dom.navLinksContainer) dom.navLinksContainer.innerHTML = navLinks.map(link => `<li><a href="${link.href}" ${link.target ? 'target="_blank" rel="noopener noreferrer"' : ''}>${link.text}</a></li>`).join('');
if (dom.footerLinksContainer) dom.footerLinksContainer.innerHTML = footerLinks.map(link => `<a href="${link.href}" target="_blank" rel="noopener noreferrer">${link.text}</a>`).join('');
const pageUrl = 'https://hownz.com/'; const shareText = 'Clean your copied text from hidden code and AI watermarks with this free tool!';
if (dom.facebookShareBtn) dom.facebookShareBtn.href = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(pageUrl)}`;
if (dom.telegramShareBtn) dom.telegramShareBtn.href = `https://t.me/share/url?url=${encodeURIComponent(pageUrl)}&text=${encodeURIComponent(shareText)}`
};
if(dom.siteSearchForm) { dom.siteSearchForm.addEventListener('submit', e => { e.preventDefault(); const query = dom.siteSearchInput.value.trim(); if (!query) return; const sites = ['mfatnz.com', 'actnz.com', 'irdnz.com', 'hownz.com']; const siteQuery = sites.map(site => `site:${site}`).join(' OR '); const fullQuery = `${query} ${siteQuery}`; const searchUrl = `https://www.google.com/search?q=${encodeURIComponent(fullQuery)}`; window.open(searchUrl, '_blank') }) }
if(dom.loginUsernameInput) { dom.loginUsernameInput.addEventListener('input', e => { const input = e.target; input.value = input.value.toLowerCase(); const usersData = _getUsersData(); const username = input.value; const submitButton = dom.loginForm.querySelector('button[type="submit"]'); if (!submitButton) return; if (username.length > 0) { if (usersData[username]) { submitButton.textContent = 'Login' } else { submitButton.textContent = 'Register' } } else { submitButton.textContent = 'Login/Register' } }) }
if(dom.loginPasswordInput) { dom.loginPasswordInput.addEventListener('input', e => { e.target.value = e.target.value.toLowerCase() }) }
if(dom.loginForm) { dom.loginForm.addEventListener('submit', e => { e.preventDefault(); const result = authManager.loginOrRegister(dom.loginUsernameInput.value, dom.loginPasswordInput.value); if (result.success) { dom.loginUsernameInput.value = ''; dom.loginPasswordInput.value = ''; updateUI(); const submitButton = dom.loginForm.querySelector('button[type="submit"]'); if (submitButton) { submitButton.textContent = 'Login/Register' } } else { dom.loginPasswordInput.value = ''; dom.loginForm.classList.add('shake'); const loginHint = dom.loggedOutControls.querySelector('.login-hint'); if (loginHint) { const originalHint = "Account & Password: 5 small English letters."; loginHint.textContent = result.message; loginHint.style.color = 'var(--error-color)'; setTimeout(() => { loginHint.textContent = originalHint; loginHint.style.color = '' }, 3000) } setTimeout(() => dom.loginForm.classList.remove('shake'), 500) } }) }
if(dom.logoutButton) { dom.logoutButton.addEventListener('click', () => { authManager.logout() }) }
// Page-specific listeners
if(dom.btnCollectCoins) { dom.btnCollectCoins.addEventListener('click', () => { if (state.pendingReward > 0 && authManager.isAuthenticated()) { coinManager.addCoins(state.pendingReward); showCollectFeedback(state.pendingReward); state.rewardGivenForInput = !0; state.pendingReward = 0; updateUI() } }) }
if(dom.textInput) { dom.textInput.addEventListener('input', e => { state.inputText = e.target.value; if (state.inputText.length === 0) { state.rewardGivenForInput = !1; state.appearanceChanged = !1; state.configChanged = !1; state.pendingReward = 0 } updateClearedText(); }) }
if(dom.markUnrecognizedCheck) { dom.markUnrecognizedCheck.addEventListener('change', e => { state.markUnrecognized = e.target.checked; localStorage.setItem(LS_KEY_MARK, state.markUnrecognized); updateClearedText(); }) }
if(dom.approvedCharsInput) { dom.approvedCharsInput.addEventListener('input', e => { state.approvedChars = e.target.value; state.configChanged = !0; localStorage.setItem(LS_KEY_CHARS, state.approvedChars); updateClearedText(); }) }
if(dom.condenseCharsInput) { dom.condenseCharsInput.addEventListener('input', e => { state.condenseChars = e.target.value; state.configChanged = !0; localStorage.setItem(LS_KEY_CONDENSE, state.condenseChars); updateClearedText(); }) }
if (dom.fontFamilySelect) { dom.fontFamilySelect.addEventListener('change', e => handleAppearanceChange(() => { state.fontFamily = e.target.value; localStorage.setItem(LS_KEY_FONT_FAMILY, state.fontFamily) })) }
if (dom.fontSizeInput) { dom.fontSizeInput.addEventListener('input', e => handleAppearanceChange(() => { state.fontSize = e.target.value; localStorage.setItem(LS_KEY_FONT_SIZE, state.fontSize) })) }
if (dom.fontColorInput) { dom.fontColorInput.addEventListener('input', e => handleAppearanceChange(() => { state.fontColor = e.target.value; localStorage.setItem(LS_KEY_FONT_COLOR, state.fontColor) })) }
if (dom.isBoldCheck) { dom.isBoldCheck.addEventListener('change', e => handleAppearanceChange(() => { state.isBold = e.target.checked; localStorage.setItem(LS_KEY_IS_BOLD, state.isBold) })) }
if (dom.saveConfigButton) { dom.saveConfigButton.addEventListener('click', () => { dom.saveFeedback.textContent = 'Settings saved!'; dom.saveFeedback.style.color = 'var(--success-color)'; dom.saveFeedback.style.opacity = 1; setTimeout(() => { dom.saveFeedback.style.opacity = 0; }, 2000) }) }
if (dom.resetDefaultsButton) { dom.resetDefaultsButton.addEventListener('click', () => { state.approvedChars = DEFAULT_APPROVED_CHARS; state.condenseChars = DEFAULT_CONDENSE_CHARS; state.markUnrecognized = DEFAULT_MARK_UNRECOGNIZED; localStorage.setItem(LS_KEY_CHARS, state.approvedChars); localStorage.setItem(LS_KEY_CONDENSE, state.condenseChars); localStorage.setItem(LS_KEY_MARK, state.markUnrecognized); handleAppearanceChange(() => { state.fontFamily = DEFAULT_FONT_FAMILY; state.fontSize = DEFAULT_FONT_SIZE; state.fontColor = DEFAULT_FONT_COLOR; state.isBold = DEFAULT_IS_BOLD; localStorage.setItem(LS_KEY_FONT_FAMILY, state.fontFamily); localStorage.setItem(LS_KEY_FONT_SIZE, state.fontSize); localStorage.setItem(LS_KEY_FONT_COLOR, state.fontColor); localStorage.setItem(LS_KEY_IS_BOLD, state.isBold) }); updateClearedText(); updateUI(); }) }
if(dom.btnGenerateReferral) { dom.btnGenerateReferral.addEventListener('click', () => { if (!authManager.isAuthenticated()) { dom.referralFeedback.textContent = 'You must be logged in to generate a link.'; dom.referralFeedback.style.color = 'var(--error-color)'; return } if (state.referralLinkGenerated) { dom.referralFeedback.textContent = 'You have already generated a link for this session.'; dom.referralFeedback.style.color = 'var(--text-color-secondary)'; return } const randomId = generateRandomString(); const referralLink = `https://hownz.com/index.html?${randomId}#why-critical`; dom.referralLinkInput.value = referralLink; dom.referralLinkWrapper.classList.remove('hidden'); coinManager.addCoins(10); state.referralLinkGenerated = !0; dom.coinBalanceDisplay.textContent = coinManager.getBalance(); dom.referralFeedback.textContent = 'Link generated! +10 Coins awarded.'; dom.referralFeedback.style.color = 'var(--success-color)'; dom.btnGenerateReferral.disabled = !0 }) }
if(dom.btnCopyReferral) { dom.btnCopyReferral.addEventListener('click', () => { navigator.clipboard.writeText(dom.referralLinkInput.value).then(() => { dom.referralFeedback.textContent = 'Copied to clipboard!'; setTimeout(() => { if (state.referralLinkGenerated) { dom.referralFeedback.textContent = 'Link generated! +10 Coins awarded.' } }, 2000) }).catch(err => { console.error('Failed to copy: ', err); dom.referralFeedback.textContent = 'Failed to copy link.'; dom.referralFeedback.style.color = 'var(--error-color)' }) }) }
if (dom.apiKeyForm) { dom.apiKeyForm.addEventListener('submit', e => { e.preventDefault(); state.personalApiKey = dom.personalApiKeyInput.value; localStorage.setItem(LS_KEY_PERSONAL_API_KEY, state.personalApiKey); dom.apiKeyFeedback.textContent = 'API Key saved locally.'; dom.apiKeyFeedback.style.color = 'var(--success-color)'; setTimeout(() => { dom.apiKeyFeedback.textContent = ''; }, 3000) }) }
if(dom.btnSummarize) { dom.btnSummarize.addEventListener('click', async () => { if (state.isSummarizing || !dom.clearedOutput.value.trim()) return; if (!checkRateLimit()) { dom.clearedOutput.value = `Error: API call limit reached (20 per minute). Please try again later or use your own API key.`; return; } state.isSummarizing = true; updateUI(); try { const apiKey = state.personalApiKey || 'AIzaSyCOe7OULVTGsDF4S5hhNkow0iNjNL53hI8'; if (!apiKey) { throw new Error('API key is not available.'); } const ai = new GoogleGenAI({ apiKey }); const prompt = `Please provide a concise summary of the following text:\n\n${dom.clearedOutput.value}`; const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: prompt }); dom.clearedOutput.value = `Gemini Generated Summary:\n\n${response.text.trim()}`; } catch (error) { if (dom.clearedOutput) dom.clearedOutput.value = `Error summarizing text: ${error.message}`; } finally { state.isSummarizing = false; updateUI(); } }); }
if (dom.btnClaimInstall) { if (state.installClaimed) { dom.btnClaimInstall.disabled = true; dom.btnClaimInstall.textContent = 'Reward Claimed'; } dom.btnClaimInstall.addEventListener('click', () => { if (authManager.isAuthenticated() && !state.installClaimed) { coinManager.addCoins(15); state.installClaimed = true; sessionStorage.setItem('installClaimed', 'true'); dom.btnClaimInstall.disabled = true; dom.btnClaimInstall.textContent = 'Reward Claimed'; updateUI(); showCollectFeedback(15); } else if (!authManager.isAuthenticated()) { const originalText = dom.btnClaimInstall.textContent; dom.btnClaimInstall.textContent = 'Please Login to Claim'; setTimeout(() => { if (!state.installClaimed) { dom.btnClaimInstall.textContent = originalText; } }, 2000); } }); }
if (dom.btnHelloWorld) { dom.btnHelloWorld.addEventListener('click', () => { if (authManager.isAuthenticated() && !state.helloClicked) { coinManager.addCoins(1); state.helloClicked = true; sessionStorage.setItem('helloClicked', 'true'); updateUI(); }}); }
if (dom.btnSaveTxt) { dom.btnSaveTxt.addEventListener('click', () => { const textToSave = dom.clearedOutput.value; if (!textToSave.trim()) return; if (authManager.isAuthenticated() && !state.txtSaved) { coinManager.addCoins(1); state.txtSaved = true; sessionStorage.setItem('txtSaved', 'true'); updateUI(); } const blob = new Blob([textToSave], { type: 'text/plain;charset=utf-8' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; const randomNumber = Math.floor(Math.random() * (1588 - 100 + 1)) + 100; link.download = `1-hownz.com-${randomNumber}.txt`; document.body.appendChild(link); link.click(); document.body.removeChild(link); URL.revokeObjectURL(url) }) }
const addCharsFromDictionary = async (filePath, feedbackNoun) => {
if (!dom.approvedCharsInput || !dom.saveFeedback) return;
try {
const response = await fetch(filePath);
if (!response.ok) throw new Error(`Failed to load ${feedbackNoun} dictionary`);
const dictionary = await response.json();
const currentCharsSet = new Set(Array.from(state.approvedChars));
let newChars = [];
const allDictValues = Object.values(dictionary).flat();
for (const item of allDictValues) {
if (typeof item === 'string') {
for (const char of Array.from(item)) {
if (!currentCharsSet.has(char)) {
currentCharsSet.add(char);
newChars.push(char);
}
}
}
}
if (newChars.length > 0) {
state.approvedChars += newChars.join('');
localStorage.setItem(LS_KEY_CHARS, state.approvedChars);
state.configChanged = true;
updateClearedText();
dom.saveFeedback.textContent = `${feedbackNoun.charAt(0).toUpperCase() + feedbackNoun.slice(1)} characters added!`;
dom.saveFeedback.style.color = 'var(--success-color)';
} else {
dom.saveFeedback.textContent = `All ${feedbackNoun} characters already present.`;
dom.saveFeedback.style.color = 'var(--text-color-secondary)';
}
} catch (error) {
console.error(`Error loading ${feedbackNoun} dictionary:`, error);
dom.saveFeedback.textContent = `Error loading ${feedbackNoun}!`;
dom.saveFeedback.style.color = 'var(--error-color)';
}
dom.saveFeedback.style.opacity = 1;
setTimeout(() => {
dom.saveFeedback.style.opacity = 0;
}, 2000);
};
if (dom.btnAddFromDictionary) {
dom.btnAddFromDictionary.addEventListener('click', () => addCharsFromDictionary('app.json', 'language'));
}
if (dom.btnAddEmojis) {
dom.btnAddEmojis.addEventListener('click', () => addCharsFromDictionary('admin.json', 'emoji'));
}
const setupCopyButton = (button, commandText) => {
if (button) {
button.addEventListener('click', () => {
navigator.clipboard.writeText(commandText).then(() => {
const originalText = button.textContent;
button.textContent = 'Copied!';
setTimeout(() => {
button.textContent = originalText;
}, 2000);
}).catch(err => {
console.error('Failed to copy command: ', err);
});
});
}
};
setupCopyButton(dom.btnCopyNpmCommand, 'npm install -g hownz');
setupCopyButton(dom.btnCopyDirectCommand, 'npm install -g https://hownz.com/hownz-2.0.0.tgz');
const initialize = () => { generateContent(); if(dom.textInput) updateClearedText(); updateUI(); };
initialize();
});
</script>
<script type="module" src="/index.tsx"></script>
</body>
</html>