You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

650 line
20KB

  1. #import "Reddit.h"
  2. #import "assets/TFHelper.h"
  3. static BOOL isRedditEnabled;
  4. static BOOL isTFDeletedOnly;
  5. static CGFloat pushshiftRequestTimeoutValue;
  6. int firstVersionPart = 4;
  7. int secondVersionPart = 49;
  8. %group Reddit_v4_current
  9. %hook CommentTreeNode
  10. %property(assign,nonatomic)id commentTreeHeaderNode;
  11. %property(assign,nonatomic)id commentTreeCommandBarNode;
  12. %end
  13. %hook CommentTreeHeaderView
  14. -(void) layoutSubviews{
  15. %orig;
  16. [[self commentTreeNode] setCommentTreeHeaderNode:self];
  17. }
  18. %end
  19. %hook CommentTreeHeaderNode
  20. -(void) didLoad{
  21. %orig;
  22. [[self commentTreeNode] setCommentTreeHeaderNode:self];
  23. }
  24. %end
  25. %hook CommentTreeCommandBarNode
  26. -(void) didLoad{
  27. %orig;
  28. [[self commentTreeNode] setCommentTreeCommandBarNode:self];
  29. }
  30. %end
  31. %hook CommentActionSheetViewController
  32. -(void) setItems:(id) arg1{
  33. NSString *commentBody = [[self comment] bodyText];
  34. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:commentBody isDeletedOnly:isTFDeletedOnly]){
  35. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  36. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  37. CGFloat scale = origImage.size.width / existingImageSize.width;
  38. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  39. id undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self comment]];
  40. arg1 = [arg1 arrayByAddingObject:undeleteItem];
  41. [undeleteItem release];
  42. }
  43. %orig;
  44. }
  45. -(void) handleDidSelectActionSheetItem:(id) arg1{
  46. %orig;
  47. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  48. [self dismissViewControllerAnimated:YES completion:nil];
  49. id commentTreeNode = [self commentTreeNode];
  50. Comment *comment = [commentTreeNode comment];
  51. [%c(TFHelper) getUndeleteDataWithID:[[comment pk] componentsSeparatedByString:@"_"][1] isComment:YES timeout:pushshiftRequestTimeoutValue extraData:nil completionTarget:self completionSelector:@selector(completeUndeleteCommentAction:)];
  52. }
  53. }
  54. %new
  55. -(void) completeUndeleteCommentAction:(NSDictionary *) data{
  56. id commentTreeNode = [self commentTreeNode];
  57. Comment *comment = [commentTreeNode comment];
  58. NSString *author = data[@"author"];
  59. NSString *body = data[@"body"];
  60. NSMutableAttributedString *bodyMutableAttributedText;
  61. id themeManager;
  62. id isNightMode;
  63. id textColor;
  64. if (secondVersionPart >= 45){
  65. themeManager = [[%c(ThemeManager) alloc] initWithAppSettings:[%c(AppSettings) sharedSettings]];
  66. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  67. if (isNightMode) {
  68. textColor = [[themeManager darkTheme] bodyTextColor];
  69. } else{
  70. textColor = [[themeManager lightTheme] bodyTextColor];
  71. }
  72. [themeManager release];
  73. } else if (secondVersionPart >= 37){
  74. themeManager = [[%c(ThemeManager) alloc] initWithTraitCollection:nil appSettings:[%c(AppSettings) sharedSettings]];
  75. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  76. if (isNightMode) {
  77. textColor = [[themeManager nightTheme] bodyTextColor];
  78. } else{
  79. textColor = [[themeManager dayTheme] bodyTextColor];
  80. }
  81. [themeManager release];
  82. } else {
  83. themeManager = [%c(ThemeManager) sharedManager];
  84. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  85. if (isNightMode) {
  86. textColor = [[themeManager nightTheme] bodyTextColor];
  87. } else{
  88. textColor = [[themeManager dayTheme] bodyTextColor];
  89. }
  90. }
  91. bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  92. [bodyMutableAttributedText beginEditing];
  93. [bodyMutableAttributedText enumerateAttribute:NSForegroundColorAttributeName inRange:NSMakeRange(0, bodyMutableAttributedText.length) options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
  94. [bodyMutableAttributedText removeAttribute:NSForegroundColorAttributeName range:range];
  95. [bodyMutableAttributedText addAttribute:NSForegroundColorAttributeName value:textColor range:range];
  96. }];
  97. [bodyMutableAttributedText endEditing];
  98. [comment setAuthor:author];
  99. [comment setBodyText:body];
  100. [comment setBodyRichTextAttributed:bodyMutableAttributedText];
  101. [comment setBodyAttributedText:bodyMutableAttributedText];
  102. [[commentTreeNode commentTreeHeaderNode] updateContentViewsForData:comment];
  103. [bodyMutableAttributedText release];
  104. }
  105. %end
  106. %hook PostDetailViewController
  107. %property(strong,nonatomic) id feedPostTextWithThumbnailNode;
  108. %property(strong,nonatomic) id feedPostDetailCellNode;
  109. %end
  110. %hook FeedPostDetailCellNode
  111. -(void) didLoad{
  112. %orig;
  113. [[[self delegate] viewController] setFeedPostDetailCellNode:self];
  114. }
  115. %end
  116. %hook PostActionSheetViewController
  117. -(void) setItems:(id) arg1{
  118. Post *post = [self post];
  119. NSString *postBody = [post selfText];
  120. if ([post isSelfPost]){
  121. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:postBody isDeletedOnly:isTFDeletedOnly]){
  122. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  123. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  124. CGFloat scale = origImage.size.width / existingImageSize.width;
  125. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  126. id undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self post]];
  127. arg1 = [arg1 arrayByAddingObject:undeleteItem];
  128. [undeleteItem release];
  129. }
  130. }
  131. %orig;
  132. }
  133. -(void) handleDidSelectActionSheetItem:(id) arg1{
  134. %orig;
  135. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  136. [self dismissViewControllerAnimated:YES completion:nil];
  137. Post *post = [self post];
  138. if ([post isSelfPost]){
  139. [%c(TFHelper) getUndeleteDataWithID:[[post pk] componentsSeparatedByString:@"_"][1] isComment:NO timeout:pushshiftRequestTimeoutValue extraData:nil completionTarget:self completionSelector:@selector(completeUndeletePostAction:)];
  140. }
  141. }
  142. }
  143. %new
  144. -(void) completeUndeletePostAction:(NSDictionary *) data{
  145. Post *post = [self post];
  146. NSString *author = data[@"author"];
  147. NSString *body = data[@"body"];
  148. id themeManager;
  149. id isNightMode;
  150. id textColor;
  151. if (secondVersionPart >= 45){
  152. themeManager = [[%c(ThemeManager) alloc] initWithAppSettings:[%c(AppSettings) sharedSettings]];
  153. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  154. if (isNightMode) {
  155. textColor = [[themeManager darkTheme] bodyTextColor];
  156. } else{
  157. textColor = [[themeManager lightTheme] bodyTextColor];
  158. }
  159. [themeManager release];
  160. } else if (secondVersionPart >= 37){
  161. themeManager = [[%c(ThemeManager) alloc] initWithTraitCollection:nil appSettings:[%c(AppSettings) sharedSettings]];
  162. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  163. if (isNightMode) {
  164. textColor = [[themeManager nightTheme] bodyTextColor];
  165. } else{
  166. textColor = [[themeManager dayTheme] bodyTextColor];
  167. }
  168. [themeManager release];
  169. } else {
  170. themeManager = [%c(ThemeManager) sharedManager];
  171. isNightMode = [[[%c(AccountManager) sharedManager] defaults] objectForKey:@"kUseNightKey"];
  172. if (isNightMode) {
  173. textColor = [[themeManager nightTheme] bodyTextColor];
  174. } else{
  175. textColor = [[themeManager dayTheme] bodyTextColor];
  176. }
  177. }
  178. NSMutableAttributedString *bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  179. [bodyMutableAttributedText beginEditing];
  180. [bodyMutableAttributedText enumerateAttribute:NSForegroundColorAttributeName inRange:NSMakeRange(0, bodyMutableAttributedText.length) options:0 usingBlock:^(id _Nullable value, NSRange range, BOOL * _Nonnull stop) {
  181. [bodyMutableAttributedText removeAttribute:NSForegroundColorAttributeName range:range];
  182. [bodyMutableAttributedText addAttribute:NSForegroundColorAttributeName value:textColor range:range];
  183. }];
  184. [bodyMutableAttributedText endEditing];
  185. [post setSelfText:body];
  186. [post setAuthor:author];
  187. [post setSelfPostRichTextAttributed:bodyMutableAttributedText];
  188. [post setPreviewFeedPostTextString:bodyMutableAttributedText];
  189. if (secondVersionPart >= 44){
  190. [[[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] contentNode] configureSelfTextNode];
  191. } else if (secondVersionPart >= 38) {
  192. [[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] configureSelfTextNode];
  193. } else {
  194. [[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] configureSelfTextNode];
  195. [[[[[self postActionSheetDelegate] controller] feedPostDetailCellNode] titleNode] configureNodes];
  196. }
  197. [bodyMutableAttributedText release];
  198. }
  199. %end
  200. %end
  201. %group Reddit_v4_ios10
  202. %hook CommentsViewController
  203. %new
  204. -(void) updateComments{
  205. [self reloadCommentsWithNewCommentsHighlight:NO autoScroll:NO animated:NO];
  206. }
  207. %new
  208. -(void) updatePostText{
  209. if (secondVersionPart >= 2){
  210. [self reloadPostSection:YES];
  211. } else {
  212. [self feedPostViewDidUpdatePost:[self postData] shouldReloadFeed:NO];
  213. }
  214. }
  215. %end
  216. %hook CommentActionSheetViewController
  217. -(void) setItems:(id) arg1{
  218. NSString *commentBody = [[self comment] bodyText];
  219. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:commentBody isDeletedOnly:isTFDeletedOnly]){
  220. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  221. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  222. CGFloat scale = origImage.size.width / existingImageSize.width;
  223. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  224. id undeleteItem;
  225. if (secondVersionPart >= 18) {
  226. undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self comment]];
  227. } else {
  228. undeleteItem = [[%c(ActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self comment]];
  229. }
  230. arg1 = [arg1 arrayByAddingObject:undeleteItem];
  231. [undeleteItem release];
  232. }
  233. %orig;
  234. }
  235. // >= 4.21
  236. -(void) handleDidSelectActionSheetItem:(id) arg1{
  237. %orig;
  238. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  239. [self dismissViewControllerAnimated:YES completion:nil];
  240. Comment *comment = [self comment];
  241. [%c(TFHelper) getUndeleteDataWithID:[[comment pk] componentsSeparatedByString:@"_"][1] isComment:YES timeout:pushshiftRequestTimeoutValue extraData:nil completionTarget:self completionSelector:@selector(completeUndeleteCommentAction:)];
  242. }
  243. }
  244. // <= 4.20
  245. -(void) actionSheetViewController:(id) arg1 didSelectItem:(id) arg2{
  246. %orig;
  247. if ([[arg2 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  248. [self dismissViewControllerAnimated:YES completion:nil];
  249. Comment *comment = [self comment];
  250. [%c(TFHelper) getUndeleteDataWithID:[[comment pk] componentsSeparatedByString:@"_"][1] isComment:YES timeout:pushshiftRequestTimeoutValue extraData:nil completionTarget:self completionSelector:@selector(completeUndeleteCommentAction:)];
  251. }
  252. }
  253. %new
  254. -(void) completeUndeleteCommentAction:(NSDictionary *) data{
  255. Comment *comment = [self comment];
  256. NSString *body = data[@"body"];
  257. NSMutableAttributedString *bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  258. [comment setAuthor:data[@"author"]];
  259. [comment setBodyText:body];
  260. [comment setBodyAttributedText:bodyMutableAttributedText];
  261. if (secondVersionPart >= 12) {
  262. [comment setBodyRichTextAttributed:bodyMutableAttributedText];
  263. }
  264. [[self commentActionSheetDelegate] updateComments];
  265. [bodyMutableAttributedText release];
  266. }
  267. %end
  268. %hook PostActionSheetViewController
  269. -(void) setItems:(id) arg1{
  270. Post *post = [self post];
  271. NSString *postBody = [post selfText];
  272. if ([post isSelfPost]){
  273. if ([%c(TFHelper) shouldShowUndeleteButtonWithInfo:postBody isDeletedOnly:isTFDeletedOnly]){
  274. UIImage* origImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  275. CGSize existingImageSize = [[arg1[0] leftIconImage] size];
  276. CGFloat scale = origImage.size.width / existingImageSize.width;
  277. UIImage *newImage = [UIImage imageWithCGImage:[origImage CGImage] scale:scale orientation:origImage.imageOrientation];
  278. id undeleteItem;
  279. if (secondVersionPart >= 18) {
  280. undeleteItem = [[%c(RUIActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self post]];
  281. } else {
  282. undeleteItem = [[%c(ActionSheetItem) alloc] initWithLeftIconImage:newImage text:@"TF did that say?" identifier:@"undeleteItemIdentifier" context:[self post]];
  283. }
  284. arg1 = [arg1 arrayByAddingObject:undeleteItem];
  285. [undeleteItem release];
  286. }
  287. }
  288. %orig;
  289. }
  290. // >= 4.21
  291. -(void) handleDidSelectActionSheetItem:(id) arg1{
  292. %orig;
  293. if ([[arg1 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  294. [self dismissViewControllerAnimated:YES completion:nil];
  295. Post *post = [self post];
  296. if ([post isSelfPost]){
  297. [%c(TFHelper) getUndeleteDataWithID:[[post pk] componentsSeparatedByString:@"_"][1] isComment:NO timeout:pushshiftRequestTimeoutValue extraData:nil completionTarget:self completionSelector:@selector(completeUndeletePostAction:)];
  298. }
  299. }
  300. }
  301. // <= 4.20
  302. -(void) actionSheetViewController:(id) arg1 didSelectItem:(id) arg2{
  303. %orig;
  304. if ([[arg2 identifier] isEqualToString:@"undeleteItemIdentifier"]){
  305. [self dismissViewControllerAnimated:YES completion:nil];
  306. Post *post = [self post];
  307. if ([post isSelfPost]){
  308. [%c(TFHelper) getUndeleteDataWithID:[[post pk] componentsSeparatedByString:@"_"][1] isComment:NO timeout:pushshiftRequestTimeoutValue extraData:nil completionTarget:self completionSelector:@selector(completeUndeletePostAction:)];
  309. }
  310. }
  311. }
  312. %new
  313. -(void) completeUndeletePostAction:(NSDictionary *) data{
  314. Post *post = [self post];
  315. NSString *body = data[@"body"];
  316. NSMutableAttributedString *bodyMutableAttributedText = [[NSMutableAttributedString alloc] initWithAttributedString:[%c(NSAttributedStringMarkdownParser) attributedStringUsingCurrentConfig:body]];
  317. [post setAuthor:data[@"author"]];
  318. [post setSelfText:body];
  319. [post setSelfTextAttributed:bodyMutableAttributedText];
  320. if (secondVersionPart >= 8) {
  321. [post setSelfPostRichTextAttributed:bodyMutableAttributedText];
  322. }
  323. if (secondVersionPart >= 15) {
  324. [post setPreviewFeedPostTextString:bodyMutableAttributedText];
  325. }
  326. [[self postActionSheetDelegate] updatePostText];
  327. [bodyMutableAttributedText release];
  328. }
  329. %end
  330. %end
  331. //outdated and unchanged from first version of this tweak...
  332. //TODO: move button to menu, add post support, make async requests once I feel like doing it
  333. %group Reddit_v3
  334. %hook CommentView
  335. %new
  336. -(void) buttonAction {
  337. id commentsViewController = [self delegate];
  338. id comment = [self comment];
  339. NSError* error;
  340. NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  341. [request setURL:[NSURL URLWithString:[NSString stringWithFormat:@"https://api.pushshift.io/reddit/search/comment/?ids=%@&fields=author,body",[comment pkWithoutPrefix]]]];
  342. [request setHTTPMethod:@"GET"];
  343. NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
  344. NSString *author = @"[author]";
  345. NSString *body = @"[body]";
  346. if (data != nil && error == nil){
  347. id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
  348. author = [[jsonData objectForKey:@"data"][0] objectForKey:@"author"];
  349. body = [[jsonData objectForKey:@"data"][0] objectForKey:@"body"];
  350. if ([body isEqualToString:@"[deleted]"] || [body isEqualToString:@"[removed]"]){
  351. body = @"[comment was unable to be archived]";
  352. }
  353. } else if (error != nil || data == nil){
  354. body = @"[an error occured]";
  355. }
  356. [comment setValue:author forKey:@"author"];
  357. [comment setValue:[%c(MarkDownParser) attributedStringFromMarkdownString: body] forKey:@"bodyAttributedText"];
  358. [comment setValue:body forKey:@"bodyText"];
  359. [commentsViewController reloadCommentsWithNewCommentsHighlight:NO autoScroll:NO animated:NO];
  360. }
  361. -(id) initWithFrame:(id)arg1{
  362. id orig = %orig;
  363. id commandView = [self commandView];
  364. UIButton *undeleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
  365. [undeleteButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
  366. UIImage* undeleteImage = [UIImage imageWithContentsOfFile:@"/var/mobile/Library/Application Support/TFDidThatSay/eye160dark.png"];
  367. [undeleteButton setImage:undeleteImage forState:UIControlStateNormal];
  368. [commandView setUndeleteButton:undeleteButton];
  369. [commandView addSubview:undeleteButton];
  370. return orig;
  371. }
  372. %end
  373. %hook CommentCommandView
  374. %property (assign, nonatomic) id undeleteButton;
  375. -(void) layoutSubviews{
  376. %orig;
  377. UIButton *button = [self undeleteButton];
  378. button.frame = CGRectMake([[self overflowButton ] frame].origin.x - 32, 0, 32, 32);
  379. }
  380. %end
  381. %end
  382. static void loadPrefs(){
  383. NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/User/Library/Preferences/com.lint.undelete.prefs.plist"];
  384. if (prefs){
  385. if ([prefs objectForKey:@"isRedditEnabled"] != nil){
  386. isRedditEnabled = [[prefs objectForKey:@"isRedditEnabled"] boolValue];
  387. } else {
  388. isRedditEnabled = YES;
  389. }
  390. if ([prefs objectForKey:@"isTFDeletedOnly"] != nil) {
  391. isTFDeletedOnly = [[prefs objectForKey:@"isTFDeletedOnly"] boolValue];
  392. } else {
  393. isTFDeletedOnly = YES;
  394. }
  395. if ([prefs objectForKey:@"requestTimeoutValue"] != nil){
  396. pushshiftRequestTimeoutValue = [[prefs objectForKey:@"requestTimeoutValue"] doubleValue];
  397. } else {
  398. pushshiftRequestTimeoutValue = 10;
  399. }
  400. } else {
  401. isRedditEnabled = YES;
  402. isTFDeletedOnly = YES;
  403. pushshiftRequestTimeoutValue = 10;
  404. }
  405. }
  406. static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  407. loadPrefs();
  408. }
  409. %ctor{
  410. loadPrefs();
  411. NSString* processName = [[NSProcessInfo processInfo] processName];
  412. @try{
  413. NSArray *redditVersion = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"] componentsSeparatedByString:@"."];
  414. firstVersionPart = [redditVersion[0] intValue];
  415. secondVersionPart = [redditVersion[1] intValue];
  416. }
  417. @catch (NSException *exc){
  418. firstVersionPart = 4;
  419. secondVersionPart = 49;
  420. }
  421. if ([processName isEqualToString:@"Reddit"]){
  422. if (isRedditEnabled) {
  423. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, prefsChanged, CFSTR("com.lint.undelete.prefs.changed"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
  424. if (firstVersionPart == 4){
  425. if (secondVersionPart <= 32){
  426. %init(Reddit_v4_ios10);
  427. } else{
  428. %init(Reddit_v4_current);
  429. }
  430. } else if (firstVersionPart == 3) {
  431. %init(Reddit_v3);
  432. }
  433. }
  434. }
  435. }