Oxygen

Oxygen don't work cant claim food
Step 105 - Attempting to click the 'Launch' button (may not be present)...
Step 105 - Attempting to switch to the app's iFrame...
Step 107 - Attempting to click the 'Claim' button...
Step 108 - An error occurred: invalid literal for int() with base 10: 'Unknown'
Step 110 - The last lucky box claim was attempted on Never..
STATUS: Considering Unknown, we'll go back to sleep for 6 minutes.
CHROME DRIVER DETACHED: It is now safe to exit the script.
29 June - 10:29 | Need to wait until 29 June - 10:35 before the next claim attempt. Approximately 6 minutes.
Waiting for slot. Current sessions: 1/1
CHROME DRIVER INITIALISED: Try not to exit the script before it detaches.
Step 101 - Attempting to check for the start button (should not be present)...
Step 102 - Attempting to open a link for the app...
Step 102 - Failed to find the 'Open Wallet' button within the expected timeframe.
Step 102 - Attempting to find the chat window/message input box...
Step 103 - Attempting to send the '/start' command...
Step 104 - Attempting to open a link for the app...
Step 104 - Failed to find the 'Open Wallet' button within the expected timeframe.
Step 105 - Attempting to click the 'Launch' button (may not be present)...
Step 105 - Attempting to switch to the app's iFrame...
Step 107 - Attempting to click the 'Claim' button...
Step 108 - An error occurred: invalid literal for int() with base 10: 'Unknown'
Step 110 - The last lucky box claim was attempted on Never..
STATUS: Considering Unknown, we'll go back to sleep for 6 minutes.
CHROME DRIVER DETACHED: It is now safe to exit the script.
29 June - 10:37 | Need to wait until 29 June - 10:43 before the next claim attempt. Approximately 6 minutes.

Oxygen don't work cant claim food Step 105 - Attempting to click the 'Launch' button (may not be present)... Step 105 - Attempting to switch to the app's iFrame... Step 107 - Attempting to click the 'Claim' button... Step 108 - An error occurred: invalid literal for int() with base 10: 'Unknown' Step 110 - The last lucky box claim was attempted on Never.. STATUS: Considering Unknown, we'll go back to sleep for 6 minutes.
CHROME DRIVER DETACHED: It is now safe to exit the script. 29 June - 10:29 | Need to wait until 29 June - 10:35 before the next claim attempt. Approximately 6 minutes. Waiting for slot. Current sessions: 1/1
CHROME DRIVER INITIALISED: Try not to exit the script before it detaches. Step 101 - Attempting to check for the start button (should not be present)... Step 102 - Attempting to open a link for the app... Step 102 - Failed to find the 'Open Wallet' button within the expected timeframe.
Step 102 - Attempting to find the chat window/message input box... Step 103 - Attempting to send the '/start' command... Step 104 - Attempting to open a link for the app... Step 104 - Failed to find the 'Open Wallet' button within the expected timeframe.
Step 105 - Attempting to click the 'Launch' button (may not be present)... Step 105 - Attempting to switch to the app's iFrame... Step 107 - Attempting to click the 'Claim' button... Step 108 - An error occurred: invalid literal for int() with base 10: 'Unknown' Step 110 - The last lucky box claim was attempted on Never.. STATUS: Considering Unknown, we'll go back to sleep for 6 minutes.
CHROME DRIVER DETACHED: It is now safe to exit the script. 29 June - 10:37 | Need to wait until 29 June - 10:43 before the next claim attempt. Approximately 6 minutes.

I'm facing with this issue too but the admin said it happen with some IP. i

this error you have is not  about claiming or not found is not even connecting to the app check on your TG if you have this message

or this message

I try to clear history with bot. And have the same message Play Now! second you image. And i have this message for all my accounts. And i try use vpn, i try use another internet connection and nothing change

if you can open the script
and  go in line 666  the devil number :)
copy paste this
`import os
import shutil
import sys
import time
import re
import json
import getpass
import random
import subprocess
from PIL import Image
from pyzbar.pyzbar import decode
import qrcode_terminal
import fcntl
from fcntl import flock, LOCK_EX, LOCK_UN, LOCK_NB
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException, TimeoutException, StaleElementReferenceException, ElementClickInterceptedException
from datetime import datetime, timedelta
from selenium.webdriver.chrome.service import Service as ChromeService
def load_settings():
global settings, settings_file
default_settings = {
"forceClaim": False,
"debugIsOn": False,
"hideSensitiveInput": True,
"screenshotQRCode": True,
"maxSessions": 1,
"verboseLevel": 2,
"lowestClaimOffset": 0,
"highestClaimOffset": 15,
"forceNewSession": False,
"useProxy": False,
"proxyAddress": "http://<IP_ADDRESS>:8080"
}
if os.path.exists(settings_file):
    with open(settings_file, "r") as f:
        loaded_settings = json.load(f)
    # Filter out unused settings from previous versions
    settings = {k: loaded_settings.get(k, v) for k, v in default_settings.items()}
    output("Settings loaded successfully.", 3)
else:
    settings = default_settings
    save_settings()

def save_settings():
global settings, settings_file
with open(settings_file, "w") as f:
json.dump(settings, f)
output("Settings saved successfully.", 3)
def output(string, level):
if settings['verboseLevel'] >= level:
print(string)
Define sessions and settings files
settings_file = "variables.txt"
status_file_path = "status.txt"
settings = {}
load_settings()
driver = None
target_element = None
random_offset = random.randint(settings['lowestClaimOffset'], settings['highestClaimOffset'])
script = "games/oxygen.py"
prefix = "Oxygen:"
url = "https://web.telegram.org/k/#@oxygenminerbot"
pot_full = "Filled"
pot_filling = "to fill"
box_claim = "Never."
def increase_step():
global step
step_int = int(step) + 1
step = f"{step_int:02}"
print(f"Initialising the {prefix} Wallet Auto-claim Python Script - Good Luck!")
def update_settings():
global settings
def update_setting(setting_key, message, default_value):
    current_value = settings.get(setting_key, default_value)
    response = input(f"\n{message} (Y/N, press Enter to keep current [{current_value}]): ").strip().lower()
    if response == "y":
        settings[setting_key] = True
    elif response == "n":
        settings[setting_key] = False

update_setting("forceClaim", "Shall we force a claim on first run? Does not wait for the timer to be filled", settings["forceClaim"])
update_setting("debugIsOn", "Should we enable debugging? This will save screenshots in your local drive", settings["debugIsOn"])
update_setting("hideSensitiveInput", "Should we hide sensitive input? Your phone number and seed phrase will not be visible on the screen", settings["hideSensitiveInput"])
update_setting("screenshotQRCode", "Shall we allow log in by QR code? The alternative is by phone number and one-time password", settings["screenshotQRCode"])

try:
    new_max_sessions = int(input(f"\nEnter the number of max concurrent claim sessions. Additional claims will queue until a session slot is free.\n(current: {settings['maxSessions']}): "))
    settings["maxSessions"] = new_max_sessions
except ValueError:
    output("Number of sessions remains unchanged.", 1)

try:
    new_verbose_level = int(input("\nEnter the number for how much information you want displaying in the console.\n 3 = all messages, 2 = claim steps, 1 = minimal steps\n(current: {}): ".format(settings['verboseLevel'])))
    if 1 <= new_verbose_level <= 3:
        settings["verboseLevel"] = new_verbose_level
        output("Verbose level updated successfully.", 2)
    else:
        output("Verbose level remains unchanged.", 2)
except ValueError:
    output("Verbose level remains unchanged.", 2)

try:
    new_lowest_offset = int(input("\nEnter the lowest possible offset for the claim timer (valid values are -30 to +30 minutes)\n(current: {}): ".format(settings['lowestClaimOffset'])))
    if -30 <= new_lowest_offset <= 30:
        settings["lowestClaimOffset"] = new_lowest_offset
        output("Lowest claim offset updated successfully.", 2)
    else:
        output("Invalid range for lowest claim offset. Please enter a value between -30 and +30.", 2)
except ValueError:
    output("Lowest claim offset remains unchanged.", 2)

try:
    new_highest_offset = int(input("\nEnter the highest possible offset for the claim timer (valid values are 0 to 60 minutes)\n(current: {}): ".format(settings['highestClaimOffset'])))
    if 0 <= new_highest_offset <= 60:
        settings["highestClaimOffset"] = new_highest_offset
        output("Highest claim offset updated successfully.", 2)
    else:
        output("Invalid range for highest claim offset. Please enter a value between 0 and 60.", 2)
except ValueError:
    output("Highest claim offset remains unchanged.", 2)

if settings["lowestClaimOffset"] > settings["highestClaimOffset"]:
    settings["lowestClaimOffset"] = settings["highestClaimOffset"]
    output("Adjusted lowest claim offset to match the highest as it was greater.", 2)

update_setting("useProxy", "Use Proxy?", settings["useProxy"])

if settings["useProxy"]:
    proxy_address = input(f"\nEnter the Proxy IP address and port (current: {settings['proxyAddress']}): ").strip()
    if proxy_address:
        settings["proxyAddress"] = proxy_address

save_settings()

update_setting("forceNewSession", "Overwrite existing session and Force New Login? Use this if your saved session has crashed\nOne-Time only (setting not saved): ", settings["forceNewSession"])

output("\nRevised settings:", 1)
for key, value in settings.items():
    output(f"{key}: {value}", 1)
output("", 1)

def get_session_id():
"""Prompts the user for a session ID or determines the next sequential ID based on a 'Wallet' prefix.
Returns:
    str: The entered session ID or the automatically generated sequential ID.
"""
global settings, prefix
output(f"Your session will be prefixed with: {prefix}", 1)
user_input = input("Enter your unique Session Name here, or hit <enter> for the next sequential wallet: ").strip()

# Set the directory where session folders are stored
screenshots_dir = "./screenshots/"

# Ensure the directory exists to avoid FileNotFoundError
if not os.path.exists(screenshots_dir):
    os.makedirs(screenshots_dir)

# List contents of the directory
try:
    dir_contents = os.listdir(screenshots_dir)
except Exception as e:
    output(f"Error accessing the directory: {e}", 1)
    return None  # or handle the error differently

# Filter directories with the 'Wallet' prefix and extract the numeric parts
wallet_dirs = [int(dir_name.replace(prefix + 'Wallet', ''))
               for dir_name in dir_contents
               if dir_name.startswith(prefix + 'Wallet') and dir_name[len(prefix) + 6:].isdigit()]

# Calculate the next wallet ID
next_wallet_id = max(wallet_dirs) + 1 if wallet_dirs else 1

# Use the next sequential wallet ID if no user input was provided
if not user_input:
    user_input = f"Wallet{next_wallet_id}"  # Ensuring the full ID is prefixed correctly

return prefix+user_input

imported_seedphrase = None
Update the settings based on user input
if len(sys.argv) > 1:
user_input = sys.argv[1]  # Get session ID from command-line argument
output(f"Session ID provided: {user_input}", 2)
# Safely check for a second argument
if len(sys.argv) > 2 and sys.argv[2] == "reset":
    settings['forceNewSession'] = True

# Check for the --seed-phrase flag and validate it
if '--seed-phrase' in sys.argv:
    seed_index = sys.argv.index('--seed-phrase') + 1
    if seed_index < len(sys.argv):
        seed_phrase = ' '.join(sys.argv[seed_index:])
        seed_words = seed_phrase.split()
        if len(seed_words) == 12:
            output(f"Seed phrase accepted:", 2)
            imported_seedphrase = seed_phrase
        else:
            output("Invalid seed phrase. Ignoring.", 2)
    else:
        output("No seed phrase provided after --seed-phrase flag. Ignoring.", 2)

else:
output("\nCurrent settings:", 1)
for key, value in settings.items():
output(f"{key}: {value}", 1)
user_input = input("\nShould we update our settings? (Default: / Yes = y): ").strip().lower()
if user_input == "y":
update_settings()
user_input = get_session_id()
session_path = "./selenium/{}".format(user_input)
os.makedirs(session_path, exist_ok=True)
screenshots_path = "./screenshots/{}".format(user_input)
os.makedirs(screenshots_path, exist_ok=True)
backup_path = "./backups/{}".format(user_input)
os.makedirs(backup_path, exist_ok=True)
step = "01"
Define our base path for debugging screenshots
screenshot_base = os.path.join(screenshots_path, "screenshot")
def setup_driver():
chrome_options = Options()
chrome_options.add_argument(f"user-data-dir={session_path}")
chrome_options.add_argument("--headless")  # Ensure headless is enabled
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
user_agent = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/124.0.2478.50 Version/17.0 Mobile/15E148 Safari/604.1"
chrome_options.add_argument(f"user-agent={user_agent}")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)

if settings["useProxy"]:
    proxy_server = settings["proxyAddress"]
    chrome_options.add_argument(f"--proxy-server={proxy_server}")

chrome_options.add_argument("--ignore-certificate-errors")
chrome_options.add_argument("--allow-running-insecure-content")
chrome_options.add_argument("--test-type")

chromedriver_path = shutil.which("chromedriver")
if chromedriver_path is None:
    output("ChromeDriver not found in PATH. Please ensure it is installed.", 1)
    exit(1)

try:
    service = Service(chromedriver_path)
    driver = webdriver.Chrome(service=service, options=chrome_options)
    return driver
except Exception as e:
    output(f"Initial ChromeDriver setup may have failed: {e}", 1)
    output("Please ensure you have the correct ChromeDriver version for your system.", 1)
    exit(1)

def run_http_proxy():
proxy_lock_file = "./start_proxy.txt"
max_wait_time = 15 * 60  # 15 minutes
wait_interval = 5  # 5 seconds
start_time = time.time()
while os.path.exists(proxy_lock_file) and (time.time() - start_time) < max_wait_time:
    output("Proxy is already running. Waiting for it to free up...", 1)
    time.sleep(wait_interval)

if os.path.exists(proxy_lock_file):
    output("Max wait time elapsed. Proceeding to run the proxy.", 1)

with open(proxy_lock_file, "w") as lock_file:
    lock_file.write(f"Proxy started at: {time.ctime()}\n")

try:
    subprocess.run(['./launch.sh', 'enable-proxy'], check=True)
    output("http-proxy started successfully.", 1)
except subprocess.CalledProcessError as e:
    output(f"Failed to start http-proxy: {e}", 1)
finally:
    os.remove(proxy_lock_file)

if settings["useProxy"] and settings["proxyAddress"] == "http://<IP_ADDRESS>:8080":
run_http_proxy()
else:
output("Proxy disabled in settings.",2)
def get_driver():
global driver
if driver is None:  # Check if driver needs to be initialized
manage_session()  # Ensure we can start a session
driver = setup_driver()
output("\nCHROME DRIVER INITIALISED: Try not to exit the script before it detaches.",2)
return driver
def quit_driver():
global driver
if driver:
driver.quit()
output("\nCHROME DRIVER DETACHED: It is now safe to exit the script.",2)
driver = None
release_session()  # Mark the session as closed
def manage_session():
current_session = session_path
current_timestamp = int(time.time())
session_started = False
new_message = True
output_priority = 1
while True:
    try:
        with open(status_file_path, "r+") as file:
            flock(file, LOCK_EX)
            status = json.load(file)

            # Clean up expired sessions
            for session_id, timestamp in list(status.items()):
                if current_timestamp - timestamp > 300:  # 5 minutes
                    del status[session_id]
                    output(f"Removed expired session: {session_id}", 3)

            # Check for available slots, exclude current session from count
            active_sessions = {k: v for k, v in status.items() if k != current_session}
            if len(active_sessions) < settings['maxSessions']:
                status[current_session] = current_timestamp
                file.seek(0)
                json.dump(status, file)
                file.truncate()
                output(f"Session started: {current_session} in {status_file_path}", 3)
                flock(file, LOCK_UN)
                session_started = True
                break
            flock(file, LOCK_UN)

        if not session_started:
            output(f"Waiting for slot. Current sessions: {len(active_sessions)}/{settings['maxSessions']}", output_priority)
            if new_message:
                new_message = False
                output_priority = 3
            time.sleep(random.randint(5, 15))
        else:
            break

    except FileNotFoundError:
        # Create file if it doesn't exist
        with open(status_file_path, "w") as file:
            flock(file, LOCK_EX)
            json.dump({}, file)
            flock(file, LOCK_UN)
    except json.decoder.JSONDecodeError:
        # Handle empty or corrupt JSON
        with open(status_file_path, "w") as file:
            flock(file, LOCK_EX)
            output("Corrupted status file. Resetting...", 3)
            json.dump({}, file)
            flock(file, LOCK_UN)

def release_session():
current_session = session_path
current_timestamp = int(time.time())
with open(status_file_path, "r+") as file:
    flock(file, LOCK_EX)
    status = json.load(file)
    if current_session in status:
        del status[current_session]
        file.seek(0)
        json.dump(status, file)
        file.truncate()
    flock(file, LOCK_UN)
    output(f"Session released: {current_session}", 3)

def log_into_telegram():
global driver, target_element, session_path, screenshots_path, backup_path, settings, step
step = "01"
def visible_QR_code():
    global driver, screenshots_path, step
    max_attempts = 5
    attempt_count = 0
    last_url = "not a url"  # Placeholder for the last detected QR code URL

    xpath = "//canvas[@class='qr-canvas']"
    driver.get(url)
    wait = WebDriverWait(driver, 30)
    output(f"Step {step} - Waiting for the first QR code - may take up to 30 seconds.", 1)
    increase_step()
    QR_code = wait.until(EC.visibility_of_element_located((By.XPATH, xpath)))

    if not QR_code:
        return False

    wait = WebDriverWait(driver, 2)

    while attempt_count < max_attempts:
        try:
            QR_code = wait.until(EC.visibility_of_element_located((By.XPATH, xpath)))
            QR_code.screenshot(f"{screenshots_path}/Step {step} - Initial QR code.png")
            image = Image.open(f"{screenshots_path}/Step {step} - Initial QR code.png")
            decoded_objects = decode(image)
            if decoded_objects:
                this_url = decoded_objects[0].data.decode('utf-8')
                if this_url != last_url:
                    last_url = this_url  # Update the last seen URL
                    attempt_count += 1
                    output("*** Important: Having @HereWalletBot open in your Telegram App might stop this script from logging in! ***\n", 2)
                    output(f"Step {step} - Our screenshot path is {screenshots_path}\n", 1)
                    output(f"Step {step} - Generating screenshot {attempt_count} of {max_attempts}\n", 2)
                    qrcode_terminal.draw(this_url)
                if attempt_count >= max_attempts:
                    output(f"Step {step} - Max attempts reached with no new QR code.", 1)
                    return False
                time.sleep(0.5)  # Wait before the next check
            else:
                time.sleep(0.5)  # No QR code decoded, wait before retrying
        except TimeoutException:
            output(f"Step {step} - QR Code is no longer visible.", 2)
            return True  # Indicates the QR code has been scanned or disappeared

    output(f"Step {step} - Failed to generate a valid QR code after multiple attempts.", 1)
    return False  # If loop completes without a successful scan

driver = get_driver()

# QR Code Method
if settings['screenshotQRCode']:
    try:

        while True:
            if visible_QR_code():  # QR code not found
                test_for_2fa()
                return  # Exit the function entirely

            # If we reach here, it means the QR code is still present:
            choice = input(f"\nStep {step} - QR Code still present. Retry (r) with a new QR code or switch to the OTP method (enter): ")
            print("")
            if choice.lower() == 'r':
                visible_QR_code()
            else:
                break

    except TimeoutException:
        output(f"Step {step} - Canvas not found: Restart the script and retry the QR Code or switch to the OTP method.", 1)

# OTP Login Method
increase_step()
output(f"Step {step} - Initiating the One-Time Password (OTP) method...\n",1)
driver.get(url)
xpath = "//button[contains(@class, 'btn-primary') and contains(., 'Log in by phone Number')]"
target_element=move_and_click(xpath, 30, False, "switch to log in by phone number", step, "visible")
target_element.click()
increase_step()

# Country Code Selection
xpath = "//div[@class='input-field-input']"
target_element = move_and_click(xpath, 30, False, "update users country", step, "visible")
target_element.click()
user_input = input(f"Step {step} - Please enter your Country Name as it appears in the Telegram list: ").strip()
target_element.send_keys(user_input)
target_element.send_keys(Keys.RETURN)
increase_step()

# Phone Number Input
xpath = "//div[@class='input-field-input' and @inputmode='decimal']"
target_element = move_and_click(xpath, 30, False, "request users phone number", step, "visible")
driver.execute_script("arguments[0].click();", target_element)
def validate_phone_number(phone):
    # Regex for validating an international phone number without leading 0 and typically 7 to 15 digits long
    pattern = re.compile(r"^[1-9][0-9]{6,14}$")
    return pattern.match(phone)

while True:
    if settings['hideSensitiveInput']:
        user_phone = getpass.getpass(f"Step {step} - Please enter your phone number without leading 0 (hidden input): ")
    else:
        user_phone = input(f"Step {step} - Please enter your phone number without leading 0 (visible input): ")

    if validate_phone_number(user_phone):
        output(f"Step {step} - Valid phone number entered.",3)
        break
    else:
        output(f"Step {step} - Invalid phone number, must be 7 to 15 digits long and without leading 0.",1)
target_element.send_keys(user_phone)
increase_step()

# Wait for the "Next" button to be clickable and click it
xpath = "//button//span[contains(text(), 'Next')]"
target_element = move_and_click(xpath, 15, False, "click next to proceed to OTP entry", step, "visible")
driver.execute_script("arguments[0].click();", target_element)
increase_step()

try:
    # Attempt to locate and interact with the OTP field
    wait = WebDriverWait(driver, 20)
    if settings['debugIsOn']:
        time.sleep(3)
        driver.save_screenshot(f"{screenshots_path}/Step {step} - Ready_for_OTP.png")
    password = wait.until(EC.visibility_of_element_located((By.XPATH, "//input[@type='tel']")))
    otp = input(f"Step {step} - What is the Telegram OTP from your app? ")
    password.click()
    password.send_keys(otp)
    output(f"Step {step} - Let's try to log in using your Telegram OTP.\n",3)
    increase_step()

except TimeoutException:
    # Check for Storage Offline
    xpath = "//button[contains(text(), 'STORAGE_OFFLINE')]"
    target_element = move_and_click(xpath, 8, False, "check for 'STORAGE_OFFLINE'", step, "visible")
    if target_element:
        output(f"Step {step} - ***Progress is blocked by a 'STORAGE_OFFLINE' button",1)
        output(f"Step {step} - If you are re-using an old Wallet session; try to delete or create a new session.",1)
        found_error = True
    # Check for flood wait
    xpath = "//button[contains(text(), 'FLOOD_WAIT')]"
    target_element = move_and_click(xpath, 8, False, "check for 'FLOOD_WAIT'", step, "visible")
    if target_element:
        output(f"Step {step} - ***Progress is blocked by a 'FLOOD_WAIT' button", 1)
        output(f"Step {step} - You need to wait for the specified number of seconds before retrying.", 1)
        output(f"Step {step} - {target_element.text}")
        found_error = True
    if not found_error:
        output(f"Step {step} - Selenium was unable to interact with the OTP screen for an unknown reason.")

except Exception as e:  # Catch any other unexpected errors
    output(f"Step {step} - Login failed. Error: {e}", 1)
    if settings['debugIsOn']:
        driver.save_screenshot(f"{screenshots_path}/Step {step} - error_Something_Occured.png")

increase_step()
test_for_2fa()

if settings['debugIsOn']:
    time.sleep(3)
    driver.save_screenshot(f"{screenshots_path}/Step {step} - After_Entering_OTP.png")

def test_for_2fa():
global settings, driver, screenshots_path, step
try:
increase_step()
WebDriverWait(driver, 30).until(lambda d: d.execute_script('return document.readyState') == 'complete')
xpath = "//input[@type='password' and contains(@class, 'input-field-input')]"
fa_input = move_and_click(xpath, 10, False, "check for 2FA requirement (will timeout if you don't have 2FA)", step, "present")
if fa_input:
if settings['hideSensitiveInput']:
tg_password = getpass.getpass(f"Step {step} - Enter your Telegram 2FA password: ")
else:
tg_password = input(f"Step {step} - Enter your Telegram 2FA password: ")
fa_input.send_keys(tg_password + Keys.RETURN)
output(f"Step {step} - 2FA password sent.\n", 3)
output(f"Step {step} - Checking if the 2FA password is correct.\n", 2)
xpath = "//*[contains(text(), 'Incorrect password')]"
try:
incorrect_password = WebDriverWait(driver, 3).until(EC.visibility_of_element_located((By.XPATH, xpath)))
output(f"Step {step} - 2FA password is marked as incorrect by Telegram - check your debug screenshot if active.", 1)
if settings['debugIsOn']:
screenshot_path = f"{screenshots_path}/Step {step} - Test QR code after session is resumed.png"
driver.save_screenshot(screenshot_path)
quit_driver()
sys.exit()  # Exit if incorrect password is detected
except TimeoutException:
pass
        output(f"Step {step} - No password error found.", 3)
        xpath = "//input[@type='password' and contains(@class, 'input-field-input')]"
        fa_input = move_and_click(xpath, 5, False, "final check to make sure we are correctly logged in", step, "present")
        if fa_input:
            output(f"Step {step} - 2FA password entry is still showing, check your debug screenshots for further information.\n", 1)
            sys.exit()
        output(f"Step {step} - 2FA password check appears to have passed OK.\n", 3)
    else:
        output(f"Step {step} - 2FA input field not found.\n", 1)

except TimeoutException:
    # 2FA field not found
    output(f"Step {step} - Two-factor Authorization not required.\n", 3)

except Exception as e:  # Catch any other unexpected errors
    output(f"Step {step} - Login failed. 2FA Error - you'll probably need to restart the script: {e}", 1)
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/Step {step} - error: Something Bad Occured.png"
        driver.save_screenshot(screenshot_path)

def next_steps():
global driver, target_element, settings, backup_path, session_path, step, imported_seedphrase
if step:
pass
else:
step = "01"
try:
    launch_iframe()
    increase_step()

    cookies_path = f"{session_path}/cookies.json"
    cookies = driver.get_cookies()
    with open(cookies_path, 'w') as file:
        json.dump(cookies, file)

except TimeoutException:
    output(f"Step {step} - Failed to find or switch to the iframe within the timeout period.",1)

except Exception as e:
    output(f"Step {step} - An error occurred: {e}",1)

def launch_iframe():
global driver, target_element, settings, step
driver = get_driver()
try:
    driver.get(url)
    WebDriverWait(driver, 30).until(lambda d: d.execute_script('return document.readyState') == 'complete')
    output(f"Step {step} - Attempting to verify if we are logged in (hopefully QR code is not present).",3)
    xpath = "//canvas[@class='qr-canvas']"
    wait = WebDriverWait(driver, 5)
    wait.until(EC.visibility_of_element_located((By.XPATH, xpath)))
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/Step {step} - Test QR code after session is resumed.png"
        driver.save_screenshot(screenshot_path)
    output(f"Step {step} - Chrome driver reports the QR code is visible: It appears we are no longer logged in.",2)
    output(f"Step {step} - Most likely you will get a warning that the central input box is not found.",2)
    output(f"Step {step} - System will try to restore session, or restart the script from CLI force a fresh log in.\n",2)

except TimeoutException:
    output(f"Step {step} - nothing found to action. The QR code test passed.\n",3)
increase_step()

driver.get(url)
WebDriverWait(driver, 30).until(lambda d: d.execute_script('return document.readyState') == 'complete')

# There is a very unlikely scenario that the chat might have been cleared.
# In this case, the "START" button needs pressing to expose the chat window!
xpath = "//button[contains(., 'START')]"
button = move_and_click(xpath, 8, False, "check for the start button (should not be present)", step, "visible")
if button:
    button.click()
increase_step()

# New link logic to avoid finding and expired link
if find_working_link(step):
    increase_step()
else:
    send_start(step)
    increase_step()
    find_working_link(step)
    increase_step()

# Now let's move to and JS click the "Launch" Button
launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

#try this
button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
if button:
    button.click()
    return
#try this in second time
button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
if button:
    button.click()
    return
increase_step()

# HereWalletBot Pop-up Handling
select_iframe(step)
increase_step()

def full_claim():
global driver, target_element, settings, session_path, step, random_offset, box_claim
step = "100"
def apply_random_offset(unmodifiedTimer):
    global settings, step, random_offset
    if settings['lowestClaimOffset'] <= settings['highestClaimOffset']:
        random_offset = random.randint(max(settings['lowestClaimOffset'], 1), max(settings['highestClaimOffset'], 1))
        modifiedTimer = unmodifiedTimer + random_offset
        output(f"Step {step} - Random offset applied to the wait timer of: {random_offset} minutes.", 2)
        return modifiedTimer

launch_iframe()
increase_step()

get_balance(False)
increase_step()

output(f"Step {step} - The last lucky box claim was attempted on {box_claim}.",2)
increase_step()

wait_time_text = get_wait_time(step, "pre-claim")

if wait_time_text != "Filled":
    matches = re.findall(r'(\d+)([hm])', wait_time_text)
    remaining_wait_time = (sum(int(value) * (60 if unit == 'h' else 1) for value, unit in matches)) + random_offset
    if remaining_wait_time < 5 or settings["forceClaim"]:
        settings['forceClaim'] = True
        output(f"Step {step} - the remaining time to claim is less than the random offset, so applying: settings['forceClaim'] = True", 3)
    else:
        output(f"STATUS: Considering {wait_time_text}, we'll go back to sleep for {remaining_wait_time} minutes.", 1)
        return remaining_wait_time

if wait_time_text == "Unknown":
    return 15

try:
    output(f"Step {step} - The pre-claim wait time is : {wait_time_text} and random offset is {random_offset} minutes.", 1)
    increase_step()

    if wait_time_text == "Filled" or settings['forceClaim']:
        try:
            xpath = "//div[@class='farm_btn']"
            button = move_and_click(xpath, 10, True, "click the 'Claim' button", step, "clickable")
            increase_step()

            # Now let's give the site a few seconds to update.
            output(f"Step {step} - Waiting 10 seconds for the totals and timer to update...", 3)
            time.sleep(10)

            wait_time_text = get_wait_time(step, "post-claim")
            matches = re.findall(r'(\d+)([hm])', wait_time_text)
            total_wait_time = apply_random_offset(sum(int(value) * (60 if unit == 'h' else 1) for value, unit in matches))
            increase_step()

            get_balance(True)
            increase_step()

            # Let's check how many boxes we have!
            output(f"Step {step} - check if there are lucky boxes..",3)
            xpath = "//div[@class='boxes_cntr']"
            boxes = monitor_element (xpath)
            output(f"Step {step} - Detected there are {boxes} boxes to claim.",3)
            if int(boxes) > 0:
                xpath = "//div[@class='boxes_d_wrap']"
                move_and_click(xpath, 10, True, "click the boxes button", step, "clickable")
                xpath = "//div[@class='boxes_d_open' and contains(text(), 'Open box')]"
                box = move_and_click(xpath, 10, True, "open the box...", step, "clickable")
                if box:
                    box_claim = datetime.now().strftime("%d %B %Y, %I:%M %p")
                    output(f"Step {step} - The date and time of the box claim has been updated to {box_claim}.",3)

            if wait_time_text == "Filled":
                output(f"STATUS: The wait timer is still showing: Filled.", 1)
                output(f"Step {step} - This means either the claim failed, or there is lag in the game.", 1)
                output(f"Step {step} - We'll check back in 1 hour to see if the claim processed and if not try again.", 2)
            else:
                output(f"STATUS: Successful Claim: Next claim {wait_time_text} / {total_wait_time} minutes.",1)
            return max(60, total_wait_time)

        except TimeoutException:
            output(f"STATUS: The claim process timed out: Maybe the site has lag? Will retry after one hour.", 1)
            return 60
        except Exception as e:
            output(f"STATUS: An error occurred while trying to claim: {e}\nLet's wait an hour and try again", 1)
            return 60

    else:
        # If the wallet isn't ready to be claimed, calculate wait time based on the timer provided on the page
        matches = re.findall(r'(\d+)([hm])', wait_time_text)
        if matches:
            total_time = sum(int(value) * (60 if unit == 'h' else 1) for value, unit in matches)
            total_time += 1
            total_time = max(5, total_time)  # Wait at least 5 minutes or the time
            output(f"Step {step} - Not Time to claim this wallet yet. Wait for {total_time} minutes until the storage is filled.", 2)
            return total_time
        else:
            output(f"Step {step} - No wait time data found? Let's check again in one hour.", 2)
            return 60  # Default wait time when no specific time until filled is found.
except Exception as e:
    output(f"Step {step} - An unexpected error occurred: {e}", 1)
    return 60  # Default wait time in case of an unexpected error

def get_balance(claimed=False):
global step
prefix = "After" if claimed else "Before"
default_priority = 2 if claimed else 3
# Dynamically adjust the log priority
priority = max(settings['verboseLevel'], default_priority)

# Construct the specific balance XPath
balance_text = f'{prefix} BALANCE:' if claimed else f'{prefix} BALANCE:'
balance_xpath = f"//span[@class='oxy_counter']"

try:
    element = monitor_element(balance_xpath)
    # Check if element is not None and process the balance
    if element:
        balance_part = element
        output(f"Step {step} - {balance_text} {balance_part}", priority)

except NoSuchElementException:
    output(f"Step {step} - Element containing '{prefix} Balance:' was not found.", priority)
except Exception as e:
    output(f"Step {step} - An error occurred: {str(e)}", priority)  # Provide error as string for logging

# Increment step function, assumed to handle next step logic
increase_step()

def click_element(xpath, timeout=20):
end_time = time.time() + timeout
while time.time() < end_time:
try:
element = driver.find_element(By.XPATH, xpath)
# Attempt to click the element
element.click()
return True
except (StaleElementReferenceException, TimeoutException, NoSuchElementException):
pass
except Exception as e:
output(f"An error occurred: {e}", 3)
try:
overlays_cleared = clear_overlays(element, step)  # Attempt to clear overlays if an error occurs
if overlays_cleared > 0:
output(f"Step {step} - Overlays cleared, retrying click...", 3)
except Exception as clear_e:
output(f"An error occurred while trying to clear overlays: {clear_e}", 3)
time.sleep(0.05)  # Short sleep to avoid busy-waiting
return False
def clear_overlays(target_element, step):
try:
# Get the location of the target element
element_location = target_element.location_once_scrolled_into_view
overlays = driver.find_elements(By.XPATH, "//*[contains(@style,'position: absolute') or contains(@style,'position: fixed')]")
overlays_cleared = 0
for overlay in overlays:
overlay_rect = overlay.rect
# Check if overlay covers the target element
if (overlay_rect['x'] <= element_location['x'] <= overlay_rect['x'] + overlay_rect['width'] and
overlay_rect['y'] <= element_location['y'] <= overlay_rect['y'] + overlay_rect['height']):
driver.execute_script("arguments[0].style.display = 'none';", overlay)
overlays_cleared += 1
output(f"Step {step} - Removed {overlays_cleared} overlay(s) covering the target.", 3)
return overlays_cleared
except Exception as e:
output(f"Step {step} - An error occurred while trying to clear overlays: {e}", 1)
return 0
def move_and_click(xpath, wait_time, click, action_description, old_step, expectedCondition):
global driver, screenshots_path, settings, step
target_element = None
def timer():
    return random.randint(1, 3) / 10

def offset():
    return random.randint(1, 5)

output(f"Step {step} - Attempting to {action_description}...", 2)

try:
    wait = WebDriverWait(driver, wait_time)
    # Check and prepare the element based on the expected condition
    if expectedCondition == "visible":
        target_element = wait.until(EC.visibility_of_element_located((By.XPATH, xpath)))
    elif expectedCondition == "present":
        target_element = wait.until(EC.presence_of_element_located((By.XPATH, xpath)))
    elif expectedCondition == "invisible":
        wait.until(EC.invisibility_of_element_located((By.XPATH, xpath)))
        return None  # Early return as there's no element to interact with
    elif expectedCondition == "clickable":
        target_element = wait.until(EC.element_to_be_clickable((By.XPATH, xpath)))

    # Check if the target_element is found
    if target_element is None:
        output(f"Step {step} - The element was not found for {action_description}.", 2)
        return None

    # Before interacting, check for and remove overlays if click is needed or visibility is essential
    if expectedCondition in ["visible", "clickable"]:
        clear_overlays(target_element, step)

    # Perform actions if the element is found and clicking is requested
    if target_element:
        if expectedCondition == "clickable":
            actions = ActionChains(driver)
            actions.move_by_offset(0, 0 - offset()) \
                    .pause(timer()) \
                    .move_by_offset(0, offset()) \
                    .pause(timer()) \
                    .move_to_element(target_element) \
                    .pause(timer()) \
                    .perform()
            output(f"Step {step} - Successfully moved to the element using ActionChains.", 3)
        if click:
            click_element(xpath, wait_time)
    return target_element

except TimeoutException:
    output(f"Step {step} - Timeout while trying to {action_description}.", 3)
    if settings['debugIsOn']:
        # Capture the page source and save it to a file
        page_source = driver.page_source
        with open(f"{screenshots_path}/{step}_page_source.html", "w", encoding="utf-8") as f:
            f.write(page_source)
        logs = driver.get_log("browser")
        with open(f"{screenshots_path}/{step}_browser_console_logs.txt", "w", encoding="utf-8") as f:
            for log in logs:
                f.write(f"{log['level']}: {log['message']}\n")

except StaleElementReferenceException:
    output(f"Step {step} - StaleElementReferenceException caught for {action_description}.", 2)

except Exception as e:
    output(f"Step {step} - An error occurred while trying to {action_description}: {e}", 1)

finally:
    if settings['debugIsOn']:
        time.sleep(5)
        screenshot_path = f"{screenshots_path}/{step}-{action_description}.png"
        driver.save_screenshot(screenshot_path)
    return target_element

def monitor_element(xpath, timeout=8):
end_time = time.time() + timeout
first_time = True
while time.time() < end_time:
try:
elements = driver.find_elements(By.XPATH, xpath)
# Debugging: Output the number of elements found
if first_time:
output(f"Step {step} - Found {len(elements)} elements with XPath: {xpath}", 3)
first_time = False
        # Get the text content of all relevant div elements
        texts = []

        # Loop through each element and clean text before adding to the list
        for element in elements:
            if element.text.strip() != "":
                cleaned_text = element.text.replace('\n', ' ').replace('\r', ' ').strip()
                texts.append(cleaned_text)

        if texts:
            combined_text = ' '.join(texts)
            return combined_text
    except (StaleElementReferenceException, TimeoutException, NoSuchElementException):
        pass
    except Exception as e:
        output(f"An error occurred: {e}", 3)
    time.sleep(0.05)  # Short sleep to avoid busy-waiting
return "Unknown"

def get_wait_time(step_number="108", beforeAfter="pre-claim", max_attempts=1):
global driver, step
for attempt in range(1, max_attempts + 1):
    try:
        output(f"Step {step} - Get the wait time...", 3)
        xpath = "//div[@class='farm_btn']"
        elements = monitor_element(xpath, 10)
        if re.search(r"[СC]ollect food", elements, re.IGNORECASE):
            return "Filled"
        xpath = "//div[@class='farm_wait']"
        elements = monitor_element(xpath, 10)
        if elements:
            return elements
        return "Unknown"
    except Exception as e:
        output(f"Step {step} - An error occurred on attempt {attempt}: {e}", 3)
        return "Unknown"

# If all attempts fail
return "Unknown"

def clear_screen():
# Attempt to clear the screen after entering the seed phrase or mobile phone number.
# For Windows
if os.name == 'nt':
os.system('cls')
# For macOS and Linux
else:
os.system('clear')
def select_iframe(old_step):
global driver, screenshots_path, settings, step
output(f"Step {step} - Attempting to switch to the app's iFrame...",2)
try:
    wait = WebDriverWait(driver, 20)
    popup_body = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "popup-body")))
    iframe = popup_body.find_element(By.TAG_NAME, "iframe")
    driver.switch_to.frame(iframe)
    output(f"Step {step} - Was successfully able to switch to the app's iFrame.\n",3)

    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/{step}-iframe-switched.png"
        driver.save_screenshot(screenshot_path)

except TimeoutException:
    output(f"Step {step} - Failed to find or switch to the iframe within the timeout period.\n",3)
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/{step}-iframe-timeout.png"
        driver.save_screenshot(screenshot_path)
except Exception as e:
    output(f"Step {step} - An error occurred while attempting to switch to the iframe: {e}\n",3)
    if settings['debugIsOn']:
        screenshot_pat,h = f"{screenshots_path}/{step}-iframe-error.png"
        driver.save_screenshot(screenshot_path)

def find_working_link(old_step):
global driver, screenshots_path, settings, step
output(f"Step {step} - Attempting to open a link for the app...",2)
start_app_xpath = "//div[contains(@class, 'reply-markup-row')]//button[.//span[contains(text(), 'Start App')]]"
try:
    start_app_buttons = WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.XPATH, start_app_xpath)))
    clicked = False

    for button in reversed(start_app_buttons):
        actions = ActionChains(driver)
        actions.move_to_element(button).pause(0.2)
        try:
            if settings['debugIsOn']:
                driver.save_screenshot(f"{screenshots_path}/{step} - Find working link.png".format(screenshots_path))
            actions.perform()
            driver.execute_script("arguments[0].click();", button)
            clicked = True
            break
        except StaleElementReferenceException:
            continue
        except ElementClickInterceptedException:
            continue

    if not clicked:
        output(f"Step {step} - None of the 'Open Wallet' buttons were clickable.\n",1)
        if settings['debugIsOn']:
            screenshot_path = f"{screenshots_path}/{step}-no-clickable-button.png"
            driver.save_screenshot(screenshot_path)
        return False
    else:
        output(f"Step {step} - Successfully able to open a link for the app..\n",3)
        if settings['debugIsOn']:
            screenshot_path = f"{screenshots_path}/{step}-app-opened.png"
            driver.save_screenshot(screenshot_path)
        return True

except TimeoutException:
    output(f"Step {step} - Failed to find the 'Open Wallet' button within the expected timeframe.\n",1)
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/{step}-timeout-finding-button.png"
        driver.save_screenshot(screenshot_path)
    return False
except Exception as e:
    output(f"Step {step} - An error occurred while trying to open the app: {e}\n",1)
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/{step}-unexpected-error-opening-app.png"
        driver.save_screenshot(screenshot_path)
    return False

def find_claim_link(old_step):
global driver, screenshots_path, settings, step
output(f"Step {step} - Attempting to open a link for the app...", 2)
# Modify the larger element:
# button_xpath = "//button[contains(@class, 'kit-button is-large is-secondary is-fill is-centered button is-active')]"
# Wait for the button to be visible
## button_element = WebDriverWait(driver, 10).until(
##     EC.visibility_of_element_located((By.XPATH, button_xpath))
## )
## if button_element:
##    driver.execute_script("arguments[0].removeAttribute('style');", button_element)

# Updated to use a more generic CSS selector
start_app_xpath = "//button[contains(text(), 'Claim')]/.."
try:
    start_app_buttons = WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.XPATH, start_app_xpath)))
    # Filter buttons to find the one with specific text
    start_app_buttons = [btn for btn in start_app_buttons]

    clicked = False

    for button in reversed(start_app_buttons):
        actions = ActionChains(driver)
        actions.move_to_element(button).pause(0.2)
        try:
            if settings['debugIsOn']:
                driver.save_screenshot(f"{screenshots_path}/{step} - Find working link.png")
            actions.perform()
            driver.execute_script("arguments[0].click();", button)
            clicked = True
            break
        except StaleElementReferenceException:
            continue
        except ElementClickInterceptedException:
            continue

    if not clicked:
        output(f"Step {step} - None of the 'Claim' buttons were clickable.\n", 1)
        if settings['debugIsOn']:
            screenshot_path = f"{screenshots_path}/{step}-no-clickable-button.png"
            driver.save_screenshot(screenshot_path)
        return False
    else:
        output(f"Step {step} - Successfully able to open a link for the app..\n", 3)
        if settings['debugIsOn']:
            screenshot_path = f"{screenshots_path}/{step}-app-opened.png"
            driver.save_screenshot(screenshot_path)
        return True

except TimeoutException:
    output(f"Step {step} - Failed to find the 'Claim' button within the expected timeframe.\n", 1)
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/{step}-timeout-finding-button.png"
        driver.save_screenshot(screenshot_path)
    return False
except Exception as e:
    output(f"Step {step} - An error occurred while trying to open the app: {e}\n", 1)
    if settings['debugIsOn']:
        screenshot_path = f"{screenshots_path}/{step}-unexpected-error-opening-app.png"
        driver.save_screenshot(screenshot_path)
    return False

def send_start(old_step):
global driver, screenshots_path, backup_path, settings, step
xpath = "//div[contains(@class, 'input-message-container')]/div[contains(@class, 'input-message-input')][1]"
def attempt_send_start():
    global backup_path
    chat_input = move_and_click(xpath, 5, False, "find the chat window/message input box", step, "present")
    if chat_input:
        increase_step()
        output(f"Step {step} - Attempting to send the '/start' command...",2)
        chat_input.send_keys("/start")
        chat_input.send_keys(Keys.RETURN)
        output(f"Step {step} - Successfully sent the '/start' command.\n",3)
        if settings['debugIsOn']:
            screenshot_path = f"{screenshots_path}/{step}-sent-start.png"
            driver.save_screenshot(screenshot_path)
        return True
    else:
        output(f"Step {step} - Failed to find the message input box.\n",1)
        return False

if not attempt_send_start():
    # Attempt failed, try restoring from backup and retry
    output(f"Step {step} - Attempting to restore from backup and retry.\n",2)
    if restore_from_backup(backup_path):
        if not attempt_send_start():  # Retry after restoring backup
            output(f"Step {step} - Retried after restoring backup, but still failed to send the '/start' command.\n",1)
    else:
        output(f"Step {step} - Backup restoration failed or backup directory does not exist.\n",1)

def restore_from_backup(path):
global step, session_path
if os.path.exists(path):
try:
quit_driver()
shutil.rmtree(session_path)
shutil.copytree(path, session_path, dirs_exist_ok=True)
driver = get_driver()
driver.get(url)
WebDriverWait(driver, 10).until(lambda d: d.execute_script('return document.readyState') == 'complete')
output(f"Step {step} - Backup restored successfully.",2)
return True
except Exception as e:
output(f"Step {step} - Error restoring backup: {e}\n",1)
return False
else:
output(f"Step {step} - Backup directory does not exist.\n",1)
return False
Start a new PM2 process
def start_pm2_app(script_path, app_name, session_name):
interpreter_path = "venv/bin/python3"
command = f"NODE_NO_WARNINGS=1 pm2 start {script_path} --name {app_name} --interpreter {interpreter_path} --watch {script_path} -- {session_name}"
subprocess.run(command, shell=True, check=True)
Save the new PM2 process
def save_pm2():
command = f"NODE_NO_WARNINGS=1 pm2 save"
result = subprocess.run(command, shell=True, text=True, capture_output=True)
print(result.stdout)
def backup_telegram():
global session_path, step
# Ask the user if they want to backup their Telegram directory
backup_prompt = input("Would you like to backup your Telegram directory? (Y/n): ").strip().lower()
if backup_prompt == 'n':
    output(f"Step {step} - Backup skipped by user choice.", 3)
    return

# Ask the user for a custom filename
custom_filename = input("Enter a custom filename for the backup (leave blank for default): ").strip()

# Define the backup destination path
if custom_filename:
    backup_directory = os.path.join(os.path.dirname(session_path), f"Telegram:{custom_filename}")
else:
    backup_directory = os.path.join(os.path.dirname(session_path), "Telegram")

try:
    # Ensure the backup directory exists and copy the contents
    if not os.path.exists(backup_directory):
        os.makedirs(backup_directory)
    shutil.copytree(session_path, backup_directory, dirs_exist_ok=True)
    output(f"Step {step} - We backed up the session data in case of a later crash!", 3)
except Exception as e:
    output(f"Step {step} - Oops, we weren't able to make a backup of the session data! Error: {e}", 1)

def main():
global session_path, settings, step
if not settings["forceNewSession"]:
load_settings()
cookies_path = os.path.join(session_path, 'cookies.json')
if os.path.exists(cookies_path) and not settings['forceNewSession']:
output("Resuming the previous session...",2)
else:
telegram_backup_dirs = [d for d in os.listdir(os.path.dirname(session_path)) if d.startswith("Telegram")]
if telegram_backup_dirs:
print("Previous Telegram login sessions found. Pressing  will select the account numbered '1':")
for i, dir_name in enumerate(telegram_backup_dirs):
print(f"{i + 1}. {dir_name}")
        user_input = input("Enter the number of the session you want to restore, or 'n' to create a new session: ").strip().lower()

        if user_input == 'n':
            log_into_telegram()
            quit_driver()
            backup_telegram()
        elif user_input.isdigit() and 0 < int(user_input) <= len(telegram_backup_dirs):
            restore_from_backup(os.path.join(os.path.dirname(session_path), telegram_backup_dirs[int(user_input) - 1]))
        else:
            restore_from_backup(os.path.join(os.path.dirname(session_path), telegram_backup_dirs[0]))  # Default to the first session

    else:
        log_into_telegram()
        quit_driver()
        backup_telegram()

    next_steps()
    quit_driver()

    try:
        shutil.copytree(session_path, backup_path, dirs_exist_ok=True)
        output("We backed up the session data in case of a later crash!",3)
    except Exception as e:
        output("Oops, we weren't able to make a backup of the session data! Error:", 1)

    pm2_session = session_path.replace("./selenium/", "")
    output(f"You could add the new/updated session to PM use: pm2 start {script} --interpreter venv/bin/python3 --name {pm2_session} -- {pm2_session}",1)
    user_choice = input("Enter 'y' to continue to 'claim' function, 'e' to exit, 'a' or <enter> to automatically add to PM2: ").lower()

    if user_choice == "e":
        output("Exiting script. You can resume the process later.", 1)
        sys.exit()
    elif user_choice == "a" or not user_choice:
        start_pm2_app(script, pm2_session, pm2_session)
        user_choice = input("Should we save your PM2 processes? (Y/n): ").lower()
        if user_choice == "y" or not user_choice:
            save_pm2()
        output(f"You can now watch the session log into PM2 with: pm2 logs {pm2_session}", 2)
        sys.exit()

while True:
    manage_session()
    wait_time = full_claim()

    if os.path.exists(status_file_path):
        with open(status_file_path, "r+") as file:
            status = json.load(file)
            if session_path in status:
                del status[session_path]
                file.seek(0)
                json.dump(status, file)
                file.truncate()
                output(f"Session released: {session_path}",3)

    quit_driver()

    now = datetime.now()
    next_claim_time = now + timedelta(minutes=wait_time)
    this_claim_str = now.strftime("%d %B - %H:%M")
    next_claim_time_str = next_claim_time.strftime("%d %B - %H:%M")
    output(f"{this_claim_str} | Need to wait until {next_claim_time_str} before the next claim attempt. Approximately {wait_time} minutes.", 1)
    if settings["forceClaim"]:
        settings["forceClaim"] = False

    while wait_time > 0:
        this_wait = min(wait_time, 15)
        now = datetime.now()
        timestamp = now.strftime("%H:%M")
        output(f"[{timestamp}] Waiting for {this_wait} more minutes...",3)
        time.sleep(this_wait * 60)  # Convert minutes to seconds
        wait_time -= this_wait
        if wait_time > 0:
            output(f"Updated wait time: {wait_time} minutes left.",3)

if name == "main":
main()`

can you go in script and make some change ? copy paste
in lines 666
#Now let's move to and JS click the "Launch" or "Play" Button
   launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
   play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

   # first try
   button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

   # second try
   button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

ok i change it. And what now i must reboot system or what? Or it will automate change while bot is working?

restart game
and  it should work
better than ever :)

can you go in script and make some change ? copy paste in lines 666
#Now let's move to and JS click the "Launch" or "Play" Button
   launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
   play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

   # first try
   button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

   # second try
   button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

Hi can you update this to the next time

Ok, to restart the game, should I turn off and on my container and that's it? Or delete the game from the list and add it again? And I didn't quite figure out the scripts. What is the difference between Oxygen-auto and Oxygen and also in LumCity

only  delete the game  you using and create a new one
Sure, here’s a more polished version of your message:
"You don't have to restart your container. The auto-upgrade is a script that handles upgrades for you. Oxygen has a food supply and an oxygen supply that are upgradable, and the bot takes care of it when you have enough balance to do so. The same applies to Lumcity."

only delete the game you using and create a new one
You don't have to restart your container. The auto-upgrade is a script that handles upgrades for you. Oxygen has a food supply and an oxygen supply that are upgradable, and the bot takes care of it when you have enough balance to do so. The same applies to Lumcity.

51|Oxygen: | Step 102 - Attempting to open a link for the app...
51|Oxygen: | Step 103 - Attempting to click the 'Launch' button (may not be present)...
51|Oxygen: | Step 104 - Attempting to switch to the app's iFrame...
51|Oxygen: | Step 108 - The last lucky box claim was attempted on Never..
51|Oxygen: | STATUS: Considering Unknown, we'll go back to sleep for 10 minutes.
51|Oxygen: |
51|Oxygen: | CHROME DRIVER DETACHED: It is now safe to exit the script.
51|Oxygen: | 29 June - 18:45 | Need to wait until 29 June - 18:55 before the next claim attempt. Approximately 10 minutes.
51|Oxygen: | Initialising the Oxygen: Wallet Auto-claim Python Script - Good Luck!
51|Oxygen: | Session ID provided: Oxygen:c6-2
51|Oxygen: | Proxy disabled in settings.
51|Oxygen: | Resuming the previous session...
51|Oxygen: |
51|Oxygen: | CHROME DRIVER INITIALISED: Try not to exit the script before it detaches.
51|Oxygen: | Step 101 - Attempting to check for the start button (should not be present)...
Step 102 - Attempting to open a link for the app...
Step 103 - Attempting to click the 'Launch' button (may not be present)...
Step 104 - Attempting to switch to the app's iFrame...
Step 108 - The last lucky box claim was attempted on Never..
STATUS: Considering Unknown, we'll go back to sleep for 9 minutes.
CHROME DRIVER DETACHED: It is now safe to exit the script.
Need to wait until 29 June - 18:55 before the next claim attempt. Approximately 9 minutes.
Hi i tried to delete all the playnow! message but Still got this error

can you go in script and make some change ? copy paste in lines 666
#Now let's move to and JS click the "Launch" or "Play" Button
   launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
   play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

   # first try
   button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

   # second try
   button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

Hi can you update this to the next time

do you have test the lil update ? with  play

can you go in script and make some change ? copy paste in lines 666
#Now let's move to and JS click the "Launch" or "Play" Button
   launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
   play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

   # first try
   button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

   # second try
   button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

Hi can you update this to the next time

do you have test the lil update ? with play

oh I'm using docker so how can edit the script

make the change outside docker :)
copy paste the full code  inside docker
cd games
rm the-game you-want-to-change .py
copy paste
i know its not  the best but  its working

And I didn't quite figure out the scripts. What is the difference between Oxygen-auto and Oxygen and also in LumCity

its upgrading for you only available for free game without fee

Ok. And i don't need to launch etc oxygen and oxygen_auto in 1 account? Or i need it?

can you go in script and make some change ? copy paste in lines 666
#Now let's move to and JS click the "Launch" or "Play" Button
   launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
   play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

   # first try
   button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

   # second try
   button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

7
Activating virtual environment...
Running script: ./games/oxygen-autoupgrade.py with arguments:
  File "/usr/src/app/./games/oxygen-autoupgrade.py", line 674
    launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
                                                                                ^
IndentationError: unindent does not match any outer indentation level
Deactivating virtual environment...```
I changed the code oxygen-autoupgrade.py in the line 666, deleted the game and wanted to add it, but I got an error
Now i have this:
```# # Now let's move to and JS click the "Launch" Button
    # launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
    # # Essayer d'abord le bouton 'Launch'
    # button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
    # if button:
    #     button.click()
    #     return

      #Now let's move to and JS click the "Launch" or "Play" Button
   launch_xpath = "//button[contains(@class, 'popup-button') and contains(., 'Launch')]"
   play_xpath = "//button[contains(@class, 'reply-markup-button-text') and contains(., 'Play')]"

   # first try
   button = move_and_click(launch_xpath, 8, False, "click the 'Launch' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

   # second try
   button = move_and_click(play_xpath, 8, False, "click the 'Play' button (may not be present)", step, "visible")
   if button:
       button.click()
       return

    # HereWalletBot Pop-up Handling```

No  don't claim :( I add your script to oxygen_auto and don't claim food (

Activating virtual environment...
Running script: ./games/oxygen-autoupgrade.py with arguments:
Initialising the Oxygen-auto: Wallet Auto-claim Python Script - Good Luck!
Current settings:
forceClaim: False
debugIsOn: False
hideSensitiveInput: True
screenshotQRCode: True
maxSessions: 2
verboseLevel: 2
lowestClaimOffset: 0
highestClaimOffset: 15
forceNewSession: False
useProxy: False
proxyAddress: http://<IP_ADDRESS>:8080
Should we update our settings? (Default: / Yes = y):
Your session will be prefixed with: Oxygen-auto:
Enter your unique Session Name here, or hit  for the next sequential wallet: Alex
Proxy disabled in settings.
Previous Telegram login sessions found. Pressing  will select the account numbered '1':

Telegram:Elena
Telegram:Alexey
Enter the number of the session you want to restore, or 'n' to create a new session: 2

CHROME DRIVER INITIALISED: Try not to exit the script before it detaches.
Step 02 - Backup restored successfully.
Step 03 - Attempting to check for the start button (should not be present)...
Step 04 - Attempting to open a link for the app...
Step 04 - Failed to find the 'Open Wallet' button within the expected timeframe.
Step 04 - Attempting to find the chat window/message input box...
Step 05 - Attempting to send the '/start' command...
Step 05 - An error occurred: Message: element not interactable
(Session info: chrome-headless-shell=126.0.6478.114)
Stacktrace:
#0 0x56085d2a469a
#1 0x56085cf86f21
#2 0x56085cfcd6d8
#3 0x56085cfcc97f
#4 0x56085cff6872
#5 0x56085cfc7d89
#6 0x56085cff6a3e
#7 0x56085d0155c3
#8 0x56085cff6613
#9 0x56085cfc64f7
#10 0x56085cfc6e4e
#11 0x56085d26a86b
#12 0x56085d26e911
#13 0x56085d25635e
#14 0x56085d26f472
#15 0x56085d23acbf
#16 0x56085d294098
#17 0x56085d294270
#18 0x56085d2a37cc
#19 0x7f0199225a94
#20 0x7f01992b2c3c
CHROME DRIVER DETACHED: It is now safe to exit the script.

useProxy: False
we need true on use proxy

No don't claim :( I add your script to oxygen_auto and don't claim food (

yes because you are not connected to the game

but what address i must to write no the bot. I don't have address . For default it <IP_ADDRESS>

If you enable this option, it will create a new process called "http-proxy" it won't show with any coins or claim time, just like the daily update, but will process your outgoing commands to employ various anti-bot tricks.
If it still doesn't work, you must have some kind of firewall / DNS issue affect where your container is hosted.

Nothing heppends  don't send command to chat...
Activating virtual environment...
Running script: ./games/enable-proxy.py with arguments:
The PM2 process is running. Skipping setup.
Deactivating virtual environment...
http-proxy started successfully.
Resuming the previous session...

CHROME DRIVER INITIALISED: Try not to exit the script before it detaches.
Step 100 - Chrome driver reports the QR code is visible: It appears we are no longer logged in.
Step 100 - Most likely you will get a warning that the central input box is not found.
Step 100 - System will try to restore session, or restart the script from CLI force a fresh log in.

Step 101 - Attempting to check for the start button (should not be present)...
Step 102 - Attempting to open a link for the app...
Step 102 - Failed to find the 'Open Wallet' button within the expected timeframe.

Step 102 - Attempting to find the chat window/message input box...
Step 102 - Failed to find the message input box.

Step 102 - Attempting to restore from backup and retry.

CHROME DRIVER DETACHED: It is now safe to exit the script.

CHROME DRIVER INITIALISED: Try not to exit the script before it detaches.
Step 102 - Backup restored successfully.
Step 102 - Attempting to find the chat window/message input box...
Step 102 - Failed to find the message input box.

Step 102 - Retried after restoring backup, but still failed to send the '/start' command.

Step 103 - Attempting to open a link for the app...
Step 103 - Failed to find the 'Open Wallet' button within the expected timeframe.

Step 104 - Attempting to click the 'Launch' button (may not be present)...
Step 104 - Attempting to click the 'Play' button (may not be present)...
Step 104 - Attempting to switch to the app's iFrame...```

setup again your telegram account you are on proxy  now you need new  session  TG

ok i'll try

Step 100 - Chrome driver reports the QR code is visible: It appears we are no longer logged in.
Step 100 - Most likely you will get a warning that the central input box is not found.
Step 100 - System will try to restore session, or restart the script from CLI force a fresh log in.

The script is telling you exactly what's happening!


Unable to import module numerous

I"m unable to get this module to work.
According to the instructions it should be as easy as
pip install numerous

Then a script like:
import sys
import os
from numerous import Numerous

n_key = os.environ["NUMEROUS_KEY"]
n_humidity1 = os.environ["NUMEROUS_HUMIDITY1"]

foo = Numerous(apiKey=n_key)
h1 = foo.metric(n_humidity1)

h1.write(42)

However that throws this error.
root@raspberrypi:~# python /home/pi/temperature/sandbox/numerous.py
Traceback (most recent call last):
  File "/home/pi/temperature/sandbox/numerous.py", line 3, in <module>
    from numerous import Numerous
  File "/home/pi/temperature/sandbox/numerous.py", line 3, in <module>
    from numerous import Numerous
ImportError: cannot import name Numerous

I've tried installing the python library from pip as both myself and as root with the same results.
Is there a secret to getting this working? Looks awesome, but my lack of python skills is preventing me from using it.

Ah - this is an obscure problem! ... your file is named "numerous.py" so "from numerous import Numerous" is trying to find "Numerous" (recursively) inside your own file!
Rename your script to somethingelse.py and see if that fixes it.

See response on github - let me know if this does/doesn't fix it.
    - neil

P.S. This one puzzled me for a bit so don't feel bad! I believe this
behavior of being able to "import from yourself" is related to the idea of
using a module itself as a shell-level command (which I don't use but
probably should have - it's a cleaner way to implement things like the
shell-cmd stuff). Anyhow, rename your test file and see if it works.
On Mon, Sep 14, 2015 at 9:35 PM, Spencer Owen<EMAIL_ADDRESS>wrote:

I"m unable to get this module to work.
According to the instructions it should be as easy as
pip install numerous
Then a script like:
import sysimport osfrom numerous import Numerous
n_key = os.environ["NUMEROUS_KEY"]
n_humidity1 = os.environ["NUMEROUS_HUMIDITY1"]
foo = Numerous(apiKey=n_key)
h1 = foo.metric(n_humidity1)
h1.write(42)
However that throws this error.
root@raspberrypi:~# python /home/pi/temperature/sandbox/numerous.py
Traceback (most recent call last):
File "/home/pi/temperature/sandbox/numerous.py", line 3, in
from numerous import Numerous
File "/home/pi/temperature/sandbox/numerous.py", line 3, in
from numerous import Numerous
ImportError: cannot import name Numerous
I've tried installing the python library from pip as both myself and as
root with the same results.
Is there a secret to getting this working? Looks awesome, but my lack of
python skills is preventing me from using it.
—
Reply to this email directly or view it on GitHub
https://github.com/outofmbufs/Nappy/issues/1.

Thank you so much. That did it. I had to revert from calling the object numerous.Numerous back to just numerous and it looks like it works.
import sys
import os
from numerous import Numerous
#import numerous

n_key = os.environ["NUMEROUS_KEY"]
n_humidity1 = os.environ["NUMEROUS_HUMIDITY1"]
n_temp_f1 = os.environ["NUMEROUS_TEMP_F1"]

#foo = numerous.Numerous(apiKey=n_key)
foo = Numerous(apiKey=n_key)
h1 = foo.metric(n_humidity1)
tf1 = foo.metric(n_temp_f1)

h1.write(44)

I still get a warning, but I'm not too worried about it.
python num-test.py
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
  InsecurePlatformWarning

Yeah, that warning is annoying; I've seen it. It's related to the age of the python in that raspberry pi distribution. If you do follow the given URL in the warning it tells you how you can silence it if you really care.
The warning is not specific to Numerous; it's one of the other layers telling you that the SSL implementation is "inadequate" (except it's not an issue for talking to numerous and so you can just ignore it).
Glad you've got it working!


Change colour if connector is enabled

I'm using this fantastic tool for visualising electronics circuits, but I want to change the colour of a network if it is enabled. So that a network that is on has green wires and that a network that is disabled has red wires, is this possible?

Hi,
I think a network on the workspace is always enabled.
What state did you mean that a network is disabled?

I mean with disabled that the cable is on state 0 (off). A cable that is disabled can maybe have the colour red? An green cable would mean than that the cable is on state 1.
This will give the possibility for seeing  what the port now does with the input cables.

Nodes change a color according to state(red or black).
Would you want see also with a color of cable?

Yes that would help with complicated circuits

I have tried to do.
Download latest from
https://github.com/kazuhikoarase/simcirjs/archive/master.zip
and modify simcir.css line 54 as follows.
.simcir-connector-hot {
  /* stroke: #ff0000; */
  stroke: #ff0000;
}


Any reason tests is not included in .npmignore file?

Before I update it, was there a specific reason for omitting the tests folder from npmignore?

No specific reason, good catch!
You're welcome to PR the change, or I'll do it once I have some spare time.

Should be fixed in 8.3.1, thanks again!


Fix up JSDoc type hinting

We're following the AirBnB coding conventions (https://github.com/airbnb/javascript), who are implicitly using curly braces for types rather than just writing out the type name. This is pretty standard, see https://github.com/airbnb/javascript and https://en.wikipedia.org/wiki/JSDoc.
Wrong
/**
 * @param Integer setid
 * @param object config
 */

Right
/**
 * @param {number} setid
 * @param {object} config
 */

See http://usejsdoc.org/tags-param.html and http://usejsdoc.org/tags-type.html

Will this trigger an eslint error? If not, can we configure estlint to do so?

Not exactly, but we probably should turn on this option: http://eslint.org/docs/rules/valid-jsdoc#prefertype

If it's not an explicit error under the airBnB standard (even if they are using it as a matter of practice) this should be a warning not an error.

+1 to stricter linting. It keeps things consistent. A warning would be fine but I'd probably still break the build on a warning tbh ;)


Executing a local service bus queue trigger gives "Unexpected status code: 400" error with JSON request body

Issue
Passing in valid JSON into the request body of a service bus queue trigger results in a "Unexpected status code: 400" error, and the function does not execute.
Any valid JSON seems to cause this error; I tried passing in a JSON service bus message with the payload in body as a string and object but received the same error.
Expected Behavior
When valid a valid JSON payload is entered in the service bus message payload prompt, the payload should be passed as a deserialized object to the service bus message trigger function argument. This is what appears to happen when the deployed function is triggered regardless of ContentType.
Steps to Reproduce

Create function
Select "Azure Service Bus Queue trigger"
Select defaults for remaining prompts
Run func start
Execute function
Select created function
Enter valid JSON in request body prompt
Receive error

Context

Windows 10 OS
TypeScript Function Project Runtime
VSCode v1.62.2
Azure Functions Extension v1.6.0
Azure Functions Core Tools v3.0.3904
Function Runtime v<IP_ADDRESS>

Downgrading Azure Functions Extension to 1.6.0 and 1.5.2 does not help the issue.

Ok I figured how to get past this. I wrap the payload in a single quote and then everything works, maybe it has always behaved like that... :)

Wrapping the payload in a single quote does not exactly fix my issue.
It does execute the trigger, but the service bus message argument is now a JSON string wrapped with single quotes.
I'd expect the extension to mimic the behavior of a triggered deployed function and pass an already-parsed object to my trigger.
I will update my original issue with expected behavior.

I am encountering the same issue with Python Azure Function attempting to run locally.  The JSON blob cannot be accepted as a request body.

Has anyone found a workaround for this? Open issue for nearly a year, just bumped into it while experimenting with an Event Grid Trigger. Same behavior as initially reported where a request will encounter a status 400 and the function isn't triggered. As noted above, surrounding the JSON body with single quotes the function is triggered but unable to be parsed. Through the Azure portal, the exact same body works as expected.


Added tests for the three functions in origin_api.go

Tests tokens with various scopes for the `VerifyAdvertiseToken` function
Tests the string created from `GetIssuerURL`
Tests token creation using the `CreateAdvertiseToken` function
Also adjusts the mocked cache in redirect_test.go to be used by both test files

@turetske Just a heads up, we need to meddle with some of these tokens, and ultimately the functions that verify them (and their tests) soon. See issue #159.
I think all this is okay for now, but we might have to come back to revisit at some point soon.

@turetske Just a heads up, we need to meddle with some of these tokens, and ultimately the functions that verify them (and their tests) soon. See issue #159.
I think all this is okay for now, but we might have to come back to revisit at some point soon.

@jhiemstrawisc Okay. I don't know enough about tokens to understand issue #159, but I will absolutely take your word for it.

@turetske - is there a corresponding issue for this PR?

@bbockelm Yeah, it's #119. I couldn't get started on my last v1.0 issue without clarification so I decided to tackle one of the unit tests issues I created. And then decided might as well test the whole file rather than one function.


[FLINK-36395][state/forst] Graceful quit for Forst StateBackend

What is the purpose of the change
There are many threads in forst statebackends. This PR makes them quit gracefully when task stop.
Brief change log

Change the order of thread quit to avoid error
Use async thread to load library and allow interrupt in task thread.

Verifying this change
This change is a trivial rework without any test coverage.
Does this pull request potentially affect one of the following parts:

Dependencies (does it add or upgrade a dependency): no
The public API, i.e., is any changed class annotated with @Public(Evolving): no
The serializers: no
The runtime per-record code paths (performance sensitive): no
Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Kubernetes/Yarn, ZooKeeper: no
The S3 file system connector: no

Documentation

Does this pull request introduce a new feature? no
If yes, how is the feature documented? not applicable

@fredia Thanks for the review, updated accordingly.

@flinkbot run azure


punycode was not support by  IsURL

`package main
import (
"fmt"
"github.com/asaskevich/govalidator"

)
func main() {
url := "http://я.мос-гортакси.рф/jxoka"
domain := "я.мос-гортакси.рф"
fmt.Println(govalidator.IsURL(url))
fmt.Println(govalidator.IsURL(domain))
}
`
output is :
false
false

Hello guys!
I forked this package cause owner disappeared. Hope, he will be back, but it would be easier to merge these changes back if he is back
Link to my repo: create issue there and we'll discuss it.


added human friendly error message if a source file could not be foun…

added human friendly error when a source file could not be found (eg. @types)

Fixes #

This seems like a small (but important) contribution, so no Contribution License Agreement is required at this point. We will now review your pull request.
Thanks,
Microsoft Pull Request Bot

Thanks for your PR. these files are not manually edited, they are auto-generated from the build . You can find more information about contributing fixes at https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md
For future references, please file an issue first to track changes.


Add informative error message when API key not provided

fixes https://github.com/runpod/runpod-python/issues/36#issuecomment-1605511127

Looks like unit tests will also need to be updated for this PR to pass, if you are unable to do so let me know and I'll try to get to it later today.

yeah I don't think I have time to ramp up on the projects unit testing!  Sorry!

Tests updated :)


Lack of proactive messaging documentation

Working with a partner in Tokyo and we are implementing proactive messaging for our Agent Hand-off scenario. There is no documentation to follow and so the partner is working in the wild going through the source code :)

@ovishesh , There is an open issue (#314), and the design is in flux, so the documentation was taken down. However, in the next release of the NuGet packages, the following pattern should work for a deployed bot.
In your bot or middleware code:
var reference = TurnContext.GetConversationReference(context.Activity);
var adapter = (context as BotFrameworkTurnContext)?.Adapter as BotFrameworkAdapter;
SubscribeUser(adapter, (context as BotFrameworkTurnContext)?.BotAppId, reference);

Depending on how your implementing proactive messaging, you will probably need to save the conversation reference for later use:
private async void SubscribeUser(BotFrameworkAdapter adapter, string appId, ConversationReference reference)
{
    await adapter.ContinueConversation(appId, reference,
        async (ITurnContext context) =>
        {
            await Task.Delay(2000);
            await context.SendActivity("You've been notified!");
        });
}

Let me know if this helps.

Thanks @JonathanFingold. So does that mean that proactive messaging is broken for this release?
This is what I have at the moment:
SubscribeUser(context.Adapter, GetConversationReference(context.Request));
      private async void SubscribeUser(BotAdapter adapter, string appId, ConversationReference reference)
        {
            await adapter.ContinueConversation(reference,
                async (IBotContext context) =>
                {
                    await Task.Delay(2000);
                    await context.SendActivity("You've been notified!");
                });
        }

But then that gives me a StackOverflowException, is that somewhat related?
The error details:
System.StackOverflowException
  HResult=0x800703E9
  Source=<Cannot evaluate the exception source>
  StackTrace:
<Cannot evaluate the exception stack trace>

Message	Evaluation of method System.Exception.get_Message requires calling method System.Reflection.RuntimeMethodInfo.CreateDelegate, which cannot be called in this context.	string

Adding to that, seems like this GetPostToBotMessage() is being recursively called.

@ovishesh , Proactive messaging is partly broken in that you need an app ID and password for your bot.
Error for testing locally without credentials for the bot:
Unhandled Exception: System.ArgumentNullException: Value cannot be null.
Parameter name: botAppId
   at Microsoft.Bot.Builder.Adapters.BotFrameworkAdapter.ContinueConversation(String botAppId, ConversationReference reference, Func`2 callback)
   at Microsoft.Bot.Samples.ProactiveBot.<SubscribeUser>d__1.MoveNext() in ...\ProactiveMessaging\ProactiveBot.cs

Here are some additional steps (and more complete information). Note that I'm using the ASP.NET Core "integration" library to write the bot:

Build the libraries locally, and include references to the following projects or assemblies:
Microsoft.Bot.Builder
Microsoft.Bot.Builder.Core
Microsoft.Bot.Builder.Core.Extensions
Microsoft.Bot.Builder.Integration.AspNet.Core
Microsoft.Bot.Connector
Microsoft.Bot.Schema
Install the following NuGet package
Microsoft.IdentityModel.Protocols.OpenIdConnect
Replace the class definition in your Startup.cs file:using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder.BotFramework;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

public class Startup
{
    public IConfiguration Configuration { get; }

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton(_ => Configuration);
        services.AddBot<ProactiveBot>(options =>
        {
            options.CredentialProvider = new ConfigurationCredentialProvider(Configuration);
            options.EnableProactiveMessages = true;
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseBotFramework();
    }
}

Define your bot (I've called mine ProactiveBot):using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Schema;
using System.Threading.Tasks;

public class ProactiveBot : IBot
{
    public Task OnReceiveActivity(ITurnContext context)
    {
        if (context.Activity.Type is ActivityTypes.Message)
        {
            var messageText = context.Activity.AsMessageActivity()?.Text;
            if (messageText?.Trim().ToLowerInvariant() is "subscribe")
            {
                // Confirm the request.
                context.SendActivity("Thank You! We will message you shortly.");

                // Queue the proactive message.
                var reference = TurnContext.GetConversationReference(context.Activity);
                SubscribeUser((BotFrameworkAdapter)context.Adapter,
                    ((BotFrameworkTurnContext)context).BotAppId, reference);
            }
            else
            {
                // Prompt the user to subscribe.
                context.SendActivity("Type `subscribe` to receive a proactive message.");
            }
        }
        return Task.CompletedTask;
    }

    private async void SubscribeUser(BotFrameworkAdapter adapter, string appId, ConversationReference reference)
    {
        // Send a proactive message.
        await adapter.ContinueConversation(appId, reference, async context =>
        {
            await Task.Delay(2000);
            await context.SendActivity("You've been notified!");
        });
    }
}

PS. GetPostToUserMessage calls GetPostToBotMessage and then swaps the From and Recipient fields. It might look like a recursive call at first, but they are two separate methods.

Merges from last night changed how to get the bot's App ID from within the bot.
In the bot's OnReceiveActivity method, update the block of code to "queue the proactive message" to the following (and update your using statements as necessary:
// Queue the proactive message.
var reference = TurnContext.GetConversationReference(context.Activity);

var claimsIdentity = context.Services.Get<IIdentity>("BotIdentity") as ClaimsIdentity;

// For requests from channel App Id is in Audience claim of JWT token. For emulator it is in AppId claim. For
// unauthenticated requests we have anonymouse identity provided auth is disabled.
// For Activities coming from Emulator AppId claim contains the Bot's AAD AppId.
var botAppIdClaim =
    (claimsIdentity.Claims?.SingleOrDefault(claim => claim.Type == AuthenticationConstants.AudienceClaim)
    ?? claimsIdentity.Claims?.SingleOrDefault(claim => claim.Type == AuthenticationConstants.AppIdClaim));

SubscribeUser((BotFrameworkAdapter)context.Adapter, botAppIdClaim.Value, reference);

Thanks @JonathanFingold. I'll pull the latest and try it out. When do you these will be pushed out to Nuget?

@ovishesh , I was hoping for a NuGet package last week, I'm not positive, but I'm guessing the next will be within two weeks. There is still a lot of refactoring going on. Which also means that my sample code is already out of date.
You can collect NuGet packages from your local build and have a stable set to work from.
I'm closing this for now, but let me know if you need any more assistance.

@JonathanFingold  : we have requirement for proactive messaging, where we are going to proactively send some more business information to users through web API calls.
current implementation is as below

we are saving conversation id, user id, from id and some other details in azure storage.

private UserEntity FillUserEntity(Activity activity, UserProfile userProfile)
        {
            string[] issuerSplits = userProfile.Issuer.Split("https://sts.windows.net/");
            if (issuerSplits != null && issuerSplits.Length > 1)
            {
                string tenantId = (issuerSplits[1].EndsWith('/')) ? issuerSplits[1].TrimEnd('/') : issuerSplits[1];
                UserEntity userEntity = new UserEntity(tenantId, $"{userProfile.UPN}-{activity.ChannelId}");
                userEntity.AadObjectId = activity.From.AadObjectId;
                userEntity.FromName = activity.From.Name;
                userEntity.FromId = activity.From.Id;
                userEntity.ConversationId = activity.Conversation.Id;
                userEntity.ChannelId = activity.ChannelId;
                userEntity.ServiceUrl = activity.ServiceUrl;
                userEntity.Locale = activity.Locale;
                userEntity.RecipientId = "Bot-id";
                userEntity.RecipientRole = activity.Recipient.Role;
                return userEntity;
            }

            return null;
        }

We are creating input JSON payload, based on table properties to send proactive message.

                    ProactiveMessage proactiveMessage = new ProactiveMessage()
                    {
                        BotId = queryResult.RecipientId,
                        MessagePayload = activityGeneratorInputModel.MessagePayload,
                        Conversation = new Microsoft.Bot.Schema.ConversationReference()
                        {
                            Bot = new Microsoft.Bot.Schema.ChannelAccount() { Id = queryResult.RecipientId, Name = "Bot", Role = "bot" },
                            User = new Microsoft.Bot.Schema.ChannelAccount() { Id = queryResult.FromId, Name = "user" },
                            Conversation = new Microsoft.Bot.Schema.ConversationAccount() { Id = queryResult.ConversationId },
                            ServiceUrl = queryResult.ServiceUrl,
                            ChannelId = queryResult.ChannelId
                        }
                    }

output JSON is sent to ProactiveController, to prompt message to Microsoft Teams.

 try
                {
                    await botFrameworkAdapter.ContinueConversationAsync(proMsg.BotId, proMsg.Conversation, async (context, token) =>
                    {
                        await context.SendActivityAsync(proMsg.MessagePayload);
                    }, new CancellationToken());
                }
                catch { }

Entire functionality flow works fine, but when user is idle for few minutes suddenly bot in teams stops to respond to proactive messages.

Post investigation we found the issue, details below.

Operation returned an invalid status code 'Unauthorized'
--

@SarangRapid Can you raise this with the support team at Stack Overflow using the botframework tag?

@SarangRapid
When 'Unauthorized' occurs during the sending of a proactive message, it can usually be fixed with a call to: MicrosoftAppCredentials.TrustServiceUrl(context.Activity.ServiceUrl);
So, the .ContinueConversation code becomes:
        await adapter.ContinueConversation(appId, reference, async context =>
        {
            MicrosoftAppCredentials.TrustServiceUrl(context.Activity.ServiceUrl);
            await Task.Delay(2000);
            await context.SendActivity("You've been notified!");
        });

it worked

FYI, part of our team built some fantastic samples/walkthrough for more complicated proactive messaging scenarios - check it out to see if it would have satisfied your issues! https://github.com/lucashuet93/botbuilder-proactivemessaging


[Feature]Use workspace mode to add typescript options

1. Your usage scenarios? | 您使用的场景？
Hope to support typescript development.
2. What is your expected outcome? | 您期望的结果是怎样的？
It is hoped that the template has built-in JS and TS modes, which can be configured and selected by the developer.

To meet this requirement, you need to use the npm workspace mode, but this requires npm>=7.0.0, that is, node>=15.0.0.(The correspondence between node and npm versions can be viewed: https://nodejs.org/en/ download/releases/). is this too demanding for developers?


elmerfem: init at 9.0

Elmer is a finite element software for multiphysical problems http://www.elmerfem.org/
Description of changes

Elmer is a finite element software for multiphysical problems
http://www.elmerfem.org/
Things done

Built on platform(s)

[x] x86_64-linux
[ ] aarch64-linux
[ ] x86_64-darwin
[ ] aarch64-darwin

For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)

[ ] sandbox = relaxed
[ ] sandbox = true

[x] Tested, as applicable:

NixOS test(s) (look inside nixos/tests)
and/or package tests
or, for functions and "core" functionality, tests in lib/tests or pkgs/test
made sure NixOS tests are linked to the relevant packages

[ ] Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
[x] Tested basic functionality of all binary files (usually in ./result/bin/)
24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)

[ ] (Package updates) Added a release notes entry if the change is major or breaking
[ ] (Module updates) Added a release notes entry if the change is significant
[ ] (Module addition) Added a release notes entry if adding a new NixOS module

[ ] Fits CONTRIBUTING.md.

Add a :+1: reaction to pull requests you find important.

Result of nixpkgs-review pr 308687 run on x86_64-linux 1


Re-enable existing cloud code

Re-enables the cloud code that was commented out.
This also causes new controls to appear on the GUI.

Was about to ask if existing seeds are unaffected, but one of the commit messages already confirms that. 💪