diff --git a/auto/gui.files.go b/auto/gui.files.go index db0a8509..f34a357f 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("1f8b080000096e8800ffec7dfb7bdb36b2e8effd2b106ddbd87b4dc9ceabf7bab6f73a76daba6d1e9f9d6c4f4fbf9efd2012925053040390b655d7fbb79f9901df0f91b295c4bbdb1f1253c46b663033981900c3bd07c7af8fdefefce6059b4573ffe0b3bd078ef3d968c48e54b8d0723a8bd8c6d1267bb4bdf3847dcfcfd5983d577aca78e0418d20d2721c474a1bb6618460d14cb0a3d7afde9e9e3c7ff7f6f5e9199b485f6c0eb1bb43df67d49d615a18a12f843764ef8c606a02cda46146c5da15cc559e60f073aa2e840e84c7c60b188cbd3c79eb9868e10beccb97ae080c0ec723e642e958b0898a012419100c3f9e1cbd7875f682861f7ee638801522c77c1e4cf7072218b060eaf030dc1f9845e0c2f0c1945eb98891f27da1f7076769c951a4fd01737d6eccfe002bf98a9f0fb04bc1bd83cf18db9b8b883377c6b511d1fe208e26ceff1de405b3280a1df13e9617fb83ff72de1d3a476a1ef2488e7d01ddc288228056272ff68537158576019f8bfdc1851497a1d251a1eaa5f4a2d9be272e800c0efdd802c46524b9ef1897fb627f67b85debc813c6d5328ca40a0a7dd5aaf1389a295dabe1cbe01c26ce078a4171e4c611932ef634d362b23f98f00bfc390c8190079f61834846be38c888c8fe60d7d738cfaf607e5fc1481b9b37377b235b2b1bc07636562a3291e6e1c8356694fd1ace6530843783040ee4063313221a543bd040834bbe5852997eb3681102c691b88a70242a616cacbc05bba647c642ee7900bd335651a4e6bbecabedf0eaeba46c021472267c2efdc52e1b7c27fc0b114997b3572216832d96bdd862871aa6668b191e1807585f4e6c17379fd19fd9ce169b3d827f8fe1df13f8f7341bbe3cc4a9450bfabec368b1ff7f0a03ccb99ecac08954b8cb76864fc5bc547788a471e62a5026e4209b8d60bd1481afb6d84b157017fe8252300a6405803c028996420388970061d64d65080e728082e7a1487b07114955a40f90abeba5383beda513e095f6d2ac676f69cf8da559cf5e4685b1d29ed09676810a2a78f96aaa2a64de65db5f97f9aaf086ba719ee6ec152a235158779183415d5c540790267202e58c63d057513614bd26f67690bd2d68958680981fcf83ac8d274de873984b1980140967ec2bf73c8503a4ce2a19e0fe943f32c6218d0eac93178cb97b3ed5a88c7114a501fce978e3d1e3675becd1936dfc6f67f3eb320535f7646c76d9e302f2297d76c22bf6247f9f12f211bc7e94bebea9e2056c160c3d0e3aadc2e7be9800b4db39a397d0dbd9ce5f13e7735f4e91fe88e4d7ddb44a099cae1175fae25cb007728e0a9d07518324c0f29535bb9cc948382433d8f412746049f75c0a4bfd27dbdb8d3d79353566f17f044aac0b0a6f68e6dcf79d12155b014a1affffb9f024671b737e95d0f4ab675f85579b5907895c810110829a00963eb06f8ad29755666cf457e07d300322c659b60c305864235c51c4703adccdeab2bf025134689931acf92c9c01a50d08150324d425c3a91a6bc1cf0d9a08be82e65a845a411b1f58706460f1065be35246b3628f969fcc90fd7594bdae10410399d259b9c9d8716f44220846c2c85a099fed118658e4c98baaadf1e202965ab2330ef646506e975030c4d85b1582486986360cbe0bf845668af00b2cb17f500da58f9e98f0d8078b01ba17544f4e39adfb76852308924e100a0ec4d14919ae8d203de5319cb1067b0f6093f3695a82fa6dc08c76eda34302f3ec0959006c469cb93f78fc68c0acb532d8d9f96a3002ecb0f76ca8b0320e76c266d203adeb5cc182dc64328459ebd82f344f912f3c92dc667891898084976021c4e114b48e3809266a1888cb02fa54116cda4805897d607f6416e0380ad201f011fee504b7e6873525c1483dcf06dad82c0f50a4f1d45f8433b49e58f6e4b83371a1e16f1c0e529a7d29e62693ffbc131089c0c0fa20f227e782fb31fc2fb48149df1f5c5f17d1c51a26bab9191cbcb36f81c7d8f51749ed2f6eca5344038d2c090a941cf9b24cd704174fabd0539741195b9e10e62f836a3d60dbe914ed60d433c98f622f151c0f5e7832b200beff3218033df6c6192783044748ad31fce3a5f17346c9c69d8b202e0149681c64a016e71094e7a90815ce61e7c4cd3caf326355140e3d8f6177b0ba2bbd48aa22c465a276418442d10b22a0caa5b094e9800abbec822723a4bc901e8acd0a50c3e2109d59e56d7a81eeaa6907d86977b723a3ec4fc5f71a1dd32e6866b0d49c1c7f481a9a591c2103f7025a4d269d10dbee6e473f58c723aea39e6c3881eab30e784e6d8f1f92827cace27e20c3caad2347ccc368d1253dd8e712a0f746b1dfac3df39264e1c707585eec6adfb250dbfa681e7c23b589609dbfdc622af0170c9cf3cb80c9090b842b8ce17af1354b68ca2eb90ed06e4a4c89dc12c105f101f43f91d393003df64c4d43c7b95d5002c677e69eb3f3a8b8ba16ca810ec267f4bf930c5b5e11aa7591d61ed5da9b3d2eac69a53a142c18a43c026ea5f0840706d6e3838c76ed03a0f95555f861610adfce30f684348835194b6cc60d1b0b01ee04bfc038541c81b907a6a80bbe18b4f0862c8f6ecc639c860430b43a934a148d0203a3dcf5b060c594a6be1d7cf43f2b564a0f3b058d13332fda282c047731b18c3eaa24574d881a4bf9206d1379356898ccf28bd2cfc28fdc722e0b8798c63ed8c9c0cb15d62f3179da1f36cc976772a7d9061ad7e83b6de63d340ac4b365f2e0a05b1c0e98f490dec9085298e5929148d1f5353639c2820d7c1a9e1c83354c53083f058f6c9fe8dde0df1f01ec8acdb954ea4af5a026086193e855aa916957b2dc800e3e0f4d6ad0856093610cf12f257c536b105f02629fcbc013576890d6baef6129170d2e66a904b4b9b9e9ea2b978382c381e434e004ba334bceb38847714ef04608eb8678d689733913607fc7c17940d6ec3bfb50b7b0fbf76580154301289fd9873bf5e5f2c0aae6b3e4a9bbb75a1fa0029b38a805060a08770cc4d8c6f535f6fb466817d8874f4581e5bfd86c866e65c8a5d7c8d1cd609f40e58f08735b49c5b1b1af60fd2b8b79557f26929fea9da2c895a53c955e9689716db43eeb6ab56235e8d32ce836f0546cc22a51d8e4b789b4241168266a94065a9a4b755b1116ceba573f98dace952f5b3d0abe00f4bd64602f431cc32849e0a2a0cda0bdd78ad3a81da9bbe36b03648e0a45d081f73754730d081f4b2d5ca4df9df04e2ddb39f86dfe2f09257f1dcae082fbb28d7b7a9325b16a1d23a75d7479a1b5ba23599a71f8946c31f5d5b8cb1dfe16ea70bf29d8b10e224ca9f76fa42f0cfb8371ff922fccab783e16fae6a6a6bf65041026c36fb17fb674f67c115167631970e4bee79f8ebe3335ef22ef8fcafd70d4f5b1f3351197faba47b4757d157b0e863d7cc5bbc275afc1ed7b3d2157ef2e046eafcf5b145500eead9d8003b65d0e01a94bf47d73b3348d72d4a731efe4ceb3885d354c62cd2029a096da5d4bb1dbdf07f40eb63be0d966cf97db5fc4349f88a1700bb0838d5e7203fe3b49eb0761a3466b1fe94e143f053fef75e083a1f6b3305d746cedea41a5af57eafe4e491cb833e19e8b2ef13e99064a0b0666fb5c1adc00319f607a2c10088359c70c95babbcf93d43b928467bc4e021020b07bd66060da1ed30ecf40199a4f4704da7a76b8dfb5437366b7a87f92d1ec6e24a0010ded682135366f6b4642499bab0545b4addfe0c0d67c537add1c99697614f9f20867691716d7cac6500e2e3b0f3104f0b0120605c6c84863633e6b65e3c226c12ab8855ace61c56dda61c65db57c327b800b9e9c2bfd2ea725db685d19568f0753a1078d0b10fbf24bd6d7cec103a05a7aa2c1cee956ff611fd32e19801dcd1064b30cdf6625da146ab945f4ba187bc61dc942d499e4606d61e7003aef176fce84a91060c6d6479329c6987f49cf656c6cfe7a7fa2cc16bd34bc8cbf1c84b3cf565fd1dd62d7d7417ae424c19994e41d636f393c1d513720f09f81b77ae0ad53c11ebe64ef22e9cbdf6993ed8e8be402ecf5f910fedc0f9f35e2e6dc7410e0e8cdbbb513c00de324a45df120e167002baae6feeececdcd17ff22defc71528d9dc2afbb1108c60e848b8436bf3c8c54c4fd8718991b87c8317301b2e2dedce0af8d96ba2701b9d36ff16791c9363f352d7b2d9eefc20f49471547fd09f93a8ed64fc9d47c49e400403e0c02056ea578fd037bb0cf62d08d1319b4aac3de34c7f3db33a5bba2c8e9e8ec0cefcedc299edce957a6a76bf0ec2f3534b18bc74906cb88523facf79a4e486790f6f3696b6357ccc9073dc79e4c5618fc53eaf5aeeda4bfdb83997713b2e474e77d76f56eebfb90159a9a691fc8fdb9b3f5dfc3e2b646a73de1915b9d6d06b88a664223eae63e1df36830c0ef7abea37a7cb5a18f4673bd6bacc6f31f1de70750ff1457a064b421ce03b8b2e8dcba6a1efa028baba5c37fd07a8581879dededde270fde85789eec385f66d90634bfcb2988b560b1b71212e5531f7621ef1a01ec4b323477b7ef70e8a31e215d82f9e0e0589aa47cd9c99a0f763aa32a307f9ece2815f6d9899141d74ecca1e701b2770af35b85831d95e2039fcc6a57f339e8dfaef831c8e04cab602dde611ff1ad7a8bb9347f52528538fb9dfb427833fd28a9bc0ab56a0a27254fa1b341134d69dba79d2c2dbd3fe8db3d6e03fd277be8552eede1a8579bfce9af7752b58fdb5e6df341bcf77f0daf0c49011ddd7911f9d33dfb809b33f9a3dda019952f12e02b3ae1679a2fd6082cb3c7f187be08a6d1ccee737dda1b364d5e5f95c8af5424dd5c59dce59a4dc187057aa0ff5a200b8e8c77cd4120e0edf0ad9c0b5003e0588addc177bbf3f9ae31839b9b5d00846a81bb37d152049ebfb0fe2f36a219285f0f6e9eef355cac29788e6d3bd0b908d0b516cb1ffdaeec7599afaf7ff824576a4a1290dd45cbaea5e3ebe79423a5df6df5f43652f21380145e9264a5e68e775c576fbb055ebef85dd05f4915721512a585297a76478022b87fb1366298a5051a06221ad565e32c0e317b021bb16f948ee7ad57ff7a8d6c60e8a98c66f17808f6e9281bbbf0a405cca511a60ec98f749d9b9dda0a77036409095c1866aaf462e42937466f2349285037df0ac51f9c2cd298b88928cfe3255782d734780353d80c5647edd7a897dff6a4ed7f115d2a7d6ef5231e95009b289526fb8b0205b616e995013374b40563e636528e8a0414ed156038a779b0a7d419e9794c07f0f028b3c7ecdaf510146e864716a92bdd8f4c30c8af3c1a01fa09635363c1d0b6df6200304625297d1767a1566078cc29a7065b0069ec092e009de5e6e0101837d20be8efcb99f07d99243848d4f8de8850cea9935c2aa41b972da4d159959410e9f19c02fe793f55cc3362ca60a2323ad4a73a2383342c1f729846b8aaf5df9074b24b9ed92dc3e1b00d4b9b97611992715a63098e592feb40311b703d18a6d7ce5b114cafb9a7f8e14df60cee6c372a4136ebedc846254413ffe6e8e4f77aa11db16e2b9c27c7ad104aef3d889acff514205860d4bb4456502fcaa4251687248540618ae8accf092c76919c489744b53259eccbb9c7cdeceb628c3b3f7ab3998b6a618dbc044162f81f9a25950c5ef41377f37105bdbe9e2fece5a27cc1c70c2fe9896d28cc8c1edbc6663b6250c901d5381f071c4c759b04e6bd1efd0d7bdf4f7b1d8c1a494a38a36350536f691434f51ab2b16db50927e2f1314547f707ce4e03ee54d5f124f755223d8e3f6d34b06d6192e5aec5c8b675d070ae2688993da9dcaba473860f107460b1175760d89274963a4aecec3cd5c6ec498f4e7bf5890e5143a75533af865bcd5cdf9b283d4f1207e1e320490b88dcf782666dc96e1336488f9b91094c6faf1f82c439b4a03dc48c496947c3802200c3cf93eb4cb8f1d050ea491d2dea9b477b3e1f830794130c06b76002d71e58c93a86b5176bd5daca20c4dbfc490cad46e11c65948034325f9006423449e05411b14121ab2051818e3b8200c51a37c910b024f481a909dfc7120ff512fe0e0e223d301808bcc6e07eea54b6f0c412d1a7d04d0d8692f017c6ca1233c1aa1c5aa96fda4668de636998443bc17ffcd134c1a1262c0042ccc110d89943c382540e238ba229c9e78098fe80255957062c117b658b698794ba1bb233a480a1a4a5a84ef1113a55940c1354cb86a413f3dee6b0756ba78e69b3c823136fdc9200e01ffe348375c9266b03130a134760a52d762e448878cf41f9d9b4a79433958845b9278038d00c58a984bdc1d3ad9152abe0d5328324bfc38c6397c86a791ef166b922f8c63e0fced7060911f415494c3730c44900750a94a784a1641ebe52e756fa86ec24c2f429b1ef1131d9d34768d03e7d46895db98bac887b5b30312e6e94d9d956130606079459e6b27b1c66cb1abda6c67563418d12be6ba1452586d1be6558d7ba3d9524c7c3aea422d1a058ae24431f9098d1d5defdc1776a9e1e404af42276d5a4157ba9416e0fdd36abbbb0ce0c75fd85bbe9253ba5a8afce6c329cc044b082e35425ab42aa405c3f36765ad1701bb29f24684f1224cc3928694f5315f4084c25ce66ae37f228c65c5473baac80c3830f80431c62008d10a0143400a17dc0e6198206530561621346598eea38ac9bf5b8dd7c459ffd307d5c81ffbc0520225d62284f1a8c6c7bcbd90299341ff4b69c9ac17a16e97e1cdb30952f6839c3cd5a0ece73084a05276820c35d9bdf390313f54e8e2acc60283499653c8e147af42ea3300d4ce2c2a6cf1669e3fe3358317ece843f19f499d662300e6fd88dd5559365d038a58569b534cf7a68a17b7157b3ee7236efd136ec7434f357afed0124c50af6744334b95792a66c13a570cd975f88243d5d99dd0b4bdde7593683bb0796cf60bc25a1e55e686401703a160620e3a5ca8436bd2e52cdd545d7b5f72374ac7b00da6c2aa3ad50e6f9e5085148cd26cd423d599c20e0561189de1904c1748bbb4ef01f5397adc87584e94bf1fa348f55b7af8db5eeb9afbda287dd33e566ddfd5ecde96eda95ec1a677d1e39de8aebf4c88bdb8b4de54ddb8c4df5fa78f63940437cac78f60da52d9e3d8d6dad07b2196cf53ab99bf3ec742d3c39f1d03c285b17c9de85a928dc1a33a499945a22021d16c5a9bdce5870ffe340be8ff10c1e882b540f397a14c1fe60f43fbf70e7f743e7bfb79dffe7fc63f8ebf5ced6b327379f8f5a4d10c2b39fef4e559b7dae86a9cadcd786b2dc7f3fc34f4300756c4013f4e6c46e09b02cfddb62c85e26ee2abe3768968296e4be9f59b26469b7ba89ab816d5d454b5e5273e40dea22e364eeb3adb5d6818bde721bff3781d4d767be0d4c0973ad0a52166460a63ac91bcf9ee43e3219af3e18649bcd6ef256ea23935b8c3c80ff3cc07663b8b9457e32db7036a914afd868431f84d9f8c766698cc05f2ca14a832bd67ee0e56e5aee0d8f66cbf49c2defd674153f296d3a286a397cb18a82a30eca2aee9fa3e35cc9a56accd6bba522cb9275e5faeca36a274be036fd644b730d85bf539fb8c0e049d08c1215d1e1f718d82c77a65d2dc8570367594679f048e0823064282c9104fa1622451bffdc4c639631c6113070c0b22fe74cb27c606c0fd93bbf6e49fd6050965e0fef4c974e3d54e0cf9ad88748acfebae8a3495d297947bbf055aaf5b6364aed9acc8ea674246cc36cf697cdf21065117db69d4a66a5d61201b53ab54d444fab3d65fc003ec9fee0e90736271e2c9b95fe5397b227515f2685f9ba1431dc808ed8536604de49586642f4e7d43e41825b59dccffa1bdc8d18f40bc350d556a6a4d29ee198d372eaa75a2ca6b04cd954574b6d962582d2ac2fbaa36b3685086eeb845a457483874db49aa352c6e41e6c8e9fba5041319ebb4549bdab15f29d95cb44ff1bbcfe9ead1ac06449d02d31599b42bfab6abefb33c9a5ec51f544b86df9b23eea44634434199f8d6564e73dd9c46398de973676d0f2440f2499e0e4738301fbe6f02d7d19d0aeb90d31d325f0ad327dad3bd46660b3395132278ae8b705c1ab439626af782db4e34e6819a6b5f089113e49190d48a7faf37b74d52b99cdf7313f0c7f9c115cd966071d51a3945756b00bf60d6ed2ad30f9cd2fff4d54bb9178740a652bb9d940271c6be24fc297d7f8744a1e03c5b4bb85db5cb8fb350ff11c85858c3ef2c5d9d044d90b9bc6d8ea06600134b83c74556d1097be329a1f785d93255bd8ee6ba7711f93d736fc4188b0cdda2dd658d9d9cc1b0f0ef0ff7482972aa5a2415be8c09ede2bfcbeb5d55aeca46cb0ee7cbcf85791ae4d3e66b1bc728ec5de7b044b01382f674ce0583ccbb1852b98fd3ceddd823b4500963a7b350ea982998198877a92428cc5ac372455871a26b61be09f556ca1a3e33099c98f1f554ca0bfa5d1bf86adc14413f43915d870ca275f959acffa08568a76d391dce47c42240b4ebba4f56e2ac8c61d53ea842089a8629c6241bad3c583ba60d3e2f7452f044d2f5175ce2377c6c41577237f91b5c6d86c1a936dbf34f21136434fed37d8cab1f902c3fcb919baea66e89d373f4ffb7e16ef136c7ea69f866bd9f94cbe226aeef9ce67cd1c2aed40e69fbf5bf31e63577ce3c35bc18d960a5e1814011dc2c1f3fcec0db8fa0a0664b680759d29a29eade5823c9077b74af43b9a87afe904981916e0f9680ee44b7e752602ef87710802f53a8ea60a9711bcd70d5498cb886dfc209f8ffa44239104c5de56b3d50a642881d49b1020a4eba7cea9482e171522b8d9bb2c68db2f5a8bf469e8efd6646a82eda3b1cd1bae612517fe299887c2443051306b0cf8077ca7802c91b4a41f616afddd9a2c75c83ea62cd9dcbf96759122e4e1da9756a85615a742877711a8225c7de9816bdc5d68b4b6c843f5604c400983debd09de64fb5e39cdf0b5ade10d96442b0ae429b65857f0a1d913b81ff4b35f7a394ecf7c36d0906a1c06c16a74acb65a332def2329936f122da3a5adb232316bcdee11351b955f067072a0bf469b2cd5686714a8e8913d5846933281d39b04b733be6af0af14c6fd44166c62a102b1df9ddcd26a4dbb58916c30e0301bfda331d93b439c05c81ec6d10ccf0cd97baeb817d383b3687d30abf308226b87fe88069631974a7b8dd8a6857d6daba4ab65588759a51ae63928f75735371de6ffeeeddb3767b465075834590a46bcfdf1ac431f27538f15ef9106fe50ebd9197d71fa3978e546e80692517952dc73212b35f90f20e161a082c55cc50674129fda482b657368e2c0d3152dd5d38f66a7ce341bddd17eb5b0d4e8f3e684fd20163d4e58f74b42803791d3f5e8cd09f48c7b2a0367d07217997a4ee3ad99ca5de193e7a538b288ec981b16824dd0d622109ab2e235e5536a9d89a679b877f787d2f8e07a524ffd7b04c5578d235ba5a04929b4c49263dd18452614c7dc3df7b40af1d3dd78752f797d2e1663c535349e70df7cca9033e3be00cce8ff2cd1ff6a61e843df5797ac558ffeed6ee1e9521a177b9bdbd58b1077ede3e2dc48630f6a795cfa0bbace5ddc25d3300f74f912f82984ae5030cd16b56546fe9edcd3e661986d84421793eca0b0c6e1e8a304a042b0637ba8c8c3cc46d939b150ab39c145d7bfe9b84932637cca65503e57503aeb903d3917dc8f85136b3fcf4385c396d371d9bd5b3e9d6a31a593c9c45b06d82b3902178f4109f80bc62f8018147ce111bbfe02bafde2a602c66aaab5a85393ed4d4b9e375a5c487159fd50e969b110d550f258e29106210d7569df38ef3f4f1668df1fe39cfcc17e33f6eb06b61030d4e223a8dde2773112a439bc09a377a7eb51b93f17be4a765b8d9b7f3f23dbbb73f1db183d61eca5725fa9b5e95bfcb42d9edda4a33eed09d0b0d2b2fc4b36e75225f5302b66654af230e1077e95fdc02fe80c31cfd20eb6a63c4f529c5713a0e7dad87e3d263d9e37c1cdfc1460e4e940c25bcef6e9e521e541db98144fec1512c6123f3ba8017a4cd5f535f67882176f7ee1bf6272a8c217cdb2b16c5939d32c25974ef3524d283303364f9f312d2f07e54aafeb2d531a65c96d591dec449827c33350b69402957aa75fa52f6c256c948f91e7bd2d24b3ade5953a1cabb8ba3ee7fcc2b1b4cc2e455628b34e4208ea316586d94e09cb348516e5cbe23ecc67965f2c4f4b96bfa10c59b00e28875a3f7afa6c18d2fb688135291b830b7a88fb721aec3267e759081ec54c202df707f8a5055852bc68b63f78fcecd96074b037d6a35c11163eee92aabfd94e0ab74e9d82d2327aa4c2859da92f5d78fc9a3ddade79c2bee7e76acc9e2b3dcd6e674d14aeedb83d7484e10709d2adb4d9cd9690b6a3ef5d5f298c4b1e04a6643ce41a98f9b914630a0cc95a79e06958378ee360c6e78d157c71c5f1ca18fb56f349630d1dcd62cd0eaff0b2c7e98b9fd8993b9b035d1bebc69e9660cb3c8fa37358795c786eaaf65c04ec4c7a33d508d27320b887e19f99f465d8d8c1b7603b48e8621a6bcf18cc6250ca55392a12aaac4a57a6f0f720be066f91e11dbaea484915d064ec588a79f31cbce4da056576fcbbe45e333d2ca6a140d2e267097463add3056884b31830bfe08d70bc85b2053b55a0175a20fdbb1091046478c003d1976ac5c716c928a43d0c5c3fa603c42539306a125d52fa28cdc8c0a5637d98a54a4d0a72914390e41b2da5599d2a1f96e52148dac8da72df2a3ccc30d57c3ec7417e84d2180c244c20bac59aa4f5114b9a61a411447258ca335a1d12cdc8b18cc6b17b2e221af61c9c0fc9c1251f811abc023d5779b16ce4631e48102100408560068b1e83e37db6e154a9a92f28a16a38320118db0b67aa8002d973fba83b84ef99adb80ada852cae96ea238a80b8dc9d8155933f8f7c1db70fff18488dc0b393c05d69ccdfe2dfe211c6177c3c9c313828ff6e1ff0093b82c9087059603f46de4a6382afe0451ad11517c2f7c640e0ca9b25b3bb0582a9413e3dae63f6564b7c0af82ac35fc848c7c1e83dd7806fe147cba0abf2318a062ce4bf99447c0eedefefcfda91da7688a2760ab7bae710f111d118bc02b0f57848580d0e9ea7bf9770a91de82d3880a064ab23a57a29375ef08771c19c8cac8d90e086c76187bfd90373547ad052d1c914d72d9a3868138b1e83fdf63e167ae13c1a6e0f1f77d7cec836facd8c721a76b6b3491051424d07226158a9005e077dff000c9f680e74fd5f000000ffff010000ffff5be53dc8d4a40000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec7d6b5b2337b2f0f7fc0a8d37c9c0beb40d73cb7b08b08781494292b93c30b339397972f691bb655ba16f2375030e617ffba92af5fde26e63c3b067f3610677eb5655aa2a5595a4eabd47c76f8fdefffcee159b459e7bf0d9de23cbfa6c346247413857723a8bd8c6d1267bb2bdf38c7dcfcf83317b19a829e3be0335fc48c9711c054ab30d2d048b66821dbd7df3fef4e4e587f76f4fcfd844ba627388dd1dba2ea3ee3453420b75219c21fba0050b26d04c6aa68358d982d98123183c4e830ba17ce1b0f11c0663af4fde5b3a9abb02fb72a52d7c8dc3f188d9503a166c12c40092f409861f4f8e5ebd397b45c30f3fb32cc00a91632ef7a7fb03e10f983fb57818ee0ff4dcb761787f4aaf6cc428705da1f6076769c951a4dc01b35daef5fe002bb9013f1f6097823b079f31b6e78988337bc69516d1fe208e26d6ff1fe405b3280a2df1319617fb83ffb23e1c5a478117f2488e5d01ddc288c2875627aff685331585763ef7c4fee0428acb305051a1eaa574a2d9be232e800c163d6c01e23292dcb5b4cd5db1bf33dcae75e4086d2b194632f00b7dd5aaf1389a05aa56c395fe394c9c0b1483e2c88e23266dec69a6c4647f30e117f8380c8190079f61834846ae38c888c8fe60d7d738cf6f607edfc0481b9b37377b23532b1bc074360e8248478a87235beb51f634f4a43f843783040ee4063d13221a543b5040834b3e5f50999e59340f01e3485c4538129530360e9c39bba69f8c85dc71007a6b1c4451e0edb2afb6c3abaf93b20950c89a704fbaf35d36f84eb817229236676f442c065b2c7bb1c50e154ccd16d3dcd716b0be9c982e6e3ea33fb39d2d367b02ff9ec2bf67f0ef79367c7988538316f4bdc268b1fbff0a03785c4da56f4541b8cb7686cf8557aa3b44d2585ee0073ae4209b8d60bd16be1b6cb1d781cf6df80b4a4107202b00e41148b4140a40bc0408b36e2a43709003143c0745da398848aa2275805c5d2fc5d9692f9d00afb497663d3b0b7b6e2ccd7a76322a8c03e5086568e7077e052f3798061532efb2edafcb7c557843dd58cf73f60a032d5158779183415d5c5407903ab2fcc01ac7a0afa26c287a4dec6d217b1bd02a0d013137f6fcac8d2375e872984be98314096bec06f6790a07489d5132c0fd297f648c431a1d58272f1873fb7caa5019e3288102f0a7e38d274f5f6cb127cfb6f1bf9dcdafcb1454dc91b1de654f0bc8a7f4d909afd8b3fc7d4ac827f0fa49fafaa68a17b0993f7438e8b40a9fbb6202d06ee78c5e426f673b7f4d9ccf5d3945fa23925f77d32a2570ba46d4e98b73c11e490f153af7a3064980e52b6b76399391b04866b0e925e8c092eeb91486facfb6b71b7b726a6acce0ff0494581714ce507bdc75ad12155b014a1affa7271cc9d986c7af129a7ef5e2abf06a33eb20912b3000425013c0d207e64d51fab2ca8c8dfe0abc0f6640c438cb9601068b6c842b8a184e87bb595df657208a022d3386359f8533a0b406a162804470c970aac64af0738d26821b4073254215401b175870a461f1065be35246b3628f869ff490fd7594bdae10410199d259b9c9d8716f44220846c2c858099fed118658e4c88baaadf1ea02965ab2330ef646506e965030c4d8fb200491520c6d187ce7f38bcc14e1175862fea01a4a7f3a62c263172c06e85e503d39e5b4ee9b158e20483a41283810472565b83682f494c7b0c60aec3d804d7ad3b404f5db8069659b9f1609cc8b676401b01971e6fee0e9930133d6ca6067e7abc108b0c3deb3a1c2ca38d8099b4907b4ae75050b7293c91066ad63b7d03c45bef093e436c38b4c0424bc040b210ea7a075c4893f0986beb82ca04f15c1a68d023fb10fcc4366018e233f1d007fc2bf9ce0c6fc30a62418a9e7d9401b9be5018a349ebaf37086d613cb7e59f64c5c28f81b878394665f0a4f67f29f770222e16b581f44fecbbae06e0cff0ba561d2f707d7d74574b1868e6e6e06071fcc5be03176fd4552fb8b9bf214d140234382022547ae2cd335c1c55141e804977e195b9e10e62f836a3d60dbe914ed60d433c943b1970a8e07af1c1919003f7ee98f811e7be38c93418223a4d618fef1d2f839a364e37ac28f4b40121a0719a8c53904e5792ac200e7b073e2668e5399b12a0a878ec3b03b58dd03354faa22c465a276418442d10b22a0caa53094e9800abbec822723a4bc900e8acd1250c3e2109d19e5ad7b816e07d30eb0d3ee6e4746d99f8a1f153aa65dd0cc60a93939be4b1aea591c2103f7023a984c3a2136dddd8e7eb08e475c453dd97002d5671df09c9a1eef92827c1cc4fd4086955b4596f0c268de253dd8e702a0f746b1dbac3df39264e1c71fb0bc98d5be65a136f5d13cf8462a1dc13a7fb9c502df9d3370ce2f7d2627cc17b6d09aabf9d72ca129bbe4ca47bb293125724b0417c447d0ff444e4f7cf4d833350d1de776410918d7f21c6be74971752d94031d84cbe87f2b19b6bc2254eb22ad1daab5377b5a58d34a75285830487904dc4ae108070caca70719edda0740f3abaaf0c3c214be9f61ec0969102b3296d88c6b361602dc097e8171a83802730f4c511b7c3168e10c591eddf0629c860430b43a934a148d0203a3dcf5b060c594a6be1d7cf43f2b564a0f3b058d13ed156d141682bb985846f72ac95513a2c6522e48db445e0d1a26b3fca2f45878c82de7b2708869ec829d0cbc5c61fd1293a7fd61c37c7926779a6da0718dbed366de43a340bc58240f16bac5e1804907e99d8c20855e2c1989145d5f6393232cd8c05fc39363b086690ae151f0c8f489de0dfefd11c0aed89c0ba5ae540f6a821036895ea51a997625cb0de8e0f250a7065d083619c610ff52c237b506f12520f6b9f41d71850669adfb1e9672d1e062864a409b9b9baebe723928381c484e0d4ea03d33e43c8b7814e7046f84b06e88679d58973301f677ec9ffb64cd7e303fea1676ffbe34b0622800e533f363a5be6cee1bd57c96fceaeeadd607a8c0260e6a818102c21d0331b6717d8dfdbe13ca06f6e1535160f92f369ba15b1a72e934727433d82750f91e616e2ba93836e615ac7f6531afeacf44f253bd5314b9b294a7d2cb3231ae8dd6675dad56ac067d9a05dd049e8a4d58250a9b3ceb4849128166a24669a0a5b954b51561e1ac7bf583a9ed5cf9b2d5a3e00b40df0b067632c4318c92042e0ada0cda3bad388dda915a1d5f1320b38250f81d787f4335d780f0b154c246faad84776ad97ae0b7b9bf2494fc7528fd0beeca36eee94d96c4aab5b49c76d1e59552c18a6469c6e153b2c5d40dc65deef0b75087bb4dc18e7510614abd7f235da1d91f8cbb977caedfc4de58a89b9b9afe961140980cbfc5fed9d2d9cb79449d8da5cf91fb5e7e3aface02af8bbc3f06f6dd51d7c5ced7445ceaeb01d1d67683d8b130ece106bc2b5cf716dcbeb71372f55621707b7ddea2a87c706fcd041cb0ed720828b844df37374bd328477d1af34e569e45ecaa61126b064901b5d4ee5a88ddfe3ea077b0dd01cf367bb9d8fe22a6f9440c855b801d6cf49a6bf0df495aef848d1aad7da43b51fc14fcbcb7be0b86dacf4277d1b1b5ab4795bede040f774a62df9e09fb5c7489f7c9d40f946060b67b52e30688fe04d363804018f43a66a8d4dd439ea4de91243ce375e2830081ddb30603d3f498767806ca507f3a22d0d6b3c5ddae1d9a33b345fd938c66ab918006d4b4a385d4d8bcad1909256dae1614d1b67e83035bf34de9757364a6d951e48b239ca55d585c2b1b4339b8ec3cc610c0e34a18141823238d89f9ac958d0b9b04cbe0162ae9c18adbb4c38cbb6af964f600173c395bba5d4e4bb6d1ba34ac0ef7a7420d1a1720f6e597acaf9d830740957444839dd3adfec33ea65d32003b9a21c87a11becd4ab429d4728be87531f68c3b9285a833c9c1dac2ce3e74de2fde9c095321c08cad8f26538c31ff929ecbd8d8fcf5e144990d7a6978199f2c84b3cf565fd1dd62d7d77e7ae424c19994e48ab1b71c9e8ea81b10f8cfc05b3df0d6a9600f5fb30f9174e5efb4c9b6e22239077bdd1bc29f87e1b3465c9feb0e021cbdfbb07602d8619c84b42b1e243cfab0a22aeeeeeedcdc7cf12fe2cd1f27d5d8293cad462018db1736125afff2380a22ee3ec6c8dc38448ef104c88a7d73834f1b2d754f7c72a7dfe36391c9363f352d7b2d9e1fc2bba4631047fd09f9368ed64fc9d47c49e400403ef4fd00dc4af1f607f6689fc5a01b27d26f5587bd698ee7b76781ea8a22a7a3b333bc3bb3523cb9d3af4c4fd7e0d95f6aa8631b8f930c1611a57e58ef2d9d90ce20ede7d3d6c6ae98938f7a8e3d992c31f8a7d4eb5ddb497f3707335713b2e474e74376f56eebfb90159a9a6977e4feac6cfdf7b0b88dd1694e78e456679b011e4433a11075fd908e793418e0ab9eefa81e5f6de8a3d15cef1aabf1fc47c7f901d43fc51528196d88f300ae2c3ab776e085aec0e26ae9f01fb45e61e061677bbbf7c9830f219e273bce9759b601cd573905b1162cf69642a27ceac32ce45d23807d4986e6eef60a873eea11d205980f0e8ea54eca179dacb9b3d3195581f9f37446a9b0cf4e8cf4bb76620e1d07905d29cc6f140e76548a0f7c32ab3df03cd0bf5df16390c1990afcb578877dc4b7ea2de6d2fc494915e2ec77ee0be1cdf4a3a4f232d4aa299c943c85ce064d34a56d9f76b2b4f4fea86ff7b80df4efeca157b9b487a35e6df2a7bfde49d53e6e7bb5cd9d78efff1a5e1992023a5a7911f9d33dbbc3cd99fca7d9a019952f12e02b3ae1a79b2fd6082c33c7f187aef0a7d1ccec737dda1b364d5e5f95c86f8248dab9b258e59a4dc187057aa0ff5a200b8e8c77cd4120e0edf0bdf404a801702cc5eee0bb5dcfdbd57a7073b30b80502d70f7264a0adf71e7c6ffc5463403e5ebc1cdf3bd868b3505cfb16d073a1701bad662f8a3df95bd2ef3f5ed0f9fe44a4d4902b2bb68d9b5747cfd9272a4f4bbad9ede464a1e0148e12449566aee78c775f5b65be0e58bdf05fd9554215721515a98a26777042882fb172b2d86595aa0a12fa2515d36cee210b327b011fb2650b1d77af5afd7c81a869eca68168f87609f8eb2b10bbf9480b9d442d721f991ae73b353536135401690c08661a6819a8f9cc08ed1db48120ad4cdb742f19d93456a1d3711e565bce04af09a066f600a93c1eaa8fd1af5e2db9eb4fd2fa2cb409d1bfd884725c0264aa5c93c51a0c0d422bd32609a8eb660ccdc44ca519180a2bd020c3d9a07734a9d919ec774008f8f327bccac5d8f41e166786491bad2fdc80483fccaa316a09f303635160c6dfb2d0600635492d2777116aa000c0f8f726ab03990c69ce002d0596e0e0e8171233587febe9c09d795498283448def8d08e59c3ac9a542ba71d9421a95554909911ecf29e09ff753c53c23a6f427414687fa546764909ae5430ed30857b5fe3b924e76c933bb65381cb66169f2322c42324e6b2cc031eb651d286603ae07c3f4da792b82e935f7143fbcc99ec19ded4625c866bd1d99a88468e2df1c9dfc5e2fb423d66d85f3e4b81542e97c045173b99a0204738c7a97c80aea25d06989c12149215098223aeb73028b5d2427d22651ad4c16fbd273b89e7d5d8c71e7476f3673512dac919720480cff43b3a492c18b1e71371f57d0eb6b6f6e2e17e50b3e6678494f6c436166f4983626db11834a16a8466fec7330d54d12988f6af437ec7d3fed75306a2429e18c8e414dbda551d0d46bc8c636d5269c88c7c7141ddd1f583b0db85355cb91dc0d12e9b1dc69a3816d0a932c772d46b6a98386733541ccec59e55e259d337c84a0038bbdba02c396a4b3d4516267e7a93666cf7a74daab4f74881a3aad9a7935dc6ae6fade24505e9238087f0e92b480c87daf68d616ec366183f4b81999c0f4f6fa31489c450bda63cc98947634f4290230fc3cb9ce841b0f0da58e54d1bcbe79b4e7f231784039c16070032670ed8191ac63587bb156adadf443bccd9fc4d06a14ce5146094823f30569204493044e15111b14b20a1215e8b8230850ac70930c014b421f989af0632cf1502fe16fe120d2018381c06b0ceea74e650b4f2c107d0addd46028097f61ac2c3113accaa191faa66d84e63d9686493413fcc71f4d131c2ac20220c41c0cbe9939342c48e530b2289a927c0e88e90f58927565c012b10f4c31ed90527743768614d094b414d529fe844e034a8609aa6543d289796773d8bab553c7b459e49189376e4900f00f7f9ac1ba6492b58109858923b0d2163b172244bc3d507e26ed29e54c256251ee09200e3403562a61aff1746b1404cbe0d5328324bfc38c6317c86a791ef1667940f08d5dee9faf0d1222e81b92986e60889300ea142827109a9279b841706ea46fc84e224c9f12bb0e11933d7f8206edf31794d895dbc88ab8b7051363e3469999ed60c2c0e08032c35c668f436f19a357d7b86e2ca851c2772db4a8c430dab70ceb5ab7a792e478d89554241a148b9564e8021233badabb3ff82ef0d20348895ec4ae9ab4622f35c8cda1db667517d699a1aebf7037bd64a714f5d5994986e3eb0856709caa6455481588edc6da4c2b1a6e43f69304ed498284390725ed6906053d025389b399eb8d3c8ae1896a4e97257078740738c42106d008014a4103109a1fd83c435063aa204c6cc228cb511d8775b31e379bafe8b31fa63f97e03f670e88489b18ca911a23dbce62b64026cd07bd2da766b09e45aa1fc7364ce52b5ace70b39683f31c8252c1091ac870d7e477cec044bd93a30a33180a4566198fa3003d7a9b51980626716ed2678bb471ff19ac183f67c29d0cfa4c6b31188737ecc6c1559365d038a585693534cf7a68a17b7157b3ee7236efd136ec7434f357afed0124c512f6744334b95792a66c13a570cd975f88243d5d99dd0b4bdde7593683d503cb6730de82d0722f34b200381d0b0390f15265429b5e17a9bce0a2ebdafb113ad63d006d3695d15628f3fc628428a4669266a19e2c4e1070ab8844ef0c8260bac55d27f88fa9cb56e43ac2f4a5787d9ac7aadbd7c65a0fdcd75ed2c3ee9972b3ee7e2fe77437ed4a768db33e8f1c6fc5757ae4c5edc5a6f2a66dc6a67a7d3cfb1ca021feac78f60da52d9e3d8d6dac07b2194cf53ab99bf3ec742d3c39f1d03c285b17c9de85ae28dc1a33a499945a22021d16c5a9b9ce5870ff635f7e8cf10c1e882b540f397a14fefe60f43fbf70ebf743ebbfb7adffb0fe31fcf57a67ebc5b39bcf47ad2608e1d9cf77a7aacd3e57c35465ee6b4359eebf9fe1a721803a26a0097a7362b6045896fe6d3e64af137715df6b344b414b72d7cd2c59b2b45bddc4e5c036aea2212fa939f20655917132f7d9d45aebc0456fb98dff9b40eaeb33df06a684b99605290b32305d9de48d17cf721f998c57170cb2cd6637792bf591c92d461ec07f0e60bb31dcdc223f996d589b548a576c94a60fc26cfc63b33486efce1750a5c1156b3ff0b29a967bc7a3d9223d67cabb355dc54f4a9b0e8a5a0e5f2ca3e0a883b28afbe7e8385772a91a33f56ea9c8b2645db93ebb57ed6408dca69f4c69aea1f039f5890b0c9e04cd2851111d7e8f81cd7267da56827c3570966594078f042e084386c21249a06f2152b4f1cfcd346619631c0103072cfb72ce24cb07c6f690bdf3eb96d40f0665e9f57065ba74eaa1027fd6c43e4462f5d745f72675a5e41dedc257a9d6dbda28b56b323b9ad291b00dbdd95f36cb439445f4c5762a99955a0b04d4e8d436113dadf694f103f824fb83e7776c4e3c5a342bfda72e654fa2be4c0af3752962b8011db1e74c0bbc93b0c884e8cfa97d8204b7b2b85ff437b81b31e81786a1aaad4c49a53dc331a7e5d44fb5584c619932a9ae16da2c0b04a5595f7447d74c0a11dcd6095510d10d1e365181874a19937b300f3f7511f8c578ee1625f5ae56c877562e13fdaff1fa7bb66a00932541b7c4646d0afd2eabf91ece2497b247d513e1b6e5cbbad789c68868323e1bcbc8cc7bb289c730bd2f6deca0e5891e4832c1c9e7067df6cde17bfa32a059731b62a60be05b66fa5a77a8f5c06473a2644e14d16f0b8257872c4d5ef15a68c79dd0324c6be1132d5c92321a904ef5e7f7e8aa57329bef63de0d7f9c115cd966071d51a3945746b00bf60d6ed22d31f9cd2fd7afda2b6c63183eb96f4097287b710a1ed70a56e702d34d0b0b2064396086f0782091be3f847c8926774d85bc09580da535ab908745072df1585a0325cea8e0df8d1a119f4e7137be892069d9ddd26479a7a4b073bb00c7fdfdc766ae1ff7f2644cdd1f8408db9c98628d45fe4b6fdb08f757685318778771d3d80bf1f891c184be8dc7d95047d90b93fddb2ca90017fa290e4678ccde077d9c373f27dea84adbd6c11cb5c101fe9f4ef6c295b0e845153a3047460bcfb776958a9d94bda49dfb0bba1667bd29b0512caf1c9e32976dc13c8579cba715e61b0f106da1d964be89bc5a44b108c0c208438d7fab606620e6f1c5a4100380eb8d83d6a18689ed06f8e72036d0d119accccfc42f7926d0df7d4ca4bffa4915684f0d94567fcdaf0ea7a2550d55ab3d7c5d94a9131a2a3b38c15d779e3590e4c5cdcd594018c66c4988083cc12be9c51ee35341971a82005ef973e334185f03814b8310ad8aaf8314280a80941b5cd229fba4373300460d77b3fd93097dc968869728784a213c967f2ec288093a07f2743b0d7c6c559a397cdeda0abbacd6879ea0896e6d03855b2cf623e952a322b1da9a5c0a71bee4f25066b9c1c1eb641878e8bd4254fa30cb44f5e5edd78a6a4ff71effaec965e36a51ad545e32d2e98bf0da65b25014e7d1cfd9cadaa152cd0a2249dfe75d553157215cbca6342aa33232c88b2bae28ff2a9afb0896a32c56daa9c02bb597de976aee6870408f8598f892025aeead2ca795b2d5c5b5d2e1a733f35a2665a11057ea9665398b8a831cdb3423c5d5b43b2ebe0ad4fd64b689ff0cec06de7a5cff0eedc1859834d8868b91288b00dd32339723a7b47b882b2c946f3f4c95730b0d901a58669b3a33b796d9a46eeeabbc1d56d106e59ab7dcb36ec161b1e02f34e5685ff992aeaa6422975f26d01106a6b7d073b810e6a8351deb8d294ce9a1703618bac909efc2d999f5ee5b550fb7264cd5e75e5bc33d951ccce6db2a8295ce6bd1a5d2e4847d240b584a8ad84e05edd28c29f99f9f9c09c29d7663addb78d5540b1f5a48a028ea06521860e3db3326aeb81d819d9fb6c6d345e9a9a2f6b4074d87f1d67c9c97d2f4578ff31634cc9fc779973dcebbf2f1dd644a1ee4f1ddf4e3e62d67777552fcc0cfeed6f466e90c6dfe01f7359f92eddaa1bff77d1cb37c62ca1be1d33512bc91cedea9200a6040660a58d7ad18ead9aca1c8037977cbac859117bea53b4c7a5880e7deb640c1713b13bef3c33804817a1b47d3009711cc4c0654f064c4367e902f477dced320098abd2de71d14c85002a937214048d74f9d5391a4c7289c41cadee5f665aff346489f86fe6e4da626d8ee8d6dde71052bb9704fc1c7103ad2141362c03f60cef96489a425fd0853ebefd664a943769fb264be5e63581729425b67e6a511aa65c5a9d0e12a025584ab2f3d708d5b85466b3b3153bddae153cadb0feffc77d9c9cd9c66f8dad470060b4e4f14c8536cb1e65dcd07493ff3add2e3f4d662030da9c6a1ef2f47c76aab4fb3437cafa44cbeaabb8896a6cad2c4ac357b40d46c547e19c0c995f41a6db28f6574c6238a1ed9a34534291338bd0b7f3be3ab06ff52cefd27b260130b1588fde1e496566bdac59264830187d9e8f7c6641f347116207b184733bcf5623235e169c21e9c45eb835e9e47105933f43d1a585a5f06ca69c4362dec6b5b255d2dc23acc2ad530cf4179b8aab9e93afa77efdfbf3ba3fd54c0a2c952d0e2fd8f671dfa38997aacf88034f05dad6767983b8fbd04af5c0bd540322a4f8a7b2e64a526ff06243cf4037fee05b1069d845b9f18d4a27c844d1c78baa4a57a7a6f76ea4cb1d18af6ab81a5469f7727ec0731ef7147d8e995460f7369a5ebd1bb13e81977eb06d6a0259b16f59cc65b3395bb3070d99e50588bc88cb96120d8046d2d7ca128af7b5346e0d699689a87079701238d0fae2779f2ff8da0f8b27164a314142985965872ac1aa3c884e298dbe78e0a42da858b30250dbd3e17f371c015349e70577fca9033e3ae00cce8ffec5375cb85a10ff114166bd5a37f5b2d3c5d4a446af291d96a1ee219b4b83837529bab460e97ee9c12921577c914cc03a50f027e0aa12b144cbd456d9996bf2799c67818665b90d0c524db4354381c7d560f8fb841c7e65a8c83b979b39b4ea10a3c828b1298d1858964c6f8944bbfbc0359da14cd7e5974cedb8a959b6752c661cb09a5cda63f9f4e9598d2dd5ae22d0dec955ce28ac7a004dc39e317400c0abef0885d7f01dd7e7153016339d55ad4a9c9f6a621cf3b252ea4b82c6920283f2d16a21a4a7e9678a4414843553a7490f79fa7bb37ef8f714efe60bf69f37d3e5308182a710f6ab7f865c704690e6fc2e8c3e97a54eecf85ef6adf56e3e65f80ccf6ee6cfcba634f187ba95cfc40ce9af4ed1b213013a3392dda9ec21b2b2dca206cb206573e9ec38a7985934cc26f63ba9148fb492778a32dd5bead1fed4a3ed255fd8457ae8dcdf74fd30b6613dccc4f01469ef625bce56c9f5e1e5226ef8d49f1ce59e19327c4cf166a801e53757d8d3d9e60ea885ff8af98deb8f04dee6c2c5356fe560a7d1e29cdac3ca1dc82d83cfd8d1f96e1a05ce975bd654aa3ecf32cac0e7622cc93e119285bfa8807f54e4fa56f44276c948f917fb9a5f039965a66e4c3711057d7e79c5f389696d9a5c80a65d64908413da6cc30db2961992681a68ccfdc85f9cc3264e789b5f33794e319d681c0a2d64f9ebf1886f43e9a634dca2768831ee2ae9cfabbccda79118247311348cbfd017e2b109614279aed0f9ebe7831181dec8dd528578485cf93a6ea6fb693c2ad52a7a0b48c1e05e1dcccd49736fcfc9a3dd9de79c6bee7e7c198bd0cd434cb2f929fb03ec2f08304e90e94decd9690b6cbdb5ddfd98f4b1e047e54e0902b60e697528c2930246be5bea360dd388efd19f71a2bb8e28a63d213f6ade293c61a2a9ac58a1d5e61ba82d3573fb1337be6015d1bebc68e9260cbbc8ca37358796cf8dd54eda5f0d99974664123482f81e00e867f66d295616307df82ed20a18b69ac1cad310f5fe96b0ba322a1caaa74690a7f0fe24b47cc300b4c75a4a40a6832762c85d73c07afb9b241991dff2eb9d34c0f83692890b4f8613dd558eb740e1ae12c06cc2f78231cef63bc6a701a805e6881f4ef42441290e13ef7455faa157fb648462171bf6fbb315d812dc9810e26d1255d7a508c0c5cba238487d78249412e7208922f66943e14320d5c58968720692363cb7d1be06186a9e29e8783fc08a531c7c3fafc608b3549eb139634c3482388e4b0f4a58cea9068468e65348eed7311d1b0e7e07c480e2ef908d4e015e8b9ca8b45231f735f82080100410866b0e831386664194e8360ea0afa244838d23e18db736b1a0005b2dfeda3ee10be67a6e2326817be4362a83ea20888cded195835f9ef91abe2f6e19f02a9117876e2db4b8df95bfc5b3cc2f8828b87330607e5e7f6019fb123980c1f9705f663e42c3526f80a4ea4105d71215c670c04aebc5930bb5b20980ae4d3e12a66ef95c45f3e5f66f80b19a9d81f7de40af02d3cb40cba2c1fa368c042fe9b4ec4e7d03c7f7fd68ed4b645143553b8d53d87888f88c6e01580adc743c26a70f0327d5ec0a566a0f7e0008292ad8e94eaa5dc78c1076d833919191b21c10dcf4f0f7f3307e6a8f4a0a5a29529ae5b34b1d026163d06fbed632cd4dc7a32dc1e3eedae9d916df49b1ee534ec6c67d2f8a384ea0e44c2b05201bc0efa821f183e910774fd5f000000ffff010000ffff83dfdfa196b30000") 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 06787b5a..09fb40cd 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 +}