1
0

Compare commits

...

6 Commits

Author SHA1 Message Date
d1eae9b5b5 Configure baclup for sqlite databases 2025-05-02 19:05:17 +03:00
76328bf6c6 Update gramps to v25.4.1
- Inline vars into docker compose file
- Replace redis with valkey
2025-05-02 18:40:13 +03:00
a31cbbe18e Add backups with gobackup and restic 2025-05-02 17:34:31 +03:00
132da79fab Add utils for backups: task. restic. gobaclup 2025-05-02 10:57:42 +03:00
676f6626f2 Update netdata to 2.4.0 2025-05-02 10:33:56 +03:00
dda5cb4449 Update eget installation path 2025-05-02 10:31:41 +03:00
13 changed files with 312 additions and 160 deletions

View File

@ -22,11 +22,13 @@ tasks:
cmds:
- ssh {{.REMOTE_USER}}@{{.REMOTE_HOST}} -t btop
edit-vars:
vars-decrypt:
cmds:
- ansible-vault edit vars/vars.yml
env:
EDITOR: micro
- ansible-vault decrypt vars/vars.yml
vars-encrypt:
cmds:
- ansible-vault encrypt vars/vars.yml
format-py-files:
cmds:

View File

@ -2,34 +2,35 @@
services:
grampsweb: &grampsweb
image: ghcr.io/gramps-project/grampsweb:v25.2.0
gramps_app: &gramps_app
image: ghcr.io/gramps-project/grampsweb:v25.4.1
container_name: gramps_app
depends_on:
- gramps_redis
restart: unless-stopped
ports:
- "127.0.0.1:${WEB_SERVER_PORT}:5000" # host:docker
- "127.0.0.1:{{ gramps_port }}:5000" # host:docker
environment:
GRAMPSWEB_TREE: "Gramps" # will create a new tree if not exists
GRAMPSWEB_SECRET_KEY: "${SECRET_KEY}"
GRAMPSWEB_SECRET_KEY: "{{ gramps_secret_key }}"
GRAMPSWEB_BASE_URL: "https://gramps.vakhrushev.me"
GRAMPSWEB_REGISTRATION_DISABLED: "true"
GRAMPSWEB_CELERY_CONFIG__broker_url: "redis://grampsweb_redis:6379/0"
GRAMPSWEB_CELERY_CONFIG__result_backend: "redis://grampsweb_redis:6379/0"
GRAMPSWEB_RATELIMIT_STORAGE_URI: redis://grampsweb_redis:6379/1
GRAMPSWEB_EMAIL_HOST: "${POSTBOX_HOST}"
GRAMPSWEB_EMAIL_PORT: "${POSTBOX_PORT}"
GRAMPSWEB_EMAIL_HOST_USER: "${POSTBOX_USER}"
GRAMPSWEB_EMAIL_HOST_PASSWORD: "${POSTBOX_PASS}"
GRAMPSWEB_RATELIMIT_STORAGE_URI: "redis://grampsweb_redis:6379/1"
GRAMPSWEB_EMAIL_HOST: "{{ postbox_host }}"
GRAMPSWEB_EMAIL_PORT: "{{ postbox_port }}"
GRAMPSWEB_EMAIL_HOST_USER: "{{ postbox_user }}"
GRAMPSWEB_EMAIL_HOST_PASSWORD: "{{ postbox_pass }}"
GRAMPSWEB_EMAIL_USE_TLS: "false"
GRAMPSWEB_DEFAULT_FROM_EMAIL: "gramps@vakhrushev.me"
GUNICORN_NUM_WORKERS: 2
# media storage at s3
GRAMPSWEB_MEDIA_BASE_DIR: "s3://av-gramps-media-storage"
AWS_ENDPOINT_URL: "https://storage.yandexcloud.net"
AWS_ACCESS_KEY_ID: "${AWS_ACCESS_KEY_ID}"
AWS_SECRET_ACCESS_KEY: "${AWS_SECRET_ACCESS_KEY}"
AWS_DEFAULT_REGION: "ru-central1"
depends_on:
- grampsweb_redis
AWS_ENDPOINT_URL: "{{ gramps_s3_endpoint }}"
AWS_ACCESS_KEY_ID: "{{ gramps_s3_access_key_id }}"
AWS_SECRET_ACCESS_KEY: "{{ gramps_s3_secret_access_key }}"
AWS_DEFAULT_REGION: "{{ gramps_s3_region }}"
volumes:
- ./data/gramps_users:/app/users # persist user database
- ./data/gramps_index:/app/indexdir # persist search index
@ -38,18 +39,17 @@ services:
- ./data/gramps_secret:/app/secret # persist flask secret
- ./data/gramps_db:/root/.gramps/grampsdb # persist Gramps database
- ./data/gramps_media:/app/media # persist media files
- ./data/gramps_tmp:/tmp
grampsweb_celery:
<<: *grampsweb # YAML merge key copying the entire grampsweb service config
ports: []
container_name: grampsweb_celery
restart: unless-stopped
gramps_celery:
<<: *gramps_app # YAML merge key copying the entire grampsweb service config
container_name: gramps_celery
depends_on:
- grampsweb_redis
- gramps_redis
restart: unless-stopped
ports: []
command: celery -A gramps_webapi.celery worker --loglevel=INFO --concurrency=2
grampsweb_redis:
image: docker.io/library/redis:7.2.4-alpine
container_name: grampsweb_redis
gramps_redis:
image: valkey/valkey:8.1.1-alpine
container_name: gramps_redis
restart: unless-stopped

View File

@ -0,0 +1,29 @@
# https://gobackup.github.io/configuration
models:
gramps:
compress_with:
type: 'tgz'
storages:
local:
type: 'local'
path: '{{ (backup_directory, "gramps") | path_join }}'
keep: 2
databases:
users:
type: sqlite
path: /home/major/applications/gramps/data/gramps_users/users.sqlite
sqlite:
type: sqlite
path: /home/major/applications/gramps/data/gramps_db/59a0f3d6-1c3d-4410-8c1d-1c9c6689659f/sqlite.db
undo:
type: sqlite
path: /home/major/applications/gramps/data/gramps_db/59a0f3d6-1c3d-4410-8c1d-1c9c6689659f/undo.db
archive:
includes:
- /home/major/applications/gramps/data
excludes:
- /home/major/applications/gramps/data/gramps_cache
- /home/major/applications/gramps/data/gramps_thumb_cache
- /home/major/applications/gramps/data/gramps_tmp

View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -eu
set -o pipefail
echo "Backup: perform backup with gobackup"
gobackup perform --config={{ backup_gobackup_config }}
echo "Backup: send backups to remote storage with retic"
restic-shell.sh backup --verbose {{ backup_directory }} \
&& restic-shell.sh check \
&& restic-shell.sh forget --compact --prune --keep-daily 90 --keep-monthly 36 \
&& restic-shell.sh check
echo "Backup: send notification"
curl -s -X POST 'https://api.telegram.org/bot{{ notifications_tg_bot_token }}/sendMessage' \
-d 'chat_id={{ notifications_tg_chat_id }}' \
-d 'parse_mode=HTML' \
-d 'text=<b>{{ notifications_name }}</b>: бекап успешно завершен!'
echo -e "\nBackup: done"

View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -eu
set -o pipefail
export RESTIC_REPOSITORY={{ restic_repository }}
export RESTIC_PASSWORD={{ restic_password }}
export AWS_ACCESS_KEY_ID={{ restic_s3_access_key }}
export AWS_SECRET_ACCESS_KEY={{ restic_s3_access_secret }}
export AWS_DEFAULT_REGION={{ restic_s3_region }}
restic "$@"

View File

@ -1,51 +0,0 @@
---
- name: 'Configure gramps application'
hosts: all
vars_files:
- vars/ports.yml
- vars/vars.yml
vars:
app_name: 'gramps'
base_dir: '/home/major/applications/{{ app_name }}/'
tasks:
- name: 'Create application directories'
ansible.builtin.file:
path: '{{ item }}'
state: 'directory'
mode: '0755'
loop:
- '{{ base_dir }}'
- '{{ (base_dir, "data") | path_join }}'
- name: 'Copy application files'
ansible.builtin.copy:
src: '{{ item }}'
dest: '{{ base_dir }}'
mode: '0644'
loop:
- './files/apps/{{ app_name }}/docker-compose.yml'
- name: 'Set up environment variables for application'
ansible.builtin.template:
src: 'env.j2'
dest: '{{ (base_dir, ".env") | path_join }}'
mode: '0644'
vars:
env_dict:
WEB_SERVER_PORT: '{{ gramps_port }}'
SECRET_KEY: '{{ gramps.secret_key }}'
AWS_ACCESS_KEY_ID: '{{ gramps.aws_access_key_id }}'
AWS_SECRET_ACCESS_KEY: '{{ gramps.aws_secret_access_key }}'
POSTBOX_HOST: '{{ postbox.host }}'
POSTBOX_PORT: '{{ postbox.port }}'
POSTBOX_USER: '{{ postbox.user }}'
POSTBOX_PASS: '{{ postbox.pass }}'
- name: 'Run application with docker compose'
community.docker.docker_compose_v2:
project_src: '{{ base_dir }}'
state: 'present'

48
playbook-backups.yml Normal file
View File

@ -0,0 +1,48 @@
---
- name: 'Configure restic and backup schedule'
hosts: all
vars_files:
- vars/vars.yml
- vars/secrets.yml
tasks:
- name: 'Copy restic shell script'
ansible.builtin.template:
src: "files/backups/restic-shell.sh.j2"
dest: "{{ bin_prefix }}/restic-shell.sh"
owner: root
group: root
mode: "0700"
- name: 'Copy restic backup script'
ansible.builtin.template:
src: "files/backups/restic-backup.sh.j2"
dest: "{{ bin_prefix }}/restic-backup.sh"
owner: root
group: root
mode: '0700'
- name: 'Create gobackup config directory'
ansible.builtin.file:
path: "{{ backup_gobackup_config | dirname }}"
state: directory
mode: '0755'
- name: 'Copy gobackup config files'
ansible.builtin.template:
src: "files/backups/gobackup.yml.j2"
dest: "{{ backup_gobackup_config }}"
owner: root
group: root
mode: '0700'
- name: "Creates a cron file for backups under /etc/cron.d"
ansible.builtin.cron:
name: restic backup
minute: "0"
hour: "0"
user: "root"
job: "systemd-cat {{ bin_prefix }}/restic-backup.sh"
cron_file: ansible_restic_backup

View File

@ -6,6 +6,12 @@
- vars/ports.yml
- vars/vars.yml
# See: https://github.com/zyedidia/eget/releases
vars:
eget_install_dir: '{{ bin_prefix }}'
eget_bin_path: '{{ (eget_install_dir, "eget") | path_join }}'
tasks:
- name: 'Install eget'
@ -13,14 +19,29 @@
name: eget
vars:
eget_version: '1.3.4'
eget_install_path: '/usr/bin/eget'
eget_install_path: '{{ eget_bin_path }}'
- name: 'Install rclone with eget'
- name: 'Install rclone'
ansible.builtin.command:
cmd: '/usr/bin/eget rclone/rclone --quiet --upgrade-only --to /usr/bin --tag v1.68.2 --asset zip'
cmd: '{{ eget_bin_path }} rclone/rclone --quiet --upgrade-only --to {{ eget_install_dir }} --asset zip --tag v1.69.2'
changed_when: false
- name: 'Install btop with eget'
- name: 'Install btop'
ansible.builtin.command:
cmd: '/usr/bin/eget aristocratos/btop --quiet --upgrade-only --to /usr/bin --tag v1.4.0'
cmd: '{{ eget_bin_path }} aristocratos/btop --quiet --upgrade-only --to {{ eget_install_dir }} --tag v1.4.2'
changed_when: false
- name: 'Install restic'
ansible.builtin.command:
cmd: '{{ eget_bin_path }} restic/restic --quiet --upgrade-only --to {{ eget_install_dir }} --tag v0.18.0'
changed_when: false
- name: 'Install gobackup'
ansible.builtin.command:
cmd: '{{ eget_bin_path }} gobackup/gobackup --quiet --upgrade-only --to {{ eget_install_dir }} --tag v2.14.0'
changed_when: false
- name: 'Install task'
ansible.builtin.command:
cmd: '{{ eget_bin_path }} go-task/task --quiet --upgrade-only --to {{ eget_install_dir }} --asset tar.gz --tag v3.43.3'
changed_when: false

34
playbook-gramps.yml Normal file
View File

@ -0,0 +1,34 @@
---
- name: 'Configure gramps application'
hosts: all
vars_files:
- vars/ports.yml
- vars/vars.yml
vars:
app_name: 'gramps'
base_dir: '/home/{{ primary_user }}/applications/{{ app_name }}/'
tasks:
- name: 'Create application directories'
ansible.builtin.file:
path: '{{ item }}'
state: 'directory'
mode: '0755'
loop:
- '{{ base_dir }}'
- '{{ (base_dir, "data") | path_join }}'
- name: 'Copy docker compose file'
ansible.builtin.template:
src: './files/apps/{{ app_name }}/docker-compose.yml.j2'
dest: '{{ base_dir }}/docker-compose.yml'
mode: '0644'
- name: 'Run application with docker compose'
community.docker.docker_compose_v2:
project_src: '{{ base_dir }}'
state: 'present'
remove_orphans: true

View File

@ -11,7 +11,7 @@
ansible.builtin.import_role:
name: netdata
vars:
netdata_version: 'v2.2.0'
netdata_version: 'v2.4.0'
netdata_exposed_port: '{{ netdata_port }}'
tags:
- monitoring

View File

@ -16,6 +16,8 @@
- jq
- make
- python3-pip
- sqlite3
- tree
tasks:

View File

@ -1,14 +1,8 @@
---
base_port: 41080
notes_port: "{{ base_port + 1 }}"
dayoff_port: "{{ base_port + 2 }}"
homepage_port: "{{ base_port + 3 }}"
netdata_port: "{{ base_port + 4 }}"
wiki_port: "{{ base_port + 5 }}"
nomie_port: "{{ base_port + 6 }}"
nomie_db_port: "{{ base_port + 7 }}"
gitea_port: "{{ base_port + 8 }}"
keycloak_port: "{{ base_port + 9 }}"
outline_port: "{{ base_port + 10 }}"
navidrome_port: "{{ base_port + 11 }}"
gramps_port: "{{ base_port + 12 }}"

View File

@ -1,69 +1,106 @@
$ANSIBLE_VAULT;1.1;AES256
31326232656538373331333566386562333865623563313931366165353939633431323062333663
3463313831316433383162383933623262636231356331370a393231393536653164653361663232
31626661623334636263336534323261336237323935336366366161366665336537383634653265
6563386130326531610a626463323739626531653731336366626139396331393531623232623332
32383937656365666239306565666232613361616439633438316636356433393139616663663433
39336631663633313362623263626237313839356562656462323235626433386138313132643732
30656165663362316433306438376266363530313539323338336563333365366465366530396465
30633431643563356131656332313564663963356662616235306333393137383135326665646530
30343131646430626462626563366133386639643033386130383063656434326634346532396636
33393165626535643731616535396431656435343032333539623538663632333462666339323839
66613463366665616165613832333931356139303835323363346564343539643062373963633263
39653533356533393530346263623930396339336630383661316163303232326135663761366534
64383766326134386462666662633965336135313064326536316332646364623430303838333737
33633332616231666434613532363963646433303531343362636232363232353161343735616533
37383064353839336436663134653237303962616132393534366234633338616634396536666338
34633237623662353066613936373862383264393931343830656563316662393133363536363331
65636531663838383538656339386134373762636164343630353232303639393130663035353335
36333461613031663435656465633934613934363238313462656234313833616234663265343436
39336635633232396130623166326662376234663632346437303131366534356439306238343764
30653732313266613430626637636235393831323237653665346238373363303439656438393436
35343464656164303565393430663930653764303761633737636532313964383037313665333064
35393466316462323566626235313637313136323331626134663863636534363666396236663132
31616164316666303465653863656536666331363433363163333566343338386130616333333364
61633331633965383834356630343237653466626237656164643435343433626434366331346531
36343165626664363039663439363236346466343061656137663932363962373639646339363164
32623265303762343833343535333463613138356336643563323435356431616366653539643065
32623639663137356262623131353135333630643435323462643032663061653066636662323233
36636364396465653637396464336161303761633366303339653834323036633666373630343762
34383734346436633962636131353235346462636632373461376265633365383861396262303032
37376434626637616437613364336536666431663434313238373333303362383538623962396262
30323334643064343237663862373034663338356430393935336131663634646130363733393164
33383832633630396434386339313331363035383634616463383363386433643334623331326261
33333463353133306530333937646238633831376165373735363462353263333930396264383039
30666239313237613437363635333863663137633961336235313036306335373166633465303239
31636135323965623836383231396535366263636164363737313761613531613633303461386533
66653230323962626539343338336533333435323565616536643436336534323730373864666366
39356330643562393434363032373338373363383565643934383464363634353435383731636534
36313031373365393236363735636234616134646334306266643336376336343464623534663766
62376330353232376232346337323562306437303631303833383430666638393835663033326135
31333166386632663564383637373266333961353139333662303333636439393835363630363539
61623435396638653937343866373165623530373664633665333962376235646163373762373734
62373262393562643737653965636462323065343530626132393834633361623531333361613337
62653966343863623666326463356130643766346638656436643738613032333462663061346335
33373263303438383236353733343766356338323231663161303830333663366232386461643730
37306663373262633635326338633136313938666230343334353735313731626363316436336130
66643264313239343334323362303165643966383661653239373731306433346465613839616261
33313438623235343366636630373963626664356531313934363035303137613465663434333265
65393665626539623232616336663832346265613934313666616266383537613066343930656237
62653935663234376634316433396631363232396337393165323131633632303330646538613330
30356361336432346435366537386362363630306333386131336663623661376163373039663461
33353936346462633732376132393339363334313137303965313762366439306361383963636130
37366336666330323665653266343662383065396563633238313564363863633165326166666634
61366666383236646161306465376635336334343461656436643161363038323534636632363464
65666133613437303931333534643235393438323138346130333338316233386536306238323463
64613335366430653766343061326361646339613363356563623466343466343930323032303532
61636561383531643664613833376636316364366166653365616336336564353130356564323331
33383934323166633338316265636363343232663033623732636636373437363837643237653464
63393436313836616335373562666532353338313035663632363265653162303233333566333538
61613563636234343433323635303462646362383763346264393734386130313362333736623236
33613237663064616330303733373434386538633463626332633534376465376135336230346366
38306135376539303131663237623764633633653933336162663636346361356664323565396430
38643262326132333832653536663535363136646336333236373661346431326430333161613535
65316438626436336235353765363233663131333063333330323731366266393466313062323539
30393564383430373661613737343634306138393566623830636633616430313531653736303739
30373439626362653639313162306237396330396633303761353635396235666333643339393061
35313535613264366435386338306633396631643838313962643334326236386237363935376531
36626338366136306631623235346138356132666632613466623132353161396464646539376665
31623862316466343435
30653161663966653439333533633634663133323666613933326363326139656632623061373834
3661633566366561316663306130393561653835623362640a316134376661396632333336333162
36323236346563396332316166396138356266636434646437386664333764636537623631323730
3330646164313062310a333765356430323634373434303036393130656234353637613234366138
63613531343761656330636235333262363165393839623432643064323638663337306237323262
30316661623835323861616564343535653163383335663132653434343537623935326437626239
30616535396334626139343931376237396462343535353066666666613961626265626239303866
61303839333866653631363462313664626539333032666561643864376563633035333234663730
34643732643731343937346133353931363666393336343339313364613062633533323963643061
35626265616136613066663064653564306237646532303637626436346365623065636436383934
37323237303939303036653865333232633665353537383931366561376664306435343238313033
39343564323163386238386663343937393566373766633531333966303430306530646535313537
64643961636533626539303932303231306230313765663435383138313165626638373564316131
32666562333166663932393830646533633261636434643234396264303730633165386638386239
37373565646662616366643334636264653333633330313238366262636437343339636130323462
38333039326462616330303663353666666232373031623964303761343963636539383165633064
33643361616164303734633435613362343265666630386565323663653237663664346665306635
34343737656637343836346334653330343633323663653766616266353635303032343266333331
37323738313732343831636531633238663764376537616562656231613630373331376332323138
64643564363064366635626230363930316232396530393862356334333261323164643937346463
31616463323637326161663038653932356464653336393032323463633762386264623265346537
31613733323434383932343733643666386233363664633234336333633438626261616638303463
63636135653333386233643637303231646332386661313665333932313938316536303961383933
62333264626566366466323066356338633136323966333535353266323066383830343538373031
36323837343836373163363632636262366361303266393534643333323737656463303438653237
31303133363338343130623831333731373634333235343537316331613663356638363234303730
30396430326163366539376466313038306338643638656466613732666132653838356437616437
61376461323238396437663635643735666533373231383238383235363530396339653461326339
64313033623665326332363433323830316330623965346334633163383631346133393966663965
33366363306365306365333166653736663764326261336531353839616161386334346136636535
37316466656335373638333937653163396434623865656162326139363265656263323831663832
37386566663936393533366131393338626361313432386130643462636166396563663237353163
33633331363764393237373730653930623037623931336539303935343230643038643833626339
33666438323431346538636434656532633538313439393335373736336633363864613437343735
39633966633630396463313431633935616236313964333265396466653339666239373564326633
65623466386166383464646338363738333531313830306566336432313736363233636633373135
61353139373965303366366230363034663664636631643739353634666334346137393331386137
30616132636463653361653131646639376264626631616538623730613936623564306337646663
66646235356435373537633235633635353437323237656266633436636636376430353266663533
39643761663062393834616532306135303161643534623530616434343764383462393961366665
39316537356535346334633731326435626337643335386361383861633362336336313364373232
30613132386264613039333838353536343565336562336539333261613762393233366665376139
35623135326164376564373263366262356564366136343165386634653737373965643235633638
38616339373365636164643462323066663162396231373765623063306438656339613239336537
64376261313332373863633864306439313735613238313066613064626534326566633736393366
31393038333339363864373838393038666536666337333165646530303736353433373365653139
64646632333638353437616663653837663731323638313862633135346138346234383364643437
35626465386438663838323135316133306561613166353965356134623938633737643639303039
39333135383466306264336339666532313639613264353761326635373332343130636130356534
63636332383935636337656434666566666332383830363131343934313638343933643365663366
37313534623431326131656135343331373964303736383633326433386633303731376430363833
38386264323562333366643939633631666466633032616536363031643665663131373938353131
63373033376438633734363163323430613363373661313061373064323430346362656662326638
37666532306638646234633966643964346232383036376562613433323134653339353164326633
32383664623934303164343634613063363839306461306461336532393764326531313630656461
38383137306461646332636436373738353431613131366338376565396531376661393865333930
32323733613864343137306530353537633333623265373434393237633631653637636138393731
30386561386539333564333662343637326430646434353938613433333337613965313231313237
35316430363665386166383364636430313362313432306638656462363531636338376331393862
37616162313966616263303433616430626466343062313737313237623865653934623366373564
31373661626261346533643936303562653561643962623237663866366664613162653865333638
61613166613030386534386562323332323634313937643565666363653263383163663238303533
37306161613066343839663032653039313235666363323535386134373932363039396233366361
34326562613233323434373466383364646562303662616561343637616631316464346564343163
61616239623163656663363863323562303731613836383438623166643638333262343037623166
66313636663939306636393431613133633638643235666661306136383539383431643435373634
36313833633633333430396535366238333233396238316533366637343565333130633737643338
30376336313835363936613565633433393736643330393738356632333739386461663937393037
32366166316162653064633161373031383563356334633731653433396533663431316435393639
30366637356362336466326362643437326139643361633431306663356534313536386661353931
36363065373662363231626339333161373436623064666330653436386162313332386462663065
63316531313930303162326233333734313939333830363039393235316636613039396134323064
36643637643432383264336231373564323066653930393636616234353239623435613634373661
38316334373864303066333065343733633063396137656535653336363731326266643663333163
35376533343435393563393930383630316163396265303430613466343132316631346434616239
66643130636431306532383432653762316338653337653731376266373730646366316562353033
61633364303065353536353234323962643932323730373138353965343039643162633334373734
64626161633865303638623366623463356338323763396661383862343131613939643034313531
35376462663438656232366638656135616634646164656136636233323030343231336339633436
30356264626230316234623335656264323837366562383538326536306133346632353463666462
36376630323530323363666630303739626661306634313938653530623566626661616233663737
30333237393133386533643466663465656465313731313232373533653233643831613636343666
65323765616335643965386165613631663661363961376430383332346335323337313131313031
64626566326131306566393266336266316239656234353631326461616233626337373037333631
32376334396431633032663364396630613034616238363837373261643165366561343462373033
64373735376362636131393233323738666434313363636430633433376261343735373464373336
37626662323439636233323638303765653034613332343831313861646566393738646335346163
66323935666138646535323235643531323931326361303937343033353737316661363239386238
64626430666335343431323364343263323731626264363831613461313237636466623539303832
66393934633836633730653033393235313138366264323532666561303261376338633930363637
64363562663363306234323737653130346239636662303064373731636230666137383866316537
32663838366463313338316537343939623061666133353966643761653030383037623138306133
34636434393037653230373662666135396465623263363233323139636334313131643731613162
39633836326661336566653031373163363634663939643563316461336133303061343034353136
34386231363239393436303364386338626537306166393734653365333938386432326632653534
61303662346538653961363135333863626232623438626264623066643736343734663136623766
61333163666161666365383830653731656465646233613431386332303637343637366133613462
38666362323733303664333865376664383661383666633138666235313634323432303734393464
30623962633566313836306165613134386666623166326666323035303934313834326136663863
33306634386635356361643338373038316465326532656433336135306635376337623965343134
31623434646632313865363934323665323062373063373062333463313861643939626232616661
32303534383230316230306238633863323631333934313439303335616531363762326136356662
36333934643761333935373163353766393464393538353262613137613161323731353638616164
63643163663632666634363466636166393863616433633963663466313132306130663964633764
6532