| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/chrome/browser/ui/browser_view_controller.h" | 5 #import "ios/chrome/browser/ui/browser_view_controller.h" |
| 6 | 6 |
| 7 #import <AssetsLibrary/AssetsLibrary.h> | 7 #import <AssetsLibrary/AssetsLibrary.h> |
| 8 #import <MobileCoreServices/MobileCoreServices.h> | 8 #import <MobileCoreServices/MobileCoreServices.h> |
| 9 #import <PassKit/PassKit.h> | 9 #import <PassKit/PassKit.h> |
| 10 #import <Photos/Photos.h> | 10 #import <Photos/Photos.h> |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 return true; | 288 return true; |
| 289 std::string url_host = url.host(); | 289 std::string url_host = url.host(); |
| 290 return url_host != kChromeUIHistoryHost && | 290 return url_host != kChromeUIHistoryHost && |
| 291 url_host != kChromeUIHistoryFrameHost; | 291 url_host != kChromeUIHistoryFrameHost; |
| 292 } | 292 } |
| 293 | 293 |
| 294 // Temporary key to use when storing native controllers vended to tabs before | 294 // Temporary key to use when storing native controllers vended to tabs before |
| 295 // they are added to the tab model. | 295 // they are added to the tab model. |
| 296 NSString* const kNativeControllerTemporaryKey = @"NativeControllerTemporaryKey"; | 296 NSString* const kNativeControllerTemporaryKey = @"NativeControllerTemporaryKey"; |
| 297 | 297 |
| 298 // Helper function to return the FindInPageController for the given |tab|. If | 298 } // namespace |
| 299 // |tab| is nullptr or has no FindTabHelper, returns nil. | |
| 300 FindInPageController* GetFindInPageController(Tab* tab) { | |
| 301 if (!tab) { | |
| 302 return nil; | |
| 303 } | |
| 304 FindTabHelper* helper = FindTabHelper::FromWebState(tab.webState); | |
| 305 if (!helper) { | |
| 306 return nil; | |
| 307 } | |
| 308 return helper->GetController(); | |
| 309 } | |
| 310 | |
| 311 } // anonymous namespace | |
| 312 | 299 |
| 313 @interface BrowserViewController ()<AppRatingPromptDelegate, | 300 @interface BrowserViewController ()<AppRatingPromptDelegate, |
| 314 ContextualSearchControllerDelegate, | 301 ContextualSearchControllerDelegate, |
| 315 ContextualSearchPanelMotionObserver, | 302 ContextualSearchPanelMotionObserver, |
| 316 CRWNativeContentProvider, | 303 CRWNativeContentProvider, |
| 317 CRWWebStateDelegate, | 304 CRWWebStateDelegate, |
| 318 DialogPresenterDelegate, | 305 DialogPresenterDelegate, |
| 319 FullScreenControllerDelegate, | 306 FullScreenControllerDelegate, |
| 320 KeyCommandsPlumbing, | 307 KeyCommandsPlumbing, |
| 321 MFMailComposeViewControllerDelegate, | 308 MFMailComposeViewControllerDelegate, |
| (...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1088 Tab* tab = [_model currentTab]; | 1075 Tab* tab = [_model currentTab]; |
| 1089 // TODO(shreyasv): Make it so the URL returned by the tab is always valid and | 1076 // TODO(shreyasv): Make it so the URL returned by the tab is always valid and |
| 1090 // remove check on net::NSURLWithGURL(tab.url) ( http://crbug.com/400999 ). | 1077 // remove check on net::NSURLWithGURL(tab.url) ( http://crbug.com/400999 ). |
| 1091 return tab && !tab.url.SchemeIs(kChromeUIScheme) && | 1078 return tab && !tab.url.SchemeIs(kChromeUIScheme) && |
| 1092 net::NSURLWithGURL(tab.url); | 1079 net::NSURLWithGURL(tab.url); |
| 1093 } | 1080 } |
| 1094 | 1081 |
| 1095 - (BOOL)canShowFindBar { | 1082 - (BOOL)canShowFindBar { |
| 1096 // Make sure web controller can handle find in page. | 1083 // Make sure web controller can handle find in page. |
| 1097 Tab* tab = [_model currentTab]; | 1084 Tab* tab = [_model currentTab]; |
| 1098 FindInPageController* controller = GetFindInPageController(tab); | 1085 if (!tab) { |
| 1099 if (![controller canFindInPage]) | |
| 1100 return NO; | 1086 return NO; |
| 1087 } |
| 1101 | 1088 |
| 1102 // Don't show twice. | 1089 auto* helper = FindTabHelper::FromWebState(tab.webState); |
| 1103 if (controller.findInPageModel.enabled) | 1090 return (helper && helper->CurrentPageSupportsFindInPage() && |
| 1104 return NO; | 1091 !helper->IsFindUIActive()); |
| 1105 | |
| 1106 return YES; | |
| 1107 } | 1092 } |
| 1108 | 1093 |
| 1109 - (web::UserAgentType)userAgentType { | 1094 - (web::UserAgentType)userAgentType { |
| 1110 web::WebState* webState = [_model currentTab].webState; | 1095 web::WebState* webState = [_model currentTab].webState; |
| 1111 if (!webState) | 1096 if (!webState) |
| 1112 return web::UserAgentType::NONE; | 1097 return web::UserAgentType::NONE; |
| 1113 web::NavigationItem* visibleItem = | 1098 web::NavigationItem* visibleItem = |
| 1114 webState->GetNavigationManager()->GetVisibleItem(); | 1099 webState->GetNavigationManager()->GetVisibleItem(); |
| 1115 if (!visibleItem) | 1100 if (!visibleItem) |
| 1116 return web::UserAgentType::NONE; | 1101 return web::UserAgentType::NONE; |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1468 name:kTabModelNewTabWillOpenNotification | 1453 name:kTabModelNewTabWillOpenNotification |
| 1469 object:_model]; | 1454 object:_model]; |
| 1470 } | 1455 } |
| 1471 | 1456 |
| 1472 - (void)pageLoadStarting:(NSNotification*)notify { | 1457 - (void)pageLoadStarting:(NSNotification*)notify { |
| 1473 Tab* tab = notify.userInfo[kTabModelTabKey]; | 1458 Tab* tab = notify.userInfo[kTabModelTabKey]; |
| 1474 DCHECK(tab && ([_model indexOfTab:tab] != NSNotFound)); | 1459 DCHECK(tab && ([_model indexOfTab:tab] != NSNotFound)); |
| 1475 // Hide find bar when navigating to a new page. | 1460 // Hide find bar when navigating to a new page. |
| 1476 [self hideFindBarWithAnimation:NO]; | 1461 [self hideFindBarWithAnimation:NO]; |
| 1477 | 1462 |
| 1478 FindInPageController* controller = GetFindInPageController(tab); | |
| 1479 controller.findInPageModel.enabled = NO; | |
| 1480 | |
| 1481 if (tab == [_model currentTab]) { | 1463 if (tab == [_model currentTab]) { |
| 1482 // TODO(pinkerton): Fill in here about hiding the forward button on | 1464 // TODO(pinkerton): Fill in here about hiding the forward button on |
| 1483 // navigation. | 1465 // navigation. |
| 1484 } | 1466 } |
| 1485 } | 1467 } |
| 1486 | 1468 |
| 1487 - (void)pageLoadStarted:(NSNotification*)notify { | 1469 - (void)pageLoadStarted:(NSNotification*)notify { |
| 1488 Tab* tab = notify.userInfo[kTabModelTabKey]; | 1470 Tab* tab = notify.userInfo[kTabModelTabKey]; |
| 1489 DCHECK(tab); | 1471 DCHECK(tab); |
| 1490 if (tab == [_model currentTab]) { | 1472 if (tab == [_model currentTab]) { |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1923 | 1905 |
| 1924 if (tab.isPrerenderTab && !_toolbarModelIOS->IsLoading()) | 1906 if (tab.isPrerenderTab && !_toolbarModelIOS->IsLoading()) |
| 1925 [_toolbarController showPrerenderingAnimation]; | 1907 [_toolbarController showPrerenderingAnimation]; |
| 1926 | 1908 |
| 1927 // Also update the loading state for the tools menu (that is really an | 1909 // Also update the loading state for the tools menu (that is really an |
| 1928 // extension of the toolbar on the iPhone). | 1910 // extension of the toolbar on the iPhone). |
| 1929 if (!IsIPadIdiom()) | 1911 if (!IsIPadIdiom()) |
| 1930 [[_toolbarController toolsPopupController] | 1912 [[_toolbarController toolsPopupController] |
| 1931 setIsTabLoading:_toolbarModelIOS->IsLoading()]; | 1913 setIsTabLoading:_toolbarModelIOS->IsLoading()]; |
| 1932 | 1914 |
| 1933 FindInPageController* controller = GetFindInPageController(tab); | 1915 auto* findHelper = FindTabHelper::FromWebState(tab.webState); |
| 1934 if (controller.findInPageModel.enabled) { | 1916 if (findHelper && findHelper->IsFindUIActive()) { |
| 1935 [self showFindBarWithAnimation:NO | 1917 [self showFindBarWithAnimation:NO |
| 1936 selectText:YES | 1918 selectText:YES |
| 1937 shouldFocus:[_findBarController isFocused]]; | 1919 shouldFocus:[_findBarController isFocused]]; |
| 1938 } | 1920 } |
| 1939 | 1921 |
| 1940 // Hide the toolbar if displaying phone NTP. | 1922 // Hide the toolbar if displaying phone NTP. |
| 1941 if (!IsIPadIdiom()) { | 1923 if (!IsIPadIdiom()) { |
| 1942 web::NavigationItem* item = [tab navigationManager]->GetVisibleItem(); | 1924 web::NavigationItem* item = [tab navigationManager]->GetVisibleItem(); |
| 1943 BOOL hideToolbar = NO; | 1925 BOOL hideToolbar = NO; |
| 1944 if (item) { | 1926 if (item) { |
| (...skipping 1958 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3903 return card; | 3885 return card; |
| 3904 } | 3886 } |
| 3905 | 3887 |
| 3906 #pragma mark - Command Handling | 3888 #pragma mark - Command Handling |
| 3907 | 3889 |
| 3908 - (IBAction)chromeExecuteCommand:(id)sender { | 3890 - (IBAction)chromeExecuteCommand:(id)sender { |
| 3909 NSInteger command = [sender tag]; | 3891 NSInteger command = [sender tag]; |
| 3910 | 3892 |
| 3911 if (!_model || !_browserState) | 3893 if (!_model || !_browserState) |
| 3912 return; | 3894 return; |
| 3895 Tab* currentTab = [_model currentTab]; |
| 3913 | 3896 |
| 3914 switch (command) { | 3897 switch (command) { |
| 3915 case IDC_BACK: | 3898 case IDC_BACK: |
| 3916 [[_model currentTab] goBack]; | 3899 [[_model currentTab] goBack]; |
| 3917 break; | 3900 break; |
| 3918 case IDC_BOOKMARK_PAGE: | 3901 case IDC_BOOKMARK_PAGE: |
| 3919 [self initializeBookmarkInteractionController]; | 3902 [self initializeBookmarkInteractionController]; |
| 3920 [_bookmarkInteractionController | 3903 [_bookmarkInteractionController |
| 3921 presentBookmarkForTab:[_model currentTab] | 3904 presentBookmarkForTab:[_model currentTab] |
| 3922 currentlyBookmarked:_toolbarModelIOS->IsCurrentTabBookmarkedByUser() | 3905 currentlyBookmarked:_toolbarModelIOS->IsCurrentTabBookmarkedByUser() |
| 3923 inView:[_toolbarController bookmarkButtonView] | 3906 inView:[_toolbarController bookmarkButtonView] |
| 3924 originRect:[_toolbarController bookmarkButtonAnchorRect]]; | 3907 originRect:[_toolbarController bookmarkButtonAnchorRect]]; |
| 3925 break; | 3908 break; |
| 3926 case IDC_CLOSE_TAB: | 3909 case IDC_CLOSE_TAB: |
| 3927 [self closeCurrentTab]; | 3910 [self closeCurrentTab]; |
| 3928 break; | 3911 break; |
| 3929 case IDC_FIND: | 3912 case IDC_FIND: |
| 3930 [self initFindBarForTab]; | 3913 [self initFindBarForTab]; |
| 3931 break; | 3914 break; |
| 3932 case IDC_FIND_NEXT: { | 3915 case IDC_FIND_NEXT: { |
| 3933 FindInPageController* findInPageController = | 3916 DCHECK(currentTab); |
| 3934 GetFindInPageController([_model currentTab]); | |
| 3935 // TODO(crbug.com/603524): Reshow find bar if necessary. | 3917 // TODO(crbug.com/603524): Reshow find bar if necessary. |
| 3936 [findInPageController findNextStringInPageWithCompletionHandler:^{ | 3918 FindTabHelper::FromWebState(currentTab.webState) |
| 3937 FindInPageModel* model = findInPageController.findInPageModel; | 3919 ->ContinueFinding(FindTabHelper::FORWARD, ^(FindInPageModel* model) { |
| 3938 [_findBarController updateResultsCount:model]; | 3920 [_findBarController updateResultsCount:model]; |
| 3939 }]; | 3921 }); |
| 3940 break; | 3922 break; |
| 3941 } | 3923 } |
| 3942 case IDC_FIND_PREVIOUS: { | 3924 case IDC_FIND_PREVIOUS: { |
| 3943 FindInPageController* findInPageController = | 3925 DCHECK(currentTab); |
| 3944 GetFindInPageController([_model currentTab]); | |
| 3945 // TODO(crbug.com/603524): Reshow find bar if necessary. | 3926 // TODO(crbug.com/603524): Reshow find bar if necessary. |
| 3946 [findInPageController findPreviousStringInPageWithCompletionHandler:^{ | 3927 FindTabHelper::FromWebState(currentTab.webState) |
| 3947 FindInPageModel* model = findInPageController.findInPageModel; | 3928 ->ContinueFinding(FindTabHelper::REVERSE, ^(FindInPageModel* model) { |
| 3948 [_findBarController updateResultsCount:model]; | 3929 [_findBarController updateResultsCount:model]; |
| 3949 }]; | 3930 }); |
| 3950 break; | 3931 break; |
| 3951 } | 3932 } |
| 3952 case IDC_FIND_CLOSE: | 3933 case IDC_FIND_CLOSE: |
| 3953 [self closeFindInPage]; | 3934 [self closeFindInPage]; |
| 3954 break; | 3935 break; |
| 3955 case IDC_FIND_UPDATE: | 3936 case IDC_FIND_UPDATE: |
| 3956 [self searchFindInPage]; | 3937 [self searchFindInPage]; |
| 3957 break; | 3938 break; |
| 3958 case IDC_FORWARD: | 3939 case IDC_FORWARD: |
| 3959 [[_model currentTab] goForward]; | 3940 [[_model currentTab] goForward]; |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4151 [_bookmarkInteractionController dismissSnackbar]; | 4132 [_bookmarkInteractionController dismissSnackbar]; |
| 4152 [_toolbarController cancelOmniboxEdit]; | 4133 [_toolbarController cancelOmniboxEdit]; |
| 4153 [_dialogPresenter cancelAllDialogs]; | 4134 [_dialogPresenter cancelAllDialogs]; |
| 4154 [self hidePageInfoPopupForView:nil]; | 4135 [self hidePageInfoPopupForView:nil]; |
| 4155 if (_voiceSearchController) | 4136 if (_voiceSearchController) |
| 4156 _voiceSearchController->DismissMicPermissionsHelp(); | 4137 _voiceSearchController->DismissMicPermissionsHelp(); |
| 4157 | 4138 |
| 4158 Tab* currentTab = [_model currentTab]; | 4139 Tab* currentTab = [_model currentTab]; |
| 4159 [currentTab dismissModals]; | 4140 [currentTab dismissModals]; |
| 4160 | 4141 |
| 4161 FindInPageController* findInPageController = | 4142 if (currentTab) { |
| 4162 GetFindInPageController(currentTab); | 4143 auto* findHelper = FindTabHelper::FromWebState(currentTab.webState); |
| 4163 [findInPageController disableFindInPageWithCompletionHandler:^{ | 4144 if (findHelper) { |
| 4164 [self updateFindBar:NO shouldFocus:NO]; | 4145 findHelper->StopFinding(^{ |
| 4165 }]; | 4146 [self updateFindBar:NO shouldFocus:NO]; |
| 4147 }); |
| 4148 } |
| 4149 } |
| 4166 | 4150 |
| 4167 [_contextualSearchController movePanelOffscreen]; | 4151 [_contextualSearchController movePanelOffscreen]; |
| 4168 [_paymentRequestManager cancelRequest]; | 4152 [_paymentRequestManager cancelRequest]; |
| 4169 [_printController dismissAnimated:YES]; | 4153 [_printController dismissAnimated:YES]; |
| 4170 _printController.reset(); | 4154 _printController.reset(); |
| 4171 [_toolbarController dismissToolsMenuPopup]; | 4155 [_toolbarController dismissToolsMenuPopup]; |
| 4172 [_contextMenuCoordinator stop]; | 4156 [_contextMenuCoordinator stop]; |
| 4173 [self dismissRateThisAppDialog]; | 4157 [self dismissRateThisAppDialog]; |
| 4174 | 4158 |
| 4175 [_contentSuggestionsCoordinator stop]; | 4159 [_contentSuggestionsCoordinator stop]; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4260 // Create find bar controller and pass it to the web controller. | 4244 // Create find bar controller and pass it to the web controller. |
| 4261 - (void)initFindBarForTab { | 4245 - (void)initFindBarForTab { |
| 4262 if (!self.canShowFindBar) | 4246 if (!self.canShowFindBar) |
| 4263 return; | 4247 return; |
| 4264 | 4248 |
| 4265 if (!_findBarController) | 4249 if (!_findBarController) |
| 4266 _findBarController.reset( | 4250 _findBarController.reset( |
| 4267 [[FindBarControllerIOS alloc] initWithIncognito:_isOffTheRecord]); | 4251 [[FindBarControllerIOS alloc] initWithIncognito:_isOffTheRecord]); |
| 4268 | 4252 |
| 4269 Tab* tab = [_model currentTab]; | 4253 Tab* tab = [_model currentTab]; |
| 4270 FindInPageController* controller = GetFindInPageController(tab); | 4254 DCHECK(tab); |
| 4271 DCHECK(!controller.findInPageModel.enabled); | 4255 auto* helper = FindTabHelper::FromWebState(tab.webState); |
| 4272 controller.findInPageModel.enabled = YES; | 4256 DCHECK(!helper->IsFindUIActive()); |
| 4257 helper->SetFindUIActive(true); |
| 4273 [self showFindBarWithAnimation:YES selectText:YES shouldFocus:YES]; | 4258 [self showFindBarWithAnimation:YES selectText:YES shouldFocus:YES]; |
| 4274 } | 4259 } |
| 4275 | 4260 |
| 4276 - (void)searchFindInPage { | 4261 - (void)searchFindInPage { |
| 4277 FindInPageController* findInPageController = | 4262 DCHECK([_model currentTab]); |
| 4278 GetFindInPageController([_model currentTab]); | 4263 auto* helper = FindTabHelper::FromWebState([_model currentTab].webState); |
| 4279 base::WeakNSObject<BrowserViewController> weakSelf(self); | 4264 base::WeakNSObject<BrowserViewController> weakSelf(self); |
| 4280 [findInPageController findStringInPage:[_findBarController searchTerm] | 4265 helper->StartFinding([_findBarController searchTerm], |
| 4281 completionHandler:^{ | 4266 ^(FindInPageModel* model) { |
| 4282 FindInPageModel* model = | |
| 4283 findInPageController.findInPageModel; | |
| 4284 [_findBarController updateResultsCount:model]; | 4267 [_findBarController updateResultsCount:model]; |
| 4285 }]; | 4268 }); |
| 4269 |
| 4286 if (!_isOffTheRecord) | 4270 if (!_isOffTheRecord) |
| 4287 [findInPageController saveSearchTerm]; | 4271 helper->PersistSearchTerm(); |
| 4288 } | 4272 } |
| 4289 | 4273 |
| 4290 - (void)closeFindInPage { | 4274 - (void)closeFindInPage { |
| 4291 base::WeakNSObject<BrowserViewController> weakSelf(self); | 4275 base::WeakNSObject<BrowserViewController> weakSelf(self); |
| 4292 FindInPageController* findInPageController = | 4276 Tab* currentTab = [_model currentTab]; |
| 4293 GetFindInPageController([_model currentTab]); | 4277 if (currentTab) { |
| 4294 [findInPageController disableFindInPageWithCompletionHandler:^{ | 4278 FindTabHelper::FromWebState(currentTab.webState)->StopFinding(^{ |
| 4295 [weakSelf updateFindBar:NO shouldFocus:NO]; | 4279 [weakSelf updateFindBar:NO shouldFocus:NO]; |
| 4296 }]; | 4280 }); |
| 4281 } |
| 4297 } | 4282 } |
| 4298 | 4283 |
| 4299 - (void)updateFindBar:(BOOL)initialUpdate shouldFocus:(BOOL)shouldFocus { | 4284 - (void)updateFindBar:(BOOL)initialUpdate shouldFocus:(BOOL)shouldFocus { |
| 4300 FindInPageController* findInPageController = | 4285 DCHECK([_model currentTab]); |
| 4301 GetFindInPageController([_model currentTab]); | 4286 auto* helper = FindTabHelper::FromWebState([_model currentTab].webState); |
| 4302 FindInPageModel* model = findInPageController.findInPageModel; | 4287 if (helper && helper->IsFindUIActive()) { |
| 4303 if (model.enabled) { | |
| 4304 if (initialUpdate && !_isOffTheRecord) { | 4288 if (initialUpdate && !_isOffTheRecord) { |
| 4305 [findInPageController restoreSearchTerm]; | 4289 helper->RestoreSearchTerm(); |
| 4306 } | 4290 } |
| 4307 | 4291 |
| 4308 [self setFramesForHeaders:[self headerViews] | 4292 [self setFramesForHeaders:[self headerViews] |
| 4309 atOffset:[self currentHeaderOffset]]; | 4293 atOffset:[self currentHeaderOffset]]; |
| 4310 [_findBarController updateView:model | 4294 [_findBarController updateView:helper->GetFindResult() |
| 4311 initialUpdate:initialUpdate | 4295 initialUpdate:initialUpdate |
| 4312 focusTextfield:shouldFocus]; | 4296 focusTextfield:shouldFocus]; |
| 4313 } else { | 4297 } else { |
| 4314 [self hideFindBarWithAnimation:YES]; | 4298 [self hideFindBarWithAnimation:YES]; |
| 4315 } | 4299 } |
| 4316 } | 4300 } |
| 4317 | 4301 |
| 4318 - (void)showAllBookmarks { | 4302 - (void)showAllBookmarks { |
| 4319 DCHECK(self.visible || self.dismissingModal); | 4303 DCHECK(self.visible || self.dismissingModal); |
| 4320 GURL URL(kChromeUIBookmarksURL); | 4304 GURL URL(kChromeUIBookmarksURL); |
| (...skipping 780 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5101 | 5085 |
| 5102 - (UIView*)voiceSearchButton { | 5086 - (UIView*)voiceSearchButton { |
| 5103 return _voiceSearchButton; | 5087 return _voiceSearchButton; |
| 5104 } | 5088 } |
| 5105 | 5089 |
| 5106 - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner { | 5090 - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner { |
| 5107 return [self currentLogoAnimationControllerOwner]; | 5091 return [self currentLogoAnimationControllerOwner]; |
| 5108 } | 5092 } |
| 5109 | 5093 |
| 5110 @end | 5094 @end |
| OLD | NEW |