From 235c087385a6e959ba7edefe4a3cbbbc00b2a534 Mon Sep 17 00:00:00 2001 From: Joe Wreschnig Date: Tue, 12 Mar 2013 12:45:20 +0100 Subject: [PATCH] Localization support. Change many names in NJKeyInputField to standard keyboard shortcut symbols. --- .../NSRunningApplication+NJPossibleNames.m | 9 +- Classes/NJDeviceController.m | 8 +- Classes/NJInputAnalog.m | 6 +- Classes/NJInputButton.m | 6 +- Classes/NJInputHat.m | 10 +- Classes/NJKeyInputField.h | 2 +- Classes/NJKeyInputField.m | 92 +++++++++--------- Classes/NJMapping.m | 15 ++- Classes/NJMappingMenuController.m | 11 ++- Classes/NJMappingsController.m | 23 ++--- Enjoyable.xcodeproj/project.pbxproj | 12 +++ Info.plist | 2 +- Resources/English.lproj/Localizable.strings | Bin 0 -> 6326 bytes 13 files changed, 114 insertions(+), 82 deletions(-) create mode 100644 Resources/English.lproj/Localizable.strings diff --git a/Categories/NSRunningApplication+NJPossibleNames.m b/Categories/NSRunningApplication+NJPossibleNames.m index a3fdaf5..895134c 100644 --- a/Categories/NSRunningApplication+NJPossibleNames.m +++ b/Categories/NSRunningApplication+NJPossibleNames.m @@ -45,8 +45,13 @@ return self.localizedName; else if (self.bundleIdentifier) return self.bundleIdentifier; - else - return @"@Application"; + else { + return NSLocalizedString(@"@Application", + @"Magic string to trigger automatic " + @"mapping renames. It should look like " + @"an identifier rather than normal " + @"word, with the @ on the front."); + } } @end diff --git a/Classes/NJDeviceController.m b/Classes/NJDeviceController.m index 2849838..2ce3fa9 100644 --- a/Classes/NJDeviceController.m +++ b/Classes/NJDeviceController.m @@ -202,13 +202,13 @@ static void remove_callback(void *ctx, IOReturn inResult, void *inSender, IOHIDD IOHIDManagerSetDeviceMatchingMultiple(_hidManager, (__bridge CFArrayRef)criteria); IOReturn ret = IOHIDManagerOpen(_hidManager, kIOHIDOptionsTypeNone); if (ret != kIOReturnSuccess) { - [[NSAlert alertWithMessageText:@"Input devices are unavailable" + [[NSAlert alertWithMessageText:NSLocalizedString(@"input devices unavailable", + @"error title when devices can't be read") defaultButton:nil alternateButton:nil otherButton:nil - informativeTextWithFormat:@"Error 0x%08x occured trying to access your devices. " - @"Input may not be correctly detected or mapped.", - ret] + informativeTextWithFormat:NSLocalizedString(@"input error 0x%08x occurred", + @"message containing IOReturn failure code when devices can't be read"), ret] beginSheetModalForWindow:outlineView.window modalDelegate:nil didEndSelector:nil diff --git a/Classes/NJInputAnalog.m b/Classes/NJInputAnalog.m index 7b4b15a..41a39f2 100644 --- a/Classes/NJInputAnalog.m +++ b/Classes/NJInputAnalog.m @@ -21,9 +21,9 @@ static float normalize(long p, long min, long max) { - (id)initWithIndex:(int)index rawMin:(long)rawMin_ rawMax:(long)rawMax_ { if ((self = [super init])) { - self.name = [[NSString alloc] initWithFormat: @"Axis %d", index]; - self.children = @[[[NJInput alloc] initWithName:@"Low" base:self], - [[NJInput alloc] initWithName:@"High" base:self]]; + self.name = [[NSString alloc] initWithFormat:NSLocalizedString(@"axis %d", @"axis name"), index]; + self.children = @[[[NJInput alloc] initWithName:NSLocalizedString(@"axis low", @"axis low trigger") base:self], + [[NJInput alloc] initWithName:NSLocalizedString(@"axis high", @"axis high trigger") base:self]]; rawMax = rawMax_; rawMin = rawMin_; } diff --git a/Classes/NJInputButton.m b/Classes/NJInputButton.m index 0c3b0ce..caa4d8e 100644 --- a/Classes/NJInputButton.m +++ b/Classes/NJInputButton.m @@ -14,10 +14,10 @@ - (id)initWithName:(NSString *)name idx:(int)idx max:(long)max { if ((self = [super init])) { _max = max; + self.name = [NSString stringWithFormat:NSLocalizedString(@"button %d", @"button name"), idx]; + if (name.length) - self.name = [NSString stringWithFormat:@"Button %d - %@", idx, name]; - else - self.name = [NSString stringWithFormat:@"Button %d", idx]; + self.name = [self.name stringByAppendingFormat:@"- %@", name]; } return self; } diff --git a/Classes/NJInputHat.m b/Classes/NJInputHat.m index e0e127f..d267b71 100644 --- a/Classes/NJInputHat.m +++ b/Classes/NJInputHat.m @@ -31,11 +31,11 @@ static BOOL active_fourway[20] = { - (id)initWithIndex:(int)index { if ((self = [super init])) { - self.children = @[[[NJInput alloc] initWithName:@"Up" base:self], - [[NJInput alloc] initWithName:@"Down" base:self], - [[NJInput alloc] initWithName:@"Left" base:self], - [[NJInput alloc] initWithName:@"Right" base:self]]; - self.name = [NSString stringWithFormat:@"Hat Switch %d", index]; + self.children = @[[[NJInput alloc] initWithName:NSLocalizedString(@"hat up", @"hat switch up state") base:self], + [[NJInput alloc] initWithName:NSLocalizedString(@"hat down", @"hat switch down state") base:self], + [[NJInput alloc] initWithName:NSLocalizedString(@"hat left", @"hat switch left state") base:self], + [[NJInput alloc] initWithName:NSLocalizedString(@"hat right", @"hat switch right state") base:self]]; + self.name = [NSString stringWithFormat:NSLocalizedString(@"hat switch %d", @"hat switch name"), index]; } return self; } diff --git a/Classes/NJKeyInputField.h b/Classes/NJKeyInputField.h index 9a7a3af..84498ff 100644 --- a/Classes/NJKeyInputField.h +++ b/Classes/NJKeyInputField.h @@ -7,7 +7,7 @@ #import -extern CGKeyCode NJKeyInputFieldEmpty; +extern const CGKeyCode NJKeyInputFieldEmpty; @protocol NJKeyInputFieldDelegate; diff --git a/Classes/NJKeyInputField.m b/Classes/NJKeyInputField.m index f4525e5..2073d8d 100644 --- a/Classes/NJKeyInputField.m +++ b/Classes/NJKeyInputField.m @@ -7,7 +7,7 @@ #import "NJKeyInputField.h" -CGKeyCode NJKeyInputFieldEmpty = 0xFFFF; +const CGKeyCode NJKeyInputFieldEmpty = 0xFFFF; @implementation NJKeyInputField @@ -33,7 +33,6 @@ CGKeyCode NJKeyInputFieldEmpty = 0xFFFF; + (NSString *)stringForKeyCode:(CGKeyCode)keyCode { switch (keyCode) { - case 0xffff: return @""; case 0x7a: return @"F1"; case 0x78: return @"F2"; case 0x63: return @"F3"; @@ -54,7 +53,7 @@ CGKeyCode NJKeyInputFieldEmpty = 0xFFFF; case 0x4f: return @"F18"; case 0x50: return @"F19"; - case 0x35: return @"Esc"; + case 0x35: return @"⎋"; case 0x32: return @"`"; case 0x12: return @"1"; @@ -71,26 +70,27 @@ CGKeyCode NJKeyInputFieldEmpty = 0xFFFF; case 0x18: return @"="; case 0x3f: return @"Fn"; - case 0x36: return @"Right Command"; - case 0x37: return @"Left Command"; - case 0x38: return @"Left Shift"; - case 0x39: return @"Caps Lock"; - case 0x3a: return @"Left Option"; - case 0x3b: return @"Left Control"; - case 0x3c: return @"Right Shift"; - case 0x3d: return @"Right Option"; - case 0x3e: return @"Right Control"; + case 0x36: return NSLocalizedString(@"Right ⌘", @"keyboard key"); + case 0x37: return NSLocalizedString(@"Left ⌘", @"keyboard key"); + case 0x38: return NSLocalizedString(@"Left ⇧", @"keyboard key"); + case 0x39: return @"⇪"; + case 0x3a: return NSLocalizedString(@"Left ⌥", @"keyboard key"); + case 0x3b: return NSLocalizedString(@"Left ⌃", @"keyboard key"); + case 0x3c: return NSLocalizedString(@"Right ⇧", @"keyboard key"); + case 0x3d: return NSLocalizedString(@"Right ⌃", @"keyboard key"); + case 0x3e: return NSLocalizedString(@"Right ⌥", @"keyboard key"); - case 0x73: return @"Home"; - case 0x74: return @"Page Up"; - case 0x75: return @"Delete"; - case 0x77: return @"End"; - case 0x79: return @"Page Down"; + case 0x73: return @"↖"; + case 0x74: return @"⇞"; + case 0x77: return @"↘"; + case 0x79: return @"⇟"; + + case 0x75: return @"⌦"; + case 0x33: return @"⌫"; - case 0x30: return @"Tab"; - case 0x33: return @"Backspace"; - case 0x24: return @"Return"; - case 0x31: return @"Space"; + case 0x30: return @"⇥"; + case 0x24: return @"↩"; + case 0x31: return @"␣"; case 0x0c: return @"Q"; case 0x0d: return @"W"; @@ -127,31 +127,35 @@ CGKeyCode NJKeyInputFieldEmpty = 0xFFFF; case 0x2f: return @"."; case 0x2c: return @"/"; - case 0x47: return @"Clear"; - case 0x51: return @"Keypad ="; - case 0x4b: return @"Keypad /"; - case 0x43: return @"Keypad *"; - case 0x59: return @"Keypad 7"; - case 0x5b: return @"Keypad 8"; - case 0x5c: return @"Keypad 9"; - case 0x4e: return @"Keypad -"; - case 0x56: return @"Keypad 4"; - case 0x57: return @"Keypad 5"; - case 0x58: return @"Keypad 6"; - case 0x45: return @"Keypad +"; - case 0x53: return @"Keypad 1"; - case 0x54: return @"Keypad 2"; - case 0x55: return @"Keypad 3"; - case 0x52: return @"Keypad 0"; - case 0x41: return @"Keypad ."; - case 0x4c: return @"Enter"; + case 0x47: return @"⌧"; + case 0x51: return NSLocalizedString(@"Key Pad =", @"numeric pad key"); + case 0x4b: return NSLocalizedString(@"Key Pad /", @"numeric pad key"); + case 0x43: return NSLocalizedString(@"Key Pad *", @"numeric pad key"); + case 0x59: return NSLocalizedString(@"Key Pad 7", @"numeric pad key"); + case 0x5b: return NSLocalizedString(@"Key Pad 8", @"numeric pad key"); + case 0x5c: return NSLocalizedString(@"Key Pad 9", @"numeric pad key"); + case 0x4e: return NSLocalizedString(@"Key Pad -", @"numeric pad key"); + case 0x56: return NSLocalizedString(@"Key Pad 4", @"numeric pad key"); + case 0x57: return NSLocalizedString(@"Key Pad 5", @"numeric pad key"); + case 0x58: return NSLocalizedString(@"Key Pad 6", @"numeric pad key"); + case 0x45: return NSLocalizedString(@"Key Pad +", @"numeric pad key"); + case 0x53: return NSLocalizedString(@"Key Pad 1", @"numeric pad key"); + case 0x54: return NSLocalizedString(@"Key Pad 2", @"numeric pad key"); + case 0x55: return NSLocalizedString(@"Key Pad 3", @"numeric pad key"); + case 0x52: return NSLocalizedString(@"Key Pad 0", @"numeric pad key"); + case 0x41: return NSLocalizedString(@"Key Pad .", @"numeric pad key"); + case 0x4c: return @"⌤"; - case 0x7e: return @"Up"; - case 0x7d: return @"Down"; - case 0x7b: return @"Left"; - case 0x7c: return @"Right"; + case 0x7e: return @"↑"; + case 0x7d: return @"↓"; + case 0x7b: return @"←"; + case 0x7c: return @"→"; + case 0xffff: // NJKeyInputFieldEmpty + return @""; default: - return [[NSString alloc] initWithFormat:@"Key 0x%x", keyCode]; + return [[NSString alloc] initWithFormat: + NSLocalizedString(@"key 0x%x", @"unknown key code"), + keyCode]; } } diff --git a/Classes/NJMapping.m b/Classes/NJMapping.m index 355dbcc..0e67cd3 100644 --- a/Classes/NJMapping.m +++ b/Classes/NJMapping.m @@ -17,14 +17,22 @@ // Extra checks during initialization because the data is often loaded // from untrusted serializations. -- (id)initWithName:(NSString *)name { +- (id)init { if ((self = [super init])) { - self.name = [name isKindOfClass:NSString.class] ? name : @"Untitled"; + self.name = NSLocalizedString(@"Untitled", @"name for new mappings"); _entries = [[NSMutableDictionary alloc] init]; } return self; } +- (id)initWithName:(NSString *)name { + if ((self = [self init])) { + if ([name isKindOfClass:NSString.class]) + self.name = name; + } + return self; +} + - (id)initWithSerialization:(NSDictionary *)serialization mappings:(NSArray *)mappings { if ((self = [self initWithName:serialization[@"name"]])) { @@ -108,7 +116,8 @@ && [serialization[@"entries"] isKindOfClass:NSDictionary.class])) { *error = [NSError errorWithDomain:@"Enjoyable" code:0 - description:@"This isn't a valid mapping file."]; + description:NSLocalizedString(@"invalid mapping file", + @"error when imported file was JSON but not a mapping")]; return nil; } diff --git a/Classes/NJMappingMenuController.m b/Classes/NJMappingMenuController.m index 882a984..03ce31d 100644 --- a/Classes/NJMappingMenuController.m +++ b/Classes/NJMappingMenuController.m @@ -76,7 +76,8 @@ [self.menu insertItem:item atIndex:index++]; if (added == MAXIMUM_MAPPINGS_IN_MENU && mappings.count > MAXIMUM_MAPPINGS_IN_MENU + 1) { - NSString *msg = [NSString stringWithFormat:@"(and %lu more…)", + NSString *msg = [NSString stringWithFormat:NSLocalizedString(@"mapping overflow %lu", + @"menu item when mappings list overflows"), mappings.count - MAXIMUM_MAPPINGS_IN_MENU]; NSMenuItem *end = [[NSMenuItem alloc] initWithTitle:msg action:@selector(_mappingListWasChosen:) @@ -99,13 +100,13 @@ } - (void)eventTranslationActivated:(NSNotification *)note { - self.eventTranslationToggle.title = @"Disable"; + self.eventTranslationToggle.title = NSLocalizedString(@"Disable", + @"menu item text to disable event translation"); } - (void)eventTranslationDeactivated:(NSNotification *)note { - self.eventTranslationToggle.title = @"Enable"; + self.eventTranslationToggle.title = NSLocalizedString(@"Enable", + @"menu item text to enable event translation"); } - - @end diff --git a/Classes/NJMappingsController.m b/Classes/NJMappingsController.m index 5faa4bf..500e901 100644 --- a/Classes/NJMappingsController.m +++ b/Classes/NJMappingsController.m @@ -22,7 +22,8 @@ - (id)init { if ((self = [super init])) { _mappings = [[NSMutableArray alloc] init]; - _currentMapping = [[NJMapping alloc] initWithName:@"(default)"]; + _currentMapping = [[NJMapping alloc] initWithName: + NSLocalizedString(@"(default)", @"default name for first the mapping")]; _manualMapping = _currentMapping; [_mappings addObject:_currentMapping]; } @@ -79,7 +80,9 @@ if (!found) { [self activateMapping:oldMapping]; - if ([oldMapping.name.lowercaseString isEqualToString:@"@application"]) { + if ([oldMapping.name.lowercaseString isEqualToString:@"@application"] + || [oldMapping.name.lowercaseString isEqualToString: + NSLocalizedString(@"@Application", nil).lowercaseString]) { oldMapping.name = app.bestMappingName; [self mappingsChanged]; } @@ -113,7 +116,7 @@ } - (IBAction)addPressed:(id)sender { - NJMapping *newMapping = [[NJMapping alloc] initWithName:@"Untitled"]; + NJMapping *newMapping = [[NJMapping alloc] init]; [_mappings addObject:newMapping]; [self activateMapping:newMapping]; [self mappingsChanged]; @@ -231,15 +234,13 @@ NJMapping *mergeInto = self[mapping.name]; if ([mergeInto hasConflictWith:mapping]) { NSAlert *conflictAlert = [[NSAlert alloc] init]; - conflictAlert.messageText = @"Replace existing mappings?"; + conflictAlert.messageText = NSLocalizedString(@"import conflict prompt", @"Title of import conflict alert"); conflictAlert.informativeText = - [NSString stringWithFormat: - @"This file contains inputs you've already mapped in \"%@\". Do you " - @"want to merge them and replace your existing mappings, or import this " - @"as a separate mapping?", mapping.name]; - [conflictAlert addButtonWithTitle:@"Merge"]; - [conflictAlert addButtonWithTitle:@"Cancel"]; - [conflictAlert addButtonWithTitle:@"New Mapping"]; + [NSString stringWithFormat:NSLocalizedString(@"import conflict in %@", @"Explanation of import conflict"), + mapping.name]; + [conflictAlert addButtonWithTitle:NSLocalizedString(@"import and merge", @"button to merge imported mappings")]; + [conflictAlert addButtonWithTitle:NSLocalizedString(@"cancel import", @"button to cancel import")]; + [conflictAlert addButtonWithTitle:NSLocalizedString(@"import new mapping", @"button to import as new mapping")]; [conflictAlert beginSheetModalForWindow:popoverActivate.window modalDelegate:self didEndSelector:@selector(mappingConflictDidResolve:returnCode:contextInfo:) diff --git a/Enjoyable.xcodeproj/project.pbxproj b/Enjoyable.xcodeproj/project.pbxproj index 7b879c4..ef109f0 100644 --- a/Enjoyable.xcodeproj/project.pbxproj +++ b/Enjoyable.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; D594BF000FAE7397007A85F2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D594BEFF0FAE7397007A85F2 /* IOKit.framework */; }; + EE1F3CEA16EF4182008C6426 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = EE1F3CE816EF4182008C6426 /* Localizable.strings */; }; EE3D897A16EA7EFC00596D1F /* Status Menu Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */; }; EE3D897C16EA806E00596D1F /* Status Menu Icon Disabled@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */; }; EE3D897F16EA817E00596D1F /* Status Menu Icon Disabled.png in Resources */ = {isa = PBXBuildFile; fileRef = EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */; }; @@ -69,6 +70,7 @@ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8D1107320486CEB800E47090 /* Enjoyable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Enjoyable.app; sourceTree = BUILT_PRODUCTS_DIR; }; D594BEFF0FAE7397007A85F2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + EE1F3CE916EF4182008C6426 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = Resources/English.lproj/Localizable.strings; sourceTree = ""; }; EE3D897916EA7EFC00596D1F /* Status Menu Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon@2x.png"; path = "Resources/Status Menu Icon@2x.png"; sourceTree = ""; }; EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon Disabled@2x.png"; path = "Resources/Status Menu Icon Disabled@2x.png"; sourceTree = ""; }; EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Status Menu Icon Disabled.png"; path = "Resources/Status Menu Icon Disabled.png"; sourceTree = ""; }; @@ -247,6 +249,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + EE1F3CE816EF4182008C6426 /* Localizable.strings */, EE3D897D16EA817E00596D1F /* Status Menu Icon Disabled.png */, EE3D897E16EA817E00596D1F /* Status Menu Icon.png */, EE3D897B16EA806E00596D1F /* Status Menu Icon Disabled@2x.png */, @@ -355,6 +358,7 @@ EE3D897C16EA806E00596D1F /* Status Menu Icon Disabled@2x.png in Resources */, EE3D897F16EA817E00596D1F /* Status Menu Icon Disabled.png in Resources */, EE3D898016EA817E00596D1F /* Status Menu Icon.png in Resources */, + EE1F3CEA16EF4182008C6426 /* Localizable.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -428,6 +432,14 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ + EE1F3CE816EF4182008C6426 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + EE1F3CE916EF4182008C6426 /* English */, + ); + name = Localizable.strings; + sourceTree = ""; + }; EEF17D1B16E8E23A00D7DC4D /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( diff --git a/Info.plist b/Info.plist index 1ce7758..7ca8cd3 100644 --- a/Info.plist +++ b/Info.plist @@ -46,7 +46,7 @@ CFBundleSignature ???? CFBundleVersion - 175 + 182 LSApplicationCategoryType public.app-category.utilities NSHumanReadableCopyright diff --git a/Resources/English.lproj/Localizable.strings b/Resources/English.lproj/Localizable.strings new file mode 100644 index 0000000000000000000000000000000000000000..4a5592664fabb56b3e5c70398f94643849762d06 GIT binary patch literal 6326 zcmb`MT~8ZF6oyCYU4B6?-9$7gZGnELs-h-MkU|^MDj#>fF}49K#$~FXNGkpr zoBU%vIr7X9@dWW8oFerWrAH}aqAH!+Op(_`_nvM@cPN1ujg z=IN1H=$5i8`E~t{+`HXyDG76-Mt`KJCEAwkO_HBo^Z0tbyi>_Nkq=fQ6m3ZI;!^)JrEe7q^n_JCo#B##zcevYa7ni0-Nn|&q8hj(g`$0I$_OSx5A9tS$XSazfPLicC7 z<9cZpxQ%_$=E69Vjb!#9eAJIT_Kcu5=AxzCO}f1(c#~e$^}FiiRlkWw`<4~Xne-`F zb8V=7?{HUdRgbHi{=QiBU$v` zp7Q9|)jTybvs0?9_<>btc|y^TV^);ifvTaJleDDA;Wa|(*?raJ)G7^cawdA8nxS=HEgDm+Ox9P%Tjo=Pf?-uETorTs(E@UeT{$xv%KXQ3~fd z-3?ptpHDYY7k{4HiSDye=_^ih_d?g~?Mm9*aOlmk3zX7+l`VNjy_1B+(u22)8=fQM z?h?bP_A@z6#g(G?#&o4qyH9TRL{~5;o%DXaly)f1(^Oje z6%S#vPi)D@7m69Dg-^mC<$Y`?KmA;OXnsA?T1UK|pShkfqgVOQCAF*UCjaqi^-MVs z-K$}hmwW+nos2wV$n&}Wn4aM&>n`T-LHIKe--Tq(%wDE`G~+q)G3`=GZTTek`kv}) zE9`~Gx-$Fr^anQR`P8{@YaXd}Jl+*}N4Sy=UZp;bkh>ni)MJP_mZj*@J#zn(hjbk# zcWgy@1&QZ|L@_g;`Z7!;%z5s zNNw-5s@6oA(QvarZjn$RG0)za$Nlw*Xvi5`d(r2JJk>XF! zu&8OIc$_b@Ui62&OGFYS&v|B2@9+M;IF*)lvu~90*OIhtqqLt8!(`? zf$>8F2DCOXer&*i)&|B;4H(eczMI_|Io`REQq~Rl-@BY5*6lNplvO)N~!#C($=bK}nzFd^iudZ({HP3)t w>fLi7=gzaBy1u!tc_!pitGSTA;KctN)W5gok$$hJ@t*B(y!l(eDg_Jv2UP>aPXGV_ literal 0 HcmV?d00001 -- 2.20.1