Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1147)

Side by Side Diff: ios/chrome/browser/ui/sad_tab/sad_tab_view.mm

Issue 2807843002: Refactor creation of SadTabView into a tab helper object (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/sad_tab/sad_tab_view.h" 5 #import "ios/chrome/browser/ui/sad_tab/sad_tab_view.h"
6 6
7 #import "base/ios/weak_nsobject.h" 7 #import "base/ios/weak_nsobject.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/mac/scoped_block.h" 9 #include "base/mac/scoped_block.h"
10 #include "base/mac/scoped_nsobject.h" 10 #include "base/mac/scoped_nsobject.h"
(...skipping 10 matching lines...) Expand all
21 #import "ios/chrome/browser/ui/url_loader.h" 21 #import "ios/chrome/browser/ui/url_loader.h"
22 #import "ios/chrome/browser/ui/util/label_link_controller.h" 22 #import "ios/chrome/browser/ui/util/label_link_controller.h"
23 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate rialButtons.h" 23 #import "ios/third_party/material_components_ios/src/components/Buttons/src/Mate rialButtons.h"
24 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h" 24 #import "ios/third_party/material_components_ios/src/components/Palettes/src/Mat erialPalettes.h"
25 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoF ontLoader.h" 25 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoF ontLoader.h"
26 #include "ios/web/public/interstitials/web_interstitial.h" 26 #include "ios/web/public/interstitials/web_interstitial.h"
27 #include "ios/web/public/web_state/web_state.h" 27 #include "ios/web/public/web_state/web_state.h"
28 #import "net/base/mac/url_conversions.h" 28 #import "net/base/mac/url_conversions.h"
29 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
30 30
31 #if !defined(__has_feature) || !__has_feature(objc_arc)
32 #error "This file requires ARC support."
33 #endif
34
31 namespace { 35 namespace {
32 // Color constants. 36 // Color constants.
33 const CGFloat kBackgroundColorBrightness = 247.0f / 255.0f; 37 const CGFloat kBackgroundColorBrightness = 247.0f / 255.0f;
34 const CGFloat kTitleLabelTextColorBrightness = 22.0f / 255.0f; 38 const CGFloat kTitleLabelTextColorBrightness = 22.0f / 255.0f;
35 const CGFloat kMessageLabelTextColorBrightness = 80.0f / 255.0f; 39 const CGFloat kMessageLabelTextColorBrightness = 80.0f / 255.0f;
36 // Layout constants. 40 // Layout constants.
37 const UIEdgeInsets kLayoutInsets = {24.0f, 24.0f, 24.0f, 24.0f}; 41 const UIEdgeInsets kLayoutInsets = {24.0f, 24.0f, 24.0f, 24.0f};
38 const CGFloat kLayoutBoundsMaxWidth = 600.0f; 42 const CGFloat kLayoutBoundsMaxWidth = 600.0f;
39 const CGFloat kContainerViewLandscapeTopPadding = 22.0f; 43 const CGFloat kContainerViewLandscapeTopPadding = 22.0f;
40 const CGFloat kTitleLabelTopPadding = 26.0f; 44 const CGFloat kTitleLabelTopPadding = 26.0f;
41 const CGFloat kMessageLabelTopPadding = 16.0f; 45 const CGFloat kMessageLabelTopPadding = 16.0f;
42 const CGFloat kHelpLabelTopPadding = 16.0f; 46 const CGFloat kHelpLabelTopPadding = 16.0f;
43 const CGFloat kReloadButtonHeight = 48.0f; 47 const CGFloat kReloadButtonHeight = 48.0f;
44 const CGFloat kReloadButtonTopPadding = 16.0f; 48 const CGFloat kReloadButtonTopPadding = 16.0f;
45 // Label font sizes. 49 // Label font sizes.
46 const CGFloat kTitleLabelFontSize = 23.0f; 50 const CGFloat kTitleLabelFontSize = 23.0f;
47 const CGFloat kMessageLabelFontSize = 14.0f; 51 const CGFloat kMessageLabelFontSize = 14.0f;
48 const CGFloat kHelpLabelFontSize = 14.0f; 52 const CGFloat kHelpLabelFontSize = 14.0f;
49 } // namespace 53 } // namespace
50 54
51 @interface SadTabView () { 55 @interface SadTabView ()
52 // The block called when |_reloadButton| is tapped.
53 base::mac::ScopedBlock<ProceduralBlock> _reloadHandler;
54 // Backing objects for properties of the same name.
55 base::scoped_nsobject<UIView> _containerView;
56 base::scoped_nsobject<UIImageView> _imageView;
57 base::scoped_nsobject<UILabel> _titleLabel;
58 base::scoped_nsobject<UILabel> _messageLabel;
59 base::scoped_nsobject<UILabel> _helpLabel;
60 base::scoped_nsobject<LabelLinkController> _helpLabelLinkController;
61 base::scoped_nsobject<MDCButton> _reloadButton;
62 }
63 56
57 @property(nonatomic, copy) ProceduralBlock reloadHandler;
64 // Container view that displays all other subviews. 58 // Container view that displays all other subviews.
65 @property(nonatomic, readonly) UIView* containerView; 59 @property(nonatomic, strong) UIView* containerView;
66 // Displays the Sad Tab face. 60 // Displays the Sad Tab face.
67 @property(nonatomic, readonly) UIImageView* imageView; 61 @property(nonatomic, strong) UIImageView* imageView;
68 // Displays the Sad Tab title. 62 // Displays the Sad Tab title.
69 @property(nonatomic, readonly) UILabel* titleLabel; 63 @property(nonatomic, strong) UILabel* titleLabel;
70 // Displays the Sad Tab message. 64 // Displays the Sad Tab message.
71 @property(nonatomic, readonly) UILabel* messageLabel; 65 @property(nonatomic, strong) UILabel* messageLabel;
72 // Displays the Sad Tab help message. 66 // Displays the Sad Tab help message.
73 @property(nonatomic, readonly) UILabel* helpLabel; 67 @property(nonatomic, strong) UILabel* helpLabel;
68 @property(nonatomic, strong) LabelLinkController* helpLabelLinkController;
74 // Button used to trigger a reload. 69 // Button used to trigger a reload.
75 @property(nonatomic, readonly) UIButton* reloadButton; 70 @property(nonatomic, strong) MDCFlatButton* reloadButton;
76 71
77 // The bounds of |containerView|, with a height updated to CGFLOAT_MAX to allow 72 // The bounds of |containerView|, with a height updated to CGFLOAT_MAX to allow
78 // text to be laid out using as many lines as necessary. 73 // text to be laid out using as many lines as necessary.
79 @property(nonatomic, readonly) CGRect containerBounds; 74 @property(nonatomic, readonly) CGRect containerBounds;
80 75
81 // Subview layout methods. Must be called in the following order, as subsequent 76 // Subview layout methods. Must be called in the following order, as subsequent
82 // layouts reference the values set in previous functions. 77 // layouts reference the values set in previous functions.
83 - (void)layoutImageView; 78 - (void)layoutImageView;
84 - (void)layoutTitleLabel; 79 - (void)layoutTitleLabel;
85 - (void)layoutMessageLabel; 80 - (void)layoutMessageLabel;
86 - (void)layoutHelpLabel; 81 - (void)layoutHelpLabel;
87 - (void)layoutReloadButton; 82 - (void)layoutReloadButton;
88 - (void)layoutContainerView; 83 - (void)layoutContainerView;
89 84
90 // The action selector for |_reloadButton|. 85 // The action selector for |_reloadButton|.
91 - (void)handleReloadButtonTapped; 86 - (void)handleReloadButtonTapped;
92 87
93 // Returns the desired background color. 88 // Returns the desired background color.
94 + (UIColor*)sadTabBackgroundColor; 89 + (UIColor*)sadTabBackgroundColor;
95 90
96 @end 91 @end
97 92
98 #pragma mark - SadTabView 93 #pragma mark - SadTabView
99 94
100 @implementation SadTabView 95 @implementation SadTabView
101 96
97 @synthesize imageView = _imageView;
98 @synthesize containerView = _containerView;
99 @synthesize titleLabel = _titleLabel;
100 @synthesize messageLabel = _messageLabel;
101 @synthesize helpLabel = _helpLabel;
102 @synthesize helpLabelLinkController = _helpLabelLinkController;
103 @synthesize reloadButton = _reloadButton;
104 @synthesize reloadHandler = _reloadHandler;
105
102 - (instancetype)initWithReloadHandler:(ProceduralBlock)reloadHandler { 106 - (instancetype)initWithReloadHandler:(ProceduralBlock)reloadHandler {
103 self = [super initWithFrame:CGRectZero]; 107 self = [super initWithFrame:CGRectZero];
104 if (self) { 108 if (self) {
105 DCHECK(reloadHandler); 109 DCHECK(reloadHandler);
106 _reloadHandler.reset([reloadHandler copy]); 110 _reloadHandler = reloadHandler;
107 self.backgroundColor = [[self class] sadTabBackgroundColor]; 111 self.backgroundColor = [[self class] sadTabBackgroundColor];
108 } 112 }
109 return self; 113 return self;
110 } 114 }
111 115
112 - (instancetype)init { 116 - (instancetype)init {
113 NOTREACHED(); 117 NOTREACHED();
114 return nil; 118 return nil;
115 } 119 }
116 120
117 - (instancetype)initWithFrame:(CGRect)frame { 121 - (instancetype)initWithFrame:(CGRect)frame {
118 NOTREACHED(); 122 NOTREACHED();
119 return nil; 123 return nil;
120 } 124 }
121 125
122 - (instancetype)initWithCoder:(NSCoder*)aDecoder { 126 - (instancetype)initWithCoder:(NSCoder*)aDecoder {
123 NOTREACHED(); 127 NOTREACHED();
124 return nil; 128 return nil;
125 } 129 }
126 130
127 #pragma mark Accessors 131 #pragma mark Accessors
128 132
129 - (UIView*)containerView { 133 - (UIView*)containerView {
130 if (!_containerView) { 134 if (!_containerView) {
131 _containerView.reset([[UIView alloc] initWithFrame:CGRectZero]); 135 _containerView = [[UIView alloc] initWithFrame:CGRectZero];
132 [_containerView setBackgroundColor:self.backgroundColor]; 136 [_containerView setBackgroundColor:self.backgroundColor];
133 } 137 }
134 return _containerView; 138 return _containerView;
135 } 139 }
136 140
137 - (UIImageView*)imageView { 141 - (UIImageView*)imageView {
138 if (!_imageView) { 142 if (!_imageView) {
139 _imageView.reset( 143 _imageView =
140 [[UIImageView alloc] initWithImage:NativeImage(IDR_CRASH_SAD_TAB)]); 144 [[UIImageView alloc] initWithImage:NativeImage(IDR_CRASH_SAD_TAB)];
141 [_imageView setBackgroundColor:self.backgroundColor]; 145 [_imageView setBackgroundColor:self.backgroundColor];
142 } 146 }
143 return _imageView.get(); 147 return _imageView;
144 } 148 }
145 149
146 - (UILabel*)titleLabel { 150 - (UILabel*)titleLabel {
147 if (!_titleLabel) { 151 if (!_titleLabel) {
148 _titleLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 152 _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
149 [_titleLabel setBackgroundColor:self.backgroundColor]; 153 [_titleLabel setBackgroundColor:self.backgroundColor];
150 [_titleLabel setText:base::SysUTF8ToNSString( 154 [_titleLabel setText:base::SysUTF8ToNSString(
151 l10n_util::GetStringUTF8(IDS_SAD_TAB_TITLE))]; 155 l10n_util::GetStringUTF8(IDS_SAD_TAB_TITLE))];
152 [_titleLabel setLineBreakMode:NSLineBreakByWordWrapping]; 156 [_titleLabel setLineBreakMode:NSLineBreakByWordWrapping];
153 [_titleLabel setNumberOfLines:0]; 157 [_titleLabel setNumberOfLines:0];
154 [_titleLabel 158 [_titleLabel
155 setTextColor:[UIColor colorWithWhite:kTitleLabelTextColorBrightness 159 setTextColor:[UIColor colorWithWhite:kTitleLabelTextColorBrightness
156 alpha:1.0]]; 160 alpha:1.0]];
157 [_titleLabel setFont:[[MDFRobotoFontLoader sharedInstance] 161 [_titleLabel setFont:[[MDFRobotoFontLoader sharedInstance]
158 regularFontOfSize:kTitleLabelFontSize]]; 162 regularFontOfSize:kTitleLabelFontSize]];
159 } 163 }
160 return _titleLabel.get(); 164 return _titleLabel;
161 } 165 }
162 166
163 - (UILabel*)messageLabel { 167 - (UILabel*)messageLabel {
164 if (!_messageLabel) { 168 if (!_messageLabel) {
165 _messageLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 169 _messageLabel = [[UILabel alloc] initWithFrame:CGRectZero];
166 [_messageLabel setBackgroundColor:self.backgroundColor]; 170 [_messageLabel setBackgroundColor:self.backgroundColor];
167 std::string messageText = l10n_util::GetStringUTF8(IDS_SAD_TAB_MESSAGE); 171 std::string messageText = l10n_util::GetStringUTF8(IDS_SAD_TAB_MESSAGE);
168 [_messageLabel setText:base::SysUTF8ToNSString(messageText)]; 172 [_messageLabel setText:base::SysUTF8ToNSString(messageText)];
169 [_messageLabel setLineBreakMode:NSLineBreakByWordWrapping]; 173 [_messageLabel setLineBreakMode:NSLineBreakByWordWrapping];
170 [_messageLabel setNumberOfLines:0]; 174 [_messageLabel setNumberOfLines:0];
171 [_messageLabel 175 [_messageLabel
172 setTextColor:[UIColor colorWithWhite:kMessageLabelTextColorBrightness 176 setTextColor:[UIColor colorWithWhite:kMessageLabelTextColorBrightness
173 alpha:1.0]]; 177 alpha:1.0]];
174 [_messageLabel setFont:[[MDFRobotoFontLoader sharedInstance] 178 [_messageLabel setFont:[[MDFRobotoFontLoader sharedInstance]
175 regularFontOfSize:kMessageLabelFontSize]]; 179 regularFontOfSize:kMessageLabelFontSize]];
176 } 180 }
177 return _messageLabel.get(); 181 return _messageLabel;
178 } 182 }
179 183
180 - (UILabel*)helpLabel { 184 - (UILabel*)helpLabel {
181 if (!_helpLabel) { 185 if (!_helpLabel) {
182 _helpLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 186 _helpLabel = [[UILabel alloc] initWithFrame:CGRectZero];
183 [_helpLabel setBackgroundColor:self.backgroundColor]; 187 [_helpLabel setBackgroundColor:self.backgroundColor];
184 [_helpLabel setNumberOfLines:0]; 188 [_helpLabel setNumberOfLines:0];
185 [_helpLabel setFont:[[MDFRobotoFontLoader sharedInstance] 189 [_helpLabel setFont:[[MDFRobotoFontLoader sharedInstance]
186 regularFontOfSize:kHelpLabelFontSize]]; 190 regularFontOfSize:kHelpLabelFontSize]];
187 [_helpLabel 191 [_helpLabel
188 setTextColor:[UIColor colorWithWhite:kMessageLabelTextColorBrightness 192 setTextColor:[UIColor colorWithWhite:kMessageLabelTextColorBrightness
189 alpha:1.0]]; 193 alpha:1.0]];
190 // Fetch help text. 194 // Fetch help text.
191 base::string16 helpLinkText( 195 base::string16 helpLinkText(
192 l10n_util::GetStringUTF16(IDS_SAD_TAB_HELP_LINK)); 196 l10n_util::GetStringUTF16(IDS_SAD_TAB_HELP_LINK));
193 NSString* helpText = base::SysUTF16ToNSString( 197 NSString* helpText = base::SysUTF16ToNSString(
194 l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE, helpLinkText)); 198 l10n_util::GetStringFUTF16(IDS_SAD_TAB_HELP_MESSAGE, helpLinkText));
195 [_helpLabel setText:helpText]; 199 [_helpLabel setText:helpText];
196 // Create link controller. 200 // Create link controller.
197 base::WeakNSObject<SadTabView> weakSelf(self); 201 base::WeakNSObject<SadTabView> weakSelf(self);
198 _helpLabelLinkController.reset([[LabelLinkController alloc] 202 _helpLabelLinkController = [[LabelLinkController alloc]
199 initWithLabel:_helpLabel 203 initWithLabel:_helpLabel
200 action:^(const GURL& url) { 204 action:^(const GURL& url) {
201 base::scoped_nsobject<OpenUrlCommand> openCommand( 205 base::scoped_nsobject<OpenUrlCommand> openCommand(
202 [[OpenUrlCommand alloc] initWithURLFromChrome:url]); 206 [[OpenUrlCommand alloc] initWithURLFromChrome:url]);
203 [weakSelf chromeExecuteCommand:openCommand]; 207 [weakSelf chromeExecuteCommand:openCommand];
204 }]); 208 }];
205 [_helpLabelLinkController 209 [_helpLabelLinkController
206 setLinkFont:[[MDFRobotoFontLoader sharedInstance] 210 setLinkFont:[[MDFRobotoFontLoader sharedInstance]
207 boldFontOfSize:kHelpLabelFontSize]]; 211 boldFontOfSize:kHelpLabelFontSize]];
208 [_helpLabelLinkController setLinkUnderlineStyle:NSUnderlineStyleSingle]; 212 [_helpLabelLinkController setLinkUnderlineStyle:NSUnderlineStyleSingle];
209 NSRange linkRange = 213 NSRange linkRange =
210 [helpText rangeOfString:base::SysUTF16ToNSString(helpLinkText)]; 214 [helpText rangeOfString:base::SysUTF16ToNSString(helpLinkText)];
211 DCHECK_NE(linkRange.location, static_cast<NSUInteger>(NSNotFound)); 215 DCHECK_NE(linkRange.location, static_cast<NSUInteger>(NSNotFound));
212 DCHECK_NE(linkRange.length, 0U); 216 DCHECK_NE(linkRange.length, 0U);
213 [_helpLabelLinkController addLinkWithRange:linkRange 217 [_helpLabelLinkController addLinkWithRange:linkRange
214 url:GURL(kCrashReasonURL)]; 218 url:GURL(kCrashReasonURL)];
215 } 219 }
216 return _helpLabel.get(); 220 return _helpLabel;
217 } 221 }
218 222
219 - (UIButton*)reloadButton { 223 - (UIButton*)reloadButton {
220 if (!_reloadButton) { 224 if (!_reloadButton) {
221 _reloadButton.reset([[MDCFlatButton alloc] init]); 225 _reloadButton = [[MDCFlatButton alloc] init];
222 [_reloadButton setBackgroundColor:[[MDCPalette cr_bluePalette] tint500] 226 [_reloadButton setBackgroundColor:[[MDCPalette cr_bluePalette] tint500]
223 forState:UIControlStateNormal]; 227 forState:UIControlStateNormal];
224 [_reloadButton setBackgroundColor:[[MDCPalette greyPalette] tint500] 228 [_reloadButton setBackgroundColor:[[MDCPalette greyPalette] tint500]
225 forState:UIControlStateDisabled]; 229 forState:UIControlStateDisabled];
226 [_reloadButton setCustomTitleColor:[UIColor whiteColor]]; 230 [_reloadButton setCustomTitleColor:[UIColor whiteColor]];
227 [_reloadButton setUnderlyingColorHint:[UIColor blackColor]]; 231 [_reloadButton setUnderlyingColorHint:[UIColor blackColor]];
228 [_reloadButton setInkColor:[UIColor colorWithWhite:1 alpha:0.2f]]; 232 [_reloadButton setInkColor:[UIColor colorWithWhite:1 alpha:0.2f]];
229 NSString* title = base::SysUTF8ToNSString( 233 NSString* title = base::SysUTF8ToNSString(
230 l10n_util::GetStringUTF8(IDS_SAD_TAB_RELOAD_LABEL)); 234 l10n_util::GetStringUTF8(IDS_SAD_TAB_RELOAD_LABEL));
231 [_reloadButton setTitle:title forState:UIControlStateNormal]; 235 [_reloadButton setTitle:title forState:UIControlStateNormal];
232 [_reloadButton setTitleColor:[UIColor whiteColor] 236 [_reloadButton setTitleColor:[UIColor whiteColor]
233 forState:UIControlStateNormal]; 237 forState:UIControlStateNormal];
234 [_reloadButton addTarget:self 238 [_reloadButton addTarget:self
235 action:@selector(handleReloadButtonTapped) 239 action:@selector(handleReloadButtonTapped)
236 forControlEvents:UIControlEventTouchUpInside]; 240 forControlEvents:UIControlEventTouchUpInside];
237 } 241 }
238 return _reloadButton.get(); 242 return _reloadButton;
239 } 243 }
240 244
241 - (CGRect)containerBounds { 245 - (CGRect)containerBounds {
242 CGFloat containerWidth = std::min( 246 CGFloat containerWidth = std::min(
243 CGRectGetWidth(self.bounds) - kLayoutInsets.left - kLayoutInsets.right, 247 CGRectGetWidth(self.bounds) - kLayoutInsets.left - kLayoutInsets.right,
244 kLayoutBoundsMaxWidth); 248 kLayoutBoundsMaxWidth);
245 return CGRectMake(0.0, 0.0, containerWidth, CGFLOAT_MAX); 249 return CGRectMake(0.0, 0.0, containerWidth, CGFLOAT_MAX);
246 } 250 }
247 251
248 #pragma mark Layout 252 #pragma mark Layout
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
380 384
381 #pragma mark Util 385 #pragma mark Util
382 386
383 - (void)handleHelpLabelLinkButtonTapped { 387 - (void)handleHelpLabelLinkButtonTapped {
384 base::scoped_nsobject<OpenUrlCommand> openCommand( 388 base::scoped_nsobject<OpenUrlCommand> openCommand(
385 [[OpenUrlCommand alloc] initWithURLFromChrome:GURL(kCrashReasonURL)]); 389 [[OpenUrlCommand alloc] initWithURLFromChrome:GURL(kCrashReasonURL)]);
386 [self chromeExecuteCommand:openCommand]; 390 [self chromeExecuteCommand:openCommand];
387 } 391 }
388 392
389 - (void)handleReloadButtonTapped { 393 - (void)handleReloadButtonTapped {
390 _reloadHandler.get()(); 394 if (self.reloadHandler) {
kkhorimoto 2017/04/10 22:31:09 We're already DCHECKing that the reload handler is
PL 2017/04/11 01:35:21 Happy to take this check out if you feel strongly
kkhorimoto 2017/04/11 02:13:15 The Chromium style guide says that if we're DCHECK
PL 2017/04/11 03:08:56 Done! I'm a little nervous but I trust your guidan
395 self.reloadHandler();
396 }
391 } 397 }
392 398
393 + (UIColor*)sadTabBackgroundColor { 399 + (UIColor*)sadTabBackgroundColor {
394 return [UIColor colorWithWhite:kBackgroundColorBrightness alpha:1.0]; 400 return [UIColor colorWithWhite:kBackgroundColorBrightness alpha:1.0];
395 } 401 }
396 402
397 @end 403 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698