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

Side by Side Diff: ios/chrome/browser/memory/memory_debugger.mm

Issue 2917193002: [ObjC ARC] Converts ios/chrome/browser/memory:memory to ARC. (Closed)
Patch Set: Use __weak Created 3 years, 6 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 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/memory/memory_debugger.h" 5 #import "ios/chrome/browser/memory/memory_debugger.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <memory> 9 #include <memory>
10 10
11 #import "base/mac/scoped_nsobject.h"
12 #import "ios/chrome/browser/memory/memory_metrics.h" 11 #import "ios/chrome/browser/memory/memory_metrics.h"
13 #include "ios/chrome/browser/ui/ui_util.h" 12 #include "ios/chrome/browser/ui/ui_util.h"
14 #import "ios/chrome/browser/ui/uikit_ui_util.h" 13 #import "ios/chrome/browser/ui/uikit_ui_util.h"
15 14
15 #if !defined(__has_feature) || !__has_feature(objc_arc)
16 #error "This file requires ARC support."
17 #endif
18
16 namespace { 19 namespace {
17 // The number of bytes in a megabyte. 20 // The number of bytes in a megabyte.
18 const CGFloat kNumBytesInMB = 1024 * 1024; 21 const CGFloat kNumBytesInMB = 1024 * 1024;
19 // The horizontal and vertical padding between subviews. 22 // The horizontal and vertical padding between subviews.
20 const CGFloat kPadding = 10; 23 const CGFloat kPadding = 10;
21 } // namespace 24 } // namespace
22 25
23 @implementation MemoryDebugger { 26 @implementation MemoryDebugger {
24 // A timer to trigger refreshes. 27 // A timer to trigger refreshes.
25 base::scoped_nsobject<NSTimer> _refreshTimer; 28 NSTimer* _refreshTimer;
26 29
27 // A timer to trigger continuous memory warnings. 30 // A timer to trigger continuous memory warnings.
28 base::scoped_nsobject<NSTimer> _memoryWarningTimer; 31 NSTimer* _memoryWarningTimer;
29 32
30 // The font to use. 33 // The font to use.
31 base::scoped_nsobject<UIFont> _font; 34 UIFont* _font;
32 35
33 // Labels for memory metrics. 36 // Labels for memory metrics.
34 base::scoped_nsobject<UILabel> _physicalFreeMemoryLabel; 37 UILabel* _physicalFreeMemoryLabel;
35 base::scoped_nsobject<UILabel> _realMemoryUsedLabel; 38 UILabel* _realMemoryUsedLabel;
36 base::scoped_nsobject<UILabel> _xcodeGaugeLabel; 39 UILabel* _xcodeGaugeLabel;
37 base::scoped_nsobject<UILabel> _dirtyVirtualMemoryLabel; 40 UILabel* _dirtyVirtualMemoryLabel;
38 41
39 // Inputs for memory commands. 42 // Inputs for memory commands.
40 base::scoped_nsobject<UITextField> _bloatField; 43 UITextField* _bloatField;
41 base::scoped_nsobject<UITextField> _refreshField; 44 UITextField* _refreshField;
42 base::scoped_nsobject<UITextField> _continuousMemoryWarningField; 45 UITextField* _continuousMemoryWarningField;
43 46
44 // A place to store the artifical memory bloat. 47 // A place to store the artifical memory bloat.
45 std::unique_ptr<uint8_t> _bloat; 48 std::unique_ptr<uint8_t> _bloat;
46 49
47 // Distance the view was pushed up to accomodate the keyboard. 50 // Distance the view was pushed up to accomodate the keyboard.
48 CGFloat _keyboardOffset; 51 CGFloat _keyboardOffset;
49 52
50 // The current orientation of the device. 53 // The current orientation of the device.
51 BOOL _currentOrientation; 54 BOOL _currentOrientation;
52 } 55 }
53 56
54 - (instancetype)init { 57 - (instancetype)init {
55 self = [super initWithFrame:CGRectZero]; 58 self = [super initWithFrame:CGRectZero];
56 if (self) { 59 if (self) {
57 _font.reset([[UIFont systemFontOfSize:14] retain]); 60 _font = [UIFont systemFontOfSize:14];
58 self.backgroundColor = [UIColor colorWithWhite:0.8f alpha:0.9f]; 61 self.backgroundColor = [UIColor colorWithWhite:0.8f alpha:0.9f];
59 self.opaque = NO; 62 self.opaque = NO;
60 63
61 [self addSubviews]; 64 [self addSubviews];
62 [self sizeToFit]; 65 [self sizeToFit];
63 [self registerForNotifications]; 66 [self registerForNotifications];
64 } 67 }
65 return self; 68 return self;
66 } 69 }
67 70
68 // NSTimers create a retain cycle so they must be invalidated before this 71 // NSTimers create a retain cycle so they must be invalidated before this
69 // instance can be deallocated. 72 // instance can be deallocated.
70 - (void)invalidateTimers { 73 - (void)invalidateTimers {
71 [_refreshTimer invalidate]; 74 [_refreshTimer invalidate];
72 [_memoryWarningTimer invalidate]; 75 [_memoryWarningTimer invalidate];
73 } 76 }
74 77
75 - (void)dealloc { 78 - (void)dealloc {
76 [[NSNotificationCenter defaultCenter] removeObserver:self]; 79 [[NSNotificationCenter defaultCenter] removeObserver:self];
77 [super dealloc];
78 } 80 }
79 81
80 #pragma mark UIView methods 82 #pragma mark UIView methods
81 83
82 - (CGSize)sizeThatFits:(CGSize)size { 84 - (CGSize)sizeThatFits:(CGSize)size {
83 CGFloat width = 0; 85 CGFloat width = 0;
84 CGFloat height = 0; 86 CGFloat height = 0;
85 for (UIView* subview in self.subviews) { 87 for (UIView* subview in self.subviews) {
86 width = MAX(width, CGRectGetMaxX(subview.frame)); 88 width = MAX(width, CGRectGetMaxX(subview.frame));
87 height = MAX(height, CGRectGetMaxY(subview.frame)); 89 height = MAX(height, CGRectGetMaxY(subview.frame));
88 } 90 }
89 return CGSizeMake(width + kPadding, height + kPadding); 91 return CGSizeMake(width + kPadding, height + kPadding);
90 } 92 }
91 93
92 #pragma mark initialization helpers 94 #pragma mark initialization helpers
93 95
94 - (void)addSubviews { 96 - (void)addSubviews {
95 // |index| is used to calculate the vertical position of each element in 97 // |index| is used to calculate the vertical position of each element in
96 // the debugger view. 98 // the debugger view.
97 NSUInteger index = 0; 99 NSUInteger index = 0;
98 100
99 // Display some metrics. 101 // Display some metrics.
100 _physicalFreeMemoryLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 102 _physicalFreeMemoryLabel = [[UILabel alloc] initWithFrame:CGRectZero];
101 [self addMetricWithName:@"Physical Free" 103 [self addMetricWithName:@"Physical Free"
102 atIndex:index++ 104 atIndex:index++
103 usingLabel:_physicalFreeMemoryLabel]; 105 usingLabel:_physicalFreeMemoryLabel];
104 _realMemoryUsedLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 106 _realMemoryUsedLabel = [[UILabel alloc] initWithFrame:CGRectZero];
105 [self addMetricWithName:@"Real Memory Used" 107 [self addMetricWithName:@"Real Memory Used"
106 atIndex:index++ 108 atIndex:index++
107 usingLabel:_realMemoryUsedLabel]; 109 usingLabel:_realMemoryUsedLabel];
108 _xcodeGaugeLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 110 _xcodeGaugeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
109 [self addMetricWithName:@"Xcode Gauge" 111 [self addMetricWithName:@"Xcode Gauge"
110 atIndex:index++ 112 atIndex:index++
111 usingLabel:_xcodeGaugeLabel]; 113 usingLabel:_xcodeGaugeLabel];
112 _dirtyVirtualMemoryLabel.reset([[UILabel alloc] initWithFrame:CGRectZero]); 114 _dirtyVirtualMemoryLabel = [[UILabel alloc] initWithFrame:CGRectZero];
113 [self addMetricWithName:@"Dirty VM" 115 [self addMetricWithName:@"Dirty VM"
114 atIndex:index++ 116 atIndex:index++
115 usingLabel:_dirtyVirtualMemoryLabel]; 117 usingLabel:_dirtyVirtualMemoryLabel];
116 118
117 // Since _performMemoryWarning is a private API it can't be compiled into 119 // Since _performMemoryWarning is a private API it can't be compiled into
118 // official builds. 120 // official builds.
119 // TODO(lliabraa): Figure out how to support memory warnings (or something 121 // TODO(lliabraa): Figure out how to support memory warnings (or something
120 // like them) in official builds. 122 // like them) in official builds.
121 #if CHROMIUM_BUILD 123 #if CHROMIUM_BUILD
122 #pragma clang diagnostic push 124 #pragma clang diagnostic push
123 #pragma clang diagnostic ignored "-Wundeclared-selector" 125 #pragma clang diagnostic ignored "-Wundeclared-selector"
124 [self addButtonWithTitle:@"Trigger Memory Warning" 126 [self addButtonWithTitle:@"Trigger Memory Warning"
125 target:[UIApplication sharedApplication] 127 target:[UIApplication sharedApplication]
126 action:@selector(_performMemoryWarning) 128 action:@selector(_performMemoryWarning)
127 withOrigin:[self originForSubviewAtIndex:index++]]; 129 withOrigin:[self originForSubviewAtIndex:index++]];
128 #pragma clang diagnostic pop 130 #pragma clang diagnostic pop
129 #endif // CHROMIUM_BUILD 131 #endif // CHROMIUM_BUILD
130 132
131 // Display a text input to set the amount of artificial memory bloat and a 133 // Display a text input to set the amount of artificial memory bloat and a
132 // button to reset the bloat to zero. 134 // button to reset the bloat to zero.
133 _bloatField.reset([[UITextField alloc] initWithFrame:CGRectZero]); 135 _bloatField = [[UITextField alloc] initWithFrame:CGRectZero];
134 [self addLabelWithText:@"Set bloat (MB)" 136 [self addLabelWithText:@"Set bloat (MB)"
135 input:_bloatField 137 input:_bloatField
136 inputTarget:self 138 inputTarget:self
137 inputAction:@selector(updateBloat) 139 inputAction:@selector(updateBloat)
138 buttonWithTitle:@"Clear" 140 buttonWithTitle:@"Clear"
139 buttonTarget:self 141 buttonTarget:self
140 buttonAction:@selector(clearBloat) 142 buttonAction:@selector(clearBloat)
141 atIndex:index++]; 143 atIndex:index++];
142 [_bloatField setText:@"0"]; 144 [_bloatField setText:@"0"];
143 [self updateBloat]; 145 [self updateBloat];
144 146
145 // Since _performMemoryWarning is a private API it can't be compiled into 147 // Since _performMemoryWarning is a private API it can't be compiled into
146 // official builds. 148 // official builds.
147 // TODO(lliabraa): Figure out how to support memory warnings (or something 149 // TODO(lliabraa): Figure out how to support memory warnings (or something
148 // like them) in official builds. 150 // like them) in official builds.
149 #if CHROMIUM_BUILD 151 #if CHROMIUM_BUILD
150 // Display a text input to control the rate of continuous memory warnings. 152 // Display a text input to control the rate of continuous memory warnings.
151 _continuousMemoryWarningField.reset( 153 _continuousMemoryWarningField =
152 [[UITextField alloc] initWithFrame:CGRectZero]); 154 [[UITextField alloc] initWithFrame:CGRectZero];
153 [self addLabelWithText:@"Set memory warning interval (secs)" 155 [self addLabelWithText:@"Set memory warning interval (secs)"
154 input:_continuousMemoryWarningField 156 input:_continuousMemoryWarningField
155 inputTarget:self 157 inputTarget:self
156 inputAction:@selector(updateMemoryWarningInterval) 158 inputAction:@selector(updateMemoryWarningInterval)
157 atIndex:index++]; 159 atIndex:index++];
158 [_continuousMemoryWarningField setText:@"0.0"]; 160 [_continuousMemoryWarningField setText:@"0.0"];
159 #endif // CHROMIUM_BUILD 161 #endif // CHROMIUM_BUILD
160 162
161 // Display a text input to control the refresh rate of the memory debugger. 163 // Display a text input to control the refresh rate of the memory debugger.
162 _refreshField.reset([[UITextField alloc] initWithFrame:CGRectZero]); 164 _refreshField = [[UITextField alloc] initWithFrame:CGRectZero];
163 [self addLabelWithText:@"Set refresh interval (secs)" 165 [self addLabelWithText:@"Set refresh interval (secs)"
164 input:_refreshField 166 input:_refreshField
165 inputTarget:self 167 inputTarget:self
166 inputAction:@selector(updateRefreshInterval) 168 inputAction:@selector(updateRefreshInterval)
167 atIndex:index++]; 169 atIndex:index++];
168 [_refreshField setText:@"0.5"]; 170 [_refreshField setText:@"0.5"];
169 [self updateRefreshInterval]; 171 [self updateRefreshInterval];
170 } 172 }
171 173
172 - (void)registerForNotifications { 174 - (void)registerForNotifications {
(...skipping 24 matching lines...) Expand all
197 - (void)addMetricWithName:(NSString*)name 199 - (void)addMetricWithName:(NSString*)name
198 atIndex:(NSUInteger)index 200 atIndex:(NSUInteger)index
199 usingLabel:(UILabel*)label { 201 usingLabel:(UILabel*)label {
200 // The width of the view for the metric's name. 202 // The width of the view for the metric's name.
201 const CGFloat kNameWidth = 150; 203 const CGFloat kNameWidth = 150;
202 // The width of the view for each metric. 204 // The width of the view for each metric.
203 const CGFloat kMetricWidth = 100; 205 const CGFloat kMetricWidth = 100;
204 CGPoint nameOrigin = [self originForSubviewAtIndex:index]; 206 CGPoint nameOrigin = [self originForSubviewAtIndex:index];
205 CGRect nameFrame = 207 CGRect nameFrame =
206 CGRectMake(nameOrigin.x, nameOrigin.y, kNameWidth, [_font lineHeight]); 208 CGRectMake(nameOrigin.x, nameOrigin.y, kNameWidth, [_font lineHeight]);
207 base::scoped_nsobject<UILabel> nameLabel( 209 UILabel* nameLabel = [[UILabel alloc] initWithFrame:nameFrame];
208 [[UILabel alloc] initWithFrame:nameFrame]);
209 [nameLabel setText:[NSString stringWithFormat:@"%@: ", name]]; 210 [nameLabel setText:[NSString stringWithFormat:@"%@: ", name]];
210 [nameLabel setFont:_font]; 211 [nameLabel setFont:_font];
211 [self addSubview:nameLabel]; 212 [self addSubview:nameLabel];
212 label.frame = CGRectMake(CGRectGetMaxX(nameFrame), nameFrame.origin.y, 213 label.frame = CGRectMake(CGRectGetMaxX(nameFrame), nameFrame.origin.y,
213 kMetricWidth, [_font lineHeight]); 214 kMetricWidth, [_font lineHeight]);
214 [label setFont:_font]; 215 [label setFont:_font];
215 [label setTextAlignment:NSTextAlignmentRight]; 216 [label setTextAlignment:NSTextAlignmentRight];
216 [self addSubview:label]; 217 [self addSubview:label];
217 } 218 }
218 219
219 // Adds a subview for a button with the given title and target/action. 220 // Adds a subview for a button with the given title and target/action.
220 - (void)addButtonWithTitle:(NSString*)title 221 - (void)addButtonWithTitle:(NSString*)title
221 target:(id)target 222 target:(id)target
222 action:(SEL)action 223 action:(SEL)action
223 withOrigin:(CGPoint)origin { 224 withOrigin:(CGPoint)origin {
224 base::scoped_nsobject<UIButton> button( 225 UIButton* button = [UIButton buttonWithType:UIButtonTypeSystem];
225 [[UIButton buttonWithType:UIButtonTypeSystem] retain]);
226 [button setTitle:title forState:UIControlStateNormal]; 226 [button setTitle:title forState:UIControlStateNormal];
227 [button titleLabel].font = _font; 227 [button titleLabel].font = _font;
228 [[button titleLabel] setTextAlignment:NSTextAlignmentCenter]; 228 [[button titleLabel] setTextAlignment:NSTextAlignmentCenter];
229 [button sizeToFit]; 229 [button sizeToFit];
230 [button setFrame:CGRectMake(origin.x, origin.y, [button frame].size.width, 230 [button setFrame:CGRectMake(origin.x, origin.y, [button frame].size.width,
231 [_font lineHeight])]; 231 [_font lineHeight])];
232 [button addTarget:target 232 [button addTarget:target
233 action:action 233 action:action
234 forControlEvents:UIControlEventTouchUpInside]; 234 forControlEvents:UIControlEventTouchUpInside];
235 [self addSubview:button]; 235 [self addSubview:button];
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 // The inputTarget/inputAction will be invoked when the user finishes editing 267 // The inputTarget/inputAction will be invoked when the user finishes editing
268 // in |input|. 268 // in |input|.
269 - (void)addLabelWithText:(NSString*)labelText 269 - (void)addLabelWithText:(NSString*)labelText
270 input:(UITextField*)input 270 input:(UITextField*)input
271 inputTarget:(id)inputTarget 271 inputTarget:(id)inputTarget
272 inputAction:(SEL)inputAction 272 inputAction:(SEL)inputAction
273 buttonWithTitle:(NSString*)buttonTitle 273 buttonWithTitle:(NSString*)buttonTitle
274 buttonTarget:(id)buttonTarget 274 buttonTarget:(id)buttonTarget
275 buttonAction:(SEL)buttonAction 275 buttonAction:(SEL)buttonAction
276 atIndex:(NSUInteger)index { 276 atIndex:(NSUInteger)index {
277 base::scoped_nsobject<UILabel> label( 277 UILabel* label = [[UILabel alloc] initWithFrame:CGRectZero];
278 [[UILabel alloc] initWithFrame:CGRectZero]);
279 if (labelText) { 278 if (labelText) {
280 [label setText:[NSString stringWithFormat:@"%@: ", labelText]]; 279 [label setText:[NSString stringWithFormat:@"%@: ", labelText]];
281 } 280 }
282 [label setFont:_font]; 281 [label setFont:_font];
283 [label sizeToFit]; 282 [label sizeToFit];
284 CGPoint labelOrigin = [self originForSubviewAtIndex:index]; 283 CGPoint labelOrigin = [self originForSubviewAtIndex:index];
285 [label setFrame:CGRectOffset([label frame], labelOrigin.x, labelOrigin.y)]; 284 [label setFrame:CGRectOffset([label frame], labelOrigin.x, labelOrigin.y)];
286 [self addSubview:label]; 285 [self addSubview:label];
287 if (input) { 286 if (input) {
288 // The width of the views for each input text field. 287 // The width of the views for each input text field.
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 NSString* errorMessage = [NSString 459 NSString* errorMessage = [NSString
461 stringWithFormat:@"Invalid value \"%@\" for refresh interval.\n" 460 stringWithFormat:@"Invalid value \"%@\" for refresh interval.\n"
462 @"Must be a positive number.\n" @"Resetting to %.1f", 461 @"Must be a positive number.\n" @"Resetting to %.1f",
463 [_refreshField text], refreshTimerValue]; 462 [_refreshField text], refreshTimerValue];
464 [self alert:errorMessage]; 463 [self alert:errorMessage];
465 [_refreshField 464 [_refreshField
466 setText:[NSString stringWithFormat:@"%.1f", refreshTimerValue]]; 465 setText:[NSString stringWithFormat:@"%.1f", refreshTimerValue]];
467 return; 466 return;
468 } 467 }
469 [_refreshTimer invalidate]; 468 [_refreshTimer invalidate];
470 _refreshTimer.reset( 469 _refreshTimer = [NSTimer scheduledTimerWithTimeInterval:refreshTimerValue
471 [[NSTimer scheduledTimerWithTimeInterval:refreshTimerValue 470 target:self
472 target:self 471 selector:@selector(refresh:)
473 selector:@selector(refresh:) 472 userInfo:nil
474 userInfo:nil 473 repeats:YES];
475 repeats:YES] retain]);
476 } 474 }
477 475
478 #pragma mark Memory warning interval methods 476 #pragma mark Memory warning interval methods
479 477
480 // Since _performMemoryWarning is a private API it can't be compiled into 478 // Since _performMemoryWarning is a private API it can't be compiled into
481 // official builds. 479 // official builds.
482 // TODO(lliabraa): Figure out how to support memory warnings (or something 480 // TODO(lliabraa): Figure out how to support memory warnings (or something
483 // like them) in official builds. 481 // like them) in official builds.
484 #if CHROMIUM_BUILD 482 #if CHROMIUM_BUILD
485 - (void)updateMemoryWarningInterval { 483 - (void)updateMemoryWarningInterval {
(...skipping 16 matching lines...) Expand all
502 @"Turning off continuous memory warnings", 500 @"Turning off continuous memory warnings",
503 text]; 501 text];
504 [self alert:errorMessage]; 502 [self alert:errorMessage];
505 [_continuousMemoryWarningField setText:@""]; 503 [_continuousMemoryWarningField setText:@""];
506 return; 504 return;
507 } 505 }
508 // If a valid value was found have the timer start triggering continuous 506 // If a valid value was found have the timer start triggering continuous
509 // memory warnings. 507 // memory warnings.
510 #pragma clang diagnostic push 508 #pragma clang diagnostic push
511 #pragma clang diagnostic ignored "-Wundeclared-selector" 509 #pragma clang diagnostic ignored "-Wundeclared-selector"
512 _memoryWarningTimer.reset( 510 _memoryWarningTimer =
513 [[NSTimer scheduledTimerWithTimeInterval:timerValue 511 [NSTimer scheduledTimerWithTimeInterval:timerValue
514 target:[UIApplication sharedApplication] 512 target:[UIApplication sharedApplication]
515 selector:@selector(_performMemoryWarning) 513 selector:@selector(_performMemoryWarning)
516 userInfo:nil 514 userInfo:nil
517 repeats:YES] retain]); 515 repeats:YES];
518 #pragma clang diagnostic push 516 #pragma clang diagnostic push
519 } 517 }
520 #endif // CHROMIUM_BUILD 518 #endif // CHROMIUM_BUILD
521 519
522 #pragma mark UITextViewDelegate methods 520 #pragma mark UITextViewDelegate methods
523 521
524 // Dismisses the keyboard if the user hits return. 522 // Dismisses the keyboard if the user hits return.
525 - (BOOL)textFieldShouldReturn:(UITextField*)textField { 523 - (BOOL)textFieldShouldReturn:(UITextField*)textField {
526 [textField resignFirstResponder]; 524 [textField resignFirstResponder];
527 return YES; 525 return YES;
(...skipping 22 matching lines...) Expand all
550 [alert addAction:[UIAlertAction actionWithTitle:@"OK" 548 [alert addAction:[UIAlertAction actionWithTitle:@"OK"
551 style:UIAlertActionStyleDefault 549 style:UIAlertActionStyleDefault
552 handler:nil]]; 550 handler:nil]];
553 [[[[UIApplication sharedApplication] keyWindow] rootViewController] 551 [[[[UIApplication sharedApplication] keyWindow] rootViewController]
554 presentViewController:alert 552 presentViewController:alert
555 animated:YES 553 animated:YES
556 completion:nil]; 554 completion:nil];
557 } 555 }
558 556
559 @end 557 @end
OLDNEW
« no previous file with comments | « ios/chrome/browser/memory/BUILD.gn ('k') | ios/chrome/browser/memory/memory_debugger_manager.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698