From 65619c2478e61ca8ad2e905efcff30324f4952f3 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Tue, 20 Feb 2024 05:13:53 +0000 Subject: [PATCH] Fixed: - Fixed a problem with synchronisation taking a long time to start in some cases. - Now we can disable E2EE encryption. Improved: - `Setup Wizard` is now more clear. - `Minimal Setup` is now more simple. - Self-hosted LiveSync now be able to use even if there are vaults with the same name. - Now Self-hosted LiveSync waits until set-up is complete. - Show reload prompts when possibly recommended while settings. New feature: - A guidance dialogue prompting for settings will be shown after the installation. Changed - Some setting names has been changed --- README.md | 10 +- docs/quick_setup.md | 102 ++++++++------ docs/setup_flyio.md | 10 +- docs/setup_own_server.md | 2 +- docs/troubleshooting.md | 10 +- images/quick_setup_1.png | Bin 25864 -> 19976 bytes images/quick_setup_5.png | Bin 36760 -> 5863 bytes images/quick_setup_7.png | Bin 10276 -> 0 bytes src/CmdSetupLiveSync.ts | 48 ++++--- src/ObsidianLiveSyncSettingTab.ts | 213 ++++++++++++++---------------- src/StorageEventManager.ts | 3 +- src/lib | 2 +- src/main.ts | 89 +++++++++++-- 13 files changed, 291 insertions(+), 198 deletions(-) delete mode 100644 images/quick_setup_7.png diff --git a/README.md b/README.md index a17e2dd..82f386a 100644 --- a/README.md +++ b/README.md @@ -34,13 +34,15 @@ This plug-in might be useful for researchers, engineers, and developers with a n [![LiveSync Setup onto Fly.io SpeedRun 2024 using Google Colab](https://img.youtube.com/vi/7sa_I1832Xc/0.jpg)](https://www.youtube.com/watch?v=7sa_I1832Xc) -- [Setup CouchDB on fly.io](docs/setup_flyio.md) +1. [Setup CouchDB on fly.io](docs/setup_flyio.md) +2. Configure plug-in in [Quick Setup](docs/quick_setup.md) ### Manually Setup -1. [Setup CouchDB on fly.io](docs/setup_flyio.md) -2. [Setup your CouchDB](docs/setup_own_server.md) -3. [Configure plug-in](docs/quick_setup.md) +1. Setup the server + 1. [Setup CouchDB on fly.io](docs/setup_flyio.md) + 2. [Setup your CouchDB](docs/setup_own_server.md) +2. Configure plug-in in [Quick Setup](docs/quick_setup.md) > [!TIP] > We are still able to use IBM Cloudant. However, it is not recommended for several reasons nowadays. Here is [Setup IBM Cloudant](docs/setup_cloudant.md) diff --git a/docs/quick_setup.md b/docs/quick_setup.md index 356afcf..ac65983 100644 --- a/docs/quick_setup.md +++ b/docs/quick_setup.md @@ -2,34 +2,51 @@ [Japanese docs](./quick_setup_ja.md) - [Chinese docs](./quick_setup_cn.md). -The plugin has so many configuration options to deal with different circumstances. However, there are not so many settings that are actually used. Therefore, `The Setup wizard` has been implemented to simplify the initial setup. - -Note: Subsequent devices are recommended to be set up using the `Copy setup URI` and `Open setup URI`. - -## The Setup wizard -Open the `🧙‍♂️ Setup wizard` in the settings dialogue. If the plugin has not been configured before, it should already be open. +The plugin has so many configuration options to deal with different circumstances. However, only a few settings are required in the normal cases. Therefore, `The Setup wizard` has been implemented to simplify the setup. ![](../images/quick_setup_1.png) -- Discard the existing configuration and set up -If you have changed any settings, this button allows you to discard all changes before setting up. +There are three methods to set up Self-hosted LiveSync. -- Do not discard the existing configuration and set up -Simply reconfigure. Be careful. In wizard mode, you cannot see all configuration items, even if they have been configured. +1. [Using setup URIs](#1-using-setup-uris) *(Recommended)* +2. [Minimal setup](#2-minimal-setup) +3. [Full manually setup the and Enable on this dialogue](#3-manually-setup) -Pressing `Next` on one of the above options will put the configuration dialog into wizard mode. +## At the first device -### Wizard mode +### 1. Using setup URIs + +> [!TIP] What is the setup URI? Why is it required? +> The setup URI is the encrypted representation of Self-hosted LiveSync configuration as a URI. This starts `obsidian://setuplivesync?settings=`. This is encrypted with a passphrase, so that it can be shared relatively securely between devices. It is a bit long, but it is one line. This allows a series of settings to be set at once without any inconsistencies. +> +> If you have configured the remote database by [Automated setup on Fly.io](./setup_flyio.md#a-very-automated-setup) or [set up your server with the tool](./setup_own_server.md#1-generate-the-setup-uri-on-a-desktop-device-or-server), **you should have one of them** + +In this procedure, [this video](https://youtu.be/7sa_I1832Xc?t=146) may help us. + +1. Click `Use` button (Or launch `Use the copied setup URI` from Command palette). +2. Paste the Setup URI into the dialogue +3. Type the passphrase of the Setup URI +4. Answer `yes` for `Importing LiveSync's conf, OK?`. +5. Answer `Set it up as secondary or subsequent device` for `How would you like to set it up?`. +6. Initialisation will begin, please hold a while. +7. You will asked about the hidden file synchronisation, answer as you like. + 1. If you are new to Self-hosted LiveSync, we can configure it later so leave it once. +8. Synchronisation has been started! `Reload app without saving` is recommended after the indicators of Self-hosted LiveSync disappear. + +OK, we can proceed the [next step](#). + +### 2. Minimal setup + +If you do not have any setup URI, Press the `start` button. The setting dialogue turns into the wizard mode and will display only minimal items. + +>[!TIP] +> We can generate the setup URI with the tool in any time. Please use [this tool](./setup_own_server.md#1-generate-the-setup-uri-on-a-desktop-device-or-server). ![](../images/quick_setup_2.png) -Let's see how to use it step-by-step. +#### Remote database configuration -## Remote Database configuration - -### Remote database configuration - -Enter the information for the database we have set up. +1. Enter the information for the database we have set up. ![](../images/quick_setup_3.png) @@ -37,13 +54,9 @@ Enter the information for the database we have set up. #### Test database connection and Check database configuration We can check the connectivity to the database, and the database settings. - ![](../images/quick_setup_5.png) -#### Test Database Connection -Check whether we can connect to the database. If it fails, there are several possible reasons, but first attempt the `Check database configuration` check to see if it fails there too. - -#### Check database configuration +#### Check and Fix database configuration Check the database settings and fix any problems on the spot. @@ -52,40 +65,43 @@ Check the database settings and fix any problems on the spot. This item may vary depending on the connection. In the above case, press all three Fix buttons. If the Fix buttons disappear and all become check marks, we are done. - -### Confidentiality configuration +#### Confidentiality configuration (Optional but very preferred) ![](../images/quick_setup_4.png) -Encrypt your database in case of unintended database exposure; enable End to End encryption and the contents of your notes will be encrypted at the moment it leaves the device. We strongly recommend enabling it. And `Path Obfuscation` also obfuscates filenames. Now stable and recommended. -Encryption is based on 256-bit AES-GCM. +Enable End-to-end encryption and the contents of your notes will be encrypted at the moment it leaves the device. We strongly recommend enabling it. And `Path Obfuscation` also obfuscates filenames. Now stable and recommended. + These setting can be disabled if you are inside a closed network and it is clear that you will not be accessed by third parties. -![](../images/quick_setup_7.png) +> [!TIP] +> Encryption is based on 256-bit AES-GCM. -#### Next -Go to the Sync Settings. +We should proceed to the Next step. -#### Discard existing database and proceed -Discard the contents of the Remote database and go to the Sync Settings. - -### Sync Settings +#### Sync Settings Finally, finish the wizard by selecting a preset for synchronisation. ![](../images/quick_setup_9_1.png) -Select any synchronisation methods we want to use and `Apply` to initialise and build the local and remote databases as required. If `All done!` is displayed, we are done. Automatically, `Copy setup URI` will open and we will be asked for a passphrase to encrypt the `Setup URI`. +Select any synchronisation methods we want to use and `Apply`. If database initialisation is required, it will be performed at this time. When `All done!` is displayed, we are ready to synchronise. + +The dialogue of `Copy settings as a new setup URI` will be open automatically. Please input a passphrase to encrypt the new `Setup URI`. (This passphrase is to encrypt the setup URI, not the vault). ![](../images/quick_setup_10.png) -Set the passphrase as you like. -The Setup URI will be copied to the clipboard, which you can then transfer to the second and subsequent devices in some way. +The Setup URI will be copied to the clipboard, please make a note(Not in Obsidian) of this. -# How to set up the second and subsequent units -After installing Self-hosted LiveSync on the first device, select `Open setup URI` from the command palette and enter the setup URI you transferred. Afterwards, enter your passphrase and a setup wizard will open. -Answer the following. +>[!TIP] +We can copy this in any time by `Copy current settings as a new setup URI`. -- `Yes` to `Importing LiveSync's conf, OK?` -- `Set it up as secondary or subsequent device` to `How would you like to set it up?`. +### 3. Manually setup -Then, The configuration will take effect and replication will start. Your files will be synchronised soon! You may need to close the settings dialog and reopen it to see the settings fields populated properly, but they will be set. +It is strongly recommended to perform a "minimal set-up" first and set up the other contents after making sure has been synchronised. + +However, if you have some specific reasons to configure it manually, please click the `Enable` button of `Enable LiveSync on this device as the set-up was completed manually`. +And, please copy the setup URI by `Copy current settings as a new setup URI` and make a note(Not in Obsidian) of this. + +## At the subsequent device +After installing Self-hosted LiveSync on the first device, we should have a setup URI. **The first choice is to use it**. Please share it with the device you want to setup. + +It is completely same as [Using setup URIs on the first device](#1-using-setup-uris). Please refer it. \ No newline at end of file diff --git a/docs/setup_flyio.md b/docs/setup_flyio.md index 2d4af87..56f38ca 100644 --- a/docs/setup_flyio.md +++ b/docs/setup_flyio.md @@ -28,8 +28,10 @@ This is how to configure fly.io and CouchDB on it for Self-hosted LiveSync. 2. Press the `Open in Colab` button. 3. Choose a region and run all blocks (Refer to video). 1. If you do not have the account yet, the sign-up page will be shown, please follow the instructions. The [Official document is here](https://fly.io/docs/hands-on/sign-up/). -4. Copy the Setup-URI and open it in the Obsidian. -5. You have been synchronised. Open the Setup-URI in subsequent devices. +4. Copy the Setup-URI and Use it in the Obsidian. +5. You have been synchronised. Use the Setup-URI in subsequent devices. + +Steps 4 and 5 are detailed in the [Quick Setup](./quick_setup.md#1-using-setup-uris). > [!NOTE] > Your automatically configured configurations will be shown on the result in the Colab note like below, and **it will not be saved**. Please make a note of it somewhere. @@ -240,8 +242,8 @@ Note: Each of these should also be repeated until finished in 200. #### 6. Use it from Self-hosted LiveSync -Now the CouchDB is ready to use from Self-hosted LiveSync. We can use `https://billowing-dawn-6619.fly.dev` in URI, `campanella` in `Username` and `dfusiuada9suy` in `Password` on Self-hosted LiveSync. `Database name` could be anything you want. -`Enhance chunk size` could be up to around `100`. +Now the CouchDB is ready to use from Self-hosted LiveSync. We can use `https://billowing-dawn-6619.fly.dev` in URI, `campanella` in `Username` and `dfusiuada9suy` in `Password` on Self-hosted LiveSync. The `Database name` could be anything you want. +Please refer to the [Minimal Setup of the Quick Setup](./quick_setup.md#2-minimal-setup). ## Delete the Instance diff --git a/docs/setup_own_server.md b/docs/setup_own_server.md index cf5edc0..c93164e 100644 --- a/docs/setup_own_server.md +++ b/docs/setup_own_server.md @@ -113,7 +113,7 @@ obsidian://setuplivesync?settings=%5B%22tm2DpsOE74nJAryprZO2M93wF%2Fvg.......4b2 ### 2. Setup Self-hosted LiveSync to Obsidian [This video](https://youtu.be/7sa_I1832Xc?t=146) may help us. 1. Install Self-hosted LiveSync -2. Choose `Open the Setup URI` from the command palette and paste the setup URI. (obsidian://setuplivesync?settings=.....). +2. Choose `Use the copied setup URI` from the command palette and paste the setup URI. (obsidian://setuplivesync?settings=.....). 3. Type `welcome` for setup-uri passphrase. 4. Answer `yes` and `Set it up...`, and finish the first dialogue with `Keep them disabled`. 5. `Reload app without save` once. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index ded2f6a..1d40ebb 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -14,7 +14,15 @@ - Fixed at: v0.21.2 (Fixed but not reviewed) - Required action: larger files will not be fixed automatically, please perform `Verify and repair all files`. If our local database and storage are not matched, we will be asked to apply which one. - +### Some setting name has been changed +- Fixed at: v0.22.6 + +| Previous name | New name | +| ---------------------------- | ---------------------------------------- | +| Open setup URI | Use the copied setup URI | +| Copy setup URI | Copy current settings as a new setup URI | +| Setup Wizard | Minimal Setup | +| Check database configuration | Check and Fix database configuration | ## FAQ diff --git a/images/quick_setup_1.png b/images/quick_setup_1.png index 0c1c92eb0b73d9249ca566dfcc81418ec4e787c0..22a873dbcdfe1d3f1df019f8cf4313e385a350d4 100644 GIT binary patch literal 19976 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 literal 25864 zcmeFYbyQqU-z^9U5+FeE-~M*8iEC<8<*hjP6)x>-JM1omxkMU z-uJur&Np|~H?wBV{cFxzz4}OHFp-duu;t~XG?0*<*&-n! ze|~|6II}j6s*3nS_Rx@(Kq?=h*hd_o*oZ5OBOz7AU_F?lB91X!<@7y}kZ}I|{UIl^ z;*cXwQhG}3d1|^?d-|BWTOoaP^l~@a`h*vH|rwzMB!x5_!PNK)Y$I*1z zz}w8q_i)vqM&zn1@l-Zej&YV=CP@y)lRya?1%ctFDWJ!qY zT0nJ3S@fhmAF=PVGbC_+n(i^86zauFLyOo}UpqfC{N2ek`ywMHCAG!%a_k#o^AANP z!^6Xi9ewwa4sjJmie`(rDkU0k{KdQdxiWb&-Mie^At535%rg6}!?s-U_X@pN49wtq zl*MQ;-t$rikVx@!24C`sS(%}^_VF`+_M}l(>8cU2x(8BZ#}yaG{Hd>ZAqRX|&}k;g z0gGkYgcX`WgJ7p|3>Ca!OJg2j3nh?UgKqJaMv*doXZ>O`t)5r`ipPxfn3c?>j181G zn2Jp{{B7oMyY0e9^8&Dfloa>7>K9{z<2Uo*#shqNwqe|+wE1VkWKa-xuF`oeQ@|@1-ev4 z!F7W5M%b4)Fvhtv$tAdQquy;#*v`67!)B9Zsihu+fVf#bO38)0*|}Y4Px|wZZ7Nl;%?| zClY774W9;+iOr7LC)J4ywZw-s5>oUhZY>6_x$9dvy^YaRE1g`zO0IHk*S%}oTQNL( zQ}Lb`W2MVZiBT8-3S7+3-AJN!@T~Bnd1!OmYku>sEJoX+Gi^U5zz~(CqZUJvYxrYK zxu!-m_fL4<1Hfv7+5_@$R! z7S^XSPTxJxT#S^f-5zufEa|R~(uue5Y%{6w%6n;j;d{64tIj zlSOgyw=Q#};-hE??H2+cbq7m1a@bU(uKfzeP3hSMXK+|1&*Q&v^ka^aK|tQ zsvO<$aKyYh6;2FeTwAVxPlWX8o^+;hKH^jBEq~jg7770upZet-xZ^W z=qU>TO|WamG+WbpyT9W@HBQY-uUM19z~JPSAR^U}@rOf$A(82?Vvr*Bkn2Kj6m^bF z8}#X2_C{HTLe^@u>miJd{c$X{+#V-=ZDj6ZGp0(avS=Fg7Rk@Pe{9YUM;EK!u9bPc z{dilzqVAbTeEm4xrdPqSl|Hh{GUHo(Hc09)-pCZml&mB@InY$-j*9wwK$Z36(=FIV zS?TazoDJ0eYEbL3tWh~}x`#n;)pFZ(;Yg^K6ia(-(V+DiwwS%l=0Ve*aK5`L3_7lm z_>6(0BhE>d1Y%EIm{p1@4Qe1ZY&Qw2u20m1<+0@@e|PB?A<&v5bPh)?>4m(~sWR-B z9ek%AwS2XvwA6CM!UlgTgJ(TVUpD%**QGODYvnqYVty7AM(<>zD@Wpes>ft|jpgWo zxE*pN)-^)+EAS(L`-EJ#qBHgyNKD?Y9@WBuO?MIgN{M&VwF`d;D2MvJThWW;D|^h4 zG*zl<_%~*}Tf;O`A)g$-)ugcI)u)WN%bNMECHHi=vtHEvcKL00p4UN|`JQ5pN5Q1o z6y?y2iXM@RNS<;A`VPZ6V;?QhbhL|cVUO~@$z={{w%+F9twFPH(Y~hWl>uEcw%iKT5R#4x7B#hUb~vE)9IN8c&pmMdGaX~+4sQ{}R&)LY$1}iKV&6AgBORFbGDEC%ACqqP~w=+q%i93$oAHxJs|Hv8vK5fU& z^O+dTig*kR9eZ)=Pu4Qd^YV_=d#JNrA@51r=3DP;2xRV9 zoT{!pk<7g-ID0ecPuDd>1DR?ZX)k0*xysOEx;fK)BhrPF`D5FA?F%8jv&uQ!lcf+% zCn-E<4xUWEB3qddmZNtNgFGX_@mj+&rz^IEB4F+&A3J~PqoGFwUFMFWGSs{-<{+~K zsQ6R+h&uKpM9obZYi1~u)MS|!MzQRT)vfny z6MJ?)5LSH=hSZcGOH1}peH@g(t^DW0%5dx<3e!u(B&fiYdovMrRgI*f?b!V2 zqi3~_Zrk`yu6H$7@31Ubuew#;*mE`q2JEc@SRrv~o00AZHCD;WY?*JcD^_jyrmB7A zExj!duIgdp>)tlq8gKa_imq7s`?7_IRID{tC&S?Cnr`mVmLZ>dIdZKPyl?6d>ntP# z0Y!0T?5t2}cAAAOoH~v2X4lkUv}jfGUw2tW@2u_@t{lrJlj(f^!1@%58Qk80-AUeD zdDNfIGNj@BgK>(3o44ef0bjbxp9!IwA*)eu0z5p1i5jHgzLu%x!+qUPO3YI{I_svC z;*UhP$JwSOFJW%eD3_zhFRte6XcTN52t2zJlu?mx`G&f`%Qn#EJR2;Z;h8IPkeC2} z`3*kEJn2|FaGAMG)!{Ds<+5>;Akv{RI9T%xJrQJl&|Qzx{1OP**gRGyM`U)pvWmrM6_t5YlNAbPzZl>pR2RbEW3 zJfBaW3q@^&@|HyA$*`(AX=}DDkfiNvNSfr3i4)1~nifB5ceWEn5?dS>D7b!xa&U{T zemf2JbA@92O8D;F*!q{dtjr=nVUXbt@kE3t{%T%1#8|xA3Qfdrm^}0%q*3YdIh+m45kD z%Gk;xpZA@p@<+?GlDB=?0A|?rMYSQBFF&o5lod#_I$n$VC-eHk|D0w#_6CcROLEFzfj`+?X4DJ zl=jo(p52sK#egdaa>Se#g39v60S?nZ$$VJ?v`b}44bjV7>+k2UsD}bMd22hze^Kz9 zCAFyKT!kHQI!mrF4O%GwVDQ<`U+4+jg?cp<18eugE?-PLPTqgof+Dj$xw9XD3X{ru zDgbhcx;1z6z4=f^uk2)?C98xfR_wYtq zw}x6{y57|~>`x|3_uVo^JRkzH4wJ9pc6VvrTjn_f-!g%qsJh6onL@QXB~;87b&<*M zG%%YA=}o>oQgxFRA#@Kaz33=*=|(_x#*)i~v#B^TtU)ADfSN^oo@r(+nNKHoeH^o- z$z2NLSQ}srJFrHfHVR6L->=U_B8uTHgs-7wJpQI-Gq~kGU7J;hi-MDS1{s0l=Bx|D z^vUuE*5=kE%_>D}*D4qRQFz^Y3u9jnV8VyR`oRMB)W+4mTZ68~v(+D!81M?~dv@_dhJq{QnjU>_Un{+|+0DIt!5t-tEi( z)6IAD^W~lQ1uE$0^@s$ zOzcuWy~1N|HYdz)^-Ca4P0y}Yz4Qi=vE0(9=z`5ffA$IwygYyF(KcM-Xi1UP??}S& za^xdj;(Aw@jq$6Frz3&j4nN;9G;0(5!bG6w%N0?pJkoe@cBAU0C1|56S>RX`Olp7o z=U=&q^p`kVE&X{L@{Z7|WqEhR+hSF9mEuDu_=i)X)5wh4Qh{&vu<+G~ULXsXBztCx zETRTh&NTI@$OdHd&OQy_2XP)YN^f~RFDz5THbkf6op%0n5zniZ{pGS^q6VO=EUJjs zC42Z!?bUztcI13_G*wk{^cx=CP{B|sZpOPzw3%34lO9F%jLxsCA~6k7e&{R3q2vWC z;TXEBW;=VPijtd%q%SW-FL%YB^l{^vRK0;zw)4lT&%vsy!e=Ne_bb;MoKG;$;gpC$ zPC%XWvf$xD-Jm}dti~J+EpHj|hZ+Vf7X+L|n64pm5IAl*5#`$1I6HUSWeONz5|9O5 zmY8-QFSiV*4D|yJGavUePm>y2yCe7g=6AH~UuRj-EK0oILpoAr3J7B#W$Qdqq55O! z(n<+%N&RwOAmnze#T3m4Lf6D}{?q2;JSJ`kf;oJt|J02M{4&@rfivR*x?l87^G`-{ z+8F}heWWTh8?GS1#285mutt@Mp$MgZJPmUbhorHI-OrD1taS$6Y%z%m(2y8+Y)$7# zN1Xmynf=mF{m!Dg)(`uNJAmW_^mIS`t$n)}s1RMT=-i@w!k5bH)VwDSF^v)GIMWnm zH)?#<8$&(YYg%uaDFnQ$6-~ZOc06Y>Y=1Gf^?NM-*(-PTL@Z~}%9)Mfi|3?S@@4b7 zkLPrau=@M=XCtbqRnB3Vx0sJNT}-Fo4tPaCnew^A7hd-*Ic{!lv%8D^!itJs*!G~h zy872ThuKf7?ZCU1rJwRyya=L}T^UrwxOSqq|--Om$9@;YQ5Cz%PnsSNE$=Cg?UB%O?SRJyGNZ*B#jdI3qhxP+mtN zZ-&QrZp6;;DKRKkDT+1hWU0yHa(HZ`JL0|703l^*f4HW-?68YHs3Rso_Hy_b+*+Yk7j*W#wKDIOQ|gnt$6mYx!at!}R>Kg&v`JkzTb2R4svNGk&8V1ux#KThR8ha&z zpZTAsuKt;Azv2;jK)mzsEj*|*H-^MJ#2yv>AMzbsp_jUw#S<~$s_=AS80&JW{^c*# z(~3dR>s(wb-;E=fu=i<>gjR2(%lm(%(%JlA3_9dYHgd->@!kJvd&H~1TQXl`vkA7z==2yB zDF~|o!J&6(;iU^){qawC6;HpXiZtEUetoqq2}@giIt>$Br=o9&q4+X(u~ zIZDgU&fc7^FE{gIh%!1H7rKZ04xh3~j+Pd&Dpl^2^o z)~=kDs+k^w)jVC#8V?!~*?@9Neg*|G+b0T;Q{`+xg> ze|n?|{Q**Pgbm9n3eG%vH@rOzs`K{UCa+fS4#aJvKfqIgeN_)LJZl3+7F6xT024N*1 z8ig-|;3s-_9kA1T*8J?O9JCgbC9|XtjqyW%70w+fFsrc^t)r#MdZGtkX!w!`%y`0}+ zRj+5w4!KKfw!;WLe>_kwT6LeAJ0XaBKhW*^ekJA!*qiRV_jyOZ^?oaL@9~8Ap?uv= zL`nD#F^Eux**u+rat|uRB0HX-`ZuYIkG_2~#qz7VMd@WFC0)Q8Evi;?5ki`;9aCxW z!H$QBXzF}ZkC?)CYx6Yr{e-fK0#&!2 zV79&G+0)I>-m@N|j==bMiJKnXj&GB*qQP)km7<74#>g9eO6yhpsSe7+En1p%nIlFO zH*wS=i8~DpfgcrZR|b@y=fokxaqP-3B#)v^V2TiR`q5x+l5gdKG3z&pPhVo$BhH}7 zpyHsK99(~?Q6WMHk+gv9z;|aW4zP>0%M}N$ckaHn?fISFv&KIAW=eO@r^bt3dQ|>I+=@YlLzjI$&X}TpZDH5CMkQ_c2d5 zxFT|z1t@Tv(Tu1S@Gyi2%V)_AJtN@G4i04g(HduM0#IzfAoAUcmAxQ8`T4wDnA`36 zAjZtageZXQmS-Rtq`dsT>~~~$_M26Z9OQk7@T+&{=@!O8!fZ5kHZf0!8xPWW9X||o zipm0D{Y+2~ zqo+Y{KAPy$i7$vfor^)w+#UPn&n8)QH&u02dvA*xHgzjJ*W<`{U*6IjjoNUmjSJ{* zvRi~gL0y@?VN@A~jc5$B(KEnF%ZzLl``$c8Wh$~CG|CxqNyljJjssXKKTpPR15TgA zP1>@zepi~Oy!%AB;&#j5s=Z7@{F1t;18P3^BHbmq1Aqep1n?j8yY=w2!iTfHEEt?rLf`;A)7o&I)65e2Z} zls_3N4N+%vw!^zQ0f~EvBI485Rh55BK3!t|?hvu+VSNARG43NR{?MS?TRuhDMQxsb z1|~6VAu99nq5!_oFwO~}R}FvCyp{D7JPDtG08g!=hHxZ8jP_00$fLZ z97pnIFeqdqQ!j(+c=Q}l4@hJ;oywBeYBlS8woK2^2}ZGpP32#ZEAaJY0uDykhEyS@ z0Sf3gEiAYe8DlS;4mACkucf-)w~-o=%;mD7xpH}_u(M=2t6o!~>CYHIoO2#OoYsI3s;cX&8qUf4NHHT{&W z7vyoRfc3?vuTMNzuNBINyL_(O$^&ctADYY&k&V-4QSUI8qBrsRBS97EJQmDE80}k( zcD>P*cR9DWqaYJd@@#|L>Sp#8iTR(()!OyDve7?*TxWOWDW_3Pu}?CPEYOQsXJ*)! zEMW9w!FFb+UqpUme!4I~13h9;%xyFaFdSO(sMoyIrYObcqpe}JPckpl57!Q21g-1` zaRo#c$Mj5ajSd8`()^m9Ntn){91F!*8pGr%PcrOX{U3SRe> zl3#e^i2vO4)o#r3B##Xoo@3ClMf5~$^YjC&Xv%r;JC*e8!fKQ4tw4PNh41hG6({I zh}yb;O`y>Z)W#Uu`oo;YSpz@UR77Lr&+Syb;@eMVth4ndm{y~~#b`a#-tVu+6WHH2dG8)qb#GOd60Xy~$|cfW*;dmn4Fca3e4xv9f`YzsFXv|S{0 zb`aiWt>nG6KRW8aL3&}e8q3#xW?d(Bl3CQu--Df!XGW-cU6ft-1XQJ&%2MbV#+fg&`$@rk$L>|Q8m*f zF-tNd`lwIKUj_F|Ae=5E;&Ogor2zu;}|A!i5jyq5MJU5y$FIDZ=pi z%!-9mk1sn+O}_8jUO&X?B3?o0C6tCy8M4(pd7{|VtSVo*;a`w^p$V;6TXg|UO^Usp z%>>XtG;&_jSKJ9@O8x!p&}>Qj>R;UneLQDHvjz80N9=e1YW=J2i0r6ar>KGlc`K^B zNv8iwRR0TY>91b(-|Y#O4}?sAH7M+tGyhjw)c+yxYJ zuXsJd>H*{9l`sApEMC0%)Ps1y*ryBTkI>HnT*cIBK`=Y_s)o=wp&c`M<=2$f8QCn= zR(QqKCEa&n61EfvU~z<1LnIDi)p&eY4+ml>oRswJ*cgsqK}ah+>lFBf}$>KIzFnPRhiyn$gr(rvej;Vs~u}4eA`>9otK0_HYN72WkkP^_9OJ; zB(5@i=Allnr4fbT{Jivp4)#N=2nDO%C>-D6<=+mxR2!wj|6InkiE~OhT&EXcDxlzL zTK6eo#4vhc_h>{P;R<%@yWrC|Tn-XdR!P9N=}0bv*<2+~8ywz-RJR55snLc2&9)ZScDlzZU$%+Wc--tZ zUvc}D7YDN(y=^`TDRzt^Fe#swlPf8tXAAcgrfmy|OQ%$U|w=zw38nHjBx>s~e@o zjI=GjYIe!T%))^-VOsi|w?DEe7f8d5v2~+(a(#=PxQKy!CZ&KYeprv9vMJL-Mp<`G z44VXSBHA6bv8YrJB>3>asl7)uIll0zy@B>2j?V1BQChRcKP6(HAzxJDLOrleSyCJhEsN?g|983)PulI;sWI@j zG%ZDQ17VSEuYxDtG`SDlnVDt#9OFf}A5K0P{bV9G@6Kg4>-Ea5F#O8yw=mw^3#mBk zpqt}f9XJ_Q6)uzDk6Esp6Rsv(ysn3~e@T6YY75N4gc@oe^dx2b`k@^8rH-=!H!}3H zHUw`z^fi=FZtsUv#+`*_S=gi3h)Mxg>S$6T)RARaWk1aC%FWa{R&w zmcJY!{S#J%*8;ga%l`5U&GE+aJ?tp@ZgcRJk=?US%9bCV)3YF?ZA5F~vEN_5CZev( zvTMOq6C?Sf0j~F>K5QDu8xNv~i{`+k*2=kyf@*Xk=6yzSqMmex zDaTp9ft73L&*T*6E5?Bz;6(_qvyXcwLuhd)yDdp#Vp|tT*}4?$TUQIa)?Qm~C_0ga zoGMbXdu3e$_DggkzmrOTppD`Pb|B8y2@v86t~(d$5LgZA;tW&oaKo0!Y$5SD=8*08 zZvmM+<68>Zj~}veyFj|yKY~QVCT?7-J{vUM{vA64W@^Gvqyq2;lAI*YGmZ**hcng_ z2dnf2*L^5vc%*W+auusQ^*6E|tNDUqLBdN~g1Vr%HN^u|LsLgBL*3}q^1)u^2Dxvu z!THI8(~KvQgSgYP7&Wdn+?n~~XUhx-bIA0=>pP8*dmf7BlN3yv6O&-GVc)3^&u5L+ zg2evZ-5ymg!(II6>OwQ+8jM=)(Nok*_)&iyajW})FV=&cJ%O@(zwCu0X&!Pg?aCVm z4tjqsQRsao8YIBQ%4ayJosLoQUT?fjQFv6IEQ8cj*PEH@k_XIu=3nS7&B}W@!7_iN zAvD&GJHf?%(nUSCsUfHlQ_LBxos}F`EnBSqzB7`~fZDM9K6-nZSi-_Vh<4Pu_o_nI zqI-48ai{Os+=Fd9(*!^`zKn^MHYcL&8X59B8|wH8#+aoh1}=OCZp)a}&U5Rz{3R}0 zUi}=b$)x4FIaY^T)-t?{vJlhlRn)t_Q;@C6wa(buJ3l+<@Sw~*xsPjM>LFxc;(hTx z^?}OYtkeK_&WRULB!68~l9ItFEChOeX<96ElP~~Tv{xfI4OOSSv5J@$7KTR~s&DlT zMF)8sTcR-%g0IIyw6hM6EN4TKtl|965u^OA5izm>di`{;+LJ%IprA#z#%z_&6zEOx z@ZF-+l4o1+duisDUQ8mK3ghTC?@7MlJ;90KOP<9~stnP6T*xML5R(b&NMS+~7syS< zQsnTJMdGf|D;>M48E{G|-xLLwhM*x|?n0|#*_NiqXV)b*r{Y-1N0MjNM zvQ&unE8cnv>c$l^&c)kfd^@Bl8rn0H>RE?5#KZ?XXY3nr=x#>W@};MykaVKIif$@r zBFVm}n7R@8$^1CRNI2YJDjpZ^KV(cQ0p3b(RoTMPR+&_|i0~bx5{<47nJk+}JZ#@A z!d(e_4{x{E3h->+?5<|ndCkeApjhSY$5qeC`JTu8djLZi*|jahfYsyd!q}ZVYqXKU zH(2)@?$Y9K)AZZQvZsr0*qE!57Uzp*@`FBXe|MkqH$)9+AlkF?DY6TJ!3^t`eiIVu z>MpBCv8$GUoc}31=3A=BUhraju)*wF6H6_jf3=Sd9D?diW|>Oa@wRdNAdGRM&4jMn zN%`U{h7fLRP^+x-#;R~=DCe+rKaoz^7G5F~YsOOG+EGzX2MVK>*(7egSvTd5Rbz#` zN$Ia7YDbCf%eNmQ|8}N@Uc)C*+-IezI%5ZTfagDu{(&g}VS@cn zsBwtKPwopM3+C%8wErS5ib(Z8ue?7&k@vhsyL$F@+I;N0rn(mHf_7m1CfjRH{y)-L{mm6a<&oD$wa=>{LuSPgxOy{um&;ptPS(6{%LgEd}lqB zl2#}lKc?_(U}Qvvvd|b2RB7CbQyiKa`d4GF##;a8Tlp+Gn-N7VCd%}TixZq0?d6)PL?`q@_K#x$Nb#qlZU1Z;r)5_ zHd+2|G()7MfrE^TyxLr92>&^?WDFO%96InRM*?1B+hLs{7NV}C%MPN#POQ|58C)d~? zh4I1jbOA*TZLcE81c$yYS#1X$x)dAvw;H!ET-Qt>P;bbKBOcT6Z+kfd&1hwgUR(={ zix!f`c!69?B!hv!7f$J9>rBO$93lsQN-rKQX8dErH9L_*3Am9O9)( z@!B+MtTX|-$ES9i)U{sZNtct{<>M~gV6quf$ZVclcWpvm{7f1cXFF(4y;Ab9EN+pX zHXi(WGBDkWH+exc>^b>B1Rut8@RSftN1mcBbwJ*P@E8w%=OpyGn;?SB+a2DvE$%OY zhkU(;l^6j0fJ&ORVVTak%IlxSIvR%N5QN@nRZceD2|FF@sqJe=$?qh?b zHlRGrpa5XPUMciV1DtdSFoQBc}Lc_sYGr ziLKm8Gl+Gx%(Kru{Wjs4K8~fsPiLeEhcMRviRk!ZZqWsv?`idV?)BItzKbsL_U3@% zHNp#~KQILn*ZL_Cb7$g1Y#^c8OyVr!+}=dF+Fa?UP}qG3+bBMMtEuBG ze%C%dRIsDR)7>_dROV%m126JRY!jB|d_wkv+#cULUH{9xSxhqQQ**3mfFH}vc33WC z-;S9caM`kVH{?#SAKU60aGgIooQl4(YIti_u$VYXy8Dxdz5eKTn~~6HE7Xg9v?l$^ zWogiBa&cqniUg_@(8I}D9{HiqK_rINWqHwxy-PoI=3>r8_}n4mp?Y%NsA2-&{ZL5o zXylT<&qEjR*3IsGCwYD)VR7?keXpTR^uvCP`_=JD)h2g^3d3}=hI z(X$$6!gPKsJAdrmcyi8KHFUPvw<#Vx4GWwcdZ9mC{NsC`U(U;HZEu4q_av=n-mu*m_kA_ z*dxCMC9!1il`~fp%l^{QayePBHH0&K4se!|t~*eRS%Rw*xGnGG5M^L<l zWaWFRdcUhmUs^+(&g9VMWmzVqN;csEoA5PGLF89ms@rV^L2EG zg8RL0yf#B>oynw>+Xu;0U!UJElf;q)1F1yQ~ij4j@Tim z2E9$hiQmlh&(^2h-;EkP?S&(FgpKrrgKYE%gI0lW(nr|teZ7QNzq!V((i@s|ZqceD zCDBxDK8v=D&H^@Y*&annSsgnr)IhkolG&UH)b=ob;U6_Pp=&0%>hy+=N4Rq|wc)QP z{@2dygshw;sUqi_*ofle0hFw*r|Y1OSI-Tf*XkeiOc?nLo!FC4VebX_ zY!7@q$VFoJsb;eBm3(3{kkYBL}~ z7ML+!YuG&}Z=gBF%&M#ztKk{Gk7n{P<_!z98el9Qx4kd)Aj+GqX8ek>&eU#?EZ37q z!cX!=pRb(% zN#*t_^h`RDwNhSDw zQchoSa9wifqDW+%sMW9K*Cw!gf_ifJ)neh!%^ zjucFV_4c07+CcOeD4!fAXuzVcDJxZ!!Z`S4vzZ3y6W>lXq?Mwjqd&W8FiWuWoC%6F zd=U0Y7lSyb)(Omd5Ls{>eJxasw~LGot5yfob5bl5NTdcRf8{}0D1{I$#|j$2^-$UR zvq)tj=0g!4WvfSjN^6J3bkOag+87y+JZ}@UcnpC(O3gn(8uv&2#S+sYckg$v`YLfk z1m)C8YC_yQ>xIHg0J`$SdPTc+&uOJi22MQR(QHpn&f*pdMR^zDL?@n&EKc%3`|FDU zM*H@Bzz}?;No5a_3b?$Ky;qL1%Ln0?Q&UaU_?3b?y#uUp@3-!1oY9vR#lJs{x_sz6 zZv<)_ZQ6cpIqwW-yWE>|?XOSMM%rGQ6|qV=)~loMIT6{%4um7CC-jAC2-?{H%0-H(G>}LcbjMh({+Q)xbLWG3p;U zcKe+&D~d|Q09^nfVRs=SobHTj@tz94rhsiCxPCp|WV;QoDE-I3Mbl>YH+k${&?pDn zjHHd@;`CiR2Bt-HtK@P!MU!&LpxeR(Qu9^*RWK_)gg>aZ#%A;YG@2>qvU4hCH*D4SY95Knibm2BN z8ua3z>k=kevHE-k@-sblJwC|*Y*@NF=9y#&b&&An397Ljf4HJx%|Nh$igVz<`3130 zd8MU^=!$2-5W{Huu6&K_Ps79}f1e%g2^h(7^|87D{;dZ1j`LeFcW?5EmrXVU_fNm| zna!Ql#j`T3mV#h|QchWDGl>d#qU}H$S~50SP6dsH#id;CNsre+QFA=!Ub?-oKYK1TS;cd;cw;r~HA`71S|3cYSaNP@ z?g>ex&UlC%%vHWEsYyXjdkza<#f{sIha4~W zGy;VJ0LRtx+6X_H$XnT*N7w%qmw2G*4LR%>+3Z^AO~3c>%v7yhm5m{|_a9^KO$F;> z&r^|9Q&x*q8&?Ctdy579*VJP^hOxatFF2h)xhvN{pOnT3^h$hjGM9L3Y?8CBgq34nb(LN14j zTmDdH?L}&z=`ovx;1l6VEhFT$>mPGkm9jVo+Z?^D9EB1BKfZ%-2$)zGwb}}$?2jX~ z0PMPQCjtg-Y>X=+8_~opjcxTtc0id9W3SA_HUl#W^x;!GJy*@EaS=}6G=oJw{aucy z8{)6+>m!Oa#`2@42M;?-J%$77^(~Y-9P}*YQ2)II;H`~rwA3R*uOwa|E>jWe3c197 zv^#f$Aux#i)jOVr88@w#&b#!q%s0LBlsZ1;9|UC33Qw$8(QIdxwUd)@DCSPuUl?M( zyKMGk3Zqr>GJ3&%AMBY&xh^%yL@20YKq^RV=|I-2TJ7HR$rSb$0fVn)h}&MW~;o5wyypq!}WnqcC7qr{>Dn>V>Vxw zf+xjiSRZ?;Mc2DQMIDZ}%BepC6-vMp)BX-t4^hW}C(<)_D2_8b#I+(5!CFSFU` zN+@l7e>k1Pd`3ci|J_zOtqsw8z6$4>zw`x%GJ!Emwe+WLnv>Y&LfRva>3*`mVqY^> zA(M-!nY?_7xmx%S?_kbOYBZ7ke!}1)f%uB-^S9i+MdA z%>9y)<>XxZ4hM~-Z<|chS#^pxN2l%iD(@ISaw+5Jc%*AC*4GMR?B_FPo$95>t+ovu zv<>hYFEh{&MuSULaC_zN3=fKq$5$)Yo4)NI(4Aeo&|gc^Z(_m>h^hTK&z0xxYW-qZ z1c$p6Qhk#zTGX}=SWALettT}am6H9e?J=xKveh$+@VYBEsDGboz52&jOH=^{>~G#L zD_u;;;}vw9-`k$|HGY%|5-%;9G-fgh{Q*3;z>Pju_=f;V6YL}Hd40)0f$h{a-JQy9 z>DRwsvsc)&EtGimMvJj5TfXZ8%grXKSyD^Aq6VU&sLkMV*MdSFlfL4$5SOteq-MIQ zw_Ej`MeBXO_CbIbvJLy#%3W}$;enT4-glz%FWn36N|s(<2W2|ayqrysq{BHCQ2>l2M+tr`w%2n;7Dm+R}JbgZaW{TMgy)wC-`&$L8F!( z@{nB}>W<3YV=fJXk4GC;@~Ksm`~6kxw8M#&&)FhW;&0RBWF`Bmut%~)&Ul-5btgP? z`)d8|cLnT^HI5Zmek}|3e0pPwPzH?iCyp9PCk8!GLcmF4<7PGxw&&xUlF`)kxb0hd z^A#J3EMC}Zv5HOu?dR}+D3cgr2{D_KVLq+usBuQ~p3`?;hLqbpu8bNkAZ~(Ik&tO( z|DBtU2+9{hAFkACz%qpCjPCFt_(6|L;=W85t4}QiLa6<8AXS9P+^n*^W#;1YP>s1; zX9x#dhK&KM553qFS0m|$K|9?YGcfN@Iz~02$-u9%?((Ov1MnHNS(Zl-tFomL1Z$9K z`XLsgLFvDEbkR)EggLf(E~af#Tx2)Mk?uG+gWq6UsNiKf9?fNDwP-Qf)$mfh9KzFL_sOD9k%`Hl&qP2=Y}@@y96W!|X4 zkOrIC!o!#GvI4_4IpT%SFR`@WHPLH72~unLxQ38p`T;d11Kz+pH(Z$SA+@%9sn)y> z8aVO)4|o^;ZRE7SPPl#(VH%imq*9p(4m9T7~b*X@6C7a>tF@%KtgQ5ql!1{BKsq zV{P(p>72fhl*gV>B~#R?XNyt(39&w+24~_Q#uDoyM?)8MF&&3=^e3D^z%YUlA-u=D zeoxzM3`Vp6x4?dg8KU3v*!l-_$+ zAXMok6se;08VCZRh(IWz_fRdggn;y3q=k+Uid27z_kQoJHM8coW@gP_St~1hXP@kx zlk>dK=Y5hbnI;sLS)ez3j^wUfAFN@_ka_TOS?|wka7qgb0BKSUEBdYV(_h-c-VCz$ zHXCmXtB$OF5U}wMWzVg3+_e3>5YO^4T1XiXcnrTfxj4nzQT_(oX^{06WQ@~81@I0? zK6I6Q82WonVbYq^+E@Eu!IjKEbu9z*69AyYQcnFHkkYp^1suXbCFFsJw) z@VAaj9{g8Q{r5d`Q_@}j2u433_s{OZuv>1Ke^{9n!3*leniE2!1)?}kVOF7Z|4{bN zCg+$i=Uvi@4<&|D-Rgf*ThedA!X|u)l$c3xc0hfSApW7gRU}R3&%@oafG=+2yeb{l zkZH2kE3cQHY4ph%{pWcqwMC;)yose_$L5Np)+witC#_vEFrx-KK+AI z{Tum`!9?OvNl?yAWSR2lMyuV68Ol-*!SbVXJ4LtF*W;hw%YM+o4}NRRJeqe&^6S&h z{If64TzOlyoe6j|OzcR52D71bR^+?&EfGx$yB~VL!-ira^PfR`M0Lp%X1}jIJ{`Gn z`HsM(#hsCq#e3Nu)iSwysFV#-D;=v8VUOv0m!Z$q!F$5vz4*mbZUlvj9@B6sgQ>V~ zNG9c%jL?Tpc|U~6zr-Ao9%X%13Fi2m0m_6&%Hz{(R-k>4Q8 z)XW+*%3MQ6uZdAls%T8!972X-AdBZoWz(_O+Nou@6-AO-t+} z7_^=lNL$7VSj3q<(@(nZxq0P*-x`_W$ZMINJ4?j%rZKe=*u=Fy)fU!{+9_-b=Xgg2 zOuX$uSRU?Bvvq6N$f*rF?X+S=z5YOVR=C?a>(Y(Xy~kA7{N9Rf^jd8f`>6f3=->Co zD8Om!MP?+it?A)4;+Z3-D;}o}ysOEV|7tGg6q-4zs3Obvr^H}RWnJ7}iTB7@@-6?L z`byOk3G0+K9^Je}LxnfP%vbLBY*rUPjfgtkR119O^n2f*fgd8nBfB+u^h`$Swk{_2 zyCv4AcSG*-i{gx1JSf|UcD$@QRX@fna(l1ZSvS1Z;B5nh9n2Fob3kQJ!{V%efW z%r$p0ScvZEi5z!{lTu)dh%gTc(ojsP!|mqX56vVBHQ)!y%oY*gwn(3C5*_PyaN_zc zFHQ#go&ng|gFp+w3O@w~8WHxb%gBTlHFGTes1A+VcaEBJ3!f12JI;Ej>UCC>J^{kF z+*){Z`Q_eGOuos~D%SkifV}t|jW^H8>lpjT5bXE9Nj)GgNGU+JrT3zZzb=^)J9&yJ z-rqdql&j6;w;n6s$oJDaf^SuD_X(d@yb{wc+YP-59#daGZ5^2vp~pq*z*jd*Jp(N^ zhPS6)VC3^A=(GM>*xouV_X?EmIGPV*S1+??IuRW8wevpDM)YqVy;!jlkv7q5$l*tj z0}{)DFjv*5t&WM@Vu6_q<{UZt=SfQzyOyU+Gu;mDnR}+;3uy zghRhQ4m%x+c72{<$d2P{G$3W?qccF+FLU<2i21=sj%ata1yf%Hn7F3|vwsDe)4^IeZ&a6xa9WEq%Y~ydUTn2EXKn8Ud8C=b0ObLJ%vD%c9aCvkEGmS%yyQR@ zELc0S#pTSO9o!RO2^X4KLKFSq1YDY(G$637&vSY-gih@+Iwb!2jf2gukG4Q@*j?D} zg7M5ckE|P$DYgkErpdmFLEB?wFxf@Qh@IAbS9^1Yv6{_8#K?-Hs&6LE>qz^KcukP& z+rMOk43Gyt7orFX)zVhgheM*9QZ+sP>9lh_t6siao}LgL&v_~RL&*oH1tWQDeZR!1 zIge5EuPfC-jCwhOWAH=UoGaqi4R?1;nY{(eZX?;6%5xX5;mctjl+Odd#xAqqp#`@2 z9Pt_{Bc{OS#vaM}Y{$Buu5pYs$t;Gvj9f1lGuw*V8pCab!0LR6&{TIUiwb#~YVJhd zb0#X5)}}`R_D^mSirhfMy9Vy+_?iq6V^yACUh@J~HU1?Zp}pJ$sM@{Zd;Cn;Jeox5 zo`?L)3Vxd23O))0`MIJ5cPd0owc*_ zOvABIynVQeuyHRMGYxJ+BX(j2L(&=yxCZ+h6$SZgS3piWLbvYl_Br0;+?Ar?eCCkG z87NS$Tlgrh8)I`~7JVQ!7d#A>ivF}aJMN-hmFS1;HVGb=8GTPwQKQBiWLkb%P%|*J zU6|#lE~AmPI_1VX*<4M&+Q`P$c*Dtv@T2rD(4ZG_zBGw-?MYF6*ta*rD3(%@C&b%W z2HcTdY@*@+qJQ3aELwmn%TaAgJh8K26t7xncH?*iteI(}LP|P8PYVhq6K=Y1z4mFJ ztmcM*0zvt{b`q`{zVPGI<09~t)c5;_@p1GyS??^5`t)a@0Ui3#p0Fv1ub$fYjF%ox zTQA}a##W?qjI)JoHiqQtEXVr3mohV{!+3PJ2_1w`y^YTw(6K#=Gxj{jk^(TbWxYGE z-cNt5ZCwX`^QRtW&vP$2rR$OG+aQ|Lv*4a_b5Y|#7jl1H%iHO!VEjRR%8GLjLHXdi z0#;u+XAeh%{sS6J2$xB!N&bw@(^KFd-IhSNJ)FXK-YPL%I)4oKRP`I>xeS z9_d))4bgaW>W}0rR3CQQ;i!m>V<5agmg${j8Ez6g=6xQXy}86avUD&zOxt5Q>#P1m z-SdYEXqIk({g$IlZ9LAW-Lz9ccF(;@<*N*MxFIut?o+r$T8Lu%EMWY!`H6p3sYD{{ z(GJ8j^*MhN`*+i&8&S|Rk3g_m_SJlh44XEG7kwdv8ZYa^`)^t1ppNY3v4_iaDHE(YBrGCI2JVH%RW z<6yzvTW_%?1pDQgc7mZTdi?AaT%3!Y}9~R)+FBoF={nVPOoqx#6q0 zMK~L(>Sgq4k6dr(O$ME;!Ca#M13;ejq4x@~ECSpg z`;}4nHO2Pytl~+=e42^ECSjEdqr(C5kR+qxV?%Z`erf!cP!Y+GD8l7GX>paWfRz<(l6o5 zr!OLC2UWq9s=2S-7IH}Q4<%%Dum)#dAI9F$D!L>(T?ozbgE#t4r@xLenE|N>ofI^T z+7q1BWpglRD`)eA6J8w~SO(!OMH+X5NRY7pM#I`SttUQt?cE-v%l)tCEcb%c#lw@f z0ukT{=-n@C5xk>kOb{o1DxV}n3Eu-{4TAdE^vBUF(vI#Aw4)oWN;`MC@GgiJ2_~ z!AY0@!#g8z*}*p17fz}|;*lBc3AmC!J32TcEC*USr!N6d$r>AOf;}tr80ptvM0{Hm4!9ze)6HRWD{T-OTk;vqNd#9>TmI0yw3_XD*4eg zJdQ}7p@3z-VW!^&#;>PKX{EK+*B45K14dlgVQ8IQUUZj=1Vmz6MISGsYT?GV+|uZ+u#yfc`zH)ejfH)RJKy{>!$jBVWpSD=t*) zWSfRD)2<@o>3h?-s)zW*-W-UAQHZlBu=(H_x-7))cQ^ROUNirUPuIR{EW_;9&)v7t z$6jFBA%E&U=Kug0@^Pqa$EQFPFX?%iu|o(mbr&Fl(F#^J1TKJa%ZH%@I1-S*HSti$z_AK+&odKpSs zXG;8lifp^JEnCDE|C|c>uV;i5u?9^IkB+~w7VesUTmxz{S#^0{wKHRNf;BU!}Z40Pp=zc z?CO@PfXctp)VTENAYbZKBkaamI@5>ndai53pSf=T-sI?fXntB@b;s?etWo(0Ut(B> ze@czhP?bRFcT1rd{4v)35pmOM%tWpi38xD9MbmG{lZ(h{{Rs@xDf*B1{7>RfpOoDF zU^4d~b$`FsQDvJ=Kp%ojvg8Zo|2gf7eTScPIAv1Bx|j#ZlxGn{<$ma~s0AM(2JhbA(E0&Fc&}Rllx$H z4Z&PNumuHP>fbp6{QZ&qH=#uMVgELc{cqsgU+KiSohFmWwrX;}_Vqo5kWH^v!JGF~ z%=60!uTIwzaB)30xGaY?vp>PONDs_FHl7}EKRa}UN_ch0J(gvV4iLt5`oFEV>9Jnv zO}2aO#IrEV8rDSYpgWLm8Nm4>j_y^FZ352q*P#T*oQVe1=IQ>T_&r#C;`qXUIbO_r2l;D%+5gAD z9nUFg-|Y_-7R}o=sFd-FsyAM_7UR^$YDo|c4F+Z$nTwS7TuQ%E_S}bL-m`4=icC#Q z%}C8owaE{lhU_iAOs^N#;Nae}{d@M3SII^E%>dXe3y>Yi0sKIY0=Xw0;7Vw(ku{nT ze-`gKA7AVH_+%2uUT+)iWMJI>HZnCg)vKmP6Q3QdLy25d)VhN3$bI^ZCt!yjcE_G9 zF7xQ&-V5S*Du^q)A$3}lFzx!l-UCMS8s5R2>kfg>p78K^Q+#Z*V|e@>kGdLt zcu>}p|K&Eznsa_Dueot0Wbq-^uLrm1LwU(Qp?{U=T>C1O_pyy}=eUZ4_(6Y{`{$d` zH?-yhmWmMgttR)FPGdF&Li&(CSwYJBCw1*BW{q~?5EvyetZ(Cjq|{i z`avxD^C{To+9H`(6dj4mt8%{!1j4m{{3#Z=3?uHe2{gE_WuLCPb|nGDO%>iel0gUa z+o;JJLjBC(uZOt|Y`TjaAEhqah?0=<>tXsuw7SEa=YsbiZwE zk@0dSI;sXoaJ^gf*(5ytaBkO9fE*IcA6!00!&=t5O8a8OUEkP1&%F$2Wh%hQ8_zJaOb`oSmSKN0O$;GlG5{YPV=VfIEZ1XKQ zd}DgnbnJ3b{v>zmJyBmnB{S|~#OSExXZMKxLuH>L6IH2P={0$!heo%Hb;7iHeG!7? z)D#BQNuM58smBXo)wAxM!|{IJQ!Y0xru@4a4IssO8j}7ufzEdnZ-^vh>xhq zBwx*^Eb=3k4X>3=OOxWx0<8ks^v&3nxQ8+MVpE3bSZqG6WwT~(`r#p-+AyZoW~|$u zyw}pZHy1tKg<5hAUd?BagG0W^bTs$OY^8N7%$f6(AP?i4V6hsy^*0pV^2gA>u0lEd zwkhrjyB2GJ6KU0m0b-Dk7ZAmXIO={=Jc#Wp6LDvjVDy7$l;KN<8fM}A*$NRj5#a!V zs|^9bt+7a?k|dleFdTrcjdPeXxyL;e1C?HN7(Le}3m=G~8PrhJO{g;#vE(G|e!U@{ z|De%MFKk4qCQ$jIi)=B@;H{+0XK|x53N4wq<}yG^wiMn*_C)`kb#k^cqvc=*V;8Y$ z8kzGRPI7JwD%CNLcvPWjwu|Mn{l2Wfbr1)h1#+Gxg>Dyb5(KoK{9wD2TuAflO$rx%zpO$@T1L+AbXQsdhz@Xo4Z zA|>}7PBTZ6y2g%0$N}4B!7768MGGkWBy)bolnZku*-nTumv^8l4&`SMQclWs%$w}N z{i3noEzR%eA+o7Ak%ocpdJ&-HEk)1A3+VN4PZqG+GhUXF`^-J|&xxvg&yyt-h`y;^ zYj31Nde(r1M7^&frd3aD%6cvFyXU&TDCShdwPFWCT+*j9%xhMUSq*1R_n}ggz$C(B3F09kMf$80{-O_nVJV>rC1JblZ*}Ap5+jmaH)AS*P2nhP}S95JsxISXHq_V zd6R?wfrU!I;|)=^l2w&z^kaj8cJtt6mu~Nx3Ydzs_NpnSiOEC*IdHJ9vie@w4C(e* z+e=t_T0Y5Uy^Nu+K)$%Wy@xboc>1q}16Xkr>_w&i46bkcZz@S@4U}n|+roDj)-HMP=uoX=qoF<0n9s`bV~Ogy zW#*Wlzpe~ldC~B|u`SCFc*Q2pK`e*nS)ZB(n~l9-2Ip%sRva81v2%y)l3Eki7KhN1 zfpgCajY<1{;_`~DMSbk8d)~?mEfJR$d@{|HHoy|tVD@y8g1=wqkQA>7B*&Ri-8pTW z)YxP!Qofk=He^j#3z`JI7#QjZbW@gny0kNOgyT zf|k#GT?Vvke$of#XrW?~a_F}E8aRIljg`WY; zFtsLCu>Pq1&2z+7d~=0MeP!5jgScX4;_e3G!W_#!6AWT7_uriAF+Y!OvkZg^F*>#B z8Xh+oJC=Cu-Ky|BP_5lVA*k2h)|;DHA%ZxQZGqXyr>D8mVC7%{PgDaM^N1x(k zN=;nuG(8B>|H_vrFy1tpZZ3~f#h4C=krG5O??tIH$`aoHoS5z z0j-pbk`dwIgt(NoSHFJ#z;`?`$v$1>7IE6rZnDoiw>{wvl6Ey42WkAcWHT{=rOfF; ziIDmxu=TGvvNV`Reh10Ivs@My70{J_E%WG0v+fo!MkX;PI;z(?yJhv#@T#Jj1$mve zFd7^c6|ie9>Y=;P+@t{&P9ia(!N(p9eaC^cQBRaqG-9Q-UHb}VaW`RaQ?1zlv12_` zp@&NUVPsRe3;GMTbuF4q@UL0;AI9t|ox~98VUWoRVery7vhkXg+nn5-LIAm1()%dT z&ni^Fx2QX0D9L+xDpjJlJv0%A%~}!Tx~ksm!8G?3c5QS;bzkTj9+)8cOd>rXZmzYc zvos@16|?capPZU3`48A&_(qWp`AqErsKlq-3-I2QIkCf{a)ydtI-_4aj-d_F8olT` zK)d+Tt4yg%sQLeUANo+j2f)9Ci#;0qog*7E-!C7`reWck3@K8>TnFfccH_omKzs!8 zTF)~T%d&fs4)Y1A;U74DCpmXLYc;E-hIdQx&mHa4^Y9(U-jMBEbs*)(I#WowD@ZXE z*h_*FGWicMQt{Z-UAKW)?;_gQxFgt9F#+I>VFpD%)sw~?^Wtpd_U2EGK=ePJ?k}eQ ruW70OC&J`^5?=pTewtC}Z&FeFkBd#_=qTJDl@O>r*Ho-fcp3g*Eu)wE diff --git a/images/quick_setup_5.png b/images/quick_setup_5.png index b3881851294b93876fe0b81b8b9a1ff5a5764a74..802b688b16cbba9e002da01b4cf0b5b5c0c325ab 100644 GIT binary patch literal 5863 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 literal 36760 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 Z09n4ZIF+Mg#%;W&qM#{XENkZfe*m+(4VM4_ diff --git a/src/CmdSetupLiveSync.ts b/src/CmdSetupLiveSync.ts index f986328..79c644f 100644 --- a/src/CmdSetupLiveSync.ts +++ b/src/CmdSetupLiveSync.ts @@ -5,7 +5,7 @@ import { PouchDB } from "./lib/src/pouchdb-browser.js"; import { askSelectString, askYesNo, askString } from "./utils"; import { decrypt, encrypt } from "./lib/src/e2ee_v2"; import { LiveSyncCommands } from "./LiveSyncCommands"; -import { delay } from "./lib/src/utils"; +import { delay, fireAndForget } from "./lib/src/utils"; import { confirmWithMessage } from "./dialogs"; import { Platform } from "./deps"; import { fetchAllUsedChunks } from "./lib/src/utils_couchdb"; @@ -17,25 +17,25 @@ export class SetupLiveSync extends LiveSyncCommands { this.plugin.addCommand({ id: "livesync-copysetupuri", - name: "Copy the setup URI", - callback: this.command_copySetupURI.bind(this), + name: "Copy settings as a new setup URI", + callback: () => fireAndForget(this.command_copySetupURI()), }); this.plugin.addCommand({ id: "livesync-copysetupuri-short", - name: "Copy the setup URI (With customization sync)", - callback: this.command_copySetupURIWithSync.bind(this), + name: "Copy settings as a new setup URI (With customization sync)", + callback: () => fireAndForget(this.command_copySetupURIWithSync()), }); this.plugin.addCommand({ id: "livesync-copysetupurifull", - name: "Copy the setup URI (Full)", - callback: this.command_copySetupURIFull.bind(this), + name: "Copy settings as a new setup URI (Full)", + callback: () => fireAndForget(this.command_copySetupURIFull()), }); this.plugin.addCommand({ id: "livesync-opensetupuri", - name: "Open the setup URI", - callback: this.command_openSetupURI.bind(this), + name: "Use the copied setup URI (Formerly Open setup URI)", + callback: () => fireAndForget(this.command_openSetupURI()), }); } onInitializeDatabase(showNotice: boolean) { } @@ -76,7 +76,7 @@ export class SetupLiveSync extends LiveSyncCommands { Logger("Setup URI copied to clipboard", LOG_LEVEL_NOTICE); } async command_copySetupURIWithSync() { - this.command_copySetupURI(false); + await this.command_copySetupURI(false); } async command_openSetupURI() { const setupURI = await askString(this.app, "Easy setup", "Set up URI", `${configURIBase}aaaaa`); @@ -108,6 +108,7 @@ export class SetupLiveSync extends LiveSyncCommands { newSettingW.configPassphraseStore = ""; newSettingW.encryptedPassphrase = ""; newSettingW.encryptedCouchDBConnection = ""; + newSettingW.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}` const setupJustImport = "Just import setting"; const setupAsNew = "Set it up as secondary or subsequent device"; const setupAsMerge = "Secondary device but try keeping local changes"; @@ -115,6 +116,7 @@ export class SetupLiveSync extends LiveSyncCommands { const setupManually = "Leave everything to me"; newSettingW.syncInternalFiles = false; newSettingW.usePluginSync = false; + newSettingW.isConfigured = true; // Migrate completely obsoleted configuration. if (!newSettingW.useIndexedDBAdapter) { newSettingW.useIndexedDBAdapter = true; @@ -333,10 +335,18 @@ Of course, we are able to disable these features.` const ret = await confirmWithMessage(this.plugin, "Database adapter", message, choices, CHOICE_YES, 10); if (ret == CHOICE_YES) { - this.plugin.settings.useIndexedDBAdapter = false; + this.plugin.settings.useIndexedDBAdapter = true; } } } + async resetLocalDatabase() { + if (this.plugin.settings.isConfigured && this.plugin.settings.additionalSuffixOfDatabaseName == "") { + // Discard the non-suffixed database + await this.plugin.resetLocalDatabase(); + } + this.plugin.settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}` + await this.plugin.resetLocalDatabase(); + } async fetchRemoteChunks() { if (!this.plugin.settings.doNotSuspendOnFetching && this.plugin.settings.readChunksOnline) { Logger(`Fetching chunks`, LOG_LEVEL_NOTICE); @@ -351,10 +361,11 @@ Of course, we are able to disable these features.` } async fetchLocal() { this.suspendExtraSync(); - this.askUseNewAdapter(); + await this.askUseNewAdapter(); + this.plugin.settings.isConfigured = true; await this.suspendReflectingDatabase(); await this.plugin.realizeSettingSyncMode(); - await this.plugin.resetLocalDatabase(); + await this.resetLocalDatabase(); await delay(1000); await this.plugin.markRemoteResolved(); await this.plugin.openDatabase(); @@ -369,10 +380,11 @@ Of course, we are able to disable these features.` } async fetchLocalWithKeepLocal() { this.suspendExtraSync(); - this.askUseNewAdapter(); + await this.askUseNewAdapter(); + this.plugin.settings.isConfigured = true; await this.suspendReflectingDatabase(); await this.plugin.realizeSettingSyncMode(); - await this.plugin.resetLocalDatabase(); + await this.resetLocalDatabase(); await delay(1000); await this.plugin.initializeDatabase(true); await this.plugin.markRemoteResolved(); @@ -388,6 +400,7 @@ Of course, we are able to disable these features.` } async rebuildRemote() { this.suspendExtraSync(); + this.plugin.settings.isConfigured = true; await this.plugin.realizeSettingSyncMode(); await this.plugin.markRemoteLocked(); await this.plugin.tryResetRemoteDatabase(); @@ -401,9 +414,10 @@ Of course, we are able to disable these features.` } async rebuildEverything() { this.suspendExtraSync(); - this.askUseNewAdapter(); + await this.askUseNewAdapter(); + this.plugin.settings.isConfigured = true; await this.plugin.realizeSettingSyncMode(); - await this.plugin.resetLocalDatabase(); + await this.resetLocalDatabase(); await delay(1000); await this.plugin.initializeDatabase(true); await this.plugin.markRemoteLocked(); diff --git a/src/ObsidianLiveSyncSettingTab.ts b/src/ObsidianLiveSyncSettingTab.ts index e62c101..e51de80 100644 --- a/src/ObsidianLiveSyncSettingTab.ts +++ b/src/ObsidianLiveSyncSettingTab.ts @@ -26,6 +26,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { } this.plugin.addLog(`Connected to ${db.info.db_name}`, LOG_LEVEL_NOTICE); } + askReload() { + scheduleTask("configReload", 250, async () => { + if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") { + // @ts-ignore + this.app.commands.executeCommandById("app:reload") + } + }) + } + closeSetting() { + // @ts-ignore + this.plugin.app.setting.close() + } display(): void { const { containerEl } = this; let encrypt = this.plugin.settings.encrypt; @@ -136,29 +148,27 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { const setupWizardEl = containerEl.createDiv(); setupWizardEl.createEl("h3", { text: "Setup wizard" }); new Setting(setupWizardEl) - .setName("Discard the existing configuration and set up") + .setName("Use the copied setup URI") + .setDesc("To setup Self-hosted LiveSync, this method is the most preferred one.") .addButton((text) => { - // eslint-disable-next-line require-await - text.setButtonText("Next").onClick(async () => { - if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) { - this.plugin.replicator.closeReplication(); - this.plugin.settings = { ...DEFAULT_SETTINGS }; - this.plugin.saveSettings(); - Logger("Configuration has been flushed, please open it again", LOG_LEVEL_NOTICE) - // @ts-ignore - this.plugin.app.setting.close() - } else { - containerEl.addClass("isWizard"); - applyDisplayEnabled(); - inWizard = true; - changeDisplay("0") - } + text.setButtonText("Use").onClick(async () => { + this.closeSetting(); + await this.plugin.addOnSetup.command_openSetupURI(); }) }) + if (this.plugin.settings.isConfigured) { + new Setting(setupWizardEl) + .setName("Copy current settings as a new setup URI") + .addButton((text) => { + text.setButtonText("Copy").onClick(async () => { + await this.plugin.addOnSetup.command_copySetupURI(); + }) + }) + } new Setting(setupWizardEl) - .setName("Do not discard the existing configuration and set up again") + .setName("Minimal setup") .addButton((text) => { - text.setButtonText("Next").onClick(async () => { + text.setButtonText("Start").onClick(async () => { this.plugin.settings.liveSync = false; this.plugin.settings.periodicReplication = false; this.plugin.settings.syncOnSave = false; @@ -172,27 +182,34 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { applyDisplayEnabled(); inWizard = true; changeDisplay("0") - }) }) - const infoWarnForSubsequent = setupWizardEl.createEl("div", { text: `To set up second or subsequent device, please use 'Copy setup URI' and 'Open setup URI'` }); - infoWarnForSubsequent.addClass("op-warn-info"); - new Setting(setupWizardEl) - .setName("Copy setup URI") - .addButton((text) => { - text.setButtonText("Copy setup URI").onClick(() => { - // @ts-ignore - this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri") - + if (!this.plugin.settings.isConfigured) { + new Setting(setupWizardEl) + .setName("Enable LiveSync on this device as the set-up was completed manually") + .addButton((text) => { + text.setButtonText("Enable").onClick(async () => { + this.plugin.settings.isConfigured = true; + await this.plugin.saveSettings(); + this.askReload(); + }) }) - }) - .addButton((text) => { - text.setButtonText("Open setup URI").onClick(() => { - // @ts-ignore - this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-opensetupuri") - + } + if (this.plugin.settings.isConfigured) { + new Setting(setupWizardEl) + .setName("Discard exist settings and databases") + .addButton((text) => { + text.setButtonText("Discard").onClick(async () => { + if (await askYesNo(this.plugin.app, "Do you really want to discard exist settings and databases?") == "yes") { + this.plugin.settings = { ...DEFAULT_SETTINGS }; + await this.plugin.saveSettingData(); + await this.plugin.resetLocalDatabase(); + // await this.plugin.initializeDatabase(); + this.askReload(); + } + }).setWarning() }) - }) + } setupWizardEl.createEl("h3", { text: "Online Tips" }); const repo = "vrtmrz/obsidian-livesync"; const topPath = "/docs/troubleshooting.md"; @@ -338,6 +355,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { new Setting(containerRemoteDatabaseEl) .setName("Test Database Connection") + .setClass("wizardHidden") .setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.") .addButton((button) => button @@ -349,8 +367,8 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { ); new Setting(containerRemoteDatabaseEl) - .setName("Check database configuration") - // .setDesc("Open database connection. If the remote database is not found and you have the privilege to create a database, the database will be created.") + .setName("Check and Fix database configuration") + .setDesc("Check the database configuration, and fix if there are any problems.") .addButton((button) => button .setButtonText("Check") @@ -557,18 +575,18 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { passphraseSetting?.controlEl.toggleClass("sls-item-dirty", passphrase != this.plugin.settings.passphrase); dynamicIteration?.controlEl.toggleClass("sls-item-dirty", useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount); usePathObfuscationEl?.controlEl.toggleClass("sls-item-dirty", usePathObfuscation != this.plugin.settings.usePathObfuscation); - if (encrypt != this.plugin.settings.encrypt || - passphrase != this.plugin.settings.passphrase || - useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount || - usePathObfuscation != this.plugin.settings.usePathObfuscation) { - applyE2EButtons.settingEl.removeClass("sls-setting-hidden"); - } else { - applyE2EButtons.settingEl.addClass("sls-setting-hidden"); - } + } else { passphraseSetting.settingEl.addClass("sls-setting-hidden"); dynamicIteration.settingEl.addClass("sls-setting-hidden"); usePathObfuscationEl.settingEl.addClass("sls-setting-hidden"); + } + if (encrypt != this.plugin.settings.encrypt || + passphrase != this.plugin.settings.passphrase || + useDynamicIterationCount != this.plugin.settings.useDynamicIterationCount || + usePathObfuscation != this.plugin.settings.usePathObfuscation) { + applyE2EButtons.settingEl.removeClass("sls-setting-hidden"); + } else { applyE2EButtons.settingEl.addClass("sls-setting-hidden"); } } @@ -703,6 +721,7 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { this.plugin.settings.passphrase = passphrase; this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount; this.plugin.settings.usePathObfuscation = usePathObfuscation; + this.plugin.settings.isConfigured = true; await this.plugin.saveSettings(); updateE2EControls(); if (sendToServer) { @@ -731,26 +750,23 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { this.plugin.settings.passphrase = passphrase; this.plugin.settings.useDynamicIterationCount = useDynamicIterationCount; this.plugin.settings.usePathObfuscation = usePathObfuscation; + this.plugin.settings.isConfigured = true; Logger("All synchronization have been temporarily disabled. Please enable them after the fetching, if you need them.", LOG_LEVEL_NOTICE) await this.plugin.saveSettings(); updateE2EControls(); applyDisplayEnabled(); - // @ts-ignore - this.plugin.app.setting.close(); + this.closeSetting(); await delay(2000); await performRebuildDB(this.plugin, method); } - let rebuildRemote = false; - new Setting(containerRemoteDatabaseEl) - .setName("") .setClass("wizardOnly") .addButton((button) => button .setButtonText("Next") - .setClass("mod-cta") + .setCta() .setDisabled(false) .onClick(() => { if (!this.plugin.settings.encrypt) { @@ -759,33 +775,13 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { if (isCloudantURI(this.plugin.settings.couchDB_URI)) { this.plugin.settings.customChunkSize = 0; } else { - this.plugin.settings.customChunkSize = 100; + this.plugin.settings.customChunkSize = 50; } - rebuildRemote = false; changeDisplay("30") }) - ); - new Setting(containerRemoteDatabaseEl) - .setName("") - .setClass("wizardOnly") - .addButton((button) => - button - .setButtonText("Discard existing database and proceed") - .setDisabled(false) - .setWarning() - .onClick(() => { - if (!this.plugin.settings.encrypt) { - this.plugin.settings.passphrase = ""; - } - if (isCloudantURI(this.plugin.settings.couchDB_URI)) { - this.plugin.settings.customChunkSize = 0; - } else { - this.plugin.settings.customChunkSize = 100; - } - rebuildRemote = true; - changeDisplay("30") - }) - ); + ) + ; + addScreenElement("0", containerRemoteDatabaseEl); const containerGeneralSettingsEl = containerEl.createDiv(); @@ -1049,25 +1045,20 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { ...presetAllDisabled } } - this.plugin.saveSettings(); + await this.plugin.saveSettings(); this.display(); await this.plugin.realizeSettingSyncMode(); if (inWizard) { - // @ts-ignore - this.plugin.app.setting.close() - await this.plugin.resetLocalDatabase(); - await this.plugin.initializeDatabase(true); - if (rebuildRemote) { - await this.plugin.markRemoteLocked(); - await this.plugin.tryResetRemoteDatabase(); - await this.plugin.markRemoteLocked(); - await this.plugin.markRemoteResolved(); + this.closeSetting(); + if (!this.plugin.settings.isConfigured) { + this.plugin.settings.isConfigured = true; + await this.plugin.saveSettings(); + await rebuildDB("localOnly"); + Logger("All done! Please set up subsequent devices with 'Copy current settings as a new setup URI' and 'Use the copied setup URI'.", LOG_LEVEL_NOTICE); + await this.plugin.addOnSetup.command_openSetupURI(); + } else { + this.askReload(); } - await this.plugin.replicate(true); - - Logger("All done! Please set up subsequent devices with 'Copy setup URI' and 'Open setup URI'.", LOG_LEVEL_NOTICE); - // @ts-ignore - this.plugin.app.commands.executeCommandById("obsidian-livesync:livesync-copysetupuri") } }) ); @@ -1286,24 +1277,21 @@ export class ObsidianLiveSyncSettingTab extends PluginSettingTab { .addButton((button) => { button.setButtonText("Merge") .onClick(async () => { - // @ts-ignore - this.plugin.app.setting.close() + this.closeSetting() await this.plugin.addOnSetup.configureHiddenFileSync("MERGE"); }) }) .addButton((button) => { button.setButtonText("Fetch") .onClick(async () => { - // @ts-ignore - this.plugin.app.setting.close() + this.closeSetting() await this.plugin.addOnSetup.configureHiddenFileSync("FETCH"); }) }) .addButton((button) => { button.setButtonText("Overwrite") .onClick(async () => { - // @ts-ignore - this.plugin.app.setting.close() + this.closeSetting() await this.plugin.addOnSetup.configureHiddenFileSync("OVERWRITE"); }) }); @@ -1694,6 +1682,18 @@ ${stringifyYaml(pluginConfig)}`; c.addClass("op-warn"); } } + + new Setting(containerHatchEl) + .setName("Back to non-configured") + .addButton((button) => + button + .setButtonText("Back") + .setDisabled(false) + .onClick(async () => { + this.plugin.settings.isConfigured = false; + await this.plugin.saveSettings(); + this.askReload(); + })); const hatchWarn = containerHatchEl.createEl("div", { text: `To stop the boot up sequence for fixing problems on databases, you can put redflag.md on top of your vault (Rebooting obsidian is required).` }); hatchWarn.addClass("op-warn-info"); @@ -1844,12 +1844,7 @@ ${stringifyYaml(pluginConfig)}`; toggle.setValue(this.plugin.settings.suspendFileWatching).onChange(async (value) => { this.plugin.settings.suspendFileWatching = value; await this.plugin.saveSettings(); - scheduleTask("configReload", 250, async () => { - if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") { - // @ts-ignore - this.app.commands.executeCommandById("app:reload") - } - }) + this.askReload(); }) ); new Setting(containerHatchEl) @@ -1859,12 +1854,7 @@ ${stringifyYaml(pluginConfig)}`; toggle.setValue(this.plugin.settings.suspendParseReplicationResult).onChange(async (value) => { this.plugin.settings.suspendParseReplicationResult = value; await this.plugin.saveSettings(); - scheduleTask("configReload", 250, async () => { - if (await askYesNo(this.app, "Do you want to restart and reload Obsidian now?") == "yes") { - // @ts-ignore - this.app.commands.executeCommandById("app:reload") - } - }) + this.askReload(); }) ); new Setting(containerHatchEl) @@ -1949,7 +1939,7 @@ ${stringifyYaml(pluginConfig)}`; let newDatabaseName = this.plugin.settings.additionalSuffixOfDatabaseName + ""; new Setting(containerHatchEl) .setName("Database suffix") - .setDesc("LiveSync could not treat multiple vaults which have same name, please add some suffix from here.") + .setDesc("LiveSync could not handle multiple vaults which have same name without different prefix, This should be automatically configured.") .addText((text) => { text.setPlaceholder("") .setValue(newDatabaseName) @@ -2163,8 +2153,7 @@ ${stringifyYaml(pluginConfig)}`; .setDisabled(false) .setWarning() .onClick(async () => { - // @ts-ignore - this.plugin.app.setting.close() + this.closeSetting() await this.plugin.dbGC(); }) ); @@ -2186,7 +2175,7 @@ ${stringifyYaml(pluginConfig)}`; applyDisplayEnabled(); if (this.selectedScreen == "") { if (lastVersion != this.plugin.settings.lastReadUpdates) { - if (JSON.stringify(this.plugin.settings) != JSON.stringify(DEFAULT_SETTINGS)) { + if (this.plugin.settings.isConfigured) { changeDisplay("100"); } else { changeDisplay("110") diff --git a/src/StorageEventManager.ts b/src/StorageEventManager.ts index 80f8edb..74e22f5 100644 --- a/src/StorageEventManager.ts +++ b/src/StorageEventManager.ts @@ -91,6 +91,8 @@ export class StorageEventManagerObsidian extends StorageEventManager { } // Cache file and waiting to can be proceed. async appendWatchEvent(params: { type: FileEventType, file: TAbstractFile | InternalFileInfo, oldPath?: string }[], ctx?: any) { + if (!this.plugin.settings.isConfigured) return; + if (this.plugin.settings.suspendFileWatching) return; for (const param of params) { if (shouldBeIgnored(param.file.path)) { continue; @@ -106,7 +108,6 @@ export class StorageEventManagerObsidian extends StorageEventManager { } if (file instanceof TFolder) continue; if (!await this.plugin.isTargetFile(file.path)) continue; - if (this.plugin.settings.suspendFileWatching) continue; let cache: null | string | ArrayBuffer; // new file or something changed, cache the changes. diff --git a/src/lib b/src/lib index 71d28f2..46256db 160000 --- a/src/lib +++ b/src/lib @@ -1 +1 @@ -Subproject commit 71d28f285df136b7e1d346696c2943004c2526ec +Subproject commit 46256dba3a12fae405d1d86f12cdec8ab93005f6 diff --git a/src/main.ts b/src/main.ts index c240aed..86a921f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -76,7 +76,13 @@ export default class ObsidianLiveSyncPlugin extends Plugin replicator!: LiveSyncDBReplicator; statusBar?: HTMLElement; - suspended = false; + _suspended = false; + get suspended() { + return this._suspended || !this.settings?.isConfigured; + } + set suspended(value: boolean) { + this._suspended = value; + } deviceAndVaultName = ""; isMobile = false; isReady = false; @@ -403,7 +409,6 @@ export default class ObsidianLiveSyncPlugin extends Plugin if (notes.length == 0) { Logger("There are no old documents"); Logger(`Checking expired file history done`); - return; } for (const v of notes) { @@ -420,6 +425,43 @@ export default class ObsidianLiveSyncPlugin extends Plugin Logger(`Something went wrong! The local database is not ready`, LOG_LEVEL_NOTICE); return; } + if (!this.settings.isConfigured) { + const message = `Hello and welcome to Self-hosted LiveSync. + +Your device seems to **not be configured yet**. Please finish the setup and synchronise your vaults! + +Click anywhere to stop counting down. + +## At the first device +- With Setup URI -> Use \`Use the copied setup URI\`. + If you have configured it automatically, you should have one. +- Without Setup URI -> Use \`Setup wizard\` in setting dialogue. **\`Minimal setup\` is recommended**. +- What is the Setup URI? -> Do not worry! We have [some docs](https://github.com/vrtmrz/obsidian-livesync/blob/main/README.md#how-to-use) now. Please refer to them once. + +## At the subsequent device +- With Setup URI -> Use \`Use the copied setup URI\`. + If you do not have it yet, you can copy it on the first device. +- Without Setup URI -> Use \`Setup wizard\` in setting dialogue, but **strongly recommends using setup URI**. +` + const OPEN_SETUP = "Open setting dialog"; + const USE_SETUP = "Use the copied setup URI"; + const DISMISS = "Dismiss"; + + const ret = await confirmWithMessage(this, "Welcome to Self-hosted LiveSync", message, [USE_SETUP, OPEN_SETUP, DISMISS], DISMISS, 40); + if (ret === OPEN_SETUP) { + try { + //@ts-ignore: undocumented api + this.app.setting.open(); + //@ts-ignore: undocumented api + this.app.setting.openTabById("obsidian-livesync"); + } catch (ex) { + Logger("Something went wrong on opening setting dialog, please open it manually", LOG_LEVEL_NOTICE); + } + } else if (ret == USE_SETUP) { + fireAndForget(this.addOnSetup.command_openSetupURI()); + } + return; + } try { if (this.isRedFlagRaised() || this.isRedFlag2Raised() || this.isRedFlag3Raised()) { @@ -736,7 +778,7 @@ Note: We can always able to read V1 format. It will be progressively converted. this.statusBar = this.addStatusBarItem(); this.statusBar.addClass("syncstatusbar"); const lastVersion = ~~(versionNumberString2Number(manifestVersion) / 1000); - if (lastVersion > this.settings.lastReadUpdates) { + if (lastVersion > this.settings.lastReadUpdates && this.settings.isConfigured) { Logger("Self-hosted LiveSync has undergone a major upgrade. Please open the setting dialog, and check the information pane.", LOG_LEVEL_NOTICE); } @@ -877,6 +919,16 @@ Note: We can always able to read V1 format. It will be progressively converted. async loadSettings() { const settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()) as ObsidianLiveSyncSettings; + + if (typeof settings.isConfigured == "undefined") { + // If migrated, mark true + if (JSON.stringify(settings) !== JSON.stringify(DEFAULT_SETTINGS)) { + settings.isConfigured = true; + } else { + settings.additionalSuffixOfDatabaseName = `${("appId" in this.app ? this.app.appId : "")}` + settings.isConfigured = false; + } + } const passphrase = await this.getPassphrase(settings); if (passphrase === false) { Logger("Could not determine passphrase for reading data.json! DO NOT synchronize with the remote before making sure your configuration is!", LOG_LEVEL_URGENT); @@ -1193,8 +1245,8 @@ We can perform a command in this file. async watchWindowVisibilityAsync() { if (this.settings.suspendFileWatching) return; + if (!this.settings.isConfigured) return; if (!this.isReady) return; - // if (this.suspended) return; const isHidden = document.hidden; await this.applyBatchChange(); if (isHidden) { @@ -1307,6 +1359,7 @@ We can perform a command in this file. watchWorkspaceOpen(file: TFile | null) { if (this.settings.suspendFileWatching) return; + if (!this.settings.isConfigured) return; if (!this.isReady) return; if (!file) return; scheduleTask("watch-workspace-open", 500, () => fireAndForget(() => this.watchWorkspaceOpenAsync(file))); @@ -1314,6 +1367,7 @@ We can perform a command in this file. async watchWorkspaceOpenAsync(file: TFile) { if (this.settings.suspendFileWatching) return; + if (!this.settings.isConfigured) return; if (!this.isReady) return; await this.applyBatchChange(); if (file == null) { @@ -1579,17 +1633,18 @@ We can perform a command in this file. localStorage.setItem(lsKey, saveData); } async loadQueuedFiles() { - if (!this.settings.suspendParseReplicationResult) { - const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName(); - const ids = [...new Set(JSON.parse(localStorage.getItem(lsKey) || "[]"))] as string[]; - const batchSize = 100; - const chunkedIds = arrayToChunkedArray(ids, batchSize); - for await (const idsBatch of chunkedIds) { - const ret = await this.localDatabase.allDocsRaw({ keys: idsBatch, include_docs: true, limit: 100 }); - this.replicationResultProcessor.enqueueAll(ret.rows.map(doc => doc.doc)); - await this.replicationResultProcessor.waitForPipeline(); - } + if (this.settings.suspendParseReplicationResult) return; + if (!this.settings.isConfigured) return; + const lsKey = "obsidian-livesync-queuefiles-" + this.getVaultName(); + const ids = [...new Set(JSON.parse(localStorage.getItem(lsKey) || "[]"))] as string[]; + const batchSize = 100; + const chunkedIds = arrayToChunkedArray(ids, batchSize); + for await (const idsBatch of chunkedIds) { + const ret = await this.localDatabase.allDocsRaw({ keys: idsBatch, include_docs: true, limit: 100 }); + this.replicationResultProcessor.enqueueAll(ret.rows.map(doc => doc.doc)); + await this.replicationResultProcessor.waitForPipeline(); } + } databaseQueueCount = reactiveSource(0); @@ -1953,6 +2008,12 @@ Or if you are sure know what had been happened, we can unlock the database from async syncAllFiles(showingNotice?: boolean) { // synchronize all files between database and storage. + if (!this.settings.isConfigured) { + if (showingNotice) { + Logger("LiveSync is not configured yet. Synchronising between the storage and the local database is now prevented.", LOG_LEVEL_NOTICE, "syncAll"); + } + return; + } let initialScan = false; if (showingNotice) { Logger("Initializing", LOG_LEVEL_NOTICE, "syncAll");