From 4daebed7e03f03de3b5716f1e8735b173da5d6b4 Mon Sep 17 00:00:00 2001 From: Mark Hoekveen Date: Sat, 18 Jul 2026 11:41:54 +0200 Subject: [PATCH] homeassistant and wireguard updates --- playbook.yml | 7 + scripts/generate-wireguard-keys.sh | 177 ---------------------- tasks/homeassistant.yml | 54 +++++++ tasks/homeassistant/docker-compose.yml.j2 | 42 +++++ tasks/homeassistant/mosquitto.conf.j2 | 6 + tasks/homeassistant/vault.yml | 6 + tasks/wireguard.yml | 33 +--- tasks/wireguard/add_client.sh | 141 ----------------- tasks/wireguard/wg0.network.j2 | 5 - vault/wireguard.yml | 88 ++++++----- 10 files changed, 165 insertions(+), 394 deletions(-) delete mode 100755 scripts/generate-wireguard-keys.sh create mode 100644 tasks/homeassistant.yml create mode 100644 tasks/homeassistant/docker-compose.yml.j2 create mode 100644 tasks/homeassistant/mosquitto.conf.j2 create mode 100644 tasks/homeassistant/vault.yml delete mode 100644 tasks/wireguard/add_client.sh diff --git a/playbook.yml b/playbook.yml index 6902c17..6d57aba 100644 --- a/playbook.yml +++ b/playbook.yml @@ -105,3 +105,10 @@ - import_tasks: tasks/pihole.yml - import_tasks: tasks/mediawiki.yml tags: leaf +- name: Kynareth install + hosts: kynareth + become: true + remote_user: nerevar + tasks: + - import_tasks: tasks/homeassistant.yml + tags: leaf diff --git a/scripts/generate-wireguard-keys.sh b/scripts/generate-wireguard-keys.sh deleted file mode 100755 index e1b9765..0000000 --- a/scripts/generate-wireguard-keys.sh +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/bash -# Generate WireGuard vanity keys and update the vault file -# Usage: ./generate-wireguard-keys.sh - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_DIR="$(dirname "$SCRIPT_DIR")" -VAULT_FILE="$REPO_DIR/vault/wireguard.yml" -TEMP_FILE=$(mktemp) - -echo "===================================" -echo "WireGuard Vanity Key Generator" -echo "===================================" -echo "" - -# Check if wireguard-vanity-address is installed -if ! command -v wireguard-vanity-address &> /dev/null; then - echo "Error: wireguard-vanity-address not found" - echo "Install it with: cargo install wireguard-vanity-address" - exit 1 -fi - -# Check if wg is installed -if ! command -v wg &> /dev/null; then - echo "Error: wg (wireguard-tools) not found" - echo "Install it with: sudo apt install wireguard-tools" - exit 1 -fi - -# Function to generate a vanity keypair -generate_vanity_key() { - local name=$1 - local search=$2 - local search_len=${#search} - local timeout=${3:-120} - - echo "Generating vanity key for $name (searching for '$search')..." - - # Try to generate vanity key with timeout - local output=$(timeout $timeout wireguard-vanity-address --in $search_len "$search" 2>&1 | grep "^private" | head -n 1 || true) - - if [ -n "$output" ]; then - local private_key=$(echo "$output" | awk '{print $2}') - local public_key=$(echo "$output" | awk '{print $4}') - echo " ✓ Found vanity key: $public_key" - else - echo " ⚠ No vanity key found in ${timeout}s, generating regular key..." - local private_key=$(wg genkey) - local public_key=$(echo "$private_key" | wg pubkey) - echo " ✓ Generated regular key: $public_key" - fi - - echo "$private_key|$public_key" -} - -echo "This will generate new WireGuard keys. This will:" -echo " 1. Generate vanity keys for all peers" -echo " 2. Update vault/wireguard.yml with the new keys" -echo "" -read -p "Continue? (y/N) " -n 1 -r -echo -if [[ ! $REPLY =~ ^[Yy]$ ]]; then - echo "Aborted." - exit 0 -fi -echo "" - -# Generate keys -echo "Generating keys (this may take a few minutes)..." -echo "" - -SERVER_KEYS=$(generate_vanity_key "server" "talos" 180) -SERVER_PRIVATE=$(echo "$SERVER_KEYS" | cut -d'|' -f1) -SERVER_PUBLIC=$(echo "$SERVER_KEYS" | cut -d'|' -f2) -echo "" - -CLIENT1_KEYS=$(generate_vanity_key "client1" "lptp" 120) -CLIENT1_PRIVATE=$(echo "$CLIENT1_KEYS" | cut -d'|' -f1) -CLIENT1_PUBLIC=$(echo "$CLIENT1_KEYS" | cut -d'|' -f2) -echo "" - -CLIENT2_KEYS=$(generate_vanity_key "client2" "phon" 120) -CLIENT2_PRIVATE=$(echo "$CLIENT2_KEYS" | cut -d'|' -f1) -CLIENT2_PUBLIC=$(echo "$CLIENT2_KEYS" | cut -d'|' -f2) -echo "" - -MASSER_KEYS=$(generate_vanity_key "masser" "mssr" 120) -MASSER_PRIVATE=$(echo "$MASSER_KEYS" | cut -d'|' -f1) -MASSER_PUBLIC=$(echo "$MASSER_KEYS" | cut -d'|' -f2) -echo "" - -# Create the vault file content -cat > "$TEMP_FILE" << EOF ---- -# WireGuard VPN Keys -# These are encrypted with ansible-vault -# To edit: ansible-vault edit vault/wireguard.yml - -wireguard_server: - private_key: "$SERVER_PRIVATE" - public_key: "$SERVER_PUBLIC" - vanity_search: "talos" - -wireguard_clients: - - name: client1 - private_key: "$CLIENT1_PRIVATE" - public_key: "$CLIENT1_PUBLIC" - vanity_search: "lptp" - ip_address: "10.8.0.2/24" - description: "Example laptop client" - - - name: client2 - private_key: "$CLIENT2_PRIVATE" - public_key: "$CLIENT2_PUBLIC" - vanity_search: "phon" - ip_address: "10.8.0.3/24" - description: "Example phone client" - - - name: masser - private_key: "$MASSER_PRIVATE" - public_key: "$MASSER_PUBLIC" - vanity_search: "mssr" - ip_address: "10.8.0.4/24" - description: "Masser phone" -EOF - -echo "===================================" -echo "Keys generated successfully!" -echo "===================================" -echo "" -echo "Summary:" -echo " Server: $SERVER_PUBLIC" -echo " Client1: $CLIENT1_PUBLIC" -echo " Client2: $CLIENT2_PUBLIC" -echo " Masser: $MASSER_PUBLIC" -echo "" - -# Check if vault file should be encrypted -if [ -f "$VAULT_FILE" ]; then - # Check if existing file is encrypted - if head -n 1 "$VAULT_FILE" | grep -q '^\$ANSIBLE_VAULT'; then - echo "Encrypting with ansible-vault..." - ansible-vault encrypt "$TEMP_FILE" --output="$VAULT_FILE" - rm -f "$TEMP_FILE" - echo "✓ Keys saved to $VAULT_FILE (encrypted)" - else - echo "⚠ Warning: Existing vault file is not encrypted" - echo "Saving unencrypted keys to $VAULT_FILE" - mv "$TEMP_FILE" "$VAULT_FILE" - echo "" - echo "To encrypt the file, run:" - echo " ansible-vault encrypt $VAULT_FILE" - fi -else - echo "Do you want to encrypt the vault file with ansible-vault? (recommended)" - read -p "Encrypt? (Y/n) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Nn]$ ]]; then - ansible-vault encrypt "$TEMP_FILE" --output="$VAULT_FILE" - rm -f "$TEMP_FILE" - echo "✓ Keys saved to $VAULT_FILE (encrypted)" - else - mv "$TEMP_FILE" "$VAULT_FILE" - echo "✓ Keys saved to $VAULT_FILE (unencrypted)" - echo "" - echo "⚠ Warning: Keys are stored unencrypted!" - echo "To encrypt them later, run:" - echo " ansible-vault encrypt $VAULT_FILE" - fi -fi - -echo "" -echo "Next steps:" -echo " 1. Run the playbook to deploy: ansible-playbook -i inventory.yml playbook.yml --limit talos --tags leaf" -echo " 2. Update your WireGuard clients with the new server public key" -echo "" diff --git a/tasks/homeassistant.yml b/tasks/homeassistant.yml new file mode 100644 index 0000000..4968f78 --- /dev/null +++ b/tasks/homeassistant.yml @@ -0,0 +1,54 @@ +- name: Create /opt/homeassistant directory + file: + path: "/opt/homeassistant" + state: directory + owner: root + group: aurbis + mode: "0775" + +- name: Create mosquitto config directory + file: + path: "/opt/homeassistant/mosquitto/config" + state: directory + owner: root + group: aurbis + mode: "0775" + +- name: Create mosquitto data directory + file: + path: "/opt/homeassistant/mosquitto/data" + state: directory + owner: "1883" + group: "1883" + mode: "0755" + +- name: Create mosquitto log directory + file: + path: "/opt/homeassistant/mosquitto/log" + state: directory + owner: "1883" + group: "1883" + mode: "0755" + +- name: Copy mosquitto config + template: + src: homeassistant/mosquitto.conf.j2 + dest: /opt/homeassistant/mosquitto/config/mosquitto.conf + group: aurbis + mode: "0644" + +- name: Include service vault + include_vars: + dir: homeassistant + files_matching: vault.yml + +- name: Copy docker-compose file + template: + src: homeassistant/docker-compose.yml.j2 + dest: /opt/homeassistant/docker-compose.yml + group: aurbis + mode: "0775" + +- name: Start homeassistant service + community.docker.docker_compose_v2: + project_src: /opt/homeassistant diff --git a/tasks/homeassistant/docker-compose.yml.j2 b/tasks/homeassistant/docker-compose.yml.j2 new file mode 100644 index 0000000..50e9da8 --- /dev/null +++ b/tasks/homeassistant/docker-compose.yml.j2 @@ -0,0 +1,42 @@ +services: + homeassistant: + container_name: homeassistant + image: ghcr.io/home-assistant/home-assistant:stable + restart: unless-stopped + network_mode: host + volumes: + - ./config:/config + - /etc/localtime:/etc/localtime:ro + environment: + - TZ=Europe/Amsterdam + privileged: true + + mosquitto: + container_name: mosquitto + image: eclipse-mosquitto:latest + restart: unless-stopped + ports: + - "1883:1883" + - "9001:9001" + volumes: + - ./mosquitto/config:/mosquitto/config + - ./mosquitto/data:/mosquitto/data + - ./mosquitto/log:/mosquitto/log + environment: + - TZ=Europe/Amsterdam + + zigbee2mqtt: + container_name: zigbee2mqtt + image: ghcr.io/koenkk/zigbee2mqtt:latest + restart: unless-stopped + volumes: + - ./zigbee2mqtt:/app/data + - /run/udev:/run/udev:ro + ports: + - "8080:8080" + devices: + - /dev/serial/by-id/usb-Itead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_V2_dc3be1218711f011862f3707773d9da9-if00-port0:/dev/ttyUSB0 + environment: + - TZ=Europe/Amsterdam + depends_on: + - mosquitto diff --git a/tasks/homeassistant/mosquitto.conf.j2 b/tasks/homeassistant/mosquitto.conf.j2 new file mode 100644 index 0000000..b5ec6de --- /dev/null +++ b/tasks/homeassistant/mosquitto.conf.j2 @@ -0,0 +1,6 @@ +listener 1883 +allow_anonymous true +persistence true +persistence_location /mosquitto/data/ +log_dest file /mosquitto/log/mosquitto.log +log_dest stdout diff --git a/tasks/homeassistant/vault.yml b/tasks/homeassistant/vault.yml new file mode 100644 index 0000000..58c431a --- /dev/null +++ b/tasks/homeassistant/vault.yml @@ -0,0 +1,6 @@ +$ANSIBLE_VAULT;1.1;AES256 +30376632353734363038306536663830306264626239303134646539646339326631303532313836 +3233346235363866376233653462326664313732373836620a633939353735383331653632633735 +62646434663936666464363661633166386331613932373538396366373763656234383838653565 +6162356463313831340a356232333763326162616365303930626132316534353464613964323663 +61323332636330323966376463373364643661343666323537626438396633623432 diff --git a/tasks/wireguard.yml b/tasks/wireguard.yml index bb241d8..3f7c107 100644 --- a/tasks/wireguard.yml +++ b/tasks/wireguard.yml @@ -31,37 +31,6 @@ - /etc/wireguard/clients - /etc/wireguard/keys -- name: Generate key generation script - copy: - dest: /etc/wireguard/generate_key.sh - mode: "0700" - content: | - #!/bin/bash - # Generate a WireGuard keypair - # Usage: ./generate_key.sh - - OUTPUT_PREFIX="$1" - - if [ -z "$OUTPUT_PREFIX" ]; then - echo "Usage: $0 " - exit 1 - fi - - echo "Generating WireGuard keypair..." - umask 077 - wg genkey | tee "${OUTPUT_PREFIX}.key" | wg pubkey > "${OUTPUT_PREFIX}.pub" - chmod 600 "${OUTPUT_PREFIX}.key" - chmod 644 "${OUTPUT_PREFIX}.pub" - echo "Keys generated: ${OUTPUT_PREFIX}.key and ${OUTPUT_PREFIX}.pub" - -- name: Deploy add_client.sh script - copy: - src: wireguard/add_client.sh - dest: /etc/wireguard/add_client.sh - mode: "0755" - owner: root - group: root - - name: Create server private key file copy: content: "{{ wireguard_server.private_key }}" @@ -138,7 +107,7 @@ iptables: table: nat chain: POSTROUTING - out_interface: "{{ ansible_default_ipv4.interface }}" + out_interface: "enp2s0" source: 10.8.0.0/24 jump: MASQUERADE comment: WireGuard masquerading diff --git a/tasks/wireguard/add_client.sh b/tasks/wireguard/add_client.sh deleted file mode 100644 index 23026a0..0000000 --- a/tasks/wireguard/add_client.sh +++ /dev/null @@ -1,141 +0,0 @@ -#!/bin/bash -# Helper script to add a new WireGuard client -# Usage: ./add_client.sh -# Example: ./add_client.sh mylaptop 4 - -set -e - -CLIENT_NAME="$1" -IP_SUFFIX="$2" - -if [ -z "$CLIENT_NAME" ] || [ -z "$IP_SUFFIX" ]; then - echo "Usage: $0 " - echo "Example: $0 mylaptop 4" - echo "" - echo "This will:" - echo " - Generate WireGuard keys for the client" - echo " - Assign IP 10.8.0.$IP_SUFFIX to the client" - echo " - Add peer to WireGuard server config" - echo " - Generate client config file and QR codes" - exit 1 -fi - -WG_DIR="/etc/wireguard" -KEYS_DIR="$WG_DIR/keys" -CLIENTS_DIR="$WG_DIR/clients" -NETDEV_FILE="/etc/systemd/network/99-wg0.netdev" - -# Check if running as root -if [ "$EUID" -ne 0 ]; then - echo "Please run as root" - exit 1 -fi - -# Check if client already exists -if [ -f "$KEYS_DIR/${CLIENT_NAME}.key" ]; then - echo "Error: Client '$CLIENT_NAME' already exists!" - exit 1 -fi - -# Check if IP is already in use -if grep -q "10.8.0.${IP_SUFFIX}/32" "$NETDEV_FILE"; then - echo "Error: IP 10.8.0.${IP_SUFFIX} is already assigned!" - echo "Choose a different IP suffix." - exit 1 -fi - -echo "==========================================" -echo "Adding WireGuard Client: $CLIENT_NAME" -echo "==========================================" -echo "Client IP: 10.8.0.${IP_SUFFIX}" -echo "" - -# Generate keys -echo "Generating keys..." -cd "$KEYS_DIR" -"$WG_DIR/generate_key.sh" "$CLIENT_NAME" - -CLIENT_PRIVATE_KEY=$(cat "${KEYS_DIR}/${CLIENT_NAME}.key") -CLIENT_PUBLIC_KEY=$(cat "${KEYS_DIR}/${CLIENT_NAME}.pub") -SERVER_PUBLIC_KEY=$(cat "${KEYS_DIR}/server.pub") - -echo "Keys generated successfully!" -echo "Public key: $CLIENT_PUBLIC_KEY" -echo "" - -# Add peer to netdev file -echo "Adding peer to server configuration..." -cat >> "$NETDEV_FILE" << EOF - -# $CLIENT_NAME -[WireGuardPeer] -PublicKey=$CLIENT_PUBLIC_KEY -AllowedIPs=10.8.0.${IP_SUFFIX}/32 -PersistentKeepalive=25 -EOF - -echo "Peer added to $NETDEV_FILE" -echo "" - -# Get server endpoint (try to detect public IP) -SERVER_ENDPOINT=$(curl -s ifconfig.me 2>/dev/null || echo "YOUR_PUBLIC_IP") -if [ "$SERVER_ENDPOINT" = "YOUR_PUBLIC_IP" ]; then - # Fallback to ansible_host if available - SERVER_ENDPOINT=$(hostname -I | awk '{print $1}') -fi - -# Create client config -echo "Creating client configuration..." -cat > "$CLIENTS_DIR/${CLIENT_NAME}.conf" << EOF -[Interface] -Address = 10.8.0.${IP_SUFFIX}/24 -PrivateKey = $CLIENT_PRIVATE_KEY -DNS = 10.8.0.1 - -[Peer] -PublicKey = $SERVER_PUBLIC_KEY -Endpoint = ${SERVER_ENDPOINT}:51820 -# Route home network traffic through WireGuard -# To route ALL traffic (full VPN), change to: 0.0.0.0/0 -AllowedIPs = 192.168.178.0/24, 10.8.0.0/24 -PersistentKeepalive = 25 -EOF - -chmod 600 "$CLIENTS_DIR/${CLIENT_NAME}.conf" -echo "Client config created at $CLIENTS_DIR/${CLIENT_NAME}.conf" -echo "" - -# Generate QR codes -echo "Generating QR codes..." -qrencode -t ansiutf8 -r "$CLIENTS_DIR/${CLIENT_NAME}.conf" > "$CLIENTS_DIR/${CLIENT_NAME}.qr.txt" -qrencode -t png -r "$CLIENTS_DIR/${CLIENT_NAME}.conf" -o "$CLIENTS_DIR/${CLIENT_NAME}.qr.png" -echo "QR codes generated!" -echo "" - -# Reload systemd-networkd -echo "Reloading systemd-networkd..." -networkctl reload -sleep 2 -echo "" - -# Display summary -echo "==========================================" -echo "Client Added Successfully!" -echo "==========================================" -echo "Client name: $CLIENT_NAME" -echo "Client IP: 10.8.0.${IP_SUFFIX}" -echo "Public key: $CLIENT_PUBLIC_KEY" -echo "" -echo "Configuration files:" -echo " - $CLIENTS_DIR/${CLIENT_NAME}.conf" -echo " - $CLIENTS_DIR/${CLIENT_NAME}.qr.txt (terminal QR)" -echo " - $CLIENTS_DIR/${CLIENT_NAME}.qr.png (image QR)" -echo "" -echo "To view QR code in terminal:" -echo " cat $CLIENTS_DIR/${CLIENT_NAME}.qr.txt" -echo "" -echo "Next steps:" -echo " 1. Copy the client config to your device" -echo " 2. Import into WireGuard client app" -echo " 3. Connect and test with: ping 10.8.0.1" -echo "==========================================" diff --git a/tasks/wireguard/wg0.network.j2 b/tasks/wireguard/wg0.network.j2 index 78a9762..a4a43f0 100644 --- a/tasks/wireguard/wg0.network.j2 +++ b/tasks/wireguard/wg0.network.j2 @@ -3,8 +3,3 @@ Name=wg0 [Network] Address=10.8.0.1/24 -IPMasquerade=ipv4 -IPForward=yes - -[Route] -Destination=192.168.178.0/24 diff --git a/vault/wireguard.yml b/vault/wireguard.yml index 10da211..1a5cf23 100644 --- a/vault/wireguard.yml +++ b/vault/wireguard.yml @@ -1,40 +1,50 @@ $ANSIBLE_VAULT;1.1;AES256 -30643738326463306330626262343761663766623936653166373965643665626332613466633233 -6364363836653735353630383134343662386237343961610a396530323364663237376665313539 -61646263386432346461623338613132633935626630333338373634623164326632343261323336 -6237646464356362630a653637393132626661386261313037366531316435643865356234323161 -61643930313337653463373133386338386464306439383464343931303633336433363564653439 -35383362656563653338623162663862623437373132636134633834623635356430363833313233 -30396139613265653466303437373237343365626164386639303733336666653830393833336536 -33616431663132643839366332383464396539653466613936353235323565626163613831356339 -36636138366133323462346331323866323934366565616433323535356535313661613863623262 -32373239613630666234613437343361373565386139363631656564363965323134666133626465 -33643064323866663365616132366430303236336134323362646662313939656563383333613234 -32396330636635656132653538653066333264663730613564373136346531323237653335366330 -36333136343537616633333232363066336635636265326462306363346335333133653436636232 -30363030646564333132643164303066386630323264393438356331303437303163666432306365 -32643630336466663862623433326131633661396136663039663830383830633638393066666632 -33613865636266663535636231666164383234323432656336396539393863623637373533336234 -30656233323238316434356564653432363566386433326530636439663137353534643464323035 -62626238626265323664626430303037653733316535326235663132376130643161303934303436 -65653130306331313533343365643461366364376433626661626531323233373430373666356364 -64613961326632623137663836656662656133303263613930366130333936633036303232636265 -30353137376362643436333062343430323964613364366532616162636539306139323437633063 -66623639666638363564386363336436626465353635666263396336323063333439626166343236 -34303133613364666334326532356364343439656564336162663639323464666435376339356436 -34346365303761353439646439353334303365633363613033303935633463316632346364303530 -61303662393636383232333963313235643434323833636263666565396438343732366531656261 -37306439623165363164613563303566313461633936363133316434313039363335353139356137 -66613631383866653365623234353538646364323735353433336431323337316565353431613034 -61333838356466343336323662343037656662333465306665333433626637356330393036363765 -38333436333063356339636139653933373938373164646139333133393333386433323738616131 -34393133313563316339336230316362363130366239313837323236303939353362636136343363 -62383061353466323330383964333534366362666331393333373964316563633639393065366165 -37636564313937393138396665303562633261396636616435636237336231306163326538623837 -32313064343963356666653035623834306662366265373437316636373361636263356464373930 -31356235313963383230663165303161643838356534353339643436323262326338386231383061 -31303064356233303539356363653038656637646632313238366364383439393866326133653462 -39303936373762323665333135393334343131313732616236363233396666616564366233383763 -33663336316430333163333938653466353361633230396633353963303038353230643364356634 -30616230613139656662303830303632366531653838396130313730663930616666336632623137 -646436343130346531313934616132636234 +63643362336265613138376231643064623837323032323766363732613439373439343438646266 +3366623162366536656433313232313334386334373261300a373532353932323930653561303032 +63616362633237666664323836303066613166306361643534343632613030313537333665303434 +3264613266343064350a656437376530316232666564646337396161333964373232633937373136 +37346331353163303735393862646637316461646365623763363233373136363331386261343232 +63376536666230653135623935666239363363386635376261393036313832363762373337316565 +64663964303465373139386334613461396637396436623834393166666439356438333563386437 +34326633636664376531656339623238636461646363356433666639346166643935316336323330 +64363735313363376664616137663063353939326135393965666331636530313933643634346334 +32356661316366313934376232666233663865363739356130613766353234643066316236396262 +31643064323062636630626431303633313735303561613338373564633538653265336636383265 +35643032393833363563386630316262653135656632303565343364626133623666363033383366 +34316337323362303639313836616365623932653530343237396162303639646533303761616562 +65653036306133363739613438616132323839666465363936666331353935326639343063363462 +38663334666537646332363231363538633435626332303662316232663564363164626431303830 +34336664346431333236666262643964346334313737666261313864656661313837356231313134 +31323861333234626563336534316166633838313633313361346665616163346137623632303462 +35393761643566616566636339663533373865366364633130373637663839323065313965353738 +63353236373630316263316431646162376639376333386339376362626435316230376439386663 +31343666656461363632646562373834333636326435663531353039396338656265663539353334 +65303835656463383830353865633432623735653038353061663633666663313362616333323862 +63383330636263363162346334353030333137653165366530333434343266303161626333623239 +62366463633963656135326364646465663233653461346662333462383863396266643866333066 +35386534336564353737383962643438373365663238373463323632323830306530666430613336 +65623437366339303136643234306438613630376334356564336261363338643762393435306564 +30363832356638643561663039663864666432616263383634333336623633343239663435323461 +62376636383365643231306337666638323931376166663730393163313366633662633334373136 +35336239333861636237656330306536363363643538396464326161386239343333666163613931 +66636335323232613839663333613763613239616433303963326563306331313361633765363535 +34666432393330373438383761393662663936646432376439396465303439346135343661653232 +31353363636563613634313034383833313466636638333036346333356432393062316437336565 +37636235633538663062636166383163613935656237353330643531376636613633616263633161 +39303738636432643933346162326637623066346332666438333232366433386334343163343964 +35663665306361633537313731656232646430656464633662323764663633663033363834626161 +63383934636164373331633961316361626636316133633865343862366130343932363038626435 +38633837363734303531323466613366316363366634313165653466336234323533386361666663 +61663566656261376431323733386331393262323662363633646334653534363038663531643465 +30346135386466386236386534326637303962343861633734313465663335306130653236316564 +63333436353538636361373232356431346139623538356135376362613339353338366432313032 +63623964643939646334343336353535373730663562633932656430323831623262376262306265 +30356537646230336662303838393363306332303766633131616237373264353761363934613964 +33613964333563316263636330383138356339363430356137613935343466313665383263313730 +37643532316466346632623463376664616531653162663533323232663730616535656534393738 +33373765396363643334636434646431366438353331346636383838343233356437353133636565 +39383465303962373033376339353333326638336232656266303261633830363065636361366632 +62303466643366613430396564363439306431636330636261373932353938383965383261666436 +34336534663333613232306461323862303938613533376635356434643761646566613534663435 +39346232376535326334326161303665343737666562653837643835363238626638653066396337 +63623538323134376263653335336537646639373562373138633463383133663564