From 9a5b227f3ee2b2a3854d3aec022cc9a0cf0868b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=9C=C9=B4=E1=B4=8B=C9=B4=E1=B4=A1=E1=B4=8F=C9=B4?= Date: Fri, 10 Apr 2020 22:13:42 +0800 Subject: [PATCH] lfsutil: add `Storager` interface and local storage (#6083) * Add Storager interface * Add tests * Add back note * Add tests for basic protocol routes * Fix lint errors --- conf/app.ini | 4 +- internal/assets/conf/conf_gen.go | 12 +- internal/conf/static.go | 13 +- internal/db/lfs.go | 46 +---- internal/db/mocks.go | 7 +- internal/lfsutil/oid.go | 4 + internal/lfsutil/storage.go | 93 +++++++++- internal/lfsutil/storage_test.go | 105 ++++++++++- internal/route/lfs/basic.go | 60 +++++-- internal/route/lfs/basic_test.go | 288 +++++++++++++++++++++++++++++++ internal/route/lfs/batch_test.go | 1 + internal/route/lfs/main_test.go | 30 ++++ internal/route/lfs/route.go | 14 +- internal/testutil/noop_logger.go | 31 ++++ 14 files changed, 620 insertions(+), 88 deletions(-) create mode 100644 internal/route/lfs/basic_test.go create mode 100644 internal/route/lfs/main_test.go create mode 100644 internal/testutil/noop_logger.go diff --git a/conf/app.ini b/conf/app.ini index 9d26ca2f4..613e2313a 100644 --- a/conf/app.ini +++ b/conf/app.ini @@ -264,7 +264,9 @@ HOST = ACCESS_CONTROL_ALLOW_ORIGIN = [lfs] -; The root path to store LFS objects. +; The storage backend for uploading new objects. +STORAGE = local +; The root path to store LFS objects on local file system. OBJECTS_PATH = data/lfs-objects [attachment] diff --git a/internal/assets/conf/conf_gen.go b/internal/assets/conf/conf_gen.go index 1beb71eb8..18d6ef783 100644 --- a/internal/assets/conf/conf_gen.go +++ b/internal/assets/conf/conf_gen.go @@ -1,6 +1,6 @@ // Code generated by go-bindata. DO NOT EDIT. // sources: -// ../../../conf/app.ini (19.431kB) +// ../../../conf/app.ini (19.517kB) // ../../../conf/auth.d/github.conf.example (181B) // ../../../conf/auth.d/ldap_bind_dn.conf.example (719B) // ../../../conf/auth.d/ldap_simple_auth.conf.example (761B) @@ -309,7 +309,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _confAppIni = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7c\xdb\x8f\xe4\xca\x79\xdf\x3b\xff\x8a\x3a\x2d\x2b\x9a\x11\xd8\x3d\x97\x3d\xbb\x67\xcf\xae\xda\x10\xb7\x9b\x33\x43\x6f\xdf\x44\x72\xf6\x72\x06\x0b\x9e\x1a\xb2\x9a\x5d\x1a\x76\x15\x55\x55\x9c\xd9\x16\x02\x43\x07\x7e\x70\x12\xc4\x4f\x49\x6c\x04\x30\x02\x18\x41\x62\xc0\x89\x13\x19\x49\x00\x59\x91\x91\x07\xd9\xef\xbb\xff\x83\x21\xd9\x41\x02\xff\x0b\xc1\xf7\x15\xd9\xcd\x9e\xe9\x19\x1d\xcb\x08\x7c\x0e\xb0\xcd\x4b\xd5\x57\xb7\xef\xf2\xfb\x2e\x9c\x6f\x90\x4f\x3e\xf9\x84\x4c\xfc\x57\x7e\x48\xf0\x9f\xf1\x74\x18\x9c\xbc\x25\xf1\x59\x10\x91\x93\x60\xe4\xc3\x7b\xc7\xb6\x9a\x8d\x7c\x2f\xf2\xc9\xd8\x7b\xe9\x93\xc1\x99\x37\x39\xf5\x23\x32\x9d\x90\xc1\x34\x0c\xfd\x68\x36\x9d\x0c\x83\xc9\x29\x19\x9c\x47\xf1\x74\x4c\x06\xd3\xc9\x49\x70\x7a\x9b\x42\x70\x42\xde\x4e\xcf\x89\x17\xfa\x64\xe6\x0d\x5e\x7a\xa7\xd0\x63\x16\x4e\x5f\x05\x43\x3f\x74\xb7\x06\x98\xbe\x06\xca\xb3\xb7\x64\x7a\x42\x82\x18\x69\x38\xcf\x49\xbc\x60\xe4\x52\x51\x91\x11\x41\x97\x8c\xc8\x39\x31\x0b\x46\x68\x59\x16\x3c\xa5\x86\x4b\xe1\x92\x94\x0a\x72\xc9\xc8\x4a\x56\x8a\xa4\x72\x59\x52\xb1\x22\x52\x11\xc3\xe8\x12\x3b\xf5\x9c\x17\xa1\x37\x19\x26\x13\x6f\xec\x93\x3e\x39\x95\xb9\xae\x09\xeb\x95\x36\x6c\x49\x2a\xcd\x14\xb9\x59\x48\xa2\x17\xb2\x2a\x32\x20\xa6\x2a\x21\xb8\xc8\x6f\x0f\xa6\x7b\x24\x30\x64\x41\x35\x11\x92\xb0\xf9\x9c\xa5\x86\x48\x41\x5e\x73\x91\xc9\x1b\xed\x3a\xcf\x89\x34\x0b\xa6\x6e\xb8\x66\x2e\xe1\xa6\x21\xb8\xa4\x26\x5d\x20\xad\x6b\x5a\x54\xb8\x8a\xdf\x38\x8f\xfc\x90\x30\x71\xcd\x95\x14\x4b\x26\x0c\xb9\xa6\x8a\xd3\xcb\x82\xf5\x9c\xf0\x7c\x92\xe0\xeb\x3e\xc9\xb9\xa9\xe7\xda\xcc\x68\x29\xb3\x07\xb7\x81\x71\x98\x01\xe9\x64\xec\xba\xe3\x92\x4e\xa9\x64\xd6\x81\xed\xe8\x18\xa6\x4d\xc7\x12\x1f\x4f\x87\xb0\x13\x19\xbb\x76\x9c\x0b\xcd\xd4\x35\x53\xef\xea\x61\xca\xea\xb2\xe0\x69\x77\x4e\x53\x18\xec\x3c\x1c\x91\x39\xec\xe5\xf6\x60\x3d\xc7\x7f\x13\xfb\xe1\xc4\x1b\x25\xd0\xa2\x4f\xbe\xb9\x37\x0b\xa7\xf1\x74\x30\x1d\xed\xeb\x67\x07\x07\xdf\xdc\x1b\x4e\xc7\x5e\x30\xd9\xd7\xcf\xbe\xb9\x77\x16\xc7\xb3\x64\x36\x0d\xe3\x7d\x7d\xb0\x73\x90\x4c\x2e\x29\x17\xf6\x7c\x77\x0e\x66\x89\x91\x3e\x29\x64\x4a\x8b\x85\xd4\xcd\x9e\x94\x4a\x1a\x99\xca\x82\x98\x05\x35\x84\x6b\x38\xc9\x8c\x18\x49\x70\x4d\x24\xe3\x0a\x0e\xc8\x28\x3a\x9f\xf3\x14\x9e\xdf\x21\xfd\x9c\x0c\x2a\xa5\x98\x30\xc5\x8a\xe8\xaa\x2c\xa5\x32\x9a\x74\x16\xc6\x94\xb0\x79\xf0\xab\xe1\x62\x9e\xe6\xbc\x43\x80\x0b\x3b\x95\xe0\xef\x3b\x3d\xa7\x59\x2f\xe9\x13\x68\x55\x4f\x88\x66\x99\x62\x5a\xc3\x50\x97\x8c\x14\x5c\x1b\x26\x58\x46\x2e\x57\x77\x47\xc6\x6d\xf1\x86\x43\x38\xe5\xc3\x1e\xfe\xdf\xac\x4a\x2a\x43\x44\xb5\xbc\x64\xea\x6b\x13\x82\xfd\x25\x7d\xf2\xe8\xf0\x10\xa8\x9c\x32\xc1\x14\x35\x8c\x68\xc3\x4a\xfd\xcc\x79\x4e\x7e\x83\xf4\x0e\x72\x99\x6b\x92\x32\x65\x48\x37\xa5\x7d\xa3\x2a\x46\xba\x59\xa5\x90\x4c\xff\xe9\x67\x4f\x0e\x17\x87\xcb\x43\x4d\xba\xb0\xc1\xfd\xe5\x0a\x7e\x7a\xec\x3d\x5d\x96\x05\xeb\xa5\x72\xe9\x3c\x77\x9e\x93\xa9\x22\x73\x25\x97\x84\x92\x5e\x39\x7f\x4f\xe6\xbc\x60\x84\xbd\x87\x19\xb3\xcc\xbe\x81\xf9\xd5\xf2\x80\x83\xf1\x39\xcc\x14\xa6\x22\x15\x23\x7b\x99\x74\x9e\x13\x21\x0d\x9c\x74\xce\x0c\x2c\xd0\xf6\xc7\x8e\xa5\xe2\xd7\xd0\xf8\x8a\xad\xf6\xed\xb4\x65\xc9\x84\xd6\x05\x29\xaf\x52\x7d\x74\x4c\xba\x5c\x20\x55\x1c\xbd\x2b\x2b\x53\xdf\xb1\x25\xe9\x0a\x79\xc5\x56\xfa\xeb\xf5\xba\x62\xab\xa6\x13\xbc\xd0\x70\x91\x31\xed\x0c\xfc\x30\x4e\x50\x87\xf5\x49\x5a\x69\x23\x97\x07\xc8\x04\x07\xcd\x30\xce\x4b\xff\xed\xce\x06\x35\xc5\xfa\x0c\x97\x5c\xf0\x65\xb5\x24\xb4\x28\xe4\x0d\xcb\x48\x3c\x8a\xc8\x35\x53\xda\x4a\xea\x0e\x96\x8b\x47\xd1\xd1\x21\xb0\x1a\x5c\x1c\x35\x17\xc7\x1d\xd7\x72\x1d\xdc\x3c\xea\xf4\x9c\x78\x14\x25\xe3\x60\x92\xbc\xf2\xc3\x28\x98\x82\x4c\x60\x33\xe7\x39\x39\x81\xa3\x28\x99\x5a\x72\x0d\xa3\x90\x9b\x05\x13\xb5\x1c\x34\x02\x70\xcd\x29\x39\x17\xfc\x7d\x23\x71\x5a\xa6\x57\xcc\xf4\x9c\xf3\x49\xf0\x26\x89\xa6\x83\x97\x7e\x9c\xcc\xfc\x70\x1c\x44\x35\xed\x27\x4f\x9e\x38\xcf\xc9\x08\xa4\x8e\xec\x0d\xc7\x5f\xec\xaf\x15\xc2\x8d\x54\x57\x4c\x69\xb2\xc7\x7a\x79\x8f\x44\xd1\x19\xa9\xca\x8c\x1a\xb6\x4f\x68\x9a\x32\xad\x41\xae\x6f\xd8\x25\x4e\x80\xa7\x0c\x04\x2d\x10\x64\x29\xb5\x21\x29\xd5\x4c\x83\xb6\x26\x99\x44\x4e\x10\xcc\x0a\x6d\xba\xa0\x22\x67\xc8\x07\x19\x9b\xd3\xaa\x30\x56\x5d\x42\x67\xaf\x30\x4c\x81\x46\x95\xa2\x58\x11\x3e\xb7\xda\x1e\xc6\xb5\xea\x8b\xc0\xf1\x81\x06\x00\x82\x40\x41\x83\x36\xa1\x9a\x80\x74\xe0\xcb\x9e\x33\x9a\x0e\xbc\x51\x12\x4e\xa7\xf1\x7d\x5a\x6b\x2d\x93\x77\x15\x97\xf3\x9c\xbc\x5e\x30\x54\xad\x46\x92\x8c\x6b\x50\xd5\xa4\xc2\x85\x0e\x86\x13\xdc\x14\x6d\xa8\xe1\x29\x0a\x85\x26\x8a\xe5\x54\x65\x05\xd3\xba\xe7\x4c\x4f\x4e\x46\xc1\xc4\x6f\xf4\xee\x9c\x16\x9a\xed\x26\x58\xc8\x3c\x07\x92\x5c\x10\x25\x2b\xc3\x54\xcf\x19\x06\x91\xf7\x62\xe4\x27\xe1\xf4\x3c\xf6\xc3\x64\x34\x3d\x25\x7d\x02\xd2\xbb\x4d\x81\x09\x24\xd0\x52\x0d\xa4\x60\xd7\xac\x20\xa7\x5f\x04\x33\xb4\x8b\xa0\x99\xac\xf2\x9e\x20\x41\x7c\xd1\xcc\xa6\xd1\x3d\xd4\x2c\xea\xb5\x48\x05\x13\x69\xd3\xd3\x25\x4b\x41\x9c\x49\x46\x0d\xed\x39\xde\x6c\x96\x0c\xbd\xd8\x4b\x66\x5e\x7c\x06\xe6\x84\x1a\xba\x73\x4e\x46\x92\x42\xd2\x8c\x50\xad\x99\xd1\x64\x8f\xf7\x58\x8f\x74\x52\x29\xe6\xc0\xe7\x86\x2d\xcb\x82\x1a\x86\x8a\xd6\x5a\x86\xce\xbe\xd5\x25\x19\xd7\x57\x84\x0b\x6d\x18\xcd\xc0\xe6\xb1\xe5\x25\xcb\x32\xd0\x83\x5c\xd8\x39\x8c\xa6\xde\x30\xf1\xa2\xc8\x8f\xa3\xe4\x24\x9c\x8e\x93\x61\x10\xbd\xbc\xbd\xa8\x82\x8a\x0c\xd6\x52\xd2\x9c\xad\x39\x98\x0a\x29\x56\x4b\x59\xa1\xd1\x50\xda\x6d\x99\xe7\xda\x6a\x03\x2b\x71\x91\x16\x55\x06\x5b\xad\xab\x4b\xdc\x9c\xc6\xd4\x2c\xa8\xc8\x8a\x8d\x4a\x56\x0c\xc4\x1b\x4d\xd2\xfb\x55\xcf\x19\x79\x08\x8e\x6a\x46\xbb\x8f\x7d\x80\x7f\xad\xbc\xec\x30\x4e\x84\x09\xc3\x15\x2b\x56\x1b\x16\x80\xf6\x1b\xf6\x81\xa5\xb5\x6d\xa7\xb5\x15\xa0\x4d\xc1\x0a\x72\x81\xe4\xd3\x42\x0a\x5c\x74\xcf\x89\xa2\xb3\x64\x6d\x4a\x37\x26\xfa\x5e\xab\xf3\x30\xa5\xda\xe2\x1c\x1f\xb7\x39\x47\xce\xb1\xa9\x92\xd2\xd4\xd6\x57\xaa\x95\xbb\x16\x67\xae\x49\xe7\x37\xce\xa6\x63\xff\xa0\xa7\xf5\xa2\x63\x09\xa1\x40\x5a\x16\x6a\x93\x02\x2b\xae\x17\xdd\x2b\xb6\xca\x99\xd8\x26\xb1\x79\x6e\x6d\x72\xc1\x00\x69\xb1\xa2\x20\x73\x2e\x32\x02\xfa\xfd\x66\xc1\xd3\x05\x81\x09\x83\x62\xa1\x45\x61\xc7\x7a\xe9\xbf\x3d\xf5\x27\x0d\xc3\x6e\xe8\x34\xbb\xd9\x4c\x19\x7b\x29\x06\xa6\x08\xd8\x53\x2a\xaa\x56\xb5\x5c\xa3\x5e\x05\x2c\x45\x68\x8d\x63\xc0\x98\xd4\x9a\xa0\x35\x63\xe7\x79\x7b\xce\x66\x83\x36\x37\x04\xd7\xc3\xad\x27\x97\xc4\x7e\xd4\xda\x8c\x16\xcb\xa4\x0b\x96\x5e\xad\xcd\x4a\x6b\x60\xcd\x7f\xc8\xc8\x0d\x37\x0b\x92\x4a\xa5\x98\x2e\xa5\x65\x76\xb3\x2a\x59\xcf\x19\x07\x93\x60\x7c\x3e\x46\xda\x51\xf0\x85\x9f\x0c\xce\xfc\xc1\xcb\xdd\x3a\x48\xb1\x1b\xc5\x0d\x23\x9d\xdf\xc6\xe3\x39\xa0\x95\x59\x48\xc5\x7f\xc8\xb2\x04\x0c\x6b\xc7\x5a\x7b\x6a\x40\xcf\x29\xe3\x12\x9e\x0b\xa9\x58\x66\x77\xa4\xd2\x8c\x5c\x56\xbc\x30\x35\xb7\x58\xb5\xdc\x73\x42\xff\x75\x18\xc4\x7e\xe2\x9d\xc7\x67\xd3\x30\xf8\xc2\x1f\xc2\x5c\xa2\xc4\x8b\x93\x28\xf6\x90\x85\x76\x4c\x05\x47\x20\x74\x27\x45\xec\x06\xa2\x90\x44\x7e\xf8\x0a\x51\x72\x5b\x22\x04\x33\x60\x9c\x08\x17\x86\xa9\x39\x4d\x2d\xa6\xbc\x4b\x08\xb5\x12\xe2\x2a\x02\x3a\x11\xe8\x8d\x82\x28\xf6\x27\xc9\xd9\x34\x8a\x1f\x04\x65\x7f\x5f\x82\xb5\xa8\x7c\x73\xaf\x91\x9b\xb5\xd0\x41\x7b\x10\x1a\x50\x02\x25\x40\xa8\x94\x97\x0b\xb0\xab\x30\x44\x2a\x85\x60\x29\xba\x1d\x28\x91\xbb\xf6\x62\xbd\x0b\xc9\x20\x98\x9d\xf9\x61\x44\xfa\x84\x32\x7d\x74\xfc\xb4\x9b\x1a\xe5\xe2\xf5\xe7\xc7\xeb\xeb\xe3\xc7\x4f\x36\xcf\x8f\x9f\x76\xf3\x74\xf9\x5d\x8b\x95\x16\x00\xf1\x5c\x42\x55\x3a\x97\x95\x3a\x7e\xfc\x64\x7d\x7d\x74\xfc\x14\xd4\xd7\x90\xcd\xb9\x60\x6b\x40\x43\x8b\x5c\x2a\x6e\x16\x4b\x8d\x22\x68\x16\x8c\xab\x35\x7b\x02\x5f\x16\x4c\xe4\x66\x41\xf6\x80\x31\xba\x47\x6d\xad\x47\x91\x37\xf7\x7b\xce\x05\x0c\x5b\xf7\x01\x16\x4b\x80\x97\xf5\x3b\xc7\x1f\x1e\x3f\x7e\x7c\xf4\x39\x68\x97\xc7\x4f\x1c\x7f\x30\x8c\x3c\x42\xea\xbb\x10\xaf\xf1\xee\xf0\xd3\xa7\xce\x70\x7d\x7b\x74\x78\xfc\xa9\xe3\x5c\x28\x56\x4a\xcd\x41\xa8\x1a\x8f\x06\x95\xd1\x1d\xbb\xb6\xa4\x82\xe6\x2c\x23\xeb\xf6\x9c\xe9\x6d\x2d\xf3\xdb\x08\x98\xbb\xed\x06\x1d\x07\x94\xd5\x5a\x4f\xe9\x54\xf1\xd2\xe0\x6a\x1a\x1e\x68\x00\x9d\x4b\xb4\x5c\x32\xc3\x97\x4c\x93\xb4\x71\x2a\x3b\x56\xe7\x0d\xc2\x60\x16\x27\xf1\xdb\x19\x60\x81\x4b\xaa\x17\x76\x77\x71\x60\x6f\x12\x05\x00\x84\x94\x66\xa6\x36\x53\xa4\x12\x8a\xa5\x32\x17\x20\x89\xcd\xbb\x9e\x03\x2d\x93\xc1\x99\x17\x46\x7e\x7c\x5b\x59\xcc\xa5\x4a\x19\x01\x8b\xb4\x22\x82\xdd\x6c\x16\xb9\xaa\x55\x7b\x8d\xb3\x7b\xce\xc9\x34\x1c\xf8\xc9\x2c\x0c\x5e\x79\xb1\x7f\x4b\x92\xf2\x42\x5e\xd2\x82\x14\x7c\xc9\x91\x49\x6b\xee\x97\xf3\xad\x4d\x23\xd4\xfa\xcf\xe0\x7e\x5a\x95\xe9\xc2\x79\x2f\x19\x15\xe8\x25\x63\xf7\x9e\x33\xf6\xde\x24\x83\xd0\xf7\xe2\x60\x3a\x49\x46\xc1\x38\x00\x89\xe8\x1e\x39\xcf\xc9\x4c\xb1\x39\x53\xa0\x48\x46\x3c\x65\x02\xc0\xa1\x91\xa4\x2c\x40\x74\xa9\x05\x73\x46\x96\x8d\xcb\x0b\x12\x03\x80\x70\x02\x16\x6f\x59\x69\x53\x3b\xd7\xa8\x9b\xd0\x0c\x72\x61\xb1\xc5\x41\x61\xc9\x59\xef\xb7\xc6\xea\x5b\x2f\xc0\x8b\xf3\x4f\xfc\x30\xf4\x87\xc9\x28\x18\xf8\x93\xc8\x07\xf9\xf1\x4a\x9a\x2e\x58\x33\x1b\x72\xdc\x3b\x74\x09\xcc\xb7\x7e\xb0\xdb\x94\x9f\x72\x63\x55\x0e\x45\x89\xb5\x1a\x79\x6b\x9f\x00\x7d\x03\xa4\x3c\x80\x7f\xa2\xb5\xef\xba\xb1\xee\x88\x37\x4f\x83\x7b\x54\x62\x83\xef\x2e\x79\xc1\x0d\x9e\xe3\x92\xe7\xe8\xe4\xb5\x4e\xf7\x72\xd5\x30\x22\xba\xca\xc8\xf6\x6b\xbc\x67\xf1\x2f\x18\x97\x64\x1c\x9c\x86\x78\x14\x0f\x8e\xa5\x98\xc8\x98\xb2\x11\x07\xe0\x45\x45\x6f\x70\x9f\x7b\xc0\x1e\x8a\x11\xaa\x40\x2f\x1a\xc0\x29\xb4\x20\x9a\xa5\x95\x82\xa9\x29\xae\xaf\xf4\x7a\xd4\xd0\x7b\x8d\xfe\x52\x12\xfa\x93\xa1\x1f\xde\xc6\xc0\xe8\x2c\xd1\xf7\xa8\x36\x36\x0c\x96\x4b\x40\xbf\x5c\x00\x2f\x00\xde\xaa\x63\x1b\xaa\x12\x0d\x4b\x20\xbe\x07\xf9\xb2\x52\x42\xc0\xfc\x16\x40\x70\xce\x80\x1d\x14\xfb\x41\xc5\xb4\xe9\x91\x73\x5d\xd1\xa2\x58\xb5\xe1\x5d\xc6\x4a\x26\x10\x4f\x2e\xe4\x0d\x28\x82\x15\x19\xcc\xce\xc9\x5e\x2a\x15\xd3\xfb\xe8\x99\x2c\xe8\x35\xeb\x91\x60\xee\x3c\x6f\xf5\x43\xef\x42\x74\x71\xb3\xf9\xb5\x0d\xf0\x20\xf3\x59\xf3\xbe\x99\xfd\x60\x76\xae\x09\xbd\xa6\xbc\x68\xe0\xef\x1d\xa7\x7d\x30\x1d\x8f\x03\xc0\xac\x7e\x3c\x38\x4b\x06\xd3\xc9\xe0\x3c\x0c\xfd\xc9\xe0\x2d\x18\x9e\x2d\x35\xd6\x63\x19\xfc\x82\x36\x1b\xd5\xd6\xa2\xf6\xba\x0d\x13\xda\x1a\x07\xd8\xa2\x1a\xb4\xc2\xcc\x49\x01\x9a\xfa\x46\xd1\x52\x83\x34\xc0\xe0\x03\x99\xb1\x31\x57\x4a\x2a\x62\xe9\x81\x0c\x45\xac\xa4\xc8\x41\x2d\x5a\xc8\xb7\x14\xfc\x85\x25\xc0\x6b\xf0\x5a\x5e\x87\xde\x2c\xf1\xdf\xc4\xfe\x04\xdc\x42\x90\x90\x9e\x79\x6f\xdc\xde\x32\x73\x7b\x4b\xaa\xae\x32\x79\x23\xe0\xce\xfe\x5c\x65\xce\x73\xf2\x8a\x16\x3c\xb3\xf3\x04\xee\xa9\xa7\x88\x73\xa3\xa4\x54\xec\x9a\xb3\x1b\xe2\xcd\x02\x70\x09\x64\xca\x29\x98\x3e\x1c\xd9\x2c\xd8\xd2\x25\xba\x4a\x17\xe0\xbc\x75\x0e\x68\xc9\x0f\xae\x8f\x0e\x9a\x61\x3a\x5b\xd3\xc6\x63\xd1\xc0\xf4\x38\x5d\xdd\x03\x5d\x82\xa4\x0d\xbd\x84\x95\xc3\x52\x2d\xfb\xde\x48\xf1\x2d\xdc\xa3\x1b\x70\x1e\x61\x47\xb6\x37\x91\x64\x92\x69\x68\x82\x07\x8a\x8a\xe1\x55\xe0\xbf\x46\x0e\x46\xee\x05\xb6\x85\xa5\x37\x33\xd9\x3e\xa3\xaa\x04\x07\xe7\xdd\x3d\x52\xb4\x16\x4f\x1c\xd3\xb6\x5d\x0b\xc8\x70\xe3\xcd\xb5\xb1\x6f\x83\x12\x79\xb1\xaa\x43\x27\x75\x3f\xe0\x53\x01\x32\x47\x2a\x94\x4e\xb3\xe0\xda\xf6\xca\xc1\xb9\xba\xe1\x25\xb3\x10\x18\x3c\x08\xb4\x00\x08\xa6\xf6\x7b\x4e\xec\x8f\x67\x6d\x5f\xed\xc0\x2c\xcb\x83\x9a\x6a\x13\x40\x00\x5b\x56\x9f\x16\x48\x77\x63\xed\xad\xd5\xb0\x6d\x59\xe6\x12\xf4\xfa\x3b\x7c\x49\x73\x76\xf0\xfd\x92\xe5\xff\xd4\x5e\x96\x22\xef\xf4\xc8\x88\xc1\x39\xb3\x65\x69\xd5\x14\xd2\x20\x20\x65\xf3\x66\x84\x9e\xe3\x8d\x46\xd3\xd7\xfe\x10\xad\x60\xb4\x36\xa8\x8d\x22\x40\x4c\x0b\xfe\x1e\x6d\x34\x3b\x17\x64\xfc\xa2\xe7\xd8\xa3\xf0\xde\x20\x96\x25\x7d\xf2\xe8\x5e\x0d\x62\xc1\x7a\xc9\x54\x3d\x6b\x6b\x81\xa0\x3f\x9c\xe2\x63\xc7\xb9\x80\x2d\xb8\xa4\x9a\x35\x38\xa1\xb9\x27\x97\x34\xbd\x62\x02\x56\x59\x87\x52\x4b\xa9\x4d\xae\xac\x83\xba\x5c\xe9\x1f\x14\x1d\xd2\xd1\x3f\x28\xb8\x61\x8f\xac\x71\x59\x6a\x78\x08\xbc\xf9\x56\x56\xd6\x12\x5a\xec\x06\xeb\x8f\xf9\xf0\x85\x65\xee\xf1\x2a\xfa\xde\xa8\xa5\xf8\x6b\x08\xd0\x90\x77\x6a\xe0\x79\x74\xfc\x19\x42\xcf\xa3\x67\x8f\x3f\x7d\x74\xec\xd4\x61\x6b\x00\x23\x4e\x13\x15\x86\xeb\x99\x17\x45\xaf\xa7\xe1\x10\x77\xef\x44\xb6\xe7\x89\x51\x92\xcd\xfc\x6b\x1b\x05\xd3\x07\xbd\xc8\x55\x6d\x13\xaf\x99\xe2\xf3\x55\x77\x5e\x15\x05\xfa\x62\xa3\x75\x60\xd8\x76\x68\xe8\x6e\xd6\x8a\x64\x97\xf4\x8a\x11\x5d\x29\xd4\x6c\x00\xef\xe8\xa5\x96\x45\x65\x58\x6d\x6e\xda\x2c\x06\x33\xed\x65\x97\xb7\x8e\x09\x20\xe7\x16\xbc\xad\x8d\x7b\x29\x61\x5b\xe0\xa0\xa6\x33\x7f\x02\x6a\x11\xd5\xcd\xa3\xc3\x5b\xfd\x79\x56\xb0\x87\xfb\x07\xc3\x91\xdf\xee\xef\x5c\x34\xe6\xe9\x96\x90\xa2\x4a\x80\xbe\x5c\x68\x43\x8b\x02\x83\x04\x2e\x01\xf8\x85\x92\x65\x24\xe9\x80\x78\x76\x50\x06\x56\x25\xd5\x9a\x00\x9e\x09\x26\x51\xec\x8d\x46\x60\x54\x5f\xde\x32\x67\x9a\xa5\xaa\x8e\x6c\x8a\x54\xad\x4a\x43\x52\x29\xaf\x78\xa3\xaf\x5c\x72\x7c\xe2\x91\x54\x66\xcc\x25\xcc\xa4\xc0\x35\x9f\x7c\x62\xb3\x2b\x36\x09\x13\x4f\xc9\x4b\xdf\x9f\x91\xb7\xd3\xf3\x90\xe0\x89\x0f\xbd\xd8\x23\x91\x77\xe2\x7f\xf2\x89\x13\xf9\x83\xd0\x8f\xc1\x89\x22\x7d\xf2\xc9\x37\xbe\x7b\x32\xf4\x5f\x83\x93\xf5\x4f\xbe\xbd\xb7\x66\xe4\x95\x26\x8a\x2d\x19\xc8\x02\xcb\xac\x81\xac\x8c\xec\x16\x32\xe7\xa2\xe7\x8c\xa6\xa7\xc1\x24\x09\xfd\xb1\x3f\x7e\xe1\x87\xc9\xd0\x7b\x0b\x9b\xf4\x59\xdd\xbb\x9e\x6b\x13\x51\xd0\x46\x02\xda\x5f\x77\x27\x5c\xcc\xa5\x5a\xae\xcd\xd8\xf4\x65\xe0\x6f\x68\xb5\x78\x35\xe1\x22\x55\x2c\xe3\x96\x8f\x76\x53\x86\xd9\x15\x32\xcf\x6d\x90\x01\x60\xa4\xcd\xd7\xd4\x64\x61\xed\x6d\x8a\xf4\x86\x01\xaa\xbe\x75\x80\xe0\xfc\xc3\xd9\x36\x03\xac\xbb\x47\xfe\xe0\x3c\xbc\x27\xde\x06\xbd\xea\xf9\x18\x49\xb8\xc8\x6c\x90\x1a\x91\xac\x5d\xa7\x36\xd4\x54\xba\x05\x9e\x60\xd3\xa2\xd8\x8b\xcf\xa3\xc4\x0e\x70\xeb\xd8\x77\x2d\x6f\x17\xc1\x1d\x94\x9a\x7d\xc3\x86\x89\x6d\xe8\x38\x17\x6c\x49\x79\xb1\xdb\xa8\x00\xc7\xe2\xeb\x4d\x84\x75\x63\x4e\xda\xb3\x2a\x15\x9b\xf3\xf7\xf0\x03\xa0\xc7\xaa\x72\xc4\x4f\xd5\xe5\xf7\x41\x41\x01\x54\xe8\x39\xd1\xf9\x8b\xdf\xf2\x07\x71\x02\x78\x38\x78\x43\xfa\xe4\xcb\x8b\x6f\xee\x6d\xb2\x66\xfb\xfa\x1d\xf9\xb2\x26\x18\x8d\xe3\x59\x03\x32\x51\xab\x71\xa3\xd1\x3b\xae\xad\x82\x5e\x9a\xb2\x07\x33\xcb\x2b\xd1\x93\x2a\x7f\xf6\xf8\xe9\x67\xae\x7d\x9a\xc3\x63\xf0\x33\x5b\xcf\x7e\xf0\x03\x7c\xf0\xe9\x93\xc7\xce\x73\x12\x34\x62\xac\x0c\x61\x22\xd3\xe8\x87\x7d\xfa\xe4\x71\xc7\xc5\x61\x23\x72\xc3\x8b\x02\x2d\x91\x66\x19\x60\x3b\xf0\xe4\x30\x1e\x10\x8f\x22\x30\x78\xd8\xf3\xf1\xd3\xcf\xa0\x23\x38\x4d\xcb\xa5\x5d\x34\xd8\x81\xf0\x64\x40\x9e\x7c\x7a\xf8\x79\x6f\x33\xd0\x2d\xa7\x6d\x43\x8a\x1b\x3b\x14\x2d\x6e\x40\x98\x9a\x11\x1b\x0d\xbd\x6b\x8d\xf5\xf6\xd8\x43\xb1\x39\x92\x3a\x19\xb4\x07\x23\x3f\x7e\x74\x7c\xbc\x0f\xc0\x99\xeb\x06\xcd\x7e\x1f\xbc\x17\x2a\xea\x2e\x75\x6b\x97\xd4\x19\xb0\x2f\x3b\xe0\xe2\x74\xc8\x77\xf0\xf5\x77\x5b\x89\x98\xdf\xfc\x92\x58\x11\xec\x39\x27\xe1\x74\x4c\xfa\x44\x48\xc5\xca\x62\xf5\x5d\xd4\xb6\xb7\x93\x64\x96\xfb\x80\x11\x7b\x8d\xfd\xf8\x1a\xed\x41\xd1\xdd\x48\x95\xf5\xda\x76\x66\xb7\xeb\x73\xe6\x8f\xa6\xa0\xd2\x6d\x26\xa9\x0e\x90\x2d\x18\x01\x9a\xd6\x23\xd3\x24\xe3\xf3\x39\x53\x4c\x98\x96\xbb\x03\xdd\x1a\xcb\x6f\xdd\xb3\x4d\x17\xd0\x59\xdb\x74\xb7\x9c\x73\xdc\x5f\x1b\x4f\xeb\x39\xd0\x0e\x83\x36\x56\x8a\x6e\xcd\x52\x5f\xf1\x92\x58\x4b\xd7\x24\x74\xdb\x69\x29\xd9\xe6\x84\x1e\x99\x8a\x62\x85\x36\x0d\x95\x3f\x06\x0c\x58\x31\xef\x6a\x9e\x0b\x70\xbe\x37\x1d\x75\xcf\x89\x5e\x06\xb3\xe4\x95\x1f\x06\x27\x6f\x77\x2b\x19\xa0\x93\x16\x1c\xb0\xda\x76\xcf\xf3\xc8\x4f\x06\x7e\x18\x07\x27\xc1\xa0\xed\x77\xef\xc8\x3e\xe1\xe9\x3f\x94\x7d\xb2\x0d\x9a\xec\xd3\xdd\x09\x74\x0c\x7b\x6f\x0e\xca\x82\x72\xd1\x01\x4c\xdd\xa0\xc7\x86\x85\x60\x2e\xb3\x91\x17\x4c\x92\xd8\x7f\x73\x8f\xef\x49\x8d\x01\x24\x46\x09\x92\x01\x82\x84\x16\x06\xb4\x35\x38\x42\x8d\x4a\x19\x07\x63\x9f\x2c\x99\xd6\x34\x67\xe4\x66\x01\xb0\x4d\x33\x1b\x8c\x3c\x8b\xc7\x23\xcb\xe7\x1a\xc5\x6f\x3b\x59\x6b\xc5\x8f\xc8\x02\xbd\x4d\x10\x06\xbb\x6b\x36\xb4\x64\xe1\x46\x49\x97\x80\xe9\x0c\x53\x9a\x2c\x68\x59\x72\x60\x67\x6f\x38\x6c\xcd\x3d\xf1\x46\x9b\xf9\x3b\x17\xb4\x32\x8b\x06\xdb\x5d\xa3\x3f\xd2\x24\x3b\x6d\xc4\xcd\xd8\x54\x63\x8a\x89\x23\x41\x96\x5c\x54\x78\x38\xde\x20\xc6\x68\x48\x32\x98\x0e\xfd\x64\x14\xbc\x42\xc4\x78\xf4\xf4\xf0\x5e\x5a\x8a\x81\x39\x69\x24\xe6\x2e\xc5\xd0\x8f\xfc\x38\x69\xe4\x68\x17\xdd\xad\x28\x2c\x22\xb4\x5a\x2b\xa4\x52\xcc\x79\x6d\x6e\xad\x21\xcf\x70\x43\x05\xbb\xd9\xd6\x1b\x0c\x37\xd6\x6f\xac\x03\xd7\x44\x96\x75\x20\x02\xf5\x98\xde\x50\x46\x9b\x64\x64\x43\xbb\x65\x4b\xd0\xc9\x67\x39\xd7\x46\xd5\x06\x3e\xf4\xbf\x77\x1e\x84\x7e\xe2\x8f\xbd\x60\x94\x60\x8d\x47\x38\x7e\x20\x72\x00\x3a\xa1\xc6\xfb\x5b\xe9\x15\x72\xcd\xc1\x6b\xae\x05\x50\x73\xc3\x36\xb4\xa3\xe0\x74\x12\x4c\x12\xf0\xb7\x1e\x4e\x8e\xa1\x28\x6e\xcd\x0f\x5a\x89\xe6\x7d\xe6\x12\x9a\xa6\xb2\x02\xc6\xb9\xd9\x38\xc3\xd6\x77\xb1\xa1\x29\x4c\xd7\xd0\x6c\xc9\x85\x6e\x25\xd6\xfc\xd3\x20\x8a\xbf\x46\x3c\x24\xa5\xa5\x49\x17\xd4\x72\xc0\xe6\x48\xda\x33\x5a\x47\x3d\x5a\x34\x93\x81\x37\x8b\x07\x67\x5e\xe3\xe8\xdd\xe3\x25\xb6\xf2\x47\x80\xb7\x16\x4c\x98\x26\x13\xd4\x84\x8e\xc8\x82\xd1\x0c\x18\x7f\x3d\xca\x2b\x3f\x04\xf9\x0d\xa7\x6f\xde\x62\x88\xdd\x9f\xc4\xa0\x52\xee\x5d\x09\x00\x39\xe0\xa6\x94\x16\xc5\xaa\x49\x71\x00\x33\xd9\x53\xb2\xcb\xb9\x7f\x26\xf7\x8f\x3c\xbd\x6f\x1b\x41\x64\x5a\x73\xb7\x52\x4f\xf5\x1a\xed\x7d\x8d\x31\x1f\x5a\x66\x72\xe6\x7b\x43\x34\x6a\x6f\xba\xaf\xfd\x17\xf0\xb2\x0b\x56\xce\x71\x2e\x60\x84\xdd\xe8\xc9\x72\xbb\x90\xb5\x4a\x46\x17\x02\xa6\x81\x9b\xb0\x5e\xa3\xe5\xf9\xc9\xb4\x56\xd3\xed\x65\x81\x3b\x81\xc9\xd4\x77\x6b\xcc\x6f\xb3\xee\xa5\x92\xd7\x3c\x63\x6a\xe3\x7c\x2d\xd9\x52\xaa\x15\x16\x91\x70\xf4\xc1\xc0\xa3\x02\x60\xac\x6d\x15\x09\x56\x42\x91\x3e\xb1\xed\xd6\x58\x52\xcc\x79\xde\xa8\x18\xbb\x43\xba\x04\x6f\xe7\x9a\xad\xc7\x78\xe6\x3c\x27\xdd\xba\xdf\x33\x0c\x60\x6c\xd2\xe9\xe0\x6e\x5b\x22\x64\xc5\x0c\x36\x84\xe1\x9f\xad\x27\x8a\x5e\x35\xf8\x6b\x35\x6c\xfb\x12\xdd\xb5\xfa\xad\xfe\x12\x7b\xe0\x2c\x9f\x35\x19\x95\xbe\x49\x4b\x17\xb4\x4d\xff\xd9\x93\x47\x9f\x7d\xee\x36\xfa\xae\xbf\xa4\x29\x55\x52\xb8\xd9\x65\xff\xd0\x05\x17\x0c\xe3\xf8\xfd\xa3\xc3\x43\x17\x1c\xb5\xc4\xf0\x25\x93\x95\xe9\x83\xaa\x6b\x16\x9c\xd4\xe5\x62\xb5\x9b\xd8\x8c\xfb\x10\x94\x36\xad\x6d\xe6\x19\xf0\xc7\x1c\x8d\xc0\x36\x84\xe6\x49\xc1\xaf\x58\x92\xdb\x22\xaf\xdd\x88\x9f\x0b\x62\x63\xb0\xe0\xcf\xde\xef\x2e\xc0\x4c\x4e\x07\x36\xaa\x7b\x4d\x0b\xe8\xa6\x59\x2a\x01\x97\x5a\x60\x60\xe7\x62\x13\xd1\xa7\x83\x24\x98\xc4\x7e\xf8\xca\x1b\x81\xc7\xf9\xe4\xf0\xb6\xcf\x5a\xf0\x79\x1d\xb0\xbc\x45\x87\x36\x94\xac\xe7\x3a\x0a\x4e\xfc\x24\x0e\x70\x31\x4f\x9f\x7c\xba\xa6\xd3\xde\x13\xe8\x36\x88\xc2\x13\x62\xe4\x15\x03\x37\x2c\x0a\x4f\x6e\xb9\x12\x49\xaa\xd5\xdc\x71\x2e\x52\x9a\x2e\xd6\x21\x0e\xbc\x21\x34\xa3\xa5\xd9\xcd\xa2\x96\x2f\x2d\x8f\x2e\xd9\x12\xdb\x77\xc0\xce\x7a\xb3\x78\x9b\x4b\x4f\xe4\xa6\x63\x1d\x17\xd8\xbd\x57\xe0\x2a\xaf\xf7\xe5\xc9\x61\xd3\xd5\x8e\x64\x8b\x5b\xd6\x23\xb9\x2d\xa7\x1e\xb1\x60\x63\xdd\x9e\xfd\xff\xe2\xc7\x5a\x82\x70\xf8\x67\xe4\xcb\x4d\xe8\xe5\xe8\xe8\xf8\xe8\xe8\xcb\x1a\xf0\x3b\xce\xc5\xc2\x98\xb2\x85\x26\x2a\x7b\x08\x1d\x0f\xb3\xf7\xdd\x81\x14\x46\xc9\xa2\xeb\x81\xed\xeb\x4e\x15\xcf\x01\x6d\x59\x8d\xb7\x05\x5c\xb1\x3c\x45\x82\x3b\xa6\x11\x0c\x7b\x83\x81\x1f\x81\x1b\x38\x89\xc3\xe9\x28\xc1\xb0\x58\x32\x0d\x83\xd3\x60\x82\xc3\x16\x73\x7d\x37\x8f\xb5\x16\x89\xd1\x49\x44\x24\xfa\x71\xba\xe7\x4c\xd1\x85\x8b\xb6\x22\x7c\xc5\x5c\x77\xeb\x06\x80\x88\x10\xc6\x2d\x99\x30\x3b\xd5\x62\x56\x87\xca\xc8\xa6\x1d\xc6\x8f\x73\xac\x26\x2b\x7e\x45\xc0\xd2\xce\xa8\xdd\x55\x8a\x4d\xa0\xb5\xc1\xea\xed\xc9\xb5\xda\xfe\x23\x87\x1f\xc9\x2e\x52\x5f\x37\x26\xd9\x0a\x47\x7e\xfa\x0f\x08\x47\x2a\x56\x30\xaa\x59\xef\xd7\x39\x24\x6b\x20\xb0\xff\xae\xb8\xf2\x3f\xea\xd6\x7e\xfb\xe0\xdb\xbf\xc6\x4e\x3e\x3a\xfe\x35\xb7\xf2\xe8\xd0\x71\x2e\x40\xc2\x61\xf7\x22\x5b\xb0\xc4\x6c\x82\xc6\x7a\x3c\xb8\x59\xf3\x0a\xe0\x8f\xac\x4c\x59\x01\x28\xcc\xac\x5b\x86\x79\x8b\x8a\xe9\x56\x1d\xb0\x14\x6b\x17\x71\x2e\x61\xb9\x5c\xe4\xa0\x8c\xbc\x49\x14\x0c\x5c\xac\xa6\x1b\x62\xca\x33\xac\x2e\x57\xf5\xd5\xc9\xe0\xe9\xf1\x71\xf3\xfb\x85\xbd\x78\x7c\x88\xbf\x47\x47\xc7\x8f\xd6\x17\xf6\xd5\xa3\x47\x8f\x3e\x5f\x5f\x4c\xa8\x90\x2e\x79\xc9\x4d\xba\x60\xc2\x25\x91\xa1\xcb\xb2\xfe\x19\xf3\xa2\xe0\xeb\xeb\x54\x49\xd4\x9d\x78\x0b\xbd\x7a\xb5\x62\x5d\x82\x14\xb6\x62\x74\x84\x5e\xca\xca\xb4\xd7\xaf\x19\xc3\x92\xd5\x67\x07\x07\xb9\x2c\xa8\xc8\x7b\x52\xe5\x07\xe5\x55\x7e\x00\xdb\x76\xf0\x8d\xf2\x2a\xef\xa6\x52\x68\x43\x05\xa8\x95\x93\x29\x00\x7e\xd2\x6f\x66\xed\x38\x17\x25\x4f\x4d\xa5\xd6\x56\x65\x5b\x03\xa0\x77\x41\xaf\xa9\xa1\x6a\xb7\x0a\xf0\x5e\x79\xb1\x17\x26\xe7\x33\xac\xdd\xda\x52\x08\xb6\xd7\x4e\xb2\xad\x2c\xca\x43\xc4\x43\x7f\x36\x8d\x82\x78\x1a\xbe\x4d\xee\x1f\x07\x68\x75\x37\x83\x0d\x16\x5c\x30\xcd\x6a\x08\x9c\x52\x5b\xcc\x42\x9b\x98\x84\x6d\x48\xb4\xac\x54\xca\x36\xb9\xa9\x7a\x0b\x53\xd1\xcb\x95\x6d\xd2\x4b\xe5\xb2\x5e\xc3\x41\xcf\x39\x0d\xeb\x09\x44\xd3\xf3\x70\x80\x31\xcc\xba\xdd\x3d\x09\xe4\xfa\xad\x6b\xbd\x37\x6b\x63\x9a\x78\x17\x26\xf4\x1b\x61\xc5\xca\x5d\x0e\x9e\xe7\x1c\x13\x7d\x4b\xac\x6e\x6c\xbc\x99\x66\xdc\x07\x3d\x99\x39\xcb\xb0\x40\x38\x6b\x56\x57\x48\x79\x55\x95\xb0\x70\x4d\x86\x93\xa8\x9e\x58\x2a\xaf\xd7\x87\xd9\x4a\xd5\x39\xcf\x6d\xe4\xcf\x3a\xf4\xee\x9a\xa3\xf4\xb3\x83\x83\x9b\x9b\x9b\x5e\xc1\x2f\x9b\x2d\x91\x2a\x47\x81\xcb\x98\x69\x9c\xff\xf8\x57\x2c\x0f\x67\x7d\x7b\x7d\x80\x48\x30\xb0\xd4\x6c\x93\x0d\x2a\xe9\x4b\x5a\xb0\x6c\x8d\xd8\x4f\xfc\xa1\x1f\x7a\xb1\x3f\x4c\x6e\xed\x81\x73\xd1\xe4\xed\x76\x3b\x04\x0b\xaa\x32\x9b\x35\xbd\x54\x8c\x5e\x6d\xf2\x82\x6b\xd2\x67\x5e\x38\x4c\x30\x1d\xfa\x22\xf4\xbd\xdb\x21\xff\xa6\x8e\xa7\x66\x99\xf3\x70\x44\x74\xba\x60\xcb\x5d\x1a\x97\x6a\x18\xe9\xaa\xae\x24\xb3\x39\x76\x70\x8c\xc7\xf5\x0c\x1b\x49\xae\x23\x7e\x2e\xe9\xe4\xdc\x74\xc8\x1e\xe2\x8d\x9c\x9b\x67\x07\x07\x9d\xfd\x1a\x38\xd1\x5c\xb0\xf5\x3b\x7b\x87\xaf\x7b\x8e\xfd\x2a\x23\x39\x0f\x47\x49\x34\x38\xf3\xc7\xad\x2c\x5b\xf1\x35\xd2\xc8\x97\x4d\xf6\x9f\x65\x07\x2c\xe3\xc6\xce\xbb\x3d\xc5\x5f\x99\x3c\x26\xb1\x6c\x2a\x08\xea\xca\x39\x78\x2b\x64\x2b\xe9\x4a\xf5\x3a\x9f\xea\xda\x70\x68\x59\x99\x4d\xf6\x19\xb3\x7d\xdb\x89\xe7\x7b\x73\xce\xce\x85\x5e\x52\x65\x56\x25\x68\xad\xfb\x63\xe6\xd1\xa6\xd1\xdd\x43\xde\xc4\xce\x4f\x42\x6f\x10\xd7\x63\xa2\x11\x1d\x7a\xd1\x99\xbf\xbe\x1b\x79\xb1\xff\x26\xd9\x7e\xe6\x4d\x4e\x47\xfe\x30\xf9\xde\xf9\x34\xde\x3c\x74\x2e\x30\xd8\xf0\x6e\xb7\xc8\x2b\x96\x57\x05\x55\x64\x4f\x48\xd1\xc5\x86\xfb\xb5\x12\xda\x94\x1f\x4a\x95\x53\xc1\x7f\x58\x7f\x7d\xd2\x8e\x59\x9c\x8f\xbc\x30\x99\x86\xa7\xeb\xb2\x9a\x16\xb7\xdf\xb0\xcb\x85\x94\x57\xef\x6e\x9d\x78\x03\x21\x2c\x16\x58\x7b\xbc\x75\xa8\x70\xfd\x09\x49\x07\xbc\x27\x70\x07\x74\x41\xd3\x2b\xb8\x40\x5d\xa0\x32\x7b\x29\x72\x43\x8b\xab\x8e\xcd\x5f\x46\x75\x72\xc6\x25\xd8\xd8\x25\x75\x53\xb8\xb0\x0d\xb1\xba\xa9\xe0\x58\x21\x67\x91\xf7\x96\x77\x30\xf4\x47\xc1\x2b\x3f\x44\x97\x67\x7a\x8e\xf9\xcf\xc7\xb7\x62\x16\x08\x33\xb8\x68\xb2\x3c\xeb\x50\x2a\x1e\x1d\x46\x61\xe3\x51\x74\x37\x12\x1b\x6f\x15\x65\x2c\xb8\x46\xeb\xd1\xb6\x8d\x5c\x58\x10\x52\xd2\x9c\x01\x36\x3d\x0d\x26\xa7\xc9\xe4\x7c\x5c\xe3\x88\xe6\x43\x8a\x02\x9c\x47\xc3\x45\x8e\x89\x46\x4c\x58\x29\xdd\x73\x2e\x0a\x99\xef\x2e\x32\xa3\x45\x01\xcd\x2c\xdf\x6f\x57\x95\x15\x32\x3f\xe8\x10\x5d\x5d\xb6\x8a\x3f\xb7\x2b\x60\x07\xf5\x21\x80\x0d\x96\x36\x6b\x5b\x47\x0e\xea\xf3\xb0\xb2\xdf\x1c\x09\xc8\xe2\xb9\x66\x56\x66\xac\xa3\x5b\x0b\xe6\xb2\x2a\x0c\x2f\x9b\x12\x8c\x06\xda\xd5\x64\x5d\x9c\x5c\xc7\xa9\x33\xbe\xf5\x53\xe7\x39\x79\x51\xcd\xe7\x4c\x35\xe5\x7b\xa0\xd3\x16\x54\x08\x56\xb8\xe4\x8a\xb1\x92\x70\x03\x52\xcb\x71\x31\xb6\x0c\x9f\x64\x58\x5b\x71\x25\xe4\x0d\xb9\xc1\xe2\x68\x78\xd9\x73\x5e\x9c\x9f\x9c\xf8\x61\x32\xf2\x27\xb8\x9d\xe0\x6b\xf9\xb5\xc3\x19\x2b\x9a\xe2\x82\x02\x31\x97\xf0\xfb\x9a\x2a\x01\xbf\xbe\x52\x52\xc1\xc5\x09\x35\xb4\xe8\x6c\x6f\x9d\xed\xe5\x8c\xfc\x57\x3e\xf8\x92\x78\xeb\x34\xfe\x64\xb3\x5b\xb5\xb5\x10\xc5\x0a\xcf\xa7\x57\x3f\x87\x73\x1a\x60\x3a\xc8\x60\x71\x04\x26\xfd\x16\x4c\xe1\xe7\x55\x35\xc5\x35\x2d\xdc\x99\xdb\x84\xe0\xe1\xd7\xa2\xb2\xb3\x6a\xcb\x86\xdd\x6c\xba\x93\x28\x69\xe0\x7c\xf6\xf4\x0d\x00\x3d\x54\xc5\x0d\xb6\xac\xa3\xb6\x7a\x1f\xf3\x84\x49\x38\x8d\x6d\x7e\xe0\x6e\xbd\xbf\x66\x39\xce\x63\xcd\x67\x24\xa3\x1c\x8b\xc5\xbd\x60\xf4\xf6\x4e\xcf\x3b\x00\x5c\x2f\xf8\x1c\x95\x82\xad\x9c\x42\x1a\x5b\xfb\x7d\xfc\xb4\x2e\xe2\x3b\x22\xdf\xf9\x0e\xdc\x61\x01\x66\x1b\xa7\x27\xd1\x59\x70\x82\x45\xe0\x4f\xef\x45\xeb\x05\x16\x71\x6d\x0f\xd3\x04\x3a\x26\x35\x62\xc7\xff\x9a\xfc\xd9\xfb\x92\x2b\x84\xe4\xab\x46\xda\xac\xa1\xda\xcb\x58\xc1\x0c\x23\x74\x6e\x30\x4b\xf0\x1e\x9b\xec\x5b\x5a\xeb\x1c\xf6\xba\x64\xc1\x4a\xca\xad\x33\xc4\xa7\x5f\xf7\x10\xad\x0a\x05\x5b\xee\x60\x15\xbf\x63\x69\xd4\x72\xf7\x6b\x53\xb1\xcb\x5c\x47\x3f\x2d\xe6\xc9\xb8\x2e\x0b\xba\xb2\x79\xf0\x76\x5c\xd2\xa6\xec\xea\x98\xce\x76\x4a\xb6\x9e\xcf\x7b\xa9\x96\xef\x36\xa1\x7f\xdc\x2b\x64\x30\x2e\x85\x73\x9b\x0b\x42\xcb\x79\xb6\x2e\x28\xa3\xab\xba\x41\x82\x3c\x73\xa7\x99\x14\x69\x03\xaf\x81\x63\xd8\xfb\x14\x13\x0d\xe4\x3d\x19\xbf\x68\x3b\x6b\x56\xb8\xc7\xf5\xd9\xe3\xc9\x19\x69\xd5\x85\x55\x96\x96\x41\xdb\x27\xf5\xa8\x9e\x7d\x5e\xcf\x7e\x07\x44\x6d\x2f\xa4\x77\x67\x25\xed\x8c\x89\x9d\xad\x85\x33\xcd\xca\x7a\xf7\x2c\xad\xcd\xa5\x9b\xa5\xa1\x03\x4a\x2e\xd9\x1c\x5c\x0d\xc1\xde\x9b\x9a\x68\xef\xee\x32\xdb\x04\xb6\x96\x8a\x6b\xec\xdd\x5e\x64\xaa\x6c\x90\xb8\x3e\x9e\xe6\x2b\x4e\x78\x4c\x0c\xd5\x57\xe8\xc9\x72\x99\xd9\x88\xfc\x0e\xe7\x3d\xac\x44\xbb\xb5\x05\xc1\x32\xd7\xb6\xac\x4b\xdb\x0f\x3a\xef\x54\xd3\xdb\x81\x7b\xf6\xa3\xac\x64\x89\x95\x7f\x08\x8b\x6c\x19\xb7\xc6\xd2\x47\x39\x37\x75\xaa\xd6\x36\x20\x7a\x25\x52\xa6\xec\xb7\x06\xa8\xde\xc1\xb7\xaf\xdf\x09\xc6\xb2\xe6\xc3\x46\x68\xb7\x50\xd2\x56\x24\xef\x5d\x52\xcd\xb2\xc6\x1b\xab\x5b\xdb\x81\xd7\xf1\xc0\xfd\x9e\x03\x28\x74\x78\x8e\x99\xcb\xef\xda\x53\x3a\x3a\xc4\x7c\x65\xb8\xf1\xec\x16\x8c\x16\x66\x61\xc7\xaf\x57\x00\xbe\x5a\x62\x9f\x27\xf8\xfc\xdd\x0e\x4a\xc7\x9f\x2e\x9c\x0d\x7e\x78\x72\x08\x5e\x9d\xa7\xf2\x6a\x13\x1d\x41\xeb\x28\x32\xf2\xad\x9c\x1b\x32\xd7\xe9\xd5\xb7\x1a\x7b\xd8\xed\x56\x42\x01\x0a\xc0\xf3\xe9\x76\x0d\xcd\x75\xc7\x79\x8e\x4e\x0d\x3a\xd3\x52\xac\xdd\x65\x6e\xba\x3a\x5d\xa2\x9f\x97\xc9\x54\xe3\x03\x20\x76\x70\xd4\xfb\xac\xf7\xd8\xf1\xc2\xd3\xc8\x9a\x91\x01\x7e\xad\xd1\xf2\x59\xf1\xd3\x30\x6d\x78\xaa\xeb\x75\xe1\x5a\x12\x5c\x1d\xbc\xd3\xef\x6e\x9f\x23\x1e\xff\xee\xa5\xc2\x00\x05\xa3\xa2\x2a\xb7\xdc\x62\x95\x2e\xf8\x35\xd3\xed\x8d\xab\x9f\x25\xa9\x6d\x7e\x67\x10\xcb\x2c\xbb\x47\x79\x4e\x62\xbe\x64\x9b\x44\xe7\xfa\x23\x14\xe0\x0b\x4b\xb7\xe5\x2d\xe0\x08\x2c\x73\xa6\xa3\x21\x80\xb9\x33\x0f\xac\x3e\x4e\xf6\x22\xe7\x18\xca\x1a\x5a\xd4\xab\xc9\x82\xe7\x8b\x82\xe7\x0b\xfb\xe5\x03\x7e\xcf\x05\x47\xa3\xd8\x52\x5e\xdb\x0a\x77\x91\x33\xbd\x86\xba\xc3\xe0\xe4\x24\x39\x0b\x4e\xcf\x46\xc1\xe9\x59\x3b\x41\x3d\xa6\xef\xef\x84\x85\xf4\x42\xde\x20\xae\xcb\xf8\x7c\x4e\xae\x39\xbb\x41\x81\x3c\x0d\x62\x4b\x67\x13\x26\x3a\xbc\x43\xc1\x9a\xaa\xc6\x4d\x83\xb9\xb5\x8d\xd6\x03\x44\xdb\x96\xec\x0e\xd5\x74\x41\x15\x4d\x31\x6f\x8d\x24\x8b\xf6\x57\x14\x0f\xd3\xc4\xf2\x7e\x6f\x10\xdb\xcf\x3a\x8e\x2d\xf5\x07\xf8\x3a\x4f\x5b\x5c\x4d\xf3\x1c\x3f\xf8\xbb\x06\xa6\x06\xfc\xf1\xf7\x61\xea\x3c\xad\x59\xfa\x74\x90\x6c\xb8\x7a\xba\xae\xf1\xb8\x0b\xe4\xf1\x98\x7b\xf5\xf3\x77\x8e\x2d\x30\xf7\x51\x1a\x0f\x9d\x71\x10\x86\xd3\xd0\x7e\x9f\xec\x0c\x46\xd3\x89\x5f\x5f\xcf\xce\x47\xa3\xfa\xf2\x74\x60\xf3\x03\xce\x85\x55\x21\x6d\x65\xd5\xfe\x24\x74\x9d\x62\xd8\xe3\x82\x2c\x64\xa5\xf4\x3e\xa9\x84\xe1\x85\x2d\xc2\x06\xdd\x0d\xea\xa9\x4e\xad\xd4\xea\x68\xcf\xa2\x06\x4a\x74\x85\x01\xfb\x79\x55\xb4\x75\xde\x7e\x5d\x94\x50\xfb\x3f\xf2\x9a\x29\xc5\xb3\x8c\x09\xac\x0c\xbb\xe6\x19\xd6\x90\x23\x49\xf4\x17\xea\xae\x2d\xe1\xab\xcb\xac\x1b\x3f\x01\xdc\x9a\x13\xef\x7c\x14\xb7\x93\x42\x4f\xc1\x1d\x2c\xf9\xbb\x3b\x2c\xc2\x0d\x5b\x6a\x1b\x0c\xb1\x1f\x70\xd9\xf8\x07\x45\xbf\x04\xd9\xc2\xfe\xb9\x85\xc8\x4f\x82\xd8\x1f\x63\xc4\x18\x36\xaa\x42\x5a\x93\xdd\x9f\x65\xac\xe3\x0e\x20\x12\x96\xd5\xa4\x40\x7c\x55\x00\x03\x20\x69\xff\xcd\x6c\x34\x0d\xfd\x64\xcb\xf3\x39\x3e\xdc\x22\xca\xb5\xae\xee\x27\x87\x64\x82\x28\x3a\xbf\x45\xe4\x68\x9b\x48\x63\x30\x81\x5d\xb9\xd1\xb7\x88\x60\x2d\x06\x37\x2b\x32\x67\x2c\x73\x4e\x7c\x7f\x88\x35\xbe\xb6\x46\xbe\x26\xf8\xb8\x89\xce\x02\xb9\x8e\x59\xb0\x25\xeb\xa6\xb2\x90\xaa\x43\x96\xcc\x50\x62\x68\xee\xda\xdc\xf2\xe5\x8a\x78\x22\x53\x92\x67\xe4\x37\xfb\xe4\x31\x7e\xc1\xe5\xc1\x49\xda\xc2\x0d\xec\x44\x0a\x7e\xc5\x48\x47\x48\x51\x97\xc2\x36\x25\xb2\xf6\x14\x6c\xdd\x40\x8b\xe9\xb4\x59\xa1\x73\x34\x6e\xa2\xab\xcf\xd6\x01\xaf\x8c\x5d\xb3\x42\x96\xe0\x11\xe6\x52\xe6\xb6\x44\xeb\xe0\x86\x5d\x1e\x58\x1b\xa8\x0f\x8e\x0f\x8f\x3e\x3d\x38\x3a\x3a\x88\x6c\x9d\x4b\x77\x2e\x55\xb7\xb5\x80\x2e\x17\xdd\xc1\x42\xc9\x25\xeb\x3e\xfa\x1c\x5f\xd6\xd3\x77\xe2\x33\x7f\xec\x27\x83\xe9\x68\x1a\x26\x63\x3f\xf6\x92\xd8\x3b\x25\x7d\xf2\xe5\x37\xe6\xf3\xc7\x8f\x3e\x7d\xf4\x65\xcd\x48\x0d\x82\xb9\x5c\x19\x0b\xb5\xad\x2a\xbc\x8d\x2c\xf7\x5a\xd8\xfe\xe9\xf8\xc5\xbe\x45\x2a\x41\x34\x1b\x79\xb6\xa6\xa8\xc1\x39\x4f\x1f\x3d\x7d\xfa\xe4\xf0\x29\x32\x58\x6f\x1d\xbf\xd8\x1c\x66\x1d\x33\x78\x80\x21\x00\xb3\x6e\xf3\xc3\xe3\xc3\xbb\x9c\xfa\x20\x89\xd0\x9f\x4d\x1f\x24\x01\x28\x39\xfd\x15\x8c\x39\x99\xc6\xc1\xe0\x36\x7b\x3f\xde\x22\xd3\x8e\xaf\x3c\x48\x6b\x1a\x9e\xde\x99\x0f\xee\x50\x53\x66\xf0\x0f\x5b\xdd\xd1\xf6\xb4\x04\xbb\xd1\x28\x0e\xbf\x62\x81\xfe\xeb\x28\x41\x81\x79\x48\x84\x1b\xa9\x7b\x88\x52\xf3\x41\xca\x16\x1d\x2c\x9c\x2e\x81\x35\xcd\x82\x55\xf7\x84\xd5\x66\xeb\xf7\x20\x89\x8a\xa7\xbb\x52\x50\x77\xbb\x61\x4d\xc8\x0b\xaa\x79\x4a\xbc\xed\x6a\x17\xcc\x8f\x4a\xc3\x52\xd3\x10\xac\x73\xec\x75\x28\xf6\x85\x17\x05\x03\x2c\x03\xb9\x15\xec\xd9\x2a\x29\xb9\x97\x7e\xcf\xd9\x10\x68\x95\x18\xaf\xb3\x0e\x75\x15\xd7\xd7\xa7\xb1\x5d\x20\xe9\xaf\xa3\x9b\x4b\x5a\x96\x58\xf1\x24\x5b\x90\x27\x2d\xa8\x06\x78\x8a\x66\xba\x67\xe4\xb2\xe8\x73\xc1\x9d\x8b\x75\x8b\x5e\xdd\xed\x9d\xe3\x5c\xf0\xa3\xa7\xe2\x9d\x33\xf2\x26\x60\x81\x09\x13\xdd\xf3\xc8\xfd\xe1\xa2\x3b\x98\xc0\xbf\x67\x2f\xe1\xdf\xf8\xb5\x9b\xb1\xee\xd0\x77\xe7\xaa\x7b\x12\xba\xa2\xe8\x4e\x46\x6e\x71\xdd\x1d\xbd\x72\x55\xd5\x0d\xcf\xdd\xef\xd3\xee\x6f\xcd\x5c\xa6\xbb\x7e\xe4\x96\xa6\xfb\x22\x74\xcb\xa2\x3b\x1b\xb9\x97\x79\xf7\xc5\xa9\xcb\x4d\x37\x88\xdd\x39\xef\x9e\x04\xae\x51\xdd\x38\x74\x53\xdd\x1d\x7c\xe1\x6a\xd5\x8d\x66\xae\xbe\xee\x46\xbe\x7b\x25\xbb\x2f\x43\x37\x2f\x80\x42\x75\xd5\x3d\xf7\x5c\x26\xba\xa7\x2f\xdc\x45\xd5\x3d\x3b\x77\xf5\x55\x37\x7a\xe9\xf2\xac\x1b\x0c\xdd\x39\xed\x06\xa1\x7b\xcd\xbb\xaf\x26\x30\xd6\x2c\xc6\x8f\x17\x60\xee\xbe\xc8\x0b\xae\x17\xee\x2f\xff\xcb\x8f\xfe\xfa\x2f\xfe\xd5\x5f\xff\xe4\x4f\x7f\xf1\xfb\xbf\xeb\xfe\xf2\xcf\xbf\xfa\xdb\xff\xf4\xaf\xed\xcd\xdf\xfd\xec\x9f\xfd\xed\x7f\xfc\xb7\xbf\xf8\xc9\x7f\xfd\xbb\x9f\xfd\xf3\xdb\x2f\xfe\xe6\x77\x7f\xfa\xcb\xaf\xfe\x3d\xbc\x18\xb2\xca\xe8\x74\xe1\xce\x15\x15\x3f\xff\x63\xca\xb5\x3b\x61\x19\x53\x05\x15\x99\x76\x0b\x6a\xae\x39\xfb\xab\x3f\xaa\xdc\x8f\x3f\xfa\xf8\x3b\x1f\xbf\xfa\xf8\xd5\x87\x9f\x7e\xf8\xc9\x87\x3f\x77\x7f\xf1\x07\xff\xe1\x17\x7f\xf8\x9f\xff\xe6\x4f\xfe\x9d\xcb\x74\x49\x7f\xfe\x67\xb2\x70\x41\x11\x57\x79\xf5\xf3\x3f\xd1\x24\x93\xe4\x85\xa2\x9a\xc3\xc3\x42\x5f\x71\xf7\xc3\x9f\x7d\xfc\x17\x1f\xfe\xe7\x87\xff\xf6\xe1\xc7\x1f\x7f\x64\x69\xb8\xdc\xd0\x82\x53\x21\x5d\x5d\xc9\x25\x77\xe3\x9f\xff\x4c\x5d\xfd\xfc\x8f\x99\xfb\x97\xbf\xc7\xfe\xea\x8f\x0c\x17\xd4\xfd\xf8\xd5\xc7\x1f\x7d\xf8\x5f\x75\x73\x7d\xcd\x84\xbe\xa2\xee\xff\xfd\x37\x7f\xf8\xbf\xff\xc7\x9f\xfe\x9f\xdf\xff\xef\x6e\x4e\x0b\x96\x4b\xf7\xe3\xef\x7c\xf8\xe9\xc7\x1f\x7d\xf8\xf1\xc7\x3f\xf8\xf0\x17\x1f\xbf\xfa\xf8\x2f\x3f\xfc\xf4\xc3\x8f\xdd\x7a\x6f\xc8\xde\xb9\xc0\x40\xfb\x4b\x2e\xf2\x4c\x2e\xf7\xdd\x31\xcd\x57\x54\xb9\x51\x21\xaf\x99\xf8\xcb\xdf\x83\x61\x02\x91\x49\xc1\x34\xa7\xc2\x9d\x31\x85\xbf\xaf\x38\xc3\x9a\x59\xcd\xdc\xd9\x7a\x55\x8e\x8d\x0a\x5a\x36\x06\x33\x04\xc8\xac\xe4\xe9\x15\x53\x96\xad\x7a\xf0\xb0\xa0\xc0\x67\xc8\x57\xc8\x5f\x0e\x32\x17\xe9\x93\x1f\x2e\x1c\xe4\x30\xbc\xec\xc6\xaf\x1d\xfc\x77\x7d\x87\x1c\x87\x7f\x40\xc8\x41\xb6\x03\x39\x54\x0e\xf2\x1e\xe9\x13\x51\x38\xc8\x80\xa4\x4f\x8a\x6b\x07\xb9\x90\xf4\x89\xaa\x1c\x64\x45\xd2\x27\xdf\xa7\x0e\xf2\x23\x8c\xa9\x1d\x64\x4a\xd2\x27\xf8\xeb\x20\x73\xc2\x5d\xe1\x20\x87\x92\x3e\xb9\xcc\x1d\x64\x53\xd2\x27\xdc\x38\xc8\xab\x30\x20\x77\x90\x61\x51\xc7\x38\xc8\xb5\xa4\x4f\xf0\xd7\x41\xee\x25\x7d\xa2\x95\x83\x2c\x0c\x97\xd7\x0e\xf2\x31\xe9\x93\x2b\xe9\x20\x33\x93\x3e\xc9\x0b\x07\x39\x9a\xf4\x49\x75\xe5\x20\x5b\x5b\x41\x3b\x7d\xe1\x20\x7b\x93\x3e\x59\x54\x0e\xf2\x38\x10\xb9\x72\x90\xd1\x61\x26\x99\x83\xdc\x8e\x2a\xc8\x41\x96\x27\x7d\x72\xcd\x1d\xe4\x7b\x5c\x8e\xe3\x5c\xe0\x5f\x83\x7a\xe7\x44\x67\xd3\xd7\xc9\xc9\x74\x1a\xfb\x61\x82\x21\x9c\x60\x72\xda\xd2\x5d\x11\x7e\x83\xc2\xeb\x3f\x6f\x55\xff\x39\x0c\xc2\xde\xb3\xb4\x6a\xc2\xd4\x36\x7f\x2b\x0d\x53\x5b\xc4\x62\x7f\x3c\x1b\x79\xb1\x9f\x60\x8e\xb3\xae\x1a\x42\x95\xfb\xff\x02\x00\x00\xff\xff\x9d\x2f\x08\x3e\xe7\x4b\x00\x00" +var _confAppIni = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7c\xdb\x8f\xe4\xca\x79\xdf\x3b\xff\x8a\x3a\x2d\x2b\x9a\x11\xd8\x3d\x97\x3d\xbb\x67\xcf\xae\xda\x10\xb7\x9b\x33\x43\x6f\xdf\x44\x72\xf6\x72\x06\x0b\x9e\x1a\xb2\x9a\x5d\x1a\x76\x15\x55\x55\x9c\xd9\x16\x02\x43\x07\x7e\x70\x12\xc4\x4f\x49\x6c\x04\x30\x02\x18\x41\x62\xc0\x89\x13\x19\x49\x00\x59\x91\x91\x07\xd9\xef\xbb\xff\x83\x21\xd9\x41\x02\xff\x0b\xc1\xf7\x15\xd9\xcd\x9e\xe9\x19\x1d\xcb\x08\x7c\x0e\xb0\xcd\x4b\xd5\x57\xb7\xef\xf2\xfb\x2e\x9c\x6f\x90\x4f\x3e\xf9\x84\x4c\xfc\x57\x7e\x48\xf0\x9f\xf1\x74\x18\x9c\xbc\x25\xf1\x59\x10\x91\x93\x60\xe4\xc3\x7b\xc7\xb6\x9a\x8d\x7c\x2f\xf2\xc9\xd8\x7b\xe9\x93\xc1\x99\x37\x39\xf5\x23\x32\x9d\x90\xc1\x34\x0c\xfd\x68\x36\x9d\x0c\x83\xc9\x29\x19\x9c\x47\xf1\x74\x4c\x06\xd3\xc9\x49\x70\x7a\x9b\x42\x70\x42\xde\x4e\xcf\x89\x17\xfa\x64\xe6\x0d\x5e\x7a\xa7\xd0\x63\x16\x4e\x5f\x05\x43\x3f\x74\xb7\x06\x98\xbe\x06\xca\xb3\xb7\x64\x7a\x42\x82\x18\x69\x38\xcf\x49\xbc\x60\xe4\x52\x51\x91\x11\x41\x97\x8c\xc8\x39\x31\x0b\x46\x68\x59\x16\x3c\xa5\x86\x4b\xe1\x92\x94\x0a\x72\xc9\xc8\x4a\x56\x8a\xa4\x72\x59\x52\xb1\x22\x52\x11\xc3\xe8\x12\x3b\xf5\x9c\x17\xa1\x37\x19\x26\x13\x6f\xec\x93\x3e\x39\x95\xb9\xae\x09\xeb\x95\x36\x6c\x49\x2a\xcd\x14\xb9\x59\x48\xa2\x17\xb2\x2a\x32\x20\xa6\x2a\x21\xb8\xc8\x6f\x0f\xa6\x7b\x24\x30\x64\x41\x35\x11\x92\xb0\xf9\x9c\xa5\x86\x48\x41\x5e\x73\x91\xc9\x1b\xed\x3a\xcf\x89\x34\x0b\xa6\x6e\xb8\x66\x2e\xe1\xa6\x21\xb8\xa4\x26\x5d\x20\xad\x6b\x5a\x54\xb8\x8a\xdf\x38\x8f\xfc\x90\x30\x71\xcd\x95\x14\x4b\x26\x0c\xb9\xa6\x8a\xd3\xcb\x82\xf5\x9c\xf0\x7c\x92\xe0\xeb\x3e\xc9\xb9\xa9\xe7\xda\xcc\x68\x29\xb3\x07\xb7\x81\x71\x98\x01\xe9\x64\xec\xba\xe3\x92\x4e\xa9\x64\xd6\x81\xed\xe8\x18\xa6\x4d\xc7\x12\x1f\x4f\x87\xb0\x13\x19\xbb\x76\x9c\x0b\xcd\xd4\x35\x53\xef\xea\x61\xca\xea\xb2\xe0\x69\x77\x4e\x53\x18\xec\x3c\x1c\x91\x39\xec\xe5\xf6\x60\x3d\xc7\x7f\x13\xfb\xe1\xc4\x1b\x25\xd0\xa2\x4f\xbe\xb9\x37\x0b\xa7\xf1\x74\x30\x1d\xed\xeb\x67\x07\x07\xdf\xdc\x1b\x4e\xc7\x5e\x30\xd9\xd7\xcf\xbe\xb9\x77\x16\xc7\xb3\x64\x36\x0d\xe3\x7d\x7d\xb0\x73\x90\x4c\x2e\x29\x17\xf6\x7c\x77\x0e\x66\x89\x91\x3e\x29\x64\x4a\x8b\x85\xd4\xcd\x9e\x94\x4a\x1a\x99\xca\x82\x98\x05\x35\x84\x6b\x38\xc9\x8c\x18\x49\x70\x4d\x24\xe3\x0a\x0e\xc8\x28\x3a\x9f\xf3\x14\x9e\xdf\x21\xfd\x9c\x0c\x2a\xa5\x98\x30\xc5\x8a\xe8\xaa\x2c\xa5\x32\x9a\x74\x16\xc6\x94\xb0\x79\xf0\xab\xe1\x62\x9e\xe6\xbc\x43\x80\x0b\x3b\x95\xe0\xef\x3b\x3d\xa7\x59\x2f\xe9\x13\x68\x55\x4f\x88\x66\x99\x62\x5a\xc3\x50\x97\x8c\x14\x5c\x1b\x26\x58\x46\x2e\x57\x77\x47\xc6\x6d\xf1\x86\x43\x38\xe5\xc3\x1e\xfe\xdf\xac\x4a\x2a\x43\x44\xb5\xbc\x64\xea\x6b\x13\x82\xfd\x25\x7d\xf2\xe8\xf0\x10\xa8\x9c\x32\xc1\x14\x35\x8c\x68\xc3\x4a\xfd\xcc\x79\x4e\x7e\x83\xf4\x0e\x72\x99\x6b\x92\x32\x65\x48\x37\xa5\x7d\xa3\x2a\x46\xba\x59\xa5\x90\x4c\xff\xe9\x67\x4f\x0e\x17\x87\xcb\x43\x4d\xba\xb0\xc1\xfd\xe5\x0a\x7e\x7a\xec\x3d\x5d\x96\x05\xeb\xa5\x72\xe9\x3c\x77\x9e\x93\xa9\x22\x73\x25\x97\x84\x92\x5e\x39\x7f\x4f\xe6\xbc\x60\x84\xbd\x87\x19\xb3\xcc\xbe\x81\xf9\xd5\xf2\x80\x83\xf1\x39\xcc\x14\xa6\x22\x15\x23\x7b\x99\x74\x9e\x13\x21\x0d\x9c\x74\xce\x0c\x2c\xd0\xf6\xc7\x8e\xa5\xe2\xd7\xd0\xf8\x8a\xad\xf6\xed\xb4\x65\xc9\x84\xd6\x05\x29\xaf\x52\x7d\x74\x4c\xba\x5c\x20\x55\x1c\xbd\x2b\x2b\x53\xdf\xb1\x25\xe9\x0a\x79\xc5\x56\xfa\xeb\xf5\xba\x62\xab\xa6\x13\xbc\xd0\x70\x91\x31\xed\x0c\xfc\x30\x4e\x50\x87\xf5\x49\x5a\x69\x23\x97\x07\xc8\x04\x07\xcd\x30\xce\x4b\xff\xed\xce\x06\x35\xc5\xfa\x0c\x97\x5c\xf0\x65\xb5\x24\xb4\x28\xe4\x0d\xcb\x48\x3c\x8a\xc8\x35\x53\xda\x4a\xea\x0e\x96\x8b\x47\xd1\xd1\x21\xb0\x1a\x5c\x1c\x35\x17\xc7\x1d\xd7\x72\x1d\xdc\x3c\xea\xf4\x9c\x78\x14\x25\xe3\x60\x92\xbc\xf2\xc3\x28\x98\x82\x4c\x60\x33\xe7\x39\x39\x81\xa3\x28\x99\x5a\x72\x0d\xa3\x90\x9b\x05\x13\xb5\x1c\x34\x02\x70\xcd\x29\x39\x17\xfc\x7d\x23\x71\x5a\xa6\x57\xcc\xf4\x9c\xf3\x49\xf0\x26\x89\xa6\x83\x97\x7e\x9c\xcc\xfc\x70\x1c\x44\x35\xed\x27\x4f\x9e\x38\xcf\xc9\x08\xa4\x8e\xec\x0d\xc7\x5f\xec\xaf\x15\xc2\x8d\x54\x57\x4c\x69\xb2\xc7\x7a\x79\x8f\x44\xd1\x19\xa9\xca\x8c\x1a\xb6\x4f\x68\x9a\x32\xad\x41\xae\x6f\xd8\x25\x4e\x80\xa7\x0c\x04\x2d\x10\x64\x29\xb5\x21\x29\xd5\x4c\x83\xb6\x26\x99\x44\x4e\x10\xcc\x0a\x6d\xba\xa0\x22\x67\xc8\x07\x19\x9b\xd3\xaa\x30\x56\x5d\x42\x67\xaf\x30\x4c\x81\x46\x95\xa2\x58\x11\x3e\xb7\xda\x1e\xc6\xb5\xea\x8b\xc0\xf1\x81\x06\x00\x82\x40\x41\x83\x36\xa1\x9a\x80\x74\xe0\xcb\x9e\x33\x9a\x0e\xbc\x51\x12\x4e\xa7\xf1\x7d\x5a\x6b\x2d\x93\x77\x15\x97\xf3\x9c\xbc\x5e\x30\x54\xad\x46\x92\x8c\x6b\x50\xd5\xa4\xc2\x85\x0e\x86\x13\xdc\x14\x6d\xa8\xe1\x29\x0a\x85\x26\x8a\xe5\x54\x65\x05\xd3\xba\xe7\x4c\x4f\x4e\x46\xc1\xc4\x6f\xf4\xee\x9c\x16\x9a\xed\x26\x58\xc8\x3c\x07\x92\x5c\x10\x25\x2b\xc3\x54\xcf\x19\x06\x91\xf7\x62\xe4\x27\xe1\xf4\x3c\xf6\xc3\x64\x34\x3d\x25\x7d\x02\xd2\xbb\x4d\x81\x09\x24\xd0\x52\x0d\xa4\x60\xd7\xac\x20\xa7\x5f\x04\x33\xb4\x8b\xa0\x99\xac\xf2\x9e\x20\x41\x7c\xd1\xcc\xa6\xd1\x3d\xd4\x2c\xea\xb5\x48\x05\x13\x69\xd3\xd3\x25\x4b\x41\x9c\x49\x46\x0d\xed\x39\xde\x6c\x96\x0c\xbd\xd8\x4b\x66\x5e\x7c\x06\xe6\x84\x1a\xba\x73\x4e\x46\x92\x42\xd2\x8c\x50\xad\x99\xd1\x64\x8f\xf7\x58\x8f\x74\x52\x29\xe6\xc0\xe7\x86\x2d\xcb\x82\x1a\x86\x8a\xd6\x5a\x86\xce\xbe\xd5\x25\x19\xd7\x57\x84\x0b\x6d\x18\xcd\xc0\xe6\xb1\xe5\x25\xcb\x32\xd0\x83\x5c\xd8\x39\x8c\xa6\xde\x30\xf1\xa2\xc8\x8f\xa3\xe4\x24\x9c\x8e\x93\x61\x10\xbd\xbc\xbd\xa8\x82\x8a\x0c\xd6\x52\xd2\x9c\xad\x39\x98\x0a\x29\x56\x4b\x59\xa1\xd1\x50\xda\x6d\x99\xe7\xda\x6a\x03\x2b\x71\x91\x16\x55\x06\x5b\xad\xab\x4b\xdc\x9c\xc6\xd4\x2c\xa8\xc8\x8a\x8d\x4a\x56\x0c\xc4\x1b\x4d\xd2\xfb\x55\xcf\x19\x79\x08\x8e\x6a\x46\xbb\x8f\x7d\x80\x7f\xad\xbc\xec\x30\x4e\x84\x09\xc3\x15\x2b\x56\x1b\x16\x80\xf6\x1b\xf6\x81\xa5\xb5\x6d\xa7\xb5\x15\xa0\x4d\xc1\x0a\x72\x81\xe4\xd3\x42\x0a\x5c\x74\xcf\x89\xa2\xb3\x64\x6d\x4a\x37\x26\xfa\x5e\xab\xf3\x30\xa5\xda\xe2\x1c\x1f\xb7\x39\x47\xce\xb1\xa9\x92\xd2\xd4\xd6\x57\xaa\x95\xbb\x16\x67\xae\x49\xe7\x37\xce\xa6\x63\xff\xa0\xa7\xf5\xa2\x63\x09\xa1\x40\x5a\x16\x6a\x93\x02\x2b\xae\x17\xdd\x2b\xb6\xca\x99\xd8\x26\xb1\x79\x6e\x6d\x72\xc1\x00\x69\xb1\xa2\x20\x73\x2e\x32\x02\xfa\xfd\x66\xc1\xd3\x05\x81\x09\x83\x62\xa1\x45\x61\xc7\x7a\xe9\xbf\x3d\xf5\x27\x0d\xc3\x6e\xe8\x34\xbb\xd9\x4c\x19\x7b\x29\x06\xa6\x08\xd8\x53\x2a\xaa\x56\xb5\x5c\xa3\x5e\x05\x2c\x45\x68\x8d\x63\xc0\x98\xd4\x9a\xa0\x35\x63\xe7\x79\x7b\xce\x66\x83\x36\x37\x04\xd7\xc3\xad\x27\x97\xc4\x7e\xd4\xda\x8c\x16\xcb\xa4\x0b\x96\x5e\xad\xcd\x4a\x6b\x60\xcd\x7f\xc8\xc8\x0d\x37\x0b\x92\x4a\xa5\x98\x2e\xa5\x65\x76\xb3\x2a\x59\xcf\x19\x07\x93\x60\x7c\x3e\x46\xda\x51\xf0\x85\x9f\x0c\xce\xfc\xc1\xcb\xdd\x3a\x48\xb1\x1b\xc5\x0d\x23\x9d\xdf\xc6\xe3\x39\xa0\x95\x59\x48\xc5\x7f\xc8\xb2\x04\x0c\x6b\xc7\x5a\x7b\x6a\x40\xcf\x29\xe3\x12\x9e\x0b\xa9\x58\x66\x77\xa4\xd2\x8c\x5c\x56\xbc\x30\x35\xb7\x58\xb5\xdc\x73\x42\xff\x75\x18\xc4\x7e\xe2\x9d\xc7\x67\xd3\x30\xf8\xc2\x1f\xc2\x5c\xa2\xc4\x8b\x93\x28\xf6\x90\x85\x76\x4c\x05\x47\x20\x74\x27\x45\xec\x06\xa2\x90\x44\x7e\xf8\x0a\x51\x72\x5b\x22\x04\x33\x60\x9c\x08\x17\x86\xa9\x39\x4d\x2d\xa6\xbc\x4b\x08\xb5\x12\xe2\x2a\x02\x3a\x11\xe8\x8d\x82\x28\xf6\x27\xc9\xd9\x34\x8a\x1f\x04\x65\x7f\x5f\x82\xb5\xa8\x7c\x73\xaf\x91\x9b\xb5\xd0\x41\x7b\x10\x1a\x50\x02\x25\x40\xa8\x94\x97\x0b\xb0\xab\x30\x44\x2a\x85\x60\x29\xba\x1d\x28\x91\xbb\xf6\x62\xbd\x0b\xc9\x20\x98\x9d\xf9\x61\x44\xfa\x84\x32\x7d\x74\xfc\xb4\x9b\x1a\xe5\xe2\xf5\xe7\xc7\xeb\xeb\xe3\xc7\x4f\x36\xcf\x8f\x9f\x76\xf3\x74\xf9\x5d\x8b\x95\x16\x00\xf1\x5c\x42\x55\x3a\x97\x95\x3a\x7e\xfc\x64\x7d\x7d\x74\xfc\x14\xd4\xd7\x90\xcd\xb9\x60\x6b\x40\x43\x8b\x5c\x2a\x6e\x16\x4b\x8d\x22\x68\x16\x8c\xab\x35\x7b\x02\x5f\x16\x4c\xe4\x66\x41\xf6\x80\x31\xba\x47\x6d\xad\x47\x91\x37\xf7\x7b\xce\x05\x0c\x5b\xf7\x01\x16\x4b\x80\x97\xf5\x3b\xc7\x1f\x1e\x3f\x7e\x7c\xf4\x39\x68\x97\xc7\x4f\x1c\x7f\x30\x8c\x3c\x42\xea\xbb\x10\xaf\xf1\xee\xf0\xd3\xa7\xce\x70\x7d\x7b\x74\x78\xfc\xa9\xe3\x5c\x28\x56\x4a\xcd\x41\xa8\x1a\x8f\x06\x95\xd1\x1d\xbb\xb6\xa4\x82\xe6\x2c\x23\xeb\xf6\x9c\xe9\x6d\x2d\xf3\xdb\x08\x98\xbb\xed\x06\x1d\x07\x94\xd5\x5a\x4f\xe9\x54\xf1\xd2\xe0\x6a\x1a\x1e\x68\x00\x9d\x4b\xb4\x5c\x32\xc3\x97\x4c\x93\xb4\x71\x2a\x3b\x56\xe7\x0d\xc2\x60\x16\x27\xf1\xdb\x19\x60\x81\x4b\xaa\x17\x76\x77\x71\x60\x6f\x12\x05\x00\x84\x94\x66\xa6\x36\x53\xa4\x12\x8a\xa5\x32\x17\x20\x89\xcd\xbb\x9e\x03\x2d\x93\xc1\x99\x17\x46\x7e\x7c\x5b\x59\xcc\xa5\x4a\x19\x01\x8b\xb4\x22\x82\xdd\x6c\x16\xb9\xaa\x55\x7b\x8d\xb3\x7b\xce\xc9\x34\x1c\xf8\xc9\x2c\x0c\x5e\x79\xb1\x7f\x4b\x92\xf2\x42\x5e\xd2\x82\x14\x7c\xc9\x91\x49\x6b\xee\x97\xf3\xad\x4d\x23\xd4\xfa\xcf\xe0\x7e\x5a\x95\xe9\xc2\x79\x2f\x19\x15\xe8\x25\x63\xf7\x9e\x33\xf6\xde\x24\x83\xd0\xf7\xe2\x60\x3a\x49\x46\xc1\x38\x00\x89\xe8\x1e\x39\xcf\xc9\x4c\xb1\x39\x53\xa0\x48\x46\x3c\x65\x02\xc0\xa1\x91\xa4\x2c\x40\x74\xa9\x05\x73\x46\x96\x8d\xcb\x0b\x12\x03\x80\x70\x02\x16\x6f\x59\x69\x53\x3b\xd7\xa8\x9b\xd0\x0c\x72\x61\xb1\xc5\x41\x61\xc9\x59\xef\xb7\xc6\xea\x5b\x2f\xc0\x8b\xf3\x4f\xfc\x30\xf4\x87\xc9\x28\x18\xf8\x93\xc8\x07\xf9\xf1\x4a\x9a\x2e\x58\x33\x1b\x72\xdc\x3b\x74\x09\xcc\xb7\x7e\xb0\xdb\x94\x9f\x72\x63\x55\x0e\x45\x89\xb5\x1a\x79\x6b\x9f\x00\x7d\x03\xa4\x3c\x80\x7f\xa2\xb5\xef\xba\xb1\xee\x88\x37\x4f\x83\x7b\x54\x62\x83\xef\x2e\x79\xc1\x0d\x9e\xe3\x92\xe7\xe8\xe4\xb5\x4e\xf7\x72\xd5\x30\x22\xba\xca\xc8\xf6\x6b\xbc\x67\xf1\x2f\x18\x97\x64\x1c\x9c\x86\x78\x14\x0f\x8e\xa5\x98\xc8\x98\xb2\x11\x07\xe0\x45\x45\x6f\x70\x9f\x7b\xc0\x1e\x8a\x11\xaa\x40\x2f\x1a\xc0\x29\xb4\x20\x9a\xa5\x95\x82\xa9\x29\xae\xaf\xf4\x7a\xd4\xd0\x7b\x8d\xfe\x52\x12\xfa\x93\xa1\x1f\xde\xc6\xc0\xe8\x2c\xd1\xf7\xa8\x36\x36\x0c\x96\x4b\x40\xbf\x5c\x00\x2f\x00\xde\xaa\x63\x1b\xaa\x12\x0d\x4b\x20\xbe\x07\xf9\xb2\x52\x42\xc0\xfc\x16\x40\x70\xce\x80\x1d\x14\xfb\x41\xc5\xb4\xe9\x91\x73\x5d\xd1\xa2\x58\xb5\xe1\x5d\xc6\x4a\x26\x10\x4f\x2e\xe4\x0d\x28\x82\x15\x19\xcc\xce\xc9\x5e\x2a\x15\xd3\xfb\xe8\x99\x2c\xe8\x35\xeb\x91\x60\xee\x3c\x6f\xf5\x43\xef\x42\x74\x71\xb3\xf9\xb5\x0d\xf0\x20\xf3\x59\xf3\xbe\x99\xfd\x60\x76\xae\x09\xbd\xa6\xbc\x68\xe0\xef\x1d\xa7\x7d\x30\x1d\x8f\x03\xc0\xac\x7e\x3c\x38\x4b\x06\xd3\xc9\xe0\x3c\x0c\xfd\xc9\xe0\x2d\x18\x9e\x2d\x35\xd6\x63\x19\xfc\x82\x36\x1b\xd5\xd6\xa2\xf6\xba\x0d\x13\xda\x1a\x07\xd8\xa2\x1a\xb4\xc2\xcc\x49\x01\x9a\xfa\x46\xd1\x52\x83\x34\xc0\xe0\x03\x99\xb1\x31\x57\x4a\x2a\x62\xe9\x81\x0c\x45\xac\xa4\xc8\x41\x2d\x5a\xc8\xb7\x14\xfc\x85\x25\xc0\x6b\xf0\x5a\x5e\x87\xde\x2c\xf1\xdf\xc4\xfe\x04\xdc\x42\x90\x90\x9e\x79\x6f\xdc\xde\x32\x73\x7b\x4b\xaa\xae\x32\x79\x23\xe0\xce\xfe\x5c\x65\xce\x73\xf2\x8a\x16\x3c\xb3\xf3\x04\xee\xa9\xa7\x88\x73\xa3\xa4\x54\xec\x9a\xb3\x1b\xe2\xcd\x02\x70\x09\x64\xca\x29\x98\x3e\x1c\xd9\x2c\xd8\xd2\x25\xba\x4a\x17\xe0\xbc\x75\x0e\x68\xc9\x0f\xae\x8f\x0e\x9a\x61\x3a\x5b\xd3\xc6\x63\xd1\xc0\xf4\x38\x5d\xdd\x03\x5d\x82\xa4\x0d\xbd\x84\x95\xc3\x52\x2d\xfb\xde\x48\xf1\x2d\xdc\xa3\x1b\x70\x1e\x61\x47\xb6\x37\x91\x64\x92\x69\x68\x82\x07\x8a\x8a\xe1\x55\xe0\xbf\x46\x0e\x46\xee\x05\xb6\x85\xa5\x37\x33\xd9\x3e\xa3\xaa\x04\x07\xe7\xdd\x3d\x52\xb4\x16\x4f\x1c\xd3\xb6\x5d\x0b\xc8\x70\xe3\xcd\xb5\xb1\x6f\x83\x12\x79\xb1\xaa\x43\x27\x75\x3f\xe0\x53\x01\x32\x47\x2a\x94\x4e\xb3\xe0\xda\xf6\xca\xc1\xb9\xba\xe1\x25\xb3\x10\x18\x3c\x08\xb4\x00\x08\xa6\xf6\x7b\x4e\xec\x8f\x67\x6d\x5f\xed\xc0\x2c\xcb\x83\x9a\x6a\x13\x40\x00\x5b\x56\x9f\x16\x48\x77\x63\xed\xad\xd5\xb0\x6d\x59\xe6\x12\xf4\xfa\x3b\x7c\x49\x73\x76\xf0\xfd\x92\xe5\xff\xd4\x5e\x96\x22\xef\xf4\xc8\x88\xc1\x39\xb3\x65\x69\xd5\x14\xd2\x20\x20\x65\xf3\x66\x84\x9e\xe3\x8d\x46\xd3\xd7\xfe\x10\xad\x60\xb4\x36\xa8\x8d\x22\x40\x4c\x0b\xfe\x1e\x6d\x34\x3b\x17\x64\xfc\xa2\xe7\xd8\xa3\xf0\xde\x20\x96\x25\x7d\xf2\xe8\x5e\x0d\x62\xc1\x7a\xc9\x54\x3d\x6b\x6b\x81\xa0\x3f\x9c\xe2\x63\xc7\xb9\x80\x2d\xb8\xa4\x9a\x35\x38\xa1\xb9\x27\x97\x34\xbd\x62\x02\x56\x59\x87\x52\x4b\xa9\x4d\xae\xac\x83\xba\x5c\xe9\x1f\x14\x1d\xd2\xd1\x3f\x28\xb8\x61\x8f\xac\x71\x59\x6a\x78\x08\xbc\xf9\x56\x56\xd6\x12\x5a\xec\x06\xeb\x8f\xf9\xf0\x85\x65\xee\xf1\x2a\xfa\xde\xa8\xa5\xf8\x6b\x08\xd0\x90\x77\x6a\xe0\x79\x74\xfc\x19\x42\xcf\xa3\x67\x8f\x3f\x7d\x74\xec\xd4\x61\x6b\x00\x23\x4e\x13\x15\x86\xeb\x99\x17\x45\xaf\xa7\xe1\x10\x77\xef\x44\xb6\xe7\x89\x51\x92\xcd\xfc\x6b\x1b\x05\xd3\x07\xbd\xc8\x55\x6d\x13\xaf\x99\xe2\xf3\x55\x77\x5e\x15\x05\xfa\x62\xa3\x75\x60\xd8\x76\x68\xe8\x6e\xd6\x8a\x64\x97\xf4\x8a\x11\x5d\x29\xd4\x6c\x00\xef\xe8\xa5\x96\x45\x65\x58\x6d\x6e\xda\x2c\x06\x33\xed\x65\x97\xb7\x8e\x09\x20\xe7\x16\xbc\xad\x8d\x7b\x29\x61\x5b\xe0\xa0\xa6\x33\x7f\x02\x6a\x11\xd5\xcd\xa3\xc3\x5b\xfd\x79\x56\xb0\x87\xfb\x07\xc3\x91\xdf\xee\xef\x5c\x34\xe6\xe9\x96\x90\xa2\x4a\x80\xbe\x5c\x68\x43\x8b\x02\x83\x04\x2e\x01\xf8\x85\x92\x65\x24\xe9\x80\x78\x76\x50\x06\x56\x25\xd5\x9a\x00\x9e\x09\x26\x51\xec\x8d\x46\x60\x54\x5f\xde\x32\x67\x9a\xa5\xaa\x8e\x6c\x8a\x54\xad\x4a\x43\x52\x29\xaf\x78\xa3\xaf\x5c\x72\x7c\xe2\x91\x54\x66\xcc\x25\xcc\xa4\xc0\x35\x9f\x7c\x62\xb3\x2b\x36\x09\x13\x4f\xc9\x4b\xdf\x9f\x91\xb7\xd3\xf3\x90\xe0\x89\x0f\xbd\xd8\x23\x91\x77\xe2\x7f\xf2\x89\x13\xf9\x83\xd0\x8f\xc1\x89\x22\x7d\xf2\xc9\x37\xbe\x7b\x32\xf4\x5f\x83\x93\xf5\x4f\xbe\xbd\xb7\x66\xe4\x95\x26\x8a\x2d\x19\xc8\x02\xcb\xac\x81\xac\x8c\xec\x16\x32\xe7\xa2\xe7\x8c\xa6\xa7\xc1\x24\x09\xfd\xb1\x3f\x7e\xe1\x87\xc9\xd0\x7b\x0b\x9b\xf4\x59\xdd\xbb\x9e\x6b\x13\x51\xd0\x46\x02\xda\x5f\x77\x27\x5c\xcc\xa5\x5a\xae\xcd\xd8\xf4\x65\xe0\x6f\x68\xb5\x78\x35\xe1\x22\x55\x2c\xe3\x96\x8f\x76\x53\x86\xd9\x15\x32\xcf\x6d\x90\x01\x60\xa4\xcd\xd7\xd4\x64\x61\xed\x6d\x8a\xf4\x86\x01\xaa\xbe\x75\x80\xe0\xfc\xc3\xd9\x36\x03\xac\xbb\x47\xfe\xe0\x3c\xbc\x27\xde\x06\xbd\xea\xf9\x18\x49\xb8\xc8\x6c\x90\x1a\x91\xac\x5d\xa7\x36\xd4\x54\xba\x05\x9e\x60\xd3\xa2\xd8\x8b\xcf\xa3\xc4\x0e\x70\xeb\xd8\x77\x2d\x6f\x17\xc1\x1d\x94\x9a\x7d\xc3\x86\x89\x6d\xe8\x38\x17\x6c\x49\x79\xb1\xdb\xa8\x00\xc7\xe2\xeb\x4d\x84\x75\x63\x4e\xda\xb3\x2a\x15\x9b\xf3\xf7\xf0\x03\xa0\xc7\xaa\x72\xc4\x4f\xd5\xe5\xf7\x41\x41\x01\x54\xe8\x39\xd1\xf9\x8b\xdf\xf2\x07\x71\x02\x78\x38\x78\x43\xfa\xe4\xcb\x8b\x6f\xee\x6d\xb2\x66\xfb\xfa\x1d\xf9\xb2\x26\x18\x8d\xe3\x59\x03\x32\x51\xab\x71\xa3\xd1\x3b\xae\xad\x82\x5e\x9a\xb2\x07\x33\xcb\x2b\xd1\x93\x2a\x7f\xf6\xf8\xe9\x67\xae\x7d\x9a\xc3\x63\xf0\x33\x5b\xcf\x7e\xf0\x03\x7c\xf0\xe9\x93\xc7\xce\x73\x12\x34\x62\xac\x0c\x61\x22\xd3\xe8\x87\x7d\xfa\xe4\x71\xc7\xc5\x61\x23\x72\xc3\x8b\x02\x2d\x91\x66\x19\x60\x3b\xf0\xe4\x30\x1e\x10\x8f\x22\x30\x78\xd8\xf3\xf1\xd3\xcf\xa0\x23\x38\x4d\xcb\xa5\x5d\x34\xd8\x81\xf0\x64\x40\x9e\x7c\x7a\xf8\x79\x6f\x33\xd0\x2d\xa7\x6d\x43\x8a\x1b\x3b\x14\x2d\x6e\x40\x98\x9a\x11\x1b\x0d\xbd\x6b\x8d\xf5\xf6\xd8\x43\xb1\x39\x92\x3a\x19\xb4\x07\x23\x3f\x7e\x74\x7c\xbc\x0f\xc0\x99\xeb\x06\xcd\x7e\x1f\xbc\x17\x2a\xea\x2e\x75\x6b\x97\xd4\x19\xb0\x2f\x3b\xe0\xe2\x74\xc8\x77\xf0\xf5\x77\x5b\x89\x98\xdf\xfc\x92\x58\x11\xec\x39\x27\xe1\x74\x4c\xfa\x44\x48\xc5\xca\x62\xf5\x5d\xd4\xb6\xb7\x93\x64\x96\xfb\x80\x11\x7b\x8d\xfd\xf8\x1a\xed\x41\xd1\xdd\x48\x95\xf5\xda\x76\x66\xb7\xeb\x73\xe6\x8f\xa6\xa0\xd2\x6d\x26\xa9\x0e\x90\x2d\x18\x01\x9a\xd6\x23\xd3\x24\xe3\xf3\x39\x53\x4c\x98\x96\xbb\x03\xdd\x1a\xcb\x6f\xdd\xb3\x4d\x17\xd0\x59\xdb\x74\xb7\x9c\x73\xdc\x5f\x1b\x4f\xeb\x39\xd0\x0e\x83\x36\x56\x8a\x6e\xcd\x52\x5f\xf1\x92\x58\x4b\xd7\x24\x74\xdb\x69\x29\xd9\xe6\x84\x1e\x99\x8a\x62\x85\x36\x0d\x95\x3f\x06\x0c\x58\x31\xef\x6a\x9e\x0b\x70\xbe\x37\x1d\x75\xcf\x89\x5e\x06\xb3\xe4\x95\x1f\x06\x27\x6f\x77\x2b\x19\xa0\x93\x16\x1c\xb0\xda\x76\xcf\xf3\xc8\x4f\x06\x7e\x18\x07\x27\xc1\xa0\xed\x77\xef\xc8\x3e\xe1\xe9\x3f\x94\x7d\xb2\x0d\x9a\xec\xd3\xdd\x09\x74\x0c\x7b\x6f\x0e\xca\x82\x72\xd1\x01\x4c\xdd\xa0\xc7\x86\x85\x60\x2e\xb3\x91\x17\x4c\x92\xd8\x7f\x73\x8f\xef\x49\x8d\x01\x24\x46\x09\x92\x01\x82\x84\x16\x06\xb4\x35\x38\x42\x8d\x4a\x19\x07\x63\x9f\x2c\x99\xd6\x34\x67\xe4\x66\x01\xb0\x4d\x33\x1b\x8c\x3c\x8b\xc7\x23\xcb\xe7\x1a\xc5\x6f\x3b\x59\x6b\xc5\x8f\xc8\x02\xbd\x4d\x10\x06\xbb\x6b\x36\xb4\x64\xe1\x46\x49\x97\x80\xe9\x0c\x53\x9a\x2c\x68\x59\x72\x60\x67\x6f\x38\x6c\xcd\x3d\xf1\x46\x9b\xf9\x3b\x17\xb4\x32\x8b\x06\xdb\x5d\xa3\x3f\xd2\x24\x3b\x6d\xc4\xcd\xd8\x54\x63\x8a\x89\x23\x41\x96\x5c\x54\x78\x38\xde\x20\xc6\x68\x48\x32\x98\x0e\xfd\x64\x14\xbc\x42\xc4\x78\xf4\xf4\xf0\x5e\x5a\x8a\x81\x39\x69\x24\xe6\x2e\xc5\xd0\x8f\xfc\x38\x69\xe4\x68\x17\xdd\xad\x28\x2c\x22\xb4\x5a\x2b\xa4\x52\xcc\x79\x6d\x6e\xad\x21\xcf\x70\x43\x05\xbb\xd9\xd6\x1b\x0c\x37\xd6\x6f\xac\x03\xd7\x44\x96\x75\x20\x02\xf5\x98\xde\x50\x46\x9b\x64\x64\x43\xbb\x65\x4b\xd0\xc9\x67\x39\xd7\x46\xd5\x06\x3e\xf4\xbf\x77\x1e\x84\x7e\xe2\x8f\xbd\x60\x94\x60\x8d\x47\x38\x7e\x20\x72\x00\x3a\xa1\xc6\xfb\x5b\xe9\x15\x72\xcd\xc1\x6b\xae\x05\x50\x73\xc3\x36\xb4\xa3\xe0\x74\x12\x4c\x12\xf0\xb7\x1e\x4e\x8e\xa1\x28\x6e\xcd\x0f\x5a\x89\xe6\x7d\xe6\x12\x9a\xa6\xb2\x02\xc6\xb9\xd9\x38\xc3\xd6\x77\xb1\xa1\x29\x4c\xd7\xd0\x6c\xc9\x85\x6e\x25\xd6\xfc\xd3\x20\x8a\xbf\x46\x3c\x24\xa5\xa5\x49\x17\xd4\x72\xc0\xe6\x48\xda\x33\x5a\x47\x3d\x5a\x34\x93\x81\x37\x8b\x07\x67\x5e\xe3\xe8\xdd\xe3\x25\xb6\xf2\x47\x80\xb7\x16\x4c\x98\x26\x13\xd4\x84\x8e\xc8\x82\xd1\x0c\x18\x7f\x3d\xca\x2b\x3f\x04\xf9\x0d\xa7\x6f\xde\x62\x88\xdd\x9f\xc4\xa0\x52\xee\x5d\x09\x00\x39\xe0\xa6\x94\x16\xc5\xaa\x49\x71\x00\x33\xd9\x53\xb2\xcb\xb9\x7f\x26\xf7\x8f\x3c\xbd\x6f\x1b\x41\x64\x5a\x73\xb7\x52\x4f\xf5\x1a\xed\x7d\x8d\x31\x1f\x5a\x66\x72\xe6\x7b\x43\x34\x6a\x6f\xba\xaf\xfd\x17\xf0\xb2\x0b\x56\xce\x71\x2e\x60\x84\xdd\xe8\xc9\x72\xbb\x90\xb5\x4a\x46\x17\x02\xa6\x81\x9b\xb0\x5e\xa3\xe5\xf9\xc9\xb4\x56\xd3\xed\x65\x81\x3b\x81\xc9\xd4\x77\x6b\xcc\x6f\xb3\xee\xa5\x92\xd7\x3c\x63\x6a\xe3\x7c\x2d\xd9\x52\xaa\x15\x16\x91\x70\xf4\xc1\xc0\xa3\x02\x60\xac\x6d\x15\x09\x56\x42\x91\x3e\xb1\xed\xd6\x58\x52\xcc\x79\xde\xa8\x18\xbb\x43\xba\x04\x6f\xe7\x9a\xad\xc7\x78\xe6\x3c\x27\xdd\xba\xdf\x33\x0c\x60\x6c\xd2\xe9\xe0\x6e\x5b\x22\x64\xc5\x0c\x36\x84\xe1\x9f\xad\x27\x8a\x5e\x35\xf8\x6b\x35\x6c\xfb\x12\xdd\xb5\xfa\xad\xfe\x12\x7b\xe0\x2c\x9f\x35\x19\x95\xbe\x49\x4b\x17\xb4\x4d\xff\xd9\x93\x47\x9f\x7d\xee\x36\xfa\xae\xbf\xa4\x29\x55\x52\xb8\xd9\x65\xff\xd0\x05\x17\x0c\xe3\xf8\xfd\xa3\xc3\x43\x17\x1c\xb5\xc4\xf0\x25\x93\x95\xe9\x83\xaa\x6b\x16\x9c\xd4\xe5\x62\xb5\x9b\xd8\x8c\xfb\x10\x94\x36\xad\x6d\xe6\x19\xf0\xc7\x1c\x8d\xc0\x36\x84\xe6\x49\xc1\xaf\x58\x92\xdb\x22\xaf\xdd\x88\x9f\x0b\x62\x63\xb0\xe0\xcf\xde\xef\x2e\xc0\x4c\x4e\x07\x36\xaa\x7b\x4d\x0b\xe8\xa6\x59\x2a\x01\x97\x5a\x60\x60\xe7\x62\x13\xd1\xa7\x83\x24\x98\xc4\x7e\xf8\xca\x1b\x81\xc7\xf9\xe4\xf0\xb6\xcf\x5a\xf0\x79\x1d\xb0\xbc\x45\x87\x36\x94\xac\xe7\x3a\x0a\x4e\xfc\x24\x0e\x70\x31\x4f\x9f\x7c\xba\xa6\xd3\xde\x13\xe8\x36\x88\xc2\x13\x62\xe4\x15\x03\x37\x2c\x0a\x4f\x6e\xb9\x12\x49\xaa\xd5\xdc\x71\x2e\x52\x9a\x2e\xd6\x21\x0e\xbc\x21\x34\xa3\xa5\xd9\xcd\xa2\x96\x2f\x2d\x8f\x2e\xd9\x12\xdb\x77\xc0\xce\x7a\xb3\x78\x9b\x4b\x4f\xe4\xa6\x63\x1d\x17\xd8\xbd\x57\xe0\x2a\xaf\xf7\xe5\xc9\x61\xd3\xd5\x8e\x64\x8b\x5b\xd6\x23\xb9\x2d\xa7\x1e\xb1\x60\x63\xdd\x9e\xfd\xff\xe2\xc7\x5a\x82\x70\xf8\x67\xe4\xcb\x4d\xe8\xe5\xe8\xe8\xf8\xe8\xe8\xcb\x1a\xf0\x3b\xce\xc5\xc2\x98\xb2\x85\x26\x2a\x7b\x08\x1d\x0f\xb3\xf7\xdd\x81\x14\x46\xc9\xa2\xeb\x81\xed\xeb\x4e\x15\xcf\x01\x6d\x59\x8d\xb7\x05\x5c\xb1\x3c\x45\x82\x3b\xa6\x11\x0c\x7b\x83\x81\x1f\x81\x1b\x38\x89\xc3\xe9\x28\xc1\xb0\x58\x32\x0d\x83\xd3\x60\x82\xc3\x16\x73\xbd\x56\x31\x46\x2a\x40\x56\x75\x78\xca\x2a\x2c\x8c\x6d\x35\x80\x40\xa2\x4b\x07\xc8\x34\x9e\x86\xde\xa9\xdf\x54\xcc\xdd\x49\x84\xad\x65\x6a\x74\x12\x35\xbd\xc0\x7d\xb2\x49\x03\x54\x0d\x0d\xb8\x9e\xa2\x63\x18\x6d\xc5\x0d\x8b\xb9\xee\xd6\xbd\x00\x67\x21\x38\x5c\x32\x61\x76\x2a\xdb\xac\x9e\x24\xd9\xb4\xc3\xa8\x74\x8e\x35\x6a\xc5\xaf\x08\x83\xda\x69\xb6\xbb\x4a\xb1\x09\xdf\x36\x93\x6c\x4f\xae\xd5\xf6\x1f\x39\xa8\x49\x76\x91\xfa\xba\x91\xce\x56\x90\xf3\xd3\x7f\x40\x90\x53\xb1\x82\x51\xcd\x7a\xbf\xce\x21\x59\xb3\x83\xfd\x77\x45\xab\xff\x51\xb7\xf6\xdb\x07\xdf\xfe\x35\x76\xf2\xd1\xf1\xaf\xb9\x95\x47\x87\x8e\x73\x01\x7a\x03\x76\x2f\xb2\x65\x50\xcc\xa6\x7d\xac\x1f\x85\x9b\x35\xaf\x00\x54\xc9\xca\x94\x15\x40\xcd\xcc\x3a\x7b\x98\x0d\xa9\x98\x6e\x55\x17\x4b\xb1\x76\x3c\xe7\x12\x96\xcb\x45\x0e\x2a\xce\x9b\x44\xc1\xc0\xc5\x1a\xbd\x21\x26\x52\xc3\xea\x72\x55\x5f\x9d\x0c\x9e\x1e\x1f\x37\xbf\x5f\xd8\x8b\xc7\x87\xf8\x7b\x74\x74\xfc\x68\x7d\x61\x5f\x3d\x7a\xf4\xe8\xf3\xf5\xc5\x84\x0a\xe9\x92\x97\xdc\xa4\x0b\x26\x5c\x12\x19\xba\x2c\xeb\x9f\x31\x2f\x0a\xbe\xbe\x4e\x95\x44\x8d\x8c\xb7\xd0\xab\x57\xab\xeb\x25\x48\x61\x2b\xf2\x47\xe8\xa5\xac\x4c\x7b\xfd\x9a\x31\x2c\x84\x7d\x76\x70\x90\xcb\x82\x8a\xbc\x27\x55\x7e\x50\x5e\xe5\x07\xb0\x6d\x07\xdf\x28\xaf\xf2\x6e\x2a\x85\x36\x54\x80\x86\x3a\x99\x82\x1b\x41\xfa\xcd\xac\x1d\xe7\xa2\xe4\xa9\xa9\xd4\xda\x56\x6d\x6b\x00\xf4\x59\xe8\x35\x35\x54\xed\x56\x01\xde\x2b\x2f\xf6\xc2\xe4\x7c\x86\x15\x61\x5b\x0a\xc1\xf6\xda\x49\xb6\x95\x9b\x79\x88\x78\xe8\xcf\xa6\x51\x10\x4f\xc3\xb7\xc9\xfd\xe3\x00\xad\xee\x66\xb0\xc1\x82\x0b\xa6\x59\x0d\xac\x53\x6a\x4b\x64\x68\x13\xe9\xb0\x0d\x89\x96\x95\x4a\xd9\x26\xe3\x55\x6f\x61\x2a\x7a\xb9\xb2\x4d\x7a\xa9\x5c\xd6\x6b\x38\xe8\x39\xa7\x61\x3d\x81\x68\x7a\x1e\x0e\x30\x32\x5a\xb7\xbb\x27\x2d\x5d\xbf\x75\xad\x4f\x68\x2d\x57\x13\x45\xc3\x32\x81\x46\x58\xb1\x1e\x98\x83\x3f\x3b\xc7\xf4\xe1\x12\x6b\x26\x1b\x1f\xa9\x19\xf7\x41\xff\x68\xce\x32\x2c\x3b\xce\x9a\xd5\x15\x52\x5e\x55\x25\x2c\x5c\x93\xe1\x24\xaa\x27\x96\xca\xeb\xf5\x61\xb6\x12\x80\xce\x73\x1b\x4f\xb4\x61\x02\x77\xcd\x51\xfa\xd9\xc1\xc1\xcd\xcd\x4d\xaf\xe0\x97\xcd\x96\x48\x95\xa3\xc0\x65\xcc\x34\x21\x85\xf8\x57\x2c\x0f\x67\x7d\x7b\x7d\x80\x73\x30\x5c\xd5\x6c\x93\x0d\x55\xe9\x4b\x5a\xb0\x6c\xed\x07\x9c\xf8\x43\x3f\xf4\x62\x7f\x98\xdc\xda\x03\xe7\xa2\xc9\x06\xee\x76\x33\x16\x54\x65\x36\x17\x7b\xa9\x18\xbd\xda\x64\x1b\xd7\xa4\xcf\xbc\x70\x98\x60\x92\xf5\x45\xe8\x7b\xb7\x13\x09\x4d\x75\x50\xcd\x32\xe7\xe1\x88\xe8\x74\xc1\x96\xbb\x34\x2e\xd5\x30\xd2\x55\x5d\x9f\x66\x33\xf7\x80\x0b\xc6\xf5\x0c\x1b\x49\xae\xe3\x88\x2e\xe9\xe4\xdc\x74\xc8\x1e\xa2\x98\x9c\x9b\x67\x07\x07\x9d\xfd\x1a\x8e\xd1\x5c\xb0\xf5\x3b\x7b\x87\xaf\x7b\x8e\xfd\xd6\x23\x39\x0f\x47\x49\x34\x38\xf3\xc7\xad\xdc\x5d\xf1\x35\x92\xd3\x97\x4d\x4d\x01\xcb\x0e\x58\xc6\x8d\x9d\x77\x7b\x8a\xbf\x32\x25\x4d\x62\xd9\xd4\x25\xd4\xf5\x78\xf0\x56\xc8\x56\x2a\x97\xea\x75\x96\xd6\xb5\x41\xd6\xb2\x32\x9b\x9c\x36\xe6\x10\xb7\xd3\xd9\xf7\x66\xb2\x9d\x0b\xbd\xa4\xca\xac\x4a\xd0\x5a\xf7\x47\xe2\xa3\x4d\xa3\xbb\x87\xbc\x89\xc8\x9f\x84\xde\x20\xae\xc7\x44\x23\x3a\xf4\xa2\x33\x7f\x7d\x37\xf2\x62\xff\x4d\xb2\xfd\xcc\x9b\x9c\x8e\xfc\x61\xf2\xbd\xf3\x69\xbc\x79\xe8\x5c\x60\x08\xe3\xdd\x6e\x91\x57\x2c\xaf\x0a\xaa\xc8\x9e\x90\xa2\x8b\x0d\xf7\x6b\x25\xb4\x29\x6a\x94\x2a\xa7\x82\xff\xb0\xfe\xa6\xa5\x1d\x09\x39\x1f\x79\x61\x32\x0d\x4f\xd7\xc5\x3a\x2d\x6e\xbf\x61\x97\x0b\x29\xaf\xde\xdd\x3a\xf1\x06\x42\x58\x2c\xb0\xf6\xa3\xeb\x00\xe4\xfa\xc3\x94\x0e\xf8\x64\xe0\x64\xe8\x82\xa6\x57\x70\x81\xba\x40\x65\xf6\x52\xe4\x86\x16\x57\x1d\x9b\x15\x8d\xea\x94\x8f\x4b\xb0\xb1\x4b\xea\xa6\x70\x61\x1b\x62\xcd\x54\xc1\xb1\xee\xce\xe2\xf9\x2d\x9f\x63\xe8\x8f\x82\x57\x7e\x88\x8e\xd4\xf4\x1c\xb3\xaa\x8f\x6f\x45\x42\x10\x66\x70\xd1\xe4\x8e\xd6\x01\x5a\x3c\x3a\x8c\xed\xc6\xa3\xe8\x6e\x7c\x37\xde\x2a\xf5\x58\x70\x8d\xd6\xa3\x6d\x1b\xb9\xb0\x20\xa4\xa4\x39\x03\x6c\x7a\x1a\x4c\x4e\x93\xc9\xf9\xb8\xc6\x11\xcd\xe7\x19\x05\xb8\xa4\x86\x8b\x1c\xd3\x97\x98\x06\x53\xba\xe7\x5c\x14\x32\xdf\x5d\xba\x46\x8b\x02\x9a\x59\xbe\xdf\xae\x55\x2b\x64\x7e\xd0\x21\xba\xba\x6c\x95\x94\x6e\xd7\xd5\x0e\xea\x43\x00\x1b\x2c\x6d\x2e\xb8\x8e\x47\xd4\xe7\x61\x65\xbf\x39\x12\x90\xc5\x73\xcd\xac\xcc\x58\xf7\xb9\x16\xcc\x65\x55\x18\x5e\x36\x85\x1d\x0d\xb4\xab\xc9\xba\x38\xb9\x8e\x53\xe7\x91\xeb\xa7\xce\x73\xf2\xa2\x9a\xcf\x99\x6a\x8a\x02\x41\xa7\x2d\xa8\x10\xac\x70\xc9\x15\x63\x25\xe1\x06\xa4\x96\xe3\x62\x6c\x71\x3f\xc9\xb0\x62\xe3\x4a\xc8\x1b\x72\x83\x25\xd7\xf0\xb2\xe7\xbc\x38\x3f\x39\xf1\xc3\x64\xe4\x4f\x70\x3b\xc1\x83\xf3\x6b\x37\x36\x56\x34\xc5\x05\x05\x62\x2e\xe1\xf7\x35\x55\x02\x7e\x7d\xa5\xa4\x82\x8b\x13\x6a\x68\xd1\xd9\xde\x3a\xdb\xcb\x19\xf9\xaf\x7c\xf0\x50\xf1\xd6\x69\xbc\xd4\x66\xb7\x6a\x6b\x21\x8a\x15\x9e\x4f\xaf\x7e\x0e\xe7\x34\xc0\x24\x93\xc1\x92\x0b\x4c\x25\x2e\x98\xc2\x8f\xb6\x6a\x8a\x6b\x5a\xb8\x33\xb7\x09\xc1\xc3\xaf\x45\x65\x67\x2d\x98\x0d\xe6\xd9\x24\x2a\x51\xd2\xc0\xf9\xec\xe9\x1b\x00\x7a\xa8\x8a\x1b\x6c\x59\xc7\x82\xf5\x3e\x66\x1f\x93\x70\x1a\xdb\xac\xc3\xdd\xaf\x08\x34\xcb\x71\x1e\x6b\x3e\x23\x19\xe5\x58\x82\xee\x05\xa3\xb7\x77\x7a\xde\x01\xe0\x7a\xc1\xe7\xa8\x14\x6c\x3d\x16\xd2\xd8\xda\xef\xe3\xa7\x75\x69\xe0\x11\xf9\xce\x77\xe0\x0e\xcb\x3a\xdb\x38\x3d\x89\xce\x82\x13\x2c\x2d\x7f\x7a\x2f\x5a\x2f\xb0\x34\x6c\x7b\x98\x26\x7c\x32\xa9\x11\x3b\xfe\xd7\x64\xe5\xde\x97\x5c\x21\x24\x5f\x35\xd2\x66\x0d\xd5\x5e\xc6\x0a\x66\x18\xa1\x73\x83\xb9\x87\xf7\xd8\x64\xdf\xd2\x5a\x67\xc6\xd7\x85\x10\x56\x52\x6e\x9d\x21\x3e\xfd\xba\x87\x68\x55\x28\xd8\x72\x07\xbf\x0d\x70\x2c\x8d\x5a\xee\x7e\x6d\x2a\x76\x99\xeb\x98\xaa\xc5\x3c\x19\xd7\x65\x41\x57\x36\xbb\xde\x8e\x76\xda\x44\x60\x1d\x29\xda\x4e\xf4\xd6\xf3\x79\x2f\xd5\xf2\xdd\x26\xa1\x80\x7b\x85\x0c\xc6\xa5\x70\x6e\x73\x41\x68\x39\xcf\x56\x1b\x65\x74\x55\x37\x48\x90\x67\xee\x34\x93\x22\x6d\xe0\x35\x70\x0c\x7b\x9f\x62\xfa\x82\xbc\x27\xe3\x17\x6d\x67\xcd\x0a\xf7\xb8\x3e\x7b\x3c\x39\x23\xad\xba\xb0\xca\xd2\x32\x68\xfb\xa4\x1e\xd5\xb3\xcf\xeb\xd9\xef\x80\xa8\xed\x85\xf4\xee\xac\xa4\x9d\x87\xb1\xb3\xb5\x70\xa6\x59\x59\xef\x9e\xa5\xb5\xb9\x74\xb3\x34\x74\x40\xc9\x25\x9b\x83\xab\x21\xd8\x7b\x53\x13\xed\xdd\x5d\x66\x9b\xc0\xd6\x52\x71\x8d\xbd\xdb\x8b\x4c\x95\x0d\x3d\xd7\xc7\xd3\x7c\x1b\x0a\x8f\x89\xa1\xfa\x0a\x3d\x59\x2e\x33\x1b\xe7\xdf\xe1\xbc\x87\x95\x68\xb7\xb6\x20\x58\xe6\xda\x16\x8b\x69\xfb\x99\xe8\x9d\x1a\x7d\x3b\x70\xcf\x7e\xea\x95\x2c\xb1\x9e\x10\x61\x91\x2d\x0e\xd7\x58\x50\x29\xe7\xa6\x4e\x00\xdb\x06\x44\xaf\x44\xca\x94\xfd\x82\x01\xd5\x3b\xf8\xf6\xf5\x3b\xc1\x58\xd6\x7c\x2e\x09\xed\x16\x4a\xda\x3a\xe7\xbd\x4b\xaa\x59\xd6\x78\x63\x75\x6b\x3b\xf0\x3a\xca\xb8\xdf\x73\x00\x85\x0e\xcf\x31\x1f\xfa\x5d\x7b\x4a\x47\x87\x98\x05\x0d\x37\x9e\xdd\x82\xd1\xc2\x2c\xec\xf8\xf5\x0a\xc0\x57\x4b\xec\xf3\x04\x9f\xbf\xdb\x41\xe9\xf8\xd3\x85\xb3\xc1\x0f\x4f\x0e\xc1\xab\xf3\x54\x5e\x6d\xa2\x23\x68\x1d\x45\x46\xbe\x95\x73\x43\xe6\x3a\xbd\xfa\x56\x63\x0f\xbb\xdd\x4a\x28\x40\x01\x78\x3e\xdd\xae\xa1\xb9\xee\x38\xcf\xd1\xa9\x41\x67\x5a\x8a\xb5\xbb\xcc\x4d\x57\xa7\x4b\xf4\xf3\x32\x99\x6a\x7c\x00\xc4\x0e\x8e\x7a\x9f\xf5\x1e\x3b\x5e\x78\x1a\x59\x33\x32\xc0\x6f\x40\x5a\x3e\x2b\x7e\x70\xa6\x0d\x4f\x75\xbd\x2e\x5c\x4b\x82\xab\x83\x77\xfa\xdd\xed\x73\xc4\xe3\xdf\xbd\x54\x18\xa0\x60\x54\x54\xe5\x96\x5b\xac\xd2\x05\xbf\x66\xba\xbd\x71\xf5\xb3\x24\xb5\xcd\xef\x0c\x62\x99\x65\xf7\x28\xcf\x49\xcc\x97\x6c\x93\x3e\x5d\x7f\xda\x02\x7c\x61\xe9\xb6\xbc\x05\x1c\x81\x65\xce\x74\x34\x04\x30\x77\xe6\x81\xd5\xc7\xc9\x5e\xe4\x1c\x43\x59\x43\x8b\x7a\x35\x59\xf0\x7c\x51\xf0\x7c\x61\xbf\xa7\xc0\xaf\xc4\xe0\x68\x14\x5b\xca\x6b\x5b\x37\x2f\x72\xa6\xd7\x50\x77\x18\x9c\x9c\x24\x67\xc1\xe9\xd9\x28\x38\x3d\x6b\xa7\xbd\xc7\xf4\xfd\x9d\xb0\x90\x5e\xc8\x1b\xc4\x75\x19\x9f\xcf\xc9\x35\x67\x37\x28\x90\xa7\x41\x6c\xe9\x6c\xc2\x44\x87\x77\x28\x58\x53\xd5\xb8\x69\x30\xb7\xb6\xd1\x7a\x80\x68\xdb\x92\xdd\xa1\x9a\x2e\xa8\xa2\x29\x66\xc3\x91\x64\xd1\xfe\x36\xe3\x61\x9a\xf8\xd1\x80\x37\x88\xed\xc7\x22\xc7\x96\xfa\x03\x7c\x9d\xa7\x2d\xae\xa6\x79\x8e\x9f\x11\x5e\x03\x53\x03\xfe\xf8\xfb\x30\x75\x9e\xd6\x2c\x7d\x3a\x48\x36\x5c\x3d\x5d\x57\x8e\xdc\x05\xf2\x78\xcc\xbd\xfa\xf9\x3b\xc7\x96\xad\xfb\x28\x8d\x87\xce\x38\x08\xc3\x69\x68\xbf\x7a\x76\x06\xa3\xe9\xc4\xaf\xaf\x67\xe7\xa3\x51\x7d\x79\x3a\xb0\x59\x07\xe7\xc2\xaa\x90\xb6\xb2\x6a\x7f\x68\xba\x4e\x5c\xec\x71\x41\x16\xb2\x52\x7a\x9f\x54\xc2\xf0\xc2\x96\x76\x83\xee\x06\xf5\x54\x27\x6c\x6a\x75\xb4\x67\x51\x03\x25\xba\xc2\x34\xc0\xbc\x2a\xda\x3a\x6f\xbf\x2e\x75\xa8\xfd\x1f\x79\xcd\x94\xe2\x59\xc6\x04\xd6\x9b\x5d\xf3\x0c\x2b\xd3\x91\x24\xfa\x0b\x75\xd7\x96\xf0\xd5\xc5\xdb\x8d\x9f\x00\x6e\xcd\x89\x77\x3e\x8a\xdb\xa9\xa6\xa7\xe0\x0e\x96\xfc\xdd\x1d\x16\xe1\x86\x2d\xb5\x0d\x86\xd8\xcf\xc2\x6c\xfc\x83\xa2\x5f\x82\x6c\x61\xff\x88\x43\xe4\x27\x41\xec\x8f\x31\x62\x0c\x1b\x55\x21\xad\xc9\xee\x8f\x3d\xd6\x71\x07\x10\x09\xcb\x6a\x52\x20\xbe\x2a\x80\x01\x90\xb4\xff\x66\x36\x9a\x86\x7e\xb2\xe5\xf9\x1c\x1f\x6e\x11\xe5\x5a\x57\xf7\x93\x43\x32\x41\x14\x9d\xdf\x22\x72\xb4\x4d\xa4\x31\x98\xc0\xae\xdc\xe8\x5b\x44\xb0\xc2\x83\x9b\x15\x99\x33\x96\x39\x27\xbe\x3f\xc4\xca\x61\x5b\x79\x5f\x13\x7c\xdc\x44\x67\x81\x5c\xc7\x2c\xd8\x92\x75\x53\x59\x48\xd5\x21\x4b\x66\x28\x31\x34\x77\x6d\xc6\xfa\x72\x45\x3c\x91\x29\xc9\x33\xf2\x9b\x7d\xf2\x18\xbf\x0b\xf3\xe0\x24\x6d\x39\x08\x76\x22\x05\xbf\x62\xa4\x23\xa4\xa8\x0b\x6c\x9b\xc2\x5b\x7b\x0a\xb6\x1a\xa1\xc5\x74\xda\xac\xd0\x39\x1a\x37\xd1\xd5\x67\xeb\x80\x57\xc6\xae\x59\x21\x4b\xf0\x08\x73\x29\x73\x5b\xf8\x75\x70\xc3\x2e\x0f\xac\x0d\xd4\x07\xc7\x87\x47\x9f\x1e\x1c\x1d\x1d\x44\xb6\x7a\xa6\x3b\x97\xaa\xdb\x5a\x40\x97\x8b\xee\x60\xa1\xe4\x92\x75\x1f\x7d\x8e\x2f\xeb\xe9\x3b\xf1\x99\x3f\xf6\x93\xc1\x74\x34\x0d\x93\xb1\x1f\x7b\x49\xec\x9d\x92\x3e\xf9\xf2\x1b\xf3\xf9\xe3\x47\x9f\x3e\xfa\xb2\x66\xa4\x06\xc1\x5c\xae\x8c\x85\xda\x56\x15\xde\x46\x96\x7b\x2d\x6c\xff\x74\xfc\x62\xdf\x22\x95\x20\x9a\x8d\x3c\x5b\xa9\xd4\xe0\x9c\xa7\x8f\x9e\x3e\x7d\x72\xf8\x14\x19\xac\xb7\x8e\x5f\x6c\x0e\xb3\x8e\x19\x3c\xc0\x10\x80\x59\xb7\xf9\xe1\xf1\xe1\x5d\x4e\x7d\x90\x44\xe8\xcf\xa6\x0f\x92\x00\x94\x9c\xfe\x0a\xc6\x9c\x4c\xe3\x60\x70\x9b\xbd\x1f\x6f\x91\x69\xc7\x57\x1e\xa4\x35\x0d\x4f\xef\xcc\x07\x77\xa8\x29\x5e\xf8\x87\xad\xee\x68\x7b\x5a\x82\xdd\x68\x14\x87\x5f\xb1\x40\xff\x75\x94\xa0\xc0\x3c\x24\xc2\x8d\xd4\x3d\x44\xa9\xf9\xcc\x65\x8b\x0e\x96\x63\x97\xc0\x9a\x66\xc1\xaa\x7b\xc2\x6a\xb3\xf5\x7b\x90\x44\xc5\xd3\x5d\x29\xa8\xbb\xdd\xb0\xd2\xe4\x05\xd5\x3c\x25\xde\x76\x0d\x0d\x66\x5d\xa5\x61\xa9\x69\x08\xd6\x99\xfb\x3a\x14\xfb\xc2\x8b\x82\x01\x16\x97\xdc\x0a\xf6\x6c\x15\xaa\xdc\x4b\xbf\xe7\x6c\x08\xb4\x0a\x97\xd7\x59\x87\xba\x36\xec\xeb\xd3\xd8\x2e\xbb\xf4\xd7\xd1\xcd\x25\x2d\x4b\xac\xa3\x92\x2d\xc8\x93\x16\x54\x03\x3c\x45\x33\xdd\x33\x72\x59\xf4\xb9\xe0\xce\xc5\xba\x45\xaf\xee\xf6\xce\x71\x2e\xf8\xd1\x53\xf1\xce\x19\x79\x13\xb0\xc0\x84\x89\xee\x79\xe4\xfe\x70\xd1\x1d\x4c\xe0\xdf\xb3\x97\xf0\x6f\xfc\xda\xcd\x58\x77\xe8\xbb\x73\xd5\x3d\x09\x5d\x51\x74\x27\x23\xb7\xb8\xee\x8e\x5e\xb9\xaa\xea\x86\xe7\xee\xf7\x69\xf7\xb7\x66\x2e\xd3\x5d\x3f\x72\x4b\xd3\x7d\x11\xba\x65\xd1\x9d\x8d\xdc\xcb\xbc\xfb\xe2\xd4\xe5\xa6\x1b\xc4\xee\x9c\x77\x4f\x02\xd7\xa8\x6e\x1c\xba\xa9\xee\x0e\xbe\x70\xb5\xea\x46\x33\x57\x5f\x77\x23\xdf\xbd\x92\xdd\x97\xa1\x9b\x17\x40\xa1\xba\xea\x9e\x7b\x2e\x13\xdd\xd3\x17\xee\xa2\xea\x9e\x9d\xbb\xfa\xaa\x1b\xbd\x74\x79\xd6\x0d\x86\xee\x9c\x76\x83\xd0\xbd\xe6\xdd\x57\x13\x18\x6b\x16\xe3\x27\x11\x30\x77\x5f\xe4\x05\xd7\x0b\xf7\x97\xff\xe5\x47\x7f\xfd\x17\xff\xea\xaf\x7f\xf2\xa7\xbf\xf8\xfd\xdf\x75\x7f\xf9\xe7\x5f\xfd\xed\x7f\xfa\xd7\xf6\xe6\xef\x7e\xf6\xcf\xfe\xf6\x3f\xfe\xdb\x5f\xfc\xe4\xbf\xfe\xdd\xcf\xfe\xf9\xed\x17\x7f\xf3\xbb\x3f\xfd\xe5\x57\xff\x1e\x5e\x0c\x59\x65\x74\xba\x70\xe7\x8a\x8a\x9f\xff\x31\xe5\xda\x9d\xb0\x8c\xa9\x82\x8a\x4c\xbb\x05\x35\xd7\x9c\xfd\xd5\x1f\x55\xee\xc7\x1f\x7d\xfc\x9d\x8f\x5f\x7d\xfc\xea\xc3\x4f\x3f\xfc\xe4\xc3\x9f\xbb\xbf\xf8\x83\xff\xf0\x8b\x3f\xfc\xcf\x7f\xf3\x27\xff\xce\x65\xba\xa4\x3f\xff\x33\x59\xb8\xa0\x88\xab\xbc\xfa\xf9\x9f\x68\x92\x49\xf2\x42\x51\xcd\xe1\x61\xa1\xaf\xb8\xfb\xe1\xcf\x3e\xfe\x8b\x0f\xff\xf3\xc3\x7f\xfb\xf0\xe3\x8f\x3f\xb2\x34\x5c\x6e\x68\xc1\xa9\x90\xae\xae\xe4\x92\xbb\xf1\xcf\x7f\xa6\xae\x7e\xfe\xc7\xcc\xfd\xcb\xdf\x63\x7f\xf5\x47\x86\x0b\xea\x7e\xfc\xea\xe3\x8f\x3e\xfc\xaf\xba\xb9\xbe\x66\x42\x5f\x51\xf7\xff\xfe\x9b\x3f\xfc\xdf\xff\xe3\x4f\xff\xcf\xef\xff\x77\x37\xa7\x05\xcb\xa5\xfb\xf1\x77\x3e\xfc\xf4\xe3\x8f\x3e\xfc\xf8\xe3\x1f\x7c\xf8\x8b\x8f\x5f\x7d\xfc\x97\x1f\x7e\xfa\xe1\xc7\x6e\xbd\x37\x64\xef\x5c\x60\xa0\xfd\x25\x17\x79\x26\x97\xfb\xee\x98\xe6\x2b\xaa\xdc\xa8\x90\xd7\x4c\xfc\xe5\xef\xc1\x30\x81\xc8\xa4\x60\x9a\x53\xe1\xce\x98\xc2\xdf\x57\x9c\x61\x25\xae\x66\xee\x6c\xbd\x2a\xc7\x46\x05\x2d\x1b\x83\x19\x02\x64\x56\xf2\xf4\x8a\x29\xcb\x56\x3d\x78\x58\x50\xe0\x33\xe4\x2b\xe4\x2f\x07\x99\x8b\xf4\xc9\x0f\x17\x0e\x72\x18\x5e\x76\xe3\xd7\x0e\xfe\xbb\xbe\x43\x8e\xc3\x3f\x4b\xe4\x20\xdb\x81\x1c\x2a\x07\x79\x8f\xf4\x89\x28\x1c\x64\x40\xd2\x27\xc5\xb5\x83\x5c\x48\xfa\x44\x55\x0e\xb2\x22\xe9\x93\xef\x53\x07\xf9\x11\xc6\xd4\x0e\x32\x25\xe9\x13\xfc\x75\x90\x39\xe1\xae\x70\x90\x43\x49\x9f\x5c\xe6\x0e\xb2\x29\xe9\x13\x6e\x1c\xe4\x55\x18\x90\x3b\xc8\xb0\xa8\x63\x1c\xe4\x5a\xd2\x27\xf8\xeb\x20\xf7\x92\x3e\xd1\xca\x41\x16\x86\xcb\x6b\x07\xf9\x98\xf4\xc9\x95\x74\x90\x99\x49\x9f\xe4\x85\x83\x1c\x4d\xfa\xa4\xba\x72\x90\xad\xad\xa0\x9d\xbe\x70\x90\xbd\x49\x9f\x2c\x2a\x07\x79\x1c\x88\x5c\x39\xc8\xe8\x30\x93\xcc\x41\x6e\x47\x15\xe4\x20\xcb\x93\x3e\xb9\xe6\x0e\xf2\x3d\x2e\xc7\x71\x2e\xf0\x6f\x4c\xbd\x73\xa2\xb3\xe9\xeb\xe4\x64\x3a\x8d\xfd\x30\xc1\x10\x4e\x30\x39\x6d\xe9\xae\x08\xbf\x6c\xe1\xf5\x1f\xcd\xaa\xff\xc8\x06\x61\xef\x59\x5a\x35\x61\x6a\x9b\xbf\x95\x86\xa9\x2d\x62\xb1\x3f\x9e\x8d\xbc\xd8\x4f\x30\xc7\x59\xd7\x22\xa1\xca\xfd\x7f\x01\x00\x00\xff\xff\x4c\x49\xa1\x6e\x3d\x4c\x00\x00" func confAppIniBytes() ([]byte, error) { return bindataRead( @@ -324,8 +324,8 @@ func confAppIni() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "conf/app.ini", size: 19431, mode: os.FileMode(0644), modTime: time.Unix(1586157337, 0)} - a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe9, 0xf3, 0x20, 0x28, 0x17, 0xe7, 0x3e, 0x3d, 0x7e, 0x70, 0x12, 0x1f, 0x40, 0x8c, 0x7f, 0xc1, 0x36, 0x23, 0xfb, 0x21, 0x13, 0x17, 0xd, 0x9, 0xa0, 0xab, 0x6a, 0x14, 0xc2, 0x98, 0x75, 0xd3}} + info := bindataFileInfo{name: "conf/app.ini", size: 19517, mode: os.FileMode(0644), modTime: time.Unix(1586521590, 0)} + a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x7, 0xbb, 0x9b, 0xa0, 0xe5, 0x3b, 0xd1, 0xc7, 0x7d, 0x5e, 0x8d, 0xdc, 0xbd, 0xd7, 0x33, 0xa7, 0xb9, 0x99, 0x65, 0xc7, 0x98, 0x8, 0x6c, 0x2d, 0xcf, 0xc4, 0xdd, 0xf3, 0xd8, 0x27, 0xca, 0xaa}} return a, nil } @@ -4904,7 +4904,7 @@ func confLocaleLocale_ruRuIni() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "conf/locale/locale_ru-RU.ini", size: 102489, mode: os.FileMode(0644), modTime: time.Unix(1586160896, 0)} + info := bindataFileInfo{name: "conf/locale/locale_ru-RU.ini", size: 102489, mode: os.FileMode(0644), modTime: time.Unix(1586169337, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x58, 0xc3, 0x29, 0xf4, 0x53, 0x64, 0x3a, 0x5, 0x3d, 0xee, 0xe1, 0x7a, 0x38, 0x95, 0x60, 0x23, 0xc8, 0x8e, 0x75, 0xda, 0xb4, 0x33, 0x65, 0x93, 0x87, 0x43, 0xb0, 0xe, 0x59, 0x64, 0x88, 0xd3}} return a, nil } @@ -4984,7 +4984,7 @@ func confLocaleLocale_trTrIni() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "conf/locale/locale_tr-TR.ini", size: 72421, mode: os.FileMode(0644), modTime: time.Unix(1586160896, 0)} + info := bindataFileInfo{name: "conf/locale/locale_tr-TR.ini", size: 72421, mode: os.FileMode(0644), modTime: time.Unix(1586169337, 0)} a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe5, 0xf5, 0x39, 0x85, 0x96, 0x73, 0x9f, 0xe, 0x47, 0xad, 0x8a, 0x8a, 0x2c, 0x31, 0x0, 0x64, 0x34, 0x48, 0xac, 0x0, 0x22, 0x12, 0x50, 0x29, 0xb1, 0x80, 0x59, 0x5e, 0xe, 0x55, 0x25, 0x16}} return a, nil } diff --git a/internal/conf/static.go b/internal/conf/static.go index 35d1a8f4f..ae153ab3e 100644 --- a/internal/conf/static.go +++ b/internal/conf/static.go @@ -193,11 +193,6 @@ var ( AccessControlAllowOrigin string } - // LFS settings - LFS struct { - ObjectsPath string - } - // Attachment settings Attachment struct { Enabled bool @@ -417,6 +412,14 @@ type DatabaseOpts struct { // Database settings var Database DatabaseOpts +type LFSOpts struct { + Storage string + ObjectsPath string +} + +// LFS settings +var LFS LFSOpts + type i18nConf struct { Langs []string `delim:","` Names []string `delim:","` diff --git a/internal/db/lfs.go b/internal/db/lfs.go index 8ae9e7185..26a24df52 100644 --- a/internal/db/lfs.go +++ b/internal/db/lfs.go @@ -6,15 +6,10 @@ package db import ( "fmt" - "io" - "os" - "path/filepath" "time" "github.com/jinzhu/gorm" - "github.com/pkg/errors" - "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/errutil" "gogs.io/gogs/internal/lfsutil" ) @@ -23,8 +18,8 @@ import ( // // NOTE: All methods are sorted in alphabetical order. type LFSStore interface { - // CreateObject streams io.ReadCloser to target storage and creates a record in database. - CreateObject(repoID int64, oid lfsutil.OID, rc io.ReadCloser, storage lfsutil.Storage) error + // CreateObject creates a LFS object record in database. + CreateObject(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error // GetObjectByOID returns the LFS object with given OID. It returns ErrLFSObjectNotExist // when not found. GetObjectByOID(repoID int64, oid lfsutil.OID) (*LFSObject, error) @@ -48,44 +43,11 @@ type LFSObject struct { CreatedAt time.Time `gorm:"NOT NULL"` } -func (db *lfs) CreateObject(repoID int64, oid lfsutil.OID, rc io.ReadCloser, storage lfsutil.Storage) error { - if storage != lfsutil.StorageLocal { - return errors.New("only local storage is supported") - } - - var ioerr error - fpath := lfsutil.StorageLocalPath(conf.LFS.ObjectsPath, oid) - defer func() { - rc.Close() - - // NOTE: Only remove the file if there is an IO error, it is OK to - // leave the file when the whole operation failed with a DB error, - // a retry on client side can safely overwrite the same file as OID - // is seen as unique to every file. - if ioerr != nil { - _ = os.Remove(fpath) - } - }() - - ioerr = os.MkdirAll(filepath.Dir(fpath), os.ModePerm) - if ioerr != nil { - return errors.Wrap(ioerr, "create directories") - } - w, ioerr := os.Create(fpath) - if ioerr != nil { - return errors.Wrap(ioerr, "create file") - } - defer w.Close() - - written, ioerr := io.Copy(w, rc) - if ioerr != nil { - return errors.Wrap(ioerr, "copy file") - } - +func (db *lfs) CreateObject(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error { object := &LFSObject{ RepoID: repoID, OID: oid, - Size: written, + Size: size, Storage: storage, } return db.DB.Create(object).Error diff --git a/internal/db/mocks.go b/internal/db/mocks.go index b81dab132..8cef2b967 100644 --- a/internal/db/mocks.go +++ b/internal/db/mocks.go @@ -5,7 +5,6 @@ package db import ( - "io" "testing" "gogs.io/gogs/internal/lfsutil" @@ -39,13 +38,13 @@ func SetMockAccessTokensStore(t *testing.T, mock AccessTokensStore) { var _ LFSStore = (*MockLFSStore)(nil) type MockLFSStore struct { - MockCreateObject func(repoID int64, oid lfsutil.OID, rc io.ReadCloser, storage lfsutil.Storage) error + MockCreateObject func(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error MockGetObjectByOID func(repoID int64, oid lfsutil.OID) (*LFSObject, error) MockGetObjectsByOIDs func(repoID int64, oids ...lfsutil.OID) ([]*LFSObject, error) } -func (m *MockLFSStore) CreateObject(repoID int64, oid lfsutil.OID, rc io.ReadCloser, storage lfsutil.Storage) error { - return m.MockCreateObject(repoID, oid, rc, storage) +func (m *MockLFSStore) CreateObject(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error { + return m.MockCreateObject(repoID, oid, size, storage) } func (m *MockLFSStore) GetObjectByOID(repoID int64, oid lfsutil.OID) (*LFSObject, error) { diff --git a/internal/lfsutil/oid.go b/internal/lfsutil/oid.go index 16d0ad3d4..ad19bd5b2 100644 --- a/internal/lfsutil/oid.go +++ b/internal/lfsutil/oid.go @@ -5,6 +5,8 @@ package lfsutil import ( + "github.com/pkg/errors" + "gogs.io/gogs/internal/lazyregexp" ) @@ -15,6 +17,8 @@ type OID string // Spec: https://github.com/git-lfs/git-lfs/blob/master/docs/spec.md var oidRe = lazyregexp.New("^[a-f0-9]{64}$") +var ErrInvalidOID = errors.New("OID is not valid") + // ValidOID returns true if given oid is valid. func ValidOID(oid OID) bool { return oidRe.MatchString(string(oid)) diff --git a/internal/lfsutil/storage.go b/internal/lfsutil/storage.go index b2bfe37f8..a357b8a8c 100644 --- a/internal/lfsutil/storage.go +++ b/internal/lfsutil/storage.go @@ -5,9 +5,31 @@ package lfsutil import ( + "io" + "os" "path/filepath" + + "github.com/pkg/errors" + + "gogs.io/gogs/internal/osutil" ) +var ErrObjectNotExist = errors.New("Object does not exist") + +// Storager is an storage backend for uploading and downloading LFS objects. +type Storager interface { + // Storage returns the name of the storage backend. + Storage() Storage + // Upload reads content from the io.ReadCloser and uploads as given oid. + // The reader is closed once upload is finished. ErrInvalidOID is returned + // if the given oid is not valid. + Upload(oid OID, rc io.ReadCloser) (int64, error) + // Download streams content of given oid to the io.Writer. It is caller's + // responsibility the close the writer when needed. ErrObjectNotExist is + // returned if the given oid does not exist. + Download(oid OID, w io.Writer) error +} + // Storage is the storage type of an LFS object. type Storage string @@ -15,12 +37,73 @@ const ( StorageLocal Storage = "local" ) -// StorageLocalPath returns computed file path for storing object on local file system. -// It returns empty string if given "oid" isn't valid. -func StorageLocalPath(root string, oid OID) string { - if !ValidOID(oid) { +var _ Storager = (*LocalStorage)(nil) + +// LocalStorage is a LFS storage backend on local file system. +type LocalStorage struct { + // The root path for storing LFS objects. + Root string +} + +func (s *LocalStorage) Storage() Storage { + return StorageLocal +} + +func (s *LocalStorage) storagePath(oid OID) string { + if len(oid) < 2 { return "" } - return filepath.Join(root, string(oid[0]), string(oid[1]), string(oid)) + return filepath.Join(s.Root, string(oid[0]), string(oid[1]), string(oid)) +} + +func (s *LocalStorage) Upload(oid OID, rc io.ReadCloser) (int64, error) { + if !ValidOID(oid) { + return 0, ErrInvalidOID + } + + var err error + fpath := s.storagePath(oid) + defer func() { + rc.Close() + + if err != nil { + _ = os.Remove(fpath) + } + }() + + err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm) + if err != nil { + return 0, errors.Wrap(err, "create directories") + } + w, err := os.Create(fpath) + if err != nil { + return 0, errors.Wrap(err, "create file") + } + defer w.Close() + + written, err := io.Copy(w, rc) + if err != nil { + return 0, errors.Wrap(err, "copy file") + } + return written, nil +} + +func (s *LocalStorage) Download(oid OID, w io.Writer) error { + fpath := s.storagePath(oid) + if !osutil.IsFile(fpath) { + return ErrObjectNotExist + } + + r, err := os.Open(fpath) + if err != nil { + return errors.Wrap(err, "open file") + } + defer r.Close() + + _, err = io.Copy(w, r) + if err != nil { + return errors.Wrap(err, "copy file") + } + return nil } diff --git a/internal/lfsutil/storage_test.go b/internal/lfsutil/storage_test.go index bfb69e4a9..867027589 100644 --- a/internal/lfsutil/storage_test.go +++ b/internal/lfsutil/storage_test.go @@ -5,39 +5,130 @@ package lfsutil import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" "runtime" + "strings" "testing" "github.com/stretchr/testify/assert" ) -func TestStorageLocalPath(t *testing.T) { +func TestLocalStorage_storagePath(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Skipping testing on Windows") return } + s := &LocalStorage{ + Root: "/lfs-objects", + } + tests := []struct { name string - root string oid OID expPath string }{ { - name: "invalid oid", - oid: OID("bad_oid"), + name: "empty oid", + oid: "", }, { name: "valid oid", - root: "/lfs-objects", - oid: OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"), + oid: "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", expPath: "/lfs-objects/e/f/ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - assert.Equal(t, test.expPath, StorageLocalPath(test.root, test.oid)) + assert.Equal(t, test.expPath, s.storagePath(test.oid)) + }) + } +} + +func TestLocalStorage_Upload(t *testing.T) { + s := &LocalStorage{ + Root: filepath.Join(os.TempDir(), "lfs-objects"), + } + t.Cleanup(func() { + _ = os.RemoveAll(s.Root) + }) + + tests := []struct { + name string + oid OID + content string + expWritten int64 + expErr error + }{ + { + name: "invalid oid", + oid: "bad_oid", + expErr: ErrInvalidOID, + }, + + { + name: "valid oid", + oid: "ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", + content: "Hello world!", + expWritten: 12, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + written, err := s.Upload(test.oid, ioutil.NopCloser(strings.NewReader(test.content))) + assert.Equal(t, test.expWritten, written) + assert.Equal(t, test.expErr, err) + }) + } +} + +func TestLocalStorage_Download(t *testing.T) { + oid := OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f") + s := &LocalStorage{ + Root: filepath.Join(os.TempDir(), "lfs-objects"), + } + t.Cleanup(func() { + _ = os.RemoveAll(s.Root) + }) + + fpath := s.storagePath(oid) + err := os.MkdirAll(filepath.Dir(fpath), os.ModePerm) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(fpath, []byte("Hello world!"), os.ModePerm) + if err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + oid OID + expContent string + expErr error + }{ + { + name: "object not exists", + oid: "bad_oid", + expErr: ErrObjectNotExist, + }, + + { + name: "valid oid", + oid: oid, + expContent: "Hello world!", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var buf bytes.Buffer + err := s.Download(test.oid, &buf) + assert.Equal(t, test.expContent, buf.String()) + assert.Equal(t, test.expErr, err) }) } } diff --git a/internal/route/lfs/basic.go b/internal/route/lfs/basic.go index f0c2dc8bd..626f5ff08 100644 --- a/internal/route/lfs/basic.go +++ b/internal/route/lfs/basic.go @@ -9,13 +9,11 @@ import ( "io" "io/ioutil" "net/http" - "os" "strconv" "gopkg.in/macaron.v1" log "unknwon.dev/clog/v2" - "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/db" "gogs.io/gogs/internal/lfsutil" "gogs.io/gogs/internal/strutil" @@ -27,8 +25,25 @@ const ( basicOperationDownload = "download" ) +type basicHandler struct { + // The default storage backend for uploading new objects. + defaultStorage lfsutil.Storage + // The list of available storage backends to access objects. + storagers map[lfsutil.Storage]lfsutil.Storager +} + +// DefaultStorager returns the default storage backend. +func (h *basicHandler) DefaultStorager() lfsutil.Storager { + return h.storagers[h.defaultStorage] +} + +// Storager returns the given storage backend. +func (h *basicHandler) Storager(storage lfsutil.Storage) lfsutil.Storager { + return h.storagers[storage] +} + // GET /{owner}/{repo}.git/info/lfs/object/basic/{oid} -func serveBasicDownload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) { +func (h *basicHandler) serveDownload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) { object, err := db.LFS.GetObjectByOID(repo.ID, oid) if err != nil { if db.IsErrLFSObjectNotExist(err) { @@ -42,28 +57,26 @@ func serveBasicDownload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID return } - fpath := lfsutil.StorageLocalPath(conf.LFS.ObjectsPath, object.OID) - r, err := os.Open(fpath) - if err != nil { + s := h.Storager(object.Storage) + if s == nil { internalServerError(c.Resp) - log.Error("Failed to open object file [path: %s]: %v", fpath, err) + log.Error("Failed to locate the object [repo_id: %d, oid: %s]: storage %q not found", object.RepoID, object.OID, object.Storage) return } - defer r.Close() c.Header().Set("Content-Type", "application/octet-stream") c.Header().Set("Content-Length", strconv.FormatInt(object.Size, 10)) c.Status(http.StatusOK) - _, err = io.Copy(c.Resp, r) + err = s.Download(object.OID, c.Resp) if err != nil { - log.Error("Failed to copy object file: %v", err) + log.Error("Failed to download object [oid: %s]: %v", object.OID, err) return } } // PUT /{owner}/{repo}.git/info/lfs/object/basic/{oid} -func serveBasicUpload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) { +func (h *basicHandler) serveUpload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) { // NOTE: LFS client will retry upload the same object if there was a partial failure, // therefore we would like to skip ones that already exist. _, err := db.LFS.GetObjectByOID(repo.ID, oid) @@ -79,8 +92,25 @@ func serveBasicUpload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) return } - err = db.LFS.CreateObject(repo.ID, oid, c.Req.Request.Body, lfsutil.StorageLocal) + s := h.DefaultStorager() + written, err := s.Upload(oid, c.Req.Request.Body) if err != nil { + if err == lfsutil.ErrInvalidOID { + responseJSON(c.Resp, http.StatusBadRequest, responseError{ + Message: err.Error(), + }) + } else { + internalServerError(c.Resp) + log.Error("Failed to upload object [storage: %s, oid: %s]: %v", s.Storage(), oid, err) + } + return + } + + err = db.LFS.CreateObject(repo.ID, oid, written, s.Storage()) + if err != nil { + // NOTE: It is OK to leave the file when the whole operation failed + // with a DB error, a retry on client side can safely overwrite the + // same file as OID is seen as unique to every file. internalServerError(c.Resp) log.Error("Failed to create object [repo_id: %d, oid: %s]: %v", repo.ID, oid, err) return @@ -91,7 +121,7 @@ func serveBasicUpload(c *macaron.Context, repo *db.Repository, oid lfsutil.OID) } // POST /{owner}/{repo}.git/info/lfs/object/basic/verify -func serveBasicVerify(c *macaron.Context, repo *db.Repository) { +func (h *basicHandler) serveVerify(c *macaron.Context, repo *db.Repository) { var request basicVerifyRequest defer c.Req.Request.Body.Close() err := json.NewDecoder(c.Req.Request.Body).Decode(&request) @@ -109,7 +139,7 @@ func serveBasicVerify(c *macaron.Context, repo *db.Repository) { return } - object, err := db.LFS.GetObjectByOID(repo.ID, lfsutil.OID(request.Oid)) + object, err := db.LFS.GetObjectByOID(repo.ID, request.Oid) if err != nil { if db.IsErrLFSObjectNotExist(err) { responseJSON(c.Resp, http.StatusNotFound, responseError{ @@ -123,7 +153,7 @@ func serveBasicVerify(c *macaron.Context, repo *db.Repository) { } if object.Size != request.Size { - responseJSON(c.Resp, http.StatusNotFound, responseError{ + responseJSON(c.Resp, http.StatusBadRequest, responseError{ Message: "Object size mismatch", }) return diff --git a/internal/route/lfs/basic_test.go b/internal/route/lfs/basic_test.go new file mode 100644 index 000000000..db2fbe616 --- /dev/null +++ b/internal/route/lfs/basic_test.go @@ -0,0 +1,288 @@ +// Copyright 2020 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package lfs + +import ( + "bytes" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "gopkg.in/macaron.v1" + + "gogs.io/gogs/internal/db" + "gogs.io/gogs/internal/lfsutil" +) + +var _ lfsutil.Storager = (*mockStorage)(nil) + +// mockStorage is a in-memory storage for LFS objects. +type mockStorage struct { + buf *bytes.Buffer +} + +func (s *mockStorage) Storage() lfsutil.Storage { + return "memory" +} + +func (s *mockStorage) Upload(oid lfsutil.OID, rc io.ReadCloser) (int64, error) { + defer rc.Close() + return io.Copy(s.buf, rc) +} + +func (s *mockStorage) Download(oid lfsutil.OID, w io.Writer) error { + _, err := io.Copy(w, s.buf) + return err +} + +func Test_basicHandler_serveDownload(t *testing.T) { + s := &mockStorage{} + basic := &basicHandler{ + defaultStorage: s.Storage(), + storagers: map[lfsutil.Storage]lfsutil.Storager{ + s.Storage(): s, + }, + } + + m := macaron.New() + m.Use(macaron.Renderer()) + m.Use(func(c *macaron.Context) { + c.Map(&db.Repository{Name: "repo"}) + c.Map(lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f")) + }) + m.Get("/", basic.serveDownload) + + tests := []struct { + name string + content string + mockLFSStore *db.MockLFSStore + expStatusCode int + expHeader http.Header + expBody string + }{ + { + name: "object does not exist", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return nil, db.ErrLFSObjectNotExist{} + }, + }, + expStatusCode: http.StatusNotFound, + expHeader: http.Header{ + "Content-Type": []string{"application/vnd.git-lfs+json"}, + }, + expBody: `{"message":"Object does not exist"}` + "\n", + }, + { + name: "storage not found", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{Storage: "bad_storage"}, nil + }, + }, + expStatusCode: http.StatusInternalServerError, + expHeader: http.Header{ + "Content-Type": []string{"application/vnd.git-lfs+json"}, + }, + expBody: `{"message":"Internal server error"}` + "\n", + }, + + { + name: "object exists", + content: "Hello world!", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{ + Size: 12, + Storage: s.Storage(), + }, nil + }, + }, + expStatusCode: http.StatusOK, + expHeader: http.Header{ + "Content-Type": []string{"application/octet-stream"}, + "Content-Length": []string{"12"}, + }, + expBody: "Hello world!", + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + db.SetMockLFSStore(t, test.mockLFSStore) + + s.buf = bytes.NewBufferString(test.content) + + r, err := http.NewRequest("GET", "/", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + m.ServeHTTP(rr, r) + + resp := rr.Result() + assert.Equal(t, test.expStatusCode, resp.StatusCode) + assert.Equal(t, test.expHeader, resp.Header) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expBody, string(body)) + }) + } +} + +func Test_basicHandler_serveUpload(t *testing.T) { + s := &mockStorage{buf: &bytes.Buffer{}} + basic := &basicHandler{ + defaultStorage: s.Storage(), + storagers: map[lfsutil.Storage]lfsutil.Storager{ + s.Storage(): s, + }, + } + + m := macaron.New() + m.Use(macaron.Renderer()) + m.Use(func(c *macaron.Context) { + c.Map(&db.Repository{Name: "repo"}) + c.Map(lfsutil.OID("ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f")) + }) + m.Put("/", basic.serveUpload) + + tests := []struct { + name string + mockLFSStore *db.MockLFSStore + expStatusCode int + expBody string + }{ + { + name: "object already exists", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{}, nil + }, + }, + expStatusCode: http.StatusOK, + }, + { + name: "new object", + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return nil, db.ErrLFSObjectNotExist{} + }, + MockCreateObject: func(repoID int64, oid lfsutil.OID, size int64, storage lfsutil.Storage) error { + return nil + }, + }, + expStatusCode: http.StatusOK, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + db.SetMockLFSStore(t, test.mockLFSStore) + + r, err := http.NewRequest("PUT", "/", strings.NewReader("Hello world!")) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + m.ServeHTTP(rr, r) + + resp := rr.Result() + assert.Equal(t, test.expStatusCode, resp.StatusCode) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expBody, string(body)) + }) + } +} + +func Test_basicHandler_serveVerify(t *testing.T) { + m := macaron.New() + m.Use(macaron.Renderer()) + m.Use(func(c *macaron.Context) { + c.Map(&db.Repository{Name: "repo"}) + }) + m.Post("/", (&basicHandler{}).serveVerify) + + tests := []struct { + name string + body string + mockLFSStore *db.MockLFSStore + expStatusCode int + expBody string + }{ + { + name: "invalid oid", + body: `{"oid": "bad_oid"}`, + expStatusCode: http.StatusBadRequest, + expBody: `{"message":"Invalid oid"}` + "\n", + }, + { + name: "object does not exist", + body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"}`, + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return nil, db.ErrLFSObjectNotExist{} + }, + }, + expStatusCode: http.StatusNotFound, + expBody: `{"message":"Object does not exist"}` + "\n", + }, + { + name: "object size mismatch", + body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f"}`, + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{Size: 12}, nil + }, + }, + expStatusCode: http.StatusBadRequest, + expBody: `{"message":"Object size mismatch"}` + "\n", + }, + + { + name: "object exists", + body: `{"oid":"ef797c8118f02dfb649607dd5d3f8c7623048c9c063d532cc95c5ed7a898a64f", "size":12}`, + mockLFSStore: &db.MockLFSStore{ + MockGetObjectByOID: func(repoID int64, oid lfsutil.OID) (*db.LFSObject, error) { + return &db.LFSObject{Size: 12}, nil + }, + }, + expStatusCode: http.StatusOK, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + db.SetMockLFSStore(t, test.mockLFSStore) + + r, err := http.NewRequest("POST", "/", strings.NewReader(test.body)) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + m.ServeHTTP(rr, r) + + resp := rr.Result() + assert.Equal(t, test.expStatusCode, resp.StatusCode) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, test.expBody, string(body)) + }) + } +} diff --git a/internal/route/lfs/batch_test.go b/internal/route/lfs/batch_test.go index 7dce20045..61cfb562c 100644 --- a/internal/route/lfs/batch_test.go +++ b/internal/route/lfs/batch_test.go @@ -23,6 +23,7 @@ func Test_serveBatch(t *testing.T) { conf.SetMockServer(t, conf.ServerOpts{ ExternalURL: "https://gogs.example.com/", }) + m := macaron.New() m.Use(func(c *macaron.Context) { c.Map(&db.User{Name: "owner"}) diff --git a/internal/route/lfs/main_test.go b/internal/route/lfs/main_test.go new file mode 100644 index 000000000..ddc04c1b4 --- /dev/null +++ b/internal/route/lfs/main_test.go @@ -0,0 +1,30 @@ +// Copyright 2020 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package lfs + +import ( + "flag" + "fmt" + "os" + "testing" + + log "unknwon.dev/clog/v2" + + "gogs.io/gogs/internal/testutil" +) + +func TestMain(m *testing.M) { + flag.Parse() + if !testing.Verbose() { + // Remove the primary logger and register a noop logger. + log.Remove(log.DefaultConsoleName) + err := log.New("noop", testutil.InitNoopLogger) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } + os.Exit(m.Run()) +} diff --git a/internal/route/lfs/route.go b/internal/route/lfs/route.go index 08045ac55..164788032 100644 --- a/internal/route/lfs/route.go +++ b/internal/route/lfs/route.go @@ -13,6 +13,7 @@ import ( log "unknwon.dev/clog/v2" "gogs.io/gogs/internal/authutil" + "gogs.io/gogs/internal/conf" "gogs.io/gogs/internal/db" "gogs.io/gogs/internal/lfsutil" ) @@ -26,10 +27,17 @@ func RegisterRoutes(r *macaron.Router) { r.Group("", func() { r.Post("/objects/batch", authorize(db.AccessModeRead), verifyAccept, verifyContentTypeJSON, serveBatch) r.Group("/objects/basic", func() { + + basic := &basicHandler{ + defaultStorage: lfsutil.Storage(conf.LFS.Storage), + storagers: map[lfsutil.Storage]lfsutil.Storager{ + lfsutil.StorageLocal: &lfsutil.LocalStorage{Root: conf.LFS.ObjectsPath}, + }, + } r.Combo("/:oid", verifyOID()). - Get(authorize(db.AccessModeRead), serveBasicDownload). - Put(authorize(db.AccessModeWrite), verifyContentTypeStream, serveBasicUpload) - r.Post("/verify", authorize(db.AccessModeWrite), verifyAccept, verifyContentTypeJSON, serveBasicVerify) + Get(authorize(db.AccessModeRead), basic.serveDownload). + Put(authorize(db.AccessModeWrite), verifyContentTypeStream, basic.serveUpload) + r.Post("/verify", authorize(db.AccessModeWrite), verifyAccept, verifyContentTypeJSON, basic.serveVerify) }) }, authenticate()) } diff --git a/internal/testutil/noop_logger.go b/internal/testutil/noop_logger.go new file mode 100644 index 000000000..bf536f3f0 --- /dev/null +++ b/internal/testutil/noop_logger.go @@ -0,0 +1,31 @@ +// Copyright 2020 The Gogs Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package testutil + +import ( + log "unknwon.dev/clog/v2" +) + +var _ log.Logger = (*noopLogger)(nil) + +// noopLogger is a placeholder logger that logs nothing. +type noopLogger struct{} + +func (l *noopLogger) Name() string { + return "noop" +} + +func (l *noopLogger) Level() log.Level { + return log.LevelTrace +} + +func (l *noopLogger) Write(log.Messager) error { + return nil +} + +// InitNoopLogger is a init function to initialize a noop logger. +var InitNoopLogger = func(name string, vs ...interface{}) (log.Logger, error) { + return &noopLogger{}, nil +}