diff --git a/Samples/MultiThreadedHTTPServer/AppDelegate.h b/Samples/MultiThreadedHTTPServer/AppDelegate.h new file mode 100644 index 00000000..b92cb926 --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/AppDelegate.h @@ -0,0 +1,11 @@ +#import + +@class HTTPServer; + + +@interface AppDelegate : NSObject +{ + HTTPServer *httpServer; +} + +@end diff --git a/Samples/MultiThreadedHTTPServer/AppDelegate.m b/Samples/MultiThreadedHTTPServer/AppDelegate.m new file mode 100644 index 00000000..6e9ec0af --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/AppDelegate.m @@ -0,0 +1,25 @@ +#import "AppDelegate.h" +#import "ThreadPoolServer.h" +#import "ThreadPerConnectionServer.h" + + +@implementation AppDelegate + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + httpServer = [[ThreadPoolServer alloc] init]; +// httpServer = [[ThreadPerConnectionServer alloc] init]; + + [httpServer setType:@"_http._tcp."]; + [httpServer setDocumentRoot:[NSURL fileURLWithPath:[@"~/Sites" stringByExpandingTildeInPath]]]; + + NSError *error = nil; + BOOL success = [httpServer start:&error]; + + if(!success) + { + NSLog(@"Error starting HTTP Server: %@", error); + } +} + +@end diff --git a/Samples/MultiThreadedHTTPServer/English.lproj/InfoPlist.strings b/Samples/MultiThreadedHTTPServer/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..cc2655a2 Binary files /dev/null and b/Samples/MultiThreadedHTTPServer/English.lproj/InfoPlist.strings differ diff --git a/Samples/MultiThreadedHTTPServer/English.lproj/MainMenu.nib/designable.nib b/Samples/MultiThreadedHTTPServer/English.lproj/MainMenu.nib/designable.nib new file mode 100644 index 00000000..0906a0ac --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/English.lproj/MainMenu.nib/designable.nib @@ -0,0 +1,2447 @@ + + + + 0 + 9E17 + 629 + 949.33 + 352.00 + + YES + + + + + YES + com.apple.InterfaceBuilderKit + com.apple.InterfaceBuilder.CocoaPlugin + + + YES + + NSApplication + + + FirstResponder + + + + + + AMainMenu + + YES + + + NewApplication + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + + NSMenuMixedState + + submenuAction: + + + + YES + + + About NewApplication + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + UHJlZmVyZW5jZXPigKY + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide NewApplication + h + 1048576 + 2147483647 + + + + + + Hide Others + + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit NewApplication + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + New + n + 1048576 + 2147483647 + + + + + + T3BlbuKApg + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save + s + 1048576 + 2147483647 + + + + + + U2F2ZSBBc+KApg + S + 1179648 + 2147483647 + + + + + + Revert to Saved + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup... + P + 1179648 + 2147483647 + + + + + + + UHJpbnTigKY + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + RmluZOKApg + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + U2hvdyBTcGVsbGluZ+KApg + : + 1048576 + 2147483647 + + + + + + Check Spelling + ; + 1048576 + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Smart Copy/Paste + + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + + 1048576 + 2147483647 + + + 2 + + + + Smart Links + + 1179648 + 2147483647 + + + 3 + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Format + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Show Fonts + t + 1048576 + 2147483647 + + + + + + Show Colors + C + 1179648 + 2147483647 + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Show Toolbar + + 1572864 + 2147483647 + + + + + + Q3VzdG9taXplIFRvb2xiYXLigKY + + 1048576 + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + NewApplication Help + ? + 1048576 + 2147483647 + + + + + + + + _NSMainMenu + + + 15 + 2 + {{335, 390}, {480, 360}} + 1946157056 + + NSWindow + + + + 256 + {480, 360} + + + + {{0, 0}, {1680, 1028}} + + + AppDelegate + + + + + YES + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + clearRecentDocuments: + + + + 127 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + showHelp: + + + + 360 + + + + orderFrontColorPanel: + + + + 361 + + + + saveDocument: + + + + 362 + + + + saveDocumentAs: + + + + 363 + + + + revertDocumentToSaved: + + + + 364 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + terminate: + + + + 369 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 373 + + + + openDocument: + + + + 374 + + + + delegate + + + + 376 + + + + + YES + + 0 + + YES + + + + + + -2 + + + RmlsZSdzIE93bmVyA + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + + MainMenu + + + 19 + + + YES + + + + + + 56 + + + YES + + + + + + 103 + + + YES + + + + 1 + + + 217 + + + YES + + + + + + 83 + + + YES + + + + + + 81 + + + YES + + + + + + + + + + + + + + + + 75 + + + 3 + + + 80 + + + 8 + + + 78 + + + 6 + + + 72 + + + + + 82 + + + 9 + + + 124 + + + YES + + + + + + 77 + + + 5 + + + 73 + + + + + + 79 + + + 7 + + + 112 + + + 10 + + + 74 + + + 2 + + + 125 + + + YES + + + + + + 126 + + + + + 205 + + + YES + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + YES + + + + + + 216 + + + YES + + + + + + 200 + + + YES + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + YES + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 106 + + + YES + + + + + + + 111 + + + + + 57 + + + YES + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + 1111 + + + 144 + + + + + 129 + + + 121 + + + 143 + + + + + 236 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 24 + + + YES + + + + + + + + + 92 + + + + + 5 + + + + + 239 + + + + + 23 + + + + + 295 + + + YES + + + + + + 296 + + + YES + + + + + + + 297 + + + + + 298 + + + + + 299 + + + YES + + + + + + 300 + + + YES + + + + + + + 344 + + + + + 345 + + + + + 211 + + + YES + + + + + + 212 + + + YES + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + YES + + + + + + 349 + + + YES + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 371 + + + YES + + + + + + 372 + + + + + 375 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 103.IBPluginDependency + 103.ImportedFromIB2 + 106.IBPluginDependency + 106.ImportedFromIB2 + 106.editorWindowContentRectSynchronizationRect + 111.IBPluginDependency + 111.ImportedFromIB2 + 112.IBPluginDependency + 112.ImportedFromIB2 + 124.IBPluginDependency + 124.ImportedFromIB2 + 125.IBPluginDependency + 125.ImportedFromIB2 + 125.editorWindowContentRectSynchronizationRect + 126.IBPluginDependency + 126.ImportedFromIB2 + 129.IBPluginDependency + 129.ImportedFromIB2 + 130.IBPluginDependency + 130.ImportedFromIB2 + 130.editorWindowContentRectSynchronizationRect + 131.IBPluginDependency + 131.ImportedFromIB2 + 134.IBPluginDependency + 134.ImportedFromIB2 + 136.IBPluginDependency + 136.ImportedFromIB2 + 143.IBPluginDependency + 143.ImportedFromIB2 + 144.IBPluginDependency + 144.ImportedFromIB2 + 145.IBPluginDependency + 145.ImportedFromIB2 + 149.IBPluginDependency + 149.ImportedFromIB2 + 150.IBPluginDependency + 150.ImportedFromIB2 + 19.IBPluginDependency + 19.ImportedFromIB2 + 195.IBPluginDependency + 195.ImportedFromIB2 + 196.IBPluginDependency + 196.ImportedFromIB2 + 197.IBPluginDependency + 197.ImportedFromIB2 + 198.IBPluginDependency + 198.ImportedFromIB2 + 199.IBPluginDependency + 199.ImportedFromIB2 + 200.IBPluginDependency + 200.ImportedFromIB2 + 200.editorWindowContentRectSynchronizationRect + 201.IBPluginDependency + 201.ImportedFromIB2 + 202.IBPluginDependency + 202.ImportedFromIB2 + 203.IBPluginDependency + 203.ImportedFromIB2 + 204.IBPluginDependency + 204.ImportedFromIB2 + 205.IBPluginDependency + 205.ImportedFromIB2 + 205.editorWindowContentRectSynchronizationRect + 206.IBPluginDependency + 206.ImportedFromIB2 + 207.IBPluginDependency + 207.ImportedFromIB2 + 208.IBPluginDependency + 208.ImportedFromIB2 + 209.IBPluginDependency + 209.ImportedFromIB2 + 210.IBPluginDependency + 210.ImportedFromIB2 + 211.IBPluginDependency + 211.ImportedFromIB2 + 212.IBPluginDependency + 212.ImportedFromIB2 + 212.editorWindowContentRectSynchronizationRect + 213.IBPluginDependency + 213.ImportedFromIB2 + 214.IBPluginDependency + 214.ImportedFromIB2 + 215.IBPluginDependency + 215.ImportedFromIB2 + 216.IBPluginDependency + 216.ImportedFromIB2 + 217.IBPluginDependency + 217.ImportedFromIB2 + 218.IBPluginDependency + 218.ImportedFromIB2 + 219.IBPluginDependency + 219.ImportedFromIB2 + 220.IBPluginDependency + 220.ImportedFromIB2 + 220.editorWindowContentRectSynchronizationRect + 221.IBPluginDependency + 221.ImportedFromIB2 + 23.IBPluginDependency + 23.ImportedFromIB2 + 236.IBPluginDependency + 236.ImportedFromIB2 + 239.IBPluginDependency + 239.ImportedFromIB2 + 24.IBPluginDependency + 24.ImportedFromIB2 + 24.editorWindowContentRectSynchronizationRect + 29.IBPluginDependency + 29.ImportedFromIB2 + 29.WindowOrigin + 29.editorWindowContentRectSynchronizationRect + 295.IBPluginDependency + 296.IBPluginDependency + 296.editorWindowContentRectSynchronizationRect + 297.IBPluginDependency + 298.IBPluginDependency + 299.IBPluginDependency + 300.IBPluginDependency + 300.editorWindowContentRectSynchronizationRect + 344.IBPluginDependency + 345.IBPluginDependency + 346.IBPluginDependency + 346.ImportedFromIB2 + 348.IBPluginDependency + 348.ImportedFromIB2 + 349.IBPluginDependency + 349.ImportedFromIB2 + 349.editorWindowContentRectSynchronizationRect + 350.IBPluginDependency + 350.ImportedFromIB2 + 351.IBPluginDependency + 351.ImportedFromIB2 + 354.IBPluginDependency + 354.ImportedFromIB2 + 371.IBPluginDependency + 371.IBWindowTemplateEditedContentRect + 371.NSWindowTemplate.visibleAtLaunch + 371.editorWindowContentRectSynchronizationRect + 372.IBPluginDependency + 375.IBPluginDependency + 5.IBPluginDependency + 5.ImportedFromIB2 + 56.IBPluginDependency + 56.ImportedFromIB2 + 57.IBPluginDependency + 57.ImportedFromIB2 + 57.editorWindowContentRectSynchronizationRect + 58.IBPluginDependency + 58.ImportedFromIB2 + 72.IBPluginDependency + 72.ImportedFromIB2 + 73.IBPluginDependency + 73.ImportedFromIB2 + 74.IBPluginDependency + 74.ImportedFromIB2 + 75.IBPluginDependency + 75.ImportedFromIB2 + 77.IBPluginDependency + 77.ImportedFromIB2 + 78.IBPluginDependency + 78.ImportedFromIB2 + 79.IBPluginDependency + 79.ImportedFromIB2 + 80.IBPluginDependency + 80.ImportedFromIB2 + 81.IBPluginDependency + 81.ImportedFromIB2 + 81.editorWindowContentRectSynchronizationRect + 82.IBPluginDependency + 82.ImportedFromIB2 + 83.IBPluginDependency + 83.ImportedFromIB2 + 92.IBPluginDependency + 92.ImportedFromIB2 + + + YES + + + + + + + + {{596, 852}, {216, 23}} + + + + + + + + + {{522, 812}, {146, 23}} + + + + + + + {{436, 809}, {64, 6}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{608, 612}, {275, 83}} + + + + + + + + + + + {{187, 434}, {243, 243}} + + + + + + + + + + + + + + + {{608, 612}, {167, 43}} + + + + + + + + + + + + + + + + + {{608, 612}, {241, 103}} + + + + + + + + + + + {{525, 802}, {197, 73}} + + + {74, 862} + {{114, 964}, {478, 20}} + + + {{475, 832}, {234, 43}} + + + + + {{231, 634}, {176, 43}} + + + + + + + + + {{608, 612}, {215, 63}} + + + + + + + + {{115, 493}, {480, 360}} + + {{115, 493}, {480, 360}} + + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + + {{23, 794}, {245, 183}} + + + + + + + + + + + + + + + + + + + + + {{145, 474}, {199, 203}} + + + + + + + + + + YES + + YES + + + YES + + + + + YES + + YES + + + YES + + + + 376 + + + + YES + + NSObject + + + YES + + YES + + + YES + + + + YES + + YES + + + YES + + + + IBProjectSource + AsyncSocket.h + + + + + 0 + ../../MultiThreadedHTTPServer.xcodeproj + 3 + + YnBsaXN0MDDUAAEAAgADAAQABQAGAAkAClgkdmVyc2lvblQkdG9wWSRhcmNoaXZlclgkb2JqZWN0cxIA +AYag0QAHAAhdSUIub2JqZWN0ZGF0YYABXxAPTlNLZXllZEFyY2hpdmVyrxECFgALAAwAMQA1ADYAPAA9 +AEIAVgBXAFgAWQALAGQACwBlAGkAagBtAHEAnACiALIAuQC6ALsAwADBAMIAxQDJAMoAzQDOANIA1gDd +AOEA4gDjAOQA6ADvAPMA9AD1APkBAwEEAQUBBgEKAREBFgEXARgBHAEjAScBKAEpAS0BNAE1ATYBNwE7 +AUQBSAFJAUoBSwFPAVYBWgFbAVwBXQFhAWgBbAFtAW4BbwFzAXoBewF8AX0BgQGIAYkBigGOAZUBlgGX +AZsBogGjAaQBpQGpAbABtQG2AbcBuwHCAcMBxAHFAckB0AHRAdIB0wHXAd4B3wHgAeEB5QHsAe0B7gH0 +AfsB/AH9AgECCAIJAgoCCwIPAhYCFwIYAhkCHQIkAiUCJgInAisCMgIzAjQCNQI5AkECRQJGAkcCSAJM +AlMCVAJVAlYCWgJhAmUCZgJnAmgCbAJzAnQCdQJ2AnoCgQKCAoMChAKIAo8CkAKRApIClgKdAp4CnwKj +AqoCrgKvArACtAK7ArwCvQK+AsICyQLKAssCzALQAtcC2ALZAtoC3wLiAuUC5gLnAuoC7gL1AvYC9wL7 +AwMDBAMFAwYDCgMRAxIDEwMXAx4DHwMgAyQDewOGA48DlAOVA5gDmQObA5wDrAO1A8ADwQPCA8oD0QPS +A9kD2gPiA+MD5APtA8ED7gP1A/4DwQP/BAUEDgPBBA8EFAPBBB0EJgQvA8EEMAQ0BDUEPgRHBEwDwQRN +BFIEWQRaBFsEZQRuA8EEbwR9BIQEhQSGBI8EmASZBKIDwQSjBLEEugTDA8EEzATVA8EE1gTbA8EE5ATr +BOwE9QPBBPYE+gT7BP0FVAWsBgQGBQYGBgcGCAYJBgoGCwYMBg0GDgYPBhAGEQYSBhMGFAYVBhYGFwYY +BhkGGgYbBhwGHQYeBh8GIAYhBiIGIwYkBiUGJgYnBigGKQYqBisGLAYtBi4GLwYwBjEGMgYzBjQGNQY2 +BjcGOAY5BjoGOwY8Bj0GPgY/BkAGQQZCBkMGRAZFBkYGRwZIBkkGSgZLBkwGTQZOBk8GUAZRBlIGUwZU +BlUGVgZXBlgGWQZcBl8G3wdfB2AHYQdiB2MHZAdlB2YHZwdoB2kHagdrB2wHbQduB28HcAdxB3IHcwd0 +B3UHdgd3B3gHeQd6B3sHfAd9B34HfweAB4EHggeDB4QHhQeGB4cHiAeJB4oHiweMB40HjgePB5AHkQeS +B5MHlAeVB5YHlweYB5kHmgebB5wHnQeeB58HoAehB6IHowekB6UHpgenB6gHqQeqB6sHrAetB64Hrwew +B7EHsgezB7QHtQe2B7cHuAe5B7oHuwe8B70Hvge/B8AHwQfCB8MHxAfFB8YHxwfIB8kHygfLB8wHzQfO +B88H0AfRB9IH0wfUB9UH1gfXB9gH2QfaB9sH3AffB+IH5VUkbnVsbN8QEgANAA4ADwAQABEAEgATABQA +FQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMFZOU1Jv +b3RWJGNsYXNzXU5TT2JqZWN0c0tleXNfEA9OU0NsYXNzZXNWYWx1ZXNfEBlOU0FjY2Vzc2liaWxpdHlP +aWRzVmFsdWVzXU5TQ29ubmVjdGlvbnNbTlNOYW1lc0tleXNbTlNGcmFtZXdvcmtdTlNDbGFzc2VzS2V5 +c1pOU09pZHNLZXlzXU5TTmFtZXNWYWx1ZXNfEBlOU0FjY2Vzc2liaWxpdHlDb25uZWN0b3JzXU5TRm9u +dE1hbmFnZXJfEBBOU1Zpc2libGVXaW5kb3dzXxAPTlNPYmplY3RzVmFsdWVzXxAXTlNBY2Nlc3NpYmls +aXR5T2lkc0tleXNZTlNOZXh0T2lkXE5TT2lkc1ZhbHVlc4ACgQIVgOWBAZKBAhSAE4EBOoAFgQGRgQGT +gQE7gQISgACABoEBOYECExEBeoEBlNIADgAyADMANFtOU0NsYXNzTmFtZYAEgANdTlNBcHBsaWNhdGlv +btIANwA4ADkAOlgkY2xhc3Nlc1okY2xhc3NuYW1logA6ADteTlNDdXN0b21PYmplY3RYTlNPYmplY3Rf +EBBJQkNvY29hRnJhbWV3b3Jr0gAOAD4APwBAWk5TLm9iamVjdHOAEqEAQYAH2gBDAA4ARABFAEYARwBI +AEkASgBLAEwATQBOAE8AUABRAFIAUwBUACtcTlNXaW5kb3dWaWV3XE5TU2NyZWVuUmVjdF1OU1dpbmRv +d1RpdGxlWU5TV1RGbGFnc11OU1dpbmRvd0NsYXNzXE5TV2luZG93UmVjdF8QD05TV2luZG93QmFja2lu +Z18QEU5TV2luZG93U3R5bGVNYXNrW05TVmlld0NsYXNzgAuAEYAQgAkSdAAAAIAKgAgQAhAPgABfEBh7 +ezMzNSwgMzkwfSwgezQ4MCwgMzYwfX1WV2luZG93WE5TV2luZG931gBaAA4AWwBcAFgAXQBeAF8AYABh +AF4AY18QD05TTmV4dFJlc3BvbmRlclhOU3ZGbGFnc1tOU0ZyYW1lU2l6ZVtOU1N1cGVydmlld4AMgA8R +AQCADYAMgA5aezQ4MCwgMzYwfdIANwA4AGYAZ6MAZwBoADtWTlNWaWV3W05TUmVzcG9uZGVyXxAWe3sw +LCAwfSwgezE2ODAsIDEwMjh9fdIANwA4AGsAbKIAbAA7XxAQTlNXaW5kb3dUZW1wbGF0ZdIANwA4AG4A +b6MAbwBwADtcTlNNdXRhYmxlU2V0VU5TU2V00gAOAD4AcgBzgOSvECgAdAB1AHYAdwB4AHkAegB7AHwA +fQB+AH8AgACBAIIAgwCEAIUAhgCHAIgAiQCKAIsAjACNAI4AjwCQAJEAkgCTAJQAlQCWAJcAmACZAJoA +m4AUgCKAKIAtgDKAN4A8gEGAR4BNgFOAWIBcgGCAZYBqgG+AdIB5gH2AgYCGgIuAkICVgJuAoICmgKuA +sIC1gLmAvoDDgMiAzYDTgNeA3IDg0wAOAJ0AngCfAKAAoVhOU1NvdXJjZVdOU0xhYmVsgCGAFYAg2AAO +AKMApAClAKYApwCoAKkAqgCrAKwArQCuAK8AsACxV05TVGl0bGVfEBFOU0tleUVxdWl2TW9kTWFza1pO +U0tleUVxdWl2XU5TTW5lbW9uaWNMb2NZTlNPbkltYWdlXE5TTWl4ZWRJbWFnZVZOU01lbnWAH4AXEgAQ +AACAGBJ/////gBmAHYAW1AAOAKMAswC0ALUAtgC3ALhWTlNOYW1lW05TTWVudUl0ZW1zgOyBARqBASKB +ARxfEBNRdWl0IE5ld0FwcGxpY2F0aW9uUXHTAA4AMgC8AL0AvgC/Xk5TUmVzb3VyY2VOYW1lgByAGoAb +V05TSW1hZ2VfEA9OU01lbnVDaGVja21hcmvSADcAOADDAMSiAMQAO18QEE5TQ3VzdG9tUmVzb3VyY2XT +AA4AMgC8AL0AvgDIgByAGoAeXxAQTlNNZW51TWl4ZWRTdGF0ZdIANwA4AMsAzKIAzAA7Wk5TTWVudUl0 +ZW1adGVybWluYXRlOtIANwA4AM8A0KMA0ADRADtfEBVOU05pYkNvbnRyb2xDb25uZWN0b3JeTlNOaWJD +b25uZWN0b3LTAA4AnQCeAJ8A1ADVgCGAI4An2AAOAKMApAClAKYApwCoAKkAqgDYAKwA2QCuAK8AsADc +gB+AJYAmgBmAHYAk0wAOAKMAtAC1AN8A4IDsgPyA/l8QG0NoZWNrIEdyYW1tYXIgV2l0aCBTcGVsbGlu +Z1BfEBZ0b2dnbGVHcmFtbWFyQ2hlY2tpbmc60wAOAJ0AngCfAOYA54AhgCmALNcADgCjAKUApgCnAKgA +qQCqAOoA2QCuAK8AsADugB+AK4AmgBmAHYAq0wAOAKMAtAC1APEA8oDsgQEkgQEmXxAPUmV2ZXJ0IHRv +IFNhdmVkXxAWcmV2ZXJ0RG9jdW1lbnRUb1NhdmVkOtMADgCdAJ4AnwD3APiAIYAugDHZAA4A+gCjAKQA +pQCmAKcAqACpAKoA2QD9AP4A/wCuAK8AsADuWU5TVG9vbFRpcIAfgCaALxIAEgAAgDCAGYAdgCpdUGFn +ZSBTZXR1cC4uLlFQXnJ1blBhZ2VMYXlvdXQ60wAOAJ0AngCfAQgBCYAhgDOANtgADgCjAKQApQCmAKcA +qACpAKoBDACsANkArgCvALABEIAfgDWAJoAZgB2ANNQADgCjALMAtAC1AE8BFAEVgOyACYEBMoEBMVRa +b29tXHBlcmZvcm1ab29tOtMADgCdAJ4AnwEaARuAIYA4gDvYAA4AowCkAKUApgCnAKgAqQCqAR4ArADZ +AK4ArwCwASKAH4A6gCaAGYAdgDnTAA4AowC0ALUBJQEmgOyBAQSBAQZeU3RhcnQgU3BlYWtpbmdec3Rh +cnRTcGVha2luZzrTAA4AnQCeAJ8BKwEsgCGAPYBA2AAOAKMApAClAKYApwCoAKkAqgEvAKwBMACuAK8A +sADugB+APoA/gBmAHYAqU05ld1FuXG5ld0RvY3VtZW50OtMADgCdAJ4AnwE5ATqAIYBCgEbZAA4AowCk +AKUApgCnAKgAqQE8AKoBPgCsAT8ArgCvALABQgFDVU5TVGFngB+ARIBFgBmAHYBDEAHTAA4AowC0ALUB +RgFHgOyBAQCBAQJfEBBTbWFydCBDb3B5L1Bhc3RlUWZfEBh0b2dnbGVTbWFydEluc2VydERlbGV0ZTrT +AA4AnQCeAJ8BTQFOgCGASIBM2AAOAKMApAClAKYApwCoAKkAqgFRAP4BUgCuAK8AsAFVgB+ASoBLgBmA +HYBJ0wAOAKMAtAC1AVgBWYDsgQESgQEUW1Nob3cgQ29sb3JzUUNfEBVvcmRlckZyb250Q29sb3JQYW5l +bDrTAA4AnQCeAJ8BXwFggCGAToBS2AAOAKMApAClAKYApwCoAKkAqgFjAKwBZACuAK8AsAFngB+AUIBR +gBmAHYBP0wAOAKMAtAC1AWoBa4DsgO2A7lRVbmRvUXpVdW5kbzrTAA4AnQCeAJ8BcQFygCGAVIBX2AAO +AKMApAClAKYApwCoAKkAqgF1AKwBdgCuAK8AsADugB+AVYBWgBmAHYAqZQBPAHAAZQBuICZRb11vcGVu +RG9jdW1lbnQ60wAOAJ0AngCfAX8BgIAhgFmAW9gADgCjAKQApQCmAKcAqACpAKoBgwCsANkArgCvALAB +IoAfgFqAJoAZgB2AOV1TdG9wIFNwZWFraW5nXXN0b3BTcGVha2luZzrTAA4AnQCeAJ8BjAGNgCGAXYBf +2AAOAKMApAClAKYApwCoAKkAqgGQAKwA2QCuAK8AsADcgB+AXoAmgBmAHYAkXxAbQ2hlY2sgU3BlbGxp +bmcgV2hpbGUgVHlwaW5nXxAedG9nZ2xlQ29udGludW91c1NwZWxsQ2hlY2tpbmc60wAOAJ0AngCfAZkB +moAhgGGAZNgADgCjAKQApQCmAKcAqACpAKoBnQD+AZ4ArgCvALAA7oAfgGKAY4AZgB2AKmgAUwBhAHYA +ZQAgAEEAcyAmUVNfEA9zYXZlRG9jdW1lbnRBczrTAA4AnQCeAJ8BpwGogCGAZoBp2AAOAKMApAClAKYA +pwCoAKkAqgGrAKwA2QCuAK8AsAGvgB+AaIAmgBmAHYBn1AAOAKMAswC0ALUBsgGzAbSA7IEBC4EBDoEB +DVpDbGVhciBNZW51XxAVY2xlYXJSZWNlbnREb2N1bWVudHM60wAOAJ0AngCfAbkBuoAhgGuAbtgADgCj +AKQApQCmAKcAqACpAKoBvQCsAb4ArgCvALAA7oAfgGyAbYAZgB2AKlRTYXZlUXNdc2F2ZURvY3VtZW50 +OtMADgCdAJ4AnwHHAciAIYBwgHPZAA4AowCkAKUApgCnAKgAqQE8AKoBywCsAcwArgCvALABQgBTgB+A +cYBygBmAHYBDXFNtYXJ0IFF1b3Rlc1FnXxAhdG9nZ2xlQXV0b21hdGljUXVvdGVTdWJzdGl0dXRpb246 +0wAOAJ0AngCfAdUB1oAhgHWAeNgADgCjAKQApQCmAKcAqACpAKoB2QD+AdoArgCvALABZ4AfgHaAd4AZ +gB2AT1RSZWRvUVpVcmVkbzrTAA4AnQCeAJ8B4wHkgCGAeoB82AAOAKMApAClAKYApwCoAKkAqgHnAKwA +2QCuAK8AsAFngB+Ae4AmgBmAHYBPVkRlbGV0ZVdkZWxldGU61AAOAe8AnQCeAJ8AHwHyAfNdTlNEZXN0 +aW5hdGlvboAhgAKAfoCA1wAOAKMApQCmAKcAqACpAKoB9gDZAK4ArwCwALGAH4B/gCaAGYAdgBZfEBRB +Ym91dCBOZXdBcHBsaWNhdGlvbl8QHW9yZGVyRnJvbnRTdGFuZGFyZEFib3V0UGFuZWw60wAOAJ0AngCf +Af8CAIAhgIKAhdgADgCjAKQApQCmAKcAqACpAKoCAwCsAgQArgCvALABZ4AfgIOAhIAZgB2AT1VQYXN0 +ZVF2VnBhc3RlOtMADgCdAJ4AnwINAg6AIYCHgIrYAA4AowCkAKUApgCnAKgAqQCqAhEArAISAK4ArwCw +ANyAH4CIgImAGYAdgCReQ2hlY2sgU3BlbGxpbmdRO15jaGVja1NwZWxsaW5nOtMADgCdAJ4AnwIbAhyA +IYCMgI/YAA4AowCkAKUApgCnAKgAqQCqAh8ArAIgAK4ArwCwAWeAH4CNgI6AGYAdgE9TQ3V0UXhUY3V0 +OtMADgCdAJ4AnwIpAiqAIYCRgJTYAA4AowCkAKUApgCnAKgAqQCqAi0ArAIuAK4ArwCwANyAH4CSgJOA +GYAdgCRuAFMAaABvAHcAIABTAHAAZQBsAGwAaQBuAGcgJlE6XxAPc2hvd0d1ZXNzUGFuZWw60wAOAJ0A +ngCfAjcCOIAhgJaAmtgADgCjAKQApQCmAKcAqACpAKoCOwI8Aj0ArgCvALACQIAfgJgSABgAAICZgBmA +HYCX0wAOAKMAtAC1AkMCRIDsgQEsgQEuXFNob3cgVG9vbGJhclF0XxATdG9nZ2xlVG9vbGJhclNob3du +OtMADgCdAJ4AnwJKAkuAIYCcgJ/YAA4AowCkAKUApgCnAKgAqQCqAk4ArAJPAK4ArwCwAO6AH4CdgJ6A +GYAdgCpmAFAAcgBpAG4AdCAmUXBWcHJpbnQ60wAOAJ0AngCfAlgCWYAhgKGApdgADgCjAKQApQCmAKcA +qACpAKoCXACsAl0ArgCvALACYIAfgKOApIAZgB2AotMADgCjALQAtQJjAmSA7IEBNIEBNl8QE05ld0Fw +cGxpY2F0aW9uIEhlbHBRP1lzaG93SGVscDrTAA4AnQCeAJ8CagJrgCGAp4Cq2AAOAKMApAClAKYApwCo +AKkAqgJuAKwCbwCuAK8AsAFngB+AqICpgBmAHYBPVENvcHlRY1Vjb3B5OtMADgCdAJ4AnwJ4AnmAIYCs +gK/YAA4AowCkAKUApgCnAKgAqQCqAnwArAJ9AK4ArwCwAO6AH4CtgK6AGYAdgCpVQ2xvc2VRd11wZXJm +b3JtQ2xvc2U60wAOAJ0AngCfAoYCh4AhgLGAtNgADgCjAKQApQCmAKcAqACpAKoCigI8AosArgCvALAA +sYAfgLKAs4AZgB2AFltIaWRlIE90aGVyc1FoXxAWaGlkZU90aGVyQXBwbGljYXRpb25zOtMADgCdAJ4A +nwKUApWAIYC2gLjYAA4AowCkAKUApgCnAKgAqQCqApgArADZAK4ArwCwAkCAH4C3gCaAGYAdgJdvEBIA +QwB1AHMAdABvAG0AaQB6AGUAIABUAG8AbwBsAGIAYQByICZfEB9ydW5Ub29sYmFyQ3VzdG9taXphdGlv +blBhbGV0dGU60wAOAJ0AngCfAqECooAhgLqAvdkADgCjAKQApQCmAKcAqACpATwAqgKlAKwBPwCuAK8A +sAKpAUOAH4C8gEWAGYAdgLvTAA4AowC0ALUCrAKtgOyA8YDzZQBGAGkAbgBkICZfEBdwZXJmb3JtRmlu +ZFBhbmVsQWN0aW9uOtMADgCdAJ4AnwKyArOAIYC/gMLYAA4AowCkAKUApgCnAKgAqQCqArYArAK3AK4A +rwCwAqmAH4DAgMGAGYAdgLtfEBFKdW1wIHRvIFNlbGVjdGlvblFqXxAdY2VudGVyU2VsZWN0aW9uSW5W +aXNpYmxlQXJlYTrTAA4AnQCeAJ8CwALBgCGAxIDH2AAOAKMApAClAKYApwCoAKkAqgLEAKwCxQCuAK8A +sAFngB+AxYDGgBmAHYBPWlNlbGVjdCBBbGxRYVpzZWxlY3RBbGw60wAOAJ0AngCfAs4Cz4AhgMmAzNgA +DgCjAKQApQCmAKcAqACpAKoC0gCsAtMArgCvALABEIAfgMqAy4AZgB2ANFhNaW5pbWl6ZVFtXxATcGVy +Zm9ybU1pbmlhdHVyaXplOtQADgHvAJ0AngLbAtwC3QLegNKAz4DOgNHSAA4AMgAzADSABIAD0gAOADIA +MwLkgASA0FtBcHBEZWxlZ2F0ZVhkZWxlZ2F0ZdIANwA4AugC6aMC6QDRADtfEBROU05pYk91dGxldENv +bm5lY3RvctMADgCdAJ4AnwLsAu2AIYDUgNbYAA4AowCkAKUApgCnAKgAqQCqAvAArADZAK4ArwCwARCA +H4DVgCaAGYAdgDRfEBJCcmluZyBBbGwgdG8gRnJvbnRfEA9hcnJhbmdlSW5Gcm9udDrTAA4AnQCeAJ8C ++QL6gCGA2IDb2QAOAKMApAClAKYApwCoAKkBPACqAv0A/gL+AK4ArwCwAUIDAoAfgNmA2oAZgB2AQxAD +W1NtYXJ0IExpbmtzUUdfEB10b2dnbGVBdXRvbWF0aWNMaW5rRGV0ZWN0aW9uOtMADgCdAJ4AnwMIAwmA +IYDdgN/YAA4AowCkAKUApgCnAKgAqQCqAwwArAKLAK4ArwCwALGAH4DegLOAGYAdgBZfEBNIaWRlIE5l +d0FwcGxpY2F0aW9uVWhpZGU60wAOAJ0AngCfAxUDFoAhgOGA49gADgCjAKQApQCmAKcAqACpAKoDGQCs +ANkArgCvALAAsYAfgOKAJoAZgB2AFlhTaG93IEFsbF8QFnVuaGlkZUFsbEFwcGxpY2F0aW9uczrSADcA +OAMhAyKjAyIDIwA7Xk5TTXV0YWJsZUFycmF5V05TQXJyYXnSAA4APgMlAyaBATivEFQDJwMoAQgC7ALA +AEEDLQFnANwDMAMxAzICDQM0AccA5gKGAzgBKwGnARoDPALOAXEDPwNAAYwDQgKUA0QDCALcA0cBIgE5 +AZkBTQNMAjcDTgIbAlgBQgFVAngBEAHyA1YBuQJKAEwDWgJAA1wDXQCgAPcDYALdA2ICqQKyAmAB/wHV +AX8A7gGvA2sDbANtALEBXwIpA3ECoQDUA3QDdQN2AxUC+QJqAeOA5oDngDOA1IDEgAeA6IBPgCSBAQeB +AQmA+ICHgQEKgHCAKYCxgQEPgD2AZoA4gQEQgMmAVIEBEYEBIYBdgQEjgLaA/4DdgM+A9IA5gEKAYYBI +gQEZgJaBASCAjIChgEOASYCsgDSAfoDvgGuAnIALgQEpgJeA9oD7gBWALoEBKIDOgQEvgLuAv4CigIKA +dYBZgCqAZ4EBJ4EBK4EBHYAWgE6AkYEBM4C6gCOBAQOBARWA8IDhgNiAp4B62gAOAKMApAN8AKUDfQCm +AKcAqACpAKoA2QCsA4AA2QOAAK4ArwCwALFdTlNJc1NlcGFyYXRvclxOU0lzRGlzYWJsZWSAH4AmCYAm +CYAZgB2AFtoADgCjAKQDfAClA30ApgCnAKgAqQCqANkArAOAANkDgACuAK8AsAFngB+AJgmAJgmAGYAd +gE/UAA4AowCzALQAtQORA5IDk4DsgOmA64DqWFNlcnZpY2Vz0gAOAD4AcgOXgOSgXxAPX05TU2Vydmlj +ZXNNZW510gA3ADgDmgCpogCpADtURWRpdNIADgA+AHIDnoDkrQFfAdUDVgIbAmoB/wHjAsADKAN2A10D +RAN0gE6AdYDvgIyAp4CCgHqAxIDngPCA+4D/gQED2gAOAKMApAN8AKUDfQCmAKcAqACpAKoA2QCsA4AA +2QOAAK4ArwCwAWeAH4AmCYAmCYAZgB2AT9oADgO2AKMApAClAKYApwCoAKkDtwCqAqkCrACsANkArgCv +ALABZwO/WU5TU3VibWVudVhOU0FjdGlvboAfgLuA8YAmgBmAHYBPgPJURmluZF5zdWJtZW51QWN0aW9u +OtIADgA+AHIDxIDkpQKhA0cDXAMyArKAuoD0gPaA+IC/2QAOAKMApAClAKYApwCoAKkBPACqA8wArAHM +AK4ArwCwAqkAU4AfgPWAcoAZgB2Au1lGaW5kIE5leHTZAA4AowCkAKUApgCnAKgAqQE8AKoD1AD+Av4A +rgCvALACqQMCgB+A94DagBmAHYC7XUZpbmQgUHJldmlvdXPZAA4AowCkAKUApgCnAKgAqQE8AKoD3ACs +A90ArgCvALACqQPhgB+A+YD6gBmAHYC7EAdfEBZVc2UgU2VsZWN0aW9uIGZvciBGaW5kUWXaAA4DtgCj +AKQApQCmAKcAqACpA7cAqgDcAN8ArADZAK4ArwCwAWcD7IAfgCSA/IAmgBmAHYBPgP1fEBRTcGVsbGlu +ZyBhbmQgR3JhbW1hctIADgA+AHID8IDkpAIpAg0BjADUgJGAh4BdgCPaAA4DtgCjAKQApQCmAKcAqACp +A7cAqgFCAUYArADZAK4ArwCwAWcD/YAfgEOBAQCAJoAZgB2AT4EBAV1TdWJzdGl0dXRpb25z0gAOAD4A +cgQBgOSjATkBxwL5gEKAcIDY2gAOA7YAowCkAKUApgCnAKgAqQO3AKoBIgElAKwA2QCuAK8AsAFnBA2A +H4A5gQEEgCaAGYAdgE+BAQVWU3BlZWNo0gAOAD4AcgQRgOSiARoBf4A4gFnaAA4DtgCjAKQApQCmAKcA +qACpA7cAqgMtA5EArADZAK4ArwCwALEEHIAfgOiA6YAmgBmAHYAWgQEI2gAOAKMApAN8AKUDfQCmAKcA +qACpAKoA2QCsA4AA2QOAAK4ArwCwARCAH4AmCYAmCYAZgB2ANNoADgO2AKMApAClAKYApwCoAKkDtwCq +Aa8BsgCsANkArgCvALAA7gQugB+AZ4EBC4AmgBmAHYAqgQEMW09wZW4gUmVjZW500gAOAD4AcgQygOSh +AaeAZl8QFl9OU1JlY2VudERvY3VtZW50c01lbnXaAA4AowCkA3wApQN9AKYApwCoAKkAqgDZAKwDgADZ +A4AArgCvALAAsYAfgCYJgCYJgBmAHYAW2gAOA7YAowCkAKUApgCnAKgAqQO3AKoBVQFYAKwA2QCuAK8A +sAM/BEaAH4BJgQESgCaAGYAdgQERgQET1AAOAKMAswC0ALUESQRKBEuA7IEBF4EBN4EBGFZGb3JtYXTS +AA4APgByBE+A5KIDdQFNgQEVgEjYAA4AowCkAKUApgCnAKgAqQCqBFQArAI9AK4ArwCwAVWAH4EBFoCZ +gBmAHYBJWlNob3cgRm9udHNZQU1haW5NZW510gAOAD4AcgRdgOSnA0wDQgNaAzwDbANiA3GBARmBASOB +ASmBARCBASuBAS+BATPaAA4DtgCjAKQApQCmAKcAqACpA7cAqgCxALYArADZAK4ArwCwAz8EbYAfgBaB +ARqAJoAZgB2BARGBARteTmV3QXBwbGljYXRpb27SAA4APgByBHGA5KsB8gMnA20DOAMwA04DCAKGAxUD +QACggH6A5oEBHYEBD4EBB4EBIIDdgLGA4YEBIYAV2AAOAKMApAClAKYApwCoAKkAqgR/AKwEgACuAK8A +sACxgB+BAR6BAR+AGYAdgBZsAFAAcgBlAGYAZQByAGUAbgBjAGUAcyAmUSzaAA4AowCkA3wApQN9AKYA +pwCoAKkAqgDZAKwDgADZA4AArgCvALAAsYAfgCYJgCYJgBmAHYAW2gAOAKMApAN8AKUDfQCmAKcAqACp +AKoA2QCsA4AA2QOAAK4ArwCwALGAH4AmCYAmCYAZgB2AFlxfTlNBcHBsZU1lbnXaAA4DtgCjAKQApQCm +AKcAqACpA7cAqgDuAPEArADZAK4ArwCwAz8EoYAfgCqBASSAJoAZgB2BARGBASVURmlsZdIADgA+AHIE +pYDkqwErAXEDNANrAngBuQGZAOYDYAD3AkqAPYBUgQEKgQEngKyAa4BhgCmBASiALoCc2gAOAKMApAN8 +AKUDfQCmAKcAqACpAKoA2QCsA4AA2QOAAK4ArwCwAO6AH4AmCYAmCYAZgB2AKtoADgCjAKQDfAClA30A +pgCnAKgAqQCqANkArAOAANkDgACuAK8AsADugB+AJgmAJgmAGYAdgCraAA4DtgCjAKQApQCmAKcAqACp +A7cAqgFnAWoArADZAK4ArwCwAz8Ey4AfgE+A7YAmgBmAHYEBEYEBKtoADgO2AKMApAClAKYApwCoAKkD +twCqAkACQwCsANkArgCvALADPwTUgB+Al4EBLIAmgBmAHYEBEYEBLVRWaWV30gAOAD4AcgTYgOSiAjcC +lICWgLbaAA4DtgCjAKQApQCmAKcAqACpA7cAqgEQAE8ArADZAK4ArwCwAz8E44AfgDSACYAmgBmAHYEB +EYEBMNIADgA+AHIE5oDkpALOAQgDMQLsgMmAM4EBCYDUXl9OU1dpbmRvd3NNZW512gAOA7YAowCkAKUA +pgCnAKgAqQO3AKoCYAJjAKwA2QCuAK8AsAM/BPSAH4CigQE0gCaAGYAdgQERgQE1VEhlbHDSAA4APgBy +BPiA5KECWIChW19OU01haW5NZW510gA3ADgE/AMjogMjADvSAA4APgMlBP+BATivEFQAsQFnARABEAFn +AB8DMANaA10AsQEQAqkA3ADuAUIA7gCxALEA7gGvASIDPwEQAO4AHwCxANwDPwJAAWcAsQAfAqkDdAFC +AO4BVQM/AkAAsQFnAmADRAM8AO4DYgCxAWcA7gDuAEEDPwNsAqkBZwCxAO4A7gAfAz8DdgKpA3EBZwFn +ASIDQgM0AO4DPwCxA0wBZwDcAz8CqQDcAWcBVQFnALEBQgFnAWeAFoBPgDSANIBPgAKBAQeBASmA+4AW +gDSAu4AkgCqAQ4AqgBaAFoAqgGeAOYEBEYA0gCqAAoAWgCSBARGAl4BPgBaAAoC7gQEDgEOAKoBJgQER +gJeAFoBPgKKA/4EBEIAqgQEvgBaAT4AqgCqAB4EBEYEBK4C7gE+AFoAqgCqAAoEBEYDwgLuBATOAT4BP +gDmBASOBAQqAKoEBEYAWgQEZgE+AJIEBEYC7gCSAT4BJgE+AFoBDgE+AT9IADgA+AyUFVoEBOK8QVQMn +AygBCALAAEEC7AMtAWcA3AMwAzEA5gM0Ag0BxwMyAoYDOAErAacBGgM8AXECzgM/A0IDQAKUAYwDRAAf +AwgC3ANHASIBTQGZATkDTAI3A04BVQIbAlgBQgJ4ARAB8gNWAbkATAJKA1oCQANcAPcAoANdA2AC3QNi +AqkCsgJgAf8B1QF/AO4BrwNrA2wDbQCxA3UBXwNxA3QCKQDUAqEDFQN2AvkCagHjgOaA54AzgMSAB4DU +gOiAT4AkgQEHgQEJgCmBAQqAh4BwgPiAsYEBD4A9gGaAOIEBEIBUgMmBARGBASOBASGAtoBdgP+AAoDd +gM+A9IA5gEiAYYBCgQEZgJaBASCASYCMgKGAQ4CsgDSAfoDvgGuAC4CcgQEpgJeA9oAugBWA+4EBKIDO +gQEvgLuAv4CigIKAdYBZgCqAZ4EBJ4EBK4EBHYAWgQEVgE6BATOBAQOAkYAjgLqA4YDwgNiAp4B60gAO +AD4DJQWugQE4rxBVBa8FsAWxBbIFswW0BbUFtgW3BbgFuQW6BbsFvAW9Bb4FvwXABcEFwgXDBcQFxQXG +BccFyAXJBcoFywXMBc0FzgXPBdAF0QXSBdMF1AXVBdYF1wXYBdkF2gXbBdwF3QXeBd8F4AXhBeIF4wXk +BeUF5gXnBegF6QXqBesF7AXtBe4F7wXwBfEF8gXzBfQF9QX2BfcF+AX5BfoF+wX8Bf0F/gX/BgAGAQYC +BgOBATyBAT2BAT6BAT+BAUCBAUGBAUKBAUOBAUSBAUWBAUaBAUeBAUiBAUmBAUqBAUuBAUyBAU2BAU6B +AU+BAVCBAVGBAVKBAVOBAVSBAVWBAVaBAVeBAViBAVmBAVqBAVuBAVyBAV2BAV6BAV+BAWCBAWGBAWKB +AWOBAWSBAWWBAWaBAWeBAWiBAWmBAWqBAWuBAWyBAW2BAW6BAW+BAXCBAXGBAXKBAXOBAXSBAXWBAXaB +AXeBAXiBAXmBAXqBAXuBAXyBAX2BAX6BAX+BAYCBAYGBAYKBAYOBAYSBAYWBAYaBAYeBAYiBAYmBAYqB +AYuBAYyBAY2BAY6BAY+BAZBZU2VwYXJhdG9yW1NlcGFyYXRvci00XxAQTWVudSBJdGVtIChab29tKV8Q +Fk1lbnUgSXRlbSAoU2VsZWN0IEFsbClfEA9XaW5kb3cgKFdpbmRvdylfEB5NZW51IEl0ZW0gKEJyaW5n +IEFsbCB0byBGcm9udClfEA9NZW51IChTZXJ2aWNlcylbTWVudSAoRWRpdClfEBtNZW51IChTcGVsbGlu +ZyBhbmQgR3JhbW1hcilfEBRNZW51IEl0ZW0gKFNlcnZpY2VzKVtTZXBhcmF0b3ItNlIxMF8QF01lbnUg +SXRlbSAoT3BlbiBSZWNlbnQpXxAaTWVudSBJdGVtIChDaGVjayBTcGVsbGluZylfEBhNZW51IEl0ZW0g +KFNtYXJ0IFF1b3RlcylfECJNZW51IEl0ZW0gKFVzZSBTZWxlY3Rpb24gZm9yIEZpbmQpXxAXTWVudSBJ +dGVtIChIaWRlIE90aGVycylbU2VwYXJhdG9yLTFROV8QFk1lbnUgSXRlbSAoQ2xlYXIgTWVudSlfEBpN +ZW51IEl0ZW0gKFN0YXJ0IFNwZWFraW5nKV8QEk1lbnUgSXRlbSAoRm9ybWF0KW8QEQBNAGUAbgB1ACAA +SQB0AGUAbQAgACgATwBwAGUAbiAmAClfEBRNZW51IEl0ZW0gKE1pbmltaXplKVhNYWluTWVudV8QEE1l +bnUgSXRlbSAoRmlsZSlbU2VwYXJhdG9yLTJvEB4ATQBlAG4AdQAgAEkAdABlAG0AIAAoAEMAdQBzAHQA +bwBtAGkAegBlACAAVABvAG8AbABiAGEAciAmAClfECdNZW51IEl0ZW0gKENoZWNrIFNwZWxsaW5nIFdo +aWxlIFR5cGluZylfEBlNZW51IEl0ZW0gKFN1YnN0aXR1dGlvbnMpXEZpbGUncyBPd25lcl8QH01lbnUg +SXRlbSAoSGlkZSBOZXdBcHBsaWNhdGlvbilcQXBwIERlbGVnYXRlXxAVTWVudSBJdGVtIChGaW5kIE5l +eHQpXU1lbnUgKFNwZWVjaClfEBdNZW51IEl0ZW0gKFNob3cgQ29sb3JzKVE4XxAcTWVudSBJdGVtIChT +bWFydCBDb3B5L1Bhc3RlKV8QGk1lbnUgSXRlbSAoTmV3QXBwbGljYXRpb24pXxAYTWVudSBJdGVtIChT +aG93IFRvb2xiYXIpW1NlcGFyYXRvci0zXU1lbnUgKEZvcm1hdClfEA9NZW51IEl0ZW0gKEN1dClfEB9N +ZW51IEl0ZW0gKE5ld0FwcGxpY2F0aW9uIEhlbHApXxAUTWVudSAoU3Vic3RpdHV0aW9ucylTMS0xXU1l +bnUgKFdpbmRvdylfECBNZW51IEl0ZW0gKEFib3V0IE5ld0FwcGxpY2F0aW9uKVtTZXBhcmF0b3ItNVEz +XENvbnRlbnQgVmlld1E2XxAQTWVudSBJdGVtIChFZGl0KVtNZW51IChWaWV3KV8QGU1lbnUgSXRlbSAo +RmluZCBQcmV2aW91cylRNVQxMTExXxAgTWVudSBJdGVtIChTcGVsbGluZyBhbmQgR3JhbW1hcilTMi0x +W0FwcGxpY2F0aW9uXxASTWVudSBJdGVtIChXaW5kb3cpW01lbnUgKEZpbmQpXxAdTWVudSBJdGVtIChK +dW1wIHRvIFNlbGVjdGlvbilRMl8QEU1lbnUgSXRlbSAoUGFzdGUpXxAQTWVudSBJdGVtIChSZWRvKV8Q +GU1lbnUgSXRlbSAoU3RvcCBTcGVha2luZylbTWVudSAoRmlsZSlfEBJNZW51IChPcGVuIFJlY2VudClR +N18QEE1lbnUgSXRlbSAoVmlldylTMTIxXxAVTWVudSAoTmV3QXBwbGljYXRpb24pXxAWTWVudSBJdGVt +IChTaG93IEZvbnRzKV8QEE1lbnUgSXRlbSAoVW5kbylRMV8QEk1lbnUgSXRlbSAoU3BlZWNoKW8QGgBN +AGUAbgB1ACAASQB0AGUAbQAgACgAUwBoAG8AdwAgAFMAcABlAGwAbABpAG4AZyAmAClfECdNZW51IEl0 +ZW0gKENoZWNrIEdyYW1tYXIgV2l0aCBTcGVsbGluZylvEBEATQBlAG4AdQAgAEkAdABlAG0AIAAoAEYA +aQBuAGQgJgApXxAUTWVudSBJdGVtIChTaG93IEFsbClfEBBNZW51IEl0ZW0gKEZpbmQpXxAXTWVudSBJ +dGVtIChTbWFydCBMaW5rcylfEBBNZW51IEl0ZW0gKENvcHkpXxASTWVudSBJdGVtIChEZWxldGUp0gAO +AD4DJQZbgQE4oNIADgA+AyUGXoEBOKDSAA4APgMlBmGBATivEH0DKAB2AIMC7ALAAEEDMACRAzEDMgM0 +AHQBxwB1AJMChgErARoAhwM8AXEBjACLAwgC3ANHATkBmQB3A0wAlgNOAVUCWAFCAIgAmwJ4AIkDVgG5 +AkoATANaAkADXANgAt0DYgKpAIoB/wCPAX8BrwB7A20AsQN0AJcAfgN2AxUC+QB9AIEB4wCEAycAeAMt +AWcA3ACMAJUA5gINAJkDOAGnAs4AfAM/A0ADQgKUAIYDRAAfASIBTQCAAI4CNwIbAH8AmACNARAB8gB6 +AJADXQCgAPcAkgKyAmAB1QDuA2sDbAFfAIICKQDUA3ECoQN1AHkAhQCUAJoCagEIgOeAKIBqgNSAxIAH +gQEHgLCBAQmA+IEBCoAUgHCAIoC5gLGAPYA4gH2BARCAVIBdgJCA3YDPgPSAQoBhgC2BARmAyIEBIIBJ +gKGAQ4CBgOCArICGgO+Aa4CcgAuBASmAl4D2gQEogM6BAS+Au4CLgIKApoBZgGeAQYEBHYAWgQEDgM2A +U4DwgOGA2IBNgGCAeoBvgOaAMoDogE+AJICVgMOAKYCHgNeBAQ+AZoDJgEeBARGBASGBASOAtoB5gP+A +AoA5gEiAXICggJaAjIBYgNOAm4A0gH6APICrgPuAFYAugLWAv4CigHWAKoEBJ4EBK4BOgGWAkYAjgQEz +gLqBARWAN4B0gL6A3ICngDPSAA4APgMlBuGBATivEH0G4gbjBuQG5QbmBucG6AbpBuoG6wbsBu0G7gbv +BvAG8QbyBvMG9Ab1BvYG9wb4BvkG+gb7BvwG/Qb+Bv8HAAcBBwIHAwcEBwUHBgcHBwgHCQcKBwsHDAcN +Bw4HDwcQBxEHEgcTBxQHFQcWBxcHGAcZBxoHGwccBx0HHgcfByAHIQciByMHJAclByYHJwcoBykHKgcr +BywHLQcuBy8HMAcxBzIHMwc0BzUHNgc3BzgHOQc6BzsHPAc9Bz4HPwdAB0EHQgdDB0QHRQdGB0cHSAdJ +B0oHSwdMB00HTgdPB1AHUQdSB1MHVAdVB1YHVwdYB1kHWgdbB1wHXQdegQGVgQGWgQGXgQGYgQGZgQGa +gQGbgQGcgQGdgQGegQGfgQGggQGhgQGigQGjgQGkgQGlgQGmgQGngQGogQGpgQGqgQGrgQGsgQGtgQGu +gQGvgQGwgQGxgQGygQGzgQG0gQG1gQG2gQG3gQG4gQG5gQG6gQG7gQG8gQG9gQG+gQG/gQHAgQHBgQHC +gQHDgQHEgQHFgQHGgQHHgQHIgQHJgQHKgQHLgQHMgQHNgQHOgQHPgQHQgQHRgQHSgQHTgQHUgQHVgQHW +gQHXgQHYgQHZgQHagQHbgQHcgQHdgQHegQHfgQHggQHhgQHigQHjgQHkgQHlgQHmgQHngQHogQHpgQHq +gQHrgQHsgQHtgQHugQHvgQHwgQHxgQHygQHzgQH0gQH1gQH2gQH3gQH4gQH5gQH6gQH7gQH8gQH9gQH+ +gQH/gQIAgQIBgQICgQIDgQIEgQIFgQIGgQIHgQIIgQIJgQIKgQILgQIMgQINgQIOgQIPgQIQgQIRENYR +AWwRAWoQBRDGEQFzEIMRAXAQXBDdEHwRAXERAV8RAVsQ8RCREFIQxBCOEQErEEgQ2xDmEIYRAXcQ0BEB +XhBQEFcQOBAlEJARASwQbxEBXRDiEQFyEEkQ4RDOEEsQThEBdBDZEQEoENUQShP//////////RATENwQ +5BDLEOAQwxB9EQFjEIEQORDTEQF4EQF2ENoQlhEBYhDfEQFrEMoRAWQQ7BDwEIIQzRDIEQFuEOgQcBDJ +EQFlEI8QfhAXEQFpEB0QlRBTEQEqEOsRAVwRAXkQ1BEBWRDeEQFoEQEpEMcQ4xAnEFYQGBA6EQF1EMEQ +2BCIEE0RAW0Q0hBqENcQURBPEQEnEM8QfxDMEQFaEGcQ0REBWBDpEOcQ9REBbxDFEO/SAA4APgByB96A +5KDSAA4APgMlB+GBATig0gAOAD4DJQfkgQE4oNIANwA4B+YH56IH5wA7Xk5TSUJPYmplY3REYXRhAAgA +GQAiACcAMQA6AD8ARABSAFQAZgSWBJwE5wTuBPUFAwUVBTEFPwVLBVcFZQVwBX4FmgWoBbsFzQXnBfEF +/gYABgMGBQYIBgsGDQYQBhIGFQYYBhsGHgYgBiIGJQYoBisGLgY3BkMGRQZHBlUGXgZnBnIGdwaGBo8G +ogarBrYGuAa7Br0G5gbzBwAHDgcYByYHMwdFB1kHZQdnB2kHawdtB3IHdAd2B3gHegd8B5cHngenB8AH +0gfbB+cH8wf1B/cH+gf8B/4IAAgLCBQIGwgiCC4IRwhQCFUIaAhxCHgIhQiLCJQIlgjpCOsI7QjvCPEI +8wj1CPcI+Qj7CP0I/wkBCQMJBQkHCQkJCwkNCQ8JEQkTCRUJFwkZCRsJHQkfCSEJIwklCScJKQkrCS0J +LwkxCTMJNQk3CTkJRglPCVcJWQlbCV0JfgmGCZoJpQmzCb0JygnRCdMJ1QnaCdwJ4QnjCeUJ5wn4Cf8K +CwoNChAKEwoWCiwKLgo7CkoKTApOClAKWApqCnMKeAqLCpgKmgqcCp4KsQq6Cr8KygrVCt4K5Qr9CwwL +GQsbCx0LHwtAC0ILRAtGC0gLSgtMC1kLWwtdC18LfQt+C5cLpAumC6gLqgvHC8kLywvNC88L0QvTC+AL +4gvlC+gL+gwTDCAMIgwkDCYMSwxVDFcMWQxbDGAMYgxkDGYMaAx2DHgMhwyUDJYMmAyaDLsMvQy/DMEM +wwzFDMcM2AzaDNwM3wziDOcM9A0BDQMNBQ0HDSgNKg0sDS4NMA0yDTQNQQ1DDUYNSQ1YDWcNdA12DXgN +eg2bDZ0Nnw2hDaMNpQ2nDasNrQ26DccNyQ3LDc0N8g34DfoN/A3+DgAOAg4EDgYOEw4VDhgOGw4uDjAO +Sw5YDloOXA5eDn8OgQ6DDoUOhw6JDosOmA6aDp0OoA6sDq4Oxg7TDtUO1w7ZDvoO/A7+DwAPAg8EDwYP +Ew8VDxcPGQ8eDyAPJg8zDzUPNw85D1oPXA9eD2APYg9kD2YPcQ9zD4EPjg+QD5IPlA+1D7cPuQ+7D70P +vw/BD88P3Q/qD+wP7g/wEBEQExAVEBcQGRAbEB0QOxBcEGkQaxBtEG8QkBCSEJQQlhCYEJoQnBCtEK8Q +wRDOENAQ0hDUEPUQ9xD5EPsQ/RD/EQEREhEUERcRGhEdESgRQBFNEU8RURFTEXQRdhF4EXoRfBF+EYAR +hRGHEZURohGkEaYRqBHNEc8R0RHTEdUR1xHZEeYR6BIMEhkSGxIdEh8SQBJCEkQSRhJIEkoSTBJRElMS +WRJmEmgSahJsEo0SjxKREpMSlRKXEpkSoBKoErkSxxLJEssSzRLPEuwS7hLwEvIS9BL2EvgTDxMvEzwT +PhNAE0ITYxNlE2cTaRNrE20TbxN1E3cTfhOLE40TjxORE7ITtBO2E7gTuhO8E74TzRPPE94T6xPtE+8T +8RQSFBQUFhQYFBoUHBQeFCIUJBQpFDYUOBQ6FDwUXRRfFGEUYxRlFGcUaRSGFIgUmhSnFKkUqxStFM4U +0BTSFNcU2RTbFN0U3xTsFO4U8RT0FQEVAxUZFSYVKBUqFSwVTRVPFVEVUxVVFVcVWRVmFWgVbxV8FX4V +gBWCFaMVpRWnFakVqxWtFa8VvBW+FcEVxBXaFdwV5hXzFfUV9xX5FhoWHBYeFiAWIhYkFiYWKxYtFjMW +QBZCFkQWRhZnFmkWaxZtFm8WcRZzFnkWexaJFpYWmBaaFpwWvRa/FsEWwxbFFscWyRbVFtcW8Bb9Fv8X +ARcDFyQXJhcoFyoXLBcuFzAXVxd5F4YXiBeKF4wXsRezF7UXtxe5F7sXvRfKF8wXzhfQF9sX9RgCGAQY +BhgIGCkYKxgtGC8YMRgzGDUYSRhLGGsYeBh6GHwYfhifGKEYoxilGKcYqRirGLYYuBjDGNAY0hjUGNYY +9xj5GPsY/Rj/GQEZAxkMGQ4ZJBk1GTcZORk7GT0ZRhlIGUoZUxlVGVcZYxlsGXUZfBmTGaAZohmkGaYZ +xxnJGcsZzRnPGdEZ0xnoGfoaBxoJGgsaDRoyGjQaNho4GjoaPBo+GkAaTBpOGm4aexp9Gn8agRqiGqQa +phqoGqoarBquGsQayhrXGtka2xrdGv4bABsCGwQbBhsIGwobExssGzUbPBtLG1MbXBtfHAocDBwOHBAc +EhwUHBYcGBwaHBwcHxwiHCQcJhwpHCscLRwvHDIcNBw2HDgcOxw9HD8cQhxFHEccShxMHE4cUBxSHFQc +VhxYHFocXBxfHGEcZBxmHGgcahxsHG4ccBxyHHQcdhx4HHocfRx/HIEcgxyFHIccihyMHI8ckRyTHJUc +lxyZHJscnRyfHKIcpRyoHKocrByuHLEcsxy1HLgcuxy9HL8cwRzDHMUc7hz8HQkdCx0NHQ4dEB0RHRMd +FR0XHUAdQh1EHUUdRx1IHUodTB1OHV8dYR1jHWUdZx1wHXkdex18HY4dlx2cHaEdqh2sHccdyR3LHc0d +zx3RHdMd1R3XHdkd2x3dHd8d4h4LHg0eDx4QHhIeEx4VHhceGR5CHkweVR5XHlkeWx5dHl8eYR5jHmUe +ah55HoIehB6PHpEekx6VHpcemR6+HsAewh7EHsYeyB7KHtQe+R77Hv0e/x8BHwMfBR8THzgfOh88Hz4f +QB9CH0QfRh9fH2Efih+MH44fkB+SH5Qflh+YH5ofsR+6H7wfxR/HH8kfyx/NH/Yf+B/6H/0f/yABIAMg +BSAIIBYgHyAhICggKiAsIC4gVyBZIFsgXiBgIGIgZCBmIGkgcCB5IHsggCCCIIQgrSCvILEgsyC1ILcg +uSC7IL4g5yDpIOsg7CDuIO8g8SDzIPUhHiEgISIhJSEnISkhKyEtITAhPCFFIUchSiFMIWUhjiGQIZIh +kyGVIZYhmCGaIZwhxSHHIckhzCHOIdAh0iHVIdgh6SHrIe4h8SH0IfsiBCIGIgsiDiIQIjEiMyI2Ijgi +OiI8Ij4iSSJTIlwiXiJtInAicyJ2InkifCJ/IoIiqyKtIq8isiK0IrYiuCK7Ir4izSLWItgi7yLxIvMi +9iL5Ivwi/yMBIwMjBSMIIwojKyMtIzAjMyM1IzcjOSNSI1QjfSN/I4EjgiOEI4UjhyOJI4sjtCO2I7gj +uSO7I7wjviPAI8IjzyP4I/oj/CP/JAEkAyQFJAgkCyQQJBkkGyQyJDQkNiQ5JDwkPiRAJEIkRCRHJEkk +SyR0JHYkeCR5JHskfCR+JIAkgiSrJK0krySwJLIksyS1JLckuSTiJOQk5iToJOok7CTuJPEk9CUdJR8l +ISUkJSYlKCUqJS0lMCU1JT4lQCVFJUclSSVyJXQldiV4JXolfCV+JYElhCWNJY8lmCWaJZwlnyWhJbAl +2SXbJd0l4CXiJeQl5iXpJewl8SX6Jfwl/yYBJg0mFiYbJiQmJybSJtQm1ibYJtom3CbeJuEm5CbmJugm +6ibsJu4m8CbyJvQm9ib4Jvom/Cb+JwEnAycFJwcnCScLJw4nECcSJxQnFicYJxsnHScfJyEnJCcmJygn +KicsJy4nMSczJzYnOCc6JzwnPidAJ0MnRidIJ0onTCdOJ1AnUidVJ1cnWSdcJ14nYCdiJ2UnaCdqJ20n +bydyJ3Qndid5J3snfSd/J4EngyeFJ4cniSeLJ5QnlyhEKEYoSChKKEwoTihQKFIoVChWKFkoXCheKGEo +YyhlKGcoaShsKG4ocChyKHUodyh5KHwofyiCKIQohiiIKIoojCiOKJAokiiUKJYomCibKJ0ooCiiKKQo +piioKKoorCiuKLAosii0KLYouSi7KL0ovyjBKMMoxijIKMsozSjPKNEo0yjVKNco2SjbKN4o4SjkKOYo +6SjrKO4o8SjzKPUo9yj5KPso/Sj/KQEpCikNKbopvSnAKcMpxinJKcwpzynSKdUp2CnbKd4p4SnkKecp +6intKfAp8yn2Kfkp/Cn/KgIqBSoIKgsqDioRKhQqFyoaKh0qICojKiYqKSosKi8qMio1KjgqOyo+KkEq +RCpHKkoqTSpQKlMqVipZKlwqXypiKmUqaCprKm4qcSp0Kncqeip9KoAqgyqGKokqjCqPKpIqlSqYKpsq +niqhKqQqpyqqKq0qsCqzKrYquSrDKs8q4ir7Kw0rLitAK0wraiuBK40rkCuqK8cr4iwHLCEsLSwvLEgs +ZSx6LJ8stiy/LNIs3i0dLUctYy1wLZItny23LcUt3y3hLgAuHS44LkQuUi5kLoYunS6hLq8u0i7eLuAu +7S7vLwIvDi8qLywvMS9UL1gvZC95L4UvpS+nL7svzi/qL/YwCzANMCAwJDA8MFUwaDBqMH8wtjDgMQUx +HDEvMUkxXDFxMXoxfTF+MYcxijGLMZQxlzKUMpYymDKaMpwynjKgMqMypTKoMqoyrTKvMrEyszK1Mrcy +uTK7Mr0ywDLCMsQyxjLIMsoyzDLOMtAy0jLVMtcy2jLcMt4y4DLiMuQy5jLoMuoy7DLuMvAy8zL1Mvcy ++jL8Mv8zATMDMwUzBzMJMwszDTMQMxIzFTMXMxkzGzMdMx8zITMjMyUzJzMpMyszLTMvMzEzMzM1Mzcz +OTM7Mz4zQDNCM0QzRzNKM00zTzNRM1MzVTNXM1kzWzNdM18zYTNjM2UzZzNpM2szbTNvM3EzczN1M3cz +eTN7M30zfzOCM4UzhzOJM4szjTOQM5IzlTOXM5kzmzOdM58zoTOqM600qjStNLA0szS2NLk0vDS/NMI0 +xTTINMs0zjTRNNQ01zTaNN004DTjNOY06TTsNO808jT1NPg0+zT+NQE1BDUHNQo1DTUQNRM1FjUZNRw1 +HzUiNSU1KDUrNS41MTU0NTc1OjU9NUA1QzVGNUk1TDVPNVI1VTVYNVs1XjVhNWQ1ZzVqNW01cDVzNXY1 +eTV8NX81gjWFNYg1izWONZE1lDWXNZo1nTWgNaM1pjWpNaw1rzWyNbU1uDW7Nb41wTXENcc1yjXNNdA1 +0zXWNdk13DXfNeI15TXoNes17jXxNfQ19zX6Nf02ADYDNgY2CTYMNg82EjYVNhg2GzYeNiE2IzYmNik2 +KzYtNjA2MjY1Njc2OTY7Nj42QTZENkY2SDZKNkw2TjZRNlM2VTZXNlk2XDZeNmE2YzZlNmc2aTZrNm42 +cDZzNnU2eDZ6Nnw2fjaANoI2hTaHNoo2jDaONpc2mTabNp02nzahNqM2pTaoNqo2rDauNrE2tDa2Nrg2 +uza9NsA2wjbFNsc2yTbLNs02zzbSNtQ21jbYNts23TbfNuE25DbmNug26jbtNu828jb1Nvc2+jb8Nv83 +AjcENwY3CDcKNww3DjcRNxM3FTcXNxk3HDceNyA3IjckNyY3KTcrNy03LzcyNzQ3Njc5Nzs3PTc/N0I3 +RDdGN083UTdSN1s3XjdfN2g3azdsN3U3egAAAAAAAAICAAAAAAAAB+gAAAAAAAAAAAAAAAAAADeJA + + + diff --git a/Samples/MultiThreadedHTTPServer/English.lproj/MainMenu.nib/keyedobjects.nib b/Samples/MultiThreadedHTTPServer/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 00000000..0cce095a Binary files /dev/null and b/Samples/MultiThreadedHTTPServer/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Samples/MultiThreadedHTTPServer/Info.plist b/Samples/MultiThreadedHTTPServer/Info.plist new file mode 100644 index 00000000..b139e61c --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.yourcompany.MultiThreadedHTTPServer + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/Samples/MultiThreadedHTTPServer/LICENSE.txt b/Samples/MultiThreadedHTTPServer/LICENSE.txt new file mode 100644 index 00000000..e472fd3b --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/LICENSE.txt @@ -0,0 +1,18 @@ +Software License Agreement (BSD License) + +Copyright (c) 2006, Deusty Designs, LLC +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Neither the name of Desuty Designs nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of Deusty Designs, LLC. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Samples/MultiThreadedHTTPServer/MultiThreadedHTTPServer.xcodeproj/project.pbxproj b/Samples/MultiThreadedHTTPServer/MultiThreadedHTTPServer.xcodeproj/project.pbxproj new file mode 100644 index 00000000..327f06f2 --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/MultiThreadedHTTPServer.xcodeproj/project.pbxproj @@ -0,0 +1,437 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 44; + objects = { + +/* Begin PBXBuildFile section */ + 8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + DC74B1220EE237ED004A1F31 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC74B1210EE237ED004A1F31 /* libcrypto.dylib */; }; + DC74B1320EE2387F004A1F31 /* ThreadPoolServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DC74B1310EE2387F004A1F31 /* ThreadPoolServer.m */; }; + DC74B18A0EE240F5004A1F31 /* ThreadPerConnectionServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DC74B1890EE240F5004A1F31 /* ThreadPerConnectionServer.m */; }; + DCAF3D580E56208700FAFF89 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAF3D570E56208700FAFF89 /* AppDelegate.m */; }; + DCD06676123C96EC006BC411 /* SSCrypto.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06675123C96EC006BC411 /* SSCrypto.m */; }; + DCD0667D123C96FE006BC411 /* DDData.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06678123C96FE006BC411 /* DDData.m */; }; + DCD0667E123C96FE006BC411 /* DDNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD0667A123C96FE006BC411 /* DDNumber.m */; }; + DCD0667F123C96FE006BC411 /* DDRange.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD0667C123C96FE006BC411 /* DDRange.m */; }; + DCD06682123C9713006BC411 /* AsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06681123C9713006BC411 /* AsyncSocket.m */; }; + DCD0668F123C9729006BC411 /* HTTPAsyncFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06684123C9729006BC411 /* HTTPAsyncFileResponse.m */; }; + DCD06690123C9729006BC411 /* HTTPAuthenticationRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06686123C9729006BC411 /* HTTPAuthenticationRequest.m */; }; + DCD06691123C9729006BC411 /* HTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06688123C9729006BC411 /* HTTPConnection.m */; }; + DCD06692123C9729006BC411 /* HTTPDynamicFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD0668A123C9729006BC411 /* HTTPDynamicFileResponse.m */; }; + DCD06693123C9729006BC411 /* HTTPResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD0668C123C9729006BC411 /* HTTPResponse.m */; }; + DCD06694123C9729006BC411 /* HTTPServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD0668E123C9729006BC411 /* HTTPServer.m */; }; + DCD06698123C9761006BC411 /* WebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD06697123C9761006BC411 /* WebSocket.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + DCAF3D510E561FB200FAFF89 /* Copy Internal Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Copy Internal Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32CA4F630368D1EE00C91783 /* MultiThreadedHTTPServer_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultiThreadedHTTPServer_Prefix.pch; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* MultiThreadedHTTPServer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MultiThreadedHTTPServer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + DC74B1210EE237ED004A1F31 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = /usr/lib/libcrypto.dylib; sourceTree = ""; }; + DC74B1300EE2387F004A1F31 /* ThreadPoolServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadPoolServer.h; sourceTree = ""; }; + DC74B1310EE2387F004A1F31 /* ThreadPoolServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadPoolServer.m; sourceTree = ""; }; + DC74B1880EE240F5004A1F31 /* ThreadPerConnectionServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadPerConnectionServer.h; sourceTree = ""; }; + DC74B1890EE240F5004A1F31 /* ThreadPerConnectionServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadPerConnectionServer.m; sourceTree = ""; }; + DCAF3D560E56208700FAFF89 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + DCAF3D570E56208700FAFF89 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + DCD06674123C96EC006BC411 /* SSCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SSCrypto.h; path = ../../SSCrypto.h; sourceTree = SOURCE_ROOT; }; + DCD06675123C96EC006BC411 /* SSCrypto.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SSCrypto.m; path = ../../SSCrypto.m; sourceTree = SOURCE_ROOT; }; + DCD06677123C96FE006BC411 /* DDData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDData.h; path = ../../DDData.h; sourceTree = SOURCE_ROOT; }; + DCD06678123C96FE006BC411 /* DDData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDData.m; path = ../../DDData.m; sourceTree = SOURCE_ROOT; }; + DCD06679123C96FE006BC411 /* DDNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDNumber.h; path = ../../DDNumber.h; sourceTree = SOURCE_ROOT; }; + DCD0667A123C96FE006BC411 /* DDNumber.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDNumber.m; path = ../../DDNumber.m; sourceTree = SOURCE_ROOT; }; + DCD0667B123C96FE006BC411 /* DDRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DDRange.h; path = ../../DDRange.h; sourceTree = SOURCE_ROOT; }; + DCD0667C123C96FE006BC411 /* DDRange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDRange.m; path = ../../DDRange.m; sourceTree = SOURCE_ROOT; }; + DCD06680123C9713006BC411 /* AsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AsyncSocket.h; path = ../../AsyncSocket.h; sourceTree = SOURCE_ROOT; }; + DCD06681123C9713006BC411 /* AsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AsyncSocket.m; path = ../../AsyncSocket.m; sourceTree = SOURCE_ROOT; }; + DCD06683123C9729006BC411 /* HTTPAsyncFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPAsyncFileResponse.h; path = ../../HTTPAsyncFileResponse.h; sourceTree = SOURCE_ROOT; }; + DCD06684123C9729006BC411 /* HTTPAsyncFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPAsyncFileResponse.m; path = ../../HTTPAsyncFileResponse.m; sourceTree = SOURCE_ROOT; }; + DCD06685123C9729006BC411 /* HTTPAuthenticationRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPAuthenticationRequest.h; path = ../../HTTPAuthenticationRequest.h; sourceTree = SOURCE_ROOT; }; + DCD06686123C9729006BC411 /* HTTPAuthenticationRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPAuthenticationRequest.m; path = ../../HTTPAuthenticationRequest.m; sourceTree = SOURCE_ROOT; }; + DCD06687123C9729006BC411 /* HTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPConnection.h; path = ../../HTTPConnection.h; sourceTree = SOURCE_ROOT; }; + DCD06688123C9729006BC411 /* HTTPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPConnection.m; path = ../../HTTPConnection.m; sourceTree = SOURCE_ROOT; }; + DCD06689123C9729006BC411 /* HTTPDynamicFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPDynamicFileResponse.h; path = ../../HTTPDynamicFileResponse.h; sourceTree = SOURCE_ROOT; }; + DCD0668A123C9729006BC411 /* HTTPDynamicFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPDynamicFileResponse.m; path = ../../HTTPDynamicFileResponse.m; sourceTree = SOURCE_ROOT; }; + DCD0668B123C9729006BC411 /* HTTPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPResponse.h; path = ../../HTTPResponse.h; sourceTree = SOURCE_ROOT; }; + DCD0668C123C9729006BC411 /* HTTPResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPResponse.m; path = ../../HTTPResponse.m; sourceTree = SOURCE_ROOT; }; + DCD0668D123C9729006BC411 /* HTTPServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPServer.h; path = ../../HTTPServer.h; sourceTree = SOURCE_ROOT; }; + DCD0668E123C9729006BC411 /* HTTPServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPServer.m; path = ../../HTTPServer.m; sourceTree = SOURCE_ROOT; }; + DCD06696123C9761006BC411 /* WebSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebSocket.h; path = ../../WebSocket.h; sourceTree = SOURCE_ROOT; }; + DCD06697123C9761006BC411 /* WebSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WebSocket.m; path = ../../WebSocket.m; sourceTree = SOURCE_ROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + DC74B1220EE237ED004A1F31 /* libcrypto.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + DCAF3D560E56208700FAFF89 /* AppDelegate.h */, + DCAF3D570E56208700FAFF89 /* AppDelegate.m */, + DC74B1300EE2387F004A1F31 /* ThreadPoolServer.h */, + DC74B1310EE2387F004A1F31 /* ThreadPoolServer.m */, + DC74B1880EE240F5004A1F31 /* ThreadPerConnectionServer.h */, + DC74B1890EE240F5004A1F31 /* ThreadPerConnectionServer.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + DC74B1210EE237ED004A1F31 /* libcrypto.dylib */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* MultiThreadedHTTPServer.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* MultiThreadedHTTPServer */ = { + isa = PBXGroup; + children = ( + DC74B11B0EE237B2004A1F31 /* SSCrypto */, + DC74B12C0EE23811004A1F31 /* Categories */, + DCAF3D3E0E561F2B00FAFF89 /* TCP */, + DCAF3D420E561F3D00FAFF89 /* HTTP */, + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = MultiThreadedHTTPServer; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 32CA4F630368D1EE00C91783 /* MultiThreadedHTTPServer_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 8D1107310486CEB800E47090 /* Info.plist */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + DC74B11B0EE237B2004A1F31 /* SSCrypto */ = { + isa = PBXGroup; + children = ( + DCD06674123C96EC006BC411 /* SSCrypto.h */, + DCD06675123C96EC006BC411 /* SSCrypto.m */, + ); + name = SSCrypto; + sourceTree = ""; + }; + DC74B12C0EE23811004A1F31 /* Categories */ = { + isa = PBXGroup; + children = ( + DCD06679123C96FE006BC411 /* DDNumber.h */, + DCD0667A123C96FE006BC411 /* DDNumber.m */, + DCD0667B123C96FE006BC411 /* DDRange.h */, + DCD0667C123C96FE006BC411 /* DDRange.m */, + DCD06677123C96FE006BC411 /* DDData.h */, + DCD06678123C96FE006BC411 /* DDData.m */, + ); + name = Categories; + sourceTree = ""; + }; + DCAF3D3E0E561F2B00FAFF89 /* TCP */ = { + isa = PBXGroup; + children = ( + DCD06680123C9713006BC411 /* AsyncSocket.h */, + DCD06681123C9713006BC411 /* AsyncSocket.m */, + ); + name = TCP; + sourceTree = ""; + }; + DCAF3D420E561F3D00FAFF89 /* HTTP */ = { + isa = PBXGroup; + children = ( + DCD06685123C9729006BC411 /* HTTPAuthenticationRequest.h */, + DCD06686123C9729006BC411 /* HTTPAuthenticationRequest.m */, + DCD0668D123C9729006BC411 /* HTTPServer.h */, + DCD0668E123C9729006BC411 /* HTTPServer.m */, + DCD06687123C9729006BC411 /* HTTPConnection.h */, + DCD06688123C9729006BC411 /* HTTPConnection.m */, + DCD0668B123C9729006BC411 /* HTTPResponse.h */, + DCD0668C123C9729006BC411 /* HTTPResponse.m */, + DCD06696123C9761006BC411 /* WebSocket.h */, + DCD06697123C9761006BC411 /* WebSocket.m */, + DCD06695123C972E006BC411 /* Advanced */, + ); + name = HTTP; + sourceTree = ""; + }; + DCD06695123C972E006BC411 /* Advanced */ = { + isa = PBXGroup; + children = ( + DCD06683123C9729006BC411 /* HTTPAsyncFileResponse.h */, + DCD06684123C9729006BC411 /* HTTPAsyncFileResponse.m */, + DCD06689123C9729006BC411 /* HTTPDynamicFileResponse.h */, + DCD0668A123C9729006BC411 /* HTTPDynamicFileResponse.m */, + ); + name = Advanced; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47090 /* MultiThreadedHTTPServer */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "MultiThreadedHTTPServer" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + DCAF3D510E561FB200FAFF89 /* Copy Internal Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MultiThreadedHTTPServer; + productInstallPath = "$(HOME)/Applications"; + productName = MultiThreadedHTTPServer; + productReference = 8D1107320486CEB800E47090 /* MultiThreadedHTTPServer.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MultiThreadedHTTPServer" */; + compatibilityVersion = "Xcode 3.0"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* MultiThreadedHTTPServer */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47090 /* MultiThreadedHTTPServer */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */, + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072D0486CEB800E47090 /* main.m in Sources */, + DCAF3D580E56208700FAFF89 /* AppDelegate.m in Sources */, + DC74B1320EE2387F004A1F31 /* ThreadPoolServer.m in Sources */, + DC74B18A0EE240F5004A1F31 /* ThreadPerConnectionServer.m in Sources */, + DCD06676123C96EC006BC411 /* SSCrypto.m in Sources */, + DCD0667D123C96FE006BC411 /* DDData.m in Sources */, + DCD0667E123C96FE006BC411 /* DDNumber.m in Sources */, + DCD0667F123C96FE006BC411 /* DDRange.m in Sources */, + DCD06682123C9713006BC411 /* AsyncSocket.m in Sources */, + DCD0668F123C9729006BC411 /* HTTPAsyncFileResponse.m in Sources */, + DCD06690123C9729006BC411 /* HTTPAuthenticationRequest.m in Sources */, + DCD06691123C9729006BC411 /* HTTPConnection.m in Sources */, + DCD06692123C9729006BC411 /* HTTPDynamicFileResponse.m in Sources */, + DCD06693123C9729006BC411 /* HTTPResponse.m in Sources */, + DCD06694123C9729006BC411 /* HTTPServer.m in Sources */, + DCD06698123C9761006BC411 /* WebSocket.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = { + isa = PBXVariantGroup; + children = ( + 29B97319FDCFA39411CA2CEA /* English */, + ); + name = MainMenu.nib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = MultiThreadedHTTPServer_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = MultiThreadedHTTPServer; + WRAPPER_EXTENSION = app; + ZERO_LINK = YES; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + ); + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = MultiThreadedHTTPServer_Prefix.pch; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + PRODUCT_NAME = MultiThreadedHTTPServer; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)"; + ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "MultiThreadedHTTPServer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MultiThreadedHTTPServer" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/Samples/MultiThreadedHTTPServer/MultiThreadedHTTPServer_Prefix.pch b/Samples/MultiThreadedHTTPServer/MultiThreadedHTTPServer_Prefix.pch new file mode 100644 index 00000000..cb7a8e16 --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/MultiThreadedHTTPServer_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'MultiThreadedHTTPServer' target in the 'MultiThreadedHTTPServer' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Samples/MultiThreadedHTTPServer/ThreadPerConnectionServer.h b/Samples/MultiThreadedHTTPServer/ThreadPerConnectionServer.h new file mode 100644 index 00000000..fe274661 --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/ThreadPerConnectionServer.h @@ -0,0 +1,25 @@ +// +// The ThreadPerConnectionServer creates a new thread for every incoming connection. +// After the thread is created, the connection is moved to the new thread. +// +// This is for DEMONSTRATION purposes only, and this technique will not scale well. +// Please understand the cost of creating threads on your target platform. +// + +#import "HTTPServer.h" +#import "HTTPConnection.h" + +@interface ThreadPerConnectionServer : HTTPServer +{ + +} + +@end + +@interface TPCConnection : HTTPConnection +{ + NSRunLoop *myRunLoop; + BOOL continueRunLoop; +} + +@end \ No newline at end of file diff --git a/Samples/MultiThreadedHTTPServer/ThreadPerConnectionServer.m b/Samples/MultiThreadedHTTPServer/ThreadPerConnectionServer.m new file mode 100644 index 00000000..b243349f --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/ThreadPerConnectionServer.m @@ -0,0 +1,94 @@ +#import "ThreadPerConnectionServer.h" +#import "AsyncSocket.h" + + +@interface HTTPConnection (InternalAPI) + +- (void)startReadingRequest; + +@end + +@implementation ThreadPerConnectionServer + +- (id)init +{ + if(self = [super init]) + { + connectionClass = [TPCConnection self]; + } + return self; +} + +@end + +@implementation TPCConnection + +- (id)initWithAsyncSocket:(AsyncSocket *)newSocket forServer:(HTTPServer *)myServer +{ + if(self = [super initWithAsyncSocket:newSocket forServer:myServer]) + { + continueRunLoop = YES; + [NSThread detachNewThreadSelector:@selector(setupRunLoop) toTarget:self withObject:nil]; + + // Note: The target of the thread is automatically retained, and released when the thread exits. + } + return self; +} + +- (void)setupRunLoop +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + @synchronized(self) + { + myRunLoop = [NSRunLoop currentRunLoop]; + } + + // Note: It is assumed the main listening socket is running on the main thread. + // If this assumption is incorrect in your case, you'll need to call switchRunLoop on correct thread. + [self performSelectorOnMainThread:@selector(switchRunLoop) withObject:nil waitUntilDone:YES]; + + [self startReadingRequest]; + + while (continueRunLoop) + { + NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init]; + + [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; + + NSLog(@"iteration"); + [innerPool release]; + } + + NSLog(@"%p: RunLoop closing down", self); + + [pool release]; +} + +- (void)switchRunLoop +{ + @synchronized(self) + { + // The moveToRunLoop method must be called on the socket's existing runloop/thread + [asyncSocket moveToRunLoop:myRunLoop]; + } + + NSLog(@"%p: Run loop up", self); +} + + +- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port +{ + // Do nothing here - wait until the socket has been moved to the proper thread +} + +/** + * Called when the connection dies. +**/ +- (void)die +{ + continueRunLoop = NO; + [super die]; +} + +@end diff --git a/Samples/MultiThreadedHTTPServer/ThreadPoolServer.h b/Samples/MultiThreadedHTTPServer/ThreadPoolServer.h new file mode 100644 index 00000000..b2ec3cdc --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/ThreadPoolServer.h @@ -0,0 +1,21 @@ +// +// The ThreadPoolServer uses a pool of threads to handle connections. +// Each incoming connection is moved to a thread within the thread pool. +// We attempt to evenly spread the connections between the threads. +// To do this, we maintain the number of connections that are on each thread. +// A new incoming connection will be placed on the thread with the least connections. +// + +#import "HTTPServer.h" +#import "HTTPConnection.h" + +// Define number of connection threads to run +#define THREAD_POOL_SIZE 10 + +@interface ThreadPoolServer : HTTPServer +{ + NSMutableArray *runLoops; + NSMutableArray *runLoopsLoad; +} + +@end diff --git a/Samples/MultiThreadedHTTPServer/ThreadPoolServer.m b/Samples/MultiThreadedHTTPServer/ThreadPoolServer.m new file mode 100644 index 00000000..3d5aeae9 --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/ThreadPoolServer.m @@ -0,0 +1,125 @@ +#import "ThreadPoolServer.h" + +@interface HTTPServer (InternalAPI) + +- (void)connectionDidDie:(NSNotification *)notification; + +@end + + +@implementation ThreadPoolServer + +- (id)init +{ + if(self = [super init]) + { + // Initialize an array to reference all the threads + runLoops = [[NSMutableArray alloc] initWithCapacity:THREAD_POOL_SIZE]; + + // Initialize an array to hold the number of connections being processed for each thread + runLoopsLoad = [[NSMutableArray alloc] initWithCapacity:THREAD_POOL_SIZE]; + + // Start threads + uint i; + for(i = 0; i < THREAD_POOL_SIZE; i++) + { + [NSThread detachNewThreadSelector:@selector(connectionThread:) + toTarget:self + withObject:[NSNumber numberWithUnsignedInt:i]]; + } + } + return self; +} + + +- (void)connectionThread:(NSNumber *)threadNum +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + @synchronized(runLoops) + { + [runLoops addObject:[NSRunLoop currentRunLoop]]; + [runLoopsLoad addObject:[NSNumber numberWithUnsignedInt:0]]; + } + + NSLog(@"Starting thread %@", threadNum); + + // We can't run the run loop unless it has an associated input source or a timer. + // So we'll just create a timer that will never fire - unless the server runs for 10,000 years. + [NSTimer scheduledTimerWithTimeInterval:DBL_MAX target:self selector:@selector(ignore:) userInfo:nil repeats:NO]; + + // Start the run loop + [[NSRunLoop currentRunLoop] run]; + + [pool release]; +} + +/** + * Called when a new socket is spawned to handle a connection. This method should return the runloop of the + * thread on which the new socket and its delegate should operate. If omitted, [NSRunLoop currentRunLoop] is used. +**/ +- (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket +{ + // Figure out what thread/runloop to run the new connection on. + // We choose the thread/runloop with the lowest number of connections. + + uint m = 0; + NSRunLoop *mLoop = nil; + uint mLoad = 0; + + @synchronized(runLoops) + { + mLoop = [runLoops objectAtIndex:0]; + mLoad = [[runLoopsLoad objectAtIndex:0] unsignedIntValue]; + + uint i; + for(i = 1; i < THREAD_POOL_SIZE; i++) + { + uint iLoad = [[runLoopsLoad objectAtIndex:i] unsignedIntValue]; + + if(iLoad < mLoad) + { + m = i; + mLoop = [runLoops objectAtIndex:i]; + mLoad = iLoad; + } + } + + [runLoopsLoad replaceObjectAtIndex:m withObject:[NSNumber numberWithUnsignedInt:(mLoad + 1)]]; + } + + NSLog(@"Choosing run loop %u with load %u", m, mLoad); + + // And finally, return the proper run loop + return mLoop; +} + +/** + * This method is automatically called when a HTTPConnection dies. + * We need to update the number of connections per thread. +**/ +- (void)connectionDidDie:(NSNotification *)notification +{ + // Note: This method is called on the thread/runloop that posted the notification + + @synchronized(runLoops) + { + unsigned int runLoopIndex = [runLoops indexOfObject:[NSRunLoop currentRunLoop]]; + + if(runLoopIndex < [runLoops count]) + { + unsigned int runLoopLoad = [[runLoopsLoad objectAtIndex:runLoopIndex] unsignedIntValue]; + + NSNumber *newLoad = [NSNumber numberWithUnsignedInt:(runLoopLoad - 1)]; + + [runLoopsLoad replaceObjectAtIndex:runLoopIndex withObject:newLoad]; + + NSLog(@"Updating run loop %u with load %@", runLoopIndex, newLoad); + } + } + + // Don't forget to call super, or the connection won't get proper deallocated! + [super connectionDidDie:notification]; +} + +@end diff --git a/Samples/MultiThreadedHTTPServer/main.m b/Samples/MultiThreadedHTTPServer/main.m new file mode 100644 index 00000000..5baac91d --- /dev/null +++ b/Samples/MultiThreadedHTTPServer/main.m @@ -0,0 +1,14 @@ +// +// main.m +// MultiThreadedHTTPServer +// +// Created by Robbie Hanson on 8/15/08. +// Copyright __MyCompanyName__ 2008. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **) argv); +}