From 693867f0746af51548f8932bc6113b74b8041abd Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 25 Nov 2016 19:57:08 +0000 Subject: [PATCH 01/15] Final bits to prepare electron distribtion: * Remove the config: nobody else wants our update URL so we'll keep it separately. Don't copy the config. * Script to yell at you if you've build a package with auto update turned off. * s/vector/webapp/ when looking for config * Use different update URLs for the various platforms --- scripts/check-electron.sh | 13 ++++++++++ scripts/electron-dist.sh | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100755 scripts/check-electron.sh create mode 100755 scripts/electron-dist.sh diff --git a/scripts/check-electron.sh b/scripts/check-electron.sh new file mode 100755 index 00000000..82b24a6c --- /dev/null +++ b/scripts/check-electron.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +update_url=`jq .update_url webapp/config.json` +echo "***************************************************" +echo +if [ $? = 0 ]; then + echo "Built electron package with update url: $update_url" +else + echo "Built electron package with no update url" + echo "This build will not auto-update." +fi +echo +echo "***************************************************" diff --git a/scripts/electron-dist.sh b/scripts/electron-dist.sh new file mode 100755 index 00000000..36f60c9e --- /dev/null +++ b/scripts/electron-dist.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -e +set -x + +if [ $# = 0 ]; then + echo "Usage: $0 " + echo "" + echo "Adds the build in electron/dist/ to a given Riot electron" + echo "download tree. If target directory is empty, create a new" + echo "download tree. This tree can be placed on a web server to" + echo "serve auto-updates (although auto-update for Mac requires" + echo "additional logic)." + exit +fi + +ver=`basename electron/dist/mac/*.dmg | cut -d '-' -f 2 | sed -e 's/\.dmg$//'` +dir=$1 + +echo "Copying files for version $ver to $dir" + +# Install packages: what the user downloads the first time, +# (DMGs for mac, exe installer for windows) +mkdir -p "$dir/install/macos" +cp electron/dist/mac/*.dmg "$dir/install/macos/" +echo "$ver" > "$dir/install/macos/latest" + +mkdir -p "$dir/install/win32/ia32" +cp electron/dist/win-ia32/*.exe "$dir/install/win32/ia32/" + +mkdir -p "$dir/install/win32/x64" +cp electron/dist/win/*.exe "$dir/install/win32/ia32/" + + +# Packages for auto-update. It would be nice if squirrel's +# auto update used the installer packages, but it doesn't +# for Reasons. zip for mac, nupkg for windows. +mkdir -p "$dir/update/macos" +cp electron/dist/mac/*.zip "$dir/update/macos/" +echo "$ver" > "$dir/update/macos/latest" + +mkdir -p "$dir/update/win32/ia32" +cp electron/dist/win-ia32/*.nupkg "$dir/update/win32/ia32/" +cat electron/dist/win-ia32/RELEASES >> "$dir/update/win32/ia32/RELEASES" +echo >> "$dir/update/win32/ia32/RELEASES" + +mkdir -p "$dir/update/win32/x64" +cp electron/dist/win/*.nupkg "$dir/update/win32/x64/" +cat electron/dist/win/RELEASES >> "$dir/update/win32/x64/RELEASES" +echo >> "$dir/update/win32/x64/RELEASES" + + +echo "All done!" +echo "$dir can now be copied to your web server." From 4073688ba618b8400c9f220791830eb41aa37281 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 25 Nov 2016 20:07:12 +0000 Subject: [PATCH 02/15] Missed an x64 --- scripts/electron-dist.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/electron-dist.sh b/scripts/electron-dist.sh index 36f60c9e..0e8efd56 100755 --- a/scripts/electron-dist.sh +++ b/scripts/electron-dist.sh @@ -29,7 +29,7 @@ mkdir -p "$dir/install/win32/ia32" cp electron/dist/win-ia32/*.exe "$dir/install/win32/ia32/" mkdir -p "$dir/install/win32/x64" -cp electron/dist/win/*.exe "$dir/install/win32/ia32/" +cp electron/dist/win/*.exe "$dir/install/win32/x64/" # Packages for auto-update. It would be nice if squirrel's From dfa7c3b72eb29fe8ab37a8231a625fd723e51a0f Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 25 Nov 2016 20:07:38 +0000 Subject: [PATCH 03/15] Animated install logo from Ben --- electron/build/install-spinner.gif | Bin 4460 -> 23967 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/electron/build/install-spinner.gif b/electron/build/install-spinner.gif index c4f832c34230af5d0267962c7e1d0fab4bab5dd0..4a89337be40cf202fe232bca49c1c0c84b278463 100644 GIT binary patch literal 23967 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 T>|@V>heO2~5&w^bLiPUwJMS@r literal 4460 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 From 97c0e2dfcd595f109e992157e7203dbccc821ac5 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 25 Nov 2016 20:08:05 +0000 Subject: [PATCH 04/15] Delete electron config from here It just has our update URL in it which only we care about --- electron/config.json | 72 -------------------------------------------- 1 file changed, 72 deletions(-) delete mode 100644 electron/config.json diff --git a/electron/config.json b/electron/config.json deleted file mode 100644 index 7bf4c4d8..00000000 --- a/electron/config.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "update_url": "https://riot.im/download/desktop/", - "default_hs_url": "https://matrix.org", - "default_is_url": "https://vector.im", - "brand": "Riot", - "integrations_ui_url": "https://scalar.vector.im/", - "integrations_rest_url": "https://scalar.vector.im/api", - "enableLabs": true, - "roomDirectory": { - "servers": [ - "matrix.org" - ], - "serverConfig": { - "matrix.org": { - "networks": [ - "_matrix", - "gitter", - "irc:freenode", - "irc:mozilla", - "irc:snoonet", - "irc:oftc" - ] - } - }, - "networks": { - "gitter": { - "protocol": "gitter", - "portalRoomPattern": "#gitter_.*:matrix.org", - "name": "Gitter", - "icon": "https://gitter.im/favicon.ico", - "example": "org/community", - "nativePattern": "[^\\s]+/[^\\s]+$" - }, - "irc:freenode": { - "protocol": "irc", - "domain": "chat.freenode.net", - "portalRoomPattern": "#freenode_.*:matrix.org", - "name": "Freenode", - "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", - "example": "#channel", - "nativePattern": "^#[^\\s]+$" - }, - "irc:mozilla": { - "protocol": "irc", - "domain": "chat.freenode.net", - "portalRoomPattern": "#mozilla_.*:matrix.org", - "name": "Mozilla", - "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", - "example": "#channel", - "nativePattern": "^#[^\\s]+$" - }, - "irc:snoonet": { - "protocol": "irc", - "domain": "ipv6-irc.snoonet.org", - "portalRoomPattern": "#_snoonet_.*:matrix.org", - "name": "Snoonet", - "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", - "example": "#channel", - "nativePattern": "^#[^\\s]+$" - }, - "irc:oftc": { - "protocol": "irc", - "domain": "irc.oftc.net", - "portalRoomPattern": "#_oftc_.*:matrix.org", - "name": "OFTC", - "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", - "example": "#channel", - "nativePattern": "^#[^\\s]+$" - } - } - } -} From c7635a362f0a096d56007343e01cb26b0e421f59 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 25 Nov 2016 20:08:45 +0000 Subject: [PATCH 05/15] Don't copy config, check update url --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fde6fbaa..3cb36125 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress", - "build:electron": "npm run clean && npm run build && cpx electron/config.json webapp/ && build -lwm", + "build:electron": "rimraf electron/dist && npm run clean && npm run build && build -wm --ia32 --x64 && scripts/check-electron.sh", "build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle", "build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev", "dist": "scripts/package.sh", From a1347e7bf1da37b00972e6c25e62b42803399d69 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 25 Nov 2016 20:09:21 +0000 Subject: [PATCH 06/15] Correct vector to webapp & platform update URLs --- electron/src/electron-main.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index 18758eee..fe083930 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -30,7 +30,7 @@ const VectorMenu = require('./vectormenu'); let vectorConfig = {}; try { - vectorConfig = require('../../vector/config.json'); + vectorConfig = require('../../webapp/config.json'); } catch (e) { // it would be nice to check the error code here and bail if the config // is unparseable, but we get MODULE_NOT_FOUND in the case of a missing @@ -112,9 +112,11 @@ function startAutoUpdate(update_url) { // 204 No Content. On windows it takes a base path and looks for // files under that path. if (process.platform == 'darwin') { - electron.autoUpdater.setFeedURL(update_url); + // macos only has 64 bit + electron.autoUpdater.setFeedURL(update_url + 'macos/'); } else if (process.platform == 'win32') { - electron.autoUpdater.setFeedURL(update_url + 'win32/'); + // We split by 32/64 bit too: the builds are different and entirely separate + electron.autoUpdater.setFeedURL(update_url + 'win32/' + process.arch + '/'); } else { // Squirrel / electron only supports auto-update on these two platforms. // I'm not even going to try to guess which feed style they'd use if they From e3290c1117a47dbf7c6cf160c7c75420b9c46147 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 1 Dec 2016 11:35:26 +0000 Subject: [PATCH 07/15] Switch to new auto-update & add linux build * Remove squirrel hooks (the installing & uninstalling is now done by the, er, installer) * Switch to electron-auto-update * Shorten initial update delay because we no longer need to wait for squirrel to release a lock file * Change update URLs because windows is now one installer for both 32 & 64 bit. * Update electron-builder to 10 where NSIS is now the default target for Windows. * Add linux to the target list, building a deb. * Remove sqirrel-specific installation spinner * Remove redundant !**/* from files --- electron/build/install-spinner.gif | Bin 23967 -> 0 bytes electron/src/electron-main.js | 41 ++++++++++------------------- electron/src/squirrelhooks.js | 30 --------------------- package.json | 12 +++++---- 4 files changed, 21 insertions(+), 62 deletions(-) delete mode 100644 electron/build/install-spinner.gif delete mode 100644 electron/src/squirrelhooks.js diff --git a/electron/build/install-spinner.gif b/electron/build/install-spinner.gif deleted file mode 100644 index 4a89337be40cf202fe232bca49c1c0c84b278463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23967 zcmd?Q^bYjBsrB|va@cXu7!6C}911`R<12@o6-PQH8Z z_uc1y?%DSbIJbZ4?$uSb*6OaVu3k?)atg8nf@Um07U10rV5zP>bfRMC>f}1@-Bo<_ zp{053OxVR zq?ew$n>=lnZ=#0)$0R??@U%=Qf{-}#Yg3h_e>ty z+y43e`z9wnf2r%#4R%u+@Vqg3Tv2%*`2KxLTGnFw@AI?3vCC4_#3?mXR-4 zM}K}@hFHem`n<-L1e>-nG;byFRi?N>B2v~b(nkYN_lTQzVIZgS#o zAL^UZ;2QhI)8}VS=JVmfbw={~{Fl0oq57r4yMexHrjJ@Qv(V)bO^Q$vI@1H>? z#o<*~x&HNOE!USf-_p`say!#K^CG6IPHunJuMM3zJH9;J2N}mCn}m0k^qnUst+akj zn}Ciw#JY5kLzJETk)x@6h8=*6rze`P#>a!Q7vj z8MkGy+uV#V?*l(2lvX7)w)&?(Jw9C*<*vr2)c5sW?thCIs`#0o7xp&rIxFpQB>!7R z)_u{tfU%O^u$+Y1hF|Fp?@O{Chx4}Un}4RIJbccp-Wsf#`Bd+bb_@V^EEd9 zqO5d$X7M^VBkFV2jx+45iE-oR@NGesmrBsfe{57QXsR+=no<(#GF)sNh(G`U@V7}% zMI9<_=3(}CFD&K*GqZ58@_?FK+1NRYQ2*@tL=CmG6rtATRpC&9Nm<$2$@{rkY5J*Z zS@=0v2wGB$i9&^agnXP}PF5afP#-5pXLlhV5o$9_7jrA2zsLVHvr|L=L&U>Dgj(XC z3($Z1lyY&ig7UKQv089)3qbh=**JLx1-N)vpj;fBeC!;8?3_HT9GpTNfhA08 zVdlf?>`wD93({8Z7H)Ph4?7oU=syjHyHN&R!z_@NBCcFvYA-tLV5p`)TAq~PrCVdiXM zr64Ur{nrYcot>o+pQHp2m$U?rBsZrtC#MXbAcugo1iyf!ge0y#J%_KkncJ``fd$m7ATHm8Gnkixc!erY&UmKaYj$f3){sx|aX*Sh)X3 zUG~3&VgKjh{%;TaUrm2K=%2%XyYAnUe>=aG^Iwm5`|H}kmp{LspB^9X?{06de_dT( z{QPl#_Wkta_~_f=*Mt4N-JR_(Tbmo}YpW~EON$HhbF(wkQ+R|8>g;H5Yi((6f;TqQ*VWckS5;P&mz9*MX^>EZ6?3UhIGa&)k_v$e6dva~QaGks@bY-DJlucxb{ zt)=-^LtRZ(MOjHvL0(Q)Mp{ZzLR?H#MEH%6pa4G~FAp~tCkHzlD+@CdBLn?wI$9cP zDkvodIoT^x5@I4k0(?AN9BeF140JS96bLdB7=(!MH$YH5fWQcV7XZuOSONIwGYWvb z0Dhy8$-|2VLLqoeMq}{ep-5~R#XR|@lHpilZu_mVrqa}BAi=<*HRJvPF7OOOCO{TlszOTY9CJR)0+RryT z-M?>7_uN^i6gfv<@LBIj=mtZ7{0*?fsY5%kY|$%9S4 z3JEw~tW{&*|B@1TaWGk^_UYsAr<;K$cMInbpG31L_;wJeglLHHo~~*)W|yK$BBr>C^w^u z6|SL2px{J8If#?V;zmh;sF+ejh}<4yph(K1P*dowh0sbcvy5A&3aXy3{Vb?S` z#-+$efT38}AnCX~rWvuy*)EQXvD|(INL%4QlQmA=!-~jMMV}N?O_{sve2j zeP-*nnb3;6aav!_1RbVqQ`xs`3|lFthr6($CgioOyHhoXZS*^qpk{IB7A24JZI$eqt>Gc zRriDc7{GJ6_lv*VqjDP^4^2PXRoD|4PVILP|2jb$2ENau8l&PzW3?yG^>>>%Rph+1 z<4ild3c?&h{}!iJ)*d^}Uu#o6W5#CCXy*(d=kbH!_WjDT%lkGede7FkU8UM{GHU0z z)O#_#ZCTIORNiDJv8+=n2VcXUG$VcGQ1Er{ZYwgVONtd_# zV(f(&2%k#*Z!~bT1AhK;8W3u;n8Wz9h&r`Ja(*3+>(@xn(i1q(-Ta;8`Gyq-u?o4n zu-iHe^C%fhm0n#V^%RD1gM$5G5OwxXYi5zM;~prHIf*~R;uG>~d(FH(%1~*E5Z1MR zBtiiy6rp1YWpdUqd`GGyIR60R1k6pOcJIzvkDt+BHca?AH~nRsXb8Ge@5|9zjI;iY zotnutTK|2qbr3|R@_Z)xO1ZPsTNdrm8wp?#uZYjpAiP6tE01CnSjA>IZYYb%d~ zS5kzdY%@64W~~S0QWePDKX5D#QVuAOWKhL0Q{ELU9#9<}eqOqlEY1PTiO@miY;(Q|V@)%f>1}LKYky1kSUkNg{E9(^rgpr1V&7+%` z7Z&WkeNX2n8*6<12iH0~i?U6%f6_PoIE%_qlDYb()Pof@y_$9dcP6uuKG;FSH_Un< zBSqlD$Y)eF2p~M7lOWo!%n;I$kMC zh-E#2UR{hd#;|UTUs#NOA{t>W0uEa&V^peE?MveX2VqxHy{b~3rwOq}wUhPqw;TJ@ zp>>1Lp^=iqk4fyj->#KQBt%02WLAmUWL8tLwHWQ-*7Nj>-9ELZjFKR)bfx zk@58v?K}RJHix8z)WS<03E-8Vu-JlWR(lk_a#lOWT+LZrLQ!sm5S`-MmaLCn6*0Ij zj!C&}!XB$FQp}QG#zWg4jLR)YRKa8gN;~IV%y<)4XW=8Tvh^i?V@ZOGa7l?=#Ldj^ zlj6|e-|tyrSs6|2S>cXkb!&I1_lU15I65n0H_=c``=~!=Y*#TeO7%w!ouAc&-~jel z`+ZD0%GpAno(!`jv+QGbT|Fq}pV(P|6in?R;& z58dEgPuK(u)3qt~&AT;m)iQ^IGj5^Gg`s4}A%a5GEj|*3eKB7ZKU^2$6c1I@#sFki zmvf2|v8C7XA= zuP*Ix7ejGQcKy`8{OH9EVsuUxdD*ldd%^4)L{@Q&C4Ov!j81)&`-3C+p6^>`w&0V2 zGmh6gVW)?Tt}$=S6u-hPONmc$oDr&m+Yz64{qephq5 zG0OY&dCqF>eU~uMqLQHo3=HOSs`asf9LshO7{{lU-x@SV>zPdQ8NU z!*lI!BCCzE^s2FfFmVI}9LuC=-N&<%_zfdh&fhGYcPCY#_YTr|V>?B4hdpge&c^8V zQ!`;Lp7|pk->3Bh5sO%A*dM9nuZ=H?{;E&t3W}3e^B^TWy6~Z9X`J3!-He-r9D)nu z`#b$K{8P--gUJ^#u#z-qH(*DXa_=yZ9ryv^7s7Q1sf#!myhiV)?$5=E>Mh57U*X>v z49kqSN%EGkl`6vZ8Z3qx06H3+|(fh+|3wV#@Sl zDtuz9vSMmFW9rso8t!A@#Iel+v8@c)K;Zu~qXYu}=9mx=-~|l&zwd$?Kp2n!X#G3E z7r@IuDKm6H&Qi!D3dBOnVVYd=*LX?mQb@d;ty4(*+g1Yi9bY7ZQ zCJ8UW0E-qe$du*i|CKT$ebS5OVGIA8GAG_%rNx#r;y;!sE_XzfkC4h%$g*CJ+smSG zx1Msp9kMT_p!f**n=(5|xRR$#lhl@m1AQUPdNtJ5xa^0`e;?z~ABbN>; zcR}hSdPE9gYOm3)Gq>@;_#75@b_9yl`=~;07pZNC^M1NSH>LVxX&chZojodCZ-9iI z@3bG{cg8NwsoO}Q5PS8paL}G^(>vZ~PA9rT*G@;GIGo_TYn2e`a-5&ibIYhS$81Bt zJWH?l0f{V#1%n^aLT9TOs{Rh}Yd2cXY7t+lGCDm+H%w!V$eTFuXxT;ca(6IFgi!)N zM*OyUpJ(XADo=aNj&~?lC!i!(>)H3PFol6*4>3_l{~I*v*SI8Z!v4*TmT3T;Ac1c5 z2|vMyU}Y-m41{FY^$a7Oqj4S{`|yx>op64FV3wRp0zaMMs%0}eUN^c7DFC-kK7*`# ze2#hs-QkB~oJxWsU8{21R95f;FvC^C;0T|~&$C#EWE+x~m81INNvovi^y{@pqO=85 znE@QBMmC~ApGwJBwT<2fF$QG~-M$L^#iPfKB(cuQZ^A&=-Pw=N6uMy9%<)v{PHGhVIcAeI?9YaQs z>M#>QajOBEt1eL+yxH)b@aa{wcXqGS6pOC|OCbw6nf72HijekDY5NU(znqwl&1^*a z6t14qU8G%*kQ{HVtoqql2C}TT@fV!n5yRtgoJq&VX|t4g$hUu;PUf4aA*eK>WVhgFD)y8qTVMwnbbKVjUxQVfku)cLSUn zl3%&!tQnxcw*1e1?J;Nx7DETA)0L|G!7nMaZKC26$Z#p*PuOex_y4`0$8JOh1i z3dRn#6^~k<^CIrfgt)AHny0Gvcoa{qu?B=u?3>3hYau>n9Ct2%x$rUxF8VQ3nuFC< z4}G6CfEDVKhFMkZzbH_6A};^gIlo@Y&40UdsVG$#AsF^!vgp?~fmndYoS9G0eoaNm z(2Ub@)IrVwIdaM<%UDPvV-%aP(9YD!ML%}_VU|hr%n!mI| zKOga#Jq2AXEoS0C?pyb_WY1vO{{|7fKo zd!n7aZWSlnM>mL7HR$vSqsu}L(3bCmv`f{ylU5t1O60#zPj4?n795tZGcB$yZKGnD z^e??~%pOC~zAC(adR^OUtEngL`N2Nw^KcL_Od_EvddjhAz}}!kZ-QBy#ZH3IdbiH? zhqmuUl67mvoTQR->-(ywZNi}rb$dDu1-a>2^twp3aa>NK$~sNtr6@SDj$2^%8AEL+ zla}HSOg-8AISSB1#L`>TrY-?VJ_`JJ#uwPFd%fd{1zr|wh_xrFa(s-Y#LBYx2^#XB zdpQa*9w}l10OXQ^z}U|JSXZ z3_k|lcOV+4AK%uudiDt1D2zFR`F#w2fv>9+!WVeio{M*oGSe}1a+Q7!%XZpptC0ql z>naKNDf5L4NA)%N0EPGS2wJLaB%53^QPn=5tbSIUio(q>Jjg=rsuui{YU4|`vJ>vp z1f^>t3Q$)}fj-!vG%N+gFHh|MAbR2bO;C^at7k9H#}uoVhuixTsSSH#`WOm9f-~0C z=4)2pX%(<8a#8gxtV`eQ`S%YNI-OFYh;>H)j8^{N!j>7zW+g214ZhK*5@XbhBmGWX z$rQ%C0uCGAEGNLK#yBx?7jM!p`KWqQlXf}rx><+uoZ8mUb01sHR&KQ2an>DAX592j z8^1A>%Q<{^I_*|A0klbhh4?}g2a8GwZ$nG->iMV*I`zHUbwfGl<0cws{hr*alpHLD zeh^N(w7JzBDo%-fbterK<&LMTJM%f{T-V%e?h`@Zw)6Ij4IQiWsy{b1cYoy>Y2sB9 zuEHBB+qqRWqxtzpan531f7J7Zm*c086V>ocZYj?B_sdh%|rYceMgS# zJSG<*R-hYeD*YmQA}YvWa!aMdX#49jR4LKuRI=r(k5D3W;Cqv!G`YhW;s~#Wd`xqD zqTlZBT7q!BA0kzVxlNy!P)U$j4&EOzHYo%_AgwN28y z`Nw9Endb*O-R)?4#ZRKrT{J`rHj_t+lcu5Wv%INrwp}GZ<7e&D;)9~$^xoFDWp|tH z6rNwtO&pVyWYFr4#kG$H;~C*4x+Jpqw0&&1>6%qY;`VVDSwlGJVUoJRNiBEFnjSJ>}@qU>0Uvk&&U}ok%XaAGl`_uoYDpH7n z_i}6*onbaoxYTPoP0!b+zU>xhHvSlQ9`PNVU~DWlcThac+zu(|2+4v3_$sc#roqw! za?Je73bYc2w&2N0o}@avY7u-#aEr?$7NJH*;F(Ft2GsRD#?v=|e=ydhq>%UjN$3%U z!=nxkjpy@Nqw|l7^yn=GAL$ARXQ{92y0&^#vd$xdQOc92V{n>FA?^T zLoFgsi5H#FIpmP`mrPHRCM5fQIfYOKX4|lj)&#_^g3TA^txgO&2yVxsed4$j zx>iY9k+hzE?y^A)ch)GKUhp7AMsfaVU2pCq9ThG`fmIK%_Xk4(PvccaZuJ@CL}UVt}shX#RTKF$oGmh$G}rm?cYs=}k*!w@^{AUQML_XYff6LKCP0q}+`{!&_W z!X4*ZZGfG;;(>s3#fo7SA03#(@Ou_Qow!$sjhAmakQ-Zgf6YT-%*ruSPa`@0cNW6> z9J7|K?ZZ9Q9W8eDs&(Fxy#jsI?=>JD+#wS}$jt$XFJl)ca89ZW;ERfD7XYKmsaU4e0i@|TB@xvH`1XtMOJ%U7S^~9@EHMuk7UFjLEgWv88i8KX& zCXS82f13!Q8w6xBEvABl52ZO+G&#%KH&RaS zbrMOo>}4VgN&t61P%Jq7p~{~8*pYQNTNWpIHOlU7Fd|t8XK9pY8^@n z@tCJZux5F+rhlhbrjLp`jb7b45+jM?9t1yD-t)b$H%Km%bPuJ@7k_Y0qh^>8cQsXa zJucxT+EiygdtD)2DVrT1#yoTqv+wPNa_1F+P#6+)aQab#u;@2OIKUMkCMVn_{6J%U7ak=PcFWlSg(DPX_a*3D=0 z3;6VqCbWW}oRhB#h?ky7_v6bqyH3voIS-}bbeR^5l7fwEGMcl>0w77P8B(7j@?+v4WTTS&rfB6ujcIv6Ck9Q7+Rz;J?Z=Xh)6Osgc}$fVu+w7LZFjT7 zC4_x5(cP_9Si<{jWfIK;l~50%Mv$z8ApHSH-SwDJPG-*KLoj)}o9uVOa&{307Bnn;4xz- zqZSn_R3oltvJ$GMB)8H|RMTpQop)q)jb-%6ry>@0C(k!iGPg9?N4mUeEgXz#zJz$a zX=p&e%qb(vdT8qsl{v4O5lbJ;SsdqzwKJleH@~cjQAW7hH zMc)tCc3X#7cj`WAVy;sA(52|avCxk{_PS^{D0bHU;fw{w)}Q8ZI%)lC4=fvB);m6J z_yW+$lU{XgF!U({;5adT>H=^E=3dnOuI<|Ra`mRh<@UC3J~?X$uVU$DCUX?#ifLdiCd)E-R(veW#%Ko-KjirXkR_ z*)e#wRAhxl|D|Vu86Vs@+POQPW%0cec7=6nI7EaG9_Vj(Ch`AN`{uFP;N3HpsOhl9 z89HT2N2a|mDTyM-+{g=dr@6AYs3|yVvmwW$&!v)mc6}rXEff7^7a={iOxq!Exu)we zB*V$5qbL^0T3n~|_<3iPl-m?!|1>VHE>~Mkmq?oiFg|3QJ!!+03lqu zB;VJhwj>ue_c=|qG;i_Nk)p&$^m>kUTre}Ua!B|IW7qX0Bu+qr#rsAT#+sf4Y0p}n z^4h9+=v#%cMdlEyt13QOWw3IDO&VbPBfr*AJW~W~NS^wwBq~>y@Vvqo~mqu=5p(jo-EbER18^d2BycW+g$jo$;Q$?9T zf}01g9`9aB9QRc#rCZYr-Qd)#1>xk+KWJKz1|Y&kX)M2|(%9nyUd=;LCl(MjhLKdr z&z~m1oS^*vk~ejZ6{fSoBG^qV{JEsfZ}t!?w`?CtJs1}eoLZJdlR<3Xml}EqiRU1X z*E8MspK*&Q6zi8k#h^AQe;Z&~^b&HQH7)Zkl{z&Nw|)i56}hyRxt3{3EE!P~u8S!Y z1mDniLRj--U4Ye*{F<0az5Kh<6gNI8qtm?RJOE)crq=+hrUU~)NnN88Ow+;ZsmUOE zVM@-}4w@@4_8f|LO~~;OB6iYh#WZ1DKOh86;d~NM@MVJ>>JUE%;f14m^&^7Ru`J<> z9pta#E+C@V;I>`R(mALN8;pJdQST=F|M`-agtdQ;a57(&dXLuvX7R%})tG;y#Q!_2 zivC|HF%mm(@<`)fl$c+;YhtnSUnsE_gMgRwluFR}Uz9kcv0yh(vF$a6q|9HGSV#*< zVNtd%Os?d$OINMEsH#1ZTD#dHL!iz{-(F{&3D~Iq63d;=41*z}>4+2O6>@mv;a!Jk zG+N|Zi}PgtCrZrezK6TNm5veAh0A8{oMPUSIVJoLN^HSB!IL(QC&Wy_(yl5NU%qi; zuL|Wuqg3tfyxdQfD00<8K~j~UApNQ#o(50T9P=2m{I4;3oL|{U^$gm|DftV7P=X>R3~nKN7DsrNe}J$4)2#%r#1d2fA0J z7RCs`B&>o8U<1(nR>cu$Gi>*x87k!W!=0S~k}fu3{nQa>WDJGuCSg?v34Cpca&%}Q zZy5yrV9gN{-h5Y8^)RbuNQlbCaZVyk%kD5;&$^lpodaJooyj&WS=I9hI*x^bhz1d4zO%^{gE9x+h^lBLy}v z2}||e&J+qVU4YdW%4n4on$kK~x06z%L!e~Qvv^5xp_tQ4k+RAMGd(?juSv+Y-2GRM?E`~4* z@eqg_iX;$w&jsGf21;rN$ud3XQQ4>&`JjZT&j<~p4c4NZeOE()&I2%p2=^gW;kRkX z)FItmG*o`YoTUgf0$}RN1iK5ak4HttL}D<#7&}B03b%%t8P?qb1eChDr4sp{hsO&t zBq&fZj_X%i6g5R(?CNGvoR}%12SHA2TH4J6+x~Yi=XX0FDiNJEbXn9>Nw^m5e5kAd zZ4z6ElgVF{ybt0z=xYQJBq6$uDpD$u#G7h}tqAFI2@Rmbh%XtnU_=b~DBIIn>tX_g zYAM;wfSb|Ue1Xheb_RJ8ft*#5QAK4TYBo|Y?#aq}L)zN|} zaPG>bBTcC>oY;!HU^lS|2_ghg0VeM6_r%eSlaMec)F*VB#gXc%EdYCYe;Q z^qUrRoVrMWI)GyFFc8^-N)G3P@L6 z6Bptv0m6dNX?Gfe!rXZP80o}1W1Vxdm(?TaG^JExmQ_J$inH{);<$8&a9qAJskmnV zbiF?qqzkVhCxw|Iut8ApAH%Rs+^ocKi%3aKf+^1-lx8_{*nAAoICQPyxNns~%tZrA zd2{`{_yDOuhFN;6{_?z}pvhXGa$tne5(R;H6jYHjTtp!fX(6<;C~ZLLEeN>OUmnc; zo0iVrGG})~hJZvNKGZ-)wGVcDRYs2ui5F2AfB(UUEwkC~aKOhyV+- z+K0al5<y*hR>adPp*OaT>rR@ZmZ>94O4H*b+6|(}jxEzzgM`}qhJ|29goN#PMv4uS{eOUq=qKzQK zfRqF+pJF~#1_Y~WcO}A?2?rqJ@|oo1ZXP#rtcOVu0pT=^3EZlZL6o)!rcoqrT;`U_ zpvw?C;ALggzw2I`Zt!YyK+@Ktj@BJpx269I*0@D9wSmooQPxs_HtT`Es6g_&$l8Q0Dc* z#fGx)GswX;3QEvMmXyBr z3IYVljf*4S<>c*(&{wS*0&X6==hWGHhe*bCuA=vY+}6RR`CqCP6Xsym(hlA9mK09b z)+!Ec*n{ELNW?zo<)(T8su2;XR4IeM6u8kdC_R3RzLoAknYY?{Hr`@D_iQ>&B!4d3dAC1d zeE;zC-YV?nc7db;DWP42w}wmBK0ZIX*b9GOOV6J($TVF%A=P02*4jnv>KxDU*VFRv zDBjF>?ZAQofR3-c%$pf7=JI{?#Cg^9!-}88K+SERC{Rzo`~s`+u5|nNeWzL!+k8N2 z@>d1^hlO`Ym_ykEImkNv&2OBpP%nnoWR6Uy(KK?aUT+dw%k^x$AH1FK3dn%zK33UO zmrSI}_oh$ngyW(|UsxIJcsOr%byvFw-bY`H>r3nh7u>#Y6!{uVDY!tlCgL^ z`;fVW_r^xl_Xw}1*cEThPjb~q_Rgz?-uq$H?*KigV~)bAbn-(d$SHv8fCl z!4AKY3r(zay3-A~t_VGX1O7pYqax*ay_s!YlEIO;^nqhXs-m1!@O@-wfzWH+(4-gd z(EG|@g)t%rnGpXY`lDaw?8NVhh`pZGqv-Ah;e$xAdck>m;qF<%o<6)NFz`Pp@o~&< zO0?Ks*d@J(Yg=Hxd=$_!ifJsO{N7LNK1xTx`;mw^;+Hb2cu+8r9BL3B!6+7vjQ?;} zsP1CKy;XdNZOlSPtSeD;Z58Db2(fZOC(1P9c~^1iI69m-&~pT9PeO%#h0h5TzRnPh z&k$EBA6M-YF4hrjAOR6XurXP~J8ut5y^H+aAJ#VJhkEb#qZoMr5-`LNNr#*etb_FD zvzpO`AnO?AjH~CIfQ1JVVzv6K`Oi_|^gazlI93&>8-K76PIXYA;Bmg!?ce@9+E+bWI1BTD}X3<)S92qCp>7+jf9L= zNm>Fj%d&Leb61ilj!0X_GRG;hd?+wz0(PO$Gmq-zC83sp-M{EYI8}SAE%PC!P&KC) ze27To8jGJ3%;n7{@J+HWGe-);X7E5#tA^5#^F~_{Fa*AJTrUIEB9^w6$Dc8#HjgK^ z>ft$3HQ(?W*fS-c&hs!--xdf(z^<|9JD3@dgSF$>_REkf%{8 z2{rQc#7`KMy10r)`FV4M(z08ds>!H)PA}u*Y8iWM8agIiEZ3-k!wO5Q2xA~xs4XKqds;R(BWRiZlOI0}4?wqJ>Zrg2*3l9Jx^*?}8@6hmREU{-9DV*qfc$1p|2dzqDGFQ^Xgv$!2`dtQ3&@Zoh zm^ZP`@r~l2e8OGZdV6|bqFQ%rC_ka~KEH@JEikJ@fT0dD#Hq`;=GmBMn;(BXeZ1KG zIE&UB8KzXi(?NyE=5~o|j`9(Pz}3@U^I=u+Z0OTQZN=6m) z2UqwWRY(grY69Y+_fqVRoBI#*edj7=A!h0wCf*$>jO+fwJh37~Owl#`x(H-pHePl{ zcml0tb_9PinnXEkZ+y;L%BIUX8`!@X9aA0|>YSpZAFoeFmx7HhI(ALuP5z0n&9I?9 z0kG#9p^9uxProW(@h>%UtqnaJGgI!OKbwZWQr#6UH;SE3i~D@~-0`$F(=7pw4m&Yj13*f4w|WW-?~ILr^LFXdI?@*nO%RgOcyY( zYrLqhLde!XYj)njRo{w1zT~PxXzVnXKh=akJ)v+uVb!;4!3i3Nj$6W4g6rqB>z7>W zS5;I9_k*TewmR}r=eWt&mFt%+<`+Vr7xZ%1y`7eqY*s9T7gJc~a}^gX`qnF*)~qC! zQvBCP6*olVXY=AWtS*<3L^ddD*L{rFQk{s5j5q69R|r*BdRRBTf>%O&7yHRJhXaV* zMaDLTzqpTWde5&iznqP2sN`-r5k>V4kC1JXoNq;ItQ-0xAIC2**Ao|=54^kBhLP_? z7jIC+0dHB?3j#=6&p)xv?c|?Rz3gu8Dj|VHw_{wlcE1CKtfM1s{aA?gYc4`1t2dW^ z?{ovdR5_y0d4{DDQ*>yB5X{Mnbye+6dJ890aXId;vi4Z+BF!Co%j>4$pw^KuVpa@> zuv^EHq_iWkVQ+tdvju_Ycs=O5?ATXSZBC-uD^%G^0lu>2B+X4yf3OboyY|(=3Zl#a zkLorJU=3AH7QQpFxo4kVF^MFqJ{$Jg7dSBoP~oGqf2F$Mqj#=5WBKCehW|< z)y&PeU-cRvU*eF{dEpE(_1cpL_GVO?>W8_4+*u8 zK%*icsi~|4kYj=$ZjCL83a@uz!v?a+#{R}KDaaEZH<(Fw)CU?ZPNZ0!erplMhEPan z#-qQ5QQ^=VjJcccgYkDcbV`G_Z99G?XcTQGSVaa|Mm+xu3;fIJf=+A>tk z$23Y|RNv*^VMoqz)z#y+tAqX){D-6{8fgHbNfb34T&QqRp#KfRz&XTyjwQG)|5yzmR-hB*L!sJzP{%C~0W z6^-K%7wj;0_Sf)fsf)|E2tbq_{J+JTU2W=t zT_h==q$S=#xnCZ^0}vf?CW@qAs(V;^NhrcE%;Ckz*=*0ORG55?G_OsUy#Cg1!tY&R z$;%DwznM5e`afS$s6R#jt>1)FXmM!nepoqpA*KL4UKOMG?cNyR82VlOK7YYg1Yqw& zFKG1UiX!7j3I0@7%I3j3AFkPWeRk}Mm|BNgLEJW zg^{VL$Ca7*|9$n7|4@$pj|HOt@4`w6CAC4SN92P-BK8{F=Ytgb;D4<$TZEvV@EHk? zmK)$HdH;Kr**84&FBeHA>y;#ai$_bPS_Xjd51AsqH8?*rhRJFC``kjMI+_V%29Ldl z7I(dUydP%&NluX~?f+61bvhb^Bv{V3 zB3)jRp55O2ELfT5h>4MQPu!ddzW45ee*DSICb8zSeYN>#>sR{iJLe;K*yo@wE1S7s z$VmHuB03)=_x+1BL$UoymE~S|Syu;DWWI>rTqM+u?~8a?TBkt_sHuwDZm0OZ#D26@ zfX0qw!soyiwY#&_>JN(aeqw|O_gs?n9|D>bg^hHwRF#SFci|d389_5we_Sg zOITd+5yhnBwv8C8hVB);ng$TcEi)W}j+X^aO;PLMXNkLsXEm|mXV6-&s!-m-D>&*< zJ4F`Fs3_D`VlTef}+ zd&q?tiiZP7{|qYx9)*2X8`O`vXqXp#{Vh3EX_JuDROuc`aqrVn_tV=kFRz&9T;C#@ z#R=<*77}F+@9czL9?!aO-1tLf?pd?DMvJrhqTDSi(sEq`cA|9oWjs>YhaM?G@)&h< ze9K#wTx@q`o~hW+*Pf}5D?DB);~Y+W?Pfb3eCzxwUk>NV5)HAKqzVl^XU@!D$S=E$ zp3q%3+4`I`!8^1K_xrI!{08exBqo}jY&Zpm8{yuvzDiQG7I}xs4$i3pqY|PptK1&T zVONiz-}O#eo!%z8dNyv=WG8iSs9x0E zX6DXP$PpiJNApG`n8J`tqw)J2jr5EH%3K!M zbL zuCK!-c*d|7JEVgho7jwLCox{(m8t{{aqg-c8u+heSyp|gln|Q2+r0WT0{V%IYO6fE zCOOg#X^swLOfoCcBce0eR}6f}dIx97>?fg3bnMD9`+O{u0a1@+;XKf_e8775HHww1 z1)XZ~E!GwMD}kM|5`rEh5vW}ziFr?k<5NnIBE>gcMzUB=GlZ!|EpdrbGbH-Lw^)|l zVI=O3X5R%$K?Z+72!1CDm^GK9<>C?Xm|==sQR^vsVVZP*|Fa#l%(PXr#QSqa_l88k zDafKQWW?V_D4-FAG(EB*c@EzZ&TC(?cNgZlOx4Kj0Mv9np1oJPJ|ln2T`-eP_FfHN zyn63Xg()s>>NPGeD{=}1ibv7-^P@oi`&072N80~jeL@G6g6=PHXpj5jUxnP;KJ7VX z{VURz%8<_$xhf(Bqer|&`cKxUQYdjNudw)E)@M#g>+-?qzgVA4_y$bO#3ui+K8xr? z`AZec$B&Tb|FS+Y$w$T~k}6DxFh2u4Yu2m$z3h!AZ<%-+%@5kAfX5^2JsNH0_LChh zY7J~(QC}a|vTP3tEI%4g-LjSrxUx@6D?bE5{lvNc&H8k&0PJyER-`c3dacP6{+spb zw8m|{3wJxZRv{x{Q4MRZS+E^ z_Q&%F2^d=Rl`U!Y?&rkBB)gc@wAT-*kWY>NQYOJK03?RpAP}MLZZNo^85NTPRyiHG zb2+dU7Wbv}vt6e6eStZ?S0^El0>*7o#Js}sUbF$mkdaZ`nvA)}co74Q4#vpgcI>;q?nW=oPruX7ryVTD2)y#KK1O z!+r2kiO@jEU1B59)fvpRXiHlA$%&u6VuOfO_hOA~PO>XL2MOWhAGB)P}u}j1qo<218YP*gN;5F-Z;#noCyz^KhjvmCKBt zDqx;%Pv|ikDtzHw$iRh*Kpu-O9^Xp?@%5VWE(0j*9zGyIlpx>EO8Aum=a;|DUxIN@2k2bWR;@M5<4U;kayQ1Bp8Zhb6g3r>Fe!fUOz8Gc zLjl`iKKnv~a0druYi6yro0wbj3L+;GGOI^O_OMdjQ}0*1-asJ)$$&ifQq@ZF{S zT92x1&~F9tuQhLq@Qv@Z^$shQIyU@$%mEoOiIueS;y2t`cvZ&d#$-=Y$93D^5FNYJ%8H7HQ`jCXUj`z+8F1DuUB}@3wg1y#{_qWx=rUeYp^`N zzh*r{?Vk_#ulahUCbYIl_Wd51WjrNtBgIVW5Nw~l}H2svF? zg0;1GGeSRO)Y_<@9R%t!avE*0b8bH)mFM@lOqTP1vU{pkXsY8nc@6N{=xKnjE6*GP zprN|^ld*o~BsNk|WVu4i*RikgtM|=6UyvIQJLXnW9di^JqOo>&=MHzd-KJeo7i;ZT zYPx5xU;#l#xDMbXmbcCBwUn-tvErvuBFcr6rf%}(_p~sqeQLos9y_UYNPAaGFHayQTgsT}i zkTuO~aD-K^4Gm!eU}5AU^Js>!Mz_`iMN(OGkatM-v)RjIuSm+TJ;A&5O;Xti{1sq|a zD<8tW8)%7SpaTYIL5{S*03FCc;=YSLGyH!T?SK6y{~vp}_E(oo`?oInZ`MSGJ)A>_ zi)8B97`K8QCLg5y4{L%}qyD%a@n;dt{==G21Sg!f_5a11bOzua-P-?b#}u49e4vjX z!7)2!e+wh@0_xHF;WPPo&wKO5b(Mb$BhkE4Z7ZOsmCoXz1@yOqL7Sdw&nSy5-nYwJ4( z;{Wf$i2n{Xxt256yzblN?cggV1Hjzoy~je^yWIcUj;#!5a_1~#X*yK>oC4pUeV^Xj zQD~#FdehzYYx&N@vzi(phKn-u{Z<#S!7pM1$|;QmZOMw$q=lo}xb! zz-spYxa+1XEEV3lO_XC_<3tI!@sv<&c#T?H^CVA zPsTMs@bsJjB#!^&9{!#l1QSbDan>skDkI>WMFlLa&`$wmQ106LYAjLG7Duotcztgg zPPsq~?NW;AlwK5-I>@eQ+!qk0|uQRd@G zX_;~B5`NDf_~m91=oG3K)jHhab|XUuA^EMxqr0hZ5Eby3HTl%{6B%}c+jKfFYo--| zW>0RsK_$HS5z~Y0LR6J%LIA6P8f`XZC0gq*HLi-(5R5_O-+uYsVCOoWsdh zWkp@*w%niZ#=dWzc$=3c>DN5H8Tn=yje!%5{^M)nHEkf|&%hAxTxtYivHz@i){Lz} z2n&D3w_Cj*V`DzuH$p4xKV!vRn*or#aeGgFHtZL@YGXxc8!n$!jNmnK0OH ztmp|KpM|&|C2GR|0M`WKf20qk^84(KLT4HA%b34P`(!pPn|Wp%<3okk&%5XZH5c}$ zsyrRD9+~oEn_ymzoTlkLzof64lMZqn%9!-V&}0dI>kF|83D+t#U_28`X1A>>?j*;d zipBN_r(P?jKuX=Q?Kt4BhLI^oE0O5b>*o50mYMED_a09Lfv67qG&rRtcU_0amXrg` zWj81S6Os$6mtSSI8MZtrLHv4GVyX)_v~v=;&P7KMw;CC>?ELM0DrmHHUisgtfWJQu8Ts8O3; zG7~ZoRLtryY3zv;om5CcJ<$eEn7jJynH?-MGp)#?D zCiE=#pK2c50gN!4c*xen*f;NnP#i#>n~l%Ug>EubX+^Dk)qzsEZ9qUu)Oz^xW3jMM;d?rh%Mqs~L}~kN(u$F(Fw`okx*-)|kB=gr~lUDyI*QpiE=$3e{+} zRVFWNsn(d$lV7Rx!k^Rs(bPh(T^r>JXMHFV`fA0QiP8n3>&n2Vtgs!3#tujU z%`{Mxu)qRzwnO5zTZ@rUy_Ul=cbsMD5Piw7b}l;^MKuPiFJO~?aKiEdvFqa)a4k>) zoZu%B$|iWK+-(T^JD)mrcn5@xf=)b4bqhKK6ZkK}EzfDw`lwAfIdTS1$p<&Xc2?zA z=q+KFU^RoM>(YaBB14%gc-)=)bC!X9yNkYg;XC(z586doFTK%Dz1zRm{9eU+-A5If z?0^ZNpE7=V5TcVLL;Kl^pn9#cqMl)Uf1qZvvsN}r%*0;4Y5rCxgP)9qZNat7ukVz9 z2vwzO{MBM|`$#EA*T$WOp5y)bB445lx)UGpNp!tx8sD#a^4jroX3ngXkHVuC_szSW zE$@dd?*D#)@-V+b{5Yv}tu+inE<|Cb<6_zh)@s)n_=EvJ&a1j_CV3imSw(J2<2s|B z-VbB_GiLB}BxWzeD?}PKv-YgH@NG?TM&>5R`-`dK$3wTgHFl1BTv@e;+B7_5brzPp zrD3B&{_cwAEAv#Z74jYl{CKpxqa@GqtJ|H|#cl=vIV)dh1Q^ou+LqhWis|mul}}z3 ztPeNrdcgGL^!Lqm76ryJB@ATJjQGX7+3z8|v0h)l+p<=S^ihT2FyYBk2Gdf_Xey=s zo)50D-|cyLJcx{j+{C*&v5_H_!3zXIe=bs0Pu+Yr$j>jJ zwaz*vV2mRgGT8ryrEqjUZity!e{MMGdD8giJ@2M_7h_+xJ^t{EAoVLOOT=gR0A_T^8+Sioi5bHK_0p8Zz>uMH96q`Mp)fDt z!I02q=7YU*zjv(!Yy(<;_Hn-z+xC8dA_&%VX!b+L`xf|7(1u~`Q8@3=V_T~Td*%?M zCU7r5v<H!(WRJhYktNM*fxWw|`##`4NjZXf)8Tee z)G5e7Q_DM4CGKgd67MYT`lho2P5AspTa4~xjK?ffGg{f`hfHIM%_${hZU0un?-2gk zxM=4{y`E^8t{!60N>&%|R)O>dm=yIt2%ZfqY1g}?FCc)4SMru$TQZBzO^}FttR|G0 zqBJ%MHC^iHkUNcZNSAiLH2auw_9B+D%*K1DwNrV_U!Ei@5CyO&Hq+Rd5 zSAKh5erHvFZeGq+&PdlH;>|3ih7b|AW!QMk(mUc|<5F-o@#J1E``Gcr_#XW?v?${k z;#5_x@RocYe|#h@QtJYpyiK6`s5Ii)KTh-^R7KRmSzs2> z)+Uy)OwDOjxTaEY#Q;6LSzrM#5OU4i94P`{r{0dwyq*SKGt6&xF827KLH=Ph;8H+` zg(%zP2%i)Kg}v;1vWs016$Ey!`RAD52zg?fWjgIQT7+qEaUXM;U3!$UE8=&2nN;wz z>5h_{!N?_-0w9rimsoOj)cDp3;#x;3>?FrsJVGs@(7?u_b|3ioq=K+rL4zw=?f@f6 z1p(p-L3AbeFG$GDDi#Th4Bx1tC4X_8>oX6V@?i1D(ubAeJ=`TFiG+sYCc{!`QdLqX z69x}^Mr2W4LT8c`2xcW^Mi~$iiaWTpU|y=0$a2P9eJWTgm0os_M9Q107V`#C=#=Ru zN?&AFeyS=P+^#h1fdX91-X>H9o|K1-lFSaE7R;nfn(|}AoK~CCN>X)y18JC!)v)QA zWkY#iT*(5l&MUaaWf}T~nCef|pC?s*?5sw-uM?N0UH(!KqgG#TRDNJxvrA(Cs}v3v zk~e}$j9pbb3H7ew5C92qrk0-QB7!3|xEzr7jLQDzi`M8G7sVQ)Ayo8};I5jypwvCAD2(H%{;|MD$evWTo7<(>b+!#Vt_eQKnH?fW* zpM*I@3IYl}DUEv7%IXVMokjJhT-tP4I{U;H+z$Er7zZ?@6|L4_<<{Vy*pO`0+R0pX zMO~VX0&{a~W9DixJmq|moTBusaoHFD@H!8$u4zoD zWrxWRXWA`M3(E_9{y{1(k9Q|L)6%=F1ZV1zt*ZCSlpE~BBM0{YbkkvIK^G2yk3Q~i zqwbvoQliR?<=VQ>;cY%UZGl)gi%vwJ?CmR7`b!3k5fHXN1203lUwkbBY+~Vja162C zjA|dCUMRkb)nel)o1fz^B&O04AU%#D-Zs2Mnv}ry?n}l!&yC@oQN|-7NDw0VE_3GY z4%1nBs1`uGqg|KVR8}8_Zc!Q2b>p^BO?oLXDMysr8-Fh`4M=g@RE71keKoVp- z#3mW9d`z2~PX91qWnZO472kIbcwsDwB=kVVm-{~6dHF+@T1p3O)@#+bY|b^+W3$Wj zthXjUq)aRvaMbK!p)K%fGIJ!p??imagThjReku1+K=Bx$b2)!yY*l*v*I6$!*9?OvFYPVxvhT9h!Ux{3XN(-sABV76n~Xw= zBy2x25txT@R0C9cmtqdhPBPFb3_6KW@asU4(C;Rn-CDePMv6?CbtpaMYLt zRVN1@98iZQRJRB%HW}Ui;I=&%n7LDFUAx zI@l$x!|N#Gkczb7GzS_PEce`60^h`ovt71)FFND26ia>x-m8*9j=qR+Y4MLn4jUbK zal$MeB)CMq`uc`N0?dNkD4{_Q+^1SZgWqGQFW+I*=EJh^fTvQ!8N$5i2GP`dXb9F8 T>|@V>heO2~5&w^bLiPUwJMS@r diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index fe083930..044eca56 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -17,13 +17,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Squirrel on windows starts the app with various flags -// as hooks to tell us when we've been installed/uninstalled -// etc. -const check_squirrel_hooks = require('./squirrelhooks'); -if (check_squirrel_hooks()) return; - const electron = require('electron'); + +// Auto updater from the 'electron-auto-updater' package for NSIS +// auto-update support (not the one that comes with electron). +const autoUpdater = require('electron-auto-updater').autoUpdater; const url = require('url'); const VectorMenu = require('./vectormenu'); @@ -45,7 +43,7 @@ const PERMITTED_URL_SCHEMES = [ ]; const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000; -const INITIAL_UPDATE_DELAY_MS = 30 * 1000; +const INITIAL_UPDATE_DELAY_MS = 5 * 1000; let mainWindow = null; let appQuitting = false; @@ -90,12 +88,12 @@ function installUpdate() { // for some reason, quitAndInstall does not fire the // before-quit event, so we need to set the flag here. appQuitting = true; - electron.autoUpdater.quitAndInstall(); + autoUpdater.quitAndInstall(); } function pollForUpdates() { try { - electron.autoUpdater.checkForUpdates(); + autoUpdater.checkForUpdates(); } catch (e) { console.log("Couldn't check for update", e); } @@ -106,30 +104,19 @@ function startAutoUpdate(update_url) { update_url = update_url + '/'; } try { - // For reasons best known to Squirrel, the way it checks for updates - // is completely different between macOS and windows. On macOS, it - // hits a URL that either gives it a 200 with some json or - // 204 No Content. On windows it takes a base path and looks for - // files under that path. + // Since writing, the electron auto update process has changed from being + // completely different between platforms to being differently completely + // different. On Mac, we set the feed URL here. On Windows, it uses a + // yaml file bundled at build time from the 'publish' entry in the + // package.json. There is no autoupdate for Linux: it's expected that + // the distro will provide it. if (process.platform == 'darwin') { - // macos only has 64 bit - electron.autoUpdater.setFeedURL(update_url + 'macos/'); - } else if (process.platform == 'win32') { - // We split by 32/64 bit too: the builds are different and entirely separate - electron.autoUpdater.setFeedURL(update_url + 'win32/' + process.arch + '/'); - } else { - // Squirrel / electron only supports auto-update on these two platforms. - // I'm not even going to try to guess which feed style they'd use if they - // implemented it on Linux, or if it would be different again. - console.log("Auto update not supported on this platform"); + autoUpdater.setFeedURL(update_url + 'macos/'); } // We check for updates ourselves rather than using 'updater' because we need to // do it in the main process (and we don't really need to check every 10 minutes: // every hour should be just fine for a desktop app) // However, we still let the main window listen for the update events. - // We also wait a short time before checking for updates the first time because - // of squirrel on windows and it taking a small amount of time to release a - // lock file. setTimeout(pollForUpdates, INITIAL_UPDATE_DELAY_MS); setInterval(pollForUpdates, UPDATE_POLL_INTERVAL_MS); } catch (err) { diff --git a/electron/src/squirrelhooks.js b/electron/src/squirrelhooks.js deleted file mode 100644 index 10fb8d9e..00000000 --- a/electron/src/squirrelhooks.js +++ /dev/null @@ -1,30 +0,0 @@ -const path = require('path'); -const spawn = require('child_process').spawn; -const app = require('electron').app; - -function run_update_exe(args, done) { - const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe'); - spawn(updateExe, args, { - detached: true - }).on('close', done); -}; - -function check_squirrel_hooks() { - if (process.platform != 'win32') return false; - - const cmd = process.argv[1]; - const target = path.basename(process.execPath); - if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') { - run_update_exe(['--createShortcut=' + target + ''], app.quit); - return true; - } else if (cmd === '--squirrel-uninstall') { - run_update_exe(['--removeShortcut=' + target + ''], app.quit); - return true; - } else if (cmd === '--squirrel-obsolete') { - app.quit(); - return true; - } - return false; -} - -module.exports = check_squirrel_hooks; diff --git a/package.json b/package.json index 54de856b..0f16ce71 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress", - "build:electron": "rimraf electron/dist && npm run clean && npm run build && build -wm --ia32 --x64 && scripts/check-electron.sh", + "build:electron": "rimraf electron/dist && npm run clean && npm run build && build -wml --ia32 --x64 && scripts/check-electron.sh", "build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle", "build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev", "dist": "scripts/package.sh", @@ -58,6 +58,7 @@ "browser-request": "^0.3.3", "classnames": "^2.1.2", "draft-js": "^0.8.1", + "electron-auto-updater": "^0.6.2", "extract-text-webpack-plugin": "^0.9.1", "favico.js": "^0.3.10", "filesize": "^3.1.2", @@ -97,7 +98,7 @@ "catw": "^1.0.1", "cpx": "^1.3.2", "css-raw-loader": "^0.1.1", - "electron-builder": "^7.23.2", + "electron-builder": "^10.4.1", "emojione": "^2.2.3", "expect": "^1.16.0", "fs-extra": "^0.30.0", @@ -134,14 +135,15 @@ "dereference": true, "//files": "We bundle everything, so we only need to include webapp/", "files": [ - "!**/*", "electron/src/**", "electron/img/**", + "node_modules/electron-auto-updater/**", "webapp/**", "package.json" ], - "squirrelWindows": { - "iconUrl": "https://riot.im/favicon.ico" + "linux": { + "target": "deb", + "maintainer": "support@riot.im" } }, "directories": { From 2930a94c791c0db13493f413ad4e487a7c6f63bd Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 1 Dec 2016 18:01:23 +0000 Subject: [PATCH 08/15] Change to update_base_url --- electron/src/electron-main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index 044eca56..3fabd01b 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -111,7 +111,7 @@ function startAutoUpdate(update_url) { // package.json. There is no autoupdate for Linux: it's expected that // the distro will provide it. if (process.platform == 'darwin') { - autoUpdater.setFeedURL(update_url + 'macos/'); + autoUpdater.setFeedURL(update_base_url + 'update/macos/'); } // We check for updates ourselves rather than using 'updater' because we need to // do it in the main process (and we don't really need to check every 10 minutes: From 9f51e2c4075460a7b3882e59238576c28064a234 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 1 Dec 2016 19:33:42 +0000 Subject: [PATCH 09/15] Auto-update & build process with NSIS for windows Amalgamate the electron build packaging into one script. Use update_base_url so we can compute the actual URL in the script for windows (because we need to put it in the build) and at runtime for mac os. --- README.md | 3 + electron/src/electron-main.js | 27 ++++--- package.json | 2 +- scripts/check-electron.sh | 13 ---- scripts/electron-dist.sh | 54 -------------- scripts/electron-package.sh | 133 ++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 78 deletions(-) delete mode 100755 scripts/check-electron.sh delete mode 100755 scripts/electron-dist.sh create mode 100755 scripts/electron-package.sh diff --git a/README.md b/README.md index 9d1fb48c..1bccbca5 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,9 @@ You can configure the app by copying `vector/config.sample.json` to valid location on this network. This is used as a hint to the user to indicate when a valid location has been entered so it's not necessary for this to be exactly correct. Optional. +1. `update_base_url` (electron app only): HTTPS URL to a web server to download + updates from. This should be the path to the directory containing `install` + and `update`. Running as a Desktop app ======================== diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index 3fabd01b..a8bdc7f9 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -99,9 +99,9 @@ function pollForUpdates() { } } -function startAutoUpdate(update_url) { - if (update_url.slice(-1) !== '/') { - update_url = update_url + '/'; +function startAutoUpdate() { + if (process.platform != 'darwin' && process.platform != 'win32') { + return; } try { // Since writing, the electron auto update process has changed from being @@ -111,7 +111,19 @@ function startAutoUpdate(update_url) { // package.json. There is no autoupdate for Linux: it's expected that // the distro will provide it. if (process.platform == 'darwin') { - autoUpdater.setFeedURL(update_base_url + 'update/macos/'); + const update_base_url = vectorConfig.update_base_url; + if (!update_base_url) { + console.log("No update_base_url: disabling auto-update"); + return; + } + if (update_base_url.slice(-1) !== '/') { + update_base_url = update_url + '/'; + } + const update_url = update_base_url + 'update/macos/tmp/'; + console.log("Starting auto update with URL: " + update_url); + autoUpdater.setFeedURL(update_url); + } else { + console.log("Starting auto update with baked-in URL"); } // We check for updates ourselves rather than using 'updater' because we need to // do it in the main process (and we don't really need to check every 10 minutes: @@ -138,12 +150,7 @@ process.on('uncaughtException', function (error) { electron.ipcMain.on('install_update', installUpdate); electron.app.on('ready', () => { - if (vectorConfig.update_url) { - console.log("Starting auto update with URL: " + vectorConfig.update_url); - startAutoUpdate(vectorConfig.update_url); - } else { - console.log("No update_url is defined: auto update is disabled"); - } + startAutoUpdate(); mainWindow = new electron.BrowserWindow({ icon: `${__dirname}/../img/riot.ico`, diff --git a/package.json b/package.json index 0f16ce71..2ffb5773 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress", - "build:electron": "rimraf electron/dist && npm run clean && npm run build && build -wml --ia32 --x64 && scripts/check-electron.sh", + "build:electron": "rimraf electron/dist && npm run clean && npm run build && build -wml --ia32 --x64", "build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle", "build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev", "dist": "scripts/package.sh", diff --git a/scripts/check-electron.sh b/scripts/check-electron.sh deleted file mode 100755 index 82b24a6c..00000000 --- a/scripts/check-electron.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -update_url=`jq .update_url webapp/config.json` -echo "***************************************************" -echo -if [ $? = 0 ]; then - echo "Built electron package with update url: $update_url" -else - echo "Built electron package with no update url" - echo "This build will not auto-update." -fi -echo -echo "***************************************************" diff --git a/scripts/electron-dist.sh b/scripts/electron-dist.sh deleted file mode 100755 index 0e8efd56..00000000 --- a/scripts/electron-dist.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash - -set -e -set -x - -if [ $# = 0 ]; then - echo "Usage: $0 " - echo "" - echo "Adds the build in electron/dist/ to a given Riot electron" - echo "download tree. If target directory is empty, create a new" - echo "download tree. This tree can be placed on a web server to" - echo "serve auto-updates (although auto-update for Mac requires" - echo "additional logic)." - exit -fi - -ver=`basename electron/dist/mac/*.dmg | cut -d '-' -f 2 | sed -e 's/\.dmg$//'` -dir=$1 - -echo "Copying files for version $ver to $dir" - -# Install packages: what the user downloads the first time, -# (DMGs for mac, exe installer for windows) -mkdir -p "$dir/install/macos" -cp electron/dist/mac/*.dmg "$dir/install/macos/" -echo "$ver" > "$dir/install/macos/latest" - -mkdir -p "$dir/install/win32/ia32" -cp electron/dist/win-ia32/*.exe "$dir/install/win32/ia32/" - -mkdir -p "$dir/install/win32/x64" -cp electron/dist/win/*.exe "$dir/install/win32/x64/" - - -# Packages for auto-update. It would be nice if squirrel's -# auto update used the installer packages, but it doesn't -# for Reasons. zip for mac, nupkg for windows. -mkdir -p "$dir/update/macos" -cp electron/dist/mac/*.zip "$dir/update/macos/" -echo "$ver" > "$dir/update/macos/latest" - -mkdir -p "$dir/update/win32/ia32" -cp electron/dist/win-ia32/*.nupkg "$dir/update/win32/ia32/" -cat electron/dist/win-ia32/RELEASES >> "$dir/update/win32/ia32/RELEASES" -echo >> "$dir/update/win32/ia32/RELEASES" - -mkdir -p "$dir/update/win32/x64" -cp electron/dist/win/*.nupkg "$dir/update/win32/x64/" -cat electron/dist/win/RELEASES >> "$dir/update/win32/x64/RELEASES" -echo >> "$dir/update/win32/x64/RELEASES" - - -echo "All done!" -echo "$dir can now be copied to your web server." diff --git a/scripts/electron-package.sh b/scripts/electron-package.sh new file mode 100755 index 00000000..8b1ccd4b --- /dev/null +++ b/scripts/electron-package.sh @@ -0,0 +1,133 @@ +#!/bin/bash + +set -e + +usage() { + echo "Usage: $0 -v -c [-n]" + echo + echo "version: commit-ish to check out and build" + echo "config file: a path to a json config file to" + echo "ship with the build. In addition, update_base_url:" + echo "from this file is used to set up auto-update." + echo "-n: build with no config file." + echo + echo "Values may also be passed as environment variables" +} + +conffile= +version= +skipcfg=0 +while getopts "c:v:n" opt; do + case $opt in + c) + conffile=$OPTARG + ;; + v) + version=$OPTARG + ;; + n) + skipcfg=1 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + usage + exit + ;; + esac +done + +if [ -z "$version" ]; then + echo "No version supplied" + usage + exit +fi + +if [ -z "$conffile" ] && [ "$skipcfg" = 0 ]; then + echo "No config file given. Use -c to supply a config file or" + echo "-n to build with no config file (and no auto update)." + exit +fi + +if [ -n "$conffile" ]; then + update_base_url=`jq -r .update_base_url $conffile` + + if [ -z "$update_base_url" ]; then + echo "No update URL supplied. Use update_base_url: null if you really" + echo "want a build with no auto-update." + usage + exit + fi + # Make sure the base URL ends in a slash if it doesn't already + update_base_url=`echo $update_base_url | sed -e 's#\([^\/]\)$#\1\/#'` +fi + +if [ ! -f package.json ]; then + echo "No package.json found. This script must be run from" + echo "the vector-web directory." + exit +fi + +echo "Building $version using Update base URL $update_base_url" + +projdir=`pwd` +builddir=`mktemp -d 2>/dev/null || mktemp -d -t 'buildtmp'` +pushd "$builddir" +git clone "$projdir" . +git checkout "$version" + +if [ -n "$conffile" ]; then + popd + cp "$conffile" "$builddir/" + pushd "$builddir" +fi + +if [ "$update_base_url" != "null" ]; then + # Inject a 'publish' configuration into the package.json. This is what + # electron-builder needs for auto-update on windows but we don't want to + # keep it in the package.json as we don't want everyone cloning the source + # and building it for themselves to get our auto-update URL. + update_url=$update_base_url/install/win32/ + jq '.build.publish.provider="generic"' package.json \ + | jq '.build.publish.url="$update_url"' \ + > package.json.tmp + mv package.json.tmp package.json +fi + +npm install +npm run build:electron + +popd + +distdir="$builddir/electron/dist" +pubdir="$projdir/electron/pub" +rm -r "$pubdir" || true +mkdir -p "$pubdir" + +# figure out what version this build is known as +# (since we could be building from a branch or indeed +# any commit-ish, not just a version tag) +vername=`python -c 'import yaml; import sys; print yaml.load(sys.stdin)["version"]' < $builddir/electron/dist/latest.yml` + +# Install packages: what the user downloads the first time, +# (DMGs for mac, exe installer for windows) +mkdir -p "$pubdir/install/macos" +cp $distdir/mac/*.dmg "$pubdir/install/macos/" + +mkdir -p "$pubdir/install/win32/" +cp $distdir/*.exe "$pubdir/install/win32/" +cp $distdir/latest.yml "$pubdir/install/win32/" + +# Packages for auto-update on mac (Windows (NSIS) uses the installer exe) +mkdir -p "$pubdir/update/macos" +cp $distdir/mac/*.zip "$pubdir/update/macos/" +echo "$ver" > "$pubdir/update/macos/latest" + +# Move the debs to the main project dir's dist folder +rm -r "$projdir/electron/dist" || true +mkdir -p "$projdir/electron/dist" +cp $distdir/*.deb "$projdir/electron/dist/" + +rm -rf "$builddir" + +echo "Riot Desktop $vername is ready to go in $pubdir: this directory can be hosted on your web server." +echo "deb archives are in electron/dist/ - these should be added into your debian repository" From 7871a3edb5aaf1822355ea9841434818eba93015 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 1 Dec 2016 19:43:04 +0000 Subject: [PATCH 10/15] Just rm dist in the clean step --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2ffb5773..e8377a0d 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:compile": "babel --source-maps -d lib src", "build:bundle": "NODE_ENV=production webpack -p --progress", "build:bundle:dev": "webpack --optimize-occurence-order --progress", - "build:electron": "rimraf electron/dist && npm run clean && npm run build && build -wml --ia32 --x64", + "build:electron": "npm run clean && npm run build && build -wml --ia32 --x64", "build": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle", "build:dev": "node scripts/babelcheck.js && npm run build:res && npm run build:config && npm run build:emojione && npm run build:css && npm run build:bundle:dev", "dist": "scripts/package.sh", @@ -47,7 +47,7 @@ "start:skins:css": "mkdirp build && catw \"src/skins/vector/css/**/*.css\" -o build/components.css", "start": "node scripts/babelcheck.js && parallelshell \"npm run start:emojione\" \"npm run start:res\" \"npm run start:config\" \"npm run start:js\" \"npm run start:skins:css\"", "start:prod": "parallelshell \"npm run start:emojione\" \"npm run start:js:prod\" \"npm run start:skins:css\"", - "clean": "rimraf build lib webapp", + "clean": "rimraf build lib webapp electron/dist", "prepublish": "npm run build:compile", "test": "karma start --single-run=true --autoWatch=false --browsers PhantomJS --colors=false", "test:multi": "karma start" From f1998497f20acffa4ad8c7be8e4fe5d67e7652b7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 2 Dec 2016 14:21:33 +0000 Subject: [PATCH 11/15] Put the riot.im config back in this repo --- electron/riot.im/README | 4 ++ electron/riot.im/config.json | 72 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 electron/riot.im/README create mode 100644 electron/riot.im/config.json diff --git a/electron/riot.im/README b/electron/riot.im/README new file mode 100644 index 00000000..09c21874 --- /dev/null +++ b/electron/riot.im/README @@ -0,0 +1,4 @@ +This directory contains the config file for the official riot.im distribution +of Riot Desktop. You probably do not want to build with this config unless +you're building the official riot.im distribution, or you'll find your builds +will replace themselves with the riot.im build. diff --git a/electron/riot.im/config.json b/electron/riot.im/config.json new file mode 100644 index 00000000..8ed2a3e8 --- /dev/null +++ b/electron/riot.im/config.json @@ -0,0 +1,72 @@ +{ + "update_base_url": "https://riot.im/download/desktop/", + "default_hs_url": "https://matrix.org", + "default_is_url": "https://vector.im", + "brand": "Riot", + "integrations_ui_url": "https://scalar.vector.im/", + "integrations_rest_url": "https://scalar.vector.im/api", + "enableLabs": true, + "roomDirectory": { + "servers": [ + "matrix.org" + ], + "serverConfig": { + "matrix.org": { + "networks": [ + "_matrix", + "gitter", + "irc:freenode", + "irc:mozilla", + "irc:snoonet", + "irc:oftc" + ] + } + }, + "networks": { + "gitter": { + "protocol": "gitter", + "portalRoomPattern": "#gitter_.*:matrix.org", + "name": "Gitter", + "icon": "https://gitter.im/favicon.ico", + "example": "org/community", + "nativePattern": "[^\\s]+/[^\\s]+$" + }, + "irc:freenode": { + "protocol": "irc", + "domain": "chat.freenode.net", + "portalRoomPattern": "#freenode_.*:matrix.org", + "name": "Freenode", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + }, + "irc:mozilla": { + "protocol": "irc", + "domain": "chat.freenode.net", + "portalRoomPattern": "#mozilla_.*:matrix.org", + "name": "Mozilla", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + }, + "irc:snoonet": { + "protocol": "irc", + "domain": "ipv6-irc.snoonet.org", + "portalRoomPattern": "#_snoonet_.*:matrix.org", + "name": "Snoonet", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + }, + "irc:oftc": { + "protocol": "irc", + "domain": "irc.oftc.net", + "portalRoomPattern": "#_oftc_.*:matrix.org", + "name": "OFTC", + "icon": "https://matrix.org/_matrix/media/v1/download/matrix.org/DHLHpDDgWNNejFmrewvwEAHX", + "example": "#channel", + "nativePattern": "^#[^\\s]+$" + } + } + } +} From 72de35a2a11f1be25a10f8e40b4eca7dd3570e98 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Dec 2016 14:08:27 +0000 Subject: [PATCH 12/15] Switch back to Squirrel installer which it turns out is by far the lesser of two evils. * Auto-update works with a proxy * The update process is reasonably atomic & faster, rather than running the uninstaller then the installer, leaving you with a broken install if you shut down your machine at the wrong time * Gets the update URL the same way as on mac, rather than baking it into the app at build time from package.json. We don't want it in package.json because only our builds want our update URL. --- electron/src/electron-main.js | 62 +++++++++++++++++++---------------- package.json | 5 +-- scripts/electron-package.sh | 30 ++++++++--------- 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/electron/src/electron-main.js b/electron/src/electron-main.js index a8bdc7f9..2ca0b9d3 100644 --- a/electron/src/electron-main.js +++ b/electron/src/electron-main.js @@ -17,11 +17,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -const electron = require('electron'); +// Squirrel on windows starts the app with various flags +// as hooks to tell us when we've been installed/uninstalled +// etc. +const check_squirrel_hooks = require('./squirrelhooks'); +if (check_squirrel_hooks()) return; -// Auto updater from the 'electron-auto-updater' package for NSIS -// auto-update support (not the one that comes with electron). -const autoUpdater = require('electron-auto-updater').autoUpdater; +const electron = require('electron'); const url = require('url'); const VectorMenu = require('./vectormenu'); @@ -43,7 +45,7 @@ const PERMITTED_URL_SCHEMES = [ ]; const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000; -const INITIAL_UPDATE_DELAY_MS = 5 * 1000; +const INITIAL_UPDATE_DELAY_MS = 30 * 1000; let mainWindow = null; let appQuitting = false; @@ -88,47 +90,44 @@ function installUpdate() { // for some reason, quitAndInstall does not fire the // before-quit event, so we need to set the flag here. appQuitting = true; - autoUpdater.quitAndInstall(); + electron.autoUpdater.quitAndInstall(); } function pollForUpdates() { try { - autoUpdater.checkForUpdates(); + electron.autoUpdater.checkForUpdates(); } catch (e) { console.log("Couldn't check for update", e); } } -function startAutoUpdate() { - if (process.platform != 'darwin' && process.platform != 'win32') { - return; +function startAutoUpdate(update_base_url) { + if (update_base_url.slice(-1) !== '/') { + update_base_url = update_base_url + '/'; } try { - // Since writing, the electron auto update process has changed from being - // completely different between platforms to being differently completely - // different. On Mac, we set the feed URL here. On Windows, it uses a - // yaml file bundled at build time from the 'publish' entry in the - // package.json. There is no autoupdate for Linux: it's expected that - // the distro will provide it. + // For reasons best known to Squirrel, the way it checks for updates + // is completely different between macOS and windows. On macOS, it + // hits a URL that either gives it a 200 with some json or + // 204 No Content. On windows it takes a base path and looks for + // files under that path. if (process.platform == 'darwin') { - const update_base_url = vectorConfig.update_base_url; - if (!update_base_url) { - console.log("No update_base_url: disabling auto-update"); - return; - } - if (update_base_url.slice(-1) !== '/') { - update_base_url = update_url + '/'; - } - const update_url = update_base_url + 'update/macos/tmp/'; - console.log("Starting auto update with URL: " + update_url); - autoUpdater.setFeedURL(update_url); + electron.autoUpdater.setFeedURL(update_base_url + 'macos/'); + } else if (process.platform == 'win32') { + electron.autoUpdater.setFeedURL(update_base_url + 'win32/' + process.arch + '/'); } else { - console.log("Starting auto update with baked-in URL"); + // Squirrel / electron only supports auto-update on these two platforms. + // I'm not even going to try to guess which feed style they'd use if they + // implemented it on Linux, or if it would be different again. + console.log("Auto update not supported on this platform"); } // We check for updates ourselves rather than using 'updater' because we need to // do it in the main process (and we don't really need to check every 10 minutes: // every hour should be just fine for a desktop app) // However, we still let the main window listen for the update events. + // We also wait a short time before checking for updates the first time because + // of squirrel on windows and it taking a small amount of time to release a + // lock file. setTimeout(pollForUpdates, INITIAL_UPDATE_DELAY_MS); setInterval(pollForUpdates, UPDATE_POLL_INTERVAL_MS); } catch (err) { @@ -150,7 +149,12 @@ process.on('uncaughtException', function (error) { electron.ipcMain.on('install_update', installUpdate); electron.app.on('ready', () => { - startAutoUpdate(); + if (vectorConfig.update_base_url) { + console.log("Starting auto update with base URL: " + vectorConfig.update_base_url); + startAutoUpdate(vectorConfig.update_base_url); + } else { + console.log("No update_base_url is defined: auto update is disabled"); + } mainWindow = new electron.BrowserWindow({ icon: `${__dirname}/../img/riot.ico`, diff --git a/package.json b/package.json index e8377a0d..ea9d3203 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "browser-request": "^0.3.3", "classnames": "^2.1.2", "draft-js": "^0.8.1", - "electron-auto-updater": "^0.6.2", "extract-text-webpack-plugin": "^0.9.1", "favico.js": "^0.3.10", "filesize": "^3.1.2", @@ -137,13 +136,15 @@ "files": [ "electron/src/**", "electron/img/**", - "node_modules/electron-auto-updater/**", "webapp/**", "package.json" ], "linux": { "target": "deb", "maintainer": "support@riot.im" + }, + "win": { + "target": "squirrel" } }, "directories": { diff --git a/scripts/electron-package.sh b/scripts/electron-package.sh index 8b1ccd4b..5830c62d 100755 --- a/scripts/electron-package.sh +++ b/scripts/electron-package.sh @@ -81,18 +81,6 @@ if [ -n "$conffile" ]; then pushd "$builddir" fi -if [ "$update_base_url" != "null" ]; then - # Inject a 'publish' configuration into the package.json. This is what - # electron-builder needs for auto-update on windows but we don't want to - # keep it in the package.json as we don't want everyone cloning the source - # and building it for themselves to get our auto-update URL. - update_url=$update_base_url/install/win32/ - jq '.build.publish.provider="generic"' package.json \ - | jq '.build.publish.url="$update_url"' \ - > package.json.tmp - mv package.json.tmp package.json -fi - npm install npm run build:electron @@ -113,15 +101,25 @@ vername=`python -c 'import yaml; import sys; print yaml.load(sys.stdin)["version mkdir -p "$pubdir/install/macos" cp $distdir/mac/*.dmg "$pubdir/install/macos/" -mkdir -p "$pubdir/install/win32/" -cp $distdir/*.exe "$pubdir/install/win32/" -cp $distdir/latest.yml "$pubdir/install/win32/" +mkdir -p "$pubdir/install/win32/ia32/" +cp $distdir/win-ia32/*.exe "$pubdir/install/win32/ia32/" -# Packages for auto-update on mac (Windows (NSIS) uses the installer exe) +mkdir -p "$pubdir/install/win32/x64/" +cp $distdir/win/*.exe "$pubdir/install/win32/x64/" + +# Packages for auto-update mkdir -p "$pubdir/update/macos" cp $distdir/mac/*.zip "$pubdir/update/macos/" echo "$ver" > "$pubdir/update/macos/latest" +mkdir -p "$pubdir/update/win32/ia32/" +cp $distdir/win-ia32/*.nupkg "$pubdir/update/win32/ia32/" +cp $distdir/win-ia32/RELEASES "$pubdir/install/win32/ia32/" + +mkdir -p "$pubdir/update/win32/x64/" +cp $distdir/win/*.nupkg "$pubdir/update/win32/x64/" +cp $distdir/win/RELEASES "$pubdir/update/win32x64ia32/" + # Move the debs to the main project dir's dist folder rm -r "$projdir/electron/dist" || true mkdir -p "$projdir/electron/dist" From b613a742f53bb8498c42dec4fb872faf5a6d0011 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Dec 2016 14:17:22 +0000 Subject: [PATCH 13/15] Forgot to re-add squirrelhooks --- electron/src/squirrelhooks.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 electron/src/squirrelhooks.js diff --git a/electron/src/squirrelhooks.js b/electron/src/squirrelhooks.js new file mode 100644 index 00000000..10fb8d9e --- /dev/null +++ b/electron/src/squirrelhooks.js @@ -0,0 +1,30 @@ +const path = require('path'); +const spawn = require('child_process').spawn; +const app = require('electron').app; + +function run_update_exe(args, done) { + const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe'); + spawn(updateExe, args, { + detached: true + }).on('close', done); +}; + +function check_squirrel_hooks() { + if (process.platform != 'win32') return false; + + const cmd = process.argv[1]; + const target = path.basename(process.execPath); + if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') { + run_update_exe(['--createShortcut=' + target + ''], app.quit); + return true; + } else if (cmd === '--squirrel-uninstall') { + run_update_exe(['--removeShortcut=' + target + ''], app.quit); + return true; + } else if (cmd === '--squirrel-obsolete') { + app.quit(); + return true; + } + return false; +} + +module.exports = check_squirrel_hooks; From 37b4734bbe0b1d26d33cd51c069614be57991c08 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Dec 2016 14:19:49 +0000 Subject: [PATCH 14/15] Also re-add installer spinner --- electron/build/install-spinner.gif | Bin 0 -> 4460 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 electron/build/install-spinner.gif diff --git a/electron/build/install-spinner.gif b/electron/build/install-spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..c4f832c34230af5d0267962c7e1d0fab4bab5dd0 GIT binary patch literal 4460 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 literal 0 HcmV?d00001 From 3d813e68e9e889a25351f82fe0b843e433bbcd51 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 5 Dec 2016 14:20:26 +0000 Subject: [PATCH 15/15] gitignore electron/pub --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2e34b6c1..1f18d9a1 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ .DS_Store npm-debug.log electron/dist +electron/pub