diff --git a/immich.yml b/immich.yml new file mode 100644 index 0000000..5a3e9d4 --- /dev/null +++ b/immich.yml @@ -0,0 +1,10 @@ +--- +- hosts: webservers + roles: + - name: immich + db_url: postgres://immich:{{ postgresql_users.immich }}@postgresql:5432/immich?sslmode=disable + external_domain: https://i.comfycamp.space + openid_client_id: "{{ immich.client_id }}" + openid_client_secret: "{{ immich.client_secret }}" + openid_issuer_url: https://auth.comfycamp.space/application/o/immich/ + openid_button_text: Login with Comfy Camp diff --git a/roles/haproxy/files/haproxy.cfg b/roles/haproxy/files/haproxy.cfg index 5f94d98..03ad930 100644 --- a/roles/haproxy/files/haproxy.cfg +++ b/roles/haproxy/files/haproxy.cfg @@ -70,6 +70,9 @@ frontend www http-request redirect location /index.php%[capture.req.uri] if host_nextcloud path_well_known use_backend nextcloud if host_nextcloud + acl host_immich hdr(host) -i i.comfycamp.space + use_backend immich if host_immich + acl host_comfycamp hdr(host) -i comfycamp.space acl host_comfycamp_tor hdr(host) -i comfycgmgfvowbbw2ckkobuvk4cejo2e56uxrhznravxnrl7itftpkad.onion use_backend comfycamp if host_comfycamp || host_comfycamp_tor @@ -190,3 +193,10 @@ backend prosody option http-server-close timeout tunnel 1h server s1 prosody:5280 check + +backend immich + mode http + option forwardfor + option http-server-close + timeout tunnel 1h + server s1 immich-1:2283 check diff --git a/roles/immich/meta/argument_specs.yml b/roles/immich/meta/argument_specs.yml new file mode 100644 index 0000000..2c3bab1 --- /dev/null +++ b/roles/immich/meta/argument_specs.yml @@ -0,0 +1,26 @@ +--- +argument_specs: + main: + options: + db_url: + type: str + required: true + external_domain: + type: str + required: true + tz: + type: str + tag: + type: str + openid_client_id: + type: str + openid_client_secret: + type: str + openid_issuer_url: + type: str + openid_button_text: + type: str + openid_scopes: + type: str + default_storage_quota_gib: + type: int diff --git a/roles/immich/tasks/main.yml b/roles/immich/tasks/main.yml new file mode 100644 index 0000000..e89e890 --- /dev/null +++ b/roles/immich/tasks/main.yml @@ -0,0 +1,65 @@ +--- +- name: Create root-owned immich config dir + become: true + ansible.builtin.file: + path: /etc/immich + state: directory + mode: "1700" + owner: root +- name: Create nested immich config dir + become: true + ansible.builtin.file: + path: /etc/immich/_data + state: directory + mode: "1755" + owner: root +- name: Copy config files + become: true + ansible.builtin.template: + src: "{{ item }}.j2" + dest: /etc/immich/_data/{{ item }} + loop: ["immich.env", "immich.json"] + register: cfg +- name: Start redis container + include_role: + name: redis + vars: + preset: persistent + container_name: immich-redis + docker_networks: + - name: immich + docker_volume: immich-redis +- name: Create immich volumes + become: true + community.docker.docker_volume: + name: "immich-model-cache" +- name: Start immich server container + become: true + community.docker.docker_container: + name: immich-1 + image: ghcr.io/immich-app/immich-server:{{ tag }} + env_file: /etc/immich/_data/immich.env + volumes: + - /etc/localtime:/etc/localtime:ro + - /mnt/hdd/immich:/usr/src/app/upload + - /etc/immich/_data:/etc/immich + networks: + - name: haproxy + - name: immich + - name: postgresql + recreate: "{{ cfg.changed }}" +- name: Start immich machine learning container + become: true + community.docker.docker_container: + name: immich-machine-learning-1 + image: ghcr.io/immich-app/immich-machine-learning:{{ tag }} + env_file: /etc/immich/_data/immich.env + volumes: + - /etc/localtime:/etc/localtime:ro + - /mnt/hdd/immich:/usr/src/app/upload + - /etc/immich/_data:/etc/immich + - immich-model-cache:/cache + networks: + - name: immich + - name: postgresql + recreate: "{{ cfg.changed }}" diff --git a/roles/immich/templates/immich.env.j2 b/roles/immich/templates/immich.env.j2 new file mode 100644 index 0000000..b3f26ad --- /dev/null +++ b/roles/immich/templates/immich.env.j2 @@ -0,0 +1,4 @@ +TZ={{ tz }} +DB_URL={{ db_url }} +IMMICH_CONFIG_FILE=/etc/immich/immich.json +REDIS_HOSTNAME=immich-redis diff --git a/roles/immich/templates/immich.json.j2 b/roles/immich/templates/immich.json.j2 new file mode 100644 index 0000000..43d5951 --- /dev/null +++ b/roles/immich/templates/immich.json.j2 @@ -0,0 +1,176 @@ +{ + "ffmpeg": { + "crf": 30, + "threads": 0, + "preset": "veryslow", + "targetVideoCodec": "vp9", + "acceptedVideoCodecs": ["h264", "hevc", "vp9", "av1"], + "targetAudioCodec": "libopus", + "acceptedAudioCodecs": ["aac", "mp3", "libopus", "pcm_s16le"], + "acceptedContainers": ["mov", "ogg", "webm"], + "targetResolution": "1080", + "maxBitrate": "0", + "bframes": -1, + "refs": 0, + "gopSize": 0, + "npl": 0, + "temporalAQ": false, + "cqMode": "auto", + "twoPass": true, + "preferredHwDevice": "auto", + "transcode": "required", + "tonemap": "hable", + "accel": "disabled", + "accelDecode": false + }, + "job": { + "backgroundTask": { + "concurrency": 1 + }, + "smartSearch": { + "concurrency": 1 + }, + "metadataExtraction": { + "concurrency": 1 + }, + "faceDetection": { + "concurrency": 1 + }, + "search": { + "concurrency": 1 + }, + "sidecar": { + "concurrency": 1 + }, + "library": { + "concurrency": 1 + }, + "migration": { + "concurrency": 1 + }, + "thumbnailGeneration": { + "concurrency": 1 + }, + "videoConversion": { + "concurrency": 1 + }, + "notifications": { + "concurrency": 1 + } + }, + "logging": { + "enabled": true, + "level": "warn" + }, + "machineLearning": { + "enabled": true, + "url": "http://immich-machine-learning-1:3003", + "clip": { + "enabled": true, + "modelName": "ViT-B-32__openai" + }, + "duplicateDetection": { + "enabled": true, + "maxDistance": 0.01 + }, + "facialRecognition": { + "enabled": true, + "modelName": "buffalo_l", + "minScore": 0.7, + "maxDistance": 0.5, + "minFaces": 3 + } + }, + "map": { + "enabled": true, + "lightStyle": "https://tiles.immich.cloud/v1/style/light.json", + "darkStyle": "https://tiles.immich.cloud/v1/style/dark.json" + }, + "reverseGeocoding": { + "enabled": true + }, + "metadata": { + "faces": { + "import": false + } + }, + "oauth": { + "autoLaunch": true, + "autoRegister": true, + "buttonText": "{{ openid_button_text }}", + "clientId": "{{ openid_client_id }}", + "clientSecret": "{{ openid_client_secret }}", + "defaultStorageQuota": {{ default_storage_quota_gib }}, + "enabled": {{ (openid_client_id is defined and openid_client_secret is defined and openid_issuer_url is defined) | string | lower }}, + "issuerUrl": "{{ openid_issuer_url }}", + "mobileOverrideEnabled": false, + "mobileRedirectUri": "", + "scope": "{{ openid_scopes }}", + "signingAlgorithm": "ES256", + "profileSigningAlgorithm": "none", + "storageLabelClaim": "preferred_username", + "storageQuotaClaim": "immich_quota" + }, + "passwordLogin": { + "enabled": true + }, + "storageTemplate": { + "enabled": false, + "hashVerificationEnabled": true, + "template": {% raw %}"{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}"{% endraw %} + }, + "image": { + "thumbnail": { + "format": "webp", + "size": 250, + "quality": 80 + }, + "preview": { + "format": "webp", + "size": 1440, + "quality": 80 + }, + "colorspace": "p3", + "extractEmbedded": false + }, + "newVersionCheck": { + "enabled": true + }, + "trash": { + "enabled": true, + "days": 30 + }, + "theme": { + "customCss": "" + }, + "library": { + "scan": { + "enabled": true, + "cronExpression": "0 0 * * *" + }, + "watch": { + "enabled": false + } + }, + "server": { + "externalDomain": "{{ external_domain }}", + "loginPageMessage": "" + }, + "notifications": { + "smtp": { + "enabled": false, + "from": "", + "replyTo": "", + "transport": { + "ignoreCert": false, + "host": "", + "port": 587, + "username": "", + "password": "" + } + } + }, + "user": { + "deleteDelay": 7 + } +} diff --git a/roles/immich/vars/main.yml b/roles/immich/vars/main.yml new file mode 100644 index 0000000..604a590 --- /dev/null +++ b/roles/immich/vars/main.yml @@ -0,0 +1,7 @@ +tz: Asia/Yekaterinburg +tag: v1.119.0 + +openid_button_text: "Login with OpenID" +openid_scopes: "openid email profile" + +default_storage_quota_gib: 20 diff --git a/roles/postgresql/docker/Dockerfile b/roles/postgresql/docker/Dockerfile new file mode 100644 index 0000000..09b8b90 --- /dev/null +++ b/roles/postgresql/docker/Dockerfile @@ -0,0 +1,8 @@ +FROM tensorchord/pgvecto-rs-binary:pg16-v0.2.1-amd64 as binary + +FROM postgres:16.4-bookworm + +COPY --from=binary /pgvecto-rs-binary-release.deb /tmp/vectors.deb +RUN apt install -y /tmp/vectors.deb && rm -f /tmp/vectors.deb + +LABEL org.opencontainers.image.source="https://git.comfycamp.space/lumin/homelab" diff --git a/roles/postgresql/files/postgresql.conf b/roles/postgresql/files/postgresql.conf index 3dc9600..a53c34f 100644 --- a/roles/postgresql/files/postgresql.conf +++ b/roles/postgresql/files/postgresql.conf @@ -682,7 +682,7 @@ log_timezone = 'Etc/UTC' # notice # warning # error -#search_path = '"$user", public' # schema names +search_path = '"$user", public, vectors' # schema names #row_security = on #default_table_access_method = 'heap' #default_tablespace = '' # a tablespace name, '' uses the default @@ -744,7 +744,7 @@ default_text_search_config = 'pg_catalog.english' #local_preload_libraries = '' #session_preload_libraries = '' -#shared_preload_libraries = '' # (change requires restart) +shared_preload_libraries = 'vectors.so' # (change requires restart) #jit_provider = 'llvmjit' # JIT library to use # - Other Defaults - diff --git a/roles/postgresql/tasks/main.yml b/roles/postgresql/tasks/main.yml index 8097a6c..68fff2d 100644 --- a/roles/postgresql/tasks/main.yml +++ b/roles/postgresql/tasks/main.yml @@ -20,7 +20,7 @@ become: true community.docker.docker_container: name: postgresql - image: postgres:16.4-bookworm + image: git.comfycamp.space/lumin/postgres:16.4-bookworm networks: - name: postgresql volumes: diff --git a/vaulted_vars.yml b/vaulted_vars.yml index d1021b7..22b41ff 100644 --- a/vaulted_vars.yml +++ b/vaulted_vars.yml @@ -1,199 +1,211 @@ $ANSIBLE_VAULT;1.1;AES256 -61316332623931633333656331386131633431616565663736366663353566633232646163643538 -3435653061376133333636303166636532663639306134640a353934343530323330393762616161 -33343633393836623630323261396632303832616231666233643665663837633565613034313163 -6333333865316336310a646332323062343537363162373062653938343036666264653938653433 -37393336303766383335653532383832313138306561323735623631643934336537616264383038 -36383336343063393335396432383431633066623339653634656533383137646430363430363964 -39663964376464373137306562326234346231326337333861666139626361643431643437303663 -36396436626630353037646130626261303239383638663132336332323264313431303565353061 -65336465653566393861306430393463383562323935663561303563643634623034636362313133 -63343434303039326331636534303363396639356161663533666234653164613362333935333738 -64383563363338376331653263396431613631363438356435316235663530343332346230633632 -34616161376363336465383034393966303231626161343032356536363265373961623634633031 -39363232356338326166376336316135313636366135343633396137383531363965653233333533 -62643135643032633961326239303762643331393835626633353237396432313239323438346536 -37613535363536386630343432366466653131303664363865393863343234656434373030653463 -38363366643337383934376239333065373462613362376564303364666231363766666439363861 -39633334343333666633323733646431626438633162356336346531663064663137396434393331 -31356361653066383838353432633863643966326634613361373464343637643766356262366238 -38343931313239316165386237363531653362313034333865386565373134623230623935383662 -38333832323833363739653961616637613263393339323830376266626130383334306139353233 -64383037386261613265373561323932666339646666323962396361643062336162646466343135 -33313339313330333339346263386361653937363836626638646630666231326131306132663763 -31653163363034366439336233306231303738656531366630616539633137353334353737343566 -62316534396232303531613236653833313966653734666665393066313162386463343533663539 -61363166363163346531653039643036376561353534623536316634356233326331356362353865 -37363961353239353862613763333431313632353030373038616230626561346532383661343462 -31313461643839643462656362666438316532393939636266636237303235333738373335326666 -39643531643064393266343465333565626636346431366239633434303436613466396566343832 -34653739633639653864616637333137633861376366626266663162616366343238306634666332 -66353864353438336161626561373830353565653932636666303262316561306637373539336639 -61626538623131666661353366643432313035353466393031666561333362353263366161653233 -31353135613165663837333230376432346663306632623930636238646664663934653532343935 -34346630663132323333353461303235393462316463336334376366643833616639396533356434 -31613437393466346265343762643864376535303264633936333531623539313934336163623636 -33363063373762336464653266663264303264663035646262386431346565393834316165383131 -33636637333162383161626139316466616166643330633463323665643034643832373362393936 -35306432613664376366663937613532356436353666353137643436343163623434366263626266 -63643432343937336337313636333764386433386435653438316330313634666166646135336139 -32353432653963363263346234313734346466613133633538333964633334366436613265323738 -36643336356261306139383032373466626462663236393438363338306137383331333432356266 -62386232393662396439326237633661386631373534636335383361303365613961623130386161 -35396239383163666562343534663937373331363938353539346436336661386236313432643763 -61643633326334343465623636656135643961333561623035353531613264363262313061366330 -34633133383164363465326232363936656634326562663664386363653931333563303136663732 -62633162643235303663323834363832353936336637383137353534393233643861393139386231 -36353433353939313066333461366661316238313637353962646236336134623066353761343937 -64653265656431306639626139313063323831613837313431613963633036343366623137326666 -38396431383036323562333163373339383736636534303337626635643262313439323166666565 -39353065663762343239333732353839313663393936666136663338343532386435323563623265 -61346230326165303234323439363034653466643936366132366437313062383031646630386636 -37336533336264646464393530363531383631366332393238643866356662623363646434373137 -61633064333131653535383436356661313537633330396265303163393034666631306334386164 -36353630663062613934353633336430646136393433363732363331663164373765383463616135 -31633962636466363162626163353139643138303534646662343133393738343830616239393632 -37363464396438313239363962653364623937336339326264303831643031393164396234336561 -35636635353665353534633065643762616638313031653764323163303462613332633665316131 -37353366363066313735396134323633616262663335343431383934613539663661346463646434 -31363737373261626434373533626464346630313766346538383137613733363130623238323736 -33396339336464333365336361333465366538383463393635393037306564386461313261393337 -64373034616261633034616630646638643065656537353930663666373336396637363137316434 -39343631633339623561306633393935316162386436613232376338623664353630333264643831 -30396133353364323865333935356662356661323762613533303361666462643839393361653865 -63663263376631343564396262313037363535636635626230353137313833633564356165343331 -35663465306638313032643233303763323738396165663661656263393664373037336333636134 -62613866663736666138613262386137613930306431333936666233363131663136386237653862 -34363739616437323638313965313365303733643730626432316264383533633038373564633533 -38666636336136333963313061336139626336613765643864613734353266336539323036343039 -65386338653461313531646136373666393165613136353431613133666532643565646334303633 -36313435306636323361313362616666623138333039346138326361396438633533316639616538 -62626632643562393331663231363262646166636134386130646339623538393766313332663532 -64643131393834636439376463323835653639323037323530663563343734313163646266336539 -37303365396334653439303634313431323337346238353037376461373933313463343464343135 -37313332653839366139313034626136373861666530666639396438383963623763653239366636 -63383333303562396261653930663437303262336531323433666239666563666162393433333139 -62343031656537303939616164663863356430383535653532633531393566653166623837353230 -30663263373763653962386337363033646562336332373236346137316264643732366564363639 -32353766346566626564383664313535613138356461356237643465363163613736633631393836 -33323036623464353261636336333462353033613938623261356535616431643734663830303436 -36373235343532346362666433323034353437623531376634633134656462326135376633633131 -32356163663036373439346463646463323763346539333133393038376464636136623461393133 -36666562613631343665303836366166626464646166613733623662313031396530383933323632 -32656337623564633162383130653930343766623261646662663837306538353531373436353539 -34306639353436386665306364353432336230663830636465346232666239376662343164303763 -37396664623764633066366330653332613237656437313332396532313639326235633133376262 -35393862653530386438656562353661326430306537336439383437393935303938353764663864 -64373931363761396563306663343932643530346236633736363530386133373838346637636436 -33363234316534373161323861363066326362326464373462623433366438663861613230646639 -31386165356137313233303534613834653966383736306239336435653933363836396239386435 -32656236613366363633353934636533343661376666623964633935633235313062393836333034 -35303663653135366134376466636237373330373664623934343163353431366534643338613239 -31326531323934613236313866613632333338323834396464346635663135373030373337643161 -66386262383232383235626239313035376238616466613064626561663135363661353035633363 -65656532393765613439356134333637616566306532383163613664353034323461356231316531 -65613633343562613233303563623463653539626130373863646132306237386130333035383433 -32306662666431313738343135613064323063303066646136633538353266623339323463633933 -36303038373264306634396663613835663463393264366162363633336538383831613233313966 -37336330376438623535396630313830336565346339323434363733323063643631346564393564 -36366137633761633932356137386661323831346130623465623332373566383437613461636633 -61376565366163633765366536373365316631316531323735356233343131363366313062643962 -61366461366639623363633135323234316237366263653563386634316335386237363638613236 -66316238313962653230633930663365643631666665383630373930373063343237393631393762 -65633030643634356636623931393832666530336536303430323761356433356562663733633031 -62323438323466623836313734646637346337633632633532393130353536396234363336663639 -63636463323436363835333737613435376231336634646533333961646532666539346332363362 -30643335613537623131346235303636663837386661333737303131636130616663626166613933 -65386564653332363635653539336630333530376439613161326233356433356262623630666330 -30343337303832656265313630386539666165373064356530323736393837383130383864613666 -31333664383862373564626363323365643236653762643861316562306239336230323838376430 -38633961356462313064353432623832663139616131346266613237363861313835373532396634 -31353163353334646532346236353838326339386233666336646662336132656533393036633334 -30326138626665346661306433626161303963396162373235363166633032393430343730613638 -39336135386461643538393136616436393432383036633036373865386230626232343236636633 -32393938323335333431343962383139613136656534613136636234633961373263336362346330 -32343066636237633263663530313239303438373431313664366362323433393366316339346531 -31326363363939373032316234333334653161356134376461343764636331623565613735663561 -31323039373136383839323061353036353238653436393062326135323464643933653764663832 -32353134623833323830383038333936626230643534383734326134303861633865393564396634 -31633836303136316333393731666633613865376164643337636137386431613239306566623637 -65643663376466616435306461383034353465343031346133653633313666663436646262616661 -62636438633032646564646565316130636135613931366238343561386134306136393237393538 -38393762646332316162333935623564346335303138333333396330346230656530346434376233 -33666135373630363538653736366162313266633731636438393761346537613232393734656365 -66663465316365373262303137303366613466646238623333326233643735363939353831326132 -33613736383861623861376233346633376362663465353531303463613934663434353630336330 -65313135366161356162306531656530303464666364666631633666383633373734366538373831 -32356464386663353638636165303635323661626464303865353866373037343264303436343431 -61636433376431633539303735636638643233643866343065356133643938383732376465663139 -35326266653036333931663161666531616465666135643537613936356262613237376636363861 -34623762636338623238666563393135646536396463386537313937643962343338316535363932 -37643539663730353861323861346666376434373934633038616436373636663931393261303462 -33636262376334373036363064363463316361613965626364386332306631633232313439333864 -36396539613733383563643739363334323537656161656362663638336632376131383865303434 -61656261303837643239643762303862353362363833623737356134386136323131373835653333 -63353833623265336561396362386332666230323239613762643137643530306533386438376137 -35643032653733316539623962303166666533626234356236353237613465663233363866393166 -64663966373134636130383237643239313430313436323637313434666366386136393735316466 -61366437653365323333303362383634376539393130333234366561383732373737396334613264 -66613835366131633763326365323531373934653266363362393664353366643035313062363532 -62326639373934646132646332616437353831653834373366623461343531613631633265336464 -30343864303562323430666538656239393530306664313464623034333031623234393037313430 -65383135366634326263653030396132396539666332313537613830613039646361326133666362 -62633235633139393361366264366536363733303266363530353635613165323833303863366238 -32316561623738333432653666616235353730393734363532363131336136623361346664326138 -31346661363038396363646534646261346433376239343761356531383364303062393831393062 -38383361633431303661353737626531346439363863306263643337646231653033653635313730 -35623734663930353930323062303761666131323163656561306432333036626139653937326338 -64323265333433363730353366363332363737613438653334353564373866383861366463303930 -35633531373265323363633066363938343561643662633262626362623466303931653565363037 -64303931376337326339393966376133383165373231303564393338666639653661623866393161 -39386630666630333261653764373131613237383038613137346662336131623038303661323863 -35343235613265333531353761636666323261636638636234306566643338313738653565643234 -39613930353666356630313938313165303239663962616361666238626537646634643331626132 -30333033353130373963373134656530313131653432643936323663353863303234313738396638 -63373630623166636536333438636631666139363837626339666361343962656365396261353934 -33646232303737616238303637326530623733326431343238383766653764616635636639333630 -30643931383464353962336338626465343637663137633365303366663937356531646330366465 -35396435363365393161636134356162396639313362373831376463636630653437623531396137 -63326438373639643333366432383930393335633666643664326434346338366636303866626535 -31346461343764363039326237366134366236346437653930353133343234346264323662623962 -32623832316665373034613435306438636235666638633864303534366261346463363163636666 -30663534373239393661313462653630393735386439363633373466323839653634366430356234 -31306463613937663330366665616437376164336234646437396564313937336432373230653939 -38633236393463366130323766656132313932376636383237313032633661393964383164323265 -34346430326465366239373230653538393962326434386136653134396239346263373436306130 -65383664333237653562383333306133396533313638656139383337346461326335313065386333 -32363863636238343438626564646265383132366666323931633831656531663630396138313837 -66653437653839326439306631333365316434383233613036303731373730613764633730393636 -38316564356533303235323361626139313566363136623363643638313864313261666261623134 -34336161393532383634616637303430303130343464303233346661316135323136616361623636 -31636439633438356637373464623163353135333439333861303965646563376462333938303430 -36623836616334383836636437376237353330373437636233353862616465613966356463366231 -33613233306237636661616565356166336431613166653764356333316433616631396465336230 -36313038626535613862333533633538306137333331613463376430346562373036363963313063 -33393166666138326534616265333764636238313432666663376366306535303166336238376363 -32383435626436323634343663333265353562666239313236366330336638306237653464353664 -66396435623532393335646139303832303361356634316539383539383035613461313331356265 -64613434363830323963653437393662383865396166353130323462646432656538356533666338 -31666138313339343232303438633938383466633962323838643161633431353766356463333765 -62386537396533343762613263393866373433383562313531666232326563313730363936373064 -61666333633039643365626661306236643238383230373133386166326462636461636366383631 -32663238633037313538646637626536303539666436653662333563633836653533633361353030 -62663434636330646439383839343132386539653262376436623463323639653734333136386130 -33333936653432363466353533383137386565313739383938346331653066383165646362363532 -64386661323433316632623037336231336136363931626266623136623930666236633433616265 -31653166383937643666623062653830326462336432346136323463316362653139666431323331 -61363133626131393735376131396234306464356138656564333530313438653432643536613238 -39613663373664383061313237353265333665363837313435653565663735386139633963363832 -35383364313034353465653935626238383034353439306265613064356264653962356539393639 -32613135643162653637656633643030373963393064646433336561313232323335633231313566 -66356166666362623337653639323736653261353361373662656365643039303865366635646534 -33333339313136393130316665323431643139373063333239356534343432663837373132336639 -32353032393631373462363937326334643435663438333663613833353039663362383336363535 -37643064613232663861386436393562646439643561623839653433343136616139633039643937 -37633432323534323639346639333931643035313538663233623963373161633139626665323939 -30666166363964383132336362343263326537393132393635316233613561353138343836333130 -64316534393234613231643033643234653339623063613534616138623835303830376662373133 -33636261663935393363386565353336363161353364393130646534336337376364626265303730 -3163613738316230393838393035396134613233356237633735 +33623562616365373036323031306663353630613366396265613134306632663230363861643935 +6536396139623338316366643235653461333961363563310a616630633938366264336661363438 +63373439643263326664643966353839303430626433306234373937656530303034366130663032 +6232333563383265630a363462633264333538373830373961656235356139653332373866376633 +34626138346237616230363239393533623637643565376237373365373065623564636538663736 +36316431316430616661313366643138366530646238343330623161663130373138386438633731 +63393065336530623231633335393438663733636630383363396364663566333239326537383434 +66663662653735643833316663616335386363613130323766656565613136323731383464626439 +34393732386437393431303363356164386631656630373562363762656563663530376665623531 +62386666316137613665323032383936653866313535326162376238616436393062353734386633 +65623635353237666465633961643835373430616539643464663033646132383631306630663964 +32303034373438613861363838353731386437356531383066363335613534663461613661316235 +38616134353334613637646237653131653532376535386338656431303235653837336131316466 +66633639323037653364303932656638623130333039346166383937326361336336346135366433 +35393562663034363335636236616561353466343064343564616365643964633337316432303530 +34633638663635363766393161626362653235363264643661643364366230313162363438336133 +33326235396332346431616664343731313835323166326330666131646462636566633061653636 +64643535616363646439386534303834633963383533626530393739323334653335336436376132 +37306137353238393465333664396439636233336139313562303432303637343765663634326536 +62343232653764646534363332326364313437396365646139636135326564376563306133383235 +63316132386437313464313338656531643366633562356166643733633934336565373464343133 +32643366613236636461363734623332623064663534623433393765363565633465653532646466 +65353639663034643532326130383137626235653036353130643439373062326436656434336339 +64376266663733363932333930653962376132636132393565333936386462653465643334353065 +66653565353665613738613663353534336530306437346237373433656164343936383061383163 +66323464346363353537373961363430323862373062323665343638373264616133383763356233 +30626532346161656134643939383165616337383831643235386239613732656238323939353331 +39376436386332666265643434343461393264303232633962323362653931326162396333393237 +65333336613363636461356562316336653839386632626439386439393133623261666564643763 +39373365633131646636306332303963663964636163373433663062303834653662363366303430 +66323263663635336565373566633835336163373561373330633032316665616235363932363062 +62336563396534363835656161626164386136333061666337383138613338643662363666653434 +62346364616365353964366236383936343462303931663862383763303562616534613535636536 +33636364373933363431306530356366333939306136333037376531633164343963313466656538 +30356634363564346563613264653536323933626636386632363365646531343736333531636132 +33663034333837363561643136303262663864363434396435623836623630313830346134653630 +30396165353864643065313562613038373137323562333262613338643937663438626539663666 +31663230303363386230393463653133653365613639633362376533366235326563356231313938 +65316432653865653861633634623730633335343534613133616339306437326432396333646566 +63626337623939356338353438306661346430313738383563323966646363643034613261623935 +33313836316661306264363534656561613634366330323939636163393534393839656666323161 +64303030633764646234366564393638616639386164643364363762346633366565303465623833 +30663866333737393163643738663236616430386535666261313333366632343463366637356230 +31326331643036623465633434383866643937636462656238653462396265376531313962383337 +34383966353132353864643666643466343938373036326530643337343435373065333638363766 +61636638613262613736373431666237306163613463396334393139633366393566616538623039 +35346564366261316565323135626531363532343338373966633532666431643835383765333131 +38613562313430326339383264666361393438663331383633396239326433623531303539363232 +63663063643763613037613261336666633634366562386630393432666439323935353230386137 +64303932633230653531393238393839343832303334336131396536633139383438346235663035 +36626464363535346563396365323562643939613830303562373636636632373463633364383862 +35373062643162386465306430666432323264363362336632353736653061343839383130376331 +63333237333235333730666133613063383234323434653938343562373932616665613631373532 +61653434623465663165626138386339396432616636656561356165343164656364396430333238 +61643036393434346633316332376364356233633335633131316238393232653063643963316232 +37376436363066643366326263386663333731353534313538356661666261303862386232336164 +37633962653766343866383431626534666561373437363430636233396232316663663133376137 +39396338623532353734653765663038316630643038623932393664333063363838363632333465 +30353836613736326232653436346566336533373838353532623764613864323536666566643236 +36656564313862643131383333323234666439353664376130353632306133303131393934333031 +32663062353532386238373364663233366438313037613731643562303739633162393362343832 +32633761616561326634333731653934626231613265613630373631313565633062343261356436 +34336362323865376336303938633263323333626339663265623562323837373031653937316631 +64396530616538326236636663633030656434393436303439343864343766396439386535653136 +37613832613636343433633165636339636132616631653265616163356639333734666234393234 +31313631663337303632656264333336343564323466333264343938623530333966323736646262 +62333137333833353033316132376266643835346564623762656533336365363266656566376533 +65323430366165323230636637646461306531306365383763323566376634656436373635646666 +31333866396637333331653337333066313334363861343030303663323964303337313533643963 +37666537336665336138313239313436316464313232303333346262396435663837313737353763 +66373139313831653730663236643039313065363537303236346138373166646433616632323766 +63383133333436383732343333376133353632376162636365613534633634643661343630626230 +64363461383131373335623835353435363336366462366235646333313633333730393835363434 +30313465343931353135323632336234316339376563333666623362326262326661326231373861 +35323532633037373864393265376561373438623738626338363535393434636336643732623561 +38393431643630373566366432663862303164663537356462656566613731323731643233663830 +63346665303531626532613666636161303962366139313362366434633939646138633165656663 +63373137376137623939306164646436396438666131626330303262626435386339386536356139 +33343063383165623032633932626262653432383438303434646566356162653733356532383535 +34313262393563393133343234356236616638383137323639633930323631643262393139323430 +39393533636231623962343935346333636536376162633433343636663461383932343665306638 +65326136623236663066666134393761663338363437303439643563326535656631653164383039 +63353938353432336662306233666265656333306230333232333161643732356134663738373962 +64646635323331363965373664366632633833306631346164613462633433616532336430636532 +66653837303339313137333731626665653562626232383731313930623963313062663131666264 +39393532356438626561613534333331343438363466643136343830333338313764636166646166 +35366165643439636264336433643063363763383365633739666439366638663836633265303832 +30333061333436643438383332313031323761333832613366383363313834363239663964383361 +39333861336663663535303633376337376235363462666265313938316265663839316666666132 +36626132396264663738613231646665646430366637633331623333326430636462653463353237 +31313732613339306265613264633361306234656561356237383366656532353635333863653566 +61646237393666623531663063663962633535316436613830613134316363376438386666366138 +37356139366163623134633030333334333236643335653135363930356465323863353638313330 +66316662653730636261333666643539353264396463323930633538326266303132313039346464 +37623237643439356233646433616530616431396161643965643037313931666237623733343530 +30373766316563633433343165393232636637356538393930373433636264386562316138343636 +36646661323534326533323532313538336531623736623830633432656666666238356462643131 +31393138646538646137623138323766613464323861613530356438313862643436353066303664 +32343434366435643338623765633133373039303165306334653035626365616337613062366534 +39363435363662643761393330383733306638306139633634326663666363633437306163313238 +35346333346665353263383562316664666136663461646533653636643431643066623461613365 +66616630666239616435623030353635333235363433653734656533343463616366373963323239 +32653863626563363363343330646631633836383435303031626335373063616462643530333961 +63643430396166623364633738386162613037363633376136306561383766636534353234323166 +64663166613466313664346330333032623436613738373832646138376336323062346537383236 +39333464346638666438306165346435623164663435316161306334346133613939656538393935 +66653232666337663936666533393036366433376637366534373338616231363639383966343531 +35383466633633383866306533303337656237336539653062643164316436643938353436356664 +38383365653937316339343337626631396233616233383534343735383862343766666536303163 +66323531373537366166623034616163366662656333313630313632323337616535646435343631 +61323063393134643063316234313032356161623964653665333731646338373438393034396534 +35663630373061653864393733376561636263343165653933313331306639656534653361393666 +39656135393466616536653435646364383863396639393738343766343664636330613239623231 +64393265373365333632626435636132616136343662626237393938633436393564383063353531 +30303764376365313038346431663264633633646137613237373336663230656231643334363330 +65666166373066613764373137643538396661343465323231313061393834626265303930633462 +30643531353236663061653539626332656638353835623664663335393930383738646166333637 +38363036366430316564343035373934636130636330333261646330653262306636633765653835 +66396165313461633765643731333166323365306135326466303932643337643865396536613565 +33613036656435636633313162313939643637316431323135666535313262383432386632373235 +31643933643365353466383666636332393366363934336330633165306364663063313562396634 +39383330393234313965373761316364643965646561623233656335636232303536356137363233 +34363263613363346531666166363661633837303065643366386237326662623064353131313863 +39633630636435326637316635616166653265333565613035653936303539353336326533636163 +39353532343566656431343462303638613063306539663935613633633734313666373866353939 +66656633336266316562616339663866373863626461623336323932613735356432636339376264 +35356561623632616636633332663862633163663339363235323763343830363566366334663336 +33383939643730396531323064633033623832363565343638636335653962663164353536353732 +65343735306166323436653439353438393763323437343666313837343330376562636236663639 +30336261383934303261663762313363303332633030633864396137653832333036303932623962 +61323431336261623937326139623666616233333134343330626338333763363336663333633364 +35636233636161656537333833646463376331396235376431633832653535366165653434353431 +63363262396465623834353339366233373135366534346166376363363130306266643065313336 +33623335653061363865653365336661613131666435346233656433326364346461656235366161 +39353862336266323534353733633037653661613062356462336631626335626163326239313238 +62653437386435333532633262306466363033653661343734363337643333643161616135663062 +38343537333532653632303439396439313733633431633039646133666132366436386333366338 +32633933356536666339303031313634396164333863643134363037623637633061623036623866 +61656266313236373737653136643938326563303663323839373364353066323332396139363066 +37333432643238323930333735303831336665633832323035313032356637303862373463336430 +65356561326664353330353266393763626638623065333538653532373431666635306630386666 +62313532636464323939363631373339623535616132353132326263383430613733633761303939 +34646561343366653735313331633363363438313365633832643231353739316163666537343462 +30383462636135616232313634363632633862663638373232356563623039666232656363336432 +64643066343566363537396230326336666163343239316166376533336261306435333339386434 +31373030623664623434656462626231636532366333306436666433303038333431386232343839 +30613930343665643835316264613231336538626536316230313361373337313431383633306539 +38366165366133393161326563393533366261626262653565656635383138323734316664346433 +35303135396436393334383435656362646261303466613233386234623965386539656664373032 +39656466363232353038373334653662366334643562636130343736323238663832383034666162 +30383663376364376137613937643032653466636632326433383364383239333634663164356163 +30613265303265636566633666653636313833646262356431373032653964626138396235306433 +65353161633461633866313264393834653638653663633237663730613230636139623236363038 +36323735653535313733316164336238633333313033653433356138623465633334653335636265 +31356666346131323466353333323632313237343839646661323432636463636531396436376163 +61666136326164633935366632636339663632346634636235646162333730336265623464666565 +30306238366639633735346231613634363938616339383863386334613537383264316531643862 +36393461663564613762313733616661303935373664353632303365316331333033323464623539 +63353038393932303363636464313937646266613833383962636461666661646362343439316135 +31353932633862356563376630326462363839626165306239623135653734333562343437613134 +37393262333632306334666361303232316636623635333862616335636139363436646432616165 +31343262386431386162393732306438356461633330383333653831363237333265613638666430 +37623133653231373461383462663930653935623131366430643530323532356563383938393063 +65353535333432646266346462646630646262333639363562353266313763616264353564666662 +64656438336238663966663434383431366530343033646233353761316638313763646630376465 +37383565313764653564303662653235616462636334363638623930363334646638353132333334 +64356136383136616166633138343166396561373933376165396634653763336664336265353730 +37356134333638613664303466353866313134366235366230393365356666653533633834613234 +35353231333263336630343830303933303935333465333962356332666235346138613530333133 +66643535663032333438303138653430393261323831623034333430626464316432656266316433 +33626534666536313633303430386231313035333833373831373639653738373031373532323136 +32306433373762353734353635643762316531333934333064323362663161306330353966343666 +63333832353332393738646433643661316633336535626464373933643732626361383031323363 +64323662393733303133643236366365623363326263303535366130356530643162356434616663 +39383566313261386237656634373761663630313662393235323330653934303438653134663831 +33613636393633616365313566356536333936626238346635396539323062653136613939376638 +66623133643163613361643435376461363239363639613039653166323432623030373761333931 +36613965306230356466303033366663636433616630316133656164356631363531323139633839 +62653832363838306238633062396230306564643038373565643162396136623232633730613735 +32343365383838373834616138623534376438663238363065376630303339633336393066353062 +36383132326237366231316433636130363033386263373539663038643861356637363466393930 +62303937643864373561373732306563313434363334316630316463636531313963343233306666 +66343366393331636433623762393738396264633034646539643133316633643934316336353634 +65633134373132323837326539626336653532363366646233373836353439323631356533356233 +36326133623762306539626534633333336130653961376635383163646436363061663236623839 +33313635666131386433313332616434356530323233626265383038656336313331383462333131 +33653134656264333662623365333231373937623139343434373931663966663238633032633165 +62656537663164643164613664613763356233623064656132623463613237393662633662386430 +33323731306464353338613564396533633630333462396330346166636639343465376139633062 +63393661383862316165626362373766376336363034643134643563363537653164646235653563 +33616166323331396137343233633535326365613038613662343030613339363036323136316365 +31343862356338663464656332303735643632303833663536356138393365663233393233383439 +33326136636665653134316235616436333962623661393437666336356536666436653831626262 +36343464393930623166336335623839333833383361346134646435393462626338386432343435 +34323562643632306364316637383437356562323930383761313666353138396238613930363963 +65333533666461323334316533353933656235333933386162613736336636653334373536373535 +34353563393866633562653266666132383230366533643835383135316566306434376339373831 +66346261633661336533353163336332323631313034623735303635303637363765383930356365 +33376361643135626531366238343730626365396634623935363639653035323864656465613434 +64613763626662653661636562306230666135383136626432613262333361643266663164663136 +63346430336663633035633434336362393465343239383436383366316261653338333764386330 +64373064386263316134383035333464353464613839383633653634363234373237383733333333 +31653166353830643636303933326433326466383535393738396535613632363432656335316561 +32383764323561316439616336393365343162613364663036303365356339336537386161623232 +63613261346234373661313962666536306361666433633965333337646136353766383334383938 +62653462343832653838643134653735303333376437373266663838653737393261336639393334 +64313534666163393262633465633437666337313034393635353865396137656139356439346265 +35336635666437363565346438626137336336333432646266386238646465616137633635343234 +30343536663730303530363839613037666135663261353137323632333537613032626235643333 +6530663563333539353235313730353737316366383334383736