diff --git a/auto/gui.files.go b/auto/gui.files.go index 236799099..56e082fdd 100644 --- a/auto/gui.files.go +++ b/auto/gui.files.go @@ -73,7 +73,7 @@ func init() { bs, _ = ioutil.ReadAll(gr) Assets["favicon.png"] = bs - bs, _ = hex.DecodeString("1f8b080000096e8800ffec7dfb7bdc36aee8effd2b186ddbd87bad193b49d37b5ddb7bfd48b7ee23c9673bdbd3d3af673f8ec499612c890a49d99975bd7ffb0148bd1f238dc749bcbbfd21f148a2400004400024a1bd4727af8e2f7e79fd82cc75181c7cb6f7c8753f1b8fc9b1881792cfe69a6c1c6f9227db3bcfc8f7f4524cc891903342231f5a445af249a2855464433146f49c91e3572f2fce4e8fde5cbc3a3b27531eb0cd11823b0c0262c029229962f28af923f2463122a6f01a574489447a8c78c267042e67e28ac988f964b280cec84fa717aed28b8021ac807b2c52d81dd5c483a71346a6220194786470f8f1f4f8c5cbf317a6fbd167ae0b54217124a0d16cdf619143a2994be378df518bc883eea399b9e52145220898dc77ceb327c75a060ef102aad4be838d02412f1d04c9a87ff019217b21d39478732a15d3fb4ea2a7eeff758a0773ad6397bd4bf8d5bef35fee9b43f7588431d57c1230000b3db208de3a7db1cffc192bbd17d190ed3b579c5dc742ea52d36beeebf9becfae800daeb9d802c2b9e63470954703b6bf33da6e00f299f2248f3517510956a3194df45cc8468b804797307001700c1e6b2fd1847b08692ed974df99d22bbc1cc5c0c883cff005cd75c00e722692dfc9cd0d8ef34b18df97d0d3c6e6ededded8b6ca3bb0c0264268a5258dc79e52e3fc6a14f26804779c140f940635674c3b75001278704d174b1a9b6ba2173150acd97b8d3d9927844c84bf2037e6272131f57dc0de9d08ad45b84bbede8edf7f933e9b0287dc290d79b0d825ce772cb8629a7b94bc640973b6487e638b1c4a189a2da268a45c107d3eb5206e3f337fe63b5b64fe04fe3d857fcfe0df5779f7d52ece2c59007b8dde92e0ff943a08a99cf1c8d522de253ba3af5858693b42d6b8a188848a29e8662b5a3fb128105be42711510ffe825150027405903c068de64c028ad780610ea6d605053d40c5f351a5fd036db44acb0394eae6531c9deea7539095eea739647f29e4d6a739643fe7c244489f49cbbb484435ba0231133536ef92ed6faa7255ba63c0b85f15e2150bc55159775182c15c5cd53be04abb91702709d82b9d77656e1bf17651bc2d6ab51781b02009a3fc1d9fab38a030963c022d62ee2410de658607689d353220fd997ce482632c3a884ef16042bdcb9944638cbd0809e8cf261b4f9e3edf224f9e6de37f3b9bdf543928a9cf13b54b9e9688cff8b313bf27cf8afb19239fc0ed27d9eddb3a5d2066d1c8a760d36a721eb02960bb5d087a85bc9dede2b6917c1af019f21f89fca69f571983b339a2c95f1c0bf2888768d069a45b3401a6affcb5eb39d7cc353a83af5e830dacd89e6b66b9ff6c7bbb1592df306396fe2760c4fab0f0472aa441e056b8d88950faf2ff0f99cf29d908e9fb94a75f3fff3a7ebf990348f50a1c8018cc0488f481bd53d6bebc3121e33f83ec831ba00925f934406092d538a3b0d16cb49bb7257f06a648b0321398f3493c074e2b502a0244886b824335918c5e2a74110201af4b164b01ef04208263059337f81ad75ccfcb10ad3ca911f9f338bf5d6382043665a3729b8be3ded8a820380963eb257cb66728c4473ebfaafb1a2fae60aa357ec6c1de189edb29141c31722162502949d087c17b11bdca5d117a854fec1f3443d94f9f4d691280c700e09969c767d4ccfb76863318a440100b0acc91e9339c1b417baa7db81309fe1ee0c6c359f604ed9b4394f4ec4fd728ccf367c60320732399fbced3270eb1de8ab3b3f3b53306ea107ade555ceb07819039f7c1eabaef61426e7319e2fced2428bd9e115ffa69f436a7cbb808c8780e1e4212cfc0eab0d3682a4611bb2e916f1a824fab4594fa07f622f700273aca3ac09ff0af60b8753fac2b094eea65ded1c666b583328f67c1229ea3f744f25fae37675712fe26b193f1ec4b16aa5cff0b20a0129182f98115bfdc2b1a24f03f930a067ddfb9b929938b2d94bebd750eded8bb2063e4e68bb4f517b7d521321d8d2d0b4a9c1c07bccad794165f8ad817d751955a9a32e64f4ebd1d88ed6c867e30da99f4a20ca546e3c10b9f6b8be0bb2fa309f0636f924b3268b0466e4de01fadf45f084ade6fc8a2a482a421e32047b53c86603ccf582c700c7b076eeefbb511ab9370e8fb04c1c1ec2ee4226d8a185799da87112ac5208c802bd7cc72a6072b04d9874fce487ec57d549b15b086c9419f5be3ad06a1ee89590fda19b8bbb1910fe7e23b8981691f3673986a4e4f3e240fd53cd128c0839016d3692fc616dcddf807f3b8a6520f14c329349ff7e07366217e480ed2894886a10c33b7d42e0b63bde8d31e84b904e9bd7112b45bcfe2493af1e30f985eec6cdf3151dbf6e81e7ccba5d230cf5f6f1111050b02c1f97544f89444cc634a51b9f886a43c25d75446e837a5ae44e189e084f808e04ff9ec34c2883d37d300b8f00b2ac8046ee8bb3b4fcab36be939f08105c4fcefa6dd5667847a5be4b56f5aedcd9f96e6b44a1b932c70321981b092f9cc0707ebe941cebbee0ed0fdaa1bfcb834841773cc3d210f12699c2532a78a4c188370825e611e2ad1e0ee812bea412c066ff823526437c2048721450cbdceb491c946818351053d2a793195a1ef461fe3cf9a9732c04f41e74485651f85c4102ea69ed147d5e4ba0bd110a900b46dcadf3b2d8359bd51b92c5d149e735539d82c09c04f0659ae897e45c83378f862313d9b709a6ca0738db1d36601a155219e2fd30717c3e2d821dc477ea73d70a6966b46aa453737f8ca313ed8c05fa3d313f086cd10c225a3dac2c4e806fffe0868d77ccea55a5769072d4109db54afd6ccb87615cf0df810d058650e5d0c3e19e610ff54a137f306f12610f6398f7cf61e1dd206f8019e72d9e122964bc09bdbdb3e58851e94020e64a78220d09b5b769e6baa9382e1ad18361df11c887b3d67e07f27d16564bcd937f647d3c31e0e4b8128c60c483eb73fd682e5d1c89ae6f3f4573fb4060c30816d12d481834908f77444c8c6cd0dc27dcda407e24367ac24f25f6cb663b732e6dc6f95e876b44fa1f147c4b9eb492db0b1b760feabaa79dd7ea69a9fd99db2ca55b53cd35e92ab71a3b721f36abd613de9d3aee836f1547e85d4b2b0e9b5d2921b156867aace122ded4f65d7237c38ef9ffd60687b67be7cf628c502007b49c77e4e38a651d2c445c99ac1fb7e274de36ea2d6a7d726c85c11b3a887ee6f4dcb7b20f8844be621ffd6a23bf36c4388db825f534efe36e2d1150d7897f40c664bead5ba8acffaf8f2424ab1265bda69f89462310bc4a42f1cfe2bb4a1415bb2e33e983033d0bfe50153e47742836bba502f9370c2e4ed6dc37e730d18a6dd6f917f76003b5a68036cc2238ad277f4e9f83b17611f7b7f14de87e36e80c0ef89b906d603e2ad1788c47731ed1108da97ae7b0561dfaba909f5d66170777bda61a822086fed001c90ed6a0a485c63ec5bb8a55996a3398c0590b5471141b50c62c321299196f95d4ba9dbdf07f20eb67bf0d92647cbfd2f23349f48a07009b0478c7ea20ae277a3ad1f448c5abd7de4bbe1f819c479afa2001cb55f98eae36327a84735582fc5c31d9224f2e6ccbb647dea7d3a8b846404dcf6902b5c00519f60782c128883ba8f11aa807bc88364565d5d1af42d4e9cdbd5d99fb99eaf37c9990e9559cc414e6dded58382275d51063c322bda2db15b232c33b7db9312ed31125d9edcab2c40e234d19ac5408bfb18a3dfc7b50ca047a39c3536dd717fb940805dca8faf425b2c7908934ddbe22a2e28158339005d08623c1ef4f9ebf91ae3cab8fa349a31e9b4da5ef2e59764e8148f7b1f25f759cb14df6ff9e2215e4dda01399e23ca6a19bdedf6a32dcb7087c46d39ed8a8b71a584abd1837bcbb846007c58aa3557a6526e15df3e9ece30bdfa6bb6256163f3b7879360b5e4659955bc7211cf21ab5ce54883dcdc44d96e8b94666324d74c3b15f8f4249c80c17fe49c9a39a75e037bf81379a379c0ff61d697d69c2417e0aa8623f8f330c2354dd5a5ea61c0f1eb37f7ce002f4ed26c6e2d7882cb0866544983dd9ddbdb2ffe4502d993b4193983abf518047d47cc4346ab5f1f6ba169f01893529318252664a02bdeed2d5e6d74b43d8d4c247981976521dbfcd4bc1c3479be893f241f45a28733f255a2ef9f9399fb92ea01a07c184502222af6ea07f2689f24601ba73cea348783798e5b97e742f62550b3dec9391e1b592b95da1b52651b4b70dbab7951251eeea4709631a5b94fed95d91c9c633a2c9c6bf45d73271f0dec7b3a5da1f34f69d7fb5652fe66f724aea764e9c6c6871ceadd35f6315e68e6a67da0f0676def7f80c76d9d4ebbb9a1f03abb1c70a1e74c22e9ea21ed706871c0d7ddda50dfb9d902a3d55defebab75eb43cfd239da9ff20c94f636c271805016835b4f8471c0f071fde9e8ef66bec2c4c3cef6f6e045f737316ea53a29a659b201afafb301e05ea8d85b8988ea86073b91f7f500fea5713477b7d7d8efd04c0e2ea1dc3938e12a7dbe6c53c907db985057983f3626541e0e5984e051df22c4a1ef03b16b65b8adc1414095fcc027f3da451882fdedcb1f830ecea588ee253a1ca2bef568b1d0e64fcaaa1847bf7749040f651fa78d57e156c3e064ec290173da786a563cbad9d201fdd150f0b802f29f1ca1d7a57440a05e7fe58f78bd97ab43c2f6fa3b1f247affd788ca90150068ed49e48ff0ec032ece143fed02cdb8ba871e6f99cd6daafd4c09c3677627fa2860d14ccfed3ad7a73d5cd216f5d599fc5268ee15c6629d1326a51816f881f16b892dd8331eb3068580bba30b1e3230031058b25de7bbdd30dc55cab9bddd05444c2b08f7a692b3c80f1636fec597cc08544fc6b68ff73d9c2929458e5d2bd0850a98131d563e869d56eb735f5ffdf0494e935434203f86959fc8c6db47a63cc8b083dad9419cf41290647e5a5fa4118ef79cd4ee3a005d3df35cb25f6913132aa4460babd3ec8e814408ff12a9d828af88338a981e3775e33c89b1700019936f854cc2ce536f837a56d0f58ceb793219817f3acefb2efd920cc65231d5c4e4477392999cd906eb21b284051e7433137231f6859760b4919ea56fba6fa5c71f9c2d5ca9a48d2947c992d3b0f7d4798b50d8e24dc7dd2788971f7434cbff4c5f0b7969ed236e95009f28d3267b651205b695b12b0e51666b0be6cc6da61c0d0918daf7406168c6c16ed026c6cee349f8c7c7b93f66e7aec76070733af24c5de568604a4171da4f31b04f989b9a3082befd160184312b692a5751124b018e4768ca499005b0869c461aab596952b88323105c2d1700efcb390b029e9eed4fcdf8ded8905c70273d4f670e1b76b046e64d324664db734af41770ea94e7cce4d154e47c680e75ce06ae48d1e528cb70d5dbbf36da49ae69eeb78c46a32e2a6d4982654426598b2534e650ee83c4bcc3fba1303b71dd496076c23ba30f0f71e778e7ab5129b139b4639b95606df25b90531c6985f78ce876e2797ad28921f7df81aa0554ce00830566bd2b6c05f32254f6c4d2909e9e2f0d91d9eb730a939de653ee1955ad0d16f932f4a99a7f53ce71175b6f360b552dcd91d7a04804ff43b7a456bcca5ce26a3ecea03737e1c29eab29267c2c6e926d568687b9d363dfb1857e083472c13486938882ab6eeb9fbc93e3bf20f4fd0caa336e65a9a11903838679cbb2a059d490f76d9b4da9611e9d98ece8bee3eeb4d06e9aba3ea78148b5c70d66ad0eb67d981678eb70b26d1b749cebb551e6cf6a470acd3ec347883a88d88bf7e0d81aedac004afdeca2cac4fcd900a083606240d402b4eee635686bb8eb7b5321c3b4660efe74d28a78287d2fcca82d596dc217b2ed66c60536776f1e83c6b966427b8cc5823240a3c86400469fa7277970e1a1e5a9cfa55e34178ff6023a8108a86018746ed104a93db09a7502732fb66abccba3180fb2a739b406870b925103b2cc7c491b0ca169eda29a8a39a5827a860b66bb2328502271910c114b531f5895ef5dc27153afa1dfc54eb80f0e8341af35b99f05951d32b144f54deaa6814345f94b7de5358960568eadd6b72d23b4afb1b40ca21de0df7f6f1be0581a2a00432c3f10d99143c7c2981c623c8ab6fa968e11fa0392161c7148aaf6c23e362ba406dc889c230794a9d789e6147f025061ea408269d9e066b3b8bf39ea5cda6952daaef228c41b776400c4873fcf615eb275cac085c29a09d8688b5c321623dd21183f5bf1d3940b35cc3265178039f01a8852857a85bb5bb510abd0d53182467f47b9c42ed1d5ea38e2a16a61f09b0434babc374c0c435f1a8de947c64812609d21e50ba64c1d8b40884bab7d2372aab1724812f88699e4ab27e8d07ef5dcd434a51e8a22ae6dc1c078b85066475b4c09381cf0cc0a975de3505bd6e9550da99b30f3522a771dbca8e530ba970c9b5677a091a4b8d9d598487428961bc9380022e6e654ebbef39d08b30d48a95d44506d56719019a476d36dbbb98b9b1550cac6e8dc1679899486e919c72135f99975f08244d93143afac5e6ce4fe994aedb22246a387d9cf1538eb2f8095dc33ac82181c73b67edba481db07ac6386ec2f3abdeb18e4b89e6b79e7b178610c352e4352080b6350170dcae6f078d716edcdd1448d2a4805131f33691c0e9a6881b1aa474c0202e46b616b22b3ece5e123589bd6cf593075860c6b39cd84c7a626e27ddb9cd73aa4a561b53ccf2174f0bdbc5ed70ca6da571f5b72f8edf23528f18dac58c1536cc9930eaabc932f0f94ce6ed22b96d61cab8a7bc9887f9e1f515f3f657a0efd2d499a0e22234fed9a0d4f80329e944b7933e8885028aeface321f63c83800d176271067c1aacc2f27c8248b6c2524acea531e20905688a207978503a724e9db9b7e62407612d79380ae64a2b3e244fd5124b67ae051e48ab1e3c03a8acdc072b570b26dbdadaf9ffb8b35f1bc576fac595e386b7bdeb680d6d66e48cc5a2034c29fb598b5e56947cc6afab6de83f1196cf326bbdb8ba7f44d3c05f3d03da87a1769565ed50c6e4318b2f2381db16e8f4771660fea9502db24e2ef12dc5d06ea0acd638abe72b4ef8cffe757eafee3d0fdef6df7ffb97f1ffd76b3b3f5fcd9ede7e34e17c4d0392c2a354ddba38996a1ca03b3966745647a8ef5fe813b36550776736a93dd24afe9b518919fd2400cef2b180c8cc56810e4aea8d91ddb1900ad86b60d822c7b8d9933718e2c0b4e1e18da56f7da71390eec92ff369486468377c12915ae5551cac367a2ea83bcf1fc5911fd19e73500876cb33d00dccaa23f13f0a10ce03f1fa8dd186d6e9908906cb89be6291e1e91ca7ce563e3ef9b953ea260b1842b0d27d8de6cdfcab19e957b4df57c999db3cffb2d5d2d4eca5e75ca560e6fac62e00c80aa89fbe7f8a430729919b3edee68c8f20a4c853dfba8d6c932b8cb3ed9a78585c26b8ca8aa46294b0799ea33665b77026236223f73b04b20f49e642656e353c27591166138218c082a8be6c0df520e64e39f9b59362ec15dbf54659a839f4399e6459ec81e8a777190d0c0c174a3b93d5a9b2fbd76a8249f0db58f9159c36dd170ad1b127addc98f793edc8d69a56058706b9a76aaa1793a30c83dab56496944b825e5b7556196ce044b4c43bbedebcf59d8920398068e2544b6b8e39f4ca50851d4b1180009b12abc884a796430f158ffb6dea0c8c45ea75aa5f0b86cae8b30bda4a98cd41168a6329650f2e007b95268a55933b2abb4cc471d68cc33a5fd9309d776dcd3a43fc14a9826118cf339fa75e900a75fe68ac8b78717e6235ad692b564a296e0b7caf075ae6829c7567f31c55f4ca2b32bb558efb23278e563643d67c8aa38dd8b9c2816182d331d9a5dc0c5b99bfa11aef6f35b1f463ece0d5eb64635a2868a6b4ae458c52ecd1a98d45f61f0db6ffe9b9876c571ab05ea56ba13daec886aa8bf51bea2c5a733f2987ef37168715f292e0a8431aebb5accccf7702819299ddfb0153fad6d0011404fd3c700c0a6c6cc07f98a0d72f7e4959b83797d3c1ee2bedb177f602cee72e0cb2d5676e18b979d03fc3f1be0a546a9ecc29700d8dd3ea5eb25ceba8daf964ba40592bb85218ff69d9d8f975528f3b5cd732f3fafad7bdb7352e02980e4158209128b6bbf5b3883d92f39ae1732971158ea423724a48e668e621140a70f31c2bddf40bf89350c6c3fc2bf88c4626796cfa926b8470dbcb18865d8dfd1e9bf870597d4120cd945d4b22ba09895daf7063052c9219a2d7cca1a40cd4ba11037f3dd8c191f77628e5a47699e0aa3bf85b19d1e6eec039f163fc577c5ccf01aae86547b73881521300c16f9db98f1ca325ddd9bcc3fc21253fab9a26ac6b324307f2c31adbac4b4f692d2e02f487d8225a5ec2b4a1deb49e907f7d4035f4f6ab84395759de24b51f7bc72d397dff8f05e70aba782078c5864b636e0fe5ff21a427d011d12fb80f4edd43090ade7823250805b25a7a8c3f895d9f1a346257c3e5a00f9137d7fce22ff87490c0af52ad13381d3089e03052e845c938d1ff8d1586d0e634119da6abe5a890d15943e1a236c014e730801ecfeb99356e424d91db2319409754877664403a5c1ccc0ef937f000ea527332a4c4aefdd894f0d786bb0aa89db47139dd754825bc38233f09599d220b520c204940902c9c8b865d993618c69c0bb335b9a987d4cc3620ba75a3d468e9870dfdeb4166655db5202b88e7529e335941f38e1afc3a37b4bc3d4f75e44a6daca9bd7d1eb7c69a5e019deb62d7c6749eaa6c49ef21bf79589690f8b1e06ffec17224eb26d852d3c342d0ea368353ed6dfba675eaec3ca765f28c5f7356ec9ac7385e0dd01e99b7228f56809332a7c353dde599dab783fe865939ae4a59f7e59267ab6c9cab2d778eda10b5f8e70ba79bcc19bbcace59d45b0c9ca0a83b35deb7773dc1bf8afb404f089a29f34ba0166bf39bd63c4938158916dd0e128effda309d91b65240b883d4cf41c77f1d83395b88e3740b2cc74aa56971124d676fd11fd51a5ae85f45ba9cd1e0e75455350cba88ef3460dca0b541eae696edb5effddc5c5eb73b3dc0b54b439568a5dfc78de638fd3a1c7860fc8027fa8f9ecdc7cd8f7488a6bc5640bcbccf3f4f1c089acf2ca7f000b0f23112d429128b0497466b3f4a672409b049eade8d89f7d34b77e2ec9784d77dfe2d2e0cfeb53f2035b0cd8f3ec0f3af08ea75eb3f9e8f52940c6f538c7753acebd1ac859ae3e37b92b7c59bab206c1b4ed73c362b009d69a454c9a0a6c6db57b3a47a26d1c1edc899e2cb77c3f658efe3d1654565d83b046411aa3d0b10e91c8d6150843e2847a97be14317e21190fd3a5b72fd96222a88497a734509f72b982d0800165e6ffbca8fc6a4b18874120ae49a71dfdcb7a4b1b8dafe1b3c8938b18777c24e5b1e1ca6ef2f3290f16e6e870798555c23898e390204f318042c5545be65da2f83fd233c1348ef345740031cdb7ee4aecce14c007138280ed86341fabe8e47b0c6329428397396a6cb62aa523466794d7beae5fd92793ff72af68903037914151f308bbad967eb2ebfe7436936c66f60a1bd952205ee9f6c96402462058107a05cc30b92aaac9cd1700f68bdb1a1aab99d6b24d4d97c62d7b5e4b76c5d975fd7b9067e5876886d29f15196951d25856f61c14f08bc274f6fe098ec9efe4adb295f4ed43a050b28f6076cbdf604889a67027d66fceeec7e4fe52fa02d65d2d6ef1ad867cddd7c3ef300cc47190c97d29eecddee2174471dfafd926d65d6c0b1b2dabf563ebfbd4cadc927205a0b4e60f7e4755d8efa882cd60615ee2aeb3bc765a4ebb5e6cbbb0c6f64b25d9d6ce296e04c91046998e38dca564dfdc3c3435b736a6e5dd9ea5e2a4469e5db4000386eae606219ee251985fe96f5888a8f4f5acbc2ffbac5ad5d41432ce6a204d4d15007c3dfb8d256029185773bbf966c6a3bc902a69a29d2af374740ec6d694db34d0cd55e56b4ea918157d1435564b85531b358c0e2722a9cfcf85bc507c5a1597b2285445276584819809c37ca7426556aec9d466a2018c675ecbaa288155dc31d598601e10ae79fbc957cf47b1b9af17d812661ccc14042e0df82cda25eecef318228a39435eee3b58d51fa6145fcff79da7cf9f3be383bd891c1786b0f42191ccfccd7732bc65161454a6d163112fec487de9c1cf6fc893ed9d67e47b7a2926e448c8597e5e6a2a706ec7d5b4634c3f70d06e21d56e3e85741d9be8fb225e528920b0fcdf219520cc479c4d4c6288379e47be8479e32489e6346c6d20f53c91e4f03d1ee53c7bf13339f7e62170adb56de24b0e9eca51a22f615ef1e0775bb323169173eecf456b8747c04e1f933b731ef0b815c05fc133e0006296485f29ac1a50a97a382eb3a16a2857e6dff7a09c0a4f6de199b57a4f6913b053e484b3b09dc3968e9821e3b07cbd6c25e96c01da7c9e005d57b4b5970b78b620670274ba038fbf31a639a04a231ab1a13c29ffec90ea5279bcc80b12b371bc22c34a4cf5b529332489714ecd764eac6624a625992e3048eb5256ca71ce440053ea08b4646cfdb0bf0adcc43293340cb1931fe16902ce0d169adc226d9af684a4af619610d46954a94759ef125dc009d793c4bb64da747b098103a7104e8fc184bd071b55bbb1ace7131a7150104040c4e0c2b2019de3e9b0d14c8859c04ce1cd78ac22709417ee4c0007f2dfddbdee187acf6dc355c82e55fbb45c1f9bec8547bd397824c5ef712093eeee9f02ab1179721a792bf5f936799b8c313710e0a61ce7a07adddde133720c8311a149273f6a7fa53ec1cff7b54472d9150bfc0930b87667c9e86e81624ad04f9fca845c488ebf22ba4af7575ccb241abfa3b8b057bae8e874553946d58049f8ad4ad5e7d05e7f7fde4dd4b66b386a8770ab7f0c911ea627e0d1839f466343957370945d2f9152dbd105046f6042eb3d6576a9703cf04279e00a6a3bbfa7b4e136e8d15bbb51d23c3de868e8e686eb0eafb8e8cfb2019dbd7d9730b9709f8cb6474ffb5be76c1bbf55e38287bdefd96279a8a1aa879038ae358088c1d4c907a74587c0d7ff050000ffff010000ffffacae81c1f7a10000") + bs, _ = hex.DecodeString("1f8b080000096e8800ffec7d6b77dc36b2e0f7fc0ab8ef249666c56ec9763cbb8aa4bbb2e44c9487ed23d9379bcdc9ce4193e86e44244103a4e41e45f3dbb7aac0f7a3c956cbb6eebdf9608b4dbcaa0a5585aa02503c7874fafae4ed2f6f5eb2451cf8475f1c3c729c2f261376a2a2a596f345ccb64eb6d993ddbd67ec7b7ea9a6ec85d273c6430f6a84b196d32456dab02d23048b17829dbc7ef5f6fcecc5bbb7afcf2fd84cfa627b8cdd1dfb3ea3ee0cd3c2087d25bc317b6704533368260d332ad1ae60aef204839f73752574283c365dc260eca7b3b78e8997bec0be7ce98ad0e0703c662e944e059ba904409221c1f0e3d9c9cb57172f69f8f1178e03582172cce7e1fc7024c2110be70e8fa2c39159862e0c1fcee9958b1829df17fa707491959cc4da1f31d7e7c61c8eb092aff8e508bb14dc3bfa82b18340c49cb90bae8d880f47493c73fee7a82858c471e488f789bc3a1cfd1fe7ddb173a28288c772ea0be816461421b43a7b7928bcb928b50b79200e4757525c474ac7a5aad7d28b17879eb8023238f463071097b1e4be635cee8bc3bdf16ea3234f1857cb28962a2cf5d5a8c69378a174a3862fc34b98381f2806c5b19bc44cbad8d3428bd9e168c6aff0e73802421e7d810d6219fbe2282722fb83dddce03cbf82f97d05236d6ddfde1e4c6cad7c00dbd954a9d8c49a4713d79849fe6b1cc8700c6f46291cc80d6621443caa77a08106d77cb9a232fd66f132028c63f121c691a884b1a9f296ec861e198bb8e701f4ce54c5b10af6d9df76a30fdfa46533a09033e381f497fb6cf49df0af442c5dce5e89448c7658fe62871d6b989a1d6678681c607d39b35ddc7e417f167b3b6cf104fe3d857fcfe0dfd7f9f0d521ce2d5ad0f706a325feff280d10703d97a113ab689fed8dbf1641a5ee1849e3042a5426e2209bad60fd24425fedb09f54c85df80b4ac128901500f204245a0a0d205e03847937b52138c8010a9e8722ed1dc52455b13e42ae6e96e2ec7497ce8057ba4bf39ebd953db796e63d7b3915a64a7b425bda852aace1e5abb9aa91799fed7e53e5abd21beac6f9ba60af481989c2ba8f1c0ceae2aa3e8034b1132a679a80be8af3a1e835b1b783ec6d41ab3504c4fc2408f3369e3491cf612e650852249ca9afdccb0c0e903aab6480fb33fec81987343ab04e5130e5eee55ca332c6519406f0e7d3ad274f9fefb027cf76f1bfbded6faa14d4dc9389d9674f4bc867f4d98b3eb067c5fb8c904fe0f593ecf56d1d2f60b370ec71d069353ef7c50ca0dd2d18bd82dede6ef19a389ffb728ef44724bfe9a75546e06c8d68d217e7823d92012a741ec62d9200cb57deec7a2163e190cc60d36bd08115dd732d2cf59fedeeb6f6e435d498c5ff0928b13e28bcb109b8ef3b152a76029436fedf81f024675b01ff90d2f46fcfff167dd8ce3b48e50a0c8008d404b0f4917d5396bebc326393bf02ef83191033cef26580c1221be38a22c6f3f17e5e97fd1588a241cb4c61cd67d102286d40a81820a1ae194ed5540b7e69d044f01534d722d20adaf8c08213038b37d81ad7325e947bb4fc64c6ecaf93fc758d081ac894cdca6dce8e07131241301226d64af8e28030c4224f5ed56d8d9757b0d4929d7174308172bb848221c6deaa08444a33b461f05dc8af7253845f6189fd836a287bf4c48c273e580cd0bda07a72ce69ddb72b1c419076825070208e4ecb706d04e9a98ee14c35d87b009b0ce65909eab71133dab58f0e09ccf3676401b00571e6e1e8e99311b3d6ca686fef6fa3096087bde74345b571b013b6901e685de7032cc86d264394b74efc52f30cf9d223c96d8e179908487809164212cd41eb88b370a6c6a1b82ea14f15c1a68d5598da07f6476e014ee3301b001fe15f41706b7e5853128cd4cb7ca0adedea00651acffd65b440eb89e54f8ebb10571afe26d128a3d9572230b9fc179d80488406d607513c3957dc4fe07fa10d4cfae1e8e6a68c2ed630f1edede8e89d7d0b3cc66ebe4c6b7f795b9d221a68624950a2e4c49755baa6b8785a459eba0eabd8f29430ff36aad703b69dcfd10e463d93fe28f752c3f1e8a527630be0fbafc229d0e3609a733248708cd49ac23f5e19bf60947cdc408449054842e32807b53c87a03ccf45a4700e7b276ee179b519aba370ec790cbb83d55de9655a1521ae12b50f22148a41100155ae85a54c0f54d8651f3c3921e595f4506cd6801a1687f8c22a6f33087457cd7bc0cebabb1b19e5702abed7e898f641b380a5e6ecf463d2d02c9218197810d06a36eb85d8767737fac13a1e731d0f64c319545ff4c0736e7bfc9814e453950c0319566e1d3b2288e2659ff4609f2b803e98247ebbf62c4ad2851f1f6079b1ab7dc7426deba379f0add4268675fe7a87a9d05f3270ceaf4326672c14ae3086ebe5372ca529bbe63a44bb2935250a4b0417c447d0ff4ccecf42f4d873350d1d1776410518df093c67ef4979752d95031d84cfe87f271db6ba22d4eb22ad3daa75b0785a5ad32a75285830ca7804dc4ae1090f0caca74739edba0740f3abaef0a3d214be5d60ec096990683296d8821b361502dc097e8571a82406730f4c51177c3168e18d5911dd08129c861430b43ad34a148d0203a3daf5b864c554a6be1b7cf43f6b56ca003b058d1313946d141681bb985a469f5492eb264483a57c90b699fc306a99ccea8bcacfd28fc272ae0a8798273ed8c9c0cb35d6af3079d61f362c966772a7d9161ad7e83b6d173db40ac4f355f2e0a05b1c8d98f490dee9085298d592914ad1cd0d3639c1822d7c1a9f9d82354c53083f058f6d9fe8dde0df1f01ec9acdb952ea2af5a02608619be8d5aa916957b1dc800e3e8f4c66d0456093610cf1df2af866d620be04c4fe22434f7c4083b4d1fd004bb96c70314b25a0cded6d5f5f851c941c0e24a70127d05d58725ec43c4e0a82b742d834c4f34e9ceb8500fb3b092f43b266dfd987a6853dbc2f03ac180940f9c23e6cd497cb43ab9a2fd2a7fede1a7d800a6ce3a00e182820dc3310635b3737d8ef1ba15d601f3e172596ff72bb1dbab521975e2b47b7837d06953f21cc5d2535c7c6be82f5af2ae675fd994a7ea677ca225795f24c7a592ec68dd186acabf58af5a04fbba0dbc053b909ab4561d3df26d69244a09da8711668692fd55d4558b8e85ffd606a7b57be7cf528f902d0f78a81bd1c710ca3a4818b923683f65e274e936ea436c7d706c81c1589b007ef6fa9e63d207c2ab570917e1be19d59b601f86dfeaf29257f1bcbf08afbb28b7b069325b56a1d23e77d7479a9b5da902ced387c4eb698fb6adae70eff1dea70bf2dd8711f449853efdf4a5f18f607e3fe355f9a57493015faf6b6a1bf650c10a6c3efb07f7574f662195367531972e4be179f8fbe0b15f491f747e57e3ceafad8f93d1197fa7a40b4757d95780e863d7cc5fbc275afc1ed7b3d23576f130277d7e71d8a2a04f7d64ec011dbad8680d435fabe85599a45399ad35874b2f12c62572d93d830484aa86576d74aec0e0f01bda3dd1e7876d98bd5f61731cd676228dc02ec61a39fb801ff9da4f5a3b051abb58f74278a9f839ff73af4c150fb45983e3a7676f5a8d6d72bf570a72409dd85702f459f789fcd43a50503b33d90063740cc67981e0b04c260ee63862add3de449a25d5787fb7d9b13177677f667192f365be46840439b3948a9edbb5a5050d2e5654011ed68b7f86e0db78c5eb70725da7d24be3ab857d980c465a2358a811af7317abf8f6b1140978739696cb8e3fe6281d077293ebe0e6e9196012c366d9babb8a1544ce60070c18971a5df67afe77b8c6bc3eaf1702ef4a855f7b2afbe624397783cfba8a5275a96f87ecd170db16ad201d8c9024136abf06dd71f6d51863b046ecb6157dc8c2b055c490eee2de21a42e7c342adb9309562abd8fa6436c7f0eaafd99184adeddf1e4e80d5a2974556f19783700ed9e52a7b1aece626cc4e5ba4389392dc30ec54c0d313700202ff19736ac69c7a15ecf14fec5d2c7df94fda5fda70915c82a91a8ce1cfc370d7626e2e4d0f014edebcbb7702b8519246736bce13fc0c6145d5dcdfdfbbbdfdf23f89237b9a5663e7f06b3302c1d8a17091d0e6d7c7b18ab9ff188352d308392610202beeed2dfedaeaa87b169227f9167f96996cfb73d372d0e2f92efa987454493c9c90af93f8fe2999992fa91c00c8c761a8c0a312af7f608f0e5902ba7126c34e753898e6787479a1745f00351b9d5de0b5918d42a9bd2e5576b0048fbd524393b8789262b48a28cd736aafe970700ee93077ae3176cd9c7c3470ecd96c8dc13fa75eefdb49f90f7b267133214b0f363e6457efaebe0f59a19999f691dc9f8dadff0116b7353aede186c2eaec32c055bc101a51370fe984438b01bee9d186fac9cd963e5acdf5beb15a8f3ef46c9da3fe29af40e968639c077065d1b9755510f9028beba5e37fd07a858187bdddddc19beeef223c4a755a2cb36c0b9a6f7200e05eb038580b89ea8107bb90f78d00f625199afbbb1b9c7768060757603e3a3a95262d5f75a8e4a31d4ca80bcc9f07132a8543362164d8b70971ec7980ec46116eab70b0a34a7ce0b359ed2a0840fff6c58f4106175a85f7e21d0e11dfbab75848f367255584b3dfbb258297b24fd2caeb50aba17032f2943a1bb5d194763cbac9d2d1fba3a1dde30ec87f670fbdcea5031cf57a933ffdf55eaa0e71dbeb6d3e8af7fe9fc32b435240471b2f227fba671f7173a678b41b3493ea197a7c4587db4cfb9d128165f624fad817e13c5ed87daecf7bb9a4cdebab13f9958aa55b288b4d6e98947c58a007faaf25b2e0c878cd1a0402de8edfca40801a00c752ec8fbedb0f827d6346b7b7fb0008d502776fa6a5083d7f69fd5f6c443350bd19db3edff770a7a4e43976ed40172240373a2c7f0cbbadd667bebefee1b3dc26a948407e0d2bbf918daf5f507a906117b5b38b38e94f005278697e91863bde7353bbeb0274f5ce73497fa555c85548951666a7d99f008ae0fe25da88719e11671c8a78d2948d8b24c2c4016cc2be553a093a6fbd0d1ad9c0d073192f92e918ecd3493e76e9490b984b234c13921fe926333bb71536036405095c1866aef472e22937416f23bd4bdf34df4ac51f9d2cd298a48d282f9215b761ef69f016a6b0c99b4eba6f10afbee848dbff22be56fad2ea473c2a013651264df617050a6c2dd22b2366e8680bc6cc6da41c150928da0f806140f3600f6833d2f37813fef1496e8fd9b5eb3128dc1c8f3c5257b91a986250dcf63302f413c6a6a682a16dbfc300608c4a52e62ace22adc0f008289d045b0269d859186336ab9815e6e0181837d64be8efab85f07d99deed4fd5f8c184502ea893dea7a3cb861da4d179958c10d9f19c12fe453f75cc7362ca70a6723a34a73a278334ac18729c45b8eaf5df9074b26b9edb2de3f1b80b4b9b92601592495663058e792ff781623ee0fd6098ddb8ee4430bbe19de18797b873b8f3dda814d9bcb7131b95106dfc5ba0535c698576c4ba9d709e9d764228bdf7206a3ed77380608951ef0a5941bd289395581cd2dbf3a529a2b33e67b0d8c572265d12d5da64b1af028f9bc537e5187771f466bb10d5d21a790d82c4f03f344b6ac9abe827eee6e30a7a73132cedbd9a62c1c7e426d9616528cc8d1edbc626fa6150c901d5184c430ea6bacd7ff25e4ffe1d7b3fcc7a1d4d5a494a38a363d0506f591434f31af2b16db51927e2f12945470f47ce5e0bee54d5f124f7552a3d8e3f6f35b06d619ae0adc3c8b675d070aee746593cab5d29a473868f107460b1971fc0b025e9ac7494dad9459689c5b3019d0eea131da2964eeb665e03b786b97e30533a4873e6e0e328cd8887dcf792666dc56e1336c88e9b91094c6f6f1e83c439b4a03dc664415947e3902200e3bfa4377970e3a1a5d4933a5e36378f0e7c3e050fa820180c6ec104ae3db292750a6b2fd66ab495618417d9d3185a83c205ca28015964be240d84689abba82662a352423da2021d7704014a346e92216069e803b3f2bd4f241eea25fc1d1c447a60301078adc1fdcca9ece08915a24fa19b060c15e12f8d95e724825539b252dfb68dd0bec7d232897682fff8a36d82234d580084987e20b433878605a91c4616455b7ecb1131fd114b138e8c582af6ca16d30e2975376617480143f93a519de22374aa280f24a8962d4987c5bded71e7d64e13d376914726deba2301c03ffc7901eb92cd53062614e64cc04a3bec528808f10e40f9d98c9f942e94884569178038d00c58a982bdc1d3adb152ebe0d5318324bfe39c6357c86a751ef152b522f8a63e0f2fef0d1222e82b92987e60889300ea0c284f0943792c7ca52eadf48dd9598c994312df2362b2af9fa041fbf573ca69ca5d6445dcdb82897171a3ccceb69a313038a0cc3297dde3303bd6e8350dae9b0a6a94f25d072d6a318cee2dc3a6d61da824391e7625158906c56a2519f980c4826eb51e8ebe5341760029d58bd8559b561ca406b93d74dbaeeea2263334f517eea657ec94b2bebab079604213c30a8e5395ae0a990271fdc4d86945c36dcc7e96a03db987b9f6246d68aa92128179c4a92c944611c208443d97c91a083cba6f0480799308a3678400a55e0108ed0336cf1134982207137a30caeed3c4e1bef98edb9d5774d88fb3c73598cf5b0222d2256ef2a4c1b0b6b79a2790438b41efcaa639ac17b11ec6ae2d53f992d632dca9e5e03947a05170824632dab7798d733051e914a8c20c4642934dc69358a13bef328ad1c0242e6dda6891351e3e8335cbe742f8b3d190692d47e2f066d9547d68330b5aa7b434ad96e6790f1d742f6f6936fdcdf60dda966d8e76fe1ab43780a458c3986e09250f4a4e94efa094aeb7f22b91a665abb27b699dfb4b7e8b7ff3a8f2058cb722ae3c088d3cfa4d67c20064bc4c98d266d02daa405df55df73e41af7a00a0ed76321a0a559e5f8d10c5d36cb228d493e509026e15b1189c390fecb6a4eff8fe2975d9895c4f8cbe12accff237f53bda58eb813bda6bbad703534d367deff53ceeb62dc9be71eecf1dc72b71bdee78796fb1adbc6d8fb1adde10b7be00688c8f35b7bea5b4c3ada7b1adf5403683adde24777b7e99be85a7201e9a0755eb22ddb8303585db60862c83504738a0c7a238b777194bbe7f12caf7091ec0037185ea114777223c1c4dfedfafdcf9e7b1f37f779dffe5fc63fcdbcddecef367b77f99749a2084e730c79daab63b5c2d5395fbae2d6585f37e819f4400ead86826e8cd99dd0f6079dab3e598fd94faaaf8dea0590a5a92fb7e6ec992a5dde923ae07b6f5132d7949cd912ba8cb8c93fbceb6d6bd0e5c7695bbf8bf0da4a10ef35d604a996b5d90f2080333f549de7afeac7090c978f5c120db6ef791773207997c62e401fce701b65be3ed1d7292d996b34da578bf461bfa10cad63fb62b6384fe7205555a5cb1eed32e9b69b9373c5eacd273b6bc5fd3d5fca4ace9a8ace5f0c53a0a8e3aa8aab87f4d4e0b2597a9315bef8e8a2c4f5255e8b34faa9d2c81bbf4932d2d3414fece7ce21283a711334ad04327df1360b3c29976b5205f0d9c6519179123810bc298a1b0c412e85b0a136dfd6b3b0b58261847c0c001cbbf1833cbf360b10364efe2ae25f58311597a3dde982ebd7aa8c49f0db18f9058c375d170a91be27addc98e793edc8c69c56098734b553bc5904a073ab9e7d544320d0fb724fc3671ceca9560856a68d77dfd310b9b950123e59106cf162f45b0995601b23ae64b600126ce5761394ab6432982eb158a60f5752a55066f14e7b208cb4b1aca480d81b680daba5afce14c7225174d33ad6657f69d4f3ad118674ac7675319db794ff74518260ba55839aee768d7a5139c7ebc2c64df1ebfa5ef8c594dd612895a01df3ad3d7b9e9674636410ee5c7a138695768b13e6465f2ca37ed7aaed95561ba173e31c22729a301e9a0747135a97ecbadfd8adbc7e18f0b822b0f21d3a91fca226405bbb46ae0bec71a93dffef2bf886a37124fa3a06ca587c5e9d05843fc49f88a1a9f4fc963f88df60c70f300f7148208b7a62d64f4c920cec626ce5fd8a4a85637000ba0a5e9a103604363f4cdc2e20ce13d59e5a54d946e1a0f31df6dc31f8488ba0cf8728db54df8a2f1e808ffcf2678a5522a9bf0a50eec81a8d2ef15c6baf5af5673a4ed24370b03191e8ef63e5d54a14cd736cbbd5c5e3b1a60af9281a5009c573026702c6e8fefe00a663f76b999cb5c0660a509dde0903a98398885039d16a2877bbf8e7e136a98d87e807f5189858e4e18f098e1313eb0c64291417f47a3ff1e365c524d30e4a055cbc18962556a3f3e2158258648a71cd35ddf58965c2149ebdd5c908d3ba5dbe8611aa742ef6f49bad3c5b38f60d3e2d70aaf044d2f5135e0b1bb005f111c437f99b7c6885716e9ea3e87ff09b698d22f3a55239e2586f9738b69dd2da68db794067f64eb336c29651f9aead84f4abf49681ef87e52c31caaeceb141fd3bae79d9bbef8c6c7b7825b2d15bc8325423ada8047a4d91b70f5150cc86c01eb3ba9413d5bcb0579a0e86e9d98621c44afe95c8d1997e0f9640ee44ffcc38508bd1fa61108d4eb249e2b5c46f0aa2c50219031dbfa41be9898ed612428f7b69ead56224305a44f46089ba394ee6980debf18a5494b59f6866d0d2542bda73b13a201d26062e027dc3f0285d2cb2b1522a5efee44a7467f1b90aa09db27639d375c835923fc73b0958589816b8185190813389221996559c930c234fabb33599a907d4ac56273cb5a39468a90bb6f5f5a0db3ae6e2975b8897629c335941eb8e06f42a37b0bc3d4cf5e849490e6dd9bf04dbeb552d00c5fdb1ade6845e8a6449e728bfb8ac4b4bb450f837ef6231aa7d9b1c2161a528de3305c8f8ef556f74ccb4d48d96e0ba5f0bec1239975aa307c3b207c5376a51ead204685ae34e29dc5b90af783de36a9715efa759c55ac67abaccd7b8d660f9df97280d3f3f50ddae4993fefcc824d5256089c1decbf9be1de807fad2d80cfe4fda4de0d10fbddd91d3d9eac8b35c906038ef3d13f1993bd33c45980ec71122ff0148fbd768afb7803388b9653b33e8f20b276e84f688f1a73adb4d78a6d5638d4144dbb5a857594576a605e80f2705573dbf1faefdebe7d7341dbbd80459b6165c4db1f2f7af4713af558f10169e08fb59e5dd0b78f5f68756d846e211995a7c50317b24a93ff06243c0e55b80c54624027f1b98dd2537285360e3c5fd3b03fff6466fd42b3c986e6be85a5419f3767ec07b11c70e6d91b9413002f0667ebd19b33e819f7e346cea8e36a30f59cc5ea7395bbc6c7b72b7b1022b6636e5908b6415b8b50684a52d796dea87326dae6e1c1dde8c962cbf79309eabfc686caba7b10562968520a1dfb10896edd812014a7dcbdf4b48af023d278992e7d7d299653c535349e71df7cceed0ac67d0198d1ff79defdf5b6308e7d5f5db34e3dfaef9b6d6d54b2aad8cbd5ae5e4678e22329cf8d34f6909fc7a5bfa4dbd5e51d560df340d721819f22e80a05d3ec505b66e43fd36bd33c8af24d74e862961fddd5381c7d23005408766c0fa4799868283f63186915105c741b9b8e2aa533c6e75c86d53329957332f99373c5fd443889f68bb450386c353b96ddf7e7f3b916733a2b4cbc6580bdd2e393c9149480bf64fc0a8841b12a1eb39b2fa1db2f6f6b60aca75acb3a35dd1ab7e479a3c59514d7f54f669e970b510da58f151e6911d24857ce1c14fd17b9fbecfb539c933fd8efc67e6cc01602865a7c02b55bfe4c458a34873751fceefc7e54ee2fa58f84dd55e3169fb3c8f77d5dfc54c5401807a9dc57eadef42d7e6415cffdd231b1ee7c645869553a249b02a9960998959324a56991f053b3ca7e6a16748608f22c809d19c8d38ce3f57ce48536b61f73c98e76cef020480630f27428e12d6787f4f298d2926dcdcaa73d4bf95b899f1dd40003a6eae6067b3cc3ab30bff2df305753e90363f958b6ac9af895723d6769a2669428019b67cf9825978372a5d7cd96198df25cb3ac09762accb3f105285bca484abdd3afca07af52362ac628d2d09672cb36d23c1d4f55525f9f0b7ee1585a6597322b5459272504f59831c362af826596d18ad257711fe6334ff75564092bde50c22a58079443ad9f7cfd7c1cd1fb788935293f820b7a88fb721eee3367ef79041ec542202d0f47f8e1035852bc7871387afafcf968727430d593421196beb592a9bfc55e06b7ce9c82ca327aa2a2a59da9af5c78fc863dd9dd7bc6bee7976aca5e283dcfef4bcd14aeedb89b7682e10709d2adb4d9cf9790ae6b137d1f0d4c2a1e0466483ce61a98f98514530a0cc94679e86958374e9370c183d60a3a5e249a1d7fc0ab9ce72f7f6617ee2200aab5d64d3c2dc1527991c497b0aeb8f0dc56ed8508d985f416aa75c017404e0f833b0be9cba8b583bf836520a18b79a23d63306b402531e4a44c86aaa25c9b7edf83701abcb58577d6ea23a555404fb1532982760a5b3c228184c30cffba15a5f32548f34502785df1d651de42d9929d2b90e90e38fe43885802a83ce4a1184a93f263075797320886ae9fd0c1f10a0f1b358baf29139366649cd2714e4cf8a466259e2e20485377563296ce950f4bea18a46462edb0bf2b3cc432d73c0870901fa13401e3067371eeb036497bc2d266182504711a575276d6874413702ae369e25e8a9886bd04c7417270a727a0c23e808eaabd5835f2290f25080800a0223061c580c1f176d878aed4dc17949b349a98100ce5a533574081fcb97bd43dc2f7c2565c07ed5242544bf509452f5cee2ec022299e27be4eba877f0aa446e0d959e8ae35e6efc9efc90463033e1eca191d557f770ff88c9dc06484a8d2d98fb1b7d69860e77bb14674c595f0bd2910b8f666c5ecee80606a904f8feb84bdd5129f42becef05732d6493879cf7163aff4a363d075f918450316e1df4d2a3ec7f6f7f717dd48ed3a44513b853bfd7388f888780a163dd8693c22ac46472fb2df2bb8d40ef4169c3750a1f59132bd54181ef8c3b8600ac6767d4f71c363d0e3dfed41492a3deaa8e8e48aeb0e4d1cb467c580c17e7f9f08bd749e8c77c74ffb6be7649bfc6e26050d7bdbd97c8228a1a6079128aa55008f813e2500464b1c005dff3f000000ffff010000ffff92c595c81aa30000") gr, _ = gzip.NewReader(bytes.NewBuffer(bs)) bs, _ = ioutil.ReadAll(gr) Assets["index.html"] = bs diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 248c30d93..000b3dd38 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -274,6 +274,8 @@ func main() { cfgFile := filepath.Join(confDir, "config.xml") go saveConfigLoop(cfgFile) + var myName string + // Load the configuration file, if it exists. // If it does not, create a template. @@ -285,9 +287,15 @@ func main() { l.Fatalln(err) } cf.Close() + myCfg := cfg.GetNodeConfiguration(myID) + if myCfg == nil || myCfg.Name == "" { + myName, _ = os.Hostname() + } else { + myName = myCfg.Name + } } else { l.Infoln("No config file; starting with empty defaults") - name, _ := os.Hostname() + myName, _ = os.Hostname() defaultRepo := filepath.Join(getHomeDir(), "Sync") cfg, err = config.Load(nil, myID) @@ -302,7 +310,7 @@ func main() { { NodeID: myID, Addresses: []string{"dynamic"}, - Name: name, + Name: myName, }, } @@ -365,7 +373,7 @@ func main() { if err != nil { l.Fatalln("leveldb.OpenFile():", err) } - m := model.NewModel(confDir, &cfg, "syncthing", Version, db) + m := model.NewModel(confDir, &cfg, myName, "syncthing", Version, db) nextRepo: for i, repo := range cfg.Repositories { diff --git a/config/config.go b/config/config.go index 366513267..3c69dc118 100644 --- a/config/config.go +++ b/config/config.go @@ -140,6 +140,15 @@ func (cfg *Configuration) NodeMap() map[protocol.NodeID]NodeConfiguration { return m } +func (cfg *Configuration) GetNodeConfiguration(nodeid protocol.NodeID) *NodeConfiguration { + for i, node := range cfg.Nodes { + if node.NodeID == nodeid { + return &cfg.Nodes[i] + } + } + return nil +} + func (cfg *Configuration) RepoMap() map[string]RepositoryConfiguration { m := make(map[string]RepositoryConfiguration, len(cfg.Repositories)) for _, r := range cfg.Repositories { diff --git a/gui/index.html b/gui/index.html index 5d1a472bd..4ae58d192 100644 --- a/gui/index.html +++ b/gui/index.html @@ -440,7 +440,8 @@
-

Shown instead of Node ID in the cluster status.

+

Shown instead of Node ID in the cluster status. Will advertised to other nodes as an optional default name.

+

Shown instead of Node ID in the cluster status. Will be updated to the name the node advertises if left empty.

diff --git a/model/model.go b/model/model.go index c15f875ec..ca11a7998 100644 --- a/model/model.go +++ b/model/model.go @@ -68,6 +68,7 @@ type Model struct { cfg *config.Configuration db *leveldb.DB + nodeName string clientName string clientVersion string @@ -101,11 +102,12 @@ var ( // NewModel creates and starts a new model. The model starts in read-only mode, // where it sends index information to connected peers and responds to requests // for file data without altering the local repository in any way. -func NewModel(indexDir string, cfg *config.Configuration, clientName, clientVersion string, db *leveldb.DB) *Model { +func NewModel(indexDir string, cfg *config.Configuration, nodeName, clientName, clientVersion string, db *leveldb.DB) *Model { m := &Model{ indexDir: indexDir, cfg: cfg, db: db, + nodeName: nodeName, clientName: clientName, clientVersion: clientVersion, repoCfgs: make(map[string]config.RepositoryConfiguration), @@ -406,6 +408,14 @@ func (m *Model) ClusterConfig(nodeID protocol.NodeID, config protocol.ClusterCon } else { m.nodeVer[nodeID] = config.ClientName + " " + config.ClientVersion } + name := config.GetOption("name") + if name != "" { + node := m.cfg.GetNodeConfiguration(nodeID) + if node != nil && node.Name == "" { + l.Infof("Node %s is called %q", nodeID, name) + node.Name = name + } + } m.pmut.Unlock() l.Infof(`Node %s client is "%s %s"`, nodeID, config.ClientName, config.ClientVersion) @@ -838,6 +848,12 @@ func (m *Model) clusterConfig(node protocol.NodeID) protocol.ClusterConfigMessag cm := protocol.ClusterConfigMessage{ ClientName: m.clientName, ClientVersion: m.clientVersion, + Options: []protocol.Option{ + { + Key: "name", + Value: m.nodeName, + }, + }, } m.rmut.RLock() diff --git a/model/model_test.go b/model/model_test.go index 70c6a78af..d7238ceae 100644 --- a/model/model_test.go +++ b/model/model_test.go @@ -57,7 +57,7 @@ func init() { func TestRequest(t *testing.T) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", &config.Configuration{}, "syncthing", "dev", db) + m := NewModel("/tmp", &config.Configuration{}, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") @@ -94,7 +94,7 @@ func genFiles(n int) []protocol.FileInfo { func BenchmarkIndex10000(b *testing.B) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", nil, "syncthing", "dev", db) + m := NewModel("/tmp", nil, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") files := genFiles(10000) @@ -107,7 +107,7 @@ func BenchmarkIndex10000(b *testing.B) { func BenchmarkIndex00100(b *testing.B) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", nil, "syncthing", "dev", db) + m := NewModel("/tmp", nil, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") files := genFiles(100) @@ -120,7 +120,7 @@ func BenchmarkIndex00100(b *testing.B) { func BenchmarkIndexUpdate10000f10000(b *testing.B) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", nil, "syncthing", "dev", db) + m := NewModel("/tmp", nil, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") files := genFiles(10000) @@ -134,7 +134,7 @@ func BenchmarkIndexUpdate10000f10000(b *testing.B) { func BenchmarkIndexUpdate10000f00100(b *testing.B) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", nil, "syncthing", "dev", db) + m := NewModel("/tmp", nil, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") files := genFiles(10000) @@ -149,7 +149,7 @@ func BenchmarkIndexUpdate10000f00100(b *testing.B) { func BenchmarkIndexUpdate10000f00001(b *testing.B) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", nil, "syncthing", "dev", db) + m := NewModel("/tmp", nil, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") files := genFiles(10000) @@ -207,7 +207,7 @@ func (FakeConnection) Statistics() protocol.Statistics { func BenchmarkRequest(b *testing.B) { db, _ := leveldb.Open(storage.NewMemStorage(), nil) - m := NewModel("/tmp", nil, "syncthing", "dev", db) + m := NewModel("/tmp", nil, "node", "syncthing", "dev", db) m.AddRepo(config.RepositoryConfiguration{ID: "default", Directory: "testdata"}) m.ScanRepo("default") @@ -259,3 +259,45 @@ func TestActivityMap(t *testing.T) { t.Errorf("Incorrect least busy node %q", node) } } + +func TestNodeRename(t *testing.T) { + ccm := protocol.ClusterConfigMessage{ + ClientName: "syncthing", + ClientVersion: "v0.9.4", + } + + cfg, _ := config.Load(nil, node1) + cfg.Nodes = []config.NodeConfiguration{ + { + NodeID: node1, + }, + } + + db, _ := leveldb.Open(storage.NewMemStorage(), nil) + m := NewModel("/tmp", &cfg, "node", "syncthing", "dev", db) + if cfg.Nodes[0].Name != "" { + t.Errorf("Node already has a name") + } + + m.ClusterConfig(node1, ccm) + if cfg.Nodes[0].Name != "" { + t.Errorf("Node already has a name") + } + + ccm.Options = []protocol.Option{ + { + Key: "name", + Value: "tester", + }, + } + m.ClusterConfig(node1, ccm) + if cfg.Nodes[0].Name != "tester" { + t.Errorf("Node did not get a name") + } + + ccm.Options[0].Value = "tester2" + m.ClusterConfig(node1, ccm) + if cfg.Nodes[0].Name != "tester" { + t.Errorf("Node name got overwritten") + } +} diff --git a/protocol/message.go b/protocol/message.go index af5afcaa6..37c9296ea 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -98,6 +98,15 @@ type ClusterConfigMessage struct { Options []Option // max:64 } +func (o *ClusterConfigMessage) GetOption(key string) string { + for _, option := range o.Options { + if option.Key == key { + return option.Value + } + } + return "" +} + type Repository struct { ID string // max:64 Nodes []Node // max:64