From 2b3359dff3a75d3d520d6c1dc7a11717cbba5916 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 22 Aug 2014 00:41:17 +0200 Subject: [PATCH] add staggered versioner --- auto/gui.files.go | 4 +- gui/app.js | 34 ++++- gui/index.html | 44 +++++- versioner/simple.go | 12 +- versioner/staggered.go | 313 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 395 insertions(+), 12 deletions(-) create mode 100644 versioner/staggered.go diff --git a/auto/gui.files.go b/auto/gui.files.go index 80cf85b5..45b74f21 100644 --- a/auto/gui.files.go +++ b/auto/gui.files.go @@ -28,7 +28,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["angular.min.js"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffec7d7b73db4692f8fffa1413febc016953a06c6753fbb34ce712d9ded3c6b15d969dbd2a457b059243111108307848e6d9faeed7dd3300e60942b292ddad3a566249404f4f4f4f4fbfa6673899b0a36cb3cde3f355c9864723f6e8e0e137ec6fd14536633f64f9398bd20540a4651ecfaa32cb0b362c3867e58ab3a337afdfbf3bfee1c3fb37ef4ed8324ef828dc0374df2709237405cb79c1f34bbe08d98782b36c09cde282155995cf399b670bcee0cff3ec92e7295fb0d9163a633f1dbfdf2fca6dc2115712cf795a607751c9e6f076c6d932ab80a438251a5e1d1fbd787df282ba0ff7f626f77f2d92382dd92ccfaea0ef27accc2b3e86bed2324e2b5effbd49aa02ff177fb3fb1368799e64b32861f79eb06594140014a5e75512e5f26f04da0b2af8a5005ecccbe0706fef32ca59b14de730acf49c4deb16e13a5b54091f06cdbb60cc4e834d54cca36493f3f9aa0ccb3c4a8b242a7970363a2444559ecc22403f6501f08df037ed4318c0323e1f2e2b781067291bde5b95e5e66d9e5dc60b9e8fd9bd065ffd6cc43eed31f86880e1822fa32a298bf063912fff9347f0ec75b4a64eff6bffe8e4ddcbfdf7d9054fa1f31d6d8fb2ec22e6755bada5686a111402ef4ecaa88ce72f61b28a5719763e1444e20718b38c3f3e6141026cdc0fc6cd8ba25a8a17e1af459606f4fc1a9886ffeb2c2af32c490069f0e292a7e5519927c0788567c53cdbc0c4d2b01afed0c330898a925ac170d22a490403705eb214240a474962d03ec716c7cfe1f9413de4e1559c2eb2ab5138839fc360c69759ceab3481912a740ceb9ef1e3424ee3aa7b29aaf99c17c5cb14619a912ca23252d1c44b36fc4ae0521f2be3bbc7d771390c3e1cbf21a86074a8413574e07a685f5def695dc8213f6307662f485008c37d11cd578a9472e4a8098b1f98ac2283259b64e7c301410dc68c7e86f1a2feaddce26c89df69c487161e6d74562ba3c1b5f2f7f5613b3487086077a734a884a7e7e58aedb387676deb66eecda640bd82b8e0e5fb78cdb3aa5478624d104a6378cecb61ad011eb06042f417df15713ae7d3001e892e475ad3504ac7b09112e33dcff32c1fd2bff04e19fd98fdf9e0403eb856c44d82ee14b69eb2b65c760a9b22f444c81d322e898186e9c3e0ee18f6f0c0e2d80d29e8eaddeab943bb9dd44fbb359c6a15e0f7249b470855b311a71b74eee573782db458fd1406f4e6474d17e053344a515e0a4b27674ed5a0f36cbd4938d131659fae0ff57768be7ccf8f531c91d661fb3ee534b6c26e4cbcc2e7a767da73b0be3cb1c1d75b5ab141a03d4d01d8816393676536cf92a3151823f04d3459953039df647909ec8beccec4bbb7c0de985f795b3b0605ce55fa020766935a6dce73b099c7e93293eddc42f8603041133a1835f2d60a08be28d485044ed64bb056e44c2de3bc28198254d139af5dac2486871b61c4c949c38760cbf3a0a8dd2c151bb96ae0d645d2a0a3db17b548af385b45979c4597519c44333001ecbd683166039e0e545405ea62d9a1ec895dc5e05eaea372be2270068c829ffb1f4ec07e5cadc0b16083ff59edbffffb8020556ca211e89e6d0382be6d9a95f4f7d1eb41d86a6e61e0d3f3b1680642dfea0230736c8800312d1bf8f194600b692be0c98307a6b242000027b8d3f84c5788751f00701925f1e21561039fb684e5ae4c9ecb92e6bcacf29410d7b6ead9943d625f7fcd921066967f7cb3a4691fb169b3caebcfb5a19951b5d7c428d81eba3a6e950b7a764db3d38333879d9ee53cba30fa36f4fef5485327f7c0531a344a4bacc31321cf0355e5a9a4d5b38686b96e092b2acac1291985f8e6d0f067902d8655d1874520a6896a3cb45a8970bef8be55530d7490af03f05b9ff3447167e1e122cee573b0ae713e52dfa2cac797a812d5e76556cd57f8e2c36681618378756d92713cf71091f335045a4e3aec573511e0cd4af7d5410838243c8f8b8b861473fa5a6f539d30328f105de51aeb5587d0e9a54abc710aae85f2d865959a26c3e0ffa5bcbccaf20b52a9c1086d43940c8315e8320d3940b698bae18a5555225fdc50a668d47c909ed0cd1961bb50e4ecb7d45a02ec1bf54e31265a3144e3d2ecf5201797dc42984078436eba4ea96a9485478d96efcce33a9a6061510af7841e9559af21bc82a59f1ca3ea136be58bc701860cf8bd7a07140d1bda468aa30fe64574c5142f0849af0a321711182de1699079042358aca29c8b7c0822036b55ae4253d8c94750b9f11a7138e22cc47db4b44441d27dd4d0540312a2e3e763a68ea6e16c9728bf035d51f23f82b9fe4110148ec4a6df49330ef6795c4867b217c520851c66d376434feb0140a477b6a3cfa31b74488b7a47779e35e303d7ac40d34f3adb144fd8c1d87a03c196efd571fac3b6e4c5fbac8c1227c09baadc01f1fd6201b308e81b0a2378a2c35d1fba87574ffceed1fd7729088058cd8bba43711c5138429929c79c99d3a5c530e19b0dcd40f8e1ddf7e0a46c4a0c1aa676a20434c5f112dc67f485459080a66b15812f0d9e3f4b39e8017073a31a470ada63c1e7680316631313e891ab087ce432635171d138e6f8f73aba00279bcd57593c071ffb878ab4ce224b8392da98a8a0c9ac3a47146bb6a872240a4d6d1c25188c57104c1619e92d5e225acafe91d2b210011125c4ee22dd5b07159771119721fbfb8aa732992b3080fadb6096d82628924109e102b07546fa324a31019cb315fc0341c6793646aae4e84d1cbf556025d107dcd3dea03a22b27e46aad0b864f36a8dd91b41152a94249af3e164f8dd13f8ef1f9fc3fb87bf14f7476d23f8eb9729fc333cfdc7e1d9fd5178ffdee8f33fe0df094431f71e0e1c6ef5576d6397376d9000440dda06d3017bc0304e07ad77051eef0336385c471ff74188e8d5e383fb8fbeb9fff8db03d3bd671c33d70e2d00043d5058f054c5becf04aefb94f1b01be3079d8ccae95a347df772f6c932f059062b8d2f5ec2bf851ada360b50b511a4ed0de372c1b7c831050cd9829086dba4f7750aed2cadea004111914f3bf251c417674688bc9aef901c4ae5f114f73e3ebc3b469b96a530eb6250ae80dd4cbe699da93e133908d251b267033f5ace5565d59838258ca96b26cd34aac8858d295d6339951e16d62272ed9ed9932d04136b8da56e56160418f465959efb21db81bf3b0d8d40ed64a18b7582e481c5b6ebee911ace98e0bd695af00d988fa94abfeddc61e0af70bf6345b49de2ba20ecff42cba3b5f0df2169b446248dc1d777be6a744fabf12db0436bb00e29319b28293cf373ddb56a4d3cda0256de1eee39b1e01c83b38319a8319bd39ec5819b8a265d355f6f30a7778ba123cbb0354ae440f858832e78fcd45bae6ea2fcecc10f0eecc1d4cb2920e5cc8f1699018d1fdec19c8462ac9899068a2688da331d2e05a12cba316bd7fad83b03ff1cd57bd4840f18fa173d74b01270f456c42880e05e002b5b4f43f7674bccb20f1166bfd9971801d369c0ba3bb5306641d9c680f63acb48fc632a18f06905a1fa70d9811ffee62a7d9bc3f4e4e5169a8d7c62ee176f5bc2ca7cebc142db8c10cc84149601f93f45e52a04d76e0873fc17765ff09220d4180c38e488fd4c28645eb9704895d6b308fb3abbd6a23b7fdf1a98b7f36b36a744fcd0da3df432c5a3d8ec2138007d6e287e9c9b4cfd8c7fbb688a1b7b009495ebb3cec406d74d7d9d665bacdf480435b77063a820a597b200c01be909588547f586e15771f162bd29b76f66bf02bff5987b64a80173b3d166803b647f15832707da2f67d34e0899c3087fcde274188c59e021a0de53d47151eece494e7ab3ac9e3610cd84b4993d777a043fde14094d76f7f690466f91e5a52011888872ee6146bdcf893f7f8a3646d604e30f0840b33ce685d19998f1102c583154718d1c9c327de8fa63c58db682d052adb7cab21a9d75645b3d245856de642519a8665574c883acbcd0f25826f2bd3eca0d9abb5542afd53ea1fda31bea2da31640bac1ed33af6a52768694ba154d351951a623b92cb499eb85ee1cede4c025cf0b00bfe9e865334b6bf5e0b94823deb443ad7ae1c67dca5a849b76aa973098bdca1a988e8a1f5f218425197a72574ea656d57443f130a5c080a86dbaa7fb4d76223683540a5c813f16af654b67660762afa04a177c89a9e0c09d0d40888b1437270f5d89016b3f4ee8bb38a5aa03f61576e1c55c94d966033d3b31d74018a83b7aa05d3c2f6f8e92a8f803581383bcfc0e7c59e05669ee464c159c7207b3076f6a5a641368132f12ee9f11b1f402571ca8a3417d4c1bdb1e4c9b3c5e47f9b60fa67994a6b745e59809431c90d0b73c9ff3b4c41d92df5b261eaa19f3eb5df2202ac429c621fcd6e68e1bab260d9b391a29808008cb297268ea441713178042c3a1c9578ae09649063a14ba71eb227449b0464463adc3b1d137b89a38cff0324d0668adbcaee9d75feff65f9bd4cb94b8d551f914641741cf6d8fba8554da66b32ec5b68660bf70cb2c516ea9b07f6f9edaaaa51763edc5bf93b17e5d80d463c8b58bad94db047e6a11978fbbbaa24540cf22c657a18cf8ba74d9771d42a156c4feb386a010018edb9f3af5b27f283ff39dd350ef5bb494f6dbc1303c60177dbf277b92186ccdcffebe77cc339897c56bdaad31b8a30f17474015926a6240c6fd669927d25b779bb6ac6402eba1162e36059bbcae3e056fc5aed794d81a7bd8315089edf4e0cc2b0cf2d4cf4e6990d659beed699207039f456ee619baf73456413ac6a84b0c8430b3a2cc31eff9addb686299d66bd7c0cd2916fb7666b3a131610a5ffa326528fd7a6a34ea64d12efef4614e6fcef0455c9ef0128b580a2f672613704da81c058b12b1b404da6edb0853726bbd91e936e5241d02ba0b6decd2d01641f8e1dd8b148bcb694bc1f5baa9d1c1b34c2e4c7ffd70dc4d06009885a1920f665584e9e24697bc496f3ab315a4ee70c1b0bf9dbc791de279c3f43c5e6eadeca7da20db94543bb1a2437dc513f609d3402528b7fdf7206f54b0bbd924b1a88a9ed051ba6b25741671fe262b9ce9db311234a64e5c217fbfa339b7490e298ceb9f2022aebb72d9f64cf416dea2cae19f6ccdc561cfb9a890d5e7ac392cf2552d38fcb72a4a0ab7048f6dc11db1cf9fade18b4f374a90c6b12ebd86ce91b439cad18e567c7e8130dea2342ed71296a2c505fdeef3509d6bb0f54ddd6bf0a9239452a6c9dd885c5877bd93bac37f2b825029dc989cfd879d895695d3f5e922719a05cbf6a9fe8e371244fb2c54e06d30da9ef6f043c1dfbf3aa124852600f2857f20f61927fdf0a77b10df8312d902cd57acd6770c8f5a24c976cfd1872ef11e8daac8bf73bfa11dac1f812ef15e0af49d9c1dfb3d27651e16a032cb613046a51e6d1465f551f1d23e86a0a2317168a7ee2da5af97e1771b90019e2c18f8928a241f1d394de560843eb19ed30ea39dc64036721ccb701ee45375e8c9558cbbbe577cb6412dd3ac00580d28ff8a466985dc10504392c5f94589069c282439b0364ebc0bc65e1726322bfad5713bcea80e1d8b4d9c090f9be3484a2ff5af4637cd51539720751e4c1454d2bfbab0c88cf96d854534bf99ac74ed10b88eac740ba49f12eb8c4e9f7d84be98dc6e833c00742b6eba99a59c29eac72deb1092836c8564ef395b873bef8c668de8ae465be5393898b2c5bd907f04adb9187eba1ed721964d0a76019c79f11154ac93431ad8094f96a22cc8482c6879057bbc2d61750e87176283bfc6d43cd6b6f30d3c08fc6281fbd3e13d58ef6f73225a0be870366ab6edf0fc633b53a0311530c58bdf94636ac52abb0adcb8a2c50e64ae19faa4f2028ff76dd3681dcf61ec9825c2378047dc8972dd63e2cce376ae9973c3dc2d5fc5619d9dbcb5b0590b5e751c8de1ba036ab72977568174247b9c917a2dea8a5fa74ab578db63d18b6a06830ec5b6b4a799174a75a8a8b4f0ef1c8b8a2f03b5f1a2c760bf60c0e6a0ed09b07d2e47fcd72935754ae70863df4596f2318b0ff76e28544dfacb312a0baa554b2e55f5a50e290ec15e93a242b23dcbae096cc7917625ec23d8d3f84c4dfcea2abb23beab1bb7233eb44025e57680829f1d87cbf5e58d983c822d46bca98ad5d0365f9e05ee2a8332e0faadc3be429be1f9b01a97cfff50f3ea5ec5d35befe827263c5e519decec5c4c313806a6eeb985e4a5061bad0b152817da7317421dbc5f881c238698b77b1e6af5a1cc7a3b7b43434548c1b352c75aad4993a02ddcee1bfabd18bbf6140d512a6acb862f7dcc438c78d8b34658ebcb4a764ac73ce151fea2ae4ced7459d41b50343a4f75aa958b9988ac9d4e36b59b10251ea76a99c7e0bf265b7b5a8b325749755d01d25778dbec6ea70817e4adc2bfcd69c4b9524968ecc6e0bb91f33c809c39c0e3c9226cb23e0253c3e99598de18020b2e6f1643c8165a76c71b43286d405c123a635dcfd927db7355c1bdb59dbeaa445f57a7a9526a6bdc9a66b8940e5472c311fd6865e7de091062fa5e1cbd2962dccbb58edeb8482548bc684fe9c9653fbd6d7fe47c032d1e74d3f636caa375115e00b04bfa7661ef7efff933fbf36de34714d09e110676bb23c28068cb12e99db2fc499397272099b70faaee7638e864748e47dcf7b5c97638be5a5796e32b1138a7d9826adca3d333fb9dbef0145b6eafbd46338bdd720c699c585cceacbbbbb45ee553d197db7f5006210cf927a11d9e4842ac1a6fc76a91974e38c938d4ddd806c6b1ce6de32d60354d608f21a8b70905cec03e1d1088d50e30766b7a8f6a003104f274694b21ae67c771039d253a874c6e3846daa3c18fba6672153019ed5ce86de7bf3d2f806d8424cabf7c01807ad64142bb4ceacdc358bc4aa630d6732d21963f0ade826f99796d23d61c982e38e2d15cd6c617a99d29591933540a0a46234f9e52a0a358cae1f0d24b4ad30dc6ccb31f2266b15b4bf7525b779304d22f9011d2e2b0765abdd21f242ebcfcfeedf18f743ebce5d35c1715f4351ba83c4a17d9fa84ca10868f0fc6ecf1238f99a4ddd00fef76da49ff9529625717778c5e45f939de6582577ed03d84f83778aabcb69562a79ac9bab1dd7ca845a0f25c04660914ddbaf265a3513785ef8a30cc0abfe662efc75b1d5d2f4ada5b1327811cce055d15c6e994906f63472fe2184c105e5c6531b88343f91a995d47f68c81b81d6eb356adb9964f63155d556ea8c5e573b15ea7ec9b83ffffeda1f12ecec1106739ae8587df3efecb378631268ce1cb243a2fd8d7805fe07ad0b61b8dc87b70bcf014d18babf92cbb657726516af8fd48fb616c89134877112b2e04dc61649bc2622cfe31430533c5054b3a8f17dde5ffce207f20ae5a99d4187a08aa5b91cdb2ca1f13e3b221885e3b35f8ea9d791d6c973e31ef8ef5eed681d59f47a965f27a720adbde963fea2d8c604f8ed392e797c0878630aaaf171bd9b8934d59e88642255b3a8cc66c5613abd4464654a5284edeb4d591182b4b809913c0ac4095689e4af0914b2455152d1fc966cf6433c9823d05ab082e08af95de36f08a762d66d1f459d314b8a3f0867c310f6fa2b0d544d8b5736576f7de2278a622b069c0a3bacd7db354bdace45612d7115c9588f5695efbc4920c292c7591b1dd21f9366bb5c74471538d5daab5da5922dcd035ee3c8dd45127c2a15458aa5391e85480c18fd7585a07923c6669a511b388cfe3b21823501d8be1945ccae314078e2938a869a11f02019baaa774e8573c794bbf4433ea7a845727346f1e1ed44b107b66fa350d4023db9798f5a10932351eab4e5cc253902d6cb527c89e09dae8c7e7cfecb1348154585a9562e77c80d798f0ab933a9528ae5b1e8af7753af629835fc43a6b19225ad5c40b4a86a3b0cc2439444958e0b77d0c1f291e88ecfac1546290203072c1050808e40bd1fb98e1c880251a4d4dd0a1ad05095266afb22b9e1f81564485a6724cbf79209bfdaaca43dae805124dfc1305538152fa52bfdc41a54168765d06957b94c6ec2a6a6f8ba31b7f44c111dd1e5988af35e11fe14f7c5e94d17a8367cc8b2a4188f3284e959bfdf146e3bcabe218bf60804df58be01abc7a7844a04f35eaea8fa41053d76d7d14f52d460348b1f56887bbd0a269bf8c43a58046e7cec4e0f0e53843ac78de0e1b3621d71ce7efe57b46b79316ce3ef1437dda4e743babed6fb5b9ace7dfc5f3b657dcec69f1491ae0075d08a8bc6966439b26dd599dd3ae14ba0d5f491e1a91ad7c7ad37933d8765336ef60b153066a7e7bbf92a4d99b405a1a3fe55afdda04b9b515a4118046fa9725d42c3026890de374836b8c0eff3a5633bd06c5f132fec817c3c66a68ad5ab7c9f81e879aa0599ce241b9fef498ae0d3d24dbd3b83f3e07fd80790ff60a2ccfc0517bf40dbbaffeb012a40439993a404dd1e8c1a54723bcc532607f8d6f425a1f9abe80989ffa11d349c51774ffa3bb7bf5706f8edf7d55cb03b60976c9d99ae3b755fd0bc9199d7c567e7470d304fd1239bb09657d48fa1231eb454b27115fd0fbc5ef206410e2e6e52d654c23de79deccd369945c45dbe275b59ef1fc0f916fe755012af9bdd8f416587cc7e4ba88558f5152a57c9493872ff94c456493d35f26bffc72363193df0216c200faa5f1eca7ecb18733cae89ddc19846138c12c834028bc7815f9fea391ccef4f06bb4d27f8eae86fff7b72d17b3877171309cda9c6b58767bb7885d52ee997ad4c47664880b6d764ff69723ec61b527cd42c28cf105ff2619051965c6c6577d1a59221be70f1090b8e944d49d9b9fc46c7d647c66f6f9927d5c27a43a92973eb521eb901dc53f9abd2c5b58296af37e80d03e053213c98879a0ed0a91db0f47c9ff28ed381be17702a71e27df583674f27d4f259fd7d295d6caad2f8b78a76b35cdf1ce8e0d16f153406ead2f39f90126514499c5e3c6971101bc6e06fafc1512fcb1cc3c832b7be5a089f85f740da0a9e17619516ab78a91c74c1d4e4cf51e2de0da71b63faec9fd51f71953da8c72a59e005f5e44303b79dc08232e0eccf0815975b835bc6d5a8cd64b6096f754fae1988f7025c79a73d828bbda7824549cea3c5f656e451f4e8a76f370d71c104c23be58e239026196bf86304bc56b159a738d38462ba33d6be0953fb22ceff136a7dda749e754bb59b02f729ec94507e172fa6c18376c48efd3a50bc1bdfe06a8e208c28c8ec82ec3542dfc2e835d42fe563d389f38d59bce386bcd31543fb4a3736902f02db647dc8137843f8c255b94eeedc86967199e02afd0fa364487cff91e3453cc75346d6e37992152e3cb4f16f3cbfaebf730c39f8bf000000ffff010000ffff012bfc89c47a0000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec7dff73db36b2f8effe2b507d72a594c8949df43af789a3f4a56e72cfd77c9b38e9bd19d7f7869220893545aa2465c72ff5fffe76172089af1465bbbdbb99a7696389582c168bc56277b1004723769cadaff378b12c59ff78c01e1f1c7ec3fe165d6413f67d962f5894ce00222df378b229b3bc60fd8273562e393b7ef7f6e38793ef3f7d7cf7e194cde3840fc23d40f7224918a12b58ce0b9e5ff259c83e159c6573a81617acc836f994b36936e30c7e2eb24b9ea77cc626d7d0187b73f271bf28af138eb89278cad3029b8b4a3685d20967f36c0324c529d1f0fae4f8e5dbd397d47cb8b7377af84b91c469c9267976056d3f6565bee143682b2de374c3abdfeb6453e0ffe2377b38829a8b249b44097bf094cda3a400a0285d6c922897bf11682fd8c0970278312d83a3bdbdcb2867c5753a856ea50b36ae6a84ab6cb649783fa8cb82213b0bd651318d9275cea7cb322cf3282d92a8e4c1f9e088106df2641201fa310b806f84bfae1f4207e6f1a23fdfc083384b59ffc1b22cd7eff3ec329ef17cc81ed4f8aa6703f6658fc147030c677c1e6d92b2083f17f9fc3f7904cfde462b6af4bff68f4f3fbcdaff985df0141adf52f738cb2e625ed5d56a8aaa164121f0eeb48cca78fa0a06ab789d61e37d41247e8031f3f8f3531624c0c6fd605817149bb928087f29b234a0e737c034fc5f675199674902488397973c2d8fcb3c01c62b3c2ba6d91a0696ba55f3871e86495494540bba936e92443000c7254b41a2b0972406cd73ac71f2033c3fa8badcbf8ad35976350827f0b71f4cf83ccbf9264da0a70a1dfdaa65fcb89053bfaa568acd74ca8be2558a30754f665119a968e239eb7f2570a98f95fe3de0abb8ec079f4ede11543038d2a06a3a703e3445377b5a13b2cbcfd981d90a121442775f46d3a522a51c396ac2e20706abc860ca26d9a2df23a8de90d1df309e55dfca6b1c2df19d7a7c64e1d17a67d5322adc28bf6f8e9aae3944009b3ba34e253c5d944bb6cf0ecf9bdaf5d89b55817a0571c1cb8ff18a679b52e1893540288de18297fd4a033c62c188e82fbe2be274cac7013c124d0eb4aaa1948e7e2d254639cff32cefd3bf50a6f47ec8fe7c70201fdc28e22641b70a5b47599bcf5b854d117a22e41e1997c440c3f830b83f861d1e581cdb9182b6d6ad965bb4db69f5b45dc3a9ab027c4fb2698450151b71b841e75efe00c5428b554fa143ef7ed474013ec54529ca4bb1d2c9915335e8345bad134e748cd9979b23bd0c972fdff393147ba435d894a79cfa56d8958957f8fcec5c7b0eab2f4f6cf0d535cdd820d09ea600ecc0b1ceb3329b66c9f1121623b04d34599530395f677909ec8becc644d97b606fccafbcb51d9d02e32a7d891db349ddac1739ac9927e93c93f5dc42f8a837c225b437a8e5ad11102c28d4890446d62b58adc8989ac779513204d9440b5e9958490c0fd7621127230d1fc25a9e07456566a9d8c85403b32e920b3a9a7d5183f48ab36574c9597419c549348125807d143586acc7d39e8aaa405d2c1b942db1ab18cccb55544e9704ce8051f077ffd329ac1f574b302c58ef7f96fb1fffde2348159ba804bae7ba0641db36cd4afa7dfcb617369a5b2cf0e96228aa81d037ba009639d6478098a60dfc7946b0855c2be0c9a347a6b242000027b8b3f85c5788551b00701925f1ec3561039bb684e9ae0c9e6b25cd79b9c953425cad55cfc7ec31fbfa6b968430b2fcf3bb390dfb808deb595e7d6e0ccd8caabd2246c176e86ab8512e68d9d5d5ce0ece1debf424e7d185d1b6a1f76f069a3a79009652af565a621e9e0a79eea92a4f25ad1a355c98ab9a30a3a21c8c9241882547863d836c315615bd5b04622e51b585562911ce672f1a35554307f92a00bbf5079e28e62c3c9cc5b97c0eab6b9c0fd45254f958882a517d5e669be9120b3ead67e83688a21b938c93a987889cafc0d172d26117554480352bcd5707216090f03c2e2e6a52cce16bac4d75c0687904ef2ad758af1a844e2b55e28d53302d94c7ae55a9aed20ffe5fcacbab2cbf20951a0c706d88927eb0045da62107c806533b5cb1dc94c8173794291a151fa425b43b236c138a8cfd865a4b807dbdde2ac6442bba685c2e7b1dc8c52937134b20949099ae53aa2ecac2a2c695efdc633a9a6061510af3841e9559a72ebc86a99f9ca0ea1373e5cefd80850cf8bdfc0014f56bda068aa10fcb8b688a29561092be2968b98860d11296062d8fb00816cb28e7221e82c860b52a97a129ec6423a8dc788b381c7e16e23e9e5ba220e93eae69aa0009d1c90f43a6f6a6e66c9b287f005d51f23f82b9fe4e1014f6c4a6df493376f687b890c664278a410a398ca66d869e551d004fef7c4b9bc73b3448937a4b739e39e303d75681ba9d74b22e9eb283a15502ce96afe824fdfebae4c5c7ac8c1227c0bb4db905e2c56c06a308e86b0a2378a2c3dd1cb9bb570dfcf6defd772908005fcd8bba45711c933b429129c79899c3a5f930e1bb358d40f8e9c30b3052d6253a0d633b50029ae2640ee633dac2c249c0a56b19812d0d963f4b39e8013073a30a470ada63c6a7b806cc862626d0235711d8c865c6a2e2a236ccf1f72aba00239b4d97593c051bfbfb0d699d59960625d531514195c9668128566cb6c991285c6ae32841677c03ce649191dee225a2a5e81f292d0b11105182ef2ec2bd95537119177119b2bf2f792a83b90203a8bf3546896d8222e994102e005b65a42fa31403c0395bc23fe0642cb22152257b6fe2f87503ab24da807b5a09aa2322eb27a40a17976cba5961f44650850a2589a6bc3fea7ff714fefbc76fe1c3a39f8b8783a612fcfa790cfff4cffe7174fe70103e7c30f8ed1ff0ef08bc9807873d8759fd5553d9654d1b240051bda6c2b8c71e31f4d341eb5d81c5fb88f58e56d1e77d10222a7a72f0f0f1370f9f7c7b609af78c63e4daa10580a0470a0b9ea9d8f799c0f590221e7665fca091b1719a1675db9d8c7d5a19f8248399c667afe0df42756deb09a8ae11a4ed8dc5e5825f23c71430640b421a6693ded619d4b3b4aa030445443e6d8947115f9c1121b26abe43722894c753dcfbf8f4e104d7b42c8551179d7239ec66f04d6b4cb599c8409086923d1af8d162ae2aab86c429b198ba46d20ca38a58d890c2359651e96161252237ee913dbd066762a5b1d4cdca820083aeacd2633fb476e077e74223503b59e8629d20b967b1eda6bda7863126786f2e2d5802cbc758a5df36eed0f157b8df32239a46715e10f67fa1e9d1acf0df21693447248dc1d7f73e6b744babb62db041abb30e2931ab28213cf373d3366b4d3cda04564a8ff69c58708cc1d8c108d4904d69cfe2c04d451dae9aaed618d3bb45d79165581b25b2276cac5e1b3c7eaa2d5737517ef6e0073bf668ece5149072ee478bcc80ca87f73026a1e82b46a681a211a2f60c874b4128936ec89ab93ef48ec03f47f51ed7ee03bafe45071dac381c9d15310a209817c0cac6d2d0edd912a3ec7d84d9aff72506c074eab06e4ecd8c5150b631a0bece3212ff9812067c5a41a83e9c766087bfbb4adfe7303c79790dd5063e31f78bb72d61657eedc142db8ce0cc84e49601f96fa272198269d78731fe0b7b28784910aa0f061c72f87e261432af9c39a44a6b59b87dad4d6bde9dbf6d0dccdbf80d9b5220be6fed1e7a99e2516c76171c803e33143fce4da66e8b7f33698a9d2d008aca75996762836b575ba7de16ebd61341cd2dcc184a48e9a42c0070273d01b3f0b8da30fc2a2e5eaed6e5f5bbc92fc06fdde71e186ac0dc6cb419e076d95fc760c981f6cbd9b81542c630c25fb238ed0743167808a8f614755c14bb739293ee16d5d33aa22d214d64cf1d1ec18f37444283ddbe3da4d15b647929480422a29c7b9851ed73e2df37d1da889aa0ff010e6896c7bc301a13231ec20a56f4555c0307a74c1bbafa587ea3ad20b450ebada2ac46632dd1560f09d62a6fb29216a87a56b4c883ccbcd0e25826f2bd2eca0daabb5542a7d93ea2fda31df596910b20cde0e6995735293b434ade8aa69a0c2fd3115c16dacc55a01b475b3970c9f302c077edbdac6669ad0e3c1761c45d1bd4b217766e53e622ecdaa89ec260b62a73605a327e7c89109664e8c15d39985a56d38ee2614a810151ade99ee6d7d9a9d80c52297039fe98bc96cd9d911df0bd824d3ae3730c0507ee6800425ca4b83979e40a0c58fb7142dfc529651db0afb0092fe6a2ccd66b68d989b9024247ddd102ede27979739c44c51fc09a18e4e577e0cb0cb74a733762cae0943b981d7853d122ab409d789670ff8888a917b8fc401d0dea63dad8f6605ae7f12acaafbb609a46697a5b548e9130c401097dcff3294f4bdc21f9bd65e2508d98df6c930791214e3e0ee1b73677dc583569584f71910208f0b09c22874b9d6862e40250683832f94a1edc3cc9408742336e5d842609e68868ac751836fa0657ede71956a6c900ad96d734fdfaebedf66b1d7a1913b75a329f82ec22e8b8ed51d5904adbacd6a6d856e0ec176e9925ca2d15f6efcd535bb57462ac3df9b732d6af0b907a74b9b6b195629bc04fcde3f2715757b408e899c458144a8faf4d977dd722146a46ec3fab0b0a1160b8fda9552ffbbbf213df3a0cd5be454369b71d0cc30276d1f77bb2278961adf9c9dff6967186e565f696766b0ceee8ddc51e5086a41a18907ebf99e689f456cda60d2b99c07aa4b98b75c226afb24fc15ab1f33525b67a3d6ce9a8c4767670ee150679ea67ab34c8d55996765c927b3ddf8a5c8f3334efa9ac82b4f4519718706126459963dcf35bf7a289695a6f5d1d378758ecdb99d5fac680297ce9ca94beb4eba9d2a09545dbf8d385399d39c3677179ca4b4c6229bc9c198dc034a174144c4ac4d412a87bdd7898925babb50cb72927e910d09d6863a7863608c24f1f5ea6985c4e5b0aaee23a4707cf32b930fdf5d3493b19006026864a3e985911a6891b5df23abce98c5690bac309c3fe76faee6d88e70dd3453cbfb6a29f6a856c5d52eec4920ef5154fd9170c0395a0dcf63f82bc51c2ee7a9dc4222b7a4447e96e14d759f8f9ebac70866f8748d0901a71b9fcdd8ee6dc2638a430ae7b8088b8ee8a65db23d159788b4d0eff642b2e0e7b4e4586ac3e66f56191af2ac1e1bf6ea2a4704bf0d016dc01fbed37abfbe2d38e12a471a84bafa173246d8e74b4e3259f5e208c37298dcbb984a9687141df7d16aa730e36b6a97b0e3e73b852ca30b92b9109ebce775277f86f45102a859dc9d93f6c0db4aa9cae4e1789d32c98b64ff977bc9620da67a1046f83d1f6b0879f0afef1f529052934019005fe8ed8679cf4c39fee4ebc0025720d345fb14adf313c6a9124d77b8e367489f7685445fe9dfb0d4d67fd087489f752a0efe46cd9ef392df3b0009559f683212af568ad28abcf8a95f63904158d81433b746f297d3d0dbf7d01e9e1c9829e2fa848f2d112d3540e46e803eb39ed30d8ba18c84a8e6319ce837caa0e3dbd8a71d7f78a4fd6a865ea1900b301e55fd1288d901b026a48b238bf28d18011852407d6c68977c2d8f3c2446679bf3a6ec719d5be63b28933e1617d1c4969a5fa6a34531f35750952ebc1444125fdab0b8b8c98df565844f5dd64a56d87c07564a55d20fd94586774baec2374c5e4361be401a05b71d3cd2ce54c51376e5987901c642b247bcfd93acc79a7376b787715da4d9e8381296b3c08f967d09ab3fe979b61e562d9a46013c099979f41c53a39a4819df2642ed2828cc0821657b0fbdb1056c570782136f82b4cf5636d3bdfc083c02f67b83f1d3e80f9fe3e27a235870e47a362db16cb3fb623051a5301533cfb5539a6562cb3abc08d2b9a6d41e61aa12f2a2ff078df751aade229f41da344580278c49d28371d06ce3c6ee71a3937ccfdf2551cd6d9ca5b0b9b35e155c3d1e8aedba1762fe5ce2c9096608fd353af445db1eb54a916a51d26bdc86630e850d696e634f34cc90e159916fe9d6391f165a0360a3a74f60e1d363b6d0f806d7339fcbf56a9a9423ac7e8fbceb2940f597cb4b7a350d5e12f47af2ca8462db954d55d0d52ec823d2745866473965d13d89623ed8adb47b067f1b91af8d555768b7f57556e7a7c64814aca6d07053f5b0e97ebd31b3179045bf478bd29967d7bf9f24c70571a9401d76d1e7615da0ccf8755b87cf6871a57f72a9ece7a473f31e1b18aaa6067eb648ac1303075cf2d242f35d8685da840b1d08ebb106ae7fd42e4e831f8bcede350a90f65d49bd1eb1b2a420a9e153ad6724dea006de136dfd0ee45dfb5a3688854515b367ce1631ea2c7c39ed7c25a5d56b2553aa6098ff29755666aabc9a2de80a2d179a653ad5ccc44646d35b2a9de8828f11855f33c06fb35b9b687b528739554d715205d85b789eeb68a7041d62afc5b9f469c2a9984c66e0c960d9ce701e4c8011e4f14619d7511980a4ecfc4f4fa109870b99b0f216b68d11daf0fa1d4017149e88c7535665f6ccb5505f7e676fab2127d4d9da54aaaad716b9a61523a50c90d47b4a3959d7b274088e17b71f4a688712fd73a7ae3229520f1a23da525d7fae9a8abd73aa54ed36cacdadf8a41c0fdc8f91a6a3d6aefddfb288f56457801c00a079b40eefd31af8c160b9ef35927fe55c0f7cec29a8aed5cac40df449f5f5032543756ae08bc3bfa63d088e9490a4bc0259d75ead6ca54add5bd3189a8781f954bcb24f63475a9d4b16464eb50fac7220553d0b995ba4da4dbcb7ffb8dfdb95d655903db0108b03e39fc339ecb3ee886dc1cd6eeb0d8d4b75d9bd93ea06e506844ddeabf659808d7a18e8104a4654b20219acdac956beb92f5455b169ec202d4be027596c76d52b8ab90dd4d7c6e2d113dbb4b5d4349f73bbae85ab50eafb8e5709d6d71f7b5a62c775f22704e050baa760acfceed32dddc503c18dbe2a8ed51912384811c2716970bef6e2ead6c9bb168cbed35299d10eecb1761133d958458275b1cca565eb5e324e34877de2b18df146ab191aaaada5a6e7729a87225049ac03e221588450960ecda548e960c6208e4117bea543d6f1d67ae740ee90c3399e330eb3a54f8d1675c7562a8d76eda99a715a6dbb05558351663752d67e3a5ba9aade245a1693c0f26d514f1225215e01dc7db6d8676abf3c66107fa608ffdd69cafca4f4eabacdd3c3370b97a64c7d99aa3795847a83ff9cb176b538f154a6897f7ba73f08d6e6d2b8c45a49a4556e8071c739f6ef7baa198de6746bb108f161daaddfe2a6e219350fb4aeede60e0d91214e8286ce9882d5121ed88f586cc937a2046b1dd52eab456decf7e8b7e579b9016877da2a506ff41e2c2cb17ef4f7ea4ab581a3e4d7551c1b04e0d9547e92c5b9d52c65fffc9c1903d79ec315529f1e8d387adb6aaff7632914085c919afa37c81d786e1ed5a74e52ffe2e4ac62b034d248531a9fdb6f3a112818de7ce4d4ba0e882b3bbf546cdbfba2fc27003f62d176916de8348d5a4a4341671e8d661d1d2ad9c9c0ee4fa7228f47cc9de08e1c5ad51bd7bb8ff462393b59c8e373ae28e6d9969e1f50db81aabe8ad20865a9cff20e6eb987d73f0ffbf3d32cae29c4c0f9c0b87df3ef9cb3786054818c35749b428d8d7805fe07ad4d41b0cc86a711478ceab895b709dd691de9844a9e1f723ed86b1214e20dd46acb87b774b0ca43ec38379b66678c3dc4d82299dc7b3f69376ce787a4fdc6a36aa30741054b7229b641b7ff819a70d41744a8ac0a20fdcb879bd4d9fe406b037310656fd69945a4b5e474e61dddbf247bdf018d693ca466bd6263aca2672c630698c367c6b0a958dc97e3464938a58e51842440702c421d7e62002465625c0c409601ef690689e49f0814b2455152d1fc96acf6535c9823d05abf06809afb5936ce015f51acca2eaf3ba2a7047e10dd9621ede4461a389b069e7cc6c6fbd41f05c4560d380b762d457bbd34121651b2371dd76a112b13acb2b9b58922185a53acf633748b6cd4a6d3151cc54232164a5369608337485491e03b5d78930281596ea54243a15b0e0c72bcc62474f8ba51b8d9859bc88cb62884055000087e4529e5c3c700cc141450bfd1108d8583d104b5ff1920bfa124da8e901de5254971c1e5453105b66fa8d484023db9798f5ae0932351eab465cc253902dacb527c89e08dae80f455a8fea9e839e13496a3dbc318c5f9d56bb76e2cd067d515eed7c3e63f045ccb38621a25645bca0a43f08cb4c9243948405be58abff58b14064d38fc6128304819e0b2e8043200b44eb43863d03966834d54e873617244899bdceae787e0c5a11159aca31fd929f6cf28b2a0f69ad174834f1270aa602a5b4a5be4749a54168765d06952b0b87ec2a6a2e66a5cbf5446e2f5dd45c883788f1cff0139f830fbc5ae3752ec52641884514a7ca4b74f0e50179dbe11e7c970f1beb77aed67875f788409f69d4551f4921ee1237a9c8d4b6e80d20c5da832de64283a679ef954a01f5ce1dfec3eecb7e8678b8e8ba5fb309b9e6b8ea469633ba08bc70b6891f6ad336a29b516dbe55cb6535fe2e9e37ad625e45834fd2007fe8ee5da5a41e0d6d987463754a092068367c25796878b6f2e9aee366b06d57366f61b153062a7e7bdffe55a701202db59d72a3bea1486691046904a091fe5ea28a05c620b17e9cae718ed13d1b8ed94cc5a0385ec59ff9ac5faf1a5aadc66c325e9954113489533c93de9d1ed3b4a187b4f6d4e68fcf403f60de3b340496e760a83dfe863d54ff585179821c8d1da0a66874e0d2e3015e181db0bfc6bb90d685a63b10f3a61b31ad54dca1f91fddcdabf768e4f89ac94a1eb04eb04dce561c5f0cf92f246774c988f2a7859b26e85de46c17caba90741731eb444b2b117768fde27710327071f3f29632a611ef3cdaed69344aaea2ebe2ed6635e1f91f22dfce5b7954f23bb1893669ee975c17b1ea06371d4a8b72b2f0259f295f7b74f6f3e8e79fcf4766f05bc0821b405f6acb7ecc9e7838a3f4dec99d5e1886238c320884c28a5791ef3f1ec8f8fea8b77de9045b1deded7f4f2e7aefc1d8c6444273a671edf07c1baf6893f16e33d3111912a0cd1b29fe345a0cf132321f35338a33c497bc1f64142517f9136d74a96488771b3f65c1b1b2472b1b972f4f6e6c647c51da34d9ccac120a4d993bb9f2742be01ecbaf4a13370a5abe5aa3350c80cf84f0601c6adc43a3b6c7d2c53ec51dc73d7d2fe04ce2c457c3f49e3f1b51cde7d5abc9dad8b449e35f37b49be57a49af8347bf6ea03250972ede20254a2f9238bd78dae020360cc1de5e81a15e9639ba91656ebdc50f9f850f40da0a9e17e1262d96f15c39538aa1c99fa2c49d824197b375d93fab3ee2ad31a01e37c90cdf0543363470db092c2803cefe845071796d70cbb885bc1ecc26e0adeec9d51df1de352f5f1f83e062efa9605192f368767d2bf2c87bf4d3b79d86b86002e1bd72c7e148938cd5fc311c5e2bafbb559c694031dc196b2f9dd6de79fd7f42ad0f9bceb376a97653e0bef0242594dfc5b371f0a8e9b163bf0e14efdad7b98a230823ce3eb44176eaa16f6274eaea5df95837e22c3133c6dc90f73a63685f69e705f265602f599ff2044a085fb82c57c9bdafa1655c26384bffc3c8a012af1a7414c4533cd06b3d9e2659e1c2431bffc6f39beaf59ec8c1ff050000ffff010000ffff03c56dfc2f820000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["app.js"] = bs @@ -73,7 +73,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["favicon.png"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffec3dfb7bdb3692bff7af40b46d63ef99929d57ef5cdb7b8e9d6edd368fcf4eb6d7ebd7db0f22210935453000694775bd7ffbcd0cf87e8894adc4deddfe9098225e338399c1cc0018ee3d387e7df4f6a7372fd82c9afb079fed3d709ccf462376a4c28596d359c4368e36d9a3ed9d27ec3b7eaec6ecb9d253c6030f6a049196e33852dab00d23048b66821dbd7ef5f6f4e4f9bbb7af4fcfd844fa627388dd1dfa3ea3ee0cd3c2087d21bc217b6704531368260d332ad6ae60aef204839f53752174203c365ec060ece5c95bc7440b5f605fbe74456070381e31174ac7824d540c20c98060f8e1e4e8c5abb31734fcf033c701ac1039e6f360ba3f10c18005538787e1fec02c0217860fa6f4ca458c94ef0bbd3f384b4b8e22ed0f98eb7363f60758c957fc7c805d0aee1d7cc6d8de5c449cb933ae8d88f607713471fe739017cca22874c4fb585eec0ffec77977e81ca979c82339f605740b238a005a9dbcd817de5414da057c2ef60717525c864a4785aa97d28b66fb9eb8003238f4630b109791e4be635cee8bfd9de176ad234f1857cb30922a28f455abc6e368a674ad862f837398381f2806c5911b474cbad8d34c8bc9fe60c22ff0e73004421e7c860d2219f9e2202322fb9d5d5de13cbf82f97d05236d6c5e5fef8d6cad6c00dbd958a9c8449a8723d79851f66b3897c110de0c1238901bcc4c886850ed40030d2ef9624965facda245081847e243842351096363e52dd8153d321672cf03e89db18a2235df655f6d871fbe4eca26402167c2e7d25fecb2c1b7c2bf109174397b256231d862d98b2d76a8616ab698e1817180f5e5c47671fd19fd99ed6cb1d923f8f718fe3d817f4fb3e1cb439c5ab4a0ef5b8c16fbff511860cef554064ea4c25db6337c2ae6a5ba43248d335781322107d96c04eba5087cb5c55eaa80bbf017948251202b00e41148b4141a40bc0408b36e2a43709003143c0f45da3b8848aa227d805c5d2fc5d9692f9d00afb497663d7b4b7b6e2ccd7af6322a8c95f684b6b40b5450c1cb57535521f32edbfebacc578537d48df33467af501989c2ba8b1c0ceae2a23a8034911328671c83be8ab2a1e835b1b783ec6d41ab3404c4fc781e646d3c69429fc35cca00a44838635fb9e7291c207556c900f7a7fc91310e6974609dbc60ccddf3a946658ca3280de04fc71b8f1e3fdb628f9e6ce37f3b9b5f9729a8b92763b3cb1e17904fe9b3137e604ff2f729211fc1eb47e9ebeb2a5ec066c1d0e3a0d32a7cee8b0940bb9d337a09bd9dedfc35713ef7e514e98f487edd4dab94c0e91a51a72fce057b20e7a8d079103548022c5f59b3cb998c844332834d2f41079674cfa5b0d47fb2bdddd89357536316ff47a0c4baa0f08666ce7ddf2951b115a0a4f17fcf852739db98f30f094dbf7af655f86133eb20912b3000425013c0d207f64d51fab2ca8c8dfe0cbc0f6640c438cb9601068b6c842b8a184e87bb595df667208a062d3386359f8533a0b401a1628084ba643855632df8b94113c157d05c8b502b68e3030b8e0c2cde606b5cca6856ecd1f29319b23f8fb2d715226820533a2bd7193bee8d4804c14818592be1b33dc2108b3c7951b5355e5cc0524b76c6c1de08caed120a86187bab421029cdd086c17701bfc84c117e8125f60faaa1f4d113131efb603140f782eac929a775dfae700441d20942c181383a29c3b511a4a73c8633d660ef016c723e4d4b50bf0d98d1ae7d7448609e3d210b80cd8833f7078f1f0d98b556063b3b5f0d46801df69e0d1556c6c14ed84c7aa0759d0fb02037990c61d63af60bcd53e40b8f24b7195e642220e1255808713805ad234e82891a06e2b2803e55049b365241621fd81f9905388e8274007c847f39c1adf9614d493052cfb3813636cb0314693cf517e10cad27963d39ee4c5c68f81b878394665f8ab9c9e43fef04442230b03e88fcc9b9e07e0cff0b6d60d2f70757574574b18689aeaf0707efec5be03176f54552fb8bebf214d140234b82022547be2cd335c1c5d32af4d46550c6962784f9d3a05a0fd8763a453b18f54cf2a3d84b05c783179e8c2c80efbf0cc6408fbd71c6c920c111526b0cff7869fc9c51b271e722884b40121a0719a8c53904e5792a428573d8397133cfabcc58158543cf63d81dacee4a2f92aa087199a85d10a150f48208a872292c653aa0c22ebbe0c908292fa48762b302d4b038446756799b5ea0bb6ada0176daddcdc828fb53f1bd46c7b40b9a192c3527c71f9386661647c8c0bd8056934927c4b6bb9bd10fd6f188eba8271b4ea0faac039e53dbe3c7a4201fabb81fc8b072ebc811f3305a74490ff6b904e8bd51ec376bcfbc2459f8f1019617bbdab72cd4b63e9a07df486d2258e72fb7980afc0503e7fc326072c202e10a63b85e7ccd129ab24bae03b49b125322b74470417c00fd4fe4f424408f3d53d3d0716e179480f19db9e7ec3c2aaeae8572a083f019fdef24c39657846a5da4b547b5f6668f0b6b5aa90e050b06298f805b293ce18181f5f820a35dfb00687e55157e5898c2b7338c3d210d624dc6129b71c3c642803bc12f300e154760ee8129ea822f062dbc21cba31bf318a721010cadcea41245a3c0c028773d2c5831a5a96f071ffdcf8a95d2c34e41e3c4cc8b360a0bc15d4c2ca34f2ac95513a2c6523e48db447e18344c66f945e967e1476e399785434c631fec64e0e50aeb97983ced0f1be6cb33b9d36c038d6bf49d36f31e1a05e2d9327970d02d0e074c7a48ef640429cc72c948a4e8ea0a9b1c61c1063e0d4f8ec11aa629849f8247b64ff46ef0ef0f0076c5e65c2a75a57a501384b049f42ad5c8b42b596e40079f872635e842b0c93086f8a712bea935882f01b1cf65e0890f6890d6baef6129170d2e66a904b4b9beeeea2b978382c381e434e004ba334bceb38847714ef04608eb8678d689733913607fc7c17940d6ec3bfb50b7b0fbf76580154301289fd9875bf5e5f2c0aae6b3e4a9bbb75a1fa0029b38a805060a08770cc4d8c6d515f6fb466817d8874f4581e5bfd86c866e65c8a5d7c8d1cd609f40e54f08735b49c5b1b1af60fd2b8b79557f26929fea9da2c895a53c955e9689716db43eeb6ab56235e8d32ce836f0546cc22a51d8e4b789b4241168266a94065a9a4b755b1116ceba573f98dace952f5b3d0abe00f4bd64602f431cc32849e0a2a0cda0bdd78ad3a81da9dbe36b03648e0a45d081f73754730d081f4b2d5ca4dfadf04e2ddb39f86dfecf09257f19cae082fbb28d7b7a9325b16a1d23a75d7479a1b5ba25599a71b84bb698fa6adce50eff15ea70bf29d8b10e224ca9f76fa42f0cfb9d71ff922fccab783e16fafabaa6bf65041026c36fb17fb474f67c115167631970e4bee77747df999a7791f707e57e3ceafad8f99a884b7ddd23dababe8a3d07c31ebee25de1bad7e0f6bd9e90ab771b02b7d7e72d8a2a00f7d64ec001db2e8780d425fabeb9599a4639ead3987772eb59c4ae1a26b1669014504bedaea5d8edef037a07db1df06cb3e7cbed2f629a3b6228dc02ec60a397dc80ff4ed2fa51d8a8d1da47ba13c54fc1cf7b1df860a8fd244c171d5bbb7a50e9eb95babf531207ee4cb8e7a24bbc4fa681d28281d93e97063740cc1d4c8f05026130eb98a15277f779927a4792f08cd74900020476cf1a0c4cdb63dae1192843737744a0ad6787fb5d3b3467768bfa4719cd6e47021ad0d08e165263f3a6662494b4b95a5044dbfa0d0e6ccd37a5d7cd91996647912f8f7096766171ad6c0ce5e0b2f31043000f2b6150608c8c3436e6b356362e6c12ac825ba8e51c56dca61d66dc55cb27b307b8e0c9b9d2ef725ab28dd69561f57830157ad0b800b12fbf647ded1c3c00aaa5271aec9c6ef51ff631ed9201d8d10c4136cbf06d56a24da1961b44af8bb167dc912c449d490ed616760ea0f37ef1e64c980a01666c7d3499628cf9e7f45cc6c6e62ff727ca6cd14bc3cbf8cb4138fb6cf515dd2d767515a4474e129c4949de32f696c3d311750302ff1178ab07de3a15ece14bf62e92befc8d36d96eb9482ec05e9f0fe1cffdf059236ece4d07018edebc5b3b01dc304e42da150f127e06b0a26aeeefee5c5f7ff14fe2cd1f27d5d829fcba1d8160ec40b84868f3f3c34845dc7f8891b971881c3317202beef535feda68a97b12903bfd167f16996cf3ae69d96bf17c177e4c3aaa38ea4fc8d771b47e4aa6e64b220700f2611028702bc5ebefd9837d16836e9cc8a0551df6a6399edf9e29dd15454e4767677877e656f1e44ebf323d5d83677fa9a1895d3c4e32584694fa61bdd774423a83b49f4f5b1bbb624e3ee839f664b2c2e077a9d7bbb693fe660f66de4ec892d39df7d9d5bba9ef4356686aa67d24f7e7d6d67f0f8bdb1a9df684476e75b619e02a9a098da89bfb74cca3c100bfedf98eeaf1d5863e1acdf5aeb11acf7f749c1f40fd535c8192d186380fe0caa273ebaa79e80b2cae960eff4eeb15061e76b6b77b9f3c7817e279b2e37c99651bd0fc36a720d682c5de4a48944f7dd885bc6b04b02fc9d0dcddbec5a18f7a847409e68383636992f265276b3edae98caac0fc713aa354d8672746065d3b31879e07c8de2acc6f150e76548a0fdc99d5aee673d0bf5df16390c19956c15abcc33ee25bf5167369be53528538fb9dfb427833fd28a9bc0ab56a0a27254fa1b341134d69dba79d2c2dbd3fe8db3d6e03fd3b7be8552eede1a8579bfce1af7752b58fdb5e6df351bcf77f0eaf0c49011ddd7a11f9c33dfb889b33f9a3dda019952f12e02b3ae1679a2fd6082cb3c7f187be08a6d1ccee73dded0d9b26afaf4ae4572a926eae2c6e73cda6e0c3023dd07f2d900547c6bbe62010f076f856ce05a801702cc5eee0dbddf97cd798c1f5f52e0042b5c0dd9b682902cf5f58ff171bd10c94af0737cff71a2ed6143cc7b61de85c04e85a8be58f7e57f6baccd7d7dfdfc9959a92046477d1b26be9f8fa39e548e9775b3dbd8d94fc042085972459a9b9e31dd7d5db6e81972f7e17f45752855c854469618a9edd11a008ee5fac8d186669818681884675d9388b43cc9ec046ec1ba5e379ebd5bf5e231b187a2aa3593c1e827d3acac62e3c6901736984a943f2035de766a7b6c2ed005942021786992abd1879ca8dd1db48120ad4cdb742f147278b34266e22caf378c995e0350ddec0143683d551fb35eae5b73d69fb5f44974a9f5bfd884725c0264aa5c9fea24081ad457a65c00c1d6dc198b98d94a3220145fb01309cd33cd853ea8cf43ca603787894d96376ed7a080a37c3238bd495ee472618e4571e8d00fd84b1a9b16068db6f310018a39294be8bb3502b303ce69453832d8034f6041780ce727370088c1be905f4f7e54cf8be4c121c246a7c6f4428e7d4492e15d28dcb16d2e8ac4a4a88f4784e01ffbc9f2ae61931653051191dea539d91411a960f394c235cd5fa6f483ad925cfec96e170d886a5cdcbb00cc938adb104c7ac9775a0980db81e0cd36be7ad08a6d7dc53fcf0267b0677b61b95209bf57664a312a2897f7374f27bbdd08e58b715ce93e35608a5f71e44cde77a0a102c30ea5d222ba81765d2128b439242a0304574d6e70416bb484ea44ba25a992cf6e5dce366f67531c69d1fbdd9cc45b5b0465e822031fc0fcd924a062ffa89bbf9b8825e5dcd17f67251bee0638697f4c4361466468f6d63b31d31a8e4806a9c8f030ea6ba4d02f35e8ffe82bdefa7bd0e468d24259cd131a8a9b7340a9a7a0dd9d8b6da8413f1f898a2a3fb0367a70177aaea7892fb2a911ec79f361ad8b630c972d76264db3a68385713c4cc9e54ee55d239c307083ab0d88b0f60d89274963a4aecec3cd5c6ec498f4e7bf5890e5143a75533af865bcd5cdf9b283d4f1207e1e320490b88dcf782666dc96e1336488f9b91094c6faf1e82c439b4a03dc48c496947c3802200c3cf93eb4cb8f1d050ea491d2dea9b477b3e1f830794130c06b76002d71e58c93a86b5176bd5daca20c4dbfc490cad46e11c65948034325f9006423449e05411b14121ab2051818e3b8200c51a37c910b024f481a909dfc7120ff512fe0e0e223d301808bcc6e07eea54b6f0c412d1a7d04d0d8692f017c6ca1233c1aa1c5aa96fda4668de636998443bc1bfffde34c1a1262c0042ccc110d89943c382540e238ba229c9e78098fe80255957062c117b658b698794ba1bb233a480a1a4a5a84ef1113a55940c1354cb86a413f3dee6b0756ba78e69b3c823136fdc9000e01ffe388375c9266b03130a134760a52d762e448878cf41f9d9b4a79433958845b9278038d00c58a984bdc1d3ad9152abe0d5328324bfc38c6397c86a791ef166b922f8c63e0fced7060911f415494c3730c44900750a94a784a1641ebe52e756fa86ec24c2f429b1ef1131d9d34768d03e7d46895db98bac887b5b30312e6e94d9d956130606079459e6b27b1c66cb1abda6c67563418d12be6ba1452586d1be6558d7ba3d9524c7c3aea422d1a058ae24431f9098d1d5defdc1b76a9e1e404af42276d5a4157ba9416e0fdd36abbbb0ce0c75fd85bbe9253ba5a8afce6c329cc044b082e35425ab42aa405c3f36765ad1701bb21f25684f1224cc3928694f5315f4084c25ce66ae37f228c65c5473baac80c3838f80431c62008d10a0143400a17dc0e6198206530561621346598eea38ac9bf5b8dd7c459ffd307d5c81ffbc0520225d62284f1a8c6c7bcbd90299341ff4a69c9ac17a16e97e1cdb30952f6839c3cd5a0ece73084a05276820c35d9bdf390313f54e8e2acc60283499653c8e147af42ea3300d4ce2c2a6cf1669e3fe3358317ece843f19f499d662300e6fd88dd58726cba0714a0bd36a699ef5d042f7e2ae66dde56cdea36dd8e968e6af5edb03488a15ece9866872af244dd9264ae19a2fbf10497aba32bb1796bacfb36c06b70f2c9fc1784b42cbbdd0c802e0742c0c40c64b95096d7a5da49aab8bae6bef47e858f700b4d954465ba1ccf3cb11a2909a4d9a857ab23841c0ad2212bd330882e916779de03fa62e5b91eb08d397e2f5691eab6e5f1b6bdd735f7b450fbb67cacdbafbbd9ad3ddb42bd935cefa3c72bc15d7e99117b7179bca9bb6199beaf5f1ec738086f858f1ec1b4a5b3c7b1adb5a0f6433d8ea757237e7d9e95a7872e2a17950b62e92bd0b5351b83566483329b544043a2c8a537b9db1e0fec7817c1fe3193c1057a81e72f42882fdc1e8ff7ee6ce6f87ceff6e3bffe5fc7df8cbd5ced6b327d79f8f5a4d10c2b39fef4e559b7dae86a9cadcd786b2dc7f3fc34f4300756c4013f4e6c46e09b02cfddb62c85e26ee2abe3768968296e4be9f59b26469b7ba89ab816d5d454b5e5273e40dea22e364eeb3adb5d6818bde721bff3781d4d767be094c0973ad0a52166460a63ac91bcf9ee43e3219af3e18649bcd6ef256ea23935b8c3c80ff3cc07663b8b9457e32db7036a914afd868431f84d9f8fb66698cc05f2ca14a832bd67ee0e5765aee0d8f66cbf49c2defd674153f296d3a286a397cb18a82a30eca2aee1fa3e35cc9a56accd6bba122cb9275e5faec936a274be036fd644b730d85bf539fb8c0e049d08c1215d1e1f718d82c77a65d2dc8570367594679f048e0823064282c9104fa1622451bffd84c639631c6113070c0b22fe74cb27c606c0fd93bbf6e49fd6050965e0f6f4d974e3d54e0cf9ad88748acfebae893495d297947bbf055aaf5b6364aed9acc8ea674246cc36cf697cdf21065117db69d4a66a5d61201b53ab54d444fab3d65fc003ec9fee0e94736271e2c9b95fe5397b227515f2685f9ba1431dc808ed8536604de49586642f4e7d43e41821b59dccffa1bdc8d18f40bc350d556a6a4d29ee198d372eaa75a2ca6b04cd954574b6d962582d2ac2fbaa36b3685086eeb845a457483874db49aa352c6e41e6c8e9fba5041319ebb4549bdab15f29d95cb44ff1bbcfe9ead1ac06449d02d31599b42bfab6abefb33c9a5ec51f544b86df9b23ee944634434199f8d6564e73dd9c46398de973676d0f2440f2499e0e4738301fbe6f02d7d19d0aeb90d31d325f0ad327dad3bd46660b3395132278ae8b705c1ab439626af782db4e34e6819a6b5f089113e49190d48a7faf37b74d52b99cdf7313f0e7f9c115cd966071d51a3945756b00bf60d6ed2ad30f9cd2fff4554bb9178740a652bb9d940271c6be24fc297d7b83b258f8162daddc26d2edcfd9a87788ec242461ff9e26c68a2ec854d636c7503b0001a5c1ebaaa36884b5f19cd0fbcaec9922d6cf7b5d3b88fc96b1b7e2f44d866ed166bacec6ce68d0707f87f3ac14b9552d1a02d74604fef157edfd86a2d76523658773e5dfcab48d7261fb3585e39c762ef3d82a5009c973326702c9ee5d8c215cc7e9ef676c19d22004b9dbd1a8754c1cc40cc433d4921c662d61b92aa430d13db0df04f2ab6d0d17198cce4c78f2a26d0dfd0e85fc3d660a209fa9c0a6c38e593af4acd677d042b45bbe9486e723e219205a75dd27a371564e38e297542904454314eb120dde9e2415db069f1fba21782a697a83ae7913b63e20377237f91b5c6d86c1a936dbf34f20936434fed37d8cab1f902c3fcb119baea66e8ad373f4ffb7e16ef0e363fd34fc3b5ec7c265f1135f77ce7b3660e957620f3cfdfad798fb12bbef1f1ade0464b052f0c8a800ee1e0797ef6065c7d0503325bc0bace1451cfd672411ec8bb5b25fa1dcdc3d77402cc0c0bf07c3207f225ff702602effb710802f53a8ea60a9711bcd70d5498cb886d7c2f9f8ffa44239104c5de56b3d50a642881d49b1020a4eba7cea9482e171522b8d9bb2c68db2f5a8bf469e8efc6646a82ed93b1cd1bae612517fe299887c2443051306b0cf8077ca7802c91b4a41f616afddd982c75c83ea52cd9dcbf96759122e4e1da9756a85615a74287b711a8225c7de9816bdc6d68b4b6c843f5604c400983debd09de64fb5e39cdf0b5ade10d96442b0ae429b65857f0a1d913b81ff4b35f7a394ecf7c36d0906a1c06c16a74acb65a332def2329936f122da3a5adb232316bcdee11351b955f067072a0bf469b2cd5686714a8e8913d5846933281d39b043733be6af0af14c6bd230b36b15081d8ef4e6e68b5a65dac48361870988dfec998ec9d21ce02640fe368866786ec3d57dc8be9c159b43e98d5790491b5437f4203cb984ba5bd466cd3c2beb655d2d532acc3ac520df31c94fbab9a9b0ef37ffbf6ed9b33dab2032c9a2c0523defe70d6a18f93a9c78af748037facf5ec8cbe38fd1cbc72237403c9a83c29eeb990959afc1b90f03050c162ae62033a894f6da495b2393471e0e98a96eae927b353679a8d6e69bf5a586af47973c2be178b1e27acfb2521c09bc8e97af4e6047ac63d95813368b98b4c3da7f1d64ce5aef0c9f3521c594476cc0d0bc126686b11084d59f19af229b5ce44d33cdcbbfb43697c703da9a7fe3582e2abc691ad52d0a4145a62c9b16e8c22138a63ee9e7b5a85f8e96ebcba97bc3e178bb1e21a1a4fb86fee32e4ccb82f0033fa3f4bf4bf5a18fad0f7d5256bd5a37fb95d78ba94c6c5dee676f522c45dfbb83837d2d8835a1e97fe82ae731777c934cc035dbe047e0aa12b144cb3456d9991bf25f7b47918661ba1d0c5243b28ac7138fa2801a810ecd81e2af230b351764e2cd46a4e70d1f56f3a6e92cc189f721994cf1594ce3a644fce05f763e1c4dacff350e1b0e5745c76ef964fa75a4ce96432f19601f64a8ec0c5635002fe82f10b2006055f78c4aebe806ebfb8ae80b19a6a2dead4647bd392e78d1617525c563f547a5a2c4435943c9678a44148435dda37cefbcf9305daf7c73827bfb35f8dfdba812d040cb5f8046ab7f85d8c04690e6fc2e8dde97a54ee4f85af92dd54e3e6dfcfc8f6ee5cfc36464f187ba9dc576a6dfa163f6d8b6737e9a84f7b0234acb42cff92cdb954493dcc8a5999923c4cf8815f653ff00b3a43ccb3b483ad29cf9314e7d504e8b936b65f8f498fe74d70333f0518793a90f096b37d7a794879d03626c5137b8584b1c4cf0e6a801e537575853d9ee0c59b9ff92f981caaf045b36c2c5b56ce344bc9a5d3bc5413cacc80cdd3674ccbcb41b9d2eb7acb944659725b56073b11e6c9f00c942da540a5dee957e90b5b091be563e4796f0bc96c6b79a50ec72aaeaecf39bf702c2db34b9115caac9310827a4c9961b653c2324da145f9b2b80ff399e517cbd392e56f284316ac03caa1d68f9e3e1b86f43e5a604dcac6e0821ee2be9c06bbccd979168247311348cbfd017e690196142f9aed0f1e3f7b36181dec8df5285784858fbba4ea6fb693c2ad53a7a0b48c1ea9706167ea4b171ebf668fb6779eb0eff8b91ab3e74a4fb3db5913856b3b6e0f1d61f84182742b6d76b325a4ede87bd7570ae392078129190fb906667e2ec5980243b2561e781ad68de33898f17963051dcd62cd0e3fe0558ed3173fb233773607aa35d68d3d2dc152791e47e7b0aeb8f0dc54edb908d899f466aa71c0e7404e0f833b33e9cbb0b183bf826520a18b69ac3d633047412913e5a84886b2a25c997edf81701abc238637e4aa232555404fb16329e6cd147ec9b50baaeaf837c9bd667a584c4381a4c58f0ee8c65aa70b90f7b31830bfe08d70bc85b2053b5520f52d90fe4d884802323ce081e84bb5e2630bdf17921a06ae1fd3f1e012971b35892e2939946664bed2a13dcc41a52605aecf2148b2899692a84e950f8bee10e468642db5bf2a3caa30d57c3ec7417e80d218cc1f4c0fbac59a64f1114b9a611c11046e58ca225a1d128dc4b18cc6b17b2e221af61c5c0bc9c1e11e8192fb005aacf262d9c8c73c90204200800ac1c8153d06c7db6ac3a952535f50bad470640230a517ce540105b2e7f6517708df335b7115b40b395a2dd54714df70b93b039b257f1ef93a6e1ffe31901a81672781bbd298bfc6bfc6238c1ef878f4627050fedd3ee01376049311a0d2673f44de4a638227e0451ad11517c2f7c640e0ca9b25b3bb0582a9413e3dae63f6564b7c0af82ac35fc848c7c1e83dd7806fe147cba0abf2318a062cd3bf9a447c0eedefefceda91da7688a2760ab7bae710f111d1186c7eb0e47848580d0e9ea7bf9770a91de82db877a064ab23a57a29374df08771c1588cac0590e086875d87bfdae370547ad052d1c914d70d9a3868f18a1e83fdfa3e167ae13c1a6e0f1f77d7cec836fad58c721a76b6b3290e51424d07226158a9003e057ddd00cc9a680e74fd7f000000ffff010000ffffe80134f3b2a40000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec7d697723b7aee0f7fc0ab65e92b6efb824bbb7cc38b6dfb8edce8d93f472ecee97c9e464eea1aa2889716d5d64d9561cdfdf3e0058fba22a59f272dfcd876eab8a1b0002200092a8bd27c7ef8f3efef2e10d9b69cf3df862ef89657d311ab1a3209c47723ad36ce368933ddbde79c17ee0e7c198bd0ea229e3be03357c1dc971ac8348b10d2504d333c18edebffb787af2fad3c7f7a7676c225db139c4ee0e5d9751778a454289e8423843f64909164ca099544c0571640b66078e60f0380d2e44e40b878de730187b7bf2d1527aee0aeccb95b6f0150ec735b3a1742cd824880124e9130c3f9d1cbd7977f686861f7e6159801522c75cee4ff707c21f307f6af130dc1fa8b96fc3f0fe945ed98851e0ba22da1f9ca525473a7207cc76b952fb03ace406fc7c805d0aee1c7cc1d89e273467f68c474ae8fd41ac27d6ff1ce40533ad434b7c8ee5c5fee0ff589f0eada3c00bb996635740b730a2f0a1d5c99b7de14c45a19dcf3db13fb890e2320c225da87a291d3ddb77c40590c1a2872d405c6ac95d4bd9dc15fb3bc3ed5a478e507624432d03bfd057ad1a8ff52c886a355ce99fc3c4b9403128d676ac99b4b1a7592426fb8309bfc0c76108843cf8021b68a95d71901191fdc9aeaf719edfc1fcbe839136366f6ef646a6563680e96c1c045ae98887235ba951f634f4a43f843783040ee4063513420faa1d4440834b3e5f50999e999e8780b116571a47a212c6c6813367d7f493b1903b0e406f8d03ad036f977db31d5e7d9b944d8042d6847bd29defb2c1f7c2bd105ada9cbd13b1186cb1ecc5163b8c606ab698e2beb280f5e5c47471f305fd99ed6cb1d933f8f71cfebd807f2fb3e1cb439c1ab4a0ef15468bddff5118c0e3d154fa960ec25db6337c29bc52dd2192c6f2023f502107d96c04ebadf0dd608bbd0d7c6ec35f500a2a005901208f40a2a58800c44b8030eba63204073940c17350a49d034d52a5a303e4ea7a29ce4e7be90478a5bd34ebd959d8736369d6b39351611c448e880cedfcc0afe0e506d3a042e65db6fd6d99af0a6fa81beb65ce5e61a0240aeb2e7230a88b8bea005269cb0fac710cfa4a6743d16b626f0bd9db8056690888b9b1e7676d1ca94297c35c4a1fa448586337b0cf533840ea8c9201ee4ff923631cd2e8c03a79c198dbe7d30895318e124400fe74bcf1ecf9ab2df6ecc536feb7b3f96d9982117764ac76d9f302f2297d76c22bf6227f9f12f219bc7e96bebea9e2056ce60f1d0e3aadc2e7ae9800b4db39a397d0dbd9ce5f13e773574e91fe88e4b7ddb44a099cae1175fae25cb027d24385ce7ddd2009b07c65cd2e67520b8b64069b5e820e2ce99e4b61a8ff627bbbb127a7a6c60cfecf40897541e10c95c75dd72a51b115a0a4f1fff6842339dbf0f85542d36f5e7d135e6d661d2472050640086a0258fac0bc294a5f5699b1d1df80f7c10cd08cb36c1960b0c86a5c51c4703adccdeab2bf015122d0326358f35938034a2b102a064804970ca76a1c097eaed0447003681e89300aa08d0b2c3852b07883ad7129f5acd8a3e12735647f1b65af2b4488804ce9acdc64ecb837221104236164ac842ff608432c72e445d5d67873014b2dd919077b2328374b281862ec63108248450c6d187ce7f38bcc14e1175862fea01a4a7f3a62c263172c06e85e503d39e5b4ee9b158e20483a41283810274aca706d04e9298f618d23b0f70036e94dd312d46f03a622dbfcb448605ebd200b80cd8833f707cf9f0d98b156063b3bdf0c46801df69e0d1556c6c14ed84c3aa075ad2b58909b4c86306b1dbb85e629f2859f24b7195e642220e1255808713805ad234efc4930f4c565017daa0836ad0efcc43e300f990538d67e3a00fe847f39c18df9614c493052cfb3813636cb0314693c75e7e10cad2796fdb2ec99b888e06f1c0e529a7d2d3c95c97fde098884af607d10f92feb82bb31fc2f220593be3fb8be2ea28b3594beb9191c7c326f81c7d8f55749edaf6eca5344038d0c090a941cb9b24cd70417270a4227b8f4cbd8f28430ff31a8d603b69d4ed10e463d933c147ba9e078f0c691da00f8f96b7f0cf4d81b679c0c12ac915a63f8c74be3e78c928deb093f2e0149681c64a016e71094e7a908039cc3ce899b394e65c6aa281c3a0ec3ee60750fa2795215212e13b50b22148a5e1001552e85a14c0754d865173c1921e58574506c96801a16077d6694b7ea05ba1d4c3bc04ebbbb1d19657f2a7e8ed031ed8266064bcdc9f15dd250cd628d0cdc0be86032e984d874773bfac13aae79a47bb2e104aacf3ae039353dde2505f93888fb810c2b77a42de1857ade253dd8e702a0f746b1dbac3df39264e1c71fb0bc98d5be65a136f5d13cf84e464ac33a7fb9c502df9d3370ce2f7d2627cc17b6508a47f36f59425376c9231feda6c494c82d115c109f40ff13393df1d163cfd434749cdb0525605ccb73ac9d67c5d5b5500e74102ea3ffad64d8f28a50ad8bb476a8d6deec79614d2bd5a160c120e511702b85231c30b09e1f64b46b1f00cdafaac20f0b53f87186b127a4411c91b1c4665cb1b110e04ef00b8c43c51acc3d30456df0c5a08533647974c38b711a12c0d0ea4c2a51340a0c8c72d7c38215539afa76f0d1ffac58293dec14344e9457b4515808ee626219ddab24574d881a4bb9206d1379356898ccf28bd263e121b79ccbc221a6b10b7632f07285f54b4c9ef6870df3e599dc69b681c635fa4e9b790f8d02f16a913c58e8168703261da4773282146ab1642452747d8d4d8eb060037f0d4f8ec11aa6298447c1b5e913bd1bfcfb13805db139174a5da91ed404216c12bd4a3532ed4a961bd0c1e5a14a0dba106c328c21fe4709dfd41ac49780d897d277c4151aa4b5ee7b58ca45838b192a016d6e6ebafacae5a0e0702039153881f6cc90f34c731de7046f84b06e88679d58973301f677ec9ffb64cd7e323fea1676ffbe14b0622800e533f363a5be6cee1bd57c96fceaeeadd607a8c0260e6a818102c21d0331b6717d8dfd7e10910decc3a7a2c0f25f6d3643b734e4d269e4e866b04fa0f23dc2dc5652716ccc2b58ffca625ed59f89e4a77aa7287265294fa59765625c1badcfba5aad580dfa340bba093c159bb04a143679563a922402cd44d569a0a5b9346a2bc2c259f7ea0753dbb9f265ab47c11780be170cec6488631825095c14b419b4775a711ab523b53abe26406605a1f03bf0fe8e6aae01e16319091be9b712dea965eb81dfe6fe9a50f2b7a1f42fb82bdbb8a7375912abd65272da4597375114ac4896661c1e922da66e30ee7287ff0e75b8db14ec580711a6d4fb77d2158afdc9b87bc9e7ea5dec8d45747353d3df520384c9f05bec9f2d9dbd9e6bea6c2c7d8edcf7fae1e83b0bbc2ef2fe14d877475d173b5f1371a9af47445bdb0d62c7c2b0871bf0ae70dd7b70fbde4fc8d55b85c0edf5798ba2f2c1bd351370c0b6cb21a0e0127ddfdc2c4da31cf569cc3b597916b1ab8649ac192405d452bb6b2176fbfb80dec176073cdbecf562fb8b98e681180ab7003bd8e82d57e0bf93b4de091b355afb4877a2f829f879ef7d170cb55f84eaa2636b574f2a7dbd0b1eef94c4be3d13f6b9e812ef93a91f448281d9ee49851b20ea01a6c7008130a875cc50a9bbc73c49bd234978c6ebc4070102bb670d06a6e931edf00c94a17a3822d0d6b3c5ddae1d9a33b345fdb3d4b3d54840032adad1426a6cded68c849236570b8a685bbfc181adf9a6f4ba3932d3ec28f2c511ced22e2cae958da11c5c769e6208e069250c0a8c9191c6c47cd6cac6854d8265700b23e9c18adbb4c38cbb6af964f600173c395bba5d4e4bb6d1ba34ac0ef7a7221a342e40ecebaf595f3b070f8046d2110d764eb7fa0ffb9876c900ec688620ab45f8362bd1a650cb2da2d7c5d833ee4816a2ce24076b0b3bfbd079bf7873264c850033b63e9a4c31c6fc6b7a2e6363f3b7c7136536e8a5e1657cb210ce3e5b7d45778b5d5ffbe99193046752922bc6de72783aa26e40e0bf026ff5c05ba7823d7ccb3e69e9ca3f68936dc545720ef6ba37843f8fc367d55c9dab0e021c7df8b47602d8619c84b42b1e243cfab0a246dcddddb9b9f9ea5fc49b3f4eaab153785a8d4030b62f6c24b4faf5a90e34779f62646e1c22c7780264c5beb9c1a78d96ba273eb9d31ff1b1c8649b0f4dcb5e8be7a7f02ee918c4ba3f21dfc77afd944ccd97440e00e443df0fc0ad14ef7f644ff6590cba7122fd5675d89be6787e7b16445d51e4747476867767568a2777fa95e9e91a3cfb4b0d556ce37192c122a2d40febbda713d219a4fd7cdadad81573f249cfb1279325067f48bddeb59df45fe660e66a42969cee7cccaede6d7d1fb2425333ed8edc9f95adff1e16b7313acd098fdcea6c33c0033d1311a2ae1ed3318f06037cd5f31dd5e3ab0d7d349aeb5d63359effe8383f80faa7b80225a30d711ec09545e7d60ebcd015585c2d1dfe83d62b0c3cec6c6ff73e79f029c4f364c7f932cb36a0f92aa720d682c5de5248944f7d9885bc6b04b02fc9d0dcdd5ee1d0473d42ba00f3c1c1b15449f9a2933577763aa32a307f9dce2815f6d989917ed74ecca1e300b22b85f98dc2c18e4af18107b3da03cf03fddb153f06199c4581bf16efb08ff856bdc55c9a1f945421ce7ee7be10de4c3f4a2a2f43ad9ac249c953e86cd04453daf669274b4bef4ffa768fdb40ffce1e7a954b7b38ead5267ff9eb9d54ede3b657dbdc89f7feafe1952129a0a3951791bfdcb33bdc9cc97f9a0d9a51f92201bea2137eaaf9628dc032731c7fe80a7faa67669feb616fd834797d5522bf0bb4b47365b1ca359b820f0bf440ffb540161c19ef9a8340c0dbe147e9095003e0588addc1f7bb9eb7abd4e0e6661700a15ae0ee4d22297cc79d1bff171bd10c94af0737cff71a2ed6143cc7b61de85c04e85a8be18f7e57f6baccd7f73f3ec8959a92046477d1b26be9f8fa35e548e9775b3dbd8d943c0290c24992acd4dcf18eebea6db7c0cb17bf0bfa2ba942ae42a2b43045cfee085004f72f8e941866698186bed0a3ba6c9cc521664f6023f65d10c55eebd5bf5e232b187a2af52c1e0fc13e1d6563177e4502e652095587e427bacecd4e4d85d5005940021b869906d17ce404768cde469250a06ebe158aef9c2c52a9b88928afe3055782d734780353980c5647edd7a817dff6a4ed7fa12f83e8dce8473c2a0136512a4de6890205a616e995015374b40563e626528e8a0414ed1560e8d13c9853ea8cf43ca603787a94d96366ed7a0a0a37c3238bd495ee472618e4571e9500fd84b1a9b16068db6f310018a39294be8bb3300ac0f0f028a7069b0369cc092e009de5e6e01018574773e8efeb99705d99243848d4f8de8850cea9935c2aa41b972da489b22a2921d2e33905fcf37eaa9867c494fe24c8e8509fea8c0c52b17cc8611ae1aad6ff40d2c92e7966b70c87c3362c4d5e864548c6698d053866bdac03c56cc0f560985e3b6f4530bde69ee28737d933b8b3dda804d9acb7231395104dfc9ba393dfeb8576c4baad709e1cb742289dcf206a2e8fa600c11ca3de25b2827a09545a627048520814a688cefa9cc062a7e544da24aa95c9625f7b0e57b36f8b31eefce8cd662eaa8535f2120489e17f6896543278d123eee6e30a7a7dedcdcde5a27cc1c70c2fe9896d28cc8c1ed3c6643b6250c902d5e88d7d0ea6ba4902f3391afd27f6be9ff63a183592947046c7a0a6ded22868ea3564639b6a134ec4e3638a8eee0fac9d06dca9aae548ee0689f458eeb4d1c036854996bb1623dbd441c3b99a2066f6a272af92ce193e41d081c5de5c81614bd259ea28b1b3f3541bb3173d3aedd5273a440d9d56cdbc1a6e35737d6f12445e9238087f0e92b480c87d6f68d616ec366183f4b81999c0f4f6fa29489c450bda53cc98947634f4290230fc32b9ce841b0f0da58e8cf4bcbe79b4e7f231784039c16070032670ed8191ac63587bb156adadf443bccd9fc4d06a14ce5146094823f30569204493044e15111b14b20a1215e8b82308501ce126190296843e3035e1e758e2a15ec2dfc241a403060381d718dc4f9dca169e5820fa14baa9c15012fec25859622658954323f54ddb08cd7b2c0d936826f8cf3f9b26388c080b80107330f866e6d0b02095c3c8a2684af23920a63f6049d695014bc43e30c5b4434add0dd919524051d25254a7f8133a0d281926a8960d4927e69dcd61ebd64e1dd366914726deb82501c03ffc7906eb9249d6062614268ec04a5bec5c8810f1f640f999b4a79433958845b9278038d00c58a984bdc2d3ad3a0896c1ab6506497e8719c72e90d5f23ce2cdf280e01bbbdc3f5f1b2444d0772431ddc0102701d429504e201425f37083e0dc48df909d684c9f12bb0e1193bd7c8606edcb5794d895dbc88ab8b7051363e3469999ed60c2c0e08032c35c668f436d19a357d5b86e2ca851c2772db4a8c430dab70ceb5ab7a792e478d89554241a148b9564e8021233badabb3ff83ef0d20348895ec4ae9ab4622f35c8cda1db667517d699a1aebf7037bd64a714f5d5994986e32b0d2b384e55b22aa40ac4766365a6150db721fb5982f62441c29c8392f63483821e81a9c4d9ccf5461ec5f04435a7cb12383cb9031ce21003688400a5a00108cd0f6c9e21a830551026366194e5a88ec3ba598f9bcd57f4d90fd39f4bf09f330744a44d0ce54885916d67315b2093e683de96533358cf74d48f631ba6f20d2d67b859cbc1790e41a9e0040d64b86bf23b6760a2dec95185190c454466198f75801ebdcd284c03933837e9b345dab8ff0c568c9f33e14e067da6b5188cc31b76e3e0aac932689cd2c2b41a9a673db4d0bdb8ab5977399bf7681b763a9af9abd7f6009262097bba219adc2b4953b68952b8e6cb2f44929eaeccee85a5eecb2c9bc1ea81e533186f4168b9171a59009c8e8501c878a932a14daf8b545e70d175edfd081deb1e80369bca682b94797e314214523349b3504f162708b85568d13b8320986e71d709fe63eab215b98e307d295e9fe6b1eaf6b5b1d623f7b597f4b07ba6dcacbbdfcb39dd4dbb925de3accf23c75b719d1e79717bb1a9bc699bb1a95e1fcf3e0768883f2b9e7d43698b674f631beb816c0653bd4eeee63c3b5d0b4f4e3c340fcad645b277a12a0ab7c60c6926a59688408745716aae3316dcffd8979f633c8307e20ad5438e1e85bf3f18fdbf5fb9f5c7a1f57fb7adff65fd63f8dbf5ced6ab17375f8e5a4d10c2b39fef4e559b7dae86a9cadcd786b2dc7f3fc34f4300754c4013f4e6c46c09b02cfddb7cc8de26ee2abe5768968296e4ae9b59b26469b7ba89cb816d5c45435e5273e40d4645c6c9dc67536bad0317bde536fe6f02a9afcf7c1b9812e65a16a42cc8c0547592375ebdc87d64325e5d30c8369bdde4add44726b7187900ff3980edc670738bfc64b6616d52295eb189147d1066e31f9ba5317c77be802a0dae58fb8197d5b4dc07ae678bf49c29efd674153f296d3a286a397cb18c82a30eca2aee9fa3e35cc9a56accd4bba522cb9275e5faec5eb59321709b7e32a5b986c2e7d4272e30781234a3444574f83d0636cb9d693b12e4ab81b32c751e3c12b8200c190a8b9640df42a468e39f9b69cc32c63802060e58f6e59c49960f8ced217be7d72da91f0ccad2ebe1ca74e9d44305feac897d88c4eaaf8bee4dea4ac93bda85af52adb7b5516ad7647634a523611b6ab3bf6c9687288be8abed54322bb51608a8d1a96d227a5aed29e307f049f6072fefd89c78b26856fa4f5dca9e447d9914e6eb9266b801add94ba604de49586442f4e7d43e41825b59dcaffa1bdc8d18f40bc350d556a6a4d29ee198d372eaa75a2ca6b04c9954570b6d960582d2ac2fbaa36b2685086eeb8451a0e9060f9b4481874a19937b300f3f7511f8c578ee1625f5ae56c877562e13fdaff0fa7bb66a00932541b7c4646d0afd2eabf91ecf2497b247d513e1b6e5cbbad789c68868323e1b4b6de63dd9c46398de973676d0f2440f2499e0e473833efbeef0237d19d0acb90d31d305f02d337dad3bd46a60b2395132278ae8b705c1ab439626af782db4e34e6819a6b5f089122e49190d48a7faf37b74d52b99cdf731ef863fce08ae6cb3838ea851ca2b23d805fb0637e99698fce697eb57ed15b6310c9fdc37a04b94bd38058f6b05ab7381e9a6850510b21c3043783c9048df1f42be4493bba642de05ac86d29a55c8e3a28392782cad81126754f0ef460dcda753dc8d6f22485a76b73459de2929ecdc2ec0717fffa999eba7bd3c1953f74721c23627a6586391ffd2db36c2fd15da14c6dd61dc34f6423c7e6430a16fe37136543a7b61b27f9b2515e0423fc5c1088fd9fba08ff3e6e7c41b5569db3a98a33638c0ffd3c95eb81216bda84207e6c868e1f9d6ae52b193b297b4737f41d7e2ac3705368ae595c353e6b22d98a7306ff9b4c27ce301a22d349bcc3791578b281601581861a8f16f15cc0cc43cbe9814620070bd71d03ad430b1dd00ff12c4063a3a8395f999f825cf04fabb8f89f4573fa902eda981d2ea6ff9d5e154b4aaa16ab5c7af8b32754243650727b8ebceb30692bcb8b9390b08c3982d09a1c113bc925eec313e1574a92108e0953f374e83f13510b83408d1aaf83a4881a20048b9c1259db24f7a330360d47037db3f99d0978c66788982a714c263f9e722d44cd03990e7db69e063abd2cce1f3d656d865b53ef4044d546b1b28dc62b1afa54b8d8ac46a6b7229c4f992cb4399e506076f9361e0a1f70a51e9c32c13d597b75f2baa3ddd7bfcbb26978dab45b55279c948a74fe3b5cb64a128cea39fb395b543a58a154492becfbbaa62ae42b8784d69544665649017575c51fe5534f7112c4759acb45381576a2fbd2fd5dcd1e0801e0b31f12505b4dc5b594e2b65ab8b6ba5c38733f35a2665a11057ea9665398b8a831cdb3423c5d5b43b2ebe0ad4fd64b689ff0cec06de7a5cff0eedc1859834d8868b91288b00dd32339723a7b47b882b2c946f3f4e95730b0d901a58669b3a33b796d9a46eeeabbc1d56d106e59ab7dcb36ec161b1e02f34e5685ff992aeaa6422975f26501a03d35be8395c0873d49a8ef5c614a6f450381b0cdde48477e1eccc7af7adaa875b13a6ea73afade19e4a0e66f36d15c14ae7b5e8526972c25ecb02969222b65341bb34634afee727678270a7dd58eb365e3555c2871612288aba811406d8f8f68c892b6e6bb0f3d3d678ba283d55d49ef6a0e930de9a8ff3529afeea71de8286f9eb38efb2c779573ebe9b4cc9a33cbe9b7edcbce5ecae4a8a1ff9d9dd9ade2c9da1cd3fe0bee653b25d3bf4f7be8f63964f4c79237cba468237d2d98728d0010cc84c01ebba15433d9b35147920ef6e99b5507be17bbac3a4860578ee6d0b141cb733e13b3f8e4310a8f7b19e06b88c606632a0822735dbf851be1ef5394f832428f6b69c7750204309a4de8400215d3f754e45921ea37006297b97db97bdce1b217d1afabb35999a60bb37b6f9c02358c9857b0a3e86505a514c8801ff8039e793259296f4234cadbf5b93a50ed97dca92f97a8d615da4086d9d999746a89615a74287ab085411aebef4c0356e151aadedc44cf56a874f296f3f7df03f642737739ae16b53c3192c383d51204fb1c59a77351f25fdccb74a8fd35b8b0d34a41a87bebf1c1dabad1e6687f85e49997c5577112d4d95a589596bf688a8d9a8fc3280932be935da641fcbe88c47143db2278b685226707a17fe76c6570dfea59cfb07b260130b1588fde9e496566bdac59264830187d9e8f7c6649f147116207b18eb19de7a31999af034610fcea2f5412dcf2388ac19fa1e0d2ca52e83c869c4362dec6b5b255d2dc23acc2ad530cf4179bcaab9e93afaf71f3f7e38a3fd54c0a2c95250e2e34f671dfa38997aacf88834f05dad6767983b8fbd06af5c89a88164549e14f75cc84a4dfe0d4878e807fedc0b62053a09b73e31a845f9089b38f074494bf5f4deecd459c4462bdaaf06961a7d3e9cb01fc5bcc71d61a7571a3dcca595ae471f4ea067dcad1b5883966c5ad4731a6fcd54eec2c0657b426125b41973c340b009da5af822a2bcee4d19815b67a2691e1e5d068c343eb89ee4c9ff3d82e2cbc6918d52884829b4c492e3a8318a4c288eb97dee444148bb701a53d2d0eb73311f073c82c613eeaa870c3933ee0ac08cfecf3e55b75c18fa104f61b1563dfa9fab85a74b89484d3e323b9a8778062d2ece8d54e6aa91c3a53ba78464c55db208e681d207013f85d0150aa6daa2b64cc93f924c633c0cb32d48e86292ed2146381c7d560f8fb841c7e65a8c83b979b39b4e61147804172530a30b13c98cf129977e7907b2b4299afdb2e89cb715476e9e4919872d2794369bfe7c3a8dc494eed6126f2960afe412573c0625e0ce19bf006250f0856b76fd1574fbd54d058ce5546b51a726db9b863c1f227121c565490341f969b110d550f2b3c4230d421a46a5430779ff79ba7bf3fe18e7e44ff6bb32dfe73385806124ee41ed16bfec9820cde14da83f9dae47e5fe52f8aef66d356efe05c86cefcec6af3bf684b197cac50fe4ac49dfbe130233319ad3a2ed29bcb1d2a20cc2266b70e5e339ac985738c924fc3ea61b89b49f748237da52eddbfad1aee4235dd54f78e5dad87cff34bd6036c1cdfc1460e4695fc25bcef6e9e52165f2de9814ef9c153e7942fc6ca106e83155d7d7d8e309a68ef895ff86e98d0bdfe4cec63265e56fa5d0e791d2ccca13ca2d88cdd3dff861190eca955ed75ba634ca3ecfc2ea6027c23c199e81b2a58f7850eff454fa4674c246f918f9975b0a9f63a965463e1c0771757dcef9856369995d8aac50669d8410d463ca0cb39d1296691268caf8cc5d98cf2c43769e583b7f43399e611d082c6afdece5ab6148eff51c6b523e411bf41077e5d4df65d6ceab103c8a99405aee0ff05b81b0a4387ab63f78feead56074b0378e46b9222c7c9e34557fb39d14ee28750a4acbe85110cecd4c7d6dc3cf6fd9b3ed9d17ec077e1e8cd9eb209a66f945f213d647187e9020dd41a476b325a4edf276d777f6e39207811f1538e41130f36b29c6141892b572df8960dd388efd19f71a2b447a1647ecf00a93119cbef9999dd9330fa8d6583776220996caeb589fc3ba62c3efa66aaf85cfcea4330b1a077c0de47430b83393ae0c1b3bf83b580612ba98c691a31466d92b7d4b6154244359512e4dbf1f4038e90019e678a98e9454013dc58ea5f09a29fc964736a8aae33f24779ae961300d0592163f9b1735d63a9d83bc9fc580f9056f84e3638c17094e0390fa1648ff4b082d0119ee735ff4a55af1670bdf17d2f2fbb61bd305d71297ab60a22fe94a43c4c87ca51b4078342d9814b83e8720f91e46e93320d3c08545770872343296dadf033caa308db8e7e1203f4169ccf1283e3fd8624db2f88c25cd308e0802372c7d07a33a241a8963a9c7b17d2e340d7b0eae85e4e0708f40c95d8116abbc5834f231f725881000108460e48a1e8363be95e13408a6aea00f7e8423e583293db7a6015020fbdd3eea0ee17b662a2e8376e12b2386ea238a6fd8dc9e81cd92ff1eb951dc3efc73203502cf4e7c7ba9317f8f7f8f47183d70f1e8c5e0a0fcdc3ee00b760493e1a3d2673f6967a931c113707484e88a0be13a632070e5cd82d9dd02c18c403e1d1ec5ec6324f197cf9719fe42ea28f6479f7904f8161e5a065d968f51346099fe5d25e273689e7f386b476adb228a9a29dcea9e43c447e831d8fc60c9f190b01a1cbc4e9f1770a919e823b877a064ab23a57a29374df041d9602c6a630124b8e1e9e8e1efe6381c951eb454b432c5758b26165abca2c760bf7f8e4534b79e0db787cfbb6b67641bfdae46390d3bdb9924fd28a1aa039130ac54009f82becf07668df680aeff1f0000ffff010000ffff9a7216a374b30000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["index.html"] = bs diff --git a/gui/app.js b/gui/app.js index 4b9b0814..b2a241ed 100644 --- a/gui/app.js +++ b/gui/app.js @@ -686,9 +686,22 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca }); if ($scope.currentRepo.Versioning && $scope.currentRepo.Versioning.Type === "simple") { $scope.currentRepo.simpleFileVersioning = true; + $scope.currentRepo.FileVersioningSelector = "simple"; $scope.currentRepo.simpleKeep = +$scope.currentRepo.Versioning.Params.keep; + } else if ($scope.currentRepo.Versioning && $scope.currentRepo.Versioning.Type === "staggered") { + $scope.currentRepo.staggeredFileVersioning = true; + $scope.currentRepo.FileVersioningSelector = "staggered"; + $scope.currentRepo.staggeredMaxAge = +$scope.currentRepo.Versioning.Params.maxAge; + $scope.currentRepo.staggeredCleanInterval = +$scope.currentRepo.Versioning.Params.cleanInterval; + $scope.currentRepo.staggeredVersionsPath = $scope.currentRepo.Versioning.Params.versionsPath; + } else { + $scope.currentRepo.FileVersioningSelector = "none"; } $scope.currentRepo.simpleKeep = $scope.currentRepo.simpleKeep || 5; + $scope.currentRepo.staggeredMaxAge = $scope.currentRepo.staggeredMaxAge || 31536000; + $scope.currentRepo.staggeredCleanInterval = $scope.currentRepo.staggeredCleanInterval || 3600; + $scope.currentRepo.staggeredVersionsPath = $scope.currentRepo.staggeredVersionsPath || ""; + $scope.editingExisting = true; $scope.repoEditor.$setPristine(); $('#editRepo').modal(); @@ -696,6 +709,11 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca $scope.addRepo = function () { $scope.currentRepo = {selectedNodes: {}}; + $scope.currentRepo.FileVersioningSelector = "none"; + $scope.currentRepo.simpleKeep = 5; + $scope.currentRepo.staggeredMaxAge = 31536000; + $scope.currentRepo.staggeredCleanInterval = 3600; + $scope.currentRepo.staggeredVersionsPath = ""; $scope.editingExisting = false; $scope.repoEditor.$setPristine(); $('#editRepo').modal(); @@ -715,7 +733,7 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca } delete repoCfg.selectedNodes; - if (repoCfg.simpleFileVersioning) { + if (repoCfg.FileVersioningSelector === "simple") { repoCfg.Versioning = { 'Type': 'simple', 'Params': { @@ -724,6 +742,20 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http, $translate, $loca }; delete repoCfg.simpleFileVersioning; delete repoCfg.simpleKeep; + } else if (repoCfg.FileVersioningSelector === "staggered") { + repoCfg.Versioning = { + 'Type': 'staggered', + 'Params': { + 'maxAge': '' + repoCfg.staggeredMaxAge, + 'cleanInterval': '' + repoCfg.staggeredCleanInterval, + 'versionsPath': '' + repoCfg.staggeredVersionsPath, + } + }; + delete repoCfg.staggeredFileVersioning; + delete repoCfg.staggeredMaxAge; + delete repoCfg.staggeredCleanInterval; + delete repoCfg.staggeredVersionsPath; + } else { delete repoCfg.Versioning; } diff --git a/gui/index.html b/gui/index.html index 1a81cce4..f9514d0b 100644 --- a/gui/index.html +++ b/gui/index.html @@ -540,14 +540,25 @@
-
+ +
+
+
+ +
+
+
-

Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.

-
+
+

Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing.

@@ -556,7 +567,30 @@ You must keep at least one version.

- +
+

Files are moved to date stamped versions in a .stversions folder when replaced or deleted by syncthing. Versions are automatically deleted if they are over the set maximum age or too many files are in a interval.

+

The following intervals are used: for the first hour a version is kept every 30 seconds, for the first day a version is kept every hour, for the first 30 days a version is kept every day, until the maximum age a version is kept every week.

+ + +

+ The maximum time to keep a version in seconds, -1 keeps versions forever. + The maximum age must be a number and cannot be blank. +

+
+
+ + +

+ The interval to clean versions in seconds. + The clean interval must be a number and cannot be blank. + Clean Interval has to be greater than 0. +

+
+
+ + +

Path where versions should be stored, leave empty to put them in .stversions folder in the repository.

+
diff --git a/versioner/simple.go b/versioner/simple.go index 3080a18a..bdb0e047 100644 --- a/versioner/simple.go +++ b/versioner/simple.go @@ -47,11 +47,15 @@ func NewSimple(repoID, repoPath string, params map[string]string) Versioner { // nil, the named file does not exist any more (has been archived). func (v Simple) Archive(filePath string) error { _, err := os.Stat(filePath) - if err != nil && os.IsNotExist(err) { - if debug { - l.Debugln("not archiving nonexistent file", filePath) + if err != nil { + if os.IsNotExist(err) { + if debug { + l.Debugln("not archiving nonexistent file", filePath) + } + return nil + } else { + return err } - return nil } versionsDir := filepath.Join(v.repoPath, ".stversions") diff --git a/versioner/staggered.go b/versioner/staggered.go new file mode 100644 index 00000000..4cb42d35 --- /dev/null +++ b/versioner/staggered.go @@ -0,0 +1,313 @@ +// Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file). +// All rights reserved. Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package versioner + +import ( + "fmt" + "github.com/syncthing/syncthing/osutil" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "time" +) + +func init() { + // Register the constructor for this type of versioner with the name "staggered" + Factories["staggered"] = NewStaggered +} + +type Interval struct { + step int64 + end int64 +} + +// The type holds our configuration +type Staggered struct { + versionsPath string + cleanInterval int64 + repoPath string + interval [4]Interval + mutex *sync.Mutex +} + +// Check if file or dir +func isFile(path string) bool { + fileordir := path + file, err := os.Open(fileordir) + if err != nil { + l.Infoln("versioner isFile:", err) + return false + } + defer file.Close() + + fileInfo, err := file.Stat() + if err != nil { + l.Infoln("versioner isFile:", err) + return false + } + return fileInfo.Mode().IsRegular() +} + +// The constructor function takes a map of parameters and creates the type. +func NewStaggered(repoID, repoPath string, params map[string]string) Versioner { + + maxAge, err := strconv.ParseInt(params["maxAge"], 10, 0) + if err != nil { + maxAge = 31536000 // Default: ~1 year + } + cleanInterval, err := strconv.ParseInt(params["cleanInterval"], 10, 0) + if err != nil { + cleanInterval = 3600 // Default: clean once per hour + } + + // Use custom path if set, otherwise .stversions in repoPath + var versionsDir string + if params["versionsPath"] == "" { + if debug { + l.Debugln("using default dir .stversions") + } + versionsDir = filepath.Join(repoPath, ".stversions") + } else { + if debug { + l.Debugln("using dir", params["versionsPath"]) + } + versionsDir = params["versionsPath"] + } + + var mutex sync.Mutex + s := Staggered{ + versionsPath: versionsDir, + cleanInterval: cleanInterval, + repoPath: repoPath, + interval: [4]Interval{ + Interval{30, 3600}, // first hour -> 30 sec between versions + Interval{3600, 86400}, // next day -> 1 h between versions + Interval{86400, 2592000}, // next 30 days -> 1 day between versions + Interval{604800, maxAge}, // next year -> 1 week between versions + }, + mutex: &mutex, + } + + if debug { + l.Debugf("instantiated %#v", s) + } + + go func() { + s.clean() + for _ = range time.Tick(time.Duration(cleanInterval) * time.Second) { + s.clean() + } + }() + + return s +} + +func (v Staggered) clean() { + if debug { + l.Debugln("Versioner clean: Waiting for lock on", v.versionsPath) + } + v.mutex.Lock() + defer v.mutex.Unlock() + if debug { + l.Debugln("Versioner clean: Cleaning", v.versionsPath) + } + + _, err := os.Stat(v.versionsPath) + if err != nil { + if os.IsNotExist(err) { + if debug { + l.Debugln("creating versions dir", v.versionsPath) + } + os.MkdirAll(v.versionsPath, 0755) + osutil.HideFile(v.versionsPath) + } else { + l.Warnln("Versioner: can't create versions dir",err) + } + } + + // Using keys of map as set + clean_filelist := make(map[string]struct{}) + clean_emptyDirs := make(map[string]struct{}) + + err = filepath.Walk(v.versionsPath, func(path string, f os.FileInfo, err error) error { + switch mode := f.Mode(); { + case mode.IsDir(): + files, _ := ioutil.ReadDir(path) + if len(files) == 0 { + clean_emptyDirs[path] = struct{}{} + } + case mode.IsRegular(): + extension := filepath.Ext(path) + name := path[0 : len(path)-len(extension)] + clean_filelist[name] = struct{}{} + } + + return nil + }) + if err != nil { + l.Warnln("Versioner: error scanning versions dir",err) + } + + for k, _ := range clean_filelist { + versions, err := filepath.Glob(k + ".v[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]") + if err != nil { + l.Warnln("Versioner: error finding versions for", k, err) + } + sort.Strings(versions) + expire(versions, v) + } + for k, _ := range clean_emptyDirs { + if k == v.versionsPath { + if debug { + l.Debugln("Cleaner: versions dir is empty, don't delete", k) + } + continue + } + if debug { + l.Debugln("Cleaner: deleting empty directory", k) + } + err = os.Remove(k) + if err != nil { + l.Warnln("Versioner: can't remove directory", k, err) + } + } + if debug { + l.Debugln("Cleaner: Finished cleaning", v.versionsPath) + } +} + +func expire(versions []string, v Staggered) { + if debug { + l.Debugln("Versioner: Expiring versions", versions) + } + now := time.Now().Unix() + var prevAge int64 + firstFile := true + for _, file := range versions { + if isFile(file) { + versiondate, err := strconv.ParseInt(strings.Replace(filepath.Ext(file), ".v", "", 1), 10, 0) + if err != nil { + l.Warnln("Versioner expire: file", file, "is invalid") + continue + } + age := now - versiondate + + var usedInterval Interval + for _, usedInterval = range v.interval { // Find the interval the file fits in + if age < usedInterval.end { + break + } + } + if lastIntv := v.interval[len(v.interval)-1]; lastIntv.end != -1 && age > lastIntv.end { + if debug { + l.Debugln("Versioner: File over maximum age -> delete ", file) + } + err = os.Remove(file) + if err != nil { + l.Warnln("Versioner: can't remove file", file, err) + } + continue + } + + if firstFile { + prevAge = age + firstFile = false + continue + } + + if prevAge-age < usedInterval.step { + if debug { + l.Debugln("too many files in step -> delete", file) + } + err = os.Remove(file) + if err != nil { + l.Warnln("Versioner: can't remove file", file, err) + } + continue + } + prevAge = age + + } else { + l.Warnln("Versioner: folder", file, "is named like a file version") + } + + } + +} + +// Move away the named file to a version archive. If this function returns +// nil, the named file does not exist any more (has been archived). +func (v Staggered) Archive(filePath string) error { + if debug { + l.Debugln("Waiting for lock on ", v.versionsPath) + } + v.mutex.Lock() + defer v.mutex.Unlock() + + _, err := os.Stat(filePath) + if err != nil { + if os.IsNotExist(err) { + if debug { + l.Debugln("not archiving nonexistent file", filePath) + } + return nil + } else { + return err + } + } + + _, err = os.Stat(v.versionsPath) + if err != nil { + if os.IsNotExist(err) { + if debug { + l.Debugln("creating versions dir", v.versionsPath) + } + os.MkdirAll(v.versionsPath, 0755) + osutil.HideFile(v.versionsPath) + } else { + return err + } + } + + if debug { + l.Debugln("archiving", filePath) + } + + file := filepath.Base(filePath) + inRepoPath, err := filepath.Rel(v.repoPath, filepath.Dir(filePath)) + if err != nil { + return err + } + + dir := filepath.Join(v.versionsPath, inRepoPath) + err = os.MkdirAll(dir, 0755) + if err != nil && !os.IsExist(err) { + return err + } + ver := file + ".v" + fmt.Sprintf("%010d", time.Now().Unix()) + dst := filepath.Join(dir, ver) + if debug { + l.Debugln("moving to", dst) + } + err = osutil.Rename(filePath, dst) + if err != nil { + return err + } + + versions, err := filepath.Glob(filepath.Join(dir, file+".v[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]")) + if err != nil { + l.Warnln("Versioner: error finding versions for", file, err) + return nil + } + + sort.Strings(versions) + expire(versions, v) + + return nil +}