From 3d055bbb79166e3dfe35d496ddd0fc94fd2f7563 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sun, 25 May 2014 20:49:08 +0200 Subject: [PATCH] Simple file versioning (fixes #218) --- auto/gui.files.go | 4 +- cmd/syncthing/main.go | 3 +- config/config.go | 57 ++++++++++++++++++--- gui/app.js | 21 +++++++- gui/index.html | 102 ++++++++++++++++++++++++-------------- model/model.go | 3 +- model/puller.go | 49 ++++++++++++++---- model/tempname.go | 8 --- model/tempname_windows.go | 31 ------------ model/util.go | 14 ------ osutil/hidden_unix.go | 11 ++++ osutil/hidden_windows.go | 35 +++++++++++++ osutil/osutil.go | 18 +++++++ scanner/walk.go | 10 +--- versioner/debug.go | 13 +++++ versioner/simple.go | 84 +++++++++++++++++++++++++++++++ versioner/versioner.go | 7 +++ 17 files changed, 350 insertions(+), 120 deletions(-) create mode 100644 osutil/hidden_unix.go create mode 100644 osutil/hidden_windows.go create mode 100644 osutil/osutil.go create mode 100644 versioner/debug.go create mode 100644 versioner/simple.go create mode 100644 versioner/versioner.go diff --git a/auto/gui.files.go b/auto/gui.files.go index 026b7ecf..ea606cab 100644 --- a/auto/gui.files.go +++ b/auto/gui.files.go @@ -18,7 +18,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["angular.min.js"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffd43c5f73dbb693eff914882e2da944a69cde4de7c68ad3699db4e7cb3f4f9ce4c5f503254212638a5448d0b6c6d577ffed022009100045db499b6a26b10d2c16fb0f8bdd05a0f1e3cf4512a78c4cf3ecaaa0f901617949476496a52c4e4b5afdbd4eca02ff89bfc9e3f183f1e345924dc3843c3a20f3302900284c176512e6f26f047ae095f04bc1f278c6bcc9830797614e8a4d3a63cb385d90c36a44b0caa232a1be57f7792372763e9cf001659e4c43407348bc9c161c4f0d1720a179962434f7bdd3aaf588e509609897f0779ca5c47f54ccb23550f868c9d87a486e1e10f820ee754e2f5f840c91ef4fead60565ef5e4113f2dab4e2e461ce04e59c45a0043b05762425a57cc202006eb69356e73c5e98edabcdf10be4ccd35ad32ca288e4ecdc82e438454635f2643fcdf32cb78c2b284d5f629f3913489e262659395d671517bc7d3c26a7a0c6745190299d673925d32c4b0a9264d905b43046737d46c63830d0c2db6fe2e88078afe382d11410817680c319d80ad71a39c93396cdb2840808f26b1481b80b5a0020dbacc10e3d46af19fc25b5200c713b5290bf09af4f691abd9aae0b05fdbb922d32d4d97b54f3eb781533e2bf8a7f1b17c306775aaea634efc4fe1ef085e9710a8c5e86c9a93283e8215517f16f8d595a8e1db9ecbc3bfe93300f618124efe997128054e180c808080846a611975103d21f3f20395ac24aa62dc923f2dfe38412d12b14d05ff4ca0c7f704ff36b9abe4cc36942236512d1455ec460779734df3488d13e3be97e9dcd1c4879cfbd709e6439732324b2bbbf8c4fb1fd37e1a3d5b583cda46957c9d4c67f3c494f4c3e450bc14efbe073ddc32dcaf8d4beb0e57a5515f3f1f83e8bf9a3ce2862fbb5644b0adbd22ce44efda3c6f24e842761515c6579d48d54819288d74d4b27b51f5eabcb161ac8ff7df870724ac0571298a8970d55e2ae372ed8884ecbd98cd288467eb56fe1279e13ff21dfa6d4564555711a337f38d1bb7cefbf52ca809b0bbe1b784374ff61e27bcb38a25e0bdadc04f1b3d54868b6c45b92d10cec2602618b65c9a2ec2aed86b4edce3ad15b53b8bf87e09f4cc9bad9ca292bf3d4250ebb425c52bf9986b38b28cfd66014301fd82098c505dd4cb3308f6410b57528a58bc17a0b9f031f4b04aee32095361e0b0580d0af02ac27c41b171b58b22ba0b140bb2b0abf191c852c6c33a71be8c4660202239081e3159287225cf1edd449e49582d471cdefefa69f61670c406685af062ec30056ddcb70b65490c791a118ab007840f40ba239f4a081a63368f8f8fef8285badb3145c0562ea2b1e450c1cef591c9d1b926873a5fe6ea75189347b6b0a23d834bb82d931de8508f3ca1f8e34081641a78f307b755c3c2463f2747f7f5f878c23e9a8aa8f1246c3789d357480203312a7c42522eecdb0335886c5bbab14a2c135cdd9868bda028f9f2a439918bd5ba385c1966bc78293a252c05141f002e4bf09d9325885d7fefe88fc2f792c64c9218ed3df368c161f32065bf99e25e837a050782c1a9a146a336725db353584687de6d6c09c936f09ec75b325f1a94bb48650f6fbb26001d4b5b1b579083d716abb895d8b41243dbdd7413b55b24fb79d3c68a743106bb1b2d0dc2936b7f70edce5b3b9beea110ed6fd21645f651ad1799c421866df5a2074482f52dced54efaecd60a206454162006bec214ee1c47ccab2f51a66b662e6a939136bd843cf679986f737a32b70fef36cff3c60d94798203f02d580337f223a402fd382e5fed3e144e7430e3f24034c0161b31d90bffe224deb7194d0419b17d1fd04ba893f68a8c482c009cd67e09fc305958a7942063f0c07566ea5481486da9be73a3b4a20f4fbf6fa8ed379f60d941d61ce957f355d6b0af362508d7366b90e3d5794d4a02984de9d98d679bc0a21ffb261b2884f57a16e12df5c8fb04bba18b64857d4ceb8b7e6f8f7fb61d534b89e31e00a2060afb09a092e2b31c5d806a0d030698b95ef45f32483f80ca6b13b452c52599c22361fcdb5c819a945270f7096ad4b0e08dec2cfe317e7bacd21605b36557b80315942f9b4284410856d4bab1deb9ab08c473f5e2bf82214eb95ee91d23f111fd74a7b66d8837e18b63176f81c8f970138fbb52fb648f678865cfd1be49a5ddc569e3235b98dd05610eb156e6999befabb1597e91e7bc9ccf4853b65a6ba4653645895f99b252609e3429345a12ed7fe4b87be1591ff632cb49c40e736e566e513dda9062446a7941b9a7284e02053425cd2bc00dc36fabea5789218f6de4feeb977e819b6db082736a4a3b38b1cac30a3e12726ea010a604818552b0c486f356dda889208ac132ddb401625de20a1e9822d21e2224f1d1cd7f14107a3121b44ca4e63781bae4c7e2dd620a315d9db3344190c5c114aad6798de315805e9e051b7982af6878cf6677b10c19671f1d6c6785bc5a9b084d630bfa530452e7d85e29722e1e283869d22da259f3ec2e92d191ac54ca9b6db25331e43a876414948b0be88310a8cddd4dddab9612041deadab54bb3a7ec531be0e2b81d4ecdb860b4be89d780040c581e55cc953df3a28af8f0fad117e78497b4ba82873f82f5b5171f63ce3675291ee07451ba07a58b344bf946152d88533ea94ef10b2596337179f1de841660ed4ba34e3b92f491e5a6b1c3ab5dd7a6ad16eade436e4f5c225887523aacfb15bc56c270781384f929183b6639950a72c0f8a751233df1ba1a9856b651fb856f681eb804168058e84b48beda2deb4ce0aa3fa0ad3818dfeffe9bbb741c14fc5e3794b08c311b959d23082ddef80dc7847590a34b1bd0fe09f3cb0f3700da48933a7f1e7224bbdad56017ed0bd62067800327095aaf8d985733d68e724fad98ee360e6b6e7140eb149cc9ecba558ae35b458ab0e82eec49b9d28e56cc92c1fda4e728cc3a8db4a677b77fe7147b00644ad00a1425be639d89c1cf128a0d76082917fb31d55bbb4490a4e01e27b790d6bc82a460dec9426737166d08a4db5d0d4e4b7212ca8cf8661bd92c33a7ca89b83cf599cc2122616bb41e097404996078f608d9ce49c682d2640955562bbd386a36b203603524df0305b1c7d510e568b6576e5d97185d10e64362ddea8f202f2a34d1aae80fe6d0f4db6dcac55957698bf5fd01185c48aee14b631a37134cc8f96ec22d97db66b9343bf24c31a2156ebe361b340d4a5207a7b780a0ed9a643d969f9891b0634e2d44d3b19b59f86f03e7e94d342ddeae8c1ec3d186e336d2aa03b70f847f6ebf61e053169a7d956b90c78b91189b2948e483cb92da3bd4cbf4e0e2db237a06adfddcee0c002927046fd311903c11e4c57b7ec552ddab94f154e1933d4aecbe6e7ef18aed593a0244d4189b3677e304962f24c5fb822a9878e274f6ca53d15f62c3e570b2fba883a0efdabc10dc713035452aeefb3d5679ad3f0a247c94f9ca00326c702171cafcb62e99b7bbfc3d105459633bfaab68539bdab3ffa1ed665c69634afe874458f6acdcce9dc7bfb760c7e4c6feea87f74fa8b1822b6b67fbf8355a72d1581614e0cb34f7b561855e6dd066ae1384c926e3d541e52b1a8467b6dc7228dda280b29604af1a5b0c7d5781700b3c69ea621ee0e98b6e12a0dd1e043bca2e4b9711d7ba775cc121ae62fabab0a9d71a27ac75ba3f34ca75a9632f7c8d3734ed6ceed938f1b734a1c91ec3c8f21b14836a65a6151aba43681c9ed8d971768d4ddcc6ec2054f23e0ff7a9b9ad58e7ad4aeb462df70d851b0033c8e247b9df531980a4ebf9d66ab65e176fe1e7a6f97dbc9114d6e5740dc8ce78a5c15e030b75dc99e82a40aef8c6b73467c6719ab4d7a56399073f3eee89df34d945bcf040429fa0a09086467863a76eac122fe3be7657f3fcb18ba76f22c1ec1acb3af11ba6a341ba1ab9cc5085d71940155871f67e7669f6e9bca7e669a67ed9dc46910a64e562cb660d13e5d5a2d844331977d0f5598109bd98d58400792907659b2bdbfe247e4cb767a4d1589acae0216b2907fb9423c947c81d6187351bb1cdb7715f3154b085a8b964957aa32220ed80f5c46e4748e7862d40eb2108f1694d4bb4deb5cd3578e838643478950a0e391b825a4e19dbc423618114741589846b733ebb528bf4e29455aaa6689963d453b6dbea729fe5b6a07f85842b5d4ddb7f5e5c1fe6d2fbfca61d6dbaf3b66bce5fb806a25dadf002810f21d24bf046e264e3b88925aba2551f5934c2751ae83a51d474fb2a8a195ae9d49b981eb6d93a7d8e06d59b90db87ac1893fdf846bdfbd869c08f825adf6db8b5eaa18e3e5cbbbe9a35ea0dc14d4b69dd992fad80842a6eac1a4af3334e20f1af6018eb35393a688d40f47645a51a95c2b08f901bfb878db5c2c203ffe4824c0d40ad0bebc21d13c93e0435bceb8f7d4f0f672d87339acca2214ac226ee1788dca540baf18d76016439fd743413a8a6cf846e8904d18bc88738836b27cc3a7aeffea3f7b83e0b98ac0a4010d3951df6faf94a7cb896587d6d2cfd5595e053b920c692cd5fd1c7342beb1acd4191325466815da57ea6489880156583c1f2a4c2762012b12d589487422223a8b577845000c1952b952a3258a17312bf0d5e1ac8af25023f848d8b8542cd1ef6bc9a74050bd3d11f77df9af49b610bf84533ef5109f93d43d4ff7ab7005676e3d5d011ac99ec4acb326c8dcaacff7650dc54b438008f547fb15f572b4f2942b5d976c44f82d780b8bbc3b60d9eff1358dfc5a80daa8c68170276012348dd390bffced4b4f7b91f346ae86da11b8aeb9ef13e75d7981e539b8ac9ffe873c567f185908871c1f5a4027b659bba5f4d3109f4f78e48ff836a4f5a1e91ec4bce9474c2715f798fe957d7af5c67c9e81b22b7bc031de2e3b5b51fc728cefc8cef87302e5478734dba0f7b1b3db50d687a4fb98592f5a3a89b8c7ec17dfc0c88aa5f8be81bbd89846bcf5d2a263d230b90a37c5dbeabb0dbebd7d5bdfdfa8e4efa278b62cd38be3175f99581ba9ea4d5cfe9427ccf9362ca4ccef09fbe3e0e6e9e8e7ed78d14ec139f04eb4b28903cb4c64afaedf771aca0918d93f2e0371163c3efb73fce79fe763ab08f0b5a0604f9e693c3b24ffedb00d45ff56fb18044130c6f784026101093bf555e47b3f0d65a1653c704931e2816b7c497d2fe309a1a8df76c9525d67e26b920e8877e48d94667e8a21bf87a96e66799816b3a48c8c1e9eeb1cb45f4d8a1b8480fb50feaa4cb155d0d2154cc7f06b2a9e093d62627338c06fd7189074b1c7df8f1d0ef4b4f74ce20c20d41d3c7f36e6239fcb19cce5a688a94ce32f25af4d2942ea92d1971206e357a62cde20250a17499c5e1c3438b818468426ab110919cb214a9eb13c699b07b6058f40d105cd8ba04c8b653c6775fee05fc6f4ea5398d82bb7fc2d639f6a58f5198fc91525b0c6ca244a3d26425190b61558500692fd845031dbb4a4c5ebc91363a87c47d4d0262a6c3523e71dc4b1a5a820138a8c14244c721a469b3b91c7cb6b6efa76d310174420fcaad2315aa48dd5f26995da8dc34169ceff010000ffff010000ffff1acec71e384d0000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffd43c6b73dbb6b2dff32b10ddb4a41299727aefed9c89e2745a27edf1c9cb1327f9e2fa03254216638a5448d08f71f4dfcf2e00527852b49db4a96612dbc0625f582c761780c60f3f55599a33322d8b8b8a964f082b6b3a22b32267695ed3e6ef555657f84ffc4d1e8eef8d1f9e66c534cec88327641e671500c5f9699dc5a5fc1b81ee0535fc52b1329db16072efde795c92ea2a9fb1459a9f92bd6644b42c923aa361d0f60523727c329cf00175994d6340b3478292561c4f0b1721a3659165b40c83a3a6759f95196098d7f0775ae4247c50cd8a1570f860c1d86a48aeef11f820ee5549cf9fc70c91ef4edad653cadebe84269475d38ac4e39209ceb988c009760aecc84a4e39c10a00aed713a3739e9edaedcbab83e72859a0b5e6454211c9f18903c9418e826aecc97e5a9645e91857519abfc03e9b12689e66365b255d158d14bc7d3c2647308df96945a6745e94944c8b22ab48561467d0c2182d758a8c7160e085b75fa7c91312bc4a2b46734004b30312cec056f8ac91c3b260c5acc8888020bf2609a8bba21500b2ab15d861c0e82583bfe42c08435c8f14e4afe3cb239a272fa7ab4a41ffb666a705ced93b9ce657e93265247c99fe36ae861bdc79bd9cd2b213fb3bc017e70739087a1e67470a05d1439a2e12de18b3b41c3772d9797bfc877119c302c9ded1cf3500a9ca01951150108ccc13aea30d487ffc80647f012b991a9a47e4bfa71925a2574c407fd52b14fee09ee6d73c7f91c7d38c260a11d1459ea76077e7b4bcda2046fbece4fb5531f320e53d77c2795894cc8f90c8eefe3a3ec2f6df848f56d70e36934dbbcaa636fec3617e68cb295a0876ba079fe81eeeb44e8fdc0b5bae5775623e1cdc65317fd005456cbfd66c41615b9ac5dca97fd044de8af030aeaa8ba24cba912a5012f16ad3d2c9edfb57eab28506f2eff7ef0f8f08f84a02847ad950a3ee76e3828de8a89ecd284d681236fb167ed23909eff36d4a6d55a62acd53160e277a5718fc4f4e194873c677836088ee3fcec26091263430a0ed4d103f6b8d85cd967843363603bb9940d86a51b3a4b8c8bb215dbbb3cef4da56eeef31f8275bb37eb14acaea32f7a9c33d213ead5f4fe3d95952162b300aa0073608667146afa6455c2632885a7b26a54bc0760b9f831c0b046ee32095371e0b4580306c02ac4724185757b06497c06385765755e1667012b3d8144e37d089cb0404466003c72b2c0f45b812bab993c89b0952c76d7e7f3bfd043b63043aab4235701946b0ea5ec4b385823c4dac89712a800744bf209abd001a683e83860fef0ef68be5aac8c15520a6beea51d4c0f11ea7c989a509532af577378f4aa4d97ba63082cd8b0ba08ef12e449817e170a441b0043a4384d969e3e2211993c7bbbbbb3a649a4847d57c94301ac6eba2a103049d9134273e15716f869dd122aede5ee4100dae68c9aeb8aa1df0f869329489d5bbb65a186cb96e2c481427051c15042fc0feeb982da2657c19ee8ec8bfc843a14b0e7190ff76c568f5be60b095ef38827e0b0a95c792a1cda146b9a8d936d210a2f5a1ad817989af09ec75b30509a94fb5965276fb8ae000d46763edf2107ae264ba896d8b41243dbdd781992ab9c9ad27f7cc7408622d56579a3bc56673efc05dbe98ebab1ee160ddef41f655e7099da7398461eead054287fc2cc7dd4ef5ee1a051b354c142406b0c6ee23092fe62356ac5640d98999a7e64cace1003d9f830cefdf8c6ec0f9cfe3dd9388151f8040b90f5303cefc91e880799956ac0c1f0f27ba1c72f81e19600a089bed807cf94236ad07494607a62ca2fb11749370b0e1120b0287b49c817f8e4fa99c984764f0c370e09456aa4411c8dc3c57c57e06a1dfb79fef349f17df60b213ccb9caaf36d7da8405294c8d97b25c87812f4adaa0a9c4bc7b31adca741943fee5c2e4509f3e85ba497cf379845dd227b043bba276c6bd35c7bfdb0fab3683ab1903a90002f60aa799e0b21224c62e00858789a956be17cdb302e23320e3768a58a47238456cde9f6b9133728b4e1ee01c5b971c10bd819f07cf4f749b434053374d7b8431594639595422a8c2b5a5b58e754558c1a39fc008be08c57aa57fa4f44f24c4b56252863de887a189b1c3e704bc0cc0c56f7db143b3073394ea9fa0d7e2eca6fa94a9c94d94b68458aff26bcbf6d5dfadba6cf7d84b67b62fdcaa33d535da2ac3aacc5fac31c918579a2c0a75b9f65f3ae65b51f9df2682e1043ab729bf281fe9d6694066744eb9a12947081e3625c4392d2bc0ede2ef5baa274b61effde8a7bd659e61bb4d90b0a51d5d5c946089190d3f31510f500043c6a85a61407e1bb2f9469544609d68d9068a28f14619cd4fd902222ef2d823711b1f74082ab141a4ec358637f1d296d7610d325a91bd3d4394c1c017a1b4f30ce43d8355900e19758b69627fc8687f7607116c91566f5c829b539c0b4b308685c684297ae9ab94b01609171f34ec54d136fdf4514e6fcdd024654ab5ddad99f11842b5334a6282f5458c5160ec55dbad9d1b4612e4edaa49b59be3571c13eab01248cdbe5db8b084de890700541c58ce9532f5ad83f2faf8d019e1c7e7b4b786aaba84ff8a251567cf337e2695e87e50b401aafbad48f4731d67955b39a34efd0e219bb57673f1d9821e74e641ad6b339d8792e5a1b3c6a173db3d4f06efce4aee86bd5eb804b37e44ed39b651ccf64a1089f3241939683b960d75c4caa85a65290b83119a5abc52f6814b651fb88c188456e04888596c17f5a6555159d557200736fa9fa3b76fa28a9f8aa7734309c311b95ed03881ddef09b90ef68b1c78623befc13f0560e7f10a5813674ee34f5591076bad027caf7bc50cf00064e02b55f1b30bef7ad0ce49f4b31dcfc1cc4dcf293c6a9398039f4b715c6b30446b0e826e259b9b29e56cc92e1fba4e72acc3a89b6a677d7bf971477006444680d0a0adcb126c4e8e7810d14b30c124bc5e8f9a5dda66054980fa5e5cc21a72aa51033ba2d95c9c1918b1a9169adaf26e188bdab36158af64af0d1fdae6e85391e6b08489c36e10f805705294d10358238725675a8b0970ca1ab5dd6ac3d16720b503524df1402d4d3e2b07abd5a2b808dcb8e2640b32d72c5eabfa02f693ab3c5e02ffeb1e3369b859e754ba61fe7a452714122bba55d91645eb68981f2db955b2fd6cd7a5877e498633426cd6c7fdcd02519782e8ede12938a4c987b2d3f213370c68c4a99b7632ea3e0de17dfc28c7406d74f410f60e029b42db13d01d38fc2dfbb5b947414cda69b64d2e035e6e449222a723924e6e2a682fd36f934387ee2da8d6779b191c584016cf68382663603800726dcb4ed3a29dfb34e19445a1755d2e3f7fcb70ad25829ab41525ce9ef9c12449c9537de18aa41e3a1e3d7295f654d8e3f4442dbce82aea38f46f066f249e58a092737d9f6d3ed392c6673d4a7ee2041d307916b8907855578bd0defb3d8e2eaa8a92854db52d2ee96dfdd1f7b02e0bb6a065c3a72f7a546b665ee7dedbb763f0637b734ffda3d35fa410b199fefd16569d1b53048639b1cc3eef59615485f71ba843e238cbbae7a1f1908a456d66cf742cd2a8adb29002a6145f2a775c8d7701306bec691ae2ee806d1bbed2108ddea74b4a9e59d7b1b75ac72ca371f9a2b9aad01927aa77bc353e8f75ae652973873c3ee16c6ddd3ef9b831e7c413c9cecb14128becca9e5658d42aab9bc0e4e6c6cb0b34ea6ee636e18aa711f07fbb4dcd5a473d322badd8371c7614ec008f27c95e157d0ca681d36fa7b96a59b89dbf83de9be5767284568bf1e676ca18b0968c9f3f3653766d27102ab80cfeac4b7556f4b78dd471e35e4eec9ba546d4ee4025cf12309df9f14717ad0d40843b04f761832ac5631aeb26898b550e8977d6154aaeadd93bf625a52b18f1a89b37bc91bfaca233007619df36ecddfd5fbe90ffbf6d5e8ff6d933d143b25f21d1832cd832fbadf67eadd914c405ebdbe7bf7fbdc8982274ca2c1e1bad8aaf9122683c5b2982a4e2b4290baa0df38e4fec3e7d952b7183bdd0db5d409cba618aeac4e20acadde4f2c6a5ec095aee58451142040dd7c2153d918c98e55f338ec18fa84bb8f935aeb7b5300ea762070a0256733bb60c4113f60a9cc1c88610ae0560ecd1bc1f7d0e62c09b2c3a87e83c6c84c6f54d5d43a6361c92f618f0527783ae8b10c638177a3b8911b58b668cb044f9972f9141bbafd017a4dcd07ddbf77795d9540b48cd2ac3a134d667c5d510f5f896b07793c773513395403c5ae8ddc654c6e97da81c7a0e879e42b840c7f34d47e0ce3b791d7830229e630f6121dd5b492f97f8750a86d260354b746cdbda9d8a3b9ae23fa542864f82544bddfe26455e5fb9e9156f39cc79c77b0bc51bbe826956a2fba58b02215ffbf2a70e7679600b5372966ec854fbf0d8cb94eff874cb01ab2cdd690734ded29385ebcd261b77c1bb6a4f2ee0e69d32fe7c1daf42ff1af222e05711cd1746bda6628c578c6f371fed02e5a6a0b66dad09a84fea20606d9e0587ba4023fe6c6717e0b8382d6b8a4ac37844a60d97cae599985f6311d7cb37d76730e39200532780794549a2792ac187aecac8ce63cbdbcb61cfe4b0265756b08aa891e3b5eaaf065e316e83590c7dd60e05ed28bae11ba1473771f43c2d21d62bca2b4ebafdab3ff50d82672a029b0734e44cfd9682a592a1678e1d5a2bb22c8fcb26d8916c4863696ea1d904f9c6b25429664a8c601c272d5562998801967844345484cec4025634aa3391e94c2474962ef1220c18f288e4b5c64b929ea6acc2b7b5b326c6c619c1a7f0d6d579897e572bb10804cd0b2b71ab9dff9a15a7e29778ca490ff1d154dbf378b7095790b2f1400b78243b12b32e9a6073ad7e4985ac1406790c10b1fed5140df772b4f260315fd56c44f85b0f8788bc3b62c5efe9254dc25681daa88d03e14ec066689ae6317fdfde971f7391f3463e0dad23f03de6d825de172102cb3370593ffd1f79a8feb072400e39de73804e5c54bbb5f4d3101f0905e48ff426acf5e1e90eccbceec74c27177720ffd24d5e7d17521630d98d3de098609b9d2d297e05cc776467fcd18cf2a3439b26e85decec269cf561e92e66d68b974e26ee40fdec1b1859b510dfaa711b1bd398775ecdf5108db38bf8aa7ad37c83c7b7b76fe72b3395fd6d1ccf16757e76f0fc2b33eb6255bd6fce1facc525df868596f96df8701c5d3f1efdbc1e9f9a293807de8a563671609989ecb4a7549d86720846f6b7eb40dc78181fff39fef3cf93b1530558cf17e2c993bba77be47f3db6a1ccbfd33e0651148df1d5ac405841c24e4315f9ce4f435968190f7c5a4c78e09a9ed33028784228aae75dba54d799f832b02724d857ca97f2ac4e7edb58dbccca38af66599d583d3cd7318b9cf29e2ce0de93bf2a24d60a5aba04720cbf8ce5a998474c6cf606f81d3203929feef057927b033ded3d963823087507cf9e8ef9c8679282bddc1435d579fab9e6b52945495d3afa5cc360fc62a0d3d7c889224596e6674f3638b81a468466cb1189192b214a9eb13233cd03dba20730d1152daba8ceab453a676dfe109ea7f4e2639cb9ebe6fcc56e9f6a58f3198fc90525b0c6ea2cc903264251d0b6135870069afd885029bb32b4c5abf9136ba82c126f781315b65690930ee6d84214920945412a1267258d93ab5bb1c7cb6b7efeb6f390564420fcaadab15aa48db5fa310e3aac237069ceff050000ffff010000ffff0f6a742d1e500000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["app.js"] = bs @@ -63,7 +63,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["favicon.png"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffec5deb73dc3692ffeebf02e6def9512772643bd9db924753e548f646b5f1a32cfb725ba97cc09098212290a00150f29cacfddbaf1be07bc81135926c6d920ff69004d0001add8d5f371e9ade3f7c7bf0e19fef5e92d82462766f8a3f44d074b9efb1d423e9d2a759b6efe9551a9a98a74bfb2994a9515208a6f6bde332e5c028e1915050adf73dcc24243df19024a3d1ec1e21d384194ac2982acdccbe979b85ff37af4e888dc97cf629e7a7fbdefffa1f5ff80732c9a8e173c1802cd4c8522875f4729f454bd62897d284ed7ba79c9d65529946d6331e99783f62a73c64be7dd9213ce58653e1eb900ab6ff24d85d2314311d2a9e192ed306adb56c3437b1546b39044f4f8862023806c926cc0de121528a155bec7b0b7a8aaf41068c9cddc302861bc1661513c917727e0e4ffa8d8cd81ba8e9d1e38b8be9c4e5aa2a70c4e6521a6d14cd26a1d693ea2d48781ac017af68875909a663c68c6ba17d27669541270cfb6cb0b04d21642ea31539b78f8464348aa041fe5c1a23933df2dfbbd9e7e745da023aed2f68c2c56a8f783f3271ca0c0f2979c372e6ed90eac30e79a180db3b44d354fb9a29be70242eeed99f5cfc57fc7d556342d592a7be91d91e79127ccf9256de001beb2732953aa321ab4ab5daf29aa542ee90d732a521fc1ec8544b10c81de21dc85c71a6a08967d0c28a4ca70a0ac286d21db154b36866ace81a3543d1594f457e0da72e604086532bcad146cabda915e5a8e2c25caa8829c7bb54a69d7e09b9941d36ef91dde7ed916e7cb164fcefeb01cfa4e6a8117b2853a093a7dd0ab8367e2afd790e46c15455d9cf56e07c1438d7b44e41e898c893b42a13719d090a63c9539075e6cf850c4fca7680683b4d06792ce5a3121cc597b101d1a913e6343c592a99a711d62215347f397ff4f4d95f77c8d3ef76f1bf278f9fb739a868c473bd479e353a5ff2e749f6997c577f2f19f9143e3f2d3f5f74fb056296061105c3d19173c116d0dadd5ad05bdd7bb25b7fb6924f055f22ffb193cf2fe755c9e0d210aff317c782dce7095a4d9a9a1e4d20266eabd919732cfe6e77b7377bb4663d5c279f82ede8a90aacd1c44a074c1213374bdc9b5ad1b7a6f1beef930f32835154c4f7ddb7949e56530c3dc514f783925f3e466c41730133014c51cce6e34b6aedb93373d3885744d07c53609d2ad2d040c280b5ebf0e78aa691379bf26459a6a04a7944ab102dac8f6ffe93a77fb3869db889c77bf614ccbee5987b9ecc4865e7a73aa14294c4621e816efb9fc110b7eb77362f370c6aff02cc82a459ef0461c9cd8a1c654f72d1e847c99dc6a395a5aae37672290b444a66913c4b1ba9904e8b99e72f5e371ff07fb9c4891a25bd786952791971f3209debecf9745ef19e2a9c94a69339fca3ad8aea965715242ccd5badb1ed9d556d72c044f0f00426e7287acf32f9e831506fb2732956598c1330a99efc38c291758c7bc01268e18b2822581c4c9e542b6cda7402358dae1a476654d5d0fd33e658d0a91e490c565cb1869ff20825f70acd63300ec7cc1810413daa8da15c76da5716bf2263f878be7c522164ed561bcb337274782b5cd1716e50c846b54e2e166b4d73c5afc811c5b4a1ca8c149505648f3b15bf7714faea9d4e72d1d0ec466a9d329d00b32c289c8045700676c036bafc68915f71a50d98d6b31d2253b1228073cf52c217246521d39aaad57352b48b9c519522a82dac77411e38c08115f781fe822f8f52348a954101c2b5296e3546f8490436b669af1ae9c0142688fddf2faa6ddbae6e5e1f271c9b6b1a3f6ba758b4edcdca5ebc612c6211cc50cf6615c786c9e2fcd5b553d9ec43cc88eb6faeec5c4462aac99c310008f49445640e9e422a0da121a02b0a063fa8270b92e4c8f2a239465699608266c0f7b336e9603ac9daa27069a3115136e6c0221bb4c9404b9dafe05eaa719a9b94c03f5f27f6a79873490600b098576e47d25d333a0d6dca8960542df867af67acda1f5aaf8d97e2714de2d93217803740403bf2dc92dc921e16ac27118b84c923042988881ed7147aa5fcaf9b84dc47449b798447c8d8a206cef466712f54e3fc1c8b1c60c2237c0a8e0e013fd8b18257468da3098092e0ef4fd06c1cb541767754a9950f720e6856279b45162de0007c1034d3259ec80029a08ffd97567f4b30821f8b8e4177a037ebf43bb0ee321c400a6a875cb1d08edf1762fdf977d4c417179791af958034909da3796ca8c99bbc6f63b6a6b4d23576a2096a0f4557c68bd12965a3c596f650942c2615afd7aa1b63dbba199db30a1a9c81ef0d7e62ff60387fa1598474bcdce25d1bc53344bf3d54908ef316fad230550d2561627cb92d32b40b7e1a2a8d5804886ca8216ac1f8026d374604ca47838d9f0cb7fefa1d5b4881ceaecc58dae9e02b9b729d9e554af32d3b18ca041c862eb4c619355632e5ff6727ca6bf4b2478dbf55579742cebb60f9eff08d8a9617b3555713c0e1e297a297bf064b4bf615174c8345a4e28caef49b3c993375714116f879870c14fa61656ca1394f298ac60fdf8e61b14cbafcfa4986b7c02e8154afc82d5be60e312b14328f7cf46e84a45d4ff92d8056b9b040f566389602d4be22c3b0c81de21746e03a5c7a4d3580ebeb4ad760fe127c146e9565cc7b00646fc13bf366ff647a08610c10b8dfa1f0465e46e0db713b077bcec213d615cca3652a1523ef984ab8d660eaf5edf3dcd58955eaedd9de22729739af63c0e43e156b532c7e8fc8cfdcc45b9a044b59dbf81db264ebb9155286d0212421baec03dd6b78da7eee47f71ec675fafde14cf1044c91371082ab7b37c22306901672d1e13306545ddca74f42fafc822ddce1a6338bd1bb861b6b1970637e6c0ac4c739b05570bfe1b162e983c5129dd65fcad0f8a3c7bfde1db7d575aff457f10d1cb3a2d501b6d6b9ad57432ec491b06b00052dab2bd7741b875a7789f708ccffd3815c7720d7e2582f5e938f868beb79207a05882209e0e76e801e43f589eef4f4e0ddc79beb6998e5302786a04d1d6008af2978628a8abd271717ff794771f261f199bca7866dc909a82405bf1ab1cc2f0f8d34543cfc35e0e93c4319481888797871816f8f06f21ea516267fc0d7a6d83cfed64ccbb31e967dcc6e85613237e33906eecdcdb3acc47b856443935fa4a90420cbdefe83dcdf2739d8af054f074dd668e6e25e8c58aa6e80a7ac8d1c3375ba65a4e7524c5baec5e1b6075b50e721ae0e799b7aefcddeda6d0c6381f35a25114d974c5575dc1fa864b11853cbb7b4a6dda8e3ff30a5b7b7a1a7aef4ef11475ba457829f6f0ea547adbfd8d6daf5971ab40da1596962a6b08ffa2e2dc28c44b3db2cc2747744f4d0e845bddbaec820852294db84d0b7b422b325b4fe1357af47d978da8db2bd8822e8dc76711e372648a12506bfc7c58b0189ff43c0e6b6e28d42cfdd227f6410dde5c5182cdd2d732b90fa8ee12dec3350b8b67efd09bc6e2286593fba38e6a4bd81073fbd544a2addbf4b8d619adb061308962e4d4c6664f72e6e577b230d0fd9b5b6a9356128741c2168a3ff38cc769bf1f9397c0d3ef08481060336647bde8f7b49b207feddc5c55eb9191990da4271964662e5202c16b2acb61a71fb5bd41aa0af7fb75a53a8edbe312708e3768176f1c7db7f7cddcd692d99aeb66a561be5f1f30ff6e8ceb8fdf3e506bee2151ac9a2e2ec4f1332df5b17f4b50df443dbcedb3bcd1ba6a7c862415d616ff030d8de04baa843992bcd82ea005a903233f166c77986a709c884bc922a4fd6b7c08eaa42431d4b6ee27c1e00e89a845424f1a4aa6aa2180c98c695899f40cab521efdd872d6bdbd0a110e82fa55a4d2219e608fe8a030b87cdd7dbe924d73ac72efe90f7ede9be811a60b0a0cb2123073dbbda37ef46b60b4fe0134a75e22c11496404c0a114e7cab37279acfe56faefb22e68c47ae4d626fa11a7422e7b2db8cb501cef1bb0e22e0f5a66d03c2a18c8a3fdbf8c44b5143cfeae5daccf0dbfd4ecb0cf90985869f0355fa6fd9ef24185c0dcdcd6b233f1770366a6af6f6bd3c4346b57556f52d60cec20ee4e9e3382807e87c07061008311ae0925999200591272068242562011e40878ab60e8488d188316f1f7002c5740fb41cc84e0d9f3563fb2d1d6b26536ddc65cbb9bd86eadee95275565b80bd2c4d385bc0559eaeeb4eeb0bee4c057111e90909ae7017967cd2c89a5886e7aeccbc31a03235f1e05b90be35e06cd6f7ee89b6758da235272070f5f0b66d85719fdfa2c04546f8d477053c37d743830d03cfab4c554e188f9e26646fb1646b67376aa55d86ee138022867f88287ee18ca8324a23a7ede0cabd65b28da91d56b8f7f23cb192835c1ff1092774e76db575ceb5d83fbe7e7c90a06f40b09e33c3dc1d8e9461f028f6b166e1c96ab46dbd176a7650964f201b924f3948283ea4e747e5293f5aabcc9153adfe3ad8c3a4e53792636e40e6811f7af1544471d9e49e4697773eb81900859bbcec95535c94a0ffafe8328ac0c0cdc39b50221c0636afbde7d6c22589c979fc1a35d9bdd4b8dab4f603605be436a14258c70f490da4277165225c581667cf48a6b2850695fda31d9b03e8405cadd56d6e3b55fcf1f82d9f52daa7e88a7c14b42416a6375c17ff0f4940a1e91070ffa5223aecc6a7d99672ae89cc1984be51a076a377376e710603fa6ad95e0698687df8a45db35bed61d45152ed7511aea6cbb575c49d2b1255ee3a20bdb77bb79182c40ae70310b1b568426f1b68c4f39572c02e5b12dea5d7529a3420383bfc1acd968ea5ab54d03d31bbb9b66256dc04199b3597d2b3dcdada43da3e546f2cb97be91cc94ed05b4104f29a66eb010c85b33492c820f813ae0fa05dea58061213c78e859e99e91e2642ed82ca7cbd225dbc54b4b2e20c7c8017002a0304e37f80844a5bd65052cc4236eb7bd468f83b58e35ba36a0c2b39f63400eeebe017033f0382456ba434e18cbb0ad09876a4d4c0d99b26486b39bcd309dc09b3b5a093d83f22c6a375d73e0849132185e101cf87ec960589d0b4a79dba45fed218141c023a2d0dab9a0e9c940bb3aa1b5fe406abf75d8a8cc14f71e2240d8acc79980a18eed29a27def4799941b4d0ad5452a7d8a3b4a53a9dbfed8af9ebd8a72ec4e27a7dac0cc8067150a5b54ca702872bb395fdb25b1eec9d99be21d756b93186579513e5e818bd10ad8c643cb16800418f98ffa6c18d9df270ee820abeb4ab7e577d5d663a3aec8f797d674e04226259a6554e191e6bebb2d6af3c8b33d8ce895bb5babe663186163c1823d6541305c195376bea4b991182c09898dbb8114ae500670e00bf223467c3a415a5f01fb554b2e8d8b09e8292bae4d680f7ec36094f3f43641eb63a0df17b6be6b58b56e51ff048c36b49c188e99587897b4dc86e7dc61753c8fdd64396801b8bda3efaa80c925ef6e7d3db424ae8fb8f194c0e5881b73fd1e1077f37cd48de0ee21823787bef104c78da0ef9a50808f1df4dd933a027dbbac788d45ebc8f2460c5ef50a2791f61c542c44e88e215a1b8ef2e8f90040bf64de79ef8ef5d5689ce429ff94e3c6a54c5e6d0ada0ccb7a785a61e49eb41a231fe33d00d04b1745012bb270616e52dd4db00ac8eb0255e2770d4c4560e9ee7b7270c36ea11bc6959734d4e147c718abfd1625aae63857b8d6e5ba66554da83a248c7d8db875c03a56a1f0de864d2ae5d2472a15666ea9157e18ab58b6705bb5fe3539ac95ab541f976f4b05aa8ee08ff06aafaf3b8e7943dae3526bfdc177c4686d95293d2f7bfc1971233495a980fccc416b407e42c52c82e40bc23142ccb4bd2d87a1d909084a9ee1c04d7bbb280d51c5a618079dfd6b3ab1bfa5039be30e468acb51d5fd9ca8bf2e7375dcc4d24287dc7ede4a795cb72f559f86e0ad2950869cfafa3e5f73711f0fd7cee5e73e81e815f786c83b29ad280c486a7dccb8795b8e3b31dde36ff7ebd8f8b8893b5b8eb1874c01480f51a4164a2628370009354900cda02cd6c10bbd63ef66ea662843092e8a603df4b34256351e53aa245c9bd2e5288cff8d3a995f75b05a8793c9fa19eb5b1a3074e78a2ac89c1b377e45c4889c61f0474879825e00aa72315001f9a8ed40bd7af1c1dd1d6055fbd65cfce204abdde934d4edbec1eaeefcbf64dbff0d8ea6062f0515c05664376a96bb34bdb5b3a57d5becaf3fb8c7b605ee12336c042a8d3dfd4d6c90ae610a71cfc016ae7a1db41d8a1db6e8ad0712eb26f48513b1e12d748dcbd8768641ede70d63ce6de796cc5a95b93de49016201027af9515e91097bcc178e055bba7cc064b2d8a4ba8096398ea605e13abaa34c2494761780dec6b872a8a4b37db1e4263c6fb3354811ed2354313a36f36bdcdd0447909e8d02e8a22f9cec525fa8205a4bed1f486c304c3b34a73df705f7acf050a7dd93aae50399114ec476b558d44ef7cd158d22a3206289d18487e880ec64304f46b29a93d7afd70e8ec4f635604445d14e6119e09abdfed35fb08b10727b36a3a4381ea10dae418d559f1bd385c57ce7ff69ecc00f70a4286b7993ba45093fe7530ccdd23110323d79c767b193b97526c665e7f1aee7fe8b06f138b36a0806b716170e6dfc0a27e50d0fbf136946099f3e3dbd383deb40c9a060c8efefdb5e4ef1f8ffee01a72150edca676dcb9a5a92bdd24fe6f8be84663237c747f3cc66d230328875706db3fc8f29b43623675d6cdf8dba79ca995ff34d80d9e5d9ebbfebb2fbf75ffeccbc67234cb3a19a0aff68019001ffbd77ffe1f0000ffff010000ffff6d99018d0e680000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec5deb73dbb696ff9ebf02e1ddcd63d6a49ca4b77bc7913593dae9ada7cd63e264bb9d4e3f402424a226090600ed681ddfbf7dcf01f87e48b42c27be6d3fb41609e000382ffcce01c04cef1fbf397affcbdb9724d47134bb37c53f24a2c9f2d061894392a54bd3f4d051abc4d7214f96e6952f122d45143179e89c1625475a460ef123aad4a183952241cf1c24c96830bb47c834669a123fa452317de8647ae1fec3a90a42ad53977dccf8f9a1f3bfee8717ee918853aaf93c6240167a6409b43a7979c88225abb54b68cc0e9d73ce2e522175adea050f747818b073ee33d73cec119e70cd69e42a9f46ecf089b7df211430e54b9e6a2e921aad4e359ae950c84e8d88276744b2083806c5dacf34e13e520a255b1c3a0b7a8e8f5e0a8c9cddc3069aeb88cd4a2692cfe4f2127ea9d72260afa1a7478fafaea6135babecc0129b0ba19596349df84a4dca272fe689076f9c7c1c7a15311532a6ed08cd33d1ab1426a1d9278d8d4d09217311acc8a5f949484a830006e4ce85d6223e20ffbd9f7e7a9e972d60d2ee82c63c5a1d10e707169d33cd7d4a5eb38c397ba47cb1475e48e0f61e513451ae62922f2c89ab7be64f16fd57f8f7b2c798ca254f5c2dd203f2c4fb3b8b1b753d1cac1b8b44a894faac6cd518cb2b9644628fbc1209f5e1ef9148940085dc23ce91c8246712867801232cc9b4baa0a06ca8dd014b140b66daa8ae9633549d6e29f26bb8740102192e2d29076b29f796969483920b732103262def1291b4e61589a568b1f980ec3f6f4abaf6c69071ff5e093c158aa3451ca04e814d9eb73be04abb8970e71938055d76655e1b857351e1ecd05a0d6162511627659b80ab34a2204b9e80ae33771e09ffac1807a8b6b564d0c7423f4ac5917c196a509daa604efdb3a5145912602f42c2f097f3474f9f7dbb479e7eb38fff7bf2f879938392063c5307e4596df2057f9ea49fc837d5fb82914fe1f5d3e2f5557b5ea066891750701c2d3d8fd80246bb5f297a637a4ff6abd746f369c497c87f9ce4f3cdbc2a185c38e22e7f5116e43e8fd16bd244f75802d161d3cc2e9865f137fbfbbdd5838ef7b0937c0abea3a72bf04613a31db0484cec2a716f6a54dfb8c6fbae4bde8b14a42889ebda77093d2f97187a8e25f60f6a7ef133600b9a45b012c012c54c3dbea4c69f5b37370d784904dd3705d6c9bc0c1d2408acd9873b9734099cd994c7cba2044dca214afae8615d7c729f3cfd8771ecc42e3cceb3a7e0f60dc7ecefc98c947e7eaa621a4505b1900760dbee2770c4cdfeadcfcb3483de3f03b3a068d6bb401872b3bc4631932caacda3e04eeda7d1a572e26671291a0452a481b8486aa5504ef395e76f4ebb1ef07fb9c4851a353d7fa853791970fd2099abf4f9745ef29e4a5c94a69339fc471b1d55232f3b885992354663c63b2bc7648149c4fd33589c83e01d4bc5a3c740bdcece65b44a435c8049f9cb0d0394ac65dc0316c3085f0401c1e6e0f2845ce1d0a613e86974d72899515dc3f42f986541ab7b2431d871c91a7ece03d4dc6b0c8f811c4e99d6a0826ad4187db16c8daf687e4dc6f0f17cf9287da8daee361417e4e4f856b8a2c24ca3928d1a9d582c3a43b3cdafc911c994a6528f549505540f5b1dbfb314fafa9d4eb2a866d9b5d2aa643a0166195038018f601dec806fb4f5d1237fcfa5d2e05a2ff68848a215019c7b9110be2009f3995254ae9e937c5ce482ca04416deebd73f2c0010eacb80ff4177c7992a0532c1d0a10ae5c716330911b07e063ebfeaa560e4c611131ff77f36e9bbeab5dd7c505c7d49a86cf9a25066d3bb36216af190b58002bd4b359c9b161b2b87eb5fd543a7b1f3262e79b49b31691902a32670c00023d67019943a490084da80fe88a82c3f7aac582c419b23c1f8e16652558a019f0fda249da9b4ed2a62a6c1c3422cada1a985783316918a98d15ec4329a7b94e08fce7aad8fcc9d75c920200ccd795dbd1743b8cd640eb7a12312a17fc93d323abe68bc663ed21ffd9d178b6cc22c01ba0a02d7d6e686e410f1b568b8841c2e411821444448f2b0abd5afeed3a257711d1a60ee1013236ef8133b55edd73d3b8bcc4264758f0087f7927c7801f8cace091516d6902a024f8f72718364a6d90dd2d536ad4839a0396d5aa6690450338001f229aaa024fa4801430c6fe5b63be0518c197f9c4603a309b2efd16acdb8403484eed984be61bf97d26269e7f4b757875b5897c6504a486ec2ccd534d7556e77d13b3d5b59576d8892ea8298ab68ee7d22974a3c196a6280a169392d79deec6f8b676451bac8205a7107b439cd82f0c1b2fd49b9056949b3f2b2d798ae8b7870ad2b1d1425f1996caa1222c0c37fb224ddbe0a766d2884580c89a1e82068ccfd1764d22d03e181cfc6478f4379fd8424418ec8a9425ad097e6f4a6e32b3d268bee6047d1143c0d086d6b8a2865224fcffcc42798359f698f1d79aea3212f33658fe27bca351238ad96aaa31e0f0e8d77c96bf794b43f67b1e31051e91461774a55e67f19cc9ab2bb2c0d77b64a0d1772b6d1acd79425135befb7a0c0b45dce6d74fc2bf05764548f59adc326dee10b3fc4864818bd14d24683b527e03a0552c0c50dd0dc71280dad7641836b943fcc20c5c8b4bafa802707d53ed1aac5f808f3cac328c790780ec0d4467ceec17a68610c60081fb2d0aafc526025f8fdb19f873e69fb1b6629e2c13211979cb64cc950257af6e9fe7b64fec526dcff60691bbcc791502267769d45962f17d407ee63adcd22518cacae4ef90255bafad5032840ea108d1651fe8eee069f3ba1fdd3b98d7e98f8753c9637045ce400aae9add888818409acfa3169f31a16af33e7d1ad217176c110ed78359ccded5c258c3809dc5b109101f17c096c9fd5ac48aad8f164b0c5a7f2d52e38f1eff7677c2563bbd225ec52708ccf2517b385a1bb65e0fb9104bc2ec01e4b48caddc306c1c1add86e81198ff5700d90d203b79ac17afc807cda39b45206a058822f6e0cfdd003d9aaa33d59ae9d1db0fbb9ba99f66b026fa604d2d60088f0944629246074faeaefef38ee2e4e3fc35794735db9213d04902713562995f1f6aa169f4f0378f27f314752066a0e6fed5153e3d1aa87b921898fc1e1feb6af3f86b332d4b7b58f621bd1586894c8fe7188437bb675981f772cd8621bf4812014096bdf991dc3f2419f8af054f065dd668e6e2598c50c87682a7e88d9c3279be65a66723a62df6e2f0d88369a8321f77879c75b377666fcc3186b1c0b9d34940932593651ff7073a592cc6f4f235bd693bebf83f4caaed7de8b96dfd47c4d106e915e0e7ab43e951fb2f66b466ffa5026d436856e890499ca3ba4b9b3023d1ec369b30ed13113d347a51efb63b3248214fe5d621f42dedc86c09adffc2d5dd2c1b4fda59b617410093db2ecf636582141a6af047dcbc18d0f83f056c6e1ade28f4dc6ef26706d16d5e8cc1d2ed36b702a9ef18dec23903851bdbd75fc06b1739cceaa7cd634e9a0778f0d54b298554fda7d41896d963305ec492a50ec98cecdfc5e36aaf85e63ebbd131b53a0c85892304adcd1fc56c8e195f5ec25bef3d8f195830604376e0fc7010c70710df5d5d1d14879101a92d24674910ad2c84c54686d5c6226eff885a0df4f59f56ab2bb53937661561dc29d036fe78f3e3973d9cd6d0e9f2a86679501e5f7f67aeee8c3b3f5f1ce0cb1f61902cc8effed421f3bdaea2770ed00f1d3b6f9e34afb99ebc8a0175b9bfc1cb60071398a2f2452615f3ca0b685ec2f4c4999d6629de262013f2bd9059dc3d023baa0b057d2cb90eb3b907a06be2d3280e27655713c940600a77267e022d579abcb32fb6ec6dcd847ca0bf14723509849f21f8cb2f2c1cd71f6f67925ca90ca7f85dd677a67b073d80b060ca3e23473da7dad79f46361b4f10130a79663d11894500c0a150e732b2b2758cfd96f66fab2e68c07af4d614ba01a79158f67a705b21bfde37e0c56d1df4cc60793462a08fe6ff4526aa61e0e137cd667d61f846b7c33e41616cb4c1557c99f447ca472502b36b5bc3cf84df0cb899beb975968969daecaa3aa4ac18f8413c9d3c670401fd1e017161028311ae0825a91400596272018a4256a011e404782b4174a4428c5e83f83b00962ba0fd206451c4d3e78d79a4a3bd65c36dda83b9e634b1395addab4fb2ac7017b489270b710bbad43e69dd627dc1812fa23ca02115cf3df2d6b859128a28d8b5ec8bcb1a03922fae82dc05b91749f3dd8bbe7e87a52991823b78f93a629a7d11e9577721a07be33cbc5d89fbe47840d03cf8b8c5526189b9d16ea47d0b926ddd9d6a343647384e00ca69bee0bebd86f2200ea80a9fd7d3aad5118a6666f5c6f2af55b900a326f83f84e4ad9bdde611f77a3b70fff2325e81403f133fcc9233cc9dae8d21f0ba661ec661bb52da96b6bd2d4ba0920bc8259e271402547ba3f3a39c74bb7226d7987c4fb432ea3a4d199998943ba0453cbf96131d75792616e7edc3ad479140c8da0e4eae6b49467b30f61f44614562e0ce991528015e533b74eee310c1e3bcfc04116d67752f2caeba815957f816a9519430c3d1436a0bdb590819e7179af1a7937f86028df6a591c99afd216c509cb63211af797bf910dcae6b50f543bc0d5e10f21293abf3fe8327e734e20179f0a0af34e052afbadb3cd388ce19c85c483b3830bb99f53bc700fbb1acd38227295e7ecb376d3b7cad268a265ceca3d4ccd94c2fff2449cb9738b50f5d98b99bc3c3e00132899b5938b03c35895fcbf89871c902301e33a2de5d97222b3420fc356ecd64533bddd61d4c6fee6e9a16b40107a5d667f5edf4d48f92f648cb4af2f3e73e49a6d2cc024688b714132b2c04f2c64d1283e07da00eb87e81df52c0b4105e3c748c76cf487e33177c96b565618bcde6a521e79153e4000401d018971bfc094485f9ca0a788847dc1c7b0d1e7b9d89d5a63660c2b39f43400ef67b031066e07548ec748f9c3196e258630eddea906a3265f10c573753613a81277bb5126606ed59d01cbae2c0092d8437bc2138f07e83308ccd7985beadb3afa6484008784514463b8f68723630ae566aad3f91daef1dd61a33c5b3870810d6db711a81a843738be8d0f941c4c54193dc74914a9fe18eb2546a8f3ff69b67afa19cdadbc989d2b032e05d85dc17153aec4799399cafcc9658fbe6ecae7847edde2466595e143fafc1c560056ce3be610b4002ccfc077d3e8c1c1e120b7490d555a7dbf2bb1ceba996d7e4fb4be33a70239312c5522af14a73dfb72d2af7c8d303cce815a75bcbe1631a616dc39c3d4543705c299366bda49916982cf189c9bb8116ae500750f039f911129f4e90d617c07ee5964bedc304f49ce59f4d680abfe6308a757a9ba4f529d0ef4b5bdf35ac5a8da87f01461f5a2c0ca72c5a381b466ed273f6b23adec7aeb31cac00c2ded1dfaa80c5256b1f7d3d36246e8eb8f196c066c48db5fe0888bb7e3f6a27b87b88e0eed037dee0d888beeb5b847de57d5b857df5c6a0f86a401efe6ca1f89ed201146ffaae2d60b63a7e12a371fdb97705336d734c5f720917a5e69a966f6ca89663eb88b7b8ca3e00f837ac63efec35c10add932ce11f333c08958aa125cdcc601cee3655db57c15a3c2eb1774f5985bd4ff1fb02305b9b9d01efb4b0e973527ef360e59157395ac5f70a988b80d57e47cac21873346f10af8e19acc5a69649c6b318042aeb722f31b3adb583eeea50784849fb06320e109b71b49779fbb2ffb0c4cd8c0ebf11b1ceec6cf9350c0f1b344c0f5f5cc7f80c81a6f9fd6b725c19606162b6de9646565efbdf1c499b41eec6be2c33872ccc96563686cf880f9b6655447de6ea3562561832931ef9998365816ef99219f4ca178463769a29f3a51e862eca23a8959a0357cd974da98f6638c51cecec5fd389f95b04cf199e9ea4b815567e1b146ddc562eafba185a980c30afb7362e3bf58de65553c68e81a5c8addb30b131277bb65a43bf1dbf84f6cea04e11ef15cfc5a7219d1cb43e536a2dd01a4d4969c070aa9bd6f50f06d94be3fd7daf31fd7e8f36646ef6aa3da6625209318b8f5abe902246550684ac480ce00ecda3cae5a83df3a9aa768522b362932a266171919b8fc25b5ba5d1295d4460f99ad58dc0d64ce4ce0bb3717f9b74afa17f018162f49b7747e65c5bf9e609367281b9b24888330c9ad0fbe482f4c8076504f9fd8bf7f6530bc61bf5c4c76b46751de9b4d2c4ca668987b2226dea0d31d42f4e6cb835d1ec7e27125710eca1e1980ecd79d7e2b0abd3b9a2db7f5361970a706a4663bf0b870342c33317ea89c97bd6bc3b1ec3b88674fb5ffe415cb0e2b8d98dc6939ffc357965726a5e13635455c117f3c9981e09508078c4123394710acff96d2e859a4e73f0e0295dbc2e3087fdc293b577903a62bf00336936bd1190f98a5427d076848e11866c64eb18186d1bfec8583a04a4eb354642e9aa8933c3ff17225deb73ea50ba46c01e15a93daf01cd89b9a8bc5ef52c9112a7c53c39749e0ca65c8795e75a30b1cec33e045d2f6fed11d9bbd7b0908396551a09aa8a7b2e7bb8029945642bf45aef762d7eede8407b70e5c0ca4d9ea21037a2c623dbeb8c1544b77998bf88cc8ec96c51514df0b81300a3841563de12676f01b4dbe9ed6aa37368bfad41afbbf956ad317d5b70b83235b24878f4cb44460811792d00e166f55a32033de7e6626092273830e85a191fe9e331314098f879fa7366e46a181b53ed8710a2413c16adcad6982ab114ee0d72e44ba7f7f30f5537b36035f5f92bbd8f8bc60dd3f9a3bf067e9be9fce2c3d943270ff3e23b97cbef4bb093ea2be03b4ead7fc924403d7ac8d98fdeaa94c420422dbe62602b7aa89db8f9fa1013640f7119ed94d885e7e15a2c6b71cae565d19807788fba7a36ff340da686d620df1cb1a042b508adc32855557cce2fa41768c57c5bdac3f3f550e14d6a2ff655a47f5b8f5306d1ef5038d7cbd8b910d17ae60d05021df6ad63d19a70e1465cd82640f85261d880112c337e7a7b76d05b96c2d080c1c1bfbf95fcf3c3c99fdc42aec381dbb48e3b779ce35afffac6bf2da21b8d8df0a7fd07d7ecd16b8072f8997df38f98fd6e9198299db52bfefe316372e53ef5f6bd679b6b57ff56daefed7f2a6d6d3b9aa6ad0a305773291b808ff917f3fe1f0000ffff010000ffffcff949c3426f0000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["index.html"] = bs diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 1f626fb0..83669f45 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -24,6 +24,7 @@ import ( "github.com/calmh/syncthing/discover" "github.com/calmh/syncthing/logger" "github.com/calmh/syncthing/model" + "github.com/calmh/syncthing/osutil" "github.com/calmh/syncthing/protocol" "github.com/calmh/syncthing/upnp" "github.com/juju/ratelimit" @@ -498,7 +499,7 @@ func saveConfigLoop(cfgFile string) { continue } - err = model.Rename(cfgFile+".tmp", cfgFile) + err = osutil.Rename(cfgFile+".tmp", cfgFile) if err != nil { l.Warnln(err) } diff --git a/config/config.go b/config/config.go index 18acd270..1698650d 100644 --- a/config/config.go +++ b/config/config.go @@ -27,13 +27,56 @@ type Configuration struct { } type RepositoryConfiguration struct { - ID string `xml:"id,attr"` - Directory string `xml:"directory,attr"` - Nodes []NodeConfiguration `xml:"node"` - ReadOnly bool `xml:"ro,attr"` - IgnorePerms bool `xml:"ignorePerms,attr"` - Invalid string `xml:"-"` // Set at runtime when there is an error, not saved - nodeIDs []string + ID string `xml:"id,attr"` + Directory string `xml:"directory,attr"` + Nodes []NodeConfiguration `xml:"node"` + ReadOnly bool `xml:"ro,attr"` + IgnorePerms bool `xml:"ignorePerms,attr"` + Invalid string `xml:"-"` // Set at runtime when there is an error, not saved + Versioning VersioningConfiguration `xml:"versioning"` + + nodeIDs []string +} + +type VersioningConfiguration struct { + Type string `xml:"type,attr"` + Params map[string]string +} + +type InternalVersioningConfiguration struct { + Type string `xml:"type,attr,omitempty"` + Params []InternalParam `xml:"param"` +} + +type InternalParam struct { + Key string `xml:"key,attr"` + Val string `xml:"val,attr"` +} + +func (c *VersioningConfiguration) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + var tmp InternalVersioningConfiguration + tmp.Type = c.Type + for k, v := range c.Params { + tmp.Params = append(tmp.Params, InternalParam{k, v}) + } + + return e.EncodeElement(tmp, start) + +} + +func (c *VersioningConfiguration) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var tmp InternalVersioningConfiguration + err := d.DecodeElement(&tmp, &start) + if err != nil { + return err + } + + c.Type = tmp.Type + c.Params = make(map[string]string, len(tmp.Params)) + for _, p := range tmp.Params { + c.Params[p.Key] = p.Val + } + return nil } func (r *RepositoryConfiguration) NodeIDs() []string { diff --git a/gui/app.js b/gui/app.js index 5ea7694d..ba046244 100644 --- a/gui/app.js +++ b/gui/app.js @@ -405,10 +405,16 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) { } $scope.editRepo = function (nodeCfg) { - $scope.currentRepo = $.extend({selectedNodes: {}}, nodeCfg); + $scope.currentRepo = angular.copy(nodeCfg); + $scope.currentRepo.selectedNodes = {}; $scope.currentRepo.Nodes.forEach(function (n) { $scope.currentRepo.selectedNodes[n.NodeID] = true; }); + if ($scope.currentRepo.Versioning && $scope.currentRepo.Versioning.Type === "simple") { + $scope.currentRepo.simpleFileVersioning = true; + $scope.currentRepo.simpleKeep = +$scope.currentRepo.Versioning.Params.keep; + } + $scope.currentRepo.simpleKeep = $scope.currentRepo.simpleKeep || 5; $scope.editingExisting = true; $scope.repoEditor.$setPristine(); $('#editRepo').modal({backdrop: 'static', keyboard: true}); @@ -436,6 +442,19 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) { } delete repoCfg.selectedNodes; + if (repoCfg.simpleFileVersioning) { + repoCfg.Versioning = { + 'Type': 'simple', + 'Params': { + 'keep': '' + repoCfg.simpleKeep, + } + }; + delete repoCfg.simpleFileVersioning; + delete repoCfg.simpleKeep; + } else { + delete repoCfg.Versioning; + } + $scope.repos[repoCfg.ID] = repoCfg; $scope.config.Repositories = repoList($scope.repos); diff --git a/gui/index.html b/gui/index.html index e7e0e831..bf782dfc 100644 --- a/gui/index.html +++ b/gui/index.html @@ -455,47 +455,75 @@