├── bot_poc ├── commands │ ├── __init__.py │ ├── utility.py │ ├── start.py │ ├── help.py │ ├── leave.py │ ├── match.py │ └── genericMessage.py ├── apis │ ├── __init__.py │ └── api_base.py ├── views.py ├── config.py └── __init__.py ├── install.sh ├── start.sh ├── Dockerfile ├── requirements.txt ├── runserver.py ├── README.md └── .gitignore /bot_poc/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bot_poc/apis/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /bot_poc/views.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | Routes and views for the flask application. 4 | """ -------------------------------------------------------------------------------- /bot_poc/apis/api_base.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | class ActionResult(): 3 | result:str 4 | message:str -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | sudo apt update -y && apt-get upgrade -y && apt-get autoremove -y 2 | sudo apt install python3-pip 3 | sudo pip3 install -r requirements.txt 4 | sudo timedatectl set-timezone Asia/Taipei 5 | sudo timedatectl # Show timezone -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | now=$(date '+%Y-%m-%d %H:%M:%S') 3 | echo "$now: staring bot..." >> boot.log 4 | ls /volume/app -lh 5 | 6 | mkdir -p /volume/app/logs 7 | chown -R www-data:www-data /volume/app 8 | chmod -R 775 /volume/app 9 | usermod -u 1000 www-data 10 | 11 | gunicorn -w 4 -k gevent --bind 0.0.0.0:5000 runserver:app -preload 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8.0 2 | 3 | LABEL MAINTAINER="Elliot Chen " 4 | 5 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 6 | 7 | WORKDIR /volume/app 8 | 9 | COPY start.sh . 10 | COPY requirements.txt . 11 | 12 | RUN pip install -r requirements.txt 13 | 14 | EXPOSE 5000 15 | 16 | CMD ["sh","start.sh"] 17 | -------------------------------------------------------------------------------- /bot_poc/config.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # 設置 App.config 3 | SECRET_KEY = 'b07481bjava7704sd25sd27d53000e6b1daI52f47' 4 | SESSION_PROTECTION = 'strong' 5 | JSON_AS_ASCII = False 6 | #CSRF_ENABLED = True 7 | TEMPLATES_AUTO_RELOAD = True 8 | 9 | # 設置 bot_poc.config 10 | BOT_API_KEY = "1234567890:ABCDEFGHIJKKKKKKKKKK" 11 | BOT_HOOK_URL = "https://Domainnnnnnnnnnnnn/hook" -------------------------------------------------------------------------------- /bot_poc/commands/utility.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | from telegram import ChatAction 3 | 4 | def send_send_typing_action(func): 5 | """Sends typing action while processing func command.""" 6 | 7 | @wraps(func) 8 | def command_func(command ,bot, update, *args, **kwargs): 9 | bot.send_chat_action(chat_id=update.effective_message.chat_id, action=ChatAction.TYPING) 10 | return func(command ,bot, update) 11 | 12 | return command_func -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aniso8601==8.0.0 2 | Babel==2.9.1 3 | bcrypt==3.1.7 4 | blinker==1.4 5 | cffi==1.13.2 6 | Click==7.0 7 | cryptography==39.0.1 8 | dnspython==1.16.0 9 | Flask==1.1.2 10 | Flask-RESTful==0.3.7 11 | gevent 12 | greenlet 13 | gunicorn==20.0.4 14 | itsdangerous==1.1.0 15 | Jinja2==2.11.3 16 | MarkupSafe==1.1.1 17 | passlib==1.7.2 18 | pip==21.1 19 | pycparser==2.19 20 | pytz==2019.3 21 | setuptools==65.5.1 22 | six==1.13.0 23 | speaklater==1.3 24 | urllib3==1.26.5 25 | Werkzeug==2.2.3 26 | WTForms==2.2.1 27 | python-telegram-bot 28 | requests 29 | redis 30 | -------------------------------------------------------------------------------- /runserver.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | This script runs the bot_poc application using a development server. 4 | """ 5 | import sys 6 | import importlib,sys 7 | importlib.reload(sys) 8 | 9 | from os import environ 10 | from bot_poc import app 11 | 12 | # Remote Debug use 13 | # import ptvsd 14 | # ptvsd.enable_attach() 15 | 16 | if __name__ == '__main__': 17 | DEBUG = environ.get('APP_DEBUG', False) 18 | if(DEBUG): 19 | app.debug = DEBUG 20 | HOST = environ.get('SERVER_HOST', '0.0.0.0') 21 | try: 22 | PORT = int(environ.get('SERVER_PORT', '5000')) 23 | except ValueError: 24 | PORT = 5000 25 | app.run(HOST, PORT, threaded=True) 26 | -------------------------------------------------------------------------------- /bot_poc/commands/start.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | usage: /start 4 | """ 5 | from .utility import send_send_typing_action 6 | from bot_poc import Commands 7 | from telegram.ext import CommandHandler, Filters 8 | from telegram.utils.helpers import escape_markdown 9 | 10 | class StartCommand(): 11 | def __init__(self): 12 | self.name = "start" 13 | self.usage = "/start ,顯示初始資訊" 14 | self.handler = CommandHandler 15 | self.filter = Filters.text 16 | 17 | @send_send_typing_action 18 | def _execute(self, bot, update): 19 | """ 顯示初始資訊 """ 20 | commands_str = "\n".join(["- /{}".format(c.name) for c in Commands]) 21 | update.message.reply_text('歡迎使用本機器人!\ 22 | \n提供的指令如下: \ 23 | \n{} \ 24 | \n\n請透過 /help 指令查閱更多。'.format(commands_str)) 25 | 26 | def registe(self,dispatcher): 27 | dispatcher.add_handler(self.handler(self.name, self._execute)) 28 | print("{} command registered!".format(self.name)) -------------------------------------------------------------------------------- /bot_poc/commands/help.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | usage: /help 4 | """ 5 | from .utility import send_send_typing_action 6 | from bot_poc import Commands 7 | from telegram import InlineKeyboardButton, InlineKeyboardMarkup 8 | from telegram.ext import CommandHandler 9 | from telegram.utils.helpers import escape_markdown 10 | 11 | class HelpCommand(): 12 | def __init__(self): 13 | self.name = "help" 14 | self.usage = "/help ,顯示指令列表" 15 | self.handler = CommandHandler 16 | 17 | @send_send_typing_action 18 | def _execute(self, bot, update): 19 | """ 顯示指令列表 """ 20 | commands_str = " \n".join(["- {}".format(c.usage) for c in Commands]) 21 | keyboard = [[InlineKeyboardButton("中文化", url='https://t.me/setlanguage/taiwan')]] 22 | reply_markup = InlineKeyboardMarkup(keyboard) 23 | 24 | update.message.reply_text('提供指令如下:\n{}'.format(commands_str), reply_markup=reply_markup) 25 | 26 | def registe(self,dispatcher): 27 | dispatcher.add_handler(self.handler(self.name, self._execute)) 28 | print("{} command registered!".format(self.name)) -------------------------------------------------------------------------------- /bot_poc/commands/leave.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | usage: /match 4 | """ 5 | from .utility import send_send_typing_action 6 | from bot_poc import redisInst 7 | from telegram.ext import StringCommandHandler, Filters 8 | from telegram.utils.helpers import escape_markdown 9 | 10 | class LeaveCommand(): 11 | def __init__(self): 12 | self.name = "leave" 13 | self.usage = "/leave ,離開配對佇列/對話" 14 | self.handler = StringCommandHandler 15 | self.filter = Filters.text 16 | 17 | @send_send_typing_action 18 | def _execute(self, bot, update): 19 | """ 離開配對 """ 20 | sender = str(update.message.chat_id) 21 | 22 | if(redisInst.lrem("queue", 0, sender) > 0): 23 | update.message.reply_text('已離開配對佇列!') 24 | return 25 | if(redisInst.get(sender)): 26 | matched = redisInst.get(sender) 27 | redisInst.delete(sender) 28 | redisInst.delete(matched) 29 | bot.send_message(chat_id=matched, text="對方已離開對話!!") 30 | update.message.reply_text('已成功離開對話!!') 31 | else: 32 | update.message.reply_text('尚未進入配對或對話中唷!!') 33 | 34 | def registe(self,dispatcher): 35 | dispatcher.add_handler(self.handler(self.name, self._execute)) 36 | print("{} command registered!".format(self.name)) -------------------------------------------------------------------------------- /bot_poc/commands/match.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | usage: /match 4 | """ 5 | from .utility import send_send_typing_action 6 | from bot_poc import redisInst 7 | from telegram.ext import StringCommandHandler, Filters 8 | from telegram.utils.helpers import escape_markdown 9 | 10 | class MatchCommand(): 11 | def __init__(self): 12 | self.name = "match" 13 | self.usage = "/match ,尋找配對" 14 | self.handler = StringCommandHandler 15 | self.filter = Filters.text 16 | 17 | @send_send_typing_action 18 | def _execute(self, bot, update): 19 | """ 尋找配對 """ 20 | sender = str(update.message.chat_id) 21 | 22 | if(redisInst.get(sender)): 23 | update.message.reply_text('請先離開對話再重新配對!') 24 | return 25 | if(redisInst.lrem("queue", 0, sender) > 0): 26 | update.message.reply_text('本已在配對佇列中,將重新進入佇列!') 27 | if(redisInst.llen("queue") > 0): 28 | matched = redisInst.lpop("queue") 29 | redisInst.set(sender,matched) 30 | redisInst.set(matched,sender) 31 | bot.send_message(chat_id=matched, text="已配對成功! 接下來發言內容將會透過Bot匿名轉發!") 32 | update.message.reply_text('已配對成功! 接下來發言內容將會透過Bot匿名轉發!') 33 | else: 34 | redisInst.lpush("queue", sender) 35 | update.message.reply_text('已進入配對序列,將會在配對成功後通知。') 36 | 37 | 38 | def registe(self,dispatcher): 39 | dispatcher.add_handler(self.handler(self.name, self._execute)) 40 | print("{} command registered!".format(self.name)) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is a proof of concept for an anonymous chat. 4 | You can find strangers to talk through the program. 5 | 6 | ## Usage 7 | 8 | Requires Python3 (It's tested on python 3.7.3) 9 | 10 | 1. Clone this project to your server side. 11 | > git clone https://github.com/keoy7am/chat_match_telegram_bot.git 12 | 2. Install python dependencies with pip 13 | > pip3 install -r requirements.txt 14 | 15 | 3. Setting up your bot config 16 | Config File Path: 17 | > bot_poc/config.py 18 | 19 | The following are the configs you need to adjust: 20 | - BOT_API_KEY 21 | > "1234567890:ABCDEFGHIJKKKKKKKKKK" (example) 22 | > If you don't have token,check [here](https://core.telegram.org/bots). 23 | 24 | - BOT_HOOK_URL 25 | > "https://Domainnnnnnnnnnnnn/hook" (example) 26 | __Note: Your protocol must be https!__ 27 | 28 | _Please put your bot token and webhook callback uri in the file._ 29 | 30 | ## Supported forwarding message types 31 | 32 | - text 33 | - photo 34 | - video 35 | - document 36 | - animation 37 | - voice 38 | - sticker 39 | - video_note 40 | 41 | ## TODO List 42 | 43 | - Decoupling data access layer 44 | - The program is depend on the Redis database for chat pairing data access now. 45 | If you abstract the data access behavior, 46 | You can support the use of other databases. 47 | - Implement something to prevent resource competition 48 | - When the number of users is large, 49 | There may be a situation where a queue is matched to different people. 50 | - Globalization 51 | - Match by user's language 52 | - Reply based on user's language (Default:English) 53 | - New Features 54 | - Add gender selection -------------------------------------------------------------------------------- /bot_poc/commands/genericMessage.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | usage: /genericMessage 4 | """ 5 | from .utility import send_send_typing_action 6 | from bot_poc import Commands, redisInst 7 | from telegram import MessageEntity 8 | from telegram.ext import MessageHandler, Filters 9 | from telegram.utils.helpers import escape_markdown 10 | 11 | class GenericMessageCommand(): 12 | def __init__(self, dispatcher): 13 | self.name = "genericMessage" 14 | self.handler = MessageHandler 15 | self.filter = Filters.all 16 | 17 | self._registe(dispatcher) 18 | 19 | @send_send_typing_action 20 | def _execute(self, bot, update): 21 | """ 處理未被其他Command捕獲的資訊 """ 22 | text = update.message.text 23 | photo = update.message.photo 24 | video = update.message.video 25 | document = update.message.document 26 | animation = update.message.animation 27 | voice = update.message.voice 28 | sticker = update.message.sticker 29 | video_note = update.message.video_note 30 | 31 | if(text): 32 | for c in Commands: 33 | if '/{}'.format(c.name) in text: 34 | c._execute(bot, update) 35 | return 36 | 37 | sender = str(update.message.chat_id) 38 | matched = redisInst.get(sender) 39 | if(matched): 40 | if(text): 41 | bot.send_message(chat_id=matched, text=text) 42 | if(photo): 43 | bot.send_photo(chat_id=matched, photo=photo) 44 | if(video): 45 | bot.send_video(chat_id=matched, video=video) 46 | if(document): 47 | bot.send_document(chat_id=matched, document=document) 48 | if(animation): 49 | bot.send_animation(chat_id=matched, animation=animation) 50 | if(voice): 51 | bot.send_voice(chat_id=matched, voice=voice) 52 | if(sticker): 53 | bot.send_sticker(chat_id=matched, sticker=sticker) 54 | if(video_note): 55 | bot.send_video_note(chat_id=matched, video_note=video_note) 56 | 57 | def _registe(self,dispatcher): 58 | dispatcher.add_handler(self.handler(self.filter, self._execute)) 59 | print("{} command registered!".format(self.name)) -------------------------------------------------------------------------------- /bot_poc/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | """ 3 | The flask application package. 4 | """ 5 | import logging 6 | import telegram 7 | import requests as req 8 | from flask import Flask, request 9 | from flask_restful import Api, Resource, reqparse 10 | from telegram.ext import Dispatcher, MessageHandler, Filters 11 | #from bot_poc.controllers.api import * 12 | logging.basicConfig(level=logging.DEBUG, 13 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') 14 | logger = logging.getLogger(__name__) 15 | 16 | import bot_poc.config 17 | app = Flask(__name__) 18 | app.config.from_object(config) 19 | 20 | import redis 21 | connectionPool = redis.ConnectionPool(host='redis', port=6379 ,decode_responses=True) 22 | redisInst = redis.Redis(connection_pool=connectionPool) 23 | redisInst.set('test','ok') 24 | 25 | logger.info("Config Loaded!") 26 | if(app.config['TEMPLATES_AUTO_RELOAD']==True): 27 | app.jinja_env.auto_reload = True 28 | print('enabled auto_reload') 29 | 30 | print("api key: {}".format(app.config['BOT_API_KEY'])) 31 | bot = telegram.Bot(token=(app.config['BOT_API_KEY'])) 32 | 33 | @app.route("/") 34 | def index(): 35 | logging.info("Web service works!") 36 | return "Service works!" 37 | 38 | @app.route("/setHook") 39 | def setHook(): 40 | try: 41 | url = "https://api.telegram.org/bot{}/setWebhook?url={}".format(app.config['BOT_API_KEY'],app.config['BOT_HOOK_URL']) 42 | res = req.get(url) 43 | result = "setting hook to {}.
result:{}".format(url,res.text) 44 | return res.text 45 | except: 46 | return "send failed." 47 | 48 | @app.route('/hook', methods=['POST']) 49 | def webhook_handler(): 50 | """Set route /hook with POST method will trigger this method.""" 51 | if request.method == "POST": 52 | update = telegram.Update.de_json(request.get_json(force=True), bot) 53 | 54 | dispatcher.process_update(update) 55 | return 'ok' 56 | 57 | def error(update, context): 58 | """Log Errors caused by Updates.""" 59 | logger.warning('Update "%s" caused error "%s"', update, context.error) 60 | 61 | dispatcher = Dispatcher(bot, None) 62 | 63 | Commands = [] 64 | from bot_poc.commands.start import StartCommand 65 | Commands.append(StartCommand()) 66 | 67 | from bot_poc.commands.help import HelpCommand 68 | Commands.append(HelpCommand()) 69 | 70 | from bot_poc.commands.match import MatchCommand 71 | Commands.append(MatchCommand()) 72 | 73 | from bot_poc.commands.leave import LeaveCommand 74 | Commands.append(LeaveCommand()) 75 | 76 | for command in Commands: 77 | command.registe(dispatcher) 78 | 79 | from bot_poc.commands.genericMessage import GenericMessageCommand 80 | GenericMessageCommand(dispatcher) 81 | 82 | dispatcher.add_error_handler(error) 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | *.pyc 3 | 4 | ##### Not shared 5 | # Server ssl certificate 6 | /data/Db 7 | /data/certbot 8 | 9 | ##### Windows 10 | # Windows thumbnail cache files 11 | Thumbs.db 12 | Thumbs.db:encryptable 13 | ehthumbs.db 14 | ehthumbs_vista.db 15 | 16 | # Dump file 17 | *.stackdump 18 | 19 | # Folder config file 20 | [Dd]esktop.ini 21 | 22 | # Recycle Bin used on file shares 23 | $RECYCLE.BIN/ 24 | 25 | # Windows Installer files 26 | *.cab 27 | *.msi 28 | *.msix 29 | *.msm 30 | *.msp 31 | 32 | # Windows shortcuts 33 | *.lnk 34 | 35 | ##### Linux 36 | *~ 37 | 38 | # temporary files which can be created if a process still has a handle open of a deleted file 39 | .fuse_hidden* 40 | 41 | # KDE directory preferences 42 | .directory 43 | 44 | # Linux trash folder which might appear on any partition or disk 45 | .Trash-* 46 | 47 | # .nfs files are created when an open file is removed but is still being accessed 48 | .nfs* 49 | 50 | ##### MacOS 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | ##### Backup 79 | *.bak 80 | *.gho 81 | *.ori 82 | *.orig 83 | *.tmp 84 | 85 | ##### GPG 86 | secring.* 87 | 88 | ##### Dropbox 89 | # Dropbox settings and caches 90 | .dropbox 91 | .dropbox.attr 92 | .dropbox.cache 93 | 94 | ##### SynopsysVCS 95 | # Waveform formats 96 | *.vcd 97 | *.vpd 98 | *.evcd 99 | *.fsdb 100 | 101 | # Default name of the simulation executable. A different name can be 102 | # specified with this switch (the associated daidir database name is 103 | # also taken from here): -o / 104 | simv 105 | 106 | # Generated for Verilog and VHDL top configs 107 | simv.daidir/ 108 | simv.db.dir/ 109 | 110 | # Infrastructure necessary to co-simulate SystemC models with 111 | # Verilog/VHDL models. An alternate directory may be specified with this 112 | # switch: -Mdir= 113 | csrc/ 114 | 115 | # Log file - the following switch allows to specify the file that will be 116 | # used to write all messages from simulation: -l 117 | *.log 118 | 119 | # Coverage results (generated with urg) and database location. The 120 | # following switch can also be used: urg -dir .vdb 121 | simv.vdb/ 122 | urgReport/ 123 | 124 | # DVE and UCLI related files. 125 | DVEfiles/ 126 | ucli.key 127 | 128 | # When the design is elaborated for DirectC, the following file is created 129 | # with declarations for C/C++ functions. 130 | vc_hdrs.h 131 | 132 | ##### SVN 133 | .svn/ 134 | 135 | ##### Mercurial 136 | .hg/ 137 | .hgignore 138 | .hgsigs 139 | .hgsub 140 | .hgsubstate 141 | .hgtags 142 | 143 | ##### Bazaar 144 | .bzr/ 145 | .bzrignore 146 | 147 | ##### CVS 148 | /CVS/* 149 | **/CVS/* 150 | .cvsignore 151 | */.cvsignore 152 | 153 | ##### TortoiseGit 154 | # Project-level settings 155 | /.tgitconfig 156 | 157 | ##### PuTTY 158 | # Private key 159 | *.ppk 160 | 161 | ##### Vim 162 | # Swap 163 | [._]*.s[a-v][a-z] 164 | !*.svg # comment out if you don't need vector files 165 | [._]*.sw[a-p] 166 | [._]s[a-rt-v][a-z] 167 | [._]ss[a-gi-z] 168 | [._]sw[a-p] 169 | 170 | # Session 171 | Session.vim 172 | Sessionx.vim 173 | 174 | # Temporary 175 | .netrwhist 176 | *~ 177 | # Auto-generated tag files 178 | tags 179 | # Persistent undo 180 | [._]*.un~ 181 | 182 | ##### Emacs 183 | # -*- mode: gitignore; -*- 184 | *~ 185 | \#*\# 186 | /.emacs.desktop 187 | /.emacs.desktop.lock 188 | *.elc 189 | auto-save-list 190 | tramp 191 | .\#* 192 | 193 | # Org-mode 194 | .org-id-locations 195 | *_archive 196 | 197 | # flymake-mode 198 | *_flymake.* 199 | 200 | # eshell files 201 | /eshell/history 202 | /eshell/lastdir 203 | 204 | # elpa packages 205 | /elpa/ 206 | 207 | # reftex files 208 | *.rel 209 | 210 | # AUCTeX auto folder 211 | /auto/ 212 | 213 | # cask packages 214 | .cask/ 215 | dist/ 216 | 217 | # Flycheck 218 | flycheck_*.el 219 | 220 | # server auth directory 221 | /server/ 222 | 223 | # projectiles files 224 | .projectile 225 | 226 | # directory configuration 227 | .dir-locals.el 228 | 229 | # network security 230 | /network-security.data 231 | 232 | ##### SublimeText 233 | # Cache files for Sublime Text 234 | *.tmlanguage.cache 235 | *.tmPreferences.cache 236 | *.stTheme.cache 237 | 238 | # Workspace files are user-specific 239 | *.sublime-workspace 240 | 241 | # Project files should be checked into the repository, unless a significant 242 | # proportion of contributors will probably not be using Sublime Text 243 | # *.sublime-project 244 | 245 | # SFTP configuration file 246 | sftp-config.json 247 | 248 | # Package control specific files 249 | Package Control.last-run 250 | Package Control.ca-list 251 | Package Control.ca-bundle 252 | Package Control.system-ca-bundle 253 | Package Control.cache/ 254 | Package Control.ca-certs/ 255 | Package Control.merged-ca-bundle 256 | Package Control.user-ca-bundle 257 | oscrypto-ca-bundle.crt 258 | bh_unicode_properties.cache 259 | 260 | # Sublime-github package stores a github token in this file 261 | # https://packagecontrol.io/packages/sublime-github 262 | GitHub.sublime-settings 263 | 264 | ##### Notepad++ 265 | # Notepad++ backups # 266 | *.bak 267 | 268 | ##### TextMate 269 | *.tmproj 270 | *.tmproject 271 | tmtags 272 | 273 | ##### VisualStudioCode 274 | .vscode/* 275 | !.vscode/settings.json 276 | !.vscode/tasks.json 277 | !.vscode/launch.json 278 | !.vscode/extensions.json 279 | *.code-workspace 280 | 281 | ##### NetBeans 282 | **/nbproject/private/ 283 | **/nbproject/Makefile-*.mk 284 | **/nbproject/Package-*.bash 285 | build/ 286 | nbbuild/ 287 | dist/ 288 | nbdist/ 289 | .nb-gradle/ 290 | 291 | ##### JetBrains 292 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 293 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 294 | 295 | # User-specific stuff 296 | .idea/**/workspace.xml 297 | .idea/**/tasks.xml 298 | .idea/**/usage.statistics.xml 299 | .idea/**/dictionaries 300 | .idea/**/shelf 301 | 302 | # Generated files 303 | .idea/**/contentModel.xml 304 | 305 | # Sensitive or high-churn files 306 | .idea/**/dataSources/ 307 | .idea/**/dataSources.ids 308 | .idea/**/dataSources.local.xml 309 | .idea/**/sqlDataSources.xml 310 | .idea/**/dynamic.xml 311 | .idea/**/uiDesigner.xml 312 | .idea/**/dbnavigator.xml 313 | 314 | # Gradle 315 | .idea/**/gradle.xml 316 | .idea/**/libraries 317 | 318 | # Gradle and Maven with auto-import 319 | # When using Gradle or Maven with auto-import, you should exclude module files, 320 | # since they will be recreated, and may cause churn. Uncomment if using 321 | # auto-import. 322 | # .idea/modules.xml 323 | # .idea/*.iml 324 | # .idea/modules 325 | # *.iml 326 | # *.ipr 327 | 328 | # CMake 329 | cmake-build-*/ 330 | 331 | # Mongo Explorer plugin 332 | .idea/**/mongoSettings.xml 333 | 334 | # File-based project format 335 | *.iws 336 | 337 | # IntelliJ 338 | out/ 339 | 340 | # mpeltonen/sbt-idea plugin 341 | .idea_modules/ 342 | 343 | # JIRA plugin 344 | atlassian-ide-plugin.xml 345 | 346 | # Cursive Clojure plugin 347 | .idea/replstate.xml 348 | 349 | # Crashlytics plugin (for Android Studio and IntelliJ) 350 | com_crashlytics_export_strings.xml 351 | crashlytics.properties 352 | crashlytics-build.properties 353 | fabric.properties 354 | 355 | # Editor-based Rest Client 356 | .idea/httpRequests 357 | 358 | # Android studio 3.1+ serialized cache file 359 | .idea/caches/build_file_checksums.ser 360 | 361 | ##### Eclipse 362 | .metadata 363 | bin/ 364 | tmp/ 365 | *.tmp 366 | *.bak 367 | *.swp 368 | *~.nib 369 | local.properties 370 | .settings/ 371 | .loadpath 372 | .recommenders 373 | 374 | # External tool builders 375 | .externalToolBuilders/ 376 | 377 | # Locally stored "Eclipse launch configurations" 378 | *.launch 379 | 380 | # PyDev specific (Python IDE for Eclipse) 381 | *.pydevproject 382 | 383 | # CDT-specific (C/C++ Development Tooling) 384 | .cproject 385 | 386 | # CDT- autotools 387 | .autotools 388 | 389 | # Java annotation processor (APT) 390 | .factorypath 391 | 392 | # PDT-specific (PHP Development Tools) 393 | .buildpath 394 | 395 | # sbteclipse plugin 396 | .target 397 | 398 | # Tern plugin 399 | .tern-project 400 | 401 | # TeXlipse plugin 402 | .texlipse 403 | 404 | # STS (Spring Tool Suite) 405 | .springBeans 406 | 407 | # Code Recommenders 408 | .recommenders/ 409 | 410 | # Annotation Processing 411 | .apt_generated/ 412 | .apt_generated_test/ 413 | 414 | # Scala IDE specific (Scala & Java development for Eclipse) 415 | .cache-main 416 | .scala_dependencies 417 | .worksheet 418 | 419 | ##### Dreamweaver 420 | # DW Dreamweaver added files 421 | _notes 422 | _compareTemp 423 | configs/ 424 | dwsync.xml 425 | dw_php_codehinting.config 426 | *.mno 427 | 428 | ##### CodeKit 429 | # General CodeKit files to ignore 430 | config.codekit 431 | config.codekit3 432 | /min 433 | 434 | ##### Gradle 435 | .gradle 436 | /build/ 437 | 438 | # Ignore Gradle GUI config 439 | gradle-app.setting 440 | 441 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 442 | !gradle-wrapper.jar 443 | 444 | # Cache of project 445 | .gradletasknamecache 446 | 447 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 448 | # gradle/wrapper/gradle-wrapper.properties 449 | 450 | ##### Composer 451 | composer.phar 452 | /vendor/ 453 | 454 | # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control 455 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 456 | composer.lock 457 | 458 | ##### PHP CodeSniffer 459 | # gitignore for the PHP Codesniffer framework 460 | # website: https://github.com/squizlabs/PHP_CodeSniffer 461 | # 462 | # Recommended template: PHP.gitignore 463 | 464 | /wpcs/* 465 | 466 | ##### SASS 467 | .sass-cache/ 468 | *.css.map 469 | *.sass.map 470 | *.scss.map 471 | app/cwbox.setting 472 | --------------------------------------------------------------------------------