Full Code of 4ch12dy/fkwechatzan for AI

master 92566a21d833 cached
23 files
53.9 KB
15.2k tokens
1 symbols
1 requests
Download .txt
Repository: 4ch12dy/fkwechatzan
Branch: master
Commit: 92566a21d833
Files: 23
Total size: 53.9 KB

Directory structure:
gitextract_7nfelxh2/

├── .gitignore
├── .theos/
│   ├── _/
│   │   ├── DEBIAN/
│   │   │   └── control
│   │   └── Library/
│   │       └── MobileSubstrate/
│   │           └── DynamicLibraries/
│   │               └── fkwechatzan.plist
│   ├── build_session
│   ├── fakeroot
│   └── last_package
├── LICENSE
├── Makefile
├── Morezan.xm
├── README.md
├── Tweak.xm
├── WBBaseViewController.h
├── WBBaseViewController.m
├── WBMultiSelectGroupsViewController.h
├── WBMultiSelectGroupsViewController.m
├── WBSettingViewController.h
├── WBSettingViewController.m
├── XEditViewController.h
├── XEditViewController.m
├── build.sh
├── control
├── fkwechatzan.plist
└── xia0WeChat.h

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

!/.theos/*
packages
obj

## Build generated
build/
DerivedData/

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/

## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/


================================================
FILE: .theos/_/DEBIAN/control
================================================
Package: com.xia0.fkwechatzan
Name: fkwechatzan
Depends: mobilesubstrate
Architecture: iphoneos-arm
Description: 微信集赞助手!集赞换礼品终结者~
Maintainer: xia0
Author: xia0
Section: Tweaks
Version: 0.0.3-3+debug
Installed-Size: 244


================================================
FILE: .theos/_/Library/MobileSubstrate/DynamicLibraries/fkwechatzan.plist
================================================
{ Filter = { Bundles = ( "com.tencent.xin" ); }; }


================================================
FILE: .theos/build_session
================================================


================================================
FILE: .theos/fakeroot
================================================


================================================
FILE: .theos/last_package
================================================
./packages/com.xia0.fkwechatzan_0.0.3-3+debug_iphoneos-arm.deb


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 xia0

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: Makefile
================================================
GO_EASY_ON_ME = 1
THEOS_DEVICE_IP = localhost
THEOS_DEVICE_PORT = 2222
ARCHS = armv7 arm64
TARGET = iphone:latest:7.0

include $(THEOS)/makefiles/common.mk

TWEAK_NAME = fkwechatzan
$(TWEAK_NAME)_FILES = $(wildcard *.m) Morezan.xm Tweak.xm
$(TWEAK_NAME)_CFLAGS = -Wno-implicit-function-declaration
include $(THEOS_MAKE_PATH)/tweak.mk

after-install::
	install.exec "killall -9 WeChat"


================================================
FILE: Morezan.xm
================================================

@interface WCDataItem : NSObject

@property (retain, nonatomic) NSMutableArray * likeUsers;

@property  (nonatomic) int likeCount;

@property (retain, nonatomic) NSString* username;

@property (retain, nonatomic) NSMutableArray * commentUsers;

@property  (nonatomic) int commentCount;

@end

@interface SettingUtil : NSObject

+(NSString*) getCurUsrName;

@end

@interface MMServiceCenter : NSObject
+ (instancetype)defaultCenter;
- (id)getService:(Class)service;
@end

@interface CContactMgr : NSObject
- (id)getSelfContact;
- (id)getContactByName:(id)arg1;
- (id)getContactList:(unsigned int)arg1 contactType:(unsigned int)arg2;
- (id)getAllContactUserName;
@end

@interface WCUserComment : NSObject

@property (retain, nonatomic) NSString * nickname;

@property (retain, nonatomic) NSString* username;
@property (retain, nonatomic) NSString* contentPattern;
@property (retain, nonatomic) NSString* content;

@property (retain, nonatomic) NSString* commentID;
@property (retain, nonatomic) NSString* m_cpKeyForComment;//@"wctlcm|33||z314250405||1563794344"   @"wctlcm|99|1|wxid_6913ohfkk7kq12|liuwenling001|1563794437"

@property (retain, nonatomic) NSString* refCommentID;
@property (retain, nonatomic) NSString* refUserName;

@property  (nonatomic) int type; //1 mean like 2 mean comment
@property  (nonatomic) int isRichText; 
@property  (nonatomic) unsigned int createTime; 

@end

@interface CBaseContact : NSObject
@property (nonatomic, copy) NSString *m_nsEncodeUserName;                // 微信用户名转码
@property (nonatomic, assign) int m_uiFriendScene;                       // 是否是自己的好友(非订阅号、自己)
@property (nonatomic,assign) BOOL m_isPlugin;                            // 是否为微信插件

@property (nonatomic,assign) unsigned int m_uiType; // 联系人类型  3:公众号  2:群聊  4:正常朋友 1:商家品牌

- (BOOL)isChatroom;
@end

@interface CContact : CBaseContact
@property (nonatomic, copy) NSString *m_nsOwner;                        // 拥有者
@property (nonatomic, copy) NSString *m_nsNickName;                     // 用户昵称
@property (nonatomic, copy) NSString *m_nsUsrName;                      // 微信id
@property (nonatomic, copy) NSString *m_nsMemberName;
@end

@interface WCCommentDetailViewControllerFB : NSObject
@property (nonatomic, copy) NSMutableArray *arrLikeList;       
@property (nonatomic, copy) WCDataItem *dataItem; 
@end

#define XLOG(log, ...)	NSLog(@"xia0:" log, ##__VA_ARGS__)

NSArray* getFriendList(){
	// if cache exsist, return it.
	NSArray* cache = [[NSUserDefaults standardUserDefaults] objectForKey:@"kFriendListCache"];
	if (cache && [cache count] > 0)
	{
		XLOG(@"getFriendList cache exsist: %d", [cache count]);
		return cache;
	}

	NSMutableArray* friendList = [NSMutableArray array];
	NSArray* allUserNameArr = [[[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]] getAllContactUserName] allObjects];
	for(NSString* curUsreName in allUserNameArr){
		CContact* curAddContact = [[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]] getContactByName:curUsreName];
		if (curAddContact.m_uiType != 1 && curAddContact.m_uiType != 2 && curAddContact.m_uiType != 3)
		{
			BOOL isNotFriendZan = [[NSUserDefaults standardUserDefaults] boolForKey:@"kNotFriendZan"];

			if (isNotFriendZan)
			{ 
				[friendList addObject:curUsreName];
			}else{
				if (curAddContact.m_uiFriendScene != 0)
				{
					[friendList addObject:curUsreName];
				}
			}
		}
	}
	[[NSUserDefaults standardUserDefaults] setObject:friendList forKey:@"kFriendListCache"];
    [[NSUserDefaults standardUserDefaults] synchronize];

	return friendList;
} 


NSMutableArray* fkzan(NSMutableArray* origLikeUsers){

	BOOL isRandomPerOpen = [[NSUserDefaults standardUserDefaults] boolForKey:@"kRandomPerOpen"];
	NSData *lastData = [[NSUserDefaults standardUserDefaults] objectForKey:@"kLastNewLikeUsers"];

	NSArray *last = [NSKeyedUnarchiver unarchiveObjectWithData:lastData];

	NSMutableArray* lastMutableArray = [NSMutableArray arrayWithArray: last];

	if (!isRandomPerOpen && lastMutableArray)
	{ 
		return lastMutableArray;
	}

	NSMutableArray* newLikeUsers = [NSMutableArray array];
	NSArray* allUserNameArr = [[[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]] getAllContactUserName] allObjects];
	// uint32_t value = arc4random() % 20;

	BOOL isKeepOld = [[NSUserDefaults standardUserDefaults] boolForKey:@"kDatatKeepOld"];

	if (isKeepOld)
	{
		// add orig like data
		if ([origLikeUsers count] > 0)
		{
			XLOG("fkzan keep old zan!");
			for(id likeItem in origLikeUsers){
				[newLikeUsers addObject:likeItem];
			}
			
		}
	}


	NSInteger zanCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"kMoreZanID"];
	if (!zanCount || zanCount == 0)
	{
		return newLikeUsers;
	}

	NSArray* friendArr = getFriendList();
	NSMutableArray* choose = [NSMutableArray arrayWithArray:friendArr];

	// create new fake data: this add 10
	for (int i = 0; i < zanCount; ++i)
	{	
		if (!choose || [choose count] <= 0)
		{
			break;
		}

		uint32_t idx = arc4random() % [choose count];
		NSString* curAddUserName = [choose objectAtIndex:idx];
		CContact* curAddContact = [[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]] getContactByName:curAddUserName];


		NSString* curAddNickName = [curAddContact m_nsNickName];

		WCUserComment* curAddUserComment = [[%c(WCUserComment) alloc] init];
		curAddUserComment.username = curAddUserName;
		curAddUserComment.nickname = curAddNickName;
		curAddUserComment.type = 1;
		curAddUserComment.isRichText = 1;
		NSTimeInterval interval=[[NSDate date] timeIntervalSince1970];
		NSInteger nowTime = interval;
		curAddUserComment.createTime = nowTime;

		[newLikeUsers addObject:curAddUserComment];
		

		BOOL isFriendZanRepeat = [[NSUserDefaults standardUserDefaults] boolForKey:@"kFriendZanRepeat"];
		if (!isFriendZanRepeat)
		{
			[choose removeObjectAtIndex:idx];
		}
	}
	NSData *data = [NSKeyedArchiver archivedDataWithRootObject: newLikeUsers]; 
	[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"kLastNewLikeUsers"];
    [[NSUserDefaults standardUserDefaults] synchronize];
	return newLikeUsers;
}


NSMutableArray* fkCmt(NSMutableArray* origCommentUsers){

	
	BOOL isRandomPerOpen = [[NSUserDefaults standardUserDefaults] boolForKey:@"kRandomPerOpen"];
	NSData* lastData = [[NSUserDefaults standardUserDefaults] objectForKey:@"kLastNewCommentUsers"];
	NSArray *last = [NSKeyedUnarchiver unarchiveObjectWithData:lastData];
	NSMutableArray* lastMutableArray = [NSMutableArray arrayWithArray: last];
	if (!isRandomPerOpen && lastMutableArray)
	{ 
		return lastMutableArray;
	}

	NSMutableArray* newCommentUsers = [NSMutableArray array];
	NSArray* allUserNameArr = [[[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]] getAllContactUserName] allObjects];
	// uint32_t value = arc4random() % 20;

	BOOL isKeepOld = [[NSUserDefaults standardUserDefaults] boolForKey:@"kDatatKeepOld"];

	if (isKeepOld)
	{
		// add orig like data
		if ([origCommentUsers count] > 0)
		{
			XLOG("fkCmt keep old cmt!");
			for(id cmtItem in origCommentUsers){
				[newCommentUsers addObject:cmtItem];
			}
			
		}
	}


	NSInteger cmtCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"kMoreCmtID"];
    if (!cmtCount || cmtCount == 0)
    {
        return newCommentUsers;
    }

    NSArray* cmtContent = @[@"高级", @"点赞就完事了", @"6666", @"赞~", @"这个不错",@"什么鬼东西= = ", @"你说的就是这个?" ,@"牛皮", @"来了~~", @"cxk牛b"];

    BOOL isOpenMyCmt = [[NSUserDefaults standardUserDefaults] boolForKey:@"kMoreCmtOpenMyCmt"];
    if (isOpenMyCmt)
    {
    	NSLog(@"xia0:create my comment content.");
        NSString * myCmtContent = [[NSUserDefaults standardUserDefaults] objectForKey:@"kMoreCmtMyCmtContent"];
        cmtContent = [myCmtContent componentsSeparatedByString:@"\n"];
    }

    NSLog(@"xia0:start creat fake cmts");
	// create new fake data: this add 10
	for (int i = 0; i < cmtCount; ++i)
	{	
		// NSLog(@"xia0:debug 1");
		NSArray* friendArr = getFriendList();
		uint32_t idx = arc4random() % [friendArr count];
		NSString* curAddUserName = [friendArr objectAtIndex:idx];
		CContact* curAddContact = [[[%c(MMServiceCenter) defaultCenter] getService:[%c(CContactMgr) class]] getContactByName:curAddUserName];
		
		NSString* curAddNickName = [curAddContact m_nsNickName];
		// NSLog(@"xia0:debug 2");
		WCUserComment* curAddUserComment = [[%c(WCUserComment) alloc] init];
		curAddUserComment.username = curAddUserName;
		curAddUserComment.nickname = curAddNickName;
		curAddUserComment.type = 2;
		curAddUserComment.commentID = [NSString stringWithFormat:@"%d", idx];
		NSTimeInterval interval=[[NSDate date] timeIntervalSince1970];
		NSInteger nowTime = interval;
		curAddUserComment.createTime = nowTime;

		uint32_t cmtContentidx = arc4random() % [cmtContent count];
		NSString* curAddUserCmtContent = [cmtContent objectAtIndex:cmtContentidx];
		curAddUserComment.content = curAddUserCmtContent;
		// curAddUserComment.contentPattern = @"<parser><type>1</type><range>{0, 3}</range></parser>";
		// curAddUserComment.m_cpKeyForComment = [NSString stringWithFormat:@"wctlcm|1||%@||%ld", curAddUserName, nowTime];
		// NSLog(@"xia0:debug 3");
		// NSLog(@"xia0:%@ %@ %d %@ %@ %@ %@", curAddUserName, curAddNickName,curAddUserComment.type, curAddUserComment.commentID, curAddUserComment.content,curAddUserComment.contentPattern,curAddUserComment.m_cpKeyForComment);
		[newCommentUsers addObject:curAddUserComment];
	}
	NSData *data = [NSKeyedArchiver archivedDataWithRootObject: newCommentUsers]; 
	[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"kLastNewCommentUsers"];
    [[NSUserDefaults standardUserDefaults] synchronize];

	return newCommentUsers;
}

 // -[MicroMessengerAppDelegate application:didFinishLaunchingWithOptions:]
%hook MicroMessengerAppDelegate

-(bool)application:(void *)arg2 didFinishLaunchingWithOptions:(void *)arg3 {
	// remove cache when reLaunch wechat for contact updating
	[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"kFriendListCache"];
	getFriendList();
	return %orig;
}

%end


// more zan in timeline detail
%hook WCCommentDetailViewControllerFB

-(void)setDataItem:(WCDataItem*)dataItem{

	BOOL isOpenFKZan = [[NSUserDefaults standardUserDefaults] boolForKey:@"kOpenFKZan"];
	if (!isOpenFKZan)
	{
		return %orig;
	}

	NSString* curUsreName = [dataItem username];
	NSString* myName = [%c(SettingUtil) getCurUsrName];
	if ([curUsreName isEqualToString:myName])
	{
		NSMutableArray* origLikeUsers = [dataItem likeUsers];
		NSMutableArray* origCommentUsers = [dataItem commentUsers];

		NSMutableArray* newLikeUsers = fkzan(origLikeUsers);
		NSMutableArray* newCommentUsers = fkCmt(origCommentUsers);

		dataItem.likeUsers = newLikeUsers;
		dataItem.likeCount = [newLikeUsers count];
		dataItem.commentUsers = newCommentUsers;
		dataItem.commentCount = [newCommentUsers count];

	}

	return %orig;
}

%end


// more zan in moment refresh
%hook WCTimelineMgr

- (void)onDataUpdated:(id)arg1 andData:(NSMutableArray*)data andAdData:(id)arg3 withChangedTime:(unsigned int)arg4{

	BOOL isOpenFKZan = [[NSUserDefaults standardUserDefaults] boolForKey:@"kOpenFKZan"];
	if (!isOpenFKZan)
	{
		return %orig;
	}

	// [[[MMServiceCenter defaultCenter] getService:[CContactMgr class]] getContactByName:[SettingUtil getCurUsrName]]
	for (WCDataItem* item in data){
		NSString* curUsreName = [item username];
		int likeCount = [item likeCount];
		NSMutableArray* likeUsers = [item likeUsers];
		NSMutableArray* origCommentUsers = [item commentUsers];

		NSString* myName = [%c(SettingUtil) getCurUsrName];

		if ([curUsreName isEqualToString:myName])
		{	
			XLOG(@"WCTimelineMgr onDataUpdated: is my timeline. start fake");
			item.likeUsers = fkzan(likeUsers);
			item.likeCount = [item.likeUsers count];

			NSMutableArray* newCommentUsers = fkCmt(origCommentUsers);
			item.commentUsers = newCommentUsers;
			item.commentCount = [newCommentUsers count];
		}

	}	
	return %orig;
}
%end

================================================
FILE: README.md
================================================
# fkwechatzan
微信集赞、评论插件,随意设置点赞数量和评论。集赞换礼品终结杀手!

### 免责申明

- 本软件仅供个人学习与交流使用,严禁用于商业以及不良用途
- 如有发现任何商业行为以及不良用途,软件(xia0)作者有权撤销使用权。
- 本软件相关声明版权及其修改权、更新权和最终解释权均属软件(xia0)作者所有

### Install

- 如果你会iOS越狱开发的话,应该装有theos环境,那么直接运行build.sh脚本就可以了。
- 如果你会安装deb插件包的话,package目录下有一个deb包。自己传到手机上手动安装也行。
- 以上你都不熟悉的话,大老板源(BigBoss源)直接在cydia里面搜索fkwechatzan安装就行



**Cydia/Sileo添加以下源获取最新的版本**

[https://xia0z.github.io](https://xia0z.github.io)

或BigBoss源搜索:fkwechatzan 

### 更新

- 2019/08/17:修复了大量bug,全新v0.0.2版本,建议都升级到该版本。

- 2019/08/25:全新v0.03版本,增加了更多的个性化积攒配置。

  

### Todo

- 选择指定好友点赞评论
- 评论时间随机化,目前就是1分钟。为了更加真实,点赞评论的时间在朋友圈的时间前随机
- ...

### Introduction

此功能的分析:[**微信集赞/评论插件分析及开发**](http://4ch12dy.site/2019/07/22/fkwechatLike/fkwechatLike/)  



### Screenshot

- 集赞助手设置界面

  <img src="https://github.com/4ch12dy/4ch12dy.github.io/blob/master/articlePic/fkwechatLike/1361564255775_.pic.jpg?raw=true" width="400" hegiht="200" align=center />

  

- 朋友圈详情界面

  <img src="https://github.com/4ch12dy/4ch12dy.github.io/blob/master/articlePic/fkwechatLike/1341564229215_.pic.jpg?raw=true" width="400" hegiht="200" align=center />

- 赞和评论

<img src="https://github.com/4ch12dy/4ch12dy.github.io/blob/master/articlePic/fkwechatLike/1321564227655_.pic.jpg?raw=true" width="400" hegiht="200" align=center />


================================================
FILE: Tweak.xm
================================================
#import "xia0WeChat.h"
#import "WBSettingViewController.h"

%hook NewSettingViewController

- (void)reloadTableData {
	%orig;

	MMTableViewInfo *tableViewInfo = MSHookIvar<id>(self, "m_tableViewMgr");

	WCTableViewSectionManager *sectionInfo = [%c(WCTableViewSectionManager) defaultSection];

	WCTableViewCellManager *settingCell = [%c(WCTableViewCellManager) normalCellForSel:@selector(setting) target:self title:@"积赞助手 V0.0.3"];
	[sectionInfo addCell:settingCell];

	[tableViewInfo insertSection:sectionInfo At:0];

	MMTableView *tableView = [tableViewInfo getTableView];
	[tableView reloadData];
}

%new
- (void)setting {
	WBSettingViewController *settingViewController = [WBSettingViewController new];
	[self.navigationController PushViewController:settingViewController animated:YES];
}

%end

================================================
FILE: WBBaseViewController.h
================================================
#import <UIKit/UIKit.h>

@interface WBBaseViewController : UIViewController

- (void)startLoadingBlocked;
- (void)startLoadingNonBlock;
- (void)startLoadingWithText:(NSString *)text;
- (void)stopLoading;
- (void)stopLoadingWithFailText:(NSString *)text;
- (void)stopLoadingWithOKText:(NSString *)text;

@end


================================================
FILE: WBBaseViewController.m
================================================
#import "WBBaseViewController.h"
#import "xia0WeChat.h"
#import <objc/objc-runtime.h>

@interface WBBaseViewController ()

@property (strong, nonatomic) MMLoadingView *loadingView;

@end

@implementation WBBaseViewController

- (void)startLoadingBlocked {
    if (!self.loadingView) {
        self.loadingView = [self createDefaultLoadingView];
        [self.view addSubview:self.loadingView];
    } else {
        [self.view bringSubviewToFront:self.loadingView];
    }
    [self.loadingView setM_bIgnoringInteractionEventsWhenLoading:YES];
    [self.loadingView setFitFrame:1];
    [self.loadingView startLoading];
}

- (void)startLoadingNonBlock {
    if (!self.loadingView) {
        self.loadingView = [self createDefaultLoadingView];
        [self.view addSubview:self.loadingView];
    } else {
        [self.view bringSubviewToFront:self.loadingView];
    }
    [self.loadingView setM_bIgnoringInteractionEventsWhenLoading:NO];
    [self.loadingView setFitFrame:1];
    [self.loadingView startLoading];
}

- (void)startLoadingWithText:(NSString *)text {
    [self startLoadingNonBlock];
    
    [self.loadingView.m_label setText:text];
}

- (MMLoadingView *)createDefaultLoadingView {
    MMLoadingView *loadingView = [[objc_getClass("MMLoadingView") alloc] init];
    
    MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
    MMLanguageMgr *languageMgr = [serviceCenter getService:objc_getClass("MMLanguageMgr")];
    NSString *loadingText = [languageMgr getStringForCurLanguage:@"Common_DefaultLoadingText"];
    
    [loadingView.m_label setText:loadingText];
    
    return loadingView;
}

- (void)stopLoading {
    [self.loadingView stopLoading];
}

- (void)stopLoadingWithFailText:(NSString *)text {
    [self.loadingView stopLoadingAndShowError:text];
}

- (void)stopLoadingWithOKText:(NSString *)text {
    [self.loadingView stopLoadingAndShowOK:text];
}

@end


================================================
FILE: WBMultiSelectGroupsViewController.h
================================================

#import <UIKit/UIKit.h>

@protocol MultiSelectGroupsViewControllerDelegate <NSObject>
- (void)onMultiSelectGroupReturn:(NSArray *)arg1;

@optional
- (void)onMultiSelectGroupCancel;
@end

@interface WBMultiSelectGroupsViewController : UIViewController

- (instancetype)initWithBlackList:(NSArray *)blackList;

@property (nonatomic, assign) id<MultiSelectGroupsViewControllerDelegate> delegate;

@end


================================================
FILE: WBMultiSelectGroupsViewController.m
================================================
#import "WBMultiSelectGroupsViewController.h"
#import "xia0WeChat.h"
#import <objc/objc-runtime.h>

@interface WBMultiSelectGroupsViewController () <ContactSelectViewDelegate>

@property (strong, nonatomic) ContactSelectView *selectView;
@property (strong, nonatomic) NSArray *blackList;

@end

@implementation WBMultiSelectGroupsViewController

- (instancetype)initWithBlackList:(NSArray *)blackList {
    if (self = [super initWithNibName:nil bundle:nil]) {
        _blackList = blackList;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initTitleArea];
    [self initSelectView];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    
    MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
    CContactMgr *contactMgr = [serviceCenter getService:objc_getClass("CContactMgr")];
    
    for (NSString *contactName in self.blackList) {
        CContact *contact = [contactMgr getContactByName:contactName];
        [self.selectView addSelect:contact];
    }
}

- (void)initTitleArea {
    self.navigationItem.leftBarButtonItem = [objc_getClass("MMUICommonUtil") getBarButtonWithTitle:@"取消" target:self action:@selector(onCancel:) style:0];
    
    self.navigationItem.rightBarButtonItem = [self rightBarButtonWithSelectCount:self.blackList.count];
    
    self.title = @"黑名单";
    
    [self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:18.0]}];
}

- (UIBarButtonItem *)rightBarButtonWithSelectCount:(unsigned long)selectCount {
    
    UIBarButtonItem *barButtonItem;
    if (selectCount == 0) {
        barButtonItem = [objc_getClass("MMUICommonUtil") getBarButtonWithTitle:@"确定" target:self action:@selector(onDone:) style:2];
    } else {
        NSString *title = [NSString stringWithFormat:@"确定(%lu)", selectCount];
        barButtonItem = [objc_getClass("MMUICommonUtil") getBarButtonWithTitle:title target:self action:@selector(onDone:) style:4];
    }
    return barButtonItem;
}

- (void)onCancel:(UIBarButtonItem *)item {
    if ([self.delegate respondsToSelector:@selector(onMultiSelectGroupCancel)]) {
        [self.delegate onMultiSelectGroupCancel];
    }
}

- (void)onDone:(UIBarButtonItem *)item {
    if ([self.delegate respondsToSelector:@selector(onMultiSelectGroupReturn:)]) {
        NSArray *blacklist = [[self.selectView.m_dicMultiSelect allKeys] copy];
        [self.delegate onMultiSelectGroupReturn:blacklist];
    }
}

- (void)initSelectView {
    self.selectView = [[objc_getClass("ContactSelectView") alloc] initWithFrame:[UIScreen mainScreen].bounds delegate:self];
    
    self.selectView.m_uiGroupScene = 5;
    self.selectView.m_bMultiSelect = YES;
    [self.selectView initData:5];
    [self.selectView initView];
    
    [self.view addSubview:self.selectView];
}

#pragma mark - ContactSelectViewDelegate
- (void)onSelectContact:(CContact *)arg1 {
    self.navigationItem.rightBarButtonItem = [self rightBarButtonWithSelectCount:[self getTotalSelectCount]];
}

- (unsigned long)getTotalSelectCount {
    return (unsigned long)[self.selectView.m_dicMultiSelect count];
}

@end


================================================
FILE: WBSettingViewController.h
================================================
#import "WBBaseViewController.h"

@interface WBSettingViewController : WBBaseViewController

@end


================================================
FILE: WBSettingViewController.m
================================================
#import "xia0WeChat.h"
#import "WBSettingViewController.h"
#import <objc/objc-runtime.h>
#import "WBMultiSelectGroupsViewController.h"
#import "XEditViewController.h"

#define XLOG(log, ...)  NSLog(@"xia0:" log, ##__VA_ARGS__)

@interface WBSettingViewController () <MultiSelectGroupsViewControllerDelegate>

@property (nonatomic, strong) WCTableViewManager *tableViewInfo;

@end

@implementation WBSettingViewController

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // 增加对iPhone X的屏幕适配
        CGRect winSize = [UIScreen mainScreen].bounds;
        if (winSize.size.height == 812) { // iPhone X 高为812
            winSize.size.height -= 88;
            winSize.origin.y = 88;
        }
        _tableViewInfo = [[objc_getClass("WCTableViewManager") alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self initTitle];
    [self reloadTableData];
    
    self.edgesForExtendedLayout = UIRectEdgeNone;

    MMTableView *tableView = [self.tableViewInfo getTableView];
    [tableView setContentInset:UIEdgeInsetsMake(0,0,65,0)];
    [self.view addSubview:tableView];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    
    [self stopLoading];
}

- (void)initTitle {
    self.title = @"积攒助手设置";
    
    [self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:18.0]}];
}

- (void)reloadTableData {
    [self.tableViewInfo clearAllSection];
    
    [self addZanSettingSection];
    [self addSupportSection];
    [self addAboutSection];
    
    MMTableView *tableView = [self.tableViewInfo getTableView];

    [tableView reloadData];
}

#pragma mark - ZanSetting
- (void)addZanSettingSection {
    WCTableViewSectionManager *sectionInfo = [objc_getClass("WCTableViewSectionManager") sectionInfoHeader:@"集赞功能设置:建议先在朋友圈详情页面刷新数据再回到朋友圈查看,每次重新打开微信会更新朋友联系人数量。bug反馈、建议可以去github发起issue。获取最新的版本,可以添加作者源:https://xia0z.github.io"];

    [sectionInfo addCell:[self createOpenFKZanCell]];
    BOOL isOpenFKZan = [[NSUserDefaults standardUserDefaults] boolForKey:@"kOpenFKZan"];
    if (isOpenFKZan)
    {
        [sectionInfo addCell:[self createFKZanCell]];
        [sectionInfo addCell:[self createFKCmtCell]];

        [sectionInfo addCell:[self createKeepOldSwitchCell]];
        [sectionInfo addCell:[self createRandomPerOpenCell]];
        [sectionInfo addCell:[self createNotFriendZanCell]];
        [sectionInfo addCell:[self createFriendZanRepeatCell]];

        [sectionInfo addCell:[self createMyCmtSwitchCell]];

        BOOL isOpenMyCmt = [[NSUserDefaults standardUserDefaults] boolForKey:@"kMoreCmtOpenMyCmt"];
        if (isOpenMyCmt)
        {
            [sectionInfo addCell:[self createMyCmtContentCell]];
        }
    }

    [self.tableViewInfo addSection:sectionInfo];
}


- (WCTableViewCellManager *)createOpenFKZanCell {

    BOOL isOpenFKZan = [[NSUserDefaults standardUserDefaults] boolForKey:@"kOpenFKZan"];

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") switchCellForSel:@selector(settingOpenFKZanSwitch:) target:self title:@"开启积攒插件功能" on:isOpenFKZan];

    return cellInfo;
}


- (WCTableViewCellManager *)createFKZanCell {
    NSInteger zanCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"kMoreZanID"];
    if (!zanCount)
    {
        zanCount = 0;
    }

     return [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(settingMoreZan) target:self title:@"集攒数量设置" rightValue:[@(zanCount) stringValue] WithDisclosureIndicator:0];
}

- (void)settingMoreZan{
    int frienfCount = 0;
    NSArray* friendArr = [[NSUserDefaults standardUserDefaults] objectForKey:@"kFriendListCache"];
    XLOG(@"settingMoreZan frienfCount:%d", [friendArr count]);
    if (friendArr)
    {
        frienfCount = [friendArr count];
    }

    NSInteger zanCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"kMoreZanID"];
    [self alertControllerWithTitle:@"积攒数量设置"
                           message:@"设置需要的赞个数\n数量最多为朋友总数量"
                           content:[NSString stringWithFormat:@"%ld", (long)zanCount]
                       placeholder:[NSString stringWithFormat:@"当前数量:%ld", (long)zanCount]
                      keyboardType:UIKeyboardTypeNumberPad
                               blk:^(UITextField *textField) {
                                   [[NSUserDefaults standardUserDefaults] setInteger:textField.text.integerValue forKey:@"kMoreZanID"];
                                   [[NSUserDefaults standardUserDefaults] synchronize];
                                   [self reloadTableData];
                               }];
}

- (WCTableViewCellManager *)createFKCmtCell {
    NSInteger cmtCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"kMoreCmtID"];
    if (!cmtCount)
    {
        cmtCount = 0;
    }

     return [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(settingMoreCmt) target:self title:@"评论数量设置" rightValue:[@(cmtCount) stringValue] WithDisclosureIndicator:0];
}

- (void)settingMoreCmt{
    int frienfCount = 0;
    NSArray* friendArr = [[NSUserDefaults standardUserDefaults] objectForKey:@"kFriendListCache"];
    XLOG(@"settingMoreCmt frienfCount:%d", [friendArr count]);
    if (friendArr)
    {
        frienfCount = [friendArr count];
    }

    NSInteger cmtCount = [[NSUserDefaults standardUserDefaults] integerForKey:@"kMoreCmtID"];
    [self alertControllerWithTitle:@"评论数量设置"
                           message:@"设置需要的评论个数\n数量最多为朋友总数量"
                           content:[NSString stringWithFormat:@"%ld", (long)cmtCount]
                       placeholder:[NSString stringWithFormat:@"当前数量:%ld", (long)cmtCount]
                      keyboardType:UIKeyboardTypeNumberPad
                               blk:^(UITextField *textField) {
                                   [[NSUserDefaults standardUserDefaults] setInteger:textField.text.integerValue forKey:@"kMoreCmtID"];
                                   [[NSUserDefaults standardUserDefaults] synchronize];
                                   [self reloadTableData];
                               }];
}

- (WCTableViewCellManager *)createKeepOldSwitchCell {

    BOOL isKeepOld = [[NSUserDefaults standardUserDefaults] boolForKey:@"kDatatKeepOld"];

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") switchCellForSel:@selector(settingKeepOldSwitch:) target:self title:@"开启保留原始赞/评论" on:isKeepOld];

    return cellInfo;
}

- (WCTableViewCellManager *)createRandomPerOpenCell {

    BOOL randomPerOpen = [[NSUserDefaults standardUserDefaults] boolForKey:@"kRandomPerOpen"];

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") switchCellForSel:@selector(settingRandomPerOpenSwitch:) target:self title:@"开启每次赞/评论数据随机刷新" on:randomPerOpen];

    return cellInfo;
}

- (WCTableViewCellManager *)createNotFriendZanCell {

    BOOL notFriendZan = [[NSUserDefaults standardUserDefaults] boolForKey:@"kNotFriendZan"];

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") switchCellForSel:@selector(settingNotFriendZanSwitch:) target:self title:@"开启非好友点赞/评论" on:notFriendZan];

    return cellInfo;
}

- (WCTableViewCellManager *)createFriendZanRepeatCell {

    BOOL friendZanRepeat = [[NSUserDefaults standardUserDefaults] boolForKey:@"kFriendZanRepeat"];

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") switchCellForSel:@selector(settingFriendZanRepeatSwitch:) target:self title:@"开启点赞好友可以重复" on:friendZanRepeat];

    return cellInfo;
}


- (WCTableViewCellManager *)createMyCmtSwitchCell {

    BOOL isOpenMyCmt = [[NSUserDefaults standardUserDefaults] boolForKey:@"kMoreCmtOpenMyCmt"];

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") switchCellForSel:@selector(settingMyCmtSwitch:) target:self title:@"开启自定义评论" on:isOpenMyCmt];

    return cellInfo;
}

- (WCTableViewCellManager *)createMyCmtContentCell {
    NSString *myCmtContent = [[NSUserDefaults standardUserDefaults] objectForKey:@"kMoreCmtMyCmtContent"];
    myCmtContent = myCmtContent.length == 0 ? @"请填写" : myCmtContent;

    WCTableViewCellManager *cellInfo = [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(settingMyCmtContent) target:self title:@"自定义评论内容" rightValue:myCmtContent WithDisclosureIndicator:1];

    return cellInfo;
}

- (void)settingOpenFKZanSwitch:(UISwitch *)arg {
    [[NSUserDefaults standardUserDefaults] setBool:arg.on forKey:@"kOpenFKZan"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self reloadTableData];
}

- (void)settingKeepOldSwitch:(UISwitch *)arg {
    [[NSUserDefaults standardUserDefaults] setBool:arg.on forKey:@"kDatatKeepOld"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self reloadTableData];
}


- (void)settingNotFriendZanSwitch:(UISwitch *)arg {
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"kFriendListCache"];
    [[NSUserDefaults standardUserDefaults] setBool:arg.on forKey:@"kNotFriendZan"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self reloadTableData];
}

- (void)settingRandomPerOpenSwitch:(UISwitch *)arg {
    [[NSUserDefaults standardUserDefaults] setBool:arg.on forKey:@"kRandomPerOpen"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self reloadTableData];
}

- (void)settingFriendZanRepeatSwitch:(UISwitch *)arg {
    [[NSUserDefaults standardUserDefaults] setBool:arg.on forKey:@"kFriendZanRepeat"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self reloadTableData];
}

- (void)settingMyCmtSwitch:(UISwitch *)arg {
    [[NSUserDefaults standardUserDefaults] setBool:arg.on forKey:@"kMoreCmtOpenMyCmt"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    [self reloadTableData];
}

- (void)settingMyCmtContent {
    XEditViewController *editVC = [[XEditViewController alloc] init];
    editVC.text = [[NSUserDefaults standardUserDefaults] objectForKey:@"kMoreCmtMyCmtContent"];
    [editVC setEndEditing:^(NSString *text) {
        [[NSUserDefaults standardUserDefaults] setObject:text forKey:@"kMoreCmtMyCmtContent"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        [self reloadTableData];
    }];
    editVC.title = @"请输入自定义评论内容";
    editVC.placeholder = @"开启时会从中随机生成(一行为一条评论)";
    [self.navigationController PushViewController:editVC animated:YES];
}

#pragma mark - About
- (void)addAboutSection {
    WCTableViewSectionManager *sectionInfo = [objc_getClass("WCTableViewSectionManager") sectionInfoHeader:@"关于我/项目" Footer:@"\nDEVELOPED BY X1A0@2019\n\n"];
    
    [sectionInfo addCell:[self createAboutmeCell]];
    [sectionInfo addCell:[self createGithubCell]];
    [sectionInfo addCell:[self createBlogCell]];
    
    [self.tableViewInfo addSection:sectionInfo];
}

- (WCTableViewCellManager *)createAboutmeCell {
    return [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(showAboutme) target:self title:@"关于我" rightValue: @"xia0" WithDisclosureIndicator:1];
}

- (WCTableViewCellManager *)createGithubCell {
    return [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(showGithub) target:self title:@"项目Github" rightValue: @"🌟star" WithDisclosureIndicator:1];
}

- (WCTableViewCellManager *)createBlogCell {
    return [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(showBlog) target:self title:@"项目分析"];
}

- (void)showAboutme {
    NSURL *gitHubUrl = [NSURL URLWithString:@"http://4ch12dy.site/aboutme/"];
    MMWebViewController *webViewController = [[objc_getClass("MMWebViewController") alloc] initWithURL:gitHubUrl presentModal:NO extraInfo:nil];
    [self.navigationController PushViewController:webViewController animated:YES];
}

- (void)showGithub {
    NSURL *gitHubUrl = [NSURL URLWithString:@"https://github.com/4ch12dy/fkwechatzan"];
    MMWebViewController *webViewController = [[objc_getClass("MMWebViewController") alloc] initWithURL:gitHubUrl presentModal:NO extraInfo:nil];
    [self.navigationController PushViewController:webViewController animated:YES];
}

- (void)showBlog {
    NSURL *blogUrl = [NSURL URLWithString:@"http://4ch12dy.site/2019/07/22/fkwechatLike/fkwechatLike/"];
    MMWebViewController *webViewController = [[objc_getClass("MMWebViewController") alloc] initWithURL:blogUrl presentModal:NO extraInfo:nil];
    [self.navigationController PushViewController:webViewController animated:YES];
}

#pragma mark - Support
- (void)addSupportSection {
    WCTableViewSectionManager *sectionInfo = [objc_getClass("WCTableViewSectionManager") sectionInfoHeader:@"若有帮助,可以打赏支持作者"];
    
    [sectionInfo addCell:[self createWeChatPayingCell]];
    
    [self.tableViewInfo addSection:sectionInfo];
}

- (WCTableViewCellManager *)createWeChatPayingCell {
    return [objc_getClass("WCTableViewCellManager") normalCellForSel:@selector(payingToAuthor) target:self title:@"微信打赏" rightValue:@"支持作者😈" WithDisclosureIndicator:1];
}

- (void)payingToAuthor {
    [self startLoadingNonBlock];
    ScanQRCodeLogicController *scanQRCodeLogic = [[objc_getClass("ScanQRCodeLogicController") alloc] initWithViewController:self CodeType:31];
    scanQRCodeLogic.fromScene = 1;
    
    NewQRCodeScanner *qrCodeScanner = [[objc_getClass("NewQRCodeScanner") alloc] initWithDelegate:scanQRCodeLogic CodeType:31];

    NSString *rewardStr = @"m0Ms67nN$+P*ZKLtExYpfe";
    NSData *rewardData = [rewardStr dataUsingEncoding:4];  
    [qrCodeScanner notifyResult:rewardStr type:@"WX_CODE" version:0 rawData:rewardData];
}

#pragma mark - MultiSelectGroupsViewControllerDelegate
- (void)onMultiSelectGroupCancel {
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (void)onMultiSelectGroupReturn:(NSArray *)arg1 {
    
    [self reloadTableData];
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)alertControllerWithTitle:(NSString *)title content:(NSString *)content placeholder:(NSString *)placeholder blk:(void (^)(UITextField *))blk {
    [self alertControllerWithTitle:title message:nil content:content placeholder:placeholder blk:blk];
}

- (void)alertControllerWithTitle:(NSString *)title message:(NSString *)message content:(NSString *)content placeholder:(NSString *)placeholder blk:(void (^)(UITextField *))blk {
    [self alertControllerWithTitle:title message:message content:content placeholder:placeholder keyboardType:UIKeyboardTypeDefault blk:blk];
}

- (void)alertControllerWithTitle:(NSString *)title message:(NSString *)message content:(NSString *)content placeholder:(NSString *)placeholder keyboardType:(UIKeyboardType)keyboardType blk:(void (^)(UITextField *))blk  {
    UIAlertController *alertController = ({
        UIAlertController *alert = [UIAlertController
                                    alertControllerWithTitle:title
                                    message:message
                                    preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"取消"
                                                  style:UIAlertActionStyleCancel
                                                handler:nil]];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定"
                                                  style:UIAlertActionStyleDestructive
                                                handler:^(UIAlertAction * _Nonnull action) {
                                                    if (blk) {
                                                        blk(alert.textFields.firstObject);
                                                    }
                                                }]];

        [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
            textField.placeholder = placeholder;
            textField.text = content;
            textField.keyboardType = keyboardType;
        }];

        alert;
    });

    [self presentViewController:alertController animated:YES completion:nil];
}

@end


================================================
FILE: XEditViewController.h
================================================

#import "xia0WeChat.h"

@interface XEditViewController : UIViewController

@property (nonatomic, copy) NSString *text;
@property (nonatomic, copy) NSString *placeholder;
@property (nonatomic, copy) void (^endEditing)(NSString *text);

@end


================================================
FILE: XEditViewController.m
================================================
#import "XEditViewController.h"

@interface XEditViewController ()

@property (nonatomic, strong) MMTextView *textView;

@end

@implementation XEditViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self initNav];
    [self initSubviews];
    [self setup];
}

- (void)initNav {
    self.navigationItem.leftBarButtonItem = [objc_getClass("MMUICommonUtil") getBarButtonWithTitle:@"返回" target:self action:@selector(onBack) style:3];
    self.navigationItem.rightBarButtonItem = [objc_getClass("MMUICommonUtil") getBarButtonWithTitle:@"完成" target:self action:@selector(onFinfsh) style:4];
    [self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName: [UIFont boldSystemFontOfSize:18.0]}];
}

- (void)initSubviews {
    self.textView = ({
        MMTextView *tv = [[objc_getClass("MMTextView") alloc] initWithFrame:CGRectMake(7, 0, SCREEN_WIDTH - 14, SCREEN_HEIGHT)];
        tv.font = [UIFont systemFontOfSize:16];

        tv;
    });

    [self.view addSubview:self.textView];
}

- (void)setup {
    self.textView.text = self.text;
    self.textView.placeholder = self.placeholder;
    self.view.backgroundColor = [UIColor whiteColor];

    [self.textView becomeFirstResponder];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyBoardChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
}

- (void)keyBoardChange:(NSNotification *)note {
    CGRect keyboardFrame = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    if (keyboardFrame.origin.y < SCREEN_HEIGHT) {
        self.textView.frame = CGRectMake(7, 0, SCREEN_WIDTH - 14, SCREEN_HEIGHT - keyboardFrame.size.height);
    } else {
        self.textView.frame = CGRectMake(7, 0, SCREEN_WIDTH - 14, SCREEN_HEIGHT);
    }
}

- (void)onBack {
    if (self.textView.text.length > 0 && ![self.textView.text isEqualToString:self.text]) {
        [self alertControllerWithTitle:@"确定不保存返回么"
                               message:nil
                             leftBlock:nil
                            rightBlock:^() {
                                [self.view endEditing:YES];
                                [self.navigationController popViewControllerAnimated:YES];
                            }];
    } else {
        [self.view endEditing:YES];
        [self.navigationController popViewControllerAnimated:YES];
    }
}

- (void)onFinfsh {
    [self.view endEditing:YES];
    if (self.endEditing) {
        self.endEditing(self.textView.text);
    }
    [self.navigationController popViewControllerAnimated:YES];
}

- (void)alertControllerWithTitle:(NSString *)title message:(NSString *)message leftBlock:(void (^)(void))leftBlk  rightBlock:(void (^)(void))rightBlk {
    UIAlertController *alertController = ({
        UIAlertController *alert = [UIAlertController
                                    alertControllerWithTitle:title
                                    message:nil
                                    preferredStyle:UIAlertControllerStyleAlert];

        [alert addAction:[UIAlertAction actionWithTitle:@"取消"
                                                  style:UIAlertActionStyleCancel
                                                handler:^(UIAlertAction * _Nonnull action) {
                                                    if (leftBlk) {
                                                        leftBlk();
                                                    }
                                                }]];

        [alert addAction:[UIAlertAction actionWithTitle:@"确定"
                                                  style:UIAlertActionStyleDefault
                                                handler:^(UIAlertAction * _Nonnull action) {
                                                    if (rightBlk) {
                                                        rightBlk();
                                                    }
                                                }]];

        alert;
    });

    [self presentViewController:alertController animated:YES completion:nil];
}

@end


================================================
FILE: build.sh
================================================
function xecho(){
	echo -e "\033[32m$1 \033[0m"
}

cydiaRepo="$HOME/xia0/iOSRE/cydiarepo/debs"
ROOT=$(cd `dirname $0`; pwd)


xecho "[1] Clear hosts file."
cat /dev/null > ~/.ssh/known_hosts

xecho "[2] Remove 0ld package."
rm -fr $ROOT/packages

xecho "[3] Compile..."
make -s clean package #> /dev/null 2>&1

xecho "[4] Copy deb to xia0Repo if need..."

if [[ -z $1 || "$1" != "cydia" ]]; then
	xecho "[*] you do not want to copy deb to cydia repo"

else
	xecho "[*] you do want to copy deb to cydia repo, let's go"
	if [[ "$1" = "cydia" &&  -d $cydiaRepo ]]; then
		
		debName=`ls $ROOT/packages/ 2>/dev/null | awk -F'_' '{print $1}'` 

		if [[ -z $debName || $debName == "" ]]; then
			xecho "[-] No deb file in $ROOT/packages"
			exit
		fi

		xecho "[*] Target deb file: $debName"

		ls $cydiaRepo | grep -q "$debName"

		if [[ "$?" == "0" ]]; then
			xecho "[*] Old $debName in xia0Repo, delete it!"
			rm "$cydiaRepo/$debName"*
		else
			xecho "[*] $debName not in xia0Repo"
		fi

		xecho "[*] Do copy $debName to $cydiaRepo"
		cp $ROOT/packages/*.deb $cydiaRepo

	else
		xecho "[*] $cydiaRepo not exsist, do not need copy deb file."
	fi
fi

xecho "[5] Install to device"
make install

xecho "[+] All Done."

================================================
FILE: control
================================================
Package: com.xia0.fkwechatzan
Name: fkwechatzan
Depends: mobilesubstrate
Version: 0.0.3
Architecture: iphoneos-arm
Description: 微信集赞助手!集赞换礼品终结者~
Maintainer: xia0
Author: xia0
Section: Tweaks


================================================
FILE: fkwechatzan.plist
================================================
{ Filter = { Bundles = ( "com.tencent.xin" ); }; }


================================================
FILE: xia0WeChat.h
================================================
#pragma mark - Util
#import <UIKit/UIKit.h>


#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
//适配IP6和6+的等比放大效果
#define FIX_SIZE(num) ((num) * SCREEN_WIDTH / 320.0)
#define FIX_FONT_SIZE(size) SCREEN_WIDTH < 375 ? ((size + 4.0) / 2.0) : SCREEN_WIDTH == 375 ? ((size + 8.0) / 2.0) : ((size + 12.0) / 2.0)
#define TKFont(size) [UIFont systemFontOfSize:FIX_FONT_SIZE(size)]
#define RGBA(r, g, b, a) [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:(a)]
#define RGB(r, g, b) RGBA(r, g, b, 1)



@interface MMTextView : UITextView
@property(retain, nonatomic) NSString *placeholder;
@end


@interface WCBizUtil : NSObject

+ (id)dictionaryWithDecodedComponets:(id)arg1 separator:(id)arg2;

@end

@interface SKBuiltinBuffer_t : NSObject

@property(retain, nonatomic) NSData *buffer; // @dynamic buffer;

@end

#pragma mark - Message

@interface WCPayInfoItem: NSObject

@property(retain, nonatomic) NSString *m_c2cNativeUrl;

@end

@interface CMessageMgr : NSObject

- (void)AddLocalMsg:(id)arg1 MsgWrap:(id)arg2 fixTime:(_Bool)arg3 NewMsgArriveNotify:(_Bool)arg4;

@end

@interface CMessageWrap : NSObject

@property (retain, nonatomic) WCPayInfoItem *m_oWCPayInfoItem;
@property (assign, nonatomic) NSUInteger m_uiMesLocalID;
@property (retain, nonatomic) NSString* m_nsFromUsr;            ///< 发信人,可能是群或个人
@property (retain, nonatomic) NSString* m_nsToUsr;              ///< 收信人
@property (assign, nonatomic) NSUInteger m_uiStatus;
@property (retain, nonatomic) NSString* m_nsContent;            ///< 消息内容
@property (retain, nonatomic) NSString* m_nsRealChatUsr;        ///< 群消息的发信人,具体是群里的哪个人
@property (assign, nonatomic) NSUInteger m_uiMessageType;
@property (assign, nonatomic) long long m_n64MesSvrID;
@property (assign, nonatomic) NSUInteger m_uiCreateTime;
@property (retain, nonatomic) NSString *m_nsDesc;
@property (retain, nonatomic) NSString *m_nsAppExtInfo;
@property (assign, nonatomic) NSUInteger m_uiAppDataSize;
@property (assign, nonatomic) NSUInteger m_uiAppMsgInnerType;
@property (retain, nonatomic) NSString *m_nsShareOpenUrl;
@property (retain, nonatomic) NSString *m_nsShareOriginUrl;
@property (retain, nonatomic) NSString *m_nsJsAppId;
@property (retain, nonatomic) NSString *m_nsPrePublishId;
@property (retain, nonatomic) NSString *m_nsAppID;
@property (retain, nonatomic) NSString *m_nsAppName;
@property (retain, nonatomic) NSString *m_nsThumbUrl;
@property (retain, nonatomic) NSString *m_nsAppMediaUrl;
@property (retain, nonatomic) NSData *m_dtThumbnail;
@property (retain, nonatomic) NSString *m_nsTitle;
@property (retain, nonatomic) NSString *m_nsMsgSource;
@property(nonatomic, assign) NSInteger m_uiGameType;  // 1、猜拳; 2、骰子; 0、自定义表情
@property(nonatomic, assign) unsigned long m_uiGameContent;
@property(nonatomic, strong) NSString *m_nsEmoticonMD5;

- (id)initWithMsgType:(long long)arg1;
+ (_Bool)isSenderFromMsgWrap:(id)arg1;

@end

@interface MMServiceCenter : NSObject

+ (instancetype)defaultCenter;
- (id)getService:(Class)service;

@end

@interface MMLanguageMgr: NSObject

- (id)getStringForCurLanguage:(id)arg1;


@end

#pragma mark - RedEnvelop

@interface WCRedEnvelopesControlData : NSObject

@property(retain, nonatomic) CMessageWrap *m_oSelectedMessageWrap;

@end

@interface WCRedEnvelopesLogicMgr: NSObject

- (void)OpenRedEnvelopesRequest:(id)params;
- (void)ReceiverQueryRedEnvelopesRequest:(id)arg1;
- (void)GetHongbaoBusinessRequest:(id)arg1 CMDID:(unsigned int)arg2 OutputType:(unsigned int)arg3;

/** Added Methods */
- (unsigned int)calculateDelaySeconds;

@end

@interface HongBaoRes : NSObject

@property(retain, nonatomic) SKBuiltinBuffer_t *retText; // @dynamic retText;
@property(nonatomic) int cgiCmdid; // @dynamic cgiCmdid;

@end

@interface HongBaoReq : NSObject

@property(retain, nonatomic) SKBuiltinBuffer_t *reqText; // @dynamic reqText;

@end

#pragma mark - Contact

@interface CContact: NSObject <NSCoding>

@property(retain, nonatomic) NSString *m_nsUsrName;
@property(retain, nonatomic) NSString *m_nsHeadImgUrl;
@property(retain, nonatomic) NSString *m_nsNickName;

- (id)getContactDisplayName;

@end

@interface CContactMgr : NSObject

- (id)getSelfContact;
- (id)getContactByName:(id)arg1;
- (id)getContactForSearchByName:(id)arg1;
- (_Bool)getContactsFromServer:(id)arg1;
- (_Bool)isInContactList:(id)arg1;
- (_Bool)addLocalContact:(id)arg1 listType:(unsigned int)arg2;

@end


#pragma mark - QRCode

@interface ScanQRCodeLogicController: NSObject

@property(nonatomic) unsigned int fromScene;
- (id)initWithViewController:(id)arg1 CodeType:(int)arg2;
- (void)tryScanOnePicture:(id)arg1;
- (void)doScanQRCode:(id)arg1;
- (void)showScanResult;

@end

@interface NewQRCodeScanner: NSObject

- (id)initWithDelegate:(id)arg1 CodeType:(int)arg2;
- (void)notifyResult:(id)arg1 type:(id)arg2 version:(int)arg3 rawData:(NSData *)arg4;

@end

#pragma mark - MMTableView

@interface MMTableViewInfo : UITableView

- (id)getTableView;
- (void)clearAllSection;
- (void)addSection:(id)arg1;
- (void)insertSection:(id)arg1 At:(unsigned int)arg2;
- (void)setContentInset:(id)arg1;

@end

@interface WCTableViewManager

- (id)getTableView;
- (void)clearAllSection;
- (void)addSection:(id)arg1;
- (void)insertSection:(id)arg1 At:(unsigned int)arg2;

@end

@interface MMTableViewSectionInfo

+ (id)sectionInfoDefaut;
+ (id)sectionInfoHeader:(id)arg1;
+ (id)sectionInfoHeader:(id)arg1 Footer:(id)arg2;
- (void)addCell:(id)arg1;

@end

@interface WCTableViewSectionManager

+ (id)defaultSection;
+ (id)sectionInfoHeader:(id)arg1;
+ (id)sectionInfoHeader:(id)arg1 Footer:(id)arg2;
- (void)addCell:(id)arg1;

@end

@interface MMTableViewCellInfo

+ (id)normalCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 accessoryType:(long long)arg4;
+ (id)switchCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 on:(_Bool)arg4;
+ (id)normalCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 rightValue:(id)arg4 accessoryType:(long long)arg5;
+ (id)normalCellForTitle:(id)arg1 rightValue:(id)arg2;
+ (id)urlCellForTitle:(id)arg1 url:(id)arg2;

@end

@interface WCTableViewCellManager
+ (id)normalCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3;
+ (id)normalCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 accessoryType:(long long)arg4;
+ (id)switchCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 on:(_Bool)arg4;
+ (id)normalCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 rightValue:(id)arg4 accessoryType:(long long)arg5;
+ (id)normalCellForSel:(SEL)arg1 target:(id)arg2 title:(id)arg3 rightValue:(id)arg4 WithDisclosureIndicator:(long long)arg5;
+ (id)normalCellForTitle:(id)arg1 rightValue:(id)arg2;
+ (id)urlCellForTitle:(id)arg1 url:(id)arg2;

@end

@interface MMTableView: UITableView

@end

#pragma mark - UI
@interface MMUICommonUtil : NSObject

+ (id)getBarButtonWithTitle:(id)arg1 target:(id)arg2 action:(SEL)arg3 style:(int)arg4;

@end

@interface MMLoadingView : UIView

@property(retain, nonatomic) UILabel *m_label; // @synthesize m_label;
@property (assign, nonatomic) BOOL m_bIgnoringInteractionEventsWhenLoading; // @synthesize m_bIgnoringInteractionEventsWhenLoading;

- (void)setFitFrame:(long long)arg1;
- (void)startLoading;
- (void)stopLoading;
- (void)stopLoadingAndShowError:(id)arg1;
- (void)stopLoadingAndShowOK:(id)arg1;


@end

@interface MMWebViewController: NSObject

- (id)initWithURL:(id)arg1 presentModal:(_Bool)arg2 extraInfo:(id)arg3;

@end


@protocol ContactSelectViewDelegate <NSObject>

- (void)onSelectContact:(CContact *)arg1;

@end

@interface ContactSelectView : UIView

@property(nonatomic) unsigned int m_uiGroupScene; // @synthesize m_uiGroupScene;
@property(nonatomic) _Bool m_bMultiSelect; // @synthesize m_bMultiSelect;
@property(retain, nonatomic) NSMutableDictionary *m_dicMultiSelect; // @synthesize m_dicMultiSelect;

- (id)initWithFrame:(struct CGRect)arg1 delegate:(id)arg2;
- (void)initData:(unsigned int)arg1;
- (void)initView;
- (void)addSelect:(id)arg1;

@end

@interface ContactsDataLogic : NSObject

@property(nonatomic) unsigned int m_uiScene; // @synthesize m_uiScene;

@end

@interface MMUINavigationController : UINavigationController

@end

#pragma mark - UtilCategory

@interface NSMutableDictionary (SafeInsert)

- (void)safeSetObject:(id)arg1 forKey:(id)arg2;

@end

@interface NSDictionary (NSDictionary_SafeJSON)

- (id)arrayForKey:(id)arg1;
- (id)dictionaryForKey:(id)arg1;
- (double)doubleForKey:(id)arg1;
- (float)floatForKey:(id)arg1;
- (long long)int64ForKey:(id)arg1;
- (long long)integerForKey:(id)arg1;
- (id)stringForKey:(id)arg1;

@end

@interface NSString (NSString_SBJSON)

- (id)JSONArray;
- (id)JSONDictionary;
- (id)JSONValue;

@end

#pragma mark - UICategory

@interface UINavigationController (LogicController)

- (void)PushViewController:(id)arg1 animated:(_Bool)arg2;

@end

@interface MMUIViewController : UIViewController

- (void)startLoadingBlocked;
- (void)startLoadingNonBlock;
- (void)startLoadingWithText:(NSString *)text;
- (void)stopLoading;
- (void)stopLoadingWithFailText:(NSString *)text;
- (void)stopLoadingWithOKText:(NSString *)text;

@end

@interface NewSettingViewController: MMUIViewController

- (void)reloadTableData;

@end

@interface ContactInfoViewController : MMUIViewController

@property(retain, nonatomic) CContact *m_contact; // @synthesize m_contact;

@end

@protocol MultiSelectContactsViewControllerDelegate <NSObject>
- (void)onMultiSelectContactReturn:(NSArray *)arg1;

@optional
- (int)getFTSCommonScene;
- (void)onMultiSelectContactCancelForSns;
- (void)onMultiSelectContactReturnForSns:(NSArray *)arg1;
@end

@interface MultiSelectContactsViewController : UIViewController

@property(nonatomic) _Bool m_bKeepCurViewAfterSelect; // @synthesize m_bKeepCurViewAfterSelect=_m_bKeepCurViewAfterSelect;
@property(nonatomic) unsigned int m_uiGroupScene; // @synthesize m_uiGroupScene;

@property(nonatomic, weak) id <MultiSelectContactsViewControllerDelegate> m_delegate; // @synthesize m_delegate;

@end

@interface GameController : NSObject
+ (NSString*)getMD5ByGameContent:(NSInteger) content;
@end

Download .txt
gitextract_7nfelxh2/

├── .gitignore
├── .theos/
│   ├── _/
│   │   ├── DEBIAN/
│   │   │   └── control
│   │   └── Library/
│   │       └── MobileSubstrate/
│   │           └── DynamicLibraries/
│   │               └── fkwechatzan.plist
│   ├── build_session
│   ├── fakeroot
│   └── last_package
├── LICENSE
├── Makefile
├── Morezan.xm
├── README.md
├── Tweak.xm
├── WBBaseViewController.h
├── WBBaseViewController.m
├── WBMultiSelectGroupsViewController.h
├── WBMultiSelectGroupsViewController.m
├── WBSettingViewController.h
├── WBSettingViewController.m
├── XEditViewController.h
├── XEditViewController.m
├── build.sh
├── control
├── fkwechatzan.plist
└── xia0WeChat.h
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: xia0WeChat.h
  type CGRect (line 276) | struct CGRect
Condensed preview — 23 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (61K chars).
[
  {
    "path": ".gitignore",
    "chars": 1432,
    "preview": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n"
  },
  {
    "path": ".theos/_/DEBIAN/control",
    "chars": 219,
    "preview": "Package: com.xia0.fkwechatzan\nName: fkwechatzan\nDepends: mobilesubstrate\nArchitecture: iphoneos-arm\nDescription: 微信集赞助手!"
  },
  {
    "path": ".theos/_/Library/MobileSubstrate/DynamicLibraries/fkwechatzan.plist",
    "chars": 51,
    "preview": "{ Filter = { Bundles = ( \"com.tencent.xin\" ); }; }\n"
  },
  {
    "path": ".theos/build_session",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".theos/fakeroot",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".theos/last_package",
    "chars": 63,
    "preview": "./packages/com.xia0.fkwechatzan_0.0.3-3+debug_iphoneos-arm.deb\n"
  },
  {
    "path": "LICENSE",
    "chars": 1061,
    "preview": "MIT License\n\nCopyright (c) 2019 xia0\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof th"
  },
  {
    "path": "Makefile",
    "chars": 385,
    "preview": "GO_EASY_ON_ME = 1\nTHEOS_DEVICE_IP = localhost\nTHEOS_DEVICE_PORT = 2222\nARCHS = armv7 arm64\nTARGET = iphone:latest:7.0\n\ni"
  },
  {
    "path": "Morezan.xm",
    "chars": 11941,
    "preview": "\n@interface WCDataItem : NSObject\n\n@property (retain, nonatomic) NSMutableArray * likeUsers;\n\n@property  (nonatomic) int"
  },
  {
    "path": "README.md",
    "chars": 1276,
    "preview": "# fkwechatzan\n微信集赞、评论插件,随意设置点赞数量和评论。集赞换礼品终结杀手!\n\n### 免责申明\n\n- 本软件仅供个人学习与交流使用,严禁用于商业以及不良用途\n- 如有发现任何商业行为以及不良用途,软件(xia0)作者有权撤"
  },
  {
    "path": "Tweak.xm",
    "chars": 797,
    "preview": "#import \"xia0WeChat.h\"\n#import \"WBSettingViewController.h\"\n\n%hook NewSettingViewController\n\n- (void)reloadTableData {\n\t%"
  },
  {
    "path": "WBBaseViewController.h",
    "chars": 308,
    "preview": "#import <UIKit/UIKit.h>\n\n@interface WBBaseViewController : UIViewController\n\n- (void)startLoadingBlocked;\n- (void)startL"
  },
  {
    "path": "WBBaseViewController.m",
    "chars": 1913,
    "preview": "#import \"WBBaseViewController.h\"\n#import \"xia0WeChat.h\"\n#import <objc/objc-runtime.h>\n\n@interface WBBaseViewController ("
  },
  {
    "path": "WBMultiSelectGroupsViewController.h",
    "chars": 400,
    "preview": "\n#import <UIKit/UIKit.h>\n\n@protocol MultiSelectGroupsViewControllerDelegate <NSObject>\n- (void)onMultiSelectGroupReturn:"
  },
  {
    "path": "WBMultiSelectGroupsViewController.m",
    "chars": 3185,
    "preview": "#import \"WBMultiSelectGroupsViewController.h\"\n#import \"xia0WeChat.h\"\n#import <objc/objc-runtime.h>\n\n@interface WBMultiSe"
  },
  {
    "path": "WBSettingViewController.h",
    "chars": 98,
    "preview": "#import \"WBBaseViewController.h\"\n\n@interface WBSettingViewController : WBBaseViewController\n\n@end\n"
  },
  {
    "path": "WBSettingViewController.m",
    "chars": 16227,
    "preview": "#import \"xia0WeChat.h\"\n#import \"WBSettingViewController.h\"\n#import <objc/objc-runtime.h>\n#import \"WBMultiSelectGroupsVie"
  },
  {
    "path": "XEditViewController.h",
    "chars": 241,
    "preview": "\n#import \"xia0WeChat.h\"\n\n@interface XEditViewController : UIViewController\n\n@property (nonatomic, copy) NSString *text;\n"
  },
  {
    "path": "XEditViewController.m",
    "chars": 4088,
    "preview": "#import \"XEditViewController.h\"\n\n@interface XEditViewController ()\n\n@property (nonatomic, strong) MMTextView *textView;\n"
  },
  {
    "path": "build.sh",
    "chars": 1214,
    "preview": "function xecho(){\n\techo -e \"\\033[32m$1 \\033[0m\"\n}\n\ncydiaRepo=\"$HOME/xia0/iOSRE/cydiarepo/debs\"\nROOT=$(cd `dirname $0`; p"
  },
  {
    "path": "control",
    "chars": 191,
    "preview": "Package: com.xia0.fkwechatzan\nName: fkwechatzan\nDepends: mobilesubstrate\nVersion: 0.0.3\nArchitecture: iphoneos-arm\nDescr"
  },
  {
    "path": "fkwechatzan.plist",
    "chars": 51,
    "preview": "{ Filter = { Bundles = ( \"com.tencent.xin\" ); }; }\n"
  },
  {
    "path": "xia0WeChat.h",
    "chars": 10095,
    "preview": "#pragma mark - Util\n#import <UIKit/UIKit.h>\n\n\n#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)\n#define SCR"
  }
]

About this extraction

This page contains the full source code of the 4ch12dy/fkwechatzan GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 23 files (53.9 KB), approximately 15.2k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!