From 7c0c383d10a08c883159185e70223b14a1264742 Mon Sep 17 00:00:00 2001 From: mds-dwa Date: Wed, 12 Jun 2019 18:07:41 -0700 Subject: [PATCH 1/5] Release version 0.5.0 [BUG] Support spaces in file names on Windows [BUG] Prompt to save modifications before history changes [BUG] Handle query strings properly during URL expansion [ENH] Support Tab/Shift+Tab indentation of selected lines [ENH] Set window icon for MacOS and add repository logo for SourceTree/GitLab Signed-off-by: mds-dwa --- docs/keyboardShortcuts.rst | 5 +- logo.png | Bin 0 -> 4306 bytes usdmanager/__init__.py | 423 ++++++++++++++++++++---------------- usdmanager/images/logo.png | Bin 3237 -> 3478 bytes usdmanager/images_rc.py | 429 +++++++++++++++++++------------------ usdmanager/utils.py | 38 ++++ usdmanager/version.py | 2 +- 7 files changed, 504 insertions(+), 393 deletions(-) create mode 100644 logo.png diff --git a/docs/keyboardShortcuts.rst b/docs/keyboardShortcuts.rst index 5eb387a..aff5ddf 100644 --- a/docs/keyboardShortcuts.rst +++ b/docs/keyboardShortcuts.rst @@ -106,4 +106,7 @@ For ease of use, there are some extra shortcuts not shown in the menus themselve - Ctrl+Shift+Tab * - Reload - F5 - + * - Indent (if text is selected) + - Tab + * - Unindent (if text is selected) + - Shift+Tab diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d5fca774f5af043fa5b3c8c03ed02ba71486d0b GIT binary patch literal 4306 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

ZWY!as}lkUHXhwx-tE|; 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 NfHt*8l^dUp{5SIRl|29e diff --git a/usdmanager/images_rc.py b/usdmanager/images_rc.py index 5db0cd2..567f32b 100644 --- a/usdmanager/images_rc.py +++ b/usdmanager/images_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt (Qt v4.6.2) +# Created by: The Resource Compiler for PyQt (Qt v4.8.5) # # WARNING! All changes made in this file will be lost! @@ -58,211 +58,226 @@ \xa5\x94\x52\x96\x25\x85\x10\x42\x4a\x29\x84\x10\xef\x97\x97\x97\ \xc9\xc0\xc0\x80\xfa\x0d\xea\xc1\x0a\x11\xec\x45\x65\x41\x00\x00\ \x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -\x00\x00\x0c\xa5\ +\x00\x00\x0d\x96\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ -\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\x74\x77\x61\x72\x65\ -\x00\x41\x64\x6f\x62\x65\x20\x49\x6d\x61\x67\x65\x52\x65\x61\x64\ -\x79\x71\xc9\x65\x3c\x00\x00\x03\x28\x69\x54\x58\x74\x58\x4d\x4c\ -\x3a\x63\x6f\x6d\x2e\x61\x64\x6f\x62\x65\x2e\x78\x6d\x70\x00\x00\ -\x00\x00\x00\x3c\x3f\x78\x70\x61\x63\x6b\x65\x74\x20\x62\x65\x67\ -\x69\x6e\x3d\x22\xef\xbb\xbf\x22\x20\x69\x64\x3d\x22\x57\x35\x4d\ -\x30\x4d\x70\x43\x65\x68\x69\x48\x7a\x72\x65\x53\x7a\x4e\x54\x63\ -\x7a\x6b\x63\x39\x64\x22\x3f\x3e\x20\x3c\x78\x3a\x78\x6d\x70\x6d\ -\x65\x74\x61\x20\x78\x6d\x6c\x6e\x73\x3a\x78\x3d\x22\x61\x64\x6f\ -\x62\x65\x3a\x6e\x73\x3a\x6d\x65\x74\x61\x2f\x22\x20\x78\x3a\x78\ -\x6d\x70\x74\x6b\x3d\x22\x41\x64\x6f\x62\x65\x20\x58\x4d\x50\x20\ -\x43\x6f\x72\x65\x20\x35\x2e\x36\x2d\x63\x31\x34\x35\x20\x37\x39\ -\x2e\x31\x36\x33\x34\x39\x39\x2c\x20\x32\x30\x31\x38\x2f\x30\x38\ -\x2f\x31\x33\x2d\x31\x36\x3a\x34\x30\x3a\x32\x32\x20\x20\x20\x20\ -\x20\x20\x20\x20\x22\x3e\x20\x3c\x72\x64\x66\x3a\x52\x44\x46\x20\ -\x78\x6d\x6c\x6e\x73\x3a\x72\x64\x66\x3d\x22\x68\x74\x74\x70\x3a\ -\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x31\x39\x39\ -\x39\x2f\x30\x32\x2f\x32\x32\x2d\x72\x64\x66\x2d\x73\x79\x6e\x74\ -\x61\x78\x2d\x6e\x73\x23\x22\x3e\x20\x3c\x72\x64\x66\x3a\x44\x65\ -\x73\x63\x72\x69\x70\x74\x69\x6f\x6e\x20\x72\x64\x66\x3a\x61\x62\ -\x6f\x75\x74\x3d\x22\x22\x20\x78\x6d\x6c\x6e\x73\x3a\x78\x6d\x70\ -\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x6e\x73\x2e\x61\x64\x6f\x62\ -\x65\x2e\x63\x6f\x6d\x2f\x78\x61\x70\x2f\x31\x2e\x30\x2f\x22\x20\ -\x78\x6d\x6c\x6e\x73\x3a\x78\x6d\x70\x4d\x4d\x3d\x22\x68\x74\x74\ -\x70\x3a\x2f\x2f\x6e\x73\x2e\x61\x64\x6f\x62\x65\x2e\x63\x6f\x6d\ -\x2f\x78\x61\x70\x2f\x31\x2e\x30\x2f\x6d\x6d\x2f\x22\x20\x78\x6d\ -\x6c\x6e\x73\x3a\x73\x74\x52\x65\x66\x3d\x22\x68\x74\x74\x70\x3a\ -\x2f\x2f\x6e\x73\x2e\x61\x64\x6f\x62\x65\x2e\x63\x6f\x6d\x2f\x78\ -\x61\x70\x2f\x31\x2e\x30\x2f\x73\x54\x79\x70\x65\x2f\x52\x65\x73\ -\x6f\x75\x72\x63\x65\x52\x65\x66\x23\x22\x20\x78\x6d\x70\x3a\x43\ -\x72\x65\x61\x74\x6f\x72\x54\x6f\x6f\x6c\x3d\x22\x41\x64\x6f\x62\ -\x65\x20\x50\x68\x6f\x74\x6f\x73\x68\x6f\x70\x20\x43\x43\x20\x32\ -\x30\x31\x39\x20\x28\x4d\x61\x63\x69\x6e\x74\x6f\x73\x68\x29\x22\ -\x20\x78\x6d\x70\x4d\x4d\x3a\x49\x6e\x73\x74\x61\x6e\x63\x65\x49\ -\x44\x3d\x22\x78\x6d\x70\x2e\x69\x69\x64\x3a\x37\x32\x33\x38\x34\ -\x31\x46\x39\x32\x44\x42\x39\x31\x31\x45\x39\x42\x37\x33\x43\x45\ -\x41\x34\x39\x42\x46\x39\x33\x33\x44\x34\x41\x22\x20\x78\x6d\x70\ -\x4d\x4d\x3a\x44\x6f\x63\x75\x6d\x65\x6e\x74\x49\x44\x3d\x22\x78\ -\x6d\x70\x2e\x64\x69\x64\x3a\x37\x32\x33\x38\x34\x31\x46\x41\x32\ -\x44\x42\x39\x31\x31\x45\x39\x42\x37\x33\x43\x45\x41\x34\x39\x42\ -\x46\x39\x33\x33\x44\x34\x41\x22\x3e\x20\x3c\x78\x6d\x70\x4d\x4d\ -\x3a\x44\x65\x72\x69\x76\x65\x64\x46\x72\x6f\x6d\x20\x73\x74\x52\ -\x65\x66\x3a\x69\x6e\x73\x74\x61\x6e\x63\x65\x49\x44\x3d\x22\x78\ -\x6d\x70\x2e\x69\x69\x64\x3a\x37\x32\x33\x38\x34\x31\x46\x37\x32\ -\x44\x42\x39\x31\x31\x45\x39\x42\x37\x33\x43\x45\x41\x34\x39\x42\ -\x46\x39\x33\x33\x44\x34\x41\x22\x20\x73\x74\x52\x65\x66\x3a\x64\ -\x6f\x63\x75\x6d\x65\x6e\x74\x49\x44\x3d\x22\x78\x6d\x70\x2e\x64\ -\x69\x64\x3a\x37\x32\x33\x38\x34\x31\x46\x38\x32\x44\x42\x39\x31\ -\x31\x45\x39\x42\x37\x33\x43\x45\x41\x34\x39\x42\x46\x39\x33\x33\ -\x44\x34\x41\x22\x2f\x3e\x20\x3c\x2f\x72\x64\x66\x3a\x44\x65\x73\ -\x63\x72\x69\x70\x74\x69\x6f\x6e\x3e\x20\x3c\x2f\x72\x64\x66\x3a\ -\x52\x44\x46\x3e\x20\x3c\x2f\x78\x3a\x78\x6d\x70\x6d\x65\x74\x61\ -\x3e\x20\x3c\x3f\x78\x70\x61\x63\x6b\x65\x74\x20\x65\x6e\x64\x3d\ -\x22\x72\x22\x3f\x3e\x35\xc2\xef\x77\x00\x00\x09\x13\x49\x44\x41\ -\x54\x78\xda\xdc\x5b\x7d\x70\x54\xd5\x15\x3f\x77\x77\xb3\xf9\xd6\ -\x24\x18\x83\x42\x98\x88\xc4\xb8\x49\xa6\x40\x11\x50\x1c\x51\x19\ -\x12\xa9\xfe\x61\x1d\x5b\x67\x8a\x32\x6d\xc9\xd8\x69\x8b\x98\x44\ -\x8a\xe3\xe8\x8c\xa8\x7f\x38\x8e\x22\x89\x8a\xd3\xd6\x42\x46\xa5\ -\x2d\xce\xa8\x53\x75\xa6\x83\xec\x6a\x4b\x23\x52\x28\xb4\xc0\x40\ -\x12\xc2\x44\x89\x7c\x94\x40\xa2\x41\x21\x09\x59\x76\xdf\xf5\x77\ -\xee\x7b\x2f\x1f\x9b\xfd\x78\x1b\x92\xdd\x97\xdc\x99\xb7\x77\xdf\ -\x7d\xf7\xeb\x77\xce\xb9\xe7\x9e\x73\xde\x7d\x42\x4a\x49\x56\x92\ -\x10\x82\xc6\x24\xd5\xfa\x88\xea\x2a\x38\xbf\x07\x77\xbf\xc2\x55\ -\xa6\x3f\x90\x4d\x18\xe5\x0d\x3c\xfb\xfb\x40\x9d\x51\x26\xab\x98\ -\x14\xae\x84\x12\x60\x00\xbc\xd7\x8b\x1e\x43\x11\xf2\x44\x78\x10\ -\x1f\xea\x54\x52\x0d\xea\xd6\x57\x8c\x3b\x01\x1c\x94\xc8\xa4\x73\ -\x7e\x3b\x49\xb1\x34\x1c\x8d\x8d\x7c\x29\xea\x6c\x8b\x0a\x9e\x09\ -\x19\xed\x3e\x8e\x94\x58\x02\xd4\x78\xa7\x80\x3d\x95\x80\x1a\x4d\ -\x9c\xf8\xd9\x32\x48\xc9\xb5\x11\x81\x4b\xfa\x19\xfa\xda\x0a\x29\ -\xf9\x27\xae\x77\x70\xff\xa0\xfe\xdc\x1b\xf7\x94\x12\xbc\x04\xbc\ -\x1b\xc1\xfd\xdf\xc6\x20\x80\x12\x62\x8c\x58\x07\x89\x59\x33\xa4\ -\x2d\xff\xce\x40\xfb\xfd\x98\x75\x1e\x72\x69\xf4\x63\x2e\x9d\x4e\ -\x34\xbb\x09\x13\x3d\x2e\x37\x2c\xb5\xa9\x04\x90\x58\x12\x1b\xbc\ -\x4e\x6e\x80\xb9\x33\x84\xf3\x98\xab\xf8\x02\xad\x73\x15\xde\xc1\ -\x7e\xcc\xfc\x2a\x34\x6b\x07\x39\xae\xb4\xef\x12\x90\xf2\x6c\x1c\ -\xc4\x3a\x3b\x4c\x77\x90\xf8\x17\x7e\x5c\x43\x00\x87\xd7\x21\x82\ -\xde\xb0\x2f\x01\x84\x58\x0f\x0e\x59\x59\x73\x2c\xde\xaf\x85\x94\ -\xcd\xb7\x32\x02\xae\xfb\xed\x49\x00\x25\xc6\x72\x1b\xd6\xaf\xb0\ -\xb0\x87\xf1\x12\xf0\x41\xd1\x99\x6d\xc1\x79\x99\x6a\x71\x24\xa7\ -\x7d\x95\xa0\xbe\x13\xcc\x46\x67\x07\x86\x28\xaf\xa1\x7c\x37\x15\ -\xdb\x1c\x88\xfd\xc1\x10\x02\x5a\xde\xdc\xa1\x04\x85\x3d\x97\x00\ -\xa7\xfa\x4a\x00\x93\x6c\xfd\xb5\x29\x65\xcf\x1c\xd0\x73\x26\x07\ -\x97\x79\x46\x80\xd7\x89\x73\xde\x20\x5a\xac\xd4\x1b\xcf\x74\x5c\ -\x94\x8c\x54\x57\xd9\x8c\xdf\x1b\xa6\x6d\xd8\xb7\x06\xe8\xd7\x73\ -\x91\x16\x94\x55\x1d\x6b\x17\x34\x44\xe1\xeb\x87\x80\xff\x10\x45\ -\x93\x44\x45\x44\xb1\xc9\xfe\x04\x30\xd2\x15\x39\xe9\x5f\x0f\xb9\ -\x3d\xdd\x11\xa6\x8e\x67\x33\xbb\x08\x94\x05\xdc\xf7\xb5\x36\x75\ -\xc8\x60\x20\x28\x22\x10\x01\xcb\x47\x9c\x41\x56\x6d\xdf\x5d\x20\ -\xce\xe4\xd9\x7c\x98\xb5\x54\x36\x56\x49\x97\xa6\xc9\x8c\xe2\xd2\ -\x02\x4a\xcf\x4c\xed\x53\x9c\xd6\x57\xc3\xd0\x25\xb1\x03\x77\x45\ -\x44\xf1\xe9\x2a\xdb\x12\xe0\x46\x05\x5e\xa4\xe3\xa7\x13\x0a\xd8\ -\xad\x94\xb0\xa4\x9e\x9f\xac\x98\x9f\x83\xf2\x12\x94\xaf\xc5\xfd\ -\x06\x10\xe3\x71\x54\x2f\x81\xde\x58\x82\xbc\x3f\x5e\x2f\xd2\x65\ -\x4f\xf0\x4d\xcc\x5c\x37\x7e\xce\xe1\x72\x1b\x9c\xee\xc1\x55\xb0\ -\x77\xd7\x31\x3f\x40\x1e\xc5\xff\xf5\x23\x15\x6c\xfc\xde\xa3\xed\ -\x24\xe0\xc6\x86\x26\x16\xe2\x54\x70\xfc\x5b\x83\x08\x0c\xbe\x1f\ -\xca\xf2\x6a\x94\xf5\x1e\x59\x59\x36\xa6\xe3\x25\x55\x02\xfa\x7a\ -\xfd\xe9\xc1\xa0\x66\xda\x19\x59\xba\x29\x27\x9d\xb8\xf9\x8e\x39\ -\x2f\x75\xab\xc9\x0f\x12\xe4\xa1\xac\xaf\x65\x8c\xc1\x27\xc7\x10\ -\xd2\x8d\xa1\x02\x74\xf8\x11\xd6\xef\x02\xc3\x34\x36\x5d\x9b\x3d\ -\xc5\xa5\x53\xe7\xb8\x5c\xce\x54\xdd\x2c\x92\x01\x29\x44\x2e\xb8\ -\xde\x33\x39\x22\x42\x3a\xf8\x42\x76\x59\xd5\x2c\xfb\x83\x62\xee\ -\xf5\xb9\x0a\xfb\xff\xbe\xec\x06\xcf\x9d\x6a\x2f\x9f\xe5\xb9\x46\ -\xa6\xb8\x9d\x4c\x80\xac\x96\xaa\xf2\x3e\x7b\x86\xc4\x6a\x7d\xc5\ -\xe0\xd1\x2c\xcc\xbe\x17\x23\xee\x84\x85\x17\x54\x3e\x7b\x5d\x65\ -\x04\xe0\x3e\xe6\x33\xeb\x9c\x20\xcf\xf0\x87\x85\x57\x88\xdd\xd5\ -\xf3\x29\xc5\xa9\xab\x21\x3f\x96\xc2\xc2\xfa\xbd\x74\xe0\xe4\x77\ -\xca\x1b\x2e\x2c\xca\xcb\x39\x51\x3d\xef\x5b\xfb\xc5\x04\x6b\x7c\ -\x77\x01\xc8\x16\x8c\x92\x1f\x62\x90\xfc\x19\xda\x79\x45\xd4\x58\ -\x5e\xad\x77\x1e\x7a\xda\xc7\xad\xb4\x90\xa0\x05\xcf\x83\xc7\x48\ -\x5d\xfb\x29\x88\xa1\x4c\xe3\x05\x20\xea\x5e\x7b\xc5\x04\x6b\x7d\ -\x8f\x00\xfc\xc7\xe0\xfc\x55\x61\xac\xb1\x87\xf0\xbc\x5b\x81\x37\ -\x42\x57\x9e\x86\xc3\xc3\x6b\x68\xb4\x9a\x45\xfc\x37\xb7\x4e\x1f\ -\x31\x49\xa1\x62\x20\xb0\x75\xe7\x5d\x63\x9a\xb4\xbf\x4e\x84\x22\ -\xb6\xbe\x0b\xd4\x7a\x61\x7c\x18\x3e\x7a\xe4\xa8\x4e\x0e\xd6\xf8\ -\x6e\x48\xc2\xcd\x9e\x86\xa6\x59\x40\x32\x07\xf9\x6c\x94\xf3\x35\ -\xe7\xf8\xb1\xaf\x0b\x7b\xce\x5f\xa4\x92\xfc\xcc\xb0\x3a\x85\xcb\ -\x3c\x05\x19\x26\x1f\xf3\xed\x45\x00\x12\xeb\xc2\xba\xb0\x23\xd3\ -\x42\x58\x71\x72\x78\xb4\x4a\x4f\x99\x59\xa9\xc4\x04\x78\xfd\xf3\ -\x13\xf4\xe8\xe2\xc2\xb0\x8d\x37\xed\xfe\xbf\x61\xe2\x8a\x7f\x24\ -\x82\x00\x71\x2c\x01\xb9\x98\x2c\x1a\xda\xe7\xba\xfb\x46\xf8\x29\ -\x2c\xd5\xb9\x53\x32\x14\xba\xa3\x9d\xbd\xf4\xd9\xb1\x73\x23\xd6\ -\x6b\x23\x76\x82\xd6\xce\x5e\x93\x72\x6f\x8d\x26\xca\x3b\x9e\x12\ -\x60\x39\xd8\x78\xc9\x1f\xe8\x42\xb6\x0b\xd7\x41\x00\x3c\x08\xc9\ -\x3e\x70\xa4\xaa\xec\x0b\x43\x8f\xb0\xcb\xfb\xcb\xc5\x75\xff\xa1\ -\x55\x77\xcc\xa0\x07\x66\x17\xa8\xe2\x77\x0f\x9e\xa1\x8d\x3b\x8e\ -\x63\x46\xcc\x13\xb8\xb4\x75\x15\xdd\x09\x89\xd2\x59\xde\x05\x1e\ -\xfb\xe4\x10\xb2\x72\x4b\x95\x03\xc1\x3b\xe9\xb5\x65\x3b\xc2\x86\ -\xc5\xd8\x59\xa9\xf1\xfd\x05\x3c\x5e\xae\xc4\x22\x60\x8c\xef\x12\ -\xfa\x36\x40\x72\x2b\xb6\xd2\xe5\x2a\x1c\x56\x5f\x39\x2a\x50\xe3\ -\xb5\x0b\xbc\x4f\xb1\x3b\x56\x76\x7b\x58\xf0\x2a\x10\xc2\xe0\x19\ -\x58\xc5\x83\xe8\x6b\x91\x3b\xd5\xf5\x99\x3b\xcb\x4d\xee\xac\x14\ -\x72\xb9\x9d\x9f\x72\xd9\xe5\x82\x1f\x3f\x09\xa8\xf5\x71\x20\xe2\ -\x02\xfe\xa6\xc7\xd0\x05\x4f\x01\xe8\xf3\x56\xfa\x2c\x7d\xb3\x79\ -\x05\x40\xbf\xad\xb6\x15\x41\xcb\x9a\x7e\x51\xba\x7d\x2c\x40\x8d\ -\x97\x04\xb0\xd5\x5e\x62\xb8\xa5\x14\x56\xcb\x49\xf9\xaa\x55\xf0\ -\xaa\x91\x26\x9d\x66\x58\x50\xd3\x64\x52\x3c\x53\xeb\x83\x2a\x91\ -\x94\x27\x01\x35\x1b\xd7\x33\x7a\x50\x53\x89\xfc\x05\x20\xd8\x86\ -\x7c\x11\xea\x54\xd3\x04\x4b\xf1\xb9\xc3\x83\xeb\xf2\x59\xe3\x1a\ -\xae\xe0\x26\x60\x1a\x3b\xb1\xbb\x8c\x03\x0d\x13\x47\x02\xc6\x5a\ -\x03\x3b\x44\x90\x8c\x17\x41\x50\x82\xda\xc4\x96\x00\xeb\xf1\x00\ -\x33\xbf\xa5\xad\xa5\xe3\xe1\xb6\xd6\xb3\xd4\xd6\xda\x41\xad\xcd\ -\xa7\x7f\xc7\x65\x86\xdf\x91\x38\x26\x24\xe5\x88\x4c\x44\x43\x88\ -\x23\x62\xe2\xaf\xca\x4e\x48\x90\x21\x24\x92\x70\x48\x4a\x99\xc2\ -\x14\xd0\x22\x9b\xc2\x92\x36\x81\x08\x0f\x27\xc2\x0e\x48\x1c\x01\ -\x98\xa3\x42\x64\x98\x76\x44\xe3\xea\x9b\xe8\xb6\xeb\x72\x06\x02\ -\x21\xa6\x33\x74\xfb\xc6\xff\x9a\x2d\xf2\x00\xa5\x3b\x62\x84\x29\ -\x29\x01\x91\xcb\x49\x2c\xce\x52\xae\xe2\xd9\xdd\x90\x9f\xa1\xc0\ -\x87\x12\x76\xf1\xcc\x5c\x2a\xc1\x33\x03\xc1\xcf\x47\x03\xde\xde\ -\x4a\x50\xa8\xa3\x71\x62\xd5\xad\x85\x11\xab\x54\x2d\xbc\xd6\x74\ -\x87\x97\x4c\xc6\x5d\x40\x1d\x7b\x69\xed\xec\x09\x2b\xa6\x5c\x66\ -\xc4\x03\x38\x75\x4e\x3e\x02\x48\x59\xc7\x1b\xfe\xef\x3f\x3f\x39\ -\x42\xa7\x98\xba\x60\xcb\xbe\xd3\x64\xc4\x1b\xff\x30\xb9\x08\xc0\ -\x5b\xa0\x10\xfb\x0d\xb0\x72\xde\x86\x3d\x74\x29\x38\x68\xfb\x5c\ -\xd2\x24\xcd\x7d\x79\x0f\xf9\x03\x9a\x29\x1a\xfb\x55\x84\x79\x52\ -\xd9\x01\x9c\x56\x6f\x9f\x46\x0e\x71\x52\xad\xf2\xfe\x20\x8d\x7c\ -\x31\x02\xae\xb8\x1c\xd7\x69\x2f\x2f\x6d\x4f\xc4\x36\x98\x70\x53\ -\xd8\x33\x77\xfa\xea\x40\x20\x28\x4f\xb4\x7f\x23\x2e\x92\x9f\xf6\ -\x9f\x3a\xaf\x3f\x00\xf8\xb4\x0c\xb7\x2c\x2c\xca\x23\x97\xcb\xb9\ -\xb2\x85\xe8\xe9\x49\x65\x09\x7a\x1a\x9a\xd8\x7b\x76\xa2\x97\x00\ -\x0f\xcb\xdd\xb5\x7f\xd9\x55\xd4\x7b\xbe\xbf\x94\x95\x7e\x5a\x46\ -\xca\xa1\x99\xc5\xf9\xc7\x35\x4d\x0d\xc5\xf3\x4a\x47\x76\xb1\xa5\ -\xaa\x6c\x5c\x25\x20\xa1\x4b\x00\x44\xe0\x77\xfa\x8f\xe9\xdb\x9c\ -\xfc\x77\xcb\xca\xf2\x45\xc3\x9e\x6f\x6e\xda\x85\x27\xb7\x18\x01\ -\x96\x17\x5a\xaa\xca\x9f\x9c\x14\x96\x20\xbf\x21\x82\x8e\x4f\xc1\ -\x5f\xbf\x18\x38\xd6\x22\x5d\x20\x80\x16\x42\x00\xc1\xde\x81\x21\ -\x01\x18\x52\x64\x82\x12\xbd\x47\x56\x96\x8f\x1b\x01\x12\xb2\x0b\ -\xb4\x30\x00\x29\x5f\xd4\xc1\x4b\x7e\x07\xb6\x33\x14\xbc\xaa\x57\ -\x55\xc6\xe7\x01\x76\xe9\xf4\x66\x5a\xd0\xba\x78\xc1\xdb\x4e\x07\ -\x18\xc7\x5d\xf8\xc4\xc7\x45\xe3\x20\x24\x0f\xe8\x8c\x74\xd8\x81\ -\xeb\x63\xa8\x80\xc1\x1c\x1e\x34\x1b\x04\xbb\x80\xe5\x30\x31\x25\ -\xe0\x08\x94\x18\xc0\xbf\x44\x34\x70\x0a\xb4\x31\xda\x49\x0f\xae\ -\x8f\x9a\x8d\x92\x06\x8e\xc2\x3f\x1b\x0f\xf8\xe4\x4b\xc0\xe0\x37\ -\x41\x99\xb8\xab\x70\x38\x44\xee\x8c\xa2\x29\x0d\x99\xd9\xa9\x52\ -\xd3\xa4\x04\x78\xa7\x45\x85\xa9\xa4\x80\x75\x41\x5b\xeb\x99\x9f\ -\x06\xfc\x5a\x1a\x48\xd2\x81\xbe\x3f\x19\xf0\x2e\x23\xc4\x0b\x92\ -\xa7\x04\xcd\x73\xfd\x92\xde\x47\xfe\x63\x9d\x87\xd2\x38\x03\x2c\ -\x44\xfe\xd4\xec\xaf\x3a\x9f\xb8\xb9\xc8\xca\x78\x65\x6f\x36\x7f\ -\x70\xea\x44\xf7\xbd\xe7\xba\x2e\xe8\x36\xb2\x39\xbe\x1e\x41\x7b\ -\x0e\x84\x58\x17\xe9\xe3\xaa\xe4\x10\x40\x85\xb1\x44\x9a\xfa\x26\ -\x40\x3f\xf0\x14\xda\x80\xb7\x36\x06\xf2\x3a\x26\xfd\x48\xcc\x01\ -\xab\xb7\x37\xa3\xae\x27\xca\xd1\xd8\x6d\xe8\xe7\x6e\xfb\xe8\x00\ -\xdd\x77\xff\x5b\x04\xf0\xba\x8b\xab\x6b\xf6\x55\xb0\xf1\x4b\x62\ -\x48\xd2\x5b\xe4\x70\x78\x28\x3a\xd1\x7f\x84\x7a\xcb\xed\xe3\x0c\ -\xd5\x7a\xf9\x68\xc7\x32\xa2\x98\x1f\x44\xf1\x6f\x63\x8c\xde\x1e\ -\x20\x2b\x27\xc3\x25\xfd\xd1\x3e\x04\x90\x62\x26\x59\x95\x3c\x3e\ -\xf7\x17\x39\x74\xc6\x1e\x51\x1a\x59\x3a\x8b\x20\xb3\x40\xf8\x29\ -\x97\x33\xed\xb1\x73\x86\x04\xb9\x49\x0a\xab\x75\x45\x14\x65\x33\ -\x35\x9e\x41\x91\xd2\xec\x12\x0f\xe8\xb2\xcc\xff\xa8\xba\xa4\xe2\ -\x14\x91\x45\x59\xd2\x2d\x85\x53\x76\x21\xc0\x61\x8b\x27\xd5\xb9\ -\xd6\x9f\x62\xbc\x4b\xfc\xc6\x8a\xbd\x07\xf0\xef\x8d\xf6\xf3\xda\ -\xf1\xb2\x03\xee\xc2\xef\xc7\x31\x25\xa0\xae\xc2\x11\xc3\x96\x28\ -\xc6\x75\x94\x22\x1f\xca\x32\xcb\xaf\x26\x8e\x1d\x86\xd8\x02\xc9\ -\xf5\x06\x6b\xbc\x8f\xa2\xf2\x2b\xc3\x26\x3f\xf8\x31\x14\x47\x3c\ -\xa7\x11\x1f\x83\x8f\xf5\x32\xb5\xd6\x77\x3f\x1a\xbe\x17\x16\xbf\ -\xfe\x7d\xd1\x0f\xb0\xf5\x1e\xb2\x97\x2f\xc0\xdc\xab\xaf\x7c\x15\ -\xff\xa6\xe3\xda\xa4\x96\x05\x51\x3b\x26\xbb\x13\x24\x58\x03\xd0\ -\x99\x96\xc0\xeb\xba\x80\xad\xc9\x5c\x15\x48\x25\x79\x00\xf9\x57\ -\xb8\xe7\x93\xa3\xfc\x5a\xde\x19\x09\x7c\xbc\xe9\x7b\x01\x06\x00\ -\x19\x34\x01\x6e\xc9\xd6\xa8\xa6\x00\x00\x00\x00\x49\x45\x4e\x44\ -\xae\x42\x60\x82\ +\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\ +\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\ +\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\ +\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\ +\xe3\x06\x0c\x15\x0f\x15\x69\x3a\x10\x2b\x00\x00\x0d\x23\x49\x44\ +\x41\x54\x78\xda\xed\x9d\x6b\x90\x14\xd5\x15\xc7\x7f\xdd\x33\xfb\ +\x5e\x77\x17\x16\xdc\x65\x05\x79\x28\x8f\x61\x02\x88\x51\x82\x51\ +\x8c\x8a\x6d\xb4\x24\x54\xa5\x8c\x26\xc4\x98\x92\x49\x52\x8a\x04\ +\x64\xc4\x07\xa9\x4a\x4c\x62\x2a\x11\x45\xd2\x46\x4a\x2a\x56\x92\ +\xd5\x32\xa5\x31\xe2\xe3\x03\x90\xc4\x4c\x51\x42\x10\x23\x2f\x79\ +\xac\xcb\x20\x8a\xe1\xb9\x2b\xcb\x63\x1f\x2c\xfb\x60\x77\xa6\xf3\ +\xa1\x17\xd8\xd9\x9d\x9e\x47\x4f\x37\x3b\x33\x7d\xcf\xa7\xdd\x9e\ +\xbe\xa7\xcf\xbd\xff\xff\xbd\x7d\xfa\xde\x73\xcf\x95\x70\xb2\xf8\ +\x03\xb3\x80\x99\xc0\x38\xa0\xa8\xe7\xea\x51\x60\x2b\xf0\x26\xaa\ +\x52\x97\xed\x4d\x20\x39\x14\xf8\xa7\x80\x5f\x24\x70\xe7\x26\xe0\ +\x21\x54\x65\xb7\x20\x40\x76\x00\x3f\x01\xf8\x18\x28\x48\xb2\xe4\ +\x1f\x50\x95\x45\x82\x00\x99\x0d\xfe\xb5\xc0\x96\x14\x34\x04\x50\ +\x95\xdb\x04\x01\x32\x13\xfc\xa1\x40\x83\x05\x9a\xde\x46\x55\xbe\ +\x23\x08\x90\x59\xe0\x4b\x40\x17\xe0\xb2\x48\xe3\x0d\xa8\xca\xa6\ +\x6c\x69\x1e\xb7\x03\xfa\xff\xbd\x16\x82\x0f\xf0\x01\xfe\x40\x0e\ +\xaa\xd2\x9d\x02\x29\x67\x00\x13\x81\xbc\x1e\x72\xee\x07\xd6\xa3\ +\x2a\x67\xc5\x08\x60\x6d\xef\x97\x81\x90\x0d\x9a\xaf\x41\x55\xb6\ +\x27\x69\xcb\xf5\xc0\x53\xc0\x2d\x31\xee\xda\x0e\x2c\x45\x55\xde\ +\x12\x23\x80\x35\x92\x6f\x93\x5e\x15\xb8\x31\x41\xe0\xf3\x81\x7f\ +\x00\x37\x27\x70\xf7\x57\x81\x55\xf8\x03\x7b\x81\x5b\x50\x95\x7a\ +\xbb\x1b\x48\xce\x72\x02\xdc\x61\x93\xde\x19\x3d\xbe\x45\x3c\xf0\ +\x47\x03\x2d\x09\x82\xdf\x5b\x26\x00\x75\x3d\xa3\x86\x20\x40\x0a\ +\x32\xd3\x46\xdd\x85\x71\xc0\x2f\x02\xf6\x01\x39\x29\xfa\x1b\x93\ +\x05\x01\xcc\x4b\x85\x8d\xba\xe3\x39\x96\x9f\x59\xf4\x8a\xdd\x8a\ +\x3f\xe0\x12\x04\x30\x27\xc7\x6c\xd4\x1d\x8a\xd1\xfb\x1f\x07\x86\ +\x59\xf4\x9c\x5c\x60\x85\x20\x80\x39\x59\x67\xa3\xee\xb6\x18\xbf\ +\x2d\xb1\xf8\x59\xf3\xf0\x07\xf2\x04\x01\x92\x97\x7f\xda\xa4\x77\ +\x23\xaa\xa2\x19\xf4\xfe\xaf\x00\x83\x6c\x78\xe6\x5c\x41\x80\xe4\ +\xa5\xc3\xae\x19\x86\x18\xbf\x3d\x61\xd3\x33\x6f\x15\x04\x48\xfa\ +\x6b\x5d\x09\x03\xf7\xd9\xa0\x79\x57\x9c\x6f\x79\x3b\x64\xa2\x20\ +\x80\x39\x79\x0d\x6b\x67\x03\xaf\x8f\x33\x0d\x9c\x6b\x53\x3d\x86\ +\x08\x02\x98\x1b\x05\x34\x0b\x3d\xf2\xb7\x51\x95\x0f\xe3\xdc\xa3\ +\xd9\x54\x93\x2e\x41\x00\xf3\x24\x38\x0e\x4c\x4b\x51\x4b\x20\xc1\ +\xa5\xe0\xd3\x36\xd5\xe2\xa8\x20\x40\x6a\x24\xd8\x0a\x78\x80\x76\ +\x13\xa5\x57\x24\x11\x0c\xf2\xae\x4d\x35\xd8\x21\x08\x90\x3a\x09\ +\xf6\xa2\x2a\x85\xc0\x6f\x12\x2c\xb1\x09\x98\x82\xaa\x2c\x4c\xe2\ +\x29\x4b\x6d\xb2\xfe\x1d\x3b\x94\x3a\x33\x28\xf4\xc2\x37\xfb\xac\ +\xc1\xe5\x45\xab\x3b\x3b\xbb\x09\x87\xf5\x57\x77\x4e\x8e\x0b\x59\ +\x96\xde\x6b\x6a\x6c\x9b\x6b\x7a\x35\x4e\x5f\xcd\x1b\x6f\xa1\xa5\ +\xad\xa8\xca\x25\x76\x34\x81\xdb\xc9\xf8\x7b\x26\x55\xad\x05\x90\ +\x24\x29\xc2\x87\xd3\x34\x76\x36\x3d\x79\xbd\xe9\xa5\xd8\xe2\xe2\ +\xfc\x7b\x5b\x5b\x3b\xb6\x59\x68\xea\x03\x76\xb5\x81\xa3\x09\x70\ +\x1e\x72\xcd\x3a\xc7\xdd\x53\x5d\x9b\x03\xbc\x5f\x77\xb8\x91\xe6\ +\xa6\x76\x2b\x54\x7e\x80\xaa\xbc\x6e\x57\xdd\x65\x01\xbf\x2d\xde\ +\xfa\x25\xc3\x47\x0e\x26\xbf\x20\x27\x55\x5d\x07\x80\x9b\xec\x34\ +\x56\x10\xc0\xca\x57\x4a\x75\xed\x09\x60\x28\x40\x38\xac\x71\xc5\ +\xb8\x4b\x29\x29\xcd\x07\x73\x23\xcc\x36\x60\x2c\xaa\x12\xb2\xd3\ +\x66\xf1\x0a\xb0\x0e\xfc\x93\xc0\xe0\xde\xd7\xc2\x61\x8d\xe1\x23\ +\xcb\x69\x2e\x6d\x6b\x3b\x7a\xb0\x31\x84\x44\x22\x8e\x5c\x18\x58\ +\x8c\xaa\x3c\x7f\x31\xec\x16\x23\x80\x35\xe0\x37\xf4\x05\xbf\x97\ +\x7f\x11\x2a\x29\x2d\x18\xce\xf3\x4a\x09\x70\x0f\xfa\x0a\x65\xdf\ +\xa5\x64\x0d\xd8\x00\x3c\x80\xaa\xb8\x2e\x16\xf8\x62\x04\xb0\x06\ +\xfc\xba\x73\xc3\xbe\x81\x54\x04\x7d\xde\xc6\x9e\x79\x88\x55\xc0\ +\xaa\x5e\x9f\x8b\xa5\xa8\x4a\xf3\x40\xda\x2f\x08\x90\x1a\xf8\xf5\ +\x40\x65\x8c\x5b\x86\x05\x7d\xde\x93\x86\xbf\x0e\x30\xf8\x82\x00\ +\xa9\xf7\xfc\xca\x38\x3d\xbf\x21\xdd\xeb\x21\x7c\x00\x73\xe0\xef\ +\x27\xf6\x0a\x63\x65\x26\x80\x2f\x46\x00\x73\xe0\x7f\x01\x8c\x8e\ +\x71\xcb\xa8\xa0\xcf\x7b\x2c\x53\xea\x23\x08\x00\x20\x81\x84\x44\ +\xcf\x34\x70\x2c\xf0\xff\x07\x8c\x8a\xa1\xe9\xf2\xa0\xcf\x7b\x38\ +\x93\xaa\xee\x68\x02\x04\x6b\xea\x26\x54\x0c\x2b\xa5\xb3\xa3\x8b\ +\xee\x50\x18\x97\x2c\xe3\xce\x91\x71\xb9\xe5\x91\x51\xc0\xaf\x89\ +\x03\xfe\x88\xa0\xcf\x7b\x24\x03\xb9\xef\x40\xf1\x07\x7e\x08\x3c\ +\x0d\x54\xc5\xb9\xf3\x55\xce\x9c\x7d\xc0\x33\x7d\xd4\x36\xc0\x1b\ +\xe3\xbe\x09\x41\x9f\xf7\xd3\x0c\x1d\xfc\x1c\x05\x7c\x01\xfa\x14\ +\x6b\x52\x01\x96\x95\x97\x95\x31\xa8\xbc\xd0\x28\xd8\x6b\x5c\xd0\ +\xe7\xfd\x2c\x53\x9b\xc4\xe5\x20\xf0\x2b\x81\x46\x8c\x26\x6d\x34\ +\xe3\xee\xd0\xda\xd2\x41\xa8\x3b\x44\x71\x49\xbf\xcd\xc6\x63\x83\ +\x3e\xef\xe7\x99\xdc\x2c\x2e\x87\x80\xef\x42\xdf\xa5\x1b\x29\xdd\ +\x61\x46\x0f\x2d\x64\xce\xd4\x4a\xbe\x3b\xb5\x82\xeb\x46\x95\x91\ +\xef\x96\xd9\x5f\xdf\x0a\x2e\x39\x62\x9c\xec\x68\xef\x42\x96\x25\ +\x0a\x8b\xce\x07\xfd\x5e\x1d\xf4\x79\xf7\x64\x7a\xd3\x38\xc5\x09\ +\x0c\xf6\xbd\x50\x5e\x98\xc3\x9a\x9f\x5c\xc5\xf4\x91\xa5\x51\x0b\ +\x2c\x7c\xf7\x53\x56\x6c\x38\x04\xf2\x85\x61\xa1\xa1\xbe\x99\xd2\ +\xb2\x02\xdc\x39\xae\xa9\x41\x9f\x77\x67\x96\x7c\x00\x0d\x48\x8f\ +\xbc\x01\x7d\xcf\xfc\x18\xf4\xed\xd3\x5d\xc0\x27\xe8\x69\x52\xb6\ +\x5b\xfc\xac\xc9\xf4\xd9\xc8\x31\x69\x58\x31\xbb\x1f\x9b\x1e\xb7\ +\xe8\xea\xda\xe3\xcc\xfe\xf3\xae\xc8\x56\xd2\xb4\x63\x3c\x7f\x5b\ +\x65\x16\x7d\x01\x5f\x34\xd0\x65\xe0\x19\x60\x71\x9c\xe7\xb6\x03\ +\x4f\xa2\x2a\xcf\x59\xf4\xdc\xe3\xf4\xda\x54\x21\x4b\x10\x5a\x9e\ +\xf8\x2e\xab\xa5\xeb\x0e\xf0\xb3\x35\x9f\xf7\xb5\xb8\x02\x55\x69\ +\xc8\x06\x02\xc8\x17\x09\xfc\x5b\x81\x4e\xe0\xd1\x04\x48\x57\x00\ +\x2c\xc3\x1f\x68\x4e\x39\x39\x82\xee\xf5\x47\xec\xa8\x59\x3f\xff\ +\x9a\xa4\x54\x2c\x99\x39\x8a\xbc\x9c\x7e\xcd\xf4\x58\xb6\x8c\x00\ +\xf2\x45\x00\x7f\x01\x10\x30\xe1\x6f\x94\x00\xbb\xf0\x07\xbe\x9d\ +\xc2\xd3\x23\xc0\x77\xcb\x12\x33\xc6\x94\x25\xad\xe4\xe1\x19\x23\ +\xfa\x5e\x5a\x20\x08\x90\x18\xf8\x77\x03\x2f\xa4\xa8\xe5\x1d\xfc\ +\x81\xa9\xa6\x4a\x76\x87\x23\x72\xec\xe4\xe7\x98\xab\xee\xc3\xdf\ +\xb8\xbc\xef\x1c\x40\x9e\x9d\x59\x3b\xb2\xe3\x2b\xc0\x1f\x18\x02\ +\xbc\x69\x91\xb6\x8d\x40\x71\xac\x1b\x3c\xd5\xb5\x95\xc0\x64\x60\ +\x2a\x70\x15\x30\xf9\xd4\xc9\xd6\x89\xc7\xea\x2e\x7c\xfd\x5d\x3e\ +\xa8\xc0\xd4\xc3\xab\x4a\xf2\x8c\x3e\xa1\x43\x82\x00\xc6\xf2\x8a\ +\x85\xba\x8a\xf0\x07\xaa\x51\x15\x9f\xa7\xba\xb6\xaa\x17\xd0\x53\ +\x7a\xfe\xf6\x44\x45\x48\x8e\xec\xf1\x87\x1a\xcd\x85\x69\x1f\x3b\ +\x1d\x35\x7f\x63\x48\x8c\x00\xc6\xbd\x7f\x28\x70\xa7\xa5\x9f\x2b\ +\x92\x74\xff\xc4\x57\x82\x73\xc3\xe1\x70\xc2\x65\x0a\x8b\x23\x7b\ +\x6e\x47\x57\xd8\xd4\xb3\x97\xaf\x3f\xd8\xd7\x75\xed\xb4\x3b\x5a\ +\x37\xd3\x7d\x80\x1f\x59\xad\x50\x0b\x6b\x52\x4b\x73\x72\x3d\xd8\ +\xed\x92\x23\xde\xdd\xdd\x61\x8d\x8d\x5f\x34\x25\xfd\xec\x17\x36\ +\xf6\x5b\xe1\x5d\x41\x96\x88\x5d\x04\xb8\xd1\x72\x8d\x12\x34\x9e\ +\x3c\x93\x5c\x11\x59\xc2\xe5\x8e\xac\xe2\x4d\x2f\x26\xb7\x63\x6b\ +\xe9\xba\x03\x74\xf6\x1f\x39\x96\x09\x02\xc4\x96\x2b\xed\x50\x7a\ +\xf6\x6c\x77\x32\x53\x57\xed\xc0\x96\xaa\x11\x83\x5e\xee\x7d\x31\ +\xac\xc1\xe4\x65\x1f\x25\xa4\x60\xed\x9e\x13\xd1\x26\x81\x4e\x66\ +\xcb\x24\x90\x9d\x4e\x60\xb9\x2d\x5a\x35\x7a\xe2\x76\x22\xe4\x0c\ +\x50\x03\xec\x44\x3f\x0d\xe4\x13\x60\x47\xd0\xe7\xed\xe8\xe5\x93\ +\xdc\x00\x8c\x3d\xf7\x6f\x4d\x7d\x2b\x43\x7e\xbe\x21\xfe\x5a\xc0\ +\xfa\x43\xe0\xea\xc7\xb8\x29\x64\x91\xd8\x45\x80\x16\x0c\x36\x4a\ +\xa4\x22\x61\x4d\x6b\x05\xe9\x55\xd0\x76\xf4\x80\xbe\x23\xe8\xf3\ +\x26\x92\x62\xdd\x03\x44\xe4\xf5\x39\xd9\xd6\xc5\x75\xcb\x37\x33\ +\xba\xa2\x88\xdb\xc7\x97\x33\xa6\xbc\x80\xd3\x9d\x21\x36\x1f\x6c\ +\xe6\xbd\x9a\x06\xc8\x75\x45\x03\x7f\x09\xaa\x72\x34\x9b\x08\x60\ +\xcf\x5a\x80\x3f\xb0\xc1\x16\x3f\x00\x3e\x44\x55\xae\x37\x69\x53\ +\x25\x50\x1f\x6b\x74\x89\xd3\x1a\x2f\xa1\x2a\x0f\x92\x65\x62\x97\ +\x0f\xb0\xc5\x26\xbd\xaf\x99\x2e\xa9\x2a\x5f\xa2\x27\x78\xde\x63\ +\xa2\x2b\x3c\x94\x8d\xe0\xdb\x39\x02\x5c\x8d\x7e\xf8\x81\xb5\xa2\ +\x2a\x92\x45\xf6\x25\x1e\x13\x08\xf3\x51\x95\x56\xb2\x54\xec\x5b\ +\x0e\xf6\x07\xf6\xf5\x76\xbc\x2c\x19\x55\x54\xe5\x6b\x16\xdb\xe8\ +\xa9\x18\x56\xba\xa7\xb3\xa3\x8b\xee\xee\x10\x2e\x97\x4b\x8f\x0a\ +\x76\x49\x6f\x34\x3c\x31\x7d\x0e\x0e\x10\x3b\xa7\x82\xef\x47\x4f\ +\xb2\x64\x95\xdc\x64\xb5\x81\x9e\x49\x55\x7b\xcf\x75\x83\x3e\xfb\ +\x02\x0e\x36\xe0\x0c\xb1\x6f\x35\x50\x4f\xa8\xf8\xa2\x45\xda\x16\ +\xa3\x2a\xed\xb6\xd9\xaa\xe9\x69\x62\x34\x0d\xc7\x89\xbd\xcb\xc1\ +\xaa\xf2\x53\xe0\x5f\x29\x6a\xf9\x23\xaa\xf2\x7b\x84\x64\x20\x01\ +\x74\x12\xdc\x91\xc2\x48\xf0\x08\xaa\x32\x4f\xc0\x94\xc9\x04\xb8\ +\x30\x12\x4c\x27\x4a\x74\xae\x81\x6c\x42\xcf\x8f\xa3\x0a\x88\x32\ +\xd7\x09\xec\x4b\x82\xcd\xc0\x44\xfc\x81\x49\xe8\x29\xdc\x6f\x44\ +\xdf\x65\x5b\x80\x3e\x9d\xbb\x17\x3d\x4d\xca\xcb\xa8\xca\x41\x01\ +\x4d\xb6\x11\xe0\x02\x11\x6a\x80\xc7\x45\xd3\x3b\xe9\x15\x20\x44\ +\x10\x40\x88\x20\x80\x10\x41\x00\x21\x82\x00\xe9\x28\x92\x9e\x31\ +\x5c\x72\x60\xba\x0c\x91\x22\x26\xc1\x14\x31\x59\xcc\x7d\x07\x8a\ +\x58\x0e\x76\x28\x01\x4c\xa6\x88\x01\x1e\x44\x55\x5e\x12\x04\xc8\ +\x6c\xf0\x45\x48\x98\x63\x09\xa0\x6f\xe4\xec\x7f\xd8\x63\x77\x38\ +\x76\x50\x68\x7f\x59\x82\xaa\x3c\x23\x08\x90\x79\x04\xe8\x17\x9d\ +\x94\x50\x8a\x98\xe8\x61\xe1\xc3\xb3\x29\x32\x58\x72\x00\xf8\xa6\ +\x53\xc4\xac\xdd\x73\x82\x59\x7f\xda\x19\x6d\x63\xc8\x90\x6c\x69\ +\x1e\x27\xcc\x03\xac\x8b\xa8\xb0\x44\x42\xe0\x03\xdc\x39\x71\x08\ +\x4f\xcf\xba\xb2\xef\x4e\x94\x72\xfc\x81\x4b\x05\x01\x32\xc7\xeb\ +\x17\x29\x62\x1c\x3c\x02\x88\x14\x31\x0e\x27\xc0\xcc\xde\xff\x88\ +\x14\x31\xce\x23\x40\x49\xef\x7f\x6c\x48\x11\x23\x08\x90\xe6\x12\ +\x91\x1e\x56\xa4\x88\x71\x1e\x01\x22\xbe\x00\x44\x8a\x18\xe7\x11\ +\xe0\x44\xef\x7f\x44\x8a\x18\xa7\x11\x40\xdf\x4d\x14\x41\x02\x91\ +\x22\xc6\x59\x23\x40\xbf\x2f\x81\x64\x52\xc4\xac\xae\x3d\x9e\xf5\ +\x29\x62\xb2\x9f\x00\xaa\xb2\x1b\x88\x38\xd1\xe3\x5c\x8a\x98\x8f\ +\x0e\x1a\x9f\xdb\xb8\xf0\xdd\x4f\x99\xdd\x7f\x1a\x18\xb2\x2c\x45\ +\x8c\x58\x0d\x14\xab\x81\xce\x90\x31\x2b\x77\xa9\x5f\xec\x6b\x58\ +\x64\x58\xe3\x58\xf1\x00\x1a\x0c\x1e\x52\xc4\x15\xe3\x2b\x72\xb7\ +\xde\x7d\x45\x57\x36\xb5\x8b\x23\x82\x42\x3d\xd5\xb5\x72\x5e\xbe\ +\x7b\xd1\xf8\x49\xc3\xc8\xcd\x73\x47\x3f\xfc\xc9\x08\xfc\xb0\x46\ +\xe5\xf0\x32\x2a\x2e\x2b\xa5\xf5\x74\xc7\x82\x6c\x6b\x1b\xa7\x44\ +\x05\x2f\x05\x90\x25\x89\x2b\x27\x54\x50\x35\xa2\x0c\xb7\xdb\x65\ +\x74\x0a\xd8\x79\xe0\x4b\xcb\x0a\x19\x3f\xa9\x8a\x41\x83\xcf\x9f\ +\x18\xb6\xdc\x53\x5d\x9b\x2b\x5e\x01\x99\xd5\xfb\xa3\xbe\xff\x65\ +\x59\xa2\xfe\x48\xd3\xed\xa7\x4e\x9e\xf1\x00\x93\x80\x4b\x81\x66\ +\xe0\x30\x9a\xb6\x71\xe2\x94\xe1\x6f\x81\x56\x10\x25\x69\xc4\x63\ +\x41\x9f\xf7\x39\x41\x80\xcc\x21\xc0\x32\xf4\x93\x4a\xfa\x4a\x6b\ +\xd0\xe7\xbd\x24\x46\xb9\xe9\xc0\x7f\x0d\x7e\xce\x0f\xfa\xbc\x9d\ +\xe2\x15\x90\xfe\xe0\xbb\x0d\xc0\x07\xb8\x36\x56\xd9\xa0\xcf\xfb\ +\x11\xfa\xb6\xf5\x68\xf2\xb0\xf0\x01\x32\x43\x8c\x3e\xd9\x5a\x82\ +\x3e\xef\xde\x04\xca\xcf\x34\xd2\xeb\xa9\xae\xcd\x13\x04\x48\xef\ +\xde\x9f\x03\x3c\x62\xf0\xf3\xb4\x44\x74\x04\x7d\xde\xcd\xc0\x69\ +\xa3\xd9\x05\x41\x80\xf4\x96\x67\x0d\xae\x37\x27\x79\xd0\xb3\xd1\ +\x19\x73\x4f\x7b\xaa\x6b\xf3\x05\x01\xd2\xb3\xf7\xe7\x02\x8b\xcc\ +\xbc\xfb\xa3\x8c\x02\x5b\x88\x76\xec\xac\x2e\x8f\x08\x02\x64\x56\ +\xef\x6f\x34\x79\xd2\xb7\x91\x2f\xf0\x5b\x4f\x75\x6d\x81\x20\x40\ +\x7a\xf5\xfe\xbc\x18\x5e\xfa\x34\x33\x3a\x83\x3e\xef\x36\xc0\x28\ +\x90\x60\xb1\x20\x40\x7a\x89\xd1\x5a\xfd\xa9\x14\x8f\x7a\x37\xf2\ +\x05\x7e\xe3\xa9\xae\x2d\x14\x04\x48\x8f\xde\x9f\x8f\x71\xc8\xf6\ +\xb4\x54\x74\x07\x7d\xde\xed\xc0\x29\x83\x9f\x1f\x15\x04\x48\x0f\ +\x31\x9a\xa2\x3d\x11\xf4\x79\xf7\x5b\xa0\x5f\x31\xb8\xfe\x6b\x4f\ +\x75\x6d\x91\x20\xc0\x00\xca\xbc\x23\xe1\x1c\x60\xbe\xc1\xcf\x96\ +\xa4\x99\x0f\xfa\xbc\x1f\xd3\x27\xc4\xac\x97\x64\xe4\x6e\xa1\xcc\ +\x5c\x0b\xf0\x07\xf2\x81\x1f\xa0\x67\x1b\x1d\x0b\xe0\x72\xcb\xa5\ +\x25\x25\xf9\x9e\x82\xe2\x3c\x4a\x4b\x0b\x90\x24\xce\x65\xff\x3e\ +\x1e\xf4\x79\x2d\xdb\xcb\xe7\xa9\xae\x9d\x8a\x7e\x38\x95\xde\x80\ +\x12\x84\xc3\x1a\x2d\xcd\xed\xd4\x1d\x6e\x7a\x05\x18\x87\xbe\x67\ +\xa0\x0b\xf8\x1c\x3d\x32\xf9\x35\x54\x45\x13\x04\x48\x1d\xf8\x41\ +\xe8\x47\xd2\xce\x36\xbc\x47\x03\x34\x8d\xb2\x21\x45\x54\x56\x95\ +\x22\x49\xd2\xe8\xa0\xcf\x7b\xc0\x62\x5f\xa3\x01\x18\x1a\x0a\x69\ +\x7c\x79\xb4\x89\x96\xc6\x36\x9d\x09\xb1\x5b\xf3\x0d\xe0\xc7\xa8\ +\xca\x99\x74\x6a\x52\x39\x83\xc0\x7f\xa8\xc7\x09\x9b\x1d\x97\xd2\ +\xb2\x44\xd3\xa9\x36\xf6\xee\xae\x0b\x07\x6b\xea\xae\xb6\xda\x14\ +\xb7\x5b\xbe\xa5\xa9\xb1\x8d\x7d\xb5\x75\xb4\x34\xb7\xeb\x5b\x8e\ +\xe3\x77\xa5\xef\x01\xad\xf8\x03\x73\x04\x01\x92\x07\x7f\x25\x66\ +\x52\xce\xcb\x92\x0c\xbc\x8d\x3f\x60\x69\x24\x4f\xcd\x8e\x23\x73\ +\xea\x0f\x37\x61\x32\xaf\xdc\xeb\xf8\x03\xbf\x14\xaf\x80\xc4\xc1\ +\x5f\x00\xbc\x60\x81\xa6\x59\xa8\xca\x5a\x0b\xec\x99\x07\xac\xb4\ +\xc0\x9e\x7b\x50\x95\x55\x82\x00\xb1\x1b\x7b\x04\x70\xc8\x32\x7d\ +\xa9\x9e\x3a\xa6\x3b\x9f\x56\x1e\x5d\x53\x31\xd0\x7b\x0c\xd2\xfd\ +\x15\xb0\xc6\x62\x42\xbd\x9f\xa2\x86\x6d\x16\xd7\x6f\xe5\x40\x37\ +\xb0\x9c\xc6\xbd\x7f\x14\x30\xd9\x62\xad\xa9\x9e\x66\xea\xb1\xd8\ +\x9e\xbb\xf0\x07\x86\x0a\x02\x18\xbd\xb3\xed\xa8\xaf\x3f\x70\x9b\ +\x49\x42\x3e\x6e\x53\x7b\x7d\x53\x10\x20\xba\xdc\x67\x93\x5e\xb3\ +\x33\x76\xf3\x6d\xb2\xe7\x5b\x82\x00\xd1\x65\x9a\x4d\x7a\x67\x98\ +\x2c\x57\x62\x93\x3d\x53\x05\x01\x32\xa3\xce\x76\x65\x56\x2f\x10\ +\x04\xb8\xb8\x12\x36\x59\xae\xdb\x26\x7b\x3a\x04\x01\xa2\x8b\x5d\ +\x47\xd0\x6f\x34\x59\xae\xc5\x26\x7b\xb6\x0b\x02\x44\x97\xbf\xda\ +\xa4\xd7\x6c\x76\x8f\x17\x6d\xb2\x67\x8d\x20\x40\x74\x59\x6d\xcb\ +\xf0\xaf\x2a\xff\x36\x55\x52\x55\x9e\x4d\xe1\xf5\x11\x4b\xde\x13\ +\x04\x88\xde\xe0\x07\x81\xdd\x16\x6b\xfd\x4f\x8a\xe5\x83\x16\xdb\ +\xb3\x0a\x55\x39\x2e\x08\x60\x2c\xb3\x2c\x26\xd5\xcd\x29\x6a\xb8\ +\xc6\xe2\xfa\xcd\x1f\xe8\x06\x4e\x6f\x02\xa8\xca\x61\x60\x61\xda\ +\x90\x49\x55\x3a\x00\xab\x4e\x0d\xb9\x67\xa0\x7b\x7f\x66\x7c\x06\ +\xaa\xca\x0a\x52\xcf\xcb\xb7\xd0\x92\xa5\x60\xdd\x9e\x97\x80\xdf\ +\xa5\xa8\xe5\x57\xe9\xb0\x14\x0c\x99\x14\x12\xa6\x47\x04\x99\xf1\ +\xc4\xef\x42\x55\xde\xb1\xc1\x9e\xb9\x40\xb5\x89\x92\xdf\x47\x55\ +\xfe\x96\x2e\xcd\x9a\x39\x13\x41\xaa\xb2\x12\x18\x0c\xbc\x95\x60\ +\x89\xbf\x00\xb9\xb6\x80\xaf\xdb\xf3\x32\x50\x06\xfc\x3d\xc1\x12\ +\x6f\x00\xc5\xe9\x04\x7e\x66\x8d\x00\x91\xbd\xef\x5c\x54\xf0\x74\ +\x60\x34\x7a\x14\x6e\x37\xb0\x0f\xd8\x78\xd1\x1b\x59\xb7\x67\x0e\ +\xf0\x75\x60\x4c\x8f\x3d\x67\xd1\x83\x59\xd6\x93\xc6\x51\xc1\xff\ +\x07\xc0\x9f\x05\x7f\x94\xb9\x48\x5b\x00\x00\x00\x00\x49\x45\x4e\ +\x44\xae\x42\x60\x82\ \x00\x00\x0f\x91\ \x89\ \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ @@ -1034,11 +1049,11 @@ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x03\ -\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x01\x00\x00\x0f\x98\ -\x00\x00\x00\x70\x00\x00\x00\x00\x00\x01\x00\x00\x2d\xd6\ +\x00\x00\x00\x3e\x00\x00\x00\x00\x00\x01\x00\x00\x10\x89\ +\x00\x00\x00\x70\x00\x00\x00\x00\x00\x01\x00\x00\x2e\xc7\ \x00\x00\x00\x12\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ \x00\x00\x00\x28\x00\x00\x00\x00\x00\x01\x00\x00\x02\xef\ -\x00\x00\x00\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x2d\ +\x00\x00\x00\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x20\x1e\ " def qInitResources(): diff --git a/usdmanager/utils.py b/usdmanager/utils.py index d4eae89..4b15bf5 100644 --- a/usdmanager/utils.py +++ b/usdmanager/utils.py @@ -83,6 +83,44 @@ def expandPath(path, parentPath=None, sdf_format_args=None): return os.path.expandvars(os.path.expanduser(os.path.normpath(path))) +def expandUrl(path, parentPath=None): + """ Expand and normalize a URL that may have variables in it and a query string after it. + + :Parameters: + path : `str` + File path + parentPath : `str` | None + Parent file path this file is defined in relation to. + Helps with asset resolution. + :Returns: + Normalized path with variables expanded. + :Rtype: + `str` + """ + sdf_format_args = {} + if "?" in path: + sdf_format_args.update(sdfQuery(QtCore.QUrl(path))) + path, query = path.split("?", 1) + query = "?" + query + else: + query = "" + return QtCore.QUrl(os.path.abspath(expandPath(path, parentPath, sdf_format_args)) + query) + + +def escapePath(path): + """ Wrap path in quotation marks on Windows. + + :Parameters: + path : `str` + File path + :Returns: + Escaped path + :Rtype: + `str` + """ + return '"{}"'.format(path) if os.name == "nt" else path + + def findModules(subdir): """ Find and import all modules in a subdirectory of this project. Ignores any files starting with an underscore or tilde. diff --git a/usdmanager/version.py b/usdmanager/version.py index e4c65de..2797b2f 100644 --- a/usdmanager/version.py +++ b/usdmanager/version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = '0.4.1' +__version__ = '0.5.0' From b5fee7f724eebceb7b10e5ff89c96a9081d4ffa5 Mon Sep 17 00:00:00 2001 From: mds-dwa Date: Tue, 18 Jun 2019 11:52:13 -0700 Subject: [PATCH 2/5] [BUG] Support spaces in file names on Windows Signed-off-by: mds-dwa --- usdmanager/__init__.py | 7 ++++--- usdmanager/utils.py | 14 -------------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/usdmanager/__init__.py b/usdmanager/__init__.py index 04a1657..077fb9b 100755 --- a/usdmanager/__init__.py +++ b/usdmanager/__init__.py @@ -2331,7 +2331,7 @@ def unindentText(self): def launchTextEditor(self): """ Launch the current file in a separate text editing application. """ - path = utils.escapePath(self.currTab.getCurrentPath()) + path = self.currTab.getCurrentPath() args = shlex.split(self.preferences['textEditor']) + [path] self.launchProcess(args) @@ -2339,7 +2339,7 @@ def launchTextEditor(self): def launchUsdView(self): """ Launch the current file in usdview. """ - path = utils.escapePath(self.currTab.getCurrentPath()) + path = self.currTab.getCurrentPath() args = [self.app.appConfig.get("usdview", "usdview"), path] self.launchProcess(args) @@ -2369,7 +2369,7 @@ def launchProgramOfChoice(self, path=None): self.preferences['lastOpenWithStr'] = prog # Launch program. - args = shlex.split(prog) + [utils.escapePath(path)] + args = shlex.split(prog) + [path] self.launchProcess(args) """ @@ -3121,6 +3121,7 @@ def launchProcess(self, args, **kwargs): try: if kwargs.get("shell"): # With shell=True, convert args to a string to call Popen with. + logger.debug("Running Popen with shell=True") if isinstance(args, list): args = subprocess.list2cmdline(args) logger.info(args) diff --git a/usdmanager/utils.py b/usdmanager/utils.py index 4b15bf5..752fc80 100644 --- a/usdmanager/utils.py +++ b/usdmanager/utils.py @@ -107,20 +107,6 @@ def expandUrl(path, parentPath=None): return QtCore.QUrl(os.path.abspath(expandPath(path, parentPath, sdf_format_args)) + query) -def escapePath(path): - """ Wrap path in quotation marks on Windows. - - :Parameters: - path : `str` - File path - :Returns: - Escaped path - :Rtype: - `str` - """ - return '"{}"'.format(path) if os.name == "nt" else path - - def findModules(subdir): """ Find and import all modules in a subdirectory of this project. Ignores any files starting with an underscore or tilde. From 5a4133728b694092eecc2f7e52618d82ff790a35 Mon Sep 17 00:00:00 2001 From: mds-dwa Date: Tue, 18 Jun 2019 12:31:14 -0700 Subject: [PATCH 3/5] [ENH] Display app version in About dialog [ENH] Clean up temp files on exit --- usdmanager/__init__.py | 29 +++++++++++++++++++---------- usdmanager/utils.py | 13 ++++++++----- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/usdmanager/__init__.py b/usdmanager/__init__.py index 077fb9b..9732c8b 100755 --- a/usdmanager/__init__.py +++ b/usdmanager/__init__.py @@ -45,6 +45,7 @@ import re import shlex import signal +import shutil import stat import subprocess import sys @@ -988,7 +989,7 @@ def saveFile(self, filePath, fileFormat=FILE_FORMAT_NONE, _checkUsd=True): elif ext == ".usd" and (fileFormat == FILE_FORMAT_USDC or (fileFormat == FILE_FORMAT_NONE and self.currTab.fileFormat == FILE_FORMAT_USDC)): crate = True if crate: - fd, tmpPath = tempfile.mkstemp(suffix=".usd") + fd, tmpPath = tempfile.mkstemp(suffix=".usd", dir=self.app.tmpDir) os.close(fd) status = False if self.saveFile(tmpPath, fileFormat, False): @@ -2189,12 +2190,11 @@ def diffFile(self): Allows you to make comparisons using a temporary file, without saving your changes. """ path = self.currTab.getCurrentPath() - fd, tmpPath = tempfile.mkstemp(suffix=QtCore.QFileInfo(path).fileName()) + fd, tmpPath = tempfile.mkstemp(suffix=QtCore.QFileInfo(path).fileName(), dir=self.app.tmpDir) with os.fdopen(fd, 'w') as f: f.write(self.currTab.textEditor.toPlainText()) args = shlex.split(self.preferences['diffTool']) + [path, tmpPath] self.launchProcess(args) - # TODO: Cleanup temp file if/when diff tool is closed. @staticmethod def getPermissionString(path): @@ -2379,11 +2379,12 @@ def launchProgramOfChoice(self, path=None): def showAboutDialog(self, *args): """ Display a modal dialog box that shows the "about" information for the application. """ + from .version import __version__ captionText = "About {}".format(self.app.appDisplayName) - aboutText = ("App Name: {0}
" - "App Path: {1}
" - "Documentation: {2}".format( - self.app.appName, self.app.appPath, self.app.appURL)) + aboutText = ("App Name: {0} {1}
" + "App Path: {2}
" + "Documentation: {3}".format( + self.app.appName, __version__, self.app.appPath, self.app.appURL)) QtWidgets.QMessageBox.about(self, captionText, aboutText) @Slot(bool) @@ -2498,7 +2499,7 @@ def readUsdCrateFile(self, fileStr): logger.debug("Binary USD file detected. Converting to ASCII representation.") self.currTab.fileFormat = FILE_FORMAT_USDC self.tabWidget.setTabIcon(self.tabWidget.currentIndex(), self.binaryIcon) - usdPath = utils.generateTemporaryUsdFile(fileStr) + usdPath = utils.generateTemporaryUsdFile(fileStr, self.app.tmpDir) with open(usdPath) as f: fileText = f.readlines() os.remove(usdPath) @@ -2519,7 +2520,7 @@ def readUsdzFile(self, fileStr): logger.debug("Uncompressing usdz file...") self.currTab.fileFormat = FILE_FORMAT_USDZ self.tabWidget.setTabIcon(self.tabWidget.currentIndex(), self.zipIcon) - usdDir = utils.unzip(fileStr) + usdDir = utils.unzip(fileStr, self.app.tmpDir) return os.path.join(usdDir, os.path.basename(fileStr)) ''' @@ -2663,7 +2664,7 @@ def setSource(self, link, isNewFile=True, newTab=False, hScrollPos=0, vScrollPos # TODO: Support nested usdz references. usd = True layer = utils.queryItemValue(link, "layer") - dest = utils.unzip(fileStr, layer) + dest = utils.unzip(fileStr, layer, self.app.tmpDir) self.restoreOverrideCursor() return self.setSource(QtCore.QUrl(dest)) else: @@ -4191,6 +4192,7 @@ def run(self): """ self.appPath = sys.argv[0] self.appName = os.path.basename(self.appPath) + self.tmpDir = None parser = argparse.ArgumentParser(prog=os.path.basename(self.appPath), description = 'File Browser/Text Editor for quick navigation and\n' @@ -4295,6 +4297,9 @@ def mainLoop(self): """ Start the application loop. """ if not App._eventLoopStarted: + # Create a temp directory for cache-like files. + self.tmpDir = tempfile.mkdtemp(prefix=self.appName) + logger.debug("Temp directory: {}".format(self.tmpDir)) App._eventLoopStarted = True self.app.exec_() @@ -4303,6 +4308,10 @@ def onExit(self): """ Callback when the application is exiting. """ App._eventLoopStarted = False + + # Clean up our temp dir. + if self.tmpDir is not None: + shutil.rmtree(self.tmpDir, ignore_errors=True) class Settings(QtCore.QSettings): diff --git a/usdmanager/utils.py b/usdmanager/utils.py index 752fc80..9824f58 100644 --- a/usdmanager/utils.py +++ b/usdmanager/utils.py @@ -131,12 +131,14 @@ def findModules(subdir): return modules -def generateTemporaryUsdFile(usdFileName): +def generateTemporaryUsdFile(usdFileName, tmpDir=None): """ Generate a temporary ASCII USD file that the user can edit. :Parameters: usdFileName : `str` Binary USD file path + tmpDir : `str` | None + Temp directory to create the new unzipped directory within :Returns: Temporary file name :Rtype: @@ -144,7 +146,7 @@ def generateTemporaryUsdFile(usdFileName): :Raises OSError: If usdcat fails """ - fd, tmpFileName = tempfile.mkstemp(suffix=".usd") + fd, tmpFileName = tempfile.mkstemp(suffix=".usd", dir=tmpDir) try: usdcat(usdFileName, tmpFileName, format="usda") finally: @@ -204,7 +206,7 @@ def usdzip(inputs, dest): # TODO: Support nested references (e.g. @set.usdz[areas/shire.usdz[architecture/BilboHouse/Table.usd]]@) -def unzip(path, layer=None): +def unzip(path, layer=None, tmpDir=None): """ Unzip a usdz format file to a temporary directory. :Parameters: @@ -213,6 +215,8 @@ def unzip(path, layer=None): layer : `str` | None Default layer within file (e.g. the portion within the square brackets here: @foo.usdz[path/to/file/within/package.usd]@) + tmpDir : `str` | None + Temp directory to create the new unzipped directory within :Returns: Destination file :Rtype: @@ -222,8 +226,7 @@ def unzip(path, layer=None): :Raises ValueError: If default layer not found """ - # TODO: Clean up this temp dir when exiting the app? - destDir = tempfile.mkdtemp(prefix="usdmanager_usdz_") + destDir = tempfile.mkdtemp(prefix="usdmanager_usdz_", dir=tmpDir) cmd = "unzip {} -d {}".format(path, destDir) logger.debug(cmd) try: From ba33905d2ae34f9f4871e5255ce9ed08f182afe2 Mon Sep 17 00:00:00 2001 From: mds-dwa Date: Thu, 20 Jun 2019 14:26:17 -0700 Subject: [PATCH 4/5] [BUG] Support spaces in file names on Windows for usdview Signed-off-by: mds-dwa --- usdmanager/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/usdmanager/__init__.py b/usdmanager/__init__.py index 9732c8b..657b4c0 100755 --- a/usdmanager/__init__.py +++ b/usdmanager/__init__.py @@ -2339,9 +2339,15 @@ def launchTextEditor(self): def launchUsdView(self): """ Launch the current file in usdview. """ + app = self.app.appConfig.get("usdview", "usdview") path = self.currTab.getCurrentPath() - args = [self.app.appConfig.get("usdview", "usdview"), path] - self.launchProcess(args) + # Files with spaces have to be double-quoted on Windows for usdview. + if os.name == "nt": + cmd = '{} "{}"'.format(app, path) + self.launchProcess(cmd, shell=True) + else: + args = [app, path] + self.launchProcess(args) @Slot() def launchProgramOfChoice(self, path=None): From 46ecf51562fe29eedd85e00a58608f6f67dcd01c Mon Sep 17 00:00:00 2001 From: mds-dwa Date: Wed, 3 Jul 2019 12:13:11 -0700 Subject: [PATCH 5/5] [BUG] Windows support for open file descriptor with usdcat [ENH] Dark theme support, including sticky user preference [ENH] Indentation improvements Deprecated "-dark" flag in favor of "-theme light" or "-theme dark" to temporarily override the sticky user theme preference. Do not indent/unindent the ending line in a multi-line selection if the cursor has no selection on the last line. Allow Shift-Tab to unindent the current line when no characters are selected (previously, this shifted the widget focus). Signed-off-by: mds-dwa --- usdmanager/__init__.py | 81 ++++++++++++++++++++++---------- usdmanager/preferences_dialog.py | 15 ++++++ usdmanager/preferences_dialog.ui | 19 ++++++-- usdmanager/utils.py | 6 +-- usdmanager/version.py | 2 +- 5 files changed, 90 insertions(+), 33 deletions(-) diff --git a/usdmanager/__init__.py b/usdmanager/__init__.py index 657b4c0..54c40f2 100755 --- a/usdmanager/__init__.py +++ b/usdmanager/__init__.py @@ -246,13 +246,32 @@ def setupUi(self): """ self.baseInstance = utils.loadUiWidget('main_window.ui', self) - # Set usdview stylesheet. - if self.app.opts['dark']: + # You now have access to the widgets defined in the ui file. + self.defaultDocFont = QtGui.QFont() + self.defaultDocFont.setStyleHint(QtGui.QFont.Courier) + self.defaultDocFont.setFamily("Monospace") + self.defaultDocFont.setPointSize(9) + self.defaultDocFont.setBold(False) + self.defaultDocFont.setItalic(False) + + self.readSettings() + self.compileLinkRegEx() + + # Changing the theme while the app is already running doesn't work well. + # Currently, we set this once, and the user must restart the application to see changes. + userThemeName = self.app.opts['theme'] or self.preferences['theme'] + if userThemeName == "dark": + # Set usdview-based stylesheet. stylesheet = resource_filename(__name__, "usdviewstyle.qss") with open(stylesheet) as f: # Qt style sheet accepts only forward slashes as path separators. sheetString = f.read().replace('RESOURCE_DIR', os.path.dirname(stylesheet).replace("\\", "/")) self.setStyleSheet(sheetString) + + # Do some additional adjustments for any dark theme, even if it's coming from the system settings. + # TODO: Be able to make these adjustments on the fly if the user changes the system theme. + if self.isDarkTheme(): + highlighter.DARK_THEME = True # Change some more stuff that the stylesheet doesn't catch. p = QtWidgets.QApplication.palette() @@ -267,19 +286,6 @@ def setupUi(self): a.binary {{color:#69F}} span.badLink {{color:#F33}} {}""" - - highlighter.DARK_THEME = True - - # You now have access to the widgets defined in the ui file. - self.defaultDocFont = QtGui.QFont() - self.defaultDocFont.setStyleHint(QtGui.QFont.Courier) - self.defaultDocFont.setFamily("Monospace") - self.defaultDocFont.setPointSize(9) - self.defaultDocFont.setBold(False) - self.defaultDocFont.setItalic(False) - - self.readSettings() - self.compileLinkRegEx() searchPaths = QtGui.QIcon.themeSearchPaths() extraSearchPaths = [x for x in self.app.appConfig.get("themeSearchPaths", []) if x not in searchPaths] @@ -646,7 +652,8 @@ def readSettings(self): 'diffTool': self.config.value("diffTool", self.app.appConfig.get("diffTool", "xdiff")), 'autoCompleteAddressBar': self.config.boolValue("autoCompleteAddressBar", True), 'useSpaces': self.config.boolValue("useSpaces", True), - 'tabSpaces': int(self.config.value("tabSpaces", 4)) + 'tabSpaces': int(self.config.value("tabSpaces", 4)), + 'theme': self.config.value("theme", None), } # Read 'programs' settings object into self.programs. @@ -728,6 +735,7 @@ def writeSettings(self): self.config.setValue("autoCompleteAddressBar", self.preferences['autoCompleteAddressBar']) self.config.setValue("useSpaces", self.preferences['useSpaces']) self.config.setValue("tabSpaces", self.preferences['tabSpaces']) + self.config.setValue("theme", self.preferences['theme']) # Write self.programs to settings object exts = self.programs.keys() @@ -1604,7 +1612,7 @@ def find(self, flags=None, startPos=3, loop=True): if cursor.hasSelection(): # Found phrase. Set cursor and formatting. currTextWidget.setTextCursor(cursor) - self.findBar.setStyleSheet("QLineEdit{{background:{}}}".format("inherit" if self.app.opts['dark'] else "none")) + self.findBar.setStyleSheet("QLineEdit{{background:{}}}".format("inherit" if self.isDarkTheme() else "none")) if loop: # Didn't just loop through the document, so hide any messages. self.labelFindPixmap.setVisible(False) @@ -1924,6 +1932,7 @@ def editPreferences(self): self.preferences['font'] = dlg.getPrefFont() self.preferences['useSpaces'] = dlg.getPrefUseSpaces() self.preferences['tabSpaces'] = dlg.getPrefTabSpaces() + self.preferences['theme'] = dlg.getPrefTheme() # Update font and line number visibility in all tabs. self.tabWidget.setFont(self.preferences['font']) @@ -1999,7 +2008,7 @@ def validateFindBar(self, text): self.buttonHighlightAll.setEnabled(False) if self.buttonHighlightAll.isChecked(): self.findHighlightAll() - self.findBar.setStyleSheet("QLineEdit{{background:{}}}".format("inherit" if self.app.opts['dark'] else "none")) + self.findBar.setStyleSheet("QLineEdit{{background:{}}}".format("inherit" if self.isDarkTheme() else "none")) self.labelFindPixmap.setVisible(False) self.labelFindStatus.setVisible(False) @@ -3028,6 +3037,17 @@ def currentTabChanged(self, idx): if not self.quitting: self.findHighlightAll() + def isDarkTheme(self): + """ Check if any dark theme is active based on the background lightness. + + :Returns: + True if the lightness factor of the window background is less than 0.5. + The 0.5 threshold to determine if it's dark is completely arbitrary. + :Rtype: + `bool` + """ + return self.palette().window().color().lightnessF() < 0.5 + def updateButtons(self): """ Update button states, text fields, and other GUI elements. """ @@ -3733,7 +3753,7 @@ def keyPressEvent(self, e): # Otherwise, QTextEdit already handles inserting the tab character. self.insertPlainText(" " * self.tabSpaces) return - elif e.key() == QtCore.Qt.Key_Backtab and e.modifiers() == QtCore.Qt.ShiftModifier and self.textCursor().hasSelection(): + elif e.key() == QtCore.Qt.Key_Backtab and e.modifiers() == QtCore.Qt.ShiftModifier: self.unindentText() return super(TextEdit, self).keyPressEvent(e) @@ -3844,7 +3864,7 @@ def indentText(self): cursor.movePosition(cursor.StartOfBlock) cursor.beginEditBlock() # Modify all blocks between selectionStart and selectionEnd - while cursor.position() <= end and not cursor.atEnd(): + while cursor.position() < end and not cursor.atEnd(): if self.useSpaces: if self.tabSpaces: cursor.insertText(" " * self.tabSpaces) @@ -3869,7 +3889,7 @@ def unindentText(self): cursor.movePosition(cursor.StartOfBlock) cursor.beginEditBlock() # Modify all blocks between selectionStart and selectionEnd - while cursor.position() <= end and not cursor.atEnd(): + while cursor.position() < end and not cursor.atEnd(): currBlock = cursor.blockNumber() for i in range(self.tabSpaces): @@ -3915,7 +3935,7 @@ def __init__(self, parent=None): """ super(BrowserTab, self).__init__(parent) - if self.window().app.opts['dark']: + if self.window().isDarkTheme(): color = QtGui.QColor(35, 35, 35).name() else: color = self.style().standardPalette().base().color().darker(105).name() @@ -4204,10 +4224,18 @@ def run(self): description = 'File Browser/Text Editor for quick navigation and\n' 'editing among text-based files that reference other files.\n\n') parser.add_argument('fileName', nargs='*', help='The file(s) to view.') - parser.add_argument("-dark", + + group = parser.add_mutually_exclusive_group() + group.add_argument("-theme", + choices=["light", "dark"], + help="Override the user theme preference. Use the Preferences dialog to save this setting)" + ) + # Legacy flag, now equivalent to "-theme dark" + group.add_argument("-dark", action="store_true", - help="Use usdview-like dark Qt theme" + help=argparse.SUPPRESS ) + parser.add_argument("-info", action="store_true", help="Log info messages" @@ -4217,11 +4245,14 @@ def run(self): help="Log debugging messages" ) results = parser.parse_args() + if results.dark: + results.theme = "dark" + logger.warning('The -dark flag has been deprecated. Please use "-theme dark" instead.') self.opts = { 'dir': os.getcwd(), 'info': results.info, 'debug': results.debug, - 'dark': results.dark + 'theme': results.theme, } # Initialize the application and settings. diff --git a/usdmanager/preferences_dialog.py b/usdmanager/preferences_dialog.py index c6798f8..08b1916 100644 --- a/usdmanager/preferences_dialog.py +++ b/usdmanager/preferences_dialog.py @@ -76,6 +76,7 @@ def setupUi(self, widget): self.useSpacesSpinBox.setValue(parent.preferences['tabSpaces']) self.lineEditTextEditor.setText(parent.preferences['textEditor']) self.lineEditDiffTool.setText(parent.preferences['diffTool']) + self.themeWidget.setChecked(parent.preferences['theme'] == "dark") self.updateFontLabel() # ----- Programs tab ----- @@ -215,6 +216,19 @@ def getPrefTextEditor(self): """ return self.lineEditTextEditor.text() + def getPrefTheme(self): + """ Get the selected theme. + + We may eventually make this a combo box supporting multiple themes, + so use the string name instead of just a boolean. + + :Returns: + Selected theme name, or None if the default + :Rtype: + `str` | None + """ + return "dark" if self.themeWidget.isChecked() else None + def getPrefUseSpaces(self): """ :Returns: @@ -318,6 +332,7 @@ def restoreDefaults(self, btn): self.lineEditDiffTool.setText(window.app.appConfig.get("diffTool", "xdiff")) self.useSpacesCheckBox.setChecked(True) self.useSpacesSpinBox.setValue(4) + self.themeWidget.setChecked(False) self.docFont = window.defaultDocFont self.updateFontLabel() diff --git a/usdmanager/preferences_dialog.ui b/usdmanager/preferences_dialog.ui index a67e332..c4f17fc 100644 --- a/usdmanager/preferences_dialog.ui +++ b/usdmanager/preferences_dialog.ui @@ -7,7 +7,7 @@ 0 0 463 - 519 + 574 @@ -162,6 +162,16 @@ + + + + Use the dark UI theme. You must restart the application to see any changes for this setting. + + + Dark theme (restart to see changes) + + + @@ -254,8 +264,8 @@ 0 0 - 417 - 260 + 119 + 72 @@ -415,6 +425,9 @@ checkBox_showAllMessages checkBox_showHiddenFiles checkBox_autoCompleteAddressBar + useSpacesCheckBox + useSpacesSpinBox + themeWidget lineEditTextEditor lineEditDiffTool buttonFont diff --git a/usdmanager/utils.py b/usdmanager/utils.py index 9824f58..2f9a8da 100644 --- a/usdmanager/utils.py +++ b/usdmanager/utils.py @@ -147,10 +147,8 @@ def generateTemporaryUsdFile(usdFileName, tmpDir=None): If usdcat fails """ fd, tmpFileName = tempfile.mkstemp(suffix=".usd", dir=tmpDir) - try: - usdcat(usdFileName, tmpFileName, format="usda") - finally: - os.close(fd) + os.close(fd) + usdcat(usdFileName, tmpFileName, format="usda") return tmpFileName diff --git a/usdmanager/version.py b/usdmanager/version.py index 2797b2f..e1cd976 100644 --- a/usdmanager/version.py +++ b/usdmanager/version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = '0.5.0' +__version__ = '0.6.0'