From 1d5b72fe8309ea04830fbb958eb3fa802a43dc71 Mon Sep 17 00:00:00 2001 From: ody Date: Tue, 2 Dec 2025 22:25:54 +0700 Subject: [PATCH] update html login js proses upbal sql json --- .vscode/settings.json | 4 + html.php | 72 +++++++ loginn.php | 113 +++++++---- ody git.js | 458 +++++++++++++++++++++--------------------- prosestopup.php | 54 +++++ upbalance.php | 27 +++ users.sql | 20 ++ 7 files changed, 476 insertions(+), 272 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 prosestopup.php create mode 100644 upbalance.php diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ba2a6c0 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.pythonProjects": [] +} \ No newline at end of file diff --git a/html.php b/html.php index 7bec743..1d0c0d9 100644 --- a/html.php +++ b/html.php @@ -1,4 +1,76 @@ + + + + + + Blackjack [21] - OCA GameHub + + + + + +
+
+

Blackjack [21]

+
+ + + +
+
Bank:
+
Taruhan: 0
+
+ +
+
+ + session_start(); // If not logged in, redirect to login if (!isset($_SESSION['username'])) { diff --git a/loginn.php b/loginn.php index b1a2137..a30fea7 100644 --- a/loginn.php +++ b/loginn.php @@ -3,66 +3,103 @@ include "koneksi.php"; session_start(); $error = ''; -if(isset($_POST['login'])){ - $username = $_POST['username']; +$success = ''; + +if(isset($_POST['register'])){ + $username = mysqli_real_escape_string($conn, $_POST['username']); $password = $_POST['password']; - - $sql = "SELECT * FROM users WHERE username='$username' AND password='$password'"; - $result = mysqli_query($conn, $sql); - - if (mysqli_num_rows($result) > 0) { - $user = mysqli_fetch_assoc($result); - $_SESSION['username'] = $user['username']; - // Initialize balance in session (default 1000 if not set) - $_SESSION['balance'] = isset($user['balance']) ? (int)$user['balance'] : 1000; - header("Location: html.php"); - exit; + $confirm_password = $_POST['confirm_password']; + + // Validasi + if(empty($username) || empty($password)) { + $error = 'All fields are required.'; + } elseif($password !== $confirm_password) { + $error = 'Passwords do not match.'; + } elseif(strlen($password) < 6) { + $error = 'Password must be at least 6 characters.'; } else { - $error = 'Invalid username or password.'; + // Cek username sudah ada + $check_sql = "SELECT id FROM users WHERE username = ?"; + $check_stmt = mysqli_prepare($conn, $check_sql); + mysqli_stmt_bind_param($check_stmt, "s", $username); + mysqli_stmt_execute($check_stmt); + mysqli_stmt_store_result($check_stmt); + + if(mysqli_stmt_num_rows($check_stmt) > 0) { + $error = 'Username already exists.'; + } else { + // Password hashing untuk keamanan + // UNTUK TESTING: simpan plain text (tidak direkomendasikan) + $hashed_password = $password; // HAPUS INI DI PRODUKSI + + // UNTUK PRODUKSI: gunakan password_hash() + // $hashed_password = password_hash($password, PASSWORD_DEFAULT); + + // Insert user baru dengan saldo awal + $insert_sql = "INSERT INTO users (username, password, balance, created_at) + VALUES (?, ?, 1000, NOW())"; + $insert_stmt = mysqli_prepare($conn, $insert_sql); + mysqli_stmt_bind_param($insert_stmt, "ss", $username, $hashed_password); + + if(mysqli_stmt_execute($insert_stmt)) { + $success = 'Registration successful! You can now login.'; + // Auto login setelah register (opsional) + $user_id = mysqli_insert_id($conn); + $_SESSION['user_id'] = $user_id; + $_SESSION['username'] = $username; + $_SESSION['balance'] = 1000; + + header("Location: html.php"); + exit; + } else { + $error = 'Registration failed. Please try again.'; + } + } } } ?> - - + - - - Login + Register
- +
-
-
- -
+ + +
+ + +
- - -
- -
- - -
- -
- - + +
+
+ + +
+ +
+ + +
+ + +
- + \ No newline at end of file diff --git a/ody git.js b/ody git.js index c6efb5b..a525c7b 100644 --- a/ody git.js +++ b/ody git.js @@ -1,14 +1,23 @@ -// SET MESSAGE (WIN/LOSE) + +// ========================= +// SET MESSAGE +// ========================= function setMessage(text, status) { - messageEl.textContent = text; - messageEl.className = status; + if (messageEl) { + messageEl.textContent = text; + messageEl.className = status; + } } -// Simple Blackjack implementation +// ========================= +// KONSTANTA KARTU +// ========================= const SUITS = ['♠', '♥', '♦', '♣']; const RANKS = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']; -// DOM +// ========================= +// DOM ELEMENTS +// ========================= const dealerHandEl = document.getElementById('dealer-hand'); const playerHandEl = document.getElementById('player-hand'); const dealerValueEl = document.getElementById('dealer-value'); @@ -23,16 +32,16 @@ const doubleBtn = document.getElementById('double'); const newRoundBtn = document.getElementById('new-round'); const messageEl = document.getElementById('message'); -// TOP UP DOM Elements - HANDLED IN HTML.PHP -// const topUpBtn = document.getElementById('top-up-btn'); -// const topUpModal = document.getElementById('top-up-modal'); -// const topUpClose = document.getElementById('top-up-close'); -// const topUpInput = document.getElementById('top-up-input'); -// const topUpConfirm = document.getElementById('top-up-confirm'); -// const topUpHistoryEl = document.getElementById('top-up-history'); -// const topUpBalanceEl = document.getElementById('top-up-balance'); +// TOPUP DOM +const topupBtn = document.getElementById('topup-btn'); +const topupModal = document.getElementById('topup-modal'); +const topupForm = document.getElementById('topup-form'); +const topupMessage = document.getElementById('topup-message'); +const modalAmount = document.getElementById('modal-amount'); -// Game variables +// ========================= +// VARIABEL GAME +// ========================= let deck = []; let dealer = []; let player = []; @@ -41,23 +50,80 @@ let balance = 0; let currentBet = 0; let inRound = false; -// TOP UP variables - HANDLED IN HTML.PHP -// let topUpAmount = 0; -// let topUpHistory = []; +// ========================================= +// AMBIL VALUE DARI PHP (HIDDEN INPUT) +// ========================================= +let gameBalance = parseInt(document.getElementById('php-balance').value); +let userId = parseInt(document.getElementById('php-userid').value); -// Initialize balance from global gameBalance -if (typeof gameBalance !== 'undefined') { - balance = gameBalance; -} else { - balance = 1000; +// ========================= +// UPDATE BALANCE DISPLAY +// ========================= +function updateBalanceDisplay() { + if (balanceEl) balanceEl.textContent = gameBalance.toLocaleString('id-ID'); + const modalBalance = document.getElementById('modal-balance'); + if (modalBalance) modalBalance.textContent = gameBalance.toLocaleString('id-ID'); } +// ========================= +// SYNC KE SERVER +// ========================= +async function syncBalanceToServer() { + try { + const response = await fetch('update_balance.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ userId, balance: gameBalance }) + }); + + const data = await response.json(); + return data.success; + } catch (err) { + console.error("Error:", err); + return false; + } +} + +// ========================= +// UPDATE SESSION PHP +// ========================= +async function updateSessionBalance() { + try { + await fetch('update_session.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ balance: gameBalance }) + }); + } catch (err) { + console.error("Error:", err); + } +} + +// ========================= +// UPDATE BALANCE LOGIC +// ========================= +function updateGameBalance(amount, type) { + if (type === 'win') gameBalance += amount; + else if (type === 'loss') gameBalance -= amount; + else if (type === 'bet') gameBalance -= amount; + else if (type === 'refund') gameBalance += amount; + + updateBalanceDisplay(); + syncBalanceToServer(); + updateSessionBalance(); +} + +window.updateGameBalance = updateGameBalance; +window.gameBalance = gameBalance; +window.userId = userId; + +// ========================= +// FUNGSI KARTU +// ========================= function makeDeck() { deck = []; for (const s of SUITS) { - for (const r of RANKS) { - deck.push({ suit: s, rank: r }); - } + for (const r of RANKS) deck.push({ suit: s, rank: r }); } } @@ -69,42 +135,45 @@ function shuffle() { } function cardValue(card) { - const r = card.rank; - if (r === 'A') return [1, 11]; - if (['J', 'Q', 'K'].includes(r)) return [10]; - return [parseInt(r, 10)]; + if (card.rank === 'A') return [1, 11]; + if (['J', 'Q', 'K'].includes(card.rank)) return [10]; + return [parseInt(card.rank)]; } function handValues(hand) { let totals = [0]; - for (const c of hand) { - const vals = cardValue(c); + + for (const card of hand) { + const cv = cardValue(card); const newTotals = []; - for (const t of totals) { - for (const v of vals) { newTotals.push(t + v); } - } - totals = Array.from(new Set(newTotals)); + + totals.forEach(t => cv.forEach(v => newTotals.push(t + v))); + + totals = [...new Set(newTotals)]; } + const valid = totals.filter(t => t <= 21); - if (valid.length) return Math.max(...valid); - return Math.min(...totals); + return valid.length ? Math.max(...valid) : Math.min(...totals); } function renderHand(el, hand, hideFirst = false) { el.innerHTML = ''; + hand.forEach((c, i) => { const div = document.createElement('div'); - div.className = 'card' + (c.suit === '♥' || c.suit === '♦' ? ' red' : ''); if (hideFirst && i === 0) { div.className = 'card back'; - div.textContent = 'TERSEMBUNYI'; + div.textContent = 'HIDE'; } else { + div.className = 'card' + ((c.suit === '♥' || c.suit === '♦') ? ' red' : ''); const top = document.createElement('div'); - top.textContent = c.rank + ' ' + c.suit; const bot = document.createElement('div'); - bot.style.alignSelf = 'flex-end'; + + top.textContent = c.rank + ' ' + c.suit; bot.textContent = c.rank + ' ' + c.suit; + bot.style.alignSelf = 'flex-end'; + div.appendChild(top); div.appendChild(bot); } @@ -113,88 +182,64 @@ function renderHand(el, hand, hideFirst = false) { }); } +// ========================= +// UPDATE UI +// ========================= function updateUI() { renderHand(dealerHandEl, dealer, dealerHidden); - renderHand(playerHandEl, player, false); + renderHand(playerHandEl, player); + dealerValueEl.textContent = dealerHidden ? '??' : 'Nilai: ' + handValues(dealer); playerValueEl.textContent = 'Nilai: ' + handValues(player); - balanceEl.textContent = balance.toLocaleString('id-ID'); - currentBetEl.textContent = currentBet.toLocaleString('id-ID'); - // updateTopUpBalance(); // Redundant -} - -function updateBalanceOnServer() { - fetch('html.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - body: 'update_balance=' + balance - }) - .then(response => { - if (response.headers.get('content-type')?.includes('application/json')) { - return response.json(); - } - return { status: 'success' }; - }) - .then(data => { - if (data.balance !== undefined) { - balance = data.balance; - gameBalance = data.balance; - } - }) - .catch(err => console.log('Balance update sent', err)); + updateBalanceDisplay(); + + if (currentBetEl) currentBetEl.textContent = currentBet.toLocaleString('id-ID'); } +// ========================= +// START ROUND +// ========================= function startRound() { if (inRound) return; - const bet = Number(betInput.value) || 0; - - if (bet <= 0 || bet > balance) { - alert('BANK TIDAK CUKUP!'); - return; - } + const bet = Number(betInput.value); + if (bet <= 0) return alert("Masukkan jumlah taruhan!"); + if (bet > gameBalance) return alert("BANK TIDAK CUKUP!"); currentBet = bet; - balance -= bet; - gameBalance = balance; + updateGameBalance(bet, 'bet'); inRound = true; dealerHidden = true; - - setMessage('', ''); + setMessage("", ""); makeDeck(); shuffle(); + dealer = [deck.pop(), deck.pop()]; player = [deck.pop(), deck.pop()]; - updateUI(); // NATURAL BLACKJACK if (handValues(player) === 21) { dealerHidden = false; updateUI(); - const dealerVal = handValues(dealer); - if (dealerVal === 21) { - balance += currentBet; - gameBalance = balance; - setMessage('Tie (seri).', ''); + if (handValues(dealer) === 21) { + updateGameBalance(currentBet, 'refund'); + setMessage("Tie!", ""); } else { - const payout = Math.floor(currentBet * 2.5); - balance += payout; - gameBalance = balance; - setMessage('Blackjack! You Win!', 'win'); + updateGameBalance(Math.floor(currentBet * 2.5), 'win'); + setMessage("Blackjack! You win!", "win"); } inRound = false; currentBet = 0; - updateUI(); - updateBalanceOnServer(); } } +// ========================= +// HIT +// ========================= function playerHit() { if (!inRound) return; @@ -203,56 +248,49 @@ function playerHit() { if (handValues(player) > 21) { dealerHidden = false; - setMessage('Bust! You Lose!', 'lose'); + setMessage("Bust! You Lose!", "lose"); inRound = false; currentBet = 0; - gameBalance = balance; - updateUI(); - updateBalanceOnServer(); } } +// ========================= +// STAND +// ========================= function playerStand() { if (!inRound) return; dealerHidden = false; - while (handValues(dealer) < 17) { - dealer.push(deck.pop()); - } + while (handValues(dealer) < 17) dealer.push(deck.pop()); + + updateUI(); const pv = handValues(player); const dv = handValues(dealer); if (dv > 21 || pv > dv) { - balance += currentBet * 2; - gameBalance = balance; - setMessage('You Win!', 'win'); - + updateGameBalance(currentBet * 2, 'win'); + setMessage("You Win!", "win"); } else if (pv === dv) { - balance += currentBet; - gameBalance = balance; - setMessage('Tie (seri).', ''); - + updateGameBalance(currentBet, 'refund'); + setMessage("Tie!", ""); } else { - setMessage('You Lose!', 'lose'); + setMessage("You Lose!", "lose"); } inRound = false; currentBet = 0; - updateUI(); - updateBalanceOnServer(); } +// ========================= +// DOUBLE +// ========================= function playerDouble() { if (!inRound) return; - if (balance < currentBet) { - alert('Bank tidak cukup untuk double.'); - return; - } + if (gameBalance < currentBet) return alert("Bank tidak cukup untuk double."); - balance -= currentBet; - gameBalance = balance; + updateGameBalance(currentBet, 'bet'); currentBet *= 2; player.push(deck.pop()); @@ -260,151 +298,103 @@ function playerDouble() { if (handValues(player) > 21) { dealerHidden = false; - setMessage('Bust! You Lose!', 'lose'); + setMessage("Bust! You Lose!", "lose"); inRound = false; currentBet = 0; - updateUI(); - updateBalanceOnServer(); return; } playerStand(); } -// TOP UP FUNCTIONS - HANDLED IN HTML.PHP -/* -function showTopUpModal() { - topUpModal.style.display = 'block'; - if(topUpInput) topUpInput.value = ''; - updateTopUpHistory(); -} - -function hideTopUpModal() { - topUpModal.style.display = 'none'; -} - -function processTopUp() { - const amount = Number(topUpInput.value) || 0; - - if (amount <= 0) { - alert('Masukkan jumlah top up yang valid!'); - return; - } - - if (amount > 1000000) { - alert('Maksimal top up adalah 1.000.000!'); - return; - } - - balance += amount; - gameBalance = balance; - topUpAmount += amount; - - topUpHistory.push({ - amount: amount, - date: new Date().toLocaleString('id-ID'), - balanceAfter: balance - }); - - updateUI(); - updateTopUpHistory(); - - setMessage(`Top up berhasil! +${amount.toLocaleString('id-ID')}`, 'win'); - - hideTopUpModal(); -} - -function updateTopUpHistory() { - if (!topUpHistoryEl) return; - - topUpHistoryEl.innerHTML = ''; - - if (topUpHistory.length === 0) { - topUpHistoryEl.innerHTML = '

Belum ada riwayat top up

'; - return; - } - - const recentHistory = topUpHistory.slice(-5).reverse(); - - recentHistory.forEach(record => { - const historyItem = document.createElement('div'); - historyItem.className = 'history-item'; - historyItem.innerHTML = ` -
+${record.amount.toLocaleString('id-ID')}
-
${record.date}
-
Saldo: ${record.balanceAfter.toLocaleString('id-ID')}
- `; - topUpHistoryEl.appendChild(historyItem); - }); -} - -function updateTopUpBalance() { - if (topUpBalanceEl) { - topUpBalanceEl.textContent = `Total Top Up: ${topUpAmount.toLocaleString('id-ID')}`; - } -} -*/ - -// EVENT LISTENERS -betBtn.addEventListener('click', function (e) { - startRound(); +// ========================= +// TOP UP MODAL +// ========================= +topupBtn.addEventListener('click', () => { + topupModal.style.display = 'flex'; + topupForm.reset(); + topupMessage.style.display = 'none'; + updateBalanceDisplay(); }); +function closeTopUpModal() { + topupModal.style.display = 'none'; + topupMessage.style.display = 'none'; +} + +window.addEventListener('click', e => { + if (e.target === topupModal) closeTopUpModal(); +}); + +function setModalAmount(amount) { + modalAmount.value = amount; +} + +function showTopUpMessage(msg, type) { + topupMessage.textContent = msg; + topupMessage.className = 'topup-message ' + type; + topupMessage.style.display = 'block'; +} + +topupForm.addEventListener('submit', e => { + e.preventDefault(); + + const bankMethod = document.querySelector('input[name="bank_method"]:checked'); + const amount = parseInt(modalAmount.value); + + if (!bankMethod) return showTopUpMessage("Pilih metode pembayaran!", "error"); + if (amount <= 0 || amount > 1000000) return showTopUpMessage("Jumlah harus 1–1.000.000", "error"); + + const formData = new FormData(topupForm); + formData.append('userId', userId); + + fetch('process_topup.php', { method: 'POST', body: formData }) + .then(res => res.json()) + .then(data => { + if (data.success) { + gameBalance = data.new_balance; + updateBalanceDisplay(); + showTopUpMessage("✓ Top up berhasil!", "success"); + setTimeout(closeTopUpModal, 2000); + } else { + showTopUpMessage(data.message, "error"); + } + }) + .catch(() => showTopUpMessage("Terjadi kesalahan.", "error")); +}); + +// ========================= +// EVENT LISTENERS +// ========================= +betBtn.addEventListener('click', startRound); hitBtn.addEventListener('click', playerHit); standBtn.addEventListener('click', playerStand); doubleBtn.addEventListener('click', playerDouble); -newRoundBtn.addEventListener('click', function () { - if (inRound && !confirm('Masih dalam ronde. Reset?')) return; - balance = 1000; - gameBalance = 1000; - currentBet = 0; - inRound = false; +newRoundBtn.addEventListener('click', () => { + if (inRound && !confirm("Masih dalam ronde. Reset?")) return; + dealer = []; player = []; deck = []; + inRound = false; dealerHidden = true; - setMessage('Bank di-reset.', ''); + currentBet = 0; + + setMessage("Game di-reset.", ""); updateUI(); - updateBalanceOnServer(); }); -// TOP UP EVENT LISTENERS - HANDLED IN HTML.PHP -/* -if (topUpBtn) { - topUpBtn.addEventListener('click', showTopUpModal); -} - -if (topUpClose) { - topUpClose.addEventListener('click', hideTopUpModal); -} - -if (topUpConfirm) { - topUpConfirm.addEventListener('click', processTopUp); -} - -window.addEventListener('click', (e) => { - if (e.target === topUpModal) { - hideTopUpModal(); - } -}); -*/ - -// KEYBOARD window.addEventListener('keydown', e => { if (e.key === 'h') playerHit(); if (e.key === 's') playerStand(); if (e.key === 'd') playerDouble(); if (e.key === 'Enter') startRound(); - /* - if (e.ctrlKey && e.key === 't') { - e.preventDefault(); - showTopUpModal(); - } - */ }); -// INITIALIZATION -updateUI(); -// updateTopUpHistory(); -// updateTopUpBalance(); +// ========================= +// INIT +// ========================= +document.addEventListener('DOMContentLoaded', () => { + updateBalanceDisplay(); +}); diff --git a/prosestopup.php b/prosestopup.php new file mode 100644 index 0000000..1bf6fc8 --- /dev/null +++ b/prosestopup.php @@ -0,0 +1,54 @@ + false, 'message' => 'Not logged in']); + exit; +} + +if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $user_id = $_SESSION['user_id']; + $amount = intval($_POST['amount']); + $bank_method = $_POST['bank_method']; + + // Validasi + if ($amount <= 0 || $amount > 1000000) { + echo json_encode(['success' => false, 'message' => 'Invalid amount']); + exit; + } + + // Update balance di database + $sql = "UPDATE users SET balance = balance + ? WHERE id = ?"; + $stmt = mysqli_prepare($conn, $sql); + mysqli_stmt_bind_param($stmt, "ii", $amount, $user_id); + + if (mysqli_stmt_execute($stmt)) { + // Get new balance + $sql2 = "SELECT balance FROM users WHERE id = ?"; + $stmt2 = mysqli_prepare($conn, $sql2); + mysqli_stmt_bind_param($stmt2, "i", $user_id); + mysqli_stmt_execute($stmt2); + $result = mysqli_stmt_get_result($stmt2); + $user = mysqli_fetch_assoc($result); + + // Update session + $_SESSION['balance'] = $user['balance']; + + // Log transaction + $log_sql = "INSERT INTO transactions (user_id, type, amount, description) + VALUES (?, 'topup', ?, 'Top up via $bank_method')"; + $log_stmt = mysqli_prepare($conn, $log_sql); + mysqli_stmt_bind_param($log_stmt, "ii", $user_id, $amount); + mysqli_stmt_execute($log_stmt); + + echo json_encode([ + 'success' => true, + 'new_balance' => $user['balance'], + 'message' => 'Top up successful' + ]); + } else { + echo json_encode(['success' => false, 'message' => 'Database error']); + } +} +?> \ No newline at end of file diff --git a/upbalance.php b/upbalance.php new file mode 100644 index 0000000..d62253f --- /dev/null +++ b/upbalance.php @@ -0,0 +1,27 @@ + false]); + exit; +} + +$data = json_decode(file_get_contents('php://input'), true); +$user_id = $_SESSION['user_id']; +$balance = intval($data['balance']); + +// Update balance di database +$sql = "UPDATE users SET balance = ? WHERE id = ?"; +$stmt = mysqli_prepare($conn, $sql); +mysqli_stmt_bind_param($stmt, "ii", $balance, $user_id); + +if (mysqli_stmt_execute($stmt)) { + // Update session + $_SESSION['balance'] = $balance; + + echo json_encode(['success' => true]); +} else { + echo json_encode(['success' => false]); +} +?> \ No newline at end of file diff --git a/users.sql b/users.sql index f264ffd..bdc4f37 100644 --- a/users.sql +++ b/users.sql @@ -68,3 +68,23 @@ COMMIT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + +-- Tabel users +CREATE TABLE users ( + id INT PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(50) UNIQUE NOT NULL, + password VARCHAR(255) NOT NULL, + balance DECIMAL(10,2) DEFAULT 0.00, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Tabel transaction history (opsional) +CREATE TABLE transactions ( + id INT PRIMARY KEY AUTO_INCREMENT, + user_id INT, + type ENUM('topup', 'win', 'loss', 'bet'), + amount DECIMAL(10,2), + description VARCHAR(255), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) +);