diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index d14d472e9..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,2 +0,0 @@ -github: Aevann1 -custom: ["https://marsey1.gumroad.com/l/rdrama"] diff --git a/.github/workflows/ossar.yml b/.github/workflows/ossar.yml deleted file mode 100644 index 726eb0c3f..000000000 --- a/.github/workflows/ossar.yml +++ /dev/null @@ -1,51 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow integrates a collection of open source static analysis tools -# with GitHub code scanning. For documentation, or to provide feedback, visit -# https://github.com/github/ossar-action -name: OSSAR - -on: - push: - branches: [ frost ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ frost ] - schedule: - - cron: '34 10 * * 3' - -jobs: - OSSAR-Scan: - # OSSAR runs on windows-latest. - # ubuntu-latest and macos-latest support coming soon - runs-on: windows-latest - permissions: - security-events: write - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Ensure a compatible version of dotnet is installed. - # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201. - # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action. - # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped. - # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action: - # - name: Install .NET - # uses: actions/setup-dotnet@v1 - # with: - # dotnet-version: '3.1.x' - - # Run open source static analysis tools - - name: Run OSSAR - uses: github/ossar-action@v1 - id: ossar - - # Upload results to the Security tab - - name: Upload OSSAR results - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: ${{ steps.ossar.outputs.sarifFile }} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d0bcac72e..ea8351575 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,11 +7,6 @@ services: - "./:/rDrama" - "./nginx.conf:/etc/nginx/sites-enabled/1" - "./nginx-serve-static.conf:/etc/nginx/includes/serve-static" - env_file: env - environment: - - DATABASE_URL=postgresql://postgres@postgres:5432 - - REDIS_URL=redis://redis - - PROXY_URL=http://opera-proxy:18080 links: - "redis" - "postgres" diff --git a/env b/env index 082eee376..81b53135a 100644 --- a/env +++ b/env @@ -1,38 +1,38 @@ -FLASK_APP=/rDrama/files/cli:app -SITE=localhost -SITE_NAME=rDrama -MASTER_KEY=blahblahblah -PROXY_URL=http://localhost:18080 -GIPHY_KEY=blahblahblah -DISCORD_SERVER_ID=blahblahblah -DISCORD_CLIENT_ID=blahblahblah -DISCORD_CLIENT_SECRET=blahblahblah -DISCORD_BOT_TOKEN=blahblahblah -HCAPTCHA_SITEKEY=blahblahblah -HCAPTCHA_SECRET=blahblahblah -YOUTUBE_KEY=blahblahblah -PUSHER_ID=blahblahblah -PUSHER_KEY=blahblahblah -IMGUR_KEY=blahblahblah -SPAM_SIMILARITY_THRESHOLD=0.5 -SPAM_URL_SIMILARITY_THRESHOLD=0.1 -SPAM_SIMILAR_COUNT_THRESHOLD=10 -COMMENT_SPAM_SIMILAR_THRESHOLD=0.5 -COMMENT_SPAM_COUNT_THRESHOLD=10 -DEFAULT_TIME_FILTER=all -GUMROAD_TOKEN=blahblahblah -GUMROAD_LINK=https://marsey1.gumroad.com/l/rdrama -GUMROAD_ID=rdrama -CARD_VIEW=0 -DISABLE_DOWNVOTES=0 -DUES=0 -DEFAULT_THEME=midnight -DEFAULT_COLOR=805ad5 -EMAIL=blahblahblah@gmail.com -MAILGUN_KEY=blahblahblah -DESCRIPTION=rdrama.net caters to drama in all forms such as: Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™. There isn't drama we won't touch, and we want it all! -CF_KEY=blahblahblah -CF_ZONE=blahblahblah -DEBIAN_FRONTEND=noninteractive -NODE_VERSION=16.13.0 -NVM_DIR=/root/.nvm +export FLASK_APP="/rDrama/files/cli:app" +export SITE="localhost" +export SITE_NAME="rDrama" +export SECRET_KEY="blahblahblah" +export DATABASE_URL="postgresql://postgres@localhost:5432" +export REDIS_URL="redis://localhost:6379" +export PROXY_URL="http://localhost:18080" +export GIPHY_KEY="blahblahblah" +export DISCORD_BOT_TOKEN="blahblahblah" +export HCAPTCHA_SITEKEY="blahblahblah" +export HCAPTCHA_SECRET="blahblahblah" +export YOUTUBE_KEY="blahblahblah" +export PUSHER_ID="blahblahblah" +export PUSHER_KEY="blahblahblah" +export IMGUR_KEY="blahblahblah" +export SPAM_SIMILARITY_THRESHOLD="0.5" +export SPAM_URL_SIMILARITY_THRESHOLD="0.1" +export SPAM_SIMILAR_COUNT_THRESHOLD="10" +export COMMENT_SPAM_SIMILAR_THRESHOLD="0.5" +export COMMENT_SPAM_COUNT_THRESHOLD="10" +export DEFAULT_TIME_FILTER="all" +export GUMROAD_TOKEN="blahblahblah" +export GUMROAD_LINK="blahblahblah" +export GUMROAD_ID="blahblahblah" +export CARD_VIEW="0" +export DISABLE_DOWNVOTES="0" +export DUES="0" +export DEFAULT_THEME="midnight" +export DEFAULT_COLOR="805ad5" +export EMAIL="blahblahblah@gmail.com" +export MAILGUN_KEY="blahblahblah" +export DESCRIPTION="rdrama.net caters to drama in all forms such as: Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™. There isn't drama we won't touch, and we want it all!" +export CF_KEY="blahblahblah" +export CF_ZONE="blahblahblah" +export DEBIAN_FRONTEND="noninteractive" +export NODE_VERSION="16.13.0" +export NVM_DIR="/root/.nvm" +export TELEGRAM_LINK="blahblahblah" diff --git a/files/__main__.py b/files/__main__.py index 5c4b88197..8a4090b54 100644 --- a/files/__main__.py +++ b/files/__main__.py @@ -24,8 +24,10 @@ app.jinja_env.auto_reload = True app.jinja_env.add_extension('jinja2.ext.do') faulthandler.enable() -app.config['SECRET_KEY'] = environ.get('MASTER_KEY') -app.config["SERVER_NAME"] = environ.get("SITE").strip() +SITE = environ.get("SITE").strip() + +app.config['SERVER_NAME'] = SITE +app.config['SECRET_KEY'] = environ.get('SECRET_KEY').strip() app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3153600 app.config["SESSION_COOKIE_NAME"] = "session_" + environ.get("SITE_NAME").strip().lower() app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 @@ -35,15 +37,14 @@ app.config["PERMANENT_SESSION_LIFETIME"] = 60 * 60 * 24 * 365 app.config['SESSION_REFRESH_EACH_REQUEST'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False -app.config['SQLALCHEMY_DATABASE_URL'] = environ.get("DATABASE_URL", "postgresql://postgres@localhost:5432") +app.config['SQLALCHEMY_DATABASE_URL'] = environ.get("DATABASE_URL").strip() app.config["CACHE_TYPE"] = "RedisCache" -app.config["CACHE_REDIS_URL"] = environ.get("REDIS_URL", "redis://localhost") - +app.config["CACHE_REDIS_URL"] = environ.get("REDIS_URL").strip() app.config['SETTINGS'] = {} -r=redis.Redis(host=environ.get("REDIS_URL", "redis://localhost"), decode_responses=True, ssl_cert_reqs=None) +r=redis.Redis(host=environ.get("REDIS_URL").strip(), decode_responses=True, ssl_cert_reqs=None) def get_CF(): with app.app_context(): @@ -74,6 +75,8 @@ if not path.isfile(f'/site_settings.json'): @app.before_request def before_request(): + if SITE == 'marsey.world' and request.path != '/kofi': + abort(404) g.agent = request.headers.get("User-Agent") if not g.agent and request.path != '/kofi': @@ -85,8 +88,10 @@ def before_request(): with open('/site_settings.json', 'r', encoding='utf_8') as f: app.config['SETTINGS'] = json.load(f) - if request.host != app.config["SERVER_NAME"]: return {"error":"Unauthorized host provided."}, 401 - if request.headers.get("CF-Worker"): return {"error":"Cloudflare workers are not allowed to access this website."}, 401 + if request.host != SITE: + return {"error": "Unauthorized host provided"}, 403 + + if request.headers.get("CF-Worker"): return {"error": "Cloudflare workers are not allowed to access this website."}, 403 if not app.config['SETTINGS']['Bots'] and request.headers.get("Authorization"): abort(403) @@ -99,6 +104,10 @@ def before_request(): request.full_path = request.full_path.rstrip('?').rstrip('/') if not request.full_path: request.full_path = '/' + if not session.get("session_id"): + session.permanent = True + session["session_id"] = secrets.token_hex(49) + @app.after_request def after_request(response): response.headers.add("Strict-Transport-Security", "max-age=31536000") diff --git a/files/assets/app_PCM_v2.4.apk b/files/assets/app_PCM_v2.5.apk similarity index 100% rename from files/assets/app_PCM_v2.4.apk rename to files/assets/app_PCM_v2.5.apk diff --git a/files/assets/app_WPD_v2.4.apk b/files/assets/app_WPD_v2.5.apk similarity index 90% rename from files/assets/app_WPD_v2.4.apk rename to files/assets/app_WPD_v2.5.apk index 147a3d8fe..2e9e4b80f 100644 Binary files a/files/assets/app_WPD_v2.4.apk and b/files/assets/app_WPD_v2.5.apk differ diff --git a/files/assets/app_rDrama_v2.4.apk b/files/assets/app_rDrama_v2.5.apk similarity index 100% rename from files/assets/app_rDrama_v2.4.apk rename to files/assets/app_rDrama_v2.5.apk diff --git a/files/assets/css/4chan.css b/files/assets/css/4chan.css index 799b43bf5..c2d8970e3 100644 --- a/files/assets/css/4chan.css +++ b/files/assets/css/4chan.css @@ -28,10 +28,6 @@ color: var(--primary) !important; } -.modal .comment-actions a { - color: var(--gray-500); -} - .navbar-light .navbar-nav .nav-link .fa, .navbar-light .navbar-nav .nav-link .fas, .navbar-light .navbar-nav .nav-link .far, .navbar-light .navbar-nav .nav-link .fab { color: var(--black); } @@ -148,10 +144,14 @@ blockquote a { .sidebar { - border-radius: 6px; - margin-top: 6px; + border-radius: 6px; + margin-top: 6px; } h5.post-title a:visited { color: #949494 !important; } + +.comment-actions > * { + color: var(--gray-500); +} diff --git a/files/assets/css/awards.css b/files/assets/css/awards.css index a98860993..33d25e52c 100644 --- a/files/assets/css/awards.css +++ b/files/assets/css/awards.css @@ -32,7 +32,7 @@ .ricardo img { max-height: 15rem !important; - max-height: min(30vw,15rem) !important; + max-height: min(30vw,15rem) !important; } .ricardoleft { diff --git a/files/assets/css/catalog.css b/files/assets/css/catalog.css index 4e04f069e..60964d344 100644 --- a/files/assets/css/catalog.css +++ b/files/assets/css/catalog.css @@ -1,70 +1,70 @@ #posts { - display: grid; - grid-template: auto / auto auto auto; + display: grid; + grid-template: auto / auto auto auto; } @media (min-width: 1668px) { - #frontpage .post-img { - height:105px; - width:150px; - } + #frontpage .post-img { + height:105px; + width:150px; + } - #frontpage .post-title { - font-size: 18px; - } + #frontpage .post-title { + font-size: 18px; + } - #frontpage .post-meta, #frontpage .post-actions { - font-size:14px; - } + #frontpage .post-meta, .post-actions button, .post-actions a { + font-size:14px; + } } @media (max-width: 960px) { - #posts { - display: grid; - grid-template: auto / auto auto; - } + #posts { + display: grid; + grid-template: auto / auto auto; + } } @media (max-width: 768px) { - #posts { - display: grid; - grid-template: auto / auto; - } + #posts { + display: grid; + grid-template: auto / auto; + } } #frontpage .sidebar { - display:none !important; + display:none !important; } #frontpage .container { - max-width: 1750px; + max-width: 1750px; } #frontpage .voting.d-md-flex { - display: none !important; + display: none !important; } #frontpage .voting.d-md-none { - display: block !important; + display: block !important; } #frontpage .card-footer { - display: block !important; + display: block !important; } #frontpage .post-actions.d-md-block { - display: none !important; + display: none !important; } #fronpage.card { - padding: 0.5rem !important; + padding: 0.5rem !important; } #frontpage .modal.d-md-none.show { - display: inline-block !important; - max-width: 30rem; + display: inline-block !important; + max-width: 30rem; } #frontpage .fa-expand-alt { - display:none; + display:none; } diff --git a/files/assets/css/classic_dark.css b/files/assets/css/classic_dark.css index 885ed7c2c..84000507c 100644 --- a/files/assets/css/classic_dark.css +++ b/files/assets/css/classic_dark.css @@ -1,7 +1,7 @@ @import 'classic.css?v=4031'; :root { - --muted: #999; - --black: #999; - --bgc: #222; + --muted: #999; + --black: #999; + --bgc: #222; } diff --git a/files/assets/css/coffee.css b/files/assets/css/coffee.css index 6c598cf8d..fded876ba 100644 --- a/files/assets/css/coffee.css +++ b/files/assets/css/coffee.css @@ -66,10 +66,6 @@ blockquote { color: var(--black) !important; } -.modal .comment-actions a { - color: var(--gray-200); -} - .navbar-light .navbar-nav .nav-link .fa, .navbar-light .navbar-nav .nav-link .fas, .navbar-light .navbar-nav .nav-link .far, .navbar-light .navbar-nav .nav-link .fab { color: var(--black); } @@ -100,10 +96,14 @@ blockquote { .sidebar { - border-radius: 6px; - margin-top: 6px; + border-radius: 6px; + margin-top: 6px; } h5.post-title a:visited { color: #949494 !important; } + +.comment-actions > * { + color: var(--gray-200); +} diff --git a/files/assets/css/dark.css b/files/assets/css/dark.css index 6f72727a1..873de18f3 100644 --- a/files/assets/css/dark.css +++ b/files/assets/css/dark.css @@ -71,12 +71,12 @@ pre { .sidebar { - border-radius: 6px; - margin-top: 6px; + border-radius: 6px; + margin-top: 6px; } .modal-content { - background-color: var(--gray-900); + background-color: var(--gray-900); } .modal .comment-actions .list-group-item { @@ -97,5 +97,5 @@ h5.post-title a:visited { } .empty-state-img { - filter: brightness(99); + filter: brightness(99); } diff --git a/files/assets/css/dramblr.css b/files/assets/css/dramblr.css index 7e5b0d86b..39f3725a5 100644 --- a/files/assets/css/dramblr.css +++ b/files/assets/css/dramblr.css @@ -135,7 +135,7 @@ color: var(--gray-700); .post-title { - color: var(--gray-300) !important; + color: var(--gray-300) !important; } .tooltip-inner { diff --git a/files/assets/css/fontawesome.css b/files/assets/css/fontawesome.css index 0fd8eab49..3afb58b92 100644 --- a/files/assets/css/fontawesome.css +++ b/files/assets/css/fontawesome.css @@ -363,3 +363,4 @@ .fa-landscape:before{content:"\e1b5"} .fa-user-ninja:before{content:"\f504"} .fa-club:before{content:"\f327"} +.fa-shirt:before{content:"\f553"} diff --git a/files/assets/css/main-dev.css b/files/assets/css/main-dev.css index f17cd9aa1..5957d56a0 100644 --- a/files/assets/css/main-dev.css +++ b/files/assets/css/main-dev.css @@ -3,9 +3,18 @@ * Live Debootstrap * ************************************************/ +/** + * Q: WHAT!!! MY CHANGE ISNT APPLYING!!! + * A: Not all files are adapted for this main-dev.css file, + * The only known pages with these applications are login.html and sign_up.html + */ /* TODO move to html ref for compatibility */ -@import url("fontawesome.css"); +/* Commented out due to main.css */ +/* @import url("fontawesome.css"); */ + +/* TEMP */ +@import url("midnight.css"); @charset "UTF-8"; *, *::before, *::after { @@ -33,7 +42,7 @@ html, body { * make a regular link, undo these for specific areas like post content, etc */ a, a:visited, a:hover, a:active { text-decoration: none; - color: var(--primary, #000); + color: var(--primary, #805ad5); } /* Font stuff */ @@ -133,6 +142,35 @@ nav { padding-top: 0; } +#login .splash-wrapper +{ + transition: .4s; +} + +/* Make login mobile */ +@media (max-width: 800px) { + #login .splash-wrapper + { + z-index: -999; + position: absolute; + display: block; + right: 0; + top: 0; + width: 100%; + height: 100%; + filter: contrast(0.4) blur(12px) sepia(20%) saturate(180%) brightness(30%); + } + #login input + { + background-color: transparent; + } + #login h1, + #login p + { + text-align: center; + } +} + #register-form-container { display: flex; flex: 1; @@ -160,7 +198,7 @@ nav { width: 100%; height: 100%; background-color: rgba(127,127,127,.25); - background-image: linear-gradient(135deg,rgba(30,30,36,0.1) 0%,var(--primary) 150%); + background-image: linear-gradient(135deg,rgba(30,30,36,0.1) 0%,var(--primary, #805ad5) 150%); z-index: 50; } diff --git a/files/assets/css/main.css b/files/assets/css/main.css index 182353668..90a8b4c36 100644 --- a/files/assets/css/main.css +++ b/files/assets/css/main.css @@ -8,6 +8,15 @@ @import url("fontawesome.css"); @charset "UTF-8"; +button { + background: none; + border: none; + padding: 0; + margin: 0; + color: var(--primary); + text-decoration: none; + background-color: transparent; +} *, *::before, *::after { box-sizing: border-box; } @@ -221,28 +230,28 @@ template { [hidden] { display: none !important; } -h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { +h1, h2, h3, h4, h5, h6 { margin-top: 1rem; margin-bottom: 1rem; font-weight: 600; line-height: 1.2; } -h1, .h1 { +h1 { font-size: 2.5rem; } -h2, .h2 { +h2 { font-size: 2rem; } -h3, .h3 { +h3 { font-size: 1.75rem; } -h4, .h4 { +h4 { font-size: 1.5rem; } -h5, .h5 { +h5 { font-size: 1.25rem; } -h6, .h6 { +h6 { font-size: 1rem; } hr { @@ -334,7 +343,7 @@ pre code { .shadow { /* box-shadow: 0 0.1px 3px rgba(190, 113, 113, 0.05), 0 0 0 0.1px rgba(0, 0, 0, 0.05); */ - box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.4); + box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.4); } .shadow-none { box-shadow: none !important; @@ -796,14 +805,14 @@ input[type=submit].btn-follow, input[type=reset].btn-follow, input[type=button]. } @keyframes expand { - 0% { opacity: 0.0; transform: scaleY(0.7); } - 100% { opacity: 1.0; transform: scaleY(1.0); } + 0% { opacity: 0.0; transform: scaleY(0.7); } + 100% { opacity: 1.0; transform: scaleY(1.0); } } .dropdown-menu-right.show { - transform-origin: top; - animation: expand .20s 1; + transform-origin: top; + animation: expand .20s 1; } @@ -825,12 +834,12 @@ input[type=submit].btn-follow, input[type=reset].btn-follow, input[type=button]. background-clip: padding-box; border: 1px solid rgba(0, 0, 0, 0.4); border-radius: 0.35rem; - box-shadow: 0px 2px 20px rgba(0, 0, 0, 0.3); + box-shadow: 0px 2px 20px rgba(0, 0, 0, 0.3); } .dropdown-menu-right { right: 0; left: auto; - left: -2px !important; + left: -2px !important; } @media (min-width: 992px) { .dropdown-menu-lg-left { @@ -1123,11 +1132,11 @@ nav align-items: center; justify-content: space-between; padding: 0.5rem 1rem; - transition: border-bottom .2s; + transition: border-bottom .2s; } .navbar-active { - border-bottom: 1px solid rgba(18, 18, 18, .4); + border-bottom: 1px solid rgba(18, 18, 18, .4); } .navbar .container, .navbar .container-fluid { display: flex; @@ -2283,6 +2292,12 @@ a.bg-light:hover, a.bg-light:focus, button.bg-light:hover, button.bg-light:focus .ml-4, .mx-4 { margin-left: 1.5rem !important; } +.mr-5, .mx-5 { + margin-right: 3rem !important; +} +.ml-5, .mx-5 { + margin-left: 3rem !important; +} .mt-5, .my-5 { margin-top: 3rem !important; } @@ -3065,7 +3080,7 @@ label.terms { padding: 0.5rem 1rem; border-radius: 0.35rem; color: var(--black); - transition: background .1s, transform .2s; + transition: background .1s, transform .2s; } .dropdown-item:hover, .dropdown-item:focus, .dropdown-item.active { color: var(--black); @@ -3073,7 +3088,7 @@ label.terms { background-color: var(--gray-300); } .dropdown-item:active { - transform: scale(0.95); + transform: scale(0.95); } @@ -3128,7 +3143,7 @@ small, .small { .active-anim.arrow-up::before { - color: var(--primary); + color: var(--primary); } @@ -3147,78 +3162,78 @@ small, .small { } .arrow-up, .arrow-down { - position: relative; - display: inline-block; + position: relative; + display: inline-block; } .arrow-up.active-anim { - animation: bounce-top .7s 1 0s; - -webkit-animation: bounce-top .7s 1 0s; + animation: bounce-top .7s 1 0s; + -webkit-animation: bounce-top .7s 1 0s; } .arrow-down.active-anim { - animation: bounce-bot .7s 1 0s; - -webkit-animation: bounce-bot .7s 1 0s; + animation: bounce-bot .7s 1 0s; + -webkit-animation: bounce-bot .7s 1 0s; } @keyframes bounce-top { - 20% { - transform: translateY(-9px); - animation-timing-function: ease-in; - opacity: 1; - } - 52% { - transform: translateY(-6px); - animation-timing-function: ease-in; - opacity: 1; - } - 69% { - transform: translateY(-3px); - animation-timing-function: ease-in; - opacity: 1; - } - 35%, - 63%, - 79%, - 100% { - transform: translateY(0px); - animation-timing-function: ease-out; - } + 20% { + transform: translateY(-9px); + animation-timing-function: ease-in; + opacity: 1; + } + 52% { + transform: translateY(-6px); + animation-timing-function: ease-in; + opacity: 1; + } + 69% { + transform: translateY(-3px); + animation-timing-function: ease-in; + opacity: 1; + } + 35%, + 63%, + 79%, + 100% { + transform: translateY(0px); + animation-timing-function: ease-out; + } } @keyframes bounce-bot { - 30% { - transform: translateY(6px); - animation-timing-function: ease-in; - opacity: 1; - } - 52% { - transform: translateY(3px); - animation-timing-function: ease-in; - opacity: 1; - } - 69% { - transform: translateY(2px); - animation-timing-function: ease-in; - opacity: 1; - } - 100% { - transform: translateY(0px); - animation-timing-function: ease-out; - } + 30% { + transform: translateY(6px); + animation-timing-function: ease-in; + opacity: 1; + } + 52% { + transform: translateY(3px); + animation-timing-function: ease-in; + opacity: 1; + } + 69% { + transform: translateY(2px); + animation-timing-function: ease-in; + opacity: 1; + } + 100% { + transform: translateY(0px); + animation-timing-function: ease-out; + } } .comment-write.collapsed { - animation: expand-reply .3s 1; + animation: expand-reply .3s 1; } @keyframes expand-reply { - 0% { opacity: .6; padding-top: 0px; height: 0px; overflow: hidden; } - 100% { opacity: 1;padding-top: 0px; height: 182px; overflow: hidden; } + 0% { opacity: .6; padding-top: 0px; height: 0px; overflow: hidden; } + 100% { opacity: 1;padding-top: 0px; height: 182px; overflow: hidden; } } .active.arrow-down::before { @@ -3255,7 +3270,7 @@ small, .small { } .score-up-anim { - color: var(--primary); + color: var(--primary); } .score-down { color: #38B2AC !important; @@ -3266,13 +3281,13 @@ small, .small { .voting .arrow-up, .voting .arrow-down { - display: block; + display: block; } .catalog .voting .arrow-up, .catalog .voting .arrow-down { - display: inline-block; + display: inline-block; } @@ -3588,23 +3603,14 @@ small, .small { .modal .post-actions .list-group-item:focus, .modal .post-actions .list-group-item:hover { background-color: var(--gray-300); } -.modal .post-actions a, .post-actions button { - color: var(--black); - font-size: 1rem; -} .modal .post-actions .fa, .modal .post-actions .fas, .modal .post-actions .far { width: 1.25rem; font-size: 1rem; } -.post-actions { - position: relative; - color: var(--muted); - font-weight: 600; - font-size: 12px; -} .post-actions .fa, .post-actions .fas, .post-actions .far { font-size: 12px; margin-right: 0.5rem; + margin-left: 0.5rem; width: 1rem; } .post-actions .voting .fa, .post-actions .voting .fas, .post-actions .voting .far { @@ -3616,9 +3622,6 @@ small, .small { .post-actions .dropdown-item:hover .fa, .post-actions .dropdown-item:hover .fas { color: var(--gray); } -.post-actions a, .post-actions button:hover .fa, .post-actions a, .post-actions button:hover .fas { - color: var(--black); -} .post-actions:hover, .post-actions:focus { z-index: 4; } @@ -3724,10 +3727,12 @@ small, .small { } .post-actions a, .post-actions button { color: var(--gray-100); + font-weight: 600; + font-size: 12px; text-decoration: none; text-transform: none; } -.post-actions a, .post-actions button:hover { +.post-actions a:hover, .post-actions button:hover { color: var(--black); } .post-actions .dropdown-item:hover { @@ -3805,10 +3810,6 @@ small, .small { .modal .comment-actions .list-group-item:focus, .modal .comment-actions .list-group-item:hover { background-color: var(--gray-300) !important; } -.modal .comment-actions a { - color: var(--gray-100); - font-size: 1rem; -} .modal .comment-actions .fa, .modal .comment-actions .fas, .modal .comment-actions .far { width: 1.25rem; font-size: 1rem; @@ -3842,9 +3843,6 @@ small, .small { .comment-actions .dropdown-item:hover .fa, .comment-actions .dropdown-item:hover .fas, .comment-actions .dropdown-item:hover .far { color: var(--black); } -.comment-actions a:hover .fa, .comment-actions a:hover .fas, .comment-actions a:hover .far { - color: var(--black); -} .comment-actions .fas.fa-ellipsis-h { font-size: 1.25rem; vertical-align: bottom; @@ -3864,13 +3862,6 @@ small, .small { .comment-actions .list-inline .list-inline-item .dropdown-item:active { color: var(--black); } -.comment-actions a { - color: var(--gray-100); - text-decoration: none; -} -.comment-actions a:hover, .comment-actions .copy-link:hover { - color: var(--black); -} .comment-actions .dropdown-item:hover { color: var(--black); } @@ -4225,9 +4216,9 @@ pre .com, code .com { -ms-transition: all 0.15s ease; transition: all 0.15s ease; width: 25vw; - height: 35vh; + height: 35vh; -o-object-fit: contain; - object-fit: contain; + object-fit: contain; } @media (max-width: 767.98px) { .gif-categories img { @@ -4262,7 +4253,7 @@ pre .com, code .com { } .modal-backdrop.show { - background-color: rgba(33, 38, 45, .8); + background-color: rgba(33, 38, 45, .8); } @media (max-width: 767.98px) { @@ -4383,13 +4374,6 @@ pre .com, code .com { .post-meta { font-size: 1rem; padding-left: 3px; -} - .post-actions { - font-weight: 400; -} - .post-actions a, .post-actions button { - font-size: 1rem; - color: var(--gray-200); } .post-actions .fa, .post-actions .fas, .post-actions .far { font-size: 1rem; @@ -4401,13 +4385,13 @@ pre .com, code .com { font-size: 1.5rem; color: var(--gray-200); opacity: 1; - } - #voting .arrow-up, - .voting .arrow-up, - .voting .arrow-down - { - display: inline-block; - } + } + #voting .arrow-up, + .voting .arrow-up, + .voting .arrow-down + { + display: inline-block; + } .active.arrow-up::before, .active.arrow-up:hover::before { color: var(--primary); @@ -4844,30 +4828,30 @@ input[type=radio] ~ .custom-control-label::before { } span[data-bs-toggle], .pat-preview { - position: relative; - display: inline-block; + position: relative; + display: inline-block; } img[src="/i/hand.webp"] { - position: absolute; - width: 90%; - height: 90%; - margin-top: -10%; - z-index: 1; + position: absolute; + width: 90%; + height: 90%; + margin-top: -10%; + z-index: 1; } img[src="/i/hand.webp"]+img { - animation: pat-pfp-anim 0.3s infinite; - transform-origin: bottom center; - margin-top: 10%; - text-align: center; - object-fit: cover; + animation: pat-pfp-anim 0.3s infinite; + transform-origin: bottom center; + margin-top: 10%; + text-align: center; + object-fit: contain; } img[src="/i/hand.webp"]+img[src^="/pp/"], img[src="/i/hand.webp"]+img[src$="/pic"] { border-radius: 50%; } @keyframes pat-pfp-anim { - 0% { transform: scale(1, 0.8) } - 50% { transform: scale(0.8, 1) } - 100% { transform: scale(1, 0.8) } + 0% { transform: scale(1, 0.8) } + 50% { transform: scale(0.8, 1) } + 100% { transform: scale(1, 0.8) } } /* Fix for
    being populated with
  1. in many contexts. */ @@ -5059,28 +5043,25 @@ img[glow]:not([data-src]) { display: none; } -.awards-wrapper a { +.awards-wrapper > div { cursor: pointer; padding: 15px !important; text-align: center; text-transform: none!important; } -.awards-wrapper a i { +.awards-wrapper > div > i { font-size: 25px; } -.awards-wrapper a.disabled { +.awards-wrapper > div.disabled { opacity: 0.6; } -.awards-wrapper a:hover:not(.disabled), .awards-wrapper .picked { +.awards-wrapper > div:hover:not(.disabled), .awards-wrapper .picked { background-color: var(--primary)!important; } -.awards-wrapper input[type="radio"]:checked+a { - background-color: var(--primary)!important; -} .award-columns { column-count: 2; @@ -5215,7 +5196,7 @@ a.emojitab { .expandedimage { width: fit-content; width: -moz-fit-content; - max-width: 100% !important; + max-width: 80% !important; } .m-5 { @@ -5236,8 +5217,8 @@ li > .sidebar { .sidebar { - border-radius: 6px; - margin-top: 6px; + border-radius: 6px; + margin-top: 6px; } @@ -5330,20 +5311,20 @@ th, td { } .glow .post-title, .glow a, .glow .post-meta *, .glow .user-info *, .glow .comment-text, .glow .comment-actions *, .glow { - color:lightgreen !important; - text-shadow:1px 1px 1px darkgreen, 0 0 5px green; + color:lightgreen !important; + text-shadow:1px 1px 1px darkgreen, 0 0 5px green; } .glow .score-up, .glow .active.arrow-up::before, .glow .arrow-up::after, .glow .arrow-up:hover::before { - color: lime !important; + color: lime !important; } .glow .score-down, .glow .active.arrow-down::before, .glow .arrow-down::after, .glow .arrow-down:hover::before { - color: lime !important; + color: lime !important; } .glow .arrow-up::before, .glow .arrow-down::before, .glow .score { - color: lightgreen; + color: lightgreen; } .glow .post-body a, .glow .comment-text a { @@ -5493,14 +5474,14 @@ audio, video { .lottery-page--wrapper { flex-direction: column; justify-content: center; - padding: 2rem; + padding: 2rem; } - .lottery-page--wrapper > div - { - width: 300px; - height: 300px; - } + .lottery-page--wrapper > div + { + width: 300px; + height: 300px; + } .lottery-page--action { margin-bottom: 1rem; @@ -5672,17 +5653,16 @@ g { } .ext-link { - position:absolute; - bottom: 0; - right: 0; - font-size:14px; - color:white; - background-color:var(--primary); - padding:3px; - border-radius:.35rem; + position:absolute; + bottom: 0; + right: 0; + font-size:14px; + color:white; + background-color:var(--primary); + padding:3px; + border-radius:.35rem; } - .pronouns { font-size: 9px; margin-left: 0.25rem; @@ -5701,8 +5681,8 @@ g { .post-preview { padding: 11px 14px 0 14px !important; - margin-bottom: 0.5rem !important; - margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + margin-top: 0.5rem !important; } @@ -5713,7 +5693,7 @@ g { } .showmore { - width: 99%; + width: 99%; padding: 5px; margin: 5px 1px; border-radius: 5px; @@ -5722,7 +5702,7 @@ g { background: -webkit-linear-gradient(left, red, orange, yellow, green, blue, indigo, violet ); text-shadow:-1px -1px 0 black,1px -1px 0 black,-1px 1px 0 black,1px 1px 0 black; font-weight: 600; - border: 2px solid var(--primary); + border: 2px solid var(--primary); font-size: 20px; } @@ -5746,74 +5726,68 @@ g { opacity: 0.65; } -@media (max-width: 767.98px) { - .post-actions { - margin-top: -5px; - } -} - .ghostdiv { - display: block; - white-space: pre-wrap; - word-break: break-word; - /* Attempt to copy the textarea/input padding */ - padding: 15px; + display: block; + white-space: pre-wrap; + word-break: break-word; + /* Attempt to copy the textarea/input padding */ + padding: 15px; } #speed-carot-modal { - background-color: var(--gray-700); - max-height: 500px; - overflow-y: auto; - overflow-x: hidden; - border-radius: 4px; - border: 1px solid rgba(255, 255, 255, 0.3); - box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); + background-color: var(--gray-700); + max-height: 500px; + overflow-y: auto; + overflow-x: hidden; + border-radius: 4px; + border: 1px solid rgba(255, 255, 255, 0.3); + box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.2); z-index:999; } #speed-carot-modal .speed-modal-option { - border-bottom: 1px solid #606060; - padding: 4px; - cursor: pointer; + border-bottom: 1px solid #606060; + padding: 4px; + cursor: pointer; } #speed-carot-modal .speed-modal-option:hover, #speed-carot-modal .speed-modal-option:focus, #speed-carot-modal .speed-modal-option.selected { - background-color: rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0.2); } #speed-carot-modal .speed-modal-image { - object-fit: contain; - width: 30px; - height: 30px; + object-fit: contain; + width: 30px; + height: 30px; } #speed-carot-modal .speed-modal-option span { - overflow: hidden; - display: inline-block; - vertical-align: middle; - margin-left: 10px; - margin-right: 10px; + overflow: hidden; + display: inline-block; + vertical-align: middle; + margin-left: 10px; + margin-right: 10px; } .rainbow-text:not(a) { - background-image: repeating-linear-gradient(135deg, violet, rgb(178, 94, 238), lightblue, green, yellow, orange, #ff7f7f 50%) !important; - color: transparent !important; - background-clip: text !important; - -webkit-background-clip: text !important; - font-weight: 700 !important; + background-image: repeating-linear-gradient(135deg, violet, rgb(178, 94, 238), lightblue, green, yellow, orange, #ff7f7f 50%) !important; + color: transparent !important; + background-clip: text !important; + -webkit-background-clip: text !important; + font-weight: 700 !important; } .rainbow-text:not(a) > p { - color: transparent !important; + color: transparent !important; } .btn-rainbow { @@ -5823,10 +5797,6 @@ g { text-shadow:-1px -1px 0 black,1px -1px 0 black,-1px 1px 0 black,1px 1px 0 black !important; } -.modal .comment-actions a { - font-weight: 600; -} - div.custom-control:last-of-type { margin-bottom: 1rem; } @@ -5877,7 +5847,7 @@ blockquote + blockquote, div > blockquote:first-child, blockquote:last-child { #searchparams-dropdown { - z-index: 100; + z-index: 1; } .contain { -o-object-fit: contain; @@ -5888,7 +5858,7 @@ blockquote + blockquote, div > blockquote:first-child, blockquote:last-child { } div.markdown { height: auto; - white-space: pre-wrap; + white-space: pre-wrap; } @media (max-width: 768px) or (min-width: 992px) { #sidebar-btn { @@ -5905,11 +5875,11 @@ div.markdown { } .directory--link:hover * { - color: var(--primary) !important; + color: var(--primary) !important; } ::-webkit-input-placeholder { - opacity: 0.7 !important; + opacity: 0.7 !important; } .text-brown { @@ -5937,9 +5907,6 @@ div.markdown { } @media (min-width: 768px) { - .expandedimage { - max-width: 80% !important; - } #speed-carot-modal .speed-modal-image { width: 50px; @@ -5949,3 +5916,37 @@ div.markdown { max-width: 90% !important } } + +.d-block { + display: block !important; +} + +.popover-bio-div { + max-height: 50vh !important; + overflow: auto; + scrollbar-width: none; + -ms-overflow-style: none; +} + +.popover-bio-div::-webkit-scrollbar { + background: transparent; +} + +@media (max-width: 768px) { + .d-mob-none { + display: none !important; + } +} + +.comment-actions > * { + color: var(--gray-100); + text-decoration: none; + text-align: left; + margin-bottom: 2px; + font-size: 1rem; + font-weight: 600; +} + +.comment-actions *:hover { + color: var(--black); +} diff --git a/files/assets/css/midnight.css b/files/assets/css/midnight.css index 49ec6a5ba..b73a145db 100644 --- a/files/assets/css/midnight.css +++ b/files/assets/css/midnight.css @@ -46,8 +46,8 @@ body, .navbar-light, .navbar-dark, .card, .modal-content, .comment-write textare .sidebar { - border-radius: 6px; - margin-top: 6px; + border-radius: 6px; + margin-top: 6px; } .table th, .table td { diff --git a/files/assets/css/rDrama.css b/files/assets/css/rDrama.css new file mode 100644 index 000000000..dfde27d55 --- /dev/null +++ b/files/assets/css/rDrama.css @@ -0,0 +1,7 @@ +.mod:before { + content: '((('; +} + +.mod:after { + content: ')))'; +} diff --git a/files/assets/css/tron.css b/files/assets/css/tron.css index 5021cc0a4..c1e8baa31 100644 --- a/files/assets/css/tron.css +++ b/files/assets/css/tron.css @@ -221,8 +221,8 @@ .sidebar { - border-radius: 6px; - margin-top: 6px; + border-radius: 6px; + margin-top: 6px; } .tooltip-inner { diff --git a/files/assets/css/win98.css b/files/assets/css/win98.css index 2faf7424c..af4dd5646 100644 --- a/files/assets/css/win98.css +++ b/files/assets/css/win98.css @@ -131,10 +131,6 @@ blockquote { color: var(--muted) !important; } -.modal-header, .modal .comment-actions a, .modal-title { - color: var(--white) !important; -} - .text-info { color: var(--primary) !important; @@ -162,10 +158,14 @@ blockquote { .sidebar { - border-radius: 0px; - margin-top: 6px; + border-radius: 0px; + margin-top: 6px; } h5.post-title a:visited { color: #5c5c5c !important; } + +.comment-actions > * { + color: var(--white); +} diff --git a/files/assets/emojis.json b/files/assets/emojis.json index 8b79bbc61..f6c39a2ee 100644 --- a/files/assets/emojis.json +++ b/files/assets/emojis.json @@ -35,6 +35,9 @@ {"name":"7","class":"Marsey Alphabet"}, {"name":"8","class":"Marsey Alphabet"}, {"name":"9","class":"Marsey Alphabet"}, + {"name":"ialt","class":"Marsey Alphabet"}, + {"name":"0alt","class":"Marsey Alphabet"}, + {"name":"ccedilla","class":"Marsey Alphabet"}, {"name":"space","class":"Marsey Alphabet"}, {"name":"comma","class":"Marsey Alphabet","tags": [","]}, {"name":"period","class":"Marsey Alphabet","tags": [".","dot"]}, @@ -42,7 +45,10 @@ {"name":"exclamationpoint","class":"Marsey Alphabet","tags": ["!"]}, {"name":"at","class":"Marsey Alphabet","tags": ["@"]}, {"name":"pound","class":"Marsey Alphabet","tags": ["#","hashtag","octothorpe"]}, + {"name":"percent","class":"Marsey Alphabet","tags": ["%"]}, + {"name":"caret","class":"Marsey Alphabet","tags":["^"]}, {"name":"ampersand","class":"Marsey Alphabet","tags": ["&","and"]}, + {"name":"asterisk","class":"Marsey Alphabet","tags": ["*","times"]}, {"name":"paren","class":"Marsey Alphabet","tags": ["(",")"]}, {"name":"brace", "class":"Marsey Alphabet", "tags": ["{","}","curly","bracket"]}, {"name":"equals","class":"Marsey Alphabet","tags": ["="]}, @@ -54,7 +60,9 @@ {"name":"emdash","class":"Marsey Alphabet","tags": ["-","—"]}, {"name":"underscore","class":"Marsey Alphabet","tags": ["_"]}, {"name":"colon", "class":"Marsey Alphabet", "tags": [":"]}, - {"name":"slash","class":"Marsey Alphabet","tags": ["/","\\"]}, + {"name":"apostrophe","class":"Marsey Alphabet","tags":["'"]}, + {"name":"quotation","class":"Marsey Alphabet","tags":["\""]}, + {"name":"slash","class":"Marsey Alphabet","tags": ["/","\\","division"]}, {"name":"vert", "class":"Marsey Alphabet", "tags": ["|","pipe","vbar","bar"]}, {"name":"tilde", "class":"Marsey Alphabet", "tags": ["~","similar","approx"]}, {"name":"angle","class":"Marsey Alphabet","tags": ["<",">","gt","lt"]}, @@ -125,17 +133,12 @@ {"name":"oplus", "class":"Marsey Alphabet", "tags": ["⊕","xor","circled","sum"]}, {"name":"otimes", "class":"Marsey Alphabet", "tags": ["⊗","tensor","circled","product"]}, {"name":"trianglelefteq", "class":"Marsey Alphabet", "tags": ["⊴"]}, - - {"name":"marseyflagarmenia","class":"Marsey Flags"}, - {"name":"marseyflagelsalvador","class":"Marsey Flags"}, + {"name":"marseyflagmaryland","class":"Marsey Flags"}, + {"name":"marseyflagcalifornia","class":"Marsey Flags"}, {"name":"marseyflagtexas","class":"Marsey Flags"}, - {"name":"marseyflagtuvalu","class":"Marsey Flags"}, - {"name":"marseyflagvatican","class":"Marsey Flags"}, + {"name":"marseyflageu","class":"Marsey Flags"}, {"name":"marseyflagafrica","class":"Marsey Flags"}, - {"name":"marseyflagbahamas","class":"Marsey Flags"}, - {"name":"marseyflagbahrain","class":"Marsey Flags"}, - {"name":"marseyflagbarbados","class":"Marsey Flags"}, {"name":"marseyflagafghanistan","class":"Marsey Flags"}, {"name":"marseyflagalbania","class":"Marsey Flags"}, {"name":"marseyflagalgeria","class":"Marsey Flags"}, @@ -144,10 +147,14 @@ {"name":"marseyflagantarctica","class":"Marsey Flags"}, {"name":"marseyflagantiguaandbarbuda","class":"Marsey Flags"}, {"name":"marseyflagargentina","class":"Marsey Flags"}, + {"name":"marseyflagarmenia","class":"Marsey Flags"}, {"name":"marseyflagaustralia","class":"Marsey Flags"}, {"name":"marseyflagaustria","class":"Marsey Flags"}, {"name":"marseyflagazerbaijan","class":"Marsey Flags"}, + {"name":"marseyflagbahamas","class":"Marsey Flags"}, + {"name":"marseyflagbahrain","class":"Marsey Flags"}, {"name":"marseyflagbangladesh","class":"Marsey Flags"}, + {"name":"marseyflagbarbados","class":"Marsey Flags"}, {"name":"marseyflagbelarus","class":"Marsey Flags"}, {"name":"marseyflagbelgium","class":"Marsey Flags"}, {"name":"marseyflagbosnia","class":"Marsey Flags"}, @@ -160,6 +167,7 @@ {"name":"marseyflagcyprus","class":"Marsey Flags"}, {"name":"marseyflagdenmark","class":"Marsey Flags"}, {"name":"marseyflagegypt","class":"Marsey Flags"}, + {"name":"marseyflagelsalvador","class":"Marsey Flags"}, {"name":"marseyflagestonia","class":"Marsey Flags"}, {"name":"marseyflagfinland","class":"Marsey Flags"}, {"name":"marseyflagfrance","class":"Marsey Flags"}, @@ -186,6 +194,7 @@ {"name":"marseyflagnorthkorea","class":"Marsey Flags"}, {"name":"marseyflagnorway","class":"Marsey Flags"}, {"name":"marseyflagpakistan","class":"Marsey Flags"}, + {"name":"marseyflagpalau","class":"Marsey Flags"}, {"name":"marseyflagpalestine","class":"Marsey Flags"}, {"name":"marseyflagperu","class":"Marsey Flags"}, {"name":"marseyflagphillipines","class":"Marsey Flags"}, @@ -206,10 +215,12 @@ {"name":"marseyflagtajikistan","class":"Marsey Flags"}, {"name":"marseyflagthailand","class":"Marsey Flags"}, {"name":"marseyflagturkey","class":"Marsey Flags"}, + {"name":"marseyflagtuvalu","class":"Marsey Flags"}, {"name":"marseyflaguae","class":"Marsey Flags"}, {"name":"marseyflaguk","class":"Marsey Flags"}, {"name":"marseyflagukraine","class":"Marsey Flags"}, {"name":"marseyflagus","class":"Marsey Flags"}, + {"name":"marseyflagvatican","class":"Marsey Flags"}, {"name":"marseyflagvietnam","class":"Marsey Flags"}, {"name":"patyl","class":"Platy","tags":["quper","platypus","mersya","wombiezolf","doodle"]}, @@ -547,6 +558,8 @@ {"name":"threesome","class":"Classic"}, {"name":"throw","class":"Classic"}, {"name":"throwaway","class":"Classic"}, + {"name":"thumbup","class":"Classic"}, + {"name":"thumbdown","class":"Classic"}, {"name":"tickle","class":"Classic"}, {"name":"typing","class":"Classic"}, {"name":"uhuh","class":"Classic"}, @@ -638,6 +651,9 @@ {"name":"truestorybro","class":"Rage"}, {"name":"xallthey","class":"Rage"}, {"name":"yuno","class":"Rage"}, + {"name":"antichrist","class":"Rage"}, + {"name":"antichristfffuuuu","class":"Rage"}, + {"name":"bluehelmet","class":"Rage"}, {"name":"afroblackjak","class":"Wojak"}, {"name":"altgirlblackjack","class":"Wojak"}, @@ -719,6 +735,7 @@ {"name":"chadlatino","tags": ["latinx"],"class":"Wojak"}, {"name":"chadlibleft","tags": ["libleft"],"class":"Wojak"}, {"name":"chadnordic","tags": ["nordic", "nazi"],"class":"Wojak"}, + {"name":"chadmediterranean","class":"Wojak"}, {"name":"chadsikh","tags": ["sikh", "indian"],"class":"Wojak"}, {"name":"chadusa","tags": ["usa", "america", "freedom"],"class":"Wojak"}, {"name":"chadsoy","class":"Wojak","tags": ["soy"]}, @@ -738,6 +755,14 @@ {"name":"npc","class":"Wojak"}, {"name":"npcfront","class":"Wojak"}, {"name":"npcmaga","class":"Wojak"}, + {"name":"chadbaby","class":"Wojak"}, + {"name":"chadstalin","class":"Wojak"}, + {"name":"chudette","class":"Wojak"}, + {"name":"chudgrug","class":"Wojak"}, + {"name":"chudnazi","class":"Wojak"}, + {"name":"chudsmug","class":"Wojak"}, + {"name":"soy4dchess","class":"Wojak"}, + {"name":"soyjaktantrum","class":"Wojak"}, {"name":"psychojak","class":"Wojak"}, {"name":"ragejak","tags": ["mad"],"class":"Wojak"}, {"name":"ragemask","tags": ["mad"],"class":"Wojak"}, @@ -751,6 +776,29 @@ {"name":"tomboy","tags": ["trans"],"class":"Wojak"}, {"name":"zoomer","class":"Wojak"}, {"name":"zoomersoy","tags": ["soyjak"],"class":"Wojak"}, + {"name":"asianenbyjak","class":"Wojak"}, + {"name":"asiangirl","class":"Wojak"}, + {"name":"asiantwinkjak","class":"Wojak"}, + {"name":"bobateagirl","class":"Wojak"}, + {"name":"chadasian2","class":"Wojak"}, + {"name":"chadindianheadset","class":"Wojak"}, + {"name":"chinesenobleman","class":"Wojak"}, + {"name":"chinesepolitician","class":"Wojak"}, + {"name":"chinesesoldierjak","class":"Wojak"}, + {"name":"greendesigirl","class":"Wojak"}, + {"name":"imperialjapanesesoldier","class":"Wojak"}, + {"name":"indiandoomergirl","class":"Wojak"}, + {"name":"kimjojongjak","class":"Wojak"}, + {"name":"kimonogirl","class":"Wojak"}, + {"name":"maojak","class":"Wojak"}, + {"name":"mongoljak","class":"Wojak"}, + {"name":"scaryasianwife","class":"Wojak"}, + {"name":"shorthairasiangirl","class":"Wojak"}, + {"name":"singaporeansoldierjak","class":"Wojak"}, + {"name":"suprisedasianwife","class":"Wojak"}, + {"name":"tiawanesesoldierjak","class":"Wojak"}, + {"name":"witheredricefarmer","class":"Wojak"}, + {"name":"yakuzajak","class":"Wojak"}, {"name":"russia","class":"Flags"}, {"name":"niger","class":"Flags"}, @@ -778,12 +826,41 @@ {"name":"sharkylove","class":"Sets"}, {"name":"sharkysad","class":"Sets"}, {"name":"sharkythink","class":"Sets"}, + {"name":"sharkymegalodon","class":"Sets"}, + {"name":"sharkydinosaur","class":"Sets"}, {"name":"tracenote","class":"Sets"}, {"name":"tracelove","class":"Sets"}, {"name":"traceberk","class":"Sets"}, {"name":"tracesmug","class":"Sets"}, {"name":"tracemad","class":"Sets"}, {"name":"tracesad","class":"Sets"}, + {"name":"parrot","class":"Sets"}, + {"name":"parrotaccessible","class":"Sets"}, + {"name":"parrotcongaparty","class":"Sets"}, + {"name":"parrotcop","class":"Sets"}, + {"name":"parrotevil","class":"Sets"}, + {"name":"parrotgithub","class":"Sets"}, + {"name":"parrothmm","class":"Sets"}, + {"name":"parrothypno","class":"Sets"}, + {"name":"parrotimposter","class":"Sets"}, + {"name":"parrotisrael","class":"Sets"}, + {"name":"parrotkazakhstan","class":"Sets"}, + {"name":"parrotmergetrain","class":"Sets"}, + {"name":"parrotmoonwalking","class":"Sets"}, + {"name":"parrotportalblue","class":"Sets"}, + {"name":"parrotportalorange","class":"Sets"}, + {"name":"parrotpumpkin","class":"Sets"}, + {"name":"parrotrevolution","class":"Sets"}, + {"name":"parrotrip","class":"Sets"}, + {"name":"parrotscience","class":"Sets"}, + {"name":"parrotshort","class":"Sets"}, + {"name":"parrotsleeping","class":"Sets"}, + {"name":"parrotslow","class":"Sets"}, + {"name":"parrottrans","class":"Sets"}, + {"name":"parrotultrafast","class":"Sets"}, + {"name":"parrotunitedstatesofamerica","class":"Sets"}, + {"name":"parrotwitnessprotection","class":"Sets"}, + {"name":"parrotzombie","class":"Sets"}, {"name":"grillcastyes", "tags":["podcast", "chad"],"class":"Misc"}, {"name":"ivoted", "tags":["democracy", "spider"],"class":"Misc"}, @@ -805,7 +882,13 @@ {"name":"chadsneedcapy", "tags":["capy", "aevann"],"class":"Misc"}, {"name":"chadthankskingcapy", "tags":["capy", "aevann", "thanks", "king"],"class":"Misc"}, {"name":"chadthanksqueencapy", "tags":["capy", "aevann", "thanks", "queen"],"class":"Misc"}, + {"name":"chadnoproblemkingcapy","class":"Misc", "tags":["capy", "aevann", "no", "problem", "king", "np"]}, + {"name":"chadnoproblemqueencapy","class":"Misc", "tags":["capy", "aevann", "no", "problem", "queen", "np"]}, {"name":"chadstevejobs","class":"Misc"}, + {"name":"chadmusk","class":"Misc"}, + {"name":"dinoyes","class":"Misc"}, + {"name":"dinono","class":"Misc"}, + {"name":"dinoconfused","class":"Misc"}, {"name":"breadmarsey","class":"Misc"}, {"name":"breadcapy","class":"Misc"}, {"name":"marseymummified","class":"Misc"}, @@ -816,8 +899,14 @@ {"name":"snoosurprise","class":"Misc"}, {"name":"snooupvote","class":"Misc"}, {"name":"snoothumbsup","class":"Misc"}, + {"name":"brooksannoyed","tags":["darrell", "suv", "waukesha", "retard", "idiot", "annoyed", "irritated", "mask", "suit", "black"],"class":"Misc"}, + {"name":"brookslaugh","class":"Misc"}, + {"name":"brookscringe","class":"Misc"}, + {"name":"brooksjustright","class":"Misc"}, + {"name":"brookskiss","class":"Misc"}, {"name":"gimp","class":"Misc"}, {"name":"taddance","class":"Misc","tags":["terry","davis","templeos","dance"]}, + {"name":"realisticelephant","class":"Misc","tags":["terry","davis","templeos"]}, {"name":"sher","class":"Misc"}, {"name":"xdoubt","class":"Misc"}, {"name":"gigachadjesus","tags": ["chad", "jesus", "christ"],"class":"Misc"}, @@ -832,14 +921,17 @@ {"name":"deuxwaifu","class":"Misc"}, {"name":"flairlessmong","class":"Misc"}, {"name":"hardislife","class":"Misc"}, + {"name":"ben10","class":"Misc"}, {"name":"redditgigachad","tags": ["chad", "gigachad"],"class":"Misc"}, {"name":"rfybear","class":"Misc"}, {"name":"etika","class":"Misc"}, {"name":"sneed","class":"Misc"}, + {"name":"sneedcat","class":"Misc"}, {"name":"retardedchildren","class":"Misc"}, {"name":"bruh","class":"Misc"}, {"name":"autism","class":"Misc"}, {"name":"doot","class":"Misc"}, + {"name":"mussolini","class":"Misc"}, {"name":"kylieface","class":"Misc"}, {"name":"queenyes","class":"Misc"}, {"name":"wholesomeseal","class":"Misc"}, @@ -851,5 +943,15 @@ {"name":"pedobear", "class":"Misc"}, {"name":"kippy","class":"Misc"}, {"name":"onerat","class":"Misc"}, - {"name":"gunt","class":"Misc"} -] \ No newline at end of file + {"name":"bitchhaditcomin","class":"Misc"}, + {"name":"duckdance", "class":"Misc"}, + {"name":"stoning","class":"Misc"}, + {"name":"stoningpills","class":"Misc"}, + {"name":"srdinepoppy","class":"Misc"}, + {"name":"gunt","class":"Misc"}, + {"name":"sneedbuddy","class":"Misc"}, + {"name":"chuckbuddy","class":"Misc"}, + {"name":"soren","class":"Misc"}, + {"name":"upsoren","class":"Misc"}, + {"name":"downdonger","class":"Misc"} +] diff --git a/files/assets/images/PCM/banners/7.webp b/files/assets/images/PCM/banners/7.webp new file mode 100644 index 000000000..c207130e0 Binary files /dev/null and b/files/assets/images/PCM/banners/7.webp differ diff --git a/files/assets/images/PCM/banners/8.webp b/files/assets/images/PCM/banners/8.webp new file mode 100644 index 000000000..08bddc13a Binary files /dev/null and b/files/assets/images/PCM/banners/8.webp differ diff --git a/files/assets/images/PCM/patron_badges/25.webp b/files/assets/images/PCM/patron_badges/25.webp index acf5b93f1..00a2a06cc 100644 Binary files a/files/assets/images/PCM/patron_badges/25.webp and b/files/assets/images/PCM/patron_badges/25.webp differ diff --git a/files/assets/images/WPD/banners/10.webp b/files/assets/images/WPD/banners/10.webp index eb6fd54a7..913754aab 100644 Binary files a/files/assets/images/WPD/banners/10.webp and b/files/assets/images/WPD/banners/10.webp differ diff --git a/files/assets/images/WPD/banners/11.webp b/files/assets/images/WPD/banners/11.webp index 75ec1e00c..80af5f3a8 100644 Binary files a/files/assets/images/WPD/banners/11.webp and b/files/assets/images/WPD/banners/11.webp differ diff --git a/files/assets/images/WPD/banners/12.webp b/files/assets/images/WPD/banners/12.webp index 4e65ee9bd..e9acffaab 100644 Binary files a/files/assets/images/WPD/banners/12.webp and b/files/assets/images/WPD/banners/12.webp differ diff --git a/files/assets/images/WPD/banners/13.webp b/files/assets/images/WPD/banners/13.webp index d25aba8af..fc36fc08f 100644 Binary files a/files/assets/images/WPD/banners/13.webp and b/files/assets/images/WPD/banners/13.webp differ diff --git a/files/assets/images/WPD/banners/14.webp b/files/assets/images/WPD/banners/14.webp index 65adf2fef..bd4131085 100644 Binary files a/files/assets/images/WPD/banners/14.webp and b/files/assets/images/WPD/banners/14.webp differ diff --git a/files/assets/images/WPD/banners/15.webp b/files/assets/images/WPD/banners/15.webp index 7e8b84164..0898eca0a 100644 Binary files a/files/assets/images/WPD/banners/15.webp and b/files/assets/images/WPD/banners/15.webp differ diff --git a/files/assets/images/WPD/banners/18.webp b/files/assets/images/WPD/banners/18.webp index c949b0e75..89fada565 100644 Binary files a/files/assets/images/WPD/banners/18.webp and b/files/assets/images/WPD/banners/18.webp differ diff --git a/files/assets/images/WPD/banners/19.webp b/files/assets/images/WPD/banners/19.webp index 75793f56d..f2b023487 100644 Binary files a/files/assets/images/WPD/banners/19.webp and b/files/assets/images/WPD/banners/19.webp differ diff --git a/files/assets/images/WPD/banners/2.webp b/files/assets/images/WPD/banners/2.webp index da8986199..988a56df4 100644 Binary files a/files/assets/images/WPD/banners/2.webp and b/files/assets/images/WPD/banners/2.webp differ diff --git a/files/assets/images/WPD/banners/20.webp b/files/assets/images/WPD/banners/20.webp index 54c6f60ba..9221340a5 100644 Binary files a/files/assets/images/WPD/banners/20.webp and b/files/assets/images/WPD/banners/20.webp differ diff --git a/files/assets/images/WPD/banners/21.webp b/files/assets/images/WPD/banners/21.webp index a21323594..d46748ddd 100644 Binary files a/files/assets/images/WPD/banners/21.webp and b/files/assets/images/WPD/banners/21.webp differ diff --git a/files/assets/images/WPD/banners/23.webp b/files/assets/images/WPD/banners/23.webp index c373df8ce..6bac771bd 100644 Binary files a/files/assets/images/WPD/banners/23.webp and b/files/assets/images/WPD/banners/23.webp differ diff --git a/files/assets/images/WPD/banners/24.webp b/files/assets/images/WPD/banners/24.webp index b9c83d763..04bc9c9f7 100644 Binary files a/files/assets/images/WPD/banners/24.webp and b/files/assets/images/WPD/banners/24.webp differ diff --git a/files/assets/images/WPD/banners/25.webp b/files/assets/images/WPD/banners/25.webp index 57d66dfbb..a438fab7a 100644 Binary files a/files/assets/images/WPD/banners/25.webp and b/files/assets/images/WPD/banners/25.webp differ diff --git a/files/assets/images/WPD/banners/26.webp b/files/assets/images/WPD/banners/26.webp index dc2fcc9f2..6f18cf9c5 100644 Binary files a/files/assets/images/WPD/banners/26.webp and b/files/assets/images/WPD/banners/26.webp differ diff --git a/files/assets/images/WPD/banners/27.webp b/files/assets/images/WPD/banners/27.webp index 4d0c8a677..a22584c4a 100644 Binary files a/files/assets/images/WPD/banners/27.webp and b/files/assets/images/WPD/banners/27.webp differ diff --git a/files/assets/images/WPD/banners/28.webp b/files/assets/images/WPD/banners/28.webp new file mode 100644 index 000000000..c65cc59be Binary files /dev/null and b/files/assets/images/WPD/banners/28.webp differ diff --git a/files/assets/images/WPD/banners/29.webp b/files/assets/images/WPD/banners/29.webp new file mode 100644 index 000000000..9cb70a391 Binary files /dev/null and b/files/assets/images/WPD/banners/29.webp differ diff --git a/files/assets/images/WPD/banners/3.webp b/files/assets/images/WPD/banners/3.webp index 2e52958c3..0a81c7630 100644 Binary files a/files/assets/images/WPD/banners/3.webp and b/files/assets/images/WPD/banners/3.webp differ diff --git a/files/assets/images/WPD/banners/30.webp b/files/assets/images/WPD/banners/30.webp new file mode 100644 index 000000000..0a58909fa Binary files /dev/null and b/files/assets/images/WPD/banners/30.webp differ diff --git a/files/assets/images/WPD/banners/4.webp b/files/assets/images/WPD/banners/4.webp index 6f22fe174..404452865 100644 Binary files a/files/assets/images/WPD/banners/4.webp and b/files/assets/images/WPD/banners/4.webp differ diff --git a/files/assets/images/WPD/banners/5.webp b/files/assets/images/WPD/banners/5.webp index b18eb2296..074944681 100644 Binary files a/files/assets/images/WPD/banners/5.webp and b/files/assets/images/WPD/banners/5.webp differ diff --git a/files/assets/images/WPD/banners/6.webp b/files/assets/images/WPD/banners/6.webp index 975163504..94efbb3b1 100644 Binary files a/files/assets/images/WPD/banners/6.webp and b/files/assets/images/WPD/banners/6.webp differ diff --git a/files/assets/images/WPD/banners/7.webp b/files/assets/images/WPD/banners/7.webp index c818b46d8..660fc81a4 100644 Binary files a/files/assets/images/WPD/banners/7.webp and b/files/assets/images/WPD/banners/7.webp differ diff --git a/files/assets/images/WPD/banners/8.webp b/files/assets/images/WPD/banners/8.webp index 8a5f031b9..1ae158b84 100644 Binary files a/files/assets/images/WPD/banners/8.webp and b/files/assets/images/WPD/banners/8.webp differ diff --git a/files/assets/images/WPD/banners/9.webp b/files/assets/images/WPD/banners/9.webp index 30c36f050..823f4a12f 100644 Binary files a/files/assets/images/WPD/banners/9.webp and b/files/assets/images/WPD/banners/9.webp differ diff --git a/files/assets/images/WPD/sidebar/1.webp b/files/assets/images/WPD/sidebar/1.webp index fd3160f3c..1aa250a5f 100644 Binary files a/files/assets/images/WPD/sidebar/1.webp and b/files/assets/images/WPD/sidebar/1.webp differ diff --git a/files/assets/images/WPD/sidebar/10.webp b/files/assets/images/WPD/sidebar/10.webp index 45b0e0110..7c5df12b8 100644 Binary files a/files/assets/images/WPD/sidebar/10.webp and b/files/assets/images/WPD/sidebar/10.webp differ diff --git a/files/assets/images/WPD/sidebar/11.webp b/files/assets/images/WPD/sidebar/11.webp index 5f9a3a340..63908fcb1 100644 Binary files a/files/assets/images/WPD/sidebar/11.webp and b/files/assets/images/WPD/sidebar/11.webp differ diff --git a/files/assets/images/WPD/sidebar/12.webp b/files/assets/images/WPD/sidebar/12.webp index d714aa40d..b95231d6d 100644 Binary files a/files/assets/images/WPD/sidebar/12.webp and b/files/assets/images/WPD/sidebar/12.webp differ diff --git a/files/assets/images/WPD/sidebar/13.webp b/files/assets/images/WPD/sidebar/13.webp index 40404b597..922746d90 100644 Binary files a/files/assets/images/WPD/sidebar/13.webp and b/files/assets/images/WPD/sidebar/13.webp differ diff --git a/files/assets/images/WPD/sidebar/14.webp b/files/assets/images/WPD/sidebar/14.webp index 4c85f06d0..fc9339b82 100644 Binary files a/files/assets/images/WPD/sidebar/14.webp and b/files/assets/images/WPD/sidebar/14.webp differ diff --git a/files/assets/images/WPD/sidebar/15.webp b/files/assets/images/WPD/sidebar/15.webp index 0a0fde549..d910a6449 100644 Binary files a/files/assets/images/WPD/sidebar/15.webp and b/files/assets/images/WPD/sidebar/15.webp differ diff --git a/files/assets/images/WPD/sidebar/16.webp b/files/assets/images/WPD/sidebar/16.webp index c5781a155..111ae17fc 100644 Binary files a/files/assets/images/WPD/sidebar/16.webp and b/files/assets/images/WPD/sidebar/16.webp differ diff --git a/files/assets/images/WPD/sidebar/17.webp b/files/assets/images/WPD/sidebar/17.webp index 31f97ec5b..97daaba7e 100644 Binary files a/files/assets/images/WPD/sidebar/17.webp and b/files/assets/images/WPD/sidebar/17.webp differ diff --git a/files/assets/images/WPD/sidebar/18.webp b/files/assets/images/WPD/sidebar/18.webp index 266152e76..9a92736e0 100644 Binary files a/files/assets/images/WPD/sidebar/18.webp and b/files/assets/images/WPD/sidebar/18.webp differ diff --git a/files/assets/images/WPD/sidebar/19.webp b/files/assets/images/WPD/sidebar/19.webp index f84768e30..d0d1ab71b 100644 Binary files a/files/assets/images/WPD/sidebar/19.webp and b/files/assets/images/WPD/sidebar/19.webp differ diff --git a/files/assets/images/WPD/sidebar/2.webp b/files/assets/images/WPD/sidebar/2.webp index e87296f63..3114450a6 100644 Binary files a/files/assets/images/WPD/sidebar/2.webp and b/files/assets/images/WPD/sidebar/2.webp differ diff --git a/files/assets/images/WPD/sidebar/21.webp b/files/assets/images/WPD/sidebar/21.webp index fdf7f8c25..11cca035c 100644 Binary files a/files/assets/images/WPD/sidebar/21.webp and b/files/assets/images/WPD/sidebar/21.webp differ diff --git a/files/assets/images/WPD/sidebar/22.webp b/files/assets/images/WPD/sidebar/22.webp index 58684c3b8..4b7942469 100644 Binary files a/files/assets/images/WPD/sidebar/22.webp and b/files/assets/images/WPD/sidebar/22.webp differ diff --git a/files/assets/images/WPD/sidebar/23.webp b/files/assets/images/WPD/sidebar/23.webp index ead11f58b..2015a69b7 100644 Binary files a/files/assets/images/WPD/sidebar/23.webp and b/files/assets/images/WPD/sidebar/23.webp differ diff --git a/files/assets/images/WPD/sidebar/24.webp b/files/assets/images/WPD/sidebar/24.webp index 1fa7fb3d3..7be9054e6 100644 Binary files a/files/assets/images/WPD/sidebar/24.webp and b/files/assets/images/WPD/sidebar/24.webp differ diff --git a/files/assets/images/WPD/sidebar/25.webp b/files/assets/images/WPD/sidebar/25.webp index dac7657d9..28c4498a5 100644 Binary files a/files/assets/images/WPD/sidebar/25.webp and b/files/assets/images/WPD/sidebar/25.webp differ diff --git a/files/assets/images/WPD/sidebar/26.webp b/files/assets/images/WPD/sidebar/26.webp index 6ba4b6acd..b0da35449 100644 Binary files a/files/assets/images/WPD/sidebar/26.webp and b/files/assets/images/WPD/sidebar/26.webp differ diff --git a/files/assets/images/WPD/sidebar/27.webp b/files/assets/images/WPD/sidebar/27.webp index db6c52a47..8143555f0 100644 Binary files a/files/assets/images/WPD/sidebar/27.webp and b/files/assets/images/WPD/sidebar/27.webp differ diff --git a/files/assets/images/WPD/sidebar/28.webp b/files/assets/images/WPD/sidebar/28.webp index e0a8d0cac..09253e75d 100644 Binary files a/files/assets/images/WPD/sidebar/28.webp and b/files/assets/images/WPD/sidebar/28.webp differ diff --git a/files/assets/images/WPD/sidebar/29.webp b/files/assets/images/WPD/sidebar/29.webp index 803e936c2..acb99fcc5 100644 Binary files a/files/assets/images/WPD/sidebar/29.webp and b/files/assets/images/WPD/sidebar/29.webp differ diff --git a/files/assets/images/WPD/sidebar/30.webp b/files/assets/images/WPD/sidebar/30.webp index c60c7381e..6d7281688 100644 Binary files a/files/assets/images/WPD/sidebar/30.webp and b/files/assets/images/WPD/sidebar/30.webp differ diff --git a/files/assets/images/WPD/sidebar/31.webp b/files/assets/images/WPD/sidebar/31.webp index f6126c91a..21b908c29 100644 Binary files a/files/assets/images/WPD/sidebar/31.webp and b/files/assets/images/WPD/sidebar/31.webp differ diff --git a/files/assets/images/WPD/sidebar/32.webp b/files/assets/images/WPD/sidebar/32.webp index 48cf2d969..083bf6719 100644 Binary files a/files/assets/images/WPD/sidebar/32.webp and b/files/assets/images/WPD/sidebar/32.webp differ diff --git a/files/assets/images/WPD/sidebar/33.webp b/files/assets/images/WPD/sidebar/33.webp index 431103a62..ca19d9b81 100644 Binary files a/files/assets/images/WPD/sidebar/33.webp and b/files/assets/images/WPD/sidebar/33.webp differ diff --git a/files/assets/images/WPD/sidebar/34.webp b/files/assets/images/WPD/sidebar/34.webp index 146d74578..8631d4ff6 100644 Binary files a/files/assets/images/WPD/sidebar/34.webp and b/files/assets/images/WPD/sidebar/34.webp differ diff --git a/files/assets/images/WPD/sidebar/35.webp b/files/assets/images/WPD/sidebar/35.webp index f89b168c3..c2b016fb0 100644 Binary files a/files/assets/images/WPD/sidebar/35.webp and b/files/assets/images/WPD/sidebar/35.webp differ diff --git a/files/assets/images/WPD/sidebar/36.webp b/files/assets/images/WPD/sidebar/36.webp index 7028361e9..9931cb5e3 100644 Binary files a/files/assets/images/WPD/sidebar/36.webp and b/files/assets/images/WPD/sidebar/36.webp differ diff --git a/files/assets/images/WPD/sidebar/37.webp b/files/assets/images/WPD/sidebar/37.webp new file mode 100644 index 000000000..da10f9f21 Binary files /dev/null and b/files/assets/images/WPD/sidebar/37.webp differ diff --git a/files/assets/images/WPD/sidebar/6.webp b/files/assets/images/WPD/sidebar/6.webp index d9df9f999..fa502b9af 100644 Binary files a/files/assets/images/WPD/sidebar/6.webp and b/files/assets/images/WPD/sidebar/6.webp differ diff --git a/files/assets/images/WPD/sidebar/7.webp b/files/assets/images/WPD/sidebar/7.webp index e02552d79..9f78e1e7e 100644 Binary files a/files/assets/images/WPD/sidebar/7.webp and b/files/assets/images/WPD/sidebar/7.webp differ diff --git a/files/assets/images/WPD/sidebar/8.webp b/files/assets/images/WPD/sidebar/8.webp index f564d3a17..c3f06d2c6 100644 Binary files a/files/assets/images/WPD/sidebar/8.webp and b/files/assets/images/WPD/sidebar/8.webp differ diff --git a/files/assets/images/WPD/sidebar/9.webp b/files/assets/images/WPD/sidebar/9.webp index b24daca79..1eb507c56 100644 Binary files a/files/assets/images/WPD/sidebar/9.webp and b/files/assets/images/WPD/sidebar/9.webp differ diff --git a/files/assets/images/backgrounds/fantasy/1.webp b/files/assets/images/backgrounds/fantasy/1.webp index 1a9361a03..aaa3b4260 100644 Binary files a/files/assets/images/backgrounds/fantasy/1.webp and b/files/assets/images/backgrounds/fantasy/1.webp differ diff --git a/files/assets/images/backgrounds/fantasy/2.webp b/files/assets/images/backgrounds/fantasy/2.webp index 580349e03..2dbc50aee 100644 Binary files a/files/assets/images/backgrounds/fantasy/2.webp and b/files/assets/images/backgrounds/fantasy/2.webp differ diff --git a/files/assets/images/backgrounds/fantasy/3.webp b/files/assets/images/backgrounds/fantasy/3.webp index aca7cd915..5f0b53063 100644 Binary files a/files/assets/images/backgrounds/fantasy/3.webp and b/files/assets/images/backgrounds/fantasy/3.webp differ diff --git a/files/assets/images/backgrounds/fantasy/4.webp b/files/assets/images/backgrounds/fantasy/4.webp index 98bd2a6f9..3bc831187 100644 Binary files a/files/assets/images/backgrounds/fantasy/4.webp and b/files/assets/images/backgrounds/fantasy/4.webp differ diff --git a/files/assets/images/backgrounds/fantasy/5.webp b/files/assets/images/backgrounds/fantasy/5.webp index 7cc3e7c3e..d5116d4b1 100644 Binary files a/files/assets/images/backgrounds/fantasy/5.webp and b/files/assets/images/backgrounds/fantasy/5.webp differ diff --git a/files/assets/images/backgrounds/fantasy/6.webp b/files/assets/images/backgrounds/fantasy/6.webp index ed4ace1c9..7c13b582e 100644 Binary files a/files/assets/images/backgrounds/fantasy/6.webp and b/files/assets/images/backgrounds/fantasy/6.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/1.webp b/files/assets/images/backgrounds/solarpunk/1.webp index 0c8f47ea6..f0dcbf548 100644 Binary files a/files/assets/images/backgrounds/solarpunk/1.webp and b/files/assets/images/backgrounds/solarpunk/1.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/10.webp b/files/assets/images/backgrounds/solarpunk/10.webp index cafd296b4..2d2f2b624 100644 Binary files a/files/assets/images/backgrounds/solarpunk/10.webp and b/files/assets/images/backgrounds/solarpunk/10.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/11.webp b/files/assets/images/backgrounds/solarpunk/11.webp index f8d26c202..7d4907101 100644 Binary files a/files/assets/images/backgrounds/solarpunk/11.webp and b/files/assets/images/backgrounds/solarpunk/11.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/12.webp b/files/assets/images/backgrounds/solarpunk/12.webp index 9b963a20a..1b7021ddd 100644 Binary files a/files/assets/images/backgrounds/solarpunk/12.webp and b/files/assets/images/backgrounds/solarpunk/12.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/13.webp b/files/assets/images/backgrounds/solarpunk/13.webp index 18ce1660e..8b0da7459 100644 Binary files a/files/assets/images/backgrounds/solarpunk/13.webp and b/files/assets/images/backgrounds/solarpunk/13.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/14.webp b/files/assets/images/backgrounds/solarpunk/14.webp index da26e3b1a..ba56dece0 100644 Binary files a/files/assets/images/backgrounds/solarpunk/14.webp and b/files/assets/images/backgrounds/solarpunk/14.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/15.webp b/files/assets/images/backgrounds/solarpunk/15.webp index c206126b5..c09263f54 100644 Binary files a/files/assets/images/backgrounds/solarpunk/15.webp and b/files/assets/images/backgrounds/solarpunk/15.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/16.webp b/files/assets/images/backgrounds/solarpunk/16.webp index 4533abcc7..e81fa912f 100644 Binary files a/files/assets/images/backgrounds/solarpunk/16.webp and b/files/assets/images/backgrounds/solarpunk/16.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/17.webp b/files/assets/images/backgrounds/solarpunk/17.webp index aeab1c067..f2ed5dbf2 100644 Binary files a/files/assets/images/backgrounds/solarpunk/17.webp and b/files/assets/images/backgrounds/solarpunk/17.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/18.webp b/files/assets/images/backgrounds/solarpunk/18.webp index 7cf102b7a..2995ad5df 100644 Binary files a/files/assets/images/backgrounds/solarpunk/18.webp and b/files/assets/images/backgrounds/solarpunk/18.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/19.webp b/files/assets/images/backgrounds/solarpunk/19.webp index f694c95a3..e8f59c003 100644 Binary files a/files/assets/images/backgrounds/solarpunk/19.webp and b/files/assets/images/backgrounds/solarpunk/19.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/2.webp b/files/assets/images/backgrounds/solarpunk/2.webp index 3af7b4afe..e19ea750f 100644 Binary files a/files/assets/images/backgrounds/solarpunk/2.webp and b/files/assets/images/backgrounds/solarpunk/2.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/3.webp b/files/assets/images/backgrounds/solarpunk/3.webp index 8afb90b0c..42da65e45 100644 Binary files a/files/assets/images/backgrounds/solarpunk/3.webp and b/files/assets/images/backgrounds/solarpunk/3.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/4.webp b/files/assets/images/backgrounds/solarpunk/4.webp index 0d0ae1f41..ef6fa0ae0 100644 Binary files a/files/assets/images/backgrounds/solarpunk/4.webp and b/files/assets/images/backgrounds/solarpunk/4.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/5.webp b/files/assets/images/backgrounds/solarpunk/5.webp index 909e71c47..c5b27c964 100644 Binary files a/files/assets/images/backgrounds/solarpunk/5.webp and b/files/assets/images/backgrounds/solarpunk/5.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/6.webp b/files/assets/images/backgrounds/solarpunk/6.webp index 5ceb403e1..8cbf4efa6 100644 Binary files a/files/assets/images/backgrounds/solarpunk/6.webp and b/files/assets/images/backgrounds/solarpunk/6.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/7.webp b/files/assets/images/backgrounds/solarpunk/7.webp index c6eb57339..e6ecc8ce9 100644 Binary files a/files/assets/images/backgrounds/solarpunk/7.webp and b/files/assets/images/backgrounds/solarpunk/7.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/8.webp b/files/assets/images/backgrounds/solarpunk/8.webp index 6bdfd94e4..006ee1550 100644 Binary files a/files/assets/images/backgrounds/solarpunk/8.webp and b/files/assets/images/backgrounds/solarpunk/8.webp differ diff --git a/files/assets/images/backgrounds/solarpunk/9.webp b/files/assets/images/backgrounds/solarpunk/9.webp index f2ba74ab6..7094aada5 100644 Binary files a/files/assets/images/backgrounds/solarpunk/9.webp and b/files/assets/images/backgrounds/solarpunk/9.webp differ diff --git a/files/assets/images/badges/171.webp b/files/assets/images/badges/171.webp index 0218964e3..7b80f9e11 100644 Binary files a/files/assets/images/badges/171.webp and b/files/assets/images/badges/171.webp differ diff --git a/files/assets/images/badges/181.webp b/files/assets/images/badges/181.webp new file mode 100644 index 000000000..ba669c604 Binary files /dev/null and b/files/assets/images/badges/181.webp differ diff --git a/files/assets/images/badges/182.webp b/files/assets/images/badges/182.webp new file mode 100644 index 000000000..5851b535f Binary files /dev/null and b/files/assets/images/badges/182.webp differ diff --git a/files/assets/images/badges/183.webp b/files/assets/images/badges/183.webp new file mode 100644 index 000000000..5f2bc6258 Binary files /dev/null and b/files/assets/images/badges/183.webp differ diff --git a/files/assets/images/badges/184.webp b/files/assets/images/badges/184.webp new file mode 100644 index 000000000..1f474805b Binary files /dev/null and b/files/assets/images/badges/184.webp differ diff --git a/files/assets/images/badges/185.webp b/files/assets/images/badges/185.webp new file mode 100644 index 000000000..c1044674a Binary files /dev/null and b/files/assets/images/badges/185.webp differ diff --git a/files/assets/images/confetti2.webp b/files/assets/images/confetti2.webp index a08efe91f..ebecdd22c 100644 Binary files a/files/assets/images/confetti2.webp and b/files/assets/images/confetti2.webp differ diff --git a/files/assets/images/emojis/0alt.webp b/files/assets/images/emojis/0alt.webp new file mode 100644 index 000000000..64f5d2a40 Binary files /dev/null and b/files/assets/images/emojis/0alt.webp differ diff --git a/files/assets/images/emojis/antichrist.webp b/files/assets/images/emojis/antichrist.webp new file mode 100644 index 000000000..ff735724d Binary files /dev/null and b/files/assets/images/emojis/antichrist.webp differ diff --git a/files/assets/images/emojis/antichristfffuuuu.webp b/files/assets/images/emojis/antichristfffuuuu.webp new file mode 100644 index 000000000..06fb6a9da Binary files /dev/null and b/files/assets/images/emojis/antichristfffuuuu.webp differ diff --git a/files/assets/images/emojis/apostrophe.webp b/files/assets/images/emojis/apostrophe.webp new file mode 100644 index 000000000..c00d5a585 Binary files /dev/null and b/files/assets/images/emojis/apostrophe.webp differ diff --git a/files/assets/images/emojis/asianenbyjak.webp b/files/assets/images/emojis/asianenbyjak.webp new file mode 100644 index 000000000..342df37dd Binary files /dev/null and b/files/assets/images/emojis/asianenbyjak.webp differ diff --git a/files/assets/images/emojis/asiangirl.webp b/files/assets/images/emojis/asiangirl.webp new file mode 100644 index 000000000..796fa4fee Binary files /dev/null and b/files/assets/images/emojis/asiangirl.webp differ diff --git a/files/assets/images/emojis/asiantwinkjak.webp b/files/assets/images/emojis/asiantwinkjak.webp new file mode 100644 index 000000000..3545dc99a Binary files /dev/null and b/files/assets/images/emojis/asiantwinkjak.webp differ diff --git a/files/assets/images/emojis/asterisk.webp b/files/assets/images/emojis/asterisk.webp new file mode 100644 index 000000000..e9386a366 Binary files /dev/null and b/files/assets/images/emojis/asterisk.webp differ diff --git a/files/assets/images/emojis/ben10.webp b/files/assets/images/emojis/ben10.webp new file mode 100644 index 000000000..8e95d6e62 Binary files /dev/null and b/files/assets/images/emojis/ben10.webp differ diff --git a/files/assets/images/emojis/bitchhaditcomin.webp b/files/assets/images/emojis/bitchhaditcomin.webp new file mode 100644 index 000000000..79ed0a241 Binary files /dev/null and b/files/assets/images/emojis/bitchhaditcomin.webp differ diff --git a/files/assets/images/emojis/bluehelmet.webp b/files/assets/images/emojis/bluehelmet.webp new file mode 100644 index 000000000..92f4d301e Binary files /dev/null and b/files/assets/images/emojis/bluehelmet.webp differ diff --git a/files/assets/images/emojis/bobateagirl.webp b/files/assets/images/emojis/bobateagirl.webp new file mode 100644 index 000000000..ab9baa98f Binary files /dev/null and b/files/assets/images/emojis/bobateagirl.webp differ diff --git a/files/assets/images/emojis/breadmarsey.webp b/files/assets/images/emojis/breadmarsey.webp index 9c54ea9a0..29fce8778 100644 Binary files a/files/assets/images/emojis/breadmarsey.webp and b/files/assets/images/emojis/breadmarsey.webp differ diff --git a/files/assets/images/emojis/brooksannoyed.webp b/files/assets/images/emojis/brooksannoyed.webp new file mode 100644 index 000000000..e98cc7db1 Binary files /dev/null and b/files/assets/images/emojis/brooksannoyed.webp differ diff --git a/files/assets/images/emojis/brookscringe.webp b/files/assets/images/emojis/brookscringe.webp new file mode 100644 index 000000000..47b5b481b Binary files /dev/null and b/files/assets/images/emojis/brookscringe.webp differ diff --git a/files/assets/images/emojis/brooksjustright.webp b/files/assets/images/emojis/brooksjustright.webp new file mode 100644 index 000000000..b3b4e7022 Binary files /dev/null and b/files/assets/images/emojis/brooksjustright.webp differ diff --git a/files/assets/images/emojis/brookskiss.webp b/files/assets/images/emojis/brookskiss.webp new file mode 100644 index 000000000..e301d0276 Binary files /dev/null and b/files/assets/images/emojis/brookskiss.webp differ diff --git a/files/assets/images/emojis/brookslaugh.webp b/files/assets/images/emojis/brookslaugh.webp new file mode 100644 index 000000000..17223de2f Binary files /dev/null and b/files/assets/images/emojis/brookslaugh.webp differ diff --git a/files/assets/images/emojis/caret.webp b/files/assets/images/emojis/caret.webp new file mode 100644 index 000000000..047055c6f Binary files /dev/null and b/files/assets/images/emojis/caret.webp differ diff --git a/files/assets/images/emojis/ccedilla.webp b/files/assets/images/emojis/ccedilla.webp new file mode 100644 index 000000000..4953b1221 Binary files /dev/null and b/files/assets/images/emojis/ccedilla.webp differ diff --git a/files/assets/images/emojis/chadasian2.webp b/files/assets/images/emojis/chadasian2.webp new file mode 100644 index 000000000..dd2bef6b9 Binary files /dev/null and b/files/assets/images/emojis/chadasian2.webp differ diff --git a/files/assets/images/emojis/chadbaby.webp b/files/assets/images/emojis/chadbaby.webp new file mode 100644 index 000000000..6c26c0fa9 Binary files /dev/null and b/files/assets/images/emojis/chadbaby.webp differ diff --git a/files/assets/images/emojis/chadindianheadset.webp b/files/assets/images/emojis/chadindianheadset.webp new file mode 100644 index 000000000..79cbca5d7 Binary files /dev/null and b/files/assets/images/emojis/chadindianheadset.webp differ diff --git a/files/assets/images/emojis/chadmediterranean.webp b/files/assets/images/emojis/chadmediterranean.webp new file mode 100644 index 000000000..795e16a49 Binary files /dev/null and b/files/assets/images/emojis/chadmediterranean.webp differ diff --git a/files/assets/images/emojis/chadmusk.webp b/files/assets/images/emojis/chadmusk.webp new file mode 100644 index 000000000..c4e782c9e Binary files /dev/null and b/files/assets/images/emojis/chadmusk.webp differ diff --git a/files/assets/images/emojis/chadnoproblemkingcapy.webp b/files/assets/images/emojis/chadnoproblemkingcapy.webp new file mode 100644 index 000000000..1106843ef Binary files /dev/null and b/files/assets/images/emojis/chadnoproblemkingcapy.webp differ diff --git a/files/assets/images/emojis/chadnoproblemqueencapy.webp b/files/assets/images/emojis/chadnoproblemqueencapy.webp new file mode 100644 index 000000000..f4e371b57 Binary files /dev/null and b/files/assets/images/emojis/chadnoproblemqueencapy.webp differ diff --git a/files/assets/images/emojis/chadstalin.webp b/files/assets/images/emojis/chadstalin.webp new file mode 100644 index 000000000..e85602d47 Binary files /dev/null and b/files/assets/images/emojis/chadstalin.webp differ diff --git a/files/assets/images/emojis/chinesenobleman.webp b/files/assets/images/emojis/chinesenobleman.webp new file mode 100644 index 000000000..609d76488 Binary files /dev/null and b/files/assets/images/emojis/chinesenobleman.webp differ diff --git a/files/assets/images/emojis/chinesepolitician.webp b/files/assets/images/emojis/chinesepolitician.webp new file mode 100644 index 000000000..1d009a77f Binary files /dev/null and b/files/assets/images/emojis/chinesepolitician.webp differ diff --git a/files/assets/images/emojis/chinesesoldierjak.webp b/files/assets/images/emojis/chinesesoldierjak.webp new file mode 100644 index 000000000..18d7c4dfb Binary files /dev/null and b/files/assets/images/emojis/chinesesoldierjak.webp differ diff --git a/files/assets/images/emojis/chuckbuddy.webp b/files/assets/images/emojis/chuckbuddy.webp new file mode 100644 index 000000000..d9a548d67 Binary files /dev/null and b/files/assets/images/emojis/chuckbuddy.webp differ diff --git a/files/assets/images/emojis/chudette.webp b/files/assets/images/emojis/chudette.webp new file mode 100644 index 000000000..4f2d50e04 Binary files /dev/null and b/files/assets/images/emojis/chudette.webp differ diff --git a/files/assets/images/emojis/chudgrug.webp b/files/assets/images/emojis/chudgrug.webp new file mode 100644 index 000000000..1f3fe7278 Binary files /dev/null and b/files/assets/images/emojis/chudgrug.webp differ diff --git a/files/assets/images/emojis/chudnazi.webp b/files/assets/images/emojis/chudnazi.webp new file mode 100644 index 000000000..f2b277af6 Binary files /dev/null and b/files/assets/images/emojis/chudnazi.webp differ diff --git a/files/assets/images/emojis/chudsmug.webp b/files/assets/images/emojis/chudsmug.webp new file mode 100644 index 000000000..899fd4361 Binary files /dev/null and b/files/assets/images/emojis/chudsmug.webp differ diff --git a/files/assets/images/emojis/dinoconfused.webp b/files/assets/images/emojis/dinoconfused.webp new file mode 100644 index 000000000..b80af5503 Binary files /dev/null and b/files/assets/images/emojis/dinoconfused.webp differ diff --git a/files/assets/images/emojis/dinono.webp b/files/assets/images/emojis/dinono.webp new file mode 100644 index 000000000..db50a9d2d Binary files /dev/null and b/files/assets/images/emojis/dinono.webp differ diff --git a/files/assets/images/emojis/dinoyes.webp b/files/assets/images/emojis/dinoyes.webp new file mode 100644 index 000000000..e62d12dbf Binary files /dev/null and b/files/assets/images/emojis/dinoyes.webp differ diff --git a/files/assets/images/emojis/downdonger.webp b/files/assets/images/emojis/downdonger.webp new file mode 100644 index 000000000..b650f8196 Binary files /dev/null and b/files/assets/images/emojis/downdonger.webp differ diff --git a/files/assets/images/emojis/duckdance.webp b/files/assets/images/emojis/duckdance.webp new file mode 100644 index 000000000..2542a3125 Binary files /dev/null and b/files/assets/images/emojis/duckdance.webp differ diff --git a/files/assets/images/emojis/greendesigirl.webp b/files/assets/images/emojis/greendesigirl.webp new file mode 100644 index 000000000..ae8d358a2 Binary files /dev/null and b/files/assets/images/emojis/greendesigirl.webp differ diff --git a/files/assets/images/emojis/ialt.webp b/files/assets/images/emojis/ialt.webp new file mode 100644 index 000000000..f85dca08f Binary files /dev/null and b/files/assets/images/emojis/ialt.webp differ diff --git a/files/assets/images/emojis/imperialjapanesesoldier.webp b/files/assets/images/emojis/imperialjapanesesoldier.webp new file mode 100644 index 000000000..b1916d855 Binary files /dev/null and b/files/assets/images/emojis/imperialjapanesesoldier.webp differ diff --git a/files/assets/images/emojis/indiandoomergirl.webp b/files/assets/images/emojis/indiandoomergirl.webp new file mode 100644 index 000000000..7c41b2efd Binary files /dev/null and b/files/assets/images/emojis/indiandoomergirl.webp differ diff --git a/files/assets/images/emojis/joanmarsey.webp b/files/assets/images/emojis/joanmarsey.webp index d97d4f343..cd49c322f 100644 Binary files a/files/assets/images/emojis/joanmarsey.webp and b/files/assets/images/emojis/joanmarsey.webp differ diff --git a/files/assets/images/emojis/kimjojongjak.webp b/files/assets/images/emojis/kimjojongjak.webp new file mode 100644 index 000000000..ece66507f Binary files /dev/null and b/files/assets/images/emojis/kimjojongjak.webp differ diff --git a/files/assets/images/emojis/kimonogirl.webp b/files/assets/images/emojis/kimonogirl.webp new file mode 100644 index 000000000..95e32753b Binary files /dev/null and b/files/assets/images/emojis/kimonogirl.webp differ diff --git a/files/assets/images/emojis/kippy.webp b/files/assets/images/emojis/kippy.webp index 8157a46d2..d949703ea 100644 Binary files a/files/assets/images/emojis/kippy.webp and b/files/assets/images/emojis/kippy.webp differ diff --git a/files/assets/images/emojis/maojak.webp b/files/assets/images/emojis/maojak.webp new file mode 100644 index 000000000..a3b299a89 Binary files /dev/null and b/files/assets/images/emojis/maojak.webp differ diff --git a/files/assets/images/emojis/marppyglow2.webp b/files/assets/images/emojis/marppyglow2.webp deleted file mode 100644 index e69de29bb..000000000 diff --git a/files/assets/images/emojis/marsey173.webp b/files/assets/images/emojis/marsey173.webp index d1250081f..7885c768c 100644 Binary files a/files/assets/images/emojis/marsey173.webp and b/files/assets/images/emojis/marsey173.webp differ diff --git a/files/assets/images/emojis/marsey1984.webp b/files/assets/images/emojis/marsey1984.webp index 3c820672e..13322fbd0 100644 Binary files a/files/assets/images/emojis/marsey1984.webp and b/files/assets/images/emojis/marsey1984.webp differ diff --git a/files/assets/images/emojis/marsey40k.webp b/files/assets/images/emojis/marsey40k.webp index b1ea07619..d4c04d346 100644 Binary files a/files/assets/images/emojis/marsey40k.webp and b/files/assets/images/emojis/marsey40k.webp differ diff --git a/files/assets/images/emojis/marsey41.webp b/files/assets/images/emojis/marsey41.webp index fa731911d..fae5854a4 100644 Binary files a/files/assets/images/emojis/marsey41.webp and b/files/assets/images/emojis/marsey41.webp differ diff --git a/files/assets/images/emojis/marsey420.webp b/files/assets/images/emojis/marsey420.webp index a9e6dd8eb..ffb15acb0 100644 Binary files a/files/assets/images/emojis/marsey420.webp and b/files/assets/images/emojis/marsey420.webp differ diff --git a/files/assets/images/emojis/marsey4chan.webp b/files/assets/images/emojis/marsey4chan.webp index 6738eb4a6..dcdbebd8e 100644 Binary files a/files/assets/images/emojis/marsey4chan.webp and b/files/assets/images/emojis/marsey4chan.webp differ diff --git a/files/assets/images/emojis/marsey57.webp b/files/assets/images/emojis/marsey57.webp index 4e33e7b76..37a1ac9f2 100644 Binary files a/files/assets/images/emojis/marsey57.webp and b/files/assets/images/emojis/marsey57.webp differ diff --git a/files/assets/images/emojis/marsey69.webp b/files/assets/images/emojis/marsey69.webp index 5e3698c82..5ab3ced73 100644 Binary files a/files/assets/images/emojis/marsey69.webp and b/files/assets/images/emojis/marsey69.webp differ diff --git a/files/assets/images/emojis/marseyabandoned.webp b/files/assets/images/emojis/marseyabandoned.webp index d6c77e21f..0d00c02c2 100644 Binary files a/files/assets/images/emojis/marseyabandoned.webp and b/files/assets/images/emojis/marseyabandoned.webp differ diff --git a/files/assets/images/emojis/marseyaceofspades.webp b/files/assets/images/emojis/marseyaceofspades.webp index 4738ef2c5..c39632b84 100644 Binary files a/files/assets/images/emojis/marseyaceofspades.webp and b/files/assets/images/emojis/marseyaceofspades.webp differ diff --git a/files/assets/images/emojis/marseyadeptusmechanicus.webp b/files/assets/images/emojis/marseyadeptusmechanicus.webp index d6ef3634d..d5e901013 100644 Binary files a/files/assets/images/emojis/marseyadeptusmechanicus.webp and b/files/assets/images/emojis/marseyadeptusmechanicus.webp differ diff --git a/files/assets/images/emojis/marseyadmire.webp b/files/assets/images/emojis/marseyadmire.webp index 6c6e0367c..584b2ed9a 100644 Binary files a/files/assets/images/emojis/marseyadmire.webp and b/files/assets/images/emojis/marseyadmire.webp differ diff --git a/files/assets/images/emojis/marseyaevannchad.webp b/files/assets/images/emojis/marseyaevannchad.webp index ac437e50c..877d8c606 100644 Binary files a/files/assets/images/emojis/marseyaevannchad.webp and b/files/assets/images/emojis/marseyaevannchad.webp differ diff --git a/files/assets/images/emojis/marseyaevannchad2.webp b/files/assets/images/emojis/marseyaevannchad2.webp index 43734f413..f75cd430c 100644 Binary files a/files/assets/images/emojis/marseyaevannchad2.webp and b/files/assets/images/emojis/marseyaevannchad2.webp differ diff --git a/files/assets/images/emojis/marseyaevannchad3.webp b/files/assets/images/emojis/marseyaevannchad3.webp index 45175a307..b3580d40b 100644 Binary files a/files/assets/images/emojis/marseyaevannchad3.webp and b/files/assets/images/emojis/marseyaevannchad3.webp differ diff --git a/files/assets/images/emojis/marseyagreefast.webp b/files/assets/images/emojis/marseyagreefast.webp index a71f9364e..06dbebc25 100644 Binary files a/files/assets/images/emojis/marseyagreefast.webp and b/files/assets/images/emojis/marseyagreefast.webp differ diff --git a/files/assets/images/emojis/marseyakshually.webp b/files/assets/images/emojis/marseyakshually.webp index 0601798dd..5affc169f 100644 Binary files a/files/assets/images/emojis/marseyakshually.webp and b/files/assets/images/emojis/marseyakshually.webp differ diff --git a/files/assets/images/emojis/marseyakumu.webp b/files/assets/images/emojis/marseyakumu.webp index f1d9caeae..c13cfb41b 100644 Binary files a/files/assets/images/emojis/marseyakumu.webp and b/files/assets/images/emojis/marseyakumu.webp differ diff --git a/files/assets/images/emojis/marseyaleistercrowley.webp b/files/assets/images/emojis/marseyaleistercrowley.webp index 829b0c139..7c2a107f3 100644 Binary files a/files/assets/images/emojis/marseyaleistercrowley.webp and b/files/assets/images/emojis/marseyaleistercrowley.webp differ diff --git a/files/assets/images/emojis/marseyalice.webp b/files/assets/images/emojis/marseyalice.webp index ee5217095..618451371 100644 Binary files a/files/assets/images/emojis/marseyalice.webp and b/files/assets/images/emojis/marseyalice.webp differ diff --git a/files/assets/images/emojis/marseyalien.webp b/files/assets/images/emojis/marseyalien.webp index a283a875e..2d575e46c 100644 Binary files a/files/assets/images/emojis/marseyalien.webp and b/files/assets/images/emojis/marseyalien.webp differ diff --git a/files/assets/images/emojis/marseyamazon.webp b/files/assets/images/emojis/marseyamazon.webp index 6b5933a8d..c8fdf40fb 100644 Binary files a/files/assets/images/emojis/marseyamazon.webp and b/files/assets/images/emojis/marseyamazon.webp differ diff --git a/files/assets/images/emojis/marseyamber.webp b/files/assets/images/emojis/marseyamber.webp index 637e6ab03..15844aedf 100644 Binary files a/files/assets/images/emojis/marseyamber.webp and b/files/assets/images/emojis/marseyamber.webp differ diff --git a/files/assets/images/emojis/marseyamogus.webp b/files/assets/images/emojis/marseyamogus.webp index f1632d62c..1b63ef913 100644 Binary files a/files/assets/images/emojis/marseyamogus.webp and b/files/assets/images/emojis/marseyamogus.webp differ diff --git a/files/assets/images/emojis/marseyanalvore.webp b/files/assets/images/emojis/marseyanalvore.webp index c13f17489..99319044e 100644 Binary files a/files/assets/images/emojis/marseyanalvore.webp and b/files/assets/images/emojis/marseyanalvore.webp differ diff --git a/files/assets/images/emojis/marseyandjesus.webp b/files/assets/images/emojis/marseyandjesus.webp index 3cfaf58aa..7f3b6f755 100644 Binary files a/files/assets/images/emojis/marseyandjesus.webp and b/files/assets/images/emojis/marseyandjesus.webp differ diff --git a/files/assets/images/emojis/marseyandmarcus.webp b/files/assets/images/emojis/marseyandmarcus.webp index 6408a63e1..b544e0cc8 100644 Binary files a/files/assets/images/emojis/marseyandmarcus.webp and b/files/assets/images/emojis/marseyandmarcus.webp differ diff --git a/files/assets/images/emojis/marseyangel.webp b/files/assets/images/emojis/marseyangel.webp index f30a8ddf1..6c1f05dde 100644 Binary files a/files/assets/images/emojis/marseyangel.webp and b/files/assets/images/emojis/marseyangel.webp differ diff --git a/files/assets/images/emojis/marseyangel2.webp b/files/assets/images/emojis/marseyangel2.webp index e98c3e39d..19d31c376 100644 Binary files a/files/assets/images/emojis/marseyangel2.webp and b/files/assets/images/emojis/marseyangel2.webp differ diff --git a/files/assets/images/emojis/marseyangel3.webp b/files/assets/images/emojis/marseyangel3.webp index dab6f01d7..8d4688b5b 100644 Binary files a/files/assets/images/emojis/marseyangel3.webp and b/files/assets/images/emojis/marseyangel3.webp differ diff --git a/files/assets/images/emojis/marseyangryexosuit.webp b/files/assets/images/emojis/marseyangryexosuit.webp index 45e5967b2..e48879f2a 100644 Binary files a/files/assets/images/emojis/marseyangryexosuit.webp and b/files/assets/images/emojis/marseyangryexosuit.webp differ diff --git a/files/assets/images/emojis/marseyangrygamer.webp b/files/assets/images/emojis/marseyangrygamer.webp index ae861718b..8bc027793 100644 Binary files a/files/assets/images/emojis/marseyangrygamer.webp and b/files/assets/images/emojis/marseyangrygamer.webp differ diff --git a/files/assets/images/emojis/marseyanime.webp b/files/assets/images/emojis/marseyanime.webp index c70956394..d7bd5017f 100644 Binary files a/files/assets/images/emojis/marseyanime.webp and b/files/assets/images/emojis/marseyanime.webp differ diff --git a/files/assets/images/emojis/marseyannoyed.webp b/files/assets/images/emojis/marseyannoyed.webp index 95eef3aaa..9e4ad8c3a 100644 Binary files a/files/assets/images/emojis/marseyannoyed.webp and b/files/assets/images/emojis/marseyannoyed.webp differ diff --git a/files/assets/images/emojis/marseyanon.webp b/files/assets/images/emojis/marseyanon.webp index 8a6f9fc24..cc94c27ac 100644 Binary files a/files/assets/images/emojis/marseyanon.webp and b/files/assets/images/emojis/marseyanon.webp differ diff --git a/files/assets/images/emojis/marseyanorexia.webp b/files/assets/images/emojis/marseyanorexia.webp index c169e79c5..7d9e2c74e 100644 Binary files a/files/assets/images/emojis/marseyanorexia.webp and b/files/assets/images/emojis/marseyanorexia.webp differ diff --git a/files/assets/images/emojis/marseyantischizo.webp b/files/assets/images/emojis/marseyantischizo.webp index 67f4e6c3c..298982ef5 100644 Binary files a/files/assets/images/emojis/marseyantischizo.webp and b/files/assets/images/emojis/marseyantischizo.webp differ diff --git a/files/assets/images/emojis/marseyaoc.webp b/files/assets/images/emojis/marseyaoc.webp index 80905a874..8f20d294d 100644 Binary files a/files/assets/images/emojis/marseyaoc.webp and b/files/assets/images/emojis/marseyaoc.webp differ diff --git a/files/assets/images/emojis/marseyappicon.webp b/files/assets/images/emojis/marseyappicon.webp index e0fca3baf..519eafac8 100644 Binary files a/files/assets/images/emojis/marseyappicon.webp and b/files/assets/images/emojis/marseyappicon.webp differ diff --git a/files/assets/images/emojis/marseyappleseed.webp b/files/assets/images/emojis/marseyappleseed.webp index 7eb8b3948..d20ad9344 100644 Binary files a/files/assets/images/emojis/marseyappleseed.webp and b/files/assets/images/emojis/marseyappleseed.webp differ diff --git a/files/assets/images/emojis/marseyargentina.webp b/files/assets/images/emojis/marseyargentina.webp index ac3d66e72..0f4c938f6 100644 Binary files a/files/assets/images/emojis/marseyargentina.webp and b/files/assets/images/emojis/marseyargentina.webp differ diff --git a/files/assets/images/emojis/marseyarmenia.webp b/files/assets/images/emojis/marseyarmenia.webp index 947e031b5..94c80dc4a 100644 Binary files a/files/assets/images/emojis/marseyarmenia.webp and b/files/assets/images/emojis/marseyarmenia.webp differ diff --git a/files/assets/images/emojis/marseyarmy.webp b/files/assets/images/emojis/marseyarmy.webp index f3acfedfb..b6937ec43 100644 Binary files a/files/assets/images/emojis/marseyarmy.webp and b/files/assets/images/emojis/marseyarmy.webp differ diff --git a/files/assets/images/emojis/marseyarthoe.webp b/files/assets/images/emojis/marseyarthoe.webp index 6008cf96b..8c4ff5394 100644 Binary files a/files/assets/images/emojis/marseyarthoe.webp and b/files/assets/images/emojis/marseyarthoe.webp differ diff --git a/files/assets/images/emojis/marseyarthoe2.webp b/files/assets/images/emojis/marseyarthoe2.webp index e21ed4831..f792051c0 100644 Binary files a/files/assets/images/emojis/marseyarthoe2.webp and b/files/assets/images/emojis/marseyarthoe2.webp differ diff --git a/files/assets/images/emojis/marseyarthoe3.webp b/files/assets/images/emojis/marseyarthoe3.webp index 1dba48da9..5002511d1 100644 Binary files a/files/assets/images/emojis/marseyarthoe3.webp and b/files/assets/images/emojis/marseyarthoe3.webp differ diff --git a/files/assets/images/emojis/marseyarthoe4.webp b/files/assets/images/emojis/marseyarthoe4.webp index c785d0f79..d0868674a 100644 Binary files a/files/assets/images/emojis/marseyarthoe4.webp and b/files/assets/images/emojis/marseyarthoe4.webp differ diff --git a/files/assets/images/emojis/marseyarthoe5.webp b/files/assets/images/emojis/marseyarthoe5.webp index d113f6acf..291eb4336 100644 Binary files a/files/assets/images/emojis/marseyarthoe5.webp and b/files/assets/images/emojis/marseyarthoe5.webp differ diff --git a/files/assets/images/emojis/marseyarthoe6.webp b/files/assets/images/emojis/marseyarthoe6.webp index 46279cf9b..ecae2fa65 100644 Binary files a/files/assets/images/emojis/marseyarthoe6.webp and b/files/assets/images/emojis/marseyarthoe6.webp differ diff --git a/files/assets/images/emojis/marseyarthoe7.webp b/files/assets/images/emojis/marseyarthoe7.webp index 45ebbcf5e..82a389808 100644 Binary files a/files/assets/images/emojis/marseyarthoe7.webp and b/files/assets/images/emojis/marseyarthoe7.webp differ diff --git a/files/assets/images/emojis/marseyarthoe8.webp b/files/assets/images/emojis/marseyarthoe8.webp index 6dc7632be..fcf3c56f1 100644 Binary files a/files/assets/images/emojis/marseyarthoe8.webp and b/files/assets/images/emojis/marseyarthoe8.webp differ diff --git a/files/assets/images/emojis/marseyascii.webp b/files/assets/images/emojis/marseyascii.webp index 9e94a7a2b..b6f81828c 100644 Binary files a/files/assets/images/emojis/marseyascii.webp and b/files/assets/images/emojis/marseyascii.webp differ diff --git a/files/assets/images/emojis/marseyascii2.webp b/files/assets/images/emojis/marseyascii2.webp index 8f0413f4b..fcba02c7c 100644 Binary files a/files/assets/images/emojis/marseyascii2.webp and b/files/assets/images/emojis/marseyascii2.webp differ diff --git a/files/assets/images/emojis/marseyasian.webp b/files/assets/images/emojis/marseyasian.webp index 1bb11b04c..240ad98d8 100644 Binary files a/files/assets/images/emojis/marseyasian.webp and b/files/assets/images/emojis/marseyasian.webp differ diff --git a/files/assets/images/emojis/marseyastronaut.webp b/files/assets/images/emojis/marseyastronaut.webp index 14e1f7bb6..a67427f83 100644 Binary files a/files/assets/images/emojis/marseyastronaut.webp and b/files/assets/images/emojis/marseyastronaut.webp differ diff --git a/files/assets/images/emojis/marseyastronaut2.webp b/files/assets/images/emojis/marseyastronaut2.webp index 3afe0210f..b19ff604e 100644 Binary files a/files/assets/images/emojis/marseyastronaut2.webp and b/files/assets/images/emojis/marseyastronaut2.webp differ diff --git a/files/assets/images/emojis/marseyatfagent.webp b/files/assets/images/emojis/marseyatfagent.webp index b7e574bb9..454f6710e 100644 Binary files a/files/assets/images/emojis/marseyatfagent.webp and b/files/assets/images/emojis/marseyatfagent.webp differ diff --git a/files/assets/images/emojis/marseyatlasshrugged.webp b/files/assets/images/emojis/marseyatlasshrugged.webp index d20dfb250..8c018aef1 100644 Binary files a/files/assets/images/emojis/marseyatlasshrugged.webp and b/files/assets/images/emojis/marseyatlasshrugged.webp differ diff --git a/files/assets/images/emojis/marseyatsume.webp b/files/assets/images/emojis/marseyatsume.webp index 7bb4437a6..600404b2e 100644 Binary files a/files/assets/images/emojis/marseyatsume.webp and b/files/assets/images/emojis/marseyatsume.webp differ diff --git a/files/assets/images/emojis/marseyattentionseeker.webp b/files/assets/images/emojis/marseyattentionseeker.webp index ad54783e2..61d20f46c 100644 Binary files a/files/assets/images/emojis/marseyattentionseeker.webp and b/files/assets/images/emojis/marseyattentionseeker.webp differ diff --git a/files/assets/images/emojis/marseyaustralian.webp b/files/assets/images/emojis/marseyaustralian.webp index 7c30f606f..b418196cc 100644 Binary files a/files/assets/images/emojis/marseyaustralian.webp and b/files/assets/images/emojis/marseyaustralian.webp differ diff --git a/files/assets/images/emojis/marseyauthleft.webp b/files/assets/images/emojis/marseyauthleft.webp index f09efc62d..cccfc17f6 100644 Binary files a/files/assets/images/emojis/marseyauthleft.webp and b/files/assets/images/emojis/marseyauthleft.webp differ diff --git a/files/assets/images/emojis/marseyauthright.webp b/files/assets/images/emojis/marseyauthright.webp index 7b3fd2327..22b9e7b17 100644 Binary files a/files/assets/images/emojis/marseyauthright.webp and b/files/assets/images/emojis/marseyauthright.webp differ diff --git a/files/assets/images/emojis/marseyautism.webp b/files/assets/images/emojis/marseyautism.webp index 2903c76fa..c686d0276 100644 Binary files a/files/assets/images/emojis/marseyautism.webp and b/files/assets/images/emojis/marseyautism.webp differ diff --git a/files/assets/images/emojis/marseyautismchonker.webp b/files/assets/images/emojis/marseyautismchonker.webp index 48c685dc5..08577c0db 100644 Binary files a/files/assets/images/emojis/marseyautismchonker.webp and b/files/assets/images/emojis/marseyautismchonker.webp differ diff --git a/files/assets/images/emojis/marseyautumn2.webp b/files/assets/images/emojis/marseyautumn2.webp index 95c725a2c..68c945426 100644 Binary files a/files/assets/images/emojis/marseyautumn2.webp and b/files/assets/images/emojis/marseyautumn2.webp differ diff --git a/files/assets/images/emojis/marseyavril1.webp b/files/assets/images/emojis/marseyavril1.webp index 5a5cb84b4..2e22f3c56 100644 Binary files a/files/assets/images/emojis/marseyavril1.webp and b/files/assets/images/emojis/marseyavril1.webp differ diff --git a/files/assets/images/emojis/marseyavril2.webp b/files/assets/images/emojis/marseyavril2.webp index 2b67b75c2..40694a7d0 100644 Binary files a/files/assets/images/emojis/marseyavril2.webp and b/files/assets/images/emojis/marseyavril2.webp differ diff --git a/files/assets/images/emojis/marseyavril3.webp b/files/assets/images/emojis/marseyavril3.webp index a133f28b7..203769868 100644 Binary files a/files/assets/images/emojis/marseyavril3.webp and b/files/assets/images/emojis/marseyavril3.webp differ diff --git a/files/assets/images/emojis/marseyaward.webp b/files/assets/images/emojis/marseyaward.webp index 5ab61fe20..c0a8bbe77 100644 Binary files a/files/assets/images/emojis/marseyaward.webp and b/files/assets/images/emojis/marseyaward.webp differ diff --git a/files/assets/images/emojis/marseyawardretard.webp b/files/assets/images/emojis/marseyawardretard.webp index f88b79f30..d2362f791 100644 Binary files a/files/assets/images/emojis/marseyawardretard.webp and b/files/assets/images/emojis/marseyawardretard.webp differ diff --git a/files/assets/images/emojis/marseyaware.webp b/files/assets/images/emojis/marseyaware.webp index 2d89b0062..3cc415a61 100644 Binary files a/files/assets/images/emojis/marseyaware.webp and b/files/assets/images/emojis/marseyaware.webp differ diff --git a/files/assets/images/emojis/marseyawesomeface.webp b/files/assets/images/emojis/marseyawesomeface.webp new file mode 100644 index 000000000..88865cd61 Binary files /dev/null and b/files/assets/images/emojis/marseyawesomeface.webp differ diff --git a/files/assets/images/emojis/marseyaxolotl.webp b/files/assets/images/emojis/marseyaxolotl.webp index bc48a1e28..8b9dace11 100644 Binary files a/files/assets/images/emojis/marseyaxolotl.webp and b/files/assets/images/emojis/marseyaxolotl.webp differ diff --git a/files/assets/images/emojis/marseyaynrand.webp b/files/assets/images/emojis/marseyaynrand.webp index 0250abd59..862d0c8af 100644 Binary files a/files/assets/images/emojis/marseyaynrand.webp and b/files/assets/images/emojis/marseyaynrand.webp differ diff --git a/files/assets/images/emojis/marseyaynrand2.webp b/files/assets/images/emojis/marseyaynrand2.webp index f048b915d..00ba52af3 100644 Binary files a/files/assets/images/emojis/marseyaynrand2.webp and b/files/assets/images/emojis/marseyaynrand2.webp differ diff --git a/files/assets/images/emojis/marseyayy.webp b/files/assets/images/emojis/marseyayy.webp index 690aa4d00..219f9bc61 100644 Binary files a/files/assets/images/emojis/marseyayy.webp and b/files/assets/images/emojis/marseyayy.webp differ diff --git a/files/assets/images/emojis/marseyazov.webp b/files/assets/images/emojis/marseyazov.webp index c1154b0be..e208223c6 100644 Binary files a/files/assets/images/emojis/marseyazov.webp and b/files/assets/images/emojis/marseyazov.webp differ diff --git a/files/assets/images/emojis/marseyazov2.webp b/files/assets/images/emojis/marseyazov2.webp index 5e5a2d914..f2e1d0ddd 100644 Binary files a/files/assets/images/emojis/marseyazov2.webp and b/files/assets/images/emojis/marseyazov2.webp differ diff --git a/files/assets/images/emojis/marseybabushka.webp b/files/assets/images/emojis/marseybabushka.webp index 30830f06f..bb9d880ce 100644 Binary files a/files/assets/images/emojis/marseybabushka.webp and b/files/assets/images/emojis/marseybabushka.webp differ diff --git a/files/assets/images/emojis/marseybaby.webp b/files/assets/images/emojis/marseybaby.webp index 864b228d0..8f7f5f991 100644 Binary files a/files/assets/images/emojis/marseybaby.webp and b/files/assets/images/emojis/marseybaby.webp differ diff --git a/files/assets/images/emojis/marseybabykiller.webp b/files/assets/images/emojis/marseybabykiller.webp index b85915fb4..4d9ce13ef 100644 Binary files a/files/assets/images/emojis/marseybabykiller.webp and b/files/assets/images/emojis/marseybabykiller.webp differ diff --git a/files/assets/images/emojis/marseybackstab.webp b/files/assets/images/emojis/marseybackstab.webp index 36ff0bc10..debba9e5d 100644 Binary files a/files/assets/images/emojis/marseybackstab.webp and b/files/assets/images/emojis/marseybackstab.webp differ diff --git a/files/assets/images/emojis/marseybadass.webp b/files/assets/images/emojis/marseybadass.webp index e4a6b9352..78ba0174e 100644 Binary files a/files/assets/images/emojis/marseybadass.webp and b/files/assets/images/emojis/marseybadass.webp differ diff --git a/files/assets/images/emojis/marseybadger.webp b/files/assets/images/emojis/marseybadger.webp index fb24a85b7..1d2c824cb 100644 Binary files a/files/assets/images/emojis/marseybadger.webp and b/files/assets/images/emojis/marseybadger.webp differ diff --git a/files/assets/images/emojis/marseybadluck.webp b/files/assets/images/emojis/marseybadluck.webp index df23eb574..d822c3c28 100644 Binary files a/files/assets/images/emojis/marseybadluck.webp and b/files/assets/images/emojis/marseybadluck.webp differ diff --git a/files/assets/images/emojis/marseybadnews.webp b/files/assets/images/emojis/marseybadnews.webp index ecc231a00..f5849fd4c 100644 Binary files a/files/assets/images/emojis/marseybadnews.webp and b/files/assets/images/emojis/marseybadnews.webp differ diff --git a/files/assets/images/emojis/marseybait.webp b/files/assets/images/emojis/marseybait.webp index a07677c86..7eec3aa0f 100644 Binary files a/files/assets/images/emojis/marseybait.webp and b/files/assets/images/emojis/marseybait.webp differ diff --git a/files/assets/images/emojis/marseyballerina.webp b/files/assets/images/emojis/marseyballerina.webp index 762e5c16f..0e42fb2de 100644 Binary files a/files/assets/images/emojis/marseyballerina.webp and b/files/assets/images/emojis/marseyballerina.webp differ diff --git a/files/assets/images/emojis/marseyban.webp b/files/assets/images/emojis/marseyban.webp index 6b2150912..0f69ed821 100644 Binary files a/files/assets/images/emojis/marseyban.webp and b/files/assets/images/emojis/marseyban.webp differ diff --git a/files/assets/images/emojis/marseybane.webp b/files/assets/images/emojis/marseybane.webp index 59410a8d4..a03e8c479 100644 Binary files a/files/assets/images/emojis/marseybane.webp and b/files/assets/images/emojis/marseybane.webp differ diff --git a/files/assets/images/emojis/marseybaphomet.webp b/files/assets/images/emojis/marseybaphomet.webp index a9b2869a7..053da9514 100644 Binary files a/files/assets/images/emojis/marseybaphomet.webp and b/files/assets/images/emojis/marseybaphomet.webp differ diff --git a/files/assets/images/emojis/marseybardfinn.webp b/files/assets/images/emojis/marseybardfinn.webp index d4fd2e567..d65cc6f43 100644 Binary files a/files/assets/images/emojis/marseybardfinn.webp and b/files/assets/images/emojis/marseybardfinn.webp differ diff --git a/files/assets/images/emojis/marseybardfinn3.webp b/files/assets/images/emojis/marseybardfinn3.webp index 04b8bac7c..58afdcf75 100644 Binary files a/files/assets/images/emojis/marseybardfinn3.webp and b/files/assets/images/emojis/marseybardfinn3.webp differ diff --git a/files/assets/images/emojis/marseybarrel.webp b/files/assets/images/emojis/marseybarrel.webp index 8622d19e4..830fa203e 100644 Binary files a/files/assets/images/emojis/marseybarrel.webp and b/files/assets/images/emojis/marseybarrel.webp differ diff --git a/files/assets/images/emojis/marseybarreldrunk.webp b/files/assets/images/emojis/marseybarreldrunk.webp index 7f1e79100..f91ac225b 100644 Binary files a/files/assets/images/emojis/marseybarreldrunk.webp and b/files/assets/images/emojis/marseybarreldrunk.webp differ diff --git a/files/assets/images/emojis/marseybateman.webp b/files/assets/images/emojis/marseybateman.webp index bd9067495..a826fdb3e 100644 Binary files a/files/assets/images/emojis/marseybateman.webp and b/files/assets/images/emojis/marseybateman.webp differ diff --git a/files/assets/images/emojis/marseybath.webp b/files/assets/images/emojis/marseybath.webp index d8a608eb9..a0b040e18 100644 Binary files a/files/assets/images/emojis/marseybath.webp and b/files/assets/images/emojis/marseybath.webp differ diff --git a/files/assets/images/emojis/marseybattered.webp b/files/assets/images/emojis/marseybattered.webp index 4ef701413..5335f610b 100644 Binary files a/files/assets/images/emojis/marseybattered.webp and b/files/assets/images/emojis/marseybattered.webp differ diff --git a/files/assets/images/emojis/marseybeach.webp b/files/assets/images/emojis/marseybeach.webp index 6499e4e5a..2a945c3e1 100644 Binary files a/files/assets/images/emojis/marseybeach.webp and b/files/assets/images/emojis/marseybeach.webp differ diff --git a/files/assets/images/emojis/marseybean.webp b/files/assets/images/emojis/marseybean.webp index 005ef0a01..77d5be95e 100644 Binary files a/files/assets/images/emojis/marseybean.webp and b/files/assets/images/emojis/marseybean.webp differ diff --git a/files/assets/images/emojis/marseybeanadorable.webp b/files/assets/images/emojis/marseybeanadorable.webp index c3064b7d6..a98eb583e 100644 Binary files a/files/assets/images/emojis/marseybeanadorable.webp and b/files/assets/images/emojis/marseybeanadorable.webp differ diff --git a/files/assets/images/emojis/marseybeanangry.webp b/files/assets/images/emojis/marseybeanangry.webp index cef73a689..4daaf7cec 100644 Binary files a/files/assets/images/emojis/marseybeanangry.webp and b/files/assets/images/emojis/marseybeanangry.webp differ diff --git a/files/assets/images/emojis/marseybeanangryfbi.webp b/files/assets/images/emojis/marseybeanangryfbi.webp index a204dbe2a..cbcea7cdc 100644 Binary files a/files/assets/images/emojis/marseybeanangryfbi.webp and b/files/assets/images/emojis/marseybeanangryfbi.webp differ diff --git a/files/assets/images/emojis/marseybeanannoyed.webp b/files/assets/images/emojis/marseybeanannoyed.webp index 2bfce38a7..7652b8054 100644 Binary files a/files/assets/images/emojis/marseybeanannoyed.webp and b/files/assets/images/emojis/marseybeanannoyed.webp differ diff --git a/files/assets/images/emojis/marseybeanbigmad.webp b/files/assets/images/emojis/marseybeanbigmad.webp index 74604bea8..683d4d9ea 100644 Binary files a/files/assets/images/emojis/marseybeanbigmad.webp and b/files/assets/images/emojis/marseybeanbigmad.webp differ diff --git a/files/assets/images/emojis/marseybeandefiant.webp b/files/assets/images/emojis/marseybeandefiant.webp index c048d627a..c56ea736d 100644 Binary files a/files/assets/images/emojis/marseybeandefiant.webp and b/files/assets/images/emojis/marseybeandefiant.webp differ diff --git a/files/assets/images/emojis/marseybeandizzy.webp b/files/assets/images/emojis/marseybeandizzy.webp index bb348dc00..fb4c4cafe 100644 Binary files a/files/assets/images/emojis/marseybeandizzy.webp and b/files/assets/images/emojis/marseybeandizzy.webp differ diff --git a/files/assets/images/emojis/marseybeandoge.webp b/files/assets/images/emojis/marseybeandoge.webp index 5115e522c..237f33aac 100644 Binary files a/files/assets/images/emojis/marseybeandoge.webp and b/files/assets/images/emojis/marseybeandoge.webp differ diff --git a/files/assets/images/emojis/marseybeandrool.webp b/files/assets/images/emojis/marseybeandrool.webp index 1079fbf9a..188f8c33f 100644 Binary files a/files/assets/images/emojis/marseybeandrool.webp and b/files/assets/images/emojis/marseybeandrool.webp differ diff --git a/files/assets/images/emojis/marseybeanflushed.webp b/files/assets/images/emojis/marseybeanflushed.webp index e321cb5f5..c65e8a4a7 100644 Binary files a/files/assets/images/emojis/marseybeanflushed.webp and b/files/assets/images/emojis/marseybeanflushed.webp differ diff --git a/files/assets/images/emojis/marseybeanimp.webp b/files/assets/images/emojis/marseybeanimp.webp index 65fc373bb..203457a72 100644 Binary files a/files/assets/images/emojis/marseybeanimp.webp and b/files/assets/images/emojis/marseybeanimp.webp differ diff --git a/files/assets/images/emojis/marseybeanmonocle.webp b/files/assets/images/emojis/marseybeanmonocle.webp index 2718026ac..477cde284 100644 Binary files a/files/assets/images/emojis/marseybeanmonocle.webp and b/files/assets/images/emojis/marseybeanmonocle.webp differ diff --git a/files/assets/images/emojis/marseybeanpensive.webp b/files/assets/images/emojis/marseybeanpensive.webp index 2974b5ca6..866b345a8 100644 Binary files a/files/assets/images/emojis/marseybeanpensive.webp and b/files/assets/images/emojis/marseybeanpensive.webp differ diff --git a/files/assets/images/emojis/marseybeanpickle.webp b/files/assets/images/emojis/marseybeanpickle.webp index 4c0c98f3b..279638a9e 100644 Binary files a/files/assets/images/emojis/marseybeanpickle.webp and b/files/assets/images/emojis/marseybeanpickle.webp differ diff --git a/files/assets/images/emojis/marseybeanpizzashill.webp b/files/assets/images/emojis/marseybeanpizzashill.webp index 21b9d9e08..9a8a98b1e 100644 Binary files a/files/assets/images/emojis/marseybeanpizzashill.webp and b/files/assets/images/emojis/marseybeanpizzashill.webp differ diff --git a/files/assets/images/emojis/marseybeanpleading.webp b/files/assets/images/emojis/marseybeanpleading.webp index 7d96c9978..68ed3f222 100644 Binary files a/files/assets/images/emojis/marseybeanpleading.webp and b/files/assets/images/emojis/marseybeanpleading.webp differ diff --git a/files/assets/images/emojis/marseybeanpleased.webp b/files/assets/images/emojis/marseybeanpleased.webp index 2403810f6..7d0c28fbf 100644 Binary files a/files/assets/images/emojis/marseybeanpleased.webp and b/files/assets/images/emojis/marseybeanpleased.webp differ diff --git a/files/assets/images/emojis/marseybeanquestion.webp b/files/assets/images/emojis/marseybeanquestion.webp index ccfb1f14d..42352c2ea 100644 Binary files a/files/assets/images/emojis/marseybeanquestion.webp and b/files/assets/images/emojis/marseybeanquestion.webp differ diff --git a/files/assets/images/emojis/marseybeanrelieved.webp b/files/assets/images/emojis/marseybeanrelieved.webp index ad5c3e47f..7e7514db5 100644 Binary files a/files/assets/images/emojis/marseybeanrelieved.webp and b/files/assets/images/emojis/marseybeanrelieved.webp differ diff --git a/files/assets/images/emojis/marseybeansick.webp b/files/assets/images/emojis/marseybeansick.webp index da39b7862..c0eeac3c4 100644 Binary files a/files/assets/images/emojis/marseybeansick.webp and b/files/assets/images/emojis/marseybeansick.webp differ diff --git a/files/assets/images/emojis/marseybeantonguepoke.webp b/files/assets/images/emojis/marseybeantonguepoke.webp index 5e87e2698..28b7eda54 100644 Binary files a/files/assets/images/emojis/marseybeantonguepoke.webp and b/files/assets/images/emojis/marseybeantonguepoke.webp differ diff --git a/files/assets/images/emojis/marseybeantyrone.webp b/files/assets/images/emojis/marseybeantyrone.webp index 90e37d4ac..84c56a70a 100644 Binary files a/files/assets/images/emojis/marseybeantyrone.webp and b/files/assets/images/emojis/marseybeantyrone.webp differ diff --git a/files/assets/images/emojis/marseybeanupset.webp b/files/assets/images/emojis/marseybeanupset.webp index 017094a78..6ebf4f390 100644 Binary files a/files/assets/images/emojis/marseybeanupset.webp and b/files/assets/images/emojis/marseybeanupset.webp differ diff --git a/files/assets/images/emojis/marseybeanwink.webp b/files/assets/images/emojis/marseybeanwink.webp index 4f967957f..61590ba9c 100644 Binary files a/files/assets/images/emojis/marseybeanwink.webp and b/files/assets/images/emojis/marseybeanwink.webp differ diff --git a/files/assets/images/emojis/marseybear.webp b/files/assets/images/emojis/marseybear.webp index af31afcac..2c35cfdbc 100644 Binary files a/files/assets/images/emojis/marseybear.webp and b/files/assets/images/emojis/marseybear.webp differ diff --git a/files/assets/images/emojis/marseybear2.webp b/files/assets/images/emojis/marseybear2.webp index 3d50ef3e0..1af2a94e9 100644 Binary files a/files/assets/images/emojis/marseybear2.webp and b/files/assets/images/emojis/marseybear2.webp differ diff --git a/files/assets/images/emojis/marseybeaver.webp b/files/assets/images/emojis/marseybeaver.webp index 106b99b5f..022e16a03 100644 Binary files a/files/assets/images/emojis/marseybeaver.webp and b/files/assets/images/emojis/marseybeaver.webp differ diff --git a/files/assets/images/emojis/marseybedsick.webp b/files/assets/images/emojis/marseybedsick.webp index e90e0e55d..cf0558444 100644 Binary files a/files/assets/images/emojis/marseybedsick.webp and b/files/assets/images/emojis/marseybedsick.webp differ diff --git a/files/assets/images/emojis/marseybeekeeper.webp b/files/assets/images/emojis/marseybeekeeper.webp index 37d2ae6b7..9a612c0ae 100644 Binary files a/files/assets/images/emojis/marseybeekeeper.webp and b/files/assets/images/emojis/marseybeekeeper.webp differ diff --git a/files/assets/images/emojis/marseybeggar.webp b/files/assets/images/emojis/marseybeggar.webp index 152a165f7..3fc6e3ee2 100644 Binary files a/files/assets/images/emojis/marseybeggar.webp and b/files/assets/images/emojis/marseybeggar.webp differ diff --git a/files/assets/images/emojis/marseybegoneprot.webp b/files/assets/images/emojis/marseybegoneprot.webp new file mode 100644 index 000000000..a11f7567b Binary files /dev/null and b/files/assets/images/emojis/marseybegoneprot.webp differ diff --git a/files/assets/images/emojis/marseybegonethot.webp b/files/assets/images/emojis/marseybegonethot.webp index ca91ef72d..27af59954 100644 Binary files a/files/assets/images/emojis/marseybegonethot.webp and b/files/assets/images/emojis/marseybegonethot.webp differ diff --git a/files/assets/images/emojis/marseyben10.webp b/files/assets/images/emojis/marseyben10.webp index cd4d9e2ae..e2d28f2ab 100644 Binary files a/files/assets/images/emojis/marseyben10.webp and b/files/assets/images/emojis/marseyben10.webp differ diff --git a/files/assets/images/emojis/marseybestfriends.webp b/files/assets/images/emojis/marseybestfriends.webp index b3dc35280..03ae287da 100644 Binary files a/files/assets/images/emojis/marseybestfriends.webp and b/files/assets/images/emojis/marseybestfriends.webp differ diff --git a/files/assets/images/emojis/marseybetauprising.webp b/files/assets/images/emojis/marseybetauprising.webp index 98cd80241..cfa79aa75 100644 Binary files a/files/assets/images/emojis/marseybetauprising.webp and b/files/assets/images/emojis/marseybetauprising.webp differ diff --git a/files/assets/images/emojis/marseybiast.webp b/files/assets/images/emojis/marseybiast.webp new file mode 100644 index 000000000..267beba97 Binary files /dev/null and b/files/assets/images/emojis/marseybiast.webp differ diff --git a/files/assets/images/emojis/marseybib.webp b/files/assets/images/emojis/marseybib.webp new file mode 100644 index 000000000..bdafcb355 Binary files /dev/null and b/files/assets/images/emojis/marseybib.webp differ diff --git a/files/assets/images/emojis/marseybiden.webp b/files/assets/images/emojis/marseybiden.webp index 88759c58b..cb0c7a80b 100644 Binary files a/files/assets/images/emojis/marseybiden.webp and b/files/assets/images/emojis/marseybiden.webp differ diff --git a/files/assets/images/emojis/marseybiden2.webp b/files/assets/images/emojis/marseybiden2.webp index 6af46c35e..69b6f5784 100644 Binary files a/files/assets/images/emojis/marseybiden2.webp and b/files/assets/images/emojis/marseybiden2.webp differ diff --git a/files/assets/images/emojis/marseybigbrain.webp b/files/assets/images/emojis/marseybigbrain.webp index 3cc5bf53a..cef7f1452 100644 Binary files a/files/assets/images/emojis/marseybigbrain.webp and b/files/assets/images/emojis/marseybigbrain.webp differ diff --git a/files/assets/images/emojis/marseybigdog.webp b/files/assets/images/emojis/marseybigdog.webp index 5592aa9d2..4a79406d0 100644 Binary files a/files/assets/images/emojis/marseybigdog.webp and b/files/assets/images/emojis/marseybigdog.webp differ diff --git a/files/assets/images/emojis/marseybigfoot.webp b/files/assets/images/emojis/marseybigfoot.webp index 8a13d9e31..d717b863a 100644 Binary files a/files/assets/images/emojis/marseybigfoot.webp and b/files/assets/images/emojis/marseybigfoot.webp differ diff --git a/files/assets/images/emojis/marseybikechainincident.webp b/files/assets/images/emojis/marseybikechainincident.webp new file mode 100644 index 000000000..abb26f947 Binary files /dev/null and b/files/assets/images/emojis/marseybikechainincident.webp differ diff --git a/files/assets/images/emojis/marseybikecuck.webp b/files/assets/images/emojis/marseybikecuck.webp index 4ee7a3548..9ce8cd142 100644 Binary files a/files/assets/images/emojis/marseybikecuck.webp and b/files/assets/images/emojis/marseybikecuck.webp differ diff --git a/files/assets/images/emojis/marseybiker.webp b/files/assets/images/emojis/marseybiker.webp index d0e0d2c6c..fac546015 100644 Binary files a/files/assets/images/emojis/marseybiker.webp and b/files/assets/images/emojis/marseybiker.webp differ diff --git a/files/assets/images/emojis/marseybingus.webp b/files/assets/images/emojis/marseybingus.webp index 3c5c6e1ed..dff2b0ddb 100644 Binary files a/files/assets/images/emojis/marseybingus.webp and b/files/assets/images/emojis/marseybingus.webp differ diff --git a/files/assets/images/emojis/marseybinladen.webp b/files/assets/images/emojis/marseybinladen.webp index 209a29dbf..1c13b1b35 100644 Binary files a/files/assets/images/emojis/marseybinladen.webp and b/files/assets/images/emojis/marseybinladen.webp differ diff --git a/files/assets/images/emojis/marseybipocmerchant.webp b/files/assets/images/emojis/marseybipocmerchant.webp new file mode 100644 index 000000000..6aba237e3 Binary files /dev/null and b/files/assets/images/emojis/marseybipocmerchant.webp differ diff --git a/files/assets/images/emojis/marseybiting.webp b/files/assets/images/emojis/marseybiting.webp index 68e170535..9155e60c3 100644 Binary files a/files/assets/images/emojis/marseybiting.webp and b/files/assets/images/emojis/marseybiting.webp differ diff --git a/files/assets/images/emojis/marseyblack.webp b/files/assets/images/emojis/marseyblack.webp index b7e2ecd48..e041635f6 100644 Binary files a/files/assets/images/emojis/marseyblack.webp and b/files/assets/images/emojis/marseyblack.webp differ diff --git a/files/assets/images/emojis/marseyblack2.webp b/files/assets/images/emojis/marseyblack2.webp index 09a100b89..6e03195b8 100644 Binary files a/files/assets/images/emojis/marseyblack2.webp and b/files/assets/images/emojis/marseyblack2.webp differ diff --git a/files/assets/images/emojis/marseyblackcat.webp b/files/assets/images/emojis/marseyblackcat.webp new file mode 100644 index 000000000..53ee94554 Binary files /dev/null and b/files/assets/images/emojis/marseyblackcat.webp differ diff --git a/files/assets/images/emojis/marseyblackcock.webp b/files/assets/images/emojis/marseyblackcock.webp index 3025c72f4..8c80ceff2 100644 Binary files a/files/assets/images/emojis/marseyblackcock.webp and b/files/assets/images/emojis/marseyblackcock.webp differ diff --git a/files/assets/images/emojis/marseyblackcop.webp b/files/assets/images/emojis/marseyblackcop.webp index 056d115da..4936f5b5b 100644 Binary files a/files/assets/images/emojis/marseyblackcop.webp and b/files/assets/images/emojis/marseyblackcop.webp differ diff --git a/files/assets/images/emojis/marseyblackface.webp b/files/assets/images/emojis/marseyblackface.webp index d9d2a99c6..e81cf3b0d 100644 Binary files a/files/assets/images/emojis/marseyblackface.webp and b/files/assets/images/emojis/marseyblackface.webp differ diff --git a/files/assets/images/emojis/marseyblackfacexmas.webp b/files/assets/images/emojis/marseyblackfacexmas.webp index 8021ff4d8..28a3d726d 100644 Binary files a/files/assets/images/emojis/marseyblackfacexmas.webp and b/files/assets/images/emojis/marseyblackfacexmas.webp differ diff --git a/files/assets/images/emojis/marseyblackgenocide.webp b/files/assets/images/emojis/marseyblackgenocide.webp new file mode 100644 index 000000000..8e7f73314 Binary files /dev/null and b/files/assets/images/emojis/marseyblackgenocide.webp differ diff --git a/files/assets/images/emojis/marseyblackjak.webp b/files/assets/images/emojis/marseyblackjak.webp index 1824b4dbb..44901c2d8 100644 Binary files a/files/assets/images/emojis/marseyblackjak.webp and b/files/assets/images/emojis/marseyblackjak.webp differ diff --git a/files/assets/images/emojis/marseyblackmage.webp b/files/assets/images/emojis/marseyblackmage.webp index 40b423621..ef3927435 100644 Binary files a/files/assets/images/emojis/marseyblackmage.webp and b/files/assets/images/emojis/marseyblackmage.webp differ diff --git a/files/assets/images/emojis/marseyblackpearlclutch.webp b/files/assets/images/emojis/marseyblackpearlclutch.webp index d511e8790..0a1dd2835 100644 Binary files a/files/assets/images/emojis/marseyblackpearlclutch.webp and b/files/assets/images/emojis/marseyblackpearlclutch.webp differ diff --git a/files/assets/images/emojis/marseyblackphillip.webp b/files/assets/images/emojis/marseyblackphillip.webp new file mode 100644 index 000000000..89597e9eb Binary files /dev/null and b/files/assets/images/emojis/marseyblackphillip.webp differ diff --git a/files/assets/images/emojis/marseyblep.webp b/files/assets/images/emojis/marseyblep.webp new file mode 100644 index 000000000..3cdb7cb32 Binary files /dev/null and b/files/assets/images/emojis/marseyblep.webp differ diff --git a/files/assets/images/emojis/marseyblep2.webp b/files/assets/images/emojis/marseyblep2.webp new file mode 100644 index 000000000..ac67d573a Binary files /dev/null and b/files/assets/images/emojis/marseyblep2.webp differ diff --git a/files/assets/images/emojis/marseyblep3.webp b/files/assets/images/emojis/marseyblep3.webp new file mode 100644 index 000000000..f57fd0870 Binary files /dev/null and b/files/assets/images/emojis/marseyblep3.webp differ diff --git a/files/assets/images/emojis/marseyblind.webp b/files/assets/images/emojis/marseyblind.webp index faeb41f29..8a8d59ad9 100644 Binary files a/files/assets/images/emojis/marseyblind.webp and b/files/assets/images/emojis/marseyblind.webp differ diff --git a/files/assets/images/emojis/marseyblm.webp b/files/assets/images/emojis/marseyblm.webp index 80203d390..d84e9cb62 100644 Binary files a/files/assets/images/emojis/marseyblm.webp and b/files/assets/images/emojis/marseyblm.webp differ diff --git a/files/assets/images/emojis/marseybloat.webp b/files/assets/images/emojis/marseybloat.webp index 5ef47a9ff..20eee02d8 100644 Binary files a/files/assets/images/emojis/marseybloat.webp and b/files/assets/images/emojis/marseybloat.webp differ diff --git a/files/assets/images/emojis/marseyblob.webp b/files/assets/images/emojis/marseyblob.webp index 3acd6b93e..78d7f6bf8 100644 Binary files a/files/assets/images/emojis/marseyblob.webp and b/files/assets/images/emojis/marseyblob.webp differ diff --git a/files/assets/images/emojis/marseybloodborne.webp b/files/assets/images/emojis/marseybloodborne.webp index 5b19b8cb7..5af621a50 100644 Binary files a/files/assets/images/emojis/marseybloodborne.webp and b/files/assets/images/emojis/marseybloodborne.webp differ diff --git a/files/assets/images/emojis/marseybloodpuddle.webp b/files/assets/images/emojis/marseybloodpuddle.webp new file mode 100644 index 000000000..33f79ce16 Binary files /dev/null and b/files/assets/images/emojis/marseybloodpuddle.webp differ diff --git a/files/assets/images/emojis/marseyblops2cel.webp b/files/assets/images/emojis/marseyblops2cel.webp index 1297c10eb..3f29d9908 100644 Binary files a/files/assets/images/emojis/marseyblops2cel.webp and b/files/assets/images/emojis/marseyblops2cel.webp differ diff --git a/files/assets/images/emojis/marseyblops2chadcel.webp b/files/assets/images/emojis/marseyblops2chadcel.webp index c6e083497..aed3ddcef 100644 Binary files a/files/assets/images/emojis/marseyblops2chadcel.webp and b/files/assets/images/emojis/marseyblops2chadcel.webp differ diff --git a/files/assets/images/emojis/marseyblops2chadcel2.webp b/files/assets/images/emojis/marseyblops2chadcel2.webp index 7a2631a1d..7c0a98ccf 100644 Binary files a/files/assets/images/emojis/marseyblops2chadcel2.webp and b/files/assets/images/emojis/marseyblops2chadcel2.webp differ diff --git a/files/assets/images/emojis/marseyblowkiss.webp b/files/assets/images/emojis/marseyblowkiss.webp index e7c22808e..f7227c48c 100644 Binary files a/files/assets/images/emojis/marseyblowkiss.webp and b/files/assets/images/emojis/marseyblowkiss.webp differ diff --git a/files/assets/images/emojis/marseyblueanime.webp b/files/assets/images/emojis/marseyblueanime.webp index 773e54e5c..0fefef792 100644 Binary files a/files/assets/images/emojis/marseyblueanime.webp and b/files/assets/images/emojis/marseyblueanime.webp differ diff --git a/files/assets/images/emojis/marseybluecheck.webp b/files/assets/images/emojis/marseybluecheck.webp index 6d74e7e52..596b8bd29 100644 Binary files a/files/assets/images/emojis/marseybluecheck.webp and b/files/assets/images/emojis/marseybluecheck.webp differ diff --git a/files/assets/images/emojis/marseybluehands.webp b/files/assets/images/emojis/marseybluehands.webp index a50d8e204..22252dc3d 100644 Binary files a/files/assets/images/emojis/marseybluehands.webp and b/files/assets/images/emojis/marseybluehands.webp differ diff --git a/files/assets/images/emojis/marseyblush.webp b/files/assets/images/emojis/marseyblush.webp index f3703b521..616c4f7c7 100644 Binary files a/files/assets/images/emojis/marseyblush.webp and b/files/assets/images/emojis/marseyblush.webp differ diff --git a/files/assets/images/emojis/marseybobpage.webp b/files/assets/images/emojis/marseybobpage.webp index ca687e92a..4e3290713 100644 Binary files a/files/assets/images/emojis/marseybobpage.webp and b/files/assets/images/emojis/marseybobpage.webp differ diff --git a/files/assets/images/emojis/marseybog.webp b/files/assets/images/emojis/marseybog.webp index abc7e6eb4..a47b62408 100644 Binary files a/files/assets/images/emojis/marseybog.webp and b/files/assets/images/emojis/marseybog.webp differ diff --git a/files/assets/images/emojis/marseybong.webp b/files/assets/images/emojis/marseybong.webp index db955413c..79db8f7aa 100644 Binary files a/files/assets/images/emojis/marseybong.webp and b/files/assets/images/emojis/marseybong.webp differ diff --git a/files/assets/images/emojis/marseybongcop.webp b/files/assets/images/emojis/marseybongcop.webp index 6904bbd59..d226f1c3c 100644 Binary files a/files/assets/images/emojis/marseybongcop.webp and b/files/assets/images/emojis/marseybongcop.webp differ diff --git a/files/assets/images/emojis/marseybonk.webp b/files/assets/images/emojis/marseybonk.webp index 382aa346e..6a6e4560b 100644 Binary files a/files/assets/images/emojis/marseybonk.webp and b/files/assets/images/emojis/marseybonk.webp differ diff --git a/files/assets/images/emojis/marseyboomer.webp b/files/assets/images/emojis/marseyboomer.webp index a481952c4..59c959783 100644 Binary files a/files/assets/images/emojis/marseyboomer.webp and b/files/assets/images/emojis/marseyboomer.webp differ diff --git a/files/assets/images/emojis/marseyboomercartoon.webp b/files/assets/images/emojis/marseyboomercartoon.webp index 24221a1d0..bdfc6f3f3 100644 Binary files a/files/assets/images/emojis/marseyboomercartoon.webp and b/files/assets/images/emojis/marseyboomercartoon.webp differ diff --git a/files/assets/images/emojis/marseybootlicker.webp b/files/assets/images/emojis/marseybootlicker.webp index 5f8e7877b..2d16a25af 100644 Binary files a/files/assets/images/emojis/marseybootlicker.webp and b/files/assets/images/emojis/marseybootlicker.webp differ diff --git a/files/assets/images/emojis/marseybootlicker2.webp b/files/assets/images/emojis/marseybootlicker2.webp index 174877a51..61235a68e 100644 Binary files a/files/assets/images/emojis/marseybootlicker2.webp and b/files/assets/images/emojis/marseybootlicker2.webp differ diff --git a/files/assets/images/emojis/marseybountyhunter.webp b/files/assets/images/emojis/marseybountyhunter.webp index 3839bbca6..6fb8c29be 100644 Binary files a/files/assets/images/emojis/marseybountyhunter.webp and b/files/assets/images/emojis/marseybountyhunter.webp differ diff --git a/files/assets/images/emojis/marseybow.webp b/files/assets/images/emojis/marseybow.webp index 8a1c26445..6ee5f5bcb 100644 Binary files a/files/assets/images/emojis/marseybow.webp and b/files/assets/images/emojis/marseybow.webp differ diff --git a/files/assets/images/emojis/marseybowl.webp b/files/assets/images/emojis/marseybowl.webp index ea449fb8c..01d06ebba 100644 Binary files a/files/assets/images/emojis/marseybowl.webp and b/files/assets/images/emojis/marseybowl.webp differ diff --git a/files/assets/images/emojis/marseybrainlet.webp b/files/assets/images/emojis/marseybrainlet.webp index 91eb46d6d..26cb6d5bc 100644 Binary files a/files/assets/images/emojis/marseybrainlet.webp and b/files/assets/images/emojis/marseybrainlet.webp differ diff --git a/files/assets/images/emojis/marseybrasileiro.webp b/files/assets/images/emojis/marseybrasileiro.webp index a3376a79d..18ca392d1 100644 Binary files a/files/assets/images/emojis/marseybrasileiro.webp and b/files/assets/images/emojis/marseybrasileiro.webp differ diff --git a/files/assets/images/emojis/marseybrave.webp b/files/assets/images/emojis/marseybrave.webp index 544c2ae15..9f3c46d13 100644 Binary files a/files/assets/images/emojis/marseybrave.webp and b/files/assets/images/emojis/marseybrave.webp differ diff --git a/files/assets/images/emojis/marseybraveheart.webp b/files/assets/images/emojis/marseybraveheart.webp index 5e34cebe3..9b1d46351 100644 Binary files a/files/assets/images/emojis/marseybraveheart.webp and b/files/assets/images/emojis/marseybraveheart.webp differ diff --git a/files/assets/images/emojis/marseybreastcancer.webp b/files/assets/images/emojis/marseybreastcancer.webp index b1080f6cd..098880ec8 100644 Binary files a/files/assets/images/emojis/marseybreastcancer.webp and b/files/assets/images/emojis/marseybreastcancer.webp differ diff --git a/files/assets/images/emojis/marseybrianna.webp b/files/assets/images/emojis/marseybrianna.webp index e873453ef..6521662b1 100644 Binary files a/files/assets/images/emojis/marseybrianna.webp and b/files/assets/images/emojis/marseybrianna.webp differ diff --git a/files/assets/images/emojis/marseybrianna2.webp b/files/assets/images/emojis/marseybrianna2.webp index a5ee6d2cb..9a8619ab8 100644 Binary files a/files/assets/images/emojis/marseybrianna2.webp and b/files/assets/images/emojis/marseybrianna2.webp differ diff --git a/files/assets/images/emojis/marseybrick.webp b/files/assets/images/emojis/marseybrick.webp index b98557a43..716ea32c4 100644 Binary files a/files/assets/images/emojis/marseybrick.webp and b/files/assets/images/emojis/marseybrick.webp differ diff --git a/files/assets/images/emojis/marseybride.webp b/files/assets/images/emojis/marseybride.webp index 73849daaf..3d8eefd12 100644 Binary files a/files/assets/images/emojis/marseybride.webp and b/files/assets/images/emojis/marseybride.webp differ diff --git a/files/assets/images/emojis/marseybruh.webp b/files/assets/images/emojis/marseybruh.webp index 20cef73d1..f3556994c 100644 Binary files a/files/assets/images/emojis/marseybruh.webp and b/files/assets/images/emojis/marseybruh.webp differ diff --git a/files/assets/images/emojis/marseybruh2.webp b/files/assets/images/emojis/marseybruh2.webp index 939fac347..dbaab5522 100644 Binary files a/files/assets/images/emojis/marseybruh2.webp and b/files/assets/images/emojis/marseybruh2.webp differ diff --git a/files/assets/images/emojis/marseybsod.webp b/files/assets/images/emojis/marseybsod.webp index c5a5d4768..cc3adf3a6 100644 Binary files a/files/assets/images/emojis/marseybsod.webp and b/files/assets/images/emojis/marseybsod.webp differ diff --git a/files/assets/images/emojis/marseybudddwyer.webp b/files/assets/images/emojis/marseybudddwyer.webp index 1fd2d50a3..a1f9f8052 100644 Binary files a/files/assets/images/emojis/marseybudddwyer.webp and b/files/assets/images/emojis/marseybudddwyer.webp differ diff --git a/files/assets/images/emojis/marseybuff.webp b/files/assets/images/emojis/marseybuff.webp index 57bddf88e..9b918e26c 100644 Binary files a/files/assets/images/emojis/marseybuff.webp and b/files/assets/images/emojis/marseybuff.webp differ diff --git a/files/assets/images/emojis/marseybug.webp b/files/assets/images/emojis/marseybug.webp index a20e2a021..c1737a1ba 100644 Binary files a/files/assets/images/emojis/marseybug.webp and b/files/assets/images/emojis/marseybug.webp differ diff --git a/files/assets/images/emojis/marseybug2.webp b/files/assets/images/emojis/marseybug2.webp index 851ba7b9d..6bee783a5 100644 Binary files a/files/assets/images/emojis/marseybug2.webp and b/files/assets/images/emojis/marseybug2.webp differ diff --git a/files/assets/images/emojis/marseybukkake.webp b/files/assets/images/emojis/marseybukkake.webp index 335cc1ad3..0ed3b887c 100644 Binary files a/files/assets/images/emojis/marseybukkake.webp and b/files/assets/images/emojis/marseybukkake.webp differ diff --git a/files/assets/images/emojis/marseybunny.webp b/files/assets/images/emojis/marseybunny.webp index 422f169e2..ccbb621f8 100644 Binary files a/files/assets/images/emojis/marseybunny.webp and b/files/assets/images/emojis/marseybunny.webp differ diff --git a/files/assets/images/emojis/marseyburger.webp b/files/assets/images/emojis/marseyburger.webp index 5179cf635..0f032d2b9 100644 Binary files a/files/assets/images/emojis/marseyburger.webp and b/files/assets/images/emojis/marseyburger.webp differ diff --git a/files/assets/images/emojis/marseyburn.webp b/files/assets/images/emojis/marseyburn.webp index f1841c2e2..2e0392ef7 100644 Binary files a/files/assets/images/emojis/marseyburn.webp and b/files/assets/images/emojis/marseyburn.webp differ diff --git a/files/assets/images/emojis/marseyburnedman.webp b/files/assets/images/emojis/marseyburnedman.webp index 44793384c..ba70a0999 100644 Binary files a/files/assets/images/emojis/marseyburnedman.webp and b/files/assets/images/emojis/marseyburnedman.webp differ diff --git a/files/assets/images/emojis/marseyburrito.webp b/files/assets/images/emojis/marseyburrito.webp index 9448d3e64..d300d449b 100644 Binary files a/files/assets/images/emojis/marseyburrito.webp and b/files/assets/images/emojis/marseyburrito.webp differ diff --git a/files/assets/images/emojis/marseybush.webp b/files/assets/images/emojis/marseybush.webp index f3e2fc65c..5217b2fc3 100644 Binary files a/files/assets/images/emojis/marseybush.webp and b/files/assets/images/emojis/marseybush.webp differ diff --git a/files/assets/images/emojis/marseybussy.webp b/files/assets/images/emojis/marseybussy.webp index bdcfe566a..dfb24bb23 100644 Binary files a/files/assets/images/emojis/marseybussy.webp and b/files/assets/images/emojis/marseybussy.webp differ diff --git a/files/assets/images/emojis/marseybutt.webp b/files/assets/images/emojis/marseybutt.webp index a2947e0c4..36ba396cd 100644 Binary files a/files/assets/images/emojis/marseybutt.webp and b/files/assets/images/emojis/marseybutt.webp differ diff --git a/files/assets/images/emojis/marseybutt2.webp b/files/assets/images/emojis/marseybutt2.webp new file mode 100644 index 000000000..6f7eabfd2 Binary files /dev/null and b/files/assets/images/emojis/marseybutt2.webp differ diff --git a/files/assets/images/emojis/marseybuttface.webp b/files/assets/images/emojis/marseybuttface.webp index d0a841aab..7d45048eb 100644 Binary files a/files/assets/images/emojis/marseybuttface.webp and b/files/assets/images/emojis/marseybuttface.webp differ diff --git a/files/assets/images/emojis/marseybux.webp b/files/assets/images/emojis/marseybux.webp index fbed5c59f..e6794b6a1 100644 Binary files a/files/assets/images/emojis/marseybux.webp and b/files/assets/images/emojis/marseybux.webp differ diff --git a/files/assets/images/emojis/marseybyeceps.webp b/files/assets/images/emojis/marseybyeceps.webp index 73db48773..d4b885e11 100644 Binary files a/files/assets/images/emojis/marseybyeceps.webp and b/files/assets/images/emojis/marseybyeceps.webp differ diff --git a/files/assets/images/emojis/marseycactuar.webp b/files/assets/images/emojis/marseycactuar.webp index d3884ec39..925917b10 100644 Binary files a/files/assets/images/emojis/marseycactuar.webp and b/files/assets/images/emojis/marseycactuar.webp differ diff --git a/files/assets/images/emojis/marseycalarts.webp b/files/assets/images/emojis/marseycalarts.webp index b0b82a2d2..14bbc9a53 100644 Binary files a/files/assets/images/emojis/marseycalarts.webp and b/files/assets/images/emojis/marseycalarts.webp differ diff --git a/files/assets/images/emojis/marseycalendar.webp b/files/assets/images/emojis/marseycalendar.webp index 73a97df66..acccc1886 100644 Binary files a/files/assets/images/emojis/marseycalendar.webp and b/files/assets/images/emojis/marseycalendar.webp differ diff --git a/files/assets/images/emojis/marseycalm.webp b/files/assets/images/emojis/marseycalm.webp new file mode 100644 index 000000000..9ba777653 Binary files /dev/null and b/files/assets/images/emojis/marseycalm.webp differ diff --git a/files/assets/images/emojis/marseycalvin.webp b/files/assets/images/emojis/marseycalvin.webp index 53e89fe0c..cdcd741c1 100644 Binary files a/files/assets/images/emojis/marseycalvin.webp and b/files/assets/images/emojis/marseycalvin.webp differ diff --git a/files/assets/images/emojis/marseycamus.webp b/files/assets/images/emojis/marseycamus.webp index 7599c94fc..1873e8739 100644 Binary files a/files/assets/images/emojis/marseycamus.webp and b/files/assets/images/emojis/marseycamus.webp differ diff --git a/files/assets/images/emojis/marseycandy.webp b/files/assets/images/emojis/marseycandy.webp new file mode 100644 index 000000000..5a37d9bfe Binary files /dev/null and b/files/assets/images/emojis/marseycandy.webp differ diff --git a/files/assets/images/emojis/marseycanned.webp b/files/assets/images/emojis/marseycanned.webp index e20051cad..788ac5c27 100644 Binary files a/files/assets/images/emojis/marseycanned.webp and b/files/assets/images/emojis/marseycanned.webp differ diff --git a/files/assets/images/emojis/marseycantsneed.webp b/files/assets/images/emojis/marseycantsneed.webp index 317406b75..f8a886319 100644 Binary files a/files/assets/images/emojis/marseycantsneed.webp and b/files/assets/images/emojis/marseycantsneed.webp differ diff --git a/files/assets/images/emojis/marseycapitalistmanlet.webp b/files/assets/images/emojis/marseycapitalistmanlet.webp index 3adbbc763..33f4b5189 100644 Binary files a/files/assets/images/emojis/marseycapitalistmanlet.webp and b/files/assets/images/emojis/marseycapitalistmanlet.webp differ diff --git a/files/assets/images/emojis/marseycapy.webp b/files/assets/images/emojis/marseycapy.webp index 6cb25a0a5..effec1b2a 100644 Binary files a/files/assets/images/emojis/marseycapy.webp and b/files/assets/images/emojis/marseycapy.webp differ diff --git a/files/assets/images/emojis/marseycapyautism.webp b/files/assets/images/emojis/marseycapyautism.webp index aeb67d305..5f903bf5c 100644 Binary files a/files/assets/images/emojis/marseycapyautism.webp and b/files/assets/images/emojis/marseycapyautism.webp differ diff --git a/files/assets/images/emojis/marseycapyautismchad.webp b/files/assets/images/emojis/marseycapyautismchad.webp index a31251901..fec20071c 100644 Binary files a/files/assets/images/emojis/marseycapyautismchad.webp and b/files/assets/images/emojis/marseycapyautismchad.webp differ diff --git a/files/assets/images/emojis/marseycapybigbrain.webp b/files/assets/images/emojis/marseycapybigbrain.webp index cee680e6e..7d4019907 100644 Binary files a/files/assets/images/emojis/marseycapybigbrain.webp and b/files/assets/images/emojis/marseycapybigbrain.webp differ diff --git a/files/assets/images/emojis/marseycapyblackface.webp b/files/assets/images/emojis/marseycapyblackface.webp index 0276ad374..ab49034c1 100644 Binary files a/files/assets/images/emojis/marseycapyblackface.webp and b/files/assets/images/emojis/marseycapyblackface.webp differ diff --git a/files/assets/images/emojis/marseycapyblowkiss.webp b/files/assets/images/emojis/marseycapyblowkiss.webp index 113f369af..1fe37d2db 100644 Binary files a/files/assets/images/emojis/marseycapyblowkiss.webp and b/files/assets/images/emojis/marseycapyblowkiss.webp differ diff --git a/files/assets/images/emojis/marseycapychad.webp b/files/assets/images/emojis/marseycapychad.webp index ac437e50c..877d8c606 100644 Binary files a/files/assets/images/emojis/marseycapychad.webp and b/files/assets/images/emojis/marseycapychad.webp differ diff --git a/files/assets/images/emojis/marseycapychad2.webp b/files/assets/images/emojis/marseycapychad2.webp index 43734f413..f75cd430c 100644 Binary files a/files/assets/images/emojis/marseycapychad2.webp and b/files/assets/images/emojis/marseycapychad2.webp differ diff --git a/files/assets/images/emojis/marseycapychad3.webp b/files/assets/images/emojis/marseycapychad3.webp index 45175a307..b3580d40b 100644 Binary files a/files/assets/images/emojis/marseycapychad3.webp and b/files/assets/images/emojis/marseycapychad3.webp differ diff --git a/files/assets/images/emojis/marseycapydinosaur.webp b/files/assets/images/emojis/marseycapydinosaur.webp index 587753c17..359d0d337 100644 Binary files a/files/assets/images/emojis/marseycapydinosaur.webp and b/files/assets/images/emojis/marseycapydinosaur.webp differ diff --git a/files/assets/images/emojis/marseycapyeffendi.webp b/files/assets/images/emojis/marseycapyeffendi.webp index 9c0438698..164844523 100644 Binary files a/files/assets/images/emojis/marseycapyeffendi.webp and b/files/assets/images/emojis/marseycapyeffendi.webp differ diff --git a/files/assets/images/emojis/marseycapygigabrain.webp b/files/assets/images/emojis/marseycapygigabrain.webp index 17bb37fb9..b63339ed3 100644 Binary files a/files/assets/images/emojis/marseycapygigabrain.webp and b/files/assets/images/emojis/marseycapygigabrain.webp differ diff --git a/files/assets/images/emojis/marseycapyheart.webp b/files/assets/images/emojis/marseycapyheart.webp index a78aa4aa0..43312e7c4 100644 Binary files a/files/assets/images/emojis/marseycapyheart.webp and b/files/assets/images/emojis/marseycapyheart.webp differ diff --git a/files/assets/images/emojis/marseycapykiss.webp b/files/assets/images/emojis/marseycapykiss.webp index 51a892b76..702d3fb7b 100644 Binary files a/files/assets/images/emojis/marseycapykiss.webp and b/files/assets/images/emojis/marseycapykiss.webp differ diff --git a/files/assets/images/emojis/marseycapylove.webp b/files/assets/images/emojis/marseycapylove.webp index bc8e93a3e..13c6a097b 100644 Binary files a/files/assets/images/emojis/marseycapylove.webp and b/files/assets/images/emojis/marseycapylove.webp differ diff --git a/files/assets/images/emojis/marseycapymerchant.webp b/files/assets/images/emojis/marseycapymerchant.webp index c1f4b5fe1..729b2371a 100644 Binary files a/files/assets/images/emojis/marseycapymerchant.webp and b/files/assets/images/emojis/marseycapymerchant.webp differ diff --git a/files/assets/images/emojis/marseycapynut.webp b/files/assets/images/emojis/marseycapynut.webp index a31e467be..1821df794 100644 Binary files a/files/assets/images/emojis/marseycapynut.webp and b/files/assets/images/emojis/marseycapynut.webp differ diff --git a/files/assets/images/emojis/marseycapypharaoh.webp b/files/assets/images/emojis/marseycapypharaoh.webp index 25e7150e4..ccd9659a4 100644 Binary files a/files/assets/images/emojis/marseycapypharaoh.webp and b/files/assets/images/emojis/marseycapypharaoh.webp differ diff --git a/files/assets/images/emojis/marseycapypunished.webp b/files/assets/images/emojis/marseycapypunished.webp index 6e1a678bb..5ef2865dd 100644 Binary files a/files/assets/images/emojis/marseycapypunished.webp and b/files/assets/images/emojis/marseycapypunished.webp differ diff --git a/files/assets/images/emojis/marseycapyshy.webp b/files/assets/images/emojis/marseycapyshy.webp index 80b2efc5a..044e8a1f4 100644 Binary files a/files/assets/images/emojis/marseycapyshy.webp and b/files/assets/images/emojis/marseycapyshy.webp differ diff --git a/files/assets/images/emojis/marseycapysuezcanal.webp b/files/assets/images/emojis/marseycapysuezcanal.webp index 63967ff0c..4741ef675 100644 Binary files a/files/assets/images/emojis/marseycapysuezcanal.webp and b/files/assets/images/emojis/marseycapysuezcanal.webp differ diff --git a/files/assets/images/emojis/marseycapytrans.webp b/files/assets/images/emojis/marseycapytrans.webp index 54f9f27d7..8a9ec56e5 100644 Binary files a/files/assets/images/emojis/marseycapytrans.webp and b/files/assets/images/emojis/marseycapytrans.webp differ diff --git a/files/assets/images/emojis/marseycard.webp b/files/assets/images/emojis/marseycard.webp index 339567c0c..528c69385 100644 Binary files a/files/assets/images/emojis/marseycard.webp and b/files/assets/images/emojis/marseycard.webp differ diff --git a/files/assets/images/emojis/marseycarp.webp b/files/assets/images/emojis/marseycarp.webp index 488793963..a1519c8d8 100644 Binary files a/files/assets/images/emojis/marseycarp.webp and b/files/assets/images/emojis/marseycarp.webp differ diff --git a/files/assets/images/emojis/marseycarp3.webp b/files/assets/images/emojis/marseycarp3.webp index 1bb00c381..e0bdfd54e 100644 Binary files a/files/assets/images/emojis/marseycarp3.webp and b/files/assets/images/emojis/marseycarp3.webp differ diff --git a/files/assets/images/emojis/marseycarp4.webp b/files/assets/images/emojis/marseycarp4.webp index 878896310..8acc29332 100644 Binary files a/files/assets/images/emojis/marseycarp4.webp and b/files/assets/images/emojis/marseycarp4.webp differ diff --git a/files/assets/images/emojis/marseycarpabusivewife.webp b/files/assets/images/emojis/marseycarpabusivewife.webp new file mode 100644 index 000000000..695b67c20 Binary files /dev/null and b/files/assets/images/emojis/marseycarpabusivewife.webp differ diff --git a/files/assets/images/emojis/marseycarpasian.webp b/files/assets/images/emojis/marseycarpasian.webp index 2bd95b4f4..e3d6b37f6 100644 Binary files a/files/assets/images/emojis/marseycarpasian.webp and b/files/assets/images/emojis/marseycarpasian.webp differ diff --git a/files/assets/images/emojis/marseycarpautism.webp b/files/assets/images/emojis/marseycarpautism.webp index 8cec52214..632d619e5 100644 Binary files a/files/assets/images/emojis/marseycarpautism.webp and b/files/assets/images/emojis/marseycarpautism.webp differ diff --git a/files/assets/images/emojis/marseycarpboobs.webp b/files/assets/images/emojis/marseycarpboobs.webp index 8a07b09a9..a012f7201 100644 Binary files a/files/assets/images/emojis/marseycarpboobs.webp and b/files/assets/images/emojis/marseycarpboobs.webp differ diff --git a/files/assets/images/emojis/marseycarpbritish.webp b/files/assets/images/emojis/marseycarpbritish.webp index 85c8072a5..893cfc42c 100644 Binary files a/files/assets/images/emojis/marseycarpbritish.webp and b/files/assets/images/emojis/marseycarpbritish.webp differ diff --git a/files/assets/images/emojis/marseycarpbuff.webp b/files/assets/images/emojis/marseycarpbuff.webp index 95ab904c5..1cf60335b 100644 Binary files a/files/assets/images/emojis/marseycarpbuff.webp and b/files/assets/images/emojis/marseycarpbuff.webp differ diff --git a/files/assets/images/emojis/marseycarpcrying.webp b/files/assets/images/emojis/marseycarpcrying.webp index c2efc2a58..1d632381b 100644 Binary files a/files/assets/images/emojis/marseycarpcrying.webp and b/files/assets/images/emojis/marseycarpcrying.webp differ diff --git a/files/assets/images/emojis/marseycarpdead.webp b/files/assets/images/emojis/marseycarpdead.webp index cedf7239a..7d8f1fb60 100644 Binary files a/files/assets/images/emojis/marseycarpdead.webp and b/files/assets/images/emojis/marseycarpdead.webp differ diff --git a/files/assets/images/emojis/marseycarpdetermined.webp b/files/assets/images/emojis/marseycarpdetermined.webp index 688262b09..1642d13e0 100644 Binary files a/files/assets/images/emojis/marseycarpdetermined.webp and b/files/assets/images/emojis/marseycarpdetermined.webp differ diff --git a/files/assets/images/emojis/marseycarpdevil.webp b/files/assets/images/emojis/marseycarpdevil.webp index cde201c24..39a59944f 100644 Binary files a/files/assets/images/emojis/marseycarpdevil.webp and b/files/assets/images/emojis/marseycarpdevil.webp differ diff --git a/files/assets/images/emojis/marseycarpdino.webp b/files/assets/images/emojis/marseycarpdino.webp index cc9163dbf..461ab4126 100644 Binary files a/files/assets/images/emojis/marseycarpdino.webp and b/files/assets/images/emojis/marseycarpdino.webp differ diff --git a/files/assets/images/emojis/marseycarpfisherman.webp b/files/assets/images/emojis/marseycarpfisherman.webp index 3cd07b8bb..af74ad46d 100644 Binary files a/files/assets/images/emojis/marseycarpfisherman.webp and b/files/assets/images/emojis/marseycarpfisherman.webp differ diff --git a/files/assets/images/emojis/marseycarpflorist.webp b/files/assets/images/emojis/marseycarpflorist.webp index b69e3f873..3f3bfb186 100644 Binary files a/files/assets/images/emojis/marseycarpflorist.webp and b/files/assets/images/emojis/marseycarpflorist.webp differ diff --git a/files/assets/images/emojis/marseycarpghost.webp b/files/assets/images/emojis/marseycarpghost.webp new file mode 100644 index 000000000..3db747c47 Binary files /dev/null and b/files/assets/images/emojis/marseycarpghost.webp differ diff --git a/files/assets/images/emojis/marseycarphug.webp b/files/assets/images/emojis/marseycarphug.webp index 3dd76b38a..89db6a2ed 100644 Binary files a/files/assets/images/emojis/marseycarphug.webp and b/files/assets/images/emojis/marseycarphug.webp differ diff --git a/files/assets/images/emojis/marseycarpina.webp b/files/assets/images/emojis/marseycarpina.webp index e405a66d3..ab4fe22b2 100644 Binary files a/files/assets/images/emojis/marseycarpina.webp and b/files/assets/images/emojis/marseycarpina.webp differ diff --git a/files/assets/images/emojis/marseycarpjannie.webp b/files/assets/images/emojis/marseycarpjannie.webp new file mode 100644 index 000000000..3f347d1cc Binary files /dev/null and b/files/assets/images/emojis/marseycarpjannie.webp differ diff --git a/files/assets/images/emojis/marseycarpjannie2.webp b/files/assets/images/emojis/marseycarpjannie2.webp new file mode 100644 index 000000000..3d48befb8 Binary files /dev/null and b/files/assets/images/emojis/marseycarpjannie2.webp differ diff --git a/files/assets/images/emojis/marseycarplazy.webp b/files/assets/images/emojis/marseycarplazy.webp index be625be20..a4e8d671e 100644 Binary files a/files/assets/images/emojis/marseycarplazy.webp and b/files/assets/images/emojis/marseycarplazy.webp differ diff --git a/files/assets/images/emojis/marseycarpler.webp b/files/assets/images/emojis/marseycarpler.webp index 3cc27d9b2..898fb810f 100644 Binary files a/files/assets/images/emojis/marseycarpler.webp and b/files/assets/images/emojis/marseycarpler.webp differ diff --git a/files/assets/images/emojis/marseycarpmerchant.webp b/files/assets/images/emojis/marseycarpmerchant.webp index f593efabc..7d67a49b7 100644 Binary files a/files/assets/images/emojis/marseycarpmerchant.webp and b/files/assets/images/emojis/marseycarpmerchant.webp differ diff --git a/files/assets/images/emojis/marseycarpmerchant2.webp b/files/assets/images/emojis/marseycarpmerchant2.webp index 896aacef4..7f0d112e6 100644 Binary files a/files/assets/images/emojis/marseycarpmerchant2.webp and b/files/assets/images/emojis/marseycarpmerchant2.webp differ diff --git a/files/assets/images/emojis/marseycarpmermaid.webp b/files/assets/images/emojis/marseycarpmermaid.webp index 237d8fe14..f68755fef 100644 Binary files a/files/assets/images/emojis/marseycarpmermaid.webp and b/files/assets/images/emojis/marseycarpmermaid.webp differ diff --git a/files/assets/images/emojis/marseycarpnoticeme.webp b/files/assets/images/emojis/marseycarpnoticeme.webp index 660e209b6..bf99ad4fb 100644 Binary files a/files/assets/images/emojis/marseycarpnoticeme.webp and b/files/assets/images/emojis/marseycarpnoticeme.webp differ diff --git a/files/assets/images/emojis/marseycarpprotest.webp b/files/assets/images/emojis/marseycarpprotest.webp index 3ac16f821..838600c5d 100644 Binary files a/files/assets/images/emojis/marseycarpprotest.webp and b/files/assets/images/emojis/marseycarpprotest.webp differ diff --git a/files/assets/images/emojis/marseycarpsnipe.webp b/files/assets/images/emojis/marseycarpsnipe.webp index b586b8cd8..e4d18ae50 100644 Binary files a/files/assets/images/emojis/marseycarpsnipe.webp and b/files/assets/images/emojis/marseycarpsnipe.webp differ diff --git a/files/assets/images/emojis/marseycarptrophy.webp b/files/assets/images/emojis/marseycarptrophy.webp index 9b7a706fe..c6f6ffc7d 100644 Binary files a/files/assets/images/emojis/marseycarptrophy.webp and b/files/assets/images/emojis/marseycarptrophy.webp differ diff --git a/files/assets/images/emojis/marseycarpupset.webp b/files/assets/images/emojis/marseycarpupset.webp index f747eb37e..da209dc22 100644 Binary files a/files/assets/images/emojis/marseycarpupset.webp and b/files/assets/images/emojis/marseycarpupset.webp differ diff --git a/files/assets/images/emojis/marseycarsuicide.webp b/files/assets/images/emojis/marseycarsuicide.webp index ba2265ca5..22ab432ef 100644 Binary files a/files/assets/images/emojis/marseycarsuicide.webp and b/files/assets/images/emojis/marseycarsuicide.webp differ diff --git a/files/assets/images/emojis/marseycat.webp b/files/assets/images/emojis/marseycat.webp index 95fb1f197..483285214 100644 Binary files a/files/assets/images/emojis/marseycat.webp and b/files/assets/images/emojis/marseycat.webp differ diff --git a/files/assets/images/emojis/marseycatgirl.webp b/files/assets/images/emojis/marseycatgirl.webp index cdb74e806..a1ad3d240 100644 Binary files a/files/assets/images/emojis/marseycatgirl.webp and b/files/assets/images/emojis/marseycatgirl.webp differ diff --git a/files/assets/images/emojis/marseycatgirl2.webp b/files/assets/images/emojis/marseycatgirl2.webp index 398edc19f..f7e059ebd 100644 Binary files a/files/assets/images/emojis/marseycatgirl2.webp and b/files/assets/images/emojis/marseycatgirl2.webp differ diff --git a/files/assets/images/emojis/marseycatgirl3.webp b/files/assets/images/emojis/marseycatgirl3.webp index 25524b111..aee0c029f 100644 Binary files a/files/assets/images/emojis/marseycatgirl3.webp and b/files/assets/images/emojis/marseycatgirl3.webp differ diff --git a/files/assets/images/emojis/marseycatgirl4.webp b/files/assets/images/emojis/marseycatgirl4.webp index 5def4283c..8ddebebd1 100644 Binary files a/files/assets/images/emojis/marseycatgirl4.webp and b/files/assets/images/emojis/marseycatgirl4.webp differ diff --git a/files/assets/images/emojis/marseycatgirl5.webp b/files/assets/images/emojis/marseycatgirl5.webp index 312da832f..b8c08ac73 100644 Binary files a/files/assets/images/emojis/marseycatgirl5.webp and b/files/assets/images/emojis/marseycatgirl5.webp differ diff --git a/files/assets/images/emojis/marseycatgirlhomofascist.webp b/files/assets/images/emojis/marseycatgirlhomofascist.webp index 0ed2bbe73..7e705efbe 100644 Binary files a/files/assets/images/emojis/marseycatgirlhomofascist.webp and b/files/assets/images/emojis/marseycatgirlhomofascist.webp differ diff --git a/files/assets/images/emojis/marseycatgirljanny.webp b/files/assets/images/emojis/marseycatgirljanny.webp index 8a9838e14..c4a2d0e7c 100644 Binary files a/files/assets/images/emojis/marseycatgirljanny.webp and b/files/assets/images/emojis/marseycatgirljanny.webp differ diff --git a/files/assets/images/emojis/marseycaveman.webp b/files/assets/images/emojis/marseycaveman.webp index 6a46440c0..8ae482887 100644 Binary files a/files/assets/images/emojis/marseycaveman.webp and b/files/assets/images/emojis/marseycaveman.webp differ diff --git a/files/assets/images/emojis/marseyceiling.webp b/files/assets/images/emojis/marseyceiling.webp index e829e0b72..8ff755944 100644 Binary files a/files/assets/images/emojis/marseyceiling.webp and b/files/assets/images/emojis/marseyceiling.webp differ diff --git a/files/assets/images/emojis/marseycenter.webp b/files/assets/images/emojis/marseycenter.webp index 478b7851c..cf63ca804 100644 Binary files a/files/assets/images/emojis/marseycenter.webp and b/files/assets/images/emojis/marseycenter.webp differ diff --git a/files/assets/images/emojis/marseychad.webp b/files/assets/images/emojis/marseychad.webp index 682054565..42e385d96 100644 Binary files a/files/assets/images/emojis/marseychad.webp and b/files/assets/images/emojis/marseychad.webp differ diff --git a/files/assets/images/emojis/marseychad2.webp b/files/assets/images/emojis/marseychad2.webp index 537e10021..8d0ce8da3 100644 Binary files a/files/assets/images/emojis/marseychad2.webp and b/files/assets/images/emojis/marseychad2.webp differ diff --git a/files/assets/images/emojis/marseychadthundercock.webp b/files/assets/images/emojis/marseychadthundercock.webp index 0fac37003..d7bdfb448 100644 Binary files a/files/assets/images/emojis/marseychadthundercock.webp and b/files/assets/images/emojis/marseychadthundercock.webp differ diff --git a/files/assets/images/emojis/marseychadyes.webp b/files/assets/images/emojis/marseychadyes.webp index abfd2ab0e..b267b5806 100644 Binary files a/files/assets/images/emojis/marseychadyes.webp and b/files/assets/images/emojis/marseychadyes.webp differ diff --git a/files/assets/images/emojis/marseycharlesiii.webp b/files/assets/images/emojis/marseycharlesiii.webp index f14552491..a1ddcb730 100644 Binary files a/files/assets/images/emojis/marseycharlesiii.webp and b/files/assets/images/emojis/marseycharlesiii.webp differ diff --git a/files/assets/images/emojis/marseycharlesmanson.webp b/files/assets/images/emojis/marseycharlesmanson.webp index 6a3ed63dd..605de4277 100644 Binary files a/files/assets/images/emojis/marseycharlesmanson.webp and b/files/assets/images/emojis/marseycharlesmanson.webp differ diff --git a/files/assets/images/emojis/marseycharliebrown.webp b/files/assets/images/emojis/marseycharliebrown.webp new file mode 100644 index 000000000..c5b92f4c7 Binary files /dev/null and b/files/assets/images/emojis/marseycharliebrown.webp differ diff --git a/files/assets/images/emojis/marseychartbar.webp b/files/assets/images/emojis/marseychartbar.webp index 8919703b6..adc12bf57 100644 Binary files a/files/assets/images/emojis/marseychartbar.webp and b/files/assets/images/emojis/marseychartbar.webp differ diff --git a/files/assets/images/emojis/marseychartgaussian.webp b/files/assets/images/emojis/marseychartgaussian.webp index 57a559b64..7a880747d 100644 Binary files a/files/assets/images/emojis/marseychartgaussian.webp and b/files/assets/images/emojis/marseychartgaussian.webp differ diff --git a/files/assets/images/emojis/marseychartpie.webp b/files/assets/images/emojis/marseychartpie.webp index ed845889a..9cbf0d744 100644 Binary files a/files/assets/images/emojis/marseychartpie.webp and b/files/assets/images/emojis/marseychartpie.webp differ diff --git a/files/assets/images/emojis/marseychartscatter.webp b/files/assets/images/emojis/marseychartscatter.webp index f4b3f2b2a..e0a05c586 100644 Binary files a/files/assets/images/emojis/marseychartscatter.webp and b/files/assets/images/emojis/marseychartscatter.webp differ diff --git a/files/assets/images/emojis/marseycheckem.webp b/files/assets/images/emojis/marseycheckem.webp index fcf68713f..6a462eb81 100644 Binary files a/files/assets/images/emojis/marseycheckem.webp and b/files/assets/images/emojis/marseycheckem.webp differ diff --git a/files/assets/images/emojis/marseycheeks.webp b/files/assets/images/emojis/marseycheeks.webp index 4ef2ccfec..54e8c1d7b 100644 Binary files a/files/assets/images/emojis/marseycheeks.webp and b/files/assets/images/emojis/marseycheeks.webp differ diff --git a/files/assets/images/emojis/marseycheeky.webp b/files/assets/images/emojis/marseycheeky.webp index 7160de905..a117837ff 100644 Binary files a/files/assets/images/emojis/marseycheeky.webp and b/files/assets/images/emojis/marseycheeky.webp differ diff --git a/files/assets/images/emojis/marseycheers.webp b/files/assets/images/emojis/marseycheers.webp index 123722413..c8089c570 100644 Binary files a/files/assets/images/emojis/marseycheers.webp and b/files/assets/images/emojis/marseycheers.webp differ diff --git a/files/assets/images/emojis/marseycheesehead.webp b/files/assets/images/emojis/marseycheesehead.webp index 368261eab..3cddf449d 100644 Binary files a/files/assets/images/emojis/marseycheesehead.webp and b/files/assets/images/emojis/marseycheesehead.webp differ diff --git a/files/assets/images/emojis/marseychef.webp b/files/assets/images/emojis/marseychef.webp index e1a25dfc1..d0b688bac 100644 Binary files a/files/assets/images/emojis/marseychef.webp and b/files/assets/images/emojis/marseychef.webp differ diff --git a/files/assets/images/emojis/marseychefkiss.webp b/files/assets/images/emojis/marseychefkiss.webp index 40bd1dba4..ea5844677 100644 Binary files a/files/assets/images/emojis/marseychefkiss.webp and b/files/assets/images/emojis/marseychefkiss.webp differ diff --git a/files/assets/images/emojis/marseychemist.webp b/files/assets/images/emojis/marseychemist.webp index ae4d84b5e..eb6943a7b 100644 Binary files a/files/assets/images/emojis/marseychemist.webp and b/files/assets/images/emojis/marseychemist.webp differ diff --git a/files/assets/images/emojis/marseychemist2.webp b/files/assets/images/emojis/marseychemist2.webp index 057180b73..d9d23e150 100644 Binary files a/files/assets/images/emojis/marseychemist2.webp and b/files/assets/images/emojis/marseychemist2.webp differ diff --git a/files/assets/images/emojis/marseycherokee.webp b/files/assets/images/emojis/marseycherokee.webp index 2844680dc..f2629ce16 100644 Binary files a/files/assets/images/emojis/marseycherokee.webp and b/files/assets/images/emojis/marseycherokee.webp differ diff --git a/files/assets/images/emojis/marseychessknight.webp b/files/assets/images/emojis/marseychessknight.webp index 091668f96..76f7c5f2c 100644 Binary files a/files/assets/images/emojis/marseychessknight.webp and b/files/assets/images/emojis/marseychessknight.webp differ diff --git a/files/assets/images/emojis/marseychicken.webp b/files/assets/images/emojis/marseychicken.webp index 488e60b23..1f4c195e0 100644 Binary files a/files/assets/images/emojis/marseychicken.webp and b/files/assets/images/emojis/marseychicken.webp differ diff --git a/files/assets/images/emojis/marseychimera.webp b/files/assets/images/emojis/marseychimera.webp index 33ed56702..159947628 100644 Binary files a/files/assets/images/emojis/marseychimera.webp and b/files/assets/images/emojis/marseychimera.webp differ diff --git a/files/assets/images/emojis/marseychinchilla.webp b/files/assets/images/emojis/marseychinchilla.webp index 474f10e79..436f1f97b 100644 Binary files a/files/assets/images/emojis/marseychinchilla.webp and b/files/assets/images/emojis/marseychinchilla.webp differ diff --git a/files/assets/images/emojis/marseychinchilla2.webp b/files/assets/images/emojis/marseychinchilla2.webp index 20518b45d..75728cceb 100644 Binary files a/files/assets/images/emojis/marseychinchilla2.webp and b/files/assets/images/emojis/marseychinchilla2.webp differ diff --git a/files/assets/images/emojis/marseychinchillalove.webp b/files/assets/images/emojis/marseychinchillalove.webp index 715455fec..b39067194 100644 Binary files a/files/assets/images/emojis/marseychinchillalove.webp and b/files/assets/images/emojis/marseychinchillalove.webp differ diff --git a/files/assets/images/emojis/marseychinesedevil.webp b/files/assets/images/emojis/marseychinesedevil.webp index 98bb7453c..adfdc5b29 100644 Binary files a/files/assets/images/emojis/marseychinesedevil.webp and b/files/assets/images/emojis/marseychinesedevil.webp differ diff --git a/files/assets/images/emojis/marseychingchong.webp b/files/assets/images/emojis/marseychingchong.webp index 6f317e41a..c5db50d7b 100644 Binary files a/files/assets/images/emojis/marseychingchong.webp and b/files/assets/images/emojis/marseychingchong.webp differ diff --git a/files/assets/images/emojis/marseychingchongpearlclutch.webp b/files/assets/images/emojis/marseychingchongpearlclutch.webp index 655287aca..60293b196 100644 Binary files a/files/assets/images/emojis/marseychingchongpearlclutch.webp and b/files/assets/images/emojis/marseychingchongpearlclutch.webp differ diff --git a/files/assets/images/emojis/marseychingchongsupremacy.webp b/files/assets/images/emojis/marseychingchongsupremacy.webp index 87e9f36e5..3e20c69c6 100644 Binary files a/files/assets/images/emojis/marseychingchongsupremacy.webp and b/files/assets/images/emojis/marseychingchongsupremacy.webp differ diff --git a/files/assets/images/emojis/marseychiobulove.webp b/files/assets/images/emojis/marseychiobulove.webp index 3dc1ae4a0..a56b673d9 100644 Binary files a/files/assets/images/emojis/marseychiobulove.webp and b/files/assets/images/emojis/marseychiobulove.webp differ diff --git a/files/assets/images/emojis/marseychocobo.webp b/files/assets/images/emojis/marseychocobo.webp index bcb7071d7..e0ece6d03 100644 Binary files a/files/assets/images/emojis/marseychocobo.webp and b/files/assets/images/emojis/marseychocobo.webp differ diff --git a/files/assets/images/emojis/marseychocolatemilk.webp b/files/assets/images/emojis/marseychocolatemilk.webp index 497c56e67..73bbbc050 100644 Binary files a/files/assets/images/emojis/marseychocolatemilk.webp and b/files/assets/images/emojis/marseychocolatemilk.webp differ diff --git a/files/assets/images/emojis/marseychonker.webp b/files/assets/images/emojis/marseychonker.webp index d85bde32e..3fbb35d8d 100644 Binary files a/files/assets/images/emojis/marseychonker.webp and b/files/assets/images/emojis/marseychonker.webp differ diff --git a/files/assets/images/emojis/marseychonker2.webp b/files/assets/images/emojis/marseychonker2.webp index a5b2e9262..0dcb27624 100644 Binary files a/files/assets/images/emojis/marseychonker2.webp and b/files/assets/images/emojis/marseychonker2.webp differ diff --git a/files/assets/images/emojis/marseychonkerbutch.webp b/files/assets/images/emojis/marseychonkerbutch.webp index 452662c42..1717fb511 100644 Binary files a/files/assets/images/emojis/marseychonkerbutch.webp and b/files/assets/images/emojis/marseychonkerbutch.webp differ diff --git a/files/assets/images/emojis/marseychonkerfoid.webp b/files/assets/images/emojis/marseychonkerfoid.webp index 05a257bf8..624a457a9 100644 Binary files a/files/assets/images/emojis/marseychonkerfoid.webp and b/files/assets/images/emojis/marseychonkerfoid.webp differ diff --git a/files/assets/images/emojis/marseychonkerfoidpuke.webp b/files/assets/images/emojis/marseychonkerfoidpuke.webp index 04f303c94..a303a2257 100644 Binary files a/files/assets/images/emojis/marseychonkerfoidpuke.webp and b/files/assets/images/emojis/marseychonkerfoidpuke.webp differ diff --git a/files/assets/images/emojis/marseychristmas.webp b/files/assets/images/emojis/marseychristmas.webp index dcfc36aa6..8ad20bcf1 100644 Binary files a/files/assets/images/emojis/marseychristmas.webp and b/files/assets/images/emojis/marseychristmas.webp differ diff --git a/files/assets/images/emojis/marseychristmasbulb.webp b/files/assets/images/emojis/marseychristmasbulb.webp index e78241b54..df70f5cf8 100644 Binary files a/files/assets/images/emojis/marseychristmasbulb.webp and b/files/assets/images/emojis/marseychristmasbulb.webp differ diff --git a/files/assets/images/emojis/marseychristmasbulb2.webp b/files/assets/images/emojis/marseychristmasbulb2.webp index 9c842a177..7f74f1236 100644 Binary files a/files/assets/images/emojis/marseychristmasbulb2.webp and b/files/assets/images/emojis/marseychristmasbulb2.webp differ diff --git a/files/assets/images/emojis/marseychristmaself.webp b/files/assets/images/emojis/marseychristmaself.webp index 7980459db..2a42f573b 100644 Binary files a/files/assets/images/emojis/marseychristmaself.webp and b/files/assets/images/emojis/marseychristmaself.webp differ diff --git a/files/assets/images/emojis/marseychristmaself2.webp b/files/assets/images/emojis/marseychristmaself2.webp index eb6234eb9..19a1f91b2 100644 Binary files a/files/assets/images/emojis/marseychristmaself2.webp and b/files/assets/images/emojis/marseychristmaself2.webp differ diff --git a/files/assets/images/emojis/marseychristmasgift.webp b/files/assets/images/emojis/marseychristmasgift.webp index c2fee4e98..655edf0b5 100644 Binary files a/files/assets/images/emojis/marseychristmasgift.webp and b/files/assets/images/emojis/marseychristmasgift.webp differ diff --git a/files/assets/images/emojis/marseychristmaslove.webp b/files/assets/images/emojis/marseychristmaslove.webp index 86b53c357..d5b889de9 100644 Binary files a/files/assets/images/emojis/marseychristmaslove.webp and b/files/assets/images/emojis/marseychristmaslove.webp differ diff --git a/files/assets/images/emojis/marseychristmasparty.webp b/files/assets/images/emojis/marseychristmasparty.webp index 124e1c780..198092581 100644 Binary files a/files/assets/images/emojis/marseychristmasparty.webp and b/files/assets/images/emojis/marseychristmasparty.webp differ diff --git a/files/assets/images/emojis/marseychristmasscarf.webp b/files/assets/images/emojis/marseychristmasscarf.webp index 2b49518bd..0a004c6ad 100644 Binary files a/files/assets/images/emojis/marseychristmasscarf.webp and b/files/assets/images/emojis/marseychristmasscarf.webp differ diff --git a/files/assets/images/emojis/marseychristmastree.webp b/files/assets/images/emojis/marseychristmastree.webp index 7055fa26f..8cb450ddd 100644 Binary files a/files/assets/images/emojis/marseychristmastree.webp and b/files/assets/images/emojis/marseychristmastree.webp differ diff --git a/files/assets/images/emojis/marseychtorrr.webp b/files/assets/images/emojis/marseychtorrr.webp index 07f7d8a00..bc26524f0 100644 Binary files a/files/assets/images/emojis/marseychtorrr.webp and b/files/assets/images/emojis/marseychtorrr.webp differ diff --git a/files/assets/images/emojis/marseychtorrr2.webp b/files/assets/images/emojis/marseychtorrr2.webp index 2b603f54e..06bad8091 100644 Binary files a/files/assets/images/emojis/marseychtorrr2.webp and b/files/assets/images/emojis/marseychtorrr2.webp differ diff --git a/files/assets/images/emojis/marseychucky.webp b/files/assets/images/emojis/marseychucky.webp index c9dfcdfc7..1891afad1 100644 Binary files a/files/assets/images/emojis/marseychucky.webp and b/files/assets/images/emojis/marseychucky.webp differ diff --git a/files/assets/images/emojis/marseychudnotes.webp b/files/assets/images/emojis/marseychudnotes.webp index 0b4a0e1ba..740afe2fa 100644 Binary files a/files/assets/images/emojis/marseychudnotes.webp and b/files/assets/images/emojis/marseychudnotes.webp differ diff --git a/files/assets/images/emojis/marseychudrentfree.webp b/files/assets/images/emojis/marseychudrentfree.webp new file mode 100644 index 000000000..cc50e2e51 Binary files /dev/null and b/files/assets/images/emojis/marseychudrentfree.webp differ diff --git a/files/assets/images/emojis/marseychungus.webp b/files/assets/images/emojis/marseychungus.webp index c64519f89..cc4060ef5 100644 Binary files a/files/assets/images/emojis/marseychungus.webp and b/files/assets/images/emojis/marseychungus.webp differ diff --git a/files/assets/images/emojis/marseycia.webp b/files/assets/images/emojis/marseycia.webp index 345f3166a..fb37e0e54 100644 Binary files a/files/assets/images/emojis/marseycia.webp and b/files/assets/images/emojis/marseycia.webp differ diff --git a/files/assets/images/emojis/marseycirno.webp b/files/assets/images/emojis/marseycirno.webp index f5e4523b2..96d5e572e 100644 Binary files a/files/assets/images/emojis/marseycirno.webp and b/files/assets/images/emojis/marseycirno.webp differ diff --git a/files/assets/images/emojis/marseycitrus.webp b/files/assets/images/emojis/marseycitrus.webp index 26e7d08c7..b7aabe665 100644 Binary files a/files/assets/images/emojis/marseycitrus.webp and b/files/assets/images/emojis/marseycitrus.webp differ diff --git a/files/assets/images/emojis/marseyclappingglasses.webp b/files/assets/images/emojis/marseyclappingglasses.webp index 18043d6b0..d85f0f8ad 100644 Binary files a/files/assets/images/emojis/marseyclappingglasses.webp and b/files/assets/images/emojis/marseyclappingglasses.webp differ diff --git a/files/assets/images/emojis/marseyclawpedo.webp b/files/assets/images/emojis/marseyclawpedo.webp index 276fbc923..047982a5f 100644 Binary files a/files/assets/images/emojis/marseyclawpedo.webp and b/files/assets/images/emojis/marseyclawpedo.webp differ diff --git a/files/assets/images/emojis/marseycleonpeterson.webp b/files/assets/images/emojis/marseycleonpeterson.webp index 879f43447..a0f7a6eb6 100644 Binary files a/files/assets/images/emojis/marseycleonpeterson.webp and b/files/assets/images/emojis/marseycleonpeterson.webp differ diff --git a/files/assets/images/emojis/marseycleonpeterson2.webp b/files/assets/images/emojis/marseycleonpeterson2.webp index 7f829cf1a..5318cbe4c 100644 Binary files a/files/assets/images/emojis/marseycleonpeterson2.webp and b/files/assets/images/emojis/marseycleonpeterson2.webp differ diff --git a/files/assets/images/emojis/marseyclintongarrison.webp b/files/assets/images/emojis/marseyclintongarrison.webp index 097c90bc5..699bce70d 100644 Binary files a/files/assets/images/emojis/marseyclintongarrison.webp and b/files/assets/images/emojis/marseyclintongarrison.webp differ diff --git a/files/assets/images/emojis/marseyclippy.webp b/files/assets/images/emojis/marseyclippy.webp index d574eef20..a859c7885 100644 Binary files a/files/assets/images/emojis/marseyclippy.webp and b/files/assets/images/emojis/marseyclippy.webp differ diff --git a/files/assets/images/emojis/marseyclown.webp b/files/assets/images/emojis/marseyclown.webp index b14211a17..9edb31ad6 100644 Binary files a/files/assets/images/emojis/marseyclown.webp and b/files/assets/images/emojis/marseyclown.webp differ diff --git a/files/assets/images/emojis/marseyclown2.webp b/files/assets/images/emojis/marseyclown2.webp index c0739812e..735d658ce 100644 Binary files a/files/assets/images/emojis/marseyclown2.webp and b/files/assets/images/emojis/marseyclown2.webp differ diff --git a/files/assets/images/emojis/marseyclueless.webp b/files/assets/images/emojis/marseyclueless.webp index 6ebcaeb9c..f4a481ef9 100644 Binary files a/files/assets/images/emojis/marseyclueless.webp and b/files/assets/images/emojis/marseyclueless.webp differ diff --git a/files/assets/images/emojis/marseycoal.webp b/files/assets/images/emojis/marseycoal.webp index 2e3d0ddec..f95ef185b 100644 Binary files a/files/assets/images/emojis/marseycoal.webp and b/files/assets/images/emojis/marseycoal.webp differ diff --git a/files/assets/images/emojis/marseycocaine.webp b/files/assets/images/emojis/marseycocaine.webp new file mode 100644 index 000000000..c6955cb68 Binary files /dev/null and b/files/assets/images/emojis/marseycocaine.webp differ diff --git a/files/assets/images/emojis/marseycock.webp b/files/assets/images/emojis/marseycock.webp index 021ef2275..316ea95a5 100644 Binary files a/files/assets/images/emojis/marseycock.webp and b/files/assets/images/emojis/marseycock.webp differ diff --git a/files/assets/images/emojis/marseycodecel.webp b/files/assets/images/emojis/marseycodecel.webp index ea22c9384..3842fabe0 100644 Binary files a/files/assets/images/emojis/marseycodecel.webp and b/files/assets/images/emojis/marseycodecel.webp differ diff --git a/files/assets/images/emojis/marseycodecellove.webp b/files/assets/images/emojis/marseycodecellove.webp index 9900775a4..1b703b3a1 100644 Binary files a/files/assets/images/emojis/marseycodecellove.webp and b/files/assets/images/emojis/marseycodecellove.webp differ diff --git a/files/assets/images/emojis/marseycoffeemug.webp b/files/assets/images/emojis/marseycoffeemug.webp index 9768ec75e..d40621545 100644 Binary files a/files/assets/images/emojis/marseycoffeemug.webp and b/files/assets/images/emojis/marseycoffeemug.webp differ diff --git a/files/assets/images/emojis/marseycoffeerecursive.webp b/files/assets/images/emojis/marseycoffeerecursive.webp index e2d1ca598..94813b4e1 100644 Binary files a/files/assets/images/emojis/marseycoffeerecursive.webp and b/files/assets/images/emojis/marseycoffeerecursive.webp differ diff --git a/files/assets/images/emojis/marseycoldtwinge.webp b/files/assets/images/emojis/marseycoldtwinge.webp new file mode 100644 index 000000000..355d0832b Binary files /dev/null and b/files/assets/images/emojis/marseycoldtwinge.webp differ diff --git a/files/assets/images/emojis/marseycolombo.webp b/files/assets/images/emojis/marseycolombo.webp index 5cb0c34bd..daf37d422 100644 Binary files a/files/assets/images/emojis/marseycolombo.webp and b/files/assets/images/emojis/marseycolombo.webp differ diff --git a/files/assets/images/emojis/marseycolorblind.webp b/files/assets/images/emojis/marseycolorblind.webp new file mode 100644 index 000000000..f1952e13d Binary files /dev/null and b/files/assets/images/emojis/marseycolorblind.webp differ diff --git a/files/assets/images/emojis/marseycolossal.webp b/files/assets/images/emojis/marseycolossal.webp index d9b382cbb..6c7e28823 100644 Binary files a/files/assets/images/emojis/marseycolossal.webp and b/files/assets/images/emojis/marseycolossal.webp differ diff --git a/files/assets/images/emojis/marseycomet.webp b/files/assets/images/emojis/marseycomet.webp index 938afc817..0fa863ead 100644 Binary files a/files/assets/images/emojis/marseycomet.webp and b/files/assets/images/emojis/marseycomet.webp differ diff --git a/files/assets/images/emojis/marseycommitted.webp b/files/assets/images/emojis/marseycommitted.webp index b058e00c4..1a84859ef 100644 Binary files a/files/assets/images/emojis/marseycommitted.webp and b/files/assets/images/emojis/marseycommitted.webp differ diff --git a/files/assets/images/emojis/marseycomrade.webp b/files/assets/images/emojis/marseycomrade.webp index c9d63ec8a..a971110a7 100644 Binary files a/files/assets/images/emojis/marseycomrade.webp and b/files/assets/images/emojis/marseycomrade.webp differ diff --git a/files/assets/images/emojis/marseycomradehandshake.webp b/files/assets/images/emojis/marseycomradehandshake.webp index 76cd18310..d5a247ca3 100644 Binary files a/files/assets/images/emojis/marseycomradehandshake.webp and b/files/assets/images/emojis/marseycomradehandshake.webp differ diff --git a/files/assets/images/emojis/marseyconfused.webp b/files/assets/images/emojis/marseyconfused.webp index aae662bca..ccfe703d7 100644 Binary files a/files/assets/images/emojis/marseyconfused.webp and b/files/assets/images/emojis/marseyconfused.webp differ diff --git a/files/assets/images/emojis/marseyconquistador.webp b/files/assets/images/emojis/marseyconquistador.webp index accc81a2f..59667212c 100644 Binary files a/files/assets/images/emojis/marseyconquistador.webp and b/files/assets/images/emojis/marseyconquistador.webp differ diff --git a/files/assets/images/emojis/marseyconstellation.webp b/files/assets/images/emojis/marseyconstellation.webp index 2d307fde8..d4b42ddd4 100644 Binary files a/files/assets/images/emojis/marseyconstellation.webp and b/files/assets/images/emojis/marseyconstellation.webp differ diff --git a/files/assets/images/emojis/marseycontemplate.webp b/files/assets/images/emojis/marseycontemplate.webp index 92a9504e3..f0b755a38 100644 Binary files a/files/assets/images/emojis/marseycontemplate.webp and b/files/assets/images/emojis/marseycontemplate.webp differ diff --git a/files/assets/images/emojis/marseycontemplatesuicide.webp b/files/assets/images/emojis/marseycontemplatesuicide.webp index 5499ec5ce..e28d29c08 100644 Binary files a/files/assets/images/emojis/marseycontemplatesuicide.webp and b/files/assets/images/emojis/marseycontemplatesuicide.webp differ diff --git a/files/assets/images/emojis/marseycontryclub.webp b/files/assets/images/emojis/marseycontryclub.webp index bce542326..03ae39b70 100644 Binary files a/files/assets/images/emojis/marseycontryclub.webp and b/files/assets/images/emojis/marseycontryclub.webp differ diff --git a/files/assets/images/emojis/marseycool.webp b/files/assets/images/emojis/marseycool.webp index 5942ca508..bbbaa7429 100644 Binary files a/files/assets/images/emojis/marseycool.webp and b/files/assets/images/emojis/marseycool.webp differ diff --git a/files/assets/images/emojis/marseycool2.webp b/files/assets/images/emojis/marseycool2.webp index bda85400f..4252389d9 100644 Binary files a/files/assets/images/emojis/marseycool2.webp and b/files/assets/images/emojis/marseycool2.webp differ diff --git a/files/assets/images/emojis/marseycoomer.webp b/files/assets/images/emojis/marseycoomer.webp index 7187c69ac..19de95caa 100644 Binary files a/files/assets/images/emojis/marseycoomer.webp and b/files/assets/images/emojis/marseycoomer.webp differ diff --git a/files/assets/images/emojis/marseycoomer2.webp b/files/assets/images/emojis/marseycoomer2.webp index 90dd6aad2..01406e2a9 100644 Binary files a/files/assets/images/emojis/marseycoomer2.webp and b/files/assets/images/emojis/marseycoomer2.webp differ diff --git a/files/assets/images/emojis/marseycoomer3.webp b/files/assets/images/emojis/marseycoomer3.webp index 53e4de213..867727835 100644 Binary files a/files/assets/images/emojis/marseycoomer3.webp and b/files/assets/images/emojis/marseycoomer3.webp differ diff --git a/files/assets/images/emojis/marseycoonass.webp b/files/assets/images/emojis/marseycoonass.webp index e400d5180..a3628b047 100644 Binary files a/files/assets/images/emojis/marseycoonass.webp and b/files/assets/images/emojis/marseycoonass.webp differ diff --git a/files/assets/images/emojis/marseycop.webp b/files/assets/images/emojis/marseycop.webp index e564b8bea..9ffd460d7 100644 Binary files a/files/assets/images/emojis/marseycop.webp and b/files/assets/images/emojis/marseycop.webp differ diff --git a/files/assets/images/emojis/marseycop2.webp b/files/assets/images/emojis/marseycop2.webp index 0de068252..951b9d9af 100644 Binary files a/files/assets/images/emojis/marseycop2.webp and b/files/assets/images/emojis/marseycop2.webp differ diff --git a/files/assets/images/emojis/marseycop3.webp b/files/assets/images/emojis/marseycop3.webp index e55064143..c3f0cf4f4 100644 Binary files a/files/assets/images/emojis/marseycop3.webp and b/files/assets/images/emojis/marseycop3.webp differ diff --git a/files/assets/images/emojis/marseycope.webp b/files/assets/images/emojis/marseycope.webp index d71936de3..c4b321a59 100644 Binary files a/files/assets/images/emojis/marseycope.webp and b/files/assets/images/emojis/marseycope.webp differ diff --git a/files/assets/images/emojis/marseycopeseethedilate.webp b/files/assets/images/emojis/marseycopeseethedilate.webp index 97de55463..7f4a4ee9e 100644 Binary files a/files/assets/images/emojis/marseycopeseethedilate.webp and b/files/assets/images/emojis/marseycopeseethedilate.webp differ diff --git a/files/assets/images/emojis/marseycopter.webp b/files/assets/images/emojis/marseycopter.webp index e2bcbc7f6..885042e52 100644 Binary files a/files/assets/images/emojis/marseycopter.webp and b/files/assets/images/emojis/marseycopter.webp differ diff --git a/files/assets/images/emojis/marseycorn.webp b/files/assets/images/emojis/marseycorn.webp index 90e561284..301c6038d 100644 Binary files a/files/assets/images/emojis/marseycorn.webp and b/files/assets/images/emojis/marseycorn.webp differ diff --git a/files/assets/images/emojis/marseycornholio.webp b/files/assets/images/emojis/marseycornholio.webp index 0a96410c0..ce35a912a 100644 Binary files a/files/assets/images/emojis/marseycornholio.webp and b/files/assets/images/emojis/marseycornholio.webp differ diff --git a/files/assets/images/emojis/marseycornlove.webp b/files/assets/images/emojis/marseycornlove.webp index 250e5ebd5..5db776680 100644 Binary files a/files/assets/images/emojis/marseycornlove.webp and b/files/assets/images/emojis/marseycornlove.webp differ diff --git a/files/assets/images/emojis/marseycortana.webp b/files/assets/images/emojis/marseycortana.webp index fa7c9bdb3..b6729bef7 100644 Binary files a/files/assets/images/emojis/marseycortana.webp and b/files/assets/images/emojis/marseycortana.webp differ diff --git a/files/assets/images/emojis/marseycorvus.webp b/files/assets/images/emojis/marseycorvus.webp index ab933a8f6..1800e56a1 100644 Binary files a/files/assets/images/emojis/marseycorvus.webp and b/files/assets/images/emojis/marseycorvus.webp differ diff --git a/files/assets/images/emojis/marseycosmopolitan.webp b/files/assets/images/emojis/marseycosmopolitan.webp index eb64d0156..0919eed0a 100644 Binary files a/files/assets/images/emojis/marseycosmopolitan.webp and b/files/assets/images/emojis/marseycosmopolitan.webp differ diff --git a/files/assets/images/emojis/marseycountryclub.webp b/files/assets/images/emojis/marseycountryclub.webp index e4462d62b..f7d810192 100644 Binary files a/files/assets/images/emojis/marseycountryclub.webp and b/files/assets/images/emojis/marseycountryclub.webp differ diff --git a/files/assets/images/emojis/marseycow.webp b/files/assets/images/emojis/marseycow.webp index a3edc8b3d..0039f7fbd 100644 Binary files a/files/assets/images/emojis/marseycow.webp and b/files/assets/images/emojis/marseycow.webp differ diff --git a/files/assets/images/emojis/marseycowboy.webp b/files/assets/images/emojis/marseycowboy.webp index e265f0525..ea85ef1e4 100644 Binary files a/files/assets/images/emojis/marseycowboy.webp and b/files/assets/images/emojis/marseycowboy.webp differ diff --git a/files/assets/images/emojis/marseycracka.webp b/files/assets/images/emojis/marseycracka.webp index 2b22ed322..d108e96f5 100644 Binary files a/files/assets/images/emojis/marseycracka.webp and b/files/assets/images/emojis/marseycracka.webp differ diff --git a/files/assets/images/emojis/marseycrayfish.webp b/files/assets/images/emojis/marseycrayfish.webp new file mode 100644 index 000000000..5ade965c8 Binary files /dev/null and b/files/assets/images/emojis/marseycrayfish.webp differ diff --git a/files/assets/images/emojis/marseycreepy.webp b/files/assets/images/emojis/marseycreepy.webp index 26f784386..2f9125710 100644 Binary files a/files/assets/images/emojis/marseycreepy.webp and b/files/assets/images/emojis/marseycreepy.webp differ diff --git a/files/assets/images/emojis/marseycringe.webp b/files/assets/images/emojis/marseycringe.webp index b5b60be47..f30d49436 100644 Binary files a/files/assets/images/emojis/marseycringe.webp and b/files/assets/images/emojis/marseycringe.webp differ diff --git a/files/assets/images/emojis/marseycringe2.webp b/files/assets/images/emojis/marseycringe2.webp index 176f52e1a..dd8abda8f 100644 Binary files a/files/assets/images/emojis/marseycringe2.webp and b/files/assets/images/emojis/marseycringe2.webp differ diff --git a/files/assets/images/emojis/marseycrucified.webp b/files/assets/images/emojis/marseycrucified.webp index 616e64795..6dc08bb6b 100644 Binary files a/files/assets/images/emojis/marseycrucified.webp and b/files/assets/images/emojis/marseycrucified.webp differ diff --git a/files/assets/images/emojis/marseycruisemissile.webp b/files/assets/images/emojis/marseycruisemissile.webp index 8396b90ea..3efce06ef 100644 Binary files a/files/assets/images/emojis/marseycruisemissile.webp and b/files/assets/images/emojis/marseycruisemissile.webp differ diff --git a/files/assets/images/emojis/marseycrusade.webp b/files/assets/images/emojis/marseycrusade.webp index 8ece43fb0..5481d77f5 100644 Binary files a/files/assets/images/emojis/marseycrusade.webp and b/files/assets/images/emojis/marseycrusade.webp differ diff --git a/files/assets/images/emojis/marseycrusader.webp b/files/assets/images/emojis/marseycrusader.webp index ffdaed744..c7eb2b47a 100644 Binary files a/files/assets/images/emojis/marseycrusader.webp and b/files/assets/images/emojis/marseycrusader.webp differ diff --git a/files/assets/images/emojis/marseycrusader2.webp b/files/assets/images/emojis/marseycrusader2.webp index 8858d47d9..37f5eeb64 100644 Binary files a/files/assets/images/emojis/marseycrusader2.webp and b/files/assets/images/emojis/marseycrusader2.webp differ diff --git a/files/assets/images/emojis/marseycry.webp b/files/assets/images/emojis/marseycry.webp index 73d765e84..e03e6083f 100644 Binary files a/files/assets/images/emojis/marseycry.webp and b/files/assets/images/emojis/marseycry.webp differ diff --git a/files/assets/images/emojis/marseycrying.webp b/files/assets/images/emojis/marseycrying.webp index e54133340..fdc683256 100644 Binary files a/files/assets/images/emojis/marseycrying.webp and b/files/assets/images/emojis/marseycrying.webp differ diff --git a/files/assets/images/emojis/marseycrying2.webp b/files/assets/images/emojis/marseycrying2.webp index e262398fc..346a2efc3 100644 Binary files a/files/assets/images/emojis/marseycrying2.webp and b/files/assets/images/emojis/marseycrying2.webp differ diff --git a/files/assets/images/emojis/marseycrystal.webp b/files/assets/images/emojis/marseycrystal.webp index be818435d..62be941dc 100644 Binary files a/files/assets/images/emojis/marseycrystal.webp and b/files/assets/images/emojis/marseycrystal.webp differ diff --git a/files/assets/images/emojis/marseycrystalmaiden.webp b/files/assets/images/emojis/marseycrystalmaiden.webp index 1c9fe56e3..446e4f8de 100644 Binary files a/files/assets/images/emojis/marseycrystalmaiden.webp and b/files/assets/images/emojis/marseycrystalmaiden.webp differ diff --git a/files/assets/images/emojis/marseycthulhu.webp b/files/assets/images/emojis/marseycthulhu.webp index 1042685f3..7602844ee 100644 Binary files a/files/assets/images/emojis/marseycthulhu.webp and b/files/assets/images/emojis/marseycthulhu.webp differ diff --git a/files/assets/images/emojis/marseycuck.webp b/files/assets/images/emojis/marseycuck.webp index de33576e9..33292fc8b 100644 Binary files a/files/assets/images/emojis/marseycuck.webp and b/files/assets/images/emojis/marseycuck.webp differ diff --git a/files/assets/images/emojis/marseycumjar1.webp b/files/assets/images/emojis/marseycumjar1.webp index 6b3060bdf..dafb84fd4 100644 Binary files a/files/assets/images/emojis/marseycumjar1.webp and b/files/assets/images/emojis/marseycumjar1.webp differ diff --git a/files/assets/images/emojis/marseycumjar2.webp b/files/assets/images/emojis/marseycumjar2.webp index 1d0b55854..b738ed0aa 100644 Binary files a/files/assets/images/emojis/marseycumjar2.webp and b/files/assets/images/emojis/marseycumjar2.webp differ diff --git a/files/assets/images/emojis/marseycumjar3.webp b/files/assets/images/emojis/marseycumjar3.webp index a3ff4b346..8616a823a 100644 Binary files a/files/assets/images/emojis/marseycumjar3.webp and b/files/assets/images/emojis/marseycumjar3.webp differ diff --git a/files/assets/images/emojis/marseycut.webp b/files/assets/images/emojis/marseycut.webp index 005999df0..9c7cfa779 100644 Binary files a/files/assets/images/emojis/marseycut.webp and b/files/assets/images/emojis/marseycut.webp differ diff --git a/files/assets/images/emojis/marseycutattention.webp b/files/assets/images/emojis/marseycutattention.webp index 3c94b5783..6b6027066 100644 Binary files a/files/assets/images/emojis/marseycutattention.webp and b/files/assets/images/emojis/marseycutattention.webp differ diff --git a/files/assets/images/emojis/marseycutemad.webp b/files/assets/images/emojis/marseycutemad.webp index 8c87074d9..c94bd517e 100644 Binary files a/files/assets/images/emojis/marseycutemad.webp and b/files/assets/images/emojis/marseycutemad.webp differ diff --git a/files/assets/images/emojis/marseycutwrist.webp b/files/assets/images/emojis/marseycutwrist.webp index ce3c172ed..634a27fca 100644 Binary files a/files/assets/images/emojis/marseycutwrist.webp and b/files/assets/images/emojis/marseycutwrist.webp differ diff --git a/files/assets/images/emojis/marseycwc.webp b/files/assets/images/emojis/marseycwc.webp index 37d8e7120..e398c7b12 100644 Binary files a/files/assets/images/emojis/marseycwc.webp and b/files/assets/images/emojis/marseycwc.webp differ diff --git a/files/assets/images/emojis/marseycyanide.webp b/files/assets/images/emojis/marseycyanide.webp index 710ed1ff4..df8122138 100644 Binary files a/files/assets/images/emojis/marseycyanide.webp and b/files/assets/images/emojis/marseycyanide.webp differ diff --git a/files/assets/images/emojis/marseydab.webp b/files/assets/images/emojis/marseydab.webp index 42d208a42..724e49ec6 100644 Binary files a/files/assets/images/emojis/marseydab.webp and b/files/assets/images/emojis/marseydab.webp differ diff --git a/files/assets/images/emojis/marseydaemon.webp b/files/assets/images/emojis/marseydaemon.webp index d2e75c658..48af160a6 100644 Binary files a/files/assets/images/emojis/marseydaemon.webp and b/files/assets/images/emojis/marseydaemon.webp differ diff --git a/files/assets/images/emojis/marseydagothur.webp b/files/assets/images/emojis/marseydagothur.webp index 4ff74c180..2d9270675 100644 Binary files a/files/assets/images/emojis/marseydagothur.webp and b/files/assets/images/emojis/marseydagothur.webp differ diff --git a/files/assets/images/emojis/marseydagothur2.webp b/files/assets/images/emojis/marseydagothur2.webp index 6207a8e71..f24a0e196 100644 Binary files a/files/assets/images/emojis/marseydagothur2.webp and b/files/assets/images/emojis/marseydagothur2.webp differ diff --git a/files/assets/images/emojis/marseydamosuzuki.webp b/files/assets/images/emojis/marseydamosuzuki.webp index 8a210266c..7f166adb4 100644 Binary files a/files/assets/images/emojis/marseydamosuzuki.webp and b/files/assets/images/emojis/marseydamosuzuki.webp differ diff --git a/files/assets/images/emojis/marseydarkbrandon.webp b/files/assets/images/emojis/marseydarkbrandon.webp new file mode 100644 index 000000000..f57889aae Binary files /dev/null and b/files/assets/images/emojis/marseydarkbrandon.webp differ diff --git a/files/assets/images/emojis/marseydarkcarp.webp b/files/assets/images/emojis/marseydarkcarp.webp index e4a067614..aae934eb5 100644 Binary files a/files/assets/images/emojis/marseydarkcarp.webp and b/files/assets/images/emojis/marseydarkcarp.webp differ diff --git a/files/assets/images/emojis/marseydarkcomrade.webp b/files/assets/images/emojis/marseydarkcomrade.webp index ea007b3c6..f9930ca3d 100644 Binary files a/files/assets/images/emojis/marseydarkcomrade.webp and b/files/assets/images/emojis/marseydarkcomrade.webp differ diff --git a/files/assets/images/emojis/marseydarkmarsey2.webp b/files/assets/images/emojis/marseydarkmarsey2.webp index 67852d734..33da732ea 100644 Binary files a/files/assets/images/emojis/marseydarkmarsey2.webp and b/files/assets/images/emojis/marseydarkmarsey2.webp differ diff --git a/files/assets/images/emojis/marseydarkpizzashill.webp b/files/assets/images/emojis/marseydarkpizzashill.webp index f1cb5d387..ea7310a61 100644 Binary files a/files/assets/images/emojis/marseydarkpizzashill.webp and b/files/assets/images/emojis/marseydarkpizzashill.webp differ diff --git a/files/assets/images/emojis/marseydarktrump.webp b/files/assets/images/emojis/marseydarktrump.webp new file mode 100644 index 000000000..6e422b5c0 Binary files /dev/null and b/files/assets/images/emojis/marseydarktrump.webp differ diff --git a/files/assets/images/emojis/marseydarkxd.webp b/files/assets/images/emojis/marseydarkxd.webp index 4e3e50571..c6cee2927 100644 Binary files a/files/assets/images/emojis/marseydarkxd.webp and b/files/assets/images/emojis/marseydarkxd.webp differ diff --git a/files/assets/images/emojis/marseydarwin.webp b/files/assets/images/emojis/marseydarwin.webp index 99eb44255..c51eda203 100644 Binary files a/files/assets/images/emojis/marseydarwin.webp and b/files/assets/images/emojis/marseydarwin.webp differ diff --git a/files/assets/images/emojis/marseydawnbreaker.webp b/files/assets/images/emojis/marseydawnbreaker.webp index 46d09e7c6..b01d6ca5c 100644 Binary files a/files/assets/images/emojis/marseydawnbreaker.webp and b/files/assets/images/emojis/marseydawnbreaker.webp differ diff --git a/files/assets/images/emojis/marseydead.webp b/files/assets/images/emojis/marseydead.webp index dea45cb5a..b4b438ec9 100644 Binary files a/files/assets/images/emojis/marseydead.webp and b/files/assets/images/emojis/marseydead.webp differ diff --git a/files/assets/images/emojis/marseydeadchat.webp b/files/assets/images/emojis/marseydeadchat.webp index c1eb88c46..84777adfb 100644 Binary files a/files/assets/images/emojis/marseydeadchat.webp and b/files/assets/images/emojis/marseydeadchat.webp differ diff --git a/files/assets/images/emojis/marseydeadeyes.webp b/files/assets/images/emojis/marseydeadeyes.webp index 55af70157..a3d392e7b 100644 Binary files a/files/assets/images/emojis/marseydeadeyes.webp and b/files/assets/images/emojis/marseydeadeyes.webp differ diff --git a/files/assets/images/emojis/marseydeadhorse.webp b/files/assets/images/emojis/marseydeadhorse.webp index 7bb4e203b..df39709ad 100644 Binary files a/files/assets/images/emojis/marseydeadhorse.webp and b/files/assets/images/emojis/marseydeadhorse.webp differ diff --git a/files/assets/images/emojis/marseydeadinside.webp b/files/assets/images/emojis/marseydeadinside.webp index 0e27b88a3..76d5fdfc8 100644 Binary files a/files/assets/images/emojis/marseydeadinside.webp and b/files/assets/images/emojis/marseydeadinside.webp differ diff --git a/files/assets/images/emojis/marseydeadinside2.webp b/files/assets/images/emojis/marseydeadinside2.webp index 9309a1cac..ad3894085 100644 Binary files a/files/assets/images/emojis/marseydeadinside2.webp and b/files/assets/images/emojis/marseydeadinside2.webp differ diff --git a/files/assets/images/emojis/marseydeadinside3.webp b/files/assets/images/emojis/marseydeadinside3.webp index 4fbbfed3f..a8b78eb96 100644 Binary files a/files/assets/images/emojis/marseydeadinside3.webp and b/files/assets/images/emojis/marseydeadinside3.webp differ diff --git a/files/assets/images/emojis/marseydeathpose.webp b/files/assets/images/emojis/marseydeathpose.webp index ae1f88f2b..21374e7c9 100644 Binary files a/files/assets/images/emojis/marseydeathpose.webp and b/files/assets/images/emojis/marseydeathpose.webp differ diff --git a/files/assets/images/emojis/marseydefenestration.webp b/files/assets/images/emojis/marseydefenestration.webp index 0b669042b..b05e6f9a7 100644 Binary files a/files/assets/images/emojis/marseydefenestration.webp and b/files/assets/images/emojis/marseydefenestration.webp differ diff --git a/files/assets/images/emojis/marseydemiurge.webp b/files/assets/images/emojis/marseydemiurge.webp index 3a80b3d15..cd5a898ef 100644 Binary files a/files/assets/images/emojis/marseydemiurge.webp and b/files/assets/images/emojis/marseydemiurge.webp differ diff --git a/files/assets/images/emojis/marseydemonicgrin.webp b/files/assets/images/emojis/marseydemonicgrin.webp index 2dbd9eb39..c217ae1f9 100644 Binary files a/files/assets/images/emojis/marseydemonicgrin.webp and b/files/assets/images/emojis/marseydemonicgrin.webp differ diff --git a/files/assets/images/emojis/marseydepressed.webp b/files/assets/images/emojis/marseydepressed.webp index 0047893cf..f697812b0 100644 Binary files a/files/assets/images/emojis/marseydepressed.webp and b/files/assets/images/emojis/marseydepressed.webp differ diff --git a/files/assets/images/emojis/marseyderanged.webp b/files/assets/images/emojis/marseyderanged.webp index d2707be9f..cf9f8336d 100644 Binary files a/files/assets/images/emojis/marseyderanged.webp and b/files/assets/images/emojis/marseyderanged.webp differ diff --git a/files/assets/images/emojis/marseydespair.webp b/files/assets/images/emojis/marseydespair.webp index d85a7c857..47d07d1e6 100644 Binary files a/files/assets/images/emojis/marseydespair.webp and b/files/assets/images/emojis/marseydespair.webp differ diff --git a/files/assets/images/emojis/marseydetective.webp b/files/assets/images/emojis/marseydetective.webp index 69fad8958..efd5a6638 100644 Binary files a/files/assets/images/emojis/marseydetective.webp and b/files/assets/images/emojis/marseydetective.webp differ diff --git a/files/assets/images/emojis/marseydetermined.webp b/files/assets/images/emojis/marseydetermined.webp index a1919cda2..8d3af3d8b 100644 Binary files a/files/assets/images/emojis/marseydetermined.webp and b/files/assets/images/emojis/marseydetermined.webp differ diff --git a/files/assets/images/emojis/marseydeux.webp b/files/assets/images/emojis/marseydeux.webp index 48057d4b4..88f89c0d4 100644 Binary files a/files/assets/images/emojis/marseydeux.webp and b/files/assets/images/emojis/marseydeux.webp differ diff --git a/files/assets/images/emojis/marseydeuxfoid.webp b/files/assets/images/emojis/marseydeuxfoid.webp index b87e551eb..92a59db06 100644 Binary files a/files/assets/images/emojis/marseydeuxfoid.webp and b/files/assets/images/emojis/marseydeuxfoid.webp differ diff --git a/files/assets/images/emojis/marseydevil.webp b/files/assets/images/emojis/marseydevil.webp index 51dd547f1..144701393 100644 Binary files a/files/assets/images/emojis/marseydevil.webp and b/files/assets/images/emojis/marseydevil.webp differ diff --git a/files/assets/images/emojis/marseydicklet.webp b/files/assets/images/emojis/marseydicklet.webp index 72edfc359..fd30b08a3 100644 Binary files a/files/assets/images/emojis/marseydicklet.webp and b/files/assets/images/emojis/marseydicklet.webp differ diff --git a/files/assets/images/emojis/marseydiehard.webp b/files/assets/images/emojis/marseydiehard.webp index f56170bc9..0dfb14fa5 100644 Binary files a/files/assets/images/emojis/marseydiehard.webp and b/files/assets/images/emojis/marseydiehard.webp differ diff --git a/files/assets/images/emojis/marseydildo.webp b/files/assets/images/emojis/marseydildo.webp index 3530ad327..925f9212d 100644 Binary files a/files/assets/images/emojis/marseydildo.webp and b/files/assets/images/emojis/marseydildo.webp differ diff --git a/files/assets/images/emojis/marseydinosaur.webp b/files/assets/images/emojis/marseydinosaur.webp index 9124e3d97..2f4fcc441 100644 Binary files a/files/assets/images/emojis/marseydinosaur.webp and b/files/assets/images/emojis/marseydinosaur.webp differ diff --git a/files/assets/images/emojis/marseydio.webp b/files/assets/images/emojis/marseydio.webp index 4db010fae..30615b66f 100644 Binary files a/files/assets/images/emojis/marseydio.webp and b/files/assets/images/emojis/marseydio.webp differ diff --git a/files/assets/images/emojis/marseydisabled.webp b/files/assets/images/emojis/marseydisabled.webp index 9156957ee..3f7ca0de5 100644 Binary files a/files/assets/images/emojis/marseydisabled.webp and b/files/assets/images/emojis/marseydisabled.webp differ diff --git a/files/assets/images/emojis/marseydisconcerting.webp b/files/assets/images/emojis/marseydisconcerting.webp index dc3940e95..be55d4f6e 100644 Binary files a/files/assets/images/emojis/marseydisconcerting.webp and b/files/assets/images/emojis/marseydisconcerting.webp differ diff --git a/files/assets/images/emojis/marseydiscord.webp b/files/assets/images/emojis/marseydiscord.webp index 91322aec5..dca53b372 100644 Binary files a/files/assets/images/emojis/marseydiscord.webp and b/files/assets/images/emojis/marseydiscord.webp differ diff --git a/files/assets/images/emojis/marseydisguise.webp b/files/assets/images/emojis/marseydisguise.webp index ef3edc0a2..76360bd95 100644 Binary files a/files/assets/images/emojis/marseydisguise.webp and b/files/assets/images/emojis/marseydisguise.webp differ diff --git a/files/assets/images/emojis/marseydisgust.webp b/files/assets/images/emojis/marseydisgust.webp index f5321aa52..837c156da 100644 Binary files a/files/assets/images/emojis/marseydisgust.webp and b/files/assets/images/emojis/marseydisgust.webp differ diff --git a/files/assets/images/emojis/marseydisintegrate.webp b/files/assets/images/emojis/marseydisintegrate.webp index 6317c1b46..e67345326 100644 Binary files a/files/assets/images/emojis/marseydisintegrate.webp and b/files/assets/images/emojis/marseydisintegrate.webp differ diff --git a/files/assets/images/emojis/marseydisney.webp b/files/assets/images/emojis/marseydisney.webp new file mode 100644 index 000000000..918b68fd2 Binary files /dev/null and b/files/assets/images/emojis/marseydisney.webp differ diff --git a/files/assets/images/emojis/marseyditto.webp b/files/assets/images/emojis/marseyditto.webp index 0fff95563..d3693e2fb 100644 Binary files a/files/assets/images/emojis/marseyditto.webp and b/files/assets/images/emojis/marseyditto.webp differ diff --git a/files/assets/images/emojis/marseyditzy.webp b/files/assets/images/emojis/marseyditzy.webp index 6b06a2e51..1e11be774 100644 Binary files a/files/assets/images/emojis/marseyditzy.webp and b/files/assets/images/emojis/marseyditzy.webp differ diff --git a/files/assets/images/emojis/marseydiversity.webp b/files/assets/images/emojis/marseydiversity.webp index 6e9e182e3..8e9dd905b 100644 Binary files a/files/assets/images/emojis/marseydiversity.webp and b/files/assets/images/emojis/marseydiversity.webp differ diff --git a/files/assets/images/emojis/marseydiy.webp b/files/assets/images/emojis/marseydiy.webp deleted file mode 100644 index e69de29bb..000000000 diff --git a/files/assets/images/emojis/marseydmx.webp b/files/assets/images/emojis/marseydmx.webp index 42a743513..95581c054 100644 Binary files a/files/assets/images/emojis/marseydmx.webp and b/files/assets/images/emojis/marseydmx.webp differ diff --git a/files/assets/images/emojis/marseydoctor.webp b/files/assets/images/emojis/marseydoctor.webp index 37cab1f0f..91ed6c863 100644 Binary files a/files/assets/images/emojis/marseydoctor.webp and b/files/assets/images/emojis/marseydoctor.webp differ diff --git a/files/assets/images/emojis/marseydog.webp b/files/assets/images/emojis/marseydog.webp index 501eef9d1..65ef23a1d 100644 Binary files a/files/assets/images/emojis/marseydog.webp and b/files/assets/images/emojis/marseydog.webp differ diff --git a/files/assets/images/emojis/marseydogwalker.webp b/files/assets/images/emojis/marseydogwalker.webp index 08d1d0114..ac5db29bc 100644 Binary files a/files/assets/images/emojis/marseydogwalker.webp and b/files/assets/images/emojis/marseydogwalker.webp differ diff --git a/files/assets/images/emojis/marseydoit.webp b/files/assets/images/emojis/marseydoit.webp index b2fe854e9..4047e7bb7 100644 Binary files a/files/assets/images/emojis/marseydoit.webp and b/files/assets/images/emojis/marseydoit.webp differ diff --git a/files/assets/images/emojis/marseydolphin.webp b/files/assets/images/emojis/marseydolphin.webp index 4a8a29683..f053be072 100644 Binary files a/files/assets/images/emojis/marseydolphin.webp and b/files/assets/images/emojis/marseydolphin.webp differ diff --git a/files/assets/images/emojis/marseydomesticabuse.webp b/files/assets/images/emojis/marseydomesticabuse.webp index d335e8550..e6aa0a70b 100644 Binary files a/files/assets/images/emojis/marseydomesticabuse.webp and b/files/assets/images/emojis/marseydomesticabuse.webp differ diff --git a/files/assets/images/emojis/marseydontplay.webp b/files/assets/images/emojis/marseydontplay.webp index e6d54db0f..dbf8be323 100644 Binary files a/files/assets/images/emojis/marseydontplay.webp and b/files/assets/images/emojis/marseydontplay.webp differ diff --git a/files/assets/images/emojis/marseydoomer.webp b/files/assets/images/emojis/marseydoomer.webp index d67d6feda..20a1b722b 100644 Binary files a/files/assets/images/emojis/marseydoomer.webp and b/files/assets/images/emojis/marseydoomer.webp differ diff --git a/files/assets/images/emojis/marseydoubt.webp b/files/assets/images/emojis/marseydoubt.webp index bab5f95e2..65e0a6101 100644 Binary files a/files/assets/images/emojis/marseydoubt.webp and b/files/assets/images/emojis/marseydoubt.webp differ diff --git a/files/assets/images/emojis/marseydoubtit.webp b/files/assets/images/emojis/marseydoubtit.webp index ddafe8e1a..0fe4bc3de 100644 Binary files a/files/assets/images/emojis/marseydoubtit.webp and b/files/assets/images/emojis/marseydoubtit.webp differ diff --git a/files/assets/images/emojis/marseydownvote.webp b/files/assets/images/emojis/marseydownvote.webp index 1b5f8e8d1..47c300889 100644 Binary files a/files/assets/images/emojis/marseydownvote.webp and b/files/assets/images/emojis/marseydownvote.webp differ diff --git a/files/assets/images/emojis/marseydracula.webp b/files/assets/images/emojis/marseydracula.webp index d5fbf0f41..4faef981b 100644 Binary files a/files/assets/images/emojis/marseydracula.webp and b/files/assets/images/emojis/marseydracula.webp differ diff --git a/files/assets/images/emojis/marseydragon.webp b/files/assets/images/emojis/marseydragon.webp index 058981b94..2de072c86 100644 Binary files a/files/assets/images/emojis/marseydragon.webp and b/files/assets/images/emojis/marseydragon.webp differ diff --git a/files/assets/images/emojis/marseydrama.webp b/files/assets/images/emojis/marseydrama.webp index 4d19d99a1..39f47e888 100644 Binary files a/files/assets/images/emojis/marseydrama.webp and b/files/assets/images/emojis/marseydrama.webp differ diff --git a/files/assets/images/emojis/marseydramautist.webp b/files/assets/images/emojis/marseydramautist.webp index 246d4abbf..67444278c 100644 Binary files a/files/assets/images/emojis/marseydramautist.webp and b/files/assets/images/emojis/marseydramautist.webp differ diff --git a/files/assets/images/emojis/marseydrawing1.webp b/files/assets/images/emojis/marseydrawing1.webp index 3604c3f04..3dd079b64 100644 Binary files a/files/assets/images/emojis/marseydrawing1.webp and b/files/assets/images/emojis/marseydrawing1.webp differ diff --git a/files/assets/images/emojis/marseydream.webp b/files/assets/images/emojis/marseydream.webp index 681b1e855..9e9f8ead1 100644 Binary files a/files/assets/images/emojis/marseydream.webp and b/files/assets/images/emojis/marseydream.webp differ diff --git a/files/assets/images/emojis/marseydrone.webp b/files/assets/images/emojis/marseydrone.webp index 5d56347a5..ec32d7412 100644 Binary files a/files/assets/images/emojis/marseydrone.webp and b/files/assets/images/emojis/marseydrone.webp differ diff --git a/files/assets/images/emojis/marseydrowned.webp b/files/assets/images/emojis/marseydrowned.webp index f5a4d4807..522a83421 100644 Binary files a/files/assets/images/emojis/marseydrowned.webp and b/files/assets/images/emojis/marseydrowned.webp differ diff --git a/files/assets/images/emojis/marseydrownedstare.webp b/files/assets/images/emojis/marseydrownedstare.webp new file mode 100644 index 000000000..ed57f56c9 Binary files /dev/null and b/files/assets/images/emojis/marseydrownedstare.webp differ diff --git a/files/assets/images/emojis/marseydrunk.webp b/files/assets/images/emojis/marseydrunk.webp index 4e44c90bb..e72e5c436 100644 Binary files a/files/assets/images/emojis/marseydrunk.webp and b/files/assets/images/emojis/marseydrunk.webp differ diff --git a/files/assets/images/emojis/marseydrunk2.webp b/files/assets/images/emojis/marseydrunk2.webp index cb214e6ba..6569faba3 100644 Binary files a/files/assets/images/emojis/marseydrunk2.webp and b/files/assets/images/emojis/marseydrunk2.webp differ diff --git a/files/assets/images/emojis/marseyduchamp.webp b/files/assets/images/emojis/marseyduchamp.webp index 9159e0254..8419e1963 100644 Binary files a/files/assets/images/emojis/marseyduchamp.webp and b/files/assets/images/emojis/marseyduchamp.webp differ diff --git a/files/assets/images/emojis/marseyduck.webp b/files/assets/images/emojis/marseyduck.webp index 72fb30b44..fc983ec22 100644 Binary files a/files/assets/images/emojis/marseyduck.webp and b/files/assets/images/emojis/marseyduck.webp differ diff --git a/files/assets/images/emojis/marseyduck2.webp b/files/assets/images/emojis/marseyduck2.webp index 85a16e132..7dfeac639 100644 Binary files a/files/assets/images/emojis/marseyduck2.webp and b/files/assets/images/emojis/marseyduck2.webp differ diff --git a/files/assets/images/emojis/marseyduck3.webp b/files/assets/images/emojis/marseyduck3.webp index 7aeb7f287..311ff5d65 100644 Binary files a/files/assets/images/emojis/marseyduck3.webp and b/files/assets/images/emojis/marseyduck3.webp differ diff --git a/files/assets/images/emojis/marseydukenukem.webp b/files/assets/images/emojis/marseydukenukem.webp index da5c0c965..f4e046936 100644 Binary files a/files/assets/images/emojis/marseydukenukem.webp and b/files/assets/images/emojis/marseydukenukem.webp differ diff --git a/files/assets/images/emojis/marseydumptruck.webp b/files/assets/images/emojis/marseydumptruck.webp index 991ca9819..08fd37d00 100644 Binary files a/files/assets/images/emojis/marseydumptruck.webp and b/files/assets/images/emojis/marseydumptruck.webp differ diff --git a/files/assets/images/emojis/marseydunce.webp b/files/assets/images/emojis/marseydunce.webp index 22ea84fc0..8af573070 100644 Binary files a/files/assets/images/emojis/marseydunce.webp and b/files/assets/images/emojis/marseydunce.webp differ diff --git a/files/assets/images/emojis/marseydunkon.webp b/files/assets/images/emojis/marseydunkon.webp index 74664e6a7..735fab6f6 100644 Binary files a/files/assets/images/emojis/marseydunkon.webp and b/files/assets/images/emojis/marseydunkon.webp differ diff --git a/files/assets/images/emojis/marseydylan.webp b/files/assets/images/emojis/marseydylan.webp index 95ee713bb..68418af33 100644 Binary files a/files/assets/images/emojis/marseydylan.webp and b/files/assets/images/emojis/marseydylan.webp differ diff --git a/files/assets/images/emojis/marseydylannroof.webp b/files/assets/images/emojis/marseydylannroof.webp new file mode 100644 index 000000000..52db8d0d8 Binary files /dev/null and b/files/assets/images/emojis/marseydylannroof.webp differ diff --git a/files/assets/images/emojis/marseydynamite.webp b/files/assets/images/emojis/marseydynamite.webp index fd16971f8..75f0693de 100644 Binary files a/files/assets/images/emojis/marseydynamite.webp and b/files/assets/images/emojis/marseydynamite.webp differ diff --git a/files/assets/images/emojis/marseyearrape.webp b/files/assets/images/emojis/marseyearrape.webp index 412d94824..452e69b34 100644 Binary files a/files/assets/images/emojis/marseyearrape.webp and b/files/assets/images/emojis/marseyearrape.webp differ diff --git a/files/assets/images/emojis/marseyecstatic.webp b/files/assets/images/emojis/marseyecstatic.webp index f7ac86025..13eaaafaf 100644 Binary files a/files/assets/images/emojis/marseyecstatic.webp and b/files/assets/images/emojis/marseyecstatic.webp differ diff --git a/files/assets/images/emojis/marseyedelgard.webp b/files/assets/images/emojis/marseyedelgard.webp index 2379362a6..564b02333 100644 Binary files a/files/assets/images/emojis/marseyedelgard.webp and b/files/assets/images/emojis/marseyedelgard.webp differ diff --git a/files/assets/images/emojis/marseyedelgard2.webp b/files/assets/images/emojis/marseyedelgard2.webp index 7c22f4fc9..dc27572a5 100644 Binary files a/files/assets/images/emojis/marseyedelgard2.webp and b/files/assets/images/emojis/marseyedelgard2.webp differ diff --git a/files/assets/images/emojis/marseyeerie1.webp b/files/assets/images/emojis/marseyeerie1.webp index 573bbcacf..ff68678e2 100644 Binary files a/files/assets/images/emojis/marseyeerie1.webp and b/files/assets/images/emojis/marseyeerie1.webp differ diff --git a/files/assets/images/emojis/marseyeerie2.webp b/files/assets/images/emojis/marseyeerie2.webp index 6b4ba948a..44e8381ae 100644 Binary files a/files/assets/images/emojis/marseyeerie2.webp and b/files/assets/images/emojis/marseyeerie2.webp differ diff --git a/files/assets/images/emojis/marseyeerie3.webp b/files/assets/images/emojis/marseyeerie3.webp index 7d92d0ba1..dceaef1f5 100644 Binary files a/files/assets/images/emojis/marseyeerie3.webp and b/files/assets/images/emojis/marseyeerie3.webp differ diff --git a/files/assets/images/emojis/marseyeggirl.webp b/files/assets/images/emojis/marseyeggirl.webp index 246c05cee..2cc3d43d0 100644 Binary files a/files/assets/images/emojis/marseyeggirl.webp and b/files/assets/images/emojis/marseyeggirl.webp differ diff --git a/files/assets/images/emojis/marseyeggless.webp b/files/assets/images/emojis/marseyeggless.webp index 560e6e421..e40d3f728 100644 Binary files a/files/assets/images/emojis/marseyeggless.webp and b/files/assets/images/emojis/marseyeggless.webp differ diff --git a/files/assets/images/emojis/marseyeh.webp b/files/assets/images/emojis/marseyeh.webp index 3b80bfac5..ab376009a 100644 Binary files a/files/assets/images/emojis/marseyeh.webp and b/files/assets/images/emojis/marseyeh.webp differ diff --git a/files/assets/images/emojis/marseyeldritch.webp b/files/assets/images/emojis/marseyeldritch.webp index 188c2565d..0749fbde2 100644 Binary files a/files/assets/images/emojis/marseyeldritch.webp and b/files/assets/images/emojis/marseyeldritch.webp differ diff --git a/files/assets/images/emojis/marseyeldritch2.webp b/files/assets/images/emojis/marseyeldritch2.webp index f892788bd..569b8947a 100644 Binary files a/files/assets/images/emojis/marseyeldritch2.webp and b/files/assets/images/emojis/marseyeldritch2.webp differ diff --git a/files/assets/images/emojis/marseyeldritchnut.webp b/files/assets/images/emojis/marseyeldritchnut.webp index e5362bfee..aae5df97b 100644 Binary files a/files/assets/images/emojis/marseyeldritchnut.webp and b/files/assets/images/emojis/marseyeldritchnut.webp differ diff --git a/files/assets/images/emojis/marseyelephant.webp b/files/assets/images/emojis/marseyelephant.webp index 306c25638..82aa7f20a 100644 Binary files a/files/assets/images/emojis/marseyelephant.webp and b/files/assets/images/emojis/marseyelephant.webp differ diff --git a/files/assets/images/emojis/marseyelephantcumjar1.webp b/files/assets/images/emojis/marseyelephantcumjar1.webp index 22ca5d503..0a1e09774 100644 Binary files a/files/assets/images/emojis/marseyelephantcumjar1.webp and b/files/assets/images/emojis/marseyelephantcumjar1.webp differ diff --git a/files/assets/images/emojis/marseyelephantcumjar2.webp b/files/assets/images/emojis/marseyelephantcumjar2.webp index 586c544a4..0f4f1cd48 100644 Binary files a/files/assets/images/emojis/marseyelephantcumjar2.webp and b/files/assets/images/emojis/marseyelephantcumjar2.webp differ diff --git a/files/assets/images/emojis/marseyelliotrodger.webp b/files/assets/images/emojis/marseyelliotrodger.webp index 0abd87745..01071a573 100644 Binary files a/files/assets/images/emojis/marseyelliotrodger.webp and b/files/assets/images/emojis/marseyelliotrodger.webp differ diff --git a/files/assets/images/emojis/marseyelliotrodger2.webp b/files/assets/images/emojis/marseyelliotrodger2.webp index d7a656bc1..9ef13425e 100644 Binary files a/files/assets/images/emojis/marseyelliotrodger2.webp and b/files/assets/images/emojis/marseyelliotrodger2.webp differ diff --git a/files/assets/images/emojis/marseyelliotrodger3.webp b/files/assets/images/emojis/marseyelliotrodger3.webp index 66ce160e2..9b5a7f147 100644 Binary files a/files/assets/images/emojis/marseyelliotrodger3.webp and b/files/assets/images/emojis/marseyelliotrodger3.webp differ diff --git a/files/assets/images/emojis/marseyelonmusk.webp b/files/assets/images/emojis/marseyelonmusk.webp index c1e280f14..41db1809a 100644 Binary files a/files/assets/images/emojis/marseyelonmusk.webp and b/files/assets/images/emojis/marseyelonmusk.webp differ diff --git a/files/assets/images/emojis/marseyembrace.webp b/files/assets/images/emojis/marseyembrace.webp index 39f03a125..e9e101ed7 100644 Binary files a/files/assets/images/emojis/marseyembrace.webp and b/files/assets/images/emojis/marseyembrace.webp differ diff --git a/files/assets/images/emojis/marseyemo.webp b/files/assets/images/emojis/marseyemo.webp index 121a5f046..defff8855 100644 Binary files a/files/assets/images/emojis/marseyemo.webp and b/files/assets/images/emojis/marseyemo.webp differ diff --git a/files/assets/images/emojis/marseyemojigrin.webp b/files/assets/images/emojis/marseyemojigrin.webp index 150c1707d..c9df35bc1 100644 Binary files a/files/assets/images/emojis/marseyemojigrin.webp and b/files/assets/images/emojis/marseyemojigrin.webp differ diff --git a/files/assets/images/emojis/marseyemojigrineyes.webp b/files/assets/images/emojis/marseyemojigrineyes.webp index 77e2824b1..73ee2c5d3 100644 Binary files a/files/assets/images/emojis/marseyemojigrineyes.webp and b/files/assets/images/emojis/marseyemojigrineyes.webp differ diff --git a/files/assets/images/emojis/marseyemojirofl.webp b/files/assets/images/emojis/marseyemojirofl.webp index 6334d04ef..31764dc1a 100644 Binary files a/files/assets/images/emojis/marseyemojirofl.webp and b/files/assets/images/emojis/marseyemojirofl.webp differ diff --git a/files/assets/images/emojis/marseyemojismilemouth.webp b/files/assets/images/emojis/marseyemojismilemouth.webp index 91267a488..cc4b235e1 100644 Binary files a/files/assets/images/emojis/marseyemojismilemouth.webp and b/files/assets/images/emojis/marseyemojismilemouth.webp differ diff --git a/files/assets/images/emojis/marseyemojismilemouthcoldsweat.webp b/files/assets/images/emojis/marseyemojismilemouthcoldsweat.webp index d90233f53..55b036cff 100644 Binary files a/files/assets/images/emojis/marseyemojismilemouthcoldsweat.webp and b/files/assets/images/emojis/marseyemojismilemouthcoldsweat.webp differ diff --git a/files/assets/images/emojis/marseyemojismilemoutheyes.webp b/files/assets/images/emojis/marseyemojismilemoutheyes.webp index 1b27edfd8..1ca5aa828 100644 Binary files a/files/assets/images/emojis/marseyemojismilemoutheyes.webp and b/files/assets/images/emojis/marseyemojismilemoutheyes.webp differ diff --git a/files/assets/images/emojis/marseyemojismilemouthtighteyes.webp b/files/assets/images/emojis/marseyemojismilemouthtighteyes.webp index face5022c..023b85fe0 100644 Binary files a/files/assets/images/emojis/marseyemojismilemouthtighteyes.webp and b/files/assets/images/emojis/marseyemojismilemouthtighteyes.webp differ diff --git a/files/assets/images/emojis/marseyemperor.webp b/files/assets/images/emojis/marseyemperor.webp index 3dc310381..d2e3367c2 100644 Binary files a/files/assets/images/emojis/marseyemperor.webp and b/files/assets/images/emojis/marseyemperor.webp differ diff --git a/files/assets/images/emojis/marseyeric.webp b/files/assets/images/emojis/marseyeric.webp index 7764fa354..27f465f4e 100644 Binary files a/files/assets/images/emojis/marseyeric.webp and b/files/assets/images/emojis/marseyeric.webp differ diff --git a/files/assets/images/emojis/marseyeskimo.webp b/files/assets/images/emojis/marseyeskimo.webp index 6a8bd0963..4f6ab08b9 100644 Binary files a/files/assets/images/emojis/marseyeskimo.webp and b/files/assets/images/emojis/marseyeskimo.webp differ diff --git a/files/assets/images/emojis/marseyespeon.webp b/files/assets/images/emojis/marseyespeon.webp index 5bbb612ab..38f5a605f 100644 Binary files a/files/assets/images/emojis/marseyespeon.webp and b/files/assets/images/emojis/marseyespeon.webp differ diff --git a/files/assets/images/emojis/marseyetika.webp b/files/assets/images/emojis/marseyetika.webp index fa4f9e0d2..091f5fec8 100644 Binary files a/files/assets/images/emojis/marseyetika.webp and b/files/assets/images/emojis/marseyetika.webp differ diff --git a/files/assets/images/emojis/marseyeva.webp b/files/assets/images/emojis/marseyeva.webp index d2f003a8f..18127ef76 100644 Binary files a/files/assets/images/emojis/marseyeva.webp and b/files/assets/images/emojis/marseyeva.webp differ diff --git a/files/assets/images/emojis/marseyevilagent.webp b/files/assets/images/emojis/marseyevilagent.webp index f20369143..cbe4a026e 100644 Binary files a/files/assets/images/emojis/marseyevilagent.webp and b/files/assets/images/emojis/marseyevilagent.webp differ diff --git a/files/assets/images/emojis/marseyevilgrin.webp b/files/assets/images/emojis/marseyevilgrin.webp index e1d30f57f..3a0a9ab5c 100644 Binary files a/files/assets/images/emojis/marseyevilgrin.webp and b/files/assets/images/emojis/marseyevilgrin.webp differ diff --git a/files/assets/images/emojis/marseyexcited.webp b/files/assets/images/emojis/marseyexcited.webp index 821644a3e..7ce022d3d 100644 Binary files a/files/assets/images/emojis/marseyexcited.webp and b/files/assets/images/emojis/marseyexcited.webp differ diff --git a/files/assets/images/emojis/marseyexcitedexosuit.webp b/files/assets/images/emojis/marseyexcitedexosuit.webp index 3961eed90..3c6a00c27 100644 Binary files a/files/assets/images/emojis/marseyexcitedexosuit.webp and b/files/assets/images/emojis/marseyexcitedexosuit.webp differ diff --git a/files/assets/images/emojis/marseyexclamationpoint.webp b/files/assets/images/emojis/marseyexclamationpoint.webp index 23e9b0454..6fed483b3 100644 Binary files a/files/assets/images/emojis/marseyexclamationpoint.webp and b/files/assets/images/emojis/marseyexclamationpoint.webp differ diff --git a/files/assets/images/emojis/marseyeyelidpulling.webp b/files/assets/images/emojis/marseyeyelidpulling.webp index 11a402e1a..307cbe175 100644 Binary files a/files/assets/images/emojis/marseyeyelidpulling.webp and b/files/assets/images/emojis/marseyeyelidpulling.webp differ diff --git a/files/assets/images/emojis/marseyeyemixer.webp b/files/assets/images/emojis/marseyeyemixer.webp index 3c4914299..9d036620d 100644 Binary files a/files/assets/images/emojis/marseyeyemixer.webp and b/files/assets/images/emojis/marseyeyemixer.webp differ diff --git a/files/assets/images/emojis/marseyeyemixer2.webp b/files/assets/images/emojis/marseyeyemixer2.webp index 36b29b74b..9591e9e72 100644 Binary files a/files/assets/images/emojis/marseyeyemixer2.webp and b/files/assets/images/emojis/marseyeyemixer2.webp differ diff --git a/files/assets/images/emojis/marseyeyeroll2.webp b/files/assets/images/emojis/marseyeyeroll2.webp index 110f0d11c..f1dbb144e 100644 Binary files a/files/assets/images/emojis/marseyeyeroll2.webp and b/files/assets/images/emojis/marseyeyeroll2.webp differ diff --git a/files/assets/images/emojis/marseyeyes.webp b/files/assets/images/emojis/marseyeyes.webp index 1990a7e9e..0da89bdfa 100644 Binary files a/files/assets/images/emojis/marseyeyes.webp and b/files/assets/images/emojis/marseyeyes.webp differ diff --git a/files/assets/images/emojis/marseyezramiller.webp b/files/assets/images/emojis/marseyezramiller.webp index 23c24faf8..46b0a6411 100644 Binary files a/files/assets/images/emojis/marseyezramiller.webp and b/files/assets/images/emojis/marseyezramiller.webp differ diff --git a/files/assets/images/emojis/marseyface.webp b/files/assets/images/emojis/marseyface.webp index 576525882..47032f4bb 100644 Binary files a/files/assets/images/emojis/marseyface.webp and b/files/assets/images/emojis/marseyface.webp differ diff --git a/files/assets/images/emojis/marseyfacepalm.webp b/files/assets/images/emojis/marseyfacepalm.webp index c553f36a1..622a39261 100644 Binary files a/files/assets/images/emojis/marseyfacepalm.webp and b/files/assets/images/emojis/marseyfacepalm.webp differ diff --git a/files/assets/images/emojis/marseyfacepeel.webp b/files/assets/images/emojis/marseyfacepeel.webp index fc75682b0..7d4019575 100644 Binary files a/files/assets/images/emojis/marseyfacepeel.webp and b/files/assets/images/emojis/marseyfacepeel.webp differ diff --git a/files/assets/images/emojis/marseyfamily.webp b/files/assets/images/emojis/marseyfamily.webp index 5f34233dc..2a6aa69b0 100644 Binary files a/files/assets/images/emojis/marseyfamily.webp and b/files/assets/images/emojis/marseyfamily.webp differ diff --git a/files/assets/images/emojis/marseyfans.webp b/files/assets/images/emojis/marseyfans.webp index 58d470500..ccf90fd5e 100644 Binary files a/files/assets/images/emojis/marseyfans.webp and b/files/assets/images/emojis/marseyfans.webp differ diff --git a/files/assets/images/emojis/marseyfatherjoseph.webp b/files/assets/images/emojis/marseyfatherjoseph.webp index 9bb7c058a..83f58b82f 100644 Binary files a/files/assets/images/emojis/marseyfatherjoseph.webp and b/files/assets/images/emojis/marseyfatherjoseph.webp differ diff --git a/files/assets/images/emojis/marseyfattie.webp b/files/assets/images/emojis/marseyfattie.webp index 06d3f37a1..84afcdf37 100644 Binary files a/files/assets/images/emojis/marseyfattie.webp and b/files/assets/images/emojis/marseyfattie.webp differ diff --git a/files/assets/images/emojis/marseyfbi.webp b/files/assets/images/emojis/marseyfbi.webp index 1bad0e8ed..e4973a358 100644 Binary files a/files/assets/images/emojis/marseyfbi.webp and b/files/assets/images/emojis/marseyfbi.webp differ diff --git a/files/assets/images/emojis/marseyfbiagent.webp b/files/assets/images/emojis/marseyfbiagent.webp index e009f238e..3f297c23b 100644 Binary files a/files/assets/images/emojis/marseyfbiagent.webp and b/files/assets/images/emojis/marseyfbiagent.webp differ diff --git a/files/assets/images/emojis/marseyfbicomputer.webp b/files/assets/images/emojis/marseyfbicomputer.webp index 19a61f8ca..24e8e65c6 100644 Binary files a/files/assets/images/emojis/marseyfbicomputer.webp and b/files/assets/images/emojis/marseyfbicomputer.webp differ diff --git a/files/assets/images/emojis/marseyfedora.webp b/files/assets/images/emojis/marseyfedora.webp index 768cdd43e..c8b08137b 100644 Binary files a/files/assets/images/emojis/marseyfedora.webp and b/files/assets/images/emojis/marseyfedora.webp differ diff --git a/files/assets/images/emojis/marseyfedoratip.webp b/files/assets/images/emojis/marseyfedoratip.webp index 9fa27986b..88fa64fd6 100644 Binary files a/files/assets/images/emojis/marseyfedoratip.webp and b/files/assets/images/emojis/marseyfedoratip.webp differ diff --git a/files/assets/images/emojis/marseyfedposthmmm.webp b/files/assets/images/emojis/marseyfedposthmmm.webp index 63dc56610..ba5c2230e 100644 Binary files a/files/assets/images/emojis/marseyfedposthmmm.webp and b/files/assets/images/emojis/marseyfedposthmmm.webp differ diff --git a/files/assets/images/emojis/marseyfedscared.webp b/files/assets/images/emojis/marseyfedscared.webp index e3078c5f2..3749f2aaf 100644 Binary files a/files/assets/images/emojis/marseyfedscared.webp and b/files/assets/images/emojis/marseyfedscared.webp differ diff --git a/files/assets/images/emojis/marseyfedscared2.webp b/files/assets/images/emojis/marseyfedscared2.webp index ca82cc0f2..ee428f6b4 100644 Binary files a/files/assets/images/emojis/marseyfedscared2.webp and b/files/assets/images/emojis/marseyfedscared2.webp differ diff --git a/files/assets/images/emojis/marseyfeelsgood.webp b/files/assets/images/emojis/marseyfeelsgood.webp index 7ad0d1821..7f004c780 100644 Binary files a/files/assets/images/emojis/marseyfeelsgood.webp and b/files/assets/images/emojis/marseyfeelsgood.webp differ diff --git a/files/assets/images/emojis/marseyfeelsgoodman.webp b/files/assets/images/emojis/marseyfeelsgoodman.webp index bd74c9352..407fd4fd3 100644 Binary files a/files/assets/images/emojis/marseyfeelsgoodman.webp and b/files/assets/images/emojis/marseyfeelsgoodman.webp differ diff --git a/files/assets/images/emojis/marseyfeet.webp b/files/assets/images/emojis/marseyfeet.webp index def158fd5..ac9824e17 100644 Binary files a/files/assets/images/emojis/marseyfeet.webp and b/files/assets/images/emojis/marseyfeet.webp differ diff --git a/files/assets/images/emojis/marseyfellowkids.webp b/files/assets/images/emojis/marseyfellowkids.webp index 5aec7abba..f41c4418c 100644 Binary files a/files/assets/images/emojis/marseyfellowkids.webp and b/files/assets/images/emojis/marseyfellowkids.webp differ diff --git a/files/assets/images/emojis/marseyfellowpedo.webp b/files/assets/images/emojis/marseyfellowpedo.webp index 31dd88292..5fc0693bd 100644 Binary files a/files/assets/images/emojis/marseyfellowpedo.webp and b/files/assets/images/emojis/marseyfellowpedo.webp differ diff --git a/files/assets/images/emojis/marseyfemboy.webp b/files/assets/images/emojis/marseyfemboy.webp index fa6e2413a..037e5fe0c 100644 Binary files a/files/assets/images/emojis/marseyfemboy.webp and b/files/assets/images/emojis/marseyfemboy.webp differ diff --git a/files/assets/images/emojis/marseyfeminist.webp b/files/assets/images/emojis/marseyfeminist.webp index d1de70710..f14be86f4 100644 Binary files a/files/assets/images/emojis/marseyfeminist.webp and b/files/assets/images/emojis/marseyfeminist.webp differ diff --git a/files/assets/images/emojis/marseyferret.webp b/files/assets/images/emojis/marseyferret.webp index c85c8fa12..3cb573741 100644 Binary files a/files/assets/images/emojis/marseyferret.webp and b/files/assets/images/emojis/marseyferret.webp differ diff --git a/files/assets/images/emojis/marseyfeynman.webp b/files/assets/images/emojis/marseyfeynman.webp index 34f2e2016..fa2ede512 100644 Binary files a/files/assets/images/emojis/marseyfeynman.webp and b/files/assets/images/emojis/marseyfeynman.webp differ diff --git a/files/assets/images/emojis/marseyfighter.webp b/files/assets/images/emojis/marseyfighter.webp index 254c33402..9be66042b 100644 Binary files a/files/assets/images/emojis/marseyfighter.webp and b/files/assets/images/emojis/marseyfighter.webp differ diff --git a/files/assets/images/emojis/marseyfigureskate.webp b/files/assets/images/emojis/marseyfigureskate.webp index 33a785872..e4fbcb8c6 100644 Binary files a/files/assets/images/emojis/marseyfigureskate.webp and b/files/assets/images/emojis/marseyfigureskate.webp differ diff --git a/files/assets/images/emojis/marseyfine.webp b/files/assets/images/emojis/marseyfine.webp index 2c137b5ed..7a0bc1852 100644 Binary files a/files/assets/images/emojis/marseyfine.webp and b/files/assets/images/emojis/marseyfine.webp differ diff --git a/files/assets/images/emojis/marseyfinger.webp b/files/assets/images/emojis/marseyfinger.webp index f58659a63..4e8bf9c7d 100644 Binary files a/files/assets/images/emojis/marseyfinger.webp and b/files/assets/images/emojis/marseyfinger.webp differ diff --git a/files/assets/images/emojis/marseyflagafghanistan.webp b/files/assets/images/emojis/marseyflagafghanistan.webp index c05b45019..90404824a 100644 Binary files a/files/assets/images/emojis/marseyflagafghanistan.webp and b/files/assets/images/emojis/marseyflagafghanistan.webp differ diff --git a/files/assets/images/emojis/marseyflagafrica.webp b/files/assets/images/emojis/marseyflagafrica.webp index b2faa1ff6..e7a288dca 100644 Binary files a/files/assets/images/emojis/marseyflagafrica.webp and b/files/assets/images/emojis/marseyflagafrica.webp differ diff --git a/files/assets/images/emojis/marseyflagalbania.webp b/files/assets/images/emojis/marseyflagalbania.webp index d4a9b79da..fa00878bb 100644 Binary files a/files/assets/images/emojis/marseyflagalbania.webp and b/files/assets/images/emojis/marseyflagalbania.webp differ diff --git a/files/assets/images/emojis/marseyflagalgeria.webp b/files/assets/images/emojis/marseyflagalgeria.webp index d8ad68513..2c5fe412a 100644 Binary files a/files/assets/images/emojis/marseyflagalgeria.webp and b/files/assets/images/emojis/marseyflagalgeria.webp differ diff --git a/files/assets/images/emojis/marseyflagandorra.webp b/files/assets/images/emojis/marseyflagandorra.webp index 35c97b666..2f04faaa0 100644 Binary files a/files/assets/images/emojis/marseyflagandorra.webp and b/files/assets/images/emojis/marseyflagandorra.webp differ diff --git a/files/assets/images/emojis/marseyflagangola.webp b/files/assets/images/emojis/marseyflagangola.webp index ccfe12faa..114089d86 100644 Binary files a/files/assets/images/emojis/marseyflagangola.webp and b/files/assets/images/emojis/marseyflagangola.webp differ diff --git a/files/assets/images/emojis/marseyflagantarctica.webp b/files/assets/images/emojis/marseyflagantarctica.webp index c18c9d1a1..8afee9db5 100644 Binary files a/files/assets/images/emojis/marseyflagantarctica.webp and b/files/assets/images/emojis/marseyflagantarctica.webp differ diff --git a/files/assets/images/emojis/marseyflagantiguaandbarbuda.webp b/files/assets/images/emojis/marseyflagantiguaandbarbuda.webp index 96229ceb3..fff94100c 100644 Binary files a/files/assets/images/emojis/marseyflagantiguaandbarbuda.webp and b/files/assets/images/emojis/marseyflagantiguaandbarbuda.webp differ diff --git a/files/assets/images/emojis/marseyflagargentina.webp b/files/assets/images/emojis/marseyflagargentina.webp index 1d0fffd75..eb5c111a6 100644 Binary files a/files/assets/images/emojis/marseyflagargentina.webp and b/files/assets/images/emojis/marseyflagargentina.webp differ diff --git a/files/assets/images/emojis/marseyflagarmenia.webp b/files/assets/images/emojis/marseyflagarmenia.webp index 68c2de88b..900224935 100644 Binary files a/files/assets/images/emojis/marseyflagarmenia.webp and b/files/assets/images/emojis/marseyflagarmenia.webp differ diff --git a/files/assets/images/emojis/marseyflagaustralia.webp b/files/assets/images/emojis/marseyflagaustralia.webp index 3a76bb401..bd679280e 100644 Binary files a/files/assets/images/emojis/marseyflagaustralia.webp and b/files/assets/images/emojis/marseyflagaustralia.webp differ diff --git a/files/assets/images/emojis/marseyflagaustria.webp b/files/assets/images/emojis/marseyflagaustria.webp index 57dcb9f72..59722a993 100644 Binary files a/files/assets/images/emojis/marseyflagaustria.webp and b/files/assets/images/emojis/marseyflagaustria.webp differ diff --git a/files/assets/images/emojis/marseyflagazerbaijan.webp b/files/assets/images/emojis/marseyflagazerbaijan.webp index 119bb1570..921815dbe 100644 Binary files a/files/assets/images/emojis/marseyflagazerbaijan.webp and b/files/assets/images/emojis/marseyflagazerbaijan.webp differ diff --git a/files/assets/images/emojis/marseyflagbahamas.webp b/files/assets/images/emojis/marseyflagbahamas.webp index 00b3fec2e..0c30654ce 100644 Binary files a/files/assets/images/emojis/marseyflagbahamas.webp and b/files/assets/images/emojis/marseyflagbahamas.webp differ diff --git a/files/assets/images/emojis/marseyflagbahrain.webp b/files/assets/images/emojis/marseyflagbahrain.webp index 6f8e40631..b4cfba1cf 100644 Binary files a/files/assets/images/emojis/marseyflagbahrain.webp and b/files/assets/images/emojis/marseyflagbahrain.webp differ diff --git a/files/assets/images/emojis/marseyflagbangladesh.webp b/files/assets/images/emojis/marseyflagbangladesh.webp index 8ef9e5f31..bf5f040c8 100644 Binary files a/files/assets/images/emojis/marseyflagbangladesh.webp and b/files/assets/images/emojis/marseyflagbangladesh.webp differ diff --git a/files/assets/images/emojis/marseyflagbarbados.webp b/files/assets/images/emojis/marseyflagbarbados.webp index 746ec6be6..0025b0eed 100644 Binary files a/files/assets/images/emojis/marseyflagbarbados.webp and b/files/assets/images/emojis/marseyflagbarbados.webp differ diff --git a/files/assets/images/emojis/marseyflagbelarus.webp b/files/assets/images/emojis/marseyflagbelarus.webp index 6e991bde2..814d4606c 100644 Binary files a/files/assets/images/emojis/marseyflagbelarus.webp and b/files/assets/images/emojis/marseyflagbelarus.webp differ diff --git a/files/assets/images/emojis/marseyflagbelgium.webp b/files/assets/images/emojis/marseyflagbelgium.webp index e37fa9d04..f58b96bfe 100644 Binary files a/files/assets/images/emojis/marseyflagbelgium.webp and b/files/assets/images/emojis/marseyflagbelgium.webp differ diff --git a/files/assets/images/emojis/marseyflagbosnia.webp b/files/assets/images/emojis/marseyflagbosnia.webp index 9240ef25c..70a81f7ed 100644 Binary files a/files/assets/images/emojis/marseyflagbosnia.webp and b/files/assets/images/emojis/marseyflagbosnia.webp differ diff --git a/files/assets/images/emojis/marseyflagbrazil.webp b/files/assets/images/emojis/marseyflagbrazil.webp index 570816702..e1952480d 100644 Binary files a/files/assets/images/emojis/marseyflagbrazil.webp and b/files/assets/images/emojis/marseyflagbrazil.webp differ diff --git a/files/assets/images/emojis/marseyflagbulgaria.webp b/files/assets/images/emojis/marseyflagbulgaria.webp index 10689e464..36f8446cf 100644 Binary files a/files/assets/images/emojis/marseyflagbulgaria.webp and b/files/assets/images/emojis/marseyflagbulgaria.webp differ diff --git a/files/assets/images/emojis/marseyflagcalifornia.webp b/files/assets/images/emojis/marseyflagcalifornia.webp new file mode 100644 index 000000000..a6310ae37 Binary files /dev/null and b/files/assets/images/emojis/marseyflagcalifornia.webp differ diff --git a/files/assets/images/emojis/marseyflagcanada.webp b/files/assets/images/emojis/marseyflagcanada.webp index 37deb8b90..7950d698a 100644 Binary files a/files/assets/images/emojis/marseyflagcanada.webp and b/files/assets/images/emojis/marseyflagcanada.webp differ diff --git a/files/assets/images/emojis/marseyflagchile.webp b/files/assets/images/emojis/marseyflagchile.webp index b6ffd338c..b76335659 100644 Binary files a/files/assets/images/emojis/marseyflagchile.webp and b/files/assets/images/emojis/marseyflagchile.webp differ diff --git a/files/assets/images/emojis/marseyflagchina.webp b/files/assets/images/emojis/marseyflagchina.webp index b3d259f12..9e5ae9df4 100644 Binary files a/files/assets/images/emojis/marseyflagchina.webp and b/files/assets/images/emojis/marseyflagchina.webp differ diff --git a/files/assets/images/emojis/marseyflagcolombia.webp b/files/assets/images/emojis/marseyflagcolombia.webp index 9e432d28e..6808862e8 100644 Binary files a/files/assets/images/emojis/marseyflagcolombia.webp and b/files/assets/images/emojis/marseyflagcolombia.webp differ diff --git a/files/assets/images/emojis/marseyflagcyprus.webp b/files/assets/images/emojis/marseyflagcyprus.webp index 888a67721..73cf1943b 100644 Binary files a/files/assets/images/emojis/marseyflagcyprus.webp and b/files/assets/images/emojis/marseyflagcyprus.webp differ diff --git a/files/assets/images/emojis/marseyflagdenmark.webp b/files/assets/images/emojis/marseyflagdenmark.webp index 0b3e5554f..36a5b4e42 100644 Binary files a/files/assets/images/emojis/marseyflagdenmark.webp and b/files/assets/images/emojis/marseyflagdenmark.webp differ diff --git a/files/assets/images/emojis/marseyflagegypt.webp b/files/assets/images/emojis/marseyflagegypt.webp index 58d149d2f..4828f8273 100644 Binary files a/files/assets/images/emojis/marseyflagegypt.webp and b/files/assets/images/emojis/marseyflagegypt.webp differ diff --git a/files/assets/images/emojis/marseyflagelsalvador.webp b/files/assets/images/emojis/marseyflagelsalvador.webp index cdcf006d8..f9770ee37 100644 Binary files a/files/assets/images/emojis/marseyflagelsalvador.webp and b/files/assets/images/emojis/marseyflagelsalvador.webp differ diff --git a/files/assets/images/emojis/marseyflagestonia.webp b/files/assets/images/emojis/marseyflagestonia.webp index 74340a9de..c72843452 100644 Binary files a/files/assets/images/emojis/marseyflagestonia.webp and b/files/assets/images/emojis/marseyflagestonia.webp differ diff --git a/files/assets/images/emojis/marseyflageu.webp b/files/assets/images/emojis/marseyflageu.webp new file mode 100644 index 000000000..6d5286eac Binary files /dev/null and b/files/assets/images/emojis/marseyflageu.webp differ diff --git a/files/assets/images/emojis/marseyflagfinland.webp b/files/assets/images/emojis/marseyflagfinland.webp index b11d5c892..1803c9b8b 100644 Binary files a/files/assets/images/emojis/marseyflagfinland.webp and b/files/assets/images/emojis/marseyflagfinland.webp differ diff --git a/files/assets/images/emojis/marseyflagfrance.webp b/files/assets/images/emojis/marseyflagfrance.webp index 1588e2840..eed126b73 100644 Binary files a/files/assets/images/emojis/marseyflagfrance.webp and b/files/assets/images/emojis/marseyflagfrance.webp differ diff --git a/files/assets/images/emojis/marseyflaggeorgia.webp b/files/assets/images/emojis/marseyflaggeorgia.webp index ac09ecb1a..16c0ff011 100644 Binary files a/files/assets/images/emojis/marseyflaggeorgia.webp and b/files/assets/images/emojis/marseyflaggeorgia.webp differ diff --git a/files/assets/images/emojis/marseyflaggermany.webp b/files/assets/images/emojis/marseyflaggermany.webp index 3139447b2..7cee86122 100644 Binary files a/files/assets/images/emojis/marseyflaggermany.webp and b/files/assets/images/emojis/marseyflaggermany.webp differ diff --git a/files/assets/images/emojis/marseyflaggreece.webp b/files/assets/images/emojis/marseyflaggreece.webp index d162b8316..b1eb0da87 100644 Binary files a/files/assets/images/emojis/marseyflaggreece.webp and b/files/assets/images/emojis/marseyflaggreece.webp differ diff --git a/files/assets/images/emojis/marseyflaghungary.webp b/files/assets/images/emojis/marseyflaghungary.webp index b477fe0c4..6adecda69 100644 Binary files a/files/assets/images/emojis/marseyflaghungary.webp and b/files/assets/images/emojis/marseyflaghungary.webp differ diff --git a/files/assets/images/emojis/marseyflagindia.webp b/files/assets/images/emojis/marseyflagindia.webp index 71ecf13c8..a9362c180 100644 Binary files a/files/assets/images/emojis/marseyflagindia.webp and b/files/assets/images/emojis/marseyflagindia.webp differ diff --git a/files/assets/images/emojis/marseyflagindonesia.webp b/files/assets/images/emojis/marseyflagindonesia.webp index a476add6f..116672f4b 100644 Binary files a/files/assets/images/emojis/marseyflagindonesia.webp and b/files/assets/images/emojis/marseyflagindonesia.webp differ diff --git a/files/assets/images/emojis/marseyflagiran.webp b/files/assets/images/emojis/marseyflagiran.webp index a5dc5a517..30e5f9376 100644 Binary files a/files/assets/images/emojis/marseyflagiran.webp and b/files/assets/images/emojis/marseyflagiran.webp differ diff --git a/files/assets/images/emojis/marseyflagiraq.webp b/files/assets/images/emojis/marseyflagiraq.webp index c483801ef..23c2cc20f 100644 Binary files a/files/assets/images/emojis/marseyflagiraq.webp and b/files/assets/images/emojis/marseyflagiraq.webp differ diff --git a/files/assets/images/emojis/marseyflagireland.webp b/files/assets/images/emojis/marseyflagireland.webp index 2146cf22d..2da769c90 100644 Binary files a/files/assets/images/emojis/marseyflagireland.webp and b/files/assets/images/emojis/marseyflagireland.webp differ diff --git a/files/assets/images/emojis/marseyflagitaly.webp b/files/assets/images/emojis/marseyflagitaly.webp index ebbee3490..6f422012c 100644 Binary files a/files/assets/images/emojis/marseyflagitaly.webp and b/files/assets/images/emojis/marseyflagitaly.webp differ diff --git a/files/assets/images/emojis/marseyflagjapan.webp b/files/assets/images/emojis/marseyflagjapan.webp index cde685472..db682ab8c 100644 Binary files a/files/assets/images/emojis/marseyflagjapan.webp and b/files/assets/images/emojis/marseyflagjapan.webp differ diff --git a/files/assets/images/emojis/marseyflagjordan.webp b/files/assets/images/emojis/marseyflagjordan.webp index cba2a8ac6..619997563 100644 Binary files a/files/assets/images/emojis/marseyflagjordan.webp and b/files/assets/images/emojis/marseyflagjordan.webp differ diff --git a/files/assets/images/emojis/marseyflagkazakhstan.webp b/files/assets/images/emojis/marseyflagkazakhstan.webp index d6f3956da..fcfaaae39 100644 Binary files a/files/assets/images/emojis/marseyflagkazakhstan.webp and b/files/assets/images/emojis/marseyflagkazakhstan.webp differ diff --git a/files/assets/images/emojis/marseyflagkenya.webp b/files/assets/images/emojis/marseyflagkenya.webp index 80457fcf9..6b26b6532 100644 Binary files a/files/assets/images/emojis/marseyflagkenya.webp and b/files/assets/images/emojis/marseyflagkenya.webp differ diff --git a/files/assets/images/emojis/marseyflaglebanon.webp b/files/assets/images/emojis/marseyflaglebanon.webp index 4fd8c8cbf..dc1a3b31e 100644 Binary files a/files/assets/images/emojis/marseyflaglebanon.webp and b/files/assets/images/emojis/marseyflaglebanon.webp differ diff --git a/files/assets/images/emojis/marseyflagmaryland.webp b/files/assets/images/emojis/marseyflagmaryland.webp index cff347b3d..2371f57f5 100644 Binary files a/files/assets/images/emojis/marseyflagmaryland.webp and b/files/assets/images/emojis/marseyflagmaryland.webp differ diff --git a/files/assets/images/emojis/marseyflagmexico.webp b/files/assets/images/emojis/marseyflagmexico.webp index fce998968..9fc141e68 100644 Binary files a/files/assets/images/emojis/marseyflagmexico.webp and b/files/assets/images/emojis/marseyflagmexico.webp differ diff --git a/files/assets/images/emojis/marseyflagnetherlands.webp b/files/assets/images/emojis/marseyflagnetherlands.webp index 3f3a7ccc4..bc2f2a93e 100644 Binary files a/files/assets/images/emojis/marseyflagnetherlands.webp and b/files/assets/images/emojis/marseyflagnetherlands.webp differ diff --git a/files/assets/images/emojis/marseyflagnewzealand.webp b/files/assets/images/emojis/marseyflagnewzealand.webp index c963dfcaa..855a70de9 100644 Binary files a/files/assets/images/emojis/marseyflagnewzealand.webp and b/files/assets/images/emojis/marseyflagnewzealand.webp differ diff --git a/files/assets/images/emojis/marseyflagniger.webp b/files/assets/images/emojis/marseyflagniger.webp index be3995e2e..2573fd8c4 100644 Binary files a/files/assets/images/emojis/marseyflagniger.webp and b/files/assets/images/emojis/marseyflagniger.webp differ diff --git a/files/assets/images/emojis/marseyflagnigeria.webp b/files/assets/images/emojis/marseyflagnigeria.webp index f51bfab9d..327422690 100644 Binary files a/files/assets/images/emojis/marseyflagnigeria.webp and b/files/assets/images/emojis/marseyflagnigeria.webp differ diff --git a/files/assets/images/emojis/marseyflagnorthkorea.webp b/files/assets/images/emojis/marseyflagnorthkorea.webp index d3f9de24a..84456b165 100644 Binary files a/files/assets/images/emojis/marseyflagnorthkorea.webp and b/files/assets/images/emojis/marseyflagnorthkorea.webp differ diff --git a/files/assets/images/emojis/marseyflagnorway.webp b/files/assets/images/emojis/marseyflagnorway.webp index 245c3191e..1df49e835 100644 Binary files a/files/assets/images/emojis/marseyflagnorway.webp and b/files/assets/images/emojis/marseyflagnorway.webp differ diff --git a/files/assets/images/emojis/marseyflagpakistan.webp b/files/assets/images/emojis/marseyflagpakistan.webp index ba0266005..77a8d8f6f 100644 Binary files a/files/assets/images/emojis/marseyflagpakistan.webp and b/files/assets/images/emojis/marseyflagpakistan.webp differ diff --git a/files/assets/images/emojis/marseyflagpalau.webp b/files/assets/images/emojis/marseyflagpalau.webp new file mode 100644 index 000000000..5127211b9 Binary files /dev/null and b/files/assets/images/emojis/marseyflagpalau.webp differ diff --git a/files/assets/images/emojis/marseyflagpalestine.webp b/files/assets/images/emojis/marseyflagpalestine.webp index 87246c274..8f93c7755 100644 Binary files a/files/assets/images/emojis/marseyflagpalestine.webp and b/files/assets/images/emojis/marseyflagpalestine.webp differ diff --git a/files/assets/images/emojis/marseyflagperu.webp b/files/assets/images/emojis/marseyflagperu.webp index 833105167..2c146fc1c 100644 Binary files a/files/assets/images/emojis/marseyflagperu.webp and b/files/assets/images/emojis/marseyflagperu.webp differ diff --git a/files/assets/images/emojis/marseyflagphillipines.webp b/files/assets/images/emojis/marseyflagphillipines.webp index 432d769f7..868595c49 100644 Binary files a/files/assets/images/emojis/marseyflagphillipines.webp and b/files/assets/images/emojis/marseyflagphillipines.webp differ diff --git a/files/assets/images/emojis/marseyflagpoland.webp b/files/assets/images/emojis/marseyflagpoland.webp index af4add02c..37c522347 100644 Binary files a/files/assets/images/emojis/marseyflagpoland.webp and b/files/assets/images/emojis/marseyflagpoland.webp differ diff --git a/files/assets/images/emojis/marseyflagportugal.webp b/files/assets/images/emojis/marseyflagportugal.webp index d6b4ad01e..e61e7082d 100644 Binary files a/files/assets/images/emojis/marseyflagportugal.webp and b/files/assets/images/emojis/marseyflagportugal.webp differ diff --git a/files/assets/images/emojis/marseyflagqatar.webp b/files/assets/images/emojis/marseyflagqatar.webp index 13eb49a9b..2b951ae51 100644 Binary files a/files/assets/images/emojis/marseyflagqatar.webp and b/files/assets/images/emojis/marseyflagqatar.webp differ diff --git a/files/assets/images/emojis/marseyflagromania.webp b/files/assets/images/emojis/marseyflagromania.webp index 1cd46a076..d5dda67d6 100644 Binary files a/files/assets/images/emojis/marseyflagromania.webp and b/files/assets/images/emojis/marseyflagromania.webp differ diff --git a/files/assets/images/emojis/marseyflagrussia.webp b/files/assets/images/emojis/marseyflagrussia.webp index 9532cec9f..2250931ad 100644 Binary files a/files/assets/images/emojis/marseyflagrussia.webp and b/files/assets/images/emojis/marseyflagrussia.webp differ diff --git a/files/assets/images/emojis/marseyflagsaudiarabia.webp b/files/assets/images/emojis/marseyflagsaudiarabia.webp index 4708a5f2f..175e81240 100644 Binary files a/files/assets/images/emojis/marseyflagsaudiarabia.webp and b/files/assets/images/emojis/marseyflagsaudiarabia.webp differ diff --git a/files/assets/images/emojis/marseyflagserbia.webp b/files/assets/images/emojis/marseyflagserbia.webp index 29086ac7e..2190e3996 100644 Binary files a/files/assets/images/emojis/marseyflagserbia.webp and b/files/assets/images/emojis/marseyflagserbia.webp differ diff --git a/files/assets/images/emojis/marseyflagsouthafrica.webp b/files/assets/images/emojis/marseyflagsouthafrica.webp index 423eacf53..b386e4097 100644 Binary files a/files/assets/images/emojis/marseyflagsouthafrica.webp and b/files/assets/images/emojis/marseyflagsouthafrica.webp differ diff --git a/files/assets/images/emojis/marseyflagsouthkorea.webp b/files/assets/images/emojis/marseyflagsouthkorea.webp index 785133c70..c944bc4d5 100644 Binary files a/files/assets/images/emojis/marseyflagsouthkorea.webp and b/files/assets/images/emojis/marseyflagsouthkorea.webp differ diff --git a/files/assets/images/emojis/marseyflagspain.webp b/files/assets/images/emojis/marseyflagspain.webp index c702e0dcc..0c936ef14 100644 Binary files a/files/assets/images/emojis/marseyflagspain.webp and b/files/assets/images/emojis/marseyflagspain.webp differ diff --git a/files/assets/images/emojis/marseyflagsweden.webp b/files/assets/images/emojis/marseyflagsweden.webp index 80aa934b0..aace4a8d4 100644 Binary files a/files/assets/images/emojis/marseyflagsweden.webp and b/files/assets/images/emojis/marseyflagsweden.webp differ diff --git a/files/assets/images/emojis/marseyflagswitzerland.webp b/files/assets/images/emojis/marseyflagswitzerland.webp index f63321e69..160269b1c 100644 Binary files a/files/assets/images/emojis/marseyflagswitzerland.webp and b/files/assets/images/emojis/marseyflagswitzerland.webp differ diff --git a/files/assets/images/emojis/marseyflagsyria.webp b/files/assets/images/emojis/marseyflagsyria.webp index 8c4d4b513..2bf2031de 100644 Binary files a/files/assets/images/emojis/marseyflagsyria.webp and b/files/assets/images/emojis/marseyflagsyria.webp differ diff --git a/files/assets/images/emojis/marseyflagtaiwan.webp b/files/assets/images/emojis/marseyflagtaiwan.webp index 89875f7a8..2c0802958 100644 Binary files a/files/assets/images/emojis/marseyflagtaiwan.webp and b/files/assets/images/emojis/marseyflagtaiwan.webp differ diff --git a/files/assets/images/emojis/marseyflagtajikistan.webp b/files/assets/images/emojis/marseyflagtajikistan.webp index 27e166f5c..28c5c6124 100644 Binary files a/files/assets/images/emojis/marseyflagtajikistan.webp and b/files/assets/images/emojis/marseyflagtajikistan.webp differ diff --git a/files/assets/images/emojis/marseyflagtexas.webp b/files/assets/images/emojis/marseyflagtexas.webp index 1b1066531..b2d290469 100644 Binary files a/files/assets/images/emojis/marseyflagtexas.webp and b/files/assets/images/emojis/marseyflagtexas.webp differ diff --git a/files/assets/images/emojis/marseyflagthailand.webp b/files/assets/images/emojis/marseyflagthailand.webp index 0e8711890..1e32ad542 100644 Binary files a/files/assets/images/emojis/marseyflagthailand.webp and b/files/assets/images/emojis/marseyflagthailand.webp differ diff --git a/files/assets/images/emojis/marseyflagturkey.webp b/files/assets/images/emojis/marseyflagturkey.webp index 15727984b..16fcabf92 100644 Binary files a/files/assets/images/emojis/marseyflagturkey.webp and b/files/assets/images/emojis/marseyflagturkey.webp differ diff --git a/files/assets/images/emojis/marseyflagtuvalu.webp b/files/assets/images/emojis/marseyflagtuvalu.webp index 6717f7328..e6e682971 100644 Binary files a/files/assets/images/emojis/marseyflagtuvalu.webp and b/files/assets/images/emojis/marseyflagtuvalu.webp differ diff --git a/files/assets/images/emojis/marseyflaguae.webp b/files/assets/images/emojis/marseyflaguae.webp index 1c1d7574d..d7abe3063 100644 Binary files a/files/assets/images/emojis/marseyflaguae.webp and b/files/assets/images/emojis/marseyflaguae.webp differ diff --git a/files/assets/images/emojis/marseyflaguk.webp b/files/assets/images/emojis/marseyflaguk.webp index e7be8ac68..3bd69f8c6 100644 Binary files a/files/assets/images/emojis/marseyflaguk.webp and b/files/assets/images/emojis/marseyflaguk.webp differ diff --git a/files/assets/images/emojis/marseyflagukraine.webp b/files/assets/images/emojis/marseyflagukraine.webp index 2ee2d734b..8c5a8e609 100644 Binary files a/files/assets/images/emojis/marseyflagukraine.webp and b/files/assets/images/emojis/marseyflagukraine.webp differ diff --git a/files/assets/images/emojis/marseyflagus.webp b/files/assets/images/emojis/marseyflagus.webp index b755b59cf..8771fc874 100644 Binary files a/files/assets/images/emojis/marseyflagus.webp and b/files/assets/images/emojis/marseyflagus.webp differ diff --git a/files/assets/images/emojis/marseyflagvatican.webp b/files/assets/images/emojis/marseyflagvatican.webp index e7db47b4a..6b0f02588 100644 Binary files a/files/assets/images/emojis/marseyflagvatican.webp and b/files/assets/images/emojis/marseyflagvatican.webp differ diff --git a/files/assets/images/emojis/marseyflagvietnam.webp b/files/assets/images/emojis/marseyflagvietnam.webp index 72ff03720..3bf24ef2b 100644 Binary files a/files/assets/images/emojis/marseyflagvietnam.webp and b/files/assets/images/emojis/marseyflagvietnam.webp differ diff --git a/files/assets/images/emojis/marseyflakes.webp b/files/assets/images/emojis/marseyflakes.webp index a1484d34e..09c8b89df 100644 Binary files a/files/assets/images/emojis/marseyflakes.webp and b/files/assets/images/emojis/marseyflakes.webp differ diff --git a/files/assets/images/emojis/marseyflamethrower.webp b/files/assets/images/emojis/marseyflamethrower.webp index 1b51892c2..8d21cfebe 100644 Binary files a/files/assets/images/emojis/marseyflamethrower.webp and b/files/assets/images/emojis/marseyflamethrower.webp differ diff --git a/files/assets/images/emojis/marseyflamewar.webp b/files/assets/images/emojis/marseyflamewar.webp index f5e88dd4f..c56e43e41 100644 Binary files a/files/assets/images/emojis/marseyflamewar.webp and b/files/assets/images/emojis/marseyflamewar.webp differ diff --git a/files/assets/images/emojis/marseyflareon.webp b/files/assets/images/emojis/marseyflareon.webp index b5fa6f416..7da04cc84 100644 Binary files a/files/assets/images/emojis/marseyflareon.webp and b/files/assets/images/emojis/marseyflareon.webp differ diff --git a/files/assets/images/emojis/marseyfloyd.webp b/files/assets/images/emojis/marseyfloyd.webp index 5df05ea7b..3ac6c72b7 100644 Binary files a/files/assets/images/emojis/marseyfloyd.webp and b/files/assets/images/emojis/marseyfloyd.webp differ diff --git a/files/assets/images/emojis/marseyfluffy.webp b/files/assets/images/emojis/marseyfluffy.webp index 04650fa94..eeef5532f 100644 Binary files a/files/assets/images/emojis/marseyfluffy.webp and b/files/assets/images/emojis/marseyfluffy.webp differ diff --git a/files/assets/images/emojis/marseyflushzoom.webp b/files/assets/images/emojis/marseyflushzoom.webp index 02f50ea41..926d1166b 100644 Binary files a/files/assets/images/emojis/marseyflushzoom.webp and b/files/assets/images/emojis/marseyflushzoom.webp differ diff --git a/files/assets/images/emojis/marseyflyingspaghettimonster.webp b/files/assets/images/emojis/marseyflyingspaghettimonster.webp index 184e1a560..a0f8a819f 100644 Binary files a/files/assets/images/emojis/marseyflyingspaghettimonster.webp and b/files/assets/images/emojis/marseyflyingspaghettimonster.webp differ diff --git a/files/assets/images/emojis/marseyfocault.webp b/files/assets/images/emojis/marseyfocault.webp index c7696c173..26ead5939 100644 Binary files a/files/assets/images/emojis/marseyfocault.webp and b/files/assets/images/emojis/marseyfocault.webp differ diff --git a/files/assets/images/emojis/marseyfoidretard.webp b/files/assets/images/emojis/marseyfoidretard.webp index 837ca097c..18e686a54 100644 Binary files a/files/assets/images/emojis/marseyfoidretard.webp and b/files/assets/images/emojis/marseyfoidretard.webp differ diff --git a/files/assets/images/emojis/marseyforevertiedup.webp b/files/assets/images/emojis/marseyforevertiedup.webp index 7ebe3c425..d1a7bcde4 100644 Binary files a/files/assets/images/emojis/marseyforevertiedup.webp and b/files/assets/images/emojis/marseyforevertiedup.webp differ diff --git a/files/assets/images/emojis/marseyfortuneteller.webp b/files/assets/images/emojis/marseyfortuneteller.webp index 6f7f22308..1ea94c4df 100644 Binary files a/files/assets/images/emojis/marseyfortuneteller.webp and b/files/assets/images/emojis/marseyfortuneteller.webp differ diff --git a/files/assets/images/emojis/marseyfoucault.webp b/files/assets/images/emojis/marseyfoucault.webp index 65ca03839..2710749b9 100644 Binary files a/files/assets/images/emojis/marseyfoucault.webp and b/files/assets/images/emojis/marseyfoucault.webp differ diff --git a/files/assets/images/emojis/marseyfranklin.webp b/files/assets/images/emojis/marseyfranklin.webp index cf0b1675e..2381a7d0e 100644 Binary files a/files/assets/images/emojis/marseyfranklin.webp and b/files/assets/images/emojis/marseyfranklin.webp differ diff --git a/files/assets/images/emojis/marseyfrenchvan.webp b/files/assets/images/emojis/marseyfrenchvan.webp index 0afac65f5..3eb72ee61 100644 Binary files a/files/assets/images/emojis/marseyfrenchvan.webp and b/files/assets/images/emojis/marseyfrenchvan.webp differ diff --git a/files/assets/images/emojis/marseyfreud.webp b/files/assets/images/emojis/marseyfreud.webp index e2ae7df60..c2b29c442 100644 Binary files a/files/assets/images/emojis/marseyfreud.webp and b/files/assets/images/emojis/marseyfreud.webp differ diff --git a/files/assets/images/emojis/marseyfrog.webp b/files/assets/images/emojis/marseyfrog.webp index 42e4e9d6a..9a4c41877 100644 Binary files a/files/assets/images/emojis/marseyfrog.webp and b/files/assets/images/emojis/marseyfrog.webp differ diff --git a/files/assets/images/emojis/marseyfrog2.webp b/files/assets/images/emojis/marseyfrog2.webp index 2fb8b52ed..44c2a4316 100644 Binary files a/files/assets/images/emojis/marseyfrog2.webp and b/files/assets/images/emojis/marseyfrog2.webp differ diff --git a/files/assets/images/emojis/marseyfrontiersman.webp b/files/assets/images/emojis/marseyfrontiersman.webp index 55a8daf11..0c6e76d5e 100644 Binary files a/files/assets/images/emojis/marseyfrontiersman.webp and b/files/assets/images/emojis/marseyfrontiersman.webp differ diff --git a/files/assets/images/emojis/marseyfrozen.webp b/files/assets/images/emojis/marseyfrozen.webp index 3ab828ba4..6f1061b41 100644 Binary files a/files/assets/images/emojis/marseyfrozen.webp and b/files/assets/images/emojis/marseyfrozen.webp differ diff --git a/files/assets/images/emojis/marseyfrozenchosen.webp b/files/assets/images/emojis/marseyfrozenchosen.webp index 6f0cc117a..935d90b2f 100644 Binary files a/files/assets/images/emojis/marseyfrozenchosen.webp and b/files/assets/images/emojis/marseyfrozenchosen.webp differ diff --git a/files/assets/images/emojis/marseyfrozenlove.webp b/files/assets/images/emojis/marseyfrozenlove.webp index e6aa873f8..a6ba0a7f7 100644 Binary files a/files/assets/images/emojis/marseyfrozenlove.webp and b/files/assets/images/emojis/marseyfrozenlove.webp differ diff --git a/files/assets/images/emojis/marseyfry.webp b/files/assets/images/emojis/marseyfry.webp index 33214b8d6..e99ae2771 100644 Binary files a/files/assets/images/emojis/marseyfry.webp and b/files/assets/images/emojis/marseyfry.webp differ diff --git a/files/assets/images/emojis/marseyfrylock.webp b/files/assets/images/emojis/marseyfrylock.webp index ccdd51751..2a8819578 100644 Binary files a/files/assets/images/emojis/marseyfrylock.webp and b/files/assets/images/emojis/marseyfrylock.webp differ diff --git a/files/assets/images/emojis/marseyfuckyou.webp b/files/assets/images/emojis/marseyfuckyou.webp index 9dd6bc2eb..ef39f4389 100644 Binary files a/files/assets/images/emojis/marseyfuckyou.webp and b/files/assets/images/emojis/marseyfuckyou.webp differ diff --git a/files/assets/images/emojis/marseyfuckyou2.webp b/files/assets/images/emojis/marseyfuckyou2.webp index 11bbbaa3b..01ea112c1 100644 Binary files a/files/assets/images/emojis/marseyfuckyou2.webp and b/files/assets/images/emojis/marseyfuckyou2.webp differ diff --git a/files/assets/images/emojis/marseyfug.webp b/files/assets/images/emojis/marseyfug.webp index aaa76d628..41f8120bf 100644 Binary files a/files/assets/images/emojis/marseyfug.webp and b/files/assets/images/emojis/marseyfug.webp differ diff --git a/files/assets/images/emojis/marseyfugg.webp b/files/assets/images/emojis/marseyfugg.webp index b52bec7f5..a9b41a1db 100644 Binary files a/files/assets/images/emojis/marseyfugg.webp and b/files/assets/images/emojis/marseyfugg.webp differ diff --git a/files/assets/images/emojis/marseyfugg2.webp b/files/assets/images/emojis/marseyfugg2.webp index 44d969741..1da834f7d 100644 Binary files a/files/assets/images/emojis/marseyfugg2.webp and b/files/assets/images/emojis/marseyfugg2.webp differ diff --git a/files/assets/images/emojis/marseyfunko.webp b/files/assets/images/emojis/marseyfunko.webp index e8ea33bfe..8024cd362 100644 Binary files a/files/assets/images/emojis/marseyfunko.webp and b/files/assets/images/emojis/marseyfunko.webp differ diff --git a/files/assets/images/emojis/marseyfuntriptime.webp b/files/assets/images/emojis/marseyfuntriptime.webp index 248624706..2b5431345 100644 Binary files a/files/assets/images/emojis/marseyfuntriptime.webp and b/files/assets/images/emojis/marseyfuntriptime.webp differ diff --git a/files/assets/images/emojis/marseyfuriosa.webp b/files/assets/images/emojis/marseyfuriosa.webp index 23bf0541e..c31fc2bc6 100644 Binary files a/files/assets/images/emojis/marseyfuriosa.webp and b/files/assets/images/emojis/marseyfuriosa.webp differ diff --git a/files/assets/images/emojis/marseyfurk.webp b/files/assets/images/emojis/marseyfurk.webp index ad8733f1a..908d43680 100644 Binary files a/files/assets/images/emojis/marseyfurk.webp and b/files/assets/images/emojis/marseyfurk.webp differ diff --git a/files/assets/images/emojis/marseyfurry.webp b/files/assets/images/emojis/marseyfurry.webp index 946e68364..8d8c2da10 100644 Binary files a/files/assets/images/emojis/marseyfurry.webp and b/files/assets/images/emojis/marseyfurry.webp differ diff --git a/files/assets/images/emojis/marseyfurry2.webp b/files/assets/images/emojis/marseyfurry2.webp index 1f77f0a0e..b62331b9c 100644 Binary files a/files/assets/images/emojis/marseyfurry2.webp and b/files/assets/images/emojis/marseyfurry2.webp differ diff --git a/files/assets/images/emojis/marseyfursona.webp b/files/assets/images/emojis/marseyfursona.webp index 5f6df0cb9..9289a8a7b 100644 Binary files a/files/assets/images/emojis/marseyfursona.webp and b/files/assets/images/emojis/marseyfursona.webp differ diff --git a/files/assets/images/emojis/marseyfursona2.webp b/files/assets/images/emojis/marseyfursona2.webp index 7ca2658c6..e2bc4f9d9 100644 Binary files a/files/assets/images/emojis/marseyfursona2.webp and b/files/assets/images/emojis/marseyfursona2.webp differ diff --git a/files/assets/images/emojis/marseyfursonatext.webp b/files/assets/images/emojis/marseyfursonatext.webp index e8ea25e05..3ba57b8db 100644 Binary files a/files/assets/images/emojis/marseyfursonatext.webp and b/files/assets/images/emojis/marseyfursonatext.webp differ diff --git a/files/assets/images/emojis/marseyfursuit.webp b/files/assets/images/emojis/marseyfursuit.webp index 5b37d6d89..fb7200528 100644 Binary files a/files/assets/images/emojis/marseyfursuit.webp and b/files/assets/images/emojis/marseyfursuit.webp differ diff --git a/files/assets/images/emojis/marseygagging.webp b/files/assets/images/emojis/marseygagging.webp index 82f6bf67d..fd99bbb70 100644 Binary files a/files/assets/images/emojis/marseygagging.webp and b/files/assets/images/emojis/marseygagging.webp differ diff --git a/files/assets/images/emojis/marseygambling.webp b/files/assets/images/emojis/marseygambling.webp index 08acb8a65..35130f48b 100644 Binary files a/files/assets/images/emojis/marseygambling.webp and b/files/assets/images/emojis/marseygambling.webp differ diff --git a/files/assets/images/emojis/marseygamer.webp b/files/assets/images/emojis/marseygamer.webp index bdc44c0de..25bf96b63 100644 Binary files a/files/assets/images/emojis/marseygamer.webp and b/files/assets/images/emojis/marseygamer.webp differ diff --git a/files/assets/images/emojis/marseygandalf.webp b/files/assets/images/emojis/marseygandalf.webp index ef076ba93..b7f32065a 100644 Binary files a/files/assets/images/emojis/marseygandalf.webp and b/files/assets/images/emojis/marseygandalf.webp differ diff --git a/files/assets/images/emojis/marseygangbang.webp b/files/assets/images/emojis/marseygangbang.webp index 63a0c74ba..ee5a2623f 100644 Binary files a/files/assets/images/emojis/marseygangbang.webp and b/files/assets/images/emojis/marseygangbang.webp differ diff --git a/files/assets/images/emojis/marseygangster.webp b/files/assets/images/emojis/marseygangster.webp index 906d82568..bb49eb339 100644 Binary files a/files/assets/images/emojis/marseygangster.webp and b/files/assets/images/emojis/marseygangster.webp differ diff --git a/files/assets/images/emojis/marseygardener.webp b/files/assets/images/emojis/marseygardener.webp index b79fa20ae..e44ac2259 100644 Binary files a/files/assets/images/emojis/marseygardener.webp and b/files/assets/images/emojis/marseygardener.webp differ diff --git a/files/assets/images/emojis/marseygarfield.webp b/files/assets/images/emojis/marseygarfield.webp index 381769134..f897a75cf 100644 Binary files a/files/assets/images/emojis/marseygarfield.webp and b/files/assets/images/emojis/marseygarfield.webp differ diff --git a/files/assets/images/emojis/marseygarfieldpipe.webp b/files/assets/images/emojis/marseygarfieldpipe.webp index 15307e7aa..23f6ea9f5 100644 Binary files a/files/assets/images/emojis/marseygarfieldpipe.webp and b/files/assets/images/emojis/marseygarfieldpipe.webp differ diff --git a/files/assets/images/emojis/marseygasp.webp b/files/assets/images/emojis/marseygasp.webp index af9a55c6b..5b1274948 100644 Binary files a/files/assets/images/emojis/marseygasp.webp and b/files/assets/images/emojis/marseygasp.webp differ diff --git a/files/assets/images/emojis/marseygeisha.webp b/files/assets/images/emojis/marseygeisha.webp index 415f932c0..111a24d9a 100644 Binary files a/files/assets/images/emojis/marseygeisha.webp and b/files/assets/images/emojis/marseygeisha.webp differ diff --git a/files/assets/images/emojis/marseygenetakovic.webp b/files/assets/images/emojis/marseygenetakovic.webp index 9c80c39af..11274273e 100644 Binary files a/files/assets/images/emojis/marseygenetakovic.webp and b/files/assets/images/emojis/marseygenetakovic.webp differ diff --git a/files/assets/images/emojis/marseygeorge.webp b/files/assets/images/emojis/marseygeorge.webp index 90ae5c4e4..166cf9d58 100644 Binary files a/files/assets/images/emojis/marseygeorge.webp and b/files/assets/images/emojis/marseygeorge.webp differ diff --git a/files/assets/images/emojis/marseyghost.webp b/files/assets/images/emojis/marseyghost.webp index b8a3dc0d2..9d13da56a 100644 Binary files a/files/assets/images/emojis/marseyghost.webp and b/files/assets/images/emojis/marseyghost.webp differ diff --git a/files/assets/images/emojis/marseyghostface.webp b/files/assets/images/emojis/marseyghostface.webp new file mode 100644 index 000000000..7a9f0ad33 Binary files /dev/null and b/files/assets/images/emojis/marseyghostface.webp differ diff --git a/files/assets/images/emojis/marseyghostface2.webp b/files/assets/images/emojis/marseyghostface2.webp new file mode 100644 index 000000000..b4b270799 Binary files /dev/null and b/files/assets/images/emojis/marseyghostface2.webp differ diff --git a/files/assets/images/emojis/marseygift.webp b/files/assets/images/emojis/marseygift.webp index 3d6448d7f..c80c6c30c 100644 Binary files a/files/assets/images/emojis/marseygift.webp and b/files/assets/images/emojis/marseygift.webp differ diff --git a/files/assets/images/emojis/marseygigachad.webp b/files/assets/images/emojis/marseygigachad.webp index afb84dd7b..f638243f0 100644 Binary files a/files/assets/images/emojis/marseygigachad.webp and b/files/assets/images/emojis/marseygigachad.webp differ diff --git a/files/assets/images/emojis/marseygigaretard.webp b/files/assets/images/emojis/marseygigaretard.webp index 9403ea3e0..ce7a0d81a 100644 Binary files a/files/assets/images/emojis/marseygigaretard.webp and b/files/assets/images/emojis/marseygigaretard.webp differ diff --git a/files/assets/images/emojis/marseygigatitty.webp b/files/assets/images/emojis/marseygigatitty.webp index b56cb284a..fb51ad990 100644 Binary files a/files/assets/images/emojis/marseygigatitty.webp and b/files/assets/images/emojis/marseygigatitty.webp differ diff --git a/files/assets/images/emojis/marseygigavaxxer.webp b/files/assets/images/emojis/marseygigavaxxer.webp index b43fcc43b..0687f0b3e 100644 Binary files a/files/assets/images/emojis/marseygigavaxxer.webp and b/files/assets/images/emojis/marseygigavaxxer.webp differ diff --git a/files/assets/images/emojis/marseygilead.webp b/files/assets/images/emojis/marseygilead.webp index 720e92c9b..c0f85ff2b 100644 Binary files a/files/assets/images/emojis/marseygilead.webp and b/files/assets/images/emojis/marseygilead.webp differ diff --git a/files/assets/images/emojis/marseygingerbread.webp b/files/assets/images/emojis/marseygingerbread.webp index 402ec0414..2e1d6513c 100644 Binary files a/files/assets/images/emojis/marseygingerbread.webp and b/files/assets/images/emojis/marseygingerbread.webp differ diff --git a/files/assets/images/emojis/marseygingerbread2.webp b/files/assets/images/emojis/marseygingerbread2.webp index dce5e1b58..78e0ee823 100644 Binary files a/files/assets/images/emojis/marseygingerbread2.webp and b/files/assets/images/emojis/marseygingerbread2.webp differ diff --git a/files/assets/images/emojis/marseygingerbread3.webp b/files/assets/images/emojis/marseygingerbread3.webp index 329abb7ec..fced1996b 100644 Binary files a/files/assets/images/emojis/marseygingerbread3.webp and b/files/assets/images/emojis/marseygingerbread3.webp differ diff --git a/files/assets/images/emojis/marseygirl.webp b/files/assets/images/emojis/marseygirl.webp index 77c099623..35e092b2d 100644 Binary files a/files/assets/images/emojis/marseygirl.webp and b/files/assets/images/emojis/marseygirl.webp differ diff --git a/files/assets/images/emojis/marseygivecrown.webp b/files/assets/images/emojis/marseygivecrown.webp index fe8c0f567..05acd1354 100644 Binary files a/files/assets/images/emojis/marseygivecrown.webp and b/files/assets/images/emojis/marseygivecrown.webp differ diff --git a/files/assets/images/emojis/marseyglaceon.webp b/files/assets/images/emojis/marseyglaceon.webp index 6824adc2e..b5d78d0f6 100644 Binary files a/files/assets/images/emojis/marseyglaceon.webp and b/files/assets/images/emojis/marseyglaceon.webp differ diff --git a/files/assets/images/emojis/marseygladiator.webp b/files/assets/images/emojis/marseygladiator.webp index 6d6ebc062..169ba1432 100644 Binary files a/files/assets/images/emojis/marseygladiator.webp and b/files/assets/images/emojis/marseygladiator.webp differ diff --git a/files/assets/images/emojis/marseyglam.webp b/files/assets/images/emojis/marseyglam.webp index 1e6462422..f39610fdf 100644 Binary files a/files/assets/images/emojis/marseyglam.webp and b/files/assets/images/emojis/marseyglam.webp differ diff --git a/files/assets/images/emojis/marseyglobohomo.webp b/files/assets/images/emojis/marseyglobohomo.webp index 59210c1bd..d49db09de 100644 Binary files a/files/assets/images/emojis/marseyglobohomo.webp and b/files/assets/images/emojis/marseyglobohomo.webp differ diff --git a/files/assets/images/emojis/marseyglow2.webp b/files/assets/images/emojis/marseyglow2.webp index 453a123d9..898c9b75e 100644 Binary files a/files/assets/images/emojis/marseyglow2.webp and b/files/assets/images/emojis/marseyglow2.webp differ diff --git a/files/assets/images/emojis/marseygoatse.webp b/files/assets/images/emojis/marseygoatse.webp index c004eedc8..2d5cbfc67 100644 Binary files a/files/assets/images/emojis/marseygoatse.webp and b/files/assets/images/emojis/marseygoatse.webp differ diff --git a/files/assets/images/emojis/marseygodel.webp b/files/assets/images/emojis/marseygodel.webp index 6f1e59a3f..8d8819b92 100644 Binary files a/files/assets/images/emojis/marseygodel.webp and b/files/assets/images/emojis/marseygodel.webp differ diff --git a/files/assets/images/emojis/marseygodfather.webp b/files/assets/images/emojis/marseygodfather.webp index 6369f51f7..32cb07d3a 100644 Binary files a/files/assets/images/emojis/marseygodfather.webp and b/files/assets/images/emojis/marseygodfather.webp differ diff --git a/files/assets/images/emojis/marseygodzilla.webp b/files/assets/images/emojis/marseygodzilla.webp index be073a90f..66e4e5614 100644 Binary files a/files/assets/images/emojis/marseygodzilla.webp and b/files/assets/images/emojis/marseygodzilla.webp differ diff --git a/files/assets/images/emojis/marseygold.webp b/files/assets/images/emojis/marseygold.webp index 8fdfebf72..1f6775e85 100644 Binary files a/files/assets/images/emojis/marseygold.webp and b/files/assets/images/emojis/marseygold.webp differ diff --git a/files/assets/images/emojis/marseygoldenshower.webp b/files/assets/images/emojis/marseygoldenshower.webp index db6549fe6..0d9396d69 100644 Binary files a/files/assets/images/emojis/marseygoldenshower.webp and b/files/assets/images/emojis/marseygoldenshower.webp differ diff --git a/files/assets/images/emojis/marseygondola.webp b/files/assets/images/emojis/marseygondola.webp index 632d81883..f82ceaa66 100644 Binary files a/files/assets/images/emojis/marseygondola.webp and b/files/assets/images/emojis/marseygondola.webp differ diff --git a/files/assets/images/emojis/marseygoodnight.webp b/files/assets/images/emojis/marseygoodnight.webp index 5f66899bc..8263e67eb 100644 Binary files a/files/assets/images/emojis/marseygoodnight.webp and b/files/assets/images/emojis/marseygoodnight.webp differ diff --git a/files/assets/images/emojis/marseygoose.webp b/files/assets/images/emojis/marseygoose.webp index 74dcc2c67..84d6cdc67 100644 Binary files a/files/assets/images/emojis/marseygoose.webp and b/files/assets/images/emojis/marseygoose.webp differ diff --git a/files/assets/images/emojis/marseygoose2.webp b/files/assets/images/emojis/marseygoose2.webp index bbd202847..d35cb5772 100644 Binary files a/files/assets/images/emojis/marseygoose2.webp and b/files/assets/images/emojis/marseygoose2.webp differ diff --git a/files/assets/images/emojis/marseygossip.webp b/files/assets/images/emojis/marseygossip.webp index bc6d17915..6d99c3794 100644 Binary files a/files/assets/images/emojis/marseygossip.webp and b/files/assets/images/emojis/marseygossip.webp differ diff --git a/files/assets/images/emojis/marseygrapes.webp b/files/assets/images/emojis/marseygrapes.webp index 74788ae8e..c012f1398 100644 Binary files a/files/assets/images/emojis/marseygrapes.webp and b/files/assets/images/emojis/marseygrapes.webp differ diff --git a/files/assets/images/emojis/marseygras.webp b/files/assets/images/emojis/marseygras.webp index 4a0059b26..4bd09db4d 100644 Binary files a/files/assets/images/emojis/marseygras.webp and b/files/assets/images/emojis/marseygras.webp differ diff --git a/files/assets/images/emojis/marseygrass.webp b/files/assets/images/emojis/marseygrass.webp index f1440814a..00f208970 100644 Binary files a/files/assets/images/emojis/marseygrass.webp and b/files/assets/images/emojis/marseygrass.webp differ diff --git a/files/assets/images/emojis/marseygreatpumpkin.webp b/files/assets/images/emojis/marseygreatpumpkin.webp new file mode 100644 index 000000000..a0e087864 Binary files /dev/null and b/files/assets/images/emojis/marseygreatpumpkin.webp differ diff --git a/files/assets/images/emojis/marseygrilling.webp b/files/assets/images/emojis/marseygrilling.webp index 2080fe1fd..d9373cd47 100644 Binary files a/files/assets/images/emojis/marseygrilling.webp and b/files/assets/images/emojis/marseygrilling.webp differ diff --git a/files/assets/images/emojis/marseygrilling2.webp b/files/assets/images/emojis/marseygrilling2.webp index ff9b091ee..63c8a2da6 100644 Binary files a/files/assets/images/emojis/marseygrilling2.webp and b/files/assets/images/emojis/marseygrilling2.webp differ diff --git a/files/assets/images/emojis/marseygrin.webp b/files/assets/images/emojis/marseygrin.webp index 7b40e2167..6113e9c6b 100644 Binary files a/files/assets/images/emojis/marseygrin.webp and b/files/assets/images/emojis/marseygrin.webp differ diff --git a/files/assets/images/emojis/marseygroomer.webp b/files/assets/images/emojis/marseygroomer.webp index e1246c37b..a02b68fe8 100644 Binary files a/files/assets/images/emojis/marseygroomer.webp and b/files/assets/images/emojis/marseygroomer.webp differ diff --git a/files/assets/images/emojis/marseygroomer2.webp b/files/assets/images/emojis/marseygroomer2.webp index d07f3f4c7..a4c1f11ac 100644 Binary files a/files/assets/images/emojis/marseygroomer2.webp and b/files/assets/images/emojis/marseygroomer2.webp differ diff --git a/files/assets/images/emojis/marseygrouns.webp b/files/assets/images/emojis/marseygrouns.webp new file mode 100644 index 000000000..f3022ba48 Binary files /dev/null and b/files/assets/images/emojis/marseygrouns.webp differ diff --git a/files/assets/images/emojis/marseygucci.webp b/files/assets/images/emojis/marseygucci.webp index 6ca19cc65..b52aa1cb9 100644 Binary files a/files/assets/images/emojis/marseygucci.webp and b/files/assets/images/emojis/marseygucci.webp differ diff --git a/files/assets/images/emojis/marseyguillotine.webp b/files/assets/images/emojis/marseyguillotine.webp index 169b53c68..9f9a84fe4 100644 Binary files a/files/assets/images/emojis/marseyguillotine.webp and b/files/assets/images/emojis/marseyguillotine.webp differ diff --git a/files/assets/images/emojis/marseygun.webp b/files/assets/images/emojis/marseygun.webp index 0bfe050dc..73519b8e5 100644 Binary files a/files/assets/images/emojis/marseygun.webp and b/files/assets/images/emojis/marseygun.webp differ diff --git a/files/assets/images/emojis/marseygundam.webp b/files/assets/images/emojis/marseygundam.webp index 35cd4c30d..f645abe1a 100644 Binary files a/files/assets/images/emojis/marseygundam.webp and b/files/assets/images/emojis/marseygundam.webp differ diff --git a/files/assets/images/emojis/marseygunned.webp b/files/assets/images/emojis/marseygunned.webp index b8fea4e43..667d39ba9 100644 Binary files a/files/assets/images/emojis/marseygunned.webp and b/files/assets/images/emojis/marseygunned.webp differ diff --git a/files/assets/images/emojis/marseygunnut.webp b/files/assets/images/emojis/marseygunnut.webp index 58f03d642..7a973ebf5 100644 Binary files a/files/assets/images/emojis/marseygunnut.webp and b/files/assets/images/emojis/marseygunnut.webp differ diff --git a/files/assets/images/emojis/marseygunshotsuicide.webp b/files/assets/images/emojis/marseygunshotsuicide.webp index 307851a5a..332741bea 100644 Binary files a/files/assets/images/emojis/marseygunshotsuicide.webp and b/files/assets/images/emojis/marseygunshotsuicide.webp differ diff --git a/files/assets/images/emojis/marseyhammerpizza.webp b/files/assets/images/emojis/marseyhammerpizza.webp index 46a94f8f9..4a8ef23c9 100644 Binary files a/files/assets/images/emojis/marseyhammerpizza.webp and b/files/assets/images/emojis/marseyhammerpizza.webp differ diff --git a/files/assets/images/emojis/marseyhammersnoo.webp b/files/assets/images/emojis/marseyhammersnoo.webp index f4a0e8a2c..fce3f1bc3 100644 Binary files a/files/assets/images/emojis/marseyhammersnoo.webp and b/files/assets/images/emojis/marseyhammersnoo.webp differ diff --git a/files/assets/images/emojis/marseyhammersrdine.webp b/files/assets/images/emojis/marseyhammersrdine.webp index e8f85327a..3e2c67d57 100644 Binary files a/files/assets/images/emojis/marseyhammersrdine.webp and b/files/assets/images/emojis/marseyhammersrdine.webp differ diff --git a/files/assets/images/emojis/marseyhandmaid.webp b/files/assets/images/emojis/marseyhandmaid.webp index bee8c3121..57877cb94 100644 Binary files a/files/assets/images/emojis/marseyhandmaid.webp and b/files/assets/images/emojis/marseyhandmaid.webp differ diff --git a/files/assets/images/emojis/marseyhandsup.webp b/files/assets/images/emojis/marseyhandsup.webp index 240bb3174..55b23f564 100644 Binary files a/files/assets/images/emojis/marseyhandsup.webp and b/files/assets/images/emojis/marseyhandsup.webp differ diff --git a/files/assets/images/emojis/marseyhanger.webp b/files/assets/images/emojis/marseyhanger.webp index dcc4b271e..4b5e0da91 100644 Binary files a/files/assets/images/emojis/marseyhanger.webp and b/files/assets/images/emojis/marseyhanger.webp differ diff --git a/files/assets/images/emojis/marseyhankhill.webp b/files/assets/images/emojis/marseyhankhill.webp index 0e73de48c..e0d646ce4 100644 Binary files a/files/assets/images/emojis/marseyhankhill.webp and b/files/assets/images/emojis/marseyhankhill.webp differ diff --git a/files/assets/images/emojis/marseyhankhill2.webp b/files/assets/images/emojis/marseyhankhill2.webp index 1ed1afdd8..c4d5fc1d8 100644 Binary files a/files/assets/images/emojis/marseyhankhill2.webp and b/files/assets/images/emojis/marseyhankhill2.webp differ diff --git a/files/assets/images/emojis/marseyhannibal.webp b/files/assets/images/emojis/marseyhannibal.webp index 631c8dacb..5e8141943 100644 Binary files a/files/assets/images/emojis/marseyhannibal.webp and b/files/assets/images/emojis/marseyhannibal.webp differ diff --git a/files/assets/images/emojis/marseyhappy.webp b/files/assets/images/emojis/marseyhappy.webp index 540af9025..77741eab0 100644 Binary files a/files/assets/images/emojis/marseyhappy.webp and b/files/assets/images/emojis/marseyhappy.webp differ diff --git a/files/assets/images/emojis/marseyhappytears.webp b/files/assets/images/emojis/marseyhappytears.webp index c58e755ce..5d9c92fc5 100644 Binary files a/files/assets/images/emojis/marseyhappytears.webp and b/files/assets/images/emojis/marseyhappytears.webp differ diff --git a/files/assets/images/emojis/marseyhatecrime.webp b/files/assets/images/emojis/marseyhatecrime.webp index d23f0b45f..f4bc8c98d 100644 Binary files a/files/assets/images/emojis/marseyhatecrime.webp and b/files/assets/images/emojis/marseyhatecrime.webp differ diff --git a/files/assets/images/emojis/marseyhatium.webp b/files/assets/images/emojis/marseyhatium.webp index 5bbd66258..0486d7801 100644 Binary files a/files/assets/images/emojis/marseyhatium.webp and b/files/assets/images/emojis/marseyhatium.webp differ diff --git a/files/assets/images/emojis/marseyhatiun.webp b/files/assets/images/emojis/marseyhatiun.webp index 5bbd66258..0486d7801 100644 Binary files a/files/assets/images/emojis/marseyhatiun.webp and b/files/assets/images/emojis/marseyhatiun.webp differ diff --git a/files/assets/images/emojis/marseyhawaii.webp b/files/assets/images/emojis/marseyhawaii.webp index e4b3306d6..e656fd579 100644 Binary files a/files/assets/images/emojis/marseyhawaii.webp and b/files/assets/images/emojis/marseyhawaii.webp differ diff --git a/files/assets/images/emojis/marseyheadcrab.webp b/files/assets/images/emojis/marseyheadcrab.webp index 1c83104f9..2a64f2732 100644 Binary files a/files/assets/images/emojis/marseyheadcrab.webp and b/files/assets/images/emojis/marseyheadcrab.webp differ diff --git a/files/assets/images/emojis/marseyheadlesshorseman.webp b/files/assets/images/emojis/marseyheadlesshorseman.webp new file mode 100644 index 000000000..b1897344a Binary files /dev/null and b/files/assets/images/emojis/marseyheadlesshorseman.webp differ diff --git a/files/assets/images/emojis/marseyhealthy.webp b/files/assets/images/emojis/marseyhealthy.webp index df2caf5b5..85665c5cb 100644 Binary files a/files/assets/images/emojis/marseyhealthy.webp and b/files/assets/images/emojis/marseyhealthy.webp differ diff --git a/files/assets/images/emojis/marseyhearts.webp b/files/assets/images/emojis/marseyhearts.webp index 2a8212b21..4a72cbd06 100644 Binary files a/files/assets/images/emojis/marseyhearts.webp and b/files/assets/images/emojis/marseyhearts.webp differ diff --git a/files/assets/images/emojis/marseyheathcliff.webp b/files/assets/images/emojis/marseyheathcliff.webp index 94d4da7f8..8d5a8d8c6 100644 Binary files a/files/assets/images/emojis/marseyheathcliff.webp and b/files/assets/images/emojis/marseyheathcliff.webp differ diff --git a/files/assets/images/emojis/marseyhellraiser.webp b/files/assets/images/emojis/marseyhellraiser.webp index 21724501c..da896ff28 100644 Binary files a/files/assets/images/emojis/marseyhellraiser.webp and b/files/assets/images/emojis/marseyhellraiser.webp differ diff --git a/files/assets/images/emojis/marseyhelp.webp b/files/assets/images/emojis/marseyhelp.webp index 217251c61..ea3a1fe87 100644 Binary files a/files/assets/images/emojis/marseyhelp.webp and b/files/assets/images/emojis/marseyhelp.webp differ diff --git a/files/assets/images/emojis/marseyhesklennyyouknow.webp b/files/assets/images/emojis/marseyhesklennyyouknow.webp index 0c739021a..3a15f1a2d 100644 Binary files a/files/assets/images/emojis/marseyhesklennyyouknow.webp and b/files/assets/images/emojis/marseyhesklennyyouknow.webp differ diff --git a/files/assets/images/emojis/marseyhesright.webp b/files/assets/images/emojis/marseyhesright.webp index db3d34c0c..d3c0eca37 100644 Binary files a/files/assets/images/emojis/marseyhesright.webp and b/files/assets/images/emojis/marseyhesright.webp differ diff --git a/files/assets/images/emojis/marseyhibernian.webp b/files/assets/images/emojis/marseyhibernian.webp index 4fbf62bf7..6cc8d0dfe 100644 Binary files a/files/assets/images/emojis/marseyhibernian.webp and b/files/assets/images/emojis/marseyhibernian.webp differ diff --git a/files/assets/images/emojis/marseyhijab.webp b/files/assets/images/emojis/marseyhijab.webp index 27297b6b5..99dc7f8d4 100644 Binary files a/files/assets/images/emojis/marseyhijab.webp and b/files/assets/images/emojis/marseyhijab.webp differ diff --git a/files/assets/images/emojis/marseyhillary.webp b/files/assets/images/emojis/marseyhillary.webp index 5752b8dfe..cabd2449f 100644 Binary files a/files/assets/images/emojis/marseyhillary.webp and b/files/assets/images/emojis/marseyhillary.webp differ diff --git a/files/assets/images/emojis/marseyhillarybackstab.webp b/files/assets/images/emojis/marseyhillarybackstab.webp index c7dc13b9b..ae99a36ec 100644 Binary files a/files/assets/images/emojis/marseyhillarybackstab.webp and b/files/assets/images/emojis/marseyhillarybackstab.webp differ diff --git a/files/assets/images/emojis/marseyhippo.webp b/files/assets/images/emojis/marseyhippo.webp index cb6b9eb5d..a7ca8c3c7 100644 Binary files a/files/assets/images/emojis/marseyhippo.webp and b/files/assets/images/emojis/marseyhippo.webp differ diff --git a/files/assets/images/emojis/marseyhitler.webp b/files/assets/images/emojis/marseyhitler.webp index f8d7669b1..36ad6c838 100644 Binary files a/files/assets/images/emojis/marseyhitler.webp and b/files/assets/images/emojis/marseyhitler.webp differ diff --git a/files/assets/images/emojis/marseyhitler2.webp b/files/assets/images/emojis/marseyhitler2.webp index df6fc6a2b..f107a8c6d 100644 Binary files a/files/assets/images/emojis/marseyhitler2.webp and b/files/assets/images/emojis/marseyhitler2.webp differ diff --git a/files/assets/images/emojis/marseyhmm.webp b/files/assets/images/emojis/marseyhmm.webp index 11fb55b48..c7c065b22 100644 Binary files a/files/assets/images/emojis/marseyhmm.webp and b/files/assets/images/emojis/marseyhmm.webp differ diff --git a/files/assets/images/emojis/marseyhmmm.webp b/files/assets/images/emojis/marseyhmmm.webp index 2d671c367..f51d5f84f 100644 Binary files a/files/assets/images/emojis/marseyhmmm.webp and b/files/assets/images/emojis/marseyhmmm.webp differ diff --git a/files/assets/images/emojis/marseyhomestar.webp b/files/assets/images/emojis/marseyhomestar.webp index 0a06ceb6b..57b6f11d5 100644 Binary files a/files/assets/images/emojis/marseyhomestar.webp and b/files/assets/images/emojis/marseyhomestar.webp differ diff --git a/files/assets/images/emojis/marseyhomochingchong.webp b/files/assets/images/emojis/marseyhomochingchong.webp index 3a7050bae..a3f66a35f 100644 Binary files a/files/assets/images/emojis/marseyhomochingchong.webp and b/files/assets/images/emojis/marseyhomochingchong.webp differ diff --git a/files/assets/images/emojis/marseyhomofascist.webp b/files/assets/images/emojis/marseyhomofascist.webp index 293c3e788..9085703f6 100644 Binary files a/files/assets/images/emojis/marseyhomofascist.webp and b/files/assets/images/emojis/marseyhomofascist.webp differ diff --git a/files/assets/images/emojis/marseyhomosupremacist.webp b/files/assets/images/emojis/marseyhomosupremacist.webp index 70b03c4ef..fba2af883 100644 Binary files a/files/assets/images/emojis/marseyhomosupremacist.webp and b/files/assets/images/emojis/marseyhomosupremacist.webp differ diff --git a/files/assets/images/emojis/marseyhomsar.webp b/files/assets/images/emojis/marseyhomsar.webp index bc92cf52f..209ce1c02 100644 Binary files a/files/assets/images/emojis/marseyhomsar.webp and b/files/assets/images/emojis/marseyhomsar.webp differ diff --git a/files/assets/images/emojis/marseyhoodwink.webp b/files/assets/images/emojis/marseyhoodwink.webp index a7e751f0e..abac13d15 100644 Binary files a/files/assets/images/emojis/marseyhoodwink.webp and b/files/assets/images/emojis/marseyhoodwink.webp differ diff --git a/files/assets/images/emojis/marseyhope.webp b/files/assets/images/emojis/marseyhope.webp index f91d379c3..2fe0e5a0a 100644 Binary files a/files/assets/images/emojis/marseyhope.webp and b/files/assets/images/emojis/marseyhope.webp differ diff --git a/files/assets/images/emojis/marseyhorseshoe.webp b/files/assets/images/emojis/marseyhorseshoe.webp index b5942fb63..77e175bc6 100644 Binary files a/files/assets/images/emojis/marseyhorseshoe.webp and b/files/assets/images/emojis/marseyhorseshoe.webp differ diff --git a/files/assets/images/emojis/marseyhotep.webp b/files/assets/images/emojis/marseyhotep.webp index 4c226682e..06d98e71f 100644 Binary files a/files/assets/images/emojis/marseyhotep.webp and b/files/assets/images/emojis/marseyhotep.webp differ diff --git a/files/assets/images/emojis/marseyhugretard.webp b/files/assets/images/emojis/marseyhugretard.webp index d79bcf6e3..1daca2c95 100644 Binary files a/files/assets/images/emojis/marseyhugretard.webp and b/files/assets/images/emojis/marseyhugretard.webp differ diff --git a/files/assets/images/emojis/marseyicecreamcone.webp b/files/assets/images/emojis/marseyicecreamcone.webp index f6389953e..04dab3252 100644 Binary files a/files/assets/images/emojis/marseyicecreamcone.webp and b/files/assets/images/emojis/marseyicecreamcone.webp differ diff --git a/files/assets/images/emojis/marseyicet.webp b/files/assets/images/emojis/marseyicet.webp new file mode 100644 index 000000000..85b9cc074 Binary files /dev/null and b/files/assets/images/emojis/marseyicet.webp differ diff --git a/files/assets/images/emojis/marseyidio3.webp b/files/assets/images/emojis/marseyidio3.webp index f9fcb39c3..222fce30d 100644 Binary files a/files/assets/images/emojis/marseyidio3.webp and b/files/assets/images/emojis/marseyidio3.webp differ diff --git a/files/assets/images/emojis/marseyidk.webp b/files/assets/images/emojis/marseyidk.webp index 3cf555b21..342a99209 100644 Binary files a/files/assets/images/emojis/marseyidk.webp and b/files/assets/images/emojis/marseyidk.webp differ diff --git a/files/assets/images/emojis/marseyill.webp b/files/assets/images/emojis/marseyill.webp index 7c067169f..7169182a1 100644 Binary files a/files/assets/images/emojis/marseyill.webp and b/files/assets/images/emojis/marseyill.webp differ diff --git a/files/assets/images/emojis/marseyilluminati.webp b/files/assets/images/emojis/marseyilluminati.webp index 882b39732..f2661b4ff 100644 Binary files a/files/assets/images/emojis/marseyilluminati.webp and b/files/assets/images/emojis/marseyilluminati.webp differ diff --git a/files/assets/images/emojis/marseyimam.webp b/files/assets/images/emojis/marseyimam.webp index 7f07b25d8..e2a732998 100644 Binary files a/files/assets/images/emojis/marseyimam.webp and b/files/assets/images/emojis/marseyimam.webp differ diff --git a/files/assets/images/emojis/marseyimmortanjoe.webp b/files/assets/images/emojis/marseyimmortanjoe.webp index 80fef4f37..5e6b4d747 100644 Binary files a/files/assets/images/emojis/marseyimmortanjoe.webp and b/files/assets/images/emojis/marseyimmortanjoe.webp differ diff --git a/files/assets/images/emojis/marseyimpossibru.webp b/files/assets/images/emojis/marseyimpossibru.webp index 9424b31fb..0e7bb0ae7 100644 Binary files a/files/assets/images/emojis/marseyimpossibru.webp and b/files/assets/images/emojis/marseyimpossibru.webp differ diff --git a/files/assets/images/emojis/marseyimposter.webp b/files/assets/images/emojis/marseyimposter.webp index 1179b995b..ed859abd1 100644 Binary files a/files/assets/images/emojis/marseyimposter.webp and b/files/assets/images/emojis/marseyimposter.webp differ diff --git a/files/assets/images/emojis/marseyinabox.webp b/files/assets/images/emojis/marseyinabox.webp index 8ab133cb3..111c84171 100644 Binary files a/files/assets/images/emojis/marseyinabox.webp and b/files/assets/images/emojis/marseyinabox.webp differ diff --git a/files/assets/images/emojis/marseyinajackolantern.webp b/files/assets/images/emojis/marseyinajackolantern.webp new file mode 100644 index 000000000..5cd3ca154 Binary files /dev/null and b/files/assets/images/emojis/marseyinajackolantern.webp differ diff --git a/files/assets/images/emojis/marseyinapumpkin.webp b/files/assets/images/emojis/marseyinapumpkin.webp new file mode 100644 index 000000000..efb792069 Binary files /dev/null and b/files/assets/images/emojis/marseyinapumpkin.webp differ diff --git a/files/assets/images/emojis/marseyinbread.webp b/files/assets/images/emojis/marseyinbread.webp index 4dc585c87..2cb257f2f 100644 Binary files a/files/assets/images/emojis/marseyinbread.webp and b/files/assets/images/emojis/marseyinbread.webp differ diff --git a/files/assets/images/emojis/marseyinnocent.webp b/files/assets/images/emojis/marseyinnocent.webp index 246fb7c53..741ba5722 100644 Binary files a/files/assets/images/emojis/marseyinnocent.webp and b/files/assets/images/emojis/marseyinnocent.webp differ diff --git a/files/assets/images/emojis/marseyinverted.webp b/files/assets/images/emojis/marseyinverted.webp index 1db956549..288d2874e 100644 Binary files a/files/assets/images/emojis/marseyinverted.webp and b/files/assets/images/emojis/marseyinverted.webp differ diff --git a/files/assets/images/emojis/marseyinvestigate.webp b/files/assets/images/emojis/marseyinvestigate.webp index abc83fb60..4b69b9851 100644 Binary files a/files/assets/images/emojis/marseyinvestigate.webp and b/files/assets/images/emojis/marseyinvestigate.webp differ diff --git a/files/assets/images/emojis/marseyira.webp b/files/assets/images/emojis/marseyira.webp index 35f1aab32..e33100cca 100644 Binary files a/files/assets/images/emojis/marseyira.webp and b/files/assets/images/emojis/marseyira.webp differ diff --git a/files/assets/images/emojis/marseyishygddt.webp b/files/assets/images/emojis/marseyishygddt.webp index 79a071a7f..43765f8c4 100644 Binary files a/files/assets/images/emojis/marseyishygddt.webp and b/files/assets/images/emojis/marseyishygddt.webp differ diff --git a/files/assets/images/emojis/marseyisis.webp b/files/assets/images/emojis/marseyisis.webp index 5975c96fd..e4b2c57dd 100644 Binary files a/files/assets/images/emojis/marseyisis.webp and b/files/assets/images/emojis/marseyisis.webp differ diff --git a/files/assets/images/emojis/marseyisrael.webp b/files/assets/images/emojis/marseyisrael.webp index 759c43f0e..8d156a6a7 100644 Binary files a/files/assets/images/emojis/marseyisrael.webp and b/files/assets/images/emojis/marseyisrael.webp differ diff --git a/files/assets/images/emojis/marseyisraellove.webp b/files/assets/images/emojis/marseyisraellove.webp index 608f382b7..f2312bc7c 100644 Binary files a/files/assets/images/emojis/marseyisraellove.webp and b/files/assets/images/emojis/marseyisraellove.webp differ diff --git a/files/assets/images/emojis/marseyit.webp b/files/assets/images/emojis/marseyit.webp index 694210037..e924a0301 100644 Binary files a/files/assets/images/emojis/marseyit.webp and b/files/assets/images/emojis/marseyit.webp differ diff --git a/files/assets/images/emojis/marseyitsallsotiresome.webp b/files/assets/images/emojis/marseyitsallsotiresome.webp new file mode 100644 index 000000000..4d19a9b23 Binary files /dev/null and b/files/assets/images/emojis/marseyitsallsotiresome.webp differ diff --git a/files/assets/images/emojis/marseyitsover.webp b/files/assets/images/emojis/marseyitsover.webp index dc003c2dd..df4a34bfe 100644 Binary files a/files/assets/images/emojis/marseyitsover.webp and b/files/assets/images/emojis/marseyitsover.webp differ diff --git a/files/assets/images/emojis/marseyjackson.webp b/files/assets/images/emojis/marseyjackson.webp index e3dce0978..992c536ce 100644 Binary files a/files/assets/images/emojis/marseyjackson.webp and b/files/assets/images/emojis/marseyjackson.webp differ diff --git a/files/assets/images/emojis/marseyjacksparrow.webp b/files/assets/images/emojis/marseyjacksparrow.webp index 7b6291aa6..cd8911476 100644 Binary files a/files/assets/images/emojis/marseyjacksparrow.webp and b/files/assets/images/emojis/marseyjacksparrow.webp differ diff --git a/files/assets/images/emojis/marseyjaguarwarrior.webp b/files/assets/images/emojis/marseyjaguarwarrior.webp index 402897b3b..5c5a6cbf2 100644 Binary files a/files/assets/images/emojis/marseyjaguarwarrior.webp and b/files/assets/images/emojis/marseyjaguarwarrior.webp differ diff --git a/files/assets/images/emojis/marseyjam.webp b/files/assets/images/emojis/marseyjam.webp index c52f150b3..5a12cfe52 100644 Binary files a/files/assets/images/emojis/marseyjam.webp and b/files/assets/images/emojis/marseyjam.webp differ diff --git a/files/assets/images/emojis/marseyjamesholmes.webp b/files/assets/images/emojis/marseyjamesholmes.webp index fb97792f3..395464f4c 100644 Binary files a/files/assets/images/emojis/marseyjamesholmes.webp and b/files/assets/images/emojis/marseyjamesholmes.webp differ diff --git a/files/assets/images/emojis/marseyjamming.webp b/files/assets/images/emojis/marseyjamming.webp index 8d0afee39..70f3135b5 100644 Binary files a/files/assets/images/emojis/marseyjamming.webp and b/files/assets/images/emojis/marseyjamming.webp differ diff --git a/files/assets/images/emojis/marseyjanny.webp b/files/assets/images/emojis/marseyjanny.webp index 11998aec7..a701c7b1d 100644 Binary files a/files/assets/images/emojis/marseyjanny.webp and b/files/assets/images/emojis/marseyjanny.webp differ diff --git a/files/assets/images/emojis/marseyjanny2.webp b/files/assets/images/emojis/marseyjanny2.webp index 4ed76d71f..4d486b448 100644 Binary files a/files/assets/images/emojis/marseyjanny2.webp and b/files/assets/images/emojis/marseyjanny2.webp differ diff --git a/files/assets/images/emojis/marseyjannymini.webp b/files/assets/images/emojis/marseyjannymini.webp index 64228760c..02515d66e 100644 Binary files a/files/assets/images/emojis/marseyjannymini.webp and b/files/assets/images/emojis/marseyjannymini.webp differ diff --git a/files/assets/images/emojis/marseyjason.webp b/files/assets/images/emojis/marseyjason.webp index a6e7deae2..703881988 100644 Binary files a/files/assets/images/emojis/marseyjason.webp and b/files/assets/images/emojis/marseyjason.webp differ diff --git a/files/assets/images/emojis/marseyjavelin.webp b/files/assets/images/emojis/marseyjavelin.webp index e196e1df0..62e1ca3ca 100644 Binary files a/files/assets/images/emojis/marseyjavelin.webp and b/files/assets/images/emojis/marseyjavelin.webp differ diff --git a/files/assets/images/emojis/marseyjcdenton.webp b/files/assets/images/emojis/marseyjcdenton.webp index ad83737ba..8af8656d5 100644 Binary files a/files/assets/images/emojis/marseyjcdenton.webp and b/files/assets/images/emojis/marseyjcdenton.webp differ diff --git a/files/assets/images/emojis/marseyjeans.webp b/files/assets/images/emojis/marseyjeans.webp index 292b72cf6..a2a3cb809 100644 Binary files a/files/assets/images/emojis/marseyjeans.webp and b/files/assets/images/emojis/marseyjeans.webp differ diff --git a/files/assets/images/emojis/marseyjesus.webp b/files/assets/images/emojis/marseyjesus.webp index 2d9d1663c..dd88ae961 100644 Binary files a/files/assets/images/emojis/marseyjesus.webp and b/files/assets/images/emojis/marseyjesus.webp differ diff --git a/files/assets/images/emojis/marseyjesus2.webp b/files/assets/images/emojis/marseyjesus2.webp index f3d5aae3a..0297b779d 100644 Binary files a/files/assets/images/emojis/marseyjesus2.webp and b/files/assets/images/emojis/marseyjesus2.webp differ diff --git a/files/assets/images/emojis/marseyjetfighter.webp b/files/assets/images/emojis/marseyjetfighter.webp index cac7b7b76..93effc533 100644 Binary files a/files/assets/images/emojis/marseyjetfighter.webp and b/files/assets/images/emojis/marseyjetfighter.webp differ diff --git a/files/assets/images/emojis/marseyjewish.webp b/files/assets/images/emojis/marseyjewish.webp new file mode 100644 index 000000000..c77bd3394 Binary files /dev/null and b/files/assets/images/emojis/marseyjewish.webp differ diff --git a/files/assets/images/emojis/marseyjewishkkk.webp b/files/assets/images/emojis/marseyjewishkkk.webp index 59411c6c0..c7a2cb548 100644 Binary files a/files/assets/images/emojis/marseyjewishkkk.webp and b/files/assets/images/emojis/marseyjewishkkk.webp differ diff --git a/files/assets/images/emojis/marseyjewoftheorient.webp b/files/assets/images/emojis/marseyjewoftheorient.webp index a5bf03676..e896d8ec1 100644 Binary files a/files/assets/images/emojis/marseyjewoftheorient.webp and b/files/assets/images/emojis/marseyjewoftheorient.webp differ diff --git a/files/assets/images/emojis/marseyjfk.webp b/files/assets/images/emojis/marseyjfk.webp index de41ec4ed..18299bdc9 100644 Binary files a/files/assets/images/emojis/marseyjfk.webp and b/files/assets/images/emojis/marseyjfk.webp differ diff --git a/files/assets/images/emojis/marseyjiangshi.webp b/files/assets/images/emojis/marseyjiangshi.webp index 9268b8a0a..b54745d6d 100644 Binary files a/files/assets/images/emojis/marseyjiangshi.webp and b/files/assets/images/emojis/marseyjiangshi.webp differ diff --git a/files/assets/images/emojis/marseyjohnson.webp b/files/assets/images/emojis/marseyjohnson.webp index f6a331ed0..cfefe10c4 100644 Binary files a/files/assets/images/emojis/marseyjohnson.webp and b/files/assets/images/emojis/marseyjohnson.webp differ diff --git a/files/assets/images/emojis/marseyjoint.webp b/files/assets/images/emojis/marseyjoint.webp index 27dc7a117..511b7e2fe 100644 Binary files a/files/assets/images/emojis/marseyjoint.webp and b/files/assets/images/emojis/marseyjoint.webp differ diff --git a/files/assets/images/emojis/marseyjolteon.webp b/files/assets/images/emojis/marseyjolteon.webp index 99fdcde65..dcc1856f1 100644 Binary files a/files/assets/images/emojis/marseyjolteon.webp and b/files/assets/images/emojis/marseyjolteon.webp differ diff --git a/files/assets/images/emojis/marseyjoseon.webp b/files/assets/images/emojis/marseyjoseon.webp index 593b3eda9..9ac4ea798 100644 Binary files a/files/assets/images/emojis/marseyjoseon.webp and b/files/assets/images/emojis/marseyjoseon.webp differ diff --git a/files/assets/images/emojis/marseyjourno.webp b/files/assets/images/emojis/marseyjourno.webp index 4ed08133c..c4f74546e 100644 Binary files a/files/assets/images/emojis/marseyjourno.webp and b/files/assets/images/emojis/marseyjourno.webp differ diff --git a/files/assets/images/emojis/marseyjoy.webp b/files/assets/images/emojis/marseyjoy.webp index ab4d4b7da..d2f4a067e 100644 Binary files a/files/assets/images/emojis/marseyjoy.webp and b/files/assets/images/emojis/marseyjoy.webp differ diff --git a/files/assets/images/emojis/marseyjudge.webp b/files/assets/images/emojis/marseyjudge.webp index f4c770017..789ba48a9 100644 Binary files a/files/assets/images/emojis/marseyjudge.webp and b/files/assets/images/emojis/marseyjudge.webp differ diff --git a/files/assets/images/emojis/marseyjunkie.webp b/files/assets/images/emojis/marseyjunkie.webp index 41b3ecc0a..bba1790b2 100644 Binary files a/files/assets/images/emojis/marseyjunkie.webp and b/files/assets/images/emojis/marseyjunkie.webp differ diff --git a/files/assets/images/emojis/marseyjunkie2.webp b/files/assets/images/emojis/marseyjunkie2.webp index ef04b9974..006d886ea 100644 Binary files a/files/assets/images/emojis/marseyjunkie2.webp and b/files/assets/images/emojis/marseyjunkie2.webp differ diff --git a/files/assets/images/emojis/marseyjurisdiction.webp b/files/assets/images/emojis/marseyjurisdiction.webp new file mode 100644 index 000000000..ec8d39841 Binary files /dev/null and b/files/assets/images/emojis/marseyjurisdiction.webp differ diff --git a/files/assets/images/emojis/marseykaiser.webp b/files/assets/images/emojis/marseykaiser.webp index aad497651..c381b2708 100644 Binary files a/files/assets/images/emojis/marseykaiser.webp and b/files/assets/images/emojis/marseykaiser.webp differ diff --git a/files/assets/images/emojis/marseykamikaze.webp b/files/assets/images/emojis/marseykamikaze.webp index 45c085e08..1da375b09 100644 Binary files a/files/assets/images/emojis/marseykamikaze.webp and b/files/assets/images/emojis/marseykamikaze.webp differ diff --git a/files/assets/images/emojis/marseykente.webp b/files/assets/images/emojis/marseykente.webp index ac514f329..1662418a3 100644 Binary files a/files/assets/images/emojis/marseykente.webp and b/files/assets/images/emojis/marseykente.webp differ diff --git a/files/assets/images/emojis/marseykermit.webp b/files/assets/images/emojis/marseykermit.webp index 8eb3b45ae..f05aa378b 100644 Binary files a/files/assets/images/emojis/marseykermit.webp and b/files/assets/images/emojis/marseykermit.webp differ diff --git a/files/assets/images/emojis/marseykernelpanic.webp b/files/assets/images/emojis/marseykernelpanic.webp index ae4217091..57bbc1765 100644 Binary files a/files/assets/images/emojis/marseykernelpanic.webp and b/files/assets/images/emojis/marseykernelpanic.webp differ diff --git a/files/assets/images/emojis/marseykfc.webp b/files/assets/images/emojis/marseykfc.webp index 72fc7b0c5..716b60d57 100644 Binary files a/files/assets/images/emojis/marseykfc.webp and b/files/assets/images/emojis/marseykfc.webp differ diff --git a/files/assets/images/emojis/marseykhorne.webp b/files/assets/images/emojis/marseykhorne.webp index 8a57ed66e..3f3b9f117 100644 Binary files a/files/assets/images/emojis/marseykhorne.webp and b/files/assets/images/emojis/marseykhorne.webp differ diff --git a/files/assets/images/emojis/marseykindness.webp b/files/assets/images/emojis/marseykindness.webp index 41186119c..9be5d0265 100644 Binary files a/files/assets/images/emojis/marseykindness.webp and b/files/assets/images/emojis/marseykindness.webp differ diff --git a/files/assets/images/emojis/marseyking.webp b/files/assets/images/emojis/marseyking.webp index 194e87102..09c87487e 100644 Binary files a/files/assets/images/emojis/marseyking.webp and b/files/assets/images/emojis/marseyking.webp differ diff --git a/files/assets/images/emojis/marseykingretard.webp b/files/assets/images/emojis/marseykingretard.webp index 725cfdf7a..2de3ecf90 100644 Binary files a/files/assets/images/emojis/marseykingretard.webp and b/files/assets/images/emojis/marseykingretard.webp differ diff --git a/files/assets/images/emojis/marseykink.webp b/files/assets/images/emojis/marseykink.webp index bce074033..492ba06fb 100644 Binary files a/files/assets/images/emojis/marseykink.webp and b/files/assets/images/emojis/marseykink.webp differ diff --git a/files/assets/images/emojis/marseykink2.webp b/files/assets/images/emojis/marseykink2.webp index c9b16edab..8f864eb53 100644 Binary files a/files/assets/images/emojis/marseykink2.webp and b/files/assets/images/emojis/marseykink2.webp differ diff --git a/files/assets/images/emojis/marseykino.webp b/files/assets/images/emojis/marseykino.webp index bffc056f1..460c5d1c8 100644 Binary files a/files/assets/images/emojis/marseykino.webp and b/files/assets/images/emojis/marseykino.webp differ diff --git a/files/assets/images/emojis/marseykirby.webp b/files/assets/images/emojis/marseykirby.webp index 809b46af5..6a215b49d 100644 Binary files a/files/assets/images/emojis/marseykirby.webp and b/files/assets/images/emojis/marseykirby.webp differ diff --git a/files/assets/images/emojis/marseykirby2.webp b/files/assets/images/emojis/marseykirby2.webp index d4d990d38..fffdba8a4 100644 Binary files a/files/assets/images/emojis/marseykirby2.webp and b/files/assets/images/emojis/marseykirby2.webp differ diff --git a/files/assets/images/emojis/marseykissinger.webp b/files/assets/images/emojis/marseykissinger.webp index 0d9c892e7..53c12fab0 100644 Binary files a/files/assets/images/emojis/marseykissinger.webp and b/files/assets/images/emojis/marseykissinger.webp differ diff --git a/files/assets/images/emojis/marseykitti.webp b/files/assets/images/emojis/marseykitti.webp index ae0df2fc6..84a326768 100644 Binary files a/files/assets/images/emojis/marseykitti.webp and b/files/assets/images/emojis/marseykitti.webp differ diff --git a/files/assets/images/emojis/marseykiwi.webp b/files/assets/images/emojis/marseykiwi.webp index f1b2b98a8..e89796003 100644 Binary files a/files/assets/images/emojis/marseykiwi.webp and b/files/assets/images/emojis/marseykiwi.webp differ diff --git a/files/assets/images/emojis/marseykiwi2.webp b/files/assets/images/emojis/marseykiwi2.webp index 422c6798a..ee38347f0 100644 Binary files a/files/assets/images/emojis/marseykiwi2.webp and b/files/assets/images/emojis/marseykiwi2.webp differ diff --git a/files/assets/images/emojis/marseykiwimom.webp b/files/assets/images/emojis/marseykiwimom.webp index 8b841e533..a5f74e928 100644 Binary files a/files/assets/images/emojis/marseykiwimom.webp and b/files/assets/images/emojis/marseykiwimom.webp differ diff --git a/files/assets/images/emojis/marseykiwivampire.webp b/files/assets/images/emojis/marseykiwivampire.webp index eb2d1982a..25d7306f9 100644 Binary files a/files/assets/images/emojis/marseykiwivampire.webp and b/files/assets/images/emojis/marseykiwivampire.webp differ diff --git a/files/assets/images/emojis/marseykkk.webp b/files/assets/images/emojis/marseykkk.webp index 0f8ef1928..d472b6838 100644 Binary files a/files/assets/images/emojis/marseykkk.webp and b/files/assets/images/emojis/marseykkk.webp differ diff --git a/files/assets/images/emojis/marseykkkblm.webp b/files/assets/images/emojis/marseykkkblm.webp index e6cc9e803..2eed8dd68 100644 Binary files a/files/assets/images/emojis/marseykkkblm.webp and b/files/assets/images/emojis/marseykkkblm.webp differ diff --git a/files/assets/images/emojis/marseykkkevil.webp b/files/assets/images/emojis/marseykkkevil.webp index 12bf6ee88..fec35f180 100644 Binary files a/files/assets/images/emojis/marseykkkevil.webp and b/files/assets/images/emojis/marseykkkevil.webp differ diff --git a/files/assets/images/emojis/marseyklenny2.webp b/files/assets/images/emojis/marseyklenny2.webp index a56a3a805..ae0eaf78d 100644 Binary files a/files/assets/images/emojis/marseyklenny2.webp and b/files/assets/images/emojis/marseyklenny2.webp differ diff --git a/files/assets/images/emojis/marseyklenny3.webp b/files/assets/images/emojis/marseyklenny3.webp index 0b7b52d8a..0a0806614 100644 Binary files a/files/assets/images/emojis/marseyklenny3.webp and b/files/assets/images/emojis/marseyklenny3.webp differ diff --git a/files/assets/images/emojis/marseyklennywinner.webp b/files/assets/images/emojis/marseyklennywinner.webp index e62ae5e1a..375ef96c2 100644 Binary files a/files/assets/images/emojis/marseyklennywinner.webp and b/files/assets/images/emojis/marseyklennywinner.webp differ diff --git a/files/assets/images/emojis/marseykneel.webp b/files/assets/images/emojis/marseykneel.webp index e31ee6b30..73e5574c7 100644 Binary files a/files/assets/images/emojis/marseykneel.webp and b/files/assets/images/emojis/marseykneel.webp differ diff --git a/files/assets/images/emojis/marseykoalalove.webp b/files/assets/images/emojis/marseykoalalove.webp index 518b37a19..2f902e924 100644 Binary files a/files/assets/images/emojis/marseykoalalove.webp and b/files/assets/images/emojis/marseykoalalove.webp differ diff --git a/files/assets/images/emojis/marseykoolaid.webp b/files/assets/images/emojis/marseykoolaid.webp index db3b2e3d7..21ddad97e 100644 Binary files a/files/assets/images/emojis/marseykoolaid.webp and b/files/assets/images/emojis/marseykoolaid.webp differ diff --git a/files/assets/images/emojis/marseykrampus.webp b/files/assets/images/emojis/marseykrampus.webp index d17fbf09b..82c8873d7 100644 Binary files a/files/assets/images/emojis/marseykrampus.webp and b/files/assets/images/emojis/marseykrampus.webp differ diff --git a/files/assets/images/emojis/marseykrampus2.webp b/files/assets/images/emojis/marseykrampus2.webp index e8f086f88..f08ff03b7 100644 Binary files a/files/assets/images/emojis/marseykrampus2.webp and b/files/assets/images/emojis/marseykrampus2.webp differ diff --git a/files/assets/images/emojis/marseykvlt.webp b/files/assets/images/emojis/marseykvlt.webp index 3533dd467..2a1dc0902 100644 Binary files a/files/assets/images/emojis/marseykvlt.webp and b/files/assets/images/emojis/marseykvlt.webp differ diff --git a/files/assets/images/emojis/marseykwanza.webp b/files/assets/images/emojis/marseykwanza.webp index 140391ef9..535381f65 100644 Binary files a/files/assets/images/emojis/marseykwanza.webp and b/files/assets/images/emojis/marseykwanza.webp differ diff --git a/files/assets/images/emojis/marseykween.webp b/files/assets/images/emojis/marseykween.webp index 8d285aa11..20c1697bd 100644 Binary files a/files/assets/images/emojis/marseykween.webp and b/files/assets/images/emojis/marseykween.webp differ diff --git a/files/assets/images/emojis/marseykweenxmas.webp b/files/assets/images/emojis/marseykweenxmas.webp index debe95ff7..824bb1730 100644 Binary files a/files/assets/images/emojis/marseykweenxmas.webp and b/files/assets/images/emojis/marseykweenxmas.webp differ diff --git a/files/assets/images/emojis/marseykyle.webp b/files/assets/images/emojis/marseykyle.webp index 7c85dd59f..ce1243c9c 100644 Binary files a/files/assets/images/emojis/marseykyle.webp and b/files/assets/images/emojis/marseykyle.webp differ diff --git a/files/assets/images/emojis/marseylain.webp b/files/assets/images/emojis/marseylain.webp index a13f7792b..c36206c5e 100644 Binary files a/files/assets/images/emojis/marseylain.webp and b/files/assets/images/emojis/marseylain.webp differ diff --git a/files/assets/images/emojis/marseylaptop.webp b/files/assets/images/emojis/marseylaptop.webp index 0a05bb32a..3c2f229bc 100644 Binary files a/files/assets/images/emojis/marseylaptop.webp and b/files/assets/images/emojis/marseylaptop.webp differ diff --git a/files/assets/images/emojis/marseylaugh.webp b/files/assets/images/emojis/marseylaugh.webp index 73c67843b..79d664c87 100644 Binary files a/files/assets/images/emojis/marseylaugh.webp and b/files/assets/images/emojis/marseylaugh.webp differ diff --git a/files/assets/images/emojis/marseylaughbothsides.webp b/files/assets/images/emojis/marseylaughbothsides.webp index c08657a38..a2b539f70 100644 Binary files a/files/assets/images/emojis/marseylaughbothsides.webp and b/files/assets/images/emojis/marseylaughbothsides.webp differ diff --git a/files/assets/images/emojis/marseylaughwith.webp b/files/assets/images/emojis/marseylaughwith.webp index d974ca0c8..52f2b5061 100644 Binary files a/files/assets/images/emojis/marseylaughwith.webp and b/files/assets/images/emojis/marseylaughwith.webp differ diff --git a/files/assets/images/emojis/marseylawlz.webp b/files/assets/images/emojis/marseylawlz.webp index 185f33d96..f82a27d5b 100644 Binary files a/files/assets/images/emojis/marseylawlz.webp and b/files/assets/images/emojis/marseylawlz.webp differ diff --git a/files/assets/images/emojis/marseyleafeon.webp b/files/assets/images/emojis/marseyleafeon.webp index 559cb2dcc..5a437b5e0 100644 Binary files a/files/assets/images/emojis/marseyleafeon.webp and b/files/assets/images/emojis/marseyleafeon.webp differ diff --git a/files/assets/images/emojis/marseylegion.webp b/files/assets/images/emojis/marseylegion.webp index 7c51e1c47..e5a25933d 100644 Binary files a/files/assets/images/emojis/marseylegion.webp and b/files/assets/images/emojis/marseylegion.webp differ diff --git a/files/assets/images/emojis/marseylegionnaire.webp b/files/assets/images/emojis/marseylegionnaire.webp index d5b58c635..fefd91f75 100644 Binary files a/files/assets/images/emojis/marseylegionnaire.webp and b/files/assets/images/emojis/marseylegionnaire.webp differ diff --git a/files/assets/images/emojis/marseylego.webp b/files/assets/images/emojis/marseylego.webp new file mode 100644 index 000000000..44408a4bd Binary files /dev/null and b/files/assets/images/emojis/marseylego.webp differ diff --git a/files/assets/images/emojis/marseylemon.webp b/files/assets/images/emojis/marseylemon.webp index 5b42d4578..6b19cdb75 100644 Binary files a/files/assets/images/emojis/marseylemon.webp and b/files/assets/images/emojis/marseylemon.webp differ diff --git a/files/assets/images/emojis/marseylenin.webp b/files/assets/images/emojis/marseylenin.webp index f7790aebd..6d951dfb5 100644 Binary files a/files/assets/images/emojis/marseylenin.webp and b/files/assets/images/emojis/marseylenin.webp differ diff --git a/files/assets/images/emojis/marseylenny.webp b/files/assets/images/emojis/marseylenny.webp index bf6ffc05d..2ab1fb6fa 100644 Binary files a/files/assets/images/emojis/marseylenny.webp and b/files/assets/images/emojis/marseylenny.webp differ diff --git a/files/assets/images/emojis/marseyletsfuckinggo.webp b/files/assets/images/emojis/marseyletsfuckinggo.webp index 1ccf0e1c6..e61d37972 100644 Binary files a/files/assets/images/emojis/marseyletsfuckinggo.webp and b/files/assets/images/emojis/marseyletsfuckinggo.webp differ diff --git a/files/assets/images/emojis/marseyletsfuckinggo2.webp b/files/assets/images/emojis/marseyletsfuckinggo2.webp index fa88e77ef..2f4b503d4 100644 Binary files a/files/assets/images/emojis/marseyletsfuckinggo2.webp and b/files/assets/images/emojis/marseyletsfuckinggo2.webp differ diff --git a/files/assets/images/emojis/marseylgbtflag.webp b/files/assets/images/emojis/marseylgbtflag.webp index 372ad45b1..d4e2fe293 100644 Binary files a/files/assets/images/emojis/marseylgbtflag.webp and b/files/assets/images/emojis/marseylgbtflag.webp differ diff --git a/files/assets/images/emojis/marseylgbtflag2.webp b/files/assets/images/emojis/marseylgbtflag2.webp index fed5c93e3..630866ff1 100644 Binary files a/files/assets/images/emojis/marseylgbtflag2.webp and b/files/assets/images/emojis/marseylgbtflag2.webp differ diff --git a/files/assets/images/emojis/marseylgbtflag3.webp b/files/assets/images/emojis/marseylgbtflag3.webp index 2dfd7acc5..db25c6d85 100644 Binary files a/files/assets/images/emojis/marseylgbtflag3.webp and b/files/assets/images/emojis/marseylgbtflag3.webp differ diff --git a/files/assets/images/emojis/marseyliathomas.webp b/files/assets/images/emojis/marseyliathomas.webp index bfa0c1a1c..9f34caf9c 100644 Binary files a/files/assets/images/emojis/marseyliathomas.webp and b/files/assets/images/emojis/marseyliathomas.webp differ diff --git a/files/assets/images/emojis/marseyliberty.webp b/files/assets/images/emojis/marseyliberty.webp index 0bec809d4..64b0f1b73 100644 Binary files a/files/assets/images/emojis/marseyliberty.webp and b/files/assets/images/emojis/marseyliberty.webp differ diff --git a/files/assets/images/emojis/marseyliberty2.webp b/files/assets/images/emojis/marseyliberty2.webp index c9e6ea4c0..03ae0e12e 100644 Binary files a/files/assets/images/emojis/marseyliberty2.webp and b/files/assets/images/emojis/marseyliberty2.webp differ diff --git a/files/assets/images/emojis/marseylibleft.webp b/files/assets/images/emojis/marseylibleft.webp index 45035769b..376cad1e8 100644 Binary files a/files/assets/images/emojis/marseylibleft.webp and b/files/assets/images/emojis/marseylibleft.webp differ diff --git a/files/assets/images/emojis/marseylibright.webp b/files/assets/images/emojis/marseylibright.webp index ff12178b0..516982a78 100644 Binary files a/files/assets/images/emojis/marseylibright.webp and b/files/assets/images/emojis/marseylibright.webp differ diff --git a/files/assets/images/emojis/marseylicking.webp b/files/assets/images/emojis/marseylicking.webp index e1bd142ee..fb2605e2a 100644 Binary files a/files/assets/images/emojis/marseylicking.webp and b/files/assets/images/emojis/marseylicking.webp differ diff --git a/files/assets/images/emojis/marseylickinglips.webp b/files/assets/images/emojis/marseylickinglips.webp index 1f05e510b..4a21990f0 100644 Binary files a/files/assets/images/emojis/marseylickinglips.webp and b/files/assets/images/emojis/marseylickinglips.webp differ diff --git a/files/assets/images/emojis/marseylifting.webp b/files/assets/images/emojis/marseylifting.webp index f3357a57b..2022c1abd 100644 Binary files a/files/assets/images/emojis/marseylifting.webp and b/files/assets/images/emojis/marseylifting.webp differ diff --git a/files/assets/images/emojis/marseylion.webp b/files/assets/images/emojis/marseylion.webp index 90ae5c4e4..166cf9d58 100644 Binary files a/files/assets/images/emojis/marseylion.webp and b/files/assets/images/emojis/marseylion.webp differ diff --git a/files/assets/images/emojis/marseyliquidator.webp b/files/assets/images/emojis/marseyliquidator.webp index c3e3958cc..a1ea1f075 100644 Binary files a/files/assets/images/emojis/marseyliquidator.webp and b/files/assets/images/emojis/marseyliquidator.webp differ diff --git a/files/assets/images/emojis/marseylizard.webp b/files/assets/images/emojis/marseylizard.webp index 138c3668e..c034a822a 100644 Binary files a/files/assets/images/emojis/marseylizard.webp and b/files/assets/images/emojis/marseylizard.webp differ diff --git a/files/assets/images/emojis/marseyllama.webp b/files/assets/images/emojis/marseyllama.webp index 64abbad1f..35e898591 100644 Binary files a/files/assets/images/emojis/marseyllama.webp and b/files/assets/images/emojis/marseyllama.webp differ diff --git a/files/assets/images/emojis/marseyllama1.webp b/files/assets/images/emojis/marseyllama1.webp index 9aa52cdc8..8acfe3f3f 100644 Binary files a/files/assets/images/emojis/marseyllama1.webp and b/files/assets/images/emojis/marseyllama1.webp differ diff --git a/files/assets/images/emojis/marseyllama2.webp b/files/assets/images/emojis/marseyllama2.webp index 5c4ff487e..ef61da86a 100644 Binary files a/files/assets/images/emojis/marseyllama2.webp and b/files/assets/images/emojis/marseyllama2.webp differ diff --git a/files/assets/images/emojis/marseyllama3.webp b/files/assets/images/emojis/marseyllama3.webp index ed5a10e98..97e62fdbe 100644 Binary files a/files/assets/images/emojis/marseyllama3.webp and b/files/assets/images/emojis/marseyllama3.webp differ diff --git a/files/assets/images/emojis/marseyloaf.webp b/files/assets/images/emojis/marseyloaf.webp index e9ffbc2c5..e59cadd11 100644 Binary files a/files/assets/images/emojis/marseyloaf.webp and b/files/assets/images/emojis/marseyloaf.webp differ diff --git a/files/assets/images/emojis/marseylois.webp b/files/assets/images/emojis/marseylois.webp index 7a46ad9de..5d890d531 100644 Binary files a/files/assets/images/emojis/marseylois.webp and b/files/assets/images/emojis/marseylois.webp differ diff --git a/files/assets/images/emojis/marseylolcow.webp b/files/assets/images/emojis/marseylolcow.webp index e4f9170a0..825a58417 100644 Binary files a/files/assets/images/emojis/marseylolcow.webp and b/files/assets/images/emojis/marseylolcow.webp differ diff --git a/files/assets/images/emojis/marseylong1.webp b/files/assets/images/emojis/marseylong1.webp index dd02c02de..130f4ab4b 100644 Binary files a/files/assets/images/emojis/marseylong1.webp and b/files/assets/images/emojis/marseylong1.webp differ diff --git a/files/assets/images/emojis/marseylong2.webp b/files/assets/images/emojis/marseylong2.webp index 885e55e7a..75355d638 100644 Binary files a/files/assets/images/emojis/marseylong2.webp and b/files/assets/images/emojis/marseylong2.webp differ diff --git a/files/assets/images/emojis/marseylong3.webp b/files/assets/images/emojis/marseylong3.webp index ed1e917b6..1cb2079f9 100644 Binary files a/files/assets/images/emojis/marseylong3.webp and b/files/assets/images/emojis/marseylong3.webp differ diff --git a/files/assets/images/emojis/marseylonghorn.webp b/files/assets/images/emojis/marseylonghorn.webp index 692246e0b..64798a410 100644 Binary files a/files/assets/images/emojis/marseylonghorn.webp and b/files/assets/images/emojis/marseylonghorn.webp differ diff --git a/files/assets/images/emojis/marseylongsurfing.webp b/files/assets/images/emojis/marseylongsurfing.webp index 62960df0a..ffa754950 100644 Binary files a/files/assets/images/emojis/marseylongsurfing.webp and b/files/assets/images/emojis/marseylongsurfing.webp differ diff --git a/files/assets/images/emojis/marseyloss.webp b/files/assets/images/emojis/marseyloss.webp index 831a53652..cfb2f94a2 100644 Binary files a/files/assets/images/emojis/marseyloss.webp and b/files/assets/images/emojis/marseyloss.webp differ diff --git a/files/assets/images/emojis/marseylouisiana.webp b/files/assets/images/emojis/marseylouisiana.webp new file mode 100644 index 000000000..38e77ee46 Binary files /dev/null and b/files/assets/images/emojis/marseylouisiana.webp differ diff --git a/files/assets/images/emojis/marseylove.webp b/files/assets/images/emojis/marseylove.webp index 957a54962..7129dcbec 100644 Binary files a/files/assets/images/emojis/marseylove.webp and b/files/assets/images/emojis/marseylove.webp differ diff --git a/files/assets/images/emojis/marseylovecraft.webp b/files/assets/images/emojis/marseylovecraft.webp index d7e79729a..a03d04f39 100644 Binary files a/files/assets/images/emojis/marseylovecraft.webp and b/files/assets/images/emojis/marseylovecraft.webp differ diff --git a/files/assets/images/emojis/marseylovecraft2.webp b/files/assets/images/emojis/marseylovecraft2.webp index a9c5b88c5..b3d81e2df 100644 Binary files a/files/assets/images/emojis/marseylovecraft2.webp and b/files/assets/images/emojis/marseylovecraft2.webp differ diff --git a/files/assets/images/emojis/marseylovegigaorgy.webp b/files/assets/images/emojis/marseylovegigaorgy.webp index ec1ea63c6..054ea2420 100644 Binary files a/files/assets/images/emojis/marseylovegigaorgy.webp and b/files/assets/images/emojis/marseylovegigaorgy.webp differ diff --git a/files/assets/images/emojis/marseylueshi.webp b/files/assets/images/emojis/marseylueshi.webp index 5d8a738f3..ef071b787 100644 Binary files a/files/assets/images/emojis/marseylueshi.webp and b/files/assets/images/emojis/marseylueshi.webp differ diff --git a/files/assets/images/emojis/marseyluther.webp b/files/assets/images/emojis/marseyluther.webp index a2747491b..346cd5d85 100644 Binary files a/files/assets/images/emojis/marseyluther.webp and b/files/assets/images/emojis/marseyluther.webp differ diff --git a/files/assets/images/emojis/marseymacarthur.webp b/files/assets/images/emojis/marseymacarthur.webp index 6766ba34c..e6ddad556 100644 Binary files a/files/assets/images/emojis/marseymacarthur.webp and b/files/assets/images/emojis/marseymacarthur.webp differ diff --git a/files/assets/images/emojis/marseymad.webp b/files/assets/images/emojis/marseymad.webp index e8271870c..b42f9d0a5 100644 Binary files a/files/assets/images/emojis/marseymad.webp and b/files/assets/images/emojis/marseymad.webp differ diff --git a/files/assets/images/emojis/marseymagahat.webp b/files/assets/images/emojis/marseymagahat.webp index ed0096e1f..20f3f5421 100644 Binary files a/files/assets/images/emojis/marseymagahat.webp and b/files/assets/images/emojis/marseymagahat.webp differ diff --git a/files/assets/images/emojis/marseymagarentfree.webp b/files/assets/images/emojis/marseymagarentfree.webp index 64d6b674c..4aa96ff63 100644 Binary files a/files/assets/images/emojis/marseymagarentfree.webp and b/files/assets/images/emojis/marseymagarentfree.webp differ diff --git a/files/assets/images/emojis/marseymajorgeneral.webp b/files/assets/images/emojis/marseymajorgeneral.webp index 6a00f39de..e3837d028 100644 Binary files a/files/assets/images/emojis/marseymajorgeneral.webp and b/files/assets/images/emojis/marseymajorgeneral.webp differ diff --git a/files/assets/images/emojis/marseymalding.webp b/files/assets/images/emojis/marseymalding.webp index 7bd4cbcc4..6109fd724 100644 Binary files a/files/assets/images/emojis/marseymalding.webp and b/files/assets/images/emojis/marseymalding.webp differ diff --git a/files/assets/images/emojis/marseymancer.webp b/files/assets/images/emojis/marseymancer.webp index 4747467d7..0f4931e7d 100644 Binary files a/files/assets/images/emojis/marseymancer.webp and b/files/assets/images/emojis/marseymancer.webp differ diff --git a/files/assets/images/emojis/marseymanifestdestiny.webp b/files/assets/images/emojis/marseymanifestdestiny.webp index 921774d5e..6bb104a93 100644 Binary files a/files/assets/images/emojis/marseymanifestdestiny.webp and b/files/assets/images/emojis/marseymanifestdestiny.webp differ diff --git a/files/assets/images/emojis/marseymanlet.webp b/files/assets/images/emojis/marseymanlet.webp index 1f9b78dae..9e25510f3 100644 Binary files a/files/assets/images/emojis/marseymanlet.webp and b/files/assets/images/emojis/marseymanlet.webp differ diff --git a/files/assets/images/emojis/marseymao.webp b/files/assets/images/emojis/marseymao.webp index ef0fc92f6..1c0c3dd94 100644 Binary files a/files/assets/images/emojis/marseymao.webp and b/files/assets/images/emojis/marseymao.webp differ diff --git a/files/assets/images/emojis/marseymaoist.webp b/files/assets/images/emojis/marseymaoist.webp index e1ec02c23..4b745af83 100644 Binary files a/files/assets/images/emojis/marseymaoist.webp and b/files/assets/images/emojis/marseymaoist.webp differ diff --git a/files/assets/images/emojis/marseymap.webp b/files/assets/images/emojis/marseymap.webp index b77a314fa..eed17ade9 100644 Binary files a/files/assets/images/emojis/marseymap.webp and b/files/assets/images/emojis/marseymap.webp differ diff --git a/files/assets/images/emojis/marseymap2.webp b/files/assets/images/emojis/marseymap2.webp index f9ceff119..35885beb5 100644 Binary files a/files/assets/images/emojis/marseymap2.webp and b/files/assets/images/emojis/marseymap2.webp differ diff --git a/files/assets/images/emojis/marseymar.webp b/files/assets/images/emojis/marseymar.webp index 69d979080..0d90ed9a8 100644 Binary files a/files/assets/images/emojis/marseymar.webp and b/files/assets/images/emojis/marseymar.webp differ diff --git a/files/assets/images/emojis/marseymars.webp b/files/assets/images/emojis/marseymars.webp index a5b0056a6..c0d63f648 100644 Binary files a/files/assets/images/emojis/marseymars.webp and b/files/assets/images/emojis/marseymars.webp differ diff --git a/files/assets/images/emojis/marseymarseylove.webp b/files/assets/images/emojis/marseymarseylove.webp index cf35740f6..d9fca74b4 100644 Binary files a/files/assets/images/emojis/marseymarseylove.webp and b/files/assets/images/emojis/marseymarseylove.webp differ diff --git a/files/assets/images/emojis/marseymarseylovelove.webp b/files/assets/images/emojis/marseymarseylovelove.webp index ec5f0bc8f..d9b4145bf 100644 Binary files a/files/assets/images/emojis/marseymarseylovelove.webp and b/files/assets/images/emojis/marseymarseylovelove.webp differ diff --git a/files/assets/images/emojis/marseymarseyloveorgy.webp b/files/assets/images/emojis/marseymarseyloveorgy.webp index 541492290..9daaac0fa 100644 Binary files a/files/assets/images/emojis/marseymarseyloveorgy.webp and b/files/assets/images/emojis/marseymarseyloveorgy.webp differ diff --git a/files/assets/images/emojis/marseymask.webp b/files/assets/images/emojis/marseymask.webp index b0f63f62f..78b30e3ee 100644 Binary files a/files/assets/images/emojis/marseymask.webp and b/files/assets/images/emojis/marseymask.webp differ diff --git a/files/assets/images/emojis/marseymasterchief.webp b/files/assets/images/emojis/marseymasterchief.webp index 8f7e5a05d..7df27af14 100644 Binary files a/files/assets/images/emojis/marseymasterchief.webp and b/files/assets/images/emojis/marseymasterchief.webp differ diff --git a/files/assets/images/emojis/marseymati.webp b/files/assets/images/emojis/marseymati.webp index ea83520f7..22cc83608 100644 Binary files a/files/assets/images/emojis/marseymati.webp and b/files/assets/images/emojis/marseymati.webp differ diff --git a/files/assets/images/emojis/marseymaxrockatansky.webp b/files/assets/images/emojis/marseymaxrockatansky.webp index b9695ad54..ee527bca3 100644 Binary files a/files/assets/images/emojis/marseymaxrockatansky.webp and b/files/assets/images/emojis/marseymaxrockatansky.webp differ diff --git a/files/assets/images/emojis/marseymayo.webp b/files/assets/images/emojis/marseymayo.webp index 7bb7710cc..7c1fce5fa 100644 Binary files a/files/assets/images/emojis/marseymayo.webp and b/files/assets/images/emojis/marseymayo.webp differ diff --git a/files/assets/images/emojis/marseymayoface.webp b/files/assets/images/emojis/marseymayoface.webp index ae7689aea..bfef93a07 100644 Binary files a/files/assets/images/emojis/marseymayoface.webp and b/files/assets/images/emojis/marseymayoface.webp differ diff --git a/files/assets/images/emojis/marseymayoparty.webp b/files/assets/images/emojis/marseymayoparty.webp index fd816ab4d..791b0b6a3 100644 Binary files a/files/assets/images/emojis/marseymayoparty.webp and b/files/assets/images/emojis/marseymayoparty.webp differ diff --git a/files/assets/images/emojis/marseymcarthur.webp b/files/assets/images/emojis/marseymcarthur.webp index 6766ba34c..e6ddad556 100644 Binary files a/files/assets/images/emojis/marseymcarthur.webp and b/files/assets/images/emojis/marseymcarthur.webp differ diff --git a/files/assets/images/emojis/marseymeatwad.webp b/files/assets/images/emojis/marseymeatwad.webp index 856666214..46854a518 100644 Binary files a/files/assets/images/emojis/marseymeatwad.webp and b/files/assets/images/emojis/marseymeatwad.webp differ diff --git a/files/assets/images/emojis/marseymech2.webp b/files/assets/images/emojis/marseymech2.webp index 1cd602c2b..0e91d946d 100644 Binary files a/files/assets/images/emojis/marseymech2.webp and b/files/assets/images/emojis/marseymech2.webp differ diff --git a/files/assets/images/emojis/marseymechanic.webp b/files/assets/images/emojis/marseymechanic.webp index f9f6f21a3..e253ecd6b 100644 Binary files a/files/assets/images/emojis/marseymechanic.webp and b/files/assets/images/emojis/marseymechanic.webp differ diff --git a/files/assets/images/emojis/marseymeds.webp b/files/assets/images/emojis/marseymeds.webp index c067f8f4d..309c7d1c5 100644 Binary files a/files/assets/images/emojis/marseymeds.webp and b/files/assets/images/emojis/marseymeds.webp differ diff --git a/files/assets/images/emojis/marseymedusa.webp b/files/assets/images/emojis/marseymedusa.webp index c9ff58934..559d4bb51 100644 Binary files a/files/assets/images/emojis/marseymedusa.webp and b/files/assets/images/emojis/marseymedusa.webp differ diff --git a/files/assets/images/emojis/marseymegalodon.webp b/files/assets/images/emojis/marseymegalodon.webp index 93992ca3e..a4e41e402 100644 Binary files a/files/assets/images/emojis/marseymegalodon.webp and b/files/assets/images/emojis/marseymegalodon.webp differ diff --git a/files/assets/images/emojis/marseymemeball.webp b/files/assets/images/emojis/marseymemeball.webp index 7f374ce4a..847de7553 100644 Binary files a/files/assets/images/emojis/marseymemeball.webp and b/files/assets/images/emojis/marseymemeball.webp differ diff --git a/files/assets/images/emojis/marseymeowth.webp b/files/assets/images/emojis/marseymeowth.webp index 0e3256d78..a1d161d93 100644 Binary files a/files/assets/images/emojis/marseymeowth.webp and b/files/assets/images/emojis/marseymeowth.webp differ diff --git a/files/assets/images/emojis/marseymerchant.webp b/files/assets/images/emojis/marseymerchant.webp index 000166bec..07807b878 100644 Binary files a/files/assets/images/emojis/marseymerchant.webp and b/files/assets/images/emojis/marseymerchant.webp differ diff --git a/files/assets/images/emojis/marseymerchantelf.webp b/files/assets/images/emojis/marseymerchantelf.webp index 82c7eedd2..13622b2ed 100644 Binary files a/files/assets/images/emojis/marseymerchantelf.webp and b/files/assets/images/emojis/marseymerchantelf.webp differ diff --git a/files/assets/images/emojis/marseymerchantsoy.webp b/files/assets/images/emojis/marseymerchantsoy.webp index 83c672408..aba1c8866 100644 Binary files a/files/assets/images/emojis/marseymerchantsoy.webp and b/files/assets/images/emojis/marseymerchantsoy.webp differ diff --git a/files/assets/images/emojis/marseymermaid.webp b/files/assets/images/emojis/marseymermaid.webp index 56b2dd01e..44f6e1a4f 100644 Binary files a/files/assets/images/emojis/marseymermaid.webp and b/files/assets/images/emojis/marseymermaid.webp differ diff --git a/files/assets/images/emojis/marseymexican.webp b/files/assets/images/emojis/marseymexican.webp index 7d19aa2e2..da64aa43e 100644 Binary files a/files/assets/images/emojis/marseymexican.webp and b/files/assets/images/emojis/marseymexican.webp differ diff --git a/files/assets/images/emojis/marseymfdoom.webp b/files/assets/images/emojis/marseymfdoom.webp index dcda67df8..392891aa2 100644 Binary files a/files/assets/images/emojis/marseymfdoom.webp and b/files/assets/images/emojis/marseymfdoom.webp differ diff --git a/files/assets/images/emojis/marseymicrobus.webp b/files/assets/images/emojis/marseymicrobus.webp index d94b66578..8d9d14b27 100644 Binary files a/files/assets/images/emojis/marseymicrobus.webp and b/files/assets/images/emojis/marseymicrobus.webp differ diff --git a/files/assets/images/emojis/marseymicrosoftpride.webp b/files/assets/images/emojis/marseymicrosoftpride.webp new file mode 100644 index 000000000..650116e59 Binary files /dev/null and b/files/assets/images/emojis/marseymicrosoftpride.webp differ diff --git a/files/assets/images/emojis/marseymidsommarchristian.webp b/files/assets/images/emojis/marseymidsommarchristian.webp index 0704b6787..2d41b6333 100644 Binary files a/files/assets/images/emojis/marseymidsommarchristian.webp and b/files/assets/images/emojis/marseymidsommarchristian.webp differ diff --git a/files/assets/images/emojis/marseymidsommardani.webp b/files/assets/images/emojis/marseymidsommardani.webp index 01d4e08ab..bc81b7d07 100644 Binary files a/files/assets/images/emojis/marseymidsommardani.webp and b/files/assets/images/emojis/marseymidsommardani.webp differ diff --git a/files/assets/images/emojis/marseymike.webp b/files/assets/images/emojis/marseymike.webp index cc1ea0d6e..23b37dbe7 100644 Binary files a/files/assets/images/emojis/marseymike.webp and b/files/assets/images/emojis/marseymike.webp differ diff --git a/files/assets/images/emojis/marseymilesdavis.webp b/files/assets/images/emojis/marseymilesdavis.webp index 2f0573c4c..467e325cf 100644 Binary files a/files/assets/images/emojis/marseymilesdavis.webp and b/files/assets/images/emojis/marseymilesdavis.webp differ diff --git a/files/assets/images/emojis/marseymime.webp b/files/assets/images/emojis/marseymime.webp index 6038c3001..eaa191bc1 100644 Binary files a/files/assets/images/emojis/marseymime.webp and b/files/assets/images/emojis/marseymime.webp differ diff --git a/files/assets/images/emojis/marseyminer.webp b/files/assets/images/emojis/marseyminer.webp index 1536b58ef..2880e4648 100644 Binary files a/files/assets/images/emojis/marseyminer.webp and b/files/assets/images/emojis/marseyminer.webp differ diff --git a/files/assets/images/emojis/marseyminimalism.webp b/files/assets/images/emojis/marseyminimalism.webp index d7751a353..3c4108d37 100644 Binary files a/files/assets/images/emojis/marseyminimalism.webp and b/files/assets/images/emojis/marseyminimalism.webp differ diff --git a/files/assets/images/emojis/marseyminimalism2.webp b/files/assets/images/emojis/marseyminimalism2.webp index 9a34949e5..ac123311e 100644 Binary files a/files/assets/images/emojis/marseyminimalism2.webp and b/files/assets/images/emojis/marseyminimalism2.webp differ diff --git a/files/assets/images/emojis/marseyminion.webp b/files/assets/images/emojis/marseyminion.webp index 877603d30..19e5fcf7c 100644 Binary files a/files/assets/images/emojis/marseyminion.webp and b/files/assets/images/emojis/marseyminion.webp differ diff --git a/files/assets/images/emojis/marseyminipixel.webp b/files/assets/images/emojis/marseyminipixel.webp index 19e7e0d79..3b416e114 100644 Binary files a/files/assets/images/emojis/marseyminipixel.webp and b/files/assets/images/emojis/marseyminipixel.webp differ diff --git a/files/assets/images/emojis/marseymischief.webp b/files/assets/images/emojis/marseymischief.webp index 54758a091..e4e461554 100644 Binary files a/files/assets/images/emojis/marseymischief.webp and b/files/assets/images/emojis/marseymischief.webp differ diff --git a/files/assets/images/emojis/marseymisinformation.webp b/files/assets/images/emojis/marseymisinformation.webp new file mode 100644 index 000000000..982c3b97f Binary files /dev/null and b/files/assets/images/emojis/marseymisinformation.webp differ diff --git a/files/assets/images/emojis/marseymissing.webp b/files/assets/images/emojis/marseymissing.webp index 8e8c6d172..a967347f1 100644 Binary files a/files/assets/images/emojis/marseymissing.webp and b/files/assets/images/emojis/marseymissing.webp differ diff --git a/files/assets/images/emojis/marseymissing2.webp b/files/assets/images/emojis/marseymissing2.webp index 91b03f822..5320dacbd 100644 Binary files a/files/assets/images/emojis/marseymissing2.webp and b/files/assets/images/emojis/marseymissing2.webp differ diff --git a/files/assets/images/emojis/marseymobility.webp b/files/assets/images/emojis/marseymobility.webp index 3209ebfbc..f4a53edbe 100644 Binary files a/files/assets/images/emojis/marseymobility.webp and b/files/assets/images/emojis/marseymobility.webp differ diff --git a/files/assets/images/emojis/marseymobster2.webp b/files/assets/images/emojis/marseymobster2.webp index 99d5a0d7f..edd133bea 100644 Binary files a/files/assets/images/emojis/marseymobster2.webp and b/files/assets/images/emojis/marseymobster2.webp differ diff --git a/files/assets/images/emojis/marseymocking.webp b/files/assets/images/emojis/marseymocking.webp index 2de422ef4..713baba14 100644 Binary files a/files/assets/images/emojis/marseymocking.webp and b/files/assets/images/emojis/marseymocking.webp differ diff --git a/files/assets/images/emojis/marseymodelo.webp b/files/assets/images/emojis/marseymodelo.webp index 79768d321..92b424890 100644 Binary files a/files/assets/images/emojis/marseymodelo.webp and b/files/assets/images/emojis/marseymodelo.webp differ diff --git a/files/assets/images/emojis/marseymodelo2.webp b/files/assets/images/emojis/marseymodelo2.webp index e584a181c..9ab77582d 100644 Binary files a/files/assets/images/emojis/marseymodelo2.webp and b/files/assets/images/emojis/marseymodelo2.webp differ diff --git a/files/assets/images/emojis/marseymommy.webp b/files/assets/images/emojis/marseymommy.webp index adcb58859..5cb90e12c 100644 Binary files a/files/assets/images/emojis/marseymommy.webp and b/files/assets/images/emojis/marseymommy.webp differ diff --git a/files/assets/images/emojis/marseymommymilkers.webp b/files/assets/images/emojis/marseymommymilkers.webp index fb8faa5ba..d5bdd5ed5 100644 Binary files a/files/assets/images/emojis/marseymommymilkers.webp and b/files/assets/images/emojis/marseymommymilkers.webp differ diff --git a/files/assets/images/emojis/marseymoney.webp b/files/assets/images/emojis/marseymoney.webp index 0d55db377..79cbc5f0f 100644 Binary files a/files/assets/images/emojis/marseymoney.webp and b/files/assets/images/emojis/marseymoney.webp differ diff --git a/files/assets/images/emojis/marseymonke.webp b/files/assets/images/emojis/marseymonke.webp index 204b1a040..dca79d4cd 100644 Binary files a/files/assets/images/emojis/marseymonke.webp and b/files/assets/images/emojis/marseymonke.webp differ diff --git a/files/assets/images/emojis/marseymononoke.webp b/files/assets/images/emojis/marseymononoke.webp index 83fb78173..2189a161a 100644 Binary files a/files/assets/images/emojis/marseymononoke.webp and b/files/assets/images/emojis/marseymononoke.webp differ diff --git a/files/assets/images/emojis/marseymoonshine.webp b/files/assets/images/emojis/marseymoonshine.webp new file mode 100644 index 000000000..6f90f4643 Binary files /dev/null and b/files/assets/images/emojis/marseymoonshine.webp differ diff --git a/files/assets/images/emojis/marseymoose.webp b/files/assets/images/emojis/marseymoose.webp index e844f267e..626eb2800 100644 Binary files a/files/assets/images/emojis/marseymoose.webp and b/files/assets/images/emojis/marseymoose.webp differ diff --git a/files/assets/images/emojis/marseymoplicker.webp b/files/assets/images/emojis/marseymoplicker.webp index 9a1ec9a5d..d23627f0c 100644 Binary files a/files/assets/images/emojis/marseymoplicker.webp and b/files/assets/images/emojis/marseymoplicker.webp differ diff --git a/files/assets/images/emojis/marseymormon.webp b/files/assets/images/emojis/marseymormon.webp index 320741752..5f0d8ac4f 100644 Binary files a/files/assets/images/emojis/marseymormon.webp and b/files/assets/images/emojis/marseymormon.webp differ diff --git a/files/assets/images/emojis/marseymorph.webp b/files/assets/images/emojis/marseymorph.webp index 34ff05c59..cc63d90a0 100644 Binary files a/files/assets/images/emojis/marseymorph.webp and b/files/assets/images/emojis/marseymorph.webp differ diff --git a/files/assets/images/emojis/marseymothermary.webp b/files/assets/images/emojis/marseymothermary.webp index 716ae32d6..112d4f44a 100644 Binary files a/files/assets/images/emojis/marseymothermary.webp and b/files/assets/images/emojis/marseymothermary.webp differ diff --git a/files/assets/images/emojis/marseymountaineer.webp b/files/assets/images/emojis/marseymountaineer.webp index 64bc35377..3f106c780 100644 Binary files a/files/assets/images/emojis/marseymountaineer.webp and b/files/assets/images/emojis/marseymountaineer.webp differ diff --git a/files/assets/images/emojis/marseymouse.webp b/files/assets/images/emojis/marseymouse.webp index 480aba8f1..e55098246 100644 Binary files a/files/assets/images/emojis/marseymouse.webp and b/files/assets/images/emojis/marseymouse.webp differ diff --git a/files/assets/images/emojis/marseymrsclaus.webp b/files/assets/images/emojis/marseymrsclaus.webp index d66e9b82d..9ccd6f852 100644 Binary files a/files/assets/images/emojis/marseymrsclaus.webp and b/files/assets/images/emojis/marseymrsclaus.webp differ diff --git a/files/assets/images/emojis/marseymspaint.webp b/files/assets/images/emojis/marseymspaint.webp index cb8ff318b..0d82c5273 100644 Binary files a/files/assets/images/emojis/marseymspaint.webp and b/files/assets/images/emojis/marseymspaint.webp differ diff --git a/files/assets/images/emojis/marseymugshot.webp b/files/assets/images/emojis/marseymugshot.webp index 9a9745259..f1bd6005c 100644 Binary files a/files/assets/images/emojis/marseymugshot.webp and b/files/assets/images/emojis/marseymugshot.webp differ diff --git a/files/assets/images/emojis/marseymummified.webp b/files/assets/images/emojis/marseymummified.webp index b3858a33d..df7b4b1cd 100644 Binary files a/files/assets/images/emojis/marseymummified.webp and b/files/assets/images/emojis/marseymummified.webp differ diff --git a/files/assets/images/emojis/marseymummy.webp b/files/assets/images/emojis/marseymummy.webp index 00cd223d6..63232b84e 100644 Binary files a/files/assets/images/emojis/marseymummy.webp and b/files/assets/images/emojis/marseymummy.webp differ diff --git a/files/assets/images/emojis/marseymummy2.webp b/files/assets/images/emojis/marseymummy2.webp index 24e47c2a9..09ea32cd9 100644 Binary files a/files/assets/images/emojis/marseymummy2.webp and b/files/assets/images/emojis/marseymummy2.webp differ diff --git a/files/assets/images/emojis/marseymummy3.webp b/files/assets/images/emojis/marseymummy3.webp index d14a8dd00..87c405158 100644 Binary files a/files/assets/images/emojis/marseymummy3.webp and b/files/assets/images/emojis/marseymummy3.webp differ diff --git a/files/assets/images/emojis/marseymushroomcloud.webp b/files/assets/images/emojis/marseymushroomcloud.webp index d72cef329..1fc12bd33 100644 Binary files a/files/assets/images/emojis/marseymushroomcloud.webp and b/files/assets/images/emojis/marseymushroomcloud.webp differ diff --git a/files/assets/images/emojis/marseymutt.webp b/files/assets/images/emojis/marseymutt.webp index 86739ac03..153051acf 100644 Binary files a/files/assets/images/emojis/marseymutt.webp and b/files/assets/images/emojis/marseymutt.webp differ diff --git a/files/assets/images/emojis/marseymutt2.webp b/files/assets/images/emojis/marseymutt2.webp index df9279183..6af337843 100644 Binary files a/files/assets/images/emojis/marseymutt2.webp and b/files/assets/images/emojis/marseymutt2.webp differ diff --git a/files/assets/images/emojis/marseymyeisha.webp b/files/assets/images/emojis/marseymyeisha.webp index 8e87c0f94..1897889bf 100644 Binary files a/files/assets/images/emojis/marseymyeisha.webp and b/files/assets/images/emojis/marseymyeisha.webp differ diff --git a/files/assets/images/emojis/marseymyers.webp b/files/assets/images/emojis/marseymyers.webp new file mode 100644 index 000000000..535cf9eb3 Binary files /dev/null and b/files/assets/images/emojis/marseymyers.webp differ diff --git a/files/assets/images/emojis/marseymyspacetom.webp b/files/assets/images/emojis/marseymyspacetom.webp index e1a40ddb2..49653f1f7 100644 Binary files a/files/assets/images/emojis/marseymyspacetom.webp and b/files/assets/images/emojis/marseymyspacetom.webp differ diff --git a/files/assets/images/emojis/marseyn8.webp b/files/assets/images/emojis/marseyn8.webp index 7b305fc67..33bb226ba 100644 Binary files a/files/assets/images/emojis/marseyn8.webp and b/files/assets/images/emojis/marseyn8.webp differ diff --git a/files/assets/images/emojis/marseynails.webp b/files/assets/images/emojis/marseynails.webp index fd85a5a85..f4fe8e0e4 100644 Binary files a/files/assets/images/emojis/marseynails.webp and b/files/assets/images/emojis/marseynails.webp differ diff --git a/files/assets/images/emojis/marseynapoleon.webp b/files/assets/images/emojis/marseynapoleon.webp index 64daeb17b..ee4a37648 100644 Binary files a/files/assets/images/emojis/marseynapoleon.webp and b/files/assets/images/emojis/marseynapoleon.webp differ diff --git a/files/assets/images/emojis/marseynapoleon2.webp b/files/assets/images/emojis/marseynapoleon2.webp index 3c9d6d7e9..5fd3ed38c 100644 Binary files a/files/assets/images/emojis/marseynapoleon2.webp and b/files/assets/images/emojis/marseynapoleon2.webp differ diff --git a/files/assets/images/emojis/marseyneat.webp b/files/assets/images/emojis/marseyneat.webp index 6d272d62a..a036cf9a2 100644 Binary files a/files/assets/images/emojis/marseyneat.webp and b/files/assets/images/emojis/marseyneat.webp differ diff --git a/files/assets/images/emojis/marseyneckbeard.webp b/files/assets/images/emojis/marseyneckbeard.webp index 032d0e324..9670dd490 100644 Binary files a/files/assets/images/emojis/marseyneckbeard.webp and b/files/assets/images/emojis/marseyneckbeard.webp differ diff --git a/files/assets/images/emojis/marseyneet.webp b/files/assets/images/emojis/marseyneet.webp index 5f196a650..1715bacb1 100644 Binary files a/files/assets/images/emojis/marseyneet.webp and b/files/assets/images/emojis/marseyneet.webp differ diff --git a/files/assets/images/emojis/marseyneko.webp b/files/assets/images/emojis/marseyneko.webp index 537ca3b37..f9a827092 100644 Binary files a/files/assets/images/emojis/marseyneko.webp and b/files/assets/images/emojis/marseyneko.webp differ diff --git a/files/assets/images/emojis/marseynerd.webp b/files/assets/images/emojis/marseynerd.webp index 5b1dbb8b4..a5839085a 100644 Binary files a/files/assets/images/emojis/marseynerd.webp and b/files/assets/images/emojis/marseynerd.webp differ diff --git a/files/assets/images/emojis/marseynerd2.webp b/files/assets/images/emojis/marseynerd2.webp index 68f0fa8cd..d121c7a7e 100644 Binary files a/files/assets/images/emojis/marseynerd2.webp and b/files/assets/images/emojis/marseynerd2.webp differ diff --git a/files/assets/images/emojis/marseynewyorker.webp b/files/assets/images/emojis/marseynewyorker.webp new file mode 100644 index 000000000..4a98bd3e6 Binary files /dev/null and b/files/assets/images/emojis/marseynewyorker.webp differ diff --git a/files/assets/images/emojis/marseynietzsche.webp b/files/assets/images/emojis/marseynietzsche.webp index c0bdf3b11..1198c2878 100644 Binary files a/files/assets/images/emojis/marseynietzsche.webp and b/files/assets/images/emojis/marseynietzsche.webp differ diff --git a/files/assets/images/emojis/marseyniggy.webp b/files/assets/images/emojis/marseyniggy.webp index 92ba989af..37f4ad1b8 100644 Binary files a/files/assets/images/emojis/marseyniggy.webp and b/files/assets/images/emojis/marseyniggy.webp differ diff --git a/files/assets/images/emojis/marseynightmare.webp b/files/assets/images/emojis/marseynightmare.webp index 961d8c082..0cfe18c2d 100644 Binary files a/files/assets/images/emojis/marseynightmare.webp and b/files/assets/images/emojis/marseynightmare.webp differ diff --git a/files/assets/images/emojis/marseyninja.webp b/files/assets/images/emojis/marseyninja.webp index da01e5fc2..d359317eb 100644 Binary files a/files/assets/images/emojis/marseyninja.webp and b/files/assets/images/emojis/marseyninja.webp differ diff --git a/files/assets/images/emojis/marseynintendo.webp b/files/assets/images/emojis/marseynintendo.webp index fa05125be..fda3298cf 100644 Binary files a/files/assets/images/emojis/marseynintendo.webp and b/files/assets/images/emojis/marseynintendo.webp differ diff --git a/files/assets/images/emojis/marseyniqab.webp b/files/assets/images/emojis/marseyniqab.webp index e4b19ef4f..3efbe9021 100644 Binary files a/files/assets/images/emojis/marseyniqab.webp and b/files/assets/images/emojis/marseyniqab.webp differ diff --git a/files/assets/images/emojis/marseyno.webp b/files/assets/images/emojis/marseyno.webp index 9df2d3851..57ac79c42 100644 Binary files a/files/assets/images/emojis/marseyno.webp and b/files/assets/images/emojis/marseyno.webp differ diff --git a/files/assets/images/emojis/marseynodox.webp b/files/assets/images/emojis/marseynodox.webp index 442266284..1d29233ce 100644 Binary files a/files/assets/images/emojis/marseynodox.webp and b/files/assets/images/emojis/marseynodox.webp differ diff --git a/files/assets/images/emojis/marseynooo.webp b/files/assets/images/emojis/marseynooo.webp index e36612831..b28928676 100644 Binary files a/files/assets/images/emojis/marseynooo.webp and b/files/assets/images/emojis/marseynooo.webp differ diff --git a/files/assets/images/emojis/marseynoooticer.webp b/files/assets/images/emojis/marseynoooticer.webp index 926707c45..361aee643 100644 Binary files a/files/assets/images/emojis/marseynoooticer.webp and b/files/assets/images/emojis/marseynoooticer.webp differ diff --git a/files/assets/images/emojis/marseynope.webp b/files/assets/images/emojis/marseynope.webp index 235d8397b..851e5ce69 100644 Binary files a/files/assets/images/emojis/marseynope.webp and b/files/assets/images/emojis/marseynope.webp differ diff --git a/files/assets/images/emojis/marseynosleep.webp b/files/assets/images/emojis/marseynosleep.webp index 02b3c7dfc..8eabbdff6 100644 Binary files a/files/assets/images/emojis/marseynosleep.webp and b/files/assets/images/emojis/marseynosleep.webp differ diff --git a/files/assets/images/emojis/marseynotes.webp b/files/assets/images/emojis/marseynotes.webp index e9397c46a..bb8d63e38 100644 Binary files a/files/assets/images/emojis/marseynotes.webp and b/files/assets/images/emojis/marseynotes.webp differ diff --git a/files/assets/images/emojis/marseynotes2.webp b/files/assets/images/emojis/marseynotes2.webp index 5a98e4cc4..8cba5d0db 100644 Binary files a/files/assets/images/emojis/marseynotes2.webp and b/files/assets/images/emojis/marseynotes2.webp differ diff --git a/files/assets/images/emojis/marseynotesglow.webp b/files/assets/images/emojis/marseynotesglow.webp index 7893fcf02..65b68c06e 100644 Binary files a/files/assets/images/emojis/marseynotesglow.webp and b/files/assets/images/emojis/marseynotesglow.webp differ diff --git a/files/assets/images/emojis/marseynouautism.webp b/files/assets/images/emojis/marseynouautism.webp index 2866a95f0..ecaa4887d 100644 Binary files a/files/assets/images/emojis/marseynouautism.webp and b/files/assets/images/emojis/marseynouautism.webp differ diff --git a/files/assets/images/emojis/marseynoyou.webp b/files/assets/images/emojis/marseynoyou.webp index 6e196b699..c49aab05e 100644 Binary files a/files/assets/images/emojis/marseynoyou.webp and b/files/assets/images/emojis/marseynoyou.webp differ diff --git a/files/assets/images/emojis/marseynoyoufellowpedo.webp b/files/assets/images/emojis/marseynoyoufellowpedo.webp index 3870b8cea..0b5ff1d49 100644 Binary files a/files/assets/images/emojis/marseynoyoufellowpedo.webp and b/files/assets/images/emojis/marseynoyoufellowpedo.webp differ diff --git a/files/assets/images/emojis/marseynpc.webp b/files/assets/images/emojis/marseynpc.webp index 71c14422f..b41a93cee 100644 Binary files a/files/assets/images/emojis/marseynpc.webp and b/files/assets/images/emojis/marseynpc.webp differ diff --git a/files/assets/images/emojis/marseynpc2.webp b/files/assets/images/emojis/marseynpc2.webp index aa67fa20c..81a5c8afa 100644 Binary files a/files/assets/images/emojis/marseynpc2.webp and b/files/assets/images/emojis/marseynpc2.webp differ diff --git a/files/assets/images/emojis/marseynpcmad.webp b/files/assets/images/emojis/marseynpcmad.webp index 778e30f3c..25f4597a5 100644 Binary files a/files/assets/images/emojis/marseynpcmad.webp and b/files/assets/images/emojis/marseynpcmad.webp differ diff --git a/files/assets/images/emojis/marseynukegoggles.webp b/files/assets/images/emojis/marseynukegoggles.webp index 0d1e5b695..20e834e19 100644 Binary files a/files/assets/images/emojis/marseynukegoggles.webp and b/files/assets/images/emojis/marseynukegoggles.webp differ diff --git a/files/assets/images/emojis/marseynull.webp b/files/assets/images/emojis/marseynull.webp index 33aac76d3..18e240a01 100644 Binary files a/files/assets/images/emojis/marseynull.webp and b/files/assets/images/emojis/marseynull.webp differ diff --git a/files/assets/images/emojis/marseynun.webp b/files/assets/images/emojis/marseynun.webp index f9bcbbc2c..46bc36be5 100644 Binary files a/files/assets/images/emojis/marseynun.webp and b/files/assets/images/emojis/marseynun.webp differ diff --git a/files/assets/images/emojis/marseynurgle.webp b/files/assets/images/emojis/marseynurgle.webp index a04cf1343..ca80a0306 100644 Binary files a/files/assets/images/emojis/marseynurgle.webp and b/files/assets/images/emojis/marseynurgle.webp differ diff --git a/files/assets/images/emojis/marseynut.webp b/files/assets/images/emojis/marseynut.webp index 4bb4de143..86d3baeaa 100644 Binary files a/files/assets/images/emojis/marseynut.webp and b/files/assets/images/emojis/marseynut.webp differ diff --git a/files/assets/images/emojis/marseynutcracker.webp b/files/assets/images/emojis/marseynutcracker.webp index b90e475d7..5298264b4 100644 Binary files a/files/assets/images/emojis/marseynutcracker.webp and b/files/assets/images/emojis/marseynutcracker.webp differ diff --git a/files/assets/images/emojis/marseyobama.webp b/files/assets/images/emojis/marseyobama.webp index d21ff8c43..1b218781d 100644 Binary files a/files/assets/images/emojis/marseyobama.webp and b/files/assets/images/emojis/marseyobama.webp differ diff --git a/files/assets/images/emojis/marseyobamacope.webp b/files/assets/images/emojis/marseyobamacope.webp index a1eb81005..4c7fdd7dc 100644 Binary files a/files/assets/images/emojis/marseyobamacope.webp and b/files/assets/images/emojis/marseyobamacope.webp differ diff --git a/files/assets/images/emojis/marseyobamahope.webp b/files/assets/images/emojis/marseyobamahope.webp index 8eb390364..4fd6d7e8e 100644 Binary files a/files/assets/images/emojis/marseyobamahope.webp and b/files/assets/images/emojis/marseyobamahope.webp differ diff --git a/files/assets/images/emojis/marseyobamanope.webp b/files/assets/images/emojis/marseyobamanope.webp index 543f40f40..d23ac190f 100644 Binary files a/files/assets/images/emojis/marseyobamanope.webp and b/files/assets/images/emojis/marseyobamanope.webp differ diff --git a/files/assets/images/emojis/marseyobamarope.webp b/files/assets/images/emojis/marseyobamarope.webp index 9653d84cd..06c8cf301 100644 Binary files a/files/assets/images/emojis/marseyobamarope.webp and b/files/assets/images/emojis/marseyobamarope.webp differ diff --git a/files/assets/images/emojis/marseyobese.webp b/files/assets/images/emojis/marseyobese.webp index eaefa8f67..49c90aec8 100644 Binary files a/files/assets/images/emojis/marseyobese.webp and b/files/assets/images/emojis/marseyobese.webp differ diff --git a/files/assets/images/emojis/marseyobesescale.webp b/files/assets/images/emojis/marseyobesescale.webp index b37c8b9f6..0b5cab07e 100644 Binary files a/files/assets/images/emojis/marseyobesescale.webp and b/files/assets/images/emojis/marseyobesescale.webp differ diff --git a/files/assets/images/emojis/marseyobey.webp b/files/assets/images/emojis/marseyobey.webp index 6c1029712..877730735 100644 Binary files a/files/assets/images/emojis/marseyobey.webp and b/files/assets/images/emojis/marseyobey.webp differ diff --git a/files/assets/images/emojis/marseyobjection.webp b/files/assets/images/emojis/marseyobjection.webp new file mode 100644 index 000000000..025e6b8d9 Binary files /dev/null and b/files/assets/images/emojis/marseyobjection.webp differ diff --git a/files/assets/images/emojis/marseyoceania.webp b/files/assets/images/emojis/marseyoceania.webp index cd2d6d020..a6c4ee9fe 100644 Binary files a/files/assets/images/emojis/marseyoceania.webp and b/files/assets/images/emojis/marseyoceania.webp differ diff --git a/files/assets/images/emojis/marseyoctopus.webp b/files/assets/images/emojis/marseyoctopus.webp index e70395a39..3e6146797 100644 Binary files a/files/assets/images/emojis/marseyoctopus.webp and b/files/assets/images/emojis/marseyoctopus.webp differ diff --git a/files/assets/images/emojis/marseyoctopus2.webp b/files/assets/images/emojis/marseyoctopus2.webp index b1fe3dddb..2658629ce 100644 Binary files a/files/assets/images/emojis/marseyoctopus2.webp and b/files/assets/images/emojis/marseyoctopus2.webp differ diff --git a/files/assets/images/emojis/marseyoctopus3.webp b/files/assets/images/emojis/marseyoctopus3.webp index 7efaa1d17..d5889e88c 100644 Binary files a/files/assets/images/emojis/marseyoctopus3.webp and b/files/assets/images/emojis/marseyoctopus3.webp differ diff --git a/files/assets/images/emojis/marseyoctopus4.webp b/files/assets/images/emojis/marseyoctopus4.webp index 21eda4ea0..64ec22b7d 100644 Binary files a/files/assets/images/emojis/marseyoctopus4.webp and b/files/assets/images/emojis/marseyoctopus4.webp differ diff --git a/files/assets/images/emojis/marseyohno.webp b/files/assets/images/emojis/marseyohno.webp index 3ead788b8..0fdcf684d 100644 Binary files a/files/assets/images/emojis/marseyohno.webp and b/files/assets/images/emojis/marseyohno.webp differ diff --git a/files/assets/images/emojis/marseyokapi.webp b/files/assets/images/emojis/marseyokapi.webp index e5b55b55f..14e66eb5b 100644 Binary files a/files/assets/images/emojis/marseyokapi.webp and b/files/assets/images/emojis/marseyokapi.webp differ diff --git a/files/assets/images/emojis/marseyokay.webp b/files/assets/images/emojis/marseyokay.webp new file mode 100644 index 000000000..c1c7c837e Binary files /dev/null and b/files/assets/images/emojis/marseyokay.webp differ diff --git a/files/assets/images/emojis/marseyokaymilk.webp b/files/assets/images/emojis/marseyokaymilk.webp new file mode 100644 index 000000000..f03871b8f Binary files /dev/null and b/files/assets/images/emojis/marseyokaymilk.webp differ diff --git a/files/assets/images/emojis/marseyolantern.webp b/files/assets/images/emojis/marseyolantern.webp index f6611fa78..06258f554 100644 Binary files a/files/assets/images/emojis/marseyolantern.webp and b/files/assets/images/emojis/marseyolantern.webp differ diff --git a/files/assets/images/emojis/marseyoldguard.webp b/files/assets/images/emojis/marseyoldguard.webp index 69e2c437d..55649d561 100644 Binary files a/files/assets/images/emojis/marseyoldguard.webp and b/files/assets/images/emojis/marseyoldguard.webp differ diff --git a/files/assets/images/emojis/marseyoldtimey.webp b/files/assets/images/emojis/marseyoldtimey.webp index 503fac580..3d51f6c78 100644 Binary files a/files/assets/images/emojis/marseyoldtimey.webp and b/files/assets/images/emojis/marseyoldtimey.webp differ diff --git a/files/assets/images/emojis/marseyoperaphantom.webp b/files/assets/images/emojis/marseyoperaphantom.webp index e98ebc430..e458c8447 100644 Binary files a/files/assets/images/emojis/marseyoperaphantom.webp and b/files/assets/images/emojis/marseyoperaphantom.webp differ diff --git a/files/assets/images/emojis/marseyopossum.webp b/files/assets/images/emojis/marseyopossum.webp index 6a4a7c7e3..4763f7dd4 100644 Binary files a/files/assets/images/emojis/marseyopossum.webp and b/files/assets/images/emojis/marseyopossum.webp differ diff --git a/files/assets/images/emojis/marseyoppenheimer.webp b/files/assets/images/emojis/marseyoppenheimer.webp index 584f16035..4d4374ffa 100644 Binary files a/files/assets/images/emojis/marseyoppenheimer.webp and b/files/assets/images/emojis/marseyoppenheimer.webp differ diff --git a/files/assets/images/emojis/marseyorca.webp b/files/assets/images/emojis/marseyorca.webp index e23078658..bea4ca7de 100644 Binary files a/files/assets/images/emojis/marseyorca.webp and b/files/assets/images/emojis/marseyorca.webp differ diff --git a/files/assets/images/emojis/marseyorthodox.webp b/files/assets/images/emojis/marseyorthodox.webp index d489a670d..05be785d2 100644 Binary files a/files/assets/images/emojis/marseyorthodox.webp and b/files/assets/images/emojis/marseyorthodox.webp differ diff --git a/files/assets/images/emojis/marseyorthodoxbrap.webp b/files/assets/images/emojis/marseyorthodoxbrap.webp index 76005c916..f4ed35192 100644 Binary files a/files/assets/images/emojis/marseyorthodoxbrap.webp and b/files/assets/images/emojis/marseyorthodoxbrap.webp differ diff --git a/files/assets/images/emojis/marseyorthodoxcarphug.webp b/files/assets/images/emojis/marseyorthodoxcarphug.webp index 897df080a..00208e5b7 100644 Binary files a/files/assets/images/emojis/marseyorthodoxcarphug.webp and b/files/assets/images/emojis/marseyorthodoxcarphug.webp differ diff --git a/files/assets/images/emojis/marseyorthodoxsmug.webp b/files/assets/images/emojis/marseyorthodoxsmug.webp index b18efa066..c25d25258 100644 Binary files a/files/assets/images/emojis/marseyorthodoxsmug.webp and b/files/assets/images/emojis/marseyorthodoxsmug.webp differ diff --git a/files/assets/images/emojis/marseyotter.webp b/files/assets/images/emojis/marseyotter.webp index f89a89913..2b9931456 100644 Binary files a/files/assets/images/emojis/marseyotter.webp and b/files/assets/images/emojis/marseyotter.webp differ diff --git a/files/assets/images/emojis/marseyouroboros.webp b/files/assets/images/emojis/marseyouroboros.webp new file mode 100644 index 000000000..194b398b8 Binary files /dev/null and b/files/assets/images/emojis/marseyouroboros.webp differ diff --git a/files/assets/images/emojis/marseyoutletsuicide.webp b/files/assets/images/emojis/marseyoutletsuicide.webp index c37041331..cb091bc27 100644 Binary files a/files/assets/images/emojis/marseyoutletsuicide.webp and b/files/assets/images/emojis/marseyoutletsuicide.webp differ diff --git a/files/assets/images/emojis/marseyoutline.webp b/files/assets/images/emojis/marseyoutline.webp index 923051e7d..a4c29f070 100644 Binary files a/files/assets/images/emojis/marseyoutline.webp and b/files/assets/images/emojis/marseyoutline.webp differ diff --git a/files/assets/images/emojis/marseyoverseether.webp b/files/assets/images/emojis/marseyoverseether.webp index 012d354fd..65570a592 100644 Binary files a/files/assets/images/emojis/marseyoverseether.webp and b/files/assets/images/emojis/marseyoverseether.webp differ diff --git a/files/assets/images/emojis/marseyowow.webp b/files/assets/images/emojis/marseyowow.webp index cee604467..1ffe0a4f9 100644 Binary files a/files/assets/images/emojis/marseyowow.webp and b/files/assets/images/emojis/marseyowow.webp differ diff --git a/files/assets/images/emojis/marseyoyster.webp b/files/assets/images/emojis/marseyoyster.webp index 6ed325e0d..01c247cdf 100644 Binary files a/files/assets/images/emojis/marseyoyster.webp and b/files/assets/images/emojis/marseyoyster.webp differ diff --git a/files/assets/images/emojis/marseypadoru.webp b/files/assets/images/emojis/marseypadoru.webp index 03f387ab6..b20213676 100644 Binary files a/files/assets/images/emojis/marseypadoru.webp and b/files/assets/images/emojis/marseypadoru.webp differ diff --git a/files/assets/images/emojis/marseypain.webp b/files/assets/images/emojis/marseypain.webp index a8cd45913..444376802 100644 Binary files a/files/assets/images/emojis/marseypain.webp and b/files/assets/images/emojis/marseypain.webp differ diff --git a/files/assets/images/emojis/marseypaint.webp b/files/assets/images/emojis/marseypaint.webp index 7189350a5..2ecb5b8d2 100644 Binary files a/files/assets/images/emojis/marseypaint.webp and b/files/assets/images/emojis/marseypaint.webp differ diff --git a/files/assets/images/emojis/marseypainter.webp b/files/assets/images/emojis/marseypainter.webp index ebe8e9240..327b8da54 100644 Binary files a/files/assets/images/emojis/marseypainter.webp and b/files/assets/images/emojis/marseypainter.webp differ diff --git a/files/assets/images/emojis/marseypaintretard.webp b/files/assets/images/emojis/marseypaintretard.webp index cf3bb0a64..bbc157d39 100644 Binary files a/files/assets/images/emojis/marseypaintretard.webp and b/files/assets/images/emojis/marseypaintretard.webp differ diff --git a/files/assets/images/emojis/marseypajeet.webp b/files/assets/images/emojis/marseypajeet.webp index a2c6fdd86..f5f3d7db0 100644 Binary files a/files/assets/images/emojis/marseypajeet.webp and b/files/assets/images/emojis/marseypajeet.webp differ diff --git a/files/assets/images/emojis/marseypanafricanism.webp b/files/assets/images/emojis/marseypanafricanism.webp index eae46c048..b2faa1ff6 100644 Binary files a/files/assets/images/emojis/marseypanafricanism.webp and b/files/assets/images/emojis/marseypanafricanism.webp differ diff --git a/files/assets/images/emojis/marseypanda.webp b/files/assets/images/emojis/marseypanda.webp index 4d94a6225..dc1ca07b0 100644 Binary files a/files/assets/images/emojis/marseypanda.webp and b/files/assets/images/emojis/marseypanda.webp differ diff --git a/files/assets/images/emojis/marseypanda2.webp b/files/assets/images/emojis/marseypanda2.webp index 2aee4e9ed..d7c95c1a5 100644 Binary files a/files/assets/images/emojis/marseypanda2.webp and b/files/assets/images/emojis/marseypanda2.webp differ diff --git a/files/assets/images/emojis/marseypanties.webp b/files/assets/images/emojis/marseypanties.webp index 7763017dd..3d56a2bc9 100644 Binary files a/files/assets/images/emojis/marseypanties.webp and b/files/assets/images/emojis/marseypanties.webp differ diff --git a/files/assets/images/emojis/marseypaperbag.webp b/files/assets/images/emojis/marseypaperbag.webp index 5a86bd109..26fa71a1e 100644 Binary files a/files/assets/images/emojis/marseypaperbag.webp and b/files/assets/images/emojis/marseypaperbag.webp differ diff --git a/files/assets/images/emojis/marseyparty.webp b/files/assets/images/emojis/marseyparty.webp index bf6636354..0e1e9f772 100644 Binary files a/files/assets/images/emojis/marseyparty.webp and b/files/assets/images/emojis/marseyparty.webp differ diff --git a/files/assets/images/emojis/marseypass.webp b/files/assets/images/emojis/marseypass.webp index 98913081d..08b619db9 100644 Binary files a/files/assets/images/emojis/marseypass.webp and b/files/assets/images/emojis/marseypass.webp differ diff --git a/files/assets/images/emojis/marseypass2.webp b/files/assets/images/emojis/marseypass2.webp index ade112fc4..78db73654 100644 Binary files a/files/assets/images/emojis/marseypass2.webp and b/files/assets/images/emojis/marseypass2.webp differ diff --git a/files/assets/images/emojis/marseypastor.webp b/files/assets/images/emojis/marseypastor.webp index 9ca1dc4b6..a84102e5e 100644 Binary files a/files/assets/images/emojis/marseypastor.webp and b/files/assets/images/emojis/marseypastor.webp differ diff --git a/files/assets/images/emojis/marseypathetic.webp b/files/assets/images/emojis/marseypathetic.webp index 14e7ac336..ba050e6d5 100644 Binary files a/files/assets/images/emojis/marseypathetic.webp and b/files/assets/images/emojis/marseypathetic.webp differ diff --git a/files/assets/images/emojis/marseypathetic2.webp b/files/assets/images/emojis/marseypathetic2.webp index 5858dc792..3bf42f55d 100644 Binary files a/files/assets/images/emojis/marseypathetic2.webp and b/files/assets/images/emojis/marseypathetic2.webp differ diff --git a/files/assets/images/emojis/marseypatriot.webp b/files/assets/images/emojis/marseypatriot.webp index 185ef7385..00812674c 100644 Binary files a/files/assets/images/emojis/marseypatriot.webp and b/files/assets/images/emojis/marseypatriot.webp differ diff --git a/files/assets/images/emojis/marseypeace.webp b/files/assets/images/emojis/marseypeace.webp index 9e04756bc..a1c4df0e3 100644 Binary files a/files/assets/images/emojis/marseypeace.webp and b/files/assets/images/emojis/marseypeace.webp differ diff --git a/files/assets/images/emojis/marseypeacekeeper.webp b/files/assets/images/emojis/marseypeacekeeper.webp index e795f0749..8a52e69d4 100644 Binary files a/files/assets/images/emojis/marseypeacekeeper.webp and b/files/assets/images/emojis/marseypeacekeeper.webp differ diff --git a/files/assets/images/emojis/marseypearlclutch.webp b/files/assets/images/emojis/marseypearlclutch.webp index efea2f6a0..a226b9b57 100644 Binary files a/files/assets/images/emojis/marseypearlclutch.webp and b/files/assets/images/emojis/marseypearlclutch.webp differ diff --git a/files/assets/images/emojis/marseypearlclutch2.webp b/files/assets/images/emojis/marseypearlclutch2.webp index 00013ca6e..3385ddbda 100644 Binary files a/files/assets/images/emojis/marseypearlclutch2.webp and b/files/assets/images/emojis/marseypearlclutch2.webp differ diff --git a/files/assets/images/emojis/marseypedo.webp b/files/assets/images/emojis/marseypedo.webp index 3fd3b3a75..1ee6a0ad1 100644 Binary files a/files/assets/images/emojis/marseypedo.webp and b/files/assets/images/emojis/marseypedo.webp differ diff --git a/files/assets/images/emojis/marseypedobear.webp b/files/assets/images/emojis/marseypedobear.webp index 22066f791..501e4e042 100644 Binary files a/files/assets/images/emojis/marseypedobear.webp and b/files/assets/images/emojis/marseypedobear.webp differ diff --git a/files/assets/images/emojis/marseypedosnipe.webp b/files/assets/images/emojis/marseypedosnipe.webp index 6dadf2d9c..d0a796a4c 100644 Binary files a/files/assets/images/emojis/marseypedosnipe.webp and b/files/assets/images/emojis/marseypedosnipe.webp differ diff --git a/files/assets/images/emojis/marseypedosuicide.webp b/files/assets/images/emojis/marseypedosuicide.webp index dfac4dff3..09ee7e78f 100644 Binary files a/files/assets/images/emojis/marseypedosuicide.webp and b/files/assets/images/emojis/marseypedosuicide.webp differ diff --git a/files/assets/images/emojis/marseypenguin.webp b/files/assets/images/emojis/marseypenguin.webp index 0fe3b66de..fa712ad86 100644 Binary files a/files/assets/images/emojis/marseypenguin.webp and b/files/assets/images/emojis/marseypenguin.webp differ diff --git a/files/assets/images/emojis/marseypenny.webp b/files/assets/images/emojis/marseypenny.webp index 14695d34f..1c49e9469 100644 Binary files a/files/assets/images/emojis/marseypenny.webp and b/files/assets/images/emojis/marseypenny.webp differ diff --git a/files/assets/images/emojis/marseypennyboo.webp b/files/assets/images/emojis/marseypennyboo.webp index 9a13c010c..59c08e071 100644 Binary files a/files/assets/images/emojis/marseypennyboo.webp and b/files/assets/images/emojis/marseypennyboo.webp differ diff --git a/files/assets/images/emojis/marseypennylove.webp b/files/assets/images/emojis/marseypennylove.webp index 00ddbc685..f1d5fc949 100644 Binary files a/files/assets/images/emojis/marseypennylove.webp and b/files/assets/images/emojis/marseypennylove.webp differ diff --git a/files/assets/images/emojis/marseypentagram.webp b/files/assets/images/emojis/marseypentagram.webp index 44bf95baa..2d36014c9 100644 Binary files a/files/assets/images/emojis/marseypentagram.webp and b/files/assets/images/emojis/marseypentagram.webp differ diff --git a/files/assets/images/emojis/marseypepe.webp b/files/assets/images/emojis/marseypepe.webp index 992c0aabd..5111c9b69 100644 Binary files a/files/assets/images/emojis/marseypepe.webp and b/files/assets/images/emojis/marseypepe.webp differ diff --git a/files/assets/images/emojis/marseypepe2.webp b/files/assets/images/emojis/marseypepe2.webp index 9c84045c7..e2f0b1c0d 100644 Binary files a/files/assets/images/emojis/marseypepe2.webp and b/files/assets/images/emojis/marseypepe2.webp differ diff --git a/files/assets/images/emojis/marseypepekittypet.webp b/files/assets/images/emojis/marseypepekittypet.webp index 91de80b7c..35a8c880d 100644 Binary files a/files/assets/images/emojis/marseypepekittypet.webp and b/files/assets/images/emojis/marseypepekittypet.webp differ diff --git a/files/assets/images/emojis/marseypepsi.webp b/files/assets/images/emojis/marseypepsi.webp index c57cc90da..06a7927ac 100644 Binary files a/files/assets/images/emojis/marseypepsi.webp and b/files/assets/images/emojis/marseypepsi.webp differ diff --git a/files/assets/images/emojis/marseyperiod.webp b/files/assets/images/emojis/marseyperiod.webp index 93d56c0c0..2387b1289 100644 Binary files a/files/assets/images/emojis/marseyperiod.webp and b/files/assets/images/emojis/marseyperiod.webp differ diff --git a/files/assets/images/emojis/marseypeterson.webp b/files/assets/images/emojis/marseypeterson.webp new file mode 100644 index 000000000..84a2efaa1 Binary files /dev/null and b/files/assets/images/emojis/marseypeterson.webp differ diff --git a/files/assets/images/emojis/marseypharaoh.webp b/files/assets/images/emojis/marseypharaoh.webp index 635b2bbd2..3a8bcf0a1 100644 Binary files a/files/assets/images/emojis/marseypharaoh.webp and b/files/assets/images/emojis/marseypharaoh.webp differ diff --git a/files/assets/images/emojis/marseypharaohcat.webp b/files/assets/images/emojis/marseypharaohcat.webp index 25a607359..b081202af 100644 Binary files a/files/assets/images/emojis/marseypharaohcat.webp and b/files/assets/images/emojis/marseypharaohcat.webp differ diff --git a/files/assets/images/emojis/marseypharoah.webp b/files/assets/images/emojis/marseypharoah.webp index 635b2bbd2..3a8bcf0a1 100644 Binary files a/files/assets/images/emojis/marseypharoah.webp and b/files/assets/images/emojis/marseypharoah.webp differ diff --git a/files/assets/images/emojis/marseyphonecall.webp b/files/assets/images/emojis/marseyphonecall.webp index 2c0220290..0de9a16d2 100644 Binary files a/files/assets/images/emojis/marseyphonecall.webp and b/files/assets/images/emojis/marseyphonecall.webp differ diff --git a/files/assets/images/emojis/marseypickle.webp b/files/assets/images/emojis/marseypickle.webp index 050b9df8a..32bc06cdc 100644 Binary files a/files/assets/images/emojis/marseypickle.webp and b/files/assets/images/emojis/marseypickle.webp differ diff --git a/files/assets/images/emojis/marseypig.webp b/files/assets/images/emojis/marseypig.webp index 8f9f32c42..904402e66 100644 Binary files a/files/assets/images/emojis/marseypig.webp and b/files/assets/images/emojis/marseypig.webp differ diff --git a/files/assets/images/emojis/marseypikachu.webp b/files/assets/images/emojis/marseypikachu.webp index fcab67e11..de58e411f 100644 Binary files a/files/assets/images/emojis/marseypikachu.webp and b/files/assets/images/emojis/marseypikachu.webp differ diff --git a/files/assets/images/emojis/marseypikachu2.webp b/files/assets/images/emojis/marseypikachu2.webp index 9e33106c5..0e5951d7b 100644 Binary files a/files/assets/images/emojis/marseypikachu2.webp and b/files/assets/images/emojis/marseypikachu2.webp differ diff --git a/files/assets/images/emojis/marseypilgrim.webp b/files/assets/images/emojis/marseypilgrim.webp index e7ac2eba9..4437c0714 100644 Binary files a/files/assets/images/emojis/marseypilgrim.webp and b/files/assets/images/emojis/marseypilgrim.webp differ diff --git a/files/assets/images/emojis/marseypills.webp b/files/assets/images/emojis/marseypills.webp index 1693dcf92..79d58ca4f 100644 Binary files a/files/assets/images/emojis/marseypills.webp and b/files/assets/images/emojis/marseypills.webp differ diff --git a/files/assets/images/emojis/marseypimp.webp b/files/assets/images/emojis/marseypimp.webp index 3da7558f3..d25499933 100644 Binary files a/files/assets/images/emojis/marseypimp.webp and b/files/assets/images/emojis/marseypimp.webp differ diff --git a/files/assets/images/emojis/marseypin.webp b/files/assets/images/emojis/marseypin.webp index 9d67bb6a4..7df98111a 100644 Binary files a/files/assets/images/emojis/marseypin.webp and b/files/assets/images/emojis/marseypin.webp differ diff --git a/files/assets/images/emojis/marseypin2.webp b/files/assets/images/emojis/marseypin2.webp index 327e9646a..e5dc4a287 100644 Binary files a/files/assets/images/emojis/marseypin2.webp and b/files/assets/images/emojis/marseypin2.webp differ diff --git a/files/assets/images/emojis/marseypinkcat.webp b/files/assets/images/emojis/marseypinkcat.webp index 80ecb63ea..4000b7858 100644 Binary files a/files/assets/images/emojis/marseypinkcat.webp and b/files/assets/images/emojis/marseypinkcat.webp differ diff --git a/files/assets/images/emojis/marseypinkname.webp b/files/assets/images/emojis/marseypinkname.webp index e19c33580..fba5cbaa1 100644 Binary files a/files/assets/images/emojis/marseypinkname.webp and b/files/assets/images/emojis/marseypinkname.webp differ diff --git a/files/assets/images/emojis/marseypinkpanther.webp b/files/assets/images/emojis/marseypinkpanther.webp index 9e9bfc66d..b386ed078 100644 Binary files a/files/assets/images/emojis/marseypinkpanther.webp and b/files/assets/images/emojis/marseypinkpanther.webp differ diff --git a/files/assets/images/emojis/marseypinochet.webp b/files/assets/images/emojis/marseypinochet.webp index a273b574e..3c0b6e0d7 100644 Binary files a/files/assets/images/emojis/marseypinochet.webp and b/files/assets/images/emojis/marseypinochet.webp differ diff --git a/files/assets/images/emojis/marseypipe.webp b/files/assets/images/emojis/marseypipe.webp index 6891445fd..4b6fccbac 100644 Binary files a/files/assets/images/emojis/marseypipe.webp and b/files/assets/images/emojis/marseypipe.webp differ diff --git a/files/assets/images/emojis/marseypipebomb.webp b/files/assets/images/emojis/marseypipebomb.webp index 078a2b96a..2802f92ea 100644 Binary files a/files/assets/images/emojis/marseypipebomb.webp and b/files/assets/images/emojis/marseypipebomb.webp differ diff --git a/files/assets/images/emojis/marseypirate.webp b/files/assets/images/emojis/marseypirate.webp index 86d9e2df0..8e51bd023 100644 Binary files a/files/assets/images/emojis/marseypirate.webp and b/files/assets/images/emojis/marseypirate.webp differ diff --git a/files/assets/images/emojis/marseypizzashill.webp b/files/assets/images/emojis/marseypizzashill.webp index 651978097..36017efec 100644 Binary files a/files/assets/images/emojis/marseypizzashill.webp and b/files/assets/images/emojis/marseypizzashill.webp differ diff --git a/files/assets/images/emojis/marseypizzaslice.webp b/files/assets/images/emojis/marseypizzaslice.webp index 4acbe1d78..7202b5e1b 100644 Binary files a/files/assets/images/emojis/marseypizzaslice.webp and b/files/assets/images/emojis/marseypizzaslice.webp differ diff --git a/files/assets/images/emojis/marseyplace.webp b/files/assets/images/emojis/marseyplace.webp index 5cd742223..138f36ef1 100644 Binary files a/files/assets/images/emojis/marseyplace.webp and b/files/assets/images/emojis/marseyplace.webp differ diff --git a/files/assets/images/emojis/marseyplace2.webp b/files/assets/images/emojis/marseyplace2.webp index 6d2d56a0b..6c755ceac 100644 Binary files a/files/assets/images/emojis/marseyplace2.webp and b/files/assets/images/emojis/marseyplace2.webp differ diff --git a/files/assets/images/emojis/marseyplacenofun.webp b/files/assets/images/emojis/marseyplacenofun.webp index 697db84a0..cf82c632c 100644 Binary files a/files/assets/images/emojis/marseyplacenofun.webp and b/files/assets/images/emojis/marseyplacenofun.webp differ diff --git a/files/assets/images/emojis/marseyplane.webp b/files/assets/images/emojis/marseyplane.webp index b84073c68..8cd79bfb7 100644 Binary files a/files/assets/images/emojis/marseyplane.webp and b/files/assets/images/emojis/marseyplane.webp differ diff --git a/files/assets/images/emojis/marseyplaty.webp b/files/assets/images/emojis/marseyplaty.webp index ead7addc8..8bbde0569 100644 Binary files a/files/assets/images/emojis/marseyplaty.webp and b/files/assets/images/emojis/marseyplaty.webp differ diff --git a/files/assets/images/emojis/marseypleading.webp b/files/assets/images/emojis/marseypleading.webp index e0e458fd4..8783f6923 100644 Binary files a/files/assets/images/emojis/marseypleading.webp and b/files/assets/images/emojis/marseypleading.webp differ diff --git a/files/assets/images/emojis/marseypleading2.webp b/files/assets/images/emojis/marseypleading2.webp index db0c481a4..e38a34705 100644 Binary files a/files/assets/images/emojis/marseypleading2.webp and b/files/assets/images/emojis/marseypleading2.webp differ diff --git a/files/assets/images/emojis/marseyplugged.webp b/files/assets/images/emojis/marseyplugged.webp index d815686ce..db43196e9 100644 Binary files a/files/assets/images/emojis/marseyplugged.webp and b/files/assets/images/emojis/marseyplugged.webp differ diff --git a/files/assets/images/emojis/marseyplush.webp b/files/assets/images/emojis/marseyplush.webp index 4af947a4a..4aadc84d5 100644 Binary files a/files/assets/images/emojis/marseyplush.webp and b/files/assets/images/emojis/marseyplush.webp differ diff --git a/files/assets/images/emojis/marseyplushie.webp b/files/assets/images/emojis/marseyplushie.webp index ce2101587..69af79ea3 100644 Binary files a/files/assets/images/emojis/marseyplushie.webp and b/files/assets/images/emojis/marseyplushie.webp differ diff --git a/files/assets/images/emojis/marseypoggers.webp b/files/assets/images/emojis/marseypoggers.webp index e11747462..423592d67 100644 Binary files a/files/assets/images/emojis/marseypoggers.webp and b/files/assets/images/emojis/marseypoggers.webp differ diff --git a/files/assets/images/emojis/marseypokerface.webp b/files/assets/images/emojis/marseypokerface.webp index 26a3145b2..662258eae 100644 Binary files a/files/assets/images/emojis/marseypokerface.webp and b/files/assets/images/emojis/marseypokerface.webp differ diff --git a/files/assets/images/emojis/marseypolarbear.webp b/files/assets/images/emojis/marseypolarbear.webp index e7a2a147e..1619e6385 100644 Binary files a/files/assets/images/emojis/marseypolarbear.webp and b/files/assets/images/emojis/marseypolarbear.webp differ diff --git a/files/assets/images/emojis/marseyponder.webp b/files/assets/images/emojis/marseyponder.webp index 7da51234b..e50ab42d1 100644 Binary files a/files/assets/images/emojis/marseyponder.webp and b/files/assets/images/emojis/marseyponder.webp differ diff --git a/files/assets/images/emojis/marseypony.webp b/files/assets/images/emojis/marseypony.webp index 68c647db1..a8d6f6fc6 100644 Binary files a/files/assets/images/emojis/marseypony.webp and b/files/assets/images/emojis/marseypony.webp differ diff --git a/files/assets/images/emojis/marseypoor.webp b/files/assets/images/emojis/marseypoor.webp index 0fd8ef0b6..85c8f8863 100644 Binary files a/files/assets/images/emojis/marseypoor.webp and b/files/assets/images/emojis/marseypoor.webp differ diff --git a/files/assets/images/emojis/marseypop.webp b/files/assets/images/emojis/marseypop.webp index 05a0c3b9e..138b3e9ca 100644 Binary files a/files/assets/images/emojis/marseypop.webp and b/files/assets/images/emojis/marseypop.webp differ diff --git a/files/assets/images/emojis/marseypopcorn.webp b/files/assets/images/emojis/marseypopcorn.webp index 8497fd7e6..f0ef2fb61 100644 Binary files a/files/assets/images/emojis/marseypopcorn.webp and b/files/assets/images/emojis/marseypopcorn.webp differ diff --git a/files/assets/images/emojis/marseypope.webp b/files/assets/images/emojis/marseypope.webp index 3e1f1db11..89f7b19c8 100644 Binary files a/files/assets/images/emojis/marseypope.webp and b/files/assets/images/emojis/marseypope.webp differ diff --git a/files/assets/images/emojis/marseypostmodern.webp b/files/assets/images/emojis/marseypostmodern.webp index a666bca66..e991cf466 100644 Binary files a/files/assets/images/emojis/marseypostmodern.webp and b/files/assets/images/emojis/marseypostmodern.webp differ diff --git a/files/assets/images/emojis/marseypotofsneed.webp b/files/assets/images/emojis/marseypotofsneed.webp index ea889747d..e9e4cbe44 100644 Binary files a/files/assets/images/emojis/marseypotofsneed.webp and b/files/assets/images/emojis/marseypotofsneed.webp differ diff --git a/files/assets/images/emojis/marseypredator.webp b/files/assets/images/emojis/marseypredator.webp index 80461959d..e9e3f6072 100644 Binary files a/files/assets/images/emojis/marseypredator.webp and b/files/assets/images/emojis/marseypredator.webp differ diff --git a/files/assets/images/emojis/marseypregunta.webp b/files/assets/images/emojis/marseypregunta.webp index c0a412b39..0aecb30ba 100644 Binary files a/files/assets/images/emojis/marseypregunta.webp and b/files/assets/images/emojis/marseypregunta.webp differ diff --git a/files/assets/images/emojis/marseypresents.webp b/files/assets/images/emojis/marseypresents.webp index cc407d67b..22b6d3ddb 100644 Binary files a/files/assets/images/emojis/marseypresents.webp and b/files/assets/images/emojis/marseypresents.webp differ diff --git a/files/assets/images/emojis/marseypretty.webp b/files/assets/images/emojis/marseypretty.webp index c8d36b9f3..3ce69546e 100644 Binary files a/files/assets/images/emojis/marseypretty.webp and b/files/assets/images/emojis/marseypretty.webp differ diff --git a/files/assets/images/emojis/marseypride.webp b/files/assets/images/emojis/marseypride.webp index 93a4d0bea..22f24f3f8 100644 Binary files a/files/assets/images/emojis/marseypride.webp and b/files/assets/images/emojis/marseypride.webp differ diff --git a/files/assets/images/emojis/marseyprideflag.webp b/files/assets/images/emojis/marseyprideflag.webp index 4eb112485..8cb0cc674 100644 Binary files a/files/assets/images/emojis/marseyprideflag.webp and b/files/assets/images/emojis/marseyprideflag.webp differ diff --git a/files/assets/images/emojis/marseypridepearlclutch.webp b/files/assets/images/emojis/marseypridepearlclutch.webp index 3c1903b4b..d8d220328 100644 Binary files a/files/assets/images/emojis/marseypridepearlclutch.webp and b/files/assets/images/emojis/marseypridepearlclutch.webp differ diff --git a/files/assets/images/emojis/marseyproctologist.webp b/files/assets/images/emojis/marseyproctologist.webp index aa7d852b3..9ac59c533 100644 Binary files a/files/assets/images/emojis/marseyproctologist.webp and b/files/assets/images/emojis/marseyproctologist.webp differ diff --git a/files/assets/images/emojis/marseyprostateexam.webp b/files/assets/images/emojis/marseyprostateexam.webp index cd502fc73..879356d5f 100644 Binary files a/files/assets/images/emojis/marseyprostateexam.webp and b/files/assets/images/emojis/marseyprostateexam.webp differ diff --git a/files/assets/images/emojis/marseyprotestno.webp b/files/assets/images/emojis/marseyprotestno.webp index 01692ad81..ee612b916 100644 Binary files a/files/assets/images/emojis/marseyprotestno.webp and b/files/assets/images/emojis/marseyprotestno.webp differ diff --git a/files/assets/images/emojis/marseyprotestyes.webp b/files/assets/images/emojis/marseyprotestyes.webp index 75ee972a3..244b62a52 100644 Binary files a/files/assets/images/emojis/marseyprotestyes.webp and b/files/assets/images/emojis/marseyprotestyes.webp differ diff --git a/files/assets/images/emojis/marseypsycho.webp b/files/assets/images/emojis/marseypsycho.webp index a5ea326c7..87613addc 100644 Binary files a/files/assets/images/emojis/marseypsycho.webp and b/files/assets/images/emojis/marseypsycho.webp differ diff --git a/files/assets/images/emojis/marseypudu.webp b/files/assets/images/emojis/marseypudu.webp new file mode 100644 index 000000000..8fc6ba8d9 Binary files /dev/null and b/files/assets/images/emojis/marseypudu.webp differ diff --git a/files/assets/images/emojis/marseypumpkin2.webp b/files/assets/images/emojis/marseypumpkin2.webp index aa0903371..8353ff6a5 100644 Binary files a/files/assets/images/emojis/marseypumpkin2.webp and b/files/assets/images/emojis/marseypumpkin2.webp differ diff --git a/files/assets/images/emojis/marseypumpkin3.webp b/files/assets/images/emojis/marseypumpkin3.webp index a66c9c085..dcd709838 100644 Binary files a/files/assets/images/emojis/marseypumpkin3.webp and b/files/assets/images/emojis/marseypumpkin3.webp differ diff --git a/files/assets/images/emojis/marseypumpkin4.webp b/files/assets/images/emojis/marseypumpkin4.webp index adf55e218..669292910 100644 Binary files a/files/assets/images/emojis/marseypumpkin4.webp and b/files/assets/images/emojis/marseypumpkin4.webp differ diff --git a/files/assets/images/emojis/marseypumpkincloak.webp b/files/assets/images/emojis/marseypumpkincloak.webp index e969177de..773d07531 100644 Binary files a/files/assets/images/emojis/marseypumpkincloak.webp and b/files/assets/images/emojis/marseypumpkincloak.webp differ diff --git a/files/assets/images/emojis/marseypumpking.webp b/files/assets/images/emojis/marseypumpking.webp index 57c4f5eb9..ab4a621b9 100644 Binary files a/files/assets/images/emojis/marseypumpking.webp and b/files/assets/images/emojis/marseypumpking.webp differ diff --git a/files/assets/images/emojis/marseypunched.webp b/files/assets/images/emojis/marseypunched.webp index e303e5a08..018e5c274 100644 Binary files a/files/assets/images/emojis/marseypunched.webp and b/files/assets/images/emojis/marseypunched.webp differ diff --git a/files/assets/images/emojis/marseypunished.webp b/files/assets/images/emojis/marseypunished.webp index 6d94969cd..115ee8917 100644 Binary files a/files/assets/images/emojis/marseypunished.webp and b/files/assets/images/emojis/marseypunished.webp differ diff --git a/files/assets/images/emojis/marseypunished2.webp b/files/assets/images/emojis/marseypunished2.webp index 8f4d2db3d..db4ecc817 100644 Binary files a/files/assets/images/emojis/marseypunished2.webp and b/files/assets/images/emojis/marseypunished2.webp differ diff --git a/files/assets/images/emojis/marseypunisher.webp b/files/assets/images/emojis/marseypunisher.webp index 0fa35cd64..770e830aa 100644 Binary files a/files/assets/images/emojis/marseypunisher.webp and b/files/assets/images/emojis/marseypunisher.webp differ diff --git a/files/assets/images/emojis/marseypuppy.webp b/files/assets/images/emojis/marseypuppy.webp index a4fb9af77..459844c55 100644 Binary files a/files/assets/images/emojis/marseypuppy.webp and b/files/assets/images/emojis/marseypuppy.webp differ diff --git a/files/assets/images/emojis/marseypureevil.webp b/files/assets/images/emojis/marseypureevil.webp index 442e90d56..2581d9829 100644 Binary files a/files/assets/images/emojis/marseypureevil.webp and b/files/assets/images/emojis/marseypureevil.webp differ diff --git a/files/assets/images/emojis/marseypusheen.webp b/files/assets/images/emojis/marseypusheen.webp index bbc9ed448..3cd523c7b 100644 Binary files a/files/assets/images/emojis/marseypusheen.webp and b/files/assets/images/emojis/marseypusheen.webp differ diff --git a/files/assets/images/emojis/marseypussyhat.webp b/files/assets/images/emojis/marseypussyhat.webp index 78b8fe0d0..050bd9494 100644 Binary files a/files/assets/images/emojis/marseypussyhat.webp and b/files/assets/images/emojis/marseypussyhat.webp differ diff --git a/files/assets/images/emojis/marseyputin.webp b/files/assets/images/emojis/marseyputin.webp index 88a2b3557..02bef41fd 100644 Binary files a/files/assets/images/emojis/marseyputin.webp and b/files/assets/images/emojis/marseyputin.webp differ diff --git a/files/assets/images/emojis/marseyqoomer.webp b/files/assets/images/emojis/marseyqoomer.webp index 576919bba..9e109e3a6 100644 Binary files a/files/assets/images/emojis/marseyqoomer.webp and b/files/assets/images/emojis/marseyqoomer.webp differ diff --git a/files/assets/images/emojis/marseyqr.webp b/files/assets/images/emojis/marseyqr.webp index b2fb995b0..b69dced8f 100644 Binary files a/files/assets/images/emojis/marseyqr.webp and b/files/assets/images/emojis/marseyqr.webp differ diff --git a/files/assets/images/emojis/marseyqr2.webp b/files/assets/images/emojis/marseyqr2.webp index 4b03446b0..3b387a909 100644 Binary files a/files/assets/images/emojis/marseyqr2.webp and b/files/assets/images/emojis/marseyqr2.webp differ diff --git a/files/assets/images/emojis/marseyquadmagyar.webp b/files/assets/images/emojis/marseyquadmagyar.webp index 84013e2d7..2eb02f5de 100644 Binary files a/files/assets/images/emojis/marseyquadmagyar.webp and b/files/assets/images/emojis/marseyquadmagyar.webp differ diff --git a/files/assets/images/emojis/marseyqueen.webp b/files/assets/images/emojis/marseyqueen.webp index 8364ebec9..ac6ff20ef 100644 Binary files a/files/assets/images/emojis/marseyqueen.webp and b/files/assets/images/emojis/marseyqueen.webp differ diff --git a/files/assets/images/emojis/marseyquestion.webp b/files/assets/images/emojis/marseyquestion.webp index bab5f95e2..65e0a6101 100644 Binary files a/files/assets/images/emojis/marseyquestion.webp and b/files/assets/images/emojis/marseyquestion.webp differ diff --git a/files/assets/images/emojis/marseyquestionmark.webp b/files/assets/images/emojis/marseyquestionmark.webp index b71966dc0..ab54b4ebe 100644 Binary files a/files/assets/images/emojis/marseyquestionmark.webp and b/files/assets/images/emojis/marseyquestionmark.webp differ diff --git a/files/assets/images/emojis/marseyrabbit.webp b/files/assets/images/emojis/marseyrabbit.webp index 933555dff..2004c9ac3 100644 Binary files a/files/assets/images/emojis/marseyrabbit.webp and b/files/assets/images/emojis/marseyrabbit.webp differ diff --git a/files/assets/images/emojis/marseyraccoon.webp b/files/assets/images/emojis/marseyraccoon.webp index b11b454f4..1d14cf43d 100644 Binary files a/files/assets/images/emojis/marseyraccoon.webp and b/files/assets/images/emojis/marseyraccoon.webp differ diff --git a/files/assets/images/emojis/marseyracist.webp b/files/assets/images/emojis/marseyracist.webp index 1e78a9a7c..fc5a15f91 100644 Binary files a/files/assets/images/emojis/marseyracist.webp and b/files/assets/images/emojis/marseyracist.webp differ diff --git a/files/assets/images/emojis/marseyracistgrandpa.webp b/files/assets/images/emojis/marseyracistgrandpa.webp index 6e371e006..ef1c89006 100644 Binary files a/files/assets/images/emojis/marseyracistgrandpa.webp and b/files/assets/images/emojis/marseyracistgrandpa.webp differ diff --git a/files/assets/images/emojis/marseyradioactive.webp b/files/assets/images/emojis/marseyradioactive.webp index 819eaad60..951685594 100644 Binary files a/files/assets/images/emojis/marseyradioactive.webp and b/files/assets/images/emojis/marseyradioactive.webp differ diff --git a/files/assets/images/emojis/marseyrage.webp b/files/assets/images/emojis/marseyrage.webp index b7123b705..2bc1e2c10 100644 Binary files a/files/assets/images/emojis/marseyrage.webp and b/files/assets/images/emojis/marseyrage.webp differ diff --git a/files/assets/images/emojis/marseyraiden.webp b/files/assets/images/emojis/marseyraiden.webp index 293d9a5f9..3e9bf7294 100644 Binary files a/files/assets/images/emojis/marseyraiden.webp and b/files/assets/images/emojis/marseyraiden.webp differ diff --git a/files/assets/images/emojis/marseyrain.webp b/files/assets/images/emojis/marseyrain.webp index 56587e969..ece1d25a2 100644 Binary files a/files/assets/images/emojis/marseyrain.webp and b/files/assets/images/emojis/marseyrain.webp differ diff --git a/files/assets/images/emojis/marseyraisinghands.webp b/files/assets/images/emojis/marseyraisinghands.webp new file mode 100644 index 000000000..4c8423e7f Binary files /dev/null and b/files/assets/images/emojis/marseyraisinghands.webp differ diff --git a/files/assets/images/emojis/marseyrake.webp b/files/assets/images/emojis/marseyrake.webp index a7b0238c4..3b319fe09 100644 Binary files a/files/assets/images/emojis/marseyrake.webp and b/files/assets/images/emojis/marseyrake.webp differ diff --git a/files/assets/images/emojis/marseyrapscallion.webp b/files/assets/images/emojis/marseyrapscallion.webp index 33b28cadd..48cd00d6d 100644 Binary files a/files/assets/images/emojis/marseyrapscallion.webp and b/files/assets/images/emojis/marseyrapscallion.webp differ diff --git a/files/assets/images/emojis/marseyrare.webp b/files/assets/images/emojis/marseyrare.webp index 6507cc9a0..a224a47fb 100644 Binary files a/files/assets/images/emojis/marseyrare.webp and b/files/assets/images/emojis/marseyrare.webp differ diff --git a/files/assets/images/emojis/marseyrasta.webp b/files/assets/images/emojis/marseyrasta.webp index 959c325dd..869516deb 100644 Binary files a/files/assets/images/emojis/marseyrasta.webp and b/files/assets/images/emojis/marseyrasta.webp differ diff --git a/files/assets/images/emojis/marseyrat.webp b/files/assets/images/emojis/marseyrat.webp index 0ef677d79..ead8f945f 100644 Binary files a/files/assets/images/emojis/marseyrat.webp and b/files/assets/images/emojis/marseyrat.webp differ diff --git a/files/assets/images/emojis/marseyratso.webp b/files/assets/images/emojis/marseyratso.webp index 20fedb7a1..5000955c2 100644 Binary files a/files/assets/images/emojis/marseyratso.webp and b/files/assets/images/emojis/marseyratso.webp differ diff --git a/files/assets/images/emojis/marseyrdramauser.webp b/files/assets/images/emojis/marseyrdramauser.webp index ce1d4f78c..56a855dbc 100644 Binary files a/files/assets/images/emojis/marseyrdramauser.webp and b/files/assets/images/emojis/marseyrdramauser.webp differ diff --git a/files/assets/images/emojis/marseyreactor.webp b/files/assets/images/emojis/marseyreactor.webp index 13986fcb1..324933ea1 100644 Binary files a/files/assets/images/emojis/marseyreactor.webp and b/files/assets/images/emojis/marseyreactor.webp differ diff --git a/files/assets/images/emojis/marseyreading.webp b/files/assets/images/emojis/marseyreading.webp index 2bbd76ad1..c36ad680b 100644 Binary files a/files/assets/images/emojis/marseyreading.webp and b/files/assets/images/emojis/marseyreading.webp differ diff --git a/files/assets/images/emojis/marseyready.webp b/files/assets/images/emojis/marseyready.webp index ab75d40a4..7eb72407b 100644 Binary files a/files/assets/images/emojis/marseyready.webp and b/files/assets/images/emojis/marseyready.webp differ diff --git a/files/assets/images/emojis/marseyrealwork.webp b/files/assets/images/emojis/marseyrealwork.webp index b91dc0038..ad6c90e52 100644 Binary files a/files/assets/images/emojis/marseyrealwork.webp and b/files/assets/images/emojis/marseyrealwork.webp differ diff --git a/files/assets/images/emojis/marseyredcoat.webp b/files/assets/images/emojis/marseyredcoat.webp index bd4f2fb30..afe737039 100644 Binary files a/files/assets/images/emojis/marseyredcoat.webp and b/files/assets/images/emojis/marseyredcoat.webp differ diff --git a/files/assets/images/emojis/marseyredflag.webp b/files/assets/images/emojis/marseyredflag.webp index 4a3bdc110..5ca7939d1 100644 Binary files a/files/assets/images/emojis/marseyredflag.webp and b/files/assets/images/emojis/marseyredflag.webp differ diff --git a/files/assets/images/emojis/marseyredmage.webp b/files/assets/images/emojis/marseyredmage.webp index b002918dc..cf4330c05 100644 Binary files a/files/assets/images/emojis/marseyredmage.webp and b/files/assets/images/emojis/marseyredmage.webp differ diff --git a/files/assets/images/emojis/marseyregular.webp b/files/assets/images/emojis/marseyregular.webp index 25457b7b4..ec6d83948 100644 Binary files a/files/assets/images/emojis/marseyregular.webp and b/files/assets/images/emojis/marseyregular.webp differ diff --git a/files/assets/images/emojis/marseyreich.webp b/files/assets/images/emojis/marseyreich.webp index a49cfe691..0cfb8e2e8 100644 Binary files a/files/assets/images/emojis/marseyreich.webp and b/files/assets/images/emojis/marseyreich.webp differ diff --git a/files/assets/images/emojis/marseyreindeer2.webp b/files/assets/images/emojis/marseyreindeer2.webp index 27ad6d93d..1ad139406 100644 Binary files a/files/assets/images/emojis/marseyreindeer2.webp and b/files/assets/images/emojis/marseyreindeer2.webp differ diff --git a/files/assets/images/emojis/marseyreindeer3.webp b/files/assets/images/emojis/marseyreindeer3.webp index a8c8e447c..c63778650 100644 Binary files a/files/assets/images/emojis/marseyreindeer3.webp and b/files/assets/images/emojis/marseyreindeer3.webp differ diff --git a/files/assets/images/emojis/marseyreindeer4.webp b/files/assets/images/emojis/marseyreindeer4.webp index da2855d55..d741a3e49 100644 Binary files a/files/assets/images/emojis/marseyreindeer4.webp and b/files/assets/images/emojis/marseyreindeer4.webp differ diff --git a/files/assets/images/emojis/marseyrelevancy.webp b/files/assets/images/emojis/marseyrelevancy.webp new file mode 100644 index 000000000..d6c7f0a98 Binary files /dev/null and b/files/assets/images/emojis/marseyrelevancy.webp differ diff --git a/files/assets/images/emojis/marseyreluctant.webp b/files/assets/images/emojis/marseyreluctant.webp index 55f20cce1..2fd77775a 100644 Binary files a/files/assets/images/emojis/marseyreluctant.webp and b/files/assets/images/emojis/marseyreluctant.webp differ diff --git a/files/assets/images/emojis/marseyremastered.webp b/files/assets/images/emojis/marseyremastered.webp index 5715ae201..6e7fecc87 100644 Binary files a/files/assets/images/emojis/marseyremastered.webp and b/files/assets/images/emojis/marseyremastered.webp differ diff --git a/files/assets/images/emojis/marseyrentfree.webp b/files/assets/images/emojis/marseyrentfree.webp index 0ef616218..873c6b19b 100644 Binary files a/files/assets/images/emojis/marseyrentfree.webp and b/files/assets/images/emojis/marseyrentfree.webp differ diff --git a/files/assets/images/emojis/marseyreportercnn.webp b/files/assets/images/emojis/marseyreportercnn.webp index 9ba90bc93..9e6d08b59 100644 Binary files a/files/assets/images/emojis/marseyreportercnn.webp and b/files/assets/images/emojis/marseyreportercnn.webp differ diff --git a/files/assets/images/emojis/marseyreporterfox.webp b/files/assets/images/emojis/marseyreporterfox.webp index 016a4f625..6e28d962d 100644 Binary files a/files/assets/images/emojis/marseyreporterfox.webp and b/files/assets/images/emojis/marseyreporterfox.webp differ diff --git a/files/assets/images/emojis/marseyrespect.webp b/files/assets/images/emojis/marseyrespect.webp new file mode 100644 index 000000000..08c8c4ed8 Binary files /dev/null and b/files/assets/images/emojis/marseyrespect.webp differ diff --git a/files/assets/images/emojis/marseyretard.webp b/files/assets/images/emojis/marseyretard.webp index eabea478f..9e160f99c 100644 Binary files a/files/assets/images/emojis/marseyretard.webp and b/files/assets/images/emojis/marseyretard.webp differ diff --git a/files/assets/images/emojis/marseyretard2.webp b/files/assets/images/emojis/marseyretard2.webp index 2e1402638..32ae8d37e 100644 Binary files a/files/assets/images/emojis/marseyretard2.webp and b/files/assets/images/emojis/marseyretard2.webp differ diff --git a/files/assets/images/emojis/marseyretard3.webp b/files/assets/images/emojis/marseyretard3.webp index 3a6fa4567..7d201fa58 100644 Binary files a/files/assets/images/emojis/marseyretard3.webp and b/files/assets/images/emojis/marseyretard3.webp differ diff --git a/files/assets/images/emojis/marseyretardchad.webp b/files/assets/images/emojis/marseyretardchad.webp index 697467d7b..d03dd6b68 100644 Binary files a/files/assets/images/emojis/marseyretardchad.webp and b/files/assets/images/emojis/marseyretardchad.webp differ diff --git a/files/assets/images/emojis/marseyretro.webp b/files/assets/images/emojis/marseyretro.webp index 268ab31e6..0171a9401 100644 Binary files a/files/assets/images/emojis/marseyretro.webp and b/files/assets/images/emojis/marseyretro.webp differ diff --git a/files/assets/images/emojis/marseyrevolution.webp b/files/assets/images/emojis/marseyrevolution.webp index 40b6b6dce..a0503652a 100644 Binary files a/files/assets/images/emojis/marseyrevolution.webp and b/files/assets/images/emojis/marseyrevolution.webp differ diff --git a/files/assets/images/emojis/marseyrick.webp b/files/assets/images/emojis/marseyrick.webp index 42ba32a73..fdc76c271 100644 Binary files a/files/assets/images/emojis/marseyrick.webp and b/files/assets/images/emojis/marseyrick.webp differ diff --git a/files/assets/images/emojis/marseyriddler.webp b/files/assets/images/emojis/marseyriddler.webp new file mode 100644 index 000000000..fffd1e71c Binary files /dev/null and b/files/assets/images/emojis/marseyriddler.webp differ diff --git a/files/assets/images/emojis/marseyridin.webp b/files/assets/images/emojis/marseyridin.webp index 37f9a5a96..cbe9e2cae 100644 Binary files a/files/assets/images/emojis/marseyridin.webp and b/files/assets/images/emojis/marseyridin.webp differ diff --git a/files/assets/images/emojis/marseyrobber.webp b/files/assets/images/emojis/marseyrobber.webp index bea9f4d67..39886db32 100644 Binary files a/files/assets/images/emojis/marseyrobber.webp and b/files/assets/images/emojis/marseyrobber.webp differ diff --git a/files/assets/images/emojis/marseyrobot.webp b/files/assets/images/emojis/marseyrobot.webp index ff586e928..e5dd2f1e9 100644 Binary files a/files/assets/images/emojis/marseyrobot.webp and b/files/assets/images/emojis/marseyrobot.webp differ diff --git a/files/assets/images/emojis/marseyroguspanish.webp b/files/assets/images/emojis/marseyroguspanish.webp new file mode 100644 index 000000000..92a568188 Binary files /dev/null and b/files/assets/images/emojis/marseyroguspanish.webp differ diff --git a/files/assets/images/emojis/marseyroo.webp b/files/assets/images/emojis/marseyroo.webp index 00364bff3..6e46c806f 100644 Binary files a/files/assets/images/emojis/marseyroo.webp and b/files/assets/images/emojis/marseyroo.webp differ diff --git a/files/assets/images/emojis/marseyrope.webp b/files/assets/images/emojis/marseyrope.webp index 5674b4a91..f74d9fd97 100644 Binary files a/files/assets/images/emojis/marseyrope.webp and b/files/assets/images/emojis/marseyrope.webp differ diff --git a/files/assets/images/emojis/marseyropewithchingchong.webp b/files/assets/images/emojis/marseyropewithchingchong.webp index be2069491..bd0426f90 100644 Binary files a/files/assets/images/emojis/marseyropewithchingchong.webp and b/files/assets/images/emojis/marseyropewithchingchong.webp differ diff --git a/files/assets/images/emojis/marseyropewithme.webp b/files/assets/images/emojis/marseyropewithme.webp index d844951e8..b8f651a63 100644 Binary files a/files/assets/images/emojis/marseyropewithme.webp and b/files/assets/images/emojis/marseyropewithme.webp differ diff --git a/files/assets/images/emojis/marseyropeyourself.webp b/files/assets/images/emojis/marseyropeyourself.webp index 3e4f3b5cd..ce29755b6 100644 Binary files a/files/assets/images/emojis/marseyropeyourself.webp and b/files/assets/images/emojis/marseyropeyourself.webp differ diff --git a/files/assets/images/emojis/marseyropeyourself2.webp b/files/assets/images/emojis/marseyropeyourself2.webp index 12202f8ec..82a94916f 100644 Binary files a/files/assets/images/emojis/marseyropeyourself2.webp and b/files/assets/images/emojis/marseyropeyourself2.webp differ diff --git a/files/assets/images/emojis/marseyropeyourselfmirror.webp b/files/assets/images/emojis/marseyropeyourselfmirror.webp index 82b7131c7..77882f80e 100644 Binary files a/files/assets/images/emojis/marseyropeyourselfmirror.webp and b/files/assets/images/emojis/marseyropeyourselfmirror.webp differ diff --git a/files/assets/images/emojis/marseyrowling.webp b/files/assets/images/emojis/marseyrowling.webp index 2ac3a59d3..497201750 100644 Binary files a/files/assets/images/emojis/marseyrowling.webp and b/files/assets/images/emojis/marseyrowling.webp differ diff --git a/files/assets/images/emojis/marseyroxsneed.webp b/files/assets/images/emojis/marseyroxsneed.webp new file mode 100644 index 000000000..6a997c4ad Binary files /dev/null and b/files/assets/images/emojis/marseyroxsneed.webp differ diff --git a/files/assets/images/emojis/marseyroxy.webp b/files/assets/images/emojis/marseyroxy.webp index 6a04f296d..e1acfac32 100644 Binary files a/files/assets/images/emojis/marseyroxy.webp and b/files/assets/images/emojis/marseyroxy.webp differ diff --git a/files/assets/images/emojis/marseyrpgcharacter.webp b/files/assets/images/emojis/marseyrpgcharacter.webp index 1c9fe56e3..446e4f8de 100644 Binary files a/files/assets/images/emojis/marseyrpgcharacter.webp and b/files/assets/images/emojis/marseyrpgcharacter.webp differ diff --git a/files/assets/images/emojis/marseyrs.webp b/files/assets/images/emojis/marseyrs.webp index 842b5b974..0b5e213d6 100644 Binary files a/files/assets/images/emojis/marseyrs.webp and b/files/assets/images/emojis/marseyrs.webp differ diff --git a/files/assets/images/emojis/marseyrulebritannia.webp b/files/assets/images/emojis/marseyrulebritannia.webp index 16ecccd3a..096eb66be 100644 Binary files a/files/assets/images/emojis/marseyrulebritannia.webp and b/files/assets/images/emojis/marseyrulebritannia.webp differ diff --git a/files/assets/images/emojis/marseyrussel.webp b/files/assets/images/emojis/marseyrussel.webp index 6a7ea814a..ca917de80 100644 Binary files a/files/assets/images/emojis/marseyrussel.webp and b/files/assets/images/emojis/marseyrussel.webp differ diff --git a/files/assets/images/emojis/marseyrussian.webp b/files/assets/images/emojis/marseyrussian.webp index 6bf009921..550cc772c 100644 Binary files a/files/assets/images/emojis/marseyrussian.webp and b/files/assets/images/emojis/marseyrussian.webp differ diff --git a/files/assets/images/emojis/marseyrustyventure.webp b/files/assets/images/emojis/marseyrustyventure.webp index a4dde0f59..75d1fe3bd 100644 Binary files a/files/assets/images/emojis/marseyrustyventure.webp and b/files/assets/images/emojis/marseyrustyventure.webp differ diff --git a/files/assets/images/emojis/marseysad.webp b/files/assets/images/emojis/marseysad.webp index 7035d0256..b48881092 100644 Binary files a/files/assets/images/emojis/marseysad.webp and b/files/assets/images/emojis/marseysad.webp differ diff --git a/files/assets/images/emojis/marseysad2.webp b/files/assets/images/emojis/marseysad2.webp index 3de13c6d3..1dc856e2d 100644 Binary files a/files/assets/images/emojis/marseysad2.webp and b/files/assets/images/emojis/marseysad2.webp differ diff --git a/files/assets/images/emojis/marseysadbox.webp b/files/assets/images/emojis/marseysadbox.webp new file mode 100644 index 000000000..cc5c6ea50 Binary files /dev/null and b/files/assets/images/emojis/marseysadbox.webp differ diff --git a/files/assets/images/emojis/marseysadcat.webp b/files/assets/images/emojis/marseysadcat.webp index 38585c43b..afca9d78c 100644 Binary files a/files/assets/images/emojis/marseysadcat.webp and b/files/assets/images/emojis/marseysadcat.webp differ diff --git a/files/assets/images/emojis/marseysadge.webp b/files/assets/images/emojis/marseysadge.webp index b98e7ad70..a3afad51d 100644 Binary files a/files/assets/images/emojis/marseysadge.webp and b/files/assets/images/emojis/marseysadge.webp differ diff --git a/files/assets/images/emojis/marseysadgun.webp b/files/assets/images/emojis/marseysadgun.webp index 1ca2ca607..a31285a69 100644 Binary files a/files/assets/images/emojis/marseysadgun.webp and b/files/assets/images/emojis/marseysadgun.webp differ diff --git a/files/assets/images/emojis/marseysailor.webp b/files/assets/images/emojis/marseysailor.webp index 27eec5cb7..0650ea025 100644 Binary files a/files/assets/images/emojis/marseysailor.webp and b/files/assets/images/emojis/marseysailor.webp differ diff --git a/files/assets/images/emojis/marseysal.webp b/files/assets/images/emojis/marseysal.webp index 12486df23..d40c80d38 100644 Binary files a/files/assets/images/emojis/marseysal.webp and b/files/assets/images/emojis/marseysal.webp differ diff --git a/files/assets/images/emojis/marseysal2.webp b/files/assets/images/emojis/marseysal2.webp index 824ad52d6..ef085acba 100644 Binary files a/files/assets/images/emojis/marseysal2.webp and b/files/assets/images/emojis/marseysal2.webp differ diff --git a/files/assets/images/emojis/marseysalad.webp b/files/assets/images/emojis/marseysalad.webp index fdbd5d154..36d8c69d6 100644 Binary files a/files/assets/images/emojis/marseysalad.webp and b/files/assets/images/emojis/marseysalad.webp differ diff --git a/files/assets/images/emojis/marseysaladfingers.webp b/files/assets/images/emojis/marseysaladfingers.webp index 798580334..9b8fcdc72 100644 Binary files a/files/assets/images/emojis/marseysaladfingers.webp and b/files/assets/images/emojis/marseysaladfingers.webp differ diff --git a/files/assets/images/emojis/marseysalat.webp b/files/assets/images/emojis/marseysalat.webp index fcf45ce91..2ba6913bc 100644 Binary files a/files/assets/images/emojis/marseysalat.webp and b/files/assets/images/emojis/marseysalat.webp differ diff --git a/files/assets/images/emojis/marseysaltlicking.webp b/files/assets/images/emojis/marseysaltlicking.webp index c95d1f4ea..21c2b48b7 100644 Binary files a/files/assets/images/emojis/marseysaltlicking.webp and b/files/assets/images/emojis/marseysaltlicking.webp differ diff --git a/files/assets/images/emojis/marseysalutearmy.webp b/files/assets/images/emojis/marseysalutearmy.webp index 8f1854a4f..d8a64574a 100644 Binary files a/files/assets/images/emojis/marseysalutearmy.webp and b/files/assets/images/emojis/marseysalutearmy.webp differ diff --git a/files/assets/images/emojis/marseysaluteconfederacy.webp b/files/assets/images/emojis/marseysaluteconfederacy.webp index d956c7f81..00cf81ff0 100644 Binary files a/files/assets/images/emojis/marseysaluteconfederacy.webp and b/files/assets/images/emojis/marseysaluteconfederacy.webp differ diff --git a/files/assets/images/emojis/marseysalutecop.webp b/files/assets/images/emojis/marseysalutecop.webp index 566216ca0..cd63740a4 100644 Binary files a/files/assets/images/emojis/marseysalutecop.webp and b/files/assets/images/emojis/marseysalutecop.webp differ diff --git a/files/assets/images/emojis/marseysalutenavy.webp b/files/assets/images/emojis/marseysalutenavy.webp index 157ed61f9..aaffd4632 100644 Binary files a/files/assets/images/emojis/marseysalutenavy.webp and b/files/assets/images/emojis/marseysalutenavy.webp differ diff --git a/files/assets/images/emojis/marseysalutepride.webp b/files/assets/images/emojis/marseysalutepride.webp index 16193b735..54e04c920 100644 Binary files a/files/assets/images/emojis/marseysalutepride.webp and b/files/assets/images/emojis/marseysalutepride.webp differ diff --git a/files/assets/images/emojis/marseysalvindicated.webp b/files/assets/images/emojis/marseysalvindicated.webp index 804ddf48c..a58b690e6 100644 Binary files a/files/assets/images/emojis/marseysalvindicated.webp and b/files/assets/images/emojis/marseysalvindicated.webp differ diff --git a/files/assets/images/emojis/marseysamhyde.webp b/files/assets/images/emojis/marseysamhyde.webp index 8328acfda..4d1172c6f 100644 Binary files a/files/assets/images/emojis/marseysamhyde.webp and b/files/assets/images/emojis/marseysamhyde.webp differ diff --git a/files/assets/images/emojis/marseysamhyde2.webp b/files/assets/images/emojis/marseysamhyde2.webp index 4b85c76ea..d34ab2018 100644 Binary files a/files/assets/images/emojis/marseysamhyde2.webp and b/files/assets/images/emojis/marseysamhyde2.webp differ diff --git a/files/assets/images/emojis/marseysanders.webp b/files/assets/images/emojis/marseysanders.webp index 943b5dd18..0a6822e40 100644 Binary files a/files/assets/images/emojis/marseysanders.webp and b/files/assets/images/emojis/marseysanders.webp differ diff --git a/files/assets/images/emojis/marseysanta.webp b/files/assets/images/emojis/marseysanta.webp index 63238a6b8..c5878b6e5 100644 Binary files a/files/assets/images/emojis/marseysanta.webp and b/files/assets/images/emojis/marseysanta.webp differ diff --git a/files/assets/images/emojis/marseysanta2.webp b/files/assets/images/emojis/marseysanta2.webp index 114a5fe11..de96638df 100644 Binary files a/files/assets/images/emojis/marseysanta2.webp and b/files/assets/images/emojis/marseysanta2.webp differ diff --git a/files/assets/images/emojis/marseysanta3.webp b/files/assets/images/emojis/marseysanta3.webp index 705cb8a27..ca0606590 100644 Binary files a/files/assets/images/emojis/marseysanta3.webp and b/files/assets/images/emojis/marseysanta3.webp differ diff --git a/files/assets/images/emojis/marseysargonofaccat.webp b/files/assets/images/emojis/marseysargonofaccat.webp index 65b34d8ce..2710a0caa 100644 Binary files a/files/assets/images/emojis/marseysargonofaccat.webp and b/files/assets/images/emojis/marseysargonofaccat.webp differ diff --git a/files/assets/images/emojis/marseysartre.webp b/files/assets/images/emojis/marseysartre.webp index b934fc4d2..b70704d0e 100644 Binary files a/files/assets/images/emojis/marseysartre.webp and b/files/assets/images/emojis/marseysartre.webp differ diff --git a/files/assets/images/emojis/marseysaruh.webp b/files/assets/images/emojis/marseysaruh.webp index 9b3e87844..cdd8eb0fb 100644 Binary files a/files/assets/images/emojis/marseysaruh.webp and b/files/assets/images/emojis/marseysaruh.webp differ diff --git a/files/assets/images/emojis/marseysatisfied.webp b/files/assets/images/emojis/marseysatisfied.webp index 03716c958..09adbae6d 100644 Binary files a/files/assets/images/emojis/marseysatisfied.webp and b/files/assets/images/emojis/marseysatisfied.webp differ diff --git a/files/assets/images/emojis/marseysatisfiedmarcus.webp b/files/assets/images/emojis/marseysatisfiedmarcus.webp index 1ac978e8d..abdac6207 100644 Binary files a/files/assets/images/emojis/marseysatisfiedmarcus.webp and b/files/assets/images/emojis/marseysatisfiedmarcus.webp differ diff --git a/files/assets/images/emojis/marseysaturn.webp b/files/assets/images/emojis/marseysaturn.webp index c2665647c..de80e1646 100644 Binary files a/files/assets/images/emojis/marseysaturn.webp and b/files/assets/images/emojis/marseysaturn.webp differ diff --git a/files/assets/images/emojis/marseysaw.webp b/files/assets/images/emojis/marseysaw.webp index a6b9c5991..3c2e300b2 100644 Binary files a/files/assets/images/emojis/marseysaw.webp and b/files/assets/images/emojis/marseysaw.webp differ diff --git a/files/assets/images/emojis/marseyscalped.webp b/files/assets/images/emojis/marseyscalped.webp index 86ade0694..e4e92648b 100644 Binary files a/files/assets/images/emojis/marseyscalped.webp and b/files/assets/images/emojis/marseyscalped.webp differ diff --git a/files/assets/images/emojis/marseyscared.webp b/files/assets/images/emojis/marseyscared.webp index b5713077f..aa4c300ef 100644 Binary files a/files/assets/images/emojis/marseyscared.webp and b/files/assets/images/emojis/marseyscared.webp differ diff --git a/files/assets/images/emojis/marseyscarf.webp b/files/assets/images/emojis/marseyscarf.webp index b580b3759..5ed489272 100644 Binary files a/files/assets/images/emojis/marseyscarf.webp and b/files/assets/images/emojis/marseyscarf.webp differ diff --git a/files/assets/images/emojis/marseyscaryteeth.webp b/files/assets/images/emojis/marseyscaryteeth.webp new file mode 100644 index 000000000..8c771a092 Binary files /dev/null and b/files/assets/images/emojis/marseyscaryteeth.webp differ diff --git a/files/assets/images/emojis/marseyschizo.webp b/files/assets/images/emojis/marseyschizo.webp index 7f673033b..315e15cbb 100644 Binary files a/files/assets/images/emojis/marseyschizo.webp and b/files/assets/images/emojis/marseyschizo.webp differ diff --git a/files/assets/images/emojis/marseyschizoabsinthelove.webp b/files/assets/images/emojis/marseyschizoabsinthelove.webp index 5559afe5b..83abfe6a8 100644 Binary files a/files/assets/images/emojis/marseyschizoabsinthelove.webp and b/files/assets/images/emojis/marseyschizoabsinthelove.webp differ diff --git a/files/assets/images/emojis/marseyschizobussylove.webp b/files/assets/images/emojis/marseyschizobussylove.webp index 6795d91a1..84128b98d 100644 Binary files a/files/assets/images/emojis/marseyschizobussylove.webp and b/files/assets/images/emojis/marseyschizobussylove.webp differ diff --git a/files/assets/images/emojis/marseyschizocapygitcommitlove.webp b/files/assets/images/emojis/marseyschizocapygitcommitlove.webp index 182700d1b..a6c4bcb60 100644 Binary files a/files/assets/images/emojis/marseyschizocapygitcommitlove.webp and b/files/assets/images/emojis/marseyschizocapygitcommitlove.webp differ diff --git a/files/assets/images/emojis/marseyschizocapylove.webp b/files/assets/images/emojis/marseyschizocapylove.webp index e97d00257..5eb049ba5 100644 Binary files a/files/assets/images/emojis/marseyschizocapylove.webp and b/files/assets/images/emojis/marseyschizocapylove.webp differ diff --git a/files/assets/images/emojis/marseyschizocarplove.webp b/files/assets/images/emojis/marseyschizocarplove.webp index 3cb5bdba5..c17e941d0 100644 Binary files a/files/assets/images/emojis/marseyschizocarplove.webp and b/files/assets/images/emojis/marseyschizocarplove.webp differ diff --git a/files/assets/images/emojis/marseyschizochadbasedcapylove.webp b/files/assets/images/emojis/marseyschizochadbasedcapylove.webp index 0c6ac4c50..5c1e5e71b 100644 Binary files a/files/assets/images/emojis/marseyschizochadbasedcapylove.webp and b/files/assets/images/emojis/marseyschizochadbasedcapylove.webp differ diff --git a/files/assets/images/emojis/marseyschizochadseethecapylove.webp b/files/assets/images/emojis/marseyschizochadseethecapylove.webp index 38d6a2694..655921fc2 100644 Binary files a/files/assets/images/emojis/marseyschizochadseethecapylove.webp and b/files/assets/images/emojis/marseyschizochadseethecapylove.webp differ diff --git a/files/assets/images/emojis/marseyschizochadthankscapylove.webp b/files/assets/images/emojis/marseyschizochadthankscapylove.webp index 64c1f4e67..eb2208b76 100644 Binary files a/files/assets/images/emojis/marseyschizochadthankscapylove.webp and b/files/assets/images/emojis/marseyschizochadthankscapylove.webp differ diff --git a/files/assets/images/emojis/marseyschizochadyescapylove.webp b/files/assets/images/emojis/marseyschizochadyescapylove.webp index 8dac7fd55..97a74d60b 100644 Binary files a/files/assets/images/emojis/marseyschizochadyescapylove.webp and b/files/assets/images/emojis/marseyschizochadyescapylove.webp differ diff --git a/files/assets/images/emojis/marseyschizodoggilove.webp b/files/assets/images/emojis/marseyschizodoggilove.webp index e15df7859..54f4a750a 100644 Binary files a/files/assets/images/emojis/marseyschizodoggilove.webp and b/files/assets/images/emojis/marseyschizodoggilove.webp differ diff --git a/files/assets/images/emojis/marseyschizodongerlove.webp b/files/assets/images/emojis/marseyschizodongerlove.webp index 75e7ef4f5..c35db497d 100644 Binary files a/files/assets/images/emojis/marseyschizodongerlove.webp and b/files/assets/images/emojis/marseyschizodongerlove.webp differ diff --git a/files/assets/images/emojis/marseyschizoducklove.webp b/files/assets/images/emojis/marseyschizoducklove.webp index 0b8571ab7..b86b5d43c 100644 Binary files a/files/assets/images/emojis/marseyschizoducklove.webp and b/files/assets/images/emojis/marseyschizoducklove.webp differ diff --git a/files/assets/images/emojis/marseyschizodussylove.webp b/files/assets/images/emojis/marseyschizodussylove.webp index 8440acb6f..5b7d99fff 100644 Binary files a/files/assets/images/emojis/marseyschizodussylove.webp and b/files/assets/images/emojis/marseyschizodussylove.webp differ diff --git a/files/assets/images/emojis/marseyschizofartbinnlove.webp b/files/assets/images/emojis/marseyschizofartbinnlove.webp index 5e86ff2ee..cf94a9c7a 100644 Binary files a/files/assets/images/emojis/marseyschizofartbinnlove.webp and b/files/assets/images/emojis/marseyschizofartbinnlove.webp differ diff --git a/files/assets/images/emojis/marseyschizogeeselove.webp b/files/assets/images/emojis/marseyschizogeeselove.webp index c85cd4c1d..6d1ef84c6 100644 Binary files a/files/assets/images/emojis/marseyschizogeeselove.webp and b/files/assets/images/emojis/marseyschizogeeselove.webp differ diff --git a/files/assets/images/emojis/marseyschizogetogetolove.webp b/files/assets/images/emojis/marseyschizogetogetolove.webp index b22e42fb1..b371702db 100644 Binary files a/files/assets/images/emojis/marseyschizogetogetolove.webp and b/files/assets/images/emojis/marseyschizogetogetolove.webp differ diff --git a/files/assets/images/emojis/marseyschizogrizzlylove.webp b/files/assets/images/emojis/marseyschizogrizzlylove.webp index cbd3acced..553a4a0c4 100644 Binary files a/files/assets/images/emojis/marseyschizogrizzlylove.webp and b/files/assets/images/emojis/marseyschizogrizzlylove.webp differ diff --git a/files/assets/images/emojis/marseyschizohanklove.webp b/files/assets/images/emojis/marseyschizohanklove.webp index a65e0e44a..34dca97eb 100644 Binary files a/files/assets/images/emojis/marseyschizohanklove.webp and b/files/assets/images/emojis/marseyschizohanklove.webp differ diff --git a/files/assets/images/emojis/marseyschizohobocellove.webp b/files/assets/images/emojis/marseyschizohobocellove.webp index 88fa88b0d..262b43f50 100644 Binary files a/files/assets/images/emojis/marseyschizohobocellove.webp and b/files/assets/images/emojis/marseyschizohobocellove.webp differ diff --git a/files/assets/images/emojis/marseyschizoidiolove.webp b/files/assets/images/emojis/marseyschizoidiolove.webp index 508c46ef0..c44c672b4 100644 Binary files a/files/assets/images/emojis/marseyschizoidiolove.webp and b/files/assets/images/emojis/marseyschizoidiolove.webp differ diff --git a/files/assets/images/emojis/marseyschizojclove.webp b/files/assets/images/emojis/marseyschizojclove.webp new file mode 100644 index 000000000..8a6f9c1b1 Binary files /dev/null and b/files/assets/images/emojis/marseyschizojclove.webp differ diff --git a/files/assets/images/emojis/marseyschizojoelove.webp b/files/assets/images/emojis/marseyschizojoelove.webp index d65eb6100..5e34fb359 100644 Binary files a/files/assets/images/emojis/marseyschizojoelove.webp and b/files/assets/images/emojis/marseyschizojoelove.webp differ diff --git a/files/assets/images/emojis/marseyschizolangleylove.webp b/files/assets/images/emojis/marseyschizolangleylove.webp index caeac28e3..3df9625f7 100644 Binary files a/files/assets/images/emojis/marseyschizolangleylove.webp and b/files/assets/images/emojis/marseyschizolangleylove.webp differ diff --git a/files/assets/images/emojis/marseyschizomajorgenerallove.webp b/files/assets/images/emojis/marseyschizomajorgenerallove.webp index c8df38909..935e99bc1 100644 Binary files a/files/assets/images/emojis/marseyschizomajorgenerallove.webp and b/files/assets/images/emojis/marseyschizomajorgenerallove.webp differ diff --git a/files/assets/images/emojis/marseyschizonekolove.webp b/files/assets/images/emojis/marseyschizonekolove.webp index 4dedd05e9..0cda96ce1 100644 Binary files a/files/assets/images/emojis/marseyschizonekolove.webp and b/files/assets/images/emojis/marseyschizonekolove.webp differ diff --git a/files/assets/images/emojis/marseyschizopennylove.webp b/files/assets/images/emojis/marseyschizopennylove.webp index a0026951a..cf7fa4664 100644 Binary files a/files/assets/images/emojis/marseyschizopennylove.webp and b/files/assets/images/emojis/marseyschizopennylove.webp differ diff --git a/files/assets/images/emojis/marseyschizosal.webp b/files/assets/images/emojis/marseyschizosal.webp index 40328d2af..f13795233 100644 Binary files a/files/assets/images/emojis/marseyschizosal.webp and b/files/assets/images/emojis/marseyschizosal.webp differ diff --git a/files/assets/images/emojis/marseyschizosallove.webp b/files/assets/images/emojis/marseyschizosallove.webp index ad27431e1..fcb15128d 100644 Binary files a/files/assets/images/emojis/marseyschizosallove.webp and b/files/assets/images/emojis/marseyschizosallove.webp differ diff --git a/files/assets/images/emojis/marseyschizoschizolove.webp b/files/assets/images/emojis/marseyschizoschizolove.webp index 2a1017ad4..fa0ea8eaf 100644 Binary files a/files/assets/images/emojis/marseyschizoschizolove.webp and b/files/assets/images/emojis/marseyschizoschizolove.webp differ diff --git a/files/assets/images/emojis/marseyschizosnakeslove.webp b/files/assets/images/emojis/marseyschizosnakeslove.webp index 0a8ec588f..b172b37e3 100644 Binary files a/files/assets/images/emojis/marseyschizosnakeslove.webp and b/files/assets/images/emojis/marseyschizosnakeslove.webp differ diff --git a/files/assets/images/emojis/marseyschizostimslove.webp b/files/assets/images/emojis/marseyschizostimslove.webp index 41453a1b3..c8724157e 100644 Binary files a/files/assets/images/emojis/marseyschizostimslove.webp and b/files/assets/images/emojis/marseyschizostimslove.webp differ diff --git a/files/assets/images/emojis/marseyschizowall.webp b/files/assets/images/emojis/marseyschizowall.webp index 30884325e..436d8489b 100644 Binary files a/files/assets/images/emojis/marseyschizowall.webp and b/files/assets/images/emojis/marseyschizowall.webp differ diff --git a/files/assets/images/emojis/marseyschopenhauer.webp b/files/assets/images/emojis/marseyschopenhauer.webp index 3859215e8..41bf0aec9 100644 Binary files a/files/assets/images/emojis/marseyschopenhauer.webp and b/files/assets/images/emojis/marseyschopenhauer.webp differ diff --git a/files/assets/images/emojis/marseyschrodinger.webp b/files/assets/images/emojis/marseyschrodinger.webp index 8f6a68ab5..4e6560f22 100644 Binary files a/files/assets/images/emojis/marseyschrodinger.webp and b/files/assets/images/emojis/marseyschrodinger.webp differ diff --git a/files/assets/images/emojis/marseyscooter.webp b/files/assets/images/emojis/marseyscooter.webp index 3209ebfbc..f4a53edbe 100644 Binary files a/files/assets/images/emojis/marseyscooter.webp and b/files/assets/images/emojis/marseyscooter.webp differ diff --git a/files/assets/images/emojis/marseyscratch.webp b/files/assets/images/emojis/marseyscratch.webp index 027543a64..c3c4f82db 100644 Binary files a/files/assets/images/emojis/marseyscratch.webp and b/files/assets/images/emojis/marseyscratch.webp differ diff --git a/files/assets/images/emojis/marseyseethe.webp b/files/assets/images/emojis/marseyseethe.webp index 8222a3a6e..365ba3499 100644 Binary files a/files/assets/images/emojis/marseyseethe.webp and b/files/assets/images/emojis/marseyseethe.webp differ diff --git a/files/assets/images/emojis/marseyselfflagellation.webp b/files/assets/images/emojis/marseyselfflagellation.webp index b87de0ac0..70140cfef 100644 Binary files a/files/assets/images/emojis/marseyselfflagellation.webp and b/files/assets/images/emojis/marseyselfflagellation.webp differ diff --git a/files/assets/images/emojis/marseysephiroth.webp b/files/assets/images/emojis/marseysephiroth.webp index 74fa9af8e..cd8a27091 100644 Binary files a/files/assets/images/emojis/marseysephiroth.webp and b/files/assets/images/emojis/marseysephiroth.webp differ diff --git a/files/assets/images/emojis/marseyseven.webp b/files/assets/images/emojis/marseyseven.webp index 40800ab96..d29107d82 100644 Binary files a/files/assets/images/emojis/marseyseven.webp and b/files/assets/images/emojis/marseyseven.webp differ diff --git a/files/assets/images/emojis/marseysexy.webp b/files/assets/images/emojis/marseysexy.webp index cac2359ef..d77c49842 100644 Binary files a/files/assets/images/emojis/marseysexy.webp and b/files/assets/images/emojis/marseysexy.webp differ diff --git a/files/assets/images/emojis/marseysexylibrarian.webp b/files/assets/images/emojis/marseysexylibrarian.webp index 11310a6e6..1669f3c83 100644 Binary files a/files/assets/images/emojis/marseysexylibrarian.webp and b/files/assets/images/emojis/marseysexylibrarian.webp differ diff --git a/files/assets/images/emojis/marseysexypepe.webp b/files/assets/images/emojis/marseysexypepe.webp index ddc0c54ac..884781a16 100644 Binary files a/files/assets/images/emojis/marseysexypepe.webp and b/files/assets/images/emojis/marseysexypepe.webp differ diff --git a/files/assets/images/emojis/marseyshake.webp b/files/assets/images/emojis/marseyshake.webp index 9f019b6db..3875b2fca 100644 Binary files a/files/assets/images/emojis/marseyshake.webp and b/files/assets/images/emojis/marseyshake.webp differ diff --git a/files/assets/images/emojis/marseyshakespeare.webp b/files/assets/images/emojis/marseyshakespeare.webp index 6e21712e6..c99fa99a5 100644 Binary files a/files/assets/images/emojis/marseyshakespeare.webp and b/files/assets/images/emojis/marseyshakespeare.webp differ diff --git a/files/assets/images/emojis/marseyshapiro.webp b/files/assets/images/emojis/marseyshapiro.webp index 19bf6dbf7..5d9b10898 100644 Binary files a/files/assets/images/emojis/marseyshapiro.webp and b/files/assets/images/emojis/marseyshapiro.webp differ diff --git a/files/assets/images/emojis/marseyshark.webp b/files/assets/images/emojis/marseyshark.webp index 5a168bcb5..b83c23a28 100644 Binary files a/files/assets/images/emojis/marseyshark.webp and b/files/assets/images/emojis/marseyshark.webp differ diff --git a/files/assets/images/emojis/marseysheep.webp b/files/assets/images/emojis/marseysheep.webp index c89689afa..ee2d54db2 100644 Binary files a/files/assets/images/emojis/marseysheep.webp and b/files/assets/images/emojis/marseysheep.webp differ diff --git a/files/assets/images/emojis/marseysheepdog.webp b/files/assets/images/emojis/marseysheepdog.webp index 9fd6b295a..5788ada64 100644 Binary files a/files/assets/images/emojis/marseysheepdog.webp and b/files/assets/images/emojis/marseysheepdog.webp differ diff --git a/files/assets/images/emojis/marseysherpa.webp b/files/assets/images/emojis/marseysherpa.webp index 426984385..d36a02b3c 100644 Binary files a/files/assets/images/emojis/marseysherpa.webp and b/files/assets/images/emojis/marseysherpa.webp differ diff --git a/files/assets/images/emojis/marseyshiftyeyes.webp b/files/assets/images/emojis/marseyshiftyeyes.webp index 7c2175a09..775a04c03 100644 Binary files a/files/assets/images/emojis/marseyshiftyeyes.webp and b/files/assets/images/emojis/marseyshiftyeyes.webp differ diff --git a/files/assets/images/emojis/marseyshisha.webp b/files/assets/images/emojis/marseyshisha.webp index d1080a1c7..b11809e35 100644 Binary files a/files/assets/images/emojis/marseyshisha.webp and b/files/assets/images/emojis/marseyshisha.webp differ diff --git a/files/assets/images/emojis/marseyshitforbrains.webp b/files/assets/images/emojis/marseyshitforbrains.webp index 6064dc686..073228247 100644 Binary files a/files/assets/images/emojis/marseyshitforbrains.webp and b/files/assets/images/emojis/marseyshitforbrains.webp differ diff --git a/files/assets/images/emojis/marseyshiva.webp b/files/assets/images/emojis/marseyshiva.webp new file mode 100644 index 000000000..ea4c48758 Binary files /dev/null and b/files/assets/images/emojis/marseyshiva.webp differ diff --git a/files/assets/images/emojis/marseyshock.webp b/files/assets/images/emojis/marseyshock.webp index 6233f88fb..a999cc92d 100644 Binary files a/files/assets/images/emojis/marseyshock.webp and b/files/assets/images/emojis/marseyshock.webp differ diff --git a/files/assets/images/emojis/marseyshook.webp b/files/assets/images/emojis/marseyshook.webp index f708aad6e..b1f5c22d0 100644 Binary files a/files/assets/images/emojis/marseyshook.webp and b/files/assets/images/emojis/marseyshook.webp differ diff --git a/files/assets/images/emojis/marseyshroom.webp b/files/assets/images/emojis/marseyshroom.webp index 5fde383c3..763336ac8 100644 Binary files a/files/assets/images/emojis/marseyshroom.webp and b/files/assets/images/emojis/marseyshroom.webp differ diff --git a/files/assets/images/emojis/marseyshrug.webp b/files/assets/images/emojis/marseyshrug.webp index a6e83c5e2..b39bab880 100644 Binary files a/files/assets/images/emojis/marseyshrug.webp and b/files/assets/images/emojis/marseyshrug.webp differ diff --git a/files/assets/images/emojis/marseyshy2.webp b/files/assets/images/emojis/marseyshy2.webp index 3d7b8c945..d4e7da80c 100644 Binary files a/files/assets/images/emojis/marseyshy2.webp and b/files/assets/images/emojis/marseyshy2.webp differ diff --git a/files/assets/images/emojis/marseysick.webp b/files/assets/images/emojis/marseysick.webp index ec26cb262..b11a04e5f 100644 Binary files a/files/assets/images/emojis/marseysick.webp and b/files/assets/images/emojis/marseysick.webp differ diff --git a/files/assets/images/emojis/marseysickos.webp b/files/assets/images/emojis/marseysickos.webp index cf3bc7812..6c803523d 100644 Binary files a/files/assets/images/emojis/marseysickos.webp and b/files/assets/images/emojis/marseysickos.webp differ diff --git a/files/assets/images/emojis/marseysickos2.webp b/files/assets/images/emojis/marseysickos2.webp index 314ae807e..8ed35fd4d 100644 Binary files a/files/assets/images/emojis/marseysickos2.webp and b/files/assets/images/emojis/marseysickos2.webp differ diff --git a/files/assets/images/emojis/marseysimpson.webp b/files/assets/images/emojis/marseysimpson.webp index faddfa6d5..7e92bea67 100644 Binary files a/files/assets/images/emojis/marseysimpson.webp and b/files/assets/images/emojis/marseysimpson.webp differ diff --git a/files/assets/images/emojis/marseysing.webp b/files/assets/images/emojis/marseysing.webp index 429296cd4..47210270e 100644 Binary files a/files/assets/images/emojis/marseysing.webp and b/files/assets/images/emojis/marseysing.webp differ diff --git a/files/assets/images/emojis/marseysingapore.webp b/files/assets/images/emojis/marseysingapore.webp index 890633e9d..441bc7665 100644 Binary files a/files/assets/images/emojis/marseysingapore.webp and b/files/assets/images/emojis/marseysingapore.webp differ diff --git a/files/assets/images/emojis/marseysipping.webp b/files/assets/images/emojis/marseysipping.webp index 27c12268e..4d4c7dae1 100644 Binary files a/files/assets/images/emojis/marseysipping.webp and b/files/assets/images/emojis/marseysipping.webp differ diff --git a/files/assets/images/emojis/marseysjw.webp b/files/assets/images/emojis/marseysjw.webp index 8ea4c7556..a78c2703c 100644 Binary files a/files/assets/images/emojis/marseysjw.webp and b/files/assets/images/emojis/marseysjw.webp differ diff --git a/files/assets/images/emojis/marseyskater.webp b/files/assets/images/emojis/marseyskater.webp index 3c0e90e9c..020361583 100644 Binary files a/files/assets/images/emojis/marseyskater.webp and b/files/assets/images/emojis/marseyskater.webp differ diff --git a/files/assets/images/emojis/marseyskeleton.webp b/files/assets/images/emojis/marseyskeleton.webp index 9d8b37022..bfeda9e58 100644 Binary files a/files/assets/images/emojis/marseyskeleton.webp and b/files/assets/images/emojis/marseyskeleton.webp differ diff --git a/files/assets/images/emojis/marseyskeleton2.webp b/files/assets/images/emojis/marseyskeleton2.webp index fbd9964d5..edad766cc 100644 Binary files a/files/assets/images/emojis/marseyskeleton2.webp and b/files/assets/images/emojis/marseyskeleton2.webp differ diff --git a/files/assets/images/emojis/marseyskeletontrex.webp b/files/assets/images/emojis/marseyskeletontrex.webp new file mode 100644 index 000000000..b1a35d16c Binary files /dev/null and b/files/assets/images/emojis/marseyskeletontrex.webp differ diff --git a/files/assets/images/emojis/marseyskeletonvelociraptor.webp b/files/assets/images/emojis/marseyskeletonvelociraptor.webp new file mode 100644 index 000000000..c159e69db Binary files /dev/null and b/files/assets/images/emojis/marseyskeletonvelociraptor.webp differ diff --git a/files/assets/images/emojis/marseyskeletor.webp b/files/assets/images/emojis/marseyskeletor.webp index da74ab134..2822ca164 100644 Binary files a/files/assets/images/emojis/marseyskeletor.webp and b/files/assets/images/emojis/marseyskeletor.webp differ diff --git a/files/assets/images/emojis/marseyskellington.webp b/files/assets/images/emojis/marseyskellington.webp new file mode 100644 index 000000000..1629c183d Binary files /dev/null and b/files/assets/images/emojis/marseyskellington.webp differ diff --git a/files/assets/images/emojis/marseyski.webp b/files/assets/images/emojis/marseyski.webp index c99bb2ed8..cca7f0c55 100644 Binary files a/files/assets/images/emojis/marseyski.webp and b/files/assets/images/emojis/marseyski.webp differ diff --git a/files/assets/images/emojis/marseyskull.webp b/files/assets/images/emojis/marseyskull.webp index 8ad035a4b..33ec87dd4 100644 Binary files a/files/assets/images/emojis/marseyskull.webp and b/files/assets/images/emojis/marseyskull.webp differ diff --git a/files/assets/images/emojis/marseyslaanesh.webp b/files/assets/images/emojis/marseyslaanesh.webp index ce27551a5..4d7daa0fb 100644 Binary files a/files/assets/images/emojis/marseyslaanesh.webp and b/files/assets/images/emojis/marseyslaanesh.webp differ diff --git a/files/assets/images/emojis/marseyslab.webp b/files/assets/images/emojis/marseyslab.webp index d35e5eceb..8ea6fc4b2 100644 Binary files a/files/assets/images/emojis/marseyslab.webp and b/files/assets/images/emojis/marseyslab.webp differ diff --git a/files/assets/images/emojis/marseysleep.webp b/files/assets/images/emojis/marseysleep.webp index cd083ef89..8e5bb50ea 100644 Binary files a/files/assets/images/emojis/marseysleep.webp and b/files/assets/images/emojis/marseysleep.webp differ diff --git a/files/assets/images/emojis/marseyslowpoke.webp b/files/assets/images/emojis/marseyslowpoke.webp index a14872a99..fbe0f1f7f 100644 Binary files a/files/assets/images/emojis/marseyslowpoke.webp and b/files/assets/images/emojis/marseyslowpoke.webp differ diff --git a/files/assets/images/emojis/marseysmirk.webp b/files/assets/images/emojis/marseysmirk.webp index 8934471b0..6136efccf 100644 Binary files a/files/assets/images/emojis/marseysmirk.webp and b/files/assets/images/emojis/marseysmirk.webp differ diff --git a/files/assets/images/emojis/marseysmoothbrain.webp b/files/assets/images/emojis/marseysmoothbrain.webp index 138e6716b..539661774 100644 Binary files a/files/assets/images/emojis/marseysmoothbrain.webp and b/files/assets/images/emojis/marseysmoothbrain.webp differ diff --git a/files/assets/images/emojis/marseysmudge.webp b/files/assets/images/emojis/marseysmudge.webp index 9590c960f..b9b4ece04 100644 Binary files a/files/assets/images/emojis/marseysmudge.webp and b/files/assets/images/emojis/marseysmudge.webp differ diff --git a/files/assets/images/emojis/marseysmug.webp b/files/assets/images/emojis/marseysmug.webp index 45a3fb114..434fe6d8f 100644 Binary files a/files/assets/images/emojis/marseysmug.webp and b/files/assets/images/emojis/marseysmug.webp differ diff --git a/files/assets/images/emojis/marseysmug2.webp b/files/assets/images/emojis/marseysmug2.webp index dfcd11450..277e04d2a 100644 Binary files a/files/assets/images/emojis/marseysmug2.webp and b/files/assets/images/emojis/marseysmug2.webp differ diff --git a/files/assets/images/emojis/marseysmug3.webp b/files/assets/images/emojis/marseysmug3.webp index 3b665a741..ab7747d81 100644 Binary files a/files/assets/images/emojis/marseysmug3.webp and b/files/assets/images/emojis/marseysmug3.webp differ diff --git a/files/assets/images/emojis/marseysmug4.webp b/files/assets/images/emojis/marseysmug4.webp index 44a3095ac..7f42dcd11 100644 Binary files a/files/assets/images/emojis/marseysmug4.webp and b/files/assets/images/emojis/marseysmug4.webp differ diff --git a/files/assets/images/emojis/marseysmugautist.webp b/files/assets/images/emojis/marseysmugautist.webp index 595b03f99..0cea849de 100644 Binary files a/files/assets/images/emojis/marseysmugautist.webp and b/files/assets/images/emojis/marseysmugautist.webp differ diff --git a/files/assets/images/emojis/marseysmugretard.webp b/files/assets/images/emojis/marseysmugretard.webp index e696599ab..234b5f9dd 100644 Binary files a/files/assets/images/emojis/marseysmugretard.webp and b/files/assets/images/emojis/marseysmugretard.webp differ diff --git a/files/assets/images/emojis/marseysmugsideeyes.webp b/files/assets/images/emojis/marseysmugsideeyes.webp index 2887388db..eb144ff60 100644 Binary files a/files/assets/images/emojis/marseysmugsideeyes.webp and b/files/assets/images/emojis/marseysmugsideeyes.webp differ diff --git a/files/assets/images/emojis/marseysnappyautism.webp b/files/assets/images/emojis/marseysnappyautism.webp index c74f6481b..a9677079c 100644 Binary files a/files/assets/images/emojis/marseysnappyautism.webp and b/files/assets/images/emojis/marseysnappyautism.webp differ diff --git a/files/assets/images/emojis/marseysnappyhug.webp b/files/assets/images/emojis/marseysnappyhug.webp index 7d8687238..d0b06439b 100644 Binary files a/files/assets/images/emojis/marseysnappyhug.webp and b/files/assets/images/emojis/marseysnappyhug.webp differ diff --git a/files/assets/images/emojis/marseysneed.webp b/files/assets/images/emojis/marseysneed.webp index ca0644db8..d46ce0444 100644 Binary files a/files/assets/images/emojis/marseysneed.webp and b/files/assets/images/emojis/marseysneed.webp differ diff --git a/files/assets/images/emojis/marseysnek.webp b/files/assets/images/emojis/marseysnek.webp index cfd1b9e9b..8c55e2d2f 100644 Binary files a/files/assets/images/emojis/marseysnek.webp and b/files/assets/images/emojis/marseysnek.webp differ diff --git a/files/assets/images/emojis/marseysniff.webp b/files/assets/images/emojis/marseysniff.webp index 72ed0c66e..5c2755041 100644 Binary files a/files/assets/images/emojis/marseysniff.webp and b/files/assets/images/emojis/marseysniff.webp differ diff --git a/files/assets/images/emojis/marseysnorlax.webp b/files/assets/images/emojis/marseysnorlax.webp index 32ce0ee9b..ad256a4de 100644 Binary files a/files/assets/images/emojis/marseysnorlax.webp and b/files/assets/images/emojis/marseysnorlax.webp differ diff --git a/files/assets/images/emojis/marseysnow.webp b/files/assets/images/emojis/marseysnow.webp index c5d9a4984..1e3e745fb 100644 Binary files a/files/assets/images/emojis/marseysnow.webp and b/files/assets/images/emojis/marseysnow.webp differ diff --git a/files/assets/images/emojis/marseysnowflake.webp b/files/assets/images/emojis/marseysnowflake.webp index 3f94a1098..341db44e8 100644 Binary files a/files/assets/images/emojis/marseysnowflake.webp and b/files/assets/images/emojis/marseysnowflake.webp differ diff --git a/files/assets/images/emojis/marseysnowman.webp b/files/assets/images/emojis/marseysnowman.webp index 50c0fad15..753f72c32 100644 Binary files a/files/assets/images/emojis/marseysnowman.webp and b/files/assets/images/emojis/marseysnowman.webp differ diff --git a/files/assets/images/emojis/marseysnowman2.webp b/files/assets/images/emojis/marseysnowman2.webp index 5d5bb3422..0ed8240d3 100644 Binary files a/files/assets/images/emojis/marseysnowman2.webp and b/files/assets/images/emojis/marseysnowman2.webp differ diff --git a/files/assets/images/emojis/marseysoccer.webp b/files/assets/images/emojis/marseysoccer.webp index 86b9da8e9..dcdd6db43 100644 Binary files a/files/assets/images/emojis/marseysoccer.webp and b/files/assets/images/emojis/marseysoccer.webp differ diff --git a/files/assets/images/emojis/marseysociety.webp b/files/assets/images/emojis/marseysociety.webp index ab038cfd4..49b24ea79 100644 Binary files a/files/assets/images/emojis/marseysociety.webp and b/files/assets/images/emojis/marseysociety.webp differ diff --git a/files/assets/images/emojis/marseysociety2.webp b/files/assets/images/emojis/marseysociety2.webp index a863ac30f..b60e74dad 100644 Binary files a/files/assets/images/emojis/marseysociety2.webp and b/files/assets/images/emojis/marseysociety2.webp differ diff --git a/files/assets/images/emojis/marseysockmlep.webp b/files/assets/images/emojis/marseysockmlep.webp index 45a635040..b6ad5b06d 100644 Binary files a/files/assets/images/emojis/marseysockmlep.webp and b/files/assets/images/emojis/marseysockmlep.webp differ diff --git a/files/assets/images/emojis/marseysoldieramerica.webp b/files/assets/images/emojis/marseysoldieramerica.webp index cf391e2ea..c1414eaa0 100644 Binary files a/files/assets/images/emojis/marseysoldieramerica.webp and b/files/assets/images/emojis/marseysoldieramerica.webp differ diff --git a/files/assets/images/emojis/marseysoldierchina.webp b/files/assets/images/emojis/marseysoldierchina.webp index 95c39ad01..71ca5dc97 100644 Binary files a/files/assets/images/emojis/marseysoldierchina.webp and b/files/assets/images/emojis/marseysoldierchina.webp differ diff --git a/files/assets/images/emojis/marseysoldierrussia.webp b/files/assets/images/emojis/marseysoldierrussia.webp index 7d793db70..fc2f28da8 100644 Binary files a/files/assets/images/emojis/marseysoldierrussia.webp and b/files/assets/images/emojis/marseysoldierrussia.webp differ diff --git a/files/assets/images/emojis/marseysombrero.webp b/files/assets/images/emojis/marseysombrero.webp index c918f99a4..34f44bea6 100644 Binary files a/files/assets/images/emojis/marseysombrero.webp and b/files/assets/images/emojis/marseysombrero.webp differ diff --git a/files/assets/images/emojis/marseysonic.webp b/files/assets/images/emojis/marseysonic.webp index a0a56e849..040959df4 100644 Binary files a/files/assets/images/emojis/marseysonic.webp and b/files/assets/images/emojis/marseysonic.webp differ diff --git a/files/assets/images/emojis/marseysonichu.webp b/files/assets/images/emojis/marseysonichu.webp index 01e94ac9f..c0b71c54d 100644 Binary files a/files/assets/images/emojis/marseysonichu.webp and b/files/assets/images/emojis/marseysonichu.webp differ diff --git a/files/assets/images/emojis/marseysonofman.webp b/files/assets/images/emojis/marseysonofman.webp index b8fb063e5..edae7e722 100644 Binary files a/files/assets/images/emojis/marseysonofman.webp and b/files/assets/images/emojis/marseysonofman.webp differ diff --git a/files/assets/images/emojis/marseysoon.webp b/files/assets/images/emojis/marseysoon.webp index dee0887f8..79f507a53 100644 Binary files a/files/assets/images/emojis/marseysoon.webp and b/files/assets/images/emojis/marseysoon.webp differ diff --git a/files/assets/images/emojis/marseysoonretarded.webp b/files/assets/images/emojis/marseysoonretarded.webp index 8145ba382..0316b18c4 100644 Binary files a/files/assets/images/emojis/marseysoonretarded.webp and b/files/assets/images/emojis/marseysoonretarded.webp differ diff --git a/files/assets/images/emojis/marseysopa.webp b/files/assets/images/emojis/marseysopa.webp index 1161d31ff..2346a3056 100644 Binary files a/files/assets/images/emojis/marseysopa.webp and b/files/assets/images/emojis/marseysopa.webp differ diff --git a/files/assets/images/emojis/marseysoren.webp b/files/assets/images/emojis/marseysoren.webp index 9ad84a2ae..7aea6225c 100644 Binary files a/files/assets/images/emojis/marseysoren.webp and b/files/assets/images/emojis/marseysoren.webp differ diff --git a/files/assets/images/emojis/marseysosa.webp b/files/assets/images/emojis/marseysosa.webp index 8bdde4694..acbe0bee9 100644 Binary files a/files/assets/images/emojis/marseysosa.webp and b/files/assets/images/emojis/marseysosa.webp differ diff --git a/files/assets/images/emojis/marseysoutherner.webp b/files/assets/images/emojis/marseysoutherner.webp index e8adee723..732754245 100644 Binary files a/files/assets/images/emojis/marseysoutherner.webp and b/files/assets/images/emojis/marseysoutherner.webp differ diff --git a/files/assets/images/emojis/marseysoycry.webp b/files/assets/images/emojis/marseysoycry.webp index 0b6dc1ddd..a9e377f3b 100644 Binary files a/files/assets/images/emojis/marseysoycry.webp and b/files/assets/images/emojis/marseysoycry.webp differ diff --git a/files/assets/images/emojis/marseysoycrytremble.webp b/files/assets/images/emojis/marseysoycrytremble.webp new file mode 100644 index 000000000..ea04f3f11 Binary files /dev/null and b/files/assets/images/emojis/marseysoycrytremble.webp differ diff --git a/files/assets/images/emojis/marseysoylentgrin.webp b/files/assets/images/emojis/marseysoylentgrin.webp index c4a3e92e4..d54cf2bb7 100644 Binary files a/files/assets/images/emojis/marseysoylentgrin.webp and b/files/assets/images/emojis/marseysoylentgrin.webp differ diff --git a/files/assets/images/emojis/marseysoypoint.webp b/files/assets/images/emojis/marseysoypoint.webp index ea51b81ed..87fdf780c 100644 Binary files a/files/assets/images/emojis/marseysoypoint.webp and b/files/assets/images/emojis/marseysoypoint.webp differ diff --git a/files/assets/images/emojis/marseysoypoint2.webp b/files/assets/images/emojis/marseysoypoint2.webp index 9b020c85f..93d01cfe2 100644 Binary files a/files/assets/images/emojis/marseysoypoint2.webp and b/files/assets/images/emojis/marseysoypoint2.webp differ diff --git a/files/assets/images/emojis/marseysoypointglow.webp b/files/assets/images/emojis/marseysoypointglow.webp new file mode 100644 index 000000000..86fd2ffde Binary files /dev/null and b/files/assets/images/emojis/marseysoypointglow.webp differ diff --git a/files/assets/images/emojis/marseysoypointgold.webp b/files/assets/images/emojis/marseysoypointgold.webp new file mode 100644 index 000000000..a73c269a1 Binary files /dev/null and b/files/assets/images/emojis/marseysoypointgold.webp differ diff --git a/files/assets/images/emojis/marseysoypointsnappyglow.webp b/files/assets/images/emojis/marseysoypointsnappyglow.webp new file mode 100644 index 000000000..160d701d7 Binary files /dev/null and b/files/assets/images/emojis/marseysoypointsnappyglow.webp differ diff --git a/files/assets/images/emojis/marseysoypointsnappygold.webp b/files/assets/images/emojis/marseysoypointsnappygold.webp new file mode 100644 index 000000000..a45175560 Binary files /dev/null and b/files/assets/images/emojis/marseysoypointsnappygold.webp differ diff --git a/files/assets/images/emojis/marseysoypointsnappyquote.webp b/files/assets/images/emojis/marseysoypointsnappyquote.webp new file mode 100644 index 000000000..38b87b56c Binary files /dev/null and b/files/assets/images/emojis/marseysoypointsnappyquote.webp differ diff --git a/files/assets/images/emojis/marseysoyrope.webp b/files/assets/images/emojis/marseysoyrope.webp index 9744bace0..e5aacaf2b 100644 Binary files a/files/assets/images/emojis/marseysoyrope.webp and b/files/assets/images/emojis/marseysoyrope.webp differ diff --git a/files/assets/images/emojis/marseysoyseethe.webp b/files/assets/images/emojis/marseysoyseethe.webp index bd8aa9129..8ce93d168 100644 Binary files a/files/assets/images/emojis/marseysoyseethe.webp and b/files/assets/images/emojis/marseysoyseethe.webp differ diff --git a/files/assets/images/emojis/marseyspa.webp b/files/assets/images/emojis/marseyspa.webp index cf723947a..04eee3ed8 100644 Binary files a/files/assets/images/emojis/marseyspa.webp and b/files/assets/images/emojis/marseyspa.webp differ diff --git a/files/assets/images/emojis/marseyspecial.webp b/files/assets/images/emojis/marseyspecial.webp index d59749f63..d2475f516 100644 Binary files a/files/assets/images/emojis/marseyspecial.webp and b/files/assets/images/emojis/marseyspecial.webp differ diff --git a/files/assets/images/emojis/marseysphericalcow.webp b/files/assets/images/emojis/marseysphericalcow.webp index 9b7cd2186..5e8e1131c 100644 Binary files a/files/assets/images/emojis/marseysphericalcow.webp and b/files/assets/images/emojis/marseysphericalcow.webp differ diff --git a/files/assets/images/emojis/marseysphinx.webp b/files/assets/images/emojis/marseysphinx.webp index c8a4c4673..5bae002e2 100644 Binary files a/files/assets/images/emojis/marseysphinx.webp and b/files/assets/images/emojis/marseysphinx.webp differ diff --git a/files/assets/images/emojis/marseyspider.webp b/files/assets/images/emojis/marseyspider.webp index 423a829e4..a089cba79 100644 Binary files a/files/assets/images/emojis/marseyspider.webp and b/files/assets/images/emojis/marseyspider.webp differ diff --git a/files/assets/images/emojis/marseyspider2.webp b/files/assets/images/emojis/marseyspider2.webp index 523b58af1..9d463947b 100644 Binary files a/files/assets/images/emojis/marseyspider2.webp and b/files/assets/images/emojis/marseyspider2.webp differ diff --git a/files/assets/images/emojis/marseyspiderman.webp b/files/assets/images/emojis/marseyspiderman.webp index c7978d256..73b164153 100644 Binary files a/files/assets/images/emojis/marseyspiderman.webp and b/files/assets/images/emojis/marseyspiderman.webp differ diff --git a/files/assets/images/emojis/marseyspirit.webp b/files/assets/images/emojis/marseyspirit.webp index f866afe8c..8b330897b 100644 Binary files a/files/assets/images/emojis/marseyspirit.webp and b/files/assets/images/emojis/marseyspirit.webp differ diff --git a/files/assets/images/emojis/marseyspittake.webp b/files/assets/images/emojis/marseyspittake.webp index 8ee159358..2bc1141cb 100644 Binary files a/files/assets/images/emojis/marseyspittake.webp and b/files/assets/images/emojis/marseyspittake.webp differ diff --git a/files/assets/images/emojis/marseyspock.webp b/files/assets/images/emojis/marseyspock.webp index 5129afb17..db7582310 100644 Binary files a/files/assets/images/emojis/marseyspock.webp and b/files/assets/images/emojis/marseyspock.webp differ diff --git a/files/assets/images/emojis/marseyspooky.webp b/files/assets/images/emojis/marseyspooky.webp index f15805469..5296543fd 100644 Binary files a/files/assets/images/emojis/marseyspooky.webp and b/files/assets/images/emojis/marseyspooky.webp differ diff --git a/files/assets/images/emojis/marseyspookysmile.webp b/files/assets/images/emojis/marseyspookysmile.webp index 3e39a930f..fa4540346 100644 Binary files a/files/assets/images/emojis/marseyspookysmile.webp and b/files/assets/images/emojis/marseyspookysmile.webp differ diff --git a/files/assets/images/emojis/marseysprite.webp b/files/assets/images/emojis/marseysprite.webp new file mode 100644 index 000000000..0c16261db Binary files /dev/null and b/files/assets/images/emojis/marseysprite.webp differ diff --git a/files/assets/images/emojis/marseyspy.webp b/files/assets/images/emojis/marseyspy.webp index a9eabe1c1..629845a36 100644 Binary files a/files/assets/images/emojis/marseyspy.webp and b/files/assets/images/emojis/marseyspy.webp differ diff --git a/files/assets/images/emojis/marseysquint.webp b/files/assets/images/emojis/marseysquint.webp index a3f2410d0..f15a11bb1 100644 Binary files a/files/assets/images/emojis/marseysquint.webp and b/files/assets/images/emojis/marseysquint.webp differ diff --git a/files/assets/images/emojis/marseysquished.webp b/files/assets/images/emojis/marseysquished.webp index f9892f3d5..88621098f 100644 Binary files a/files/assets/images/emojis/marseysquished.webp and b/files/assets/images/emojis/marseysquished.webp differ diff --git a/files/assets/images/emojis/marseysrdine.webp b/files/assets/images/emojis/marseysrdine.webp index 53247d09c..0fdcb2ea3 100644 Binary files a/files/assets/images/emojis/marseysrdine.webp and b/files/assets/images/emojis/marseysrdine.webp differ diff --git a/files/assets/images/emojis/marseyssflag.webp b/files/assets/images/emojis/marseyssflag.webp index 426caa6d4..df547c23b 100644 Binary files a/files/assets/images/emojis/marseyssflag.webp and b/files/assets/images/emojis/marseyssflag.webp differ diff --git a/files/assets/images/emojis/marseystalin.webp b/files/assets/images/emojis/marseystalin.webp index ca928504c..1a613b6ec 100644 Binary files a/files/assets/images/emojis/marseystalin.webp and b/files/assets/images/emojis/marseystalin.webp differ diff --git a/files/assets/images/emojis/marseystarbucks.webp b/files/assets/images/emojis/marseystarbucks.webp index 410d165f9..009252e37 100644 Binary files a/files/assets/images/emojis/marseystarbucks.webp and b/files/assets/images/emojis/marseystarbucks.webp differ diff --git a/files/assets/images/emojis/marseystars.webp b/files/assets/images/emojis/marseystars.webp index a5e8ea51d..a363ed56a 100644 Binary files a/files/assets/images/emojis/marseystars.webp and b/files/assets/images/emojis/marseystars.webp differ diff --git a/files/assets/images/emojis/marseystars2.webp b/files/assets/images/emojis/marseystars2.webp index a875a02a0..ded58b2fb 100644 Binary files a/files/assets/images/emojis/marseystars2.webp and b/files/assets/images/emojis/marseystars2.webp differ diff --git a/files/assets/images/emojis/marseysteaming.webp b/files/assets/images/emojis/marseysteaming.webp index f524745c3..6a4f705fd 100644 Binary files a/files/assets/images/emojis/marseysteaming.webp and b/files/assets/images/emojis/marseysteaming.webp differ diff --git a/files/assets/images/emojis/marseystein.webp b/files/assets/images/emojis/marseystein.webp index 72d5c8e67..ad003b460 100644 Binary files a/files/assets/images/emojis/marseystein.webp and b/files/assets/images/emojis/marseystein.webp differ diff --git a/files/assets/images/emojis/marseystinky.webp b/files/assets/images/emojis/marseystinky.webp index af6193d0e..add364a4d 100644 Binary files a/files/assets/images/emojis/marseystinky.webp and b/files/assets/images/emojis/marseystinky.webp differ diff --git a/files/assets/images/emojis/marseystocksdown.webp b/files/assets/images/emojis/marseystocksdown.webp index 364dda402..8b212f677 100644 Binary files a/files/assets/images/emojis/marseystocksdown.webp and b/files/assets/images/emojis/marseystocksdown.webp differ diff --git a/files/assets/images/emojis/marseystocksup.webp b/files/assets/images/emojis/marseystocksup.webp index 05e971bb6..80b3ab83e 100644 Binary files a/files/assets/images/emojis/marseystocksup.webp and b/files/assets/images/emojis/marseystocksup.webp differ diff --git a/files/assets/images/emojis/marseystonetoss.webp b/files/assets/images/emojis/marseystonetoss.webp index 025fdd464..5accd701d 100644 Binary files a/files/assets/images/emojis/marseystonetoss.webp and b/files/assets/images/emojis/marseystonetoss.webp differ diff --git a/files/assets/images/emojis/marseystrawman.webp b/files/assets/images/emojis/marseystrawman.webp index dea950d7b..58a351899 100644 Binary files a/files/assets/images/emojis/marseystrawman.webp and b/files/assets/images/emojis/marseystrawman.webp differ diff --git a/files/assets/images/emojis/marseystroke.webp b/files/assets/images/emojis/marseystroke.webp index 0ab6001f6..5e278a7ec 100644 Binary files a/files/assets/images/emojis/marseystroke.webp and b/files/assets/images/emojis/marseystroke.webp differ diff --git a/files/assets/images/emojis/marseystuffed.webp b/files/assets/images/emojis/marseystuffed.webp index 91973bc13..d975e99b8 100644 Binary files a/files/assets/images/emojis/marseystuffed.webp and b/files/assets/images/emojis/marseystuffed.webp differ diff --git a/files/assets/images/emojis/marseysuffragette.webp b/files/assets/images/emojis/marseysuffragette.webp index 82f0f06a6..74563fba5 100644 Binary files a/files/assets/images/emojis/marseysuffragette.webp and b/files/assets/images/emojis/marseysuffragette.webp differ diff --git a/files/assets/images/emojis/marseysuicidepills.webp b/files/assets/images/emojis/marseysuicidepills.webp index 1693dcf92..79d58ca4f 100644 Binary files a/files/assets/images/emojis/marseysuicidepills.webp and b/files/assets/images/emojis/marseysuicidepills.webp differ diff --git a/files/assets/images/emojis/marseysuit.webp b/files/assets/images/emojis/marseysuit.webp index 0d32fcc0c..0e34f6acb 100644 Binary files a/files/assets/images/emojis/marseysuit.webp and b/files/assets/images/emojis/marseysuit.webp differ diff --git a/files/assets/images/emojis/marseysully.webp b/files/assets/images/emojis/marseysully.webp index f56a115f1..c7052ab30 100644 Binary files a/files/assets/images/emojis/marseysully.webp and b/files/assets/images/emojis/marseysully.webp differ diff --git a/files/assets/images/emojis/marseysunflower.webp b/files/assets/images/emojis/marseysunflower.webp index c0651e943..24d5e60b3 100644 Binary files a/files/assets/images/emojis/marseysunflower.webp and b/files/assets/images/emojis/marseysunflower.webp differ diff --git a/files/assets/images/emojis/marseysuper.webp b/files/assets/images/emojis/marseysuper.webp index ec1db65de..327f1f448 100644 Binary files a/files/assets/images/emojis/marseysuper.webp and b/files/assets/images/emojis/marseysuper.webp differ diff --git a/files/assets/images/emojis/marseysurfing.webp b/files/assets/images/emojis/marseysurfing.webp index 5e0554489..c1062a066 100644 Binary files a/files/assets/images/emojis/marseysurfing.webp and b/files/assets/images/emojis/marseysurfing.webp differ diff --git a/files/assets/images/emojis/marseysurprised.webp b/files/assets/images/emojis/marseysurprised.webp index d1fa16474..1a6443f28 100644 Binary files a/files/assets/images/emojis/marseysurprised.webp and b/files/assets/images/emojis/marseysurprised.webp differ diff --git a/files/assets/images/emojis/marseysus.webp b/files/assets/images/emojis/marseysus.webp index 59318d4fc..754e198f9 100644 Binary files a/files/assets/images/emojis/marseysus.webp and b/files/assets/images/emojis/marseysus.webp differ diff --git a/files/assets/images/emojis/marseysuspicious.webp b/files/assets/images/emojis/marseysuspicious.webp index 53d95a824..602ad4da6 100644 Binary files a/files/assets/images/emojis/marseysuspicious.webp and b/files/assets/images/emojis/marseysuspicious.webp differ diff --git a/files/assets/images/emojis/marseysvengoolie.webp b/files/assets/images/emojis/marseysvengoolie.webp new file mode 100644 index 000000000..c92c11a03 Binary files /dev/null and b/files/assets/images/emojis/marseysvengoolie.webp differ diff --git a/files/assets/images/emojis/marseyswastika.webp b/files/assets/images/emojis/marseyswastika.webp index 3de5f577a..53c69790f 100644 Binary files a/files/assets/images/emojis/marseyswastika.webp and b/files/assets/images/emojis/marseyswastika.webp differ diff --git a/files/assets/images/emojis/marseysweating.webp b/files/assets/images/emojis/marseysweating.webp index cd1256ed1..51be8958b 100644 Binary files a/files/assets/images/emojis/marseysweating.webp and b/files/assets/images/emojis/marseysweating.webp differ diff --git a/files/assets/images/emojis/marseysylveon.webp b/files/assets/images/emojis/marseysylveon.webp index ba71e181f..b47f34778 100644 Binary files a/files/assets/images/emojis/marseysylveon.webp and b/files/assets/images/emojis/marseysylveon.webp differ diff --git a/files/assets/images/emojis/marseytabletired.webp b/files/assets/images/emojis/marseytabletired.webp index ff5a5f6d3..46ba17f2c 100644 Binary files a/files/assets/images/emojis/marseytabletired.webp and b/files/assets/images/emojis/marseytabletired.webp differ diff --git a/files/assets/images/emojis/marseytabletired2.webp b/files/assets/images/emojis/marseytabletired2.webp index 62236c28a..178d22178 100644 Binary files a/files/assets/images/emojis/marseytabletired2.webp and b/files/assets/images/emojis/marseytabletired2.webp differ diff --git a/files/assets/images/emojis/marseytakit.webp b/files/assets/images/emojis/marseytakit.webp new file mode 100644 index 000000000..996a5e1f3 Binary files /dev/null and b/files/assets/images/emojis/marseytakit.webp differ diff --git a/files/assets/images/emojis/marseytaliban.webp b/files/assets/images/emojis/marseytaliban.webp index be629c9b0..494b39b57 100644 Binary files a/files/assets/images/emojis/marseytaliban.webp and b/files/assets/images/emojis/marseytaliban.webp differ diff --git a/files/assets/images/emojis/marseytalking.webp b/files/assets/images/emojis/marseytalking.webp index 5658cd501..85a209beb 100644 Binary files a/files/assets/images/emojis/marseytalking.webp and b/files/assets/images/emojis/marseytalking.webp differ diff --git a/files/assets/images/emojis/marseytampon.webp b/files/assets/images/emojis/marseytampon.webp index 711598efc..f5b030bef 100644 Binary files a/files/assets/images/emojis/marseytampon.webp and b/files/assets/images/emojis/marseytampon.webp differ diff --git a/files/assets/images/emojis/marseytangerinefeline.webp b/files/assets/images/emojis/marseytangerinefeline.webp index 66a46a702..0c40e944b 100644 Binary files a/files/assets/images/emojis/marseytangerinefeline.webp and b/files/assets/images/emojis/marseytangerinefeline.webp differ diff --git a/files/assets/images/emojis/marseytank.webp b/files/assets/images/emojis/marseytank.webp index 206585757..5d3976207 100644 Binary files a/files/assets/images/emojis/marseytank.webp and b/files/assets/images/emojis/marseytank.webp differ diff --git a/files/assets/images/emojis/marseytankushanka.webp b/files/assets/images/emojis/marseytankushanka.webp index ddd4bf6d5..acbfc16ac 100644 Binary files a/files/assets/images/emojis/marseytankushanka.webp and b/files/assets/images/emojis/marseytankushanka.webp differ diff --git a/files/assets/images/emojis/marseytariq.webp b/files/assets/images/emojis/marseytariq.webp index 4f35f4728..0e62b83a1 100644 Binary files a/files/assets/images/emojis/marseytariq.webp and b/files/assets/images/emojis/marseytariq.webp differ diff --git a/files/assets/images/emojis/marseytarrant.webp b/files/assets/images/emojis/marseytarrant.webp index 96c7cc43e..c023893e3 100644 Binary files a/files/assets/images/emojis/marseytarrant.webp and b/files/assets/images/emojis/marseytarrant.webp differ diff --git a/files/assets/images/emojis/marseytarrant2.webp b/files/assets/images/emojis/marseytarrant2.webp index 96c7cc43e..c023893e3 100644 Binary files a/files/assets/images/emojis/marseytarrant2.webp and b/files/assets/images/emojis/marseytarrant2.webp differ diff --git a/files/assets/images/emojis/marseytea.webp b/files/assets/images/emojis/marseytea.webp index ee837f104..5fa1dc8ca 100644 Binary files a/files/assets/images/emojis/marseytea.webp and b/files/assets/images/emojis/marseytea.webp differ diff --git a/files/assets/images/emojis/marseyteaparty.webp b/files/assets/images/emojis/marseyteaparty.webp index 02e471de5..5e0932bfb 100644 Binary files a/files/assets/images/emojis/marseyteaparty.webp and b/files/assets/images/emojis/marseyteaparty.webp differ diff --git a/files/assets/images/emojis/marseytears.webp b/files/assets/images/emojis/marseytears.webp index 67e97787a..c5c16415b 100644 Binary files a/files/assets/images/emojis/marseytears.webp and b/files/assets/images/emojis/marseytears.webp differ diff --git a/files/assets/images/emojis/marseytearsofblood.webp b/files/assets/images/emojis/marseytearsofblood.webp index b0df87f8e..e13c28a00 100644 Binary files a/files/assets/images/emojis/marseytearsofblood.webp and b/files/assets/images/emojis/marseytearsofblood.webp differ diff --git a/files/assets/images/emojis/marseytedsimp.webp b/files/assets/images/emojis/marseytedsimp.webp index e0d34da35..63c000d06 100644 Binary files a/files/assets/images/emojis/marseytedsimp.webp and b/files/assets/images/emojis/marseytedsimp.webp differ diff --git a/files/assets/images/emojis/marseytelegram.webp b/files/assets/images/emojis/marseytelegram.webp index 74e67f348..c8d82397c 100644 Binary files a/files/assets/images/emojis/marseytelegram.webp and b/files/assets/images/emojis/marseytelegram.webp differ diff --git a/files/assets/images/emojis/marseytemplate.webp b/files/assets/images/emojis/marseytemplate.webp index 9f41e72a7..8de6c67ce 100644 Binary files a/files/assets/images/emojis/marseytemplate.webp and b/files/assets/images/emojis/marseytemplate.webp differ diff --git a/files/assets/images/emojis/marseyterfdomesticabuse.webp b/files/assets/images/emojis/marseyterfdomesticabuse.webp index f69c1a383..4ddd5e3b9 100644 Binary files a/files/assets/images/emojis/marseyterfdomesticabuse.webp and b/files/assets/images/emojis/marseyterfdomesticabuse.webp differ diff --git a/files/assets/images/emojis/marseyterrydavis.webp b/files/assets/images/emojis/marseyterrydavis.webp index 81deedec0..586c029ef 100644 Binary files a/files/assets/images/emojis/marseyterrydavis.webp and b/files/assets/images/emojis/marseyterrydavis.webp differ diff --git a/files/assets/images/emojis/marseyteruteru.webp b/files/assets/images/emojis/marseyteruteru.webp index de834781f..5a85df5ed 100644 Binary files a/files/assets/images/emojis/marseyteruteru.webp and b/files/assets/images/emojis/marseyteruteru.webp differ diff --git a/files/assets/images/emojis/marseytexan.webp b/files/assets/images/emojis/marseytexan.webp index 0af2527c5..10616f867 100644 Binary files a/files/assets/images/emojis/marseytexan.webp and b/files/assets/images/emojis/marseytexan.webp differ diff --git a/files/assets/images/emojis/marseytf2heavy.webp b/files/assets/images/emojis/marseytf2heavy.webp index 98e828636..d99070216 100644 Binary files a/files/assets/images/emojis/marseytf2heavy.webp and b/files/assets/images/emojis/marseytf2heavy.webp differ diff --git a/files/assets/images/emojis/marseytf2scout.webp b/files/assets/images/emojis/marseytf2scout.webp index 20b18efba..fa2a1f914 100644 Binary files a/files/assets/images/emojis/marseytf2scout.webp and b/files/assets/images/emojis/marseytf2scout.webp differ diff --git a/files/assets/images/emojis/marseytf2spy.webp b/files/assets/images/emojis/marseytf2spy.webp index 414b0f106..e054f0aa2 100644 Binary files a/files/assets/images/emojis/marseytf2spy.webp and b/files/assets/images/emojis/marseytf2spy.webp differ diff --git a/files/assets/images/emojis/marseythegrey.webp b/files/assets/images/emojis/marseythegrey.webp index 522ed8d28..246c4cade 100644 Binary files a/files/assets/images/emojis/marseythegrey.webp and b/files/assets/images/emojis/marseythegrey.webp differ diff --git a/files/assets/images/emojis/marseytheorist.webp b/files/assets/images/emojis/marseytheorist.webp index 09cb80ed3..665adca6e 100644 Binary files a/files/assets/images/emojis/marseytheorist.webp and b/files/assets/images/emojis/marseytheorist.webp differ diff --git a/files/assets/images/emojis/marseytherapist.webp b/files/assets/images/emojis/marseytherapist.webp index a765911fc..5c27d5d7d 100644 Binary files a/files/assets/images/emojis/marseytherapist.webp and b/files/assets/images/emojis/marseytherapist.webp differ diff --git a/files/assets/images/emojis/marseythief.webp b/files/assets/images/emojis/marseythief.webp index ae7f842ab..32368ae30 100644 Binary files a/files/assets/images/emojis/marseythief.webp and b/files/assets/images/emojis/marseythief.webp differ diff --git a/files/assets/images/emojis/marseything.webp b/files/assets/images/emojis/marseything.webp index 9576913bc..e854e6dcb 100644 Binary files a/files/assets/images/emojis/marseything.webp and b/files/assets/images/emojis/marseything.webp differ diff --git a/files/assets/images/emojis/marseything2.webp b/files/assets/images/emojis/marseything2.webp new file mode 100644 index 000000000..2a855e0ab Binary files /dev/null and b/files/assets/images/emojis/marseything2.webp differ diff --git a/files/assets/images/emojis/marseythinkinghallowseve.webp b/files/assets/images/emojis/marseythinkinghallowseve.webp new file mode 100644 index 000000000..2b7028d76 Binary files /dev/null and b/files/assets/images/emojis/marseythinkinghallowseve.webp differ diff --git a/files/assets/images/emojis/marseythinkorino.webp b/files/assets/images/emojis/marseythinkorino.webp index 80ade4d7d..9c21e02f7 100644 Binary files a/files/assets/images/emojis/marseythinkorino.webp and b/files/assets/images/emojis/marseythinkorino.webp differ diff --git a/files/assets/images/emojis/marseythomas.webp b/files/assets/images/emojis/marseythomas.webp index 5ad212098..fafb4b2a7 100644 Binary files a/files/assets/images/emojis/marseythomas.webp and b/files/assets/images/emojis/marseythomas.webp differ diff --git a/files/assets/images/emojis/marseythonk.webp b/files/assets/images/emojis/marseythonk.webp index 75bd25e79..80ccca8c4 100644 Binary files a/files/assets/images/emojis/marseythonk.webp and b/files/assets/images/emojis/marseythonk.webp differ diff --git a/files/assets/images/emojis/marseythroatsinging.webp b/files/assets/images/emojis/marseythroatsinging.webp index 844b054f3..674102fe1 100644 Binary files a/files/assets/images/emojis/marseythroatsinging.webp and b/files/assets/images/emojis/marseythroatsinging.webp differ diff --git a/files/assets/images/emojis/marseythumbsup.webp b/files/assets/images/emojis/marseythumbsup.webp index 7388f32f2..094ec0d4c 100644 Binary files a/files/assets/images/emojis/marseythumbsup.webp and b/files/assets/images/emojis/marseythumbsup.webp differ diff --git a/files/assets/images/emojis/marseytiger.webp b/files/assets/images/emojis/marseytiger.webp index 5c9c7df42..701a60280 100644 Binary files a/files/assets/images/emojis/marseytiger.webp and b/files/assets/images/emojis/marseytiger.webp differ diff --git a/files/assets/images/emojis/marseytigerball.webp b/files/assets/images/emojis/marseytigerball.webp index e5ee187d8..542e246a5 100644 Binary files a/files/assets/images/emojis/marseytigerball.webp and b/files/assets/images/emojis/marseytigerball.webp differ diff --git a/files/assets/images/emojis/marseytigernewyear.webp b/files/assets/images/emojis/marseytigernewyear.webp index 8927da0ca..e96f84604 100644 Binary files a/files/assets/images/emojis/marseytigernewyear.webp and b/files/assets/images/emojis/marseytigernewyear.webp differ diff --git a/files/assets/images/emojis/marseytimbit.webp b/files/assets/images/emojis/marseytimbit.webp index 536f5c854..f852b8455 100644 Binary files a/files/assets/images/emojis/marseytimbit.webp and b/files/assets/images/emojis/marseytimbit.webp differ diff --git a/files/assets/images/emojis/marseytimmy.webp b/files/assets/images/emojis/marseytimmy.webp index afb5bb943..77eae4291 100644 Binary files a/files/assets/images/emojis/marseytimmy.webp and b/files/assets/images/emojis/marseytimmy.webp differ diff --git a/files/assets/images/emojis/marseytinfoil.webp b/files/assets/images/emojis/marseytinfoil.webp index 49d6d787e..0f3fb8d92 100644 Binary files a/files/assets/images/emojis/marseytinfoil.webp and b/files/assets/images/emojis/marseytinfoil.webp differ diff --git a/files/assets/images/emojis/marseytinfoil2.webp b/files/assets/images/emojis/marseytinfoil2.webp index 3b447a4f6..c74386068 100644 Binary files a/files/assets/images/emojis/marseytinfoil2.webp and b/files/assets/images/emojis/marseytinfoil2.webp differ diff --git a/files/assets/images/emojis/marseytiny1.webp b/files/assets/images/emojis/marseytiny1.webp index 42ab72a2a..f84a05b23 100644 Binary files a/files/assets/images/emojis/marseytiny1.webp and b/files/assets/images/emojis/marseytiny1.webp differ diff --git a/files/assets/images/emojis/marseytiny2.webp b/files/assets/images/emojis/marseytiny2.webp index da700b936..c6d2248c9 100644 Binary files a/files/assets/images/emojis/marseytiny2.webp and b/files/assets/images/emojis/marseytiny2.webp differ diff --git a/files/assets/images/emojis/marseytiny3.webp b/files/assets/images/emojis/marseytiny3.webp index 304dd311d..c4e04c503 100644 Binary files a/files/assets/images/emojis/marseytiny3.webp and b/files/assets/images/emojis/marseytiny3.webp differ diff --git a/files/assets/images/emojis/marseytiny4.webp b/files/assets/images/emojis/marseytiny4.webp index 907b08717..9b8558f2a 100644 Binary files a/files/assets/images/emojis/marseytiny4.webp and b/files/assets/images/emojis/marseytiny4.webp differ diff --git a/files/assets/images/emojis/marseytlsm.webp b/files/assets/images/emojis/marseytlsm.webp new file mode 100644 index 000000000..b370f0913 Binary files /dev/null and b/files/assets/images/emojis/marseytlsm.webp differ diff --git a/files/assets/images/emojis/marseytoasterbath.webp b/files/assets/images/emojis/marseytoasterbath.webp index 23b534cd5..b2ba0d4e5 100644 Binary files a/files/assets/images/emojis/marseytoasterbath.webp and b/files/assets/images/emojis/marseytoasterbath.webp differ diff --git a/files/assets/images/emojis/marseytoilet.webp b/files/assets/images/emojis/marseytoilet.webp index 9b7e296fc..dcbdbaf4d 100644 Binary files a/files/assets/images/emojis/marseytoilet.webp and b/files/assets/images/emojis/marseytoilet.webp differ diff --git a/files/assets/images/emojis/marseytom.webp b/files/assets/images/emojis/marseytom.webp index 5332090b3..6967ff1b7 100644 Binary files a/files/assets/images/emojis/marseytom.webp and b/files/assets/images/emojis/marseytom.webp differ diff --git a/files/assets/images/emojis/marseytombstone.webp b/files/assets/images/emojis/marseytombstone.webp index 6bbe8e218..b55c931b8 100644 Binary files a/files/assets/images/emojis/marseytombstone.webp and b/files/assets/images/emojis/marseytombstone.webp differ diff --git a/files/assets/images/emojis/marseytonberry.webp b/files/assets/images/emojis/marseytonberry.webp index 069db91f8..a66759d82 100644 Binary files a/files/assets/images/emojis/marseytonberry.webp and b/files/assets/images/emojis/marseytonberry.webp differ diff --git a/files/assets/images/emojis/marseytrad.webp b/files/assets/images/emojis/marseytrad.webp index d4a69edd2..ed44566d0 100644 Binary files a/files/assets/images/emojis/marseytrad.webp and b/files/assets/images/emojis/marseytrad.webp differ diff --git a/files/assets/images/emojis/marseytrad2.webp b/files/assets/images/emojis/marseytrad2.webp index f274598b3..4aefa3777 100644 Binary files a/files/assets/images/emojis/marseytrad2.webp and b/files/assets/images/emojis/marseytrad2.webp differ diff --git a/files/assets/images/emojis/marseytrain2.webp b/files/assets/images/emojis/marseytrain2.webp index 4e1b0bd17..75f1802a1 100644 Binary files a/files/assets/images/emojis/marseytrain2.webp and b/files/assets/images/emojis/marseytrain2.webp differ diff --git a/files/assets/images/emojis/marseytrans.webp b/files/assets/images/emojis/marseytrans.webp index 5704e6dba..3a26d8fc1 100644 Binary files a/files/assets/images/emojis/marseytrans.webp and b/files/assets/images/emojis/marseytrans.webp differ diff --git a/files/assets/images/emojis/marseytrans2.webp b/files/assets/images/emojis/marseytrans2.webp index ff94ce563..c16066c7f 100644 Binary files a/files/assets/images/emojis/marseytrans2.webp and b/files/assets/images/emojis/marseytrans2.webp differ diff --git a/files/assets/images/emojis/marseytransattentionseeker.webp b/files/assets/images/emojis/marseytransattentionseeker.webp index 249109470..7a11f4694 100644 Binary files a/files/assets/images/emojis/marseytransattentionseeker.webp and b/files/assets/images/emojis/marseytransattentionseeker.webp differ diff --git a/files/assets/images/emojis/marseytransflag.webp b/files/assets/images/emojis/marseytransflag.webp index d901f2a17..c9a8ff2c4 100644 Binary files a/files/assets/images/emojis/marseytransflag.webp and b/files/assets/images/emojis/marseytransflag.webp differ diff --git a/files/assets/images/emojis/marseytransrentfree.webp b/files/assets/images/emojis/marseytransrentfree.webp index 1834535b7..ca651148d 100644 Binary files a/files/assets/images/emojis/marseytransrentfree.webp and b/files/assets/images/emojis/marseytransrentfree.webp differ diff --git a/files/assets/images/emojis/marseytree.webp b/files/assets/images/emojis/marseytree.webp index fb02adace..8d02c191c 100644 Binary files a/files/assets/images/emojis/marseytree.webp and b/files/assets/images/emojis/marseytree.webp differ diff --git a/files/assets/images/emojis/marseytrickortreat.webp b/files/assets/images/emojis/marseytrickortreat.webp index 6f88ed03f..519a3ea19 100644 Binary files a/files/assets/images/emojis/marseytrickortreat.webp and b/files/assets/images/emojis/marseytrickortreat.webp differ diff --git a/files/assets/images/emojis/marseytrogdor.webp b/files/assets/images/emojis/marseytrogdor.webp index 97b1b2742..45a1df2f0 100644 Binary files a/files/assets/images/emojis/marseytrogdor.webp and b/files/assets/images/emojis/marseytrogdor.webp differ diff --git a/files/assets/images/emojis/marseytroll.webp b/files/assets/images/emojis/marseytroll.webp index d59197817..807085cd9 100644 Binary files a/files/assets/images/emojis/marseytroll.webp and b/files/assets/images/emojis/marseytroll.webp differ diff --git a/files/assets/images/emojis/marseytroll2.webp b/files/assets/images/emojis/marseytroll2.webp index 37bbf599c..cd4a702d9 100644 Binary files a/files/assets/images/emojis/marseytroll2.webp and b/files/assets/images/emojis/marseytroll2.webp differ diff --git a/files/assets/images/emojis/marseytrollcrazy.webp b/files/assets/images/emojis/marseytrollcrazy.webp index 50096b2f6..af7b1ea86 100644 Binary files a/files/assets/images/emojis/marseytrollcrazy.webp and b/files/assets/images/emojis/marseytrollcrazy.webp differ diff --git a/files/assets/images/emojis/marseytrollgun.webp b/files/assets/images/emojis/marseytrollgun.webp index 4225d0967..8982ea482 100644 Binary files a/files/assets/images/emojis/marseytrollgun.webp and b/files/assets/images/emojis/marseytrollgun.webp differ diff --git a/files/assets/images/emojis/marseytrollolol.webp b/files/assets/images/emojis/marseytrollolol.webp index 32b1d20bf..f126b33d6 100644 Binary files a/files/assets/images/emojis/marseytrollolol.webp and b/files/assets/images/emojis/marseytrollolol.webp differ diff --git a/files/assets/images/emojis/marseytrotsky.webp b/files/assets/images/emojis/marseytrotsky.webp index 46eedb0c5..5e2382a0a 100644 Binary files a/files/assets/images/emojis/marseytrotsky.webp and b/files/assets/images/emojis/marseytrotsky.webp differ diff --git a/files/assets/images/emojis/marseytroublemaker.webp b/files/assets/images/emojis/marseytroublemaker.webp index 8a4bb7a76..2edc8d677 100644 Binary files a/files/assets/images/emojis/marseytroublemaker.webp and b/files/assets/images/emojis/marseytroublemaker.webp differ diff --git a/files/assets/images/emojis/marseytruck.webp b/files/assets/images/emojis/marseytruck.webp index c2a9557b4..6eef7692b 100644 Binary files a/files/assets/images/emojis/marseytruck.webp and b/files/assets/images/emojis/marseytruck.webp differ diff --git a/files/assets/images/emojis/marseytrump.webp b/files/assets/images/emojis/marseytrump.webp index b4f59eaf3..bc59e9399 100644 Binary files a/files/assets/images/emojis/marseytrump.webp and b/files/assets/images/emojis/marseytrump.webp differ diff --git a/files/assets/images/emojis/marseytrumpgarrison.webp b/files/assets/images/emojis/marseytrumpgarrison.webp index e2b1dd536..9ccf4b48e 100644 Binary files a/files/assets/images/emojis/marseytrumpgarrison.webp and b/files/assets/images/emojis/marseytrumpgarrison.webp differ diff --git a/files/assets/images/emojis/marseytrumpgrill.webp b/files/assets/images/emojis/marseytrumpgrill.webp index 32f1dc7d8..bf6ad407e 100644 Binary files a/files/assets/images/emojis/marseytrumpgrill.webp and b/files/assets/images/emojis/marseytrumpgrill.webp differ diff --git a/files/assets/images/emojis/marseytucker.webp b/files/assets/images/emojis/marseytucker.webp index 1eec63edc..abf2142b7 100644 Binary files a/files/assets/images/emojis/marseytucker.webp and b/files/assets/images/emojis/marseytucker.webp differ diff --git a/files/assets/images/emojis/marseytuckermilkers.webp b/files/assets/images/emojis/marseytuckermilkers.webp index 49ad74515..57e9e244a 100644 Binary files a/files/assets/images/emojis/marseytuckermilkers.webp and b/files/assets/images/emojis/marseytuckermilkers.webp differ diff --git a/files/assets/images/emojis/marseyturban.webp b/files/assets/images/emojis/marseyturban.webp index 07518ac07..6c8dea45e 100644 Binary files a/files/assets/images/emojis/marseyturban.webp and b/files/assets/images/emojis/marseyturban.webp differ diff --git a/files/assets/images/emojis/marseyturkey.webp b/files/assets/images/emojis/marseyturkey.webp index bcb42bded..1a9d6fc58 100644 Binary files a/files/assets/images/emojis/marseyturkey.webp and b/files/assets/images/emojis/marseyturkey.webp differ diff --git a/files/assets/images/emojis/marseyturkeyhappy.webp b/files/assets/images/emojis/marseyturkeyhappy.webp index cd0f0cdba..666244dfb 100644 Binary files a/files/assets/images/emojis/marseyturkeyhappy.webp and b/files/assets/images/emojis/marseyturkeyhappy.webp differ diff --git a/files/assets/images/emojis/marseyturkroach.webp b/files/assets/images/emojis/marseyturkroach.webp index 58b3c754f..3a6e1aec8 100644 Binary files a/files/assets/images/emojis/marseyturkroach.webp and b/files/assets/images/emojis/marseyturkroach.webp differ diff --git a/files/assets/images/emojis/marseyturnedon.webp b/files/assets/images/emojis/marseyturnedon.webp index 01aa8c5af..c666a6f83 100644 Binary files a/files/assets/images/emojis/marseyturnedon.webp and b/files/assets/images/emojis/marseyturnedon.webp differ diff --git a/files/assets/images/emojis/marseytv.webp b/files/assets/images/emojis/marseytv.webp index b383dfdc0..c792cbbe1 100644 Binary files a/files/assets/images/emojis/marseytv.webp and b/files/assets/images/emojis/marseytv.webp differ diff --git a/files/assets/images/emojis/marseytzeentch.webp b/files/assets/images/emojis/marseytzeentch.webp index bb1a0094d..593095bd2 100644 Binary files a/files/assets/images/emojis/marseytzeentch.webp and b/files/assets/images/emojis/marseytzeentch.webp differ diff --git a/files/assets/images/emojis/marseyuglyxmasweater.webp b/files/assets/images/emojis/marseyuglyxmasweater.webp index 69c412965..53d625123 100644 Binary files a/files/assets/images/emojis/marseyuglyxmasweater.webp and b/files/assets/images/emojis/marseyuglyxmasweater.webp differ diff --git a/files/assets/images/emojis/marseyumbreon.webp b/files/assets/images/emojis/marseyumbreon.webp index 63445d4cd..d432dca1a 100644 Binary files a/files/assets/images/emojis/marseyumbreon.webp and b/files/assets/images/emojis/marseyumbreon.webp differ diff --git a/files/assets/images/emojis/marseyumbreon2.webp b/files/assets/images/emojis/marseyumbreon2.webp index 0653781d6..5ac73e0db 100644 Binary files a/files/assets/images/emojis/marseyumbreon2.webp and b/files/assets/images/emojis/marseyumbreon2.webp differ diff --git a/files/assets/images/emojis/marseyunabomber.webp b/files/assets/images/emojis/marseyunabomber.webp index 491293b18..b45245996 100644 Binary files a/files/assets/images/emojis/marseyunabomber.webp and b/files/assets/images/emojis/marseyunabomber.webp differ diff --git a/files/assets/images/emojis/marseyunabomber2.webp b/files/assets/images/emojis/marseyunabomber2.webp index 7006d4f4c..6c4903791 100644 Binary files a/files/assets/images/emojis/marseyunabomber2.webp and b/files/assets/images/emojis/marseyunabomber2.webp differ diff --git a/files/assets/images/emojis/marseyunamused.webp b/files/assets/images/emojis/marseyunamused.webp index a3ce2381c..d226c6afb 100644 Binary files a/files/assets/images/emojis/marseyunamused.webp and b/files/assets/images/emojis/marseyunamused.webp differ diff --git a/files/assets/images/emojis/marseyupset.webp b/files/assets/images/emojis/marseyupset.webp index 8f83e1c97..96d0e81bd 100644 Binary files a/files/assets/images/emojis/marseyupset.webp and b/files/assets/images/emojis/marseyupset.webp differ diff --git a/files/assets/images/emojis/marseyupvote.webp b/files/assets/images/emojis/marseyupvote.webp index 27beabe01..ba9ca720d 100644 Binary files a/files/assets/images/emojis/marseyupvote.webp and b/files/assets/images/emojis/marseyupvote.webp differ diff --git a/files/assets/images/emojis/marseyupvote2.webp b/files/assets/images/emojis/marseyupvote2.webp index 483ef5187..40ee9ce1d 100644 Binary files a/files/assets/images/emojis/marseyupvote2.webp and b/files/assets/images/emojis/marseyupvote2.webp differ diff --git a/files/assets/images/emojis/marseyuwuw.webp b/files/assets/images/emojis/marseyuwuw.webp index 363f48136..09de52b99 100644 Binary files a/files/assets/images/emojis/marseyuwuw.webp and b/files/assets/images/emojis/marseyuwuw.webp differ diff --git a/files/assets/images/emojis/marseyvampeek.webp b/files/assets/images/emojis/marseyvampeek.webp new file mode 100644 index 000000000..ba001032e Binary files /dev/null and b/files/assets/images/emojis/marseyvampeek.webp differ diff --git a/files/assets/images/emojis/marseyvampire.webp b/files/assets/images/emojis/marseyvampire.webp index fd8263f63..c9fd9459f 100644 Binary files a/files/assets/images/emojis/marseyvampire.webp and b/files/assets/images/emojis/marseyvampire.webp differ diff --git a/files/assets/images/emojis/marseyvampirebite.webp b/files/assets/images/emojis/marseyvampirebite.webp index d4f91fce2..5ef49904f 100644 Binary files a/files/assets/images/emojis/marseyvampirebite.webp and b/files/assets/images/emojis/marseyvampirebite.webp differ diff --git a/files/assets/images/emojis/marseyvan.webp b/files/assets/images/emojis/marseyvan.webp index 363686b06..8fd131f54 100644 Binary files a/files/assets/images/emojis/marseyvan.webp and b/files/assets/images/emojis/marseyvan.webp differ diff --git a/files/assets/images/emojis/marseyvapecrying.webp b/files/assets/images/emojis/marseyvapecrying.webp index 9b137f09e..8873ce1fc 100644 Binary files a/files/assets/images/emojis/marseyvapecrying.webp and b/files/assets/images/emojis/marseyvapecrying.webp differ diff --git a/files/assets/images/emojis/marseyvaporeon.webp b/files/assets/images/emojis/marseyvaporeon.webp index 313a9965c..5dc0ef5e5 100644 Binary files a/files/assets/images/emojis/marseyvaporeon.webp and b/files/assets/images/emojis/marseyvaporeon.webp differ diff --git a/files/assets/images/emojis/marseyvargfinnselfdefense.webp b/files/assets/images/emojis/marseyvargfinnselfdefense.webp index de63a8232..8fc0be3de 100644 Binary files a/files/assets/images/emojis/marseyvargfinnselfdefense.webp and b/files/assets/images/emojis/marseyvargfinnselfdefense.webp differ diff --git a/files/assets/images/emojis/marseyvargselfdefense.webp b/files/assets/images/emojis/marseyvargselfdefense.webp index 924cb6a0b..3744db5b6 100644 Binary files a/files/assets/images/emojis/marseyvargselfdefense.webp and b/files/assets/images/emojis/marseyvargselfdefense.webp differ diff --git a/files/assets/images/emojis/marseyvatnik.webp b/files/assets/images/emojis/marseyvatnik.webp index d66ba5d2d..4f432e551 100644 Binary files a/files/assets/images/emojis/marseyvatnik.webp and b/files/assets/images/emojis/marseyvatnik.webp differ diff --git a/files/assets/images/emojis/marseyvaxmaxx.webp b/files/assets/images/emojis/marseyvaxmaxx.webp index 51bea7576..c28cbbf9b 100644 Binary files a/files/assets/images/emojis/marseyvaxmaxx.webp and b/files/assets/images/emojis/marseyvaxmaxx.webp differ diff --git a/files/assets/images/emojis/marseyvelociraptor.webp b/files/assets/images/emojis/marseyvelociraptor.webp index d2ea49ea6..b36917020 100644 Binary files a/files/assets/images/emojis/marseyvelociraptor.webp and b/files/assets/images/emojis/marseyvelociraptor.webp differ diff --git a/files/assets/images/emojis/marseyvengeance.webp b/files/assets/images/emojis/marseyvengeance.webp index 6d9e1c24e..6386821ed 100644 Binary files a/files/assets/images/emojis/marseyvengeance.webp and b/files/assets/images/emojis/marseyvengeance.webp differ diff --git a/files/assets/images/emojis/marseyveryworried.webp b/files/assets/images/emojis/marseyveryworried.webp index 87b1e24e1..e781218e4 100644 Binary files a/files/assets/images/emojis/marseyveryworried.webp and b/files/assets/images/emojis/marseyveryworried.webp differ diff --git a/files/assets/images/emojis/marseyveryworriedfed.webp b/files/assets/images/emojis/marseyveryworriedfed.webp new file mode 100644 index 000000000..92c082a64 Binary files /dev/null and b/files/assets/images/emojis/marseyveryworriedfed.webp differ diff --git a/files/assets/images/emojis/marseyvietnam.webp b/files/assets/images/emojis/marseyvietnam.webp index 764632f07..a99900e64 100644 Binary files a/files/assets/images/emojis/marseyvietnam.webp and b/files/assets/images/emojis/marseyvietnam.webp differ diff --git a/files/assets/images/emojis/marseyvirus.webp b/files/assets/images/emojis/marseyvirus.webp index 4b5bc1b4a..cea164d2b 100644 Binary files a/files/assets/images/emojis/marseyvirus.webp and b/files/assets/images/emojis/marseyvirus.webp differ diff --git a/files/assets/images/emojis/marseyvore.webp b/files/assets/images/emojis/marseyvore.webp index d8f3fcf1e..77ca57686 100644 Binary files a/files/assets/images/emojis/marseyvore.webp and b/files/assets/images/emojis/marseyvore.webp differ diff --git a/files/assets/images/emojis/marseyvore2.webp b/files/assets/images/emojis/marseyvore2.webp index 095739eba..5926670b8 100644 Binary files a/files/assets/images/emojis/marseyvore2.webp and b/files/assets/images/emojis/marseyvore2.webp differ diff --git a/files/assets/images/emojis/marseyvorezombiewolf.webp b/files/assets/images/emojis/marseyvorezombiewolf.webp index be539062c..0de10d04e 100644 Binary files a/files/assets/images/emojis/marseyvorezombiewolf.webp and b/files/assets/images/emojis/marseyvorezombiewolf.webp differ diff --git a/files/assets/images/emojis/marseywagie.webp b/files/assets/images/emojis/marseywagie.webp index 97a2f53f7..a5c637de5 100644 Binary files a/files/assets/images/emojis/marseywagie.webp and b/files/assets/images/emojis/marseywagie.webp differ diff --git a/files/assets/images/emojis/marseywait.webp b/files/assets/images/emojis/marseywait.webp index f1a39394e..197ea677a 100644 Binary files a/files/assets/images/emojis/marseywait.webp and b/files/assets/images/emojis/marseywait.webp differ diff --git a/files/assets/images/emojis/marseywall.webp b/files/assets/images/emojis/marseywall.webp index f9b647458..3e6173444 100644 Binary files a/files/assets/images/emojis/marseywall.webp and b/files/assets/images/emojis/marseywall.webp differ diff --git a/files/assets/images/emojis/marseywallst.webp b/files/assets/images/emojis/marseywallst.webp index ee14fc308..82ec54819 100644 Binary files a/files/assets/images/emojis/marseywallst.webp and b/files/assets/images/emojis/marseywallst.webp differ diff --git a/files/assets/images/emojis/marseywalterwhite.webp b/files/assets/images/emojis/marseywalterwhite.webp index a93146ca9..489cf5e98 100644 Binary files a/files/assets/images/emojis/marseywalterwhite.webp and b/files/assets/images/emojis/marseywalterwhite.webp differ diff --git a/files/assets/images/emojis/marseywarboy.webp b/files/assets/images/emojis/marseywarboy.webp index 1d07f10c4..afc457e4d 100644 Binary files a/files/assets/images/emojis/marseywarboy.webp and b/files/assets/images/emojis/marseywarboy.webp differ diff --git a/files/assets/images/emojis/marseywarhol.webp b/files/assets/images/emojis/marseywarhol.webp index 3643901c1..5beeb521a 100644 Binary files a/files/assets/images/emojis/marseywarhol.webp and b/files/assets/images/emojis/marseywarhol.webp differ diff --git a/files/assets/images/emojis/marseywatchingtv.webp b/files/assets/images/emojis/marseywatchingtv.webp index d68badfac..166631df7 100644 Binary files a/files/assets/images/emojis/marseywatchingtv.webp and b/files/assets/images/emojis/marseywatchingtv.webp differ diff --git a/files/assets/images/emojis/marseywatermark.webp b/files/assets/images/emojis/marseywatermark.webp index 23b567d30..82a988685 100644 Binary files a/files/assets/images/emojis/marseywatermark.webp and b/files/assets/images/emojis/marseywatermark.webp differ diff --git a/files/assets/images/emojis/marseywave.webp b/files/assets/images/emojis/marseywave.webp index 5cf9c9813..0801222bc 100644 Binary files a/files/assets/images/emojis/marseywave.webp and b/files/assets/images/emojis/marseywave.webp differ diff --git a/files/assets/images/emojis/marseyweeb.webp b/files/assets/images/emojis/marseyweeb.webp index b5a85b242..af1a1e75e 100644 Binary files a/files/assets/images/emojis/marseyweeb.webp and b/files/assets/images/emojis/marseyweeb.webp differ diff --git a/files/assets/images/emojis/marseywendy.webp b/files/assets/images/emojis/marseywendy.webp index 3cb66c5fb..8c0f24f51 100644 Binary files a/files/assets/images/emojis/marseywendy.webp and b/files/assets/images/emojis/marseywendy.webp differ diff --git a/files/assets/images/emojis/marseywerewolf.webp b/files/assets/images/emojis/marseywerewolf.webp new file mode 100644 index 000000000..a963b78b3 Binary files /dev/null and b/files/assets/images/emojis/marseywerewolf.webp differ diff --git a/files/assets/images/emojis/marseywhelmed.webp b/files/assets/images/emojis/marseywhelmed.webp index 6b080ca12..22acec24b 100644 Binary files a/files/assets/images/emojis/marseywhelmed.webp and b/files/assets/images/emojis/marseywhelmed.webp differ diff --git a/files/assets/images/emojis/marseywhirlyhat.webp b/files/assets/images/emojis/marseywhirlyhat.webp index 1d80fe2bb..dbfa1d20c 100644 Binary files a/files/assets/images/emojis/marseywhirlyhat.webp and b/files/assets/images/emojis/marseywhirlyhat.webp differ diff --git a/files/assets/images/emojis/marseywhiteflag.webp b/files/assets/images/emojis/marseywhiteflag.webp index a6d3c7a3e..4a210ece3 100644 Binary files a/files/assets/images/emojis/marseywhiteflag.webp and b/files/assets/images/emojis/marseywhiteflag.webp differ diff --git a/files/assets/images/emojis/marseywhitemage.webp b/files/assets/images/emojis/marseywhitemage.webp index 8fe366a37..24b2a5982 100644 Binary files a/files/assets/images/emojis/marseywhitemage.webp and b/files/assets/images/emojis/marseywhitemage.webp differ diff --git a/files/assets/images/emojis/marseywholesome.webp b/files/assets/images/emojis/marseywholesome.webp index a48b72fa9..b7e069c2b 100644 Binary files a/files/assets/images/emojis/marseywholesome.webp and b/files/assets/images/emojis/marseywholesome.webp differ diff --git a/files/assets/images/emojis/marseywholesome2.webp b/files/assets/images/emojis/marseywholesome2.webp index cc7640f80..7bc0c0c8a 100644 Binary files a/files/assets/images/emojis/marseywholesome2.webp and b/files/assets/images/emojis/marseywholesome2.webp differ diff --git a/files/assets/images/emojis/marseywinemom.webp b/files/assets/images/emojis/marseywinemom.webp index ccdd24ad4..5851b6e6b 100644 Binary files a/files/assets/images/emojis/marseywinemom.webp and b/files/assets/images/emojis/marseywinemom.webp differ diff --git a/files/assets/images/emojis/marseywink.webp b/files/assets/images/emojis/marseywink.webp index 60f82c997..b41784172 100644 Binary files a/files/assets/images/emojis/marseywink.webp and b/files/assets/images/emojis/marseywink.webp differ diff --git a/files/assets/images/emojis/marseywink2.webp b/files/assets/images/emojis/marseywink2.webp index 371ec897a..b83825df8 100644 Binary files a/files/assets/images/emojis/marseywink2.webp and b/files/assets/images/emojis/marseywink2.webp differ diff --git a/files/assets/images/emojis/marseywinner.webp b/files/assets/images/emojis/marseywinner.webp index 6dcd5c9a8..ee81210fc 100644 Binary files a/files/assets/images/emojis/marseywinner.webp and b/files/assets/images/emojis/marseywinner.webp differ diff --git a/files/assets/images/emojis/marseywise.webp b/files/assets/images/emojis/marseywise.webp index 5aaa5911a..9bf36ab04 100644 Binary files a/files/assets/images/emojis/marseywise.webp and b/files/assets/images/emojis/marseywise.webp differ diff --git a/files/assets/images/emojis/marseywitch.webp b/files/assets/images/emojis/marseywitch.webp index b1b256f80..fd04d3f9e 100644 Binary files a/files/assets/images/emojis/marseywitch.webp and b/files/assets/images/emojis/marseywitch.webp differ diff --git a/files/assets/images/emojis/marseywitch2.webp b/files/assets/images/emojis/marseywitch2.webp index a419f2b88..168bb8a5f 100644 Binary files a/files/assets/images/emojis/marseywitch2.webp and b/files/assets/images/emojis/marseywitch2.webp differ diff --git a/files/assets/images/emojis/marseywitch3.webp b/files/assets/images/emojis/marseywitch3.webp index a56447e51..a9152acf5 100644 Binary files a/files/assets/images/emojis/marseywitch3.webp and b/files/assets/images/emojis/marseywitch3.webp differ diff --git a/files/assets/images/emojis/marseywizard.webp b/files/assets/images/emojis/marseywizard.webp index 36b52db4b..698318094 100644 Binary files a/files/assets/images/emojis/marseywizard.webp and b/files/assets/images/emojis/marseywizard.webp differ diff --git a/files/assets/images/emojis/marseywoah.webp b/files/assets/images/emojis/marseywoah.webp index 703333578..0b07e6408 100644 Binary files a/files/assets/images/emojis/marseywoah.webp and b/files/assets/images/emojis/marseywoah.webp differ diff --git a/files/assets/images/emojis/marseywolf.webp b/files/assets/images/emojis/marseywolf.webp index d2d3ac669..7261f15aa 100644 Binary files a/files/assets/images/emojis/marseywolf.webp and b/files/assets/images/emojis/marseywolf.webp differ diff --git a/files/assets/images/emojis/marseywolfwalker.webp b/files/assets/images/emojis/marseywolfwalker.webp index f97579c04..4996bc155 100644 Binary files a/files/assets/images/emojis/marseywolfwalker.webp and b/files/assets/images/emojis/marseywolfwalker.webp differ diff --git a/files/assets/images/emojis/marseywomanmoment.webp b/files/assets/images/emojis/marseywomanmoment.webp new file mode 100644 index 000000000..2fa5673b3 Binary files /dev/null and b/files/assets/images/emojis/marseywomanmoment.webp differ diff --git a/files/assets/images/emojis/marseywoodchipper.webp b/files/assets/images/emojis/marseywoodchipper.webp index 4581f95a2..b543902e2 100644 Binary files a/files/assets/images/emojis/marseywoodchipper.webp and b/files/assets/images/emojis/marseywoodchipper.webp differ diff --git a/files/assets/images/emojis/marseywords.webp b/files/assets/images/emojis/marseywords.webp index a57726403..b814b6647 100644 Binary files a/files/assets/images/emojis/marseywords.webp and b/files/assets/images/emojis/marseywords.webp differ diff --git a/files/assets/images/emojis/marseywords2.webp b/files/assets/images/emojis/marseywords2.webp index 5468558e7..d75c80375 100644 Binary files a/files/assets/images/emojis/marseywords2.webp and b/files/assets/images/emojis/marseywords2.webp differ diff --git a/files/assets/images/emojis/marseyworldcup.webp b/files/assets/images/emojis/marseyworldcup.webp index 83d7ef50f..4fa34b0fa 100644 Binary files a/files/assets/images/emojis/marseyworldcup.webp and b/files/assets/images/emojis/marseyworldcup.webp differ diff --git a/files/assets/images/emojis/marseyworried.webp b/files/assets/images/emojis/marseyworried.webp index d92439e3c..6f485c9e9 100644 Binary files a/files/assets/images/emojis/marseyworried.webp and b/files/assets/images/emojis/marseyworried.webp differ diff --git a/files/assets/images/emojis/marseywraith.webp b/files/assets/images/emojis/marseywraith.webp new file mode 100644 index 000000000..b7599212f Binary files /dev/null and b/files/assets/images/emojis/marseywraith.webp differ diff --git a/files/assets/images/emojis/marseywrongthonk.webp b/files/assets/images/emojis/marseywrongthonk.webp index 610afd58b..557a5cc25 100644 Binary files a/files/assets/images/emojis/marseywrongthonk.webp and b/files/assets/images/emojis/marseywrongthonk.webp differ diff --git a/files/assets/images/emojis/marseywtf.webp b/files/assets/images/emojis/marseywtf.webp index 1b1e62138..632894657 100644 Binary files a/files/assets/images/emojis/marseywtf.webp and b/files/assets/images/emojis/marseywtf.webp differ diff --git a/files/assets/images/emojis/marseywtf2.webp b/files/assets/images/emojis/marseywtf2.webp index ee0bdba25..14c215646 100644 Binary files a/files/assets/images/emojis/marseywtf2.webp and b/files/assets/images/emojis/marseywtf2.webp differ diff --git a/files/assets/images/emojis/marseywut.webp b/files/assets/images/emojis/marseywut.webp index 14e7ac336..ba050e6d5 100644 Binary files a/files/assets/images/emojis/marseywut.webp and b/files/assets/images/emojis/marseywut.webp differ diff --git a/files/assets/images/emojis/marseywut2.webp b/files/assets/images/emojis/marseywut2.webp index 177762870..75ea196e9 100644 Binary files a/files/assets/images/emojis/marseywut2.webp and b/files/assets/images/emojis/marseywut2.webp differ diff --git a/files/assets/images/emojis/marseyxd.webp b/files/assets/images/emojis/marseyxd.webp index ae796d5d3..58c0d960e 100644 Binary files a/files/assets/images/emojis/marseyxd.webp and b/files/assets/images/emojis/marseyxd.webp differ diff --git a/files/assets/images/emojis/marseyxdoubt.webp b/files/assets/images/emojis/marseyxdoubt.webp index 9fe089f31..7cc0ec798 100644 Binary files a/files/assets/images/emojis/marseyxdoubt.webp and b/files/assets/images/emojis/marseyxdoubt.webp differ diff --git a/files/assets/images/emojis/marseyxi.webp b/files/assets/images/emojis/marseyxi.webp index ba137300b..5ffa6d696 100644 Binary files a/files/assets/images/emojis/marseyxi.webp and b/files/assets/images/emojis/marseyxi.webp differ diff --git a/files/assets/images/emojis/marseyxmr.webp b/files/assets/images/emojis/marseyxmr.webp index c1170d4ab..7531a901f 100644 Binary files a/files/assets/images/emojis/marseyxmr.webp and b/files/assets/images/emojis/marseyxmr.webp differ diff --git a/files/assets/images/emojis/marseyyass.webp b/files/assets/images/emojis/marseyyass.webp index 55765b70f..2f11ce1e7 100644 Binary files a/files/assets/images/emojis/marseyyass.webp and b/files/assets/images/emojis/marseyyass.webp differ diff --git a/files/assets/images/emojis/marseyyawn.webp b/files/assets/images/emojis/marseyyawn.webp index 86cba0489..be07283f8 100644 Binary files a/files/assets/images/emojis/marseyyawn.webp and b/files/assets/images/emojis/marseyyawn.webp differ diff --git a/files/assets/images/emojis/marseyyeezus.webp b/files/assets/images/emojis/marseyyeezus.webp index 8580a0ec4..5dbb9950d 100644 Binary files a/files/assets/images/emojis/marseyyeezus.webp and b/files/assets/images/emojis/marseyyeezus.webp differ diff --git a/files/assets/images/emojis/marseyyes.webp b/files/assets/images/emojis/marseyyes.webp index c5b217ee2..f7848b225 100644 Binary files a/files/assets/images/emojis/marseyyes.webp and b/files/assets/images/emojis/marseyyes.webp differ diff --git a/files/assets/images/emojis/marseyyeti.webp b/files/assets/images/emojis/marseyyeti.webp index 90396187c..b57d16acc 100644 Binary files a/files/assets/images/emojis/marseyyeti.webp and b/files/assets/images/emojis/marseyyeti.webp differ diff --git a/files/assets/images/emojis/marseyyikes.webp b/files/assets/images/emojis/marseyyikes.webp index f12383cf2..ddf4b2e24 100644 Binary files a/files/assets/images/emojis/marseyyikes.webp and b/files/assets/images/emojis/marseyyikes.webp differ diff --git a/files/assets/images/emojis/marseyyinzer.webp b/files/assets/images/emojis/marseyyinzer.webp index abaec07e0..174140357 100644 Binary files a/files/assets/images/emojis/marseyyinzer.webp and b/files/assets/images/emojis/marseyyinzer.webp differ diff --git a/files/assets/images/emojis/marseyyugi.webp b/files/assets/images/emojis/marseyyugi.webp index 208d8e6df..f5f7a189c 100644 Binary files a/files/assets/images/emojis/marseyyugi.webp and b/files/assets/images/emojis/marseyyugi.webp differ diff --git a/files/assets/images/emojis/marseyza.webp b/files/assets/images/emojis/marseyza.webp index 0f99e563b..9ff696ff0 100644 Binary files a/files/assets/images/emojis/marseyza.webp and b/files/assets/images/emojis/marseyza.webp differ diff --git a/files/assets/images/emojis/marseyzaku.webp b/files/assets/images/emojis/marseyzaku.webp index a2cf8402b..bc5a8925a 100644 Binary files a/files/assets/images/emojis/marseyzaku.webp and b/files/assets/images/emojis/marseyzaku.webp differ diff --git a/files/assets/images/emojis/marseyzizek.webp b/files/assets/images/emojis/marseyzizek.webp index 966ab163b..966a6680f 100644 Binary files a/files/assets/images/emojis/marseyzizek.webp and b/files/assets/images/emojis/marseyzizek.webp differ diff --git a/files/assets/images/emojis/marseyzodiac.webp b/files/assets/images/emojis/marseyzodiac.webp index 7b2c7719b..634da1620 100644 Binary files a/files/assets/images/emojis/marseyzodiac.webp and b/files/assets/images/emojis/marseyzodiac.webp differ diff --git a/files/assets/images/emojis/marseyzodiac2.webp b/files/assets/images/emojis/marseyzodiac2.webp new file mode 100644 index 000000000..95276b8ea Binary files /dev/null and b/files/assets/images/emojis/marseyzodiac2.webp differ diff --git a/files/assets/images/emojis/marseyzombie.webp b/files/assets/images/emojis/marseyzombie.webp index 7046fffd4..4a0286975 100644 Binary files a/files/assets/images/emojis/marseyzombie.webp and b/files/assets/images/emojis/marseyzombie.webp differ diff --git a/files/assets/images/emojis/marseyzombie2.webp b/files/assets/images/emojis/marseyzombie2.webp index de3614ffe..38b496f01 100644 Binary files a/files/assets/images/emojis/marseyzombie2.webp and b/files/assets/images/emojis/marseyzombie2.webp differ diff --git a/files/assets/images/emojis/marseyzombiewolfamogus.webp b/files/assets/images/emojis/marseyzombiewolfamogus.webp index 349dbfcd0..7c1f5b613 100644 Binary files a/files/assets/images/emojis/marseyzombiewolfamogus.webp and b/files/assets/images/emojis/marseyzombiewolfamogus.webp differ diff --git a/files/assets/images/emojis/marseyzombiewolflove.webp b/files/assets/images/emojis/marseyzombiewolflove.webp index 95a9652ea..580353902 100644 Binary files a/files/assets/images/emojis/marseyzombiewolflove.webp and b/files/assets/images/emojis/marseyzombiewolflove.webp differ diff --git a/files/assets/images/emojis/marseyzombiewolfmarseymask.webp b/files/assets/images/emojis/marseyzombiewolfmarseymask.webp index 6bf4eed75..f8cff57ee 100644 Binary files a/files/assets/images/emojis/marseyzombiewolfmarseymask.webp and b/files/assets/images/emojis/marseyzombiewolfmarseymask.webp differ diff --git a/files/assets/images/emojis/marseyzombiewolftrample.webp b/files/assets/images/emojis/marseyzombiewolftrample.webp index 8fd47e091..4434cded0 100644 Binary files a/files/assets/images/emojis/marseyzombiewolftrample.webp and b/files/assets/images/emojis/marseyzombiewolftrample.webp differ diff --git a/files/assets/images/emojis/marseyzoomer.webp b/files/assets/images/emojis/marseyzoomer.webp index 4c3f0d16a..518631466 100644 Binary files a/files/assets/images/emojis/marseyzoomer.webp and b/files/assets/images/emojis/marseyzoomer.webp differ diff --git a/files/assets/images/emojis/marseyzwei.webp b/files/assets/images/emojis/marseyzwei.webp index 8cbb2c4e3..0df1c7fee 100644 Binary files a/files/assets/images/emojis/marseyzwei.webp and b/files/assets/images/emojis/marseyzwei.webp differ diff --git a/files/assets/images/emojis/mcmarsey.webp b/files/assets/images/emojis/mcmarsey.webp index 1d0a2b402..be1fc1eba 100644 Binary files a/files/assets/images/emojis/mcmarsey.webp and b/files/assets/images/emojis/mcmarsey.webp differ diff --git a/files/assets/images/emojis/mongoljak.webp b/files/assets/images/emojis/mongoljak.webp new file mode 100644 index 000000000..ad91a2ea8 Binary files /dev/null and b/files/assets/images/emojis/mongoljak.webp differ diff --git a/files/assets/images/emojis/mussolini.webp b/files/assets/images/emojis/mussolini.webp new file mode 100644 index 000000000..3492e6fb8 Binary files /dev/null and b/files/assets/images/emojis/mussolini.webp differ diff --git a/files/assets/images/emojis/parrot.webp b/files/assets/images/emojis/parrot.webp new file mode 100644 index 000000000..0f1e4c375 Binary files /dev/null and b/files/assets/images/emojis/parrot.webp differ diff --git a/files/assets/images/emojis/parrotaccessible.webp b/files/assets/images/emojis/parrotaccessible.webp new file mode 100644 index 000000000..85cb5dcda Binary files /dev/null and b/files/assets/images/emojis/parrotaccessible.webp differ diff --git a/files/assets/images/emojis/parrotcongaparty.webp b/files/assets/images/emojis/parrotcongaparty.webp new file mode 100644 index 000000000..fed1ba520 Binary files /dev/null and b/files/assets/images/emojis/parrotcongaparty.webp differ diff --git a/files/assets/images/emojis/parrotcop.webp b/files/assets/images/emojis/parrotcop.webp new file mode 100644 index 000000000..d2514c7ca Binary files /dev/null and b/files/assets/images/emojis/parrotcop.webp differ diff --git a/files/assets/images/emojis/parrotevil.webp b/files/assets/images/emojis/parrotevil.webp new file mode 100644 index 000000000..5957d586d Binary files /dev/null and b/files/assets/images/emojis/parrotevil.webp differ diff --git a/files/assets/images/emojis/parrotgithub.webp b/files/assets/images/emojis/parrotgithub.webp new file mode 100644 index 000000000..163c6076b Binary files /dev/null and b/files/assets/images/emojis/parrotgithub.webp differ diff --git a/files/assets/images/emojis/parrothmm.webp b/files/assets/images/emojis/parrothmm.webp new file mode 100644 index 000000000..fa80baaec Binary files /dev/null and b/files/assets/images/emojis/parrothmm.webp differ diff --git a/files/assets/images/emojis/parrothypno.webp b/files/assets/images/emojis/parrothypno.webp new file mode 100644 index 000000000..b6aa5b190 Binary files /dev/null and b/files/assets/images/emojis/parrothypno.webp differ diff --git a/files/assets/images/emojis/parrotimposter.webp b/files/assets/images/emojis/parrotimposter.webp new file mode 100644 index 000000000..37ff1040f Binary files /dev/null and b/files/assets/images/emojis/parrotimposter.webp differ diff --git a/files/assets/images/emojis/parrotisrael.webp b/files/assets/images/emojis/parrotisrael.webp new file mode 100644 index 000000000..7f35f05b7 Binary files /dev/null and b/files/assets/images/emojis/parrotisrael.webp differ diff --git a/files/assets/images/emojis/parrotkazakhstan.webp b/files/assets/images/emojis/parrotkazakhstan.webp new file mode 100644 index 000000000..38224c31c Binary files /dev/null and b/files/assets/images/emojis/parrotkazakhstan.webp differ diff --git a/files/assets/images/emojis/parrotmergetrain.webp b/files/assets/images/emojis/parrotmergetrain.webp new file mode 100644 index 000000000..9005cd8ba Binary files /dev/null and b/files/assets/images/emojis/parrotmergetrain.webp differ diff --git a/files/assets/images/emojis/parrotmoonwalking.webp b/files/assets/images/emojis/parrotmoonwalking.webp new file mode 100644 index 000000000..814dc2d86 Binary files /dev/null and b/files/assets/images/emojis/parrotmoonwalking.webp differ diff --git a/files/assets/images/emojis/parrotportalblue.webp b/files/assets/images/emojis/parrotportalblue.webp new file mode 100644 index 000000000..8d924f17e Binary files /dev/null and b/files/assets/images/emojis/parrotportalblue.webp differ diff --git a/files/assets/images/emojis/parrotportalorange.webp b/files/assets/images/emojis/parrotportalorange.webp new file mode 100644 index 000000000..81dfb3f5c Binary files /dev/null and b/files/assets/images/emojis/parrotportalorange.webp differ diff --git a/files/assets/images/emojis/parrotpumpkin.webp b/files/assets/images/emojis/parrotpumpkin.webp new file mode 100644 index 000000000..96125621b Binary files /dev/null and b/files/assets/images/emojis/parrotpumpkin.webp differ diff --git a/files/assets/images/emojis/parrotrevolution.webp b/files/assets/images/emojis/parrotrevolution.webp new file mode 100644 index 000000000..8c3fdfbb8 Binary files /dev/null and b/files/assets/images/emojis/parrotrevolution.webp differ diff --git a/files/assets/images/emojis/parrotrip.webp b/files/assets/images/emojis/parrotrip.webp new file mode 100644 index 000000000..81187440e Binary files /dev/null and b/files/assets/images/emojis/parrotrip.webp differ diff --git a/files/assets/images/emojis/parrotscience.webp b/files/assets/images/emojis/parrotscience.webp new file mode 100644 index 000000000..4e80fac8b Binary files /dev/null and b/files/assets/images/emojis/parrotscience.webp differ diff --git a/files/assets/images/emojis/parrotshort.webp b/files/assets/images/emojis/parrotshort.webp new file mode 100644 index 000000000..9b3c4ca6a Binary files /dev/null and b/files/assets/images/emojis/parrotshort.webp differ diff --git a/files/assets/images/emojis/parrotsleeping.webp b/files/assets/images/emojis/parrotsleeping.webp new file mode 100644 index 000000000..1caa054d2 Binary files /dev/null and b/files/assets/images/emojis/parrotsleeping.webp differ diff --git a/files/assets/images/emojis/parrotslow.webp b/files/assets/images/emojis/parrotslow.webp new file mode 100644 index 000000000..241ed54a5 Binary files /dev/null and b/files/assets/images/emojis/parrotslow.webp differ diff --git a/files/assets/images/emojis/parrottrans.webp b/files/assets/images/emojis/parrottrans.webp new file mode 100644 index 000000000..2693f8149 Binary files /dev/null and b/files/assets/images/emojis/parrottrans.webp differ diff --git a/files/assets/images/emojis/parrotultrafast.webp b/files/assets/images/emojis/parrotultrafast.webp new file mode 100644 index 000000000..3fd85bc91 Binary files /dev/null and b/files/assets/images/emojis/parrotultrafast.webp differ diff --git a/files/assets/images/emojis/parrotunitedstatesofamerica.webp b/files/assets/images/emojis/parrotunitedstatesofamerica.webp new file mode 100644 index 000000000..f9e1ba14b Binary files /dev/null and b/files/assets/images/emojis/parrotunitedstatesofamerica.webp differ diff --git a/files/assets/images/emojis/parrotwitnessprotection.webp b/files/assets/images/emojis/parrotwitnessprotection.webp new file mode 100644 index 000000000..38bc2718a Binary files /dev/null and b/files/assets/images/emojis/parrotwitnessprotection.webp differ diff --git a/files/assets/images/emojis/parrotzombie.webp b/files/assets/images/emojis/parrotzombie.webp new file mode 100644 index 000000000..6d18f78cc Binary files /dev/null and b/files/assets/images/emojis/parrotzombie.webp differ diff --git a/files/assets/images/emojis/percent.webp b/files/assets/images/emojis/percent.webp new file mode 100644 index 000000000..4a3106a30 Binary files /dev/null and b/files/assets/images/emojis/percent.webp differ diff --git a/files/assets/images/emojis/quotation.webp b/files/assets/images/emojis/quotation.webp new file mode 100644 index 000000000..e66edf177 Binary files /dev/null and b/files/assets/images/emojis/quotation.webp differ diff --git a/files/assets/images/emojis/realisticelephant.webp b/files/assets/images/emojis/realisticelephant.webp new file mode 100644 index 000000000..b3b1990a6 Binary files /dev/null and b/files/assets/images/emojis/realisticelephant.webp differ diff --git a/files/assets/images/emojis/ripbozo.webp b/files/assets/images/emojis/ripbozo.webp index 6e1fde85a..b90cddd7f 100644 Binary files a/files/assets/images/emojis/ripbozo.webp and b/files/assets/images/emojis/ripbozo.webp differ diff --git a/files/assets/images/emojis/scaryasianwife.webp b/files/assets/images/emojis/scaryasianwife.webp new file mode 100644 index 000000000..27f7ff2ee Binary files /dev/null and b/files/assets/images/emojis/scaryasianwife.webp differ diff --git a/files/assets/images/emojis/schopenmarsey.webp b/files/assets/images/emojis/schopenmarsey.webp index 523a42456..b87246739 100644 Binary files a/files/assets/images/emojis/schopenmarsey.webp and b/files/assets/images/emojis/schopenmarsey.webp differ diff --git a/files/assets/images/emojis/sharkmarsey.webp b/files/assets/images/emojis/sharkmarsey.webp index 57a55d5b1..945ed1676 100644 Binary files a/files/assets/images/emojis/sharkmarsey.webp and b/files/assets/images/emojis/sharkmarsey.webp differ diff --git a/files/assets/images/emojis/sharkydinosaur.webp b/files/assets/images/emojis/sharkydinosaur.webp new file mode 100644 index 000000000..b1b546e89 Binary files /dev/null and b/files/assets/images/emojis/sharkydinosaur.webp differ diff --git a/files/assets/images/emojis/sharkymegalodon.webp b/files/assets/images/emojis/sharkymegalodon.webp new file mode 100644 index 000000000..09acb4b97 Binary files /dev/null and b/files/assets/images/emojis/sharkymegalodon.webp differ diff --git a/files/assets/images/emojis/sher.webp b/files/assets/images/emojis/sher.webp index 8c36f31ac..e9d3c6725 100644 Binary files a/files/assets/images/emojis/sher.webp and b/files/assets/images/emojis/sher.webp differ diff --git a/files/assets/images/emojis/sherpat.webp b/files/assets/images/emojis/sherpat.webp index 8c36f31ac..e9d3c6725 100644 Binary files a/files/assets/images/emojis/sherpat.webp and b/files/assets/images/emojis/sherpat.webp differ diff --git a/files/assets/images/emojis/shorthairasiangirl.webp b/files/assets/images/emojis/shorthairasiangirl.webp new file mode 100644 index 000000000..a4aae0704 Binary files /dev/null and b/files/assets/images/emojis/shorthairasiangirl.webp differ diff --git a/files/assets/images/emojis/singaporeansoldierjak.webp b/files/assets/images/emojis/singaporeansoldierjak.webp new file mode 100644 index 000000000..2da7b6c21 Binary files /dev/null and b/files/assets/images/emojis/singaporeansoldierjak.webp differ diff --git a/files/assets/images/emojis/sneedbuddy.webp b/files/assets/images/emojis/sneedbuddy.webp new file mode 100644 index 000000000..59be60c8f Binary files /dev/null and b/files/assets/images/emojis/sneedbuddy.webp differ diff --git a/files/assets/images/emojis/sneedcat.webp b/files/assets/images/emojis/sneedcat.webp new file mode 100644 index 000000000..42eca9609 Binary files /dev/null and b/files/assets/images/emojis/sneedcat.webp differ diff --git a/files/assets/images/emojis/soren.webp b/files/assets/images/emojis/soren.webp new file mode 100644 index 000000000..1fc9cb57a Binary files /dev/null and b/files/assets/images/emojis/soren.webp differ diff --git a/files/assets/images/emojis/soy4dchess.webp b/files/assets/images/emojis/soy4dchess.webp new file mode 100644 index 000000000..56e936ae3 Binary files /dev/null and b/files/assets/images/emojis/soy4dchess.webp differ diff --git a/files/assets/images/emojis/soyjaktantrum.webp b/files/assets/images/emojis/soyjaktantrum.webp new file mode 100644 index 000000000..bac7c12eb Binary files /dev/null and b/files/assets/images/emojis/soyjaktantrum.webp differ diff --git a/files/assets/images/emojis/srdinepoppy.webp b/files/assets/images/emojis/srdinepoppy.webp new file mode 100644 index 000000000..4c002799b Binary files /dev/null and b/files/assets/images/emojis/srdinepoppy.webp differ diff --git a/files/assets/images/emojis/stoning.webp b/files/assets/images/emojis/stoning.webp new file mode 100644 index 000000000..064aa1819 Binary files /dev/null and b/files/assets/images/emojis/stoning.webp differ diff --git a/files/assets/images/emojis/stoningpills.webp b/files/assets/images/emojis/stoningpills.webp new file mode 100644 index 000000000..1710d074b Binary files /dev/null and b/files/assets/images/emojis/stoningpills.webp differ diff --git a/files/assets/images/emojis/suprisedasianwife.webp b/files/assets/images/emojis/suprisedasianwife.webp new file mode 100644 index 000000000..bbf8a88ca Binary files /dev/null and b/files/assets/images/emojis/suprisedasianwife.webp differ diff --git a/files/assets/images/emojis/taylaugh.webp b/files/assets/images/emojis/taylaugh.webp index 3a8d7d4fc..604da7535 100644 Binary files a/files/assets/images/emojis/taylaugh.webp and b/files/assets/images/emojis/taylaugh.webp differ diff --git a/files/assets/images/emojis/thumbdown.webp b/files/assets/images/emojis/thumbdown.webp new file mode 100644 index 000000000..b003b238b Binary files /dev/null and b/files/assets/images/emojis/thumbdown.webp differ diff --git a/files/assets/images/emojis/thumbup.webp b/files/assets/images/emojis/thumbup.webp new file mode 100644 index 000000000..68685f252 Binary files /dev/null and b/files/assets/images/emojis/thumbup.webp differ diff --git a/files/assets/images/emojis/tiawanesesoldierjak.webp b/files/assets/images/emojis/tiawanesesoldierjak.webp new file mode 100644 index 000000000..bfb058fcd Binary files /dev/null and b/files/assets/images/emojis/tiawanesesoldierjak.webp differ diff --git a/files/assets/images/emojis/upsoren.webp b/files/assets/images/emojis/upsoren.webp new file mode 100644 index 000000000..a1c5179a9 Binary files /dev/null and b/files/assets/images/emojis/upsoren.webp differ diff --git a/files/assets/images/emojis/witheredricefarmer.webp b/files/assets/images/emojis/witheredricefarmer.webp new file mode 100644 index 000000000..0ac4ee7b3 Binary files /dev/null and b/files/assets/images/emojis/witheredricefarmer.webp differ diff --git a/files/assets/images/emojis/wolfmarseyhead.webp b/files/assets/images/emojis/wolfmarseyhead.webp index 8d9001696..1117b31ac 100644 Binary files a/files/assets/images/emojis/wolfmarseyhead.webp and b/files/assets/images/emojis/wolfmarseyhead.webp differ diff --git a/files/assets/images/emojis/wolfmarseymask.webp b/files/assets/images/emojis/wolfmarseymask.webp index f89745262..412899c7e 100644 Binary files a/files/assets/images/emojis/wolfmarseymask.webp and b/files/assets/images/emojis/wolfmarseymask.webp differ diff --git a/files/assets/images/emojis/wolfpat.webp b/files/assets/images/emojis/wolfpat.webp index 4356d0b7c..7c57f8483 100644 Binary files a/files/assets/images/emojis/wolfpat.webp and b/files/assets/images/emojis/wolfpat.webp differ diff --git a/files/assets/images/emojis/wolfpat2.webp b/files/assets/images/emojis/wolfpat2.webp index 57a7a6a1a..23e646b50 100644 Binary files a/files/assets/images/emojis/wolfpat2.webp and b/files/assets/images/emojis/wolfpat2.webp differ diff --git a/files/assets/images/emojis/yakuzajak.webp b/files/assets/images/emojis/yakuzajak.webp new file mode 100644 index 000000000..771871ef7 Binary files /dev/null and b/files/assets/images/emojis/yakuzajak.webp differ diff --git a/files/assets/images/firework-explosion.webp b/files/assets/images/firework-explosion.webp index d04a68c57..e0eae598a 100644 Binary files a/files/assets/images/firework-explosion.webp and b/files/assets/images/firework-explosion.webp differ diff --git a/files/assets/images/firework-trail.webp b/files/assets/images/firework-trail.webp index 7c16c4506..9baad5800 100644 Binary files a/files/assets/images/firework-trail.webp and b/files/assets/images/firework-trail.webp differ diff --git a/files/assets/images/hats/A Beautiful Mind.webp b/files/assets/images/hats/A Beautiful Mind.webp index 0c79a5d9b..f0414367b 100644 Binary files a/files/assets/images/hats/A Beautiful Mind.webp and b/files/assets/images/hats/A Beautiful Mind.webp differ diff --git a/files/assets/images/hats/Afonso 3.webp b/files/assets/images/hats/Afonso 3.webp new file mode 100644 index 000000000..17794db4e Binary files /dev/null and b/files/assets/images/hats/Afonso 3.webp differ diff --git a/files/assets/images/hats/BUBBLES.webp b/files/assets/images/hats/BUBBLES.webp index 5fa5d4271..a4c379b82 100644 Binary files a/files/assets/images/hats/BUBBLES.webp and b/files/assets/images/hats/BUBBLES.webp differ diff --git a/files/assets/images/hats/Balloons I.webp b/files/assets/images/hats/Balloons I.webp new file mode 100644 index 000000000..3970b914f Binary files /dev/null and b/files/assets/images/hats/Balloons I.webp differ diff --git a/files/assets/images/hats/Balloons II.webp b/files/assets/images/hats/Balloons II.webp new file mode 100644 index 000000000..1c80a0891 Binary files /dev/null and b/files/assets/images/hats/Balloons II.webp differ diff --git a/files/assets/images/hats/Bartman.webp b/files/assets/images/hats/Bartman.webp new file mode 100644 index 000000000..bfac2179c Binary files /dev/null and b/files/assets/images/hats/Bartman.webp differ diff --git a/files/assets/images/hats/Bats.webp b/files/assets/images/hats/Bats.webp index 80efb2411..38e1bc645 100644 Binary files a/files/assets/images/hats/Bats.webp and b/files/assets/images/hats/Bats.webp differ diff --git a/files/assets/images/hats/Bell Pepper (red).webp b/files/assets/images/hats/Bell Pepper (red).webp new file mode 100644 index 000000000..b03b77049 Binary files /dev/null and b/files/assets/images/hats/Bell Pepper (red).webp differ diff --git a/files/assets/images/hats/Bell pepper (green).webp b/files/assets/images/hats/Bell pepper (green).webp new file mode 100644 index 000000000..2469ff443 Binary files /dev/null and b/files/assets/images/hats/Bell pepper (green).webp differ diff --git a/files/assets/images/hats/Bell pepper (yellow).webp b/files/assets/images/hats/Bell pepper (yellow).webp new file mode 100644 index 000000000..34ddb5c24 Binary files /dev/null and b/files/assets/images/hats/Bell pepper (yellow).webp differ diff --git a/files/assets/images/hats/Blood Rain.webp b/files/assets/images/hats/Blood Rain.webp new file mode 100644 index 000000000..ed3a6899b Binary files /dev/null and b/files/assets/images/hats/Blood Rain.webp differ diff --git a/files/assets/images/hats/Bloody Tusks.webp b/files/assets/images/hats/Bloody Tusks.webp new file mode 100644 index 000000000..b0b113674 Binary files /dev/null and b/files/assets/images/hats/Bloody Tusks.webp differ diff --git a/files/assets/images/hats/Booba2.webp b/files/assets/images/hats/Booba2.webp index 4d85cdafa..f3e57f5b7 100644 Binary files a/files/assets/images/hats/Booba2.webp and b/files/assets/images/hats/Booba2.webp differ diff --git a/files/assets/images/hats/Bowl.webp b/files/assets/images/hats/Bowl.webp new file mode 100644 index 000000000..967ce80ea Binary files /dev/null and b/files/assets/images/hats/Bowl.webp differ diff --git a/files/assets/images/hats/Buried.webp b/files/assets/images/hats/Buried.webp new file mode 100644 index 000000000..8c6ba8c89 Binary files /dev/null and b/files/assets/images/hats/Buried.webp differ diff --git a/files/assets/images/hats/Butterflies.webp b/files/assets/images/hats/Butterflies.webp index e6e11f30c..4faec9082 100644 Binary files a/files/assets/images/hats/Butterflies.webp and b/files/assets/images/hats/Butterflies.webp differ diff --git a/files/assets/images/hats/Cheers.webp b/files/assets/images/hats/Cheers.webp new file mode 100644 index 000000000..9dba7ab23 Binary files /dev/null and b/files/assets/images/hats/Cheers.webp differ diff --git a/files/assets/images/hats/Cloudy.webp b/files/assets/images/hats/Cloudy.webp index a6052556c..507e108a5 100644 Binary files a/files/assets/images/hats/Cloudy.webp and b/files/assets/images/hats/Cloudy.webp differ diff --git a/files/assets/images/hats/Coin Fall (green).webp b/files/assets/images/hats/Coin Fall (green).webp new file mode 100644 index 000000000..822764d2f Binary files /dev/null and b/files/assets/images/hats/Coin Fall (green).webp differ diff --git a/files/assets/images/hats/Coin Fall (red).webp b/files/assets/images/hats/Coin Fall (red).webp new file mode 100644 index 000000000..3dab09453 Binary files /dev/null and b/files/assets/images/hats/Coin Fall (red).webp differ diff --git a/files/assets/images/hats/Coins.webp b/files/assets/images/hats/Coins.webp index e83c62fd5..fc6cbaeb2 100644 Binary files a/files/assets/images/hats/Coins.webp and b/files/assets/images/hats/Coins.webp differ diff --git a/files/assets/images/hats/Confetti.webp b/files/assets/images/hats/Confetti.webp index c9dfe6208..861a1c0bd 100644 Binary files a/files/assets/images/hats/Confetti.webp and b/files/assets/images/hats/Confetti.webp differ diff --git a/files/assets/images/hats/Cottagecore.webp b/files/assets/images/hats/Cottagecore.webp index b6dceaaf1..e0973d914 100644 Binary files a/files/assets/images/hats/Cottagecore.webp and b/files/assets/images/hats/Cottagecore.webp differ diff --git a/files/assets/images/hats/Cursor.webp b/files/assets/images/hats/Cursor.webp index 8af9ea6bb..a951c7961 100644 Binary files a/files/assets/images/hats/Cursor.webp and b/files/assets/images/hats/Cursor.webp differ diff --git a/files/assets/images/hats/Demoman.webp b/files/assets/images/hats/Demoman.webp index e7d52c7ec..a14eecbe8 100644 Binary files a/files/assets/images/hats/Demoman.webp and b/files/assets/images/hats/Demoman.webp differ diff --git a/files/assets/images/hats/Dishonored Overseer mask.webp b/files/assets/images/hats/Dishonored Overseer mask.webp new file mode 100644 index 000000000..b8036ba97 Binary files /dev/null and b/files/assets/images/hats/Dishonored Overseer mask.webp differ diff --git a/files/assets/images/hats/Duel Wielding 2.webp b/files/assets/images/hats/Duel Wielding 2.webp new file mode 100644 index 000000000..ba589beae Binary files /dev/null and b/files/assets/images/hats/Duel Wielding 2.webp differ diff --git a/files/assets/images/hats/EldenRing.webp b/files/assets/images/hats/EldenRing.webp new file mode 100644 index 000000000..510952f2d Binary files /dev/null and b/files/assets/images/hats/EldenRing.webp differ diff --git a/files/assets/images/hats/Elite Pedo Sniper.webp b/files/assets/images/hats/Elite Pedo Sniper.webp new file mode 100644 index 000000000..8f77498d0 Binary files /dev/null and b/files/assets/images/hats/Elite Pedo Sniper.webp differ diff --git a/files/assets/images/hats/Engineer.webp b/files/assets/images/hats/Engineer.webp index da5d2251c..5dabc7c38 100644 Binary files a/files/assets/images/hats/Engineer.webp and b/files/assets/images/hats/Engineer.webp differ diff --git a/files/assets/images/hats/FDJ.webp b/files/assets/images/hats/FDJ.webp new file mode 100644 index 000000000..aa30864f7 Binary files /dev/null and b/files/assets/images/hats/FDJ.webp differ diff --git a/files/assets/images/hats/Fedora (ice).webp b/files/assets/images/hats/Fedora (ice).webp new file mode 100644 index 000000000..502213974 Binary files /dev/null and b/files/assets/images/hats/Fedora (ice).webp differ diff --git a/files/assets/images/hats/Gambler.webp b/files/assets/images/hats/Gambler.webp new file mode 100644 index 000000000..3152840fb Binary files /dev/null and b/files/assets/images/hats/Gambler.webp differ diff --git a/files/assets/images/hats/Globohomo.webp b/files/assets/images/hats/Globohomo.webp index 128520332..e88af1a93 100644 Binary files a/files/assets/images/hats/Globohomo.webp and b/files/assets/images/hats/Globohomo.webp differ diff --git a/files/assets/images/hats/Haunted.webp b/files/assets/images/hats/Haunted.webp new file mode 100644 index 000000000..3ee02fe15 Binary files /dev/null and b/files/assets/images/hats/Haunted.webp differ diff --git a/files/assets/images/hats/Heart Poof.webp b/files/assets/images/hats/Heart Poof.webp new file mode 100644 index 000000000..0bee1dda5 Binary files /dev/null and b/files/assets/images/hats/Heart Poof.webp differ diff --git a/files/assets/images/hats/I love STIMS.webp b/files/assets/images/hats/I love STIMS.webp new file mode 100644 index 000000000..440f9fe1f Binary files /dev/null and b/files/assets/images/hats/I love STIMS.webp differ diff --git a/files/assets/images/hats/Imperial Japan.webp b/files/assets/images/hats/Imperial Japan.webp new file mode 100644 index 000000000..30563dd23 Binary files /dev/null and b/files/assets/images/hats/Imperial Japan.webp differ diff --git a/files/assets/images/hats/Italian Sin.webp b/files/assets/images/hats/Italian Sin.webp new file mode 100644 index 000000000..ade61a228 Binary files /dev/null and b/files/assets/images/hats/Italian Sin.webp differ diff --git a/files/assets/images/hats/Jellyfish Fields.webp b/files/assets/images/hats/Jellyfish Fields.webp new file mode 100644 index 000000000..4d4a023a7 Binary files /dev/null and b/files/assets/images/hats/Jellyfish Fields.webp differ diff --git a/files/assets/images/hats/Kasa 1.webp b/files/assets/images/hats/Kasa 1.webp new file mode 100644 index 000000000..e42bcc248 Binary files /dev/null and b/files/assets/images/hats/Kasa 1.webp differ diff --git a/files/assets/images/hats/Kasa 2.webp b/files/assets/images/hats/Kasa 2.webp new file mode 100644 index 000000000..b1e023281 Binary files /dev/null and b/files/assets/images/hats/Kasa 2.webp differ diff --git a/files/assets/images/hats/Kasa 3.webp b/files/assets/images/hats/Kasa 3.webp new file mode 100644 index 000000000..25a266199 Binary files /dev/null and b/files/assets/images/hats/Kasa 3.webp differ diff --git a/files/assets/images/hats/Lantern head.webp b/files/assets/images/hats/Lantern head.webp new file mode 100644 index 000000000..823eeef98 Binary files /dev/null and b/files/assets/images/hats/Lantern head.webp differ diff --git a/files/assets/images/hats/Lightning strike.webp b/files/assets/images/hats/Lightning strike.webp new file mode 100644 index 000000000..af97229bb Binary files /dev/null and b/files/assets/images/hats/Lightning strike.webp differ diff --git a/files/assets/images/hats/Loading.webp b/files/assets/images/hats/Loading.webp index fcc2a12bf..1279c30ee 100644 Binary files a/files/assets/images/hats/Loading.webp and b/files/assets/images/hats/Loading.webp differ diff --git a/files/assets/images/hats/Make It Rain.webp b/files/assets/images/hats/Make It Rain.webp new file mode 100644 index 000000000..816daf930 Binary files /dev/null and b/files/assets/images/hats/Make It Rain.webp differ diff --git a/files/assets/images/hats/Nicholas Cage Vore.webp b/files/assets/images/hats/Nicholas Cage Vore.webp new file mode 100644 index 000000000..84b488203 Binary files /dev/null and b/files/assets/images/hats/Nicholas Cage Vore.webp differ diff --git a/files/assets/images/hats/Niconico.webp b/files/assets/images/hats/Niconico.webp index d06bdcbda..d36fe90de 100644 Binary files a/files/assets/images/hats/Niconico.webp and b/files/assets/images/hats/Niconico.webp differ diff --git a/files/assets/images/hats/Noble 6 helmet.webp b/files/assets/images/hats/Noble 6 helmet.webp new file mode 100644 index 000000000..95f054566 Binary files /dev/null and b/files/assets/images/hats/Noble 6 helmet.webp differ diff --git a/files/assets/images/hats/Nose.webp b/files/assets/images/hats/Nose.webp new file mode 100644 index 000000000..4181fb035 Binary files /dev/null and b/files/assets/images/hats/Nose.webp differ diff --git a/files/assets/images/hats/Patrick Lick.webp b/files/assets/images/hats/Patrick Lick.webp new file mode 100644 index 000000000..bc9d7f64b Binary files /dev/null and b/files/assets/images/hats/Patrick Lick.webp differ diff --git a/files/assets/images/hats/Pinwheels.webp b/files/assets/images/hats/Pinwheels.webp index 08a039b80..b86aee749 100644 Binary files a/files/assets/images/hats/Pinwheels.webp and b/files/assets/images/hats/Pinwheels.webp differ diff --git a/files/assets/images/hats/Proud Virgin.webp b/files/assets/images/hats/Proud Virgin.webp new file mode 100644 index 000000000..8de46decb Binary files /dev/null and b/files/assets/images/hats/Proud Virgin.webp differ diff --git a/files/assets/images/hats/Psychedelic.webp b/files/assets/images/hats/Psychedelic.webp new file mode 100644 index 000000000..ea438a10f Binary files /dev/null and b/files/assets/images/hats/Psychedelic.webp differ diff --git a/files/assets/images/hats/Punished Snake.webp b/files/assets/images/hats/Punished Snake.webp new file mode 100644 index 000000000..ec041bcc0 Binary files /dev/null and b/files/assets/images/hats/Punished Snake.webp differ diff --git a/files/assets/images/hats/RIP BOZO.webp b/files/assets/images/hats/RIP BOZO.webp new file mode 100644 index 000000000..33a642946 Binary files /dev/null and b/files/assets/images/hats/RIP BOZO.webp differ diff --git a/files/assets/images/hats/Racecar Hat.webp b/files/assets/images/hats/Racecar Hat.webp new file mode 100644 index 000000000..c558d5dfc Binary files /dev/null and b/files/assets/images/hats/Racecar Hat.webp differ diff --git a/files/assets/images/hats/Rain.webp b/files/assets/images/hats/Rain.webp index 0c804a265..554b27de4 100644 Binary files a/files/assets/images/hats/Rain.webp and b/files/assets/images/hats/Rain.webp differ diff --git a/files/assets/images/hats/Rascal.webp b/files/assets/images/hats/Rascal.webp new file mode 100644 index 000000000..aebe1a2f4 Binary files /dev/null and b/files/assets/images/hats/Rascal.webp differ diff --git a/files/assets/images/hats/Red Ducky.webp b/files/assets/images/hats/Red Ducky.webp new file mode 100644 index 000000000..1031c1533 Binary files /dev/null and b/files/assets/images/hats/Red Ducky.webp differ diff --git a/files/assets/images/hats/Rocket League.webp b/files/assets/images/hats/Rocket League.webp new file mode 100644 index 000000000..c20d08c64 Binary files /dev/null and b/files/assets/images/hats/Rocket League.webp differ diff --git a/files/assets/images/hats/Roulette.webp b/files/assets/images/hats/Roulette.webp index bd644eb56..f2ae4def3 100644 Binary files a/files/assets/images/hats/Roulette.webp and b/files/assets/images/hats/Roulette.webp differ diff --git a/files/assets/images/hats/Shovel Knight.webp b/files/assets/images/hats/Shovel Knight.webp new file mode 100644 index 000000000..088c2db8a Binary files /dev/null and b/files/assets/images/hats/Shovel Knight.webp differ diff --git a/files/assets/images/hats/Sleepy.webp b/files/assets/images/hats/Sleepy.webp index ffea6af20..442dd151b 100644 Binary files a/files/assets/images/hats/Sleepy.webp and b/files/assets/images/hats/Sleepy.webp differ diff --git a/files/assets/images/hats/Snekshat.webp b/files/assets/images/hats/Snekshat.webp index 044372b26..400888486 100644 Binary files a/files/assets/images/hats/Snekshat.webp and b/files/assets/images/hats/Snekshat.webp differ diff --git a/files/assets/images/hats/Sniffer.webp b/files/assets/images/hats/Sniffer.webp new file mode 100644 index 000000000..e57e28561 Binary files /dev/null and b/files/assets/images/hats/Sniffer.webp differ diff --git a/files/assets/images/hats/Sparkles.webp b/files/assets/images/hats/Sparkles.webp index dc3b49fdb..f0a785919 100644 Binary files a/files/assets/images/hats/Sparkles.webp and b/files/assets/images/hats/Sparkles.webp differ diff --git a/files/assets/images/hats/Spotlight.webp b/files/assets/images/hats/Spotlight.webp index 688fc0dba..a418d861a 100644 Binary files a/files/assets/images/hats/Spotlight.webp and b/files/assets/images/hats/Spotlight.webp differ diff --git a/files/assets/images/hats/Starfall.webp b/files/assets/images/hats/Starfall.webp new file mode 100644 index 000000000..9cd871141 Binary files /dev/null and b/files/assets/images/hats/Starfall.webp differ diff --git a/files/assets/images/hats/Stinky.webp b/files/assets/images/hats/Stinky.webp index 03c91b265..d4e93fe25 100644 Binary files a/files/assets/images/hats/Stinky.webp and b/files/assets/images/hats/Stinky.webp differ diff --git a/files/assets/images/hats/TV.webp b/files/assets/images/hats/TV.webp new file mode 100644 index 000000000..0306ea75d Binary files /dev/null and b/files/assets/images/hats/TV.webp differ diff --git a/files/assets/images/hats/Target practice.webp b/files/assets/images/hats/Target practice.webp new file mode 100644 index 000000000..d20ea38ab Binary files /dev/null and b/files/assets/images/hats/Target practice.webp differ diff --git a/files/assets/images/hats/Tawhid Finger I.webp b/files/assets/images/hats/Tawhid Finger I.webp new file mode 100644 index 000000000..814799cba Binary files /dev/null and b/files/assets/images/hats/Tawhid Finger I.webp differ diff --git a/files/assets/images/hats/Tawhid Finger II.webp b/files/assets/images/hats/Tawhid Finger II.webp new file mode 100644 index 000000000..76c81fc18 Binary files /dev/null and b/files/assets/images/hats/Tawhid Finger II.webp differ diff --git a/files/assets/images/hats/The Poo.webp b/files/assets/images/hats/The Poo.webp new file mode 100644 index 000000000..606d8adb9 Binary files /dev/null and b/files/assets/images/hats/The Poo.webp differ diff --git a/files/assets/images/hats/Thigarette.webp b/files/assets/images/hats/Thigarette.webp index 50d25b609..dff56e539 100644 Binary files a/files/assets/images/hats/Thigarette.webp and b/files/assets/images/hats/Thigarette.webp differ diff --git a/files/assets/images/hats/Top Hat (double rainbow).webp b/files/assets/images/hats/Top Hat (double rainbow).webp new file mode 100644 index 000000000..9e36e1d42 Binary files /dev/null and b/files/assets/images/hats/Top Hat (double rainbow).webp differ diff --git a/files/assets/images/hats/Trapped.webp b/files/assets/images/hats/Trapped.webp new file mode 100644 index 000000000..98dc1b9b3 Binary files /dev/null and b/files/assets/images/hats/Trapped.webp differ diff --git a/files/assets/images/hats/Tuff Golem.webp b/files/assets/images/hats/Tuff Golem.webp new file mode 100644 index 000000000..aa006aa10 Binary files /dev/null and b/files/assets/images/hats/Tuff Golem.webp differ diff --git a/files/assets/images/hats/Twinkle.webp b/files/assets/images/hats/Twinkle.webp index b90fecbc7..9044dcd7d 100644 Binary files a/files/assets/images/hats/Twinkle.webp and b/files/assets/images/hats/Twinkle.webp differ diff --git a/files/assets/images/hats/USA.webp b/files/assets/images/hats/USA.webp new file mode 100644 index 000000000..2cc0f9b11 Binary files /dev/null and b/files/assets/images/hats/USA.webp differ diff --git a/files/assets/images/hats/Venus Flytrap.webp b/files/assets/images/hats/Venus Flytrap.webp new file mode 100644 index 000000000..f6e4de60b Binary files /dev/null and b/files/assets/images/hats/Venus Flytrap.webp differ diff --git a/files/assets/images/hats/Walter white.webp b/files/assets/images/hats/Walter white.webp new file mode 100644 index 000000000..72dab8e29 Binary files /dev/null and b/files/assets/images/hats/Walter white.webp differ diff --git a/files/assets/images/hats/Wise mystical tree.webp b/files/assets/images/hats/Wise mystical tree.webp new file mode 100644 index 000000000..5210572e3 Binary files /dev/null and b/files/assets/images/hats/Wise mystical tree.webp differ diff --git a/files/assets/images/hats/Wizard.webp b/files/assets/images/hats/Wizard.webp new file mode 100644 index 000000000..c41b21387 Binary files /dev/null and b/files/assets/images/hats/Wizard.webp differ diff --git a/files/assets/images/hats/Wombat.webp b/files/assets/images/hats/Wombat.webp new file mode 100644 index 000000000..5da6ec979 Binary files /dev/null and b/files/assets/images/hats/Wombat.webp differ diff --git a/files/assets/images/hats/Xanax bar.webp b/files/assets/images/hats/Xanax bar.webp new file mode 100644 index 000000000..424e3fa7b Binary files /dev/null and b/files/assets/images/hats/Xanax bar.webp differ diff --git a/files/assets/images/hats/Yolo swag 420 rekt.webp b/files/assets/images/hats/Yolo swag 420 rekt.webp index 61126d0f9..eb0f5b1c3 100644 Binary files a/files/assets/images/hats/Yolo swag 420 rekt.webp and b/files/assets/images/hats/Yolo swag 420 rekt.webp differ diff --git a/files/assets/images/hats/Zen.webp b/files/assets/images/hats/Zen.webp index 24dd64d18..4a976b0e0 100644 Binary files a/files/assets/images/hats/Zen.webp and b/files/assets/images/hats/Zen.webp differ diff --git a/files/assets/images/hats/astolfo 1.webp b/files/assets/images/hats/astolfo 1.webp new file mode 100644 index 000000000..550f6b1a6 Binary files /dev/null and b/files/assets/images/hats/astolfo 1.webp differ diff --git a/files/assets/images/hats/astolfo 2.webp b/files/assets/images/hats/astolfo 2.webp new file mode 100644 index 000000000..9311e4fb6 Binary files /dev/null and b/files/assets/images/hats/astolfo 2.webp differ diff --git a/files/assets/images/hats/corvo attano mask.webp b/files/assets/images/hats/corvo attano mask.webp new file mode 100644 index 000000000..6cbfd25ee Binary files /dev/null and b/files/assets/images/hats/corvo attano mask.webp differ diff --git a/files/assets/images/hats/sailor moon peek.webp b/files/assets/images/hats/sailor moon peek.webp new file mode 100644 index 000000000..aacd169a2 Binary files /dev/null and b/files/assets/images/hats/sailor moon peek.webp differ diff --git a/files/assets/images/pfps/agendaposter/1.webp b/files/assets/images/pfps/agendaposter/1.webp deleted file mode 100644 index 4da49608e..000000000 Binary files a/files/assets/images/pfps/agendaposter/1.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/10.webp b/files/assets/images/pfps/agendaposter/10.webp deleted file mode 100644 index 47cb03363..000000000 Binary files a/files/assets/images/pfps/agendaposter/10.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/11.webp b/files/assets/images/pfps/agendaposter/11.webp deleted file mode 100644 index 6daf94973..000000000 Binary files a/files/assets/images/pfps/agendaposter/11.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/12.webp b/files/assets/images/pfps/agendaposter/12.webp deleted file mode 100644 index c552f4936..000000000 Binary files a/files/assets/images/pfps/agendaposter/12.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/13.webp b/files/assets/images/pfps/agendaposter/13.webp deleted file mode 100644 index c232aba47..000000000 Binary files a/files/assets/images/pfps/agendaposter/13.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/14.webp b/files/assets/images/pfps/agendaposter/14.webp deleted file mode 100644 index 62c86d79a..000000000 Binary files a/files/assets/images/pfps/agendaposter/14.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/15.webp b/files/assets/images/pfps/agendaposter/15.webp deleted file mode 100644 index 127cfe36f..000000000 Binary files a/files/assets/images/pfps/agendaposter/15.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/16.webp b/files/assets/images/pfps/agendaposter/16.webp deleted file mode 100644 index ce2a15a18..000000000 Binary files a/files/assets/images/pfps/agendaposter/16.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/17.webp b/files/assets/images/pfps/agendaposter/17.webp deleted file mode 100644 index cd616b12f..000000000 Binary files a/files/assets/images/pfps/agendaposter/17.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/18.webp b/files/assets/images/pfps/agendaposter/18.webp deleted file mode 100644 index 35d24d376..000000000 Binary files a/files/assets/images/pfps/agendaposter/18.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/19.webp b/files/assets/images/pfps/agendaposter/19.webp deleted file mode 100644 index 53efd3fbb..000000000 Binary files a/files/assets/images/pfps/agendaposter/19.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/2.webp b/files/assets/images/pfps/agendaposter/2.webp deleted file mode 100644 index 24be7473b..000000000 Binary files a/files/assets/images/pfps/agendaposter/2.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/20.webp b/files/assets/images/pfps/agendaposter/20.webp deleted file mode 100644 index d5324a2d6..000000000 Binary files a/files/assets/images/pfps/agendaposter/20.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/21.webp b/files/assets/images/pfps/agendaposter/21.webp deleted file mode 100644 index 3e66f6b9b..000000000 Binary files a/files/assets/images/pfps/agendaposter/21.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/22.webp b/files/assets/images/pfps/agendaposter/22.webp deleted file mode 100644 index a20b70312..000000000 Binary files a/files/assets/images/pfps/agendaposter/22.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/23.webp b/files/assets/images/pfps/agendaposter/23.webp deleted file mode 100644 index 5be03fc33..000000000 Binary files a/files/assets/images/pfps/agendaposter/23.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/24.webp b/files/assets/images/pfps/agendaposter/24.webp deleted file mode 100644 index 3ced589f2..000000000 Binary files a/files/assets/images/pfps/agendaposter/24.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/25.webp b/files/assets/images/pfps/agendaposter/25.webp deleted file mode 100644 index 878bb1c53..000000000 Binary files a/files/assets/images/pfps/agendaposter/25.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/26.webp b/files/assets/images/pfps/agendaposter/26.webp deleted file mode 100644 index 9cd11e9c4..000000000 Binary files a/files/assets/images/pfps/agendaposter/26.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/27.webp b/files/assets/images/pfps/agendaposter/27.webp deleted file mode 100644 index f32f4453b..000000000 Binary files a/files/assets/images/pfps/agendaposter/27.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/28.webp b/files/assets/images/pfps/agendaposter/28.webp deleted file mode 100644 index fbaf9bee5..000000000 Binary files a/files/assets/images/pfps/agendaposter/28.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/29.webp b/files/assets/images/pfps/agendaposter/29.webp deleted file mode 100644 index 82ab1d366..000000000 Binary files a/files/assets/images/pfps/agendaposter/29.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/3.webp b/files/assets/images/pfps/agendaposter/3.webp deleted file mode 100644 index 600e7c238..000000000 Binary files a/files/assets/images/pfps/agendaposter/3.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/30.webp b/files/assets/images/pfps/agendaposter/30.webp deleted file mode 100644 index 37c6d1a66..000000000 Binary files a/files/assets/images/pfps/agendaposter/30.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/31.webp b/files/assets/images/pfps/agendaposter/31.webp deleted file mode 100644 index a466cf2a6..000000000 Binary files a/files/assets/images/pfps/agendaposter/31.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/32.webp b/files/assets/images/pfps/agendaposter/32.webp deleted file mode 100644 index 28a64e791..000000000 Binary files a/files/assets/images/pfps/agendaposter/32.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/33.webp b/files/assets/images/pfps/agendaposter/33.webp deleted file mode 100644 index 83ba9b87d..000000000 Binary files a/files/assets/images/pfps/agendaposter/33.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/34.webp b/files/assets/images/pfps/agendaposter/34.webp deleted file mode 100644 index 5d9853487..000000000 Binary files a/files/assets/images/pfps/agendaposter/34.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/35.webp b/files/assets/images/pfps/agendaposter/35.webp deleted file mode 100644 index c77b1458c..000000000 Binary files a/files/assets/images/pfps/agendaposter/35.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/36.webp b/files/assets/images/pfps/agendaposter/36.webp deleted file mode 100644 index a80ff73c9..000000000 Binary files a/files/assets/images/pfps/agendaposter/36.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/37.webp b/files/assets/images/pfps/agendaposter/37.webp deleted file mode 100644 index a573d3f04..000000000 Binary files a/files/assets/images/pfps/agendaposter/37.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/38.webp b/files/assets/images/pfps/agendaposter/38.webp deleted file mode 100644 index 62b7051ed..000000000 Binary files a/files/assets/images/pfps/agendaposter/38.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/39.webp b/files/assets/images/pfps/agendaposter/39.webp deleted file mode 100644 index 23068cc77..000000000 Binary files a/files/assets/images/pfps/agendaposter/39.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/4.webp b/files/assets/images/pfps/agendaposter/4.webp deleted file mode 100644 index 84e0de6b2..000000000 Binary files a/files/assets/images/pfps/agendaposter/4.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/40.webp b/files/assets/images/pfps/agendaposter/40.webp deleted file mode 100644 index 7aa4e2737..000000000 Binary files a/files/assets/images/pfps/agendaposter/40.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/41.webp b/files/assets/images/pfps/agendaposter/41.webp deleted file mode 100644 index 230e93f8b..000000000 Binary files a/files/assets/images/pfps/agendaposter/41.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/42.webp b/files/assets/images/pfps/agendaposter/42.webp deleted file mode 100644 index 1f1fe0fe7..000000000 Binary files a/files/assets/images/pfps/agendaposter/42.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/43.webp b/files/assets/images/pfps/agendaposter/43.webp deleted file mode 100644 index 1039e29fa..000000000 Binary files a/files/assets/images/pfps/agendaposter/43.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/44.webp b/files/assets/images/pfps/agendaposter/44.webp deleted file mode 100644 index 46746bf01..000000000 Binary files a/files/assets/images/pfps/agendaposter/44.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/45.webp b/files/assets/images/pfps/agendaposter/45.webp deleted file mode 100644 index 23f2af534..000000000 Binary files a/files/assets/images/pfps/agendaposter/45.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/46.webp b/files/assets/images/pfps/agendaposter/46.webp deleted file mode 100644 index 7825b1f15..000000000 Binary files a/files/assets/images/pfps/agendaposter/46.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/47.webp b/files/assets/images/pfps/agendaposter/47.webp deleted file mode 100644 index 5cc06def1..000000000 Binary files a/files/assets/images/pfps/agendaposter/47.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/48.webp b/files/assets/images/pfps/agendaposter/48.webp deleted file mode 100644 index 1b4bfdfa7..000000000 Binary files a/files/assets/images/pfps/agendaposter/48.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/49.webp b/files/assets/images/pfps/agendaposter/49.webp deleted file mode 100644 index 3d319c306..000000000 Binary files a/files/assets/images/pfps/agendaposter/49.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/5.webp b/files/assets/images/pfps/agendaposter/5.webp deleted file mode 100644 index f533c10c0..000000000 Binary files a/files/assets/images/pfps/agendaposter/5.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/50.webp b/files/assets/images/pfps/agendaposter/50.webp deleted file mode 100644 index b18d7dfde..000000000 Binary files a/files/assets/images/pfps/agendaposter/50.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/51.webp b/files/assets/images/pfps/agendaposter/51.webp deleted file mode 100644 index e95bca8b6..000000000 Binary files a/files/assets/images/pfps/agendaposter/51.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/52.webp b/files/assets/images/pfps/agendaposter/52.webp deleted file mode 100644 index dbbf6dd1b..000000000 Binary files a/files/assets/images/pfps/agendaposter/52.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/53.webp b/files/assets/images/pfps/agendaposter/53.webp deleted file mode 100644 index dd833b66a..000000000 Binary files a/files/assets/images/pfps/agendaposter/53.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/54.webp b/files/assets/images/pfps/agendaposter/54.webp deleted file mode 100644 index 0af7c9447..000000000 Binary files a/files/assets/images/pfps/agendaposter/54.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/55.webp b/files/assets/images/pfps/agendaposter/55.webp deleted file mode 100644 index c99b42365..000000000 Binary files a/files/assets/images/pfps/agendaposter/55.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/56.webp b/files/assets/images/pfps/agendaposter/56.webp deleted file mode 100644 index 7ca8d4a17..000000000 Binary files a/files/assets/images/pfps/agendaposter/56.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/57.webp b/files/assets/images/pfps/agendaposter/57.webp deleted file mode 100644 index 653bcff6e..000000000 Binary files a/files/assets/images/pfps/agendaposter/57.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/6.webp b/files/assets/images/pfps/agendaposter/6.webp deleted file mode 100644 index 6e5667684..000000000 Binary files a/files/assets/images/pfps/agendaposter/6.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/7.webp b/files/assets/images/pfps/agendaposter/7.webp deleted file mode 100644 index 0d5d577c3..000000000 Binary files a/files/assets/images/pfps/agendaposter/7.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/8.webp b/files/assets/images/pfps/agendaposter/8.webp deleted file mode 100644 index 4175c59e0..000000000 Binary files a/files/assets/images/pfps/agendaposter/8.webp and /dev/null differ diff --git a/files/assets/images/pfps/agendaposter/9.webp b/files/assets/images/pfps/agendaposter/9.webp deleted file mode 100644 index 23a1796fd..000000000 Binary files a/files/assets/images/pfps/agendaposter/9.webp and /dev/null differ diff --git a/files/assets/images/rDrama/banners-event/2022-birthgay/20.webp b/files/assets/images/rDrama/banners-event/2022-birthgay/20.webp index 1df07374c..d2694ddc8 100644 Binary files a/files/assets/images/rDrama/banners-event/2022-birthgay/20.webp and b/files/assets/images/rDrama/banners-event/2022-birthgay/20.webp differ diff --git a/files/assets/images/rDrama/banners-event/2022-birthgay/21.webp b/files/assets/images/rDrama/banners-event/2022-birthgay/21.webp index f04463cb5..ba394e2dd 100644 Binary files a/files/assets/images/rDrama/banners-event/2022-birthgay/21.webp and b/files/assets/images/rDrama/banners-event/2022-birthgay/21.webp differ diff --git a/files/assets/images/rDrama/banners-event/2022-birthgay/22.webp b/files/assets/images/rDrama/banners-event/2022-birthgay/22.webp index 5bfa99d58..7982e70a1 100644 Binary files a/files/assets/images/rDrama/banners-event/2022-birthgay/22.webp and b/files/assets/images/rDrama/banners-event/2022-birthgay/22.webp differ diff --git a/files/assets/images/rDrama/banners-event/2022-birthgay/23.webp b/files/assets/images/rDrama/banners-event/2022-birthgay/23.webp index 66a9fd974..46cebbe2e 100644 Binary files a/files/assets/images/rDrama/banners-event/2022-birthgay/23.webp and b/files/assets/images/rDrama/banners-event/2022-birthgay/23.webp differ diff --git a/files/assets/images/rDrama/banners-event/2022-birthgay/24.webp b/files/assets/images/rDrama/banners-event/2022-birthgay/24.webp index bd5d02c98..d731bb7e8 100644 Binary files a/files/assets/images/rDrama/banners-event/2022-birthgay/24.webp and b/files/assets/images/rDrama/banners-event/2022-birthgay/24.webp differ diff --git a/files/assets/images/rDrama/banners-event/2022-birthgay/25.webp b/files/assets/images/rDrama/banners-event/2022-birthgay/25.webp index 2a281e112..a70220784 100644 Binary files a/files/assets/images/rDrama/banners-event/2022-birthgay/25.webp and b/files/assets/images/rDrama/banners-event/2022-birthgay/25.webp differ diff --git a/files/assets/images/rDrama/banners/1.webp b/files/assets/images/rDrama/banners/1.webp index c240ea74f..6734e0771 100644 Binary files a/files/assets/images/rDrama/banners/1.webp and b/files/assets/images/rDrama/banners/1.webp differ diff --git a/files/assets/images/rDrama/banners/10.webp b/files/assets/images/rDrama/banners/10.webp index b669a12c6..3b78bec75 100644 Binary files a/files/assets/images/rDrama/banners/10.webp and b/files/assets/images/rDrama/banners/10.webp differ diff --git a/files/assets/images/rDrama/banners/100.webp b/files/assets/images/rDrama/banners/100.webp index 8fb60dec5..74baea43e 100644 Binary files a/files/assets/images/rDrama/banners/100.webp and b/files/assets/images/rDrama/banners/100.webp differ diff --git a/files/assets/images/rDrama/banners/101.webp b/files/assets/images/rDrama/banners/101.webp index 3876d7497..db0d472d6 100644 Binary files a/files/assets/images/rDrama/banners/101.webp and b/files/assets/images/rDrama/banners/101.webp differ diff --git a/files/assets/images/rDrama/banners/102.webp b/files/assets/images/rDrama/banners/102.webp index 96740b9a9..7c5c5ccd5 100644 Binary files a/files/assets/images/rDrama/banners/102.webp and b/files/assets/images/rDrama/banners/102.webp differ diff --git a/files/assets/images/rDrama/banners/103.webp b/files/assets/images/rDrama/banners/103.webp index caf672c6e..5a6cc0b2f 100644 Binary files a/files/assets/images/rDrama/banners/103.webp and b/files/assets/images/rDrama/banners/103.webp differ diff --git a/files/assets/images/rDrama/banners/104.webp b/files/assets/images/rDrama/banners/104.webp index 47c5d043b..a9d5d7972 100644 Binary files a/files/assets/images/rDrama/banners/104.webp and b/files/assets/images/rDrama/banners/104.webp differ diff --git a/files/assets/images/rDrama/banners/105.webp b/files/assets/images/rDrama/banners/105.webp index f53e95c02..2443dcc1a 100644 Binary files a/files/assets/images/rDrama/banners/105.webp and b/files/assets/images/rDrama/banners/105.webp differ diff --git a/files/assets/images/rDrama/banners/106.webp b/files/assets/images/rDrama/banners/106.webp index f318266e9..d08968eed 100644 Binary files a/files/assets/images/rDrama/banners/106.webp and b/files/assets/images/rDrama/banners/106.webp differ diff --git a/files/assets/images/rDrama/banners/107.webp b/files/assets/images/rDrama/banners/107.webp index 7f0ab6f3c..4ae5f3830 100644 Binary files a/files/assets/images/rDrama/banners/107.webp and b/files/assets/images/rDrama/banners/107.webp differ diff --git a/files/assets/images/rDrama/banners/108.webp b/files/assets/images/rDrama/banners/108.webp index 13a95aacd..9c533daeb 100644 Binary files a/files/assets/images/rDrama/banners/108.webp and b/files/assets/images/rDrama/banners/108.webp differ diff --git a/files/assets/images/rDrama/banners/109.webp b/files/assets/images/rDrama/banners/109.webp index 9eeb500b5..0f368790b 100644 Binary files a/files/assets/images/rDrama/banners/109.webp and b/files/assets/images/rDrama/banners/109.webp differ diff --git a/files/assets/images/rDrama/banners/11.webp b/files/assets/images/rDrama/banners/11.webp index 98e629196..0a66d329a 100644 Binary files a/files/assets/images/rDrama/banners/11.webp and b/files/assets/images/rDrama/banners/11.webp differ diff --git a/files/assets/images/rDrama/banners/110.webp b/files/assets/images/rDrama/banners/110.webp index 281bf71ee..504018aeb 100644 Binary files a/files/assets/images/rDrama/banners/110.webp and b/files/assets/images/rDrama/banners/110.webp differ diff --git a/files/assets/images/rDrama/banners/111.webp b/files/assets/images/rDrama/banners/111.webp index a03a75e39..c6b34894f 100644 Binary files a/files/assets/images/rDrama/banners/111.webp and b/files/assets/images/rDrama/banners/111.webp differ diff --git a/files/assets/images/rDrama/banners/112.webp b/files/assets/images/rDrama/banners/112.webp index 16234c7d6..1217d0059 100644 Binary files a/files/assets/images/rDrama/banners/112.webp and b/files/assets/images/rDrama/banners/112.webp differ diff --git a/files/assets/images/rDrama/banners/113.webp b/files/assets/images/rDrama/banners/113.webp index b00426f21..c0afd136e 100644 Binary files a/files/assets/images/rDrama/banners/113.webp and b/files/assets/images/rDrama/banners/113.webp differ diff --git a/files/assets/images/rDrama/banners/118.webp b/files/assets/images/rDrama/banners/118.webp index 431d122b3..c6f6b64c5 100644 Binary files a/files/assets/images/rDrama/banners/118.webp and b/files/assets/images/rDrama/banners/118.webp differ diff --git a/files/assets/images/rDrama/banners/12.webp b/files/assets/images/rDrama/banners/12.webp index c06f22b53..c121bc6dc 100644 Binary files a/files/assets/images/rDrama/banners/12.webp and b/files/assets/images/rDrama/banners/12.webp differ diff --git a/files/assets/images/rDrama/banners/120.webp b/files/assets/images/rDrama/banners/120.webp index 96d0ba47f..346a28f3d 100644 Binary files a/files/assets/images/rDrama/banners/120.webp and b/files/assets/images/rDrama/banners/120.webp differ diff --git a/files/assets/images/rDrama/banners/121.webp b/files/assets/images/rDrama/banners/121.webp index 1b9c71e8a..9da276a1e 100644 Binary files a/files/assets/images/rDrama/banners/121.webp and b/files/assets/images/rDrama/banners/121.webp differ diff --git a/files/assets/images/rDrama/banners/122.webp b/files/assets/images/rDrama/banners/122.webp index b22d492ef..165b77e5a 100644 Binary files a/files/assets/images/rDrama/banners/122.webp and b/files/assets/images/rDrama/banners/122.webp differ diff --git a/files/assets/images/rDrama/banners/123.webp b/files/assets/images/rDrama/banners/123.webp index 31f261871..f4bf66b0e 100644 Binary files a/files/assets/images/rDrama/banners/123.webp and b/files/assets/images/rDrama/banners/123.webp differ diff --git a/files/assets/images/rDrama/banners/124.webp b/files/assets/images/rDrama/banners/124.webp index 03602ce83..6f2ca0f83 100644 Binary files a/files/assets/images/rDrama/banners/124.webp and b/files/assets/images/rDrama/banners/124.webp differ diff --git a/files/assets/images/rDrama/banners/128.webp b/files/assets/images/rDrama/banners/128.webp index 3a69fdac7..38e6b5d48 100644 Binary files a/files/assets/images/rDrama/banners/128.webp and b/files/assets/images/rDrama/banners/128.webp differ diff --git a/files/assets/images/rDrama/banners/129.webp b/files/assets/images/rDrama/banners/129.webp index 95d41615f..dd3aca16a 100644 Binary files a/files/assets/images/rDrama/banners/129.webp and b/files/assets/images/rDrama/banners/129.webp differ diff --git a/files/assets/images/rDrama/banners/13.webp b/files/assets/images/rDrama/banners/13.webp index 500e6ec2e..48a481499 100644 Binary files a/files/assets/images/rDrama/banners/13.webp and b/files/assets/images/rDrama/banners/13.webp differ diff --git a/files/assets/images/rDrama/banners/130.webp b/files/assets/images/rDrama/banners/130.webp index 2a1a643a1..347133236 100644 Binary files a/files/assets/images/rDrama/banners/130.webp and b/files/assets/images/rDrama/banners/130.webp differ diff --git a/files/assets/images/rDrama/banners/133.webp b/files/assets/images/rDrama/banners/133.webp index d5ebbd3a1..b26428c96 100644 Binary files a/files/assets/images/rDrama/banners/133.webp and b/files/assets/images/rDrama/banners/133.webp differ diff --git a/files/assets/images/rDrama/banners/137.webp b/files/assets/images/rDrama/banners/137.webp index 5ec789262..e6d4d4989 100644 Binary files a/files/assets/images/rDrama/banners/137.webp and b/files/assets/images/rDrama/banners/137.webp differ diff --git a/files/assets/images/rDrama/banners/138.webp b/files/assets/images/rDrama/banners/138.webp index 81c20ccec..3dcedca4f 100644 Binary files a/files/assets/images/rDrama/banners/138.webp and b/files/assets/images/rDrama/banners/138.webp differ diff --git a/files/assets/images/rDrama/banners/14.webp b/files/assets/images/rDrama/banners/14.webp index 1c0bf2e15..b37d84432 100644 Binary files a/files/assets/images/rDrama/banners/14.webp and b/files/assets/images/rDrama/banners/14.webp differ diff --git a/files/assets/images/rDrama/banners/141.webp b/files/assets/images/rDrama/banners/141.webp index 765eaa930..26251344e 100644 Binary files a/files/assets/images/rDrama/banners/141.webp and b/files/assets/images/rDrama/banners/141.webp differ diff --git a/files/assets/images/rDrama/banners/142.webp b/files/assets/images/rDrama/banners/142.webp index fcf35c97d..068baf248 100644 Binary files a/files/assets/images/rDrama/banners/142.webp and b/files/assets/images/rDrama/banners/142.webp differ diff --git a/files/assets/images/rDrama/banners/143.webp b/files/assets/images/rDrama/banners/143.webp index 3c0aed646..f08c87328 100644 Binary files a/files/assets/images/rDrama/banners/143.webp and b/files/assets/images/rDrama/banners/143.webp differ diff --git a/files/assets/images/rDrama/banners/144.webp b/files/assets/images/rDrama/banners/144.webp index ae1b2a249..c0fa619f1 100644 Binary files a/files/assets/images/rDrama/banners/144.webp and b/files/assets/images/rDrama/banners/144.webp differ diff --git a/files/assets/images/rDrama/banners/146.webp b/files/assets/images/rDrama/banners/146.webp index 543465146..65bcdef3a 100644 Binary files a/files/assets/images/rDrama/banners/146.webp and b/files/assets/images/rDrama/banners/146.webp differ diff --git a/files/assets/images/rDrama/banners/148.webp b/files/assets/images/rDrama/banners/148.webp deleted file mode 100644 index b06ebfaa4..000000000 Binary files a/files/assets/images/rDrama/banners/148.webp and /dev/null differ diff --git a/files/assets/images/rDrama/banners/15.webp b/files/assets/images/rDrama/banners/15.webp index 727a6e11a..a37818721 100644 Binary files a/files/assets/images/rDrama/banners/15.webp and b/files/assets/images/rDrama/banners/15.webp differ diff --git a/files/assets/images/rDrama/banners/16.webp b/files/assets/images/rDrama/banners/16.webp index 8c780cc2c..62a3c45ed 100644 Binary files a/files/assets/images/rDrama/banners/16.webp and b/files/assets/images/rDrama/banners/16.webp differ diff --git a/files/assets/images/rDrama/banners/17.webp b/files/assets/images/rDrama/banners/17.webp index 9d417dafa..9f3d6a223 100644 Binary files a/files/assets/images/rDrama/banners/17.webp and b/files/assets/images/rDrama/banners/17.webp differ diff --git a/files/assets/images/rDrama/banners/18.webp b/files/assets/images/rDrama/banners/18.webp index 542ddceca..1e2c91b63 100644 Binary files a/files/assets/images/rDrama/banners/18.webp and b/files/assets/images/rDrama/banners/18.webp differ diff --git a/files/assets/images/rDrama/banners/19.webp b/files/assets/images/rDrama/banners/19.webp index 184280cb6..0e1ba2cf5 100644 Binary files a/files/assets/images/rDrama/banners/19.webp and b/files/assets/images/rDrama/banners/19.webp differ diff --git a/files/assets/images/rDrama/banners/2.webp b/files/assets/images/rDrama/banners/2.webp index 76a94269b..9d12244b5 100644 Binary files a/files/assets/images/rDrama/banners/2.webp and b/files/assets/images/rDrama/banners/2.webp differ diff --git a/files/assets/images/rDrama/banners/20.webp b/files/assets/images/rDrama/banners/20.webp index 2ecb22918..87909f0d2 100644 Binary files a/files/assets/images/rDrama/banners/20.webp and b/files/assets/images/rDrama/banners/20.webp differ diff --git a/files/assets/images/rDrama/banners/21.webp b/files/assets/images/rDrama/banners/21.webp index 9b31ef0b5..4e0a444b4 100644 Binary files a/files/assets/images/rDrama/banners/21.webp and b/files/assets/images/rDrama/banners/21.webp differ diff --git a/files/assets/images/rDrama/banners/22.webp b/files/assets/images/rDrama/banners/22.webp index 13d8bfb53..2f323b90b 100644 Binary files a/files/assets/images/rDrama/banners/22.webp and b/files/assets/images/rDrama/banners/22.webp differ diff --git a/files/assets/images/rDrama/banners/23.webp b/files/assets/images/rDrama/banners/23.webp index 405011608..95665609b 100644 Binary files a/files/assets/images/rDrama/banners/23.webp and b/files/assets/images/rDrama/banners/23.webp differ diff --git a/files/assets/images/rDrama/banners/24.webp b/files/assets/images/rDrama/banners/24.webp index f0c659746..d4e36ae23 100644 Binary files a/files/assets/images/rDrama/banners/24.webp and b/files/assets/images/rDrama/banners/24.webp differ diff --git a/files/assets/images/rDrama/banners/25.webp b/files/assets/images/rDrama/banners/25.webp index 1eb9a049e..c52cb72e2 100644 Binary files a/files/assets/images/rDrama/banners/25.webp and b/files/assets/images/rDrama/banners/25.webp differ diff --git a/files/assets/images/rDrama/banners/26.webp b/files/assets/images/rDrama/banners/26.webp index 063ee7d4a..041df8ded 100644 Binary files a/files/assets/images/rDrama/banners/26.webp and b/files/assets/images/rDrama/banners/26.webp differ diff --git a/files/assets/images/rDrama/banners/27.webp b/files/assets/images/rDrama/banners/27.webp index 5282f4748..8850f1e9d 100644 Binary files a/files/assets/images/rDrama/banners/27.webp and b/files/assets/images/rDrama/banners/27.webp differ diff --git a/files/assets/images/rDrama/banners/28.webp b/files/assets/images/rDrama/banners/28.webp index 5c8233a49..2a0bb8098 100644 Binary files a/files/assets/images/rDrama/banners/28.webp and b/files/assets/images/rDrama/banners/28.webp differ diff --git a/files/assets/images/rDrama/banners/29.webp b/files/assets/images/rDrama/banners/29.webp index 332ee3c13..f17e8f659 100644 Binary files a/files/assets/images/rDrama/banners/29.webp and b/files/assets/images/rDrama/banners/29.webp differ diff --git a/files/assets/images/rDrama/banners/3.webp b/files/assets/images/rDrama/banners/3.webp index 788f1b2c1..2228693bd 100644 Binary files a/files/assets/images/rDrama/banners/3.webp and b/files/assets/images/rDrama/banners/3.webp differ diff --git a/files/assets/images/rDrama/banners/30.webp b/files/assets/images/rDrama/banners/30.webp index ac42f08ae..f2601340e 100644 Binary files a/files/assets/images/rDrama/banners/30.webp and b/files/assets/images/rDrama/banners/30.webp differ diff --git a/files/assets/images/rDrama/banners/32.webp b/files/assets/images/rDrama/banners/32.webp index 6966a468d..75585f0ef 100644 Binary files a/files/assets/images/rDrama/banners/32.webp and b/files/assets/images/rDrama/banners/32.webp differ diff --git a/files/assets/images/rDrama/banners/33.webp b/files/assets/images/rDrama/banners/33.webp index 919501358..ce7739beb 100644 Binary files a/files/assets/images/rDrama/banners/33.webp and b/files/assets/images/rDrama/banners/33.webp differ diff --git a/files/assets/images/rDrama/banners/35.webp b/files/assets/images/rDrama/banners/35.webp index edf2484f7..788d07acb 100644 Binary files a/files/assets/images/rDrama/banners/35.webp and b/files/assets/images/rDrama/banners/35.webp differ diff --git a/files/assets/images/rDrama/banners/36.webp b/files/assets/images/rDrama/banners/36.webp index 31eb208f3..132e91497 100644 Binary files a/files/assets/images/rDrama/banners/36.webp and b/files/assets/images/rDrama/banners/36.webp differ diff --git a/files/assets/images/rDrama/banners/37.webp b/files/assets/images/rDrama/banners/37.webp index cc786e713..96047c125 100644 Binary files a/files/assets/images/rDrama/banners/37.webp and b/files/assets/images/rDrama/banners/37.webp differ diff --git a/files/assets/images/rDrama/banners/38.webp b/files/assets/images/rDrama/banners/38.webp index 900edf830..2d16ee294 100644 Binary files a/files/assets/images/rDrama/banners/38.webp and b/files/assets/images/rDrama/banners/38.webp differ diff --git a/files/assets/images/rDrama/banners/39.webp b/files/assets/images/rDrama/banners/39.webp index dbe27df20..9b67effd8 100644 Binary files a/files/assets/images/rDrama/banners/39.webp and b/files/assets/images/rDrama/banners/39.webp differ diff --git a/files/assets/images/rDrama/banners/4.webp b/files/assets/images/rDrama/banners/4.webp index 4c343b5bb..eb4ddc6fa 100644 Binary files a/files/assets/images/rDrama/banners/4.webp and b/files/assets/images/rDrama/banners/4.webp differ diff --git a/files/assets/images/rDrama/banners/40.webp b/files/assets/images/rDrama/banners/40.webp index 404772965..5209166ce 100644 Binary files a/files/assets/images/rDrama/banners/40.webp and b/files/assets/images/rDrama/banners/40.webp differ diff --git a/files/assets/images/rDrama/banners/41.webp b/files/assets/images/rDrama/banners/41.webp index 200272166..fe7fb2dd5 100644 Binary files a/files/assets/images/rDrama/banners/41.webp and b/files/assets/images/rDrama/banners/41.webp differ diff --git a/files/assets/images/rDrama/banners/43.webp b/files/assets/images/rDrama/banners/43.webp index fd4a88d26..75d43b08b 100644 Binary files a/files/assets/images/rDrama/banners/43.webp and b/files/assets/images/rDrama/banners/43.webp differ diff --git a/files/assets/images/rDrama/banners/44.webp b/files/assets/images/rDrama/banners/44.webp index 80a9939cb..c7a24f287 100644 Binary files a/files/assets/images/rDrama/banners/44.webp and b/files/assets/images/rDrama/banners/44.webp differ diff --git a/files/assets/images/rDrama/banners/45.webp b/files/assets/images/rDrama/banners/45.webp index 507a9e2b9..c9886b070 100644 Binary files a/files/assets/images/rDrama/banners/45.webp and b/files/assets/images/rDrama/banners/45.webp differ diff --git a/files/assets/images/rDrama/banners/46.webp b/files/assets/images/rDrama/banners/46.webp index 4c307fe56..a3db5f3fd 100644 Binary files a/files/assets/images/rDrama/banners/46.webp and b/files/assets/images/rDrama/banners/46.webp differ diff --git a/files/assets/images/rDrama/banners/47.webp b/files/assets/images/rDrama/banners/47.webp index bde6fbcef..a51fbe16d 100644 Binary files a/files/assets/images/rDrama/banners/47.webp and b/files/assets/images/rDrama/banners/47.webp differ diff --git a/files/assets/images/rDrama/banners/49.webp b/files/assets/images/rDrama/banners/49.webp index 93c91b6bc..bd1a2f749 100644 Binary files a/files/assets/images/rDrama/banners/49.webp and b/files/assets/images/rDrama/banners/49.webp differ diff --git a/files/assets/images/rDrama/banners/5.webp b/files/assets/images/rDrama/banners/5.webp index b48edfa9f..aecec7b7d 100644 Binary files a/files/assets/images/rDrama/banners/5.webp and b/files/assets/images/rDrama/banners/5.webp differ diff --git a/files/assets/images/rDrama/banners/50.webp b/files/assets/images/rDrama/banners/50.webp index fb05fbd11..2076d699c 100644 Binary files a/files/assets/images/rDrama/banners/50.webp and b/files/assets/images/rDrama/banners/50.webp differ diff --git a/files/assets/images/rDrama/banners/51.webp b/files/assets/images/rDrama/banners/51.webp index 9e6feaf57..217ec1b4e 100644 Binary files a/files/assets/images/rDrama/banners/51.webp and b/files/assets/images/rDrama/banners/51.webp differ diff --git a/files/assets/images/rDrama/banners/52.webp b/files/assets/images/rDrama/banners/52.webp index 4df43f5c5..f6457f979 100644 Binary files a/files/assets/images/rDrama/banners/52.webp and b/files/assets/images/rDrama/banners/52.webp differ diff --git a/files/assets/images/rDrama/banners/53.webp b/files/assets/images/rDrama/banners/53.webp index 3868c7314..4d1782f3b 100644 Binary files a/files/assets/images/rDrama/banners/53.webp and b/files/assets/images/rDrama/banners/53.webp differ diff --git a/files/assets/images/rDrama/banners/54.webp b/files/assets/images/rDrama/banners/54.webp index 399c4311a..3c346af83 100644 Binary files a/files/assets/images/rDrama/banners/54.webp and b/files/assets/images/rDrama/banners/54.webp differ diff --git a/files/assets/images/rDrama/banners/55.webp b/files/assets/images/rDrama/banners/55.webp index 68946f4e7..500fa2602 100644 Binary files a/files/assets/images/rDrama/banners/55.webp and b/files/assets/images/rDrama/banners/55.webp differ diff --git a/files/assets/images/rDrama/banners/56.webp b/files/assets/images/rDrama/banners/56.webp index 8c1cdfd69..335108490 100644 Binary files a/files/assets/images/rDrama/banners/56.webp and b/files/assets/images/rDrama/banners/56.webp differ diff --git a/files/assets/images/rDrama/banners/57.webp b/files/assets/images/rDrama/banners/57.webp index 72e005d38..0dd72eae1 100644 Binary files a/files/assets/images/rDrama/banners/57.webp and b/files/assets/images/rDrama/banners/57.webp differ diff --git a/files/assets/images/rDrama/banners/58.webp b/files/assets/images/rDrama/banners/58.webp index 102ee11b6..e66acb561 100644 Binary files a/files/assets/images/rDrama/banners/58.webp and b/files/assets/images/rDrama/banners/58.webp differ diff --git a/files/assets/images/rDrama/banners/59.webp b/files/assets/images/rDrama/banners/59.webp index 7865d090d..390a1d139 100644 Binary files a/files/assets/images/rDrama/banners/59.webp and b/files/assets/images/rDrama/banners/59.webp differ diff --git a/files/assets/images/rDrama/banners/6.webp b/files/assets/images/rDrama/banners/6.webp index 2b41e3a13..c5db21119 100644 Binary files a/files/assets/images/rDrama/banners/6.webp and b/files/assets/images/rDrama/banners/6.webp differ diff --git a/files/assets/images/rDrama/banners/60.webp b/files/assets/images/rDrama/banners/60.webp index 218a8f2bc..2d9115686 100644 Binary files a/files/assets/images/rDrama/banners/60.webp and b/files/assets/images/rDrama/banners/60.webp differ diff --git a/files/assets/images/rDrama/banners/62.webp b/files/assets/images/rDrama/banners/62.webp index 32e6be156..36193339a 100644 Binary files a/files/assets/images/rDrama/banners/62.webp and b/files/assets/images/rDrama/banners/62.webp differ diff --git a/files/assets/images/rDrama/banners/63.webp b/files/assets/images/rDrama/banners/63.webp index 4bafe178f..1caa87d62 100644 Binary files a/files/assets/images/rDrama/banners/63.webp and b/files/assets/images/rDrama/banners/63.webp differ diff --git a/files/assets/images/rDrama/banners/64.webp b/files/assets/images/rDrama/banners/64.webp index fc18c63bd..1b1950cd2 100644 Binary files a/files/assets/images/rDrama/banners/64.webp and b/files/assets/images/rDrama/banners/64.webp differ diff --git a/files/assets/images/rDrama/banners/65.webp b/files/assets/images/rDrama/banners/65.webp index 9882f5845..f0a822a2b 100644 Binary files a/files/assets/images/rDrama/banners/65.webp and b/files/assets/images/rDrama/banners/65.webp differ diff --git a/files/assets/images/rDrama/banners/66.webp b/files/assets/images/rDrama/banners/66.webp index 6e2d4c768..2450cfe7e 100644 Binary files a/files/assets/images/rDrama/banners/66.webp and b/files/assets/images/rDrama/banners/66.webp differ diff --git a/files/assets/images/rDrama/banners/67.webp b/files/assets/images/rDrama/banners/67.webp index 4ee45a795..36cce78bd 100644 Binary files a/files/assets/images/rDrama/banners/67.webp and b/files/assets/images/rDrama/banners/67.webp differ diff --git a/files/assets/images/rDrama/banners/68.webp b/files/assets/images/rDrama/banners/68.webp index cb6e92a92..b45a0dcbd 100644 Binary files a/files/assets/images/rDrama/banners/68.webp and b/files/assets/images/rDrama/banners/68.webp differ diff --git a/files/assets/images/rDrama/banners/69.webp b/files/assets/images/rDrama/banners/69.webp index 62012b1ce..e16848dc8 100644 Binary files a/files/assets/images/rDrama/banners/69.webp and b/files/assets/images/rDrama/banners/69.webp differ diff --git a/files/assets/images/rDrama/banners/7.webp b/files/assets/images/rDrama/banners/7.webp index 8093e3c90..566a54595 100644 Binary files a/files/assets/images/rDrama/banners/7.webp and b/files/assets/images/rDrama/banners/7.webp differ diff --git a/files/assets/images/rDrama/banners/70.webp b/files/assets/images/rDrama/banners/70.webp index 85bfd5322..e3c5c03ac 100644 Binary files a/files/assets/images/rDrama/banners/70.webp and b/files/assets/images/rDrama/banners/70.webp differ diff --git a/files/assets/images/rDrama/banners/71.webp b/files/assets/images/rDrama/banners/71.webp index 9e324d06d..c0876dad1 100644 Binary files a/files/assets/images/rDrama/banners/71.webp and b/files/assets/images/rDrama/banners/71.webp differ diff --git a/files/assets/images/rDrama/banners/72.webp b/files/assets/images/rDrama/banners/72.webp index 45761832b..6183ea0df 100644 Binary files a/files/assets/images/rDrama/banners/72.webp and b/files/assets/images/rDrama/banners/72.webp differ diff --git a/files/assets/images/rDrama/banners/74.webp b/files/assets/images/rDrama/banners/74.webp index 604863cae..07f16bce1 100644 Binary files a/files/assets/images/rDrama/banners/74.webp and b/files/assets/images/rDrama/banners/74.webp differ diff --git a/files/assets/images/rDrama/banners/75.webp b/files/assets/images/rDrama/banners/75.webp index ab9f7d80a..f9c7dfbf8 100644 Binary files a/files/assets/images/rDrama/banners/75.webp and b/files/assets/images/rDrama/banners/75.webp differ diff --git a/files/assets/images/rDrama/banners/76.webp b/files/assets/images/rDrama/banners/76.webp index 86937afa7..8769acbc3 100644 Binary files a/files/assets/images/rDrama/banners/76.webp and b/files/assets/images/rDrama/banners/76.webp differ diff --git a/files/assets/images/rDrama/banners/77.webp b/files/assets/images/rDrama/banners/77.webp index 6562eba8b..bf67209a0 100644 Binary files a/files/assets/images/rDrama/banners/77.webp and b/files/assets/images/rDrama/banners/77.webp differ diff --git a/files/assets/images/rDrama/banners/78.webp b/files/assets/images/rDrama/banners/78.webp index 6b84608c8..1471d5adf 100644 Binary files a/files/assets/images/rDrama/banners/78.webp and b/files/assets/images/rDrama/banners/78.webp differ diff --git a/files/assets/images/rDrama/banners/79.webp b/files/assets/images/rDrama/banners/79.webp index 66031dc77..69640066a 100644 Binary files a/files/assets/images/rDrama/banners/79.webp and b/files/assets/images/rDrama/banners/79.webp differ diff --git a/files/assets/images/rDrama/banners/8.webp b/files/assets/images/rDrama/banners/8.webp index f084307c3..53f876dee 100644 Binary files a/files/assets/images/rDrama/banners/8.webp and b/files/assets/images/rDrama/banners/8.webp differ diff --git a/files/assets/images/rDrama/banners/80.webp b/files/assets/images/rDrama/banners/80.webp index 9ce743680..486bc0ddc 100644 Binary files a/files/assets/images/rDrama/banners/80.webp and b/files/assets/images/rDrama/banners/80.webp differ diff --git a/files/assets/images/rDrama/banners/81.webp b/files/assets/images/rDrama/banners/81.webp index 4cf6766ae..8f203ccbb 100644 Binary files a/files/assets/images/rDrama/banners/81.webp and b/files/assets/images/rDrama/banners/81.webp differ diff --git a/files/assets/images/rDrama/banners/82.webp b/files/assets/images/rDrama/banners/82.webp index 97bfdcac5..8dda225a0 100644 Binary files a/files/assets/images/rDrama/banners/82.webp and b/files/assets/images/rDrama/banners/82.webp differ diff --git a/files/assets/images/rDrama/banners/83.webp b/files/assets/images/rDrama/banners/83.webp index 3d1db441d..013e00bd5 100644 Binary files a/files/assets/images/rDrama/banners/83.webp and b/files/assets/images/rDrama/banners/83.webp differ diff --git a/files/assets/images/rDrama/banners/84.webp b/files/assets/images/rDrama/banners/84.webp index 15ce21311..a6add5877 100644 Binary files a/files/assets/images/rDrama/banners/84.webp and b/files/assets/images/rDrama/banners/84.webp differ diff --git a/files/assets/images/rDrama/banners/85.webp b/files/assets/images/rDrama/banners/85.webp index 090695f63..3ab7e49fb 100644 Binary files a/files/assets/images/rDrama/banners/85.webp and b/files/assets/images/rDrama/banners/85.webp differ diff --git a/files/assets/images/rDrama/banners/86.webp b/files/assets/images/rDrama/banners/86.webp index d15d41cfc..cbbc2ed27 100644 Binary files a/files/assets/images/rDrama/banners/86.webp and b/files/assets/images/rDrama/banners/86.webp differ diff --git a/files/assets/images/rDrama/banners/87.webp b/files/assets/images/rDrama/banners/87.webp index 386455e28..25dc36c93 100644 Binary files a/files/assets/images/rDrama/banners/87.webp and b/files/assets/images/rDrama/banners/87.webp differ diff --git a/files/assets/images/rDrama/banners/88.webp b/files/assets/images/rDrama/banners/88.webp index 416b58754..161c10cff 100644 Binary files a/files/assets/images/rDrama/banners/88.webp and b/files/assets/images/rDrama/banners/88.webp differ diff --git a/files/assets/images/rDrama/banners/89.webp b/files/assets/images/rDrama/banners/89.webp index c87515d51..c2e199d9a 100644 Binary files a/files/assets/images/rDrama/banners/89.webp and b/files/assets/images/rDrama/banners/89.webp differ diff --git a/files/assets/images/rDrama/banners/9.webp b/files/assets/images/rDrama/banners/9.webp index d8a69304d..65f8a7d2a 100644 Binary files a/files/assets/images/rDrama/banners/9.webp and b/files/assets/images/rDrama/banners/9.webp differ diff --git a/files/assets/images/rDrama/banners/90.webp b/files/assets/images/rDrama/banners/90.webp index c9d2dd69a..a5fce2ecb 100644 Binary files a/files/assets/images/rDrama/banners/90.webp and b/files/assets/images/rDrama/banners/90.webp differ diff --git a/files/assets/images/rDrama/banners/91.webp b/files/assets/images/rDrama/banners/91.webp index ea0125174..e65400099 100644 Binary files a/files/assets/images/rDrama/banners/91.webp and b/files/assets/images/rDrama/banners/91.webp differ diff --git a/files/assets/images/rDrama/banners/92.webp b/files/assets/images/rDrama/banners/92.webp index 178a80217..462ec3e69 100644 Binary files a/files/assets/images/rDrama/banners/92.webp and b/files/assets/images/rDrama/banners/92.webp differ diff --git a/files/assets/images/rDrama/banners/93.webp b/files/assets/images/rDrama/banners/93.webp index f175c4f44..bec1848fb 100644 Binary files a/files/assets/images/rDrama/banners/93.webp and b/files/assets/images/rDrama/banners/93.webp differ diff --git a/files/assets/images/rDrama/banners/94.webp b/files/assets/images/rDrama/banners/94.webp index 1b7e6e514..035fb76ab 100644 Binary files a/files/assets/images/rDrama/banners/94.webp and b/files/assets/images/rDrama/banners/94.webp differ diff --git a/files/assets/images/rDrama/banners/95.webp b/files/assets/images/rDrama/banners/95.webp index d3b7fd5c8..3384969c1 100644 Binary files a/files/assets/images/rDrama/banners/95.webp and b/files/assets/images/rDrama/banners/95.webp differ diff --git a/files/assets/images/rDrama/banners/96.webp b/files/assets/images/rDrama/banners/96.webp index 4b32a95d5..370d627bd 100644 Binary files a/files/assets/images/rDrama/banners/96.webp and b/files/assets/images/rDrama/banners/96.webp differ diff --git a/files/assets/images/rDrama/banners/97.webp b/files/assets/images/rDrama/banners/97.webp index fdc240483..a04488cb4 100644 Binary files a/files/assets/images/rDrama/banners/97.webp and b/files/assets/images/rDrama/banners/97.webp differ diff --git a/files/assets/images/rDrama/banners/98.webp b/files/assets/images/rDrama/banners/98.webp index 5eeeb6288..5b9989d23 100644 Binary files a/files/assets/images/rDrama/banners/98.webp and b/files/assets/images/rDrama/banners/98.webp differ diff --git a/files/assets/images/rDrama/banners/99.webp b/files/assets/images/rDrama/banners/99.webp index a392a058c..2bf740575 100644 Binary files a/files/assets/images/rDrama/banners/99.webp and b/files/assets/images/rDrama/banners/99.webp differ diff --git a/files/assets/images/rDrama/cover.webp b/files/assets/images/rDrama/cover.webp index 417da77a7..3b1a81784 100644 Binary files a/files/assets/images/rDrama/cover.webp and b/files/assets/images/rDrama/cover.webp differ diff --git a/files/assets/images/rDrama/default_text.webp b/files/assets/images/rDrama/default_text.webp index eb2b5d1df..3c5c64e23 100644 Binary files a/files/assets/images/rDrama/default_text.webp and b/files/assets/images/rDrama/default_text.webp differ diff --git a/files/assets/images/rDrama/logo.webp b/files/assets/images/rDrama/logo.webp index 25a726fa9..7f997ad20 100644 Binary files a/files/assets/images/rDrama/logo.webp and b/files/assets/images/rDrama/logo.webp differ diff --git a/files/assets/images/rDrama/patron_badges/25.webp b/files/assets/images/rDrama/patron_badges/25.webp index acf5b93f1..00a2a06cc 100644 Binary files a/files/assets/images/rDrama/patron_badges/25.webp and b/files/assets/images/rDrama/patron_badges/25.webp differ diff --git a/files/assets/images/rDrama/sidebar/113.webp b/files/assets/images/rDrama/sidebar/113.webp index 5d3096cdd..be705d50c 100644 Binary files a/files/assets/images/rDrama/sidebar/113.webp and b/files/assets/images/rDrama/sidebar/113.webp differ diff --git a/files/assets/images/rDrama/sidebar/139.webp b/files/assets/images/rDrama/sidebar/139.webp new file mode 100644 index 000000000..d614565e5 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/139.webp differ diff --git a/files/assets/images/rDrama/sidebar/140.webp b/files/assets/images/rDrama/sidebar/140.webp deleted file mode 100644 index d64320ce4..000000000 Binary files a/files/assets/images/rDrama/sidebar/140.webp and /dev/null differ diff --git a/files/assets/images/rDrama/sidebar/142.webp b/files/assets/images/rDrama/sidebar/142.webp index 6ff4ce7ef..c909b7d6c 100644 Binary files a/files/assets/images/rDrama/sidebar/142.webp and b/files/assets/images/rDrama/sidebar/142.webp differ diff --git a/files/assets/images/rDrama/sidebar/15.webp b/files/assets/images/rDrama/sidebar/15.webp index 8c9c42d58..a85002bbc 100644 Binary files a/files/assets/images/rDrama/sidebar/15.webp and b/files/assets/images/rDrama/sidebar/15.webp differ diff --git a/files/assets/images/rDrama/sidebar/153.webp b/files/assets/images/rDrama/sidebar/153.webp index 27cb1ea48..c535c67af 100644 Binary files a/files/assets/images/rDrama/sidebar/153.webp and b/files/assets/images/rDrama/sidebar/153.webp differ diff --git a/files/assets/images/rDrama/sidebar/162.webp b/files/assets/images/rDrama/sidebar/162.webp index f0644ea5b..eafbb96a0 100644 Binary files a/files/assets/images/rDrama/sidebar/162.webp and b/files/assets/images/rDrama/sidebar/162.webp differ diff --git a/files/assets/images/rDrama/sidebar/167.webp b/files/assets/images/rDrama/sidebar/167.webp index 8b9c195aa..8a56f0b82 100644 Binary files a/files/assets/images/rDrama/sidebar/167.webp and b/files/assets/images/rDrama/sidebar/167.webp differ diff --git a/files/assets/images/rDrama/sidebar/172.webp b/files/assets/images/rDrama/sidebar/172.webp index cc7eb926b..bad405e7c 100644 Binary files a/files/assets/images/rDrama/sidebar/172.webp and b/files/assets/images/rDrama/sidebar/172.webp differ diff --git a/files/assets/images/rDrama/sidebar/177.webp b/files/assets/images/rDrama/sidebar/177.webp index 27cbcc694..60fa45723 100644 Binary files a/files/assets/images/rDrama/sidebar/177.webp and b/files/assets/images/rDrama/sidebar/177.webp differ diff --git a/files/assets/images/rDrama/sidebar/184.webp b/files/assets/images/rDrama/sidebar/184.webp index b99b72105..158813972 100644 Binary files a/files/assets/images/rDrama/sidebar/184.webp and b/files/assets/images/rDrama/sidebar/184.webp differ diff --git a/files/assets/images/rDrama/sidebar/194.webp b/files/assets/images/rDrama/sidebar/194.webp new file mode 100644 index 000000000..bec8929a8 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/194.webp differ diff --git a/files/assets/images/rDrama/sidebar/210.webp b/files/assets/images/rDrama/sidebar/210.webp index a856406ad..20326f04e 100644 Binary files a/files/assets/images/rDrama/sidebar/210.webp and b/files/assets/images/rDrama/sidebar/210.webp differ diff --git a/files/assets/images/rDrama/sidebar/237.webp b/files/assets/images/rDrama/sidebar/237.webp index 6992481eb..983c9345c 100644 Binary files a/files/assets/images/rDrama/sidebar/237.webp and b/files/assets/images/rDrama/sidebar/237.webp differ diff --git a/files/assets/images/rDrama/sidebar/254.webp b/files/assets/images/rDrama/sidebar/254.webp deleted file mode 100644 index b82fbe043..000000000 Binary files a/files/assets/images/rDrama/sidebar/254.webp and /dev/null differ diff --git a/files/assets/images/rDrama/sidebar/256.webp b/files/assets/images/rDrama/sidebar/256.webp index 6d565445a..f3174457c 100644 Binary files a/files/assets/images/rDrama/sidebar/256.webp and b/files/assets/images/rDrama/sidebar/256.webp differ diff --git a/files/assets/images/rDrama/sidebar/265.webp b/files/assets/images/rDrama/sidebar/265.webp index 84f884930..dfe022163 100644 Binary files a/files/assets/images/rDrama/sidebar/265.webp and b/files/assets/images/rDrama/sidebar/265.webp differ diff --git a/files/assets/images/rDrama/sidebar/269.webp b/files/assets/images/rDrama/sidebar/269.webp index c9a5bf2f0..c851cbf8e 100644 Binary files a/files/assets/images/rDrama/sidebar/269.webp and b/files/assets/images/rDrama/sidebar/269.webp differ diff --git a/files/assets/images/rDrama/sidebar/290.webp b/files/assets/images/rDrama/sidebar/290.webp index dcf1471d3..3e67989d8 100644 Binary files a/files/assets/images/rDrama/sidebar/290.webp and b/files/assets/images/rDrama/sidebar/290.webp differ diff --git a/files/assets/images/rDrama/sidebar/320.webp b/files/assets/images/rDrama/sidebar/320.webp index 6a66f33d6..2cc1143a5 100644 Binary files a/files/assets/images/rDrama/sidebar/320.webp and b/files/assets/images/rDrama/sidebar/320.webp differ diff --git a/files/assets/images/rDrama/sidebar/358.webp b/files/assets/images/rDrama/sidebar/358.webp index 9de75ea31..8a681bac9 100644 Binary files a/files/assets/images/rDrama/sidebar/358.webp and b/files/assets/images/rDrama/sidebar/358.webp differ diff --git a/files/assets/images/rDrama/sidebar/361.webp b/files/assets/images/rDrama/sidebar/361.webp index e220659d2..59d89cf38 100644 Binary files a/files/assets/images/rDrama/sidebar/361.webp and b/files/assets/images/rDrama/sidebar/361.webp differ diff --git a/files/assets/images/rDrama/sidebar/372.webp b/files/assets/images/rDrama/sidebar/372.webp index 9f15e5240..40685e127 100644 Binary files a/files/assets/images/rDrama/sidebar/372.webp and b/files/assets/images/rDrama/sidebar/372.webp differ diff --git a/files/assets/images/rDrama/sidebar/374.webp b/files/assets/images/rDrama/sidebar/374.webp index 58099d014..a199aa502 100644 Binary files a/files/assets/images/rDrama/sidebar/374.webp and b/files/assets/images/rDrama/sidebar/374.webp differ diff --git a/files/assets/images/rDrama/sidebar/395.webp b/files/assets/images/rDrama/sidebar/395.webp index f289ff64e..95b9823af 100644 Binary files a/files/assets/images/rDrama/sidebar/395.webp and b/files/assets/images/rDrama/sidebar/395.webp differ diff --git a/files/assets/images/rDrama/sidebar/40.webp b/files/assets/images/rDrama/sidebar/40.webp index 021c53e2b..4e26ea7e2 100644 Binary files a/files/assets/images/rDrama/sidebar/40.webp and b/files/assets/images/rDrama/sidebar/40.webp differ diff --git a/files/assets/images/rDrama/sidebar/404.webp b/files/assets/images/rDrama/sidebar/404.webp index 14dbd651d..72f97afd5 100644 Binary files a/files/assets/images/rDrama/sidebar/404.webp and b/files/assets/images/rDrama/sidebar/404.webp differ diff --git a/files/assets/images/rDrama/sidebar/405.webp b/files/assets/images/rDrama/sidebar/405.webp index 326285ef5..dd7b90f65 100644 Binary files a/files/assets/images/rDrama/sidebar/405.webp and b/files/assets/images/rDrama/sidebar/405.webp differ diff --git a/files/assets/images/rDrama/sidebar/408.webp b/files/assets/images/rDrama/sidebar/408.webp index 4243a2b9c..016e78507 100644 Binary files a/files/assets/images/rDrama/sidebar/408.webp and b/files/assets/images/rDrama/sidebar/408.webp differ diff --git a/files/assets/images/rDrama/sidebar/42.webp b/files/assets/images/rDrama/sidebar/42.webp index 4f0fbd7a2..d3c01f146 100644 Binary files a/files/assets/images/rDrama/sidebar/42.webp and b/files/assets/images/rDrama/sidebar/42.webp differ diff --git a/files/assets/images/rDrama/sidebar/422.webp b/files/assets/images/rDrama/sidebar/422.webp index 59f8c1587..a9ebad6de 100644 Binary files a/files/assets/images/rDrama/sidebar/422.webp and b/files/assets/images/rDrama/sidebar/422.webp differ diff --git a/files/assets/images/rDrama/sidebar/437.webp b/files/assets/images/rDrama/sidebar/437.webp index 6b9f0bf57..723c6a192 100644 Binary files a/files/assets/images/rDrama/sidebar/437.webp and b/files/assets/images/rDrama/sidebar/437.webp differ diff --git a/files/assets/images/rDrama/sidebar/449.webp b/files/assets/images/rDrama/sidebar/449.webp index fc3d0df2b..1329e1a7d 100644 Binary files a/files/assets/images/rDrama/sidebar/449.webp and b/files/assets/images/rDrama/sidebar/449.webp differ diff --git a/files/assets/images/rDrama/sidebar/456.webp b/files/assets/images/rDrama/sidebar/456.webp index 54a9195d1..511cce217 100644 Binary files a/files/assets/images/rDrama/sidebar/456.webp and b/files/assets/images/rDrama/sidebar/456.webp differ diff --git a/files/assets/images/rDrama/sidebar/518.webp b/files/assets/images/rDrama/sidebar/518.webp index 484a43e53..7a3ee3f54 100644 Binary files a/files/assets/images/rDrama/sidebar/518.webp and b/files/assets/images/rDrama/sidebar/518.webp differ diff --git a/files/assets/images/rDrama/sidebar/532.webp b/files/assets/images/rDrama/sidebar/532.webp index ec644f3be..e967b88a1 100644 Binary files a/files/assets/images/rDrama/sidebar/532.webp and b/files/assets/images/rDrama/sidebar/532.webp differ diff --git a/files/assets/images/rDrama/sidebar/54.webp b/files/assets/images/rDrama/sidebar/54.webp index 882c7656c..5e909e812 100644 Binary files a/files/assets/images/rDrama/sidebar/54.webp and b/files/assets/images/rDrama/sidebar/54.webp differ diff --git a/files/assets/images/rDrama/sidebar/585.webp b/files/assets/images/rDrama/sidebar/585.webp index 6eac59a54..323e7bb85 100644 Binary files a/files/assets/images/rDrama/sidebar/585.webp and b/files/assets/images/rDrama/sidebar/585.webp differ diff --git a/files/assets/images/rDrama/sidebar/589.webp b/files/assets/images/rDrama/sidebar/589.webp index bd90e690c..0e5211339 100644 Binary files a/files/assets/images/rDrama/sidebar/589.webp and b/files/assets/images/rDrama/sidebar/589.webp differ diff --git a/files/assets/images/rDrama/sidebar/590.webp b/files/assets/images/rDrama/sidebar/590.webp index e6398fa5b..89512f69c 100644 Binary files a/files/assets/images/rDrama/sidebar/590.webp and b/files/assets/images/rDrama/sidebar/590.webp differ diff --git a/files/assets/images/rDrama/sidebar/594.webp b/files/assets/images/rDrama/sidebar/594.webp index 47702390e..ab66016c7 100644 Binary files a/files/assets/images/rDrama/sidebar/594.webp and b/files/assets/images/rDrama/sidebar/594.webp differ diff --git a/files/assets/images/rDrama/sidebar/626.webp b/files/assets/images/rDrama/sidebar/626.webp index 5f2065748..ddee5990f 100644 Binary files a/files/assets/images/rDrama/sidebar/626.webp and b/files/assets/images/rDrama/sidebar/626.webp differ diff --git a/files/assets/images/rDrama/sidebar/630.webp b/files/assets/images/rDrama/sidebar/630.webp index 203286f6b..58ef92cff 100644 Binary files a/files/assets/images/rDrama/sidebar/630.webp and b/files/assets/images/rDrama/sidebar/630.webp differ diff --git a/files/assets/images/rDrama/sidebar/645.webp b/files/assets/images/rDrama/sidebar/645.webp index 5a0271f27..85e7b3258 100644 Binary files a/files/assets/images/rDrama/sidebar/645.webp and b/files/assets/images/rDrama/sidebar/645.webp differ diff --git a/files/assets/images/rDrama/sidebar/67.webp b/files/assets/images/rDrama/sidebar/67.webp index 4d659c368..fe3edcfb8 100644 Binary files a/files/assets/images/rDrama/sidebar/67.webp and b/files/assets/images/rDrama/sidebar/67.webp differ diff --git a/files/assets/images/rDrama/sidebar/687.webp b/files/assets/images/rDrama/sidebar/687.webp index d7f1499e1..e4e0029b3 100644 Binary files a/files/assets/images/rDrama/sidebar/687.webp and b/files/assets/images/rDrama/sidebar/687.webp differ diff --git a/files/assets/images/rDrama/sidebar/694.webp b/files/assets/images/rDrama/sidebar/694.webp index 355a21485..195cc3e07 100644 Binary files a/files/assets/images/rDrama/sidebar/694.webp and b/files/assets/images/rDrama/sidebar/694.webp differ diff --git a/files/assets/images/rDrama/sidebar/707.webp b/files/assets/images/rDrama/sidebar/707.webp index 46a553862..16e605894 100644 Binary files a/files/assets/images/rDrama/sidebar/707.webp and b/files/assets/images/rDrama/sidebar/707.webp differ diff --git a/files/assets/images/rDrama/sidebar/710.webp b/files/assets/images/rDrama/sidebar/710.webp index bc7dc64f0..aabf8471b 100644 Binary files a/files/assets/images/rDrama/sidebar/710.webp and b/files/assets/images/rDrama/sidebar/710.webp differ diff --git a/files/assets/images/rDrama/sidebar/717.webp b/files/assets/images/rDrama/sidebar/717.webp index 49318cc0a..ab3a3ea6d 100644 Binary files a/files/assets/images/rDrama/sidebar/717.webp and b/files/assets/images/rDrama/sidebar/717.webp differ diff --git a/files/assets/images/rDrama/sidebar/720.webp b/files/assets/images/rDrama/sidebar/720.webp deleted file mode 100644 index 100d54b44..000000000 Binary files a/files/assets/images/rDrama/sidebar/720.webp and /dev/null differ diff --git a/files/assets/images/rDrama/sidebar/759.webp b/files/assets/images/rDrama/sidebar/759.webp index 0981f9b7c..30f61711c 100644 Binary files a/files/assets/images/rDrama/sidebar/759.webp and b/files/assets/images/rDrama/sidebar/759.webp differ diff --git a/files/assets/images/rDrama/sidebar/787.webp b/files/assets/images/rDrama/sidebar/787.webp index 260ab5510..9b2e51520 100644 Binary files a/files/assets/images/rDrama/sidebar/787.webp and b/files/assets/images/rDrama/sidebar/787.webp differ diff --git a/files/assets/images/rDrama/sidebar/790.webp b/files/assets/images/rDrama/sidebar/790.webp index 590e54408..a57f19355 100644 Binary files a/files/assets/images/rDrama/sidebar/790.webp and b/files/assets/images/rDrama/sidebar/790.webp differ diff --git a/files/assets/images/rDrama/sidebar/795.webp b/files/assets/images/rDrama/sidebar/795.webp index 39584edc5..fb0e843af 100644 Binary files a/files/assets/images/rDrama/sidebar/795.webp and b/files/assets/images/rDrama/sidebar/795.webp differ diff --git a/files/assets/images/rDrama/sidebar/800.webp b/files/assets/images/rDrama/sidebar/800.webp index 4c4bee677..f550ce07b 100644 Binary files a/files/assets/images/rDrama/sidebar/800.webp and b/files/assets/images/rDrama/sidebar/800.webp differ diff --git a/files/assets/images/rDrama/sidebar/804.webp b/files/assets/images/rDrama/sidebar/804.webp index 067d2d1c9..65d0e93fb 100644 Binary files a/files/assets/images/rDrama/sidebar/804.webp and b/files/assets/images/rDrama/sidebar/804.webp differ diff --git a/files/assets/images/rDrama/sidebar/805.webp b/files/assets/images/rDrama/sidebar/805.webp index 603175c95..7300346e4 100644 Binary files a/files/assets/images/rDrama/sidebar/805.webp and b/files/assets/images/rDrama/sidebar/805.webp differ diff --git a/files/assets/images/rDrama/sidebar/806.webp b/files/assets/images/rDrama/sidebar/806.webp index 7a57e6668..4bb52ad56 100644 Binary files a/files/assets/images/rDrama/sidebar/806.webp and b/files/assets/images/rDrama/sidebar/806.webp differ diff --git a/files/assets/images/rDrama/sidebar/807.webp b/files/assets/images/rDrama/sidebar/807.webp index 2b384e186..8a6a022a7 100644 Binary files a/files/assets/images/rDrama/sidebar/807.webp and b/files/assets/images/rDrama/sidebar/807.webp differ diff --git a/files/assets/images/rDrama/sidebar/808.webp b/files/assets/images/rDrama/sidebar/808.webp index f116225ff..2927e94d1 100644 Binary files a/files/assets/images/rDrama/sidebar/808.webp and b/files/assets/images/rDrama/sidebar/808.webp differ diff --git a/files/assets/images/rDrama/sidebar/809.webp b/files/assets/images/rDrama/sidebar/809.webp index 3189eff4f..3799fd80c 100644 Binary files a/files/assets/images/rDrama/sidebar/809.webp and b/files/assets/images/rDrama/sidebar/809.webp differ diff --git a/files/assets/images/rDrama/sidebar/810.webp b/files/assets/images/rDrama/sidebar/810.webp index ad59ba3d7..251e41205 100644 Binary files a/files/assets/images/rDrama/sidebar/810.webp and b/files/assets/images/rDrama/sidebar/810.webp differ diff --git a/files/assets/images/rDrama/sidebar/811.webp b/files/assets/images/rDrama/sidebar/811.webp index d663202bd..6e6c79f6b 100644 Binary files a/files/assets/images/rDrama/sidebar/811.webp and b/files/assets/images/rDrama/sidebar/811.webp differ diff --git a/files/assets/images/rDrama/sidebar/812.webp b/files/assets/images/rDrama/sidebar/812.webp index f1d0b2807..8bb348787 100644 Binary files a/files/assets/images/rDrama/sidebar/812.webp and b/files/assets/images/rDrama/sidebar/812.webp differ diff --git a/files/assets/images/rDrama/sidebar/813.webp b/files/assets/images/rDrama/sidebar/813.webp index 5432b519f..a763bf27a 100644 Binary files a/files/assets/images/rDrama/sidebar/813.webp and b/files/assets/images/rDrama/sidebar/813.webp differ diff --git a/files/assets/images/rDrama/sidebar/814.webp b/files/assets/images/rDrama/sidebar/814.webp index cf1456ed5..7c7df002c 100644 Binary files a/files/assets/images/rDrama/sidebar/814.webp and b/files/assets/images/rDrama/sidebar/814.webp differ diff --git a/files/assets/images/rDrama/sidebar/815.webp b/files/assets/images/rDrama/sidebar/815.webp index 6b10c81d2..c9a18cba9 100644 Binary files a/files/assets/images/rDrama/sidebar/815.webp and b/files/assets/images/rDrama/sidebar/815.webp differ diff --git a/files/assets/images/rDrama/sidebar/816.webp b/files/assets/images/rDrama/sidebar/816.webp index 0f788c363..deeb9eb5c 100644 Binary files a/files/assets/images/rDrama/sidebar/816.webp and b/files/assets/images/rDrama/sidebar/816.webp differ diff --git a/files/assets/images/rDrama/sidebar/817.webp b/files/assets/images/rDrama/sidebar/817.webp index a22392d03..4413c7480 100644 Binary files a/files/assets/images/rDrama/sidebar/817.webp and b/files/assets/images/rDrama/sidebar/817.webp differ diff --git a/files/assets/images/rDrama/sidebar/818.webp b/files/assets/images/rDrama/sidebar/818.webp index 0f9d6ebcc..3ead8e250 100644 Binary files a/files/assets/images/rDrama/sidebar/818.webp and b/files/assets/images/rDrama/sidebar/818.webp differ diff --git a/files/assets/images/rDrama/sidebar/819.webp b/files/assets/images/rDrama/sidebar/819.webp new file mode 100644 index 000000000..2e07f08ac Binary files /dev/null and b/files/assets/images/rDrama/sidebar/819.webp differ diff --git a/files/assets/images/rDrama/sidebar/820.webp b/files/assets/images/rDrama/sidebar/820.webp new file mode 100644 index 000000000..09bfc40cc Binary files /dev/null and b/files/assets/images/rDrama/sidebar/820.webp differ diff --git a/files/assets/images/rDrama/sidebar/821.webp b/files/assets/images/rDrama/sidebar/821.webp new file mode 100644 index 000000000..03963bf5a Binary files /dev/null and b/files/assets/images/rDrama/sidebar/821.webp differ diff --git a/files/assets/images/rDrama/sidebar/822.webp b/files/assets/images/rDrama/sidebar/822.webp new file mode 100644 index 000000000..564f9ff2d Binary files /dev/null and b/files/assets/images/rDrama/sidebar/822.webp differ diff --git a/files/assets/images/rDrama/sidebar/823.webp b/files/assets/images/rDrama/sidebar/823.webp new file mode 100644 index 000000000..976865126 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/823.webp differ diff --git a/files/assets/images/rDrama/sidebar/824.webp b/files/assets/images/rDrama/sidebar/824.webp new file mode 100644 index 000000000..cc865a36b Binary files /dev/null and b/files/assets/images/rDrama/sidebar/824.webp differ diff --git a/files/assets/images/rDrama/sidebar/825.webp b/files/assets/images/rDrama/sidebar/825.webp new file mode 100644 index 000000000..ba842bfa4 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/825.webp differ diff --git a/files/assets/images/rDrama/sidebar/826.webp b/files/assets/images/rDrama/sidebar/826.webp new file mode 100644 index 000000000..1546b0a29 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/826.webp differ diff --git a/files/assets/images/rDrama/sidebar/827.webp b/files/assets/images/rDrama/sidebar/827.webp new file mode 100644 index 000000000..8963b0acc Binary files /dev/null and b/files/assets/images/rDrama/sidebar/827.webp differ diff --git a/files/assets/images/rDrama/sidebar/829.webp b/files/assets/images/rDrama/sidebar/829.webp new file mode 100644 index 000000000..8595f77da Binary files /dev/null and b/files/assets/images/rDrama/sidebar/829.webp differ diff --git a/files/assets/images/rDrama/sidebar/830.webp b/files/assets/images/rDrama/sidebar/830.webp new file mode 100644 index 000000000..efb69d9d7 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/830.webp differ diff --git a/files/assets/images/rDrama/sidebar/831.webp b/files/assets/images/rDrama/sidebar/831.webp new file mode 100644 index 000000000..78542a9fa Binary files /dev/null and b/files/assets/images/rDrama/sidebar/831.webp differ diff --git a/files/assets/images/rDrama/sidebar/832.webp b/files/assets/images/rDrama/sidebar/832.webp new file mode 100644 index 000000000..b73dfa4a7 Binary files /dev/null and b/files/assets/images/rDrama/sidebar/832.webp differ diff --git a/files/assets/images/rDrama/sidebar/833.webp b/files/assets/images/rDrama/sidebar/833.webp new file mode 100644 index 000000000..26a8ed57e Binary files /dev/null and b/files/assets/images/rDrama/sidebar/833.webp differ diff --git a/files/assets/js/award_modal.js b/files/assets/js/award_modal.js index a597d0a21..1d7438e0a 100644 --- a/files/assets/js/award_modal.js +++ b/files/assets/js/award_modal.js @@ -86,13 +86,9 @@ function vote(type, id, dir) { } } } - - const xhr = new XMLHttpRequest(); - xhr.open("POST", "/vote/" + type.replace('-mobile','') + "/" + id + "/" + votedirection); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - xhr.send(form); + + const xhr = createXhrWithFormKey("/vote/" + type.replace('-mobile','') + "/" + id + "/" + votedirection); + xhr[0].send(xhr[1]); } function pick(kind, canbuy1, canbuy2) { @@ -111,7 +107,9 @@ function pick(kind, canbuy1, canbuy2) { let ownednum = Number(document.getElementById(`${kind}-owned`).textContent); document.getElementById('giveaward').disabled = (ownednum == 0); document.getElementById('kind').value=kind; - try {document.getElementsByClassName('picked')[0].classList.toggle('picked');} catch(e) {console.log(e)} + if (document.getElementsByClassName('picked').length > 0) { + document.getElementsByClassName('picked')[0].classList.toggle('picked'); + } document.getElementById(kind).classList.toggle('picked') if (kind == "flairlock") { document.getElementById('notelabel').innerHTML = "New flair:"; @@ -127,49 +125,45 @@ function pick(kind, canbuy1, canbuy2) { function buy(mb) { const kind = document.getElementById('kind').value; - const xhr = new XMLHttpRequest(); url = `/buy/${kind}` if (mb) url += "?mb=true" - xhr.open("POST", url); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - + const xhr = createXhrWithFormKey(url); if(typeof data === 'object' && data !== null) { for(let k of Object.keys(data)) { form.append(k, data[k]); } } - - - form.append("formkey", formkey()); - xhr.onload = function() { + xhr[0].onload = function() { let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data["message"]) { - document.getElementById('toast-post-success-text2').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success2')).show(); + success = xhr[0].status >= 200 && xhr[0].status < 300; + showToast(success, getMessageFromJsonData(success, data), true); + if (success) { document.getElementById('giveaward').disabled=false; let owned = document.getElementById(`${kind}-owned`) let ownednum = Number(owned.textContent); owned.textContent = ownednum + 1 - } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text2').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error2')).show(); } }; - xhr.send(form); + xhr[0].send(xhr[1]); } function giveaward(t) { + const kind = document.getElementById('kind').value; post_toast_callback(t.dataset.action, { - "kind": document.getElementById('kind').value, + "kind": kind, "note": document.getElementById('note').value - } + }, + (xhr) => { + if(xhr.status == 200) { + let owned = document.getElementById(`${kind}-owned`) + let ownednum = Number(owned.textContent); + owned.textContent = ownednum - 1 + } + } ); } diff --git a/files/assets/js/ban_modal.js b/files/assets/js/ban_modal.js index 6be925fff..2e4d968c9 100644 --- a/files/assets/js/ban_modal.js +++ b/files/assets/js/ban_modal.js @@ -5,26 +5,15 @@ function banModal(link, id, name) { document.getElementById("banUserButton").onclick = function() { let form = new FormData(document.getElementById("banModalForm")); - form.append("formkey", formkey()); - - const xhr = new XMLHttpRequest(); - xhr.open("POST", `/ban_user/${id}?form`); - xhr.setRequestHeader('xhr', 'xhr'); - - xhr.onload = function() { + const xhr = createXhrWithFormKey(`/ban_user/${id}?form`, "POST", form); + xhr[0].onload = function() { let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); - } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); - } + success = xhr[0].status >= 200 && xhr[0].status < 300; + showToast(success, getMessageFromJsonData(success, data)); }; - xhr.send(form); + xhr[0].send(xhr[1]); } } \ No newline at end of file diff --git a/files/assets/js/bootstrap.js b/files/assets/js/bootstrap.js index 8b4ca23e5..b045941de 100644 --- a/files/assets/js/bootstrap.js +++ b/files/assets/js/bootstrap.js @@ -1,352 +1 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i="#"+i.split("#")[1]),e=i&&"#"!==i?i.trim():null}return e},e=e=>{const i=t(e);return i&&document.querySelector(i)?i:null},i=e=>{const i=t(e);return i?document.querySelector(i):null},n=t=>{t.dispatchEvent(new Event("transitionend"))},s=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),o=t=>s(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,r=(t,e,i)=>{Object.keys(i).forEach(n=>{const o=i[n],r=e[n],a=r&&s(r)?"element":null==(l=r)?""+l:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(o).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${o}".`)})},a=t=>!(!s(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",()=>{f.forEach(t=>t())}),f.push(e)):e()},g=t=>{"function"==typeof t&&t()},_=(t,e,i=!0)=>{if(!i)return void g(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let o=!1;const r=({target:i})=>{i===e&&(o=!0,e.removeEventListener("transitionend",r),g(t))};e.addEventListener("transitionend",r),setTimeout(()=>{o||n(e)},s)},b=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,E={};let A=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},O=/^(mouseenter|mouseleave)/i,C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function k(t,e){return e&&`${e}::${A++}`||t.uidEvent||A++}function L(t){const e=k(t);return t.uidEvent=e,E[e]=E[e]||{},E[e]}function x(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=D(e,i,n),l=L(t),c=l[a]||(l[a]={}),h=x(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=k(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function N(t,e,i,n,s){const o=x(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function I(t){return t=t.replace(y,""),T[t]||t}const P={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=D(e,i,n),a=r!==e,l=L(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void N(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach(i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach(o=>{if(o.includes(n)){const n=s[o];N(t,e,i,n.originalHandler,n.delegationSelector)}})}(t,l,i,e.slice(1))});const h=l[r]||{};Object.keys(h).forEach(i=>{const n=i.replace(w,"");if(!a||e.includes(n)){const e=h[i];N(t,l,r,e.originalHandler,e.delegationSelector)}})},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u(),s=I(e),o=e!==s,r=C.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach(t=>{Object.defineProperty(d,t,{get:()=>i[t]})}),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},j=new Map;var M={set(t,e,i){j.has(t)||j.set(t,new Map);const n=j.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>j.has(t)&&j.get(t).get(e)||null,remove(t,e){if(!j.has(t))return;const i=j.get(t);i.delete(e),0===i.size&&j.delete(t)}};class H{constructor(t){(t=o(t))&&(this._element=t,M.set(this._element,this.constructor.DATA_KEY,this))}dispose(){M.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach(t=>{this[t]=null})}_queueCallback(t,e,i=!0){_(t,e,i)}static getInstance(t){return M.get(o(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.1"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return"bs."+this.NAME}static get EVENT_KEY(){return"."+this.DATA_KEY}}const B=(t,e="hide")=>{const n="click.dismiss"+t.EVENT_KEY,s=t.NAME;P.on(document,n,`[data-bs-dismiss="${s}"]`,(function(n){if(["A","AREA"].includes(this.tagName)&&n.preventDefault(),l(this))return;const o=i(this)||this.closest("."+s);t.getOrCreateInstance(o)[e]()}))};class R extends H{static get NAME(){return"alert"}close(){if(P.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback(()=>this._destroyElement(),this._element,t)}_destroyElement(){this._element.remove(),P.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=R.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}B(R,"close"),m(R);class W extends H{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function z(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function q(t){return t.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}P.on(document,"click.bs.button.data-api",'[data-bs-toggle="button"]',t=>{t.preventDefault();const e=t.target.closest('[data-bs-toggle="button"]');W.getOrCreateInstance(e).toggle()}),m(W);const F={setDataAttribute(t,e,i){t.setAttribute("data-bs-"+q(e),i)},removeDataAttribute(t,e){t.removeAttribute("data-bs-"+q(e))},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter(t=>t.startsWith("bs")).forEach(i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=z(t.dataset[i])}),e},getDataAttribute:(t,e)=>z(t.getAttribute("data-bs-"+q(e))),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},U={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(t=>t+':not([tabindex^="-"])').join(", ");return this.find(e,t).filter(t=>!l(t)&&a(t))}},$={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},V={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},K="next",X="prev",Y="left",Q="right",G={ArrowLeft:Q,ArrowRight:Y};class Z extends H{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=U.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return $}static get NAME(){return"carousel"}next(){this._slide(K)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(X)}pause(t){t||(this._isPaused=!0),U.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(n(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=U.findOne(".active.carousel-item",this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void P.one(this._element,"slid.bs.carousel",()=>this.to(t));if(e===t)return this.pause(),void this.cycle();const i=t>e?K:X;this._slide(i,this._items[t])}_getConfig(t){return t={...$,...F.getDataAttributes(this._element),..."object"==typeof t?t:{}},r("carousel",t,V),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?Q:Y)}_addEventListeners(){this._config.keyboard&&P.on(this._element,"keydown.bs.carousel",t=>this._keydown(t)),"hover"===this._config.pause&&(P.on(this._element,"mouseenter.bs.carousel",t=>this.pause(t)),P.on(this._element,"mouseleave.bs.carousel",t=>this.cycle(t))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(t=>this.cycle(t),500+this._config.interval))};U.find(".carousel-item img",this._element).forEach(t=>{P.on(t,"dragstart.bs.carousel",t=>t.preventDefault())}),this._pointerEvent?(P.on(this._element,"pointerdown.bs.carousel",t=>e(t)),P.on(this._element,"pointerup.bs.carousel",t=>n(t)),this._element.classList.add("pointer-event")):(P.on(this._element,"touchstart.bs.carousel",t=>e(t)),P.on(this._element,"touchmove.bs.carousel",t=>i(t)),P.on(this._element,"touchend.bs.carousel",t=>n(t)))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=G[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?U.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===K;return b(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(U.findOne(".active.carousel-item",this._element));return P.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=U.findOne(".active",this._indicatorsElement);e.classList.remove("active"),e.removeAttribute("aria-current");const i=U.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{P.trigger(this._element,"slid.bs.carousel",{relatedTarget:o,direction:u,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),d(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add("active"),n.classList.remove("active",h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove("active"),o.classList.add("active"),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[Q,Y].includes(t)?p()?t===Y?X:K:t===Y?K:X:t}_orderToDirection(t){return[K,X].includes(t)?p()?t===X?Y:Q:t===X?Q:Y:t}static carouselInterface(t,e){const i=Z.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){Z.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=i(this);if(!e||!e.classList.contains("carousel"))return;const n={...F.getDataAttributes(e),...F.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(n.interval=!1),Z.carouselInterface(e,n),s&&Z.getInstance(e).to(s),t.preventDefault()}}P.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",Z.dataApiClickHandler),P.on(window,"load.bs.carousel.data-api",()=>{const t=U.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element);null!==s&&o.length&&(this._selector=s,this._triggerArray.push(i))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return J}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=U.find(".collapse .collapse",this._config.parent);e=U.find(".collapse.show, .collapse.collapsing",this._config.parent).filter(e=>!t.includes(e))}const i=U.findOne(this._selector);if(e.length){const n=e.find(t=>i!==t);if(t=n?et.getInstance(n):null,t&&t._isTransitioning)return}if(P.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach(e=>{i!==e&&et.getOrCreateInstance(e,{toggle:!1}).hide(),t||M.set(e,"bs.collapse",null)});const n=this._getDimension();this._element.classList.remove("collapse"),this._element.classList.add("collapsing"),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s="scroll"+(n[0].toUpperCase()+n.slice(1));this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove("collapsing"),this._element.classList.add("collapse","show"),this._element.style[n]="",P.trigger(this._element,"shown.bs.collapse")},this._element,!0),this._element.style[n]=this._element[s]+"px"}hide(){if(this._isTransitioning||!this._isShown())return;if(P.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=this._element.getBoundingClientRect()[t]+"px",d(this._element),this._element.classList.add("collapsing"),this._element.classList.remove("collapse","show");const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove("collapsing"),this._element.classList.add("collapse"),P.trigger(this._element,"hidden.bs.collapse")},this._element,!0)}_isShown(t=this._element){return t.classList.contains("show")}_getConfig(t){return(t={...J,...F.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=o(t.parent),r("collapse",t,tt),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=U.find(".collapse .collapse",this._config.parent);U.find('[data-bs-toggle="collapse"]',this._config.parent).filter(e=>!t.includes(e)).forEach(t=>{const e=i(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))})}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach(t=>{e?t.classList.remove("collapsed"):t.classList.add("collapsed"),t.setAttribute("aria-expanded",e)})}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=et.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}P.on(document,"click.bs.collapse.data-api",'[data-bs-toggle="collapse"]',(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const i=e(this);U.find(i).forEach(t=>{et.getOrCreateInstance(t,{toggle:!1}).toggle()})})),m(et);var it="top",nt="bottom",st="right",ot="left",rt=[it,nt,st,ot],at="end",lt=rt.reduce((function(t,e){return t.concat([e+"-start",e+"-"+at])}),[]),ct=[].concat(rt,["auto"]).reduce((function(t,e){return t.concat([e,e+"-start",e+"-"+at])}),[]),ht=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function dt(t){return t?(t.nodeName||"").toLowerCase():null}function ut(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ft(t){return t instanceof ut(t).Element||t instanceof Element}function pt(t){return t instanceof ut(t).HTMLElement||t instanceof HTMLElement}function mt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof ut(t).ShadowRoot||t instanceof ShadowRoot)}var gt={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];pt(s)&&dt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});pt(n)&&dt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function _t(t){return t.split("-")[0]}var bt=Math.round;function vt(t,e){void 0===e&&(e=!1);var i=t.getBoundingClientRect(),n=1,s=1;if(pt(t)&&e){var o=t.offsetHeight,r=t.offsetWidth;r>0&&(n=i.width/r||1),o>0&&(s=i.height/o||1)}return{width:bt(i.width/n),height:bt(i.height/s),top:bt(i.top/s),right:bt(i.right/n),bottom:bt(i.bottom/s),left:bt(i.left/n),x:bt(i.left/n),y:bt(i.top/s)}}function yt(t){var e=vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function wt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&mt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Et(t){return ut(t).getComputedStyle(t)}function At(t){return["table","td","th"].indexOf(dt(t))>=0}function Tt(t){return((ft(t)?t.ownerDocument:t.document)||window.document).documentElement}function Ot(t){return"html"===dt(t)?t:t.assignedSlot||t.parentNode||(mt(t)?t.host:null)||Tt(t)}function Ct(t){return pt(t)&&"fixed"!==Et(t).position?t.offsetParent:null}function kt(t){for(var e=ut(t),i=Ct(t);i&&At(i)&&"static"===Et(i).position;)i=Ct(i);return i&&("html"===dt(i)||"body"===dt(i)&&"static"===Et(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&pt(t)&&"fixed"===Et(t).position)return null;for(var i=Ot(t);pt(i)&&["html","body"].indexOf(dt(i))<0;){var n=Et(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Lt(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var xt=Math.max,Dt=Math.min,St=Math.round;function Nt(t,e,i){return xt(t,Dt(e,i))}function It(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Pt(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}var jt={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=_t(i.placement),l=Lt(a),c=[ot,st].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return It("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Pt(t,rt))}(s.padding,i),d=yt(o),u="y"===l?it:ot,f="y"===l?nt:st,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=kt(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=Nt(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&wt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Mt(t){return t.split("-")[1]}var Ht={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Bt(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:St(St(e*n)/n)||0,y:St(St(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=ot,v=it,y=window;if(c){var w=kt(i),E="clientHeight",A="clientWidth";w===ut(i)&&"static"!==Et(w=Tt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==it&&(s!==ot&&s!==st||o!==at)||(v=nt,m-=w[E]-n.height,m*=l?1:-1),s!==ot&&(s!==it&&s!==nt||o!==at)||(b=st,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&Ht);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}var Rt={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:_t(e.placement),variation:Mt(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,Bt(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,Bt(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}},Wt={passive:!0},zt={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=ut(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,Wt)})),a&&l.addEventListener("resize",i.update,Wt),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,Wt)})),a&&l.removeEventListener("resize",i.update,Wt)}},data:{}},qt={left:"right",right:"left",bottom:"top",top:"bottom"};function Ft(t){return t.replace(/left|right|bottom|top/g,(function(t){return qt[t]}))}var Ut={start:"end",end:"start"};function $t(t){return t.replace(/start|end/g,(function(t){return Ut[t]}))}function Vt(t){var e=ut(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Kt(t){return vt(Tt(t)).left+Vt(t).scrollLeft}function Xt(t){var e=Et(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Yt(t,e){var i;void 0===e&&(e=[]);var n=function t(e){return["html","body","#document"].indexOf(dt(e))>=0?e.ownerDocument.body:pt(e)&&Xt(e)?e:t(Ot(e))}(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=ut(n),r=s?[o].concat(o.visualViewport||[],Xt(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Yt(Ot(r)))}function Qt(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Gt(t,e){return"viewport"===e?Qt(function(t){var e=ut(t),i=Tt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+Kt(t),y:a}}(t)):pt(e)?function(t){var e=vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Qt(function(t){var e,i=Tt(t),n=Vt(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=xt(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=xt(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Kt(t),l=-n.scrollTop;return"rtl"===Et(s||i).direction&&(a+=xt(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Tt(t)))}function Zt(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?_t(s):null,r=s?Mt(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case it:e={x:a,y:i.y-n.height};break;case nt:e={x:a,y:i.y+i.height};break;case st:e={x:i.x+i.width,y:l};break;case ot:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Lt(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case"start":e[c]=e[c]-(i[h]/2-n[h]/2);break;case at:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function Jt(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?"clippingParents":o,a=i.rootBoundary,l=void 0===a?"viewport":a,c=i.elementContext,h=void 0===c?"popper":c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=It("number"!=typeof p?p:Pt(p,rt)),g="popper"===h?"reference":"popper",_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Yt(Ot(t)),i=["absolute","fixed"].indexOf(Et(t).position)>=0&&pt(t)?kt(t):t;return ft(i)?e.filter((function(t){return ft(t)&&wt(t,i)&&"body"!==dt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Gt(t,i);return e.top=xt(n.top,e.top),e.right=Dt(n.right,e.right),e.bottom=Dt(n.bottom,e.bottom),e.left=xt(n.left,e.left),e}),Gt(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}(ft(b)?b:b.contextElement||Tt(t.elements.popper),r,l),y=vt(t.elements.reference),w=Zt({reference:y,element:_,strategy:"absolute",placement:s}),E=Qt(Object.assign({},_,w)),A="popper"===h?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if("popper"===h&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[st,nt].indexOf(t)>=0?1:-1,i=[it,nt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function te(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ct:l,h=Mt(n),d=h?a?lt:lt.filter((function(t){return Mt(t)===h})):rt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=Jt(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[_t(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}var ee={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=_t(g),b=l||(_!==g&&p?function(t){if("auto"===_t(t))return[];var e=Ft(t);return[$t(t),e,$t(e)]}(g):[Ft(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat("auto"===_t(i)?te(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=Jt(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?st:ot:L?nt:it;y[D]>w[D]&&(N=Ft(N));var I=Ft(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ie(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ne(t){return[it,st,nt,ot].some((function(e){return t[e]>=0}))}var se={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=Jt(e,{elementContext:"reference"}),a=Jt(e,{altBoundary:!0}),l=ie(r,n),c=ie(a,s,o),h=ne(l),d=ne(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},oe={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ct.reduce((function(t,i){return t[i]=function(t,e,i){var n=_t(t),s=[ot,it].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[ot,st].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},re={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Zt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},ae={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=Jt(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=_t(e.placement),b=Mt(e.placement),v=!b,y=Lt(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?it:ot,L="y"===y?nt:st,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P="start"===b?A[x]:T[x],j="start"===b?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?yt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],z=Nt(0,A[x],H[x]),q=v?A[x]/2-I-z-R-O:P-z-R-O,F=v?-A[x]/2+I+z+W+O:j+z+W+O,U=e.elements.arrow&&kt(e.elements.arrow),$=U?"y"===y?U.clientTop||0:U.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+q-V-$,X=E[y]+F-V;if(o){var Y=Nt(f?Dt(S,K):S,D,f?xt(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?it:ot,G="x"===y?nt:st,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=Nt(f?Dt(J,K):J,Z,f?xt(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function le(t,e,i){void 0===i&&(i=!1);var n,s,o=pt(e),r=pt(e)&&function(t){var e=t.getBoundingClientRect(),i=e.width/t.offsetWidth||1,n=e.height/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Tt(e),l=vt(t,r),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==dt(e)||Xt(a))&&(c=(n=e)!==ut(n)&&pt(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Vt(n)),pt(e)?((h=vt(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Kt(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}var ce={placement:"bottom",modifiers:[],strategy:"absolute"};function he(){for(var t=arguments.length,e=new Array(t),i=0;iP.on(t,"mouseover",h)),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add("show"),this._element.classList.add("show"),P.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(l(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){P.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",h)),this._popper&&this._popper.destroy(),this._menu.classList.remove("show"),this._element.classList.remove("show"),this._element.setAttribute("aria-expanded","false"),F.removeDataAttribute(this._menu,"popper"),P.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...F.getDataAttributes(this._element),...t},r("dropdown",t,this.constructor.DefaultType),"object"==typeof t.reference&&!s(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError("dropdown".toUpperCase()+': Option "reference" provided type "object" without a required "getBoundingClientRect" method.');return t}_createPopper(t){if(void 0===me)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:s(this._config.reference)?e=o(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find(t=>"applyStyles"===t.name&&!1===t.enabled);this._popper=pe(e,this._menu,i),n&&F.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains("show")}_getMenuElement(){return U.next(this._element,".dropdown-menu")[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return we;if(t.classList.contains("dropstart"))return Ee;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?be:_e:e?ye:ve}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=U.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(a);i.length&&b(i,e,"ArrowDown"===t,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Oe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=U.find('[data-bs-toggle="dropdown"]');for(let i=0,n=e.length;ie+t),this._setElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight",e=>e+t),this._setElementAttributes(".sticky-top","marginRight",e=>e-t)}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=i(Number.parseFloat(s))+"px"})}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight"),this._resetElementAttributes(".sticky-top","marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=F.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(F.removeDataAttribute(t,e),t.style[e]=i)})}_applyManipulationCallback(t,e){s(t)?e(t):U.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const ke={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},Le={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"};class xe{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&d(this._getElement()),this._getElement().classList.add("show"),this._emulateAnimation(()=>{g(t)})):g(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove("show"),this._emulateAnimation(()=>{this.dispose(),g(t)})):g(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...ke,..."object"==typeof t?t:{}}).rootElement=o(t.rootElement),r("backdrop",t,Le),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),P.on(this._getElement(),"mousedown.bs.backdrop",()=>{g(this._config.clickCallback)}),this._isAppended=!0)}dispose(){this._isAppended&&(P.off(this._element,"mousedown.bs.backdrop"),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const De={trapElement:null,autofocus:!0},Se={trapElement:"element",autofocus:"boolean"};class Ne{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),P.off(document,".bs.focustrap"),P.on(document,"focusin.bs.focustrap",t=>this._handleFocusin(t)),P.on(document,"keydown.tab.bs.focustrap",t=>this._handleKeydown(t)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,P.off(document,".bs.focustrap"))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=U.focusableChildren(i);0===n.length?i.focus():"backward"===this._lastTabNavDirection?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?"backward":"forward")}_getConfig(t){return t={...De,..."object"==typeof t?t:{}},r("focustrap",t,Se),t}}const Ie={backdrop:!0,keyboard:!0,focus:!0},Pe={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"};class je extends H{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=U.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new Ce}static get Default(){return Ie}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,"show.bs.modal",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add("modal-open"),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),P.on(this._dialog,"mousedown.dismiss.bs.modal",()=>{P.one(this._element,"mouseup.dismiss.bs.modal",t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)})}),this._showBackdrop(()=>this._showElement(t)))}hide(){if(!this._isShown||this._isTransitioning)return;if(P.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove("show"),P.off(this._element,"click.dismiss.bs.modal"),P.off(this._dialog,"mousedown.dismiss.bs.modal"),this._queueCallback(()=>this._hideModal(),this._element,t)}dispose(){[window,this._dialog].forEach(t=>P.off(t,".bs.modal")),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new xe({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ne({trapElement:this._element})}_getConfig(t){return t={...Ie,...F.getDataAttributes(this._element),..."object"==typeof t?t:{}},r("modal",t,Pe),t}_showElement(t){const e=this._isAnimated(),i=U.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&d(this._element),this._element.classList.add("show"),this._queueCallback(()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,P.trigger(this._element,"shown.bs.modal",{relatedTarget:t})},this._dialog,e)}_setEscapeEvent(){this._isShown?P.on(this._element,"keydown.dismiss.bs.modal",t=>{this._config.keyboard&&"Escape"===t.key?(t.preventDefault(),this.hide()):this._config.keyboard||"Escape"!==t.key||this._triggerBackdropTransition()}):P.off(this._element,"keydown.dismiss.bs.modal")}_setResizeEvent(){this._isShown?P.on(window,"resize.bs.modal",()=>this._adjustDialog()):P.off(window,"resize.bs.modal")}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove("modal-open"),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,"hidden.bs.modal")})}_showBackdrop(t){P.on(this._element,"click.dismiss.bs.modal",t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())}),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains("modal-static")||(n||(i.overflowY="hidden"),t.add("modal-static"),this._queueCallback(()=>{t.remove("modal-static"),n||this._queueCallback(()=>{i.overflowY=""},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!p()||i&&!t&&p())&&(this._element.style.paddingLeft=e+"px"),(i&&!t&&!p()||!i&&t&&p())&&(this._element.style.paddingRight=e+"px")}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=je.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}P.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=i(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,"show.bs.modal",t=>{t.defaultPrevented||P.one(e,"hidden.bs.modal",()=>{a(this)&&this.focus()})});const n=U.findOne(".modal.show");n&&je.getInstance(n).hide(),je.getOrCreateInstance(e).toggle(this)})),B(je),m(je);const Me={backdrop:!0,keyboard:!0,scroll:!1},He={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"};class Be extends H{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return"offcanvas"}static get Default(){return Me}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new Ce).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add("show"),this._queueCallback(()=>{this._config.scroll||this._focustrap.activate(),P.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove("show"),this._backdrop.hide(),this._queueCallback(()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new Ce).reset(),P.trigger(this._element,"hidden.bs.offcanvas")},this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Me,...F.getDataAttributes(this._element),..."object"==typeof t?t:{}},r("offcanvas",t,He),t}_initializeBackDrop(){return new xe({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ne({trapElement:this._element})}_addEventListeners(){P.on(this._element,"keydown.dismiss.bs.offcanvas",t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()})}static jQueryInterface(t){return this.each((function(){const e=Be.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}P.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=i(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;P.one(e,"hidden.bs.offcanvas",()=>{a(this)&&this.focus()});const n=U.findOne(".offcanvas.show");n&&n!==e&&Be.getInstance(n).hide(),Be.getOrCreateInstance(e).toggle(this)})),P.on(window,"load.bs.offcanvas.data-api",()=>U.find(".offcanvas.show").forEach(t=>Be.getOrCreateInstance(t).show())),B(Be),m(Be);const Re=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),We=/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i,ze=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,qe=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Re.has(i)||Boolean(We.test(t.nodeValue)||ze.test(t.nodeValue));const n=e.filter(t=>t instanceof RegExp);for(let t=0,e=n.length;t{qe(t,a)||i.removeAttribute(t.nodeName)})}return n.body.innerHTML}const Ue=new Set(["sanitize","allowList","sanitizeFn"]),$e={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ve={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},Ke={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Xe={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"};class Ye extends H{constructor(t,e){if(void 0===me)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return Ke}static get NAME(){return"tooltip"}static get Event(){return Xe}static get DefaultType(){return $e}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains("show"))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.Event.SHOW),e=c(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(".tooltip-inner").innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add("fade");const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;M.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),P.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=pe(this._element,n,this._getPopperConfig(r)),n.classList.add("show");const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>{P.on(t,"mouseover",h)});const d=this.tip.classList.contains("fade");this._queueCallback(()=>{const t=this._hoverState;this._hoverState=null,P.trigger(this._element,this.constructor.Event.SHOWN),"out"===t&&this._leave(null,this)},this.tip,d)}hide(){if(!this._popper)return;const t=this.getTipElement();if(P.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove("show"),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",h)),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains("fade");this._queueCallback(()=>{this._isWithActiveTrigger()||("show"!==this._hoverState&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())},this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove("fade","show"),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".tooltip-inner")}_sanitizeAndSetContent(t,e,i){const n=U.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return s(e)?(e=o(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Fe(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ve[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach(t=>{if("click"===t)P.on(this._element,this.constructor.Event.CLICK,this._config.selector,t=>this.toggle(t));else if("manual"!==t){const e="hover"===t?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i="hover"===t?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;P.on(this._element,e,this._config.selector,t=>this._enter(t)),P.on(this._element,i,this._config.selector,t=>this._leave(t))}}),this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),e.getTipElement().classList.contains("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e._config.delay&&e._config.delay.show?e._timeout=setTimeout(()=>{"show"===e._hoverState&&e.show()},e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e._config.delay&&e._config.delay.hide?e._timeout=setTimeout(()=>{"out"===e._hoverState&&e.hide()},e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=F.getDataAttributes(this._element);return Object.keys(e).forEach(t=>{Ue.has(t)&&delete e[t]}),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:o(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),r("tooltip",t,this.constructor.DefaultType),t.sanitize&&(t.template=Fe(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=Ye.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(Ye);const Qe={...Ye.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},Ge={...Ye.DefaultType,content:"(string|element|function)"},Ze={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Je extends Ye{static get Default(){return Qe}static get NAME(){return"popover"}static get Event(){return Ze}static get DefaultType(){return Ge}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=Je.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(Je);const ti={offset:10,method:"auto",target:""},ei={offset:"number",method:"string",target:"(string|element)"},ii=".nav-link, .list-group-item, .dropdown-item";class ni extends H{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,P.on(this._scrollElement,"scroll.bs.scrollspy",()=>this._process()),this.refresh(),this._process()}static get Default(){return ti}static get NAME(){return"scrollspy"}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":"position",i="auto"===this._config.method?t:this._config.method,n="position"===i?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),U.find(ii,this._config.target).map(t=>{const s=e(t),o=s?U.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[F[i](o).top+n,s]}return null}).filter(t=>t).sort((t,e)=>t[0]-e[0]).forEach(t=>{this._offsets.push(t[0]),this._targets.push(t[1])})}dispose(){P.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...ti,...F.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=o(t.target)||document.documentElement,r("scrollspy",t,ei),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`),i=U.findOne(e.join(","),this._config.target);i.classList.add("active"),i.classList.contains("dropdown-item")?U.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add("active"):U.parents(i,".nav, .list-group").forEach(t=>{U.prev(t,".nav-link, .list-group-item").forEach(t=>t.classList.add("active")),U.prev(t,".nav-item").forEach(t=>{U.children(t,".nav-link").forEach(t=>t.classList.add("active"))})}),P.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){U.find(ii,this._config.target).filter(t=>t.classList.contains("active")).forEach(t=>t.classList.remove("active"))}static jQueryInterface(t){return this.each((function(){const e=ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(window,"load.bs.scrollspy.data-api",()=>{U.find('[data-bs-spy="scroll"]').forEach(t=>new ni(t))}),m(ni);class si extends H{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains("active"))return;let t;const e=i(this._element),n=this._element.closest(".nav, .list-group");if(n){const e="UL"===n.nodeName||"OL"===n.nodeName?":scope > li > .active":".active";t=U.find(e,n),t=t[t.length-1]}const s=t?P.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(P.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,n);const o=()=>{P.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),P.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?U.children(e,".active"):U.find(":scope > li > .active",e))[0],s=i&&n&&n.classList.contains("fade"),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove("show"),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove("active");const t=U.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d(t),t.classList.contains("fade")&&t.classList.add("show");let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&U.find(".dropdown-toggle",e).forEach(t=>t.classList.add("active")),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=si.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||si.getOrCreateInstance(this).show()})),m(si);const oi={animation:"boolean",autohide:"boolean",delay:"number"},ri={animation:!0,autohide:!0,delay:5e3};class ai extends H{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return oi}static get Default(){return ri}static get NAME(){return"toast"}show(){P.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove("hide"),d(this._element),this._element.classList.add("show"),this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.remove("showing"),P.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this._element.classList.contains("show")&&(P.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.add("hide"),this._element.classList.remove("showing"),this._element.classList.remove("show"),P.trigger(this._element,"hidden.bs.toast")},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),super.dispose()}_getConfig(t){return t={...ri,...F.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},r("toast",t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,"mouseover.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"mouseout.bs.toast",t=>this._onInteraction(t,!1)),P.on(this._element,"focusin.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"focusout.bs.toast",t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ai.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return B(ai),m(ai),{Alert:R,Button:W,Carousel:Z,Collapse:et,Dropdown:Oe,Modal:je,Offcanvas:Be,Popover:Je,ScrollSpy:ni,Tab:si,Toast:ai,Tooltip:Ye}})); - -if (window.location.pathname != '/submit') -{ - document.addEventListener('keydown', (e) => { - if(!((e.ctrlKey || e.metaKey) && e.key === "Enter")) return; - - const targetDOM = document.activeElement; - if(!(targetDOM instanceof HTMLTextAreaElement || targetDOM instanceof HTMLInputElement)) return; - - const formDOM = targetDOM.parentElement; - - const submitButtonDOMs = formDOM.querySelectorAll('input[type=submit], .btn-primary'); - if(submitButtonDOMs.length === 0) - throw new TypeError("I am unable to find the submit button :(. Contact the head custodian immediately.") - - const btn = submitButtonDOMs[0] - btn.click(); - }); -} - -addEventListener('show.bs.modal', function (e) { - location.hash = "modal"; -}); - -addEventListener('hide.bs.modal', function (e) { - if(location.hash == "#modal") { - history.back(); - } -}); - -addEventListener('hashchange', function (e) { - if(location.hash != "#modal") { - const curr_modal = bootstrap.Modal.getInstance(document.getElementsByClassName('show')[0]) - if (curr_modal) curr_modal.hide() - } -}); - -function disable(t) { - t.classList.add('disabled'); - setTimeout(() => { - t.classList.remove("disabled"); - }, 2000); -} - -function autoExpand (field) { - xpos=window.scrollX; - ypos=window.scrollY; - - field.style.height = 'inherit'; - - var computed = window.getComputedStyle(field); - - var height = parseInt(computed.getPropertyValue('border-top-width'), 10) - + parseInt(computed.getPropertyValue('padding-top'), 10) - + field.scrollHeight - + parseInt(computed.getPropertyValue('padding-bottom'), 10) - + parseInt(computed.getPropertyValue('border-bottom-width'), 10); - - field.style.height = height + 'px'; - - window.scrollTo(xpos,ypos); -}; - -document.addEventListener('input', function (event) { - if (event.target.tagName.toLowerCase() !== 'textarea') return; - autoExpand(event.target); -}, false); - -function smoothScrollTop() -{ - window.scrollTo({ top: 0, behavior: 'smooth' }); -} - -// Click navbar to scroll back to top -(() => { - let toplisteners = [ - document.querySelector('nav') - ]; - - for (let i of toplisteners) - { - i.addEventListener('click', (e) => { - if (e.target.id === "navbar" || - e.target.classList.contains("container-fluid") || - e.target.id == "navbarResponsive" || - e.target.id == "logo-container" || - e.target.classList.contains("srd")) - smoothScrollTop(); - }, false); - } -})(); - -// Dynamic shadow when the user scrolls -document.addEventListener('scroll',function (event) { - let nav = document.querySelector("nav"); - let i = (Math.min(20, window.scrollY/4)+1)/21; - nav.style.boxShadow="0px 2px "+i*21+"px rgba(15,15,15,"+i*.3+")"; - if (window.scrollY <= 0) - { -// nav.classList.remove("shadow"); - nav.classList.remove("navbar-active"); - nav.style.boxShadow = "unset"; - } - else - { -// nav.classList.add("shadow"); - nav.classList.add("navbar-active"); - } - -}, false); - -function formkey() { - let formkey = document.getElementById("formkey") - if (formkey) return formkey.innerHTML; - else return null; -} - -function expandDesktopImage(url) { - const e = this.event - if(e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) - return true; - e.preventDefault(); - if (!url) - { - url = e.target.dataset.src - if (!url) url = e.target.src - } - document.getElementById("desktop-expanded-image").src = url.replace("200w_d.webp", "giphy.webp"); - document.getElementById("desktop-expanded-image-wrap-link").href = url; - bootstrap.Modal.getOrCreateInstance(document.getElementById('expandImageModal')).show(); -}; - -document.addEventListener("click", function(e){ - const element = e.target - if (element instanceof HTMLImageElement && element.alt.startsWith('![](')) - expandDesktopImage() -}); - -function bs_trigger(e) { - let tooltipTriggerList = [].slice.call(e.querySelectorAll('[data-bs-toggle="tooltip"]')); - tooltipTriggerList.map(function(element){ - return bootstrap.Tooltip.getOrCreateInstance(element); - }); - - const popoverTriggerList = [].slice.call(e.querySelectorAll('[data-bs-toggle="popover"]')); - popoverTriggerList.map(function(popoverTriggerEl) { - const popoverId = popoverTriggerEl.getAttribute('data-content-id'); - let contentEl; - try {contentEl = e.getElementById(popoverId);} - catch(t) {contentEl = document.getElementById(popoverId);} - if (contentEl) { - return bootstrap.Popover.getOrCreateInstance(popoverTriggerEl, { - content: contentEl.innerHTML, - html: true, - }); - } - }) - - if (typeof update_speed_emoji_modal != 'undefined') { - let forms = e.querySelectorAll("textarea, .allow-emojis"); - forms.forEach(i => { - let pseudo_div = document.createElement("div"); - pseudo_div.className = "ghostdiv"; - pseudo_div.style.display = "none"; - i.after(pseudo_div); - i.addEventListener('input', update_speed_emoji_modal, false); - i.addEventListener('keydown', speed_carot_navigate, false); - }); - } -} - -var bsTriggerOnReady = function() { - bs_trigger(document); -} - -if (document.readyState === "complete" || - (document.readyState !== "loading" && !document.documentElement.doScroll)) { - bsTriggerOnReady(); -} else { - document.addEventListener("DOMContentLoaded", bsTriggerOnReady); -} - -function post_toast(t, url, button1, button2, classname, extra_actions) { - let isShopConfirm = t.id.startsWith('buy1-go') || t.id.startsWith('buy2-go'); - - if (!isShopConfirm) - { - t.disabled = true; - t.classList.add("disabled"); - } - const xhr = new XMLHttpRequest(); - xhr.open("POST", url); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - - - xhr.onload = function() { - let data - try {data = JSON.parse(xhr.response)} - catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); - - if (button1) - { - if (typeof(button1) == 'boolean') - location.reload() - else { - document.getElementById(button1).classList.toggle(classname); - document.getElementById(button2).classList.toggle(classname); - } - } - - if (extra_actions) extra_actions(xhr); - } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); - } - if (!isShopConfirm) - { - setTimeout(() => { - t.disabled = false; - t.classList.remove("disabled"); - }, 2000); - } - }; - - xhr.send(form); - -} - -function post_toast_callback(url, data, callback) { - const xhr = new XMLHttpRequest(); - xhr.open("POST", url); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - - if(typeof data === 'object' && data !== null) { - for(let k of Object.keys(data)) { - form.append(k, data[k]); - } - } - - form.append("formkey", formkey()); - xhr.onload = function() { - let result - if (callback) result = callback(xhr); - if (xhr.status >= 200 && xhr.status < 300) { - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')); - myToast.hide(); - - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')); - myToast.show(); - - try { - if(typeof result == "string") { - document.getElementById('toast-post-success-text').innerText = result; - } else { - document.getElementById('toast-post-success-text').innerText = JSON.parse(xhr.response)["message"]; - } - } catch(e) { - } - - return true; - } else { - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')); - myToast.hide(); - - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')); - myToast.show(); - - try { - if(typeof result == "string") { - document.getElementById('toast-post-error-text').innerText = result; - } else { - document.getElementById('toast-post-error-text').innerText = JSON.parse(xhr.response)["error"]; - } - return false - } catch(e) {console.log(e)} - - return false; - } - }; - - xhr.send(form); - -} - -function escapeHTML(unsafe) { - return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); -} - -function changename(s1,s2) { - let files = document.getElementById(s2).files; - let filename = ''; - for (const e of files) { - filename += e.name.substr(0, 20) + ', '; - } - document.getElementById(s1).innerHTML = escapeHTML(filename.slice(0, -2)); -} - -function showmore() { - const btn = this.event.target - const div = btn.parentElement.nextElementSibling - div.classList.toggle('d-none') - if (div.classList.contains('d-none')) - btn.innerHTML = 'SHOW MORE' - else - btn.innerHTML = 'SHOW LESS' -} - -function formatDate(d) { - var year = d.getFullYear(); - var monthAbbr = d.toLocaleDateString('en-us', {month: 'short'}); - var day = d.getDate(); - var hour = ("0" + d.getHours()).slice(-2); - var minute = ("0" + d.getMinutes()).slice(-2); - var second = ("0" + d.getSeconds()).slice(-2); - var tzAbbr = d.toLocaleTimeString('en-us', {timeZoneName: 'short'}).split(' ')[2]; - - return (day + " " + monthAbbr + " " + year + " " - + hour + ":" + minute + ":" + second + " " + tzAbbr); -} - -const timestamps = document.querySelectorAll('[data-time]'); - -for (const e of timestamps) { - const date = new Date(e.dataset.time*1000); - e.innerHTML = formatDate(date); -}; - -function timestamp(str, ti) { - const date = new Date(ti*1000); - document.getElementById(str).setAttribute("data-bs-original-title", formatDate(date)); -}; - -function areyousure(t) { - if (t.value) - t.value = 'Are you sure?' - else - t.innerHTML = t.innerHTML.replace(t.textContent, 'Are you sure?') - - t.setAttribute("onclick", t.dataset.click); - - if (t.dataset.dismiss) - t.setAttribute("data-bs-dismiss", t.dataset.dismiss); -} +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i="#"+i.split("#")[1]),e=i&&"#"!==i?i.trim():null}return e},e=e=>{const i=t(e);return i&&document.querySelector(i)?i:null},i=e=>{const i=t(e);return i?document.querySelector(i):null},n=t=>{t.dispatchEvent(new Event("transitionend"))},s=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),o=t=>s(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,r=(t,e,i)=>{Object.keys(i).forEach(n=>{const o=i[n],r=e[n],a=r&&s(r)?"element":null==(l=r)?""+l:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(o).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${o}".`)})},a=t=>!(!s(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},f=[],p=()=>"rtl"===document.documentElement.dir,m=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",()=>{f.forEach(t=>t())}),f.push(e)):e()},g=t=>{"function"==typeof t&&t()},_=(t,e,i=!0)=>{if(!i)return void g(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let o=!1;const r=({target:i})=>{i===e&&(o=!0,e.removeEventListener("transitionend",r),g(t))};e.addEventListener("transitionend",r),setTimeout(()=>{o||n(e)},s)},b=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,E={};let A=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},O=/^(mouseenter|mouseleave)/i,C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function k(t,e){return e&&`${e}::${A++}`||t.uidEvent||A++}function L(t){const e=k(t);return t.uidEvent=e,E[e]=E[e]||{},E[e]}function x(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=D(e,i,n),l=L(t),c=l[a]||(l[a]={}),h=x(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=k(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function N(t,e,i,n,s){const o=x(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function I(t){return t=t.replace(y,""),T[t]||t}const P={on(t,e,i,n){S(t,e,i,n,!1)},one(t,e,i,n){S(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=D(e,i,n),a=r!==e,l=L(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void N(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach(i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach(o=>{if(o.includes(n)){const n=s[o];N(t,e,i,n.originalHandler,n.delegationSelector)}})}(t,l,i,e.slice(1))});const h=l[r]||{};Object.keys(h).forEach(i=>{const n=i.replace(w,"");if(!a||e.includes(n)){const e=h[i];N(t,l,r,e.originalHandler,e.delegationSelector)}})},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u(),s=I(e),o=e!==s,r=C.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach(t=>{Object.defineProperty(d,t,{get:()=>i[t]})}),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},j=new Map;var M={set(t,e,i){j.has(t)||j.set(t,new Map);const n=j.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>j.has(t)&&j.get(t).get(e)||null,remove(t,e){if(!j.has(t))return;const i=j.get(t);i.delete(e),0===i.size&&j.delete(t)}};class H{constructor(t){(t=o(t))&&(this._element=t,M.set(this._element,this.constructor.DATA_KEY,this))}dispose(){M.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach(t=>{this[t]=null})}_queueCallback(t,e,i=!0){_(t,e,i)}static getInstance(t){return M.get(o(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.1"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return"bs."+this.NAME}static get EVENT_KEY(){return"."+this.DATA_KEY}}const B=(t,e="hide")=>{const n="click.dismiss"+t.EVENT_KEY,s=t.NAME;P.on(document,n,`[data-bs-dismiss="${s}"]`,(function(n){if(["A","AREA"].includes(this.tagName)&&n.preventDefault(),l(this))return;const o=i(this)||this.closest("."+s);t.getOrCreateInstance(o)[e]()}))};class R extends H{static get NAME(){return"alert"}close(){if(P.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback(()=>this._destroyElement(),this._element,t)}_destroyElement(){this._element.remove(),P.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=R.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}B(R,"close"),m(R);class W extends H{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function z(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function q(t){return t.replace(/[A-Z]/g,t=>"-"+t.toLowerCase())}P.on(document,"click.bs.button.data-api",'[data-bs-toggle="button"]',t=>{t.preventDefault();const e=t.target.closest('[data-bs-toggle="button"]');W.getOrCreateInstance(e).toggle()}),m(W);const F={setDataAttribute(t,e,i){t.setAttribute("data-bs-"+q(e),i)},removeDataAttribute(t,e){t.removeAttribute("data-bs-"+q(e))},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter(t=>t.startsWith("bs")).forEach(i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=z(t.dataset[i])}),e},getDataAttribute:(t,e)=>z(t.getAttribute("data-bs-"+q(e))),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},U={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(t=>t+':not([tabindex^="-"])').join(", ");return this.find(e,t).filter(t=>!l(t)&&a(t))}},$={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},V={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},K="next",X="prev",Y="left",Q="right",G={ArrowLeft:Q,ArrowRight:Y};class Z extends H{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=U.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return $}static get NAME(){return"carousel"}next(){this._slide(K)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(X)}pause(t){t||(this._isPaused=!0),U.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(n(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=U.findOne(".active.carousel-item",this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void P.one(this._element,"slid.bs.carousel",()=>this.to(t));if(e===t)return this.pause(),void this.cycle();const i=t>e?K:X;this._slide(i,this._items[t])}_getConfig(t){return t={...$,...F.getDataAttributes(this._element),..."object"==typeof t?t:{}},r("carousel",t,V),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?Q:Y)}_addEventListeners(){this._config.keyboard&&P.on(this._element,"keydown.bs.carousel",t=>this._keydown(t)),"hover"===this._config.pause&&(P.on(this._element,"mouseenter.bs.carousel",t=>this.pause(t)),P.on(this._element,"mouseleave.bs.carousel",t=>this.cycle(t))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(t=>this.cycle(t),500+this._config.interval))};U.find(".carousel-item img",this._element).forEach(t=>{P.on(t,"dragstart.bs.carousel",t=>t.preventDefault())}),this._pointerEvent?(P.on(this._element,"pointerdown.bs.carousel",t=>e(t)),P.on(this._element,"pointerup.bs.carousel",t=>n(t)),this._element.classList.add("pointer-event")):(P.on(this._element,"touchstart.bs.carousel",t=>e(t)),P.on(this._element,"touchmove.bs.carousel",t=>i(t)),P.on(this._element,"touchend.bs.carousel",t=>n(t)))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=G[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?U.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===K;return b(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(U.findOne(".active.carousel-item",this._element));return P.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=U.findOne(".active",this._indicatorsElement);e.classList.remove("active"),e.removeAttribute("aria-current");const i=U.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{P.trigger(this._element,"slid.bs.carousel",{relatedTarget:o,direction:u,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),d(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add("active"),n.classList.remove("active",h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove("active"),o.classList.add("active"),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[Q,Y].includes(t)?p()?t===Y?X:K:t===Y?K:X:t}_orderToDirection(t){return[K,X].includes(t)?p()?t===X?Y:Q:t===X?Q:Y:t}static carouselInterface(t,e){const i=Z.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){Z.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=i(this);if(!e||!e.classList.contains("carousel"))return;const n={...F.getDataAttributes(e),...F.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(n.interval=!1),Z.carouselInterface(e,n),s&&Z.getInstance(e).to(s),t.preventDefault()}}P.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",Z.dataApiClickHandler),P.on(window,"load.bs.carousel.data-api",()=>{const t=U.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element);null!==s&&o.length&&(this._selector=s,this._triggerArray.push(i))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return J}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=U.find(".collapse .collapse",this._config.parent);e=U.find(".collapse.show, .collapse.collapsing",this._config.parent).filter(e=>!t.includes(e))}const i=U.findOne(this._selector);if(e.length){const n=e.find(t=>i!==t);if(t=n?et.getInstance(n):null,t&&t._isTransitioning)return}if(P.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach(e=>{i!==e&&et.getOrCreateInstance(e,{toggle:!1}).hide(),t||M.set(e,"bs.collapse",null)});const n=this._getDimension();this._element.classList.remove("collapse"),this._element.classList.add("collapsing"),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s="scroll"+(n[0].toUpperCase()+n.slice(1));this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove("collapsing"),this._element.classList.add("collapse","show"),this._element.style[n]="",P.trigger(this._element,"shown.bs.collapse")},this._element,!0),this._element.style[n]=this._element[s]+"px"}hide(){if(this._isTransitioning||!this._isShown())return;if(P.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=this._element.getBoundingClientRect()[t]+"px",d(this._element),this._element.classList.add("collapsing"),this._element.classList.remove("collapse","show");const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove("collapsing"),this._element.classList.add("collapse"),P.trigger(this._element,"hidden.bs.collapse")},this._element,!0)}_isShown(t=this._element){return t.classList.contains("show")}_getConfig(t){return(t={...J,...F.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=o(t.parent),r("collapse",t,tt),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=U.find(".collapse .collapse",this._config.parent);U.find('[data-bs-toggle="collapse"]',this._config.parent).filter(e=>!t.includes(e)).forEach(t=>{const e=i(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))})}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach(t=>{e?t.classList.remove("collapsed"):t.classList.add("collapsed"),t.setAttribute("aria-expanded",e)})}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=et.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}P.on(document,"click.bs.collapse.data-api",'[data-bs-toggle="collapse"]',(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const i=e(this);U.find(i).forEach(t=>{et.getOrCreateInstance(t,{toggle:!1}).toggle()})})),m(et);var it="top",nt="bottom",st="right",ot="left",rt=[it,nt,st,ot],at="end",lt=rt.reduce((function(t,e){return t.concat([e+"-start",e+"-"+at])}),[]),ct=[].concat(rt,["auto"]).reduce((function(t,e){return t.concat([e,e+"-start",e+"-"+at])}),[]),ht=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function dt(t){return t?(t.nodeName||"").toLowerCase():null}function ut(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function ft(t){return t instanceof ut(t).Element||t instanceof Element}function pt(t){return t instanceof ut(t).HTMLElement||t instanceof HTMLElement}function mt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof ut(t).ShadowRoot||t instanceof ShadowRoot)}var gt={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];pt(s)&&dt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});pt(n)&&dt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function _t(t){return t.split("-")[0]}var bt=Math.round;function vt(t,e){void 0===e&&(e=!1);var i=t.getBoundingClientRect(),n=1,s=1;if(pt(t)&&e){var o=t.offsetHeight,r=t.offsetWidth;r>0&&(n=i.width/r||1),o>0&&(s=i.height/o||1)}return{width:bt(i.width/n),height:bt(i.height/s),top:bt(i.top/s),right:bt(i.right/n),bottom:bt(i.bottom/s),left:bt(i.left/n),x:bt(i.left/n),y:bt(i.top/s)}}function yt(t){var e=vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function wt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&mt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Et(t){return ut(t).getComputedStyle(t)}function At(t){return["table","td","th"].indexOf(dt(t))>=0}function Tt(t){return((ft(t)?t.ownerDocument:t.document)||window.document).documentElement}function Ot(t){return"html"===dt(t)?t:t.assignedSlot||t.parentNode||(mt(t)?t.host:null)||Tt(t)}function Ct(t){return pt(t)&&"fixed"!==Et(t).position?t.offsetParent:null}function kt(t){for(var e=ut(t),i=Ct(t);i&&At(i)&&"static"===Et(i).position;)i=Ct(i);return i&&("html"===dt(i)||"body"===dt(i)&&"static"===Et(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&pt(t)&&"fixed"===Et(t).position)return null;for(var i=Ot(t);pt(i)&&["html","body"].indexOf(dt(i))<0;){var n=Et(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function Lt(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var xt=Math.max,Dt=Math.min,St=Math.round;function Nt(t,e,i){return xt(t,Dt(e,i))}function It(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function Pt(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}var jt={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=_t(i.placement),l=Lt(a),c=[ot,st].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return It("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:Pt(t,rt))}(s.padding,i),d=yt(o),u="y"===l?it:ot,f="y"===l?nt:st,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=kt(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=Nt(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&wt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Mt(t){return t.split("-")[1]}var Ht={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Bt(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:St(St(e*n)/n)||0,y:St(St(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=ot,v=it,y=window;if(c){var w=kt(i),E="clientHeight",A="clientWidth";w===ut(i)&&"static"!==Et(w=Tt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==it&&(s!==ot&&s!==st||o!==at)||(v=nt,m-=w[E]-n.height,m*=l?1:-1),s!==ot&&(s!==it&&s!==nt||o!==at)||(b=st,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&Ht);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}var Rt={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:_t(e.placement),variation:Mt(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,Bt(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,Bt(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}},Wt={passive:!0},zt={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=ut(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,Wt)})),a&&l.addEventListener("resize",i.update,Wt),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,Wt)})),a&&l.removeEventListener("resize",i.update,Wt)}},data:{}},qt={left:"right",right:"left",bottom:"top",top:"bottom"};function Ft(t){return t.replace(/left|right|bottom|top/g,(function(t){return qt[t]}))}var Ut={start:"end",end:"start"};function $t(t){return t.replace(/start|end/g,(function(t){return Ut[t]}))}function Vt(t){var e=ut(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Kt(t){return vt(Tt(t)).left+Vt(t).scrollLeft}function Xt(t){var e=Et(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Yt(t,e){var i;void 0===e&&(e=[]);var n=function t(e){return["html","body","#document"].indexOf(dt(e))>=0?e.ownerDocument.body:pt(e)&&Xt(e)?e:t(Ot(e))}(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=ut(n),r=s?[o].concat(o.visualViewport||[],Xt(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Yt(Ot(r)))}function Qt(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Gt(t,e){return"viewport"===e?Qt(function(t){var e=ut(t),i=Tt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+Kt(t),y:a}}(t)):pt(e)?function(t){var e=vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Qt(function(t){var e,i=Tt(t),n=Vt(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=xt(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=xt(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Kt(t),l=-n.scrollTop;return"rtl"===Et(s||i).direction&&(a+=xt(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Tt(t)))}function Zt(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?_t(s):null,r=s?Mt(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case it:e={x:a,y:i.y-n.height};break;case nt:e={x:a,y:i.y+i.height};break;case st:e={x:i.x+i.width,y:l};break;case ot:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?Lt(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case"start":e[c]=e[c]-(i[h]/2-n[h]/2);break;case at:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function Jt(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?"clippingParents":o,a=i.rootBoundary,l=void 0===a?"viewport":a,c=i.elementContext,h=void 0===c?"popper":c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=It("number"!=typeof p?p:Pt(p,rt)),g="popper"===h?"reference":"popper",_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Yt(Ot(t)),i=["absolute","fixed"].indexOf(Et(t).position)>=0&&pt(t)?kt(t):t;return ft(i)?e.filter((function(t){return ft(t)&&wt(t,i)&&"body"!==dt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Gt(t,i);return e.top=xt(n.top,e.top),e.right=Dt(n.right,e.right),e.bottom=Dt(n.bottom,e.bottom),e.left=xt(n.left,e.left),e}),Gt(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}(ft(b)?b:b.contextElement||Tt(t.elements.popper),r,l),y=vt(t.elements.reference),w=Zt({reference:y,element:_,strategy:"absolute",placement:s}),E=Qt(Object.assign({},_,w)),A="popper"===h?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if("popper"===h&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[st,nt].indexOf(t)>=0?1:-1,i=[it,nt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function te(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?ct:l,h=Mt(n),d=h?a?lt:lt.filter((function(t){return Mt(t)===h})):rt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=Jt(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[_t(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}var ee={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=_t(g),b=l||(_!==g&&p?function(t){if("auto"===_t(t))return[];var e=Ft(t);return[$t(t),e,$t(e)]}(g):[Ft(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat("auto"===_t(i)?te(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=Jt(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?st:ot:L?nt:it;y[D]>w[D]&&(N=Ft(N));var I=Ft(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ie(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ne(t){return[it,st,nt,ot].some((function(e){return t[e]>=0}))}var se={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=Jt(e,{elementContext:"reference"}),a=Jt(e,{altBoundary:!0}),l=ie(r,n),c=ie(a,s,o),h=ne(l),d=ne(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},oe={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=ct.reduce((function(t,i){return t[i]=function(t,e,i){var n=_t(t),s=[ot,it].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[ot,st].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},re={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Zt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},ae={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=Jt(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=_t(e.placement),b=Mt(e.placement),v=!b,y=Lt(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?it:ot,L="y"===y?nt:st,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P="start"===b?A[x]:T[x],j="start"===b?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?yt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],z=Nt(0,A[x],H[x]),q=v?A[x]/2-I-z-R-O:P-z-R-O,F=v?-A[x]/2+I+z+W+O:j+z+W+O,U=e.elements.arrow&&kt(e.elements.arrow),$=U?"y"===y?U.clientTop||0:U.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+q-V-$,X=E[y]+F-V;if(o){var Y=Nt(f?Dt(S,K):S,D,f?xt(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?it:ot,G="x"===y?nt:st,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=Nt(f?Dt(J,K):J,Z,f?xt(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function le(t,e,i){void 0===i&&(i=!1);var n,s,o=pt(e),r=pt(e)&&function(t){var e=t.getBoundingClientRect(),i=e.width/t.offsetWidth||1,n=e.height/t.offsetHeight||1;return 1!==i||1!==n}(e),a=Tt(e),l=vt(t,r),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==dt(e)||Xt(a))&&(c=(n=e)!==ut(n)&&pt(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Vt(n)),pt(e)?((h=vt(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Kt(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}var ce={placement:"bottom",modifiers:[],strategy:"absolute"};function he(){for(var t=arguments.length,e=new Array(t),i=0;iP.on(t,"mouseover",h)),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add("show"),this._element.classList.add("show"),P.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(l(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){P.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",h)),this._popper&&this._popper.destroy(),this._menu.classList.remove("show"),this._element.classList.remove("show"),this._element.setAttribute("aria-expanded","false"),F.removeDataAttribute(this._menu,"popper"),P.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...F.getDataAttributes(this._element),...t},r("dropdown",t,this.constructor.DefaultType),"object"==typeof t.reference&&!s(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError("dropdown".toUpperCase()+': Option "reference" provided type "object" without a required "getBoundingClientRect" method.');return t}_createPopper(t){if(void 0===me)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:s(this._config.reference)?e=o(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find(t=>"applyStyles"===t.name&&!1===t.enabled);this._popper=pe(e,this._menu,i),n&&F.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains("show")}_getMenuElement(){return U.next(this._element,".dropdown-menu")[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return we;if(t.classList.contains("dropstart"))return Ee;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?be:_e:e?ye:ve}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=U.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(a);i.length&&b(i,e,"ArrowDown"===t,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=Oe.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=U.find('[data-bs-toggle="dropdown"]');for(let i=0,n=e.length;ie+t),this._setElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight",e=>e+t),this._setElementAttributes(".sticky-top","marginRight",e=>e-t)}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=i(Number.parseFloat(s))+"px"})}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(".fixed-top, .fixed-bottom, .is-fixed, .sticky-top","paddingRight"),this._resetElementAttributes(".sticky-top","marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&F.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=F.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(F.removeDataAttribute(t,e),t.style[e]=i)})}_applyManipulationCallback(t,e){s(t)?e(t):U.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const ke={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},Le={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"};class xe{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&d(this._getElement()),this._getElement().classList.add("show"),this._emulateAnimation(()=>{g(t)})):g(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove("show"),this._emulateAnimation(()=>{this.dispose(),g(t)})):g(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...ke,..."object"==typeof t?t:{}}).rootElement=o(t.rootElement),r("backdrop",t,Le),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),P.on(this._getElement(),"mousedown.bs.backdrop",()=>{g(this._config.clickCallback)}),this._isAppended=!0)}dispose(){this._isAppended&&(P.off(this._element,"mousedown.bs.backdrop"),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const De={trapElement:null,autofocus:!0},Se={trapElement:"element",autofocus:"boolean"};class Ne{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),P.off(document,".bs.focustrap"),P.on(document,"focusin.bs.focustrap",t=>this._handleFocusin(t)),P.on(document,"keydown.tab.bs.focustrap",t=>this._handleKeydown(t)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,P.off(document,".bs.focustrap"))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=U.focusableChildren(i);0===n.length?i.focus():"backward"===this._lastTabNavDirection?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?"backward":"forward")}_getConfig(t){return t={...De,..."object"==typeof t?t:{}},r("focustrap",t,Se),t}}const Ie={backdrop:!0,keyboard:!0,focus:!0},Pe={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"};class je extends H{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=U.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new Ce}static get Default(){return Ie}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,"show.bs.modal",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add("modal-open"),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),P.on(this._dialog,"mousedown.dismiss.bs.modal",()=>{P.one(this._element,"mouseup.dismiss.bs.modal",t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)})}),this._showBackdrop(()=>this._showElement(t)))}hide(){if(!this._isShown||this._isTransitioning)return;if(P.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove("show"),P.off(this._element,"click.dismiss.bs.modal"),P.off(this._dialog,"mousedown.dismiss.bs.modal"),this._queueCallback(()=>this._hideModal(),this._element,t)}dispose(){[window,this._dialog].forEach(t=>P.off(t,".bs.modal")),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new xe({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ne({trapElement:this._element})}_getConfig(t){return t={...Ie,...F.getDataAttributes(this._element),..."object"==typeof t?t:{}},r("modal",t,Pe),t}_showElement(t){const e=this._isAnimated(),i=U.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&d(this._element),this._element.classList.add("show"),this._queueCallback(()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,P.trigger(this._element,"shown.bs.modal",{relatedTarget:t})},this._dialog,e)}_setEscapeEvent(){this._isShown?P.on(this._element,"keydown.dismiss.bs.modal",t=>{this._config.keyboard&&"Escape"===t.key?(t.preventDefault(),this.hide()):this._config.keyboard||"Escape"!==t.key||this._triggerBackdropTransition()}):P.off(this._element,"keydown.dismiss.bs.modal")}_setResizeEvent(){this._isShown?P.on(window,"resize.bs.modal",()=>this._adjustDialog()):P.off(window,"resize.bs.modal")}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove("modal-open"),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,"hidden.bs.modal")})}_showBackdrop(t){P.on(this._element,"click.dismiss.bs.modal",t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())}),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains("modal-static")||(n||(i.overflowY="hidden"),t.add("modal-static"),this._queueCallback(()=>{t.remove("modal-static"),n||this._queueCallback(()=>{i.overflowY=""},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!p()||i&&!t&&p())&&(this._element.style.paddingLeft=e+"px"),(i&&!t&&!p()||!i&&t&&p())&&(this._element.style.paddingRight=e+"px")}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=je.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}P.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=i(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,"show.bs.modal",t=>{t.defaultPrevented||P.one(e,"hidden.bs.modal",()=>{a(this)&&this.focus()})});const n=U.findOne(".modal.show");n&&je.getInstance(n).hide(),je.getOrCreateInstance(e).toggle(this)})),B(je),m(je);const Me={backdrop:!0,keyboard:!0,scroll:!1},He={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"};class Be extends H{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return"offcanvas"}static get Default(){return Me}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new Ce).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add("show"),this._queueCallback(()=>{this._config.scroll||this._focustrap.activate(),P.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove("show"),this._backdrop.hide(),this._queueCallback(()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new Ce).reset(),P.trigger(this._element,"hidden.bs.offcanvas")},this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Me,...F.getDataAttributes(this._element),..."object"==typeof t?t:{}},r("offcanvas",t,He),t}_initializeBackDrop(){return new xe({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ne({trapElement:this._element})}_addEventListeners(){P.on(this._element,"keydown.dismiss.bs.offcanvas",t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()})}static jQueryInterface(t){return this.each((function(){const e=Be.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}P.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=i(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;P.one(e,"hidden.bs.offcanvas",()=>{a(this)&&this.focus()});const n=U.findOne(".offcanvas.show");n&&n!==e&&Be.getInstance(n).hide(),Be.getOrCreateInstance(e).toggle(this)})),P.on(window,"load.bs.offcanvas.data-api",()=>U.find(".offcanvas.show").forEach(t=>Be.getOrCreateInstance(t).show())),B(Be),m(Be);const Re=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),We=/^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/i,ze=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,qe=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Re.has(i)||Boolean(We.test(t.nodeValue)||ze.test(t.nodeValue));const n=e.filter(t=>t instanceof RegExp);for(let t=0,e=n.length;t{qe(t,a)||i.removeAttribute(t.nodeName)})}return n.body.innerHTML}const Ue=new Set(["sanitize","allowList","sanitizeFn"]),$e={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ve={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},Ke={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},Xe={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"};class Ye extends H{constructor(t,e){if(void 0===me)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return Ke}static get NAME(){return"tooltip"}static get Event(){return Xe}static get DefaultType(){return $e}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains("show"))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.Event.SHOW),e=c(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(".tooltip-inner").innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add("fade");const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;M.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),P.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=pe(this._element,n,this._getPopperConfig(r)),n.classList.add("show");const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>{P.on(t,"mouseover",h)});const d=this.tip.classList.contains("fade");this._queueCallback(()=>{const t=this._hoverState;this._hoverState=null,P.trigger(this._element,this.constructor.Event.SHOWN),"out"===t&&this._leave(null,this)},this.tip,d)}hide(){if(!this._popper)return;const t=this.getTipElement();if(P.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove("show"),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach(t=>P.off(t,"mouseover",h)),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains("fade");this._queueCallback(()=>{this._isWithActiveTrigger()||("show"!==this._hoverState&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())},this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove("fade","show"),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".tooltip-inner")}_sanitizeAndSetContent(t,e,i){const n=U.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return s(e)?(e=o(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Fe(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ve[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach(t=>{if("click"===t)P.on(this._element,this.constructor.Event.CLICK,this._config.selector,t=>this.toggle(t));else if("manual"!==t){const e="hover"===t?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i="hover"===t?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;P.on(this._element,e,this._config.selector,t=>this._enter(t)),P.on(this._element,i,this._config.selector,t=>this._leave(t))}}),this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(".modal"),"hide.bs.modal",this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?"focus":"hover"]=!0),e.getTipElement().classList.contains("show")||"show"===e._hoverState?e._hoverState="show":(clearTimeout(e._timeout),e._hoverState="show",e._config.delay&&e._config.delay.show?e._timeout=setTimeout(()=>{"show"===e._hoverState&&e.show()},e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?"focus":"hover"]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState="out",e._config.delay&&e._config.delay.hide?e._timeout=setTimeout(()=>{"out"===e._hoverState&&e.hide()},e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=F.getDataAttributes(this._element);return Object.keys(e).forEach(t=>{Ue.has(t)&&delete e[t]}),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:o(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),r("tooltip",t,this.constructor.DefaultType),t.sanitize&&(t.template=Fe(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map(t=>t.trim()).forEach(e=>t.classList.remove(e))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=Ye.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(Ye);const Qe={...Ye.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},Ge={...Ye.DefaultType,content:"(string|element|function)"},Ze={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class Je extends Ye{static get Default(){return Qe}static get NAME(){return"popover"}static get Event(){return Ze}static get DefaultType(){return Ge}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=Je.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}m(Je);const ti={offset:10,method:"auto",target:""},ei={offset:"number",method:"string",target:"(string|element)"},ii=".nav-link, .list-group-item, .dropdown-item";class ni extends H{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,P.on(this._scrollElement,"scroll.bs.scrollspy",()=>this._process()),this.refresh(),this._process()}static get Default(){return ti}static get NAME(){return"scrollspy"}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":"position",i="auto"===this._config.method?t:this._config.method,n="position"===i?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),U.find(ii,this._config.target).map(t=>{const s=e(t),o=s?U.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[F[i](o).top+n,s]}return null}).filter(t=>t).sort((t,e)=>t[0]-e[0]).forEach(t=>{this._offsets.push(t[0]),this._targets.push(t[1])})}dispose(){P.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...ti,...F.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=o(t.target)||document.documentElement,r("scrollspy",t,ei),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`),i=U.findOne(e.join(","),this._config.target);i.classList.add("active"),i.classList.contains("dropdown-item")?U.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add("active"):U.parents(i,".nav, .list-group").forEach(t=>{U.prev(t,".nav-link, .list-group-item").forEach(t=>t.classList.add("active")),U.prev(t,".nav-item").forEach(t=>{U.children(t,".nav-link").forEach(t=>t.classList.add("active"))})}),P.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){U.find(ii,this._config.target).filter(t=>t.classList.contains("active")).forEach(t=>t.classList.remove("active"))}static jQueryInterface(t){return this.each((function(){const e=ni.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(window,"load.bs.scrollspy.data-api",()=>{U.find('[data-bs-spy="scroll"]').forEach(t=>new ni(t))}),m(ni);class si extends H{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains("active"))return;let t;const e=i(this._element),n=this._element.closest(".nav, .list-group");if(n){const e="UL"===n.nodeName||"OL"===n.nodeName?":scope > li > .active":".active";t=U.find(e,n),t=t[t.length-1]}const s=t?P.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(P.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,n);const o=()=>{P.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),P.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?U.children(e,".active"):U.find(":scope > li > .active",e))[0],s=i&&n&&n.classList.contains("fade"),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove("show"),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove("active");const t=U.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove("active"),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add("active"),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),d(t),t.classList.contains("fade")&&t.classList.add("show");let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&U.find(".dropdown-toggle",e).forEach(t=>t.classList.add("active")),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=si.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||si.getOrCreateInstance(this).show()})),m(si);const oi={animation:"boolean",autohide:"boolean",delay:"number"},ri={animation:!0,autohide:!0,delay:5e3};class ai extends H{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return oi}static get Default(){return ri}static get NAME(){return"toast"}show(){P.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove("hide"),d(this._element),this._element.classList.add("show"),this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.remove("showing"),P.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this._element.classList.contains("show")&&(P.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add("showing"),this._queueCallback(()=>{this._element.classList.add("hide"),this._element.classList.remove("showing"),this._element.classList.remove("show"),P.trigger(this._element,"hidden.bs.toast")},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains("show")&&this._element.classList.remove("show"),super.dispose()}_getConfig(t){return t={...ri,...F.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},r("toast",t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,"mouseover.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"mouseout.bs.toast",t=>this._onInteraction(t,!1)),P.on(this._element,"focusin.bs.toast",t=>this._onInteraction(t,!0)),P.on(this._element,"focusout.bs.toast",t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=ai.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return B(ai),m(ai),{Alert:R,Button:W,Carousel:Z,Collapse:et,Dropdown:Oe,Modal:je,Offcanvas:Be,Popover:Je,ScrollSpy:ni,Tab:si,Toast:ai,Tooltip:Ye}})); \ No newline at end of file diff --git a/files/assets/js/comments+submission_listing.js b/files/assets/js/comments+submission_listing.js index 56ee65f5f..ebf6e0209 100644 --- a/files/assets/js/comments+submission_listing.js +++ b/files/assets/js/comments+submission_listing.js @@ -41,7 +41,7 @@ function popclick(e) { badgesDOM.innerHTML = ""; for (const badge of author["badges"]) { const badgeDOM = popClickBadgeTemplateDOM.cloneNode(); - badgeDOM.src = badge + "?v=1025"; + badgeDOM.src = badge + "?b=4"; badgesDOM.append(badgeDOM); } @@ -73,12 +73,8 @@ document.addEventListener("click", function(){ }); function post(url) { - const xhr = new XMLHttpRequest(); - xhr.open("POST", url); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - xhr.send(form); + const xhr = createXhrWithFormKey(url); + xhr[0].send(xhr[1]); }; function poll_vote_0(oid, parentid, kind) { diff --git a/files/assets/js/comments.js b/files/assets/js/comments.js index f903b94c6..8472ab60c 100644 --- a/files/assets/js/comments.js +++ b/files/assets/js/comments.js @@ -1,6 +1,5 @@ function poll_vote_no_v() { - document.getElementById('toast-post-error-text').innerText = "Only logged-in users can vote!"; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + showToast(false, "Only logged-in users can vote!"); } function expandMarkdown(id,type) { diff --git a/files/assets/js/comments_admin.js b/files/assets/js/comments_admin.js index 4de331e8b..65ebb0410 100644 --- a/files/assets/js/comments_admin.js +++ b/files/assets/js/comments_admin.js @@ -1,101 +1,53 @@ -function removeComment(post_id,button1,button2) { +function removeComment(t,post_id,button1,button2,cls) { url="/remove_comment/"+post_id - post(url) + post_toast(t,url,button1,button2,cls) - try { - document.getElementById("comment-"+post_id+"-only").classList.add("banned"); - } catch(e) { - document.getElementById("context").classList.add("banned"); + if (window.location.pathname == '/admin/reported/comments') + { + document.getElementById("post-info-"+post_id).remove() + document.getElementById("comment-"+post_id).remove() } - - var button=document.getElementById("remove-"+post_id); - button.onclick=function(){approveComment(post_id)}; - button.innerHTML='Approve' - - if (typeof button1 !== 'undefined') { - document.getElementById(button1).classList.toggle("d-md-block"); - document.getElementById(button2).classList.toggle("d-md-block"); - } -}; - -function approveComment(post_id,button1,button2) { - url="/approve_comment/"+post_id - - post(url) - - try { - document.getElementById("comment-"+post_id+"-only").classList.remove("banned"); - } catch(e) { - document.getElementById("context").classList.remove("banned"); - } - - var button=document.getElementById("remove-"+post_id); - button.onclick=function(){removeComment(post_id)}; - button.innerHTML='Remove' - - if (typeof button1 !== 'undefined') { - document.getElementById(button1).classList.toggle("d-md-block"); - document.getElementById(button2).classList.toggle("d-md-block"); - } -} - - -function removeComment2(post_id,button1,button2) { - url="/remove_comment/"+post_id - - post(url) - - document.getElementById("comment-"+post_id+"-only").classList.add("banned"); - var button=document.getElementById("remove-"+post_id); - button.onclick=function(){approveComment(post_id)}; - button.innerHTML='Approve' - - if (typeof button1 !== 'undefined') { - document.getElementById(button1).classList.toggle("d-none"); - document.getElementById(button2).classList.toggle("d-none"); - } -}; - -function approveComment2(post_id,button1,button2) { - url="/approve_comment/"+post_id - - post(url) - - document.getElementById("comment-"+post_id+"-only").classList.remove("banned"); - var button=document.getElementById("remove-"+post_id); - button.onclick=function(){removeComment(post_id)}; - button.innerHTML='Remove' - - if (typeof button1 !== 'undefined') { - document.getElementById(button1).classList.toggle("d-none"); - document.getElementById(button2).classList.toggle("d-none"); - } -} - -function adminMuteUser(userId, muteStatus, buttonId) { - let form = new FormData(); - form.append("formkey", formkey()); - - const xhr = new XMLHttpRequest(); - xhr.open("POST", `/mute_user/${userId}/${muteStatus}`); - xhr.setRequestHeader('xhr', 'xhr'); - - xhr.onload = function() { - let data - try {data = JSON.parse(xhr.response)} - catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); - } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + else + { + try { + document.getElementById("comment-"+post_id+"-only").classList.add("banned"); + } catch(e) { + document.getElementById("context").classList.add("banned"); } - }; + } +}; - xhr.send(form); +function approveComment(t,post_id,button1,button2,cls) { + url="/approve_comment/"+post_id - document.getElementById('mute-user-' + buttonId).classList.add("d-none"); + post_toast(t,url,button1,button2,cls) + + if (window.location.pathname == '/admin/reported/comments') + { + document.getElementById("post-info-"+post_id).remove() + document.getElementById("comment-"+post_id).remove() + } + else + { + try { + document.getElementById("comment-"+post_id+"-only").classList.remove("banned"); + } catch(e) { + document.getElementById("context").classList.remove("banned"); + } + } +} + +function adminToggleMute(userId, muteStatus, buttonId) { + const xhr = createXhrWithFormKey(`/mute_user/${userId}/${muteStatus}`); + xhr[0].onload = function() { + let data + try {data = JSON.parse(xhr[0].response)} + catch(e) {console.log(e)} + success = xhr[0].status >= 200 && xhr[0].status < 300; + showToast(success, getMessageFromJsonData(success, data)); + }; + xhr[0].send(xhr[1]); + document.getElementById('mute-user-' + buttonId).classList.toggle("d-none"); + document.getElementById('unmute-user-' + buttonId).classList.toggle("d-none"); } diff --git a/files/assets/js/comments_v.js b/files/assets/js/comments_v.js index b4911963f..1a00d205d 100644 --- a/files/assets/js/comments_v.js +++ b/files/assets/js/comments_v.js @@ -29,29 +29,20 @@ function report_commentModal(id, author) { this.innerHTML='Reporting comment'; this.disabled = true; this.classList.add('disabled'); - const xhr = new XMLHttpRequest(); - xhr.open("POST", '/report/comment/'+id); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); + const form = new FormData(); form.append("reason", reason_comment.value); + const xhr = createXhrWithFormKey("/report/comment/" + id, "POST", form); - xhr.onload = function() { + xhr[0].onload = function() { let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); - } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); - } + success = xhr[0].status >= 200 && xhr[0].status < 300; + showToast(success, getMessageFromJsonData(success, data)); }; - xhr.onerror=function(){alert(errortext)}; - xhr.send(form); + xhr[0].onerror=function(){alert(errortext)}; + xhr[0].send(xhr[1]); } }; @@ -101,30 +92,31 @@ function toggleEdit(id){ function delete_commentModal(id) { document.getElementById("deleteCommentButton").onclick = function() { - const xhr = new XMLHttpRequest(); - xhr.open("POST", `/delete/comment/${id}`); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - xhr.onload = function() { + const xhr = createXhrWithFormKey(`/delete/comment/${id}`); + xhr[0].onload = function() { let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementsByClassName(`comment-${id}-only`)[0].classList.add('deleted'); - document.getElementById(`delete-${id}`).classList.add('d-none'); - document.getElementById(`undelete-${id}`).classList.remove('d-none'); - document.getElementById(`delete2-${id}`).classList.add('d-none'); - document.getElementById(`undelete2-${id}`).classList.remove('d-none'); - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); + if (xhr[0].status >= 200 && xhr[0].status < 300 && data && data['message']) { + if (window.location.pathname == '/admin/reported/comments') + { + document.getElementById("post-info-"+id).remove() + document.getElementById("comment-"+id).remove() + } + else + { + document.getElementsByClassName(`comment-${id}-only`)[0].classList.add('deleted'); + document.getElementById(`delete-${id}`).classList.add('d-none'); + document.getElementById(`undelete-${id}`).classList.remove('d-none'); + document.getElementById(`delete2-${id}`).classList.add('d-none'); + document.getElementById(`undelete2-${id}`).classList.remove('d-none'); + } + showToast(true, getMessageFromJsonData(true, data)); } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + showToast(false, getMessageFromJsonData(false, data)); } }; - xhr.send(form); + xhr[0].send(xhr[1]); }; } @@ -134,22 +126,18 @@ function post_reply(id){ btn.classList.add('disabled'); const form = new FormData(); - form.append('formkey', formkey()); form.append('parent_id', id); form.append('body', document.getElementById('reply-form-body-'+id).value); - try { for (const e of document.getElementById('file-upload').files) form.append('file', e); } catch(e) {} - - const xhr = new XMLHttpRequest(); - xhr.open("post", "/reply"); - xhr.setRequestHeader('xhr', 'xhr'); - xhr.onload=function(){ + + const xhr = createXhrWithFormKey("/reply", "POST", form); + xhr[0].onload=function(){ let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} if (data && data["comment"]) { const comments = document.getElementById('replies-of-c_' + id); @@ -165,18 +153,15 @@ function post_reply(id){ document.getElementById('reply-form-body-'+id).value = '' document.getElementById('message-reply-'+id).innerHTML = '' ToggleReplyBox('reply-message-'+id) - } - else { - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - else document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + } else { + showToast(false, getMessageFromJsonData(false, data)); } setTimeout(() => { btn.disabled = false; btn.classList.remove('disabled'); }, 2000); } - xhr.send(form) + xhr[0].send(xhr[1]); } function comment_edit(id){ @@ -185,8 +170,6 @@ function comment_edit(id){ btn.classList.add('disabled'); const form = new FormData(); - - form.append('formkey', formkey()); form.append('body', document.getElementById('comment-edit-body-'+id).value); try { @@ -194,13 +177,10 @@ function comment_edit(id){ form.append('file', e); } catch(e) {} - - const xhr = new XMLHttpRequest(); - xhr.open("post", "/edit_comment/"+id); - xhr.setRequestHeader('xhr', 'xhr'); - xhr.onload=function(){ + const xhr = createXhrWithFormKey("/edit_comment/"+id, "POST", form); + xhr[0].onload=function(){ let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} if (data && data["comment"]) { commentForm=document.getElementById('comment-text-'+id); @@ -210,16 +190,14 @@ function comment_edit(id){ document.getElementById('filename-edit-reply-' + id).innerHTML = ''; } else { - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - else document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + showToast(false, getMessageFromJsonData(false, data)); } setTimeout(() => { btn.disabled = false; btn.classList.remove('disabled'); }, 1000); } - xhr.send(form) + xhr[0].send(xhr[1]); } function post_comment(fullname, hide){ @@ -269,9 +247,7 @@ function post_comment(fullname, hide){ document.getElementById('filename-show-reply-' + fullname).innerHTML = ''; } else { - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - else document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + showToast(false, getMessageFromJsonData(false, data)); setTimeout(() => { btn.disabled = false; btn.classList.remove('disabled'); @@ -283,56 +259,52 @@ function post_comment(fullname, hide){ document.onpaste = function(event) { var focused = document.activeElement; + const files = event.clipboardData.files + + if (files.length > 4) + { + alert("You can't upload more than 4 files at one time!") + return + } + + if (!files.length) return + if (focused.id.includes('reply-form-body-')) { - files = event.clipboardData.files - if (files.length) - { - var fullname = focused.dataset.fullname; - f=document.getElementById('file-upload-reply-' + fullname); - try { - let filename = '' - for (const file of files) - filename += file.name + ', ' - filename = filename.toLowerCase().slice(0, -2) - f.files = files; - document.getElementById('filename-show-reply-' + fullname).textContent = filename; - } - catch(e) {} + var fullname = focused.dataset.fullname; + f=document.getElementById('file-upload-reply-' + fullname); + try { + let filename = '' + for (const file of files) + filename += file.name + ', ' + filename = filename.toLowerCase().slice(0, -2) + f.files = files; + document.getElementById('filename-show-reply-' + fullname).textContent = filename; } + catch(e) {} } else if (focused.id.includes('comment-edit-body-')) { - files = event.clipboardData.files - if (files.length) - { - var id = focused.dataset.id; - f=document.getElementById('file-edit-reply-' + id); - let filename = '' - for (const file of files) - filename += file.name + ', ' - filename = filename.toLowerCase().slice(0, -2) - f.files = files; - document.getElementById('filename-edit-reply-' + id).textContent = filename; - } + var id = focused.dataset.id; + f=document.getElementById('file-edit-reply-' + id); + let filename = '' + for (const file of files) + filename += file.name + ', ' + filename = filename.toLowerCase().slice(0, -2) + f.files = files; + document.getElementById('filename-edit-reply-' + id).textContent = filename; } else if (focused.id.includes('post-edit-box-')) { - files = event.clipboardData.files - if (files.length) - { - var id = focused.dataset.id; - f=document.getElementById('file-upload-edit-' + id); - let filename = '' - for (const file of files) - filename += file.name + ', ' - filename = filename.toLowerCase().slice(0, -2) - f.files = files; - document.getElementById('filename-show-edit-' + id).textContent = filename; - } + var id = focused.dataset.id; + f=document.getElementById('file-upload-edit-' + id); + let filename = '' + for (const file of files) + filename += file.name + ', ' + filename = filename.toLowerCase().slice(0, -2) + f.files = files; + document.getElementById('filename-show-edit-' + id).textContent = filename; } } function handle_action(type, cid, thing) { - - const btns = document.getElementsByClassName(`action-${cid}`) for (const btn of btns) { @@ -358,11 +330,8 @@ function handle_action(type, cid, thing) { if (data && data["response"]) { const element = document.getElementById(`${type}-${cid}`); element.innerHTML = data["response"] - } - else { - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - else document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + } else { + showToast(false, getMessageFromJsonData(false, data)); } setTimeout(() => { for (const btn of btns) diff --git a/files/assets/js/core.js b/files/assets/js/core.js new file mode 100644 index 000000000..5da577d9d --- /dev/null +++ b/files/assets/js/core.js @@ -0,0 +1,388 @@ +function isShopConfirmation(t) { + return t.id.startsWith('buy1-') || t.id.startsWith('buy2-'); +} + +function prePostToastNonShopActions(t, url, button1, button2, className) { + let isShopConfirm = isShopConfirmation(t); + + if (!isShopConfirm) + { + t.disabled = true; + t.classList.add("disabled"); + } +} + +function getMessageFromJsonData(success, json) { + let message = success ? "Success!" : "Error, please try again later"; + let key = success ? "message" : "error"; + if (!json || !json[key]) return message; + message = json[key]; + if (!success && json["details"]) { + message = json["details"]; + } + return message; +} + +function showToast(success, message, isToastTwo=false) { + let element = success ? "toast-post-success" : "toast-post-error"; + let textElement = element + "-text"; + if (isToastTwo) { + element = element + "2"; + textElement = textElement + "2"; + } + if (!message) { + message = success ? "Success" : "Error, please try again later"; + } + document.getElementById(textElement).innerText = message; + bootstrap.Toast.getOrCreateInstance(document.getElementById(element)).show(); +} + +function postToastLoad(xhr, className, button1, button2, extraActionsOnSuccess, extraActionsOnError) { + let data + try { + data = JSON.parse(xhr.response) + } + catch (e) { + console.log(e) + } + success = xhr.status >= 200 && xhr.status < 300; + showToast(success, getMessageFromJsonData(success, data)); + if (success) { + if (button1) + { + if (typeof(button1) == 'boolean') { + location.reload() + } else { + document.getElementById(button1).classList.toggle(className); + document.getElementById(button2).classList.toggle(className); + } + } + if (extraActionsOnSuccess) extraActionsOnSuccess(xhr); + } else { + if (extraActionsOnError) extraActionsOnError(xhr); + } +} + +function postPostToastNonShopActions(t, url, button1, button2, className) { + let isShopConfirm = isShopConfirmation(t); + if (!isShopConfirm) + { + setTimeout(() => { + t.disabled = false; + t.classList.remove("disabled"); + }, 2000); + } +} + +function createXhrWithFormKey(url, method="POST", form=new FormData()) { + const xhr = new XMLHttpRequest(); + xhr.open(method, url); + xhr.setRequestHeader('xhr', 'xhr'); + if (!form) form = new FormData(); + form.append("formkey", formkey()); + return [xhr, form]; // hacky but less stupid than what we were doing before +} + +function postToast(t, url, button1, button2, className, extraActions, extraActionsError) { + prePostToastNonShopActions(t, url, button1, button2, className); + const xhr = createXhrWithFormKey(url); + xhr[0].onload = function() { + postToastLoad(xhr[0], className, button1, button2, extraActions, extraActionsError) + postPostToastNonShopActions(t, url, button1, button2, className) + }; + xhr[0].send(xhr[1]); +} + +/* temporary compatability function. js styling wants us to use thisCase so any new things should use that */ +function post_toast(t, url, button1, button2, classname, extra_actions, extra_actions_error) { + postToast(t, url, button1, button2, classname, extra_actions, extra_actions_error); +} + +function post_toast_callback(url, data, callback) { + let form = new FormData(); + if(typeof data === 'object' && data !== null) { + for(let k of Object.keys(data)) { + form.append(k, data[k]); + } + } + const xhr = createXhrWithFormKey(url, "POST", form); + xhr[0].onload = function() { + let result + if (callback) result = callback(xhr[0]); + let message; + let success = xhr[0].status >= 200 && xhr[0].status < 300; + if (typeof result == "string") { + message = result; + } else { + message = getMessageFromJsonData(success, JSON.parse(xhr[0].response)); + } + let oldToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-' + (success ? 'error': 'success'))); // intentionally reversed here: this is the old toast + oldToast.hide(); + showToast(success, message); + return success; + }; + xhr[0].send(xhr[1]); +} + +if (window.location.pathname != '/submit') +{ + document.addEventListener('keydown', (e) => { + if(!((e.ctrlKey || e.metaKey) && e.key === "Enter")) return; + + const targetDOM = document.activeElement; + if(!(targetDOM instanceof HTMLTextAreaElement || targetDOM instanceof HTMLInputElement)) return; + + const formDOM = targetDOM.parentElement; + + const submitButtonDOMs = formDOM.querySelectorAll('input[type=submit], .btn-primary'); + if(submitButtonDOMs.length === 0) + throw new TypeError("I am unable to find the submit button :(. Contact the head custodian immediately.") + + const btn = submitButtonDOMs[0] + btn.click(); + }); +} + +addEventListener('show.bs.modal', function (e) { + location.hash = "modal"; +}); + +addEventListener('hide.bs.modal', function (e) { + if(location.hash == "#modal") { + history.back(); + } +}); + +addEventListener('hashchange', function (e) { + if(location.hash != "#modal") { + const curr_modal = bootstrap.Modal.getInstance(document.getElementsByClassName('show')[0]) + if (curr_modal) curr_modal.hide() + } +}); + +function disable(t) { + t.classList.add('disabled'); + setTimeout(() => { + t.classList.remove("disabled"); + }, 2000); +} + +function autoExpand (field) { + xpos=window.scrollX; + ypos=window.scrollY; + + field.style.height = 'inherit'; + + var computed = window.getComputedStyle(field); + + var height = parseInt(computed.getPropertyValue('border-top-width'), 10) + + parseInt(computed.getPropertyValue('padding-top'), 10) + + field.scrollHeight + + parseInt(computed.getPropertyValue('padding-bottom'), 10) + + parseInt(computed.getPropertyValue('border-bottom-width'), 10); + + field.style.height = height + 'px'; + if (Math.abs(window.scrollX - xpos) < 1 && Math.abs(window.scrollY - ypos) < 1) return; + window.scrollTo(xpos,ypos); +}; + +document.addEventListener('input', function (event) { + if (event.target.tagName.toLowerCase() !== 'textarea') return; + autoExpand(event.target); +}, false); + +function smoothScrollTop() +{ + window.scrollTo({ top: 0, behavior: 'smooth' }); +} + +// Click navbar to scroll back to top +(() => { + let toplisteners = [ + document.querySelector('nav') + ]; + + for (let i of toplisteners) + { + i.addEventListener('click', (e) => { + if (e.target.id === "navbar" || + e.target.classList.contains("container-fluid") || + e.target.id == "navbarResponsive" || + e.target.id == "logo-container" || + e.target.classList.contains("srd")) + smoothScrollTop(); + }, false); + } +})(); + +// Dynamic shadow when the user scrolls +document.addEventListener('scroll',function (event) { + let nav = document.querySelector("nav"); + let i = (Math.min(20, window.scrollY/4)+1)/21; + nav.style.boxShadow="0px 2px "+i*21+"px rgba(15,15,15,"+i*.3+")"; + if (window.scrollY <= 0) + { +// nav.classList.remove("shadow"); + nav.classList.remove("navbar-active"); + nav.style.boxShadow = "unset"; + } + else + { +// nav.classList.add("shadow"); + nav.classList.add("navbar-active"); + } + +}, false); + +function formkey() { + let formkey = document.getElementById("formkey") + if (formkey) return formkey.innerHTML; + else return null; +} + +function expandDesktopImage(url) { + const e = this.event + if(e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) + return true; + e.preventDefault(); + if (!url) + { + url = e.target.dataset.src + if (!url) url = e.target.src + } + document.getElementById("desktop-expanded-image").src = url.replace("200w_d.webp", "giphy.webp"); + document.getElementById("desktop-expanded-image-wrap-link").href = url; + bootstrap.Modal.getOrCreateInstance(document.getElementById('expandImageModal')).show(); +}; + +document.addEventListener("click", function(e){ + const element = e.target + if (element instanceof HTMLImageElement && element.alt.startsWith('![](')) + expandDesktopImage() +}); + +function bs_trigger(e) { + let tooltipTriggerList = [].slice.call(e.querySelectorAll('[data-bs-toggle="tooltip"]')); + tooltipTriggerList.map(function(element){ + return bootstrap.Tooltip.getOrCreateInstance(element); + }); + + const popoverTriggerList = [].slice.call(e.querySelectorAll('[data-bs-toggle="popover"]')); + popoverTriggerList.map(function(popoverTriggerEl) { + const popoverId = popoverTriggerEl.getAttribute('data-content-id'); + let contentEl; + try {contentEl = e.getElementById(popoverId);} + catch(t) {contentEl = document.getElementById(popoverId);} + if (contentEl) { + return bootstrap.Popover.getOrCreateInstance(popoverTriggerEl, { + content: contentEl.innerHTML, + html: true, + }); + } + }) + + if (typeof update_speed_emoji_modal != 'undefined') { + let forms = e.querySelectorAll("textarea, .allow-emojis"); + forms.forEach(i => { + let pseudo_div = document.createElement("div"); + pseudo_div.className = "ghostdiv"; + pseudo_div.style.display = "none"; + i.after(pseudo_div); + i.addEventListener('input', update_speed_emoji_modal, false); + i.addEventListener('keydown', speed_carot_navigate, false); + }); + } +} + +var bsTriggerOnReady = function() { + bs_trigger(document); +} + +if (document.readyState === "complete" || + (document.readyState !== "loading" && !document.documentElement.doScroll)) { + bsTriggerOnReady(); +} else { + document.addEventListener("DOMContentLoaded", bsTriggerOnReady); +} + +function escapeHTML(unsafe) { + return unsafe.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); +} + +function changename(s1,s2) { + const files = document.getElementById(s2).files; + if (files.length > 4) + { + alert("You can't upload more than 4 files at one time!") + document.getElementById(s2).files = null + return + } + let filename = ''; + for (const e of files) { + filename += e.name.substr(0, 20) + ', '; + } + document.getElementById(s1).innerHTML = escapeHTML(filename.slice(0, -2)); +} + +function showmore() { + const btn = this.event.target + const div = btn.parentElement.nextElementSibling + div.classList.toggle('d-none') + if (div.classList.contains('d-none')) + btn.innerHTML = 'SHOW MORE' + else + btn.innerHTML = 'SHOW LESS' +} + +function formatDate(d) { + var year = d.getFullYear(); + var monthAbbr = d.toLocaleDateString('en-us', {month: 'short'}); + var day = d.getDate(); + var hour = ("0" + d.getHours()).slice(-2); + var minute = ("0" + d.getMinutes()).slice(-2); + var second = ("0" + d.getSeconds()).slice(-2); + var tzAbbr = d.toLocaleTimeString('en-us', {timeZoneName: 'short'}).split(' ')[2]; + + return (day + " " + monthAbbr + " " + year + " " + + hour + ":" + minute + ":" + second + " " + tzAbbr); +} + +const timestamps = document.querySelectorAll('[data-time]'); + +for (const e of timestamps) { + const date = new Date(e.dataset.time*1000); + e.innerHTML = formatDate(date); +}; + +function timestamp(str, ti) { + const date = new Date(ti*1000); + document.getElementById(str).setAttribute("data-bs-original-title", formatDate(date)); +}; + +function areyousure(t) { + if (t.value) + t.value = 'Are you sure?' + else + t.innerHTML = t.innerHTML.replace(t.textContent, 'Are you sure?') + + t.setAttribute("onclick", t.dataset.click); + + if (t.dataset.dismiss) + t.setAttribute("data-bs-dismiss", t.dataset.dismiss); +} + +function prepare_to_pause(audio) { + for (const e of document.querySelectorAll('video,audio')) + { + e.addEventListener('play', () => { + if (!audio.paused) audio.pause(); + }); + } + + for (const e of document.getElementsByTagName('lite-youtube')) + { + e.addEventListener('click', (event) => { + if (!audio.paused) audio.pause(); + }); + } +} diff --git a/files/assets/js/delete_post_modal.js b/files/assets/js/delete_post_modal.js index 4d6d7ee26..16554f16b 100644 --- a/files/assets/js/delete_post_modal.js +++ b/files/assets/js/delete_post_modal.js @@ -1,28 +1,30 @@ function delete_postModal(id) { document.getElementById("deletePostButton").onclick = function() { - const xhr = new XMLHttpRequest(); - xhr.open("POST", `/delete_post/${id}`); - xhr.setRequestHeader('xhr', 'xhr'); - const form = new FormData() - form.append("formkey", formkey()); - xhr.onload = function() { + const xhr = createXhrWithFormKey(`/delete_post/${id}`); + xhr[0].onload = function() { let data - try {data = JSON.parse(xhr.response)} + try {data = JSON.parse(xhr[0].response)} catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementById(`post-${id}`).classList.add('deleted'); - document.getElementById(`delete-${id}`).classList.add('d-none'); - document.getElementById(`undelete-${id}`).classList.remove('d-none'); - document.getElementById(`delete2-${id}`).classList.add('d-none'); - document.getElementById(`undelete2-${id}`).classList.remove('d-none'); - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); + success = xhr[0].status >= 200 && xhr[0].status < 300; + showToast(success, getMessageFromJsonData(success, data)); + if (success && data["message"]) { + if (window.location.pathname == '/admin/reported/posts') + { + document.getElementById("flaggers-"+id).remove() + document.getElementById("post-"+id).remove() + } + else + { + document.getElementById(`post-${id}`).classList.add('deleted'); + document.getElementById(`delete-${id}`).classList.add('d-none'); + document.getElementById(`undelete-${id}`).classList.remove('d-none'); + document.getElementById(`delete2-${id}`).classList.add('d-none'); + document.getElementById(`undelete2-${id}`).classList.remove('d-none'); + } } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); + showToast(false, getMessageFromJsonData(false, data)); } }; - xhr.send(form); + xhr[0].send(xhr[1]); }; -} \ No newline at end of file +} diff --git a/files/assets/js/followers.js b/files/assets/js/followers.js index 6f7c650bd..d237e5905 100644 --- a/files/assets/js/followers.js +++ b/files/assets/js/followers.js @@ -1,5 +1,4 @@ -function removeFollower(event, username) { - post_toast(event.target,'/remove_follow/' + username); - let table = document.getElementById("followers-table"); - table.removeChild(event.target.parentElement.parentElement); -} \ No newline at end of file +function removeFollower(t, username) { + post_toast(t,'/remove_follow/' + username); + t.parentElement.parentElement.remove(); +} diff --git a/files/assets/js/following.js b/files/assets/js/following.js index 535359c18..ba846496c 100644 --- a/files/assets/js/following.js +++ b/files/assets/js/following.js @@ -1,5 +1,4 @@ -function removeFollowing(event, username) { - post_toast(event.target,'/unfollow/' + username); - let table = document.getElementById("followers-table"); - table.removeChild(event.target.parentElement.parentElement); -} \ No newline at end of file +function removeFollowing(t, username) { + post_toast(t,'/unfollow/' + username); + t.parentElement.parentElement.remove(); +} diff --git a/files/assets/js/formatting.js b/files/assets/js/formatting.js deleted file mode 100644 index 8271ae463..000000000 --- a/files/assets/js/formatting.js +++ /dev/null @@ -1,57 +0,0 @@ - -function makeBold(form) { - var text = document.getElementById(form); - var startIndex = text.selectionStart, - endIndex = text.selectionEnd; - var selectedText = text.value.substring(startIndex, endIndex); - - const format = '**' - - if (selectedText.includes('**')) { - text.value = selectedText.replace(/\*/g, ''); - } - else if (selectedText.length == 0) { - text.value = text.value.substring(0, startIndex) + selectedText + text.value.substring(endIndex); - } - else { - text.value = text.value.substring(0, startIndex) + format + selectedText + format + text.value.substring(endIndex); - } -} - -function makeItalics(form) { - var text = document.getElementById(form); - var startIndex = text.selectionStart, - endIndex = text.selectionEnd; - var selectedText = text.value.substring(startIndex, endIndex); - - const format = '*' - - if (selectedText.includes('*')) { - text.value = selectedText.replace(/\*/g, ''); - } - else if (selectedText.length == 0) { - text.value = text.value.substring(0, startIndex) + selectedText + text.value.substring(endIndex); - } - else { - text.value = text.value.substring(0, startIndex) + format + selectedText + format + text.value.substring(endIndex); - } -} - -function makeQuote(form) { - var text = document.getElementById(form); - var startIndex = text.selectionStart, - endIndex = text.selectionEnd; - var selectedText = text.value.substring(startIndex, endIndex); - - const format = '>' - - if (selectedText.includes('>')) { - text.value = text.value.substring(0, startIndex) + selectedText.replace(/\>/g, '') + text.value.substring(endIndex); - } - else if (selectedText.length == 0) { - text.value = text.value.substring(0, startIndex) + selectedText + text.value.substring(endIndex); - } - else { - text.value = text.value.substring(0, startIndex) + format + selectedText + text.value.substring(endIndex); - } -} \ No newline at end of file diff --git a/files/assets/js/hcaptcha.js b/files/assets/js/hcaptcha.js index 7c9460e58..8bc551980 100644 --- a/files/assets/js/hcaptcha.js +++ b/files/assets/js/hcaptcha.js @@ -1 +1 @@ -var hcaptcha=function(){"use strict";function e(e){var t=this.constructor;return this.then((function(n){return t.resolve(e()).then((function(){return n}))}),(function(n){return t.resolve(e()).then((function(){return t.reject(n)}))}))}function t(e){return new this((function(t,n){if(!e||"undefined"==typeof e.length)return n(new TypeError(typeof e+" "+e+" is not iterable(cannot read property Symbol(Symbol.iterator))"));var i=Array.prototype.slice.call(e);if(0===i.length)return t([]);var r=i.length;function o(e,n){if(n&&("object"==typeof n||"function"==typeof n)){var a=n.then;if("function"==typeof a)return void a.call(n,(function(t){o(e,t)}),(function(n){i[e]={status:"rejected",reason:n},0==--r&&t(i)}))}i[e]={status:"fulfilled",value:n},0==--r&&t(i)}for(var a=0;a>>0,o=Math.min(0|n,r);if(o<0)o=Math.max(0,r+o);else if(o>=r)return-1;if(void 0===t){for(;o!==r;++o)if(void 0===i[o]&&o in i)return o}else if(t!=t){for(;o!==r;++o)if(i[o]!=i[o])return o}else for(;o!==r;++o)if(i[o]===t)return o;return-1}}(Object)),Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),document.getElementsByClassName||(window.Element.prototype.getElementsByClassName=document.constructor.prototype.getElementsByClassName=function(e){if(document.querySelectorAll)return document.querySelectorAll("."+e);for(var t=document.getElementsByTagName("*"),n=new RegExp("(^|\\s)"+e+"(\\s|$)"),i=[],r=0;rthis.length)&&(t=this.length),this.substring(t-e.length,t)===e});try{if(Object.defineProperty&&Object.getOwnPropertyDescriptor&&Object.getOwnPropertyDescriptor(Element.prototype,"textContent")&&!Object.getOwnPropertyDescriptor(Element.prototype,"textContent").get){var m=Object.getOwnPropertyDescriptor(Element.prototype,"innerText");Object.defineProperty(Element.prototype,"textContent",{get:function(){return m.get.call(this)},set:function(e){m.set.call(this,e)}})}}catch(ln){}Function.prototype.bind||(Function.prototype.bind=function(e){if("function"!=typeof this)throw new TypeError("Function.prototype.bind: Item Can Not Be Bound.");var t=Array.prototype.slice.call(arguments,1),n=this,i=function(){},r=function(){return n.apply(this instanceof i?this:e,t.concat(Array.prototype.slice.call(arguments)))};return this.prototype&&(i.prototype=this.prototype),r.prototype=new i,r}),"function"!=typeof Object.create&&(Object.create=function(e,t){function n(){}if(n.prototype=e,"object"==typeof t)for(var i in t)t.hasOwnProperty(i)&&(n[i]=t[i]);return new n}),Date.now||(Date.now=function(){return(new Date).getTime()}),window.console||(window.console={});for(var g,y,v,w,b,_,x=["error","info","log","show","table","trace","warn"],C=function(e){},k=x.length;--k>-1;)p=x[k],window.console[p]||(window.console[p]=C);if(window.atob)try{window.atob(" ")}catch(dn){window.atob=(g=window.atob,(y=function(e){return g(String(e).replace(/[\t\n\f\r ]+/g,""))}).original=g,y)}else{var E="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",O=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;window.atob=function(e){if(e=String(e).replace(/[\t\n\f\r ]+/g,""),!O.test(e))throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");var t,n,i;e+="==".slice(2-(3&e.length));for(var r="",o=0;o>16&255):64===i?String.fromCharCode(t>>16&255,t>>8&255):String.fromCharCode(t>>16&255,t>>8&255,255&t);return r}}if(Event.prototype.preventDefault||(Event.prototype.preventDefault=function(){this.returnValue=!1}),Event.prototype.stopPropagation||(Event.prototype.stopPropagation=function(){this.cancelBubble=!0}),window.Prototype&&Array.prototype.toJSON){console.error("[hCaptcha] Custom JSON polyfill detected, please remove to ensure hCaptcha works properly");var S=Array.prototype.toJSON,I=JSON.stringify;JSON.stringify=function(e){try{return delete Array.prototype.toJSON,I(e)}finally{Array.prototype.toJSON=S}}}Object.keys||(Object.keys=(v=Object.prototype.hasOwnProperty,w=!Object.prototype.propertyIsEnumerable.call({toString:null},"toString"),_=(b=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"]).length,function(e){if("function"!=typeof e&&("object"!=typeof e||null===e))throw new TypeError("Object.keys called on non-object");var t,n,i=[];for(t in e)v.call(e,t)&&i.push(t);if(w)for(n=0;n<_;n++)v.call(e,b[n])&&i.push(b[n]);return i}));var P="challenge-passed",B="challenge-escaped",T="challenge-closed",M="challenge-expired",A="invalid-data",j="bundle-error",$="network-error",L="rate-limited",R="challenge-error",D="incomplete-answer",N="missing-captcha",z="missing-sitekey",W="invalid-captcha-id";function F(e,t){this.cause=e,this.message=t}function U(e){F.call(this,W,"Invalid hCaptcha id: "+e)}function J(){F.call(this,N,"No hCaptcha exists.")}function H(){F.call(this,z,"Missing sitekey - https://hcaptcha.com/docs/configuration#jsapi")}F.prototype=Error.prototype;var q=[],X=[],Y={add:function(e){q.push(e)},remove:function(e){for(var t=!1,n=q.length;--n>-1&&!1===t;)q[n].id===e.id&&(t=q[n],q.splice(n,1));return t},each:function(e){for(var t=-1;++t10&&X.splice(0,X.length-10)},getSession:function(){return X}};function G(){var e=this;this._bottom=0,this._top=0,this.storage={},this.add=function(t){return e.storage[e._top]=t,e._top++,t},this.remove=function(){if(!e.empty()){var t=e._bottom,n=e.storage[t];return e.storage[t]=null,e._bottom++,n}},this.empty=function(){return e._top===e._bottom},this.size=function(){return e._top-e._bottom}}var V={queue:G,depth:function un(e,t,n){if("object"==typeof e&&e[t]&&e[t].length>0)for(var i=e[t].length;--i>-1;)un(e[t][i],t,n);e!==undefined&&n(e)},breathe:function(e,t,n){var i=new G,r=null;for(i.add(e),r=i.remove();r;){for(var o=0;o0||navigator.msMaxTouchPoints>0),t=!1,n&&(t=["iOS","Windows Phone","Windows Mobile","Android","BlackBerry OS"].indexOf(n.name)>=0),e&&t),this.dpr=function(){return window.devicePixelRatio||1},this.mobile&&n&&"Windows"===n.family&&i.indexOf("touch")<0&&(this.mobile=!1),this.os="iOS"===n.family?"ios":"Android"===n.family?"android":"Mac OS X"===n.family?"mac":"Windows"===n.family?"windows":"Linux"===n.family?"linux":n.family.toLowerCase(),this.version=function(){if(!n)return"unknown";var e=n.major;return n.minor&&(e+="."+n.minor),n.patch&&(e+="."+n.patch),e}()}},se={host:null,file:null,sitekey:null,a11y_tfe:null,pingdom:"safari"===ae.Browser.type&&"windows"!==ae.System.os&&"mac"!==ae.System.os&&"ios"!==ae.System.os&&"android"!==ae.System.os,assetDomain:"https://newassets.hcaptcha.com",assetUrl:"https://newassets.hcaptcha.com/captcha/v1/e09e16a/static",width:null,height:null,mobile:null},he={se:null,custom:!1,tplinks:"on",language:null,reportapi:"https://accounts.hcaptcha.com",endpoint:"https://hcaptcha.com",endpointOverride:null,size:"normal",theme:"light",assethost:null,imghost:null,recaptchacompat:"true"};function ce(e,t){e.style.width="304px",e.style.height="78px",e.style.backgroundColor="#f9e5e5",e.style.position="relative",e.innerHTML="";var n=document.createElement("div");n.style.width="284px",n.style.position="absolute",n.style.top="12px",n.style.left="10px",n.style.color="#7c0a06",n.style.fontSize="14px",n.style.fontWeight="normal",n.style.lineHeight="18px",n.innerHTML=t||"Please upgrade your browser to complete this captcha.",e.appendChild(n)}var le=!0;function de(e){var t={message:e.name+": "+e.message};e.stack&&(t.stack_trace={trace:e.stack}),pe("report error","internal","debug",t),ue("internal error","error",se.file)}function ue(e,t,n,i){if(t=t||"error",le){var r="warn"===t?"warning":t;window.Raven&&Raven.captureMessage(e,{level:r,logger:n,extra:i})}}function pe(e,t,n,i){le&&window.Raven&&Raven.captureBreadcrumb({message:e,category:t,level:n,data:i})}function fe(e){var t=[].slice.call(arguments,1);"string"==typeof e?window[e]?"function"==typeof window[e]?window[e].apply(null,t):console.log("[hCaptcha] Callback '"+e+"' is not a function."):console.log("[hCaptcha] Callback '"+e+"' is not defined."):"function"==typeof e?e.apply(null,t):console.log("[hcaptcha] Invalid callback '"+e+"'.")}function me(){try{fe.apply(null,arguments)}catch(ln){console.error("[hCaptcha] There was an error in your callback."),console.error(ln)}}var ge={UUID:function(e){return/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i.test(e)||!1},UUIDv4:function(e){return/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(e)||!1},URL:function(e){var t=new RegExp("^(http|https)://"),n=new RegExp("^((?!(data|javascript):).)*$");return t.test(e)&&n.test(e)}};function ye(e,t){var n,i="attempts"in(t=t||{})?t.attempts:1,r=t.delay||0,o=t.onFail;return n=function(t,n,a){e().then(t,(function(e){var t=i-- >0;o&&(t=!1!==o(e)&&t),t?setTimeout(a,r):n(e)}))},new Promise((function(e,t){n(e,t,(function i(){n(e,t,i)}))}))}var ve={eventName:function(e){var t=e;return"down"===e||"up"===e||"move"===e||"over"===e||"out"===e?t=!ae.System.mobile||"down"!==e&&"up"!==e&&"move"!==e?"mouse"+e:"down"===e?"touchstart":"up"===e?"touchend":"touchmove":"enter"===e&&(t="keydown"),t},actionName:function(e){var t=e;return"touchstart"===t||"mousedown"===t?t="down":"touchmove"===t||"mousemove"===t?t="move":"touchend"===t||"mouseup"===t?t="up":"mouseover"===t?t="over":"mouseout"===t&&(t="out"),t},eventCallback:function(e,t,n){var i=ve.actionName(e);return function(r){if(r=r||window.event,"down"===i||"move"===i||"up"===i||"over"===i||"out"===i||"click"===i){var o=ve.eventCoords(r);if(!o)return;var a=n.getBoundingClientRect();r.windowX=o.x,r.windowY=o.y,r.elementX=r.windowX-(a.x||a.left),r.elementY=r.windowY-(a.y||a.top)}r.keyNum=r.which||r.keyCode||0,"enter"===e&&13!==r.keyNum&&32!==r.keyNum||(r.action=i,r.targetElement=n,t(r))}},eventCoords:function(e){if(!e)return null;var t=e;if(e.touches||e.changedTouches){var n=e.touches&&e.touches.length>=1?e.touches:e.changedTouches;n&&n[0]&&(t=n[0])}return"number"==typeof t.pageX&&"number"==typeof t.pageY?{x:t.pageX,y:t.pageY}:"number"==typeof t.clientX&&"number"==typeof t.clientY?{x:t.clientX,y:t.clientY}:null}};function we(e){this.r=255,this.g=255,this.b=255,this.a=1,this.h=1,this.s=1,this.l=1,this.parseString(e)}function be(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e}we.hasAlpha=function(e){return"string"==typeof e&&(-1!==e.indexOf("rgba")||9===e.length&&"#"===e[0])},we.prototype.parseString=function(e){e&&(0===e.indexOf("#")?this.fromHex(e):0===e.indexOf("rgb")&&this.fromRGBA(e))},we.prototype.fromHex=function(e){var t=1;9===e.length&&(t=parseInt(e.substr(7,2),16)/255);var n=(e=e.substr(1,6)).replace(/^([a-f\d])([a-f\d])([a-f\d])?$/i,(function(e,t,n,i){return t+t+n+n+i+i})),i=parseInt(n,16),r=i>>16,o=i>>8&255,a=255&i;this.setRGBA(r,o,a,t)},we.prototype.fromRGBA=function(e){var t=e.indexOf("rgba"),n=e.substr(t).replace(/rgba?\(/,"").replace(/\)/,"").replace(/[\s+]/g,"").split(","),i=Math.floor(parseInt(n[0])),r=Math.floor(parseInt(n[1])),o=Math.floor(parseInt(n[2])),a=parseFloat(n[3]);this.setRGBA(i,r,o,a)},we.prototype.setRGB=function(e,t,n){this.setRGBA(e,t,n,1)},we.prototype.setRGBA=function(e,t,n,i){this.r=e,this.g=t,this.b=n,this.a=isNaN(i)?this.a:i,this.updateHSL()},we.prototype.hsl2rgb=function(e,t,n){if(0===t){var i=Math.round(255*n);return this.setRGB(i,i,i),this}var r=n<=.5?n*(1+t):n+t-n*t,o=2*n-r;return this.r=Math.round(255*be(o,r,e+1/3)),this.g=Math.round(255*be(o,r,e)),this.b=Math.round(255*be(o,r,e-1/3)),this.h=e,this.s=t,this.l=n,this},we.prototype.updateHSL=function(){var e,t=this.r/255,n=this.g/255,i=this.b/255,r=Math.max(t,n,i),o=Math.min(t,n,i),a=null,s=(r+o)/2;if(r===o)a=e=0;else{var h=r-o;switch(e=s>.5?h/(2-r-o):h/(r+o),r){case t:a=(n-i)/h+(n1&&(e/=100),this.hsl2rgb(this.h,this.s,e),this},we.prototype.saturation=function(e){return e>1&&(e/=100),this.hsl2rgb(this.h,e,this.l),this},we.prototype.hue=function(e){return this.hsl2rgb(e/360,this.s,this.l),this};var _e=["Webkit","Moz","ms"],xe=document.createElement("div").style,Ce={};function ke(e){var t=Ce[e];return t||(e in xe?e:Ce[e]=function(e){for(var t=e[0].toUpperCase()+e.slice(1),n=_e.length;n--;)if((e=_e[n]+t)in xe)return e}(e)||e)}function Ee(e,t,n){if(this.dom=null,this._clss=[],this._nodes=[],this._listeners=[],this._frag=null,e&&"object"==typeof e){this.dom=e;var i=[],r=[];"string"==typeof e.className&&(r=e.className.split(" "));for(var o=0;o=0||e.indexOf(".")>=0))&&(e&&(t=e),e="div"),this.dom=document.createElement(e),t&&(t.indexOf("#")>=0?this.dom.id=t.split("#")[1]:(t.indexOf(".")>=0&&(t=t.split(".")[1]),this.addClass.call(this,t)));!0===n&&(this._frag=document.createDocumentFragment(),this._frag.appendChild(this.dom))}Ee.prototype.createElement=function(e,t){var n=new Ee(e,t,!1);return this.appendElement.call(this,n),this._nodes.push(n),n},Ee.prototype.appendElement=function(e){if(e===undefined)return de({name:"DomElement Add Child",message:"Child Element is undefined"});var t;t=e._frag!==undefined&&null!==e._frag?e._frag:e.dom!==undefined?e.dom:e;try{e instanceof Ee&&(e._parent=this),this.dom.appendChild(t)}catch(dn){de({name:"DomElement Add Child",message:"Failed to append child."})}return this},Ee.prototype.removeElement=function(e){try{var t;if(e._nodes)for(t=e._nodes.length;t--;)e.removeElement(e._nodes[t]);for(t=this._nodes.length;--t>-1;)this._nodes[t]===e&&this._nodes.splice(t,1);this.dom.removeChild(e.dom||e),e.__destroy&&e.__destroy()}catch(dn){de({name:"DomElement Remove Child",message:"Failed to remove child."})}},Ee.prototype.addClass=function(e){return!1===this.hasClass.call(this,e)&&(this._clss.push(e),this.dom.className=this._clss.join(" ")),this},Ee.prototype.hasClass=function(e){for(var t=-1!==this.dom.className.split(" ").indexOf(e),n=this._clss.length;n--&&!t;)t=this._clss[n]===e;return t},Ee.prototype.removeClass=function(e){for(var t=this._clss.length;--t>-1;)this._clss[t]===e&&this._clss.splice(t,1);return this.dom.className=this._clss.join(" "),this},Ee.prototype.text=function(e){if(this&&this.dom){if(!e)return this.dom.textContent;for(var t,n,i,r,o=/&(.*?);/g,a=/<[a-z][\s\S]*>/i;null!==(t=o.exec(e));){!1===a.test(t[0])?(i=t[0],r=void 0,(r=document.createElement("div")).innerHTML=i,n=r.textContent,e=e.replace(new RegExp(t[0],"g"),n)):e=e.replace(t[0],"")}return this.dom.textContent=e,this}},Ee.prototype.content=Ee.prototype.text,Ee.prototype.css=function(e){var t,n="ie"===ae.Browser.type&&8===ae.Browser.version;for(var i in e){t=e[i];try{"opacity"!==i&&"zIndex"!==i&&"fontWeight"!==i&&isFinite(t)&&parseFloat(t)===t&&(t+="px");var r=ke(i);n&&"opacity"===i?this.dom.style.filter="alpha(opacity="+100*t+")":n&&we.hasAlpha(t)?this.dom.style[r]=new we(t).getHex():this.dom.style[r]=t}catch(ln){}}return this},Ee.prototype.backgroundImage=function(e,t,n,i){var r=t!==undefined&&n!==undefined,o={"-ms-high-contrast-adjust":"none"};if("object"==typeof t&&(i=t),i===undefined&&(i={}),r){var a=e.width/e.height,s=t,h=s/a;i.cover&&hn&&(s=(h=n)*a),o.width=s,o.height=h,i.center&&(o.marginLeft=-s/2,o.marginTop=-h/2,o.position="absolute",o.left="50%",o.top="50%"),(i.left||i.right)&&(o.left=i.left||0,o.top=i.top||0)}"ie"===ae.Browser.type&&8===ae.Browser.version?o.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+e.src+"',sizingMethod='scale')":(o.background="url("+e.src+")",o.backgroundPosition="50% 50%",o.backgroundRepeat="no-repeat",o.backgroundSize=r?s+"px "+h+"px":i.cover?"cover":i.contain?"contain":"100%"),this.css.call(this,o)},Ee.prototype.setAttribute=function(e,t){var n;if("object"==typeof e)for(var i in e)n=e[i],this.dom.setAttribute(i,n);else this.dom.setAttribute(e,t)},Ee.prototype.removeAttribute=function(e,t){var n;if("object"==typeof e)for(var i in e)n=e[i],this.dom.removeAttribute(i,n);else this.dom.removeAttribute(e,t)},Ee.prototype.addEventListener=function(e,t,n){var i={event:ve.eventName(e),handler:ve.eventCallback(e,t,this.dom),callback:t};this._listeners.push(i),this.dom.addEventListener?this.dom.addEventListener(i.event,i.handler,n):this.dom.attachEvent("on"+i.event,i.handler)},Ee.prototype.removeEventListener=function(e,t,n){for(var i,r=this._listeners.length;--r>-1;)(i=this._listeners[r]).event===e&&i.callback===t&&(this._listeners.splice(r,1),this.dom.removeEventListener?this.dom.removeEventListener(i.event,i.handler,n):this.dom.detachEvent("on"+i.event,i.handler))},Ee.prototype.focus=function(){this.dom.focus()},Ee.prototype.blur=function(){this.dom.blur()},Ee.prototype.html=function(e){return e&&(this.dom.innerHTML=e),this.dom.innerHTML},Ee.prototype.__destroy=function(){for(var e,t=this._listeners.length;--t>-1;)e=this._listeners[t],this._listeners.splice(t,1),this.dom.removeEventListener?this.dom.removeEventListener(e.event,e.handler):this.dom.detachEvent("on"+e.event,e.handler);return this.dom=null,this._clss=[],this._nodes=[],this._listeners=[],this._frag=null,e=null,null};var Oe=function(e,t){var n={},i=Array.prototype.slice.call(arguments,2);for(var r in t.apply(e,i),e)n[r]=e[r]},Se=function(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e};function Ie(e,t){Oe(this,Ee,t||"div",e),this.children=[],this._events=[]}Se(Ie,Ee),Ie.prototype.initComponent=function(e,t,n){var i=new e(t);return i._parent=this,this.children.push(i),i.dom&&(n!==undefined?n.appendElement&&n.appendElement(i):this.appendElement(i)),i},Ie.prototype.destroy=function(){var e=this;try{V.depth(this,"children",(function(t){if(e!==t)for(var n=e.children.length;--n>-1;)e.children[n]===t&&e.children.splice(n,1);t._destroy&&t._destroy(),t=null}))}catch(dn){throw new Error("Trouble destroying nodes: "+dn)}return null},Ie.prototype._destroy=function(){try{this.onDestroy&&this.onDestroy(),this._parent.removeElement&&this._parent.removeElement(this);for(var e=this._events.length;--e>-1;)this._events.splice(e,1);this.children=null,this._destroy=null,this._events=null,this.destroy=null,this.emit=null,this.on=null,this.off=null,this.initComponent=null}catch(dn){de({name:"DomComponent",message:"Failed to destroy."})}},Ie.prototype.on=function(e,t){for(var n=this._events.length,i=!1;--n>-1&&!1===i;)this._events[n].event===e&&(i=this._events[n]);!1===i&&(i={event:e,listeners:[]},this._events.push(i)),i.listeners.push(t)},Ie.prototype.off=function(e,t){for(var n=this._events.length;--n>-1;)if(this._events[n].event===e){for(var i=this._events[n].listeners.length;--i>-1;)this._events[n].listeners[i]===t&&this._events[n].listeners.splice(i,1);0===this._events[n].listeners.length&&this._events.splice(n,1)}},Ie.prototype.emit=function(e){for(var t=Array.prototype.slice.call(arguments,1),n=this._events.length;--n>-1&&this._events;)if(this._events[n].event===e)for(var i=this._events[n].listeners.length;--i>-1;)this._events[n].listeners[i].apply(this,t)};var Pe={af:"Afrikaans",sq:"Albanian",am:"Amharic",ar:"Arabic",hy:"Armenian",az:"Azerbaijani",eu:"Basque",be:"Belarusian",bn:"Bengali",bg:"Bulgarian",bs:"Bosnian",my:"Burmese",ca:"Catalan",ceb:"Cebuano",zh:"Chinese","zh-CN":"Chinese Simplified","zh-TW":"Chinese Traditional",co:"Corsican",hr:"Croatian",cs:"Czech",da:"Danish",nl:"Dutch",en:"English",eo:"Esperanto",et:"Estonian",fa:"Persian",fi:"Finnish",fr:"French",fy:"Frisian",gd:"Gaelic",gl:"Galacian",ka:"Georgian",de:"German",el:"Greek",gu:"Gujurati",ht:"Haitian",ha:"Hausa",haw:"Hawaiian",he:"Hebrew",hi:"Hindi",hmn:"Hmong",hu:"Hungarian",is:"Icelandic",ig:"Igbo",id:"Indonesian",ga:"Irish",it:"Italian",ja:"Japanese",jw:"Javanese",kn:"Kannada",kk:"Kazakh",km:"Khmer",rw:"Kinyarwanda",ky:"Kirghiz",ko:"Korean",ku:"Kurdish",lo:"Lao",la:"Latin",lv:"Latvian",lt:"Lithuanian",lb:"Luxembourgish",mk:"Macedonian",mg:"Malagasy",ms:"Malay",ml:"Malayalam",mt:"Maltese",mi:"Maori",mr:"Marathi",mn:"Mongolian",ne:"Nepali",no:"Norwegian",ny:"Nyanja",or:"Oriya",pl:"Polish","pt-BR":"Portuguese (Brazil)",pt:"Portuguese (Portugal)",ps:"Pashto",pa:"Punjabi",ro:"Romanian",ru:"Russian",sm:"Samoan",sn:"Shona",sd:"Sindhi",si:"Singhalese",sr:"Serbian",sk:"Slovak",sl:"Slovenian",so:"Somani",st:"Southern Sotho",es:"Spanish",su:"Sundanese",sw:"Swahili",sv:"Swedish",tl:"Tagalog",tg:"Tajik",ta:"Tamil",tt:"Tatar",te:"Teluga",th:"Thai",tr:"Turkish",tk:"Turkmen",ug:"Uyghur",uk:"Ukrainian",ur:"Urdu",uz:"Uzbek",vi:"Vietnamese",cy:"Welsh",xh:"Xhosa",yi:"Yiddish",yo:"Yoruba",zu:"Zulu"},Be={zh:{"I am human":"我是人"},ar:{"I am human":"أنا الإنسان"},af:{"I am human":"Ek is menslike"},am:{"I am human":"እኔ ሰው ነኝ"},hy:{"I am human":"ÔµÕ½ Õ´Õ¡Ö€Õ¤ Õ¥Õ´"},az:{"I am human":"MÉ™n insanam"},eu:{"I am human":"Gizakia naiz"},bn:{"I am human":"আমি মানব নই"},bg:{"I am human":"Аз съм човек"},ca:{"I am human":"Sóc humà "},hr:{"I am human":"Ja sam čovjek"},cs:{"I am human":"Jsem človÄ›k"},da:{"I am human":"Jeg er et menneske"},nl:{"I am human":"Ik ben een mens"},et:{"I am human":"Ma olen inimeste"},fi:{"I am human":"Olen ihminen"},fr:{"I am human":"Je suis humain"},gl:{"I am human":"Eu son humano"},ka:{"I am human":"მე ვარადამიანი"},de:{"I am human":"Ich bin ein Mensch"},el:{"I am human":"Είμαι άνθρωπος"},gu:{"I am human":"હું માનવ છું"},iw:{"I am human":". ×× ×™ ×× ×•×©×™"},hi:{"I am human":"मैं मानव हूं"},hu:{"I am human":"Nem vagyok robot"},is:{"I am human":"Ég er manneskja"},id:{"I am human":"Aku manusia"},it:{"I am human":"Sono un essere umano"},ja:{"I am human":"私は人間です"},kn:{"I am human":"ನಾನು ಮಾನವನು"},ko:{"I am human":"사람입니다"},lo:{"I am human":"ຂ້ອຍເປັນມະນຸດ"},lv:{"I am human":"Es esmu cilvÄ“ks"},lt:{"I am human":"AÅ¡ esu žmogaus"},ms:{"I am human":"Saya manusia"},ml:{"I am human":"ഞാൻ മനുഷ്യനാണ്"},mr:{"I am human":"मी मानवी आहे"},mn:{"I am human":"Би бол хүн"},no:{"I am human":"Jeg er menneskelig"},fa:{"I am human":"من انسانی هستم"},pl:{"I am human":"Jestem czÅ‚owiekiem"},pt:{"I am human":"Sou humano"},ro:{"I am human":"Eu sunt om"},ru:{"I am human":"Я человек"},sr:{"I am human":"Ja sam ljudski"},si:{"I am human":"මම මිනිස්සු"},sk:{"I am human":"Ja som človek"},sl:{"I am human":"Jaz sem človeÅ¡ki"},es:{"I am human":"Soy humano"},sw:{"I am human":"Mimi ni binadamu"},sv:{"I am human":"Jag är människa"},ta:{"I am human":"நான் மனித"},te:{"I am human":"నేను మనిషిని"},th:{"I am human":"ผมมนุษย์"},tr:{"I am human":"Ben bir insanım"},uk:{"I am human":"Я людини"},ur:{"I am human":"میں انسان ہوں"},vi:{"I am human":"Tôi là con người"},zu:{"I am human":"Ngingumuntu"}},Te=null,Me={translate:function(e,t){var n=Me.getBestTrans(Be),i=n&&n[e];if(i=i||e,t)for(var r=Object.keys(t),o=r.length;o--;)i=i.replace(new RegExp("{{"+r[o]+"}}","g"),t[r[o]]);return i},getBestTrans:function(e){var t=Me.getLocale();return t in e?e[t]:Me.getShortLocale(t)in e?e[Me.getShortLocale(t)]:"en"in e?e.en:null},getLocale:function(){var e=Te||window.navigator.userLanguage||window.navigator.language,t=Me.getShortLocale(e);return"in"===t&&(e="id"),"iw"===t&&(e="he"),"nb"===t&&(e="no"),"ji"===t&&(e="yi"),"zh-CN"===e&&(e="zh"),"jv"===t&&(e="jw"),Pe[e]?e:Pe[t]?t:"en"},setLocale:function(e){Te=e},getShortLocale:function(e){return e.indexOf("-")>=0?e.substring(0,e.indexOf("-")):e},isShortLocale:function(e){return 2===e.length||3===e.length},addTable:function(e,t){if(t||(t=Object.create(null)),Be[e]){var n=Be[e];for(var i in t)n[i]=t[i]}else Be[e]=t;return Be[e]},getTable:function(e){return Be[e]},addTables:function(e){for(var t in e)Me.addTable(t,e[t]);return Be},getTables:function(){return Be}};function Ae(e,t){this._period=e,this._interval=t,this._date=[],this._data=[],this._prevTimestamp=0,this._meanPeriod=0,this._meanCounter=0}Ae.prototype.getMeanPeriod=function(){return this._meanPeriod},Ae.prototype.getData=function(){return this._cleanStaleData(),this._data},Ae.prototype.getSize=function(){return this._cleanStaleData(),this._data.length},Ae.prototype.getCapacity=function(){return 0===this._period?this._interval:Math.ceil(this._interval/this._period)},Ae.prototype.push=function(e,t){this._cleanStaleData();var n=0===this._date.length;if(e-(this._date[this._date.length-1]||0)>=this._period&&(this._date.push(e),this._data.push(t)),!n){var i=e-this._prevTimestamp;this._meanPeriod=(this._meanPeriod*this._meanCounter+i)/(this._meanCounter+1),this._meanCounter++}this._prevTimestamp=e},Ae.prototype._cleanStaleData=function(){for(var e=Date.now(),t=this._date.length-1;t>=0;t--){if(e-this._date[t]>=this._interval){this._date.splice(0,t+1),this._data.splice(0,t+1);break}}};var je={touchstart:"ts",touchend:"te",touchmove:"tm",touchcancel:"tc"},$e={mousedown:"md",mouseup:"mu",mousemove:"mm"},Le={keydown:"kd",keyup:"ku"},Re={devicemotion:"dm"},De=function(e,t){var n=$e[e],i=null;return function(e){i=function(e){return[e.windowX,e.windowY,Date.now()]}(e),t(n,i)}},Ne=function(e,t){var n=je[e],i=null;return function(e){i=function(e){var t=[];try{var n,i;if(e.touches&&e.touches.length>=1?n=e.touches:e.changedTouches&&e.changedTouches.length>=1&&(n=e.changedTouches),n){for(var r=0;r-1&&!o;)(o=i[r][1]===n.id)&&(t=i[r][0])}catch(a){t=""}return t}function Ze(e,t){var n=e instanceof HTMLIFrameElement;try{n?e.parentNode&&e.contentWindow.postMessage(JSON.stringify(t),"*"):e.postMessage(JSON.stringify(t),"*")}catch(ln){ue(ln.message,"error","messaging")}}function et(e,t){this.target=e,this.id=t,this.messages=[],this.incoming=[],this.waiting=[]}function tt(e,t){var n=this,i={},r=new Promise((function(e,t){i.resolve=e,i.reject=t})),o={source:"hcaptcha",label:e,id:n.id,promise:null,lookup:t};return r.then((function(e){o.promise="resolve",null!==e&&(o.contents=e),Ze(n.target,o)}))["catch"]((function(e){o.promise="reject",null!==e&&(o.error=e),Ze(n.target,o)})),i}et.prototype.setID=function(e){this.id=e},et.prototype.contact=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");var n=this,i=Date.now().toString(36),r={source:"hcaptcha",label:e,id:this.id,promise:"create",lookup:i};if(t){if("object"!=typeof t)throw new Error("Message must be an object.");r.contents=t}return new Promise((function(t,o){n.waiting.push({label:e,reject:o,resolve:t,lookup:i}),Ze(n.target,r)}))},et.prototype.listen=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");for(var n=this.messages.length,i=!1;--n>-1&&!1===i;)this.messages[n].label===e&&(i=this.messages[n]);!1===i&&(i={label:e,listeners:[]},this.messages.push(i)),i.listeners.push(t)},et.prototype.answer=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");for(var n=this.incoming.length,i=!1;--n>-1&&!1===i;)this.incoming[n].label===e&&(i=this.incoming[n]);!1===i&&(i={label:e,listeners:[]},this.incoming.push(i)),i.listeners.push(t)},et.prototype.send=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");var n={source:"hcaptcha",label:e,id:this.id};if(t){if("object"!=typeof t)throw new Error("Message must be an object.");n.contents=t}Ze(this.target,n)},et.prototype.check=function(e,t){for(var n=[].concat.apply([],[this.messages,this.incoming,this.waiting]),i=[],r=-1;++r-1&&!1===h;)this.waiting[s].label===t.label&&this.waiting[s].lookup===t.lookup&&(h=!0,this.waiting.splice(s,1));continue}for(r=0;r-1&&!1===t;)e.id===nt.chats[n].id&&e.target===nt.chats[n].target&&(t=nt.chats[n],nt.chats.splice(n,1));return t},handle:function(e){var t=e.data;if("string"==typeof t)try{if(!(t.indexOf("hcaptcha")>=0))return;t=JSON.parse(t);for(var n,i=nt.chats,r=-1;++r=0&&(n=t[i]);return n}catch(dn){return""}},hasCookie:function(e){return!!it.getCookie(e)},supportsAPI:function(){try{return"hasStorageAccess"in document&&"requestStorageAccess"in document}catch(dn){return!1}},hasAccess:function(){return new Promise((function(e){document.hasStorageAccess().then((function(){e(!0)}))["catch"]((function(){e(!1)}))}))},requestAccess:function(){try{return document.requestStorageAccess()}catch(dn){return Promise.resolve()}}};function rt(){try{return Object.keys(window).sort().join(",")}catch(dn){return null}}function ot(e,t){for(var n in t){var i=t[n];switch(typeof i){case"string":e[n]=i;break;case"object":e[n]=e[n]||{},ot(e[n],i);break;default:throw new Error("Source theme contains invalid data types. Only string and object types are supported.")}}}function at(e,t){try{return e in t}catch(n){return!1}}function st(e){return!!e&&"object"==typeof e}function ht(e){return st(e)?ct({},e):e}function ct(e,t){var n,i={},r=Object.keys(e);for(n=0;n=0&&wt.use(n.theme),this._state={escaped:!1,passed:!1,expiredChallenge:!1,expiredResponse:!1},this._origData=null,this._promise=null,this._responseTimer=null,this.challenge=new _t(t,n),this.checkbox=new xt(e,t,n),this.initChallenge=this.initChallenge.bind(this),this.closeChallenge=this.closeChallenge.bind(this),this.displayChallenge=this.displayChallenge.bind(this),this.getGetCaptchaManifest=this.getGetCaptchaManifest.bind(this)}function kt(){Oe(this,Ee,"canvas");var e=this;this.element=this.dom,this.ctx=this.element.getContext("2d"),this.scale=1,this.dpr=window.devicePixelRatio||1,this.clearColor="#fff",this.ctx.roundedRect=function(t,n,i,r,o){var a=i>0?o:-o,s=r>0?o:-o;e.ctx.beginPath(),e.ctx.moveTo(t+a,n),e.ctx.lineTo(t+i-a,n),e.ctx.quadraticCurveTo(t+i,n,t+i,n+s),e.ctx.lineTo(t+i,n+r-s),e.ctx.quadraticCurveTo(t+i,n+r,t+i-a,n+r),e.ctx.lineTo(t+a,n+r),e.ctx.quadraticCurveTo(t,n+r,t,n+r-s),e.ctx.lineTo(t,n+s),e.ctx.quadraticCurveTo(t,n,t+a,n),e.ctx.closePath()}}function Et(e){e=e||{},this.x=e.x||0,this.y=e.y||0,this.rotate=this.rotate.bind(this),this.getDistance=this.getDistance.bind(this),this.radius=0,this.tolerance=0,this.fill=!1,this.stroke=!1,this.fillColor="#fff",this.strokeColor="#fff",this.strokeWidth=1}function Ot(e,t,n){Oe(this,Et,e),this.handleIn=new Et(t),this.handleOut=new Et(n),this.prev=null,this.next=null,this.index=0}function St(e){if(null===e)return"";var t=[];return It(e,t),t.join("&")}function It(e,t){var n,i;if("object"==typeof e)for(i in e)!0===Pt(n=e[i])?It(n,t):t[t.length]=Bt(i,n);else if(!0===Array.isArray(e))for(var r=0;rn.clientHeight,c=a?(r-this.width)/2:e.bounding.left+e.tick.right+10;(c+this.width+t>r||c<0)&&(c=(r-this.width)/2,a=!0);var l=(n.scrollHeight=i+o&&(d=i+o-(this.height+t)),d=Math.max(Math.min(d,l),10);var u=e.bounding.top+e.tick.y+i-d-10,p=this.height-10-30;return u=Math.max(Math.min(u,p),t),this.$container.css({left:c,top:d}),this.$arrow.fg.css({display:a?"none":"block"}),this.$arrow.bg.css({display:a?"none":"block"}),this.$arrow.css({top:u}),this.top=d,this.$container.dom.getBoundingClientRect(),h}},_t.prototype.destroy=function(){this._visible&&this.close.call(this),this._hasCustomContainer?this._parent.removeChild(this.$iframe.dom):(this._parent.removeChild(this.$container.dom),this.$container=this.$container.__destroy()),this.$iframe=this.$iframe.__destroy(),nt.removeChat(this.chat),this.chat=this.chat.destroy()},_t.prototype.setReady=function(e){if(this.ready=e,this.ready)for(var t,n=this.listeners.length;--n>-1;)t=this.listeners[n],this.listeners.splice(n,1),t()},_t.prototype.onReady=function(e){var t=Array.prototype.slice.call(arguments,1),n=function(){e.apply(null,t)};this.ready?n():this.listeners.push(n)},_t.prototype.onOverlayClick=function(e){this._hasCustomContainer||this.$overlay.addEventListener("click",e)},_t.prototype.setConfig=function(e){return this.chat?this.chat.contact("challenge-update",e):Promise.resolve()},_t.prototype.setData=function(e){this.chat&&this.chat.send("challenge-data",e)},xt.prototype.setResponse=function(e){this.response=e,this.$iframe.dom.setAttribute("data-hcaptcha-response",e),"off"!==he.recaptchacompat&&(this.$textArea0.dom.value=e),this.$textArea1.dom.value=e},xt.prototype.style=function(){switch(this.config.size){case"compact":this.$iframe.css({width:164,height:144});break;case"invisible":this.$iframe.css({display:"none"});break;default:this.$iframe.css({width:303,height:78,overflow:"hidden"})}},xt.prototype.reset=function(){this._ticked=!1,this.chat&&this.chat.send("checkbox-reset")},xt.prototype.clearLoading=function(){this.chat&&this.chat.send("checkbox-clear")},xt.prototype.sendTranslation=function(e){var t={locale:e,table:Me.getTable(e)||{}};this.chat&&this.chat.send("checkbox-translate",t)},xt.prototype.status=function(e,t){this.chat&&this.chat.send("checkbox-status",{text:e||null,a11yOnly:t||!1})},xt.prototype.tick=function(){this._ticked=!0,this.chat&&this.chat.send("checkbox-tick")},xt.prototype.getTickLocation=function(){return this.chat.contact("checkbox-location")},xt.prototype.getOffset=function(){var e=this.$iframe.dom;e.offsetParent||(e=e.parentElement);for(var t=0,n=0;e;)t+=e.offsetLeft,n+=e.offsetTop,e=e.offsetParent;return{top:n,left:t}},xt.prototype.getBounding=function(){return this.$iframe.dom.getBoundingClientRect()},xt.prototype.destroy=function(){this._ticked&&this.reset(),this.$container.removeElement(this.$iframe),this.$container.removeElement(this.$textArea1),"off"!==he.recaptchacompat&&(this.$container.removeElement(this.$textArea0),this.$textArea0=this.$textArea0.__destroy()),this.$textArea1=this.$textArea1.__destroy(),this.$container=this.$container.__destroy(),this.$iframe=this.$iframe.__destroy(),nt.removeChat(this.chat),this.chat=this.chat.destroy()},Ct.prototype._resetTimer=function(){null!==this._responseTimer&&(clearTimeout(this._responseTimer),this._responseTimer=null)},Ct.prototype.initChallenge=function(e){e||(e={}),this._origData=e;var t=this.getGetCaptchaManifest(),n=e.charity||null,i=e.a11yChallenge||!1,r=e.link||null,o=e.action||"",a=e.rqdata||null,s=ae.Browser.width(),h=ae.Browser.height();this._active=!0,this._resetTimer(),this._resetState(),this.checkbox.setResponse(""),this.challenge.setup({a11yChallenge:i,manifest:t,width:s,height:h,charity:n,link:r,action:o,rqdata:a,wdata:rt()})},Ct.prototype.getGetCaptchaManifest=function(){var e=(this._origData||{}).manifest||null;return e||((e=Object.create(null)).st=Date.now()),e.v=1,e.topLevel=Ue.getData(),e.session=Y.getSession(),e.widgetList=Y.getCaptchaIdList(),e.widgetId=this.id,e.href=window.location.href,e.prev=JSON.parse(JSON.stringify(this._state)),e},Ct.prototype.displayChallenge=function(e){if(this._active){var t=this;this.visible=!0;var n=this.checkbox,i=this.challenge,r=ae.Browser.height();if(!("ie"===ae.Browser.type&&8===ae.Browser.version)){var o=window.getComputedStyle(document.body).getPropertyValue("overflow-y");this.overflow.override="hidden"===o,this.overflow.override&&(this.overflow.cssUsed=""===document.body.style.overflow&&""===document.body.style.overflowY,this.overflow.cssUsed||(this.overflow.value=""===o?"auto":o),this.overflow.scroll=ae.Browser.scrollY(),document.body.style.overflowY="auto")}return new Promise((function(o){n.status(),n.getTickLocation().then((function(a){if(t._active){if(i.size(e.width,e.height,e.mobile),i.show(),n.clearLoading(),n.location.bounding=n.getBounding(),n.location.tick=a,n.location.offset=n.getOffset(),i.position(n.location))(window.document.scrollingElement||document.getElementsByTagName("html")[0]).scrollTop=Math.abs(i.height-r)+i.top;o()}}))})).then((function(){t.onOpen&&me(t.onOpen)}))}},Ct.prototype.resize=function(e,t,n){var i=this,r=this.checkbox,o=this.challenge;o.getDimensions(e,t).then((function(e){e&&o.size(e.width,e.height,e.mobile),r.location.bounding=r.getBounding(),r.location.offset=r.getOffset(),ae.System.mobile&&!n||o.position(r.location)}))["catch"]((function(e){i.closeChallenge.call(i,{event:R,message:"Captcha resize caused error.",error:e})}))},Ct.prototype.position=function(){var e=this.checkbox,t=this.challenge;ae.System.mobile||(e.location.bounding=e.getBounding(),t.position(e.location))},Ct.prototype.reset=function(){this.checkbox.reset(),this.checkbox.setResponse(""),this._resetTimer(),this._resetState()},Ct.prototype._resetState=function(){for(var e in this._state)this._state[e]=!1},Ct.prototype.closeChallenge=function(e){this.visible=!1,this._active=!1;var t=this,n=this.checkbox,i=this.challenge;this.overflow.override&&((window.document.scrollingElement||document.getElementsByTagName("html")[0]).scrollTop=this.overflow.scroll,this.overflow.override=!1,this.overflow.scroll=0,document.body.style.overflowY=this.overflow.cssUsed?null:this.overflow.value);var r=e.response||"";switch(n.setResponse(r),i.close(e.event),n.$iframe.dom.focus(),e.event){case B:this._state.escaped=!0,n.reset(),t.onClose&&me(t.onClose),t._promise&&t._promise.reject(T);break;case M:this._state.expiredChallenge=!0,n.reset(),n.status("hCaptcha window closed due to timeout.",!0),t.onChalExpire&&me(t.onChalExpire),t._promise&&t._promise.reject(M);break;case R:case j:case $:var o=e.event;n.reset(),e.event===$?(n.status(e.message),429===e.status?o=L:"invalid-data"===e.message&&(o=A)):e.event===j?o=R:e.event===R&&"Answers are incomplete"===e.message&&(o=D),this.onError&&me(this.onError,o),t._promise&&t._promise.reject(o);break;case P:this._state.passed=!0,n.tick(),this.onPass&&me(this.onPass,r),t._promise&&t._promise.resolve({response:r,key:Ke(this.id)}),"number"==typeof e.expiration&&(t._resetTimer(),t._responseTimer=setTimeout((function(){try{n.reset(),n.setResponse(""),n.status("hCaptcha security token has expired. Please complete the challenge again.",!0)}catch(dn){ue("Checkbox not present or could not destroy on expiration: "+dn.message,"error","global")}t.onExpire&&me(t.onExpire),t._responseTimer=null,t._state.expiredResponse=!0}),1e3*e.expiration))}t._promise=null},Ct.prototype.updateTranslation=function(e){this.checkbox.sendTranslation(e),this.challenge.sendTranslation(e)},Ct.prototype.isReady=function(){return this._ready},Ct.prototype.setReady=function(e){if(this._ready=e,this._ready)for(var t,n=this._listeners.length;--n>-1;)t=this._listeners[n],this._listeners.splice(n,1),t()},Ct.prototype.setPromise=function(e){this._promise=e},Ct.prototype.onReady=function(e){var t=Array.prototype.slice.call(arguments,1),n=function(){e.apply(null,t)};this._ready?n():this._listeners.push(n)},Ct.prototype.destroy=function(){(this._resetTimer(),this.overflow.override)&&((window.document.scrollingElement||document.getElementsByTagName("html")[0]).scrollTop=this.overflow.scroll,this.overflow.override=!1,this.overflow.scroll=0,document.body.style.overflowY=this.overflow.cssUsed?null:this.overflow.value);this.challenge.destroy(),this.checkbox.destroy(),this.challenge=null,this.checkbox=null},Ct.prototype.setSiteConfig=function(e){var t=e&&e.features&&e.features.custom_theme;if(this.config.themeConfig&&t){var n="custom-"+this.id;wt.add(n,wt.extend(wt.active(),this.config.themeConfig)),wt.use(n),this.challenge.style()}return this.challenge.setConfig({siteConfig:e,wdata:rt()})},Se(kt,Ee),kt.prototype.dimensions=function(e,t){this.css({width:e,height:t}),this.element.width=Math.round(e/this.scale)*this.dpr,this.element.height=Math.round(t/this.scale)*this.dpr,this.ctx.scale(this.dpr,this.dpr),this.width=Math.round(e/this.scale),this.height=Math.round(t/this.scale)},kt.prototype.clear=function(){this.ctx&&this.ctx.clearRect(0,0,this.element.width,this.element.height)},kt.prototype.draw=function(){this.ctx&&(this.ctx.fillStyle=this.clearColor,this.ctx.fillRect(0,0,this.element.width,this.element.height))},kt.prototype._destroy=function(){this.__destroy(),this.element=null,this.ctx=null,this.width=null,this.height=null},Et.prototype.rotate=function(e,t){var n=function(e){return e*(Math.PI/180)}(t),i=Math.sin(n),r=Math.cos(n),o=this.x-e.x,a=this.y-e.y;this.x=o*r-a*i+e.x,this.y=o*i+a*r+e.y},Et.prototype.getDistance=function(e){return Math.sqrt(Math.pow(this.x-e.x,2)+Math.pow(this.y-e.y,2))},Et.prototype.getAngle=function(e){var t=e.x-this.x,n=e.y-this.y,i=180*Math.atan2(n,t)/Math.PI;return i<0&&(i+=360),i},Et.prototype.hitTest=function(e){return this.radius+this.tolerance>=this.getDistance(e)},Et.prototype.restrict=function(e,t,n,i){if("x"!==e&&"y"!==e)throw new Error("Point.restrict requires a value: x or y");return t+this[e]i&&(t=i-this[e]),this[e]+t},Et.prototype.draw=function(e){e.ctx.beginPath(),e.ctx.arc(this.x,this.y,this.radius/e.scale,0,2*Math.PI,!1),this.fill&&(e.ctx.fillStyle=this.fillColor,e.ctx.fill()),this.stroke&&(e.ctx.strokeStyle=this.strokeColor,e.ctx.lineWidth=this.strokeWidth/e.scale,e.ctx.stroke())},Se(Ot,Et),Ot.prototype.set=function(e,t,n){this.x=e.x||this.x,this.y=e.y||this.y,t===undefined?(this.handleIn.x=this.x,this.handleIn.y=this.y):(this.handleIn.x=t.x,this.handleIn.y=t.y),n===undefined?(this.handleOut.x=this.x,this.handleOut.y=this.y):(this.handleOut.x=n.x,this.handleOut.y=n.y)},Ot.prototype.clone=function(){var e={x:this.x,y:this.y},t={x:this.handleIn.x,y:this.handleIn.y},n={x:this.handleOut.x,y:this.handleOut.y},i=new Ot;return t.x===n.x&&t.y===n.y?i.set(e):i.set(e,t,n),i.index=this.index,i.prev=this.prev,i.next=this.next,i.radius=this.radius,i.tolerance=this.tolerance,i.fill=this.fill,i.stroke=this.stroke,i.fillColor=this.fillColor,i.strokeColor=this.strokeColor,i.strokeWidth=this.strokeWidth,i},Ot.prototype.move=function(e,t){this.x+=e,this.y+=t,this.handleIn.x+=e,this.handleIn.y+=t,this.handleOut.x+=e,this.handleOut.y+=t},Ot.prototype.render=function(e){this.handleIn.x!==this.x&&this.handleIn.y!==this.y&&this.handleIn.draw(e),this.handleOut.x!==this.x&&this.handleOut.y!==this.y&&this.handleOut.draw(e),this.draw(e)};var Tt={400:"Rate limited or network error. Please retry.",429:"Your computer or network has sent too many requests.",500:"Cannot contact hCaptcha. Check your connection and try again."},Mt=function(e){try{return Me.translate(Tt[e])}catch(dn){return!1}},At="undefined"!=typeof XDomainRequest&&!("withCredentials"in XMLHttpRequest.prototype);function jt(e,t,n){n=n||{};var i={url:t,method:e.toUpperCase(),responseType:n.responseType||"string",dataType:n.dataType||null,withCredentials:n.withCredentials||!1,headers:n.headers||null,data:n.data||null,timeout:n.timeout||null};return i.legacy=i.withCredentials&&At,i.data&&("json"===i.dataType&&"object"==typeof i.data&&(i.data=JSON.stringify(i.data)),"query"===i.dataType&&(i.data=St(i.data))),n.retry?ye((function(){return $t(i)}),n.retry):$t(i)}function $t(e){var t=e.legacy?new XDomainRequest:new XMLHttpRequest,n="function"==typeof e.url?e.url():e.url;return new Promise((function(i,r){var o,a=function(o){return function(){var a=t.response||t.responseText,s=t.statusText||"",h=t.status,c=t.readyState;if(4===c||e.legacy){if("json"===e.responseType&&a)try{a=JSON.parse(a)}catch(l){}if("error"===o||h>=400&&h<=511)return void r({event:$,endpoint:n,response:a,state:c,status:h,message:Mt(h||400)||s});i({state:c,status:h,body:a,message:s})}}};if((t.onload=a("complete"),t.onerror=t.ontimeout=a("error"),t.open(e.method,n),e.timeout&&(t.timeout=e.timeout),!e.legacy)&&(t.withCredentials=e.withCredentials,e.headers))for(var s in e.headers)o=e.headers[s],t.setRequestHeader(s,o);setTimeout((function(){t.send(e.data)}),0)}))}var Lt=function(e,t){if("object"==typeof e&&t===undefined&&(e=(t=e).url),null===e)throw new Error("Url missing");return jt("GET",e,t)},Rt=function(e){return e.toLowerCase().match(/\.(?:jpg|gif|png|jpeg|svg)$/g)?"image":e.toLowerCase().match(/\.(?:js)$/g)?"script":"file"},Dt=function(e){if(he.assethost&&e.indexOf(se.assetDomain)>=0)return he.assethost+e.replace(se.assetDomain,"");if(he.imghost&&e.indexOf("imgs")>=0){var t=e.indexOf(".ai")>=0?e.indexOf(".ai")+3:e.indexOf(".com")+4;return he.imghost+e.substr(t,e.length)}return e},Nt=["svg","gif","png"];function zt(e,t){t=t||{};var n,i=e;if(0===i.indexOf("data:image"))for(var r=!1,o=Nt.length,a=-1;a++=0)&&(n=Nt[a]);else n=i.substr(i.lastIndexOf(".")+1,i.length);!!(!document.createElementNS||!document.createElementNS("https://www.w3.org/2000/svg","svg").createSVGRect)&&t.fallback&&(t.fallback.indexOf(".")>=0?n=(i=t.fallback).substr(i.lastIndexOf(".")+1,i.length):(i=e.substr(0,e.indexOf(n))+t.fallback,n=t.fallback)),t.prefix&&(i=t.prefix+"/"+i),this.attribs={crossOrigin:t.crossOrigin||null},this.id=i,this.src=Dt(i),this.ext=n,this.width=0,this.height=0,this.aspect=0,this.loaded=!1,this.error=!1,this.element=null,this.cb={load:[],error:[]}}function Wt(e,t,n){for(var i=e[t],r=i.length,o=null;--r>-1;)o=i[r],i.splice(r,1),o(n);"error"===t?e.load=[]:e.error=[]}function Ft(e,t){var n=e;t||(t={}),t.prefix&&(n=t.prefix+"/"+e),this.attribs={defer:t.defer||null,async:t.async||null,crossOrigin:t.crossOrigin||null},this.id=n,this.src=Dt(n),this.loaded=!1,this.error=!1,this.element=null,this.cb={load:[],error:[]}}function Ut(e,t,n){for(var i=e[t],r=i.length,o=null;--r>-1;)o=i[r],i.splice(r,1),o(n);"error"===t?e.load=[]:e.error=[]}function Jt(e,t){var n=e;t||(t={}),t.prefix&&(n=t.prefix+"/"+e),this.id=n,this.src=Dt(n),this.loaded=!1,this.error=!1,this.cb={load:[],error:[]},this.data=null}function Ht(e,t,n){for(var i=e[t],r=i.length,o=null;--r>-1;)o=i[r],i.splice(r,1),o(n);"error"===t?e.load=[]:e.error=[]}zt.prototype.load=function(){return("svg"===this.ext?this._loadSvg():this._loadImg())["catch"]((function(e){throw ue("Asset failed","error","assets",{error:e}),e}))},zt.prototype._loadSvg=function(){var e,t=this,n=this.src,i=this.id;if(0===n.indexOf("data:image/svg+xml")){var r=n.slice("data:image/svg+xml,".length);e=Promise.resolve(decodeURIComponent(r))}else e=Lt(n).then((function(e){return e.body}));return e.then((function(e){var n=(new DOMParser).parseFromString(e,"image/svg+xml").documentElement,i=parseInt(n.getAttribute("width")),r=parseInt(n.getAttribute("height"));return t._imgLoaded(n,i,r),t}))["catch"]((function(e){t.error=!0;var n=(e&&e.message?e.message:"Loading Error")+": "+i;throw Wt(t.cb,"error",n),n}))},zt.prototype._loadImg=function(){var e=this,t=this.attribs,n=this.src,i=this.id;return new Promise((function(r,o){var a=new Image;t.crossOrigin&&(a.crossOrigin=t.crossOrigin),a.onerror=function(t){e.error=!0,a.onload=a.onerror=null;var n=(t&&t.message?t.message:"Loading Error")+": "+i;Wt(e.cb,"error",n),o(n)},a.onload=function(){e.loaded||(e._imgLoaded(a,a.width,a.height),a.onload=a.onerror=null,r(e))},a.src=n,a.complete&&a.onload()}))},zt.prototype._imgLoaded=function(e,t,n){this.element=new Ee(e),this.width=t,this.height=n,this.aspect=t/n,this.loaded=!0,Wt(this.cb,"load",this)},zt.prototype.onload=function(e){this.error||(this.loaded?e(this):this.cb.load.push(e))},zt.prototype.onerror=function(e){this.loaded&&!this.error||(this.error?e(this):this.cb.error.push(e))},Ft.prototype.load=function(){var e=this,t=this.attribs,n=this.src,i=this.id;return new Promise((function(r,o){var a=document.createElement("script");e.element=a,a.onerror=function(t){e.error=!0,a.onload=a.onreadystatechange=a.onerror=null;var n=(t.message||"Loading Error")+": "+i;Ut(e.cb,"error",n),o(n)},a.onload=a.onreadystatechange=function(){this.loaded||a.readyState&&"loaded"!==a.readyState&&"complete"!==a.readyState||(e.loaded=!0,a.onload=a.onreadystatechange=a.onerror=null,document.body.removeChild(a),Ut(e.cb,"load",e),r(e))},a.type="text/javascript",a.src=n,t.crossOrigin&&(a.crossorigin=t.crossOrigin),t.async&&(a.async=!0),t.defer&&(a.defer=!0),document.body.appendChild(a),a.complete&&a.onload()}))},Ft.prototype.onload=function(e){this.error||(this.loaded?e(this):this.cb.load.push(e))},Ft.prototype.onerror=function(e){this.loaded&&!this.error||(this.error?e(this):this.cb.error.push(e))},Jt.prototype.load=function(){var e=this,t=this.src,n=this.id;return new Promise((function(i,r){var o={};t.indexOf("json")>=0&&(o.responseType="json"),Lt(t,o).then((function(t){e.loaded=!0,e.data=t.body,Ht(e.cb,"load",e),i(e)}))["catch"]((function(t){e.error=!0;var i=(t&&t.message?t.message:"Loading Error")+": "+n;Ht(e.cb,"error",i),r(i)}))}))},Jt.prototype.onload=function(e){this.error||(this.loaded?e(this):this.cb.load.push(e))},Jt.prototype.onerror=function(e){this.loaded&&!this.error||(this.error?e(this):this.cb.error.push(e))};var qt=[],Xt={add:function(e,t){var n=Rt(e);return Xt[n]?Xt[n](e,t):Promise.resolve(null)},batch:function(e,t){for(var n=[],i=-1;++i-1&&!r;)r=(o=qt[i]).id===e||-1!==o.id.indexOf("/"===e[0]?"":"/"+e);if(!r)return t(null);o.onload(t),o.onerror(n)}))}};function Yt(e){if("en"===e)return Promise.resolve();var t=e+".json";return new Promise((function(n,i){Xt.retrieve(t).then((function(n){return n||Xt.file(t,{prefix:"https://newassets.hcaptcha.com/captcha/v1/e09e16a/static/i18n"}).then((function(t){return Me.addTable(e,t.data),t}))})).then((function(e){n(e.data)}))["catch"]((function(e){i(e)}))}))}var Gt=0,Vt=["hl","custom","tplinks","sitekey","theme","size","tabindex","challenge-container"];var Qt={render:function(e,t){if("string"==typeof e&&(e=document.getElementById(e)),e&&1===e.nodeType)if(function(e){if(!e||!("challenge-container"in e))return!0;var t=e["challenge-container"];return"string"==typeof t&&(t=document.getElementById(t)),!!t&&1===t.nodeType}(t)){if(!1!==nt.isSupported()){for(var n,i,r=e.getElementsByTagName("iframe"),o=-1;++oupgrade your browser or enable it for hCaptcha.com")}else console.log("[hCaptcha] render: invalid challenge container '"+t["challenge-container"]+"'.");else console.log("[hCaptcha] render: invalid container '"+e+"'.");function v(e,t){var n=e.locale;function i(e){if(e)try{e.updateTranslation(n)}catch(ln){ue("Failed to update text translation: "+JSON.stringify(ln),"error","translation")}}n&&Yt(n).then((function(){t?i(g):Y.each(i)}))["catch"]((function(e){ue("Language failed to load: "+n,"error","api")}))}},reset:function(e){var t;if(e){if(!(t=Y.getById(e)))throw new U(e);t.reset()}else{if(!(t=Y.getByIndex(0)))throw new J;t.reset()}},remove:function(e){var t=e?Y.getById(e):Y.getByIndex(0);if(!t)throw e?new U(e):new J;Y.remove(t),t.destroy(),t=null},execute:Qe,getResponse:function(e){var t,n;if((n=e?Y.getById(e):Y.getByIndex(0))&&(t=n.checkbox.response||""),void 0!==t)return t;throw e?new U(e):new J},getRespKey:Ke,close:function(e){var t=!1;if(!(t=e?Y.getById(e):Y.getByIndex(0)))throw e?new U(e):new J;t.closeChallenge({event:B})},setData:function(e,t){if("object"!=typeof e||t||(t=e,e=null),!t||"object"!=typeof t)throw Error("[hCaptcha] invalid data supplied");var n=!1;if(!(n=e?Y.getById(e):Y.getByIndex(0)))throw e?new U(e):new J;var i=n.challenge.setData.bind(n.challenge);n.onReady(i,t)},nodes:Y};se.file="hcaptcha";var Kt=document.currentScript,Zt=!1,en=!1,tn="on",nn=ae.Browser.width()/ae.Browser.height(),rn=window.hcaptcha||!1;function on(){var e=ae.Browser.width(),t=ae.Browser.height(),n=ae.System.mobile&&nn!==e/t;nn=e/t,hn(),Qt.nodes.each((function(i){i.visible&&i.resize(e,t,n)}))}function an(e){e.preventDefault&&e.preventDefault(),sn(),Qt.nodes.each((function(e){e.visible&&e.position()}))}function sn(){Ue.circBuffPush("xy",[ae.Browser.scrollX(),ae.Browser.scrollY(),document.documentElement.clientWidth/ae.Browser.width(),Date.now()])}function hn(){Ue.circBuffPush("wn",[ae.Browser.width(),ae.Browser.height(),ae.System.dpr(),Date.now()])}!function(e){var t=Array.prototype.slice.call(arguments,1);!0!==qe&&"interactive"!==document.readyState&&"loaded"!==document.readyState&&"complete"!==document.readyState?(Je.push({fn:e,args:t}),!1===He&&Xe()):setTimeout((function(){e(t)}),1)}((function(){rn||(!function(){var e;e=Kt?[Kt]:document.getElementsByTagName("script");var t=-1,n=!1,i=null,r=null;for(;++t=0?e.split("&"):[e]:[],a=0;a=0){if(t=o[a].split("="),n=decodeURIComponent(t[0]),"false"!==(i=decodeURIComponent(t[1]))&&"true"!==i||(i="true"===i),"theme"===n||"themeConfig"===n)try{i=JSON.parse(i)}catch(dn){}r[n]=i}return r}(i[1]);Zt=o.onload||!1,en=o.render||!1,"off"===o.tplinks&&(tn="off");he.tplinks=tn,he.language=o.hl||null,o.endpoint&&(he.endpointOverride=o.endpoint);he.reportapi=o.reportapi||he.reportapi,he.imghost=o.imghost||null,he.custom=o.custom||he.custom,he.se=o.se||null,he.assethost=o.assethost||null,he.assethost&&!ge.URL(he.assethost)&&(he.assethost=null,console.error("Invalid assethost uri."));he.recaptchacompat=o.recaptchacompat||he.recaptchacompat,se.host=o.host||window.location.hostname,he.language=he.language||window.navigator.userLanguage||window.navigator.language,Me.setLocale(he.language),a=o.sentry===undefined||o.sentry,void(le=a),"off"===he.recaptchacompat?console.log("recaptchacompat disabled"):window.grecaptcha=cn;var a}(),function(){var e=Me.getLocale();if(e.indexOf("en")>=0)return;Yt(e).then((function(){Qt.nodes.each((function(t){if(t)try{t.updateTranslation(e)}catch(ln){ue("Failed to update text translation: "+JSON.stringify(ln),"error","translation")}}))}))["catch"]((function(){ue("Language failed to load: "+e,"error","api")}))}(),!1===en||"onload"===en?function(e){for(var t=document.getElementsByClassName("h-captcha"),n=[],i=0;i>>0,o=Math.min(0|n,r);if(o<0)o=Math.max(0,r+o);else if(o>=r)return-1;if(void 0===t){for(;o!==r;++o)if(void 0===i[o]&&o in i)return o}else if(t!=t){for(;o!==r;++o)if(i[o]!=i[o])return o}else for(;o!==r;++o)if(i[o]===t)return o;return-1}}(Object)),Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),document.getElementsByClassName||(window.Element.prototype.getElementsByClassName=document.constructor.prototype.getElementsByClassName=function(e){if(document.querySelectorAll)return document.querySelectorAll("."+e);for(var t=document.getElementsByTagName("*"),n=new RegExp("(^|\\s)"+e+"(\\s|$)"),i=[],r=0;rthis.length)&&(t=this.length),this.substring(t-e.length,t)===e});try{if(Object.defineProperty&&Object.getOwnPropertyDescriptor&&Object.getOwnPropertyDescriptor(Element.prototype,"textContent")&&!Object.getOwnPropertyDescriptor(Element.prototype,"textContent").get){var m=Object.getOwnPropertyDescriptor(Element.prototype,"innerText");Object.defineProperty(Element.prototype,"textContent",{get:function(){return m.get.call(this)},set:function(e){m.set.call(this,e)}})}}catch(ln){}Function.prototype.bind||(Function.prototype.bind=function(e){if("function"!=typeof this)throw new TypeError("Function.prototype.bind: Item Can Not Be Bound.");var t=Array.prototype.slice.call(arguments,1),n=this,i=function(){},r=function(){return n.apply(this instanceof i?this:e,t.concat(Array.prototype.slice.call(arguments)))};return this.prototype&&(i.prototype=this.prototype),r.prototype=new i,r}),"function"!=typeof Object.create&&(Object.create=function(e,t){function n(){}if(n.prototype=e,"object"==typeof t)for(var i in t)t.hasOwnProperty(i)&&(n[i]=t[i]);return new n}),Date.now||(Date.now=function(){return(new Date).getTime()}),window.console||(window.console={});for(var g,y,v,w,b,_,x=["error","info","log","show","table","trace","warn"],C=function(e){},k=x.length;--k>-1;)p=x[k],window.console[p]||(window.console[p]=C);if(window.atob)try{window.atob(" ")}catch(dn){window.atob=(g=window.atob,(y=function(e){return g(String(e).replace(/[\t\n\f\r ]+/g,""))}).original=g,y)}else{var E="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",O=/^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;window.atob=function(e){if(e=String(e).replace(/[\t\n\f\r ]+/g,""),!O.test(e))throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");var t,n,i;e+="==".slice(2-(3&e.length));for(var r="",o=0;o>16&255):64===i?String.fromCharCode(t>>16&255,t>>8&255):String.fromCharCode(t>>16&255,t>>8&255,255&t);return r}}if(Event.prototype.preventDefault||(Event.prototype.preventDefault=function(){this.returnValue=!1}),Event.prototype.stopPropagation||(Event.prototype.stopPropagation=function(){this.cancelBubble=!0}),window.Prototype&&Array.prototype.toJSON){console.error("[hCaptcha] Custom JSON polyfill detected, please remove to ensure hCaptcha works properly");var S=Array.prototype.toJSON,I=JSON.stringify;JSON.stringify=function(e){try{return delete Array.prototype.toJSON,I(e)}finally{Array.prototype.toJSON=S}}}Object.keys||(Object.keys=(v=Object.prototype.hasOwnProperty,w=!Object.prototype.propertyIsEnumerable.call({toString:null},"toString"),_=(b=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"]).length,function(e){if("function"!=typeof e&&("object"!=typeof e||null===e))throw new TypeError("Object.keys called on non-object");var t,n,i=[];for(t in e)v.call(e,t)&&i.push(t);if(w)for(n=0;n<_;n++)v.call(e,b[n])&&i.push(b[n]);return i}));var P="challenge-passed",B="challenge-escaped",T="challenge-closed",M="challenge-expired",A="invalid-data",j="bundle-error",$="network-error",L="rate-limited",R="challenge-error",D="incomplete-answer",N="missing-captcha",z="missing-sitekey",W="invalid-captcha-id";function F(e,t){this.cause=e,this.message=t}function U(e){F.call(this,W,"Invalid hCaptcha id: "+e)}function J(){F.call(this,N,"No hCaptcha exists.")}function H(){F.call(this,z,"Missing sitekey - https://hcaptcha.com/docs/configuration#jsapi")}F.prototype=Error.prototype;var q=[],X=[],Y={add:function(e){q.push(e)},remove:function(e){for(var t=!1,n=q.length;--n>-1&&!1===t;)q[n].id===e.id&&(t=q[n],q.splice(n,1));return t},each:function(e){for(var t=-1;++t10&&X.splice(0,X.length-10)},getSession:function(){return X}};function G(){var e=this;this._bottom=0,this._top=0,this.storage={},this.add=function(t){return e.storage[e._top]=t,e._top++,t},this.remove=function(){if(!e.empty()){var t=e._bottom,n=e.storage[t];return e.storage[t]=null,e._bottom++,n}},this.empty=function(){return e._top===e._bottom},this.size=function(){return e._top-e._bottom}}var V={queue:G,depth:function un(e,t,n){if("object"==typeof e&&e[t]&&e[t].length>0)for(var i=e[t].length;--i>-1;)un(e[t][i],t,n);e!==undefined&&n(e)},breathe:function(e,t,n){var i=new G,r=null;for(i.add(e),r=i.remove();r;){for(var o=0;o0||navigator.msMaxTouchPoints>0),t=!1,n&&(t=["iOS","Windows Phone","Windows Mobile","Android","BlackBerry OS"].indexOf(n.name)>=0),e&&t),this.dpr=function(){return window.devicePixelRatio||1},this.mobile&&n&&"Windows"===n.family&&i.indexOf("touch")<0&&(this.mobile=!1),this.os="iOS"===n.family?"ios":"Android"===n.family?"android":"Mac OS X"===n.family?"mac":"Windows"===n.family?"windows":"Linux"===n.family?"linux":n.family.toLowerCase(),this.version=function(){if(!n)return"unknown";var e=n.major;return n.minor&&(e+="."+n.minor),n.patch&&(e+="."+n.patch),e}()}},se={host:null,file:null,sitekey:null,a11y_tfe:null,pingdom:"safari"===ae.Browser.type&&"windows"!==ae.System.os&&"mac"!==ae.System.os&&"ios"!==ae.System.os&&"android"!==ae.System.os,assetDomain:"https://newassets.hcaptcha.com",assetUrl:"https://newassets.hcaptcha.com/captcha/v1/e09e16a/static",width:null,height:null,mobile:null},he={se:null,custom:!1,tplinks:"on",language:null,reportapi:"https://accounts.hcaptcha.com",endpoint:"https://hcaptcha.com",endpointOverride:null,size:"normal",theme:"light",assethost:null,imghost:null,recaptchacompat:"true"};function ce(e,t){e.style.width="304px",e.style.height="78px",e.style.backgroundColor="#f9e5e5",e.style.position="relative",e.innerHTML="";var n=document.createElement("div");n.style.width="284px",n.style.position="absolute",n.style.top="12px",n.style.left="10px",n.style.color="#7c0a06",n.style.fontSize="14px",n.style.fontWeight="normal",n.style.lineHeight="18px",n.innerHTML=t||"Please upgrade your browser to complete this captcha.",e.appendChild(n)}var le=!0;function de(e){var t={message:e.name+": "+e.message};e.stack&&(t.stack_trace={trace:e.stack}),pe("report error","internal","debug",t),ue("internal error","error",se.file)}function ue(e,t,n,i){if(t=t||"error",le){var r="warn"===t?"warning":t;window.Raven&&Raven.captureMessage(e,{level:r,logger:n,extra:i})}}function pe(e,t,n,i){le&&window.Raven&&Raven.captureBreadcrumb({message:e,category:t,level:n,data:i})}function fe(e){var t=[].slice.call(arguments,1);"string"==typeof e?window[e]?"function"==typeof window[e]?window[e].apply(null,t):console.log("[hCaptcha] Callback '"+e+"' is not a function."):console.log("[hCaptcha] Callback '"+e+"' is not defined."):"function"==typeof e?e.apply(null,t):console.log("[hcaptcha] Invalid callback '"+e+"'.")}function me(){try{fe.apply(null,arguments)}catch(ln){console.error("[hCaptcha] There was an error in your callback."),console.error(ln)}}var ge={UUID:function(e){return/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i.test(e)||!1},UUIDv4:function(e){return/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(e)||!1},URL:function(e){var t=new RegExp("^(http|https)://"),n=new RegExp("^((?!(data|javascript):).)*$");return t.test(e)&&n.test(e)}};function ye(e,t){var n,i="attempts"in(t=t||{})?t.attempts:1,r=t.delay||0,o=t.onFail;return n=function(t,n,a){e().then(t,(function(e){var t=i-- >0;o&&(t=!1!==o(e)&&t),t?setTimeout(a,r):n(e)}))},new Promise((function(e,t){n(e,t,(function i(){n(e,t,i)}))}))}var ve={eventName:function(e){var t=e;return"down"===e||"up"===e||"move"===e||"over"===e||"out"===e?t=!ae.System.mobile||"down"!==e&&"up"!==e&&"move"!==e?"mouse"+e:"down"===e?"touchstart":"up"===e?"touchend":"touchmove":"enter"===e&&(t="keydown"),t},actionName:function(e){var t=e;return"touchstart"===t||"mousedown"===t?t="down":"touchmove"===t||"mousemove"===t?t="move":"touchend"===t||"mouseup"===t?t="up":"mouseover"===t?t="over":"mouseout"===t&&(t="out"),t},eventCallback:function(e,t,n){var i=ve.actionName(e);return function(r){if(r=r||window.event,"down"===i||"move"===i||"up"===i||"over"===i||"out"===i||"click"===i){var o=ve.eventCoords(r);if(!o)return;var a=n.getBoundingClientRect();r.windowX=o.x,r.windowY=o.y,r.elementX=r.windowX-(a.x||a.left),r.elementY=r.windowY-(a.y||a.top)}r.keyNum=r.which||r.keyCode||0,"enter"===e&&13!==r.keyNum&&32!==r.keyNum||(r.action=i,r.targetElement=n,t(r))}},eventCoords:function(e){if(!e)return null;var t=e;if(e.touches||e.changedTouches){var n=e.touches&&e.touches.length>=1?e.touches:e.changedTouches;n&&n[0]&&(t=n[0])}return"number"==typeof t.pageX&&"number"==typeof t.pageY?{x:t.pageX,y:t.pageY}:"number"==typeof t.clientX&&"number"==typeof t.clientY?{x:t.clientX,y:t.clientY}:null}};function we(e){this.r=255,this.g=255,this.b=255,this.a=1,this.h=1,this.s=1,this.l=1,this.parseString(e)}function be(e,t,n){return n<0&&(n+=1),n>1&&(n-=1),n<1/6?e+6*(t-e)*n:n<.5?t:n<2/3?e+(t-e)*(2/3-n)*6:e}we.hasAlpha=function(e){return"string"==typeof e&&(-1!==e.indexOf("rgba")||9===e.length&&"#"===e[0])},we.prototype.parseString=function(e){e&&(0===e.indexOf("#")?this.fromHex(e):0===e.indexOf("rgb")&&this.fromRGBA(e))},we.prototype.fromHex=function(e){var t=1;9===e.length&&(t=parseInt(e.substr(7,2),16)/255);var n=(e=e.substr(1,6)).replace(/^([a-f\d])([a-f\d])([a-f\d])?$/i,(function(e,t,n,i){return t+t+n+n+i+i})),i=parseInt(n,16),r=i>>16,o=i>>8&255,a=255&i;this.setRGBA(r,o,a,t)},we.prototype.fromRGBA=function(e){var t=e.indexOf("rgba"),n=e.substr(t).replace(/rgba?\(/,"").replace(/\)/,"").replace(/[\s+]/g,"").split(","),i=Math.floor(parseInt(n[0])),r=Math.floor(parseInt(n[1])),o=Math.floor(parseInt(n[2])),a=parseFloat(n[3]);this.setRGBA(i,r,o,a)},we.prototype.setRGB=function(e,t,n){this.setRGBA(e,t,n,1)},we.prototype.setRGBA=function(e,t,n,i){this.r=e,this.g=t,this.b=n,this.a=isNaN(i)?this.a:i,this.updateHSL()},we.prototype.hsl2rgb=function(e,t,n){if(0===t){var i=Math.round(255*n);return this.setRGB(i,i,i),this}var r=n<=.5?n*(1+t):n+t-n*t,o=2*n-r;return this.r=Math.round(255*be(o,r,e+1/3)),this.g=Math.round(255*be(o,r,e)),this.b=Math.round(255*be(o,r,e-1/3)),this.h=e,this.s=t,this.l=n,this},we.prototype.updateHSL=function(){var e,t=this.r/255,n=this.g/255,i=this.b/255,r=Math.max(t,n,i),o=Math.min(t,n,i),a=null,s=(r+o)/2;if(r===o)a=e=0;else{var h=r-o;switch(e=s>.5?h/(2-r-o):h/(r+o),r){case t:a=(n-i)/h+(n1&&(e/=100),this.hsl2rgb(this.h,this.s,e),this},we.prototype.saturation=function(e){return e>1&&(e/=100),this.hsl2rgb(this.h,e,this.l),this},we.prototype.hue=function(e){return this.hsl2rgb(e/360,this.s,this.l),this};var _e=["Webkit","Moz","ms"],xe=document.createElement("div").style,Ce={};function ke(e){var t=Ce[e];return t||(e in xe?e:Ce[e]=function(e){for(var t=e[0].toUpperCase()+e.slice(1),n=_e.length;n--;)if((e=_e[n]+t)in xe)return e}(e)||e)}function Ee(e,t,n){if(this.dom=null,this._clss=[],this._nodes=[],this._listeners=[],this._frag=null,e&&"object"==typeof e){this.dom=e;var i=[],r=[];"string"==typeof e.className&&(r=e.className.split(" "));for(var o=0;o=0||e.indexOf(".")>=0))&&(e&&(t=e),e="div"),this.dom=document.createElement(e),t&&(t.indexOf("#")>=0?this.dom.id=t.split("#")[1]:(t.indexOf(".")>=0&&(t=t.split(".")[1]),this.addClass.call(this,t)));!0===n&&(this._frag=document.createDocumentFragment(),this._frag.appendChild(this.dom))}Ee.prototype.createElement=function(e,t){var n=new Ee(e,t,!1);return this.appendElement.call(this,n),this._nodes.push(n),n},Ee.prototype.appendElement=function(e){if(e===undefined)return de({name:"DomElement Add Child",message:"Child Element is undefined"});var t;t=e._frag!==undefined&&null!==e._frag?e._frag:e.dom!==undefined?e.dom:e;try{e instanceof Ee&&(e._parent=this),this.dom.appendChild(t)}catch(dn){de({name:"DomElement Add Child",message:"Failed to append child."})}return this},Ee.prototype.removeElement=function(e){try{var t;if(e._nodes)for(t=e._nodes.length;t--;)e.removeElement(e._nodes[t]);for(t=this._nodes.length;--t>-1;)this._nodes[t]===e&&this._nodes.splice(t,1);this.dom.removeChild(e.dom||e),e.__destroy&&e.__destroy()}catch(dn){de({name:"DomElement Remove Child",message:"Failed to remove child."})}},Ee.prototype.addClass=function(e){return!1===this.hasClass.call(this,e)&&(this._clss.push(e),this.dom.className=this._clss.join(" ")),this},Ee.prototype.hasClass=function(e){for(var t=-1!==this.dom.className.split(" ").indexOf(e),n=this._clss.length;n--&&!t;)t=this._clss[n]===e;return t},Ee.prototype.removeClass=function(e){for(var t=this._clss.length;--t>-1;)this._clss[t]===e&&this._clss.splice(t,1);return this.dom.className=this._clss.join(" "),this},Ee.prototype.text=function(e){if(this&&this.dom){if(!e)return this.dom.textContent;for(var t,n,i,r,o=/&(.*?);/g,a=/<[a-z][\s\S]*>/i;null!==(t=o.exec(e));){!1===a.test(t[0])?(i=t[0],r=void 0,(r=document.createElement("div")).innerHTML=i,n=r.textContent,e=e.replace(new RegExp(t[0],"g"),n)):e=e.replace(t[0],"")}return this.dom.textContent=e,this}},Ee.prototype.content=Ee.prototype.text,Ee.prototype.css=function(e){var t,n="ie"===ae.Browser.type&&8===ae.Browser.version;for(var i in e){t=e[i];try{"opacity"!==i&&"zIndex"!==i&&"fontWeight"!==i&&isFinite(t)&&parseFloat(t)===t&&(t+="px");var r=ke(i);n&&"opacity"===i?this.dom.style.filter="alpha(opacity="+100*t+")":n&&we.hasAlpha(t)?this.dom.style[r]=new we(t).getHex():this.dom.style[r]=t}catch(ln){}}return this},Ee.prototype.backgroundImage=function(e,t,n,i){var r=t!==undefined&&n!==undefined,o={"-ms-high-contrast-adjust":"none"};if("object"==typeof t&&(i=t),i===undefined&&(i={}),r){var a=e.width/e.height,s=t,h=s/a;i.cover&&hn&&(s=(h=n)*a),o.width=s,o.height=h,i.center&&(o.marginLeft=-s/2,o.marginTop=-h/2,o.position="absolute",o.left="50%",o.top="50%"),(i.left||i.right)&&(o.left=i.left||0,o.top=i.top||0)}"ie"===ae.Browser.type&&8===ae.Browser.version?o.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+e.src+"',sizingMethod='scale')":(o.background="url("+e.src+")",o.backgroundPosition="50% 50%",o.backgroundRepeat="no-repeat",o.backgroundSize=r?s+"px "+h+"px":i.cover?"cover":i.contain?"contain":"100%"),this.css.call(this,o)},Ee.prototype.setAttribute=function(e,t){var n;if("object"==typeof e)for(var i in e)n=e[i],this.dom.setAttribute(i,n);else this.dom.setAttribute(e,t)},Ee.prototype.removeAttribute=function(e,t){var n;if("object"==typeof e)for(var i in e)n=e[i],this.dom.removeAttribute(i,n);else this.dom.removeAttribute(e,t)},Ee.prototype.addEventListener=function(e,t,n){var i={event:ve.eventName(e),handler:ve.eventCallback(e,t,this.dom),callback:t};this._listeners.push(i),this.dom.addEventListener?this.dom.addEventListener(i.event,i.handler,n):this.dom.attachEvent("on"+i.event,i.handler)},Ee.prototype.removeEventListener=function(e,t,n){for(var i,r=this._listeners.length;--r>-1;)(i=this._listeners[r]).event===e&&i.callback===t&&(this._listeners.splice(r,1),this.dom.removeEventListener?this.dom.removeEventListener(i.event,i.handler,n):this.dom.detachEvent("on"+i.event,i.handler))},Ee.prototype.focus=function(){this.dom.focus()},Ee.prototype.blur=function(){this.dom.blur()},Ee.prototype.html=function(e){return e&&(this.dom.innerHTML=e),this.dom.innerHTML},Ee.prototype.__destroy=function(){for(var e,t=this._listeners.length;--t>-1;)e=this._listeners[t],this._listeners.splice(t,1),this.dom.removeEventListener?this.dom.removeEventListener(e.event,e.handler):this.dom.detachEvent("on"+e.event,e.handler);return this.dom=null,this._clss=[],this._nodes=[],this._listeners=[],this._frag=null,e=null,null};var Oe=function(e,t){var n={},i=Array.prototype.slice.call(arguments,2);for(var r in t.apply(e,i),e)n[r]=e[r]},Se=function(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e};function Ie(e,t){Oe(this,Ee,t||"div",e),this.children=[],this._events=[]}Se(Ie,Ee),Ie.prototype.initComponent=function(e,t,n){var i=new e(t);return i._parent=this,this.children.push(i),i.dom&&(n!==undefined?n.appendElement&&n.appendElement(i):this.appendElement(i)),i},Ie.prototype.destroy=function(){var e=this;try{V.depth(this,"children",(function(t){if(e!==t)for(var n=e.children.length;--n>-1;)e.children[n]===t&&e.children.splice(n,1);t._destroy&&t._destroy(),t=null}))}catch(dn){throw new Error("Trouble destroying nodes: "+dn)}return null},Ie.prototype._destroy=function(){try{this.onDestroy&&this.onDestroy(),this._parent.removeElement&&this._parent.removeElement(this);for(var e=this._events.length;--e>-1;)this._events.splice(e,1);this.children=null,this._destroy=null,this._events=null,this.destroy=null,this.emit=null,this.on=null,this.off=null,this.initComponent=null}catch(dn){de({name:"DomComponent",message:"Failed to destroy."})}},Ie.prototype.on=function(e,t){for(var n=this._events.length,i=!1;--n>-1&&!1===i;)this._events[n].event===e&&(i=this._events[n]);!1===i&&(i={event:e,listeners:[]},this._events.push(i)),i.listeners.push(t)},Ie.prototype.off=function(e,t){for(var n=this._events.length;--n>-1;)if(this._events[n].event===e){for(var i=this._events[n].listeners.length;--i>-1;)this._events[n].listeners[i]===t&&this._events[n].listeners.splice(i,1);0===this._events[n].listeners.length&&this._events.splice(n,1)}},Ie.prototype.emit=function(e){for(var t=Array.prototype.slice.call(arguments,1),n=this._events.length;--n>-1&&this._events;)if(this._events[n].event===e)for(var i=this._events[n].listeners.length;--i>-1;)this._events[n].listeners[i].apply(this,t)};var Pe={af:"Afrikaans",sq:"Albanian",am:"Amharic",ar:"Arabic",hy:"Armenian",az:"Azerbaijani",eu:"Basque",be:"Belarusian",bn:"Bengali",bg:"Bulgarian",bs:"Bosnian",my:"Burmese",ca:"Catalan",ceb:"Cebuano",zh:"Chinese","zh-CN":"Chinese Simplified","zh-TW":"Chinese Traditional",co:"Corsican",hr:"Croatian",cs:"Czech",da:"Danish",nl:"Dutch",en:"English",eo:"Esperanto",et:"Estonian",fa:"Persian",fi:"Finnish",fr:"French",fy:"Frisian",gd:"Gaelic",gl:"Galacian",ka:"Georgian",de:"German",el:"Greek",gu:"Gujurati",ht:"Haitian",ha:"Hausa",haw:"Hawaiian",he:"Hebrew",hi:"Hindi",hmn:"Hmong",hu:"Hungarian",is:"Icelandic",ig:"Igbo",id:"Indonesian",ga:"Irish",it:"Italian",ja:"Japanese",jw:"Javanese",kn:"Kannada",kk:"Kazakh",km:"Khmer",rw:"Kinyarwanda",ky:"Kirghiz",ko:"Korean",ku:"Kurdish",lo:"Lao",la:"Latin",lv:"Latvian",lt:"Lithuanian",lb:"Luxembourgish",mk:"Macedonian",mg:"Malagasy",ms:"Malay",ml:"Malayalam",mt:"Maltese",mi:"Maori",mr:"Marathi",mn:"Mongolian",ne:"Nepali",no:"Norwegian",ny:"Nyanja",or:"Oriya",pl:"Polish","pt-BR":"Portuguese (Brazil)",pt:"Portuguese (Portugal)",ps:"Pashto",pa:"Punjabi",ro:"Romanian",ru:"Russian",sm:"Samoan",sn:"Shona",sd:"Sindhi",si:"Singhalese",sr:"Serbian",sk:"Slovak",sl:"Slovenian",so:"Somani",st:"Southern Sotho",es:"Spanish",su:"Sundanese",sw:"Swahili",sv:"Swedish",tl:"Tagalog",tg:"Tajik",ta:"Tamil",tt:"Tatar",te:"Teluga",th:"Thai",tr:"Turkish",tk:"Turkmen",ug:"Uyghur",uk:"Ukrainian",ur:"Urdu",uz:"Uzbek",vi:"Vietnamese",cy:"Welsh",xh:"Xhosa",yi:"Yiddish",yo:"Yoruba",zu:"Zulu"},Be={zh:{"I am human":"我是人"},ar:{"I am human":"أنا الإنسان"},af:{"I am human":"Ek is menslike"},am:{"I am human":"እኔ ሰው ነኝ"},hy:{"I am human":"ÔµÕ½ Õ´Õ¡Ö€Õ¤ Õ¥Õ´"},az:{"I am human":"MÉ™n insanam"},eu:{"I am human":"Gizakia naiz"},bn:{"I am human":"আমি মানব নই"},bg:{"I am human":"Аз съм човек"},ca:{"I am human":"Sóc humà "},hr:{"I am human":"Ja sam čovjek"},cs:{"I am human":"Jsem človÄ›k"},da:{"I am human":"Jeg er et menneske"},nl:{"I am human":"Ik ben een mens"},et:{"I am human":"Ma olen inimeste"},fi:{"I am human":"Olen ihminen"},fr:{"I am human":"Je suis humain"},gl:{"I am human":"Eu son humano"},ka:{"I am human":"მე ვარადამიანი"},de:{"I am human":"Ich bin ein Mensch"},el:{"I am human":"Είμαι άνθρωπος"},gu:{"I am human":"હું માનવ છું"},iw:{"I am human":". ×× ×™ ×× ×•×©×™"},hi:{"I am human":"मैं मानव हूं"},hu:{"I am human":"Nem vagyok robot"},is:{"I am human":"Ég er manneskja"},id:{"I am human":"Aku manusia"},it:{"I am human":"Sono un essere umano"},ja:{"I am human":"私は人間です"},kn:{"I am human":"ನಾನು ಮಾನವನು"},ko:{"I am human":"사람입니다"},lo:{"I am human":"ຂ້ອຍເປັນມະນຸດ"},lv:{"I am human":"Es esmu cilvÄ“ks"},lt:{"I am human":"AÅ¡ esu žmogaus"},ms:{"I am human":"Saya manusia"},ml:{"I am human":"ഞാൻ മനുഷ്യനാണ്"},mr:{"I am human":"मी मानवी आहे"},mn:{"I am human":"Би бол хүн"},no:{"I am human":"Jeg er menneskelig"},fa:{"I am human":"من انسانی هستم"},pl:{"I am human":"Jestem czÅ‚owiekiem"},pt:{"I am human":"Sou humano"},ro:{"I am human":"Eu sunt om"},ru:{"I am human":"Я человек"},sr:{"I am human":"Ja sam ljudski"},si:{"I am human":"මම මිනිස්සු"},sk:{"I am human":"Ja som človek"},sl:{"I am human":"Jaz sem človeÅ¡ki"},es:{"I am human":"Soy humano"},sw:{"I am human":"Mimi ni binadamu"},sv:{"I am human":"Jag är människa"},ta:{"I am human":"நான் மனித"},te:{"I am human":"నేను మనిషిని"},th:{"I am human":"ผมมนุษย์"},tr:{"I am human":"Ben bir insanım"},uk:{"I am human":"Я людини"},ur:{"I am human":"میں انسان ہوں"},vi:{"I am human":"Tôi là con người"},zu:{"I am human":"Ngingumuntu"}},Te=null,Me={translate:function(e,t){var n=Me.getBestTrans(Be),i=n&&n[e];if(i=i||e,t)for(var r=Object.keys(t),o=r.length;o--;)i=i.replace(new RegExp("{{"+r[o]+"}}","g"),t[r[o]]);return i},getBestTrans:function(e){var t=Me.getLocale();return t in e?e[t]:Me.getShortLocale(t)in e?e[Me.getShortLocale(t)]:"en"in e?e.en:null},getLocale:function(){var e=Te||window.navigator.userLanguage||window.navigator.language,t=Me.getShortLocale(e);return"in"===t&&(e="id"),"iw"===t&&(e="he"),"nb"===t&&(e="no"),"ji"===t&&(e="yi"),"zh-CN"===e&&(e="zh"),"jv"===t&&(e="jw"),Pe[e]?e:Pe[t]?t:"en"},setLocale:function(e){Te=e},getShortLocale:function(e){return e.indexOf("-")>=0?e.substring(0,e.indexOf("-")):e},isShortLocale:function(e){return 2===e.length||3===e.length},addTable:function(e,t){if(t||(t=Object.create(null)),Be[e]){var n=Be[e];for(var i in t)n[i]=t[i]}else Be[e]=t;return Be[e]},getTable:function(e){return Be[e]},addTables:function(e){for(var t in e)Me.addTable(t,e[t]);return Be},getTables:function(){return Be}};function Ae(e,t){this._period=e,this._interval=t,this._date=[],this._data=[],this._prevTimestamp=0,this._meanPeriod=0,this._meanCounter=0}Ae.prototype.getMeanPeriod=function(){return this._meanPeriod},Ae.prototype.getData=function(){return this._cleanStaleData(),this._data},Ae.prototype.getSize=function(){return this._cleanStaleData(),this._data.length},Ae.prototype.getCapacity=function(){return 0===this._period?this._interval:Math.ceil(this._interval/this._period)},Ae.prototype.push=function(e,t){this._cleanStaleData();var n=0===this._date.length;if(e-(this._date[this._date.length-1]||0)>=this._period&&(this._date.push(e),this._data.push(t)),!n){var i=e-this._prevTimestamp;this._meanPeriod=(this._meanPeriod*this._meanCounter+i)/(this._meanCounter+1),this._meanCounter++}this._prevTimestamp=e},Ae.prototype._cleanStaleData=function(){for(var e=Date.now(),t=this._date.length-1;t>=0;t--){if(e-this._date[t]>=this._interval){this._date.splice(0,t+1),this._data.splice(0,t+1);break}}};var je={touchstart:"ts",touchend:"te",touchmove:"tm",touchcancel:"tc"},$e={mousedown:"md",mouseup:"mu",mousemove:"mm"},Le={keydown:"kd",keyup:"ku"},Re={devicemotion:"dm"},De=function(e,t){var n=$e[e],i=null;return function(e){i=function(e){return[e.windowX,e.windowY,Date.now()]}(e),t(n,i)}},Ne=function(e,t){var n=je[e],i=null;return function(e){i=function(e){var t=[];try{var n,i;if(e.touches&&e.touches.length>=1?n=e.touches:e.changedTouches&&e.changedTouches.length>=1&&(n=e.changedTouches),n){for(var r=0;r-1&&!o;)(o=i[r][1]===n.id)&&(t=i[r][0])}catch(a){t=""}return t}function Ze(e,t){var n=e instanceof HTMLIFrameElement;try{n?e.parentNode&&e.contentWindow.postMessage(JSON.stringify(t),"*"):e.postMessage(JSON.stringify(t),"*")}catch(ln){ue(ln.message,"error","messaging")}}function et(e,t){this.target=e,this.id=t,this.messages=[],this.incoming=[],this.waiting=[]}function tt(e,t){var n=this,i={},r=new Promise((function(e,t){i.resolve=e,i.reject=t})),o={source:"hcaptcha",label:e,id:n.id,promise:null,lookup:t};return r.then((function(e){o.promise="resolve",null!==e&&(o.contents=e),Ze(n.target,o)}))["catch"]((function(e){o.promise="reject",null!==e&&(o.error=e),Ze(n.target,o)})),i}et.prototype.setID=function(e){this.id=e},et.prototype.contact=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");var n=this,i=Date.now().toString(36),r={source:"hcaptcha",label:e,id:this.id,promise:"create",lookup:i};if(t){if("object"!=typeof t)throw new Error("Message must be an object.");r.contents=t}return new Promise((function(t,o){n.waiting.push({label:e,reject:o,resolve:t,lookup:i}),Ze(n.target,r)}))},et.prototype.listen=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");for(var n=this.messages.length,i=!1;--n>-1&&!1===i;)this.messages[n].label===e&&(i=this.messages[n]);!1===i&&(i={label:e,listeners:[]},this.messages.push(i)),i.listeners.push(t)},et.prototype.answer=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");for(var n=this.incoming.length,i=!1;--n>-1&&!1===i;)this.incoming[n].label===e&&(i=this.incoming[n]);!1===i&&(i={label:e,listeners:[]},this.incoming.push(i)),i.listeners.push(t)},et.prototype.send=function(e,t){if(!this.id)throw new Error("Chat requires unique id to communicate between windows");var n={source:"hcaptcha",label:e,id:this.id};if(t){if("object"!=typeof t)throw new Error("Message must be an object.");n.contents=t}Ze(this.target,n)},et.prototype.check=function(e,t){for(var n=[].concat.apply([],[this.messages,this.incoming,this.waiting]),i=[],r=-1;++r-1&&!1===h;)this.waiting[s].label===t.label&&this.waiting[s].lookup===t.lookup&&(h=!0,this.waiting.splice(s,1));continue}for(r=0;r-1&&!1===t;)e.id===nt.chats[n].id&&e.target===nt.chats[n].target&&(t=nt.chats[n],nt.chats.splice(n,1));return t},handle:function(e){var t=e.data;if("string"==typeof t)try{if(!(t.indexOf("hcaptcha")>=0))return;t=JSON.parse(t);for(var n,i=nt.chats,r=-1;++r=0&&(n=t[i]);return n}catch(dn){return""}},hasCookie:function(e){return!!it.getCookie(e)},supportsAPI:function(){try{return"hasStorageAccess"in document&&"requestStorageAccess"in document}catch(dn){return!1}},hasAccess:function(){return new Promise((function(e){document.hasStorageAccess().then((function(){e(!0)}))["catch"]((function(){e(!1)}))}))},requestAccess:function(){try{return document.requestStorageAccess()}catch(dn){return Promise.resolve()}}};function rt(){try{return Object.keys(window).sort().join(",")}catch(dn){return null}}function ot(e,t){for(var n in t){var i=t[n];switch(typeof i){case"string":e[n]=i;break;case"object":e[n]=e[n]||{},ot(e[n],i);break;default:throw new Error("Source theme contains invalid data types. Only string and object types are supported.")}}}function at(e,t){try{return e in t}catch(n){return!1}}function st(e){return!!e&&"object"==typeof e}function ht(e){return st(e)?ct({},e):e}function ct(e,t){var n,i={},r=Object.keys(e);for(n=0;n=0&&wt.use(n.theme),this._state={escaped:!1,passed:!1,expiredChallenge:!1,expiredResponse:!1},this._origData=null,this._promise=null,this._responseTimer=null,this.challenge=new _t(t,n),this.checkbox=new xt(e,t,n),this.initChallenge=this.initChallenge.bind(this),this.closeChallenge=this.closeChallenge.bind(this),this.displayChallenge=this.displayChallenge.bind(this),this.getGetCaptchaManifest=this.getGetCaptchaManifest.bind(this)}function kt(){Oe(this,Ee,"canvas");var e=this;this.element=this.dom,this.ctx=this.element.getContext("2d"),this.scale=1,this.dpr=window.devicePixelRatio||1,this.clearColor="#fff",this.ctx.roundedRect=function(t,n,i,r,o){var a=i>0?o:-o,s=r>0?o:-o;e.ctx.beginPath(),e.ctx.moveTo(t+a,n),e.ctx.lineTo(t+i-a,n),e.ctx.quadraticCurveTo(t+i,n,t+i,n+s),e.ctx.lineTo(t+i,n+r-s),e.ctx.quadraticCurveTo(t+i,n+r,t+i-a,n+r),e.ctx.lineTo(t+a,n+r),e.ctx.quadraticCurveTo(t,n+r,t,n+r-s),e.ctx.lineTo(t,n+s),e.ctx.quadraticCurveTo(t,n,t+a,n),e.ctx.closePath()}}function Et(e){e=e||{},this.x=e.x||0,this.y=e.y||0,this.rotate=this.rotate.bind(this),this.getDistance=this.getDistance.bind(this),this.radius=0,this.tolerance=0,this.fill=!1,this.stroke=!1,this.fillColor="#fff",this.strokeColor="#fff",this.strokeWidth=1}function Ot(e,t,n){Oe(this,Et,e),this.handleIn=new Et(t),this.handleOut=new Et(n),this.prev=null,this.next=null,this.index=0}function St(e){if(null===e)return"";var t=[];return It(e,t),t.join("&")}function It(e,t){var n,i;if("object"==typeof e)for(i in e)!0===Pt(n=e[i])?It(n,t):t[t.length]=Bt(i,n);else if(!0===Array.isArray(e))for(var r=0;rn.clientHeight,c=a?(r-this.width)/2:e.bounding.left+e.tick.right+10;(c+this.width+t>r||c<0)&&(c=(r-this.width)/2,a=!0);var l=(n.scrollHeight=i+o&&(d=i+o-(this.height+t)),d=Math.max(Math.min(d,l),10);var u=e.bounding.top+e.tick.y+i-d-10,p=this.height-10-30;return u=Math.max(Math.min(u,p),t),this.$container.css({left:c,top:d}),this.$arrow.fg.css({display:a?"none":"block"}),this.$arrow.bg.css({display:a?"none":"block"}),this.$arrow.css({top:u}),this.top=d,this.$container.dom.getBoundingClientRect(),h}},_t.prototype.destroy=function(){this._visible&&this.close.call(this),this._hasCustomContainer?this._parent.removeChild(this.$iframe.dom):(this._parent.removeChild(this.$container.dom),this.$container=this.$container.__destroy()),this.$iframe=this.$iframe.__destroy(),nt.removeChat(this.chat),this.chat=this.chat.destroy()},_t.prototype.setReady=function(e){if(this.ready=e,this.ready)for(var t,n=this.listeners.length;--n>-1;)t=this.listeners[n],this.listeners.splice(n,1),t()},_t.prototype.onReady=function(e){var t=Array.prototype.slice.call(arguments,1),n=function(){e.apply(null,t)};this.ready?n():this.listeners.push(n)},_t.prototype.onOverlayClick=function(e){this._hasCustomContainer||this.$overlay.addEventListener("click",e)},_t.prototype.setConfig=function(e){return this.chat?this.chat.contact("challenge-update",e):Promise.resolve()},_t.prototype.setData=function(e){this.chat&&this.chat.send("challenge-data",e)},xt.prototype.setResponse=function(e){this.response=e,this.$iframe.dom.setAttribute("data-hcaptcha-response",e),"off"!==he.recaptchacompat&&(this.$textArea0.dom.value=e),this.$textArea1.dom.value=e},xt.prototype.style=function(){switch(this.config.size){case"compact":this.$iframe.css({width:164,height:144});break;case"invisible":this.$iframe.css({display:"none"});break;default:this.$iframe.css({width:303,height:78,overflow:"hidden"})}},xt.prototype.reset=function(){this._ticked=!1,this.chat&&this.chat.send("checkbox-reset")},xt.prototype.clearLoading=function(){this.chat&&this.chat.send("checkbox-clear")},xt.prototype.sendTranslation=function(e){var t={locale:e,table:Me.getTable(e)||{}};this.chat&&this.chat.send("checkbox-translate",t)},xt.prototype.status=function(e,t){this.chat&&this.chat.send("checkbox-status",{text:e||null,a11yOnly:t||!1})},xt.prototype.tick=function(){this._ticked=!0,this.chat&&this.chat.send("checkbox-tick")},xt.prototype.getTickLocation=function(){return this.chat.contact("checkbox-location")},xt.prototype.getOffset=function(){var e=this.$iframe.dom;e.offsetParent||(e=e.parentElement);for(var t=0,n=0;e;)t+=e.offsetLeft,n+=e.offsetTop,e=e.offsetParent;return{top:n,left:t}},xt.prototype.getBounding=function(){return this.$iframe.dom.getBoundingClientRect()},xt.prototype.destroy=function(){this._ticked&&this.reset(),this.$container.removeElement(this.$iframe),this.$container.removeElement(this.$textArea1),"off"!==he.recaptchacompat&&(this.$container.removeElement(this.$textArea0),this.$textArea0=this.$textArea0.__destroy()),this.$textArea1=this.$textArea1.__destroy(),this.$container=this.$container.__destroy(),this.$iframe=this.$iframe.__destroy(),nt.removeChat(this.chat),this.chat=this.chat.destroy()},Ct.prototype._resetTimer=function(){null!==this._responseTimer&&(clearTimeout(this._responseTimer),this._responseTimer=null)},Ct.prototype.initChallenge=function(e){e||(e={}),this._origData=e;var t=this.getGetCaptchaManifest(),n=e.charity||null,i=e.a11yChallenge||!1,r=e.link||null,o=e.action||"",a=e.rqdata||null,s=ae.Browser.width(),h=ae.Browser.height();this._active=!0,this._resetTimer(),this._resetState(),this.checkbox.setResponse(""),this.challenge.setup({a11yChallenge:i,manifest:t,width:s,height:h,charity:n,link:r,action:o,rqdata:a,wdata:rt()})},Ct.prototype.getGetCaptchaManifest=function(){var e=(this._origData||{}).manifest||null;return e||((e=Object.create(null)).st=Date.now()),e.v=1,e.topLevel=Ue.getData(),e.session=Y.getSession(),e.widgetList=Y.getCaptchaIdList(),e.widgetId=this.id,e.href=window.location.href,e.prev=JSON.parse(JSON.stringify(this._state)),e},Ct.prototype.displayChallenge=function(e){if(this._active){var t=this;this.visible=!0;var n=this.checkbox,i=this.challenge,r=ae.Browser.height();if(!("ie"===ae.Browser.type&&8===ae.Browser.version)){var o=window.getComputedStyle(document.body).getPropertyValue("overflow-y");this.overflow.override="hidden"===o,this.overflow.override&&(this.overflow.cssUsed=""===document.body.style.overflow&&""===document.body.style.overflowY,this.overflow.cssUsed||(this.overflow.value=""===o?"auto":o),this.overflow.scroll=ae.Browser.scrollY(),document.body.style.overflowY="auto")}return new Promise((function(o){n.status(),n.getTickLocation().then((function(a){if(t._active){if(i.size(e.width,e.height,e.mobile),i.show(),n.clearLoading(),n.location.bounding=n.getBounding(),n.location.tick=a,n.location.offset=n.getOffset(),i.position(n.location))(window.document.scrollingElement||document.getElementsByTagName("html")[0]).scrollTop=Math.abs(i.height-r)+i.top;o()}}))})).then((function(){t.onOpen&&me(t.onOpen)}))}},Ct.prototype.resize=function(e,t,n){var i=this,r=this.checkbox,o=this.challenge;o.getDimensions(e,t).then((function(e){e&&o.size(e.width,e.height,e.mobile),r.location.bounding=r.getBounding(),r.location.offset=r.getOffset(),ae.System.mobile&&!n||o.position(r.location)}))["catch"]((function(e){i.closeChallenge.call(i,{event:R,message:"Captcha resize caused error.",error:e})}))},Ct.prototype.position=function(){var e=this.checkbox,t=this.challenge;ae.System.mobile||(e.location.bounding=e.getBounding(),t.position(e.location))},Ct.prototype.reset=function(){this.checkbox.reset(),this.checkbox.setResponse(""),this._resetTimer(),this._resetState()},Ct.prototype._resetState=function(){for(var e in this._state)this._state[e]=!1},Ct.prototype.closeChallenge=function(e){this.visible=!1,this._active=!1;var t=this,n=this.checkbox,i=this.challenge;this.overflow.override&&((window.document.scrollingElement||document.getElementsByTagName("html")[0]).scrollTop=this.overflow.scroll,this.overflow.override=!1,this.overflow.scroll=0,document.body.style.overflowY=this.overflow.cssUsed?null:this.overflow.value);var r=e.response||"";switch(n.setResponse(r),i.close(e.event),n.$iframe.dom.focus(),e.event){case B:this._state.escaped=!0,n.reset(),t.onClose&&me(t.onClose),t._promise&&t._promise.reject(T);break;case M:this._state.expiredChallenge=!0,n.reset(),n.status("hCaptcha window closed due to timeout.",!0),t.onChalExpire&&me(t.onChalExpire),t._promise&&t._promise.reject(M);break;case R:case j:case $:var o=e.event;n.reset(),e.event===$?(n.status(e.message),429===e.status?o=L:"invalid-data"===e.message&&(o=A)):e.event===j?o=R:e.event===R&&"Answers are incomplete"===e.message&&(o=D),this.onError&&me(this.onError,o),t._promise&&t._promise.reject(o);break;case P:this._state.passed=!0,n.tick(),this.onPass&&me(this.onPass,r),t._promise&&t._promise.resolve({response:r,key:Ke(this.id)}),"number"==typeof e.expiration&&(t._resetTimer(),t._responseTimer=setTimeout((function(){try{n.reset(),n.setResponse(""),n.status("hCaptcha security token has expired. Please complete the challenge again.",!0)}catch(dn){ue("Checkbox not present or could not destroy on expiration: "+dn.message,"error","global")}t.onExpire&&me(t.onExpire),t._responseTimer=null,t._state.expiredResponse=!0}),1e3*e.expiration))}t._promise=null},Ct.prototype.updateTranslation=function(e){this.checkbox.sendTranslation(e),this.challenge.sendTranslation(e)},Ct.prototype.isReady=function(){return this._ready},Ct.prototype.setReady=function(e){if(this._ready=e,this._ready)for(var t,n=this._listeners.length;--n>-1;)t=this._listeners[n],this._listeners.splice(n,1),t()},Ct.prototype.setPromise=function(e){this._promise=e},Ct.prototype.onReady=function(e){var t=Array.prototype.slice.call(arguments,1),n=function(){e.apply(null,t)};this._ready?n():this._listeners.push(n)},Ct.prototype.destroy=function(){(this._resetTimer(),this.overflow.override)&&((window.document.scrollingElement||document.getElementsByTagName("html")[0]).scrollTop=this.overflow.scroll,this.overflow.override=!1,this.overflow.scroll=0,document.body.style.overflowY=this.overflow.cssUsed?null:this.overflow.value);this.challenge.destroy(),this.checkbox.destroy(),this.challenge=null,this.checkbox=null},Ct.prototype.setSiteConfig=function(e){var t=e&&e.features&&e.features.custom_theme;if(this.config.themeConfig&&t){var n="custom-"+this.id;wt.add(n,wt.extend(wt.active(),this.config.themeConfig)),wt.use(n),this.challenge.style()}return this.challenge.setConfig({siteConfig:e,wdata:rt()})},Se(kt,Ee),kt.prototype.dimensions=function(e,t){this.css({width:e,height:t}),this.element.width=Math.round(e/this.scale)*this.dpr,this.element.height=Math.round(t/this.scale)*this.dpr,this.ctx.scale(this.dpr,this.dpr),this.width=Math.round(e/this.scale),this.height=Math.round(t/this.scale)},kt.prototype.clear=function(){this.ctx&&this.ctx.clearRect(0,0,this.element.width,this.element.height)},kt.prototype.draw=function(){this.ctx&&(this.ctx.fillStyle=this.clearColor,this.ctx.fillRect(0,0,this.element.width,this.element.height))},kt.prototype._destroy=function(){this.__destroy(),this.element=null,this.ctx=null,this.width=null,this.height=null},Et.prototype.rotate=function(e,t){var n=function(e){return e*(Math.PI/180)}(t),i=Math.sin(n),r=Math.cos(n),o=this.x-e.x,a=this.y-e.y;this.x=o*r-a*i+e.x,this.y=o*i+a*r+e.y},Et.prototype.getDistance=function(e){return Math.sqrt(Math.pow(this.x-e.x,2)+Math.pow(this.y-e.y,2))},Et.prototype.getAngle=function(e){var t=e.x-this.x,n=e.y-this.y,i=180*Math.atan2(n,t)/Math.PI;return i<0&&(i+=360),i},Et.prototype.hitTest=function(e){return this.radius+this.tolerance>=this.getDistance(e)},Et.prototype.restrict=function(e,t,n,i){if("x"!==e&&"y"!==e)throw new Error("Point.restrict requires a value: x or y");return t+this[e]i&&(t=i-this[e]),this[e]+t},Et.prototype.draw=function(e){e.ctx.beginPath(),e.ctx.arc(this.x,this.y,this.radius/e.scale,0,2*Math.PI,!1),this.fill&&(e.ctx.fillStyle=this.fillColor,e.ctx.fill()),this.stroke&&(e.ctx.strokeStyle=this.strokeColor,e.ctx.lineWidth=this.strokeWidth/e.scale,e.ctx.stroke())},Se(Ot,Et),Ot.prototype.set=function(e,t,n){this.x=e.x||this.x,this.y=e.y||this.y,t===undefined?(this.handleIn.x=this.x,this.handleIn.y=this.y):(this.handleIn.x=t.x,this.handleIn.y=t.y),n===undefined?(this.handleOut.x=this.x,this.handleOut.y=this.y):(this.handleOut.x=n.x,this.handleOut.y=n.y)},Ot.prototype.clone=function(){var e={x:this.x,y:this.y},t={x:this.handleIn.x,y:this.handleIn.y},n={x:this.handleOut.x,y:this.handleOut.y},i=new Ot;return t.x===n.x&&t.y===n.y?i.set(e):i.set(e,t,n),i.index=this.index,i.prev=this.prev,i.next=this.next,i.radius=this.radius,i.tolerance=this.tolerance,i.fill=this.fill,i.stroke=this.stroke,i.fillColor=this.fillColor,i.strokeColor=this.strokeColor,i.strokeWidth=this.strokeWidth,i},Ot.prototype.move=function(e,t){this.x+=e,this.y+=t,this.handleIn.x+=e,this.handleIn.y+=t,this.handleOut.x+=e,this.handleOut.y+=t},Ot.prototype.render=function(e){this.handleIn.x!==this.x&&this.handleIn.y!==this.y&&this.handleIn.draw(e),this.handleOut.x!==this.x&&this.handleOut.y!==this.y&&this.handleOut.draw(e),this.draw(e)};var Tt={400:"Rate limited or network error. Please retry.",429:"Your computer or network has sent too many requests.",500:"Cannot contact hCaptcha. Check your connection and try again."},Mt=function(e){try{return Me.translate(Tt[e])}catch(dn){return!1}},At="undefined"!=typeof XDomainRequest&&!("withCredentials"in XMLHttpRequest.prototype);function jt(e,t,n){n=n||{};var i={url:t,method:e.toUpperCase(),responseType:n.responseType||"string",dataType:n.dataType||null,withCredentials:n.withCredentials||!1,headers:n.headers||null,data:n.data||null,timeout:n.timeout||null};return i.legacy=i.withCredentials&&At,i.data&&("json"===i.dataType&&"object"==typeof i.data&&(i.data=JSON.stringify(i.data)),"query"===i.dataType&&(i.data=St(i.data))),n.retry?ye((function(){return $t(i)}),n.retry):$t(i)}function $t(e){var t=e.legacy?new XDomainRequest:new XMLHttpRequest,n="function"==typeof e.url?e.url():e.url;return new Promise((function(i,r){var o,a=function(o){return function(){var a=t.response||t.responseText,s=t.statusText||"",h=t.status,c=t.readyState;if(4===c||e.legacy){if("json"===e.responseType&&a)try{a=JSON.parse(a)}catch(l){}if("error"===o||h>=400&&h<=511)return void r({event:$,endpoint:n,response:a,state:c,status:h,message:Mt(h||400)||s});i({state:c,status:h,body:a,message:s})}}};if((t.onload=a("complete"),t.onerror=t.ontimeout=a("error"),t.open(e.method,n),e.timeout&&(t.timeout=e.timeout),!e.legacy)&&(t.withCredentials=e.withCredentials,e.headers))for(var s in e.headers)o=e.headers[s],t.setRequestHeader(s,o);setTimeout((function(){t.send(e.data)}),0)}))}var Lt=function(e,t){if("object"==typeof e&&t===undefined&&(e=(t=e).url),null===e)throw new Error("Url missing");return jt("GET",e,t)},Rt=function(e){return e.toLowerCase().match(/\.(?:jpg|gif|png|jpeg|svg)$/g)?"image":e.toLowerCase().match(/\.(?:js)$/g)?"script":"file"},Dt=function(e){if(he.assethost&&e.indexOf(se.assetDomain)>=0)return he.assethost+e.replace(se.assetDomain,"");if(he.imghost&&e.indexOf("imgs")>=0){var t=e.indexOf(".ai")>=0?e.indexOf(".ai")+3:e.indexOf(".com")+4;return he.imghost+e.substr(t,e.length)}return e},Nt=["svg","gif","png"];function zt(e,t){t=t||{};var n,i=e;if(0===i.indexOf("data:image"))for(var r=!1,o=Nt.length,a=-1;a++=0)&&(n=Nt[a]);else n=i.substr(i.lastIndexOf(".")+1,i.length);!!(!document.createElementNS||!document.createElementNS("https://www.w3.org/2000/svg","svg").createSVGRect)&&t.fallback&&(t.fallback.indexOf(".")>=0?n=(i=t.fallback).substr(i.lastIndexOf(".")+1,i.length):(i=e.substr(0,e.indexOf(n))+t.fallback,n=t.fallback)),t.prefix&&(i=t.prefix+"/"+i),this.attribs={crossOrigin:t.crossOrigin||null},this.id=i,this.src=Dt(i),this.ext=n,this.width=0,this.height=0,this.aspect=0,this.loaded=!1,this.error=!1,this.element=null,this.cb={load:[],error:[]}}function Wt(e,t,n){for(var i=e[t],r=i.length,o=null;--r>-1;)o=i[r],i.splice(r,1),o(n);"error"===t?e.load=[]:e.error=[]}function Ft(e,t){var n=e;t||(t={}),t.prefix&&(n=t.prefix+"/"+e),this.attribs={defer:t.defer||null,async:t.async||null,crossOrigin:t.crossOrigin||null},this.id=n,this.src=Dt(n),this.loaded=!1,this.error=!1,this.element=null,this.cb={load:[],error:[]}}function Ut(e,t,n){for(var i=e[t],r=i.length,o=null;--r>-1;)o=i[r],i.splice(r,1),o(n);"error"===t?e.load=[]:e.error=[]}function Jt(e,t){var n=e;t||(t={}),t.prefix&&(n=t.prefix+"/"+e),this.id=n,this.src=Dt(n),this.loaded=!1,this.error=!1,this.cb={load:[],error:[]},this.data=null}function Ht(e,t,n){for(var i=e[t],r=i.length,o=null;--r>-1;)o=i[r],i.splice(r,1),o(n);"error"===t?e.load=[]:e.error=[]}zt.prototype.load=function(){return("svg"===this.ext?this._loadSvg():this._loadImg())["catch"]((function(e){throw ue("Asset failed","error","assets",{error:e}),e}))},zt.prototype._loadSvg=function(){var e,t=this,n=this.src,i=this.id;if(0===n.indexOf("data:image/svg+xml")){var r=n.slice("data:image/svg+xml,".length);e=Promise.resolve(decodeURIComponent(r))}else e=Lt(n).then((function(e){return e.body}));return e.then((function(e){var n=(new DOMParser).parseFromString(e,"image/svg+xml").documentElement,i=parseInt(n.getAttribute("width")),r=parseInt(n.getAttribute("height"));return t._imgLoaded(n,i,r),t}))["catch"]((function(e){t.error=!0;var n=(e&&e.message?e.message:"Loading Error")+": "+i;throw Wt(t.cb,"error",n),n}))},zt.prototype._loadImg=function(){var e=this,t=this.attribs,n=this.src,i=this.id;return new Promise((function(r,o){var a=new Image;t.crossOrigin&&(a.crossOrigin=t.crossOrigin),a.onerror=function(t){e.error=!0,a.onload=a.onerror=null;var n=(t&&t.message?t.message:"Loading Error")+": "+i;Wt(e.cb,"error",n),o(n)},a.onload=function(){e.loaded||(e._imgLoaded(a,a.width,a.height),a.onload=a.onerror=null,r(e))},a.src=n,a.complete&&a.onload()}))},zt.prototype._imgLoaded=function(e,t,n){this.element=new Ee(e),this.width=t,this.height=n,this.aspect=t/n,this.loaded=!0,Wt(this.cb,"load",this)},zt.prototype.onload=function(e){this.error||(this.loaded?e(this):this.cb.load.push(e))},zt.prototype.onerror=function(e){this.loaded&&!this.error||(this.error?e(this):this.cb.error.push(e))},Ft.prototype.load=function(){var e=this,t=this.attribs,n=this.src,i=this.id;return new Promise((function(r,o){var a=document.createElement("script");e.element=a,a.onerror=function(t){e.error=!0,a.onload=a.onreadystatechange=a.onerror=null;var n=(t.message||"Loading Error")+": "+i;Ut(e.cb,"error",n),o(n)},a.onload=a.onreadystatechange=function(){this.loaded||a.readyState&&"loaded"!==a.readyState&&"complete"!==a.readyState||(e.loaded=!0,a.onload=a.onreadystatechange=a.onerror=null,document.body.removeChild(a),Ut(e.cb,"load",e),r(e))},a.type="text/javascript",a.src=n,t.crossOrigin&&(a.crossorigin=t.crossOrigin),t.async&&(a.async=!0),t.defer&&(a.defer=!0),document.body.appendChild(a),a.complete&&a.onload()}))},Ft.prototype.onload=function(e){this.error||(this.loaded?e(this):this.cb.load.push(e))},Ft.prototype.onerror=function(e){this.loaded&&!this.error||(this.error?e(this):this.cb.error.push(e))},Jt.prototype.load=function(){var e=this,t=this.src,n=this.id;return new Promise((function(i,r){var o={};t.indexOf("json")>=0&&(o.responseType="json"),Lt(t,o).then((function(t){e.loaded=!0,e.data=t.body,Ht(e.cb,"load",e),i(e)}))["catch"]((function(t){e.error=!0;var i=(t&&t.message?t.message:"Loading Error")+": "+n;Ht(e.cb,"error",i),r(i)}))}))},Jt.prototype.onload=function(e){this.error||(this.loaded?e(this):this.cb.load.push(e))},Jt.prototype.onerror=function(e){this.loaded&&!this.error||(this.error?e(this):this.cb.error.push(e))};var qt=[],Xt={add:function(e,t){var n=Rt(e);return Xt[n]?Xt[n](e,t):Promise.resolve(null)},batch:function(e,t){for(var n=[],i=-1;++i-1&&!r;)r=(o=qt[i]).id===e||-1!==o.id.indexOf("/"===e[0]?"":"/"+e);if(!r)return t(null);o.onload(t),o.onerror(n)}))}};function Yt(e){if("en"===e)return Promise.resolve();var t=e+".json";return new Promise((function(n,i){Xt.retrieve(t).then((function(n){return n||Xt.file(t,{prefix:"https://newassets.hcaptcha.com/captcha/v1/e09e16a/static/i18n"}).then((function(t){return Me.addTable(e,t.data),t}))})).then((function(e){n(e.data)}))["catch"]((function(e){i(e)}))}))}var Gt=0,Vt=["hl","custom","tplinks","sitekey","theme","size","tabindex","challenge-container"];var Qt={render:function(e,t){if("string"==typeof e&&(e=document.getElementById(e)),e&&1===e.nodeType)if(function(e){if(!e||!("challenge-container"in e))return!0;var t=e["challenge-container"];return"string"==typeof t&&(t=document.getElementById(t)),!!t&&1===t.nodeType}(t)){if(!1!==nt.isSupported()){for(var n,i,r=e.getElementsByTagName("iframe"),o=-1;++oupgrade your browser or enable it for hCaptcha.com")}else console.log("[hCaptcha] render: invalid challenge container '"+t["challenge-container"]+"'.");else console.log("[hCaptcha] render: invalid container '"+e+"'.");function v(e,t){var n=e.locale;function i(e){if(e)try{e.updateTranslation(n)}catch(ln){ue("Failed to update text translation: "+JSON.stringify(ln),"error","translation")}}n&&Yt(n).then((function(){t?i(g):Y.each(i)}))["catch"]((function(e){ue("Language failed to load: "+n,"error","api")}))}},reset:function(e){var t;if(e){if(!(t=Y.getById(e)))throw new U(e);t.reset()}else{if(!(t=Y.getByIndex(0)))throw new J;t.reset()}},remove:function(e){var t=e?Y.getById(e):Y.getByIndex(0);if(!t)throw e?new U(e):new J;Y.remove(t),t.destroy(),t=null},execute:Qe,getResponse:function(e){var t,n;if((n=e?Y.getById(e):Y.getByIndex(0))&&(t=n.checkbox.response||""),void 0!==t)return t;throw e?new U(e):new J},getRespKey:Ke,close:function(e){var t=!1;if(!(t=e?Y.getById(e):Y.getByIndex(0)))throw e?new U(e):new J;t.closeChallenge({event:B})},setData:function(e,t){if("object"!=typeof e||t||(t=e,e=null),!t||"object"!=typeof t)throw Error("[hCaptcha] invalid data supplied");var n=!1;if(!(n=e?Y.getById(e):Y.getByIndex(0)))throw e?new U(e):new J;var i=n.challenge.setData.bind(n.challenge);n.onReady(i,t)},nodes:Y};se.file="hcaptcha";var Kt=document.currentScript,Zt=!1,en=!1,tn="on",nn=ae.Browser.width()/ae.Browser.height(),rn=window.hcaptcha||!1;function on(){var e=ae.Browser.width(),t=ae.Browser.height(),n=ae.System.mobile&&nn!==e/t;nn=e/t,hn(),Qt.nodes.each((function(i){i.visible&&i.resize(e,t,n)}))}function an(e){e.preventDefault&&e.preventDefault(),sn(),Qt.nodes.each((function(e){e.visible&&e.position()}))}function sn(){Ue.circBuffPush("xy",[ae.Browser.scrollX(),ae.Browser.scrollY(),document.documentElement.clientWidth/ae.Browser.width(),Date.now()])}function hn(){Ue.circBuffPush("wn",[ae.Browser.width(),ae.Browser.height(),ae.System.dpr(),Date.now()])}!function(e){var t=Array.prototype.slice.call(arguments,1);!0!==qe&&"interactive"!==document.readyState&&"loaded"!==document.readyState&&"complete"!==document.readyState?(Je.push({fn:e,args:t}),!1===He&&Xe()):setTimeout((function(){e(t)}),1)}((function(){rn||(!function(){var e;e=Kt?[Kt]:document.getElementsByTagName("script");var t=-1,n=!1,i=null,r=null;for(;++t=0?e.split("&"):[e]:[],a=0;a=0){if(t=o[a].split("="),n=decodeURIComponent(t[0]),"false"!==(i=decodeURIComponent(t[1]))&&"true"!==i||(i="true"===i),"theme"===n||"themeConfig"===n)try{i=JSON.parse(i)}catch(dn){}r[n]=i}return r}(i[1]);Zt=o.onload||!1,en=o.render||!1,"off"===o.tplinks&&(tn="off");he.tplinks=tn,he.language=o.hl||null,o.endpoint&&(he.endpointOverride=o.endpoint);he.reportapi=o.reportapi||he.reportapi,he.imghost=o.imghost||null,he.custom=o.custom||he.custom,he.se=o.se||null,he.assethost=o.assethost||null,he.assethost&&!ge.URL(he.assethost)&&(he.assethost=null,console.error("Invalid assethost uri."));he.recaptchacompat=o.recaptchacompat||he.recaptchacompat,se.host=o.host||window.location.hostname,he.language=he.language||window.navigator.userLanguage||window.navigator.language,Me.setLocale(he.language),a=o.sentry===undefined||o.sentry,void(le=a),"off"===he.recaptchacompat?console.log("recaptchacompat disabled"):window.grecaptcha=cn;var a}(),function(){var e=Me.getLocale();if(e.indexOf("en")>=0)return;Yt(e).then((function(){Qt.nodes.each((function(t){if(t)try{t.updateTranslation(e)}catch(ln){ue("Failed to update text translation: "+JSON.stringify(ln),"error","translation")}}))}))["catch"]((function(){ue("Language failed to load: "+e,"error","api")}))}(),!1===en||"onload"===en?function(e){for(var t=document.getElementsByClassName("h-captcha"),n=[],i=0;i {}) { - const xhr = new XMLHttpRequest(); - const url = `/lottery/${uri}`; - xhr.open(method, url); - xhr.onload = handleLotteryResponse.bind(null, xhr, method, callback); - const form = new FormData(); form.append("formkey", formkey()); - form.append("quantity", purchaseQuantity) - - xhr.send(form); + form.append("quantity", purchaseQuantity); + const xhr = createXhrWithFormKey(`/lottery/${uri}`, method, form); + xhr[0].onload = handleLotteryResponse.bind(null, xhr[0], method, callback); + xhr[0].send(xhr[1]); } function handleLotteryResponse(xhr, method, callback) { diff --git a/files/assets/js/pinpost.js b/files/assets/js/pinpost.js new file mode 100644 index 000000000..32c36ab6d --- /dev/null +++ b/files/assets/js/pinpost.js @@ -0,0 +1,27 @@ +function pinPost(t, id) { + t.disabled = true; + t.classList.add("disabled"); + post_toast_callback(`/sticky/${id}`, + { + }, + (xhr) => { + if (xhr.status >= 200 && xhr.status < 300) { + response = JSON.parse(xhr.response); + length = response["length"]; + if (length == "permanently") { + t.innerHTML = t.innerHTML.replace(t.textContent, 'Pin for 1 hour'); + t.classList.add('d-none'); + } else { + t.innerHTML = t.innerHTML.replace(t.textContent, 'Pin permanently'); + } + t.nextElementSibling.classList.remove('d-none'); + t.disabled = false; + t.classList.remove("disabled"); + } + } + ); + setTimeout(() => { + t.disabled = false; + t.classList.remove("disabled"); + }, 2000); +} diff --git a/files/assets/js/report_post_modal.js b/files/assets/js/report_post_modal.js index 555599e74..ebb51bff3 100644 --- a/files/assets/js/report_post_modal.js +++ b/files/assets/js/report_post_modal.js @@ -39,14 +39,8 @@ function report_postModal(id) { let data try {data = JSON.parse(xhr.response)} catch(e) {console.log(e)} - if (xhr.status >= 200 && xhr.status < 300 && data && data['message']) { - document.getElementById('toast-post-success-text').innerText = data["message"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')).show(); - } else { - document.getElementById('toast-post-error-text').innerText = "Error, please try again later." - if (data && data["error"]) document.getElementById('toast-post-error-text').innerText = data["error"]; - bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')).show(); - } + success = xhr.status >= 200 && xhr.status < 300; + showToast(success, getMessageFromJsonData(success, data)); }; xhr.onerror=function(){alert(errortext)}; diff --git a/files/assets/js/settings_blocks.js b/files/assets/js/settings_blocks.js index af1269b38..2b928e5f3 100644 --- a/files/assets/js/settings_blocks.js +++ b/files/assets/js/settings_blocks.js @@ -1,13 +1,8 @@ function block_user() { - var usernameField = document.getElementById("exile-username"); - var isValidUsername = usernameField.checkValidity(); - username = usernameField.value; - if (isValidUsername) { - const xhr = new XMLHttpRequest(); xhr.open("post", "/settings/block"); xhr.setRequestHeader('xhr', 'xhr'); @@ -19,11 +14,7 @@ function block_user() { location.reload(); } else { - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')); - myToast.hide(); - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')); - myToast.show(); - document.getElementById("toast-error-message").textContent = "Error. Please try again later."; + showToast(false, "Error, please try again later."); } } xhr.send(f) diff --git a/files/assets/js/settings_profile.js b/files/assets/js/settings_profile.js index 11ba72ab2..a9c81d264 100644 --- a/files/assets/js/settings_profile.js +++ b/files/assets/js/settings_profile.js @@ -87,7 +87,14 @@ function updatebgselection(){ document.onpaste = function(event) { var focused = document.activeElement; if (focused.id == 'bio-text') { - files = event.clipboardData.files + const files = event.clipboardData.files + + if (files.length > 4) + { + alert("You can't upload more than 4 files at one time!") + return + } + if (files.length) { f=document.getElementById('file-upload'); diff --git a/files/assets/js/signup.js b/files/assets/js/signup.js index a05318540..c03fc5640 100644 --- a/files/assets/js/signup.js +++ b/files/assets/js/signup.js @@ -18,7 +18,7 @@ document.getElementById('username-register').addEventListener('input', function const userName = document.getElementById("username-register").value; const id = document.getElementById("usernameHelpRegister"); - if (/[^a-zA-Z0-9_\-$]/.test(userName)) { + if (/[^a-zA-Z0-9_\-$]/.test(userName) && false) { id.innerHTML = 'No special characters or spaces allowed.'; } else { id.innerHTML = 'Username is a-okay!'; @@ -38,4 +38,4 @@ document.getElementById('username-register').addEventListener('input', function }) } } -}); \ No newline at end of file +}); diff --git a/files/assets/js/submission_admin.js b/files/assets/js/submission_admin.js new file mode 100644 index 000000000..f85c8e310 --- /dev/null +++ b/files/assets/js/submission_admin.js @@ -0,0 +1,31 @@ +function removePost(t,post_id,button1,button2,cls) { + url="/remove_post/"+post_id + + post_toast(t,url,button1,button2,cls) + + if (window.location.pathname == '/admin/reported/posts') + { + document.getElementById("flaggers-"+post_id).remove() + document.getElementById("post-"+post_id).remove() + } + else + { + document.getElementById("post-"+post_id).classList.add("banned"); + } +}; + +function approvePost(t,post_id,button1,button2,cls) { + url="/approve_post/"+post_id + + post_toast(t,url,button1,button2,cls) + + if (window.location.pathname == '/admin/reported/posts') + { + document.getElementById("flaggers-"+post_id).remove() + document.getElementById("post-"+post_id).remove() + } + else + { + document.getElementById("post-"+post_id).classList.remove("banned"); + } +} diff --git a/files/assets/js/submit.js b/files/assets/js/submit.js index ef0bc80b3..d9afeffcb 100644 --- a/files/assets/js/submit.js +++ b/files/assets/js/submit.js @@ -55,6 +55,12 @@ function hide_image() { document.onpaste = function(event) { files = event.clipboardData.files + if (files.length > 4) + { + alert("You can't upload more than 4 files at one time!") + return + } + filename = files[0] if (filename) @@ -80,9 +86,10 @@ document.onpaste = function(event) { fileReader.addEventListener("load", function () {document.getElementById('image-preview').setAttribute('src', this.result);}); } document.getElementById('file-upload').setAttribute('required', 'false'); + document.getElementById('post-url').value = null; + localStorage.setItem("post-url", "") + document.getElementById('image-upload-block').classList.remove('d-none') } - document.getElementById('post-url').value = null; - localStorage.setItem("post-url", "") checkForRequired(); } } @@ -157,8 +164,9 @@ function checkRepost() { const system = document.getElementById('system') system.innerHTML = `To post an image, use a direct image link such as i.imgur.com`; const url = document.getElementById('post-url').value + const min_repost_check = 9; - if (url) { + if (url && url.length >= min_repost_check) { const xhr = new XMLHttpRequest(); xhr.open("post", "/is_repost"); xhr.setRequestHeader('xhr', 'xhr'); @@ -189,4 +197,4 @@ document.addEventListener('keydown', (e) => { submitButton.click(); }); -checkRepost(); \ No newline at end of file +checkRepost(); diff --git a/files/assets/js/userpage.js b/files/assets/js/userpage.js index 780e553f6..7b2763894 100644 --- a/files/assets/js/userpage.js +++ b/files/assets/js/userpage.js @@ -16,6 +16,8 @@ if (u_username) document.getElementById('userpage').addEventListener('click', () => { if (audio.paused) audio.play(); }, {once : true}); + + prepare_to_pause(audio) } else { @@ -49,6 +51,8 @@ else if (audio.paused) audio.play(); }, {once : true}); } + + prepare_to_pause(audio) } } @@ -57,4 +61,4 @@ function badge_timestamp(t) { const text = t.getAttribute("data-bs-original-title") t.setAttribute("data-bs-original-title", `${text} ${date.toString()}`); t.removeAttribute("onmouseover") -} \ No newline at end of file +} diff --git a/files/assets/js/userpage_v.js b/files/assets/js/userpage_v.js index 13623ce92..cf478ad16 100644 --- a/files/assets/js/userpage_v.js +++ b/files/assets/js/userpage_v.js @@ -105,13 +105,9 @@ function submitFormAjax(e) { xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { let data = JSON.parse(xhr.response); - try { - document.getElementById('toast-post-success-text').innerText = data["message"]; - } catch(e) { - document.getElementById('toast-post-success-text').innerText = "Action successful!"; - } - var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')); - myToast.show(); + showToast(true, getMessageFromJsonData(true, data)); + document.getElementById('input-message').value = '' + document.getElementById('input-message-mobile').value = '' return true } else { document.getElementById('toast-post-error-text').innerText = "Error, please try again later." @@ -120,6 +116,7 @@ function submitFormAjax(e) { var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-error')); myToast.show(); document.getElementById('toast-post-error-text').innerText = data["error"]; + if (data && data["details"]) document.getElementById('toast-post-error-text').innerText = data["details"]; } catch(e) { var myToast = bootstrap.Toast.getOrCreateInstance(document.getElementById('toast-post-success')); myToast.hide(); @@ -132,4 +129,4 @@ function submitFormAjax(e) { xhr.send(formData); return false -} \ No newline at end of file +} diff --git a/files/assets/manifest_WPD.json b/files/assets/manifest_WPD.json index 33d26d7db..1bd81a7d3 100644 --- a/files/assets/manifest_WPD.json +++ b/files/assets/manifest_WPD.json @@ -1,8 +1,8 @@ { "name": "WPD", "short_name": "WPD", - "start_url": "https://watchpeopledie.co", + "start_url": "https://watchpeopledie.tv", "display": "standalone", "background_color": "#2A96F3", "description": "WPD" -} \ No newline at end of file +} diff --git a/files/classes/clients.py b/files/classes/clients.py index 15d03313d..2a9ef6280 100644 --- a/files/classes/clients.py +++ b/files/classes/clients.py @@ -33,7 +33,7 @@ class OauthApp(Base): @property @lazy def permalink(self): - return f"/admin/app/{self.id}" + return f"{SITE_FULL}/admin/app/{self.id}/posts" @lazy def idlist(self, page=1): diff --git a/files/classes/comment.py b/files/classes/comment.py index 406c5fd5a..e7c2fcc6a 100644 --- a/files/classes/comment.py +++ b/files/classes/comment.py @@ -9,8 +9,8 @@ from files.__main__ import Base from files.classes.votes import CommentVote from files.helpers.const import * from files.helpers.regex import * -from files.helpers.regex import * from files.helpers.lazy import lazy +from files.helpers.sorting_and_time import * from .flags import CommentFlag from .votes import CommentVote from .saves import CommentSaveRelationship @@ -69,8 +69,7 @@ class Comment(Base): post = relationship("Submission", back_populates="comments") author = relationship("User", primaryjoin="User.id==Comment.author_id") senttouser = relationship("User", primaryjoin="User.id==Comment.sentto") - parent_comment = relationship("Comment", remote_side=[id], back_populates="child_comments") - child_comments = relationship("Comment", order_by="Comment.stickied, Comment.realupvotes.desc()", remote_side=[parent_comment_id], back_populates="parent_comment") + parent_comment = relationship("Comment", remote_side=[id]) awards = relationship("AwardRelationship", order_by="AwardRelationship.awarded_utc.desc()", back_populates="comment") flags = relationship("CommentFlag", order_by="CommentFlag.created_utc") options = relationship("CommentOption", order_by="CommentOption.id") @@ -121,64 +120,12 @@ class Comment(Base): if notif_utc: timestamp = notif_utc elif self.created_utc: timestamp = self.created_utc else: return None - - age = int(time.time()) - timestamp - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(timestamp) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" + return make_age_string(timestamp) @property @lazy def edited_string(self): - - age = int(time.time()) - self.edited_utc - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(self.edited_utc) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" + return make_age_string(self.edited_utc) @property @lazy @@ -207,26 +154,16 @@ class Comment(Base): elif self.parent_submission: return f"p_{self.parent_submission}" @lazy - def replies(self, sort=None): - if self.replies2 != None: - replies = self.replies2 - elif not self.parent_submission: - replies = g.db.query(Comment).filter_by(parent_comment_id=self.id).order_by(Comment.id).all() - else: - replies = self.child_comments - - return [x for x in replies if not x.author.shadowbanned] - - - @lazy - def replies3(self, sort): + def replies(self, sort, v): if self.replies2 != None: return self.replies2 - - if not self.parent_submission: - return g.db.query(Comment).filter_by(parent_comment_id=self.id).order_by(Comment.id).all() - return self.child_comments + replies = g.db.query(Comment).filter_by(parent_comment_id=self.id).order_by(Comment.stickied) + + if not self.parent_submission: sort='old' + + return sort_objects(sort, replies, Comment, + include_shadowbanned=(v and v.can_see_shadowbanned)).all() @property @@ -311,7 +248,7 @@ class Comment(Base): 'is_bot': self.is_bot, 'flags': flags, 'author': '👻' if self.ghost else self.author.json, - 'replies': [x.json for x in self.replies()] + 'replies': [x.json for x in self.replies(sort="old", v=None)] } if self.level >= 2: data['parent_comment_id'] = self.parent_comment_id @@ -323,7 +260,7 @@ class Comment(Base): if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))): return f"

    {CC} ONLY

    " if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]" - if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]" + if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return "" body = self.body_html or "" @@ -333,7 +270,7 @@ class Comment(Base): body = normalize_urls_runtime(body, v) - if v and v.controversial: + if not v or v.controversial: captured = [] for i in controversial_regex.finditer(body): if i.group(1) in captured: continue @@ -390,7 +327,7 @@ class Comment(Base): if self.post and self.post.club and not (v and (v.paid_dues or v.id in [self.author_id, self.post.author_id] or (self.parent_comment and v.id == self.parent_comment.author_id))): return f"{CC} ONLY" if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]" - if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]" + if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return "" body = self.body diff --git a/files/classes/leaderboard.py b/files/classes/leaderboard.py new file mode 100644 index 000000000..00ba45182 --- /dev/null +++ b/files/classes/leaderboard.py @@ -0,0 +1,98 @@ +from typing import Any, Callable, Optional, Tuple, Union +from sqlalchemy import func, Column +from sqlalchemy.orm import scoped_session + +from files.helpers.const import LEADERBOARD_LIMIT + +from .badges import Badge +from .marsey import Marsey +from .user import User +from .userblock import UserBlock + +class Leaderboard: + """ + Represents an request-context leaderboard. None of this is persisted yet, + although this is probably a good idea to do at some point. + """ + all_users = None + v_position = 0 + v_value = None + value_func = None + + def __init__(self, header_name:str, table_header_name:str, html_id:str, table_column_name:str, + user_relative_url:Optional[str], query_function:Callable[..., Tuple[Any, Any, Any]], + criteria, v:User, value_func:Optional[Callable[[User], Union[int, Column]]], db:scoped_session, users, limit=LEADERBOARD_LIMIT): + self.header_name = header_name + self.table_header_name = table_header_name + self.html_id = html_id + self.table_column_name = table_column_name + self.user_relative_url = user_relative_url + self.limit = limit + lb = query_function(criteria, v, db, users, limit) + self.all_users = lb[0] + self.v_position = lb[1] + self.v_value = lb[2] + if not self.v_value: + if value_func: + self.value_func = value_func + self.v_value = value_func(v) + else: + self.value_func = lambda u: u[1] or 0 + + @classmethod + def get_simple_lb(cls, order_by, v:User, db:scoped_session, users, limit:int): + leaderboard = users.order_by(order_by.desc()).limit(limit).all() + position = None + if v not in leaderboard: + sq = db.query(User.id, func.rank().over(order_by=order_by.desc()).label("rank")).subquery() + position = db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] + return (leaderboard, position, None) + + @classmethod + def count_and_label(cls, criteria): + return func.count(criteria).label("count") + + @classmethod + def rank_filtered_rank_label_by_desc(cls, criteria): + return func.rank().over(order_by=func.count(criteria).desc()).label("rank") + + @classmethod + def get_badge_marsey_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit): + sq = db.query(lb_criteria, cls.count_and_label(lb_criteria), cls.rank_filtered_rank_label_by_desc(lb_criteria)).group_by(lb_criteria).subquery() + sq_criteria = None + if lb_criteria == Badge.user_id: + sq_criteria = User.id == sq.c.user_id + elif lb_criteria == Marsey.author_id: + sq_criteria = User.id == sq.c.author_id + else: + raise ValueError("This leaderboard function only supports Badge.user_id and Marsey.author_id") + + leaderboard = db.query(User, sq.c.count).join(sq, sq_criteria).order_by(sq.c.count.desc()) + position = db.query(User.id, sq.c.rank, sq.c.count).join(sq, sq_criteria).filter(User.id == v.id).one_or_none() + if position: position = (position[1], position[2]) + else: position = (leaderboard.count() + 1, 0) + leaderboard = leaderboard.limit(limit).all() + return (leaderboard, position[0], position[1]) + + @classmethod + def get_blockers_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit): + if lb_criteria != UserBlock.target_id: + raise ValueError("This leaderboard function only supports UserBlock.target_id") + sq = db.query(lb_criteria, cls.count_and_label(lb_criteria)).group_by(lb_criteria).subquery() + leaderboard = db.query(User, sq.c.count).join(User, User.id == sq.c.target_id).order_by(sq.c.count.desc()) + + sq = db.query(lb_criteria, cls.count_and_label(lb_criteria), cls.rank_filtered_rank_label_by_desc(lb_criteria)).group_by(lb_criteria).subquery() + position = db.query(sq.c.rank, sq.c.count).join(User, User.id == sq.c.target_id).filter(sq.c.target_id == v.id).limit(1).one_or_none() + if not position: position = (leaderboard.count() + 1, 0) + leaderboard = leaderboard.limit(limit).all() + return (leaderboard, position[0], position[1]) + + @classmethod + def get_hat_lb(cls, lb_criteria, v:User, db:scoped_session, users:Any, limit): + leaderboard = db.query(User.id, func.count(lb_criteria)).join(lb_criteria).group_by(User).order_by(func.count(lb_criteria).desc()) + sq = db.query(User.id, cls.count_and_label(lb_criteria), cls.rank_filtered_rank_label_by_desc(lb_criteria)).join(lb_criteria).group_by(User).subquery() + position = db.query(sq.c.rank, sq.c.count).filter(sq.c.id == v.id).limit(1).one_or_none() + if not position: position = (leaderboard.count() + 1, 0) + leaderboard = leaderboard.limit(limit).all() + return (leaderboard, position[0], position[1]) + diff --git a/files/classes/mod_logs.py b/files/classes/mod_logs.py index 9a8bec5e4..3f696eed8 100644 --- a/files/classes/mod_logs.py +++ b/files/classes/mod_logs.py @@ -6,6 +6,7 @@ from files.helpers.lazy import lazy from copy import deepcopy from files.helpers.const import * from files.helpers.regex import censor_slurs +from files.helpers.sorting_and_time import make_age_string class ModAction(Base): __tablename__ = "modactions" @@ -32,37 +33,10 @@ class ModAction(Base): @property @lazy def age_string(self): - - age = int(time.time()) - self.created_utc - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(self.created_utc) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" + return make_age_string(self.created_utc) @property def note(self): - if self.kind=="ban_user": if self.target_post: return f'for post' elif self.target_comment_id: return f'for comment' @@ -73,11 +47,8 @@ class ModAction(Base): @property @lazy def string(self): - output = ACTIONTYPES[self.kind]["str"].format(self=self, cc=CC_TITLE) - if self.note: output += f" ({self.note})" - return output @property @@ -416,7 +387,7 @@ ACTIONTYPES = { "color": 'bg-success' }, 'update_marsey': { - "str": 'updated marsey image', + "str": 'updated marsey', "icon": 'fa-cat', "color": 'bg-success' }, diff --git a/files/classes/sub_logs.py b/files/classes/sub_logs.py index 0b3ddc8a4..51ecf2dae 100644 --- a/files/classes/sub_logs.py +++ b/files/classes/sub_logs.py @@ -5,6 +5,7 @@ import time from files.helpers.lazy import lazy from files.helpers.const import * from files.helpers.regex import censor_slurs +from files.helpers.sorting_and_time import make_age_string class SubAction(Base): __tablename__ = "subactions" @@ -32,42 +33,13 @@ class SubAction(Base): @property @lazy def age_string(self): - - age = int(time.time()) - self.created_utc - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(self.created_utc) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" + return make_age_string(self.created_utc) @property @lazy def string(self): - output = ACTIONTYPES[self.kind]["str"].format(self=self, cc=CC_TITLE) - if self._note: output += f" ({self._note})" - return output @property diff --git a/files/classes/submission.py b/files/classes/submission.py index e00e0e154..0946e2e41 100644 --- a/files/classes/submission.py +++ b/files/classes/submission.py @@ -9,6 +9,7 @@ from files.__main__ import Base from files.helpers.const import * from files.helpers.regex import * from files.helpers.lazy import lazy +from files.helpers.sorting_and_time import make_age_string from .flags import Flag from .comment import Comment, normalize_urls_runtime from .saves import SaveRelationship @@ -100,64 +101,12 @@ class Submission(Base): @property @lazy def age_string(self): - - age = int(time.time()) - self.created_utc - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(self.created_utc) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" + return make_age_string(self.created_utc) @property @lazy def edited_string(self): - - age = int(time.time()) - self.edited_utc - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(self.edited_utc) - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" - + return make_age_string(self.edited_utc) @property @lazy @@ -310,11 +259,11 @@ class Submission(Base): if url.startswith("https://old.reddit.com/r/") and '/comments/' in url and "sort=" not in url: if "?" in url: url += "&context=9" else: url += "?context=8" - if v and v.controversial: url += "&sort=controversial" - elif url.startswith("https://watchpeopledie.co/videos/"): + if not v or v.controversial: url += "&sort=controversial" + elif url.startswith("https://watchpeopledie.tv/videos/"): # Semi-temporary fix for self-hosted unproxied video serving - url = url.replace("https://watchpeopledie.co/videos/", - "https://videos.watchpeopledie.co/", 1) + url = url.replace("https://watchpeopledie.tv/videos/", + "https://videos.watchpeopledie.tv/", 1) return url @@ -331,7 +280,7 @@ class Submission(Base): def realbody(self, v, listing=False): if self.club and not (v and (v.paid_dues or v.id == self.author_id)): return f"

    {CC} ONLY

    " if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]" - if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]" + if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return "" body = self.body_html or "" @@ -400,7 +349,7 @@ class Submission(Base): @lazy def plainbody(self, v): if self.deleted_utc != 0 and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.author.id)): return "[Deleted by user]" - if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']): return "[Removed by admins]" + if self.is_banned and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id == self.author.id): return "" if self.club and not (v and (v.paid_dues or v.id == self.author_id)): return f"

    {CC} ONLY

    " body = self.body @@ -449,9 +398,7 @@ class Submission(Base): @property @lazy def is_image(self): - if self.url and (self.url.lower().endswith('.webp') or self.url.lower().endswith('.jpg') or self.url.lower().endswith('.png') or self.url.lower().endswith('.gif') or self.url.lower().endswith('.jpeg') or self.url.lower().endswith('?maxwidth=9999') or self.url.lower().endswith('&fidelity=high')) and is_safe_url(self.url): - return True - return False + return self.url and any((self.url.lower().endswith(x) for x in ('.webp','.jpg','.png','.gif','.jpeg','?maxwidth=9999','&fidelity=high'))) and is_safe_url(self.url) @lazy def filtered_flags(self, v): diff --git a/files/classes/user.py b/files/classes/user.py index 21f01d096..6965a1cb1 100644 --- a/files/classes/user.py +++ b/files/classes/user.py @@ -2,7 +2,6 @@ from sqlalchemy.orm import deferred, aliased from sqlalchemy.sql import func from secrets import token_hex import pyotp -from files.helpers.discord import remove_user from files.helpers.media import * from files.helpers.const import * from files.classes.casino_game import Casino_Game @@ -59,7 +58,6 @@ class User(Base): marseyawarded = Column(Integer) rehab = Column(Integer) longpost = Column(Integer) - unblockable = Column(Boolean) bird = Column(Integer) email = deferred(Column(String)) css = Column(String) @@ -80,7 +78,6 @@ class User(Base): over_18 = Column(Boolean, default=False) hidevotedon = Column(Boolean, default=False) highlightcomments = Column(Boolean, default=True) - poorcel = Column(Boolean, default=False) slurreplacer = Column(Boolean, default=True) flairchanged = Column(Integer) newtab = Column(Boolean, default=False) @@ -88,20 +85,14 @@ class User(Base): reddit = Column(String, default='old.reddit.com') nitter = Column(Boolean) imginn = Column(Boolean) - mute = Column(Boolean) - unmutable = Column(Boolean) - eye = Column(Boolean) - alt = Column(Boolean) - offsitementions = Column(Boolean, default=False, nullable=False) frontsize = Column(Integer, default=25) - controversial = Column(Boolean, default=False) + controversial = Column(Boolean, default=True) bio = deferred(Column(String)) bio_html = Column(String) sig = deferred(Column(String)) sig_html = Column(String) fp = Column(String) sigs_disabled = Column(Boolean) - fish = Column(Boolean) progressivestack = Column(Integer) deflector = Column(Integer) friends = deferred(Column(String)) @@ -114,14 +105,13 @@ class User(Base): is_muted = Column(Boolean, default=False, nullable=False) club_allowed = Column(Boolean) login_nonce = Column(Integer, default=0) - reserved = deferred(Column(String)) coins = Column(Integer, default=0) truecoins = Column(Integer, default=0) procoins = Column(Integer, default=0) mfa_secret = deferred(Column(String)) is_private = Column(Boolean, default=False) stored_subscriber_count = Column(Integer, default=0) - defaultsortingcomments = Column(String, default="top") + defaultsortingcomments = Column(String, default="hot") defaultsorting = Column(String, default="hot") defaulttime = Column(String, default=DEFAULT_TIME_FILTER) is_nofollow = Column(Boolean, default=False) @@ -289,6 +279,14 @@ class User(Base): if self.bite: return "565656" return self.namecolor + @property + @lazy + def is_votes_real(self): + if self.is_suspended_permanently or self.shadowbanned: return False + if self.agendaposter: return False + if self.profile_url.startswith('/e/') and not self.customtitle and self.namecolor == DEFAULT_COLOR: return False + return True + @lazy def mods(self, sub): if self.is_suspended_permanently or self.shadowbanned: return False @@ -460,19 +458,19 @@ class User(Base): @cache.memoize(timeout=86400) def userpagelisting(self, site=None, v=None, page=1, sort="new", t="all"): + if self.shadowbanned and not (v and v.can_see_shadowbanned): return [] - if self.shadowbanned and not (v and (v.admin_level >= PERMS['USER_SHADOWBAN'] or v.id == self.id)): return [] - - posts = g.db.query(Submission.id).filter_by(author_id=self.id, is_pinned=False) + posts = g.db.query(Submission.id).filter_by(author_id=self.id, is_pinned=False, is_banned=False) if not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or v.id == self.id)): posts = posts.filter_by(is_banned=False, private=False, ghost=False, deleted_utc=0) posts = apply_time_filter(t, posts, Submission) - posts = sort_posts(sort, posts) + posts = sort_objects(sort, posts, Submission, + include_shadowbanned=(v and v.can_see_shadowbanned)) - posts = posts.offset(25 * (page - 1)).limit(26).all() + posts = posts.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all() return [x[0] for x in posts] @@ -593,7 +591,7 @@ class User(Base): Notification.user_id == self.id, Notification.read == False, Comment.is_banned == False, Comment.deleted_utc == 0) - if not self.shadowbanned and self.admin_level < PERMS['USER_SHADOWBAN']: + if not self.can_see_shadowbanned: notifs = notifs.join(Comment.author).filter(User.shadowbanned == None) return notifs.count() + self.post_notifications_count + self.modaction_notifications_count @@ -618,7 +616,7 @@ class User(Base): Comment.parent_submission == None, ) - if not self.shadowbanned and self.admin_level < PERMS['USER_SHADOWBAN']: + if not self.can_see_shadowbanned: notifs = notifs.join(Comment.author).filter(User.shadowbanned == None) return notifs.count() @@ -757,7 +755,7 @@ class User(Base): @lazy def profile_url(self): if self.agendaposter: - return f"{SITE_FULL}/assets/images/pfps/agendaposter/{random.randint(1, 57)}.webp?v=1" + return f"{SITE_FULL}/e/chudsey.webp" if self.rainbow: return f"{SITE_FULL}/e/marseysalutepride.webp" if self.profileurl: @@ -775,8 +773,8 @@ class User(Base): 'bannerurl': self.banner_url, 'bio_html': self.bio_html_eager, 'coins': self.coins, - 'post_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN'])) else self.post_count, - 'comment_count': 0 if self.shadowbanned and not (v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN'])) else self.comment_count, + 'post_count': 0 if self.shadowbanned and not (v and v.can_see_shadowbanned) else self.post_count, + 'comment_count': 0 if self.shadowbanned and not (v and v.can_see_shadowbanned) else self.comment_count, 'badges': [x.path for x in self.badges], } @@ -814,11 +812,10 @@ class User(Base): - def ban(self, admin=None, reason=None, days=0): + def ban(self, admin=None, reason=None, days=0.0): if days: self.unban_utc = int(time.time()) + (days * 86400) g.db.add(self) - elif self.discord_id: remove_user(self) self.is_banned = admin.id if admin else AUTOJANNY_ID if reason and len(reason) <= 256: @@ -922,6 +919,8 @@ class User(Base): return 'Contributed at least $50' if self.patron == 5: return 'Contributed at least $100' + if self.patron == 6: + return 'Contributed at least $200' return '' @property @@ -967,3 +966,44 @@ class User(Base): return name return f'((({self.username})))' return self.username + + @property + @lazy + def can_see_shadowbanned(self): + return (self.admin_level >= PERMS['USER_SHADOWBAN']) or self.shadowbanned + + + @property + @lazy + def unmutable(self): + return self.has_badge(67) + + @property + @lazy + def mute(self): + return self.has_badge(68) + + @property + @lazy + def eye(self): + return self.has_badge(83) + + @property + @lazy + def alt(self): + return self.has_badge(84) + + @property + @lazy + def unblockable(self): + return self.has_badge(87) + + @property + @lazy + def fish(self): + return self.has_badge(90) + + @property + @lazy + def offsitementions(self): + return self.has_badge(140) diff --git a/files/classes/views.py b/files/classes/views.py index b3007003d..ded2b84d5 100644 --- a/files/classes/views.py +++ b/files/classes/views.py @@ -4,6 +4,8 @@ from files.__main__ import Base from files.helpers.lazy import * import time +from files.helpers.sorting_and_time import make_age_string + class ViewerRelationship(Base): __tablename__ = "viewers" @@ -26,36 +28,9 @@ class ViewerRelationship(Base): @property @lazy def last_view_since(self): - return int(time.time()) - self.last_view_utc @property @lazy def last_view_string(self): - - age = self.last_view_since - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(self.last_view_utc) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" + return make_age_string(self.last_view_utc) diff --git a/files/classes/votes.py b/files/classes/votes.py index 897776986..89e72956e 100644 --- a/files/classes/votes.py +++ b/files/classes/votes.py @@ -14,6 +14,7 @@ class Vote(Base): vote_type = Column(Integer) app_id = Column(Integer, ForeignKey("oauth_apps.id")) real = Column(Boolean, default=True) + coins = Column(Integer, default=1, nullable=False) created_utc = Column(Integer) user = relationship("User") @@ -44,6 +45,7 @@ class CommentVote(Base): vote_type = Column(Integer) app_id = Column(Integer, ForeignKey("oauth_apps.id")) real = Column(Boolean, default=True) + coins = Column(Integer, default=1, nullable=False) created_utc = Column(Integer) user = relationship("User") diff --git a/files/helpers/actions.py b/files/helpers/actions.py index b319f7ecc..518f28729 100644 --- a/files/helpers/actions.py +++ b/files/helpers/actions.py @@ -62,6 +62,7 @@ def execute_snappy(post, v): else: SNAPPY_CHOICES = SNAPPY_QUOTES elif SNAPPY_MARSEYS: SNAPPY_CHOICES = SNAPPY_MARSEYS elif SNAPPY_QUOTES: SNAPPY_CHOICES = SNAPPY_QUOTES + else: SNAPPY_CHOICES = [""] body = random.choice(SNAPPY_CHOICES).strip() if body.startswith('▼'): @@ -135,17 +136,17 @@ def execute_snappy(post, v): addition += f'* [archive.org](https://web.archive.org/{href})\n' addition += f'* [archive.ph](https://archive.ph/?url={quote(href)}&run=1) (click to archive)\n' addition += f'* [ghostarchive.org](https://ghostarchive.org/search?term={quote(href)}) (click to archive)\n\n' - if len(f'{body}{addition}') > 10000: break + if len(f'{body}{addition}') > COMMENT_BODY_LENGTH_LIMIT: break body += addition archive_url(href) - body = body.strip()[:POST_BODY_LENGTH_LIMIT] + body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT] body_html = sanitize(body) if len(body_html) == 0: return - if len(body_html) < POST_BODY_HTML_LENGTH_LIMIT: + if len(body_html) < COMMENT_BODY_HTML_LENGTH_LIMIT: c = Comment(author_id=SNAPPY_ID, distinguish_level=6, parent_submission=post.id, @@ -311,3 +312,140 @@ def execute_basedbot(c, level, body, parent_submission, parent_post, v): n = Notification(comment_id=c_based.id, user_id=v.id) g.db.add(n) + +def execute_antispam_submission_check(title, v, url): + now = int(time.time()) + cutoff = now - 60 * 60 * 24 + + similar_posts = g.db.query(Submission).filter( + Submission.author_id == v.id, + Submission.title.op('<->')(title) < SPAM_SIMILARITY_THRESHOLD, + Submission.created_utc > cutoff + ).all() + + if url: + similar_urls = g.db.query(Submission).filter( + Submission.author_id == v.id, + Submission.url.op('<->')(url) < SPAM_URL_SIMILARITY_THRESHOLD, + Submission.created_utc > cutoff + ).all() + else: similar_urls = [] + + threshold = SPAM_SIMILAR_COUNT_THRESHOLD + if v.age >= (60 * 60 * 24 * 7): threshold *= 3 + elif v.age >= (60 * 60 * 24): threshold *= 2 + + if max(len(similar_urls), len(similar_posts)) >= threshold: + text = "Your account has been banned for **1 day** for the following reason:\n\n> Too much spam!" + send_repeatable_notification(v.id, text) + + v.ban(reason="Spamming.", + days=1) + + for post in similar_posts + similar_urls: + post.is_banned = True + post.is_pinned = False + post.ban_reason = "AutoJanny" + g.db.add(post) + ma=ModAction( + user_id=AUTOJANNY_ID, + target_submission_id=post.id, + kind="ban_post", + _note="spam" + ) + g.db.add(ma) + return False + return True + +def execute_blackjack(v, target, body, type): + if not blackjack or not body: return True + if any(i in body.lower() for i in blackjack.split()): + v.shadowbanned = 'AutoJanny' + if not v.is_banned: v.ban_reason = f"Blackjack" + g.db.add(v) + notif = None + extra_info = "unknown entity" + if type == 'submission': + extra_info = f"submission ({target.permalink})" + elif type == 'comment' or type == 'message': + extra_info = f"{type} ({target.permalink})" + notif = Notification(comment_id=target.id, user_id=CARP_ID) + elif type == 'chat': + extra_info = "chat message" + elif type == 'flag': + extra_info = f"reports on {target.permalink}" + + if notif: + g.db.add(notif) + g.db.flush() + elif extra_info: send_repeatable_notification(CARP_ID, f"Blackjack for {v.name}: {extra_info}") + return False + return True + +def execute_antispam_comment_check(body:str, v:User): + if v.id in ANTISPAM_BYPASS_IDS: return + if len(body) <= COMMENT_SPAM_LENGTH_THRESHOLD: return + now = int(time.time()) + cutoff = now - 60 * 60 * 24 + + similar_comments = g.db.query(Comment).filter( + Comment.author_id == v.id, + Comment.body.op('<->')(body) < COMMENT_SPAM_SIMILAR_THRESHOLD, + Comment.created_utc > cutoff + ).all() + + threshold = COMMENT_SPAM_COUNT_THRESHOLD + if v.age >= (60 * 60 * 24 * 7): + threshold *= 3 + elif v.age >= (60 * 60 * 24): + threshold *= 2 + + if len(similar_comments) <= threshold: return + text = "Your account has been banned for **1 day** for the following reason:\n\n> Too much spam!" + send_repeatable_notification(v.id, text) + v.ban(reason="Spamming.", + days=1) + for comment in similar_comments: + comment.is_banned = True + comment.ban_reason = "AutoJanny" + g.db.add(comment) + ma=ModAction( + user_id=AUTOJANNY_ID, + target_comment_id=comment.id, + kind="ban_comment", + _note="spam" + ) + g.db.add(ma) + g.db.commit() + abort(403, "Too much spam!") + +def execute_lawlz_actions(v:User, p:Submission): + if v.id != LAWLZ_ID: return + if SITE_NAME != 'rDrama': return + if not FEATURES['PINS']: return + p.stickied_utc = int(time.time()) + 86400 + p.stickied = v.username + p.distinguish_level = 6 + p.flair = ":ben10: Required Reading" + pin_time = 'for 1 day' + ma_1=ModAction( + kind="pin_post", + user_id=v.id, + target_submission_id=p.id, + _note=pin_time + ) + ma_2=ModAction( + kind="distinguish_post", + user_id=v.id, + target_submission_id=p.id + ) + ma_3=ModAction( + kind="flair_post", + user_id=v.id, + target_submission_id=p.id, + _note=f'"{p.flair}"' + ) + g.db.add(p) + g.db.add(ma_1) + g.db.add(ma_2) + g.db.add(ma_3) diff --git a/files/helpers/alerts.py b/files/helpers/alerts.py index ffff2e041..2d6b99353 100644 --- a/files/helpers/alerts.py +++ b/files/helpers/alerts.py @@ -91,7 +91,10 @@ def NOTIFY_USERS(text, v): names = set(m.group(2) for m in mention_regex.finditer(text)) for user in get_users(names, graceful=True): - if v.id != user.id and not v.any_block_exists(user): + if user.username == 'jannies' and v.truecoins >= ADMIN_PING_TRUESCORE_MINIMUM and not v.shadowbanned: + admins = [x[0] for x in g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_ADMIN_PING']).all()] + notify_users.update(admins) + elif v.id != user.id and not v.any_block_exists(user): notify_users.add(user.id) if SITE_NAME == "WPD" and 'daisy' in text.lower(): diff --git a/files/helpers/awards.py b/files/helpers/awards.py index 6986e59b6..637e2132f 100644 --- a/files/helpers/awards.py +++ b/files/helpers/awards.py @@ -2,7 +2,6 @@ from flask import g import time from files.helpers.alerts import send_repeatable_notification from files.helpers.const import * -from files.helpers.discord import remove_role from files.classes.badges import Badge from files.classes.user import User @@ -17,7 +16,6 @@ def award_timers(v, bot=False): v.patron = 0 v.patron_utc = 0 notify_if_not_bot(f"Your {patron} status has expired!") - if not bot and v.discord_id: remove_role(v, "1") if v.unban_utc and v.unban_utc < now: v.is_banned = 0 v.unban_utc = 0 diff --git a/files/helpers/casino.py b/files/helpers/casino.py index 089cb0304..fd3f59a61 100644 --- a/files/helpers/casino.py +++ b/files/helpers/casino.py @@ -9,99 +9,99 @@ from files.helpers.wrappers import * def get_game_feed(game): - games = g.db.query(Casino_Game) \ - .filter(Casino_Game.active == False, Casino_Game.kind == game) \ - .order_by(Casino_Game.created_utc.desc()).limit(30).all() + games = g.db.query(Casino_Game) \ + .filter(Casino_Game.active == False, Casino_Game.kind == game) \ + .order_by(Casino_Game.created_utc.desc()).limit(30).all() - def format_game(game): - user = g.db.query(User).filter(User.id == game.user_id).one() - wonlost = 'lost' if game.winnings < 0 else 'won' - relevant_currency = "coin" if game.currency == "coins" else "marseybux" + def format_game(game): + user = g.db.query(User).filter(User.id == game.user_id).one() + wonlost = 'lost' if game.winnings < 0 else 'won' + relevant_currency = "coin" if game.currency == "coins" else "marseybux" - return { - "user": user.username, - "won_or_lost": wonlost, - "amount": abs(game.winnings), - "currency": relevant_currency - } + return { + "user": user.username, + "won_or_lost": wonlost, + "amount": abs(game.winnings), + "currency": relevant_currency + } - return list(map(format_game, games)) + return list(map(format_game, games)) def get_game_leaderboard(game): - timestamp_24h_ago = time.time() - 86400 - timestamp_all_time = 1662825600 # "All Time" starts on release day + timestamp_24h_ago = time.time() - 86400 + timestamp_all_time = 1662825600 # "All Time" starts on release day - biggest_win_all_time = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( - Casino_Game).join(User).order_by(Casino_Game.winnings.desc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_all_time).limit(1).one_or_none() + biggest_win_all_time = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( + Casino_Game).join(User).order_by(Casino_Game.winnings.desc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_all_time).limit(1).one_or_none() - biggest_win_last_24h = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( - Casino_Game).join(User).order_by(Casino_Game.winnings.desc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_24h_ago).limit(1).one_or_none() + biggest_win_last_24h = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( + Casino_Game).join(User).order_by(Casino_Game.winnings.desc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_24h_ago).limit(1).one_or_none() - biggest_loss_all_time = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( - Casino_Game).join(User).order_by(Casino_Game.winnings.asc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_all_time).limit(1).one_or_none() + biggest_loss_all_time = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( + Casino_Game).join(User).order_by(Casino_Game.winnings.asc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_all_time).limit(1).one_or_none() - biggest_loss_last_24h = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( - Casino_Game).join(User).order_by(Casino_Game.winnings.asc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_24h_ago).limit(1).one_or_none() + biggest_loss_last_24h = g.db.query(Casino_Game.user_id, User.username, Casino_Game.currency, Casino_Game.winnings).select_from( + Casino_Game).join(User).order_by(Casino_Game.winnings.asc()).filter(Casino_Game.kind == game, Casino_Game.created_utc > timestamp_24h_ago).limit(1).one_or_none() - if not biggest_win_all_time: - biggest_win_all_time = [None, None, None, 0] + if not biggest_win_all_time: + biggest_win_all_time = [None, None, None, 0] - if not biggest_win_last_24h: - biggest_win_last_24h = [None, None, None, 0] + if not biggest_win_last_24h: + biggest_win_last_24h = [None, None, None, 0] - if not biggest_loss_all_time: - biggest_loss_all_time = [None, None, None, 0] + if not biggest_loss_all_time: + biggest_loss_all_time = [None, None, None, 0] - if not biggest_loss_last_24h: - biggest_loss_last_24h = [None, None, None, 0] + if not biggest_loss_last_24h: + biggest_loss_last_24h = [None, None, None, 0] - return { - "all_time": { - "biggest_win": { + return { + "all_time": { + "biggest_win": { "user": biggest_win_all_time[1], "currency": biggest_win_all_time[2], "amount": biggest_win_all_time[3] }, - "biggest_loss": { + "biggest_loss": { "user": biggest_loss_all_time[1], "currency": biggest_loss_all_time[2], "amount": abs(biggest_loss_all_time[3]) } - }, - "last_24h": { - "biggest_win": { + }, + "last_24h": { + "biggest_win": { "user": biggest_win_last_24h[1], "currency": biggest_win_last_24h[2], "amount": biggest_win_last_24h[3] }, - "biggest_loss": { + "biggest_loss": { "user": biggest_loss_last_24h[1], "currency": biggest_loss_last_24h[2], "amount": abs(biggest_loss_last_24h[3]) } - } - } + } + } def distribute_wager_badges(user, wager, won): - badges_earned = [] + badges_earned = [] - if won: - if wager >= 1000: - badges_earned.append(160) - if wager >= 10000: - badges_earned.append(161) - if wager >= 100000: - badges_earned.append(162) - else: - if wager >= 1000: - badges_earned.append(157) - if wager >= 10000: - badges_earned.append(158) - if wager >= 100000: - badges_earned.append(159) + if won: + if wager >= 1000: + badges_earned.append(160) + if wager >= 10000: + badges_earned.append(161) + if wager >= 100000: + badges_earned.append(162) + else: + if wager >= 1000: + badges_earned.append(157) + if wager >= 10000: + badges_earned.append(158) + if wager >= 100000: + badges_earned.append(159) - for badge in badges_earned: - badge_grant(user, badge) + for badge in badges_earned: + badge_grant(user, badge) diff --git a/files/helpers/cloudflare.py b/files/helpers/cloudflare.py new file mode 100644 index 000000000..4dafa3516 --- /dev/null +++ b/files/helpers/cloudflare.py @@ -0,0 +1,42 @@ +import json +from typing import List, Union, Optional +from files.helpers.const import * +import requests + +CLOUDFLARE_API_URL = "https://api.cloudflare.com/client/v4" +CLOUDFLARE_REQUEST_TIMEOUT_SECS = 5 +DEFAULT_CLOUDFLARE_ZONE = 'blahblahblah' + +def _request_from_cloudflare(url:str, method:str, post_data_str) -> bool: + if CF_ZONE == DEFAULT_CLOUDFLARE_ZONE: return False + try: + res = str(requests.request(method, f"{CLOUDFLARE_API_URL}/zones/{CF_ZONE}/{url}", headers=CF_HEADERS, data=post_data_str, timeout=CLOUDFLARE_REQUEST_TIMEOUT_SECS)) + except: + return False + return res == "" + +def get_security_level() -> Optional[str]: + res = None + try: + res = requests.get(f'{CLOUDFLARE_API_URL}/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, timeout=CLOUDFLARE_REQUEST_TIMEOUT_SECS).json()['result']['value'] + except: + pass + return res + +def set_security_level(under_attack="high") -> bool: + return _request_from_cloudflare("settings/security_level", "PATCH", f'{{"value":"{under_attack}"}}') + +def purge_entire_cache() -> bool: + return _request_from_cloudflare("purge_cache", "POST", '{"purge_everything":true}') + +def purge_files_in_cache(files:Union[List[str],str]) -> bool: + if CF_ZONE == DEFAULT_CLOUDFLARE_ZONE: return False + if isinstance(files, str): + files = [files] + post_data = {"files": files} + res = None + try: + res = requests.post(f'{CLOUDFLARE_API_URL}/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data=json.dumps(post_data), timeout=CLOUDFLARE_REQUEST_TIMEOUT_SECS) + except: + return False + return res == "" diff --git a/files/helpers/const.py b/files/helpers/const.py index a6f999e07..a07d1103e 100644 --- a/files/helpers/const.py +++ b/files/helpers/const.py @@ -9,15 +9,11 @@ from flask import request import tldextract from os import path - SITE = environ.get("SITE").strip() SITE_NAME = environ.get("SITE_NAME").strip() -MASTER_KEY = environ.get("MASTER_KEY").strip() +SECRET_KEY = environ.get("SECRET_KEY").strip() PROXY_URL = environ.get("PROXY_URL").strip() GIPHY_KEY = environ.get('GIPHY_KEY').strip() -DISCORD_SERVER_ID = environ.get("DISCORD_SERVER_ID").strip() -DISCORD_CLIENT_ID = environ.get("DISCORD_CLIENT_ID").strip() -DISCORD_CLIENT_SECRET = environ.get("DISCORD_CLIENT_SECRET").strip() DISCORD_BOT_TOKEN = environ.get("DISCORD_BOT_TOKEN").strip() HCAPTCHA_SITEKEY = environ.get("HCAPTCHA_SITEKEY").strip() HCAPTCHA_SECRET = environ.get("HCAPTCHA_SECRET").strip() @@ -44,6 +40,7 @@ MAILGUN_KEY = environ.get("MAILGUN_KEY").strip() DESCRIPTION = environ.get("DESCRIPTION").strip() CF_KEY = environ.get("CF_KEY").strip() CF_ZONE = environ.get("CF_ZONE").strip() +TELEGRAM_LINK = environ.get("TELEGRAM_LINK").strip() GLOBAL = environ.get("GLOBAL", "").strip() blackjack = environ.get("BLACKJACK", "").strip() @@ -51,12 +48,17 @@ FP = environ.get("FP", "").strip() KOFI_TOKEN = environ.get("KOFI_TOKEN", "").strip() KOFI_LINK = environ.get("KOFI_LINK", "").strip() +PUSHER_ID_CSP = "" +if PUSHER_ID != "blahblahblah": + PUSHER_ID_CSP = f" {PUSHER_ID}.pushnotifications.pusher.com" +CONTENT_SECURITY_POLICY_DEFAULT = "script-src 'self' 'unsafe-inline' ajax.cloudflare.com; connect-src 'self'; object-src 'none';" +CONTENT_SECURITY_POLICY_HOME = f"script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self' tls-user1.fpapi.io api.fpjs.io{PUSHER_ID_CSP}; object-src 'none';" if SITE == "localhost": SITE_FULL = 'http://' + SITE else: SITE_FULL = 'https://' + SITE -if SITE == 'pcmemes.net': CC = "SPLASH MOUNTAIN" +if SITE_NAME == 'PCM': CC = "SPLASH MOUNTAIN" else: CC = "COUNTRY CLUB" CC_TITLE = CC.title() @@ -94,7 +96,6 @@ SLURS = { "tranny": ':marseytrain:', "troon": ':marseytrain:', "dyke": "cute lesbian", - "gook": "superior IQ Asian", "kike": "jewish chad", "daisy's destruction": "Cars 2", "daisys destruction": "Cars 2", @@ -108,30 +109,21 @@ if SITE_NAME == 'rDrama': "pedophile": "libertarian", "kill yourself": "keep yourself safe", "steve akins": "penny verity oaken", - "nonewnormal": "HorseDewormerAddicts", "latinos": "latinx", "latino": "latinx", "latinas": "latinx", "latina": "latinx", "hispanics": "latinx", "hispanic": "latinx", - "lavon affair": "Lavon Misunderstanding", - "shylock": "Israeli friend", "i hate marsey": "i love marsey", - "dancing israelis": "i love Israel", "sodomite": "total dreamboat", "pajeet": "sexy Indian dude", - "tenant": "renthog", "renter": "rentoid", "autistic": "neurodivergent", "i hate carp": "i love Carp", "gamer": "g*mer", "journalist": "journ*list", "journalism": "journ*lism", - "wuhan flu": "SARS-CoV-2 syndemic", - "china flu": "SARS-CoV-2 syndemic", - "china virus": "SARS-CoV-2 syndemic", - "kung flu": "SARS-CoV-2 syndemic", "elon musk": "rocket daddy", "fake and gay": "fake and straight", " rapist": " male feminist", @@ -156,13 +148,16 @@ AGENDAPOSTER_MSG_HTML = """

    Hi here.

    """ +DISCORD_CHANGELOG_CHANNEL_IDS = [1022232469606498324] +WPD_CHANNEL_ID = 1013990963846332456 +PIN_AWARD_TEXT = " (pin award)" ################################################################################ ### SITE SPECIFIC CONSTANTS ################################################################################ PERMS = { # Minimum admin_level to perform action. - 'ADMIN_ADD': 3, # note: explicitly disabled on rDrama + 'ADMIN_ADD': 3, 'ADMIN_REMOVE': 3, 'ADMIN_ADD_PERM_LEVEL': 2, # permission level given when user added via site 'ADMIN_ACTIONS_REVERT': 3, @@ -170,15 +165,17 @@ PERMS = { # Minimum admin_level to perform action. 'ADMIN_HOME_VISIBLE': 2, 'DOMAINS_BAN': 3, 'HOLE_CREATE': 0, - 'HOLE_GLOBAL_MODERATION': 3, + 'HOLE_GLOBAL_MODERATION': 4, 'FLAGS_REMOVE': 2, 'VOTES_VISIBLE': 0, 'USER_BLOCKS_VISIBLE': 0, 'USER_FOLLOWS_VISIBLE': 0, 'USER_VOTERS_VISIBLE': 0, + 'POST_COMMENT_INFINITE_PINGS': 1, 'POST_COMMENT_MODERATION': 2, 'POST_COMMENT_DISTINGUISH': 1, 'POST_COMMENT_MODERATION_TOOLS_VISIBLE': 2, # note: does not affect API at all + 'POST_BYPASS_REPOST_CHECKING': 1, 'POST_EDITING': 3, 'USER_BADGES': 2, 'USER_BAN': 2, @@ -193,7 +190,7 @@ PERMS = { # Minimum admin_level to perform action. 'POST_TO_POLL_THREAD': 2, 'POST_BETS': 3, 'POST_BETS_DISTRIBUTE': 3, # probably should be the same as POST_BETS but w/e - 'BYPASS_PIN_LIMIT': 3, + 'BYPASS_PIN_LIMIT': 2, 'VIEW_PENDING_SUBMITTED_MARSEYS': 3, 'VIEW_PENDING_SUBMITTED_HATS': 3, 'MODERATE_PENDING_SUBMITTED_MARSEYS': 3, # note: there is an extra check so that only """carp""" can approve them @@ -217,12 +214,15 @@ PERMS = { # Minimum admin_level to perform action. 'VIEW_PATRONS': 3, # note: extra check for Aevann, carp, or snakes 'VIEW_VOTE_BUTTONS_ON_USER_PAGE': 2, 'PRINT_MARSEYBUX_FOR_KIPPY_ON_PCMEMES': 3, # note: explicitly disabled on rDrama + 'SITE_BYPASS_READ_ONLY_MODE': 1, 'SITE_SETTINGS': 3, 'SITE_SETTINGS_SIDEBARS_BANNERS_BADGES': 3, 'SITE_SETTINGS_SNAPPY_QUOTES': 3, 'SITE_SETTINGS_UNDER_ATTACK': 3, 'SITE_CACHE_PURGE_CDN': 3, 'SITE_CACHE_DUMP_INTERNAL': 2, + 'SITE_WARN_ON_INVALID_AUTH': 1, + 'NOTIFICATIONS_ADMIN_PING': 2, 'NOTIFICATIONS_HOLE_INACTIVITY_DELETION': 2, 'NOTIFICATIONS_HOLE_CREATION': 2, 'NOTIFICATIONS_FROM_SHADOWBANNED_USERS': 3, @@ -256,11 +256,73 @@ FEATURES = { 'PATRON_ICONS': False, } +WERKZEUG_ERROR_DESCRIPTIONS = { + 400: "The browser (or proxy) sent a request that this server could not understand.", + 401: "The server could not verify that you are authorized to access the URL requested. You either supplied the wrong credentials (e.g. a bad password), or your browser doesn't understand how to supply the credentials required.", + 403: "You don't have the permission to access the requested resource. It is either read-protected or not readable by the server.", + 404: "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.", + 405: "The method is not allowed for the requested URL.", + 406: "The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request.", + 409: "A conflict happened while processing the request. The resource might have been modified while the request was being processed.", + 413: "The data value transmitted exceeds the capacity limit.", + 414: "The length of the requested URL exceeds the capacity limit for this server. The request cannot be processed.", + 415: "The server does not support the media type transmitted in the request.", + 417: "The server could not meet the requirements of the Expect header", + 418: "This server is a teapot, not a coffee machine", + 429: "This user has exceeded an allotted request count. Try again later.", + 500: "The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.", +} + +ERROR_TITLES = { + 400: "Bad Request", + 401: "Unauthorized", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Too Many Pings", + 409: "Conflict", + 413: "Payload Too Large", + 415: "Unsupported Media Type", + 418: "I'm a teapot", + 429: "Too Many Requests", + 500: "Internal Server Error", +} + +ERROR_MSGS = { + 400: "That request was bad and you should feel bad.", + 401: "What you're trying to do requires an account. I think. The original error message said something about a castle and I hated that.", + 403: "YOU AREN'T WELCOME HERE GO AWAY", + 404: "Someone typed something wrong and it was probably you, please do better.", + 405: "idk how anyone gets this error but if you see this, remember to follow @carpathianflorist
    the original error text here talked about internet gremlins and wtf", + 406: "Max limit is 5 for comments and 50 for posts", + 409: "There's a conflict between what you're trying to do and what you or someone else has done and because of that you can't do what you're trying to do. So maybe like... don't try and do that? Sorry not sorry", + 413: "That's a heckin' chonker of a file! Please make it smaller or maybe like upload it somewhere else idk", + 415: "Please upload only Image, Video, or Audio files!", + 418: "this really shouldn't happen now that we autoconvert webm files but if it does there's a cool teapot marsey so there's that", + 429: "go spam somewhere else nerd", + 500: "Hiiiii it's carp! I think this error means that there's a timeout error. And I think that means something took too long to load so it decided not to work at all. If you keep seeing this on the same page but not other pages, then something is probably wrong with that specific function. It may not be called a function, but that sounds right to me. Anyway, ping me and I'll whine to someone smarter to fix it. Don't bother them. Thanks ily <3", +} + +ERROR_MARSEYS = { + 400: "marseybrainlet", + 401: "marseydead", + 403: "marseytroll", + 404: "marseyconfused", + 405: "marseyretard", + 406: "marseyrage", + 409: "marseynoyou", + 413: "marseychonker2", + 415: "marseydetective", + 418: "marseytea", + 429: "marseyrentfree", + 500: "marseycarp3", +} + EMOJI_MARSEYS = True EMOJI_SRCS = ['files/assets/emojis.json'] PIN_LIMIT = 3 -POST_RATE_LIMIT = '1/second;2/minute;10/hour;50/day' +POST_RATE_LIMIT = '1/second;10/hour;50/day' POST_TITLE_LENGTH_LIMIT = 500 # do not make larger than 500 without altering the table POST_TITLE_HTML_LENGTH_LIMIT = 1500 # do not make larger than 1500 without altering the table POST_BODY_LENGTH_LIMIT = 20000 # do not make larger than 20000 without altering the table @@ -269,10 +331,13 @@ COMMENT_BODY_LENGTH_LIMIT = 10000 # do not make larger than 10000 characters wit COMMENT_BODY_HTML_LENGTH_LIMIT = 20000 # do not make larger than 20000 characters without altering the table COMMENT_MAX_DEPTH = 200 TRANSFER_MESSAGE_LENGTH_LIMIT = 200 # do not make larger than 10000 characters (comment limit) without altering the table +MIN_REPOST_CHECK_URL_LENGTH = 9 # also change the constant in checkRepost() of submit.js +ADMIN_PING_TRUESCORE_MINIMUM = 500 LOGGEDIN_ACTIVE_TIME = 15 * 60 PFP_DEFAULT_MARSEY = True NOTIFICATION_SPAM_AGE_THRESHOLD = 0.5 * 86400 +COMMENT_SPAM_LENGTH_THRESHOLD = 50 HOLE_NAME = 'hole' HOLE_STYLE_FLAIR = False @@ -307,13 +372,12 @@ DAD_ID = 0 MOM_ID = 0 DONGER_ID = 0 GEESE_ID = 0 +BLACKJACKBTZ_ID = 0 POLL_THREAD = 0 POLL_BET_COINS = 200 WELCOME_MSG = f"Welcome to {SITE_NAME}!" -ROLES={} -CASINO_ENABLED = True LOTTERY_TICKET_COST = 12 LOTTERY_SINK_RATE = 3 LOTTERY_DURATION = 60 * 60 * 24 * 7 @@ -323,16 +387,30 @@ BANNER_THREAD = 0 BADGE_THREAD = 0 SNAPPY_THREAD = 0 GIFT_NOTIF_ID = 5 +SIGNUP_FOLLOW_ID = 0 +NOTIFICATION_THREAD = 1 + +MAX_IMAGE_SIZE_BANNER_RESIZED_KB = 500 +MAX_IMAGE_AUDIO_SIZE_MB = 8 +MAX_IMAGE_AUDIO_SIZE_MB_PATRON = 16 +MAX_VIDEO_SIZE_MB = 32 +MAX_VIDEO_SIZE_MB_PATRON = 64 + +ANTISPAM_BYPASS_IDS = () + +PAGE_SIZE = 25 +LEADERBOARD_LIMIT = PAGE_SIZE if SITE == 'rdrama.net': FEATURES['PRONOUNS'] = True FEATURES['HOUSES'] = True - PERMS['ADMIN_ADD_PERM_LEVEL'] = 0 # extra check here to disallow adding admins on site + PERMS['ADMIN_ADD'] = 4 SIDEBAR_THREAD = 37696 BANNER_THREAD = 37697 BADGE_THREAD = 37833 SNAPPY_THREAD = 37749 + NOTIFICATION_THREAD = 6489 HOLE_COST = 50000 HOLE_INACTIVITY_DELETION = True @@ -363,27 +441,20 @@ if SITE == 'rdrama.net': MOM_ID = 4588 DONGER_ID = 541 GEESE_ID = 1710 + BLACKJACKBTZ_ID = 12732 + + ANTISPAM_BYPASS_IDS = (1703, 13427) GIFT_NOTIF_ID = CARP_ID POLL_THREAD = 79285 - WELCOME_MSG = "Hi there! It's me, your soon-to-be favorite rDrama user @carpathianflorist here to give you a brief rundown on some of the sick features we have here. You'll probably want to start by following me, though. So go ahead and click my name and then smash that Follow button. This is actually really important, so go on. Hurry.\n\nThanks!\n\nNext up: If you're a member of the media, similarly just shoot me a DM and I'll set about verifying you and then we can take care of your sad journalism stuff.\n\n**FOR EVERYONE ELSE**\n\n Begin by navigating to [the settings page](/settings/profile) (we'll be prettying this up so it's less convoluted soon, don't worry) and getting some basic customization done.\n\n### Themes\n\nDefinitely change your theme right away, the default one (Midnight) is pretty enough, but why not use something *exotic* like Win98, or *flashy* like Tron? Even Coffee is super tasteful and way more fun than the default. More themes to come when we get around to it!\n\n### Avatar/pfp\n\nYou'll want to set this pretty soon. Set the banner too while you're at it. Your profile is important!\n\n### Flairs\n\nSince you're already on the settings page, you may as well set a flair, too. As with your username, you can - obviously - choose the color of this, either with a hex value or just from the preset colors. And also like your username, you can change this at any time. [Paypigs](https://marsey1.gumroad.com/l/rdrama) can even further relive the glory days of 90s-00s internet and set obnoxious signatures.\n\n### PROFILE ANTHEMS\n\nSpeaking of profiles, hey, remember MySpace? Do you miss autoplaying music assaulting your ears every time you visited a friend's page? Yeah, we brought that back. Enter a YouTube URL, wait a few seconds for it to process, and then BAM! you've got a profile anthem which people cannot mute. Unless they spend 20,000 dramacoin in the shop for a mute button. Which you can then remove from your profile by spending 40,000 dramacoin on an unmuteable anthem. Get fucked poors!\n\n### Dramacoin?\n\nDramacoin is basically our take on the karma system. Except unlike the karma system, it's not gay and boring and stupid and useless. Dramacoin can be spent at [Marsey's Dramacoin Emporium](/shop) on upgrades to your user experience (many more coming than what's already listed there), and best of all on tremendously annoying awards to fuck with your fellow dramautists. We're always adding more, so check back regularly in case you happen to miss one of the announcement posts.\n\nLike karma, dramacoin is obtained by getting upvotes on your threads and comments. *Unlike* karma, it's also obtained by getting downvotes on your threads and comments. Downvotes don't really do anything here - they pay the same amount of dramacoin and they increase thread/comment ranking just the same as an upvote. You just use them to express petty disapproval and hopefully start a fight. Because all votes are visible here. To hell with your anonymity.\n\nDramacoin can also be traded amongst users from their profiles. Note that there is a 3% transaction fee.\n\n### Badges\n\nRemember all those neat little metallic icons you saw on my profile when you were following me? If not, scroll back up and go have a look. And doublecheck to make sure you pressed the Follow button. Anyway, those are badges. You earn them by doing a variety of things. Some of them even offer benefits, like discounts at the shop. A [complete list of badges and their requirements can be found here](/badges), though I add more pretty regularly, so keep an eye on the [changelog](/h/changelog).\n\n### Other stuff\n\nWe're always adding new features, and we take a fun-first approach to development. If you have a suggestion for something that would be fun, funny, annoying - or best of all, some combination of all three - definitely make a thread about it. Or just DM me if you're shy. Weirdo. Anyway there's also the [leaderboards](/leaderboard), boring stuff like two-factor authentication you can toggle on somewhere in the settings page (psycho), the ability to save posts and comments, more than a thousand emojis already (most of which are rDrama originals), and on and on and on and on. This is just the basics, mostly to help you get acquainted with some of the things you can do here to make it more easy on the eyes, customizable, and enjoyable. If you don't enjoy it, just go away! We're not changing things to suit you! Get out of here loser! And no, you can't delete your account :na:\n\nI love you.
    *xoxo Carp* 💋" - ROLES={ - "admin": "992254560330600508", - "linked": "890342909390520382", - "1": "868129042346414132", - "2": "875569477671067688", - "3": "869434199575236649", - "4": "868140288013664296", - "5": "947236580794450010", - "6": "947236351445725204", - "7": "886781932430565418", - } + WELCOME_MSG = "Hi there! It's me, your soon-to-be favorite rDrama user @carpathianflorist here to give you a brief rundown on some of the sick features we have here. You'll probably want to start by following me, though. So go ahead and click my name and then smash that Follow button. This is actually really important, so go on. Hurry.\n\nThanks!\n\nNext up: If you're a member of the media, similarly just shoot me a DM and I'll set about verifying you and then we can take care of your sad journalism stuff.\n\n**FOR EVERYONE ELSE**\n\n Begin by navigating to [the settings page](/settings/profile) (we'll be prettying this up so it's less convoluted soon, don't worry) and getting some basic customization done.\n\n### Themes\n\nDefinitely change your theme right away, the default one (Midnight) is pretty enough, but why not use something *exotic* like Win98, or *flashy* like Tron? Even Coffee is super tasteful and way more fun than the default. More themes to come when we get around to it!\n\n### Avatar/pfp\n\nYou'll want to set this pretty soon. Set the banner too while you're at it. Your profile is important!\n\n### Flairs\n\nSince you're already on the settings page, you may as well set a flair, too. As with your username, you can - obviously - choose the color of this, either with a hex value or just from the preset colors. And also like your username, you can change this at any time. Paypigs can even further relive the glory days of 90s-00s internet and set obnoxious signatures.\n\n### PROFILE ANTHEMS\n\nSpeaking of profiles, hey, remember MySpace? Do you miss autoplaying music assaulting your ears every time you visited a friend's page? Yeah, we brought that back. Enter a YouTube URL, wait a few seconds for it to process, and then BAM! you've got a profile anthem which people cannot mute. Unless they spend 20,000 dramacoin in the shop for a mute button. Which you can then remove from your profile by spending 40,000 dramacoin on an unmuteable anthem. Get fucked poors!\n\n### Dramacoin?\n\nDramacoin is basically our take on the karma system. Except unlike the karma system, it's not gay and boring and stupid and useless. Dramacoin can be spent at [Marsey's Dramacoin Emporium](/shop) on upgrades to your user experience (many more coming than what's already listed there), and best of all on tremendously annoying awards to fuck with your fellow dramautists. We're always adding more, so check back regularly in case you happen to miss one of the announcement posts.\n\nLike karma, dramacoin is obtained by getting upvotes on your threads and comments. *Unlike* karma, it's also obtained by getting downvotes on your threads and comments. Downvotes don't really do anything here - they pay the same amount of dramacoin and they increase thread/comment ranking just the same as an upvote. You just use them to express petty disapproval and hopefully start a fight. Because all votes are visible here. To hell with your anonymity.\n\nDramacoin can also be traded amongst users from their profiles. Note that there is a 3% transaction fee.\n\n### Badges\n\nRemember all those neat little metallic icons you saw on my profile when you were following me? If not, scroll back up and go have a look. And doublecheck to make sure you pressed the Follow button. Anyway, those are badges. You earn them by doing a variety of things. Some of them even offer benefits, like discounts at the shop. A [complete list of badges and their requirements can be found here](/badges), though I add more pretty regularly, so keep an eye on the [changelog](/h/changelog).\n\n### Other stuff\n\nWe're always adding new features, and we take a fun-first approach to development. If you have a suggestion for something that would be fun, funny, annoying - or best of all, some combination of all three - definitely make a thread about it. Or just DM me if you're shy. Weirdo. Anyway there's also the [leaderboards](/leaderboard), boring stuff like two-factor authentication you can toggle on somewhere in the settings page (psycho), the ability to save posts and comments, more than a thousand emojis already (most of which are rDrama originals), and on and on and on and on. This is just the basics, mostly to help you get acquainted with some of the things you can do here to make it more easy on the eyes, customizable, and enjoyable. If you don't enjoy it, just go away! We're not changing things to suit you! Get out of here loser! And no, you can't delete your account :na:\n\nI love you.
    *xoxo Carp* 💋" elif SITE == 'pcmemes.net': PIN_LIMIT = 10 FEATURES['REPOST_DETECTION'] = False - FEATURES['GAMBLING'] = False + ERROR_MSGS[500] = "Hiiiii it's nigger! I think this error means that there's a nigger error. And I think that means something took too long to load so it decided to be a nigger. If you keep seeing this on the same page but not other pages, then something its probably a niggerfaggot. It may not be called a nigger, but that sounds right to me. Anyway, ping me and I'll whine to someone smarter to fix it. Don't bother them. Thanks ily <3" + ERROR_MARSEYS[500] = "wholesome" POST_RATE_LIMIT = '1/second;4/minute;20/hour;100/day' HOLE_COST = 2000 @@ -395,24 +466,28 @@ elif SITE == 'pcmemes.net': BASEDBOT_ID = 800 KIPPY_ID = 1592 - GIFT_NOTIF_ID = 1592 + GIFT_NOTIF_ID = KIPPY_ID + SIGNUP_FOLLOW_ID = KIPPY_ID + NOTIFICATION_THREAD = 2487 CARP_ID = 13 AEVANN_ID = 1 SNAKES_ID = 2279 - WELCOME_MSG = "Welcome to pcmemes.net! Don't forget to turn off the slur filter [here](/settings/content#slurreplacer)" + WELCOME_MSG = "Welcome to pcmemes.net! Don't forget to turn off the slur filter [here](/settings/content#slurreplacer)!" - CASINO_ENABLED = False LOTTERY_TICKET_COST = 12 LOTTERY_SINK_RATE = -8 BANNER_THREAD = 28307 -elif SITE == 'watchpeopledie.co': - WELCOME_MSG = """Hi, you! Welcome to WatchPeopleDie.co, this really cool site where you can go to watch people die. I'm @CLiTPEELER! If you have any questions about how things work here, or suggestions on how to make them work better than they already do, definitely slide on into my DMs (no fat chicks).\nThere's an enormously robust suite of fun features we have here and we're always looking for more to add. Way, way too many to go over in an automated welcome message. And you're probably here for the videos of people dying more than any sort of weird, paradoxical digital community aspect anyway, so I won't bore you with a tedious overview of them. Just head on over to [your settings page](https://watchpeopledie.co/settings/profile) and have a look at some of the basic profile stuff, at least. You can change your profile picture, username, flair, colors, banners, bio, profile anthem (autoplaying song on your page, like it's MySpace or some shit, hell yeah), CSS, all sorts of things.\nOr you can just go back to the main feed and carry on with watching people die. That's what the site is for, after all. Have fun!\nThough, while I have your attention (realistically I probably don't; this is quite a lot of text) - if you'd like to fund WPD's continued existence in the face of commercial and governmental censors, it would be really cool if you'd stop by our [Kofi page](https://ko-fi.com/wpdco/tiers) and consider contributing some paltry sum each month to help us pay for hosting. *But only if you want*. **We do not serve ads. We will never serve ads. We do not sell data. We will never sell data. We do not paywall ANY usage of the site. We will never paywall ANY usage of the site.** Any and all contributions are strictly voluntary and should only be because you'd like to help the site continue to grow and thrive.\nAnyway, in closing, WPD is entirely open source. We don't really need new full-time coders or anything, but if you'd like to take a look at our repo - or even submit a PR to change, fix, or add some things - go right ahead! We are on [GitHub](https://github.com/Aevann1/rDrama).\nWell, that's all. Thanks again for signing up. It's an automated message and all, but I really do mean that. Thank you, specifically. I love you. Romantically. Deeply. Passionately.\nHave fun!""" +elif SITE == 'watchpeopledie.tv': + PIN_LIMIT = 4 + WELCOME_MSG = """Hi, you! Welcome to WatchPeopleDie.tv, this really cool site where you can go to watch people die. I'm @CLiTPEELER! If you have any questions about how things work here, or suggestions on how to make them work better than they already do, definitely slide on into my DMs (no fat chicks).\nThere's an enormously robust suite of fun features we have here and we're always looking for more to add. Way, way too many to go over in an automated welcome message. And you're probably here for the videos of people dying more than any sort of weird, paradoxical digital community aspect anyway, so I won't bore you with a tedious overview of them. Just head on over to [your settings page](https://watchpeopledie.tv/settings/profile) and have a look at some of the basic profile stuff, at least. You can change your profile picture, username, flair, colors, banners, bio, profile anthem (autoplaying song on your page, like it's MySpace or some shit, hell yeah), CSS, all sorts of things.\nOr you can just go back to the main feed and carry on with watching people die. That's what the site is for, after all. Have fun!\nAnyway, in closing, WPD is entirely open source. We don't really need new full-time coders or anything, but if you'd like to take a look at our repo - or even submit a PR to change, fix, or add some things - go right ahead! We are on [GitHub](https://github.com/Aevann1/rDrama).\nWell, that's all. Thanks again for signing up. It's an automated message and all, but I really do mean that. Thank you, specifically. I love you. Romantically. Deeply. Passionately.\nHave fun!""" FEATURES['PATRON_ICONS'] = True PERMS['HOLE_CREATE'] = 2 + PERMS['POST_EDITING'] = 2 + PERMS['ADMIN_ADD'] = 4 SIDEBAR_THREAD = 5403 BANNER_THREAD = 9869 @@ -431,6 +506,7 @@ elif SITE == 'watchpeopledie.co': SNAKES_ID = 32 GIFT_NOTIF_ID = CARP_ID + SIGNUP_FOLLOW_ID = CARP_ID else: # localhost or testing environment implied FEATURES['PRONOUNS'] = True @@ -441,6 +517,7 @@ bots = {AUTOJANNY_ID, SNAPPY_ID, LONGPOSTBOT_ID, ZOZBOT_ID, BASEDBOT_ID} COLORS = {'ff66ac','805ad5','62ca56','38a169','80ffff','2a96f3','eb4963','ff0000','f39731','30409f','3e98a7','e4432d','7b9ae4','ec72de','7f8fa6', 'f8db58','8cdbe6', DEFAULT_COLOR} AWARDS = { + ### Deprecated "ghost": { "kind": "ghost", "title": "Ghost", @@ -457,6 +534,7 @@ AWARDS = { "color": "text-success", "price": 10000 }, + ### Fistmas 2021 "snow": { "kind": "snow", "title": "Snow", @@ -505,6 +583,7 @@ AWARDS = { "color": "text-green-500", "price": 1000 }, + ### Homoween 2021 & 2022 "haunt": { "kind": "haunt", "title": "Haunt", @@ -545,13 +624,87 @@ AWARDS = { "color": "text-gray", "price": 200 }, + ### Homoween 2022 + "jumpscare": { + "kind": "jumpscare", + "title": "Jumpscare", + "description": "", + "icon": "fas fa-coffin-cross", + "color": "text-purple", + "price": 600 + }, + "hw-bite": { + "kind": "hw-bite", + "title": "Zombie Bite", + "description": "", + "icon": "fas fa-biohazard", + "color": "text-danger", + "price": 500 + }, + "hw-vax": { + "kind": "hw-vax", + "title": "Vaxxmaxx", + "description": "", + "icon": "fas fa-syringe", + "color": "text-blue", + "price": 500 + }, + "hw-grinch": { + "kind": "hw-grinch", + "title": "Hallowgrinch", + "description": "", + "icon": "fas fa-angry", + "color": "text-orange", + "price": 1000 + }, + "flashlight": { + "kind": "flashlight", + "title": "Flashlight", + "description": "", + "icon": "fas fa-flashlight", + "color": "text-black", + "price": 400 + }, + "candy-corn": { + "kind": "candy-corn", + "title": "Candy Corn", + "description": "", + "icon": "fas fa-candy-corn", + "color": "text-orange", + "price": 400 + }, + "ectoplasm": { + "kind": "ectoplasm", + "title": "Ectoplasm", + "description": "", + "icon": "fas fa-ghost", + "color": "text-success", + "price": 400 + }, + "bones": { + "kind": "bones", + "title": "Bones", + "description": "", + "icon": "fas fa-bone", + "color": "text-white", + "price": 200 + }, + "pumpkin": { + "kind": "pumpkin", + "title": "Pumpkin", + "description": "", + "icon": "fas fa-jack-o-lantern", + "color": "text-orange", + "price": 200 + }, + ### Standard "marsify": { "kind": "marsify", "title": "Marsify", "description": "Marsifies the recipient's comments for 6 hours.", "icon": "fas fa-cat", "color": "text-white", - "price": 400 + "price": 150 }, "shit": { "kind": "shit", @@ -559,7 +712,7 @@ AWARDS = { "description": "Makes flies swarm the post.", "icon": "fas fa-poop", "color": "text-black-50", - "price": 500 + "price": 150 }, "fireflies": { "kind": "fireflies", @@ -567,7 +720,7 @@ AWARDS = { "description": "Makes fireflies swarm the post.", "icon": "fas fa-sparkles", "color": "text-warning", - "price": 500 + "price": 150 }, "train": { "kind": "train", @@ -575,7 +728,7 @@ AWARDS = { "description": "Summons a train on the post.", "icon": "fas fa-train", "color": "text-pink", - "price": 500 + "price": 150 }, "scooter": { "kind": "scooter", @@ -583,7 +736,7 @@ AWARDS = { "description": "Summons a scooter on the post.", "icon": "fas fa-flag-usa", "color": "text-muted", - "price": 500 + "price": 150 }, "wholesome": { "kind": "wholesome", @@ -591,7 +744,7 @@ AWARDS = { "description": "Summons a wholesome marsey on the post.", "icon": "fas fa-smile-beam", "color": "text-yellow", - "price": 500 + "price": 150 }, "firework": { "kind": "firework", @@ -599,7 +752,7 @@ AWARDS = { "description": "Summons fireworks on the post.", "icon": "fas fa-bahai", "color": "text-danger", - "price": 500 + "price": 150 }, "confetti": { "kind": "confetti", @@ -607,7 +760,7 @@ AWARDS = { "description": "Summons confetti to fall on the post.", "icon": "fas fa-party-horn", "color": "text-yellow", - "price": 500 + "price": 150 }, "ricardo": { "kind": "ricardo", @@ -615,7 +768,7 @@ AWARDS = { "description": "Summons Ricardo to dance on the post.", "icon": "fas fa-pinata", "color": "text-pink", - "price": 500 + "price": 150 }, "tilt": { "kind": "tilt", @@ -623,7 +776,7 @@ AWARDS = { "description": "Tilts the post or comment", "icon": "fas fa-car-tilt", "color": "text-blue", - "price": 500 + "price": 150 }, "glowie": { "kind": "glowie", @@ -631,7 +784,7 @@ AWARDS = { "description": "Indicates that the recipient can be seen when driving. Just run them over.", "icon": "fas fa-user-secret", "color": "text-green", - "price": 500 + "price": 150 }, "rehab": { "kind": "rehab", @@ -641,6 +794,14 @@ AWARDS = { "color": "text-black", "price": 777 }, + "offsitementions": { + "kind": "offsitementions", + "title": "Y'all Seein' Eye", + "description": "Gives the recipient access to notifications when people off-site talk about us.", + "icon": "fas fa-eyes", + "color": "text-orange", + "price": 1000, + }, "lootbox": { "kind": "lootbox", "title": "Lootbox", @@ -706,13 +867,13 @@ AWARDS = { "price": 1500 }, "spider": { - "kind": "spider", - "title": "Spider!", - "description": f"Summons a spider to terrorize the recipient for 24 hours.", - "icon": "fas fa-spider", - "color": "text-brown", - "price": 2000 - }, + "kind": "spider", + "title": "Spider!", + "description": f"Summons a spider to terrorize the recipient for 24 hours.", + "icon": "fas fa-spider", + "color": "text-brown", + "price": 2000 + }, "agendaposter": { "kind": "agendaposter", "title": "Chud", @@ -777,14 +938,6 @@ AWARDS = { "color": "text-silver", "price": 10000 }, - "offsitementions": { - "kind": "offsitementions", - "title": "Y'all Seein' Eye", - "description": "Gives the recipient access to notifications when people off-site talk about us.", - "icon": "fas fa-eyes", - "color": "text-orange", - "price": 10000, - }, "unblockable": { "kind": "unblockable", "title": "Unblockable", @@ -864,7 +1017,7 @@ if SITE_NAME == 'PCM': "description": "Summons Croag on the post.", "icon": "fas fa-head-side", "color": "text-gold", - "price": 500 + "price": 150 }, "toe": { "kind": "toe", @@ -872,7 +1025,7 @@ if SITE_NAME == 'PCM': "description": "Summons Blade's toe on the post.", "icon": "fas fa-socks", "color": "text-blue", - "price": 500 + "price": 150 }, "crab": { "kind": "crab", @@ -888,8 +1041,10 @@ if SITE_NAME == 'PCM': # Disable unused awards, and site-specific award inclusion/exclusion. AWARDS_DISABLED = [ 'ghost', 'nword', 'lootbox', # Generic - 'snow', 'gingerbread', 'lights', 'candycane', 'fireplace', # Fistmas - 'grinch', 'haunt', 'upsidedown', 'stab', 'spiders', 'fog', # Homoween + 'snow', 'gingerbread', 'lights', 'candycane', 'fireplace', 'grinch', # Fistmas + 'haunt', 'upsidedown', 'stab', 'spiders', 'fog', # Homoween '21 + 'jumpscare', 'hw-bite', 'hw-vax', 'hw-grinch', 'flashlight', # Homoween '22 + 'candy-corn', 'ectoplasm', 'bones', 'pumpkin', # Homoween '22 (cont'd) ] @@ -937,8 +1092,10 @@ for k, val in temp: if SITE_NAME != 'rDrama': AWARDS_DISABLED.append('progressivestack') -if SITE == 'pcmemes.net': - AWARDS_DISABLED.extend(['ban','pizzashill','marsey','bird','grass','chud','unblockable']) +if SITE_NAME == 'PCM': + # Previous set of disabled, changed temporarily by request 2022-10-17 + #AWARDS_DISABLED.extend(['ban','pizzashill','marsey','bird','grass','chud','unblockable']) + AWARDS_DISABLED.extend(['unblockable']) AWARDS_DISABLED.remove('ghost') elif SITE_NAME == 'WPD': AWARDS_DISABLED.remove('lootbox') @@ -960,8 +1117,6 @@ TROLLTITLES = [ NOTIFIED_USERS = { 'aevan': AEVANN_ID, - ' aev': AEVANN_ID, - 'aev ': AEVANN_ID, 'avean': AEVANN_ID, 'joan': JOAN_ID, 'pewkie': JOAN_ID, @@ -973,6 +1128,7 @@ NOTIFIED_USERS = { 'scitzocel': SCHIZO_ID, 'snakes': SNAKES_ID, 'sneks': SNAKES_ID, + 'jc': JUSTCOOL_ID, 'justcool': JUSTCOOL_ID, 'geese': GEESE_ID, 'clit': CARP_ID, @@ -1003,6 +1159,8 @@ if SITE != 'localhost': if SITE == 'rdrama.net': REDDIT_NOTIFS_SITE.add('marsey') + REDDIT_NOTIFS_SITE.add('"r/Drama"') + REDDIT_NOTIFS_SITE.add('justice4darrell') REDDIT_NOTIFS_USERS = { 'idio3': IDIO_ID, 'aevann': AEVANN_ID, @@ -1010,6 +1168,7 @@ if SITE == 'rdrama.net': 'carpathianflorist': CARP_ID, 'carpathian florist': CARP_ID, 'the_homocracy': HOMO_ID, + 'justcool393': JUSTCOOL_ID } elif SITE_NAME == 'WPD': REDDIT_NOTIFS_SITE.update({'watchpeopledie', 'makemycoffin'}) @@ -1068,7 +1227,7 @@ approved_embed_hosts = { SITE, 'rdrama.net', 'pcmemes.net', - 'watchpeopledie.co', + 'watchpeopledie.tv', 'imgur.com', 'lain.la', 'pngfind.com', @@ -1158,11 +1317,9 @@ tiers={ "(Jigsaw)": 6, } -DISCORD_WELCOME_CHANNEL = "846509313941700618" - has_sidebar = path.exists(f'files/templates/sidebar_{SITE_NAME}.html') has_logo = path.exists(f'files/assets/images/{SITE_NAME}/logo.webp') -has_app = path.exists(f'files/assets/app_{SITE_NAME}_v2.4.apk') +has_app = path.exists(f'files/assets/app_{SITE_NAME}_v2.5.apk') ONLINE_STR = f'{SITE}_online' @@ -1180,3 +1337,5 @@ forced_hats = { "is_suspended": ("Behind Bars", "This user is banned and needs to do better!"), "agendaposter": ("Egg_irl", "This user is getting in touch with xir identity!") } + +EMAIL_REGEX_PATTERN = '[A-Za-z0-9._%+-]{1,64}@[A-Za-z0-9.-]{2,63}\.[A-Za-z]{2,63}' diff --git a/files/helpers/discord.py b/files/helpers/discord.py index dd72bb077..ca92db46b 100644 --- a/files/helpers/discord.py +++ b/files/helpers/discord.py @@ -1,54 +1,17 @@ import requests -import threading + from .const import * -headers = {"Authorization": f"Bot {DISCORD_BOT_TOKEN}"} - -def discord_wrap(f): - - def wrapper(*args, **kwargs): - - user=args[0] - if not user.discord_id: - return - - - thread=threading.Thread(target=f, args=args, kwargs=kwargs) - thread.start() - - wrapper.__name__=f.__name__ - return wrapper - - - -@discord_wrap -def add_role(user, role_name): - role_id = ROLES[role_name] - url = f"https://discordapp.com/api/guilds/{DISCORD_SERVER_ID}/members/{user.discord_id}/roles/{role_id}" - requests.put(url, headers=headers, timeout=5) - -@discord_wrap -def remove_role(user, role_name): - role_id = ROLES[role_name] - url = f"https://discordapp.com/api/guilds/{DISCORD_SERVER_ID}/members/{user.discord_id}/roles/{role_id}" - requests.delete(url, headers=headers, timeout=5) - -@discord_wrap -def remove_user(user): - url=f"https://discordapp.com/api/guilds/{DISCORD_SERVER_ID}/members/{user.discord_id}" - requests.delete(url, headers=headers, timeout=5) - -@discord_wrap -def set_nick(user, nick): - url=f"https://discordapp.com/api/guilds/{DISCORD_SERVER_ID}/members/{user.discord_id}" - data={"nick": nick} - requests.patch(url, headers=headers, json=data, timeout=5) +def discord_message_send(channel_id, message): + requests.post( + f"https://discordapp.com/api/channels/{channel_id}/messages", + headers={"Authorization": f"Bot {DISCORD_BOT_TOKEN}"}, + data={"content": message}, + timeout=5) def send_changelog_message(message): - data={"content": message} - requests.post("https://discordapp.com/api/channels/924485611715452940/messages", headers=headers, data=data, timeout=5) - requests.post("https://discordapp.com/api/channels/1013992002624426015/messages", headers=headers, data=data, timeout=5) + for channel_id in DISCORD_CHANGELOG_CHANNEL_IDS: + discord_message_send(channel_id, message) def send_wpd_message(message): - data={"content": message} - requests.post("https://discordapp.com/api/channels/1013990963846332456/messages", headers=headers, data=data, timeout=5) + discord_message_send(WPD_CHANNEL_ID, message) diff --git a/files/helpers/get.py b/files/helpers/get.py index 58710d4a9..04c99289a 100644 --- a/files/helpers/get.py +++ b/files/helpers/get.py @@ -1,10 +1,16 @@ +from typing import Callable, Iterable, List, Optional, Union from files.classes import * from flask import g -def get_id(username, graceful=False): - - username = username.replace('\\', '').replace('_', '\_').replace('%', '').strip() +def sanitize_username(username:str) -> str: + if not username: return username + return username.replace('\\', '').replace('_', '\_').replace('%', '').replace('(', '').replace(')', '').strip() +def get_id(username:str, graceful=False) -> Optional[int]: + username = sanitize_username(username) + if not username: + if graceful: return None + abort(404) user = g.db.query( User.id ).filter( @@ -15,19 +21,20 @@ def get_id(username, graceful=False): ).one_or_none() if not user: - if not graceful: abort(404) - else: return None + if graceful: return None + abort(404) return user[0] - -def get_user(username, v=None, graceful=False, rendered=False, include_blocks=False, include_shadowbanned=True): +def get_user(username:str, v:Optional[User]=None, graceful=False, rendered=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]: if not username: - if not graceful: abort(404) - else: return None - - username = username.replace('\\', '').replace('_', '\_').replace('%', '').replace('(', '').replace(')', '').strip() + if graceful: return None + abort(404) + username = sanitize_username(username) + if not username: + if graceful: return None + abort(404) user = g.db.query( User ).filter( @@ -39,40 +46,20 @@ def get_user(username, v=None, graceful=False, rendered=False, include_blocks=Fa user = user.one_or_none() - if not user or (user.shadowbanned and not (include_shadowbanned or (v and (v.admin_level >= PERMS['USER_SHADOWBAN'] or v.shadowbanned)))): - if not graceful: abort(404) - else: return None + if not user or (user.shadowbanned and not (include_shadowbanned or (v and v.can_see_shadowbanned))): + if graceful: return None + abort(404) if rendered and v and include_blocks: - if v.id == user.id: - user.is_blocked = False - user.is_blocking = False - else: - block = g.db.query(UserBlock).filter( - or_( - and_( - UserBlock.user_id == v.id, - UserBlock.target_id == user.id - ), - and_(UserBlock.user_id == user.id, - UserBlock.target_id == v.id - ) - ) - ).first() - - user.is_blocking = block and block.user_id == v.id - user.is_blocked = block and block.target_id == v.id - - + user = add_block_props(user, v) return user -def get_users(usernames, graceful=False): - - def clean(n): - return n.replace('\\', '').replace('_', '\_').replace('%', '').strip() - - usernames = [clean(n) for n in usernames] - +def get_users(usernames:Iterable[str], graceful=False) -> List[User]: + if not usernames: return [] + usernames = [sanitize_username(n) for n in usernames] + if not any(usernames): + if graceful and len(usernames) == 0: return [] + abort(404) users = g.db.query(User).filter( or_( User.username.ilike(any_(usernames)), @@ -85,43 +72,29 @@ def get_users(usernames, graceful=False): return users -def get_account(id, v=None, graceful=False, include_blocks=False, include_shadowbanned=True): - +def get_account(id:Union[str, int], v:Optional[User]=None, graceful=False, include_blocks=False, include_shadowbanned=True) -> Optional[User]: try: id = int(id) except: - if not graceful: abort(404) - else: return None + if graceful: return None + abort(404) user = g.db.get(User, id) - if not user or (user.shadowbanned and not (include_shadowbanned or (v and (v.admin_level >= PERMS['USER_SHADOWBAN'] or v.shadowbanned)))): + if not user or (user.shadowbanned and not (include_shadowbanned or (v and v.can_see_shadowbanned))): if not graceful: abort(404) else: return None - if v and include_blocks: - block = g.db.query(UserBlock).filter( - or_( - and_( - UserBlock.user_id == v.id, - UserBlock.target_id == user.id - ), - and_(UserBlock.user_id == user.id, - UserBlock.target_id == v.id - ) - ) - ).first() - - user.is_blocking = block and block.user_id == v.id - user.is_blocked = block and block.target_id == v.id - + if include_blocks: + user = add_block_props(user, v) return user -def get_post(i, v=None, graceful=False): - +def get_post(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Optional[Submission]: try: i = int(i) - except: abort(404) + except: + if graceful: return None + else: abort(404) if not i: if graceful: return None @@ -167,10 +140,8 @@ def get_post(i, v=None, graceful=False): return x -def get_posts(pids, v=None): - - if not pids: - return [] +def get_posts(pids:Iterable[int], v:Optional[User]=None) -> List[Submission]: + if not pids: return [] if v: vt = g.db.query(Vote.vote_type, Vote.submission_id).filter( @@ -210,10 +181,11 @@ def get_posts(pids, v=None): return sorted(output, key=lambda x: pids.index(x.id)) -def get_comment(i, v=None, graceful=False): - +def get_comment(i:Union[str, int], v:Optional[User]=None, graceful=False) -> Optional[Comment]: try: i = int(i) - except: abort(404) + except: + if graceful: return None + abort(404) if not i: if graceful: return None @@ -224,81 +196,113 @@ def get_comment(i, v=None, graceful=False): if graceful: return None else: abort(404) - if v: - block = g.db.query(UserBlock).filter( - or_( - and_( - UserBlock.user_id == v.id, - UserBlock.target_id == comment.author_id - ), - and_( - UserBlock.user_id == comment.author_id, - UserBlock.target_id == v.id - ) + return add_vote_and_block_props(comment, v, CommentVote) + +def add_block_props(target:Union[Submission, Comment, User], v:Optional[User]): + if not v: return target + id = None + + if any(isinstance(target, cls) for cls in [Submission, Comment]): + id = target.author_id + elif isinstance(target, User): + id = target.id + else: + raise TypeError("add_block_props only supports non-None submissions, comments, and users") + + if hasattr(target, 'is_blocking') and hasattr(target, 'is_blocked'): + return target + + if v.id == id or id == AUTOJANNY_ID: # users can't block or be blocked by themselves or AutoJanny + target.is_blocking = False + target.is_blocked = False + return target + + block = g.db.query(UserBlock).filter( + or_( + and_( + UserBlock.user_id == v.id, + UserBlock.target_id == id + ), + and_( + UserBlock.user_id == id, + UserBlock.target_id == v.id ) - ).first() + ) + ).first() + target.is_blocking = block and block.user_id == v.id + target.is_blocked = block and block.target_id == v.id + return target - vt = g.db.query(CommentVote.vote_type).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() - comment.is_blocking = block and block.user_id == v.id - comment.is_blocked = block and block.target_id == v.id - comment.voted = vt.vote_type if vt else 0 +def add_vote_props(target:Union[Submission, Comment], v:Optional[User], vote_cls): + if hasattr(target, 'voted'): return target - return comment + vt = g.db.query(vote_cls.vote_type).filter_by(user_id=v.id) + if vote_cls == Vote: + vt = vt.filter_by(submission_id=target.id) + elif vote_cls == CommentVote: + vt = vt.filter_by(comment_id=target.id) + else: + vt = None + if vt: vt = vt.one_or_none() + target.voted = vt.vote_type if vt else 0 + return target +def add_vote_and_block_props(target:Union[Submission, Comment], v:Optional[User], vote_cls): + if not v: return target + target = add_block_props(target, v) + return add_vote_props(target, v, vote_cls) -def get_comments(cids, v=None, load_parent=False): - +def get_comments(cids:Iterable[int], v:Optional[User]=None) -> List[Comment]: if not cids: return [] - if v: - votes = g.db.query(CommentVote.vote_type, CommentVote.comment_id).filter_by(user_id=v.id).subquery() - - blocking = v.blocking.subquery() - - blocked = v.blocked.subquery() - - comments = g.db.query( - Comment, - votes.c.vote_type, - blocking.c.target_id, - blocked.c.target_id, - ).filter(Comment.id.in_(cids)) - - if not (v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN'])): - comments = comments.join(Comment.author).filter(User.shadowbanned == None) - - comments = comments.join( - votes, - votes.c.comment_id == Comment.id, - isouter=True - ).join( - blocking, - blocking.c.target_id == Comment.author_id, - isouter=True - ).join( - blocked, - blocked.c.user_id == Comment.author_id, - isouter=True - ).all() - - output = [] - for c in comments: - comment = c[0] - comment.voted = c[1] or 0 - comment.is_blocking = c[2] or 0 - comment.is_blocked = c[3] or 0 - output.append(comment) - + output = get_comments_v_properties(v, True, None, Comment.id.in_(cids))[1] else: output = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.id.in_(cids)).all() - - if load_parent: - parents = [x.parent_comment_id for x in output if x.parent_comment_id] - parents = get_comments(parents, v=v) - return sorted(output, key=lambda x: cids.index(x.id)) -def get_sub_by_name(sub, v=None, graceful=False): +def get_comments_v_properties(v:User, include_shadowbanned=True, should_keep_func:Optional[Callable[[Comment], bool]]=None, *criterion): + if not v: + raise TypeError("A user is required") + votes = g.db.query(CommentVote.vote_type, CommentVote.comment_id).filter_by(user_id=v.id).subquery() + blocking = v.blocking.subquery() + blocked = v.blocked.subquery() + comments = g.db.query( + Comment, + votes.c.vote_type, + blocking.c.target_id, + blocked.c.target_id, + ) + + if not include_shadowbanned and not v.can_see_shadowbanned: + comments = comments.join(Comment.author).filter(User.shadowbanned == None) + + comments = comments.filter(*criterion) + comments = comments.join( + votes, + votes.c.comment_id == Comment.id, + isouter=True + ).join( + blocking, + blocking.c.target_id == Comment.author_id, + isouter=True + ).join( + blocked, + blocked.c.user_id == Comment.author_id, + isouter=True + ) + queried = comments.all() + output = [] + dump = [] + for c in queried: + comment = c[0] + comment.voted = c[1] or 0 + comment.is_blocking = c[2] or 0 + comment.is_blocked = c[3] or 0 + if not should_keep_func or should_keep_func(c[0]): output.append(comment) + else: dump.append(comment) + return (comments, output) + +def get_sub_by_name(sub:str, v:Optional[User]=None, graceful=False) -> Optional[Sub]: if not sub: if graceful: return None else: abort(404) @@ -311,23 +315,3 @@ def get_sub_by_name(sub, v=None, graceful=False): if graceful: return None else: abort(404) return sub - -def get_domain(s): - - parts = s.split(".") - domain_list = set() - for i in range(len(parts)): - new_domain = parts[i] - for j in range(i + 1, len(parts)): - new_domain += "." + parts[j] - - domain_list.add(new_domain) - - doms = g.db.query(BannedDomain).filter(BannedDomain.domain.in_(domain_list)).all() - - if not doms: - return None - - doms = sorted(doms, key=lambda x: len(x.domain), reverse=True) - - return doms[0] diff --git a/files/helpers/jinja2.py b/files/helpers/jinja2.py index d8113de80..b4ad87454 100644 --- a/files/helpers/jinja2.py +++ b/files/helpers/jinja2.py @@ -5,6 +5,7 @@ from os import listdir, environ from .const import * import time from files.helpers.assetcache import assetcache_path +from files.helpers.wrappers import calc_users @app.template_filter("post_embed") def post_embed(id, v): @@ -28,34 +29,7 @@ def template_asset_siteimg(asset_path): @app.template_filter("timestamp") def timestamp(timestamp): - - age = int(time.time()) - timestamp - - if age < 60: - return "just now" - elif age < 3600: - minutes = int(age / 60) - return f"{minutes}m ago" - elif age < 86400: - hours = int(age / 3600) - return f"{hours}hr ago" - elif age < 2678400: - days = int(age / 86400) - return f"{days}d ago" - - now = time.gmtime() - ctd = time.gmtime(timestamp) - - months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year) - if now.tm_mday < ctd.tm_mday: - months -= 1 - - if months < 12: - return f"{months}mo ago" - else: - years = int(months / 12) - return f"{years}yr ago" - + return make_age_string(timestamp) @app.context_processor def inject_constants(): @@ -65,8 +39,7 @@ def inject_constants(): "PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR, "COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES, "HOLE_NAME":HOLE_NAME, "HOLE_STYLE_FLAIR":HOLE_STYLE_FLAIR, "HOLE_REQUIRED":HOLE_REQUIRED, - "CASINO_ENABLED":CASINO_ENABLED, "GUMROAD_LINK":GUMROAD_LINK, - "DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION, + "GUMROAD_LINK":GUMROAD_LINK, "DEFAULT_THEME":DEFAULT_THEME, "DESCRIPTION":DESCRIPTION, "has_sidebar":has_sidebar, "has_logo":has_logo, "has_app":has_app, "FP":FP, "NOTIF_MODACTION_JL_MIN":NOTIF_MODACTION_JL_MIN, "cache":cache, "ONLINE_STR":ONLINE_STR, "patron":patron, "DUES":DUES, @@ -75,5 +48,8 @@ def inject_constants(): "KOFI_TOKEN":KOFI_TOKEN, "KOFI_LINK":KOFI_LINK, "approved_embed_hosts":approved_embed_hosts, "site_settings":app.config['SETTINGS'], - "EMAIL":EMAIL, + "EMAIL":EMAIL, "calc_users":calc_users, "TELEGRAM_LINK":TELEGRAM_LINK, + "EMAIL_REGEX_PATTERN":EMAIL_REGEX_PATTERN, + "CONTENT_SECURITY_POLICY_DEFAULT":CONTENT_SECURITY_POLICY_DEFAULT, + "CONTENT_SECURITY_POLICY_HOME":CONTENT_SECURITY_POLICY_HOME, } diff --git a/files/helpers/lottery.py b/files/helpers/lottery.py index e976e2b4d..3281eb73a 100644 --- a/files/helpers/lottery.py +++ b/files/helpers/lottery.py @@ -103,7 +103,7 @@ def purchase_lottery_tickets(v, quantity=1): if (most_recent_lottery is None): return False, "There is no active lottery." - v.coins -= LOTTERY_TICKET_COST * quantity + v.charge_account('coins', LOTTERY_TICKET_COST * quantity) v.currently_held_lottery_tickets += quantity v.total_held_lottery_tickets += quantity @@ -125,4 +125,3 @@ def grant_lottery_tickets_to_user(v, quantity): active_lottery.prize += prize_value active_lottery.tickets_sold += quantity - diff --git a/files/helpers/media.py b/files/helpers/media.py index 62828c9c5..46ff5c10f 100644 --- a/files/helpers/media.py +++ b/files/helpers/media.py @@ -11,6 +11,7 @@ import gevent import imagehash from shutil import copyfile from files.classes.media import * +from files.helpers.cloudflare import purge_files_in_cache from files.__main__ import db_session def process_files(): @@ -24,9 +25,9 @@ def process_files(): url = process_image(name, patron=g.v.patron) body += f"\n\n![]({url})" elif file.content_type.startswith('video/'): - body += f"\n\n{process_video(file)}" + body += f"\n\n{SITE_FULL}{process_video(file)}" elif file.content_type.startswith('audio/'): - body += f"\n\n{process_audio(file)}" + body += f"\n\n{SITE_FULL}{process_audio(file)}" else: abort(415) return body @@ -36,26 +37,27 @@ def process_audio(file): name = f'/audio/{time.time()}'.replace('.','') extension = file.filename.split('.')[-1].lower() - if extension not in ['aac', 'amr', 'flac', 'm4a', 'm4b', 'mp3', 'ogg', 'wav']: - extension = 'mp3' name = name + '.' + extension file.save(name) size = os.stat(name).st_size - if size > 16 * 1024 * 1024 or not g.v.patron and size > 8 * 1024 * 1024: + if size > MAX_IMAGE_AUDIO_SIZE_MB_PATRON * 1024 * 1024 or not g.v.patron and size > MAX_IMAGE_AUDIO_SIZE_MB * 1024 * 1024: os.remove(name) - abort(413) + abort(413, f"Max image/audio size is {MAX_IMAGE_AUDIO_SIZE_MB} MB ({MAX_IMAGE_AUDIO_SIZE_MB_PATRON} MB for {patron.lower()}s)") + + media = g.db.query(Media).filter_by(filename=name, kind='audio').one_or_none() + if media: g.db.delete(media) media = Media( kind='audio', - filename=name.split('/')[-1], + filename=name, user_id=g.v.id, size=size ) g.db.add(media) - return f'{SITE_FULL}{name}' + return name def webm_to_mp4(old, new, vid): @@ -63,13 +65,15 @@ def webm_to_mp4(old, new, vid): subprocess.run(["ffmpeg", "-y", "-loglevel", "warning", "-nostats", "-threads:v", "1", "-i", old, "-map_metadata", "-1", tmp], check=True, stderr=subprocess.STDOUT) os.replace(tmp, new) os.remove(old) - requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, - data=f'{{"files": ["{SITE_FULL}{new}"]}}', timeout=5) - + purge_files_in_cache(f"{SITE_FULL}{new}") db = db_session() + + media = db.query(Media).filter_by(filename=new, kind='video').one_or_none() + if media: db.delete(media) + media = Media( kind='video', - filename=new.split('/')[-1], + filename=new, user_id=vid, size=os.stat(new).st_size ) @@ -83,13 +87,13 @@ def process_video(file): file.save(old) size = os.stat(old).st_size - if SITE_NAME != 'WPD' and (size > 32 * 1024 * 1024 or not g.v.patron and size > 64 * 1024 * 1024): + if (SITE_NAME != 'WPD' and + (size > MAX_VIDEO_SIZE_MB_PATRON * 1024 * 1024 + or not g.v.patron and size > MAX_VIDEO_SIZE_MB * 1024 * 1024)): os.remove(old) - abort(414) + abort(413, f"Max video size is {MAX_VIDEO_SIZE_MB} MB ({MAX_VIDEO_SIZE_MB_PATRON} MB for paypigs)") extension = file.filename.split('.')[-1].lower() - if extension not in ['avi', 'mp4', 'webm', 'm4v', 'mov', 'mkv']: - extension = 'mp4' new = old + '.' + extension if extension == 'webm': @@ -100,87 +104,82 @@ def process_video(file): subprocess.run(["ffmpeg", "-y", "-loglevel", "warning", "-nostats", "-i", old, "-map_metadata", "-1", "-c:v", "copy", "-c:a", "copy", new], check=True) os.remove(old) + media = g.db.query(Media).filter_by(filename=new, kind='video').one_or_none() + if media: g.db.delete(media) + media = Media( kind='video', - filename=new.split('/')[-1], + filename=new, user_id=g.v.id, size=os.stat(new).st_size ) g.db.add(media) - return f'{SITE_FULL}{new}' + return new def process_image(filename=None, resize=0, trim=False, uploader=None, patron=False, db=None): size = os.stat(filename).st_size - if size > 16 * 1024 * 1024 or not patron and size > 8 * 1024 * 1024: + if size > MAX_IMAGE_AUDIO_SIZE_MB_PATRON * 1024 * 1024 or not patron and size > MAX_IMAGE_AUDIO_SIZE_MB * 1024 * 1024: os.remove(filename) - abort(413) + abort(413, f"Max image/audio size is {MAX_IMAGE_AUDIO_SIZE_MB} MB ({MAX_IMAGE_AUDIO_SIZE_MB_PATRON} MB for paypigs)") - i = Image.open(filename) - - if resize and i.width > resize: + with Image.open(filename) as i: + params = ["convert", "-coalesce", filename, "-quality", "88", "-define", "webp:method=6", "-strip", "-auto-orient"] if trim and len(list(Iterator(i))) == 1: - subprocess.run(["convert", filename, "-coalesce", "-trim", "-resize", f"{resize}>", filename]) - else: - try: subprocess.run(["convert", filename, "-coalesce", "-resize", f"{resize}>", filename]) - except: pass - elif i.format.lower() != "webp": + params.append("-trim") + if resize and i.width > resize: + params.extend(["-resize", f"{resize}>"]) - exif = i.getexif() - for k in exif.keys(): - if k != 0x0112: - exif[k] = None - del exif[k] - i.info["exif"] = exif.tobytes() - - if i.format.lower() == "gif": - gifwebp(input_image=filename, output_image=filename, option="-mixed -metadata none -f 100 -mt -m 6") - else: - i = ImageOps.exif_transpose(i) - i.save(filename, format="WEBP", method=6, quality=88) + params.append(filename) + subprocess.run(params) - if resize in (300,400,1200): - if os.stat(filename).st_size > 1 * 1024 * 1024: + if resize: + if os.stat(filename).st_size > MAX_IMAGE_SIZE_BANNER_RESIZED_KB * 1024: os.remove(filename) - abort(413) + abort(413, f"Max size for site assets is {MAX_IMAGE_SIZE_BANNER_RESIZED_KB} KB") - if resize == 1200: - path = f'files/assets/images/{SITE_NAME}/banners' - elif resize == 400: - path = f'files/assets/images/{SITE_NAME}/sidebar' - else: - path = f'files/assets/images/badges' + if filename.startswith('files/assets/images/'): + path = filename.rsplit('/', 1)[0] + kind = path.split('/')[-1] - hashes = {} + if kind in ('banners','sidebar','badges'): + hashes = {} - for img in os.listdir(path): - if resize == 400 and img in ('256.webp','585.webp'): continue - img_path = f'{path}/{img}' - if img_path == filename: continue - img = Image.open(img_path) - i_hash = str(imagehash.phash(img)) - if i_hash in hashes.keys(): - print(hashes[i_hash], flush=True) - print(img_path, flush=True) - else: hashes[i_hash] = img_path + for img in os.listdir(path): + if resize == 400 and img in ('256.webp','585.webp'): continue + img_path = f'{path}/{img}' + if img_path == filename: continue - i = Image.open(filename) - i_hash = str(imagehash.phash(i)) - if i_hash in hashes.keys(): - os.remove(filename) - abort(417) + with Image.open(img_path) as i: + i_hash = str(imagehash.phash(i)) + + if i_hash in hashes.keys(): + print(hashes[i_hash], flush=True) + print(img_path, flush=True) + else: hashes[i_hash] = img_path + + with Image.open(filename) as i: + i_hash = str(imagehash.phash(i)) + + if i_hash in hashes.keys(): + os.remove(filename) + abort(409, "Image already exists!") + + db = db or g.db + + media = db.query(Media).filter_by(filename=filename, kind='image').one_or_none() + if media: db.delete(media) media = Media( kind='image', - filename=filename.split('/')[-1], + filename=filename, user_id=uploader or g.v.id, size=os.stat(filename).st_size ) - db = db or g.db db.add(media) return filename diff --git a/files/helpers/offsitementions.py b/files/helpers/offsitementions.py index c59c07c03..0804714b0 100644 --- a/files/helpers/offsitementions.py +++ b/files/helpers/offsitementions.py @@ -5,6 +5,7 @@ from sqlalchemy import or_ import files.helpers.const as const from files.classes.user import User from files.classes.comment import Comment +from files.classes.badges import Badge from files.classes.notifications import Notification from files.helpers.sanitize import sanitize @@ -16,10 +17,11 @@ from files.helpers.sanitize import sanitize def offsite_mentions_task(): if const.REDDIT_NOTIFS_SITE: - row_send_to = g.db.query(User.id) \ - .filter(or_(User.admin_level >= const.PERMS['NOTIFICATIONS_REDDIT'], - User.offsitementions == True)).all() + row_send_to = g.db.query(Badge.user_id).filter_by(badge_id=140).all() + row_send_to += g.db.query(User.id).filter(or_(User.admin_level >= const.PERMS['NOTIFICATIONS_REDDIT'])).all() + send_to = [x[0] for x in row_send_to] + send_to = set(send_to) site_mentions = get_mentions(const.REDDIT_NOTIFS_SITE) notify_mentions(send_to, site_mentions) @@ -34,13 +36,12 @@ def get_mentions(queries): mentions = [] for kind, query in itertools.product(kinds, queries): try: - data = requests.get(f'https://api.pushshift.io/reddit/{kind}/search?html_decode=true&q={query}&size=1', timeout=5).json()['data'] + # Special cases: PokemonGoRaids says 'Marsey' a lot unrelated to us. + # SubSimulatorGPT2 is just bots + data = requests.get(f'https://api.pushshift.io/reddit/{kind}/search?html_decode=true&q={query}&subreddit=!PokemonGoRaids,!SubSimulatorGPT2&size=1', timeout=5).json()['data'] except: break for i in data: - # Special case: PokemonGoRaids says 'Marsey' a lot unrelated to us. - if i['subreddit'] == 'PokemonGoRaids': continue - if kind == 'comment': body = i["body"].replace('>', '> ') text = f'

    {body}

    ' diff --git a/files/helpers/regex.py b/files/helpers/regex.py index 4f68ca1de..0065c36bc 100644 --- a/files/helpers/regex.py +++ b/files/helpers/regex.py @@ -27,6 +27,8 @@ poll_regex = re.compile("\s*\$\$([^\$\n]+)\$\$\s*", flags=re.A) bet_regex = re.compile("\s*\$\$\$([^\$\n]+)\$\$\$\s*", flags=re.A) choice_regex = re.compile("\s*&&([^\$\n]+)&&\s*", flags=re.A) +html_comment_regex = re.compile("", flags=re.A) + title_regex = re.compile("[^\w ]", flags=re.A) based_regex = re.compile("based and (.{1,20}?)(-| )pilled", flags=re.I|re.A) @@ -50,7 +52,7 @@ emoji_regex3 = re.compile(f'(?(.+?)<\/a>', flags=re.A) snappy_youtube_regex = re.compile(' 0: - number = randint(0, 37) # 37 is 00 + if len(participants) > 0: + number = randint(0, 37) # 37 is 00 - if number > 0 and number < 37: # 0 and 00 do not pay anything - winners, payouts, rewards_by_game_id = determine_roulette_winners(number, bets) - else: - winners = [] - payouts = {} - rewards_by_game_id = {} + if number > 0 and number < 37: # 0 and 00 do not pay anything + winners, payouts, rewards_by_game_id = determine_roulette_winners(number, bets) + else: + winners = [] + payouts = {} + rewards_by_game_id = {} - # Pay out to the winners and send a notification. - for user_id in winners: - gambler = get_account(user_id) - gambler_payout = payouts[user_id] - coin_winnings = gambler_payout['coins'] - procoin_winnings = gambler_payout['procoins'] + # Pay out to the winners and send a notification. + for user_id in winners: + gambler = get_account(user_id) + gambler_payout = payouts[user_id] + coin_winnings = gambler_payout['coins'] + procoin_winnings = gambler_payout['procoins'] - gambler.pay_account('coins', coin_winnings) - gambler.pay_account('procoins', procoin_winnings) + gambler.pay_account('coins', coin_winnings) + gambler.pay_account('procoins', procoin_winnings) - # Notify the winners. - notification_text = f"Winning number: {number}\nCongratulations! One or more of your roulette bets paid off!\n" + # Notify the winners. + notification_text = f"Winning number: {number}\nCongratulations! One or more of your roulette bets paid off!\n" - if coin_winnings > 0: - notification_text = notification_text + \ - f"* You received {coin_winnings} coins.\n" + if coin_winnings > 0: + notification_text = notification_text + \ + f"* You received {coin_winnings} coins.\n" - if procoin_winnings > 0: - notification_text = notification_text + \ - f"* You received {procoin_winnings} marseybux.\n" + if procoin_winnings > 0: + notification_text = notification_text + \ + f"* You received {procoin_winnings} marseybux.\n" - send_repeatable_notification(user_id, notification_text) + send_repeatable_notification(user_id, notification_text) - # Give condolences. - for participant in participants: - if not participant in winners: - send_repeatable_notification( - participant, f"Winning number: {number}\nSorry, none of your recent roulette bets paid off.") + # Give condolences. + for participant in participants: + if not participant in winners: + send_repeatable_notification( + participant, f"Winning number: {number}\nSorry, none of your recent roulette bets paid off.") - g.db.flush() + g.db.flush() - # Adjust game winnings. - for game in active_games: - if rewards_by_game_id.get(game.id): - game.winnings = rewards_by_game_id[game.id] - else: - game.winnings = -game.wager + # Adjust game winnings. + for game in active_games: + if rewards_by_game_id.get(game.id): + game.winnings = rewards_by_game_id[game.id] + else: + game.winnings = -game.wager - game.active = False - g.db.add(game) + game.active = False + g.db.add(game) - # Commit early when dirty because of long-running tasks after roulette - g.db.commit() + # Commit early when dirty because of long-running tasks after roulette + g.db.commit() def determine_roulette_winners(number, bets): - winners = [] - payouts = {} - rewards_by_game_id = {} + winners = [] + payouts = {} + rewards_by_game_id = {} - def add_to_winnings(bet): - game_id = int(bet['game_id']) - gambler_id = bet['gambler'] - wager_amount = bet['wager']['amount'] - bet_kind = bet['bet'] - reward = wager_amount * PAYOUT_MULITPLIERS[bet_kind] - payout = wager_amount + reward - currency = bet['wager']['currency'] + def add_to_winnings(bet): + game_id = int(bet['game_id']) + gambler_id = bet['gambler'] + wager_amount = bet['wager']['amount'] + bet_kind = bet['bet'] + reward = wager_amount * PAYOUT_MULITPLIERS[bet_kind] + payout = wager_amount + reward + currency = bet['wager']['currency'] - if not gambler_id in winners: - winners.append(gambler_id) + if not gambler_id in winners: + winners.append(gambler_id) - if not payouts.get(gambler_id): - payouts[gambler_id] = { - 'coins': 0, - 'procoins': 0 - } + if not payouts.get(gambler_id): + payouts[gambler_id] = { + 'coins': 0, + 'procoins': 0 + } - if not rewards_by_game_id.get(game_id): - rewards_by_game_id[game_id] = reward + if not rewards_by_game_id.get(game_id): + rewards_by_game_id[game_id] = reward - payouts[gambler_id][currency] += payout + payouts[gambler_id][currency] += payout - # Straight-Up Bet - for bet in bets[RouletteAction.STRAIGHT_UP_BET]: - if int(bet['which']) == number: - add_to_winnings(bet) + # Straight-Up Bet + for bet in bets[RouletteAction.STRAIGHT_UP_BET]: + if int(bet['which']) == number: + add_to_winnings(bet) - # Line Bet - line = -1 - for i in range(1, 7): - if number in LINES[i]: - line = i + # Line Bet + line = -1 + for i in range(1, 7): + if number in LINES[i]: + line = i - for bet in bets[RouletteAction.LINE_BET]: - if int(bet['which']) == line: - add_to_winnings(bet) + for bet in bets[RouletteAction.LINE_BET]: + if int(bet['which']) == line: + add_to_winnings(bet) - # Column Bet - column = -1 - for i in range(1, 4): - if number in COLUMNS[i]: - column = i + # Column Bet + column = -1 + for i in range(1, 4): + if number in COLUMNS[i]: + column = i - for bet in bets[RouletteAction.COLUMN_BET]: - if int(bet['which']) == column: - add_to_winnings(bet) + for bet in bets[RouletteAction.COLUMN_BET]: + if int(bet['which']) == column: + add_to_winnings(bet) - # Dozen Bet - dozen = -1 - for i in range(1, 4): - if number in DOZENS[i]: - dozen = i + # Dozen Bet + dozen = -1 + for i in range(1, 4): + if number in DOZENS[i]: + dozen = i - for bet in bets[RouletteAction.DOZEN_BET]: - if int(bet['which']) == dozen: - add_to_winnings(bet) + for bet in bets[RouletteAction.DOZEN_BET]: + if int(bet['which']) == dozen: + add_to_winnings(bet) - # Even/Odd Bet - even_odd = RouletteEvenOdd.EVEN if number % 2 == 0 else RouletteEvenOdd.ODD + # Even/Odd Bet + even_odd = RouletteEvenOdd.EVEN if number % 2 == 0 else RouletteEvenOdd.ODD - for bet in bets[RouletteAction.EVEN_ODD_BET]: - if bet['which'] == even_odd: - add_to_winnings(bet) + for bet in bets[RouletteAction.EVEN_ODD_BET]: + if bet['which'] == even_odd: + add_to_winnings(bet) - # Red/Black Bet - red_black = RouletteRedBlack.RED if number in REDS else RouletteRedBlack.BLACK + # Red/Black Bet + red_black = RouletteRedBlack.RED if number in REDS else RouletteRedBlack.BLACK - for bet in bets[RouletteAction.RED_BLACK_BET]: - if bet['which'] == red_black: - add_to_winnings(bet) + for bet in bets[RouletteAction.RED_BLACK_BET]: + if bet['which'] == red_black: + add_to_winnings(bet) - # High/Low Bet - high_low = RouletteHighLow.HIGH if number > 18 else RouletteHighLow.LOW + # High/Low Bet + high_low = RouletteHighLow.HIGH if number > 18 else RouletteHighLow.LOW - for bet in bets[RouletteAction.HIGH_LOW_BET]: - if bet['which'] == high_low: - add_to_winnings(bet) + for bet in bets[RouletteAction.HIGH_LOW_BET]: + if bet['which'] == high_low: + add_to_winnings(bet) - return winners, payouts, rewards_by_game_id + return winners, payouts, rewards_by_game_id def get_roulette_bets(): - return get_roulette_bets_and_betters()[1] + return get_roulette_bets_and_betters()[1] diff --git a/files/helpers/sanitize.py b/files/helpers/sanitize.py index 4ba05b248..cb0345212 100644 --- a/files/helpers/sanitize.py +++ b/files/helpers/sanitize.py @@ -17,7 +17,7 @@ import requests allowed_tags = ('b','blockquote','br','code','del','em','h1','h2','h3','h4','h5','h6','hr','i', 'li','ol','p','pre','strong','sub','sup','table','tbody','th','thead','td','tr','ul', - 'marquee','a','span','ruby','rp','rt','spoiler','img','lite-youtube','video','source','audio','g') + 'marquee','a','span','ruby','rp','rt','spoiler','img','lite-youtube','video','audio','g') allowed_styles = ['color', 'background-color', 'font-weight', 'text-align', 'filter',] @@ -57,10 +57,8 @@ def allowed_attributes(tag, name, value): if tag == 'video': if name == 'controls' and value == '': return True if name == 'preload' and value == 'none': return True - return False - - if tag == 'source': if name == 'src': return is_safe_url(value) + return False if tag == 'audio': if name == 'src': return is_safe_url(value) @@ -197,6 +195,7 @@ def sanitize_raw_title(sanitized): def sanitize_raw_body(sanitized, is_post): if not sanitized: return "" + sanitized = html_comment_regex.sub('', sanitized) sanitized = sanitized.replace('\u200e','').replace('\u200b','').replace("\ufeff", "").replace("\r\n", "\n") sanitized = sanitized.strip() return sanitized[:POST_BODY_LENGTH_LIMIT if is_post else COMMENT_BODY_LENGTH_LIMIT] @@ -233,7 +232,8 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_marseys sanitized = strikethrough_regex.sub(r'\1\2', sanitized) - sanitized = sanitized.replace('\u200e','').replace('\u200b','').replace("\ufeff", "").replace("𒐪","").replace("\u0589", ":") + # replacing zero width characters, overlines, fake colons + sanitized = sanitized.replace('\u200e','').replace('\u200b','').replace("\ufeff", "").replace("\u033f","").replace("\u0589", ":") sanitized = reddit_regex.sub(r'\1/\2', sanitized) sanitized = sub_regex.sub(r'\1/\2', sanitized) @@ -241,7 +241,7 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_marseys v = getattr(g, 'v', None) names = set(m.group(2) for m in mention_regex.finditer(sanitized)) - if limit_pings and len(names) > limit_pings and not v.admin_level: abort(406) + if limit_pings and len(names) > limit_pings and not v.admin_level >= PERMS['POST_COMMENT_INFINITE_PINGS']: abort(406) users_list = get_users(names, graceful=True) users_dict = {} for u in users_list: @@ -336,7 +336,7 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_marseys sanitized = sanitized.replace(i.group(0), htmlsource) - sanitized = video_sub_regex.sub(r'\1', sanitized) + sanitized = video_sub_regex.sub(r'\1', sanitized) sanitized = audio_sub_regex.sub(r'\1', sanitized) if count_marseys: @@ -363,25 +363,17 @@ def sanitize(sanitized, golden=True, limit_pings=0, showmore=True, count_marseys domain_list = set() for link in links: - href = link.get("href") if not href: continue - url = urlparse(href) - domain = url.netloc - url_path = url.path - domain_list.add(domain+url_path) + d = tldextract.extract(href).registered_domain + url.path + domain_list.add(d) - parts = domain.split(".") - for i in range(len(parts)): - new_domain = parts[i] - for j in range(i + 1, len(parts)): - new_domain += "." + parts[j] - domain_list.add(new_domain) - - bans = g.db.query(BannedDomain.domain).filter(BannedDomain.domain.in_(list(domain_list))).all() - - if bans: abort(403, description=f"Remove the banned domains {bans} and try again!") + banned_domains = g.db.query(BannedDomain).all() + for x in banned_domains: + for y in domain_list: + if y.startswith(x.domain): + abort(403, description=f'Remove the banned link "{x.domain}" and try again!\nReason for link ban: "{x.reason}"') if '
    ' not in sanitized:
     		sanitized = sanitized.replace('\n','')
    diff --git a/files/helpers/security.py b/files/helpers/security.py
    index 257bb9544..45470217c 100644
    --- a/files/helpers/security.py
    +++ b/files/helpers/security.py
    @@ -6,7 +6,7 @@ def generate_hash(string):
     
     	msg = bytes(string, "utf-16")
     
    -	return hmac.new(key=bytes(MASTER_KEY, "utf-16"),
    +	return hmac.new(key=bytes(SECRET_KEY, "utf-16"),
     					msg=msg,
     					digestmod='md5'
     					).hexdigest()
    diff --git a/files/helpers/sorting_and_time.py b/files/helpers/sorting_and_time.py
    index 25baa621d..2cefff115 100644
    --- a/files/helpers/sorting_and_time.py
    +++ b/files/helpers/sorting_and_time.py
    @@ -1,9 +1,9 @@
     import time
    -from files.classes.comment import Comment
    -from files.classes.submission import Submission
    +from typing import Optional
     from files.helpers.const import *
    +from sqlalchemy.sql import func
     
    -def apply_time_filter(t, objects, Class):
    +def apply_time_filter(t, objects, cls):
     	now = int(time.time())
     	if t == 'hour':
     		cutoff = now - 3600
    @@ -18,33 +18,57 @@ def apply_time_filter(t, objects, Class):
     	else:
     		cutoff = 0
     
    -	return objects.filter(Class.created_utc >= cutoff)
    +	return objects.filter(cls.created_utc >= cutoff)
     
    -def sort_comments(sort, comments):
    +def sort_objects(sort, objects, cls, include_shadowbanned=False):
    +	if not include_shadowbanned:
    +		cls_user = cls.__mapper__.relationships['author'].entity.entity
    +		objects = objects.join(cls.author).filter(cls_user.shadowbanned == None)
     
    -	if sort == 'new':
    -		return comments.order_by(Comment.id.desc())
    -	elif sort == 'old':
    -		return comments.order_by(Comment.id)
    -	elif sort == 'controversial':
    -		return comments.order_by((Comment.upvotes+1)/(Comment.downvotes+1) + (Comment.downvotes+1)/(Comment.upvotes+1), Comment.downvotes.desc(), Comment.id.desc())
    -	elif sort == "bottom":
    -		return comments.order_by(Comment.upvotes - Comment.downvotes)
    -	elif SITE_NAME == 'rDrama':
    -		return comments.order_by(Comment.realupvotes.desc(), Comment.id.desc())
    -	else:
    -		return comments.order_by(Comment.downvotes - Comment.upvotes, Comment.id.desc())
    -
    -def sort_posts(sort, posts):
    -	if sort == "new":
    -		return posts.order_by(Submission.created_utc.desc())
    +	if sort == 'hot':
    +		ti = int(time.time()) + 3600
    +		if SITE_NAME == 'rDrama': metric = cls.realupvotes
    +		else: metric = cls.upvotes - cls.downvotes
    +		if cls.__name__ == "Submission": metric += cls.comment_count/5
    +		return objects.order_by(-1000000*(metric + 1)/(func.power(((ti - cls.created_utc)/1000), 1.23)), cls.created_utc.desc())
    +	elif sort == "bump" and cls.__name__ == "Submission":
    +		return objects.filter(cls.comment_count > 1).order_by(cls.bump_utc.desc(), cls.created_utc.desc())
    +	elif sort == "comments" and cls.__name__ == "Submission":
    +		return objects.order_by(cls.comment_count.desc(), cls.created_utc.desc())
    +	elif sort == "new":
    +		return objects.order_by(cls.created_utc.desc())
     	elif sort == "old":
    -		return posts.order_by(Submission.created_utc)
    +		return objects.order_by(cls.created_utc)
     	elif sort == "controversial":
    -		return posts.order_by((Submission.upvotes+1)/(Submission.downvotes+1) + (Submission.downvotes+1)/(Submission.upvotes+1), Submission.downvotes.desc(), Submission.created_utc.desc())
    +		return objects.order_by((cls.upvotes+1)/(cls.downvotes+1) + (cls.downvotes+1)/(cls.upvotes+1), cls.downvotes.desc(), cls.created_utc.desc())
     	elif sort == "bottom":
    -		return posts.order_by(Submission.upvotes - Submission.downvotes, Submission.created_utc.desc())
    -	elif sort == "comments":
    -		return posts.order_by(Submission.comment_count.desc(), Submission.created_utc.desc())
    +		return objects.order_by(cls.upvotes - cls.downvotes, cls.created_utc.desc())
     	else:
    -		return posts.order_by(Submission.downvotes - Submission.upvotes, Submission.created_utc.desc())
    +		return objects.order_by(cls.downvotes - cls.upvotes, cls.created_utc.desc())
    +
    +def make_age_string(compare:Optional[int]) -> str:
    +	if not compare or compare < 1577865600: return ""
    +	age = int(time.time()) - compare
    +
    +	if age < 60:
    +		return "just now"
    +	elif age < 3600:
    +		minutes = int(age / 60)
    +		return f"{minutes}m ago"
    +	elif age < 86400:
    +		hours = int(age / 3600)
    +		return f"{hours}hr ago"
    +	elif age < 2678400:
    +		days = int(age / 86400)
    +		return f"{days}d ago"
    +
    +	now = time.gmtime()
    +	ctd = time.gmtime(compare)
    +	months = now.tm_mon - ctd.tm_mon + 12 * (now.tm_year - ctd.tm_year)
    +	if now.tm_mday < ctd.tm_mday:
    +		months -= 1
    +	if months < 12:
    +		return f"{months}mo ago"
    +	else:
    +		years = int(months / 12)
    +		return f"{years}yr ago"
    diff --git a/files/helpers/stats.py b/files/helpers/stats.py
    index bd98613c6..ed91b6970 100644
    --- a/files/helpers/stats.py
    +++ b/files/helpers/stats.py
    @@ -82,7 +82,7 @@ def chart(kind, site):
     
     	file = chart_path(kind, site)
     
    -	plt.savefig(file)
    +	plt.savefig(file, bbox_inches='tight')
     	plt.clf()
     	return file
     
    diff --git a/files/helpers/twentyone.py b/files/helpers/twentyone.py
    index 4990068da..8a6c2c4ad 100644
    --- a/files/helpers/twentyone.py
    +++ b/files/helpers/twentyone.py
    @@ -8,20 +8,20 @@ from flask import g
     
     
     class BlackjackStatus(str, Enum):
    -    PLAYING = "PLAYING"
    -    STAYED = "STAYED"
    -    PUSHED = "PUSHED"
    -    WON = "WON"
    -    LOST = "LOST"
    -    BLACKJACK = "BLACKJACK"
    +	PLAYING = "PLAYING"
    +	STAYED = "STAYED"
    +	PUSHED = "PUSHED"
    +	WON = "WON"
    +	LOST = "LOST"
    +	BLACKJACK = "BLACKJACK"
     
     
     class BlackjackAction(str, Enum):
    -    DEAL = "DEAL"
    -    HIT = "HIT"
    -    STAY = "STAY"
    -    DOUBLE_DOWN = "DOUBLE_DOWN"
    -    BUY_INSURANCE = "BUY_INSURANCE"
    +	DEAL = "DEAL"
    +	HIT = "HIT"
    +	STAY = "STAY"
    +	DOUBLE_DOWN = "DOUBLE_DOWN"
    +	BUY_INSURANCE = "BUY_INSURANCE"
     
     
     ranks = ("2", "3", "4", "5", "6", "7", "8", "9", "X", "J", "Q", "K", "A")
    @@ -32,350 +32,350 @@ minimum_bet = 5
     
     
     def get_initial_state():
    -    return {
    -        "player": [],
    -        "player_value": 0,
    -        "dealer": [],
    -        "dealer_value": 0,
    -        "player_bought_insurance": False,
    -        "player_doubled_down": False,
    -        "status": BlackjackStatus.PLAYING,
    -        "actions": [BlackjackAction.DEAL],
    -        "wager": {
    -            "amount": 0,
    -            "currency": "coins"
    -        },
    -        "payout": 0
    -    }
    +	return {
    +		"player": [],
    +		"player_value": 0,
    +		"dealer": [],
    +		"dealer_value": 0,
    +		"player_bought_insurance": False,
    +		"player_doubled_down": False,
    +		"status": BlackjackStatus.PLAYING,
    +		"actions": [BlackjackAction.DEAL],
    +		"wager": {
    +			"amount": 0,
    +			"currency": "coins"
    +		},
    +		"payout": 0
    +	}
     
     
     def build_casino_game(gambler, wager, currency):
    -    initial_state = get_initial_state()
    -    initial_state['wager']['amount'] = wager
    -    initial_state['wager']['currency'] = currency
    +	initial_state = get_initial_state()
    +	initial_state['wager']['amount'] = wager
    +	initial_state['wager']['currency'] = currency
     
    -    casino_game = Casino_Game()
    -    casino_game.user_id = gambler.id
    -    casino_game.currency = currency
    -    casino_game.wager = wager
    -    casino_game.winnings = 0
    -    casino_game.kind = 'blackjack'
    -    casino_game.game_state = json.dumps(initial_state)
    -    casino_game.active = True
    -    g.db.add(casino_game)
    +	casino_game = Casino_Game()
    +	casino_game.user_id = gambler.id
    +	casino_game.currency = currency
    +	casino_game.wager = wager
    +	casino_game.winnings = 0
    +	casino_game.kind = 'blackjack'
    +	casino_game.game_state = json.dumps(initial_state)
    +	casino_game.active = True
    +	g.db.add(casino_game)
     
    -    return casino_game
    +	return casino_game
     
     
     def get_active_twentyone_game(gambler):
    -    return g.db.query(Casino_Game).filter(
    -        Casino_Game.active == True,
    -        Casino_Game.kind == 'blackjack',
    -        Casino_Game.user_id == gambler.id).first()
    +	return g.db.query(Casino_Game).filter(
    +		Casino_Game.active == True,
    +		Casino_Game.kind == 'blackjack',
    +		Casino_Game.user_id == gambler.id).first()
     
     
     def get_active_twentyone_game_state(gambler):
    -    active_game = get_active_twentyone_game(gambler)
    -    full_state = json.loads(active_game.game_state)
    -    return remove_exploitable_information(full_state)
    +	active_game = get_active_twentyone_game(gambler)
    +	full_state = json.loads(active_game.game_state)
    +	return remove_exploitable_information(full_state)
     
     
     def charge_gambler(gambler, amount, currency):
    -    charged = gambler.charge_account(currency, amount)
    -    
    -    if not charged:
    -        raise Exception("Gambler cannot afford charge.")
    +	charged = gambler.charge_account(currency, amount)
    +	
    +	if not charged:
    +		raise Exception("Gambler cannot afford charge.")
     
     
     def create_new_game(gambler, wager, currency):
    -    existing_game = get_active_twentyone_game(gambler)
    -    over_minimum_bet = wager >= minimum_bet
    +	existing_game = get_active_twentyone_game(gambler)
    +	over_minimum_bet = wager >= minimum_bet
     
    -    if existing_game:
    -        raise Exception("Gambler already has a game in progress.")
    +	if existing_game:
    +		raise Exception("Gambler already has a game in progress.")
     
    -    if not over_minimum_bet:
    -        raise Exception(f"Gambler must bet over {minimum_bet} {currency}.")
    +	if not over_minimum_bet:
    +		raise Exception(f"Gambler must bet over {minimum_bet} {currency}.")
     
    -    try:
    -        charge_gambler(gambler, wager, currency)
    -        new_game = build_casino_game(gambler, wager, currency)
    -        g.db.add(new_game)
    -        g.db.commit()
    -    except:
    -        raise Exception(f"Gambler cannot afford to bet {wager} {currency}.")
    +	try:
    +		charge_gambler(gambler, wager, currency)
    +		new_game = build_casino_game(gambler, wager, currency)
    +		g.db.add(new_game)
    +		g.db.commit()
    +	except:
    +		raise Exception(f"Gambler cannot afford to bet {wager} {currency}.")
     
     
     def handle_blackjack_deal(state):
    -    deck = build_deck(state)
    -    first = deck.pop()
    -    second = deck.pop()
    -    third = deck.pop()
    -    fourth = deck.pop()
    -    state['player'] = [first, third]
    -    state['dealer'] = [second, fourth]
    +	deck = build_deck(state)
    +	first = deck.pop()
    +	second = deck.pop()
    +	third = deck.pop()
    +	fourth = deck.pop()
    +	state['player'] = [first, third]
    +	state['dealer'] = [second, fourth]
     
    -    return state
    +	return state
     
     
     def handle_blackjack_hit(state):
    -    deck = build_deck(state)
    -    next_card = deck.pop()
    -    state['player'].append(next_card)
    +	deck = build_deck(state)
    +	next_card = deck.pop()
    +	state['player'].append(next_card)
     
    -    return state
    +	return state
     
     
     def handle_blackjack_stay(state):
    -    state['status'] = BlackjackStatus.STAYED
    +	state['status'] = BlackjackStatus.STAYED
     
    -    return state
    +	return state
     
     
     def handle_blackjack_double_down(state):
    -    state['player_doubled_down'] = True
    -    state = handle_blackjack_hit(state)
    -    state = handle_blackjack_stay(state)
    +	state['player_doubled_down'] = True
    +	state = handle_blackjack_hit(state)
    +	state = handle_blackjack_stay(state)
     
    -    return state
    +	return state
     
     
     def handle_blackjack_buy_insurance(state):
    -    state['player_bought_insurance'] = True
    +	state['player_bought_insurance'] = True
     
    -    return state
    +	return state
     
     
     def check_for_completion(state):
    -    after_initial_deal = len(
    -        state['player']) == 2 and len(state['dealer']) == 2
    -    player_hand_value = get_value_of_hand(state['player'])
    -    dealer_hand_value = get_value_of_hand(state['dealer'])
    +	after_initial_deal = len(
    +		state['player']) == 2 and len(state['dealer']) == 2
    +	player_hand_value = get_value_of_hand(state['player'])
    +	dealer_hand_value = get_value_of_hand(state['dealer'])
     
    -    # Both player and dealer were initially dealt 21: Push.
    -    if after_initial_deal and player_hand_value == 21 and dealer_hand_value == 21:
    -        state['status'] = BlackjackStatus.PUSHED
    -        return True, state
    +	# Both player and dealer were initially dealt 21: Push.
    +	if after_initial_deal and player_hand_value == 21 and dealer_hand_value == 21:
    +		state['status'] = BlackjackStatus.PUSHED
    +		return True, state
     
    -    # Player was originally dealt 21, dealer was not: Blackjack.
    -    if after_initial_deal and player_hand_value == 21:
    -        state['status'] = BlackjackStatus.BLACKJACK
    -        return True, state
    +	# Player was originally dealt 21, dealer was not: Blackjack.
    +	if after_initial_deal and player_hand_value == 21:
    +		state['status'] = BlackjackStatus.BLACKJACK
    +		return True, state
     
    -    # Player went bust: Lost.
    -    if player_hand_value == -1:
    -        state['status'] = BlackjackStatus.LOST
    -        return True, state
    +	# Player went bust: Lost.
    +	if player_hand_value == -1:
    +		state['status'] = BlackjackStatus.LOST
    +		return True, state
     
    -    # Player chose to stay: Deal rest for dealer then determine winner.
    -    if state['status'] == BlackjackStatus.STAYED:
    -        deck = build_deck(state)
    +	# Player chose to stay: Deal rest for dealer then determine winner.
    +	if state['status'] == BlackjackStatus.STAYED:
    +		deck = build_deck(state)
     
    -        while dealer_hand_value < 17 and dealer_hand_value != -1:
    -            next_card = deck.pop()
    -            state['dealer'].append(next_card)
    -            dealer_hand_value = get_value_of_hand(state['dealer'])
    +		while dealer_hand_value < 17 and dealer_hand_value != -1:
    +			next_card = deck.pop()
    +			state['dealer'].append(next_card)
    +			dealer_hand_value = get_value_of_hand(state['dealer'])
     
    -        if player_hand_value > dealer_hand_value or dealer_hand_value == -1:
    -            state['status'] = BlackjackStatus.WON
    -        elif dealer_hand_value > player_hand_value:
    -            state['status'] = BlackjackStatus.LOST
    -        else:
    -            state['status'] = BlackjackStatus.PUSHED
    +		if player_hand_value > dealer_hand_value or dealer_hand_value == -1:
    +			state['status'] = BlackjackStatus.WON
    +		elif dealer_hand_value > player_hand_value:
    +			state['status'] = BlackjackStatus.LOST
    +		else:
    +			state['status'] = BlackjackStatus.PUSHED
     
    -        state['player_value'] = get_value_of_hand(state['player'])
    -        state['dealer_value'] = get_value_of_hand(state['dealer'])
    +		state['player_value'] = get_value_of_hand(state['player'])
    +		state['dealer_value'] = get_value_of_hand(state['dealer'])
     
    -        return True, state
    +		return True, state
     
    -    return False, state
    +	return False, state
     
     
     def does_insurance_apply(state):
    -    dealer = state['dealer']
    -    dealer_hand_value = get_value_of_hand(dealer)
    -    dealer_first_card_ace = dealer[0][0] == 'A'
    -    dealer_never_hit = len(dealer) == 2
    -    return dealer_hand_value == 21 and dealer_first_card_ace and dealer_never_hit
    +	dealer = state['dealer']
    +	dealer_hand_value = get_value_of_hand(dealer)
    +	dealer_first_card_ace = dealer[0][0] == 'A'
    +	dealer_never_hit = len(dealer) == 2
    +	return dealer_hand_value == 21 and dealer_first_card_ace and dealer_never_hit
     
     
     def can_purchase_insurance(state):
    -    dealer = state['dealer']
    -    dealer_first_card_ace = dealer[0][0] == 'A'
    -    dealer_never_hit = len(dealer) == 2
    -    return dealer_first_card_ace and dealer_never_hit and not state['player_bought_insurance']
    +	dealer = state['dealer']
    +	dealer_first_card_ace = dealer[0][0] == 'A'
    +	dealer_never_hit = len(dealer) == 2
    +	return dealer_first_card_ace and dealer_never_hit and not state['player_bought_insurance']
     
     
     def can_double_down(state):
    -    player = state['player']
    -    player_hand_value = get_value_of_hand(player)
    -    player_never_hit = len(player) == 2
    -    return player_hand_value in (10, 11) and player_never_hit
    +	player = state['player']
    +	player_hand_value = get_value_of_hand(player)
    +	player_never_hit = len(player) == 2
    +	return player_hand_value in (10, 11) and player_never_hit
     
     
     def handle_payout(gambler, state, game):
    -    status = state['status']
    -    payout = 0
    +	status = state['status']
    +	payout = 0
     
    -    if status == BlackjackStatus.BLACKJACK:
    -        game.winnings = floor(game.wager * 3/2)
    -        payout = game.wager + game.winnings
    -    elif status == BlackjackStatus.WON:
    -        game.winnings = game.wager
    -        payout = game.wager * 2
    -    elif status == BlackjackStatus.LOST:
    -        dealer = state['dealer']
    -        dealer_first_card_ace = dealer[0][0] == 'A'
    -        dealer_never_hit = len(dealer) == 2
    -        dealer_hand_value = get_value_of_hand(dealer) == 21
    -        insurance_applies = dealer_hand_value == 21 and dealer_first_card_ace and dealer_never_hit
    +	if status == BlackjackStatus.BLACKJACK:
    +		game.winnings = floor(game.wager * 3/2)
    +		payout = game.wager + game.winnings
    +	elif status == BlackjackStatus.WON:
    +		game.winnings = game.wager
    +		payout = game.wager * 2
    +	elif status == BlackjackStatus.LOST:
    +		dealer = state['dealer']
    +		dealer_first_card_ace = dealer[0][0] == 'A'
    +		dealer_never_hit = len(dealer) == 2
    +		dealer_hand_value = get_value_of_hand(dealer) == 21
    +		insurance_applies = dealer_hand_value == 21 and dealer_first_card_ace and dealer_never_hit
     
    -        if insurance_applies and state['player_bought_insurance']:
    -            game.winnings = 0
    -            payout = game.wager
    -        else:
    -            game.winnings = -game.wager
    -            payout = 0
    -    elif status == BlackjackStatus.PUSHED:
    -        game.winnings = 0
    -        payout = game.wager
    -    else:
    -        raise Exception("Attempted to payout a game that has not finished.")
    +		if insurance_applies and state['player_bought_insurance']:
    +			game.winnings = 0
    +			payout = game.wager
    +		else:
    +			game.winnings = -game.wager
    +			payout = 0
    +	elif status == BlackjackStatus.PUSHED:
    +		game.winnings = 0
    +		payout = game.wager
    +	else:
    +		raise Exception("Attempted to payout a game that has not finished.")
     
    -    gambler.pay_account(game.currency, payout)
    -    
    -    if game.currency == 'coins':
    -        if status in (BlackjackStatus.BLACKJACK, BlackjackStatus.WON):
    -            distribute_wager_badges(gambler, game.wager, won=True)
    -        elif status == BlackjackStatus.LOST:
    -            distribute_wager_badges(gambler, game.wager, won=False)
    +	gambler.pay_account(game.currency, payout)
    +	
    +	if game.currency == 'coins':
    +		if status in (BlackjackStatus.BLACKJACK, BlackjackStatus.WON):
    +			distribute_wager_badges(gambler, game.wager, won=True)
    +		elif status == BlackjackStatus.LOST:
    +			distribute_wager_badges(gambler, game.wager, won=False)
     
    -    game.active = False
    -    g.db.add(game)
    +	game.active = False
    +	g.db.add(game)
     
    -    return payout
    +	return payout
     
     
     def remove_exploitable_information(state):
    -    safe_state = state
    -    
    -    if len(safe_state['dealer']) >= 2:
    -        safe_state['dealer'][1] = '?'
    +	safe_state = state
    +	
    +	if len(safe_state['dealer']) >= 2:
    +		safe_state['dealer'][1] = '?'
     
    -    safe_state['dealer_value'] = '?'
    -    return safe_state
    +	safe_state['dealer_value'] = '?'
    +	return safe_state
     
     
     action_handlers = {
    -    BlackjackAction.DEAL: handle_blackjack_deal,
    -    BlackjackAction.HIT: handle_blackjack_hit,
    -    BlackjackAction.STAY: handle_blackjack_stay,
    -    BlackjackAction.DOUBLE_DOWN: handle_blackjack_double_down,
    -    BlackjackAction.BUY_INSURANCE: handle_blackjack_buy_insurance,
    +	BlackjackAction.DEAL: handle_blackjack_deal,
    +	BlackjackAction.HIT: handle_blackjack_hit,
    +	BlackjackAction.STAY: handle_blackjack_stay,
    +	BlackjackAction.DOUBLE_DOWN: handle_blackjack_double_down,
    +	BlackjackAction.BUY_INSURANCE: handle_blackjack_buy_insurance,
     }
     
     
     def dispatch_action(gambler, action):
    -    game = get_active_twentyone_game(gambler)
    -    handler = action_handlers[action]
    +	game = get_active_twentyone_game(gambler)
    +	handler = action_handlers[action]
     
    -    if not game:
    -        raise Exception(
    -            'Gambler has no active blackjack game.')
    -    if not handler:
    -        raise Exception(
    -            f'Illegal action {action} passed to Blackjack#dispatch_action.')
    +	if not game:
    +		raise Exception(
    +			'Gambler has no active blackjack game.')
    +	if not handler:
    +		raise Exception(
    +			f'Illegal action {action} passed to Blackjack#dispatch_action.')
     
    -    state = json.loads(game.game_state)
    +	state = json.loads(game.game_state)
     
    -    if action == BlackjackAction.BUY_INSURANCE:
    -        if not can_purchase_insurance(state):
    -            raise Exception("Insurance cannot be purchased.")
    +	if action == BlackjackAction.BUY_INSURANCE:
    +		if not can_purchase_insurance(state):
    +			raise Exception("Insurance cannot be purchased.")
     
    -        charge_gambler(gambler, floor(game.wager / 2), game.currency)
    -    if action == BlackjackAction.DOUBLE_DOWN:
    -        if not can_double_down(state):
    -            raise Exception("Cannot double down.")
    +		charge_gambler(gambler, floor(game.wager / 2), game.currency)
    +	if action == BlackjackAction.DOUBLE_DOWN:
    +		if not can_double_down(state):
    +			raise Exception("Cannot double down.")
     
    -        charge_gambler(gambler, game.wager, game.currency)
    -        game.wager *= 2
    +		charge_gambler(gambler, game.wager, game.currency)
    +		game.wager *= 2
     
    -    new_state = handler(state)
    -    new_state['player_value'] = get_value_of_hand(new_state['player'])
    -    new_state['dealer_value'] = get_value_of_hand(new_state['dealer'])
    -    new_state['actions'] = get_available_actions(new_state)
    +	new_state = handler(state)
    +	new_state['player_value'] = get_value_of_hand(new_state['player'])
    +	new_state['dealer_value'] = get_value_of_hand(new_state['dealer'])
    +	new_state['actions'] = get_available_actions(new_state)
     
    -    game.game_state = json.dumps(new_state)
    -    g.db.add(game)
    +	game.game_state = json.dumps(new_state)
    +	g.db.add(game)
     
    -    game_over, final_state = check_for_completion(new_state)
    +	game_over, final_state = check_for_completion(new_state)
     
    -    if game_over:
    -        payout = handle_payout(gambler, final_state, game)
    -        final_state['actions'] = [BlackjackAction.DEAL]
    -        final_state['payout'] = payout
    -        return final_state
    -    else:
    -        safe_state = remove_exploitable_information(new_state)
    -        return safe_state
    +	if game_over:
    +		payout = handle_payout(gambler, final_state, game)
    +		final_state['actions'] = [BlackjackAction.DEAL]
    +		final_state['payout'] = payout
    +		return final_state
    +	else:
    +		safe_state = remove_exploitable_information(new_state)
    +		return safe_state
     
     
     def shuffle(collection):
    -    random.shuffle(collection)
    -    return collection
    +	random.shuffle(collection)
    +	return collection
     
     
     def build_deck(state):
    -    card_counts = {}
    +	card_counts = {}
     
    -    for card in deck:
    -        card_counts[card] = deck_count
    +	for card in deck:
    +		card_counts[card] = deck_count
     
    -    cards_already_dealt = state['player'].copy()
    -    cards_already_dealt.extend(state['dealer'].copy())
    +	cards_already_dealt = state['player'].copy()
    +	cards_already_dealt.extend(state['dealer'].copy())
     
    -    for card in cards_already_dealt:
    -        card_counts[card] = card_counts[card] - 1
    +	for card in cards_already_dealt:
    +		card_counts[card] = card_counts[card] - 1
     
    -    deck_without_already_dealt_cards = []
    +	deck_without_already_dealt_cards = []
     
    -    for card in deck:
    -        amount = card_counts[card]
    +	for card in deck:
    +		amount = card_counts[card]
     
    -        for _ in range(amount):
    -            deck_without_already_dealt_cards.append(card)
    +		for _ in range(amount):
    +			deck_without_already_dealt_cards.append(card)
     
    -    return shuffle(deck_without_already_dealt_cards)
    +	return shuffle(deck_without_already_dealt_cards)
     
     
     def get_value_of_card(card):
    -    rank = card[0]
    -    return 0 if rank == "A" else min(ranks.index(rank) + 2, 10)
    +	rank = card[0]
    +	return 0 if rank == "A" else min(ranks.index(rank) + 2, 10)
     
     
     def get_value_of_hand(hand):
    -    without_aces = sum(map(get_value_of_card, hand))
    -    ace_count = sum("A" in c for c in hand)
    -    possibilities = []
    +	without_aces = sum(map(get_value_of_card, hand))
    +	ace_count = sum("A" in c for c in hand)
    +	possibilities = []
     
    -    for i in range(ace_count + 1):
    -        value = without_aces + (ace_count - i) + i * 11
    -        possibilities.append(-1 if value > 21 else value)
    +	for i in range(ace_count + 1):
    +		value = without_aces + (ace_count - i) + i * 11
    +		possibilities.append(-1 if value > 21 else value)
     
    -    return max(possibilities)
    +	return max(possibilities)
     
     
     def get_available_actions(state):
    -    actions = []
    +	actions = []
     
    -    if state['status'] == BlackjackStatus.PLAYING:
    -        actions.append(BlackjackAction.HIT)
    -        actions.append(BlackjackAction.STAY)
    +	if state['status'] == BlackjackStatus.PLAYING:
    +		actions.append(BlackjackAction.HIT)
    +		actions.append(BlackjackAction.STAY)
     
    -    if can_double_down(state):
    -        actions.append(BlackjackAction.DOUBLE_DOWN)
    +	if can_double_down(state):
    +		actions.append(BlackjackAction.DOUBLE_DOWN)
     
    -    if can_purchase_insurance(state):
    -        actions.append(BlackjackAction.BUY_INSURANCE)
    +	if can_purchase_insurance(state):
    +		actions.append(BlackjackAction.BUY_INSURANCE)
     
    -    return actions
    +	return actions
    diff --git a/files/helpers/wrappers.py b/files/helpers/wrappers.py
    index e58fd72cb..59691e913 100644
    --- a/files/helpers/wrappers.py
    +++ b/files/helpers/wrappers.py
    @@ -8,14 +8,31 @@ import functools
     import user_agents
     import time
     
    +def calc_users(v):
    +	loggedin = cache.get(f'{SITE}_loggedin') or {}
    +	loggedout = cache.get(f'{SITE}_loggedout') or {}
    +	timestamp = int(time.time())
    +	if v:
    +		if session["session_id"] in loggedout: del loggedout[session["session_id"]]
    +		loggedin[v.id] = timestamp
    +	else:
    +		ua = str(user_agents.parse(g.agent))
    +		if 'spider' not in ua.lower() and 'bot' not in ua.lower():
    +			loggedout[session["session_id"]] = (timestamp, ua)
    +	
    +	loggedin = {k: v for k, v in loggedin.items() if (timestamp - v) < LOGGEDIN_ACTIVE_TIME}
    +	loggedout = {k: v for k, v in loggedout.items() if (timestamp - v[0]) < LOGGEDIN_ACTIVE_TIME}
    +	cache.set(f'{SITE}_loggedin', loggedin)
    +	cache.set(f'{SITE}_loggedout', loggedout)
    +
    +	g.loggedin_counter = len(loggedin)
    +	g.loggedout_counter = len(loggedout)
    +	return ''
    +
     def get_logged_in_user():
    -
     	if hasattr(g, 'v'): return g.v
    -
     	if not (hasattr(g, 'db') and g.db): g.db = db_session()
    -
     	v = None
    -
     	token = request.headers.get("Authorization","").strip()
     	if token:
     		client = g.db.query(ClientAuth).filter(ClientAuth.access_token == token).one_or_none()
    @@ -32,7 +49,9 @@ def get_logged_in_user():
     				return None
     			else:
     				nonce = session.get("login_nonce", 0)
    -				if nonce < v.login_nonce or v.id != id: abort(401)
    +				if nonce < v.login_nonce or v.id != id:
    +					session.clear()
    +					return None
     
     				if request.method != "GET":
     					submitted_key = request.values.get("formkey")
    @@ -40,63 +59,37 @@ def get_logged_in_user():
     					if not v.validate_formkey(submitted_key): abort(401)
     
     				v.client = None
    +	g.is_api_or_xhr = bool((v and v.client) or request.headers.get("xhr"))
     
    -
    -	if request.method.lower() != "get" and app.config['SETTINGS']['Read-only mode'] and not (v and v.admin_level):
    +	if request.method.lower() != "get" and app.config['SETTINGS']['Read-only mode'] and not (v and v.admin_level >= PERMS['SITE_BYPASS_READ_ONLY_MODE']):
     		abort(403)
     
     
    -	if not session.get("session_id"):
    -		session.permanent = True
    -		session["session_id"] = secrets.token_hex(49)
    -		
    -	loggedin = cache.get(f'{SITE}_loggedin') or {}
    -	loggedout = cache.get(f'{SITE}_loggedout') or {}
    -	g.loggedin_counter = 0
    -	g.loggedout_counter = 0
    +	g.v = v
     
    -	timestamp = int(time.time())
     	if v:
    -		if session["session_id"] in loggedout: del loggedout[session["session_id"]]
    -		loggedin[v.id] = timestamp
    +		v.poor = session.get('poor')
     		# Check against last_active + ACTIVE_TIME to reduce frequency of
     		# UPDATEs in exchange for a ±ACTIVE_TIME margin of error.
    +		timestamp = int(time.time())
     		if (v.last_active + LOGGEDIN_ACTIVE_TIME) < timestamp:
     			v.last_active = timestamp
     			g.db.add(v)
    -	else:
    -		ua = str(user_agents.parse(g.agent))
    -		if 'spider' not in ua.lower() and 'bot' not in ua.lower():
    -			loggedout[session["session_id"]] = (timestamp, ua)
    -	
    -	g.loggedin_counter = len([x for x in loggedin.values() if timestamp-x < LOGGEDIN_ACTIVE_TIME])
    -	cache.set(f'{SITE}_loggedin', loggedin)
    -
    -	g.loggedout_counter = len([x for x in loggedout.values() if timestamp-x[0] < LOGGEDIN_ACTIVE_TIME])
    -	cache.set(f'{SITE}_loggedout', loggedout)
    -
    -	g.v = v
    -
    -	if v: v.poor = session.get('poor')
     
     	if AEVANN_ID and request.headers.get("Cf-Ipcountry") == 'EG':
    -		if v and not v.username.startswith('Aev'):
    +		if v and not v.username.startswith('Aev') and v.truecoins > 0:
     			with open(f"/eg", "r+", encoding="utf-8") as f:
     				ip = request.headers.get('CF-Connecting-IP')
     				if f'@{v.username}, ' not in f.read():
     					t = str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time())))
     					f.write(f'@{v.username}, {v.truecoins}, {ip}, {t}\n')
    -		elif not v and request.path not in ('/login','/signup'):
    -			abort(401)
     
     	return v
     
     def auth_desired(f):
     	def wrapper(*args, **kwargs):
     		v = get_logged_in_user()
    -
     		return make_response(f(*args, v=v, **kwargs))
    -
     	wrapper.__name__ = f.__name__
     	return wrapper
     
    @@ -105,6 +98,11 @@ def auth_desired_with_logingate(f):
     		v = get_logged_in_user()
     		if app.config['SETTINGS']['login_required'] and not v: abort(401)
     
    +		#### WPD TEMP #### disable this /logged_out thing on .co
    +		if SITE == 'watchpeopledie.co':
    +			return make_response(f(*args, v=v, **kwargs))
    +		#### END WPD TEMP ####
    +
     		if not v and not request.path.startswith('/logged_out'):
     			return redirect(f"/logged_out{request.full_path}")
     
    @@ -129,48 +127,31 @@ def auth_required(f):
     	return wrapper
     
     def is_not_permabanned(f):
    -
     	def wrapper(*args, **kwargs):
    -
     		v = get_logged_in_user()
    -
     		if not v: abort(401)
    -
    -		if v.is_suspended_permanently:
    -			return {"error": "Internal server error"}, 500
    -
    +		if v.is_suspended_permanently: abort(403)
     		return make_response(f(*args, v=v, **kwargs))
    -
     	wrapper.__name__ = f.__name__
     	return wrapper
     
    -
     def admin_level_required(x):
    -
     	def wrapper_maker(f):
    -
     		def wrapper(*args, **kwargs):
    -
     			v = get_logged_in_user()
    -
     			if not v: abort(401)
    -
     			if v.admin_level < x: abort(403)
    -			
     			return make_response(f(*args, v=v, **kwargs))
     
     		wrapper.__name__ = f.__name__
     		return wrapper
    -
     	return wrapper_maker
     
    -def casino_required(f):
    -	def wrapper(*args, **kwargs):
    -		v = get_logged_in_user()
    -
    -		if not CASINO_ENABLED: abort(404)
    -
    -		return make_response(f(v=v))
    -
    -	wrapper.__name__ = f.__name__
    -	return wrapper
    +def feature_required(x):
    +	def wrapper_maker(f):
    +		def wrapper(*args, **kwargs):
    +			if not FEATURES[x]: abort(404)
    +			return make_response(f(*args, **kwargs))
    +		wrapper.__name__ = f.__name__
    +		return wrapper
    +	return wrapper_maker
    diff --git a/files/routes/__init__.py b/files/routes/__init__.py
    index f9c046e1c..f8654050d 100644
    --- a/files/routes/__init__.py
    +++ b/files/routes/__init__.py
    @@ -1,6 +1,5 @@
     from .admin import *
     from .comments import *
    -from .discord import *
     from .errors import *
     from .reporting import *
     from .front import *
    diff --git a/files/routes/admin.py b/files/routes/admin.py
    index f5b9f93ee..928d963c6 100644
    --- a/files/routes/admin.py
    +++ b/files/routes/admin.py
    @@ -11,12 +11,12 @@ from files.helpers.get import *
     from files.helpers.media import *
     from files.helpers.const import *
     from files.helpers.actions import *
    +from files.helpers.cloudflare import *
     from files.classes import *
     from flask import *
     from files.__main__ import app, cache, limiter
     from .front import frontlist
     from .login import check_for_alts
    -from files.helpers.discord import add_role
     import datetime
     import requests
     from urllib.parse import quote, urlencode
    @@ -24,11 +24,11 @@ from urllib.parse import quote, urlencode
     @app.post('/kippy')
     @admin_level_required(PERMS['PRINT_MARSEYBUX_FOR_KIPPY_ON_PCMEMES'])
     def kippy(v):
    -	if SITE == 'rdrama.net': abort(404)
    +	if SITE != 'pcmemes.net': abort(404)
     	kippy = get_account(KIPPY_ID)
     	kippy.procoins += 10000
     	g.db.add(kippy)
    -	return '10k marseycoins printed!'
    +	return '10k marseybux printed!'
     
     @app.get('/admin/loggedin')
     @admin_level_required(PERMS['VIEW_ACTIVE_USERS'])
    @@ -196,7 +196,7 @@ def remove_admin(v, username):
     @admin_level_required(PERMS['POST_BETS_DISTRIBUTE'])
     def distribute(v, option_id):
     	autojanny = get_account(AUTOJANNY_ID)
    -	if autojanny.coins == 0: return {"error": "@AutoJanny has 0 coins"}, 400
    +	if autojanny.coins == 0: abort(400, "@AutoJanny has 0 coins")
     
     	try: option_id = int(option_id)
     	except: abort(400)
    @@ -216,7 +216,7 @@ def distribute(v, option_id):
     		if o.exclusive >= 2: pool += o.upvotes
     	pool *= POLL_BET_COINS
     
    -	autojanny.coins -= pool
    +	autojanny.charge_account('coins', pool)
     	if autojanny.coins < 0: autojanny.coins = 0
     	g.db.add(autojanny)
     
    @@ -283,7 +283,7 @@ def revert_actions(v, username):
     		user.ban_reason = None
     		if user.is_banned:
     			user.is_banned = 0
    -			send_repeatable_notification(user.id, f"@{v.username} has unbanned you!")
    +			send_repeatable_notification(user.id, f"@{v.username} (Admin) has unbanned you!")
     		g.db.add(user)
     
     		for u in user.alts:
    @@ -292,7 +292,7 @@ def revert_actions(v, username):
     			u.ban_reason = None
     			if u.is_banned:
     				u.is_banned = 0
    -				send_repeatable_notification(u.id, f"@{v.username} has unbanned you!")
    +				send_repeatable_notification(u.id, f"@{v.username} (Admin) has unbanned you!")
     			g.db.add(u)
     
     	return {"message": f"@{user.username}'s admin actions have been reverted!"}
    @@ -303,7 +303,7 @@ def revert_actions(v, username):
     def club_allow(v, username):
     	u = get_user(username, v=v)
     
    -	if u.admin_level >= v.admin_level: return {"error": "noob"}, 400
    +	if u.admin_level >= v.admin_level: abort(403, 'noob')
     
     	u.club_allowed = True
     	g.db.add(u)
    @@ -319,7 +319,7 @@ def club_allow(v, username):
     	)
     	g.db.add(ma)
     
    -	send_repeatable_notification(u.id, f"@{v.username} (admin) has inducted you into the {CC_TITLE}!")
    +	send_repeatable_notification(u.id, f"@{v.username} (Admin) has inducted you into the {CC_TITLE}!")
     
     	return {"message": f"@{u.username} has been allowed into the {CC_TITLE}!"}
     
    @@ -329,7 +329,7 @@ def club_allow(v, username):
     def club_ban(v, username):
     	u = get_user(username, v=v)
     
    -	if u.admin_level >= v.admin_level: return {"error": "noob"}, 400
    +	if u.admin_level >= v.admin_level: abort(403, 'noob')
     
     	u.club_allowed = False
     
    @@ -344,15 +344,14 @@ def club_ban(v, username):
     	)
     	g.db.add(ma)
     
    -	send_repeatable_notification(u.id, f"@{v.username} (admin) has disallowed you from the {CC_TITLE}!")
    +	send_repeatable_notification(u.id, f"@{v.username} (Admin) has disallowed you from the {CC_TITLE}!")
     
     	return {"message": f"@{u.username} has been disallowed from the {CC_TITLE}. Deserved."}
     
     
     @app.get("/admin/shadowbanned")
    -@auth_required
    +@admin_level_required(PERMS['USER_SHADOWBAN'])
     def shadowbanned(v):
    -	if not (v and v.admin_level >= PERMS['USER_SHADOWBAN']): abort(404)
     	users = g.db.query(User).filter(User.shadowbanned != None).order_by(User.shadowbanned).all()
     	return render_template("shadowbanned.html", v=v, users=users)
     
    @@ -366,11 +365,11 @@ def image_posts_listing(v):
     
     	posts = g.db.query(Submission).order_by(Submission.id.desc())
     
    -	firstrange = 25 * (page - 1)
    -	secondrange = firstrange+26
    +	firstrange = PAGE_SIZE * (page - 1)
    +	secondrange = firstrange + PAGE_SIZE + 1
     	posts = [x.id for x in posts if x.is_image][firstrange:secondrange]
    -	next_exists = (len(posts) > 25)
    -	posts = get_posts(posts[:25], v=v)
    +	next_exists = (len(posts) > PAGE_SIZE)
    +	posts = get_posts(posts[:PAGE_SIZE], v=v)
     
     	return render_template("admin/image_posts.html", v=v, listing=posts, next_exists=next_exists, page=page, sort="new")
     
    @@ -383,12 +382,13 @@ def reported_posts(v):
     
     	listing = g.db.query(Submission).filter_by(
     		is_approved=None,
    -		is_banned=False
    -	).join(Submission.flags).order_by(Submission.id.desc()).offset(25 * (page - 1)).limit(26)
    +		is_banned=False,
    +		deleted_utc=0
    +	).join(Submission.flags).order_by(Submission.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1)
     
     	listing = [p.id for p in listing]
    -	next_exists = len(listing) > 25
    -	listing = listing[:25]
    +	next_exists = len(listing) > PAGE_SIZE
    +	listing = listing[:PAGE_SIZE]
     
     	listing = get_posts(listing, v=v)
     
    @@ -405,12 +405,13 @@ def reported_comments(v):
     	listing = g.db.query(Comment
     					).filter_by(
     		is_approved=None,
    -		is_banned=False
    -	).join(Comment.flags).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
    +		is_banned=False,
    +		deleted_utc=0
    +	).join(Comment.flags).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all()
     
     	listing = [c.id for c in listing]
    -	next_exists = len(listing) > 25
    -	listing = listing[:25]
    +	next_exists = len(listing) > PAGE_SIZE
    +	listing = listing[:PAGE_SIZE]
     
     	listing = get_comments(listing, v=v)
     
    @@ -427,9 +428,7 @@ def admin_home(v):
     	under_attack = False
     
     	if v.admin_level >= PERMS['SITE_SETTINGS_UNDER_ATTACK']:
    -		if CF_ZONE == 'blahblahblah': response = 'high'
    -		else: response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, timeout=5).json()['result']['value']
    -		under_attack = response == 'under_attack'
    +		under_attack = (get_security_level() or 'high') == 'under_attack'
     
     	gitref = admin_git_head()
     	
    @@ -480,76 +479,65 @@ def purge_cache(v):
     	online = cache.get(ONLINE_STR)
     	cache.clear()
     	cache.set(ONLINE_STR, online)
    -
    -	response = str(requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, data='{"purge_everything":true}', timeout=5))
    -
    +	if not purge_entire_cache():
    +		abort(400, 'Failed to purge cache')
     	ma = ModAction(
     		kind="purge_cache",
     		user_id=v.id
     	)
     	g.db.add(ma)
    -
    -	if response == "": return {"message": "Cache purged!"}
    -	return {"error": "Failed to purge cache."}, 400
    +	return {"message": "Cache purged!"}
     
     
     @app.post("/admin/under_attack")
     @admin_level_required(PERMS['SITE_SETTINGS_UNDER_ATTACK'])
     def under_attack(v):
    -	response = requests.get(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, timeout=5).json()['result']['value']
    -
    -	if response == 'under_attack':
    -		ma = ModAction(
    -			kind="disable_under_attack",
    -			user_id=v.id,
    -		)
    -		g.db.add(ma)
    -
    -		response = str(requests.patch(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, data='{"value":"high"}', timeout=5))
    -		if response == "": return {"message": "Under attack mode disabled!"}
    -		return {"error": "Failed to disable under attack mode."}, 400
    -	else:
    -		ma = ModAction(
    -			kind="enable_under_attack",
    -			user_id=v.id,
    -		)
    -		g.db.add(ma)
    -
    -		response = str(requests.patch(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/settings/security_level', headers=CF_HEADERS, data='{"value":"under_attack"}', timeout=5))
    -		if response == "": return {"message": "Under attack mode enabled!"}
    -		return {"error": "Failed to enable under attack mode."}, 400
    +	response = get_security_level()
    +	if not response:
    +		abort(400, 'Could not retrieve the current security level')
    +	old_under_attack_mode = response == 'under_attack'
    +	enable_disable_str = 'disable' if old_under_attack_mode else 'enable'
    +	new_security_level = 'high' if old_under_attack_mode else 'under_attack'
    +	if not set_security_level(new_security_level):
    +		abort(400, f'Failed to {enable_disable_str} under attack mode')
    +	ma = ModAction(
    +		kind=f"{enable_disable_str}_under_attack",
    +		user_id=v.id,
    +	)
    +	g.db.add(ma)
    +	return {"message": f"Under attack mode {enable_disable_str}d!"}
     
     @app.get("/admin/badge_grant")
    +@app.get("/admin/badge_remove")
     @admin_level_required(PERMS['USER_BADGES'])
    +@feature_required('BADGES')
     def badge_grant_get(v):
    -	if not FEATURES['BADGES']:
    -		abort(404)
    -
    +	grant = request.url.endswith("grant")
     	badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
    -	return render_template("admin/badge_grant.html", v=v, badge_types=badges)
    -
    +	return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=grant)
     
     @app.post("/admin/badge_grant")
     @limiter.limit("1/second;30/minute;200/hour;1000/day")
     @admin_level_required(PERMS['USER_BADGES'])
    +@feature_required('BADGES')
     def badge_grant_post(v):
    -	if not FEATURES['BADGES']:
    -		abort(404)
    -
     	badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
     
     	user = get_user(request.values.get("username").strip(), graceful=True)
     	if not user:
    -		return render_template("admin/badge_grant.html", v=v, badge_types=badges, error="User not found.")
    +		return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=True, error="User not found.")
     
     	try: badge_id = int(request.values.get("badge_id"))
     	except: abort(400)
     
    -	if badge_id in {16,17,21,22,23,24,25,26,27,94,95,96,97,98,109,137} and v.id != AEVANN_ID and SITE != 'pcmemes.net':
    +	if SITE == 'watchpeopledie.tv' and badge_id not in {99,101}:
    +		abort(403)
    +
    +	if badge_id in {16,17,21,22,23,24,25,26,27,94,95,96,97,98,109,137,67,68,83,84,87,90,140} and v.id != AEVANN_ID and SITE != 'pcmemes.net':
     		abort(403)
     
     	if user.has_badge(badge_id):
    -		return render_template("admin/badge_grant.html", v=v, badge_types=badges, error="User already has that badge.")
    +		return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=True, error="User already has that badge.")
     	
     	new_badge = Badge(badge_id=badge_id, user_id=user.id)
     
    @@ -565,7 +553,7 @@ def badge_grant_post(v):
     	g.db.flush()
     
     	if v.id != user.id:
    -		text = f"@{v.username} has given you the following profile badge:\n\n![]({new_badge.path})\n\n**{new_badge.name}**\n\n{new_badge.badge.description}"
    +		text = f"@{v.username} (Admin) has given you the following profile badge:\n\n![]({new_badge.path})\n\n**{new_badge.name}**\n\n{new_badge.badge.description}"
     		send_repeatable_notification(user.id, text)
     	
     	ma = ModAction(
    @@ -575,44 +563,31 @@ def badge_grant_post(v):
     		_note=new_badge.name
     	)
     	g.db.add(ma)
    -
    -	return render_template("admin/badge_grant.html", v=v, badge_types=badges, msg=f"{new_badge.name} Badge granted to @{user.username} successfully!")
    -
    -
    -
    -@app.get("/admin/badge_remove")
    -@admin_level_required(PERMS['USER_BADGES'])
    -def badge_remove_get(v):
    -	if not FEATURES['BADGES']:
    -		abort(404)
    -
    -	badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
    -
    -	return render_template("admin/badge_remove.html", v=v, badge_types=badges)
    -
    +	return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=True, msg=f"{new_badge.name} Badge granted to @{user.username} successfully!")
     
     @app.post("/admin/badge_remove")
     @limiter.limit("1/second;30/minute;200/hour;1000/day")
     @admin_level_required(PERMS['USER_BADGES'])
    +@feature_required('BADGES')
     def badge_remove_post(v):
    -	if not FEATURES['BADGES']:
    -		abort(404)
    -	
     	badges = g.db.query(BadgeDef).order_by(BadgeDef.id).all()
     
     	user = get_user(request.values.get("username").strip(), graceful=True)
     	if not user:
    -		return render_template("admin/badge_remove.html", v=v, badge_types=badges, error="User not found.")
    +		return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=False, error="User not found.")
     
     	try: badge_id = int(request.values.get("badge_id"))
     	except: abort(400)
     
    +	if badge_id in {67,68,83,84,87,90,140} and v.id != AEVANN_ID and SITE != 'pcmemes.net':
    +		abort(403)
    +
     	badge = user.has_badge(badge_id)
     	if not badge:
    -		return render_template("admin/badge_remove.html", v=v, badge_types=badges, error="User doesn't have that badge.")
    +		return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=False, error="User doesn't have that badge.")
     
     	if v.id != user.id:
    -		text = f"@{v.username} has removed the following profile badge from you:\n\n![]({badge.path})\n\n**{badge.name}**\n\n{badge.badge.description}"
    +		text = f"@{v.username} (Admin) has removed the following profile badge from you:\n\n![]({badge.path})\n\n**{badge.name}**\n\n{badge.badge.description}"
     		send_repeatable_notification(user.id, text)
     
     	ma = ModAction(
    @@ -622,11 +597,8 @@ def badge_remove_post(v):
     		_note=badge.name
     	)
     	g.db.add(ma)
    -
     	g.db.delete(badge)
    -
    -
    -	return render_template("admin/badge_remove.html", v=v, badge_types=badges, msg=f"{badge.name} Badge removed from @{user.username} successfully!")
    +	return render_template("admin/badge_admin.html", v=v, badge_types=badges, grant=False, msg=f"{badge.name} Badge removed from @{user.username} successfully!")
     
     
     @app.get("/admin/users")
    @@ -636,10 +608,10 @@ def users_list(v):
     	try: page = int(request.values.get("page", 1))
     	except: page = 1
     
    -	users = g.db.query(User).order_by(User.id.desc()).offset(25 * (page - 1)).limit(26).all()
    +	users = g.db.query(User).order_by(User.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
     
    -	next_exists = (len(users) > 25)
    -	users = users[:25]
    +	next_exists = (len(users) > PAGE_SIZE)
    +	users = users[:PAGE_SIZE]
     
     	return render_template("user_cards.html",
     						v=v,
    @@ -760,9 +732,8 @@ def alt_votes_get(v):
     @limiter.limit("1/second;30/minute;200/hour;1000/day")
     @admin_level_required(PERMS['USER_LINK'])
     def admin_link_accounts(v):
    -
    -	u1 = int(request.values.get("u1"))
    -	u2 = int(request.values.get("u2"))
    +	u1 = get_account(request.values.get("u1")).id
    +	u2 = get_account(request.values.get("u2")).id
     
     	new_alt = Alt(
     		user1=u1, 
    @@ -790,19 +761,13 @@ def admin_link_accounts(v):
     @app.get("/admin/removed/posts")
     @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
     def admin_removed(v):
    -
     	try: page = int(request.values.get("page", 1))
     	except: page = 1
    -
     	if page < 1: abort(400)
    -	
    -	ids = g.db.query(Submission.id).join(Submission.author).filter(or_(Submission.is_banned==True, User.shadowbanned != None)).order_by(Submission.id.desc()).offset(25 * (page - 1)).limit(26).all()
    -
    +	ids = g.db.query(Submission.id).join(Submission.author).filter(or_(Submission.is_banned==True, User.shadowbanned != None)).order_by(Submission.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
     	ids=[x[0] for x in ids]
    -
    -	next_exists = len(ids) > 25
    -
    -	ids = ids[:25]
    +	next_exists = len(ids) > PAGE_SIZE
    +	ids = ids[:PAGE_SIZE]
     
     	posts = get_posts(ids, v=v)
     
    @@ -817,20 +782,14 @@ def admin_removed(v):
     @app.get("/admin/removed/comments")
     @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
     def admin_removed_comments(v):
    -
     	try: page = int(request.values.get("page", 1))
     	except: page = 1
     	
    -	ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()
    -
    +	ids = g.db.query(Comment.id).join(Comment.author).filter(or_(Comment.is_banned==True, User.shadowbanned != None)).order_by(Comment.id.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE).all()
     	ids=[x[0] for x in ids]
    -
    -	next_exists = len(ids) > 25
    -
    -	ids = ids[:25]
    -
    +	next_exists = len(ids) > PAGE_SIZE
    +	ids = ids[:PAGE_SIZE]
     	comments = get_comments(ids, v=v)
    -
     	return render_template("admin/removed_comments.html",
     						v=v,
     						listing=comments,
    @@ -853,7 +812,9 @@ def agendaposter(user_id, v):
     	user.agendaposter = expiry
     	g.db.add(user)
     
    -	if days: note = f"for {days} days"
    +	if days:
    +		days_txt = str(days).split('.0')[0]
    +		note = f"for {days_txt} days"
     	else: note = "permanently"
     
     	ma = ModAction(
    @@ -866,7 +827,7 @@ def agendaposter(user_id, v):
     
     	badge_grant(user=user, badge_id=28)
     
    -	send_repeatable_notification(user.id, f"@{v.username} has marked you as a chud ({note}).")
    +	send_repeatable_notification(user.id, f"@{v.username} (Admin) has marked you as a chud ({note}).")
     
     	
     	return redirect(user.url)
    @@ -896,7 +857,7 @@ def unagendaposter(user_id, v):
     	badge = user.has_badge(28)
     	if badge: g.db.delete(badge)
     
    -	send_repeatable_notification(user.id, f"@{v.username} has unmarked you as a chud.")
    +	send_repeatable_notification(user.id, f"@{v.username} (Admin) has unmarked you as a chud.")
     
     	return {"message": f"@{user.username}'s chud theme has been disabled!"}
     
    @@ -997,9 +958,14 @@ def admin_title_change(user_id, v):
     def ban_user(user_id, v):
     	user = get_account(user_id)
     
    -	if user.admin_level >= v.admin_level: abort(403)
    +	if user.admin_level > v.admin_level:
    +		abort(403)
     
    -	days = float(request.values.get("days")) if request.values.get('days') else 0
    +	days = 0.0
    +	try:
    +		days = float(request.values.get("days"))
    +	except:
    +		pass
     
     	reason = request.values.get("reason").strip()[:256]
     	reason = filter_emojis_only(reason)
    @@ -1011,21 +977,22 @@ def ban_user(user_id, v):
     
     	if request.values.get("alts"):
     		for x in user.alts:
    -			if x.admin_level: break
    +			if x.admin_level > v.admin_level:
    +				continue
     			x.ban(admin=v, reason=reason, days=days)
     
    +	duration = "permanently"
     	if days:
    -		if reason: text = f"@{v.username} has banned you for **{days}** days for the following reason:\n\n> {reason}"
    -		else: text = f"@{v.username} has banned you for **{days}** days."
    +		days_txt = str(days).split('.0')[0]
    +		duration = f"for {days_txt} day"
    +		if days != 1: duration += "s"
    +		if reason: text = f"@{v.username} (Admin) has banned you for **{days_txt}** days for the following reason:\n\n> {reason}"
    +		else: text = f"@{v.username} (Admin) has banned you for **{days_txt}** days."
     	else:
    -		if reason: text = f"@{v.username} has banned you permanently for the following reason:\n\n> {reason}"
    -		else: text = f"@{v.username} has banned you permanently."
    +		if reason: text = f"@{v.username} (Admin) has banned you permanently for the following reason:\n\n> {reason}"
    +		else: text = f"@{v.username} (Admin) has banned you permanently."
     
     	send_repeatable_notification(user.id, text)
    -	
    -	if days == 0: duration = "permanently"
    -	elif days == 1: duration = "for 1 day"
    -	else: duration = f"for {days} days"
     
     	note = f'reason: "{reason}", duration: {duration}'
     	ma=ModAction(
    @@ -1065,11 +1032,11 @@ def unban_user(user_id, v):
     	user.is_banned = 0
     	user.unban_utc = 0
     	user.ban_reason = None
    -	send_repeatable_notification(user.id, f"@{v.username} has unbanned you!")
    +	send_repeatable_notification(user.id, f"@{v.username} (Admin) has unbanned you!")
     	g.db.add(user)
     
     	for x in user.alts:
    -		if x.is_banned: send_repeatable_notification(x.id, f"@{v.username} has unbanned you!")
    +		if x.is_banned: send_repeatable_notification(x.id, f"@{v.username} (Admin) has unbanned you!")
     		x.is_banned = 0
     		x.unban_utc = 0
     		x.ban_reason = None
    @@ -1122,13 +1089,12 @@ def remove_post(post_id, v):
     	post = get_post(post_id)
     	post.is_banned = True
     	post.is_approved = None
    -	post.stickied = None
    +	if post.stickied and not post.stickied.endswith(PIN_AWARD_TEXT):
    +		post.stickied = None
     	post.is_pinned = False
     	post.ban_reason = v.username
     	g.db.add(post)
     
    -	
    -
     	ma=ModAction(
     		kind="ban_post",
     		user_id=v.id,
    @@ -1140,10 +1106,7 @@ def remove_post(post_id, v):
     
     	v.coins += 1
     	g.db.add(v)
    -
    -	requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS,
    -		data=f'{{"files": ["https://{SITE}/logged_out"]}}', timeout=5)
    -
    +	purge_files_in_cache(f"https://{SITE}/logged_out")
     	return {"message": "Post removed!"}
     
     
    @@ -1155,7 +1118,7 @@ def approve_post(post_id, v):
     	post = get_post(post_id)
     
     	if post.author.id == v.id and post.author.agendaposter and AGENDAPOSTER_PHRASE not in post.body.lower() and post.sub != 'chudrama':
    -		return {"error": "You can't bypass the chud award!"}, 400
    +		abort(400, "You can't bypass the chud award!")
     
     	if post.is_banned:
     		ma=ModAction(
    @@ -1173,7 +1136,7 @@ def approve_post(post_id, v):
     
     	cache.delete_memoized(frontlist)
     
    -	v.coins -= 1
    +	v.charge_account('coins', 1)
     	g.db.add(v)
     
     	return {"message": "Post approved!"}
    @@ -1209,42 +1172,52 @@ def distinguish_post(post_id, v):
     
     @app.post("/sticky/")
     @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
    +@feature_required('PINS')
     def sticky_post(post_id, v):
    -	if not FEATURES['PINS']:
    -		abort(403)
    -
     	post = get_post(post_id)
    -	if not post.stickied:
    -		pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False).count()
    -		if pins >= PIN_LIMIT:
    -			if v.admin_level >= PERMS['BYPASS_PIN_LIMIT']:
    -				post.stickied = v.username
    -				post.stickied_utc = int(time.time()) + 3600
    -			else: return {"error": f"Can't exceed {PIN_LIMIT} pinned posts limit!"}, 403
    -		else: post.stickied = v.username
    -		g.db.add(post)
    +	if post.is_banned: abort(403, "Can't sticky removed posts!")
    +	if post.stickied and post.stickied.endswith(PIN_AWARD_TEXT):
    +		abort(403, "Can't pin award pins!")
     
    -		ma=ModAction(
    -			kind="pin_post",
    -			user_id=v.id,
    -			target_submission_id=post.id
    -		)
    -		g.db.add(ma)
    +	pins = g.db.query(Submission).filter(Submission.stickied != None, Submission.is_banned == False).count()
    +	extra_pin_slots = 1 if post.stickied else 0
     
    +	if pins >= PIN_LIMIT + extra_pin_slots and v.admin_level < PERMS['BYPASS_PIN_LIMIT']:
    +		abort(403, f"Can't exceed {PIN_LIMIT} pinned posts limit!")
    +
    +	if not post.stickied_utc:
    +		post.stickied_utc = int(time.time()) + 3600
    +		pin_time = 'for 1 hour'
     		if v.id != post.author_id:
    -			send_repeatable_notification(post.author_id, f"@{v.username} has pinned [{post.title}](/post/{post_id})!")
    +			send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has pinned [{post.title}](/post/{post_id})!")
    +	else:
    +		post.stickied_utc = None
    +		pin_time = 'permanently'
     
    -		cache.delete_memoized(frontlist)
    -	return {"message": "Post pinned!"}
    +	post.stickied = v.username
    +
    +	g.db.add(post)
    +
    +	ma=ModAction(
    +		kind="pin_post",
    +		user_id=v.id,
    +		target_submission_id=post.id,
    +		_note=pin_time
    +	)
    +	g.db.add(ma)
    +
    +	cache.delete_memoized(frontlist)
    +
    +	return {"message": f"Post pinned {pin_time}!", "length": pin_time}, 201
     
     @app.post("/unsticky/")
     @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
     def unsticky_post(post_id, v):
    -
     	post = get_post(post_id)
     	if post.stickied:
    -		if post.stickied.endswith('(pin award)'): return {"error": "Can't unpin award pins!"}, 403
    -
    +		if post.stickied.endswith(PIN_AWARD_TEXT): abort(403, "Can't unpin award pins!")
    +		if post.author_id == LAWLZ_ID and post.stickied_utc and SITE_NAME == 'rDrama': abort(403, "Can't unpin lawlzposts!")
    +		
     		post.stickied = None
     		post.stickied_utc = None
     		g.db.add(post)
    @@ -1257,7 +1230,7 @@ def unsticky_post(post_id, v):
     		g.db.add(ma)
     
     		if v.id != post.author_id:
    -			send_repeatable_notification(post.author_id, f"@{v.username} has unpinned [{post.title}](/post/{post_id})!")
    +			send_repeatable_notification(post.author_id, f"@{v.username} (Admin) has unpinned [{post.title}](/post/{post_id})!")
     
     		cache.delete_memoized(frontlist)
     	return {"message": "Post unpinned!"}
    @@ -1280,7 +1253,7 @@ def sticky_comment(cid, v):
     		g.db.add(ma)
     
     		if v.id != comment.author_id:
    -			message = f"@{v.username} has pinned your [comment]({comment.shortlink})!"
    +			message = f"@{v.username} (Admin) has pinned your [comment]({comment.shortlink})!"
     			send_repeatable_notification(comment.author_id, message)
     
     	return {"message": "Comment pinned!"}
    @@ -1293,7 +1266,7 @@ def unsticky_comment(cid, v):
     	comment = get_comment(cid, v=v)
     	
     	if comment.stickied:
    -		if comment.stickied.endswith("(pin award)"): return {"error": "Can't unpin award pins!"}, 403
    +		if comment.stickied.endswith(PIN_AWARD_TEXT): abort(403, "Can't unpin award pins!")
     
     		comment.stickied = None
     		g.db.add(comment)
    @@ -1306,7 +1279,7 @@ def unsticky_comment(cid, v):
     		g.db.add(ma)
     
     		if v.id != comment.author_id:
    -			message = f"@{v.username} has unpinned your [comment]({comment.shortlink})!"
    +			message = f"@{v.username} (Admin) has unpinned your [comment]({comment.shortlink})!"
     			send_repeatable_notification(comment.author_id, message)
     
     	return {"message": "Comment unpinned!"}
    @@ -1341,7 +1314,7 @@ def approve_comment(c_id, v):
     	if not comment: abort(404)
     	
     	if comment.author.id == v.id and comment.author.agendaposter and AGENDAPOSTER_PHRASE not in comment.body.lower() and comment.post.sub != 'chudrama':
    -		return {"error": "You can't bypass the chud award!"}, 400
    +		abort(400, "You can't bypass the chud award!")
     
     	if comment.is_banned:
     		ma=ModAction(
    @@ -1412,27 +1385,19 @@ def admin_banned_domains(v):
     	banned_domains = g.db.query(BannedDomain).all()
     	return render_template("admin/banned_domains.html", v=v, banned_domains=banned_domains)
     
    -@app.post("/admin/banned_domains")
    +@app.post("/admin/ban_domain")
     @limiter.limit("1/second;30/minute;200/hour;1000/day")
     @admin_level_required(PERMS['DOMAINS_BAN'])
    -def admin_toggle_ban_domain(v):
    +def ban_domain(v):
     
     	domain=request.values.get("domain", "").strip()
     	if not domain: abort(400)
     
     	reason=request.values.get("reason").strip()
    +	if not reason: abort(400, 'Reason is required!')
     
    -	d = g.db.query(BannedDomain).filter_by(domain=domain).one_or_none()
    -	if d:
    -		g.db.delete(d)
    -		ma = ModAction(
    -			kind="unban_domain",
    -			user_id=v.id,
    -			_note=domain
    -		)
    -		g.db.add(ma)
    -
    -	else:
    +	existing = g.db.get(BannedDomain, domain)
    +	if not existing:
     		d = BannedDomain(domain=domain, reason=reason)
     		g.db.add(d)
     		ma = ModAction(
    @@ -1442,9 +1407,28 @@ def admin_toggle_ban_domain(v):
     		)
     		g.db.add(ma)
     
    -
     	return redirect("/admin/banned_domains/")
     
    +
    +@app.post("/admin/unban_domain/")
    +@limiter.limit("1/second;30/minute;200/hour;1000/day")
    +@admin_level_required(PERMS['DOMAINS_BAN'])
    +def unban_domain(v, domain):
    +	existing = g.db.get(BannedDomain, domain)
    +	if not existing: abort(400, 'Domain is not banned!')
    +	
    +	g.db.delete(existing)
    +	ma = ModAction(
    +		kind="unban_domain",
    +		user_id=v.id,
    +		_note=domain
    +	)
    +	g.db.add(ma)
    +
    +	return {"message": f"{domain} has been unbanned!"}
    +
    +
    +
     @app.post("/admin/nuke_user")
     @limiter.limit("1/second;30/minute;200/hour;1000/day")
     @admin_level_required(PERMS['POST_COMMENT_MODERATION'])
    diff --git a/files/routes/asset_submissions.py b/files/routes/asset_submissions.py
    index 27cb5a5c2..fdb298e9b 100644
    --- a/files/routes/asset_submissions.py
    +++ b/files/routes/asset_submissions.py
    @@ -1,5 +1,6 @@
     from shutil import move, copyfile
     from os import rename, path
    +from typing import Union
     
     from files.__main__ import app, limiter
     from files.helpers.const import *
    @@ -9,7 +10,11 @@ from files.helpers.get import *
     from files.helpers.wrappers import *
     from files.routes.static import marsey_list
     
    -if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
    +if SITE not in ('pcmemes.net', 'watchpeopledie.tv'):
    +	ASSET_TYPES = (Marsey, HatDef)
    +	CAN_APPROVE_ASSETS = (AEVANN_ID, CARP_ID, SNAKES_ID)
    +	CAN_UPDATE_ASSETS = (AEVANN_ID, CARP_ID, SNAKES_ID, GEESE_ID, JUSTCOOL_ID)
    +
     	@app.get('/asset_submissions/')
     	@limiter.exempt
     	def asset_submissions(path):
    @@ -38,7 +43,6 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     	@app.post("/submit/marseys")
     	@auth_required
     	def submit_marsey(v):
    -
     		file = request.files["image"]
     		name = request.values.get('name').lower().strip()
     		tags = request.values.get('tags').lower().strip()
    @@ -91,32 +95,38 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     
     		return render_template("submit_marseys.html", v=v, marseys=marseys, msg=f"'{name}' submitted successfully!")
     
    +	def verify_permissions_and_get_asset(cls, asset_type:str, v:User, name:str, make_lower=False):
    +		if cls not in ASSET_TYPES: raise Exception("not a valid asset type")
    +		if AEVANN_ID and v.id not in CAN_APPROVE_ASSETS:
    +			abort(403, f"Only Carp can approve {asset_type}!")
    +		name = name.strip()
    +		if make_lower: name = name.lower()
    +		asset = None
    +		if cls == HatDef:
    +			asset = g.db.query(cls).filter_by(name=name).one_or_none()
    +		else:
    +			asset = g.db.get(cls, name)
    +		if not asset:
    +			abort(404, f"This {asset} '{name}' doesn't exist!")
    +		return asset
     
     	@app.post("/admin/approve/marsey/")
     	@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_MARSEYS'])
     	def approve_marsey(v, name):
    -		if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, SNAKES_ID):
    -			return {"error": "Only Carp can approve marseys!"}, 403
    -
    -		name = name.lower().strip()
    -
    -		marsey = g.db.query(Marsey).filter_by(name=name).one_or_none()
    -		if not marsey:
    -			return {"error": f"This marsey '{name}' doesn't exist!"}, 404
    -
    +		marsey = verify_permissions_and_get_asset(Marsey, "marsey", v, name, True)
     		tags = request.values.get('tags').lower().strip()
     		if not tags:
    -			return {"error": "You need to include tags!"}, 400
    +			abort(400, "You need to include tags!")
     
     		new_name = request.values.get('name').lower().strip()
     		if not new_name:
    -			return {"error": "You need to include name!"}, 400
    +			abort(400, "You need to include name!")
     
     
     		if not marsey_regex.fullmatch(new_name):
    -			return {"error": "Invalid name!"}, 400
    +			abort(400, "Invalid name!")
     		if not tags_regex.fullmatch(tags):
    -			return {"error": "Invalid tags!"}, 400
    +			abort(400, "Invalid tags!")
     
     
     		marsey.name = new_name
    @@ -132,9 +142,7 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     			badge_grant(badge_id=16, user=author)
     		else:
     			badge_grant(badge_id=17, user=author)
    -
    -		requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, 
    -			data=f'{{"files": ["https://{SITE}/e/{marsey.name}.webp"]}}', timeout=5)
    +		purge_files_in_cache(f"https://{SITE}/e/{marsey.name}/webp")
     		cache.delete_memoized(marsey_list)
     
     
    @@ -147,42 +155,48 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     
     		author.coins += 250
     		g.db.add(author)
    -		msg = f"@{v.username} has approved a marsey you made: :{marsey.name}:\nYou have received 250 coins as a reward!"
    -		send_repeatable_notification(author.id, msg)
     
    -		if v.id not in (author.id, marsey.submitter_id):
    -			msg = f"@{v.username} has approved a marsey you submitted: :{marsey.name}:"
    +		if v.id != author.id:
    +			msg = f"@{v.username} (Admin) has approved a marsey you made: :{marsey.name}:\nYou have received 250 coins as a reward!"
    +			send_repeatable_notification(author.id, msg)
    +
    +		if v.id != marsey.submitter_id and author.id != marsey.submitter_id:
    +			msg = f"@{v.username} (Admin) has approved a marsey you submitted: :{marsey.name}:"
     			send_repeatable_notification(marsey.submitter_id, msg)
     
     		marsey.submitter_id = None
     
     		return {"message": f"'{marsey.name}' approved!"}
     
    +	def remove_asset(cls, type_name:str, v:User, name:str) -> dict[str, str]:
    +		if cls not in ASSET_TYPES: raise Exception("not a valid asset type")
    +		should_make_lower = cls == Marsey
    +		if should_make_lower: name = name.lower()
    +		name = name.strip()
    +		if not name:
    +			abort(400, f"You need to specify a {type_name}!")
    +		asset = None
    +		if cls == HatDef:
    +			asset = g.db.query(cls).filter_by(name=name).one_or_none()
    +		else:
    +			asset = g.db.get(cls, name)
    +		if not asset:
    +			abort(404, f"This {type_name} '{name}' doesn't exist!")
    +		if v.id not in (asset.submitter_id, AEVANN_ID, CARP_ID):
    +			abort(403, f"Only Carp can remove {type_name}s!")
    +		name = asset.name
    +		if v.id != asset.submitter_id:
    +			msg = f"@{v.username} has rejected a {type_name} you submitted: `'{name}'`"
    +			send_repeatable_notification(asset.submitter_id, msg)
    +		g.db.delete(asset)
    +		os.remove(f"/asset_submissions/{type_name}s/{name}.webp")
    +		os.remove(f"/asset_submissions/{type_name}s/{name}")
    +		return {"message": f"'{name}' removed!"}
     
     	@app.post("/remove/marsey/")
     	@auth_required
     	def remove_marsey(v, name):
    -		name = name.lower().strip()
    -
    -		marsey = g.db.query(Marsey).filter_by(name=name).one_or_none()
    -		if not marsey:
    -			return {"error": f"This marsey '{name}' doesn't exist!"}, 404
    -
    -		if v.id not in (marsey.submitter_id, AEVANN_ID, CARP_ID):
    -			return {"error": "Only Carp can remove marseys!"}, 403
    -
    -		if v.id != marsey.submitter_id:
    -			msg = f"@{v.username} has rejected a marsey you submitted: `'{marsey.name}'`"
    -			send_repeatable_notification(marsey.submitter_id, msg)
    -
    -		g.db.delete(marsey)
    -		os.remove(f"/asset_submissions/marseys/{marsey.name}.webp")
    -		os.remove(f"/asset_submissions/marseys/{marsey.name}")
    -
    -		return {"message": f"'{marsey.name}' removed!"}
    -
    -
    -
    +		return remove_asset(Marsey, "marsey", v, name)
     
     	@app.get("/submit/hats")
     	@auth_required
    @@ -195,7 +209,6 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     	@app.post("/submit/hats")
     	@auth_required
     	def submit_hat(v):
    -
     		name = request.values.get('name').strip()
     		description = request.values.get('description').strip()
     		username = request.values.get('author').strip()
    @@ -229,17 +242,17 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     		highquality = f'/asset_submissions/hats/{name}'
     		file.save(highquality)
     
    -		i = Image.open(highquality)
    -		if i.width > 100 or i.height > 130:
    -			os.remove(highquality)
    -			return error("Images must be 100x130")
    +		with Image.open(highquality) as i:
    +			if i.width > 100 or i.height > 130:
    +				os.remove(highquality)
    +				return error("Images must be 100x130")
     
     		if len(list(Iterator(i))) > 1: price = 1000
     		else: price = 500
     
     		filename = f'/asset_submissions/hats/{name}.webp'
     		copyfile(highquality, filename)
    -		process_image(filename)
    +		process_image(filename, resize=100)
     
     		hat = HatDef(name=name, author_id=author.id, description=description, price=price, submitter_id=v.id)
     		g.db.add(hat)
    @@ -254,30 +267,20 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     	@app.post("/admin/approve/hat/")
     	@admin_level_required(PERMS['MODERATE_PENDING_SUBMITTED_HATS'])
     	def approve_hat(v, name):
    -		if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, SNAKES_ID):
    -			return {"error": "Only Carp can approve hats!"}, 403
    -
    -		name = name.strip()
    -
    -		hat = g.db.query(HatDef).filter_by(name=name).one_or_none()
    -		if not hat:
    -			return {"error": f"This hat '{name}' doesn't exist!"}, 404
    -
    +		hat = verify_permissions_and_get_asset(HatDef, "hat", v, name, False)
     		description = request.values.get('description').strip()
    -		if not description:
    -			return {"error": "You need to include description!"}, 400
    +		if not description: abort(400, "You need to include a description!")
     
     		new_name = request.values.get('name').strip()
    -		if not new_name:
    -			return {"error": "You need to include name!"}, 400
    +		if not new_name: abort(400, "You need to include a name!")
    +		if not hat_regex.fullmatch(new_name): abort(400, "Invalid name!")
    +		if not description_regex.fullmatch(description): abort(400, "Invalid description!")
     
    -		if not hat_regex.fullmatch(new_name):
    -			return {"error": "Invalid name!"}, 400
    -
    -		if not description_regex.fullmatch(description):
    -			return {"error": "Invalid description!"}, 400
    -
    -		hat.price = int(request.values.get('price'))
    +		try:
    +			hat.price = int(request.values.get('price'))
    +			if hat.price < 0: raise ValueError("Invalid hat price")
    +		except:
    +			abort(400, "Invalid hat price")
     		hat.name = new_name
     		hat.description = description
     		g.db.add(hat)
    @@ -304,9 +307,12 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     		g.db.add(hat_copy)
     
     
    +		if v.id != author.id:
    +			msg = f"@{v.username} (Admin) has approved a hat you made: '{hat.name}'"
    +			send_repeatable_notification(author.id, msg)
     
    -		if v.id != hat.submitter_id:
    -			msg = f"@{v.username} has approved a hat you submitted: '{hat.name}'"
    +		if v.id != hat.submitter_id and author.id != hat.submitter_id:
    +			msg = f"@{v.username} (Admin) has approved a hat you submitted: '{hat.name}'"
     			send_repeatable_notification(hat.submitter_id, msg)
     
     		hat.submitter_id = None
    @@ -324,94 +330,87 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     	@app.post("/remove/hat/")
     	@auth_required
     	def remove_hat(v, name):
    -		name = name.strip()
    -
    -		hat = g.db.query(HatDef).filter_by(name=name).one_or_none()
    -		if not hat:
    -			return {"error": f"This hat '{name}' doesn't exist!"}, 404
    -
    -		if v.id not in (hat.submitter_id, AEVANN_ID, CARP_ID):
    -			return {"error": "Only Carp can remove hats!"}, 403
    -
    -		if v.id != hat.submitter_id:
    -			msg = f"@{v.username} has rejected a hat you submitted: `'{hat.name}'`"
    -			send_repeatable_notification(hat.submitter_id, msg)
    -
    -		g.db.delete(hat)
    -		os.remove(f"/asset_submissions/hats/{hat.name}.webp")
    -		os.remove(f"/asset_submissions/hats/{hat.name}")
    -
    -		return {"message": f"'{hat.name}' removed!"}
    -
    -
    +		return remove_asset(HatDef, 'hat', v, name)
     
     	@app.get("/admin/update/marseys")
     	@admin_level_required(PERMS['UPDATE_MARSEYS'])
     	def update_marseys(v):
    -		if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
    +		if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
     			abort(403)
    -
    -		return render_template("update_assets.html", v=v, type="Marsey")
    +		name = request.values.get('name')
    +		tags = None
    +		error = None
    +		if name:
    +			marsey = g.db.get(Marsey, name)
    +			if marsey:
    +				tags = marsey.tags
    +			else:
    +				name = None
    +				error = "A marsey with this name doesn't exist!"
    +		return render_template("update_assets.html", v=v, error=error, name=name, tags=tags, type="Marsey")
     
     
     	@app.post("/admin/update/marseys")
     	@admin_level_required(PERMS['UPDATE_MARSEYS'])
     	def update_marsey(v):
    -		if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
    +		if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
     			abort(403)
     
     		file = request.files["image"]
     		name = request.values.get('name').lower().strip()
    +		tags = request.values.get('tags').lower().strip()
     
     		def error(error):
    -			return render_template("update_assets.html", v=v, error=error, type="Marsey")
    -
    -		if request.headers.get("cf-ipcountry") == "T1":
    -			return error("Image uploads are not allowed through TOR.")
    -
    -		if not file or not file.content_type.startswith('image/'):
    -			return error("You need to submit an image!")
    +			return render_template("update_assets.html", v=v, error=error, name=name, tags=tags, type="Marsey")
     
     		if not marsey_regex.fullmatch(name):
     			return error("Invalid name!")
     
    -		existing = g.db.query(Marsey.name).filter_by(name=name).one_or_none()
    +		existing = g.db.get(Marsey, name)
     		if not existing:
     			return error("A marsey with this name doesn't exist!")
     
    -		for x in ('png','jpeg','webp','gif'):
    -			if path.isfile(f'/asset_submissions/marseys/original/{name}.{x}'):
    -				os.remove(f'/asset_submissions/marseys/original/{name}.{x}')
    +		if file:
    +			if request.headers.get("cf-ipcountry") == "T1":
    +				return error("Image uploads are not allowed through TOR.")
    +			if not file.content_type.startswith('image/'):
    +				return error("You need to submit an image!")
    +			
    +			for x in ('png','jpeg','webp','gif'):
    +				if path.isfile(f'/asset_submissions/marseys/original/{name}.{x}'):
    +					os.remove(f'/asset_submissions/marseys/original/{name}.{x}')
     
    -		highquality = f"/asset_submissions/marseys/{name}"
    -		file.save(highquality)
    -		with Image.open(highquality) as i:
    -			format = i.format.lower()
    -		new_path = f'/asset_submissions/marseys/original/{name}.{format}'
    -		rename(highquality, new_path)
    +			highquality = f"/asset_submissions/marseys/{name}"
    +			file.save(highquality)
    +			with Image.open(highquality) as i:
    +				format = i.format.lower()
    +			new_path = f'/asset_submissions/marseys/original/{name}.{format}'
    +			rename(highquality, new_path)
     
    -		filename = f"files/assets/images/emojis/{name}.webp"
    -		copyfile(new_path, filename)
    -		process_image(filename, resize=200, trim=True)
    -
    -		requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, 
    -			data=f'{{"files": ["https://{SITE}/e/{name}.webp", "https://{SITE}/assets/images/emojis/{name}.webp", "https://{SITE}/asset_submissions/marseys/original/{name}.{format}"]}}', timeout=5)
    +			filename = f"files/assets/images/emojis/{name}.webp"
    +			copyfile(new_path, filename)
    +			process_image(filename, resize=200, trim=True)
    +			purge_files_in_cache([f"https://{SITE}/e/{name}.webp", f"https://{SITE}/assets/images/emojis/{name}.webp", f"https://{SITE}/asset_submissions/marseys/original/{name}.{format}"])
    +		
    +		if tags and existing.tags != tags:
    +			existing.tags = tags
    +			g.db.add(existing)
    +		elif not file:
    +			return error("You need to update this marsey!")
     
     		ma = ModAction(
     			kind="update_marsey",
     			user_id=v.id,
    -			_note=name
    +			_note=f'{name}'
     		)
     		g.db.add(ma)
     
    -		return render_template("update_assets.html", v=v, msg=f"'{name}' updated successfully!", type="Marsey")
    -
    -
    +		return render_template("update_assets.html", v=v, msg=f"'{name}' updated successfully!", name=name, tags=tags, type="Marsey")
     
     	@app.get("/admin/update/hats")
     	@admin_level_required(PERMS['UPDATE_HATS'])
     	def update_hats(v):
    -		if AEVANN_ID and v.id not in (AEVANN_ID, CARP_ID, GEESE_ID, SNAKES_ID):
    +		if AEVANN_ID and v.id not in CAN_UPDATE_ASSETS:
     			abort(403)
     
     		return render_template("update_assets.html", v=v, type="Hat")
    @@ -461,15 +460,12 @@ if SITE not in ('pcmemes.net', 'watchpeopledie.co'):
     
     		filename = f"files/assets/images/hats/{name}.webp"
     		copyfile(new_path, filename)
    -		process_image(filename)
    -
    -		requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, 
    -			data=f'{{"files": ["https://{SITE}/i/hats/{name}.webp", "https://{SITE}/assets/images/hats/{name}.webp", "https://{SITE}/asset_submissions/hats/original/{name}.{format}"]}}', timeout=5)
    -
    +		process_image(filename, resize=100)
    +		purge_files_in_cache([f"https://{SITE}/i/hats/{name}.webp", f"https://{SITE}/assets/images/hats/{name}.webp", f"https://{SITE}/asset_submissions/hats/original/{name}.{format}"])
     		ma = ModAction(
     			kind="update_hat",
     			user_id=v.id,
    -			_note=name
    +			_note=f'{name}'
     		)
     		g.db.add(ma)
     
    diff --git a/files/routes/awards.py b/files/routes/awards.py
    index b5630ebb1..b3ad38ee9 100644
    --- a/files/routes/awards.py
    +++ b/files/routes/awards.py
    @@ -4,7 +4,6 @@ from files.helpers.alerts import *
     from files.helpers.get import *
     from files.helpers.const import *
     from files.helpers.regex import *
    -from files.helpers.discord import *
     from files.helpers.actions import *
     from files.classes.award import *
     from .front import frontlist
    @@ -17,10 +16,8 @@ from copy import deepcopy
     @app.get("/shop")
     @app.get("/settings/shop")
     @auth_required
    +@feature_required('AWARDS')
     def shop(v):
    -	if not FEATURES['AWARDS']:
    -		abort(404)
    -
     	AWARDS = deepcopy(AWARDS2)
     
     	if v.house:
    @@ -44,15 +41,15 @@ def shop(v):
     @app.post("/buy/")
     @limiter.limit("100/minute;200/hour;1000/day")
     @auth_required
    +@feature_required('BADGES')
     def buy(v, award):
    -	if not FEATURES['AWARDS']:
    -		abort(404)
    +	
     
     	if award == 'benefactor' and not request.values.get("mb"):
    -		return {"error": "You can only buy the Benefactor award with marseybux."}, 403
    +		abort(403, "You can only buy the Benefactor award with marseybux.")
     
     	if award == 'ghost' and v.admin_level < PERMS['BUY_GHOST_AWARD']:
    -		return {"error": "Only admins can buy this award."}, 403
    +		abort(403, "Only admins can buy this award")
     
     	AWARDS = deepcopy(AWARDS2)
     
    @@ -67,15 +64,15 @@ def buy(v, award):
     
     	if request.values.get("mb"):
     		if award == "grass":
    -			return {"error": "You can't buy the grass award with marseybux."}, 403
    +			abort(403, "You can't buy the grass award with marseybux.")
     
     		charged = v.charge_account('procoins', price)
     		if not charged:
    -			return {"error": "Not enough marseybux."}, 400
    +			abort(400, "Not enough marseybux.")
     	else:
     		charged = v.charge_account('coins', price)
     		if not charged:
    -			return {"error": "Not enough coins."}, 400
    +			abort(400, "Not enough coins.")
     
     		v.coins_spent += price
     		if v.coins_spent >= 1000000:
    @@ -127,10 +124,8 @@ def buy(v, award):
     @limiter.limit("1/second;30/minute;200/hour;1000/day")
     @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
     @is_not_permabanned
    +@feature_required('BADGES')
     def award_thing(v, thing_type, id):
    -	if not FEATURES['AWARDS']:
    -		abort(404)
    -
     	if thing_type == 'post': thing = get_post(id)
     	else: thing = get_comment(id)
     
    @@ -142,8 +137,7 @@ def award_thing(v, thing_type, id):
     	if v.house:
     		AWARDS[v.house] = HOUSE_AWARDS[v.house]
     
    -	if kind not in AWARDS:
    -		return {"error": "This award doesn't exist."}, 404
    +	if kind not in AWARDS: abort(404, "This award doesn't exist")
     
     	award = g.db.query(AwardRelationship).filter(
     		AwardRelationship.kind == kind,
    @@ -152,8 +146,7 @@ def award_thing(v, thing_type, id):
     		AwardRelationship.comment_id == None
     	).first()
     
    -	if not award:
    -		return {"error": "You don't have that award."}, 404
    +	if not award: abort(404, "You don't have that award")
     
     	if thing_type == 'post': award.submission_id = thing.id
     	else: award.comment_id = thing.id
    @@ -167,13 +160,13 @@ def award_thing(v, thing_type, id):
     	if author.shadowbanned: abort(404)
     
     	if SITE == 'rdrama.net' and author.id in (PIZZASHILL_ID, CARP_ID):
    -		return {"error": "This user is immune to awards."}, 403
    +		abort(403, "This user is immune to awards.")
     
     	if kind == "benefactor" and author.id == v.id:
    -		return {"error": "You can't use this award on yourself."}, 400
    +		abort(400, "You can't use this award on yourself.")
     
     	if kind == 'marsify' and author.marsify == 1:
    -		return {"error": "User is already permanently marsified!"}, 403
    +		abort(403, "User is already permanently marsified!")
     
     	if v.id != author.id:
     		safe_username = "👻" if thing.ghost else f"@{author.username}"
    @@ -209,19 +202,6 @@ def award_thing(v, thing_type, id):
     		elif author.unban_utc:
     			author.unban_utc += 86400
     			send_repeatable_notification(author.id, f"Your account has been banned for **yet another day** for {link}. Seriously man?")
    -
    -		if v.admin_level >= PERMS['USER_BAN']:
    -			log_link = f'/{thing_type}/{thing.id}'
    -			reason = f'{log_link}'
    -
    -			note = f'reason: "{reason}", duration: for 1 day'
    -			ma=ModAction(
    -				kind="ban_user",
    -				user_id=v.id,
    -				target_user_id=author.id,
    -				_note=note
    -				)
    -			g.db.add(ma)
     	elif kind == "unban":
     		if not author.is_suspended or not author.unban_utc or time.time() > author.unban_utc: abort(403)
     
    @@ -233,39 +213,18 @@ def award_thing(v, thing_type, id):
     			author.is_banned = 0
     			author.ban_reason = None
     			send_repeatable_notification(author.id, "You have been unbanned!")
    -
    -		if v.admin_level >= PERMS['USER_BAN']:
    -			ma=ModAction(
    -				kind="unban_user",
    -				user_id=v.id,
    -				target_user_id=author.id,
    -				)
    -			g.db.add(ma)
     	elif kind == "grass":
     		author.is_banned = AUTOJANNY_ID
     		author.ban_reason = f"grass award used by @{v.username} on /{thing_type}/{thing.id}"
     		author.unban_utc = int(time.time()) + 30 * 86400
     		send_repeatable_notification(author.id, f"Your account has been banned permanently for {link}. You must [provide the admins](/contact) a timestamped picture of you touching grass/snow/sand/ass to get unbanned!")
    -
    -		if v.admin_level >= PERMS['USER_BAN']:
    -			log_link = f'/{thing_type}/{thing.id}'
    -			reason = f'{log_link}'
    -
    -			note = f'reason: "{reason}", duration: for 30 days'
    -			ma=ModAction(
    -				kind="ban_user",
    -				user_id=v.id,
    -				target_user_id=author.id,
    -				_note=note
    -				)
    -			g.db.add(ma)
     	elif kind == "pin":
    -		if not FEATURES['PINS']:
    -			abort(403)
    +		if not FEATURES['PINS']: abort(403)
    +		if thing.is_banned: abort(403)
     		if thing.stickied and thing.stickied_utc:
     			thing.stickied_utc += 3600
     		else:
    -			thing.stickied = f'{v.username} (pin award)'
    +			thing.stickied = f'{v.username}{PIN_AWARD_TEXT}'
     			if thing_type == 'comment':
     				thing.stickied_utc = int(time.time()) + 3600*6
     			else:
    @@ -273,7 +232,8 @@ def award_thing(v, thing_type, id):
     		g.db.add(thing)
     		cache.delete_memoized(frontlist)
     	elif kind == "unpin":
    -		if not thing.stickied_utc: abort(403)
    +		if not thing.stickied_utc: abort(400)
    +		if thing.author_id == LAWLZ_ID and SITE_NAME == 'rDrama': abort(403, "You can't unpin lawlzposts!")
     
     		if thing_type == 'comment':
     			t = thing.stickied_utc - 3600*6
    @@ -288,21 +248,12 @@ def award_thing(v, thing_type, id):
     		g.db.add(thing)
     	elif kind == "agendaposter" and not (author.agendaposter and author.agendaposter == 0):
     		if author.marseyawarded:
    -			return {"error": "This user is the under the effect of a conflicting award: Marsey award."}, 404
    +			abort(409, "This user is under the effect of a conflicting award: Marsey award.")
     
     		if author.agendaposter and time.time() < author.agendaposter: author.agendaposter += 86400
     		else: author.agendaposter = int(time.time()) + 86400
     		
     		badge_grant(user=author, badge_id=28)
    -
    -		if v.admin_level >= PERMS['USER_AGENDAPOSTER']:
    -			ma = ModAction(
    -				kind="agendaposter",
    -				user_id=v.id,
    -				target_user_id=author.id,
    -				_note=f"for 1 day"
    -			)
    -			g.db.add(ma)
     	elif kind == "flairlock":
     		if thing.ghost: abort(403)
     		new_name = note[:100].replace("𒐪","")
    @@ -316,10 +267,8 @@ def award_thing(v, thing_type, id):
     			author.flairchanged = int(time.time()) + 86400
     			badge_grant(user=author, badge_id=96)
     	elif kind == "pause":
    -		author.mute = True
     		badge_grant(badge_id=68, user=author)
     	elif kind == "unpausable":
    -		author.unmutable = True
     		badge_grant(badge_id=67, user=author)
     	elif kind == "marsey":
     		if author.marseyawarded: author.marseyawarded += 86400
    @@ -327,31 +276,26 @@ def award_thing(v, thing_type, id):
     		badge_grant(user=author, badge_id=98)
     	elif kind == "pizzashill":
     		if author.bird:
    -			return {"error": "This user is the under the effect of a conflicting award: Bird Site award."}, 404
    +			abort(409, "This user is under the effect of a conflicting award: Bird Site award.")
     		if author.longpost: author.longpost += 86400
     		else: author.longpost = int(time.time()) + 86400
     		badge_grant(user=author, badge_id=97)
     	elif kind == "bird":
     		if author.longpost:
    -			return {"error": "This user is the under the effect of a conflicting award: Pizzashill award."}, 404
    +			abort(409, "This user is under the effect of a conflicting award: Pizzashill award.")
     		if author.bird: author.bird += 86400
     		else: author.bird = int(time.time()) + 86400
     		badge_grant(user=author, badge_id=95)
     	elif kind == "eye":
    -		author.eye = True
     		badge_grant(badge_id=83, user=author)
     	elif kind == "offsitementions":
    -		author.offsitementions = True
     		badge_grant(user=author, badge_id=140)
     	elif kind == "alt":
    -		author.alt = True
     		badge_grant(badge_id=84, user=author)
     	elif kind == "unblockable":
    -		author.unblockable = True
     		badge_grant(badge_id=87, user=author)
     		for block in g.db.query(UserBlock).filter_by(target_id=author.id).all(): g.db.delete(block)
     	elif kind == "fish":
    -		author.fish = True
     		badge_grant(badge_id=90, user=author)
     	elif kind == "progressivestack":
     		if not FEATURES['PINS']:
    @@ -360,12 +304,11 @@ def award_thing(v, thing_type, id):
     		else: author.progressivestack = int(time.time()) + 21600
     		badge_grant(user=author, badge_id=94)
     	elif kind == "benefactor":
    -		if author.patron: return {"error": "This user is already a paypig!"}, 400
    +		if author.patron: abort(409, f"This user is already a {patron.lower()}!")
     		author.patron = 1
     		if author.patron_utc: author.patron_utc += 2629746
     		else: author.patron_utc = int(time.time()) + 2629746
     		author.procoins += 2500
    -		if author.discord_id: add_role(author, "1")
     		badge_grant(user=v, badge_id=103)
     	elif kind == "rehab":
     		if author.rehab: author.rehab += 86400
    @@ -416,7 +359,7 @@ def award_thing(v, thing_type, id):
     			if author.marsify: body = marsify(body)
     			thing.body_html = sanitize(body, limit_pings=5)
     			g.db.add(thing)
    -	elif ("Femboy" in kind and kind == v.house):
    +	elif ("Femboy" in kind and kind == v.house) or kind == 'rainbow':
     		if author.rainbow: author.rainbow += 86400
     		else: author.rainbow = int(time.time()) + 86400
     		badge_grant(user=author, badge_id=171)
    diff --git a/files/routes/casino.py b/files/routes/casino.py
    index 7053de0f5..b51fb1617 100644
    --- a/files/routes/casino.py
    +++ b/files/routes/casino.py
    @@ -14,229 +14,217 @@ from files.helpers.lottery import *
     @app.get("/casino")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def casino(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return render_template("casino/rehab.html", v=v)
    +	if v.rehab:
    +		return render_template("casino/rehab.html", v=v)
     
    -    return render_template("casino.html", v=v)
    +	return render_template("casino.html", v=v)
     
     
     @app.get("/casino/")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def casino_game_page(v, game):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return render_template("casino/rehab.html", v=v)
    -    elif game not in CASINO_GAME_KINDS:
    -        abort(404)
    +	if v.rehab:
    +		return render_template("casino/rehab.html", v=v)
    +	elif game not in CASINO_GAME_KINDS:
    +		abort(404)
     
    -    feed = json.dumps(get_game_feed(game))
    -    leaderboard = json.dumps(get_game_leaderboard(game))
    +	feed = json.dumps(get_game_feed(game))
    +	leaderboard = json.dumps(get_game_leaderboard(game))
     
    -    game_state = ''
    -    if game == 'blackjack':
    -        if get_active_twentyone_game(v):
    -            game_state = json.dumps(get_active_twentyone_game_state(v))
    +	game_state = ''
    +	if game == 'blackjack':
    +		if get_active_twentyone_game(v):
    +			game_state = json.dumps(get_active_twentyone_game_state(v))
     
    -    return render_template(
    -        f"casino/{game}_screen.html",
    -        v=v,
    -        game=game,
    -        feed=feed,
    -        leaderboard=leaderboard,
    -        game_state=game_state
    -    )
    +	return render_template(
    +		f"casino/{game}_screen.html",
    +		v=v,
    +		game=game,
    +		feed=feed,
    +		leaderboard=leaderboard,
    +		game_state=game_state
    +	)
     
     
     @app.get("/casino//feed")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def casino_game_feed(v, game):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    -    elif game not in CASINO_GAME_KINDS:
    -        abort(404)
    +	if v.rehab: 
    +		abort(403, "You are under Rehab award effect!")
    +	elif game not in CASINO_GAME_KINDS:
    +		abort(404)
     
    -    feed = get_game_feed(game)
    -    return {"feed": feed}
    +	feed = get_game_feed(game)
    +	return {"feed": feed}
     
     
     # Lottershe
     @app.get("/lottershe")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def lottershe(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)  
    -    elif v.rehab:
    -        return render_template("casino/rehab.html", v=v)
    +	if v.rehab:
    +		return render_template("casino/rehab.html", v=v)
     
    -    participants = get_users_participating_in_lottery()
    -    return render_template("lottery.html", v=v, participants=participants)
    +	participants = get_users_participating_in_lottery()
    +	return render_template("lottery.html", v=v, participants=participants)
     
     # Slots
     @app.post("/casino/slots")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def pull_slots(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        wager = int(request.values.get("wager"))
    -    except:
    -        return {"error": "Invalid wager."}, 400
    +	try:
    +		wager = int(request.values.get("wager"))
    +	except:
    +		abort(400, "Invalid wager.")
     
    -    try:
    -        currency = request.values.get("currency")
    -    except:
    -        return {"error": "Invalid currency (expected 'coin' or 'marseybux')."}, 400
    +	try:
    +		currency = request.values.get("currency")
    +	except:
    +		abort(400, "Invalid currency (expected 'coin' or 'marseybux').")
     
    -    if (currency == "coin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
    -        return {"error": f"Not enough {currency} to make that bet."}, 400
    +	if (currency == "coin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
    +		abort(400, f"Not enough {currency} to make that bet")
     
    -    success, game_state = casino_slot_pull(v, wager, currency)
    +	success, game_state = casino_slot_pull(v, wager, currency)
     
    -    if success:
    -        return {"game_state": game_state, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    else:
    -        return {"error": f"Wager must be more than 5 {currency}."}, 400
    +	if success:
    +		return {"game_state": game_state, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	else:
    +		abort(400, f"Wager must be more than 5 {currency}")
     
     
     # 21
     @app.post("/casino/twentyone/deal")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def blackjack_deal_to_player(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        wager = int(request.values.get("wager"))
    -        currency = request.values.get("currency")
    -        create_new_game(v, wager, currency)
    -        state = dispatch_action(v, BlackjackAction.DEAL)
    -        feed = get_game_feed('blackjack')
    +	try:
    +		wager = int(request.values.get("wager"))
    +		currency = request.values.get("currency")
    +		create_new_game(v, wager, currency)
    +		state = dispatch_action(v, BlackjackAction.DEAL)
    +		feed = get_game_feed('blackjack')
     
    -        return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    except Exception as e:
    -        return {"error": str(e)}, 400
    +		return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	except Exception as e:
    +		abort(400, str(e))
     
     
     @app.post("/casino/twentyone/hit")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def blackjack_player_hit(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        state = dispatch_action(v, BlackjackAction.HIT)
    -        feed = get_game_feed('blackjack')
    -        return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    except:
    -        return {"error": "Unable to hit."}, 400
    +	try:
    +		state = dispatch_action(v, BlackjackAction.HIT)
    +		feed = get_game_feed('blackjack')
    +		return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	except:
    +		abort(400, "Unable to hit.")
     
     
     @app.post("/casino/twentyone/stay")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def blackjack_player_stay(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        state = dispatch_action(v, BlackjackAction.STAY)
    -        feed = get_game_feed('blackjack')
    -        return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    except:
    -        return {"error": "Unable to stay."}, 400
    +	try:
    +		state = dispatch_action(v, BlackjackAction.STAY)
    +		feed = get_game_feed('blackjack')
    +		return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	except:
    +		abort(400, "Unable to stay.")
     
     
     @app.post("/casino/twentyone/double-down")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def blackjack_player_doubled_down(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        state = dispatch_action(v, BlackjackAction.DOUBLE_DOWN)
    -        feed = get_game_feed('blackjack')
    -        return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    except:
    -        return {"error": "Unable to double down."}, 400
    +	try:
    +		state = dispatch_action(v, BlackjackAction.DOUBLE_DOWN)
    +		feed = get_game_feed('blackjack')
    +		return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	except:
    +		abort(400, "Unable to double down.")
     
     
     @app.post("/casino/twentyone/buy-insurance")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def blackjack_player_bought_insurance(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        state = dispatch_action(v, BlackjackAction.BUY_INSURANCE)
    -        feed = get_game_feed('blackjack')
    -        return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    except:
    -        return {"error": "Unable to buy insurance."}, 400
    +	try:
    +		state = dispatch_action(v, BlackjackAction.BUY_INSURANCE)
    +		feed = get_game_feed('blackjack')
    +		return {"success": True, "state": state, "feed": feed, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	except:
    +		abort(403, "Unable to buy insurance.")
     
     # Roulette
     @app.get("/casino/roulette/bets")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def roulette_get_bets(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    bets = get_roulette_bets()
    +	bets = get_roulette_bets()
     
    -    return {"success": True, "bets": bets, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	return {"success": True, "bets": bets, "gambler": {"coins": v.coins, "procoins": v.procoins}}
     
     
     @app.post("/casino/roulette/place-bet")
     @limiter.limit("100/minute;2000/hour;12000/day")
     @auth_required
    +@feature_required('GAMBLING')
     def roulette_player_placed_bet(v):
    -    if not FEATURES['GAMBLING']:
    -        abort(404)
    -    elif v.rehab:
    -        return {"error": "You are under Rehab award effect!"}, 400
    +	if v.rehab:
    +		abort(403, "You are under Rehab award effect!")
     
    -    try:
    -        bet = request.values.get("bet")
    -        which = request.values.get("which")
    -        amount = int(request.values.get("wager"))
    -        currency = request.values.get("currency")
    +	try:
    +		bet = request.values.get("bet")
    +		which = request.values.get("which")
    +		amount = int(request.values.get("wager"))
    +		currency = request.values.get("currency")
     
    -        if amount < 5:
    -            return {"error": f"Minimum bet is 5 {currency}."}
    +		if amount < 5:
    +			abort(400, f"Minimum bet is 5 {currency}.")
     
    -        gambler_placed_roulette_bet(v, bet, which, amount, currency)
    +		gambler_placed_roulette_bet(v, bet, which, amount, currency)
     
    -        bets = get_roulette_bets()
    +		bets = get_roulette_bets()
     
    -        return {"success": True, "bets": bets, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    -    except:
    -        return {"error": "Unable to place a bet."}, 400
    +		return {"success": True, "bets": bets, "gambler": {"coins": v.coins, "procoins": v.procoins}}
    +	except:
    +		abort(400, "Unable to place a bet.")
    diff --git a/files/routes/chat.py b/files/routes/chat.py
    index 56a53b4d6..c68773d69 100644
    --- a/files/routes/chat.py
    +++ b/files/routes/chat.py
    @@ -6,6 +6,7 @@ from files.helpers.sanitize import sanitize
     from files.helpers.const import *
     from files.helpers.alerts import *
     from files.helpers.regex import *
    +from files.helpers.actions import *
     from flask_socketio import SocketIO, emit
     from files.__main__ import app, limiter, cache
     from flask import render_template
    @@ -78,14 +79,11 @@ def speak(data, v):
     		"time": int(time.time()),
     	}
     	
    -	if v.shadowbanned:
    +	if v.shadowbanned or not execute_blackjack(v, None, text, "chat"):
     		emit('speak', data)
    -	elif blackjack and any(i in text.lower() for i in blackjack.split()):
    +	elif ('discord.gg' in text or 'discord.com' in text or 'discordapp.com' in text):
    +		# Follows same logic as in users.py:message2/messagereply; TODO: unify?
     		emit('speak', data)
    -		v.shadowbanned = 'AutoJanny'
    -		if not v.is_banned: v.ban_reason = 'Blackjack'
    -		g.db.add(v)
    -		send_repeatable_notification(CARP_ID, f"{v.username} has been shadowbanned because of a chat message.")
     	elif recipient:
     		if user_ids_to_socket_ids.get(recipient):
     			recipient_sid = user_ids_to_socket_ids[recipient]
    diff --git a/files/routes/comments.py b/files/routes/comments.py
    index 547a34af8..d206b7e75 100644
    --- a/files/routes/comments.py
    +++ b/files/routes/comments.py
    @@ -36,7 +36,7 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
     	comment = get_comment(cid, v=v)
     	if not comment.can_see(v): abort(403)
     	
    -	if comment.author.shadowbanned and not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
    +	if comment.author.shadowbanned and not (v and v.can_see_shadowbanned):
     		abort(404)
     
     	if v and request.values.get("read"):
    @@ -46,20 +46,17 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
     			g.db.add(notif)
     
     	if comment.post and comment.post.club and not (v and (v.paid_dues or v.id in [comment.author_id, comment.post.author_id])): abort(403)
    -
     	if not comment.parent_submission and not (v and (comment.author.id == v.id or comment.sentto == v.id)) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) : abort(403)
     	
     	if not pid:
     		if comment.parent_submission: pid = comment.parent_submission
    -		elif SITE_NAME == 'rDrama': pid = 6489
    -		elif SITE == 'pcmemes.net': pid = 2487
    -		else: pid = 1
    +		else: pid = NOTIFICATION_THREAD
     	
     	post = get_post(pid, v=v)
     	
     	if post.over_18 and not (v and v.over_18) and not session.get('over_18', 0) >= int(time.time()):
    -		if request.headers.get("Authorization"): return {"error": 'This content is not suitable for some users and situations.'}, 403
    -		else: return render_template("errors/nsfw.html", v=v)
    +		if v and v.client: abort(403, "This content is not suitable for some users and situations.")
    +		else: return render_template("errors/nsfw.html", v=v), 403
     
     	try: context = min(int(request.values.get("context", 0)), 8)
     	except: context = 0
    @@ -71,53 +68,16 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
     	top_comment = c
     
     	if v: defaultsortingcomments = v.defaultsortingcomments
    -	else: defaultsortingcomments = "top"
    +	else: defaultsortingcomments = "hot"
     	sort=request.values.get("sort", defaultsortingcomments)
     
     	if v:
    -		votes = g.db.query(CommentVote.vote_type, CommentVote.comment_id).filter_by(user_id=v.id).subquery()
    -
    -		blocking = v.blocking.subquery()
    -
    -		blocked = v.blocked.subquery()
    -
    -		comments = g.db.query(
    -			Comment,
    -			votes.c.vote_type,
    -			blocking.c.target_id,
    -			blocked.c.target_id,
    -		)
    -
    -		if not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
    -			comments = comments.join(Comment.author).filter(User.shadowbanned == None)
    -		 
    -		comments=comments.filter(
    -			Comment.top_comment_id == c.top_comment_id
    -		).join(
    -			votes,
    -			votes.c.comment_id == Comment.id,
    -			isouter=True
    -		).join(
    -			blocking,
    -			blocking.c.target_id == Comment.author_id,
    -			isouter=True
    -		).join(
    -			blocked,
    -			blocked.c.user_id == Comment.author_id,
    -			isouter=True
    -		)
    -
    -		output = []
    -		for c in comments:
    -			comment = c[0]
    -			comment.voted = c[1] or 0
    -			comment.is_blocking = c[2] or 0
    -			comment.is_blocked = c[3] or 0
    -			output.append(comment)
    -
    +		# this is required because otherwise the vote and block
    +		# props won't save properly unless you put them in a list
    +		output = get_comments_v_properties(v, False, None, Comment.top_comment_id == c.top_comment_id)[1]
     	post.replies=[top_comment]
     			
    -	if request.headers.get("Authorization"): return top_comment.json
    +	if v and v.client: return top_comment.json
     	else: 
     		if post.is_banned and not (v and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.author_id == v.id)): template = "submission_banned.html"
     		else: template = "submission.html"
    @@ -128,17 +88,17 @@ def post_pid_comment_cid(cid, pid=None, anything=None, v=None, sub=None):
     @limiter.limit("1/second;20/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
     @auth_required
     def comment(v):
    -	if v.is_suspended: return {"error": "You can't perform this action while banned."}, 403
    +	if v.is_suspended: abort(403, "You can't perform this action while banned.")
     
     	parent_submission = request.values.get("submission").strip()
     	parent_fullname = request.values.get("parent_fullname").strip()
     
     	parent_post = get_post(parent_submission, v=v)
     	sub = parent_post.sub
    -	if sub and v.exiled_from(sub): return {"error": f"You're exiled from /h/{sub}"}, 403
    +	if sub and v.exiled_from(sub): abort(403, f"You're exiled from /h/{sub}")
     
     	if sub in ('furry','vampire','racist','femboy') and not v.client and not v.house.lower().startswith(sub):
    -		return {"error": f"You need to be a member of House {sub.capitalize()} to comment in /h/{sub}"}, 400
    +		abort(403, f"You need to be a member of House {sub.capitalize()} to comment in /h/{sub}")
     
     	if parent_post.club and not (v and (v.paid_dues or v.id == parent_post.author_id)): abort(403)
     
    @@ -159,18 +119,17 @@ def comment(v):
     	if not parent.can_see(v): abort(404)
     	if parent.deleted_utc != 0: abort(404)
     
    -	if level > COMMENT_MAX_DEPTH:
    -		return {"error": f"Max comment level is {COMMENT_MAX_DEPTH}"}, 400
    +	if level > COMMENT_MAX_DEPTH: abort(400, f"Max comment level is {COMMENT_MAX_DEPTH}")
     
     	body = sanitize_raw_body(request.values.get("body", ""), False)
     
     	if parent_post.id not in ADMIGGERS:
     		if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
    -			return {"error":"You have to type more than 280 characters!"}, 403
    +			abort(403, "You have to type more than 280 characters!")
     		elif v.bird and len(body) > 140:
    -			return {"error":"You have to type less than 140 characters!"}, 403
    +			abort(403, "You have to type less than 140 characters!")
     
    -	if not body and not request.files.get('file'): return {"error":"You need to actually write something!"}, 400
    +	if not body and not request.files.get('file'): abort(400, "You need to actually write something!")
     	
     	options = []
     	for i in poll_regex.finditer(body):
    @@ -189,30 +148,28 @@ def comment(v):
     				oldname = f'/images/{time.time()}'.replace('.','') + '.webp'
     				file.save(oldname)
     				image = process_image(oldname, patron=v.patron)
    -				if image == "": return {"error":"Image upload failed"}, 400
    +				if image == "": abort(400, "Image upload failed")
     				if v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] and level == 1:
    -					if parent_post.id == SIDEBAR_THREAD:
    -						li = sorted(os.listdir(f'files/assets/images/{SITE_NAME}/sidebar'),
    +					def process_sidebar_or_banner(type, resize=0):
    +						li = sorted(os.listdir(f'files/assets/images/{SITE_NAME}/{type}'),
     							key=lambda e: int(e.split('.webp')[0]))[-1]
     						num = int(li.split('.webp')[0]) + 1
    -						filename = f'files/assets/images/{SITE_NAME}/sidebar/{num}.webp'
    +						filename = f'files/assets/images/{SITE_NAME}/{type}/{num}.webp'
     						copyfile(oldname, filename)
    -						process_image(filename, resize=400)
    +						process_image(filename, resize=resize)
    +
    +					if parent_post.id == SIDEBAR_THREAD:
    +						process_sidebar_or_banner('sidebar', 400)
     					elif parent_post.id == BANNER_THREAD:
     						banner_width = 1200 if not SITE_NAME == 'PCM' else 0
    -						li = sorted(os.listdir(f'files/assets/images/{SITE_NAME}/banners'),
    -							key=lambda e: int(e.split('.webp')[0]))[-1]
    -						num = int(li.split('.webp')[0]) + 1
    -						filename = f'files/assets/images/{SITE_NAME}/banners/{num}.webp'
    -						copyfile(oldname, filename)
    -						process_image(filename, resize=banner_width)
    +						process_sidebar_or_banner('banners', banner_width)
     					elif parent_post.id == BADGE_THREAD:
     						try:
     							badge_def = loads(body)
     							name = badge_def["name"]
     
     							existing = g.db.query(BadgeDef).filter_by(name=name).one_or_none()
    -							if existing: return {"error": "A badge with this name already exists!"}, 403
    +							if existing: abort(409, "A badge with this name already exists!")
     
     							badge = BadgeDef(name=name, description=badge_def["description"])
     							g.db.add(badge)
    @@ -220,15 +177,14 @@ def comment(v):
     							filename = f'files/assets/images/badges/{badge.id}.webp'
     							copyfile(oldname, filename)
     							process_image(filename, resize=300)
    -							requests.post(f'https://api.cloudflare.com/client/v4/zones/{CF_ZONE}/purge_cache', headers=CF_HEADERS, 
    -								data=f'{{"files": ["https://{SITE}/assets/images/badges/{badge.id}.webp"]}}', timeout=5)
    +							purge_files_in_cache(f"https://{SITE}/assets/images/badges/{badge.id}.webp")
     						except Exception as e:
    -							return {"error": str(e)}, 400
    +							abort(400, str(e))
     				body += f"\n\n![]({image})"
     			elif file.content_type.startswith('video/'):
    -				body += f"\n\n{process_video(file)}"
    +				body += f"\n\n{SITE_FULL}{process_video(file)}"
     			elif file.content_type.startswith('audio/'):
    -				body += f"\n\n{process_audio(file)}"
    +				body += f"\n\n{SITE_FULL}{process_audio(file)}"
     			else:
     				abort(415)
     
    @@ -256,50 +212,16 @@ def comment(v):
     																	Comment.parent_submission == parent_submission,
     																	Comment.body_html == body_html
     																	).first()
    -		if existing: return {"error": f"You already made that comment: /comment/{existing.id}"}, 409
    +		if existing: abort(409, f"You already made that comment: /comment/{existing.id}")
     
     	if parent.author.any_block_exists(v) and v.admin_level < PERMS['POST_COMMENT_MODERATION']:
    -		return {"error": "You can't reply to users who have blocked you or users that you have blocked."}, 403
    +		abort(403, "You can't reply to users who have blocked you or users that you have blocked.")
     
    -	is_bot = v.id != BBBB_ID and (bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID))
    +	is_bot = (v.client is not None
    +		and v.id != BBBB_ID
    +		or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID))
     
    -	if len(body) > 50:
    -		now = int(time.time())
    -		cutoff = now - 60 * 60 * 24
    -
    -		similar_comments = g.db.query(Comment).filter(
    -			Comment.author_id == v.id,
    -			Comment.body.op('<->')(body) < COMMENT_SPAM_SIMILAR_THRESHOLD,
    -			Comment.created_utc > cutoff
    -		).all()
    -
    -		threshold = COMMENT_SPAM_COUNT_THRESHOLD
    -		if v.age >= (60 * 60 * 24 * 7):
    -			threshold *= 3
    -		elif v.age >= (60 * 60 * 24):
    -			threshold *= 2
    -
    -		if len(similar_comments) > threshold:
    -			text = "Your account has been banned for **1 day** for the following reason:\n\n> Too much spam!"
    -			send_repeatable_notification(v.id, text)
    -
    -			v.ban(reason="Spamming.",
    -					days=1)
    -
    -			for comment in similar_comments:
    -				comment.is_banned = True
    -				comment.ban_reason = "AutoJanny"
    -				g.db.add(comment)
    -				ma=ModAction(
    -					user_id=AUTOJANNY_ID,
    -					target_comment_id=comment.id,
    -					kind="ban_comment",
    -					_note="spam"
    -					)
    -				g.db.add(ma)
    -
    -			g.db.commit()
    -			return {"error": "Too much spam!"}, 403
    +	execute_antispam_comment_check(body, v)
     
     	if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400)
     
    @@ -319,11 +241,7 @@ def comment(v):
     	g.db.add(c)
     	g.db.flush()
     
    -	if blackjack and any(i in c.body.lower() for i in blackjack.split()):
    -		v.shadowbanned = 'AutoJanny'
    -		if not v.is_banned: v.ban_reason = 'Blackjack'
    -		notif = Notification(comment_id=c.id, user_id=CARP_ID)
    -		g.db.add(notif)
    +	execute_blackjack(v, c, c.body, "comment")
     
     	if c.level == 1: c.top_comment_id = c.id
     	else: c.top_comment_id = parent.top_comment_id
    @@ -348,19 +266,13 @@ def comment(v):
     		execute_basedbot(c, level, body, parent_submission, parent_post, v)
     
     	if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and parent_post.sub != 'chudrama':
    -
     		c.is_banned = True
     		c.ban_reason = "AutoJanny"
    -
     		g.db.add(c)
     
    -
     		body = AGENDAPOSTER_MSG.format(username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE)
    -
     		body_jannied_html = AGENDAPOSTER_MSG_HTML.format(id=v.id, username=v.username, type='comment', AGENDAPOSTER_PHRASE=AGENDAPOSTER_PHRASE)
     
    -
    -
     		c_jannied = Comment(author_id=AUTOJANNY_ID,
     			parent_submission=parent_submission,
     			distinguish_level=6,
    @@ -444,7 +356,7 @@ def comment(v):
     		g.db.add(c)
     
     	if v.marseyawarded and parent_post.id not in ADMIGGERS and marseyaward_body_regex.search(body_html):
    -		return {"error":"You can only type marseys!"}, 403
    +		abort(403, "You can only type marseys!")
     
     	check_for_treasure(body, c)
     
    @@ -458,7 +370,7 @@ def comment(v):
     
     	g.db.flush()
     
    -	if request.headers.get("Authorization"): return c.json
    +	if v.client: return c.json
     	return {"comment": render_template("comments.html", v=v, comments=[c])}
     
     
    @@ -471,7 +383,7 @@ def edit_comment(cid, v):
     	c = get_comment(cid, v=v)
     
     	if time.time() - c.created_utc > 7*24*60*60 and not (c.post and c.post.private):
    -		return {"error":"You can't edit comments older than 1 week!"}, 403
    +		abort(403, "You can't edit comments older than 1 week!")
     
     	if c.author_id != v.id: abort(403)
     	if not c.post: abort(403)
    @@ -479,13 +391,13 @@ def edit_comment(cid, v):
     	body = sanitize_raw_body(request.values.get("body", ""), False)
     
     	if len(body) < 1 and not (request.files.get("file") and request.headers.get("cf-ipcountry") != "T1"):
    -		return {"error":"You have to actually type something!"}, 400
    +		abort(400, "You have to actually type something!")
     
     	if body != c.body or request.files.get("file") and request.headers.get("cf-ipcountry") != "T1":
     		if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
    -			return {"error":"You have to type more than 280 characters!"}, 403
    +			abort(403, "You have to type more than 280 characters!")
     		elif v.bird and len(body) > 140:
    -			return {"error":"You have to type less than 140 characters!"}, 403
    +			abort(403, "You have to type less than 140 characters!")
     
     		for i in poll_regex.finditer(body):
     			body = body.replace(i.group(0), "")
    @@ -505,39 +417,7 @@ def edit_comment(cid, v):
     			)
     			g.db.add(option)
     
    -		if len(body) > 50:
    -			now = int(time.time())
    -			cutoff = now - 60 * 60 * 24
    -
    -			similar_comments = g.db.query(Comment
    -			).filter(
    -				Comment.author_id == v.id,
    -				Comment.body.op('<->')(body) < SPAM_SIMILARITY_THRESHOLD,
    -				Comment.created_utc > cutoff
    -			).all()
    -
    -			threshold = SPAM_SIMILAR_COUNT_THRESHOLD
    -			if v.age >= (60 * 60 * 24 * 30):
    -				threshold *= 4
    -			elif v.age >= (60 * 60 * 24 * 7):
    -				threshold *= 3
    -			elif v.age >= (60 * 60 * 24):
    -				threshold *= 2
    -
    -			if len(similar_comments) > threshold:
    -				text = "Your account has been banned for **1 day** for the following reason:\n\n> Too much spam!"
    -				send_repeatable_notification(v.id, text)
    -
    -				v.ban(reason="Spamming.",
    -						days=1)
    -
    -				for comment in similar_comments:
    -					comment.is_banned = True
    -					comment.ban_reason = "AutoJanny"
    -					g.db.add(comment)
    -
    -				g.db.commit()
    -				return {"error": "Too much spam!"}, 403
    +		execute_antispam_comment_check(body, v)
     
     		body += process_files()
     		body = body.strip()[:COMMENT_BODY_LENGTH_LIMIT] # process_files potentially adds characters to the post
    @@ -555,22 +435,15 @@ def edit_comment(cid, v):
     		if len(body_html) > COMMENT_BODY_HTML_LENGTH_LIMIT: abort(400)
     
     		if v.marseyawarded and marseyaward_body_regex.search(body_html):
    -			return {"error":"You can only type marseys!"}, 403
    +			abort(403, "You can only type marseys!")
     
     		c.body = body
     		c.body_html = body_html
     
    -		if blackjack and any(i in c.body.lower() for i in blackjack.split()):
    -			v.shadowbanned = 'AutoJanny'
    -			if not v.is_banned: v.ban_reason = 'Blackjack'
    -			g.db.add(v)
    -			notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=CARP_ID).one_or_none()
    -			if not notif:
    -				notif = Notification(comment_id=c.id, user_id=CARP_ID)
    -				g.db.add(notif)
    +		execute_blackjack(v, c, c.body, "comment")
     
     		if v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in c.body.lower() and c.post.sub != 'chudrama':
    -			return {"error": f'You have to include "{AGENDAPOSTER_PHRASE}" in your comment!'}, 403
    +			abort(403, f'You have to include "{AGENDAPOSTER_PHRASE}" in your comment!')
     
     
     		if int(time.time()) - c.created_utc > 60 * 3: c.edited_utc = int(time.time())
    @@ -647,9 +520,9 @@ def undelete_comment(cid, v):
     
     @app.post("/pin_comment/")
     @auth_required
    +@feature_required('PINS')
     def pin_comment(cid, v):
    -	if not FEATURES['PINS']:
    -		abort(403)
    +	
     	comment = get_comment(cid, v=v)
     	
     	if not comment.stickied:
    @@ -678,7 +551,7 @@ def unpin_comment(cid, v):
     		if v.id != comment.post.author_id: abort(403)
     
     		if not comment.stickied.endswith(" (OP)"): 
    -			return {"error": "You can only unpin comments you have pinned!"}, 400
    +			abort(403, "You can only unpin comments you have pinned!")
     
     		comment.stickied = None
     		g.db.add(comment)
    @@ -747,7 +620,6 @@ def diff_words(answer, guess):
     @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
     @auth_required
     def handle_wordle_action(cid, v):
    -
     	comment = get_comment(cid)
     
     	if v.id != comment.author_id:
    @@ -759,8 +631,7 @@ def handle_wordle_action(cid, v):
     	try: guess = request.values.get("thing").strip().lower()
     	except: abort(400)
     
    -	if len(guess) != 5:
    -		return {"error": "Not a valid guess!"}, 400
    +	if len(guess) != 5: abort(400, "Not a valid guess!")
     
     	if status == "active":
     		guesses += "".join(cg + WORDLE_COLOR_MAPPINGS[diff] for cg, diff in zip(guess, diff_words(answer, guess)))
    diff --git a/files/routes/discord.py b/files/routes/discord.py
    deleted file mode 100644
    index 2d2f31cc7..000000000
    --- a/files/routes/discord.py
    +++ /dev/null
    @@ -1,132 +0,0 @@
    -from files.helpers.wrappers import *
    -from files.helpers.security import *
    -from files.helpers.discord import add_role
    -from files.__main__ import app
    -import requests
    -
    -
    -@app.get("/discord")
    -@is_not_permabanned
    -def join_discord(v):
    -	
    -	if v.shadowbanned: return {"error": "Internal server error"}, 400
    -	
    -	now=int(time.time())
    -
    -	state=generate_hash(f"{now}+{v.id}+discord")
    -
    -	state=f"{now}.{state}"
    -
    -	return redirect(f"https://discord.com/api/oauth2/authorize?client_id={DISCORD_CLIENT_ID}&redirect_uri=https%3A%2F%2F{SITE}%2Fdiscord_redirect&response_type=code&scope=identify%20guilds.join&state={state}")
    -
    -
    -@app.get("/discord_redirect")
    -@is_not_permabanned
    -def discord_redirect(v):
    -	if v.shadowbanned: abort(400)
    -	now = int(time.time())
    -	state = request.values.get('state')
    -	if not state or not '.' in state: abort(400)
    -	state = state.split('.')
    -	timestamp= state[0]
    -	state= state[1]
    -
    -	try:
    -		if int(timestamp) < now-600:
    -			abort(400)
    -	except:
    -		abort(400)
    -
    -	if not validate_hash(f"{timestamp}+{v.id}+discord", state):
    -		abort(400)
    -
    -	code = request.values.get("code","")
    -	if not code:
    -		abort(400)
    -
    -	data={
    -		"client_id": DISCORD_CLIENT_ID,
    -		'client_secret': DISCORD_CLIENT_SECRET,
    -		'grant_type': 'authorization_code',
    -		'code': code,
    -		'redirect_uri': f"https://{SITE}/discord_redirect",
    -		'scope': 'identify guilds.join'
    -	}
    -	headers={
    -		'Content-Type': 'application/x-www-form-urlencoded'
    -	}
    -	url="https://discord.com/api/oauth2/token"
    -
    -	x=requests.post(url, headers=headers, data=data, timeout=5)
    -
    -	x=x.json()
    -
    -
    -	token=x["access_token"]
    -
    -
    -	url="https://discord.com/api/users/@me"
    -	headers={
    -		'Authorization': f"Bearer {token}"
    -	}
    -	x=requests.get(url, headers=headers, timeout=5)
    -
    -	x=x.json()
    -
    -
    -
    -	headers={
    -		'Authorization': f"Bot {DISCORD_BOT_TOKEN}",
    -		'Content-Type': "application/json"
    -	}
    -
    -	if v.discord_id and v.discord_id != x['id']:
    -		url=f"https://discord.com/api/guilds/{DISCORD_SERVER_ID}/members/{v.discord_id}"
    -		requests.delete(url, headers=headers, timeout=5)
    -
    -	if g.db.query(User).filter(User.id!=v.id, User.discord_id==x["id"]).one_or_none():
    -		return render_template("message.html", title="Discord account already linked.", error="This Discord account is already in use by another user.", v=v)
    -
    -	v.discord_id=x["id"]
    -	g.db.add(v)
    -
    -	url=f"https://discord.com/api/guilds/{DISCORD_SERVER_ID}/members/{x['id']}"
    -
    -	name=v.username
    -
    -	data={
    -		"access_token":token,
    -		"nick":name,
    -	}
    -
    -	x=requests.put(url, headers=headers, json=data, timeout=5)
    -
    -	if x.status_code in {201, 204}:
    -		time.sleep(0.1)
    -		add_role(v, "linked")
    -
    -		if v.patron:
    -			time.sleep(0.1)
    -			add_role(v, str(v.patron))
    -
    -		if SITE == 'rdrama.net' and v.id == AEVANN_ID:
    -			time.sleep(0.1)
    -			add_role(v, "admin")
    -
    -			time.sleep(0.1)
    -			requests.put("https://discord.com/api/guilds/913091440035389520/members/788152118669606932", headers=headers, json={"access_token":token,"roles":[915260962540511292]}, timeout=5)
    -	else:
    -		return x.json()
    -
    -
    -	if x.status_code==204:
    -
    -		url=f"https://discord.com/api/guilds/{DISCORD_SERVER_ID}/members/{v.discord_id}"
    -		data={
    -			"nick": name
    -		}
    -
    -		requests.patch(url, headers=headers, json=data, timeout=5)
    -
    -
    -	return redirect(f"https://discord.com/channels/{DISCORD_SERVER_ID}/{DISCORD_WELCOME_CHANNEL}")
    diff --git a/files/routes/errors.py b/files/routes/errors.py
    index 484b89871..7a91b2bee 100644
    --- a/files/routes/errors.py
    +++ b/files/routes/errors.py
    @@ -4,17 +4,38 @@ from urllib.parse import quote, urlencode
     import time
     from files.__main__ import app, limiter
     
    -
    +# If you're adding an error, go here:
    +# https://github.com/pallets/werkzeug/blob/main/src/werkzeug/exceptions.py
    +# and copy the description for the error code you're adding and add it to
    +# the constant WERKZEUG_ERROR_DESCRIPTIONS so that the default error message
    +# doesn't show up on the message. Be exact or it won't work properly.
     
     @app.errorhandler(400)
    -def error_400(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "400 Bad Request"}, 400
    -	else: return render_template('errors/400.html', err=True), 400
    +@app.errorhandler(403)
    +@app.errorhandler(404)
    +@app.errorhandler(405)
    +@app.errorhandler(406)
    +@app.errorhandler(409)
    +@app.errorhandler(413)
    +@app.errorhandler(415)
    +@app.errorhandler(418)
    +@app.errorhandler(429)
    +def error(e):
    +	title = ERROR_TITLES.get(e.code, str(e.code))
    +	msg = ERROR_MSGS.get(e.code, str(e.code))
    +	details = e.description
    +
    +	if WERKZEUG_ERROR_DESCRIPTIONS.get(e.code, None) == details:
    +		details = None
    +	# for here and 401, not using g.is_api_or_xhr is intentional since API users won't get invalid token errors otherwise
    +	if request.headers.get("Authorization") or request.headers.get("xhr"):
    +		return {"error": title, "code": e.code, "description": msg, "details": details}, e.code
    +	img = ERROR_MARSEYS.get(e.code, 'marseyl')
    +	return render_template('errors/error.html', err=True, title=title, msg=msg, details=details, img=img), e.code
     
     @app.errorhandler(401)
     def error_401(e):
    -
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "401 Not Authorized"}, 401
    +	if request.headers.get("Authorization") or request.headers.get("xhr"): return error(e)
     	else:
     		path = request.path
     		qs = urlencode(dict(request.values))
    @@ -23,75 +44,10 @@ def error_401(e):
     		if session.get("history"): return redirect(f"/login?redirect={argval}")
     		else: return redirect(f"/signup?redirect={argval}")
     
    -@app.errorhandler(406)
    -def error_406(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"):
    -		return {"error": "Too many pings: max limit is 5 for comments and 50 for posts"}, 406
    -	else: return render_template('errors/406.html', err=True), 406
    -
    -@app.errorhandler(403)
    -def error_403(e):
    -
    -	description = e.description
    -	if description == "You don't have the permission to access the requested resource. It is either read-protected or not readable by the server.": description = ''
    -	
    -	if request.headers.get("Authorization") or request.headers.get("xhr"):
    -		if not description: description = "403 Forbidden"
    -		return {"error": description}, 403
    -	else:
    -		if not description: description = "YOU AREN'T WELCOME HERE GO AWAY"
    -		return render_template('errors/403.html', description=description, err=True), 403
    -
    -
    -@app.errorhandler(404)
    -def error_404(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "404 Not Found"}, 404
    -	else: return render_template('errors/404.html', err=True), 404
    -
    -@app.errorhandler(405)
    -def error_405(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "405 Method Not Allowed"}, 405
    -	else: return render_template('errors/405.html', err=True), 405
    -
    -@app.errorhandler(413)
    -def error_413(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"):
    -		return {"error": "Max image/audio size is 8 MB (16 MB for paypigs)"}, 413
    -	else: return render_template('errors/413.html', err=True), 413
    -
    -@app.errorhandler(414)
    -def error_414(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"):
    -		return {"error": "Max video size is 32 MB (64 MB for paypigs)"}, 414
    -	else: return render_template('errors/414.html', err=True), 414
    -
    -@app.errorhandler(415)
    -def error_415(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "Please upload only Image, Video, or Audio files!"}, 415
    -	else: return render_template('errors/415.html', err=True), 415
    -
    -@app.errorhandler(417)
    -def error_417(e):
    -	return {"error": "Image already exists!"}, 417
    -
    -@app.errorhandler(418)
    -def error_418(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"):
    -		return {"error": "WEBM videos are not allowed, please convert your video to MP4 and re-upload it!"}, 418
    -	else: return render_template('errors/418.html', err=True), 418
    -
    -@app.errorhandler(429)
    -def error_429(e):
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "429 Too Many Requests"}, 429
    -	else: return render_template('errors/429.html', err=True), 429
    -
    -
     @app.errorhandler(500)
     def error_500(e):
     	g.db.rollback()
    -
    -	if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": "500 Internal Server Error"}, 500
    -	else: return render_template('errors/500.html', err=True), 500
    +	return error(e)
     
     
     @app.post("/allow_nsfw")
    diff --git a/files/routes/front.py b/files/routes/front.py
    index fa1263b17..5ef45fe03 100644
    --- a/files/routes/front.py
    +++ b/files/routes/front.py
    @@ -1,6 +1,5 @@
     from files.helpers.wrappers import *
     from files.helpers.get import *
    -from files.helpers.discord import *
     from files.helpers.const import *
     from files.helpers.sorting_and_time import *
     from files.__main__ import app, cache, limiter
    @@ -18,7 +17,31 @@ from files.helpers.awards import award_timers
     @limiter.limit("3/second;30/minute;5000/hour;10000/day")
     @auth_desired_with_logingate
     def front_all(v, sub=None, subdomain=None):
    -
    +	#### WPD TEMP #### special front logic
    +	from files.helpers.security import generate_hash, validate_hash
    +	from datetime import datetime
    +	now = datetime.utcnow()
    +	if SITE == 'watchpeopledie.co':
    +		if v and not v.admin_level and not v.id <= 9: # security: don't auto login admins or bots
    +			hash = generate_hash(f'{v.id}+{now.year}+{now.month}+{now.day}+{now.hour}+WPDusermigration')
    +			return redirect(f'https://watchpeopledie.tv/logged_out?user={v.id}&code={hash}', 301)
    +		else:
    +			return redirect('https://watchpeopledie.tv/logged_out', 301)
    +	elif SITE == 'watchpeopledie.tv' and not v: # security: don't try to login people into accounts more than once
    +		req_user = request.values.get('user')
    +		req_code = request.values.get('code')
    +		if req_user and req_code:
    +			from files.routes.login import on_login
    +			user = get_account(req_user, graceful=True)
    +			if user:
    +				if user.admin_level or user.id <= 9:
    +					abort(401)
    +				else:
    +					if validate_hash(req_code, f'{user.id}+{now.year}+{now.month}+{now.day}+{now.hour}+WPDusermigration'):
    +						on_login(user)
    +						return redirect('/')
    +			return redirect('/logged_out')
    +	#### WPD TEMP #### end special front logic
     	if sub:
     		sub = sub.strip().lower()
     		if sub == 'chudrama' and not (v and v.can_see_chudrama): abort(403)
    @@ -72,7 +95,7 @@ def front_all(v, sub=None, subdomain=None):
     		if v.hidevotedon: posts = [x for x in posts if not hasattr(x, 'voted') or not x.voted]
     		award_timers(v)
     
    -	if request.headers.get("Authorization"): return {"data": [x.json for x in posts], "next_exists": next_exists}
    +	if v and v.client: return {"data": [x.json for x in posts], "next_exists": next_exists}
     	return render_template("home.html", v=v, listing=posts, next_exists=next_exists, sort=sort, t=t, page=page, ccmode=ccmode, sub=sub, home=True, pins=pins)
     
     
    @@ -112,36 +135,13 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, ccmode="false"
     			word = word.replace('\\', '').replace('_', '\_').replace('%', '\%').strip()
     			posts=posts.filter(not_(Submission.title.ilike(f'%{word}%')))
     
    -	if not (v and v.shadowbanned):
    -		posts = posts.join(Submission.author).filter(User.shadowbanned == None)
    -
    -	if sort == 'hot':
    -		ti = int(time.time()) + 3600
    -		if SITE_NAME == 'rDrama':
    -			posts = posts.order_by(-1000000*(Submission.realupvotes + 1 + Submission.comment_count/5)/(func.power(((ti - Submission.created_utc)/1000), 1.23)), Submission.created_utc.desc())
    -		else:
    -			posts = posts.order_by(-1000000*(Submission.upvotes - Submission.downvotes + 1)/(func.power(((ti - Submission.created_utc)/1000), 1.23)), Submission.created_utc.desc())
    -	elif sort == "bump":
    -		posts = posts.filter(Submission.comment_count > 1).order_by(Submission.bump_utc.desc(), Submission.created_utc.desc())
    -	else:
    -		posts = sort_posts(sort, posts)
    +	posts = sort_objects(sort, posts, Submission,
    +		include_shadowbanned=(v and v.can_see_shadowbanned))
     
     	if v: size = v.frontsize or 0
    -	else: size = 25
    +	else: size = PAGE_SIZE
     
    -	if False:
    -		posts = posts.offset(size * (page - 1)).limit(100).all()
    -		social_found = False
    -		music_found = False
    -		for post in posts:
    -			if post.sub == 'social':
    -				if social_found: posts.remove(post)
    -				else: social_found = True
    -			elif post.sub == 'music':
    -				if music_found: posts.remove(post)
    -				else: music_found = True
    -	else:
    -		posts = posts.offset(size * (page - 1)).limit(size+1).all()
    +	posts = posts.offset(size * (page - 1)).limit(size+1).all()
     
     	next_exists = (len(posts) > size)
     
    @@ -163,7 +163,8 @@ def frontlist(v=None, sort="hot", page=1, t="all", ids_only=True, ccmode="false"
     
     
     		if v: pins = pins.filter(Submission.author_id.notin_(v.userblocks))
    -
    +		if SITE_NAME == 'rDrama':
    +			pins = pins.order_by(Submission.author_id != LAWLZ_ID)
     		pins = pins.order_by(Submission.created_utc.desc()).all()
     
     		posts = pins + posts
    @@ -200,8 +201,6 @@ def random_user(v):
     @app.get("/comments")
     @auth_required
     def all_comments(v):
    -
    -
     	try: page = max(int(request.values.get("page", 1)), 1)
     	except: page = 1
     
    @@ -213,7 +212,6 @@ def all_comments(v):
     
     	try: lt=int(request.values.get("before", 0))
     	except: lt=0
    -
     	idlist = comment_idlist(v=v,
     							page=page,
     							sort=sort,
    @@ -224,31 +222,29 @@ def all_comments(v):
     							)
     
     	comments = get_comments(idlist, v=v)
    +	next_exists = len(idlist) > PAGE_SIZE
    +	idlist = idlist[:PAGE_SIZE]
     
    -	next_exists = len(idlist) > 25
    -
    -	idlist = idlist[:25]
    -
    -	if request.headers.get("Authorization"): return {"data": [x.json for x in comments]}
    +	if v.client: return {"data": [x.json for x in comments]}
     	return render_template("home_comments.html", v=v, sort=sort, t=t, page=page, comments=comments, standalone=True, next_exists=next_exists)
     
     
    -
     @cache.memoize(timeout=86400)
    -def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all", gt=0, lt=0, site=None):
    -
    -	comments = g.db.query(Comment.id).filter(Comment.parent_submission != None, Comment.author_id.notin_(v.userblocks))
    +def comment_idlist(v=None, page=1, sort="new", t="all", gt=0, lt=0, site=None):
    +	comments = g.db.query(Comment.id) \
    +		.join(Comment.post) \
    +		.filter(Comment.parent_submission != None)
     
     	if v.admin_level < PERMS['POST_COMMENT_MODERATION']:
    -		private = [x[0] for x in g.db.query(Submission.id).filter(Submission.private == True).all()]
    -
    -		comments = comments.filter(Comment.is_banned==False, Comment.deleted_utc == 0, Comment.parent_submission.notin_(private))
    -
    +		comments = comments.filter(
    +			Comment.is_banned == False,
    +			Comment.deleted_utc == 0,
    +			Submission.private == False,
    +			Comment.author_id.notin_(v.userblocks),
    +		)
     
     	if not v.paid_dues:
    -		club = [x[0] for x in g.db.query(Submission.id).filter(Submission.club == True).all()]
    -		comments = comments.filter(Comment.parent_submission.notin_(club))
    -
    +		comments = comments.filter(Submission.club == False)
     
     	if gt: comments = comments.filter(Comment.created_utc > gt)
     	if lt: comments = comments.filter(Comment.created_utc < lt)
    @@ -256,7 +252,8 @@ def comment_idlist(page=1, v=None, nsfw=False, sort="new", t="all", gt=0, lt=0,
     	if not gt and not lt:
     		comments = apply_time_filter(t, comments, Comment)
     
    -	comments = sort_comments(sort, comments)
    +	comments = sort_objects(sort, comments, Comment,
    +		include_shadowbanned=(v and v.can_see_shadowbanned))
     
    -	comments = comments.offset(25 * (page - 1)).limit(26).all()
    +	comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()
     	return [x[0] for x in comments]
    diff --git a/files/routes/giphy.py b/files/routes/giphy.py
    index 11142c6a1..5adcda9e7 100644
    --- a/files/routes/giphy.py
    +++ b/files/routes/giphy.py
    @@ -12,7 +12,11 @@ from files.__main__ import app
     def giphy(v=None, path=None):
     
     	searchTerm = request.values.get("searchTerm", "").strip()
    -	limit = int(request.values.get("limit", 48))
    +	limit = 48
    +	try:
    +		limit = int(request.values.get("limit", 48))
    +	except:
    +		pass
     	if searchTerm and limit:
     		url = f"https://api.giphy.com/v1/gifs/search?q={searchTerm}&api_key={GIPHY_KEY}&limit={limit}"
     	elif searchTerm and not limit:
    diff --git a/files/routes/hats.py b/files/routes/hats.py
    index 024bcc3db..2025f3f7e 100644
    --- a/files/routes/hats.py
    +++ b/files/routes/hats.py
    @@ -1,4 +1,4 @@
    -from files.__main__ import app
    +from files.__main__ import app, limiter
     from files.classes.hats import *
     from files.helpers.alerts import *
     from files.helpers.wrappers import *
    @@ -8,9 +8,8 @@ from flask import g
     
     @app.get("/hats")
     @auth_required
    +@feature_required('HATS')
     def hats(v):
    -	if not FEATURES['HATS']: abort(404)
    -
     	owned_hat_ids = [x.hat_id for x in v.owned_hats]
     
     	if request.values.get("sort") == 'author_asc':
    @@ -33,30 +32,28 @@ def hats(v):
     	return render_template("hats.html", owned_hat_ids=owned_hat_ids, hats=hats, v=v, sales=sales, num_of_hats=num_of_hats)
     
     @app.post("/buy_hat/")
    +@limiter.limit('100/minute;1000/3 days')
     @auth_required
    +@feature_required('HATS')
     def buy_hat(v, hat_id):
    -	if not FEATURES['HATS']: abort(404)
    -
     	try: hat_id = int(hat_id)
    -	except: return {"error": "Hat not found!"}, 400
    +	except: abort(404, "Hat not found!")
     
     	hat = g.db.query(HatDef).filter_by(submitter_id=None, id=hat_id).one_or_none()
    -	if not hat: return {"error": "Hat not found!"}, 400
    +	if not hat: abort(404, "Hat not found!")
     
     	existing = g.db.query(Hat).filter_by(user_id=v.id, hat_id=hat.id).one_or_none()
    -	if existing: return {"error": "You already own this hat!"}, 400
    +	if existing: abort(400, "You already own this hat!")
     
     	if request.values.get("mb"):
     		charged = v.charge_account('procoins', hat.price)
    -		if not charged:
    -			return {"error": "Not enough marseybux."}, 400
    +		if not charged: abort(400, "Not enough marseybux.")
     
     		hat.author.procoins += hat.price * 0.1
     		currency = "marseybux"
     	else:
     		charged = v.charge_account('coins', hat.price)
    -		if not charged:
    -			return {"error": "Not enough coins."}, 400
    +		if not charged: abort(400, "Not enough coins.")
     
     		v.coins_spent_on_hats += hat.price
     		hat.author.coins += hat.price * 0.1
    @@ -85,14 +82,13 @@ def buy_hat(v, hat_id):
     
     @app.post("/equip_hat/")
     @auth_required
    +@feature_required('HATS')
     def equip_hat(v, hat_id):
    -	if not FEATURES['HATS']: abort(404)
    -
     	try: hat_id = int(hat_id)
    -	except: return {"error": "Hat not found!"}, 400
    +	except: abort(404, "Hat not found!")
     
     	hat = g.db.query(Hat).filter_by(hat_id=hat_id, user_id=v.id).one_or_none()
    -	if not hat: return {"error": "You don't own this hat!"}, 400
    +	if not hat: abort(403, "You don't own this hat!")
     
     	hat.equipped = True
     	g.db.add(hat)
    @@ -101,14 +97,13 @@ def equip_hat(v, hat_id):
     
     @app.post("/unequip_hat/")
     @auth_required
    +@feature_required('HATS')
     def unequip_hat(v, hat_id):
    -	if not FEATURES['HATS']: abort(404)
    -
     	try: hat_id = int(hat_id)
    -	except: return {"error": "Hat not found!"}, 400
    +	except: abort(404, "Hat not found!")
     
     	hat = g.db.query(Hat).filter_by(hat_id=hat_id, user_id=v.id).one_or_none()
    -	if not hat: return {"error": "You don't own this hat!"}, 400
    +	if not hat: abort(403, "You don't own this hat!")
     
     	hat.equipped = False
     	g.db.add(hat)
    @@ -118,17 +113,16 @@ def unequip_hat(v, hat_id):
     @app.get("/hat_owners/")
     @auth_required
     def hat_owners(v, hat_id):
    -
     	try: hat_id = int(hat_id)
     	except: abort(400)
     
     	try: page = int(request.values.get("page", 1))
     	except: page = 1
     
    -	users = [x[1] for x in g.db.query(Hat, User).join(Hat.owners).filter(Hat.hat_id == hat_id).offset(25 * (page - 1)).limit(26).all()]
    +	users = [x[1] for x in g.db.query(Hat, User).join(Hat.owners).filter(Hat.hat_id == hat_id).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all()]
     
    -	next_exists = (len(users) > 25)
    -	users = users[:25]
    +	next_exists = (len(users) > PAGE_SIZE)
    +	users = users[:PAGE_SIZE]
     
     	return render_template("user_cards.html",
     						v=v,
    diff --git a/files/routes/login.py b/files/routes/login.py
    index 3d6f9da0e..a4aa49ebf 100644
    --- a/files/routes/login.py
    +++ b/files/routes/login.py
    @@ -1,6 +1,6 @@
     from urllib.parse import urlencode
     from files.mail import *
    -from files.__main__ import app, limiter
    +from files.__main__ import app, get_CF, limiter
     from files.helpers.const import *
     from files.helpers.regex import *
     from files.helpers.actions import *
    @@ -21,7 +21,7 @@ def login_get(v):
     	return render_template("login.html", failed=False, redirect=redir)
     
     
    -def check_for_alts(current):
    +def check_for_alts(current:User):
     	current_id = current.id
     	if current_id in (1691,6790,7069,36152):
     		session["history"] = []
    @@ -29,8 +29,15 @@ def check_for_alts(current):
     	ids = [x[0] for x in g.db.query(User.id).all()]
     	past_accs = set(session.get("history", []))
     
    +	def add_alt(user1:int, user2:int):
    +		li = [user1, user2]
    +		existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none()
    +		if not existing:
    +			new_alt = Alt(user1=user1, user2=user2)
    +			g.db.add(new_alt)
    +			g.db.flush()
    +
     	for past_id in list(past_accs):
    -		
     		if past_id not in ids:
     			past_accs.remove(past_id)
     			continue
    @@ -39,46 +46,17 @@ def check_for_alts(current):
     		if past_id == current_id: continue
     
     		li = [past_id, current_id]
    -		existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none()
    -
    -		if not existing:
    -			new_alt = Alt(user1=past_id, user2=current_id)
    -			g.db.add(new_alt)
    -			g.db.flush()
    -			
    -		otheralts = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).all()
    -		for a in otheralts:
    +		add_alt(past_id, current_id)
    +		other_alts = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).all()
    +		for a in other_alts:
     			if a.user1 != past_id:
    -				li = [a.user1, past_id]
    -				existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none()
    -				if not existing:
    -					new_alt = Alt(user1=a.user1, user2=past_id)
    -					g.db.add(new_alt)
    -					g.db.flush()
    -
    +				add_alt(a.user1, past_id)
     			if a.user1 != current_id:
    -				li = [a.user1, current_id]
    -				existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none()
    -				if not existing:
    -					new_alt = Alt(user1=a.user1, user2=current_id)
    -					g.db.add(new_alt)
    -					g.db.flush()
    -
    +				add_alt(a.user1, current_id)
     			if a.user2 != past_id:
    -				li = [a.user2, past_id]
    -				existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none()
    -				if not existing:
    -					new_alt = Alt(user1=a.user2, user2=past_id)
    -					g.db.add(new_alt)
    -					g.db.flush()
    -
    +				add_alt(a.user2, past_id)
     			if a.user2 != current_id:
    -				li = [a.user2, current_id]
    -				existing = g.db.query(Alt).filter(Alt.user1.in_(li), Alt.user2.in_(li)).one_or_none()
    -				if not existing:
    -					new_alt = Alt(user1=a.user2, user2=current_id)
    -					g.db.add(new_alt)
    -					g.db.flush()
    +				add_alt(a.user2, current_id)
     	
     	past_accs.add(current_id)
     	session["history"] = list(past_accs)
    @@ -94,10 +72,19 @@ def check_for_alts(current):
     			g.db.add(u)
     
     
    +def login_deduct_when(resp):
    +	if not g:
    +		return False
    +	elif not hasattr(g, 'login_failed'):
    +		return False
    +	return g.login_failed
    +
     @app.post("/login")
    -@limiter.limit("1/second;6/minute;200/hour;1000/day")
    +@limiter.limit("6/minute;10/day",
    +	deduct_when=login_deduct_when)
     def login_post():
     	template = ''
    +	g.login_failed = True
     
     	username = request.values.get("username")
     
    @@ -118,14 +105,15 @@ def login_post():
     
     
     	if request.values.get("password"):
    -
     		if not account.verifyPass(request.values.get("password")):
    +			log_failed_admin_login_attempt(account, "password")
     			time.sleep(random.uniform(0, 2))
     			return render_template("login.html", failed=True)
     
     		if account.mfa_secret:
     			now = int(time.time())
     			hash = generate_hash(f"{account.id}+{now}+2fachallenge")
    +			g.login_failed = False
     			return render_template("login_2fa.html",
     								v=account,
     								time=now,
    @@ -147,6 +135,7 @@ def login_post():
     
     		if not account.validate_2fa(request.values.get("2fa_token", "").strip()):
     			hash = generate_hash(f"{account.id}+{now}+2fachallenge")
    +			log_failed_admin_login_attempt(account, "2FA token")
     			return render_template("login_2fa.html",
     								v=account,
     								time=now,
    @@ -156,6 +145,7 @@ def login_post():
     	else:
     		abort(400)
     
    +	g.login_failed = False
     	on_login(account)
     
     	redir = request.values.get("redirect")
    @@ -164,17 +154,29 @@ def login_post():
     		if is_site_url(redir): return redirect(redir)
     	return redirect('/')
     
    +def log_failed_admin_login_attempt(account:User, type:str):
    +		if not account or account.admin_level < PERMS['SITE_WARN_ON_INVALID_AUTH']: return
    +		ip = get_CF()
    +		print(f"Admin user from {ip} failed to login to account @{account.user_name} (invalid {type})!")
    +		try:
    +			with open(f"/admin_failed_logins", "a+", encoding="utf-8") as f:
    +				t = str(time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time())))
    +				f.write(f"{t}, {ip}, {account.username}, {type}\n")
    +		except:
    +			pass
    +
     def on_login(account, redir=None):
     	session["lo_user"] = account.id
     	session["login_nonce"] = account.login_nonce
     	if account.id == AEVANN_ID: session["verified"] = time.time()
     	check_for_alts(account)
     
    +
     @app.get("/me")
     @app.get("/@me")
     @auth_required
     def me(v):
    -	if request.headers.get("Authorization"): return v.json
    +	if v.client: return v.json
     	else: return redirect(v.url)
     
     
    @@ -219,7 +221,7 @@ def sign_up_get(v):
     
     	formkey_hashstr = str(now) + token + g.agent
     
    -	formkey = hmac.new(key=bytes(MASTER_KEY, "utf-16"),
    +	formkey = hmac.new(key=bytes(SECRET_KEY, "utf-16"),
     					msg=bytes(formkey_hashstr, "utf-16"),
     					digestmod='md5'
     					).hexdigest()
    @@ -258,7 +260,7 @@ def sign_up_post(v):
     
     	correct_formkey_hashstr = form_timestamp + submitted_token + g.agent
     
    -	correct_formkey = hmac.new(key=bytes(MASTER_KEY, "utf-16"),
    +	correct_formkey = hmac.new(key=bytes(SECRET_KEY, "utf-16"),
     								msg=bytes(correct_formkey_hashstr, "utf-16"),
     								digestmod='md5'
     							).hexdigest()
    @@ -304,9 +306,6 @@ def sign_up_post(v):
     	else: email = None
     
     	existing_account = get_user(username, graceful=True)
    -	if existing_account and existing_account.reserved:
    -		return redirect(existing_account.url)
    -
     	if existing_account:
     		return signup_error("An account with that username already exists.")
     
    @@ -327,7 +326,11 @@ def sign_up_post(v):
     
     	session.pop("signup_token")
     
    -	ref_id = int(request.values.get("referred_by", 0))
    +	ref_id = 0
    +	try:
    +		ref_id = int(request.values.get("referred_by", 0))
    +	except:
    +		pass
     
     	users_count = g.db.query(User).count()
     	if users_count == 4:
    @@ -374,22 +377,15 @@ def sign_up_post(v):
     
     	session["lo_user"] = new_user.id
     	
    -	if SITE == 'rdrama.net':
    +	if SIGNUP_FOLLOW_ID:
    +		signup_autofollow = get_account(SIGNUP_FOLLOW_ID)
    +		new_follow = Follow(user_id=new_user.id, target_id=signup_autofollow.id)
    +		g.db.add(new_follow)
    +		signup_autofollow.stored_subscriber_count += 1
    +		g.db.add(signup_autofollow)
    +		send_notification(signup_autofollow.id, f"A new user - @{new_user.username} - has followed you automatically!")
    +	elif CARP_ID:
     		send_notification(CARP_ID, f"A new user - @{new_user.username} - has signed up!")
    -	if SITE == 'watchpeopledie.co':
    -		carp = get_account(CARP_ID)
    -		new_follow = Follow(user_id=new_user.id, target_id=carp.id)
    -		g.db.add(new_follow)
    -		carp.stored_subscriber_count += 1
    -		g.db.add(carp)
    -		send_notification(carp.id, f"A new user - @{new_user.username} - has followed you automatically!")
    -	if SITE == 'pcmemes.net':
    -		kippy = get_account(KIPPY_ID)
    -		new_follow = Follow(user_id=new_user.id, target_id=kippy.id)
    -		g.db.add(new_follow)
    -		kippy.stored_subscriber_count += 1
    -		g.db.add(kippy)
    -		send_notification(kippy.id, f"A new user - @{new_user.username} - has followed you automatically!")
     
     	redir = request.values.get("redirect")
     	if redir:
    @@ -441,10 +437,12 @@ def post_forgot():
     
     @app.get("/reset")
     def get_reset():
    -
     	user_id = request.values.get("id")
    -
    -	timestamp = int(request.values.get("time",0))
    +	timestamp = 0
    +	try:
    +		timestamp = int(request.values.get("time",0))
    +	except:
    +		pass
     	token = request.values.get("token")
     
     	now = int(time.time())
    @@ -480,8 +478,11 @@ def post_reset(v):
     	if v: return redirect('/')
     
     	user_id = request.values.get("user_id")
    -
    -	timestamp = int(request.values.get("time"))
    +	timestamp = 0
    +	try:
    +		timestamp = int(request.values.get("time"))
    +	except:
    +		abort(400)
     	token = request.values.get("token")
     
     	password = request.values.get("password")
    @@ -566,11 +567,13 @@ def request_2fa_disable():
     
     @app.get("/reset_2fa")
     def reset_2fa():
    -
     	now=int(time.time())
     	t = request.values.get("t")
     	if not t: abort(400)
    -	t = int(t)
    +	try:
    +		t = int(t)
    +	except:
    +		abort(400)
     
     	if now > t+3600*24:
     		return render_template("message.html",
    diff --git a/files/routes/lottery.py b/files/routes/lottery.py
    index 3546d1517..930b56205 100644
    --- a/files/routes/lottery.py
    +++ b/files/routes/lottery.py
    @@ -9,7 +9,7 @@ import requests
     
     @app.post("/lottery/end")
     @admin_level_required(PERMS['LOTTERY_ADMIN'])
    -@casino_required
    +@feature_required('GAMBLING')
     def lottery_end(v):
     	success, message = end_lottery_session()
     	return {"message": message} if success else {"error": message}
    @@ -17,7 +17,7 @@ def lottery_end(v):
     
     @app.post("/lottery/start")
     @admin_level_required(PERMS['LOTTERY_ADMIN'])
    -@casino_required
    +@feature_required('GAMBLING')
     def lottery_start(v):
     	start_new_lottery_session()
     	return {"message": "Lottery started."}
    @@ -26,10 +26,10 @@ def lottery_start(v):
     @app.post("/lottery/buy")
     @limiter.limit("3/second;100/minute;500/hour;1000/day")
     @auth_required
    -@casino_required
    +@feature_required('GAMBLING')
     def lottery_buy(v):
     	try: quantity = int(request.values.get("quantity"))
    -	except: return {"error": "Invalid ticket quantity."}, 400
    +	except: abort(400, "Invalid ticket quantity.")
     
     	success, message = purchase_lottery_tickets(v, quantity)
     	lottery, participants = get_active_lottery_stats()
    @@ -44,7 +44,7 @@ def lottery_buy(v):
     @app.get("/lottery/active")
     @limiter.limit("3/second;100/minute;500/hour;1000/day")
     @auth_required
    -@casino_required
    +@feature_required('GAMBLING')
     def lottery_active(v):
     	lottery, participants = get_active_lottery_stats()
     
    @@ -52,7 +52,7 @@ def lottery_active(v):
     
     @app.get("/admin/lottery/participants")
     @admin_level_required(PERMS['LOTTERY_VIEW_PARTICIPANTS'])
    -@casino_required
    +@feature_required('GAMBLING')
     def lottery_admin(v):
     	participants = get_users_participating_in_lottery()
     	return render_template("admin/lottery.html", v=v, participants=participants)
    diff --git a/files/routes/notifications.py b/files/routes/notifications.py
    index f76e31196..9a3d6e05d 100644
    --- a/files/routes/notifications.py
    +++ b/files/routes/notifications.py
    @@ -41,13 +41,13 @@ def notifications_modmail(v):
     	try: page = max(int(request.values.get("page", 1)), 1)
     	except: page = 1
     
    -	comments = g.db.query(Comment).filter(Comment.sentto==2).order_by(Comment.id.desc()).offset(25*(page-1)).limit(26).all()
    -	next_exists = (len(comments) > 25)
    -	listing = comments[:25]
    +	comments = g.db.query(Comment).filter(Comment.sentto==2).order_by(Comment.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all()
    +	next_exists = (len(comments) > PAGE_SIZE)
    +	listing = comments[:PAGE_SIZE]
     
     	g.db.commit()
     
    -	if request.headers.get("Authorization"): return {"data":[x.json for x in listing]}
    +	if v.client: return {"data":[x.json for x in listing]}
     
     	return render_template("notifications.html",
     							v=v,
    @@ -92,7 +92,7 @@ def notifications_messages(v):
     	message_threads = message_threads.join(thread_order,
     						thread_order.c.top_comment_id == Comment.top_comment_id)
     	message_threads = message_threads.order_by(thread_order.c.created_utc.desc()) \
    -						.offset(25*(page-1)).limit(26).all()
    +						.offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all()
     
     	# Clear notifications (used for unread indicator only) for all user messages.
     	notifs_unread_row = g.db.query(Notification.comment_id).join(Comment).filter(
    @@ -117,7 +117,7 @@ def notifications_messages(v):
     		c.unread = True
     		list_to_perserve_unread_attribute.append(c)
     
    -	if request.headers.get("Authorization"): return {"data":[x.json for x in listing]}
    +	if v.client: return {"data":[x.json for x in listing]}
     
     	return render_template("notifications.html",
     							v=v,
    @@ -147,7 +147,7 @@ def notifications_posts(v):
     		Submission.author_id != v.id,
     		Submission.ghost == False,
     		Submission.author_id.notin_(v.userblocks)
    -	).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()]
    +	).order_by(Submission.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all()]
     
     	next_exists = (len(listing) > 25)
     	listing = listing[:25]
    @@ -159,7 +159,7 @@ def notifications_posts(v):
     	v.last_viewed_post_notifs = int(time.time())
     	g.db.add(v)
     
    -	if request.headers.get("Authorization"): return {"data":[x.json for x in listing]}
    +	if v.client: return {"data":[x.json for x in listing]}
     
     	return render_template("notifications.html",
     							v=v,
    @@ -177,10 +177,10 @@ def notifications_modactions(v):
     	try: page = max(int(request.values.get("page", 1)), 1)
     	except: page = 1
     
    -	listing = g.db.query(ModAction).filter(ModAction.user_id != v.id).order_by(ModAction.id.desc()).offset(25*(page-1)).limit(26).all()
    +	listing = g.db.query(ModAction).filter(ModAction.user_id != v.id).order_by(ModAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all()
     
    -	next_exists = len(listing) > 25
    -	listing = listing[:25]
    +	next_exists = len(listing) > PAGE_SIZE
    +	listing = listing[:PAGE_SIZE]
     
     	for ma in listing:
     		ma.unread = ma.created_utc > v.last_viewed_log_notifs
    @@ -230,7 +230,7 @@ def notifications_reddit(v):
     
     	g.db.commit()
     
    -	if request.headers.get("Authorization"): return {"data":[x.json for x in listing]}
    +	if v.client: return {"data":[x.json for x in listing]}
     
     	return render_template("notifications.html",
     							v=v,
    @@ -258,16 +258,11 @@ def notifications(v):
     		or_(Comment.sentto == None, Comment.sentto == 2),
     	).order_by(Notification.created_utc.desc())
     
    -	if not (v and (v.shadowbanned or v.admin_level >= PERMS['NOTIFICATIONS_FROM_SHADOWBANNED_USERS'])):
    -		comments = comments.join(Comment.author).filter(User.shadowbanned == None)
    -
    -	comments = comments.offset(25 * (page - 1)).limit(26).all()
    -
    -	next_exists = (len(comments) > 25)
    -	comments = comments[:25]
    +	comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all()
     
    +	next_exists = (len(comments) > PAGE_SIZE)
    +	comments = comments[:PAGE_SIZE]
     	cids = [x[0].id for x in comments]
    -
     	comms = get_comments(cids, v=v)
     
     	listing = []
    @@ -301,7 +296,7 @@ def notifications(v):
     
     	g.db.commit()
     
    -	if request.headers.get("Authorization"): return {"data":[x.json for x in listing]}
    +	if v.client: return {"data":[x.json for x in listing]}
     
     	return render_template("notifications.html",
     							v=v,
    diff --git a/files/routes/oauth.py b/files/routes/oauth.py
    index ea736d6cf..e1e6fe3ce 100644
    --- a/files/routes/oauth.py
    +++ b/files/routes/oauth.py
    @@ -97,8 +97,10 @@ def request_api_keys(v):
     @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
     @auth_required
     def delete_oauth_app(v, aid):
    -
    -	aid = int(aid)
    +	try:
    +		aid = int(aid)
    +	except:
    +		abort(404)
     	app = g.db.get(OauthApp, aid)
     	if not app: abort(404)
     	
    @@ -118,8 +120,10 @@ def delete_oauth_app(v, aid):
     @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}')
     @is_not_permabanned
     def edit_oauth_app(v, aid):
    -
    -	aid = int(aid)
    +	try:
    +		aid = int(aid)
    +	except:
    +		abort(404)
     	app = g.db.get(OauthApp, aid)
     	if not app: abort(404)
     
    @@ -158,7 +162,7 @@ def admin_app_approve(v, aid):
     
     		g.db.add(new_auth)
     
    -		send_repeatable_notification(user.id, f"@{v.username} has approved your application `{app.app_name}`. Here's your access token: `{access_token}`\nPlease check the guide [here](/api) if you don't know what to do next, and join this [discord server](/discord) if you need help!")
    +		send_repeatable_notification(user.id, f"@{v.username} (Admin) has approved your application `{app.app_name}`. Here's your access token: `{access_token}`\nPlease check the guide [here](/api) if you don't know what to do next!")
     
     		ma = ModAction(
     			kind="approve_app",
    @@ -181,7 +185,7 @@ def admin_app_revoke(v, aid):
     		for auth in g.db.query(ClientAuth).filter_by(oauth_client=app.id).all(): g.db.delete(auth)
     
     		if v.id != app.author.id:
    -			send_repeatable_notification(app.author.id, f"@{v.username} has revoked your application `{app.app_name}`.")
    +			send_repeatable_notification(app.author.id, f"@{v.username} (Admin) has revoked your application `{app.app_name}`.")
     
     		g.db.delete(app)
     
    @@ -207,7 +211,7 @@ def admin_app_reject(v, aid):
     		for auth in g.db.query(ClientAuth).filter_by(oauth_client=app.id).all(): g.db.delete(auth)
     
     		if v.id != app.author.id:
    -			send_repeatable_notification(app.author.id, f"@{v.username} has rejected your application `{app.app_name}`.")
    +			send_repeatable_notification(app.author.id, f"@{v.username} (Admin) has rejected your application `{app.app_name}`.")
     
     		g.db.delete(app)
     
    @@ -222,9 +226,9 @@ def admin_app_reject(v, aid):
     	return {"message": f"'{app.app_name}' rejected!"}
     
     
    -@app.get("/admin/app/")
    +@app.get("/admin/app//posts")
     @admin_level_required(PERMS['APPS_MODERATION'])
    -def admin_app_id(v, aid):
    +def admin_app_id_posts(v, aid):
     	aid=aid
     	oauth = g.db.get(OauthApp, aid)
     	if not oauth: abort(404)
    diff --git a/files/routes/polls.py b/files/routes/polls.py
    index b75cfc68b..387df1e08 100644
    --- a/files/routes/polls.py
    +++ b/files/routes/polls.py
    @@ -9,21 +9,20 @@ from files.__main__ import app
     @app.post("/vote/post/option/")
     @is_not_permabanned
     def vote_option(option_id, v):
    -
    -	option_id = int(option_id)
    -
    +	try:
    +		option_id = int(option_id)
    +	except:
    +		abort(404)
     	option = g.db.get(SubmissionOption, option_id)
    -
     	if not option: abort(404)
    -
     	sub = option.post.sub
     
     	if sub in ('furry','vampire','racist','femboy') and not v.house.lower().startswith(sub):
    -		return {"error": f"You need to be a member of House {sub.capitalize()} to vote on polls in /h/{sub}"}, 400
    +		abort(403, f"You need to be a member of House {sub.capitalize()} to vote on polls in /h/{sub}")
     
     	if option.exclusive == 2:
    -		if v.coins < POLL_BET_COINS: return {"error": f"You don't have {POLL_BET_COINS} coins!"}, 400
    -		v.coins -= POLL_BET_COINS
    +		if v.coins < POLL_BET_COINS: abort(400, f"You don't have {POLL_BET_COINS} coins!")
    +		v.charge_account('coins', POLL_BET_COINS)
     		g.db.add(v)
     		autojanny = get_account(AUTOJANNY_ID)
     		autojanny.coins += POLL_BET_COINS
    @@ -35,7 +34,7 @@ def vote_option(option_id, v):
     			SubmissionOptionVote.submission_id==option.submission_id,
     			SubmissionOption.exclusive==option.exclusive).one_or_none()
     		if vote:
    -			if option.exclusive == 2: return {"error": "You already voted on this bet!"}, 400
    +			if option.exclusive == 2: abort(400, "You already voted on this bet!")
     			g.db.delete(vote)
     
     	existing = g.db.query(SubmissionOptionVote).filter_by(option_id=option_id, user_id=v.id).one_or_none()
    @@ -54,15 +53,13 @@ def vote_option(option_id, v):
     @app.get("/votes/post/option/")
     @auth_required
     def option_votes(option_id, v):
    -
    -	option_id = int(option_id)
    -
    +	try:
    +		option_id = int(option_id)
    +	except:
    +		abort(404)
     	option = g.db.get(SubmissionOption, option_id)
    -
     	if not option: abort(404)
    -
     	if option.post.ghost: abort(403)
    -
     	ups = g.db.query(SubmissionOptionVote).filter_by(option_id=option_id).order_by(SubmissionOptionVote.created_utc).all()
     
     	return render_template("poll_votes.html",
    @@ -75,17 +72,15 @@ def option_votes(option_id, v):
     @app.post("/vote/comment/option/")
     @is_not_permabanned
     def vote_option_comment(option_id, v):
    -
    -	option_id = int(option_id)
    -
    +	try:
    +		option_id = int(option_id)
    +	except:
    +		abort(404)
     	option = g.db.get(CommentOption, option_id)
    -
     	if not option: abort(404)
    -
     	sub = option.comment.post.sub
    -
     	if sub in ('furry','vampire','racist','femboy') and not v.house.lower().startswith(sub):
    -		return {"error": f"You need to be a member of House {sub.capitalize()} to vote on polls in /h/{sub}"}, 400
    +		abort(403, f"You need to be a member of House {sub.capitalize()} to vote on polls in /h/{sub}")
     
     	if option.exclusive:
     		vote = g.db.query(CommentOptionVote).join(CommentOption).filter(
    @@ -111,9 +106,10 @@ def vote_option_comment(option_id, v):
     @app.get("/votes/comment/option/")
     @auth_required
     def option_votes_comment(option_id, v):
    -
    -	option_id = int(option_id)
    -
    +	try:
    +		option_id = int(option_id)
    +	except:
    +		abort(404)
     	option = g.db.get(CommentOption, option_id)
     
     	if not option: abort(404)
    diff --git a/files/routes/posts.py b/files/routes/posts.py
    index 1a21a7191..bc0bcaf2c 100644
    --- a/files/routes/posts.py
    +++ b/files/routes/posts.py
    @@ -15,7 +15,7 @@ from files.classes import *
     from flask import *
     from io import BytesIO
     from files.__main__ import app, limiter, cache, db_session
    -from PIL import Image as PILimage
    +from PIL import Image
     from .front import frontlist
     from urllib.parse import ParseResult, urlunparse, urlparse, quote, unquote
     from os import path
    @@ -30,10 +30,8 @@ titleheaders = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWe
     
     @app.post("/club_post/")
     @auth_required
    +@feature_required('COUNTRY_CLUB')
     def club_post(pid, v):
    -	if not FEATURES['COUNTRY_CLUB']:
    -		abort(403)
    -
     	post = get_post(pid)
     	if post.author_id != v.id and v.admin_level < PERMS['POST_COMMENT_MODERATION']: abort(403)
     
    @@ -49,19 +47,17 @@ def club_post(pid, v):
     			)
     			g.db.add(ma)
     
    -			message = f"@{v.username} (admin) has moved [{post.title}]({post.shortlink}) to the {CC_TITLE}!"
    +			message = f"@{v.username} (Admin) has moved [{post.title}]({post.shortlink}) to the {CC_TITLE}!"
     			send_repeatable_notification(post.author_id, message)
     
     	return {"message": f"Post has been moved to the {CC_TITLE}!"}
     
     @app.post("/unclub_post/")
     @auth_required
    +@feature_required('COUNTRY_CLUB')
     def unclub_post(pid, v):
    -	if not FEATURES['COUNTRY_CLUB']:
    -		abort(403)
    -
     	post = get_post(pid)
    -	if post.author_id != v.id and v.admin_level < 2: abort(403)
    +	if post.author_id != v.id and v.admin_level < PERMS['POST_COMMENT_MODERATION']: abort(403)
     
     	if post.club:
     		post.club = False
    @@ -75,7 +71,7 @@ def unclub_post(pid, v):
     			)
     			g.db.add(ma)
     
    -			message = f"@{v.username} (admin) has removed [{post.title}]({post.shortlink}) from the {CC_TITLE}!"
    +			message = f"@{v.username} (Admin) has removed [{post.title}]({post.shortlink}) from the {CC_TITLE}!"
     			send_repeatable_notification(post.author_id, message)
     
     	return {"message": f"Post has been removed from the {CC_TITLE}!"}
    @@ -106,9 +102,10 @@ def publish(pid, v):
     	cache.delete_memoized(frontlist)
     	cache.delete_memoized(User.userpagelisting)
     
    -	send_changelog_message(post.permalink)
    +	if post.sub == 'changelog':
    +		send_changelog_message(post.permalink)
     
    -	if SITE == 'watchpeopledie.co':
    +	if SITE == 'watchpeopledie.tv':
     		send_wpd_message(post.permalink)
     
     	execute_snappy(post, v)
    @@ -143,78 +140,45 @@ def post_id(pid, anything=None, v=None, sub=None):
     	if not post.can_see(v): abort(403)
     
     	if post.over_18 and not (v and v.over_18) and session.get('over_18', 0) < int(time.time()):
    -		if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error":"Must be 18+ to view"}, 451
    +		if g.is_api_or_xhr: return {"error":"Must be 18+ to view"}, 451
     		return render_template("errors/nsfw.html", v=v)
     
     	if post.new or 'megathread' in post.title.lower(): defaultsortingcomments = 'new'
     	elif v: defaultsortingcomments = v.defaultsortingcomments
    -	else: defaultsortingcomments = "top"
    +	else: defaultsortingcomments = "hot"
     	sort = request.values.get("sort", defaultsortingcomments)
     
     	if post.club and not (v and (v.paid_dues or v.id == post.author_id)): abort(403)
     
     	if v:
    -		votes = g.db.query(CommentVote.vote_type, CommentVote.comment_id).filter_by(user_id=v.id).subquery()
    -
    -		blocking = v.blocking.subquery()
    -
    -		blocked = v.blocked.subquery()
    -
    -		comments = g.db.query(
    -			Comment,
    -			votes.c.vote_type,
    -			blocking.c.target_id,
    -			blocked.c.target_id,
    -		)
    -		
    -		if not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
    -			comments = comments.join(Comment.author).filter(User.shadowbanned == None)
    - 
    -		comments=comments.filter(Comment.parent_submission == post.id, Comment.level < 10).join(
    -			votes,
    -			votes.c.comment_id == Comment.id,
    -			isouter=True
    -		).join(
    -			blocking,
    -			blocking.c.target_id == Comment.author_id,
    -			isouter=True
    -		).join(
    -			blocked,
    -			blocked.c.user_id == Comment.author_id,
    -			isouter=True
    -		)
    -
    -		output = []
    -		for c in comments.all():
    -			comment = c[0]
    -			comment.voted = c[1] or 0
    -			comment.is_blocking = c[2] or 0
    -			comment.is_blocked = c[3] or 0
    -			output.append(comment)
    -
    +		# shadowban check is done in sort_objects
    +		# output is needed: see comments.py
    +		comments, output = get_comments_v_properties(v, True, None, Comment.parent_submission == post.id, Comment.level < 10)
     		pinned = [c[0] for c in comments.filter(Comment.stickied != None).all()]
    -
     		comments = comments.filter(Comment.level == 1, Comment.stickied == None)
    -
    -		comments = sort_comments(sort, comments)
    -
    +		comments = sort_objects(sort, comments, Comment,
    +			include_shadowbanned=(v and v.can_see_shadowbanned))
     		comments = [c[0] for c in comments.all()]
     	else:
     		pinned = g.db.query(Comment).filter(Comment.parent_submission == post.id, Comment.stickied != None).all()
     
    -		comments = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.parent_submission == post.id, Comment.level == 1, Comment.stickied == None)
    +		comments = g.db.query(Comment).filter(
    +				Comment.parent_submission == post.id,
    +				Comment.level == 1,
    +				Comment.stickied == None
    +			)
     
    -		comments = sort_comments(sort, comments)
    +		comments = sort_objects(sort, comments, Comment,
    +			include_shadowbanned=False)
     
     		comments = comments.all()
     
     	offset = 0
     	ids = set()
     
    -	if v and v.poorcel: threshold = 50
    -	else: threshold = 100
    +	threshold = 100
     
    -	if post.comment_count > threshold+25 and not request.headers.get("Authorization") and not request.values.get("all"):
    +	if post.comment_count > threshold+25 and not (v and v.client) and not request.values.get("all"):
     		comments2 = []
     		count = 0
     		if post.created_utc > 1638672040:
    @@ -252,7 +216,7 @@ def post_id(pid, anything=None, v=None, sub=None):
     	post.views += 1
     	g.db.add(post)
     
    -	if request.headers.get("Authorization"):
    +	if v and v.client:
     		return post.json
     
     	template = "submission.html"
    @@ -270,59 +234,31 @@ def post_id(pid, anything=None, v=None, sub=None):
     def viewmore(v, pid, sort, offset):
     	post = get_post(pid, v=v)
     	if post.club and not (v and (v.paid_dues or v.id == post.author_id)): abort(403)
    -
    -	offset = int(offset)
    +	try:
    +		offset = int(offset)
    +	except: abort(400)
     	try: ids = set(int(x) for x in request.values.get("ids").split(','))
     	except: abort(400)
     	
     	if v:
    -		votes = g.db.query(CommentVote.vote_type, CommentVote.comment_id).filter_by(user_id=v.id).subquery()
    -
    -		blocking = v.blocking.subquery()
    -
    -		blocked = v.blocked.subquery()
    -
    -		comments = g.db.query(
    -			Comment,
    -			votes.c.vote_type,
    -			blocking.c.target_id,
    -			blocked.c.target_id,
    -		).filter(Comment.parent_submission == pid, Comment.stickied == None, Comment.id.notin_(ids), Comment.level < 10)
    -		
    -		if not (v and v.shadowbanned) and not (v and v.admin_level >= PERMS['USER_SHADOWBAN']):
    -			comments = comments.join(Comment.author).filter(User.shadowbanned == None)
    - 
    -		comments=comments.join(
    -			votes,
    -			votes.c.comment_id == Comment.id,
    -			isouter=True
    -		).join(
    -			blocking,
    -			blocking.c.target_id == Comment.author_id,
    -			isouter=True
    -		).join(
    -			blocked,
    -			blocked.c.user_id == Comment.author_id,
    -			isouter=True
    -		)
    -
    -		output = []
    -		for c in comments.all():
    -			comment = c[0]
    -			comment.voted = c[1] or 0
    -			comment.is_blocking = c[2] or 0
    -			comment.is_blocked = c[3] or 0
    -			output.append(comment)
    -		
    +		# shadowban check is done in sort_objects
    +		# output is needed: see comments.py
    +		comments, output = get_comments_v_properties(v, True, None, Comment.parent_submission == pid, Comment.stickied == None, Comment.id.notin_(ids), Comment.level < 10)
     		comments = comments.filter(Comment.level == 1)
    -
    -		comments = sort_comments(sort, comments)
    +		comments = sort_objects(sort, comments, Comment,
    +			include_shadowbanned=(v and v.can_see_shadowbanned))
     
     		comments = [c[0] for c in comments.all()]
     	else:
    -		comments = g.db.query(Comment).join(Comment.author).filter(User.shadowbanned == None, Comment.parent_submission == pid, Comment.level == 1, Comment.stickied == None, Comment.id.notin_(ids))
    +		comments = g.db.query(Comment).filter(
    +				Comment.parent_submission == pid,
    +				Comment.level == 1,
    +				Comment.stickied == None,
    +				Comment.id.notin_(ids)
    +			)
     
    -		comments = sort_comments(sort, comments)
    +		comments = sort_objects(sort, comments, Comment,
    +			include_shadowbanned=False)
     		
     		comments = comments.offset(offset).all()
     
    @@ -358,44 +294,13 @@ def morecomments(v, cid):
     	tcid = g.db.query(Comment.top_comment_id).filter_by(id=cid).one_or_none()[0]
     
     	if v:
    -		votes = g.db.query(CommentVote.vote_type, CommentVote.comment_id).filter_by(user_id=v.id).subquery()
    -
    -		blocking = v.blocking.subquery()
    -
    -		blocked = v.blocked.subquery()
    -
    -		comments = g.db.query(
    -			Comment,
    -			votes.c.vote_type,
    -			blocking.c.target_id,
    -			blocked.c.target_id,
    -		).filter(Comment.top_comment_id == tcid, Comment.level > 9).join(
    -			votes,
    -			votes.c.comment_id == Comment.id,
    -			isouter=True
    -		).join(
    -			blocking,
    -			blocking.c.target_id == Comment.author_id,
    -			isouter=True
    -		).join(
    -			blocked,
    -			blocked.c.user_id == Comment.author_id,
    -			isouter=True
    -		)
    -
    -		output = []
    -		dump = []
    -		for c in comments.all():
    -			comment = c[0]
    -			comment.voted = c[1] or 0
    -			comment.is_blocking = c[2] or 0
    -			comment.is_blocked = c[3] or 0
    -			if c[0].parent_comment_id == int(cid): output.append(comment)
    -			else: dump.append(comment)
    +		# shadowban check is done in sort_objects i think
    +		# output is needed: see comments.py
    +		comments, output = get_comments_v_properties(v, True, lambda c:bool(c.parent_comment_id == int(cid)), Comment.top_comment_id == tcid, Comment.level > 9)
     		comments = output
     	else:
     		c = get_comment(cid)
    -		comments = c.replies(None)
    +		comments = c.replies(sort=request.values.get('sort'), v=v)
     
     	if comments: p = comments[0].post
     	else: p = None
    @@ -411,24 +316,29 @@ def edit_post(pid, v):
     	if v.id != p.author_id and v.admin_level < PERMS['POST_EDITING']:
     		abort(403)
     
    +	# Disable edits on things older than 1wk unless it's a draft or editor is a jannie
    +	if (time.time() - p.created_utc > 7*24*60*60 and not p.private
    +			and not v.admin_level >= PERMS['POST_EDITING']):
    +		abort(403, "You can't edit posts older than 1 week!")
    +
     	title = sanitize_raw_title(request.values.get("title", ""))
     	body = sanitize_raw_body(request.values.get("body", ""), True)
     
     	if v.id == p.author_id:
     		if v.longpost and (len(body) < 280 or ' [](' in body or body.startswith('[](')):
    -			return {"error":"You have to type more than 280 characters!"}, 403
    +			abort(403, "You have to type more than 280 characters!")
     		elif v.bird and len(body) > 140:
    -			return {"error":"You have to type less than 140 characters!"}, 403
    +			abort(403, "You have to type less than 140 characters!")
     
     	if not title:
    -		return {"error": "Please enter a better title."}, 400
    +		abort(400, "Please enter a better title.")
     	if title != p.title:
     		torture = (v.agendaposter and not v.marseyawarded and p.sub != 'chudrama' and v.id == p.author_id)
     
     		title_html = filter_emojis_only(title, golden=False, torture=torture)
     
     		if v.id == p.author_id and v.marseyawarded and not marseyaward_title_regex.fullmatch(title_html):
    -			return {"error":"You can only type marseys!"}, 403
    +			abort(403, "You can only type marseys!")
     
     		p.title = title
     		p.title_html = title_html
    @@ -461,23 +371,21 @@ def edit_post(pid, v):
     		body_html = sanitize(body, golden=False, limit_pings=100, showmore=False, torture=torture)
     
     		if v.id == p.author_id and v.marseyawarded and marseyaward_body_regex.search(body_html):
    -			return {"error":"You can only type marseys!"}, 403
    +			abort(403, "You can only type marseys!")
     
     
     		p.body = body
     
    -		if blackjack and any(i in f'{p.body} {p.title} {p.url}'.lower() for i in blackjack.split()):
    -			v.shadowbanned = 'AutoJanny'
    -			if not v.is_banned: v.ban_reason = 'Blackjack'
    -			g.db.add(v)
    -			send_repeatable_notification(CARP_ID, p.permalink)
    +		for text in [p.body, p.title, p.url]:
    +			if not execute_blackjack(v, p, text, 'submission'): break
     
    -		if len(body_html) > POST_BODY_HTML_LENGTH_LIMIT: return {"error":f"Submission body_html too long! (max {POST_BODY_HTML_LENGTH_LIMIT} characters)"}, 400
    +		if len(body_html) > POST_BODY_HTML_LENGTH_LIMIT: 
    +			abort(400, f"Submission body_html too long! (max {POST_BODY_HTML_LENGTH_LIMIT} characters)")
     
     		p.body_html = body_html
     
     		if v.id == p.author_id and v.agendaposter and not v.marseyawarded and AGENDAPOSTER_PHRASE not in f'{p.body}{p.title}'.lower() and p.sub != 'chudrama':
    -			return {"error": f'You have to include "{AGENDAPOSTER_PHRASE}" in your post!'}, 403
    +			abort(403, f'You have to include "{AGENDAPOSTER_PHRASE}" in your post!')
     
     
     	if not p.private and not p.ghost:
    @@ -600,9 +508,9 @@ def thumbnail_thread(pid):
     			if image_req.headers.get("Content-Type","").startswith("image/svg"):
     				continue
     
    -			image = PILimage.open(BytesIO(image_req.content))
    -			if image.width < 30 or image.height < 30:
    -				continue
    +			with Image.open(BytesIO(image_req.content)) as i:
    +				if i.width < 30 or i.height < 30:
    +					continue
     
     			break
     
    @@ -614,17 +522,16 @@ def thumbnail_thread(pid):
     
     	elif x.headers.get("Content-Type","").startswith("image/"):
     		image_req=x
    -		image = PILimage.open(BytesIO(x.content))
    +		with Image.open(BytesIO(x.content)) as i:
    +			size = len(i.fp.read())
    +			if size > 8 * 1024 * 1024:
    +				db.close()
    +				return
     
     	else:
     		db.close()
     		return
     
    -	size = len(image.fp.read())
    -	if size > 8 * 1024 * 1024:
    -		db.close()
    -		return
    -
     	name = f'/images/{time.time()}'.replace('.','') + '.webp'
     
     	with open(name, "wb") as file:
    @@ -641,11 +548,12 @@ def thumbnail_thread(pid):
     
     @app.post("/is_repost")
     def is_repost():
    +	not_a_repost = {'permalink': ''}
     	if not FEATURES['REPOST_DETECTION']:
    -		return {'permalink': ''}
    +		return not_a_repost
     
     	url = request.values.get('url')
    -	if not url: abort(400)
    +	if not url or len(url) < MIN_REPOST_CHECK_URL_LENGTH: abort(400)
     
     	url = normalize_url(url)
     	parsed_url = urlparse(url)
    @@ -670,7 +578,6 @@ def is_repost():
     							fragment=parsed_url.fragment)
     	
     	url = urlunparse(new_url)
    -
     	url = url.rstrip('/')
     
     	search_url = url.replace('%', '').replace('\\', '').replace('_', '\_').strip()
    @@ -680,7 +587,7 @@ def is_repost():
     		Submission.is_banned == False
     	).first()
     	if repost: return {'permalink': repost.permalink}
    -	else: return {'permalink': ''}
    +	else: return not_a_repost
     
     @app.post("/submit")
     @app.post("/h//submit")
    @@ -697,7 +604,7 @@ def submit_post(v, sub=None):
     	body = sanitize_raw_body(request.values.get("body", ""), True)
     
     	def error(error):
    -		if request.headers.get("Authorization") or request.headers.get("xhr"): return {"error": error}, 400
    +		if g.is_api_or_xhr: abort(400, error)
     	
     		SUBS = [x[0] for x in g.db.query(Sub.name).order_by(Sub.name).all()]
     		return render_template("submit.html", SUBS=SUBS, v=v, error=error, title=title, url=url, body=body), 400
    @@ -776,16 +683,16 @@ def submit_post(v, sub=None):
     			Submission.deleted_utc == 0,
     			Submission.is_banned == False
     		).first()
    -		if repost and FEATURES['REPOST_DETECTION']:
    +		if repost and FEATURES['REPOST_DETECTION'] and not v.admin_level >= PERMS['POST_BYPASS_REPOST_CHECKING']:
     			return redirect(repost.permalink)
     
    -		domain_obj = get_domain(domain)
    -		if not domain_obj: domain_obj = get_domain(domain+parsed_url.path)
    +		y = tldextract.extract(url).registered_domain + parsed_url.path
    +		banned_domains = g.db.query(BannedDomain).all()
    +		for x in banned_domains:
    +			if y.startswith(x.domain):
    +				return error(f'Remove the banned link "{x.domain}" and try again!
    Reason for link ban: "{x.reason}"') - if domain_obj: - reason = f"Remove the {domain_obj.domain} link from your post and try again. {domain_obj.reason}" - return error(reason) - elif "twitter.com" == domain: + if "twitter.com" == domain: try: embed = requests.get("https://publish.twitter.com/oembed", params={"url":url, "omit_script":"t"}, timeout=5).json()["html"] embed = embed.replace('')(title) < SPAM_SIMILARITY_THRESHOLD, - Submission.created_utc > cutoff - ).all() - - if url: - similar_urls = g.db.query(Submission).filter( - Submission.author_id == v.id, - Submission.url.op('<->')(url) < SPAM_URL_SIMILARITY_THRESHOLD, - Submission.created_utc > cutoff - ).all() - else: similar_urls = [] - - threshold = SPAM_SIMILAR_COUNT_THRESHOLD - if v.age >= (60 * 60 * 24 * 7): threshold *= 3 - elif v.age >= (60 * 60 * 24): threshold *= 2 - - if max(len(similar_urls), len(similar_posts)) >= threshold: - - text = "Your account has been banned for **1 day** for the following reason:\n\n> Too much spam!" - send_repeatable_notification(v.id, text) - - v.ban(reason="Spamming.", - days=1) - - for post in similar_posts + similar_urls: - post.is_banned = True - post.is_pinned = False - post.ban_reason = "AutoJanny" - g.db.add(post) - ma=ModAction( - user_id=AUTOJANNY_ID, - target_submission_id=post.id, - kind="ban_post", - _note="spam" - ) - g.db.add(ma) + if not execute_antispam_submission_check(title, v, url): return redirect("/notifications") if len(url) > 2048: return error("There's a 2048 character limit for URLs.") + bets = [] if v and v.admin_level >= PERMS['POST_BETS']: - bets = [] for i in bet_regex.finditer(body): bets.append(i.group(1)) body = body.replace(i.group(0), "") @@ -907,15 +773,16 @@ def submit_post(v, sub=None): if embed and len(embed) > 1500: embed = None - is_bot = v.id != BBBB_ID and bool(request.headers.get("Authorization")) or (SITE == 'pcmemes.net' and v.id == SNAPPY_ID) - if request.values.get("ghost") and v.coins >= 100: - v.coins -= 100 + v.charge_account('coins', 100) ghost = True else: ghost = False if embed: embed = embed.strip() + if url and url.startswith(SITE_FULL): + url = url.split(SITE_FULL)[1] + post = Submission( private=bool(request.values.get("private","")), notify=bool(request.values.get("notify","")), @@ -924,7 +791,7 @@ def submit_post(v, sub=None): over_18=bool(request.values.get("over_18","")), new=bool(request.values.get("new","")), app_id=v.client.application.id if v.client else None, - is_bot = is_bot, + is_bot=(v.client is not None), url=url, body=body, body_html=body_html, @@ -938,11 +805,8 @@ def submit_post(v, sub=None): g.db.add(post) g.db.flush() - if blackjack and any(i in f'{post.body} {post.title} {post.url}'.lower() for i in blackjack.split()): - v.shadowbanned = 'AutoJanny' - if not v.is_banned: v.ban_reason = 'Blackjack' - g.db.add(v) - send_repeatable_notification(CARP_ID, post.permalink) + for text in [post.body, post.title, post.url]: + if not execute_blackjack(v, post, text, 'submission'): break for option in options: option = SubmissionOption( @@ -1061,17 +925,19 @@ def submit_post(v, sub=None): post.upvotes += 3 g.db.add(post) + execute_lawlz_actions(v, post) + cache.delete_memoized(frontlist) cache.delete_memoized(User.userpagelisting) if post.sub == 'changelog' and not post.private: send_changelog_message(post.permalink) - if not post.private and SITE == 'watchpeopledie.co': + if not post.private and SITE == 'watchpeopledie.tv': send_wpd_message(post.permalink) g.db.commit() - if request.headers.get("Authorization"): return post.json + if v.client: return post.json else: post.voted = 1 if post.new or 'megathread' in post.title.lower(): sort = 'new' @@ -1087,6 +953,9 @@ def delete_post_pid(pid, v): post = get_post(pid) if post.author_id != v.id: abort(403) + # Temporary special logic by Carp request for events of 2022-10-10 + if SITE_NAME == 'rDrama' and post.author_id == 3161: abort(403) + if not post.deleted_utc: post.deleted_utc = int(time.time()) post.is_pinned = False @@ -1196,7 +1065,7 @@ def pin_post(post_id, v): post = get_post(post_id) if post: - if v.id != post.author_id: return {"error": "Only the post author's can do that!"}, 400 + if v.id != post.author_id: abort(400, "Only the post author's can do that!") post.is_pinned = not post.is_pinned g.db.add(post) @@ -1204,7 +1073,7 @@ def pin_post(post_id, v): if post.is_pinned: return {"message": "Post pinned!"} else: return {"message": "Post unpinned!"} - return {"error": "Post not found!"}, 400 + return abort(404, "Post not found!") extensions = ( diff --git a/files/routes/reporting.py b/files/routes/reporting.py index 45c000498..797fd8ad4 100644 --- a/files/routes/reporting.py +++ b/files/routes/reporting.py @@ -1,6 +1,7 @@ from files.helpers.wrappers import * from files.helpers.get import * from files.helpers.alerts import * +from files.helpers.actions import * from flask import g from files.__main__ import app, limiter from os import path @@ -11,24 +12,14 @@ from files.helpers.sanitize import filter_emojis_only @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required def flag_post(pid, v): - post = get_post(pid) - reason = request.values.get("reason", "").strip() - if blackjack and any(i in reason.lower() for i in blackjack.split()): - v.shadowbanned = 'AutoJanny' - if not v.is_banned: v.ban_reason = 'Blackjack' - send_repeatable_notification(CARP_ID, f"reports on {post.permalink}") - - if v.is_muted: - return {"error": "You are forbidden from making reports."}, 400 - + execute_blackjack(v, post, reason, 'flag') + if v.is_muted: abort(400, "You are forbidden from making reports.") reason = reason[:100] - reason = filter_emojis_only(reason) - - if len(reason) > 350: return {"error": "Too long."}, 400 + if len(reason) > 350: abort(400, "Too long.") if reason.startswith('!') and (v.admin_level >= PERMS['POST_COMMENT_MODERATION'] or post.sub and v.mods(post.sub)): post.flair = reason[1:] @@ -58,16 +49,16 @@ def flag_post(pid, v): sub_to = g.db.get(Sub, sub_to) sub_to = sub_to.name if sub_to else None - if sub_from == sub_to: {"error": f"Post is already in /h/{sub_to}"}, 400 + if sub_from == sub_to: abort(400, f"Post is already in /h/{sub_to}") if post.author.exiled_from(sub_to): - return {"error": f"User is exiled from this {HOLE_NAME}!"}, 400 + abort(400, f"User is exiled from this {HOLE_NAME}!") if sub_to in ('furry','vampire','racist','femboy') and not v.client and not post.author.house.lower().startswith(sub_to): if v.id == post.author_id: - return {"error": f"You need to be a member of House {sub.capitalize()} to post in /h/{sub}"}, 403 + abort(403, f"You need to be a member of House {sub_to.capitalize()} to post in /h/{sub_to}") else: - return {"error": f"@{post.author.username} needs to be a member of House {sub.capitalize()} for their post to be moved to /h/{sub}"}, 400 + abort(403, f"@{post.author.username} needs to be a member of House {sub_to.capitalize()} for their post to be moved to /h/{sub_to}") post.sub = sub_to g.db.add(post) @@ -103,8 +94,7 @@ def flag_post(pid, v): return {"message": f"Post moved to /h/{post.sub}"} else: existing = g.db.query(Flag.post_id).filter_by(user_id=v.id, post_id=post.id).one_or_none() - if existing: - return {"error": "You already reported this post!"}, 409 + if existing: abort(409, "You already reported this post!") flag = Flag(post_id=post.id, user_id=v.id, reason=reason) g.db.add(flag) @@ -121,21 +111,14 @@ def flag_comment(cid, v): comment = get_comment(cid) existing = g.db.query(CommentFlag.comment_id).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() - if existing: - return {"error": "You already reported this comment!"}, 409 + if existing: abort(409, "You already reported this comment!") reason = request.values.get("reason", "").strip() - - if blackjack and any(i in reason.lower() for i in blackjack.split()): - v.shadowbanned = 'AutoJanny' - if not v.is_banned: v.ban_reason = 'Blackjack' - send_repeatable_notification(CARP_ID, f"reports on {comment.permalink}") - + execute_blackjack(v, comment, reason, 'flag') reason = reason[:100] - reason = filter_emojis_only(reason) - if len(reason) > 350: return {"error": "Too long."}, 400 + if len(reason) > 350: abort(400, "Too long.") flag = CommentFlag(comment_id=comment.id, user_id=v.id, reason=reason) @@ -148,12 +131,10 @@ def flag_comment(cid, v): @limiter.limit("4/second;100/minute;300/hour;2000/day") @admin_level_required(PERMS['FLAGS_REMOVE']) def remove_report_post(v, pid, uid): - try: pid = int(pid) uid = int(uid) except: abort(400) - report = g.db.query(Flag).filter_by(post_id=pid, user_id=uid).one_or_none() if report: @@ -175,10 +156,10 @@ def remove_report_post(v, pid, uid): @limiter.limit("4/second;100/minute;300/hour;2000/day") @admin_level_required(PERMS['FLAGS_REMOVE']) def remove_report_comment(v, cid, uid): - - cid = int(cid) - uid = int(uid) - + try: + cid = int(cid) + uid = int(uid) + except: abort(400) report = g.db.query(CommentFlag).filter_by(comment_id=cid, user_id=uid).one_or_none() if report: diff --git a/files/routes/search.py b/files/routes/search.py index 24257bbaf..0aa3b6dd5 100644 --- a/files/routes/search.py +++ b/files/routes/search.py @@ -67,15 +67,12 @@ def searchposts(v): Submission.is_banned == False, Submission.private == False) - if v.admin_level < PERMS['USER_SHADOWBAN']: - posts = posts.filter(User.shadowbanned == None) - if 'author' in criteria: posts = posts.filter(Submission.ghost == False) author = get_user(criteria['author'], v=v, include_shadowbanned=False) if author.is_private and author.id != v.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye: - if request.headers.get("Authorization"): - return {"error": f"@{author.username}'s profile is private; You can't use the 'author' syntax on them"}, 400 + if v.client: + abort(403, f"@{author.username}'s profile is private; You can't use the 'author' syntax on them") return render_template("search.html", v=v, query=query, @@ -145,23 +142,21 @@ def searchposts(v): posts = apply_time_filter(t, posts, Submission) - posts = sort_posts(sort, posts) + posts = sort_objects(sort, posts, Submission, + include_shadowbanned=(v and v.can_see_shadowbanned)) total = posts.count() - posts = posts.offset(25 * (page - 1)).limit(26).all() + posts = posts.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all() ids = [x[0] for x in posts] - - - - next_exists = (len(ids) > 25) - ids = ids[:25] + next_exists = (len(ids) > PAGE_SIZE) + ids = ids[:PAGE_SIZE] posts = get_posts(ids, v=v) - if request.headers.get("Authorization"): return {"total":total, "data":[x.json for x in posts]} + if v.client: return {"total":total, "data":[x.json for x in posts]} return render_template("search.html", v=v, @@ -193,7 +188,7 @@ def searchcomments(v): if 'post' in criteria: try: post = int(criteria['post']) - except: return {"error": f"Post with id {post} does not exist."}, 400 + except: abort(404) comments = comments.filter(Comment.parent_submission == post) @@ -201,8 +196,8 @@ def searchcomments(v): comments = comments.filter(Comment.ghost == False) author = get_user(criteria['author'], v=v, include_shadowbanned=False) if author.is_private and author.id != v.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye: - if request.headers.get("Authorization"): - return {"error": f"@{author.username}'s profile is private; You can't use the 'author' syntax on them"}, 400 + if v.client: + abort(403, f"@{author.username}'s profile is private; You can't use the 'author' syntax on them") return render_template("search_comments.html", v=v, query=query, total=0, page=page, comments=[], sort=sort, t=t, next_exists=False, error=f"@{author.username}'s profile is private; You can't use the 'author' syntax on them.") @@ -210,6 +205,7 @@ def searchcomments(v): if 'q' in criteria: tokens = map(lambda x: re.sub(r'[\0():|&*!<>]', '', x), criteria['q']) + tokens = filter(lambda x: len(x) > 0, tokens) tokens = map(lambda x: re.sub(r'\s+', ' <-> ', x), tokens) comments = comments.filter(Comment.body_ts.match( ' & '.join(tokens), @@ -248,20 +244,21 @@ def searchcomments(v): except: abort(400) comments = comments.filter(Comment.created_utc < before) - comments = sort_comments(sort, comments) + comments = sort_objects(sort, comments, Comment, + include_shadowbanned=(v and v.can_see_shadowbanned)) total = comments.count() - comments = comments.offset(25 * (page - 1)).limit(26).all() + comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all() ids = [x[0] for x in comments] - next_exists = (len(ids) > 25) - ids = ids[:25] + next_exists = (len(ids) > PAGE_SIZE) + ids = ids[:PAGE_SIZE] comments = get_comments(ids, v=v) - if request.headers.get("Authorization"): return {"total":total, "data":[x.json for x in comments]} + if v.client: return {"total":total, "data":[x.json for x in comments]} return render_template("search_comments.html", v=v, query=query, total=total, page=page, comments=comments, sort=sort, t=t, next_exists=next_exists, standalone=True) @@ -291,9 +288,9 @@ def searchusers(v): total=users.count() - users = users.offset(25 * (page-1)).limit(26).all() - next_exists=(len(users)>25) - users=users[:25] + users = users.offset(PAGE_SIZE * (page-1)).limit(PAGE_SIZE+1).all() + next_exists=(len(users)>PAGE_SIZE) + users=users[:PAGE_SIZE] - if request.headers.get("Authorization"): return {"data": [x.json for x in users]} + if v.client: return {"data": [x.json for x in users]} return render_template("search_users.html", v=v, query=query, total=total, page=page, users=users, sort=sort, t=t, next_exists=next_exists) diff --git a/files/routes/settings.py b/files/routes/settings.py index c262b53a8..64edac386 100644 --- a/files/routes/settings.py +++ b/files/routes/settings.py @@ -1,7 +1,6 @@ from __future__ import unicode_literals from files.helpers.alerts import * from files.helpers.sanitize import * -from files.helpers.discord import remove_user, set_nick from files.helpers.const import * from files.helpers.regex import * from files.helpers.actions import * @@ -13,7 +12,6 @@ import youtube_dl from .front import frontlist import os from files.helpers.sanitize import filter_emojis_only -from files.helpers.discord import add_role from shutil import copyfile import requests import tldextract @@ -48,10 +46,10 @@ def settings_profile_post(v): updated = True v.slurreplacer = request.values.get("slurreplacer") == 'true' - elif request.values.get("poorcel", v.poor) != v.poor: + elif request.values.get("poor", v.poor) != v.poor: updated = True - v.poorcel = request.values.get("poorcel") == 'true' - session['poor'] = v.poorcel + v.poor = request.values.get("poor") == 'true' + session['poor'] = v.poor elif request.values.get("hidevotedon", v.hidevotedon) != v.hidevotedon: updated = True @@ -240,7 +238,7 @@ def settings_profile_post(v): defaultsortingcomments = request.values.get("defaultsortingcomments") if defaultsortingcomments: - if defaultsortingcomments in {"new", "old", "controversial", "top", "bottom"}: + if defaultsortingcomments in {"new", "old", "controversial", "top", "hot", "bottom"}: v.defaultsortingcomments = defaultsortingcomments updated = True else: abort(400) @@ -263,7 +261,7 @@ def settings_profile_post(v): if theme: if theme in {"4chan","classic","classic_dark","coffee","dark","dramblr","light","midnight","transparent","tron","win98"}: if theme == "transparent" and not v.background: - return {"error": "You need to set a background to use the transparent theme!"}, 400 + abort(400, "You need to set a background to use the transparent theme!") v.theme = theme if theme == "win98": v.themecolor = "30409f" updated = True @@ -276,8 +274,8 @@ def settings_profile_post(v): if v.house: cost = 2000 else: cost = 500 - if v.coins >= cost: v.coins -= cost - elif v.procoins >= cost: v.procoins -= cost + if v.coins >= cost: v.charge_account('coins', cost) + elif v.procoins >= cost: v.charge_account('procoins', cost) else: abort(403) if house == "None": house = '' @@ -294,7 +292,7 @@ def settings_profile_post(v): return {"message": "Your settings have been updated."} else: - return {"error": "You didn't change anything."}, 400 + abort(400, "You didn't change anything.") @app.post("/settings/filters") @@ -348,26 +346,25 @@ def themecolor(v): @auth_required def gumroad(v): if not (v.email and v.is_activated): - return {"error": f"You must have a verified email to verify {patron} status and claim your rewards!"}, 400 + abort(400, f"You must have a verified email to verify {patron} status and claim your rewards!") data = {'access_token': GUMROAD_TOKEN, 'email': v.email} response = requests.get('https://api.gumroad.com/v2/sales', data=data, timeout=5).json()["sales"] - if len(response) == 0: return {"error": "Email not found"}, 404 + if len(response) == 0: abort(404, "Email not found") response = [x for x in response if x['variants_and_quantity']] response = response[0] tier = tiers[response["variants_and_quantity"]] - if v.patron == tier: return {"error": f"{patron} rewards already claimed"}, 400 + if v.patron == tier: abort(400, f"{patron} rewards already claimed") procoins = procoins_li[tier] - procoins_li[v.patron] - if procoins < 0: return {"error": f"{patron} rewards already claimed"}, 400 + if procoins < 0: abort(400, f"{patron} rewards already claimed") existing = g.db.query(User.id).filter(User.email == v.email, User.is_activated == True, User.patron >= tier).first() - if existing: return {"error": f"{patron} rewards already claimed on another account"}, 400 + if existing: abort(400, f"{patron} rewards already claimed on another account") v.patron = tier - if v.discord_id: add_role(v, f"{tier}") v.procoins += procoins send_repeatable_notification(v.id, f"You have received {procoins} Marseybux! You can use them to buy awards in the [shop](/shop).") @@ -513,7 +510,7 @@ def settings_log_out_others(v): @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required def settings_images_profile(v): - if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403 + if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.") file = request.files["profile"] @@ -547,11 +544,9 @@ def settings_images_profile(v): @limiter.limit("1/second;30/minute;200/hour;1000/day") @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required +@feature_required('USERS_PROFILE_BANNER') def settings_images_banner(v): - if not FEATURES['USERS_PROFILE_BANNER']: - abort(403) - - if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403 + if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.") file = request.files["banner"] @@ -586,12 +581,12 @@ def settings_css_get(v): @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required def settings_css(v): - if v.agendaposter: return {"error": "Agendapostered users can't edit css!"}, 400 + if v.agendaposter: abort(400, "Agendapostered users can't edit CSS!") css = request.values.get("css").strip().replace('\\', '').strip()[:4000] if '= PERMS['USER_BLOCKS_VISIBLE']: @@ -684,21 +670,6 @@ def settings_apps(v): return render_template("settings_apps.html", v=v) - -@app.post("/settings/remove_discord") -@limiter.limit("1/second;30/minute;200/hour;1000/day") -@limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') -@auth_required -def settings_remove_discord(v): - - remove_user(v) - - v.discord_id=None - g.db.add(v) - - - return redirect("/settings/profile") - @app.get("/settings/content") @auth_required def settings_content_get(v): @@ -710,7 +681,6 @@ def settings_content_get(v): @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @is_not_permabanned def settings_name_change(v): - new_name=request.values.get("name").strip() if new_name==v.username: @@ -738,15 +708,10 @@ def settings_name_change(v): error=f"Username `{new_name}` is already in use.") v=get_account(v.id) - v.username=new_name v.name_changed_utc=int(time.time()) - - set_nick(v, new_name) - g.db.add(v) - return redirect("/settings/profile") @@ -755,9 +720,9 @@ def settings_name_change(v): @limiter.limit("3/second;10/day") @limiter.limit("3/second;10/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required +@feature_required('USERS_PROFILE_SONG') def settings_song_change_mp3(v): - if not FEATURES['USERS_PROFILE_SONG']: - abort(403) + file = request.files['file'] if file.content_type != 'audio/mpeg': @@ -787,9 +752,9 @@ def settings_song_change_mp3(v): @limiter.limit("3/second;10/day") @limiter.limit("3/second;10/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required +@feature_required('USERS_PROFILE_SONG') def settings_song_change(v): - if not FEATURES['USERS_PROFILE_SONG']: - abort(403) + song=request.values.get("song").strip() @@ -892,9 +857,9 @@ def settings_title_change(v): @limiter.limit("1/second;30/minute;200/hour;1000/day") @limiter.limit("1/second;30/minute;200/hour;1000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required +@feature_required('PRONOUNS') def settings_pronouns_change(v): - if not FEATURES['PRONOUNS']: - abort(403) + pronouns = request.values.get("pronouns").replace("𒐪","").strip() diff --git a/files/routes/static.py b/files/routes/static.py index 4b54bed28..8d27a3d74 100644 --- a/files/routes/static.py +++ b/files/routes/static.py @@ -81,7 +81,7 @@ def sidebar(v): @app.get("/stats") @auth_required def participation_stats(v): - if request.headers.get("Authorization"): return stats_cached() + if v.client: return stats_cached() return render_template("stats.html", v=v, title="Content Statistics", data=stats_cached()) @cache.memoize(timeout=86400) @@ -158,10 +158,10 @@ def log(v): types = types2 if kind: actions = actions.filter_by(kind=kind) - actions = actions.order_by(ModAction.id.desc()).offset(25*(page-1)).limit(26).all() + actions = actions.order_by(ModAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all() - next_exists=len(actions)>25 - actions=actions[:25] + next_exists=len(actions) > PAGE_SIZE + actions=actions[:PAGE_SIZE] admins = [x[0] for x in g.db.query(User.username).filter(User.admin_level >= PERMS['ADMIN_MOP_VISIBLE']).order_by(User.username).all()] return render_template("log.html", v=v, admins=admins, types=types, admin=admin, type=kind, actions=actions, next_exists=next_exists, page=page) @@ -169,7 +169,6 @@ def log(v): @app.get("/log/") @auth_required def log_item(id, v): - try: id = int(id) except: abort(404) @@ -233,7 +232,7 @@ def submit_contact(v): new_comment.top_comment_id = new_comment.id admins = g.db.query(User).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL']) - if SITE == 'watchpeopledie.co': + if SITE == 'watchpeopledie.tv': admins = admins.filter(User.id != AEVANN_ID) for admin in admins.all(): @@ -254,45 +253,34 @@ def archives(path): if request.path.endswith('.css'): resp.headers.add("Content-Type", "text/css") return resp +def static_file(dir:str, path:str, should_cache:bool, is_webp:bool) -> Response: + resp = make_response(send_from_directory(dir, path)) + if should_cache: + resp.headers.remove("Cache-Control") + resp.headers.add("Cache-Control", "public, max-age=3153600") + if is_webp: + resp.headers.remove("Content-Type") + resp.headers.add("Content-Type", "image/webp") + return resp + @app.get('/e/') @limiter.exempt def emoji(emoji): if not emoji.endswith('.webp'): abort(404) - resp = make_response(send_from_directory('assets/images/emojis', emoji)) - resp.headers.remove("Cache-Control") - resp.headers.add("Cache-Control", "public, max-age=3153600") - resp.headers.remove("Content-Type") - resp.headers.add("Content-Type", "image/webp") - return resp + return static_file('assets/images/emojis', emoji, True, True) @app.get('/i/') @limiter.exempt def image(path): - resp = make_response(send_from_directory('assets/images', path)) - if request.path.endswith('.webp') or request.path.endswith('.gif') or request.path.endswith('.ttf') or request.path.endswith('.woff2'): - resp.headers.remove("Cache-Control") - resp.headers.add("Cache-Control", "public, max-age=3153600") - - if request.path.endswith('.webp'): - resp.headers.remove("Content-Type") - resp.headers.add("Content-Type", "image/webp") - - return resp + is_webp = path.endswith('.webp') + return static_file('assets/images', path, is_webp or path.endswith('.gif') or path.endswith('.ttf') or path.endswith('.woff2'), is_webp) @app.get('/assets/') @app.get('/static/assets/') @limiter.exempt def static_service(path): - resp = make_response(send_from_directory('assets', path)) - if request.path.endswith('.webp') or request.path.endswith('.gif') or request.path.endswith('.ttf') or request.path.endswith('.woff2'): - resp.headers.remove("Cache-Control") - resp.headers.add("Cache-Control", "public, max-age=3153600") - - if request.path.endswith('.webp'): - resp.headers.remove("Content-Type") - resp.headers.add("Content-Type", "image/webp") - - return resp + is_webp = path.endswith('.webp') + return static_file('assets', path, is_webp or path.endswith('.gif') or path.endswith('.ttf') or path.endswith('.woff2'), is_webp) ### BEGIN FALLBACK ASSET SERVING # In production, we have nginx serve these locations now. @@ -303,28 +291,17 @@ def static_service(path): @app.get("/static/images/") @limiter.exempt def images(path): - resp = make_response(send_from_directory('/images', path)) - resp.headers.remove("Cache-Control") - resp.headers.add("Cache-Control", "public, max-age=3153600") - resp.headers.remove("Content-Type") - resp.headers.add("Content-Type" ,"image/webp") - return resp + return static_file('/images', path, True, True) @app.get('/videos/') @limiter.exempt def videos(path): - resp = make_response(send_from_directory('/videos', path)) - resp.headers.remove("Cache-Control") - resp.headers.add("Cache-Control", "public, max-age=3153600") - return resp + return static_file('/videos', path, True, False) @app.get('/audio/') @limiter.exempt def audio(path): - resp = make_response(send_from_directory('/audio', path)) - resp.headers.remove("Cache-Control") - resp.headers.add("Cache-Control", "public, max-age=3153600") - return resp + return static_file('/audio', path, True, False) ### END FALLBACK ASSET SERVING @@ -348,18 +325,14 @@ def badge_list(site): @app.get("/badges") @auth_required +@feature_required('BADGES') def badges(v): - if not FEATURES['BADGES']: - abort(404) - badges, counts = badge_list(SITE) return render_template("badges.html", v=v, badges=badges, counts=counts) @app.get("/blocks") @admin_level_required(PERMS['USER_BLOCKS_VISIBLE']) def blocks(v): - - blocks=g.db.query(UserBlock).all() users = [] targets = [] @@ -375,14 +348,12 @@ def blocks(v): @app.get("/banned") @auth_required def banned(v): - users = g.db.query(User).filter(User.is_banned > 0, User.unban_utc == 0).all() return render_template("banned.html", v=v, users=users) @app.get("/formatting") @auth_required def formatting(v): - return render_template("formatting.html", v=v) @app.get("/service-worker.js") @@ -393,7 +364,6 @@ def serviceworker(): @app.get("/settings/security") @auth_required def settings_security(v): - return render_template("settings_security.html", v=v, mfa_secret=pyotp.random_base32() if not v.mfa_secret else None @@ -427,11 +397,11 @@ def transfers(v): try: page = max(int(request.values.get("page", 1)), 1) except: page = 1 - comments = comments.offset(25 * (page - 1)).limit(26).all() - next_exists = len(comments) > 25 - comments = comments[:25] + comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all() + next_exists = len(comments) > PAGE_SIZE + comments = comments[:PAGE_SIZE] - if request.headers.get("Authorization"): + if v.client: return {"data": [x.json for x in comments]} else: return render_template("transfers.html", v=v, page=page, comments=comments, standalone=True, next_exists=next_exists) @@ -443,6 +413,7 @@ if not os.path.exists(f'files/templates/donate_{SITE_NAME}.html'): @app.get('/donate') @auth_required def donate(v): + if v.truecoins < 1000: abort(404) return render_template(f'donate_{SITE_NAME}.html', v=v) @@ -463,16 +434,16 @@ if SITE == 'pcmemes.net': y = live_regex.search(text) count = y.group(3) - if count == '1 παρακολουθεί τώρα': + if count == '1 watching now': count = "1" - if 'περιμένει' in count: + if 'waiting' in count: if live != '': return process_streamer(id, '') else: return None - count = int(count.replace('.', '')) + count = int(count.replace(',', '')) t = live_thumb_regex.search(text) @@ -572,13 +543,13 @@ if SITE == 'pcmemes.net': else: text = requests.get(link, cookies={'CONSENT': 'YES+1'}, timeout=5).text try: id = id_regex.search(text).group(1) - except: return {"error": "Invalid ID"} + except: abort(400, "Invalid ID") live = cache.get('live') or [] offline = cache.get('offline') or [] if not id or len(id) != 24: - return {"error": "Invalid ID"} + abort(400, "Invalid ID") existing = g.db.get(Streamer, id) if not existing: @@ -586,7 +557,7 @@ if SITE == 'pcmemes.net': g.db.add(streamer) g.db.flush() if v.id != KIPPY_ID: - send_repeatable_notification(KIPPY_ID, f"@{v.username} has added a [new YouTube channel](https://www.youtube.com/channel/{streamer.id})") + send_repeatable_notification(KIPPY_ID, f"@{v.username} (Admin) has added a [new YouTube channel](https://www.youtube.com/channel/{streamer.id})") processed = process_streamer(id) if processed: @@ -609,7 +580,7 @@ if SITE == 'pcmemes.net': streamer = g.db.get(Streamer, id) if streamer: if v.id != KIPPY_ID: - send_repeatable_notification(KIPPY_ID, f"@{v.username} has removed a [YouTube channel](https://www.youtube.com/channel/{streamer.id})") + send_repeatable_notification(KIPPY_ID, f"@{v.username} (Admin) has removed a [YouTube channel](https://www.youtube.com/channel/{streamer.id})") g.db.delete(streamer) live = cache.get('live') or [] diff --git a/files/routes/subs.py b/files/routes/subs.py index 1f9b80bb2..15ed3dbf6 100644 --- a/files/routes/subs.py +++ b/files/routes/subs.py @@ -95,7 +95,7 @@ def unexile(v, sub, uid): ) g.db.add(ma) - if request.headers.get("Authorization") or request.headers.get("xhr"): + if g.is_api_or_xhr: return {"message": f"@{u.username} has been unexiled from /h/{sub} successfully!"} @@ -207,7 +207,7 @@ def sub_exilees(v, sub): def sub_blockers(v, sub): sub = get_sub_by_name(sub) if sub.name == "chudrama" and not v.can_see_chudrama: abort(403) - users = g.db.query(User).join(SubBlock) \ + users = g.db.query(User, SubBlock).join(SubBlock) \ .filter_by(sub=sub.name) \ .order_by(nullslast(SubBlock.created_utc.desc()), User.username).all() @@ -220,7 +220,7 @@ def sub_blockers(v, sub): def sub_followers(v, sub): sub = get_sub_by_name(sub) if sub.name == "chudrama" and not v.can_see_chudrama: abort(403) - users = g.db.query(User).join(SubSubscription) \ + users = g.db.query(User, SubSubscription).join(SubSubscription) \ .filter_by(sub=sub.name) \ .order_by(nullslast(SubSubscription.created_utc.desc()), User.username).all() @@ -245,7 +245,7 @@ def add_mod(v, sub): user = get_user(user, v=v, include_shadowbanned=False) if sub in ('furry','vampire','racist','femboy') and not v.client and not user.house.lower().startswith(sub): - return {"error": f"@{user.username} needs to be a member of House {sub.capitalize()} to be added as a mod there!"}, 400 + abort(403, f"@{user.username} needs to be a member of House {sub.capitalize()} to be added as a mod there!") existing = g.db.query(Mod).filter_by(user_id=user.id, sub=sub).one_or_none() @@ -332,7 +332,7 @@ def create_sub2(v): if v.coins < HOLE_COST: return render_template("sub/create_hole.html", v=v, cost=HOLE_COST, error="You don't have enough coins!"), 403 - v.coins -= HOLE_COST + v.charge_account('coins', HOLE_COST) g.db.add(v) if v.shadowbanned: return {"error": "Internal Server Error"}, 500 @@ -470,7 +470,7 @@ def get_sub_css(sub): @limiter.limit("1/second;10/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @is_not_permabanned def sub_banner(v, sub): - if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403 + if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.") sub = get_sub_by_name(sub) if not v.mods(sub.name): abort(403) @@ -480,7 +480,7 @@ def sub_banner(v, sub): name = f'/images/{time.time()}'.replace('.','') + '.webp' file.save(name) - bannerurl = process_image(name, patron=v.patron) + bannerurl = process_image(name, patron=v.patron, resize=1200) if bannerurl: if sub.bannerurl and '/images/' in sub.bannerurl: @@ -503,7 +503,7 @@ def sub_banner(v, sub): @limiter.limit("1/second;10/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @is_not_permabanned def sub_sidebar(v, sub): - if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403 + if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.") sub = get_sub_by_name(sub) if not v.mods(sub.name): abort(403) @@ -512,7 +512,7 @@ def sub_sidebar(v, sub): file = request.files["sidebar"] name = f'/images/{time.time()}'.replace('.','') + '.webp' file.save(name) - sidebarurl = process_image(name, patron=v.patron) + sidebarurl = process_image(name, patron=v.patron, resize=400) if sidebarurl: if sub.sidebarurl and '/images/' in sub.sidebarurl: @@ -535,7 +535,7 @@ def sub_sidebar(v, sub): @limiter.limit("1/second;10/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @is_not_permabanned def sub_marsey(v, sub): - if request.headers.get("cf-ipcountry") == "T1": return {"error":"Image uploads are not allowed through TOR."}, 403 + if request.headers.get("cf-ipcountry") == "T1": abort(403, "Image uploads are not allowed through TOR.") sub = get_sub_by_name(sub) if not v.mods(sub.name): abort(403) @@ -544,7 +544,7 @@ def sub_marsey(v, sub): file = request.files["marsey"] name = f'/images/{time.time()}'.replace('.','') + '.webp' file.save(name) - marseyurl = process_image(name, patron=v.patron) + marseyurl = process_image(name, patron=v.patron, resize=200) if marseyurl: if sub.marseyurl and '/images/' in sub.marseyurl: @@ -653,9 +653,9 @@ def sub_stealth(v, sub): @app.post("/mod_pin/") @is_not_permabanned +@feature_required('PINS') def mod_pin(cid, v): - if not FEATURES['PINS']: - abort(403) + comment = get_comment(cid, v=v) if not comment.stickied: @@ -737,7 +737,7 @@ def hole_log(v, sub): types = types2 if kind: actions = actions.filter_by(kind=kind) - actions = actions.order_by(SubAction.id.desc()).offset(25*(page-1)).limit(26).all() + actions = actions.order_by(SubAction.id.desc()).offset(PAGE_SIZE*(page-1)).limit(PAGE_SIZE+1).all() next_exists=len(actions)>25 actions=actions[:25] diff --git a/files/routes/users.py b/files/routes/users.py index a8cd94fb5..c2d671645 100644 --- a/files/routes/users.py +++ b/files/routes/users.py @@ -2,12 +2,14 @@ import qrcode import io import time import math +from files.classes.leaderboard import Leaderboard from files.classes.views import * from files.classes.transactions import * from files.helpers.alerts import * from files.helpers.sanitize import * from files.helpers.const import * from files.helpers.sorting_and_time import * +from files.helpers.actions import * from files.mail import * from flask import * from files.__main__ import app, limiter, db_session @@ -26,17 +28,25 @@ def upvoters_downvoters(v, username, uid, cls, vote_cls, vote_dir, template, sta if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403) if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403) id = u.id - uid = int(uid) + try: + uid = int(uid) + except: + abort(404) page = max(1, int(request.values.get("page", 1))) - listing = g.db.query(cls).join(vote_cls).filter(cls.ghost == False, cls.is_banned == False, cls.deleted_utc == 0, vote_cls.vote_type==vote_dir, cls.author_id==id, vote_cls.user_id==uid).order_by(cls.created_utc.desc()).offset(25 * (page - 1)).limit(26).all() + listing = g.db.query(cls).join(vote_cls).filter(cls.ghost == False, cls.is_banned == False, cls.deleted_utc == 0, vote_cls.vote_type==vote_dir, cls.author_id==id, vote_cls.user_id==uid).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all() listing = [p.id for p in listing] - next_exists = len(listing) > 25 - listing = listing[:25] + next_exists = len(listing) > PAGE_SIZE + listing = listing[:PAGE_SIZE] - listing = get_posts(listing, v=v) + if cls == Submission: + listing = get_posts(listing, v=v) + elif cls == Comment: + listing = get_comments(listing, v=v) + else: + listing = [] return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone) @@ -68,17 +78,25 @@ def upvoting_downvoting(v, username, uid, cls, vote_cls, vote_dir, template, sta if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): abort(403) if not (v.id == u.id or v.admin_level >= PERMS['USER_VOTERS_VISIBLE']): abort(403) id = u.id - uid = int(uid) + try: + uid = int(uid) + except: + abort(404) page = max(1, int(request.values.get("page", 1))) - listing = g.db.query(cls).join(vote_cls).filter(cls.ghost == False, cls.is_banned == False, cls.deleted_utc == 0, vote_cls.vote_type==vote_dir, vote_cls.user_id==id, cls.author_id==uid).order_by(cls.created_utc.desc()).offset(25 * (page - 1)).limit(26).all() + listing = g.db.query(cls).join(vote_cls).filter(cls.ghost == False, cls.is_banned == False, cls.deleted_utc == 0, vote_cls.vote_type==vote_dir, vote_cls.user_id==id, cls.author_id==uid).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all() listing = [p.id for p in listing] - next_exists = len(listing) > 25 - listing = listing[:25] - - listing = get_posts(listing, v=v) + next_exists = len(listing) > PAGE_SIZE + listing = listing[:PAGE_SIZE] + + if cls == Submission: + listing = get_posts(listing, v=v) + elif cls == Comment: + listing = get_comments(listing, v=v) + else: + listing = [] return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone) @@ -119,12 +137,17 @@ def user_voted(v, username, cls, vote_cls, vote_dir, template, standalone): cls.author_id != u.id, vote_cls.user_id == u.id, vote_cls.vote_type == vote_dir - ).order_by(cls.created_utc.desc()).offset(25 * (page - 1)).limit(26).all() + ).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all() listing = [p.id for p in listing] - next_exists = len(listing) > 25 - listing = listing[:25] - listing = get_posts(listing, v=v) + next_exists = len(listing) > PAGE_SIZE + listing = listing[:PAGE_SIZE] + if cls == Submission: + listing = get_posts(listing, v=v) + elif cls == Comment: + listing = get_comments(listing, v=v) + else: + listing = [] return render_template(template, next_exists=next_exists, listing=listing, page=page, v=v, standalone=standalone) @@ -137,29 +160,20 @@ def user_upvoted_posts(v, username): @app.get("/@/upvoted/comments") @auth_required def user_upvoted_comments(v, username): - return user_voted(v, username, Comment, CommentVote, -1, "voted_comments.html", True) - - -@app.get("/poorcels") -@auth_required -def poorcels(v): - users = g.db.query(User).filter_by(poorcel=True).all() - - return render_template("poorcels.html", v=v, users=users) + return user_voted(v, username, Comment, CommentVote, 1, "voted_comments.html", True) @app.get("/grassed") @auth_required def grassed(v): users = g.db.query(User).filter(User.ban_reason.like('grass award used by @%')).all() - return render_template("grassed.html", v=v, users=users) -@app.get("/agendaposters") +@app.get("/chuds") @auth_required -def agendaposters(v): +def chuds(v): users = g.db.query(User).filter(User.agendaposter > 0).order_by(User.username).all() - return render_template("agendaposters.html", v=v, users=users) + return render_template("chuds.html", v=v, users=users) def all_upvoters_downvoters(v, username, vote_dir, is_who_simps_hates): vote_str = 'votes' @@ -204,7 +218,7 @@ def all_upvoters_downvoters(v, username, vote_dir, is_who_simps_hates): name2 = f'Who @{username} {simps_haters}' if is_who_simps_hates else f'@{username} biggest {simps_haters}' - return render_template("voters.html", v=v, users=users[:25], pos=pos, name=vote_name, name2=name2, total=total) + return render_template("voters.html", v=v, users=users[:PAGE_SIZE], pos=pos, name=vote_name, name2=name2, total=total) @app.get("/@/upvoters") @auth_required @@ -230,9 +244,9 @@ def downvoting(v, username): @limiter.limit("1/second;5/day") @limiter.limit("1/second;5/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required +@feature_required('USERS_SUICIDE') def suicide(v, username): - if not FEATURES['USERS_SUICIDE']: - abort(403) + user = get_user(username) suicide = f"Hi there,\n\nA [concerned user](/id/{v.id}) reached out to us about you.\n\nWhen you're in the middle of something painful, it may feel like you don't have a lot of options. But whatever you're going through, you deserve help and there are people who are here for you.\n\nThere are resources available in your area that are free, confidential, and available 24/7:\n\n- Call, Text, or Chat with Canada's [Crisis Services Canada](https://www.crisisservicescanada.ca/en/)\n- Call, Email, or Visit the UK's [Samaritans](https://www.samaritans.org/)\n- Text CHAT to America's [Crisis Text Line](https://www.crisistextline.org/) at 741741.\nIf you don't see a resource in your area above, the moderators keep a comprehensive list of resources and hotlines for people organized by location. Find Someone Now\n\nIf you think you may be depressed or struggling in another way, don't ignore it or brush it aside. Take yourself and your feelings seriously, and reach out to someone.\n\nIt may not feel like it, but you have options. There are people available to listen to you, and ways to move forward.\n\nYour fellow users care about you and there are people who want to help." @@ -259,14 +273,14 @@ def transfer_coins(v, username): amount = int(amount) if amount.isdigit() else None reason = request.values.get("reason", "").strip() - if amount is None or amount <= 0: return {"error": "Invalid amount of coins."}, 400 - if v.coins < amount: return {"error": "You don't have enough coins."}, 400 - if amount < 100: return {"error": "You have to gift at least 100 coins."}, 400 + if amount is None or amount <= 0: abort(400, "Invalid amount of coins.") + if v.coins < amount: abort(400, "You don't have enough coins.") + if amount < 100: abort(400, "You have to gift at least 100 coins.") if not v.patron and not receiver.patron and not v.alts_patron and not receiver.alts_patron: tax = math.ceil(amount*0.03) else: tax = 0 - v.coins -= amount + v.charge_account('coins', amount) if not v.shadowbanned: receiver.coins += amount - tax @@ -275,7 +289,7 @@ def transfer_coins(v, username): notif_text = f":marseycapitalistmanlet: @{v.username} has gifted you {amount-tax} coins!" if reason: - if len(reason) > TRANSFER_MESSAGE_LENGTH_LIMIT: return {"error": f"Reason is too long, max {TRANSFER_MESSAGE_LENGTH_LIMIT} characters"},400 + if len(reason) > TRANSFER_MESSAGE_LENGTH_LIMIT: abort(400, f"Reason is too long, max {TRANSFER_MESSAGE_LENGTH_LIMIT} characters") notif_text += f"\n\n> {reason}" log_message += f"\n\n> {reason}" @@ -286,8 +300,7 @@ def transfer_coins(v, username): g.db.add(v) return {"message": f"{amount-tax} coins have been transferred to @{receiver.username}"}, 200 - - return {"message": "You can't transfer coins to yourself!"}, 400 + abort(400, "You can't transfer coins to yourself!") @app.post("/@/transfer_bux") @@ -302,11 +315,11 @@ def transfer_bux(v, username): amount = int(amount) if amount.isdigit() else None reason = request.values.get("reason", "").strip() - if not amount or amount < 0: return {"error": "Invalid amount of marseybux."}, 400 - if v.procoins < amount: return {"error": "You don't have enough marseybux"}, 400 - if amount < 100: return {"error": "You have to gift at least 100 marseybux."}, 400 + if not amount or amount < 0: abort(400, "Invalid amount of marseybux.") + if v.procoins < amount: abort(400, "You don't have enough marseybux") + if amount < 100: abort(400, "You have to gift at least 100 marseybux.") - v.procoins -= amount + v.charge_account('procoins', amount) if not v.shadowbanned: receiver.procoins += amount @@ -315,7 +328,7 @@ def transfer_bux(v, username): notif_text = f":marseycapitalistmanlet: @{v.username} has gifted you {amount} marseybux!" if reason: - if len(reason) > 200: return {"error": "Reason is too long, max 200 characters"},400 + if len(reason) > 200: abort(400, "Reason is too long, max 200 characters") notif_text += f"\n\n> {reason}" log_message += f"\n\n> {reason}" @@ -326,107 +339,33 @@ def transfer_bux(v, username): g.db.add(v) return {"message": f"{amount} marseybux have been transferred to @{receiver.username}"}, 200 - return {"message": "You can't transfer marseybux to yourself!"}, 400 + abort(400, "You can't transfer marseybux to yourslef!") @app.get("/leaderboard") @auth_required def leaderboard(v): - users = g.db.query(User) - users1 = users.order_by(User.coins.desc()).limit(25).all() - if v in users1: - pos1 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.coins.desc()).label("rank")).subquery() - pos1 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] + coins = Leaderboard("Coins", "coins", "coins", "Coins", None, Leaderboard.get_simple_lb, User.coins, v, lambda u:u.coins, g.db, users) + subscribers = Leaderboard("Followers", "followers", "followers", "Followers", None, Leaderboard.get_simple_lb, User.stored_subscriber_count, v, lambda u:u.stored_subscriber_count, g.db, users) + posts = Leaderboard("Posts", "post count", "posts", "Posts", "", Leaderboard.get_simple_lb, User.post_count, v, lambda u:u.post_count, g.db, users) + comments = Leaderboard("Comments", "comment count", "comments", "Comments", "comments", Leaderboard.get_simple_lb, User.comment_count, v, lambda u:u.comment_count, g.db, users) + received_awards = Leaderboard("Awards", "received awards", "awards", "Awards", None, Leaderboard.get_simple_lb, User.received_award_count, v, lambda u:u.received_award_count, g.db, users) + coins_spent = Leaderboard("Spent in shop", "coins spent in shop", "spent", "Coins", None, Leaderboard.get_simple_lb, User.coins_spent, v, lambda u:u.coins_spent, g.db, users) + truecoins = Leaderboard("Truescore", "truescore", "truescore", "Truescore", None, Leaderboard.get_simple_lb, User.truecoins, v, lambda u:u.truecoins, g.db, users) - users2 = users.order_by(User.stored_subscriber_count.desc()).limit(25).all() - if v in users2: - pos2 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.stored_subscriber_count.desc()).label("rank")).subquery() - pos2 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] + badges = Leaderboard("Badges", "badges", "badges", "Badges", None, Leaderboard.get_badge_marsey_lb, Badge.user_id, v, None, g.db, None) + marseys = Leaderboard("Marseys", "Marseys made", "marseys", "Marseys", None, Leaderboard.get_badge_marsey_lb, Marsey.author_id, v, None, g.db, None) if SITE_NAME == 'rDrama' else None - users3 = users.order_by(User.post_count.desc()).limit(25).all() - if v in users3: - pos3 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.post_count.desc()).label("rank")).subquery() - pos3 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] + blocks = Leaderboard("Blocked", "most blocked", "blocked", "Blocked By", "blockers", Leaderboard.get_blockers_lb, UserBlock.target_id, v, None, g.db, None) - users4 = users.order_by(User.comment_count.desc()).limit(25).all() - if v in users4: - pos4 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.comment_count.desc()).label("rank")).subquery() - pos4 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] + owned_hats = Leaderboard("Owned hats", "owned hats", "owned-hats", "Owned Hats", None, Leaderboard.get_hat_lb, User.owned_hats, v, None, g.db, None) + designed_hats = Leaderboard("Designed hats", "designed hats", "designed-hats", "Designed Hats", None, Leaderboard.get_hat_lb, User.designed_hats, v, None, g.db, None) - users5 = users.order_by(User.received_award_count.desc()).limit(25).all() - if v in users5: - pos5 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.received_award_count.desc()).label("rank")).subquery() - pos5 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] + leaderboards = [coins, coins_spent, truecoins, subscribers, posts, comments, received_awards, badges, marseys, blocks, owned_hats, designed_hats] - users7 = users.order_by(User.coins_spent.desc()).limit(25).all() - if v in users7: - pos7 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.coins_spent.desc()).label("rank")).subquery() - pos7 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] - - - - users10 = users.order_by(User.truecoins.desc()).limit(25).all() - if v in users10: - pos10 = None - else: - sq = g.db.query(User.id, func.rank().over(order_by=User.truecoins.desc()).label("rank")).subquery() - pos10 = g.db.query(sq.c.id, sq.c.rank).filter(sq.c.id == v.id).limit(1).one()[1] - - sq = g.db.query(Badge.user_id, func.count(Badge.user_id).label("count"), func.rank().over(order_by=func.count(Badge.user_id).desc()).label("rank")).group_by(Badge.user_id).subquery() - users11 = g.db.query(User, sq.c.count).join(sq, User.id==sq.c.user_id).order_by(sq.c.count.desc()) - pos11 = g.db.query(User.id, sq.c.rank, sq.c.count).join(sq, User.id==sq.c.user_id).filter(User.id == v.id).one_or_none() - if pos11: pos11 = (pos11[1],pos11[2]) - else: pos11 = (users11.count()+1, 0) - users11 = users11.limit(25).all() - - if SITE_NAME == 'rDrama': - sq = g.db.query(Marsey.author_id, func.count(Marsey.author_id).label("count"), func.rank().over(order_by=func.count(Marsey.author_id).desc()).label("rank")).filter(Marsey.submitter_id==None).group_by(Marsey.author_id).subquery() - users12 = g.db.query(User, sq.c.count).join(sq, User.id==sq.c.author_id).order_by(sq.c.count.desc()) - pos12 = g.db.query(User.id, sq.c.rank, sq.c.count).join(sq, User.id==sq.c.author_id).filter(User.id == v.id).one_or_none() - if pos12: pos12 = (pos12[1],pos12[2]) - else: pos12 = (users12.count()+1, 0) - users12 = users12.limit(25).all() - else: - users12 = None - pos12 = None - - sq = g.db.query(UserBlock.target_id, func.count(UserBlock.target_id).label("count")).group_by(UserBlock.target_id).subquery() - users16 = g.db.query(User, sq.c.count).join(User, User.id == sq.c.target_id).order_by(sq.c.count.desc()) - - sq = g.db.query(UserBlock.target_id, func.count(UserBlock.target_id).label("count"), func.rank().over(order_by=func.count(UserBlock.target_id).desc()).label("rank")).group_by(UserBlock.target_id).subquery() - pos16 = g.db.query(sq.c.rank, sq.c.count).join(User, User.id == sq.c.target_id).filter(sq.c.target_id == v.id).limit(1).one_or_none() - if not pos16: pos16 = (users16.count()+1, 0) - users16 = users16.limit(25).all() - - users17 = g.db.query(User, func.count(User.owned_hats)).join(User.owned_hats).group_by(User).order_by(func.count(User.owned_hats).desc()) - sq = g.db.query(User.id, func.count(User.owned_hats).label("count"), func.rank().over(order_by=func.count(User.owned_hats).desc()).label("rank")).join(User.owned_hats).group_by(User).subquery() - pos17 = g.db.query(sq.c.rank, sq.c.count).filter(sq.c.id == v.id).limit(1).one_or_none() - if not pos17: pos17 = (users17.count()+1, 0) - users17 = users17.limit(25).all() - - users18 = g.db.query(User, func.count(User.designed_hats)).join(User.designed_hats).group_by(User).order_by(func.count(User.designed_hats).desc()) - sq = g.db.query(User.id, func.count(User.designed_hats).label("count"), func.rank().over(order_by=func.count(User.designed_hats).desc()).label("rank")).join(User.designed_hats).group_by(User).subquery() - pos18 = g.db.query(sq.c.rank, sq.c.count).filter(sq.c.id == v.id).limit(1).one_or_none() - if not pos18: pos18 = (users18.count()+1, 0) - users18 = users18.limit(25).all() - - return render_template("leaderboard.html", v=v, users1=users1, pos1=pos1, users2=users2, pos2=pos2, - users3=users3, pos3=pos3, users4=users4, pos4=pos4, users5=users5, pos5=pos5, - users7=users7, pos7=pos7, users10=users10, pos10=pos10, users11=users11, pos11=pos11, users12=users12, pos12=pos12, users16=users16, pos16=pos16, users17=users17, pos17=pos17, users18=users18, pos18=pos18) + return render_template("leaderboard.html", v=v, leaderboards=leaderboards) @app.get("//css") def get_css(id): @@ -495,26 +434,26 @@ def message2(v, username): user = get_user(username, v=v, include_blocks=True, include_shadowbanned=False) if hasattr(user, 'is_blocking') and user.is_blocking: - return {"error": "You're blocking this user."}, 403 + abort(403, "You're blocking this user.") if v.admin_level <= PERMS['MESSAGE_BLOCKED_USERS'] and hasattr(user, 'is_blocked') and user.is_blocked: - return {"error": "This user is blocking you."}, 403 + abort(403, "This user is blocking you.") - message = request.values.get("message", "").strip()[:10000].strip() - - if not message: return {"error": "Message is empty!"}, 400 - - if 'linkedin.com' in message: return {"error": "This domain 'linkedin.com' is banned."}, 403 + message = sanitize_raw_body(request.values.get("message"), False) + if not message: abort(400, "Message is empty!") + if 'linkedin.com' in message: abort(403, "This domain 'linkedin.com' is banned.") + if v.id != AEVANN_ID and ('discord.gg' in message or 'discord.com' in message or 'discordapp.com' in message): + abort(403, "Stop grooming!") body_html = sanitize(message) - if not (SITE == 'rdrama.net' and user.id == 12732): + if not (SITE == 'rdrama.net' and user.id == BLACKJACKBTZ_ID): existing = g.db.query(Comment.id).filter(Comment.author_id == v.id, Comment.sentto == user.id, Comment.body_html == body_html, ).first() - if existing: return {"error": "Message already exists."}, 403 + if existing: abort(403, "Message already exists.") c = Comment(author_id=v.id, parent_submission=None, @@ -523,19 +462,8 @@ def message2(v, username): body_html=body_html ) g.db.add(c) - g.db.flush() - - if blackjack and any(i in c.body_html.lower() for i in blackjack.split()): - v.shadowbanned = 'AutoJanny' - if not v.is_banned: v.ban_reason = 'Blackjack' - g.db.add(v) - notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=CARP_ID).one_or_none() - if not notif: - notif = Notification(comment_id=c.id, user_id=CARP_ID) - g.db.add(notif) - g.db.flush() - + execute_blackjack(v, c, c.body_html, 'message') c.top_comment_id = c.id if user.id not in bots: @@ -565,21 +493,22 @@ def message2(v, username): @limiter.limit("1/second;6/minute;50/hour;200/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @auth_required def messagereply(v): - body = request.values.get("body", "").strip().replace('‎','') - body = body.replace('\r\n', '\n')[:COMMENT_BODY_LENGTH_LIMIT] + body = sanitize_raw_body(request.values.get("body"), False) + if not body and not request.files.get("file"): abort(400, "Message is empty!") - if not body and not request.files.get("file"): return {"error": "Message is empty!"}, 400 + if 'linkedin.com' in body: abort(403, "This domain 'linkedin.com' is banned") - if 'linkedin.com' in body: return {"error": "this domain 'linkedin.com' is banned"}, 400 + if v.id != AEVANN_ID and ('discord.gg' in body or 'discord.com' in body or 'discordapp.com' in body): + abort(403, "Stop grooming!") - id = int(request.values.get("parent_id")) + id = request.values.get("parent_id") parent = get_comment(id, v=v) user_id = parent.author.id if v.is_suspended_permanently and parent.sentto != 2: - return {"error": "You are permabanned and may not reply to messages."}, 400 + abort(400, "You are permabanned and may not reply to messages.") elif v.is_muted and parent.sentto == 2: - return {"error": "You are forbidden from replying to modmail."}, 400 + abort(400, "You are forbidden from replying to modmail.") if parent.sentto == 2: user_id = None elif v.id == user_id: user_id = parent.sentto @@ -601,16 +530,7 @@ def messagereply(v): ) g.db.add(c) g.db.flush() - - if blackjack and any(i in c.body_html.lower() for i in blackjack.split()): - v.shadowbanned = 'AutoJanny' - if not v.is_banned: v.ban_reason = 'Blackjack' - g.db.add(v) - notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=CARP_ID).one_or_none() - if not notif: - notif = Notification(comment_id=c.id, user_id=CARP_ID) - g.db.add(notif) - g.db.flush() + execute_blackjack(v, c, c.body_html, 'message') if user_id and user_id not in (v.id, 2, bots): notif = g.db.query(Notification).filter_by(comment_id=c.id, user_id=user_id).one_or_none() @@ -634,7 +554,7 @@ def messagereply(v): if c.top_comment.sentto == 2: admins = g.db.query(User.id).filter(User.admin_level >= PERMS['NOTIFICATIONS_MODMAIL'], User.id != v.id) - if SITE == 'watchpeopledie.co': + if SITE == 'watchpeopledie.tv': admins = admins.filter(User.id != AEVANN_ID) admins = [x[0] for x in admins.all()] @@ -646,7 +566,7 @@ def messagereply(v): notif = Notification(comment_id=c.id, user_id=admin) g.db.add(notif) - ids = [c.top_comment.id] + [x.id for x in c.top_comment.replies(None)] + ids = [c.top_comment.id] + [x.id for x in c.top_comment.replies(sort="old", v=v)] notifications = g.db.query(Notification).filter(Notification.comment_id.in_(ids), Notification.user_id.in_(admins)) for n in notifications: g.db.delete(n) @@ -709,7 +629,7 @@ def redditor_moment_redirect(username, v): @auth_required def followers(username, v): u = get_user(username, v=v, include_shadowbanned=False) - if u.id == CARP_ID and SITE == 'watchpeopledie.co': abort(403) + if u.id == CARP_ID and SITE == 'watchpeopledie.tv': abort(403) if not (v.id == u.id or v.admin_level >= PERMS['USER_FOLLOWS_VISIBLE']): abort(403) @@ -767,12 +687,6 @@ def u_username(username, v=None): if username != u.username: return redirect(SITE_FULL + request.full_path.replace(username, u.username)) - if u.reserved: - if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"): - return {"error": f"This username is reserved for: {u.reserved}"}, 418 - - return render_template("userpage_reserved.html", u=u, v=v) - if v and v.id not in (u.id, DAD_ID) and u.viewers_recorded: g.db.flush() view = g.db.query(ViewerRelationship).filter_by(viewer_id=v.id, user_id=u.id).one_or_none() @@ -785,15 +699,15 @@ def u_username(username, v=None): if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): - if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"): - return {"error": "This userpage is private"}, 403 + if g.is_api_or_xhr or request.path.endswith(".json"): + abort(403, "This userpage is private") return render_template("userpage_private.html", u=u, v=v) if v and hasattr(u, 'is_blocking') and u.is_blocking: - if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"): - return {"error": f"You are blocking @{u.username}."}, 403 + if g.is_api_or_xhr or request.path.endswith(".json"): + abort(403, f"You are blocking @{u.username}.") return render_template("userpage_blocking.html", u=u, v=v) @@ -805,12 +719,12 @@ def u_username(username, v=None): ids = u.userpagelisting(site=SITE, v=v, page=page, sort=sort, t=t) - next_exists = (len(ids) > 25) - ids = ids[:25] + next_exists = (len(ids) > PAGE_SIZE) + ids = ids[:PAGE_SIZE] if page == 1: sticky = [] - sticky = g.db.query(Submission).filter_by(is_pinned=True, author_id=u.id).all() + sticky = g.db.query(Submission).filter_by(is_pinned=True, author_id=u.id, is_banned=False).all() if sticky: for p in sticky: ids = [p.id] + ids @@ -818,7 +732,7 @@ def u_username(username, v=None): listing = get_posts(ids, v=v) if u.unban_utc: - if request.headers.get("Authorization") or request.path.endswith(".json"): + if (v and v.client) or request.path.endswith(".json"): return {"data": [x.json for x in listing]} return render_template("userpage.html", @@ -832,7 +746,7 @@ def u_username(username, v=None): next_exists=next_exists, is_following=is_following) - if request.headers.get("Authorization") or request.path.endswith(".json"): + if (v and v.client) or request.path.endswith(".json"): return {"data": [x.json for x in listing]} return render_template("userpage.html", @@ -864,20 +778,14 @@ def u_username_comments(username, v=None): u = user - if u.reserved: - if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"): - return {"error": f"This username is reserved for: {u.reserved}"}, 418 - return render_template("userpage_reserved.html", u=u, v=v) - - if u.is_private and (not v or (v.id != u.id and v.admin_level < PERMS['VIEW_PRIVATE_PROFILES'] and not v.eye)): - if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"): - return {"error": "This userpage is private"}, 403 + if g.is_api_or_xhr or request.path.endswith(".json"): + abort(403, "This userpage is private") return render_template("userpage_private.html", u=u, v=v) if v and hasattr(u, 'is_blocking') and u.is_blocking: - if request.headers.get("Authorization") or request.headers.get("xhr") or request.path.endswith(".json"): - return {"error": f"You are blocking @{u.username}."}, 403 + if g.is_api_or_xhr or request.path.endswith(".json"): + abort(403, f"You are blocking @{u.username}.") return render_template("userpage_blocking.html", u=u, v=v) try: page = max(int(request.values.get("page", "1")), 1) @@ -899,23 +807,23 @@ def u_username_comments(username, v=None): comments = comments.filter( Comment.is_banned == False, Comment.ghost == False, - comment_post_author.shadowbanned == None, Comment.deleted_utc == 0 ) comments = apply_time_filter(t, comments, Comment) - comments = sort_comments(sort, comments) + comments = sort_objects(sort, comments, Comment, + include_shadowbanned=(v and v.can_see_shadowbanned)) - comments = comments.offset(25 * (page - 1)).limit(26).all() + comments = comments.offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE+1).all() ids = [x.id for x in comments] - next_exists = (len(ids) > 25) - ids = ids[:25] + next_exists = (len(ids) > PAGE_SIZE) + ids = ids[:PAGE_SIZE] listing = get_comments(ids, v=v) - if request.headers.get("Authorization") or request.path.endswith(".json"): + if (v and v.client) or request.path.endswith(".json"): return {"data": [c.json for c in listing]} return render_template("userpage_comments.html", u=user, v=v, listing=listing, page=page, sort=sort, t=t,next_exists=next_exists, is_following=is_following, standalone=True) @@ -928,9 +836,9 @@ def u_username_info(username, v=None): user=get_user(username, v=v, include_blocks=True, include_shadowbanned=False) if hasattr(user, 'is_blocking') and user.is_blocking: - return {"error": "You're blocking this user."}, 401 + abort(401, "You're blocking this user.") elif hasattr(user, 'is_blocked') and user.is_blocked: - return {"error": "This user is blocking you."}, 403 + abort(403, "This user is blocking you.") return user.json @@ -941,9 +849,9 @@ def u_user_id_info(id, v=None): user=get_account(id, v=v, include_blocks=True, include_shadowbanned=False) if hasattr(user, 'is_blocking') and user.is_blocking: - return {"error": "You're blocking this user."}, 401 + abort(403, "You're blocking this user.") elif hasattr(user, 'is_blocked') and user.is_blocked: - return {"error": "This user is blocking you."}, 403 + abort(403, "This user is blocking you.") return user.json @@ -956,10 +864,10 @@ def follow_user(username, v): target = get_user(username, v=v, include_shadowbanned=False) if target.id==v.id: - return {"error": "You can't follow yourself!"}, 400 + abort(400, "You can't follow yourself!") if target.is_nofollow: - return {"error": "This user has disallowed other users from following them!"}, 403 + abort(403, "This user has disallowed other users from following them!") if g.db.query(Follow).filter_by(user_id=v.id, target_id=target.id).one_or_none(): return {"message": f"@{target.username} has been followed!"} @@ -988,7 +896,7 @@ def unfollow_user(username, v): if target.fish: if not v.shadowbanned: send_notification(target.id, f"@{v.username} has tried to unfollow you and failed because of your fish award!") - return {"error": "You can't unfollow this user!"}, 400 + abort(400, "You can't unfollow this user!") follow = g.db.query(Follow).filter_by(user_id=v.id, target_id=target.id).one_or_none() @@ -1051,77 +959,47 @@ def user_profile_name(username): x = get_user(username) return redirect(x.profile_url) +def get_saves_and_subscribes(v, template, relationship_cls, page:int, standalone=False): + PAGE_SIZE = 25 + if relationship_cls in (SaveRelationship, Subscription): + query = relationship_cls.submission_id + join = relationship_cls.post + cls = Submission + elif relationship_cls in (CommentSaveRelationship): + query = relationship_cls.comment_id + join = relationship_cls.comment + cls = Comment + else: + raise TypeError("Relationships supported is SaveRelationship, Subscription, CommentSaveRelationship") + ids = [x[0] for x in g.db.query(query).join(join).filter(relationship_cls.user_id == v.id).order_by(cls.created_utc.desc()).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all()] + next_exists = len(ids) > PAGE_SIZE + ids = ids[:PAGE_SIZE] + if cls is Submission: + listing = get_posts(ids, v=v) + elif cls is Comment: + listing = get_comments(ids, v=v) + else: + raise TypeError("Only supports Submissions and Comments. This is probably the result of a bug with *this* function") + if v.client: return {"data": [x.json for x in listing]} + return render_template(template, u=v, v=v, listing=listing, page=page, next_exists=next_exists, standalone=standalone) + @app.get("/@/saved/posts") @auth_required def saved_posts(v, username): - - page=int(request.values.get("page",1)) - - ids = [x[0] for x in g.db.query(SaveRelationship.submission_id).join(SaveRelationship.post).filter(SaveRelationship.user_id == v.id).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()] - - next_exists=len(ids)>25 - - ids=ids[:25] - - listing = get_posts(ids, v=v) - - if request.headers.get("Authorization"): return {"data": [x.json for x in listing]} - return render_template("userpage.html", - u=v, - v=v, - listing=listing, - page=page, - next_exists=next_exists, - ) - + page = max(1, int(request.values.get("page", 1))) + return get_saves_and_subscribes(v, "userpage.html", SaveRelationship, page, False) @app.get("/@/saved/comments") @auth_required def saved_comments(v, username): - - page=int(request.values.get("page",1)) - - ids = [x[0] for x in g.db.query(CommentSaveRelationship.comment_id).join(CommentSaveRelationship.comment).filter(CommentSaveRelationship.user_id == v.id).order_by(Comment.id.desc()).offset(25 * (page - 1)).limit(26).all()] - - next_exists=len(ids) > 25 - - ids=ids[:25] - - listing = get_comments(ids, v=v) - - if request.headers.get("Authorization"): return {"data": [x.json for x in listing]} - return render_template("userpage_comments.html", - u=v, - v=v, - listing=listing, - page=page, - next_exists=next_exists, - standalone=True) + page = max(1, int(request.values.get("page", 1))) + return get_saves_and_subscribes(v, "userpage_comments.html", CommentSaveRelationship, page, True) @app.get("/@/subscribed/posts") @auth_required def subscribed_posts(v, username): - - page=int(request.values.get("page",1)) - - ids = [x[0] for x in g.db.query(Subscription.submission_id).join(Subscription.post).filter(Subscription.user_id == v.id).order_by(Submission.created_utc.desc()).offset(25 * (page - 1)).limit(26).all()] - - next_exists=len(ids)>25 - - ids=ids[:25] - - listing = get_posts(ids, v=v) - - if request.headers.get("Authorization"): return {"data": [x.json for x in listing]} - return render_template("userpage.html", - u=v, - v=v, - listing=listing, - page=page, - next_exists=next_exists, - ) - - + page = max(1, int(request.values.get("page", 1))) + return get_saves_and_subscribes(v, "userpage.html", Subscription, page, False) @app.post("/fp/") @auth_required @@ -1169,10 +1047,10 @@ def bid_list(v, bid): try: page = int(request.values.get("page", 1)) except: page = 1 - users = g.db.query(User).join(User.badges).filter(Badge.badge_id==bid).offset(25 * (page - 1)).limit(26).all() + users = g.db.query(User).join(User.badges).filter(Badge.badge_id==bid).offset(PAGE_SIZE * (page - 1)).limit(PAGE_SIZE + 1).all() - next_exists = (len(users) > 25) - users = users[:25] + next_exists = (len(users) > PAGE_SIZE) + users = users[:PAGE_SIZE] return render_template("user_cards.html", v=v, @@ -1191,7 +1069,11 @@ def kofi(): id = data['kofi_transaction_id'] created_utc = int(time.mktime(time.strptime(data['timestamp'].split('.')[0], "%Y-%m-%dT%H:%M:%SZ"))) type = data['type'] - amount = int(float(data['amount'])) + amount = 0 + try: + amount = int(float(data['amount'])) + except: + abort(400, 'invalid amount') email = data['email'] transaction = Transaction( @@ -1210,7 +1092,8 @@ kofi_tiers={ 10: 2, 20: 3, 50: 4, - 100: 5 + 100: 5, + 200: 6 } @app.post("/settings/kofi") @@ -1218,20 +1101,19 @@ kofi_tiers={ @auth_required def settings_kofi(v): if not (v.email and v.is_activated): - return {"error": f"You must have a verified email to verify {patron} status and claim your rewards!"}, 400 + abort(400, f"You must have a verified email to verify {patron} status and claim your rewards!") transaction = g.db.query(Transaction).filter_by(email=v.email).order_by(Transaction.created_utc.desc()).first() if not transaction: - return {"error": "Email not found"}, 404 + abort(404, "Email not found") if transaction.claimed: - return {"error": f"{patron} rewards already claimed"}, 400 + abort(400, f"{patron} rewards already claimed") tier = kofi_tiers[transaction.amount] v.patron = tier - if v.discord_id: add_role(v, f"{tier}") procoins = procoins_li[tier] diff --git a/files/routes/votes.py b/files/routes/votes.py index f98204a9d..033f1c4a5 100644 --- a/files/routes/votes.py +++ b/files/routes/votes.py @@ -42,152 +42,118 @@ def vote_info_get(v, link): ups=ups, downs=downs) +def vote_post_comment(target_id, new, v, cls, vote_cls): + if new == "-1" and DISABLE_DOWNVOTES: abort(403) + if new not in ["-1", "0", "1"]: abort(400) + if v.client and v.id != BBBB_ID: abort(403) + new = int(new) + target = None + if cls == Submission: + target = get_post(target_id) + elif cls == Comment: + target = get_comment(target_id) + if not target.post: abort(404) + else: + abort(404) + + coin_delta = 1 + if v.id == target.author.id: + coin_delta = 0 + + coin_mult = 1 + + g.db.flush() + existing = g.db.query(vote_cls).filter_by(user_id=v.id) + if vote_cls == Vote: + existing = existing.filter_by(submission_id=target.id) + elif vote_cls == CommentVote: + existing = existing.filter_by(comment_id=target.id) + else: + abort(400) + existing = existing.one_or_none() + + if DOUBLE_XP_ENABLED > 0 and int(time.time()) > DOUBLE_XP_ENABLED: + coin_mult = 2 + coin_value = coin_delta * coin_mult + + if existing and existing.vote_type == new: return "", 204 + if existing: + if existing.vote_type == 0 and new != 0: + target.author.coins += coin_value + target.author.truecoins += coin_delta + g.db.add(target.author) + existing.vote_type = new + existing.coins = coin_value + g.db.add(existing) + elif existing.vote_type != 0 and new == 0: + target.author.charge_account('coins', existing.coins) + target.author.truecoins -= coin_delta + g.db.add(target.author) + g.db.delete(existing) + else: + existing.vote_type = new + g.db.add(existing) + elif new != 0: + target.author.coins += coin_value + target.author.truecoins += coin_delta + g.db.add(target.author) + + real = new != 1 or v.is_votes_real + vote = None + if vote_cls == Vote: + vote = Vote(user_id=v.id, + vote_type=new, + submission_id=target_id, + app_id=v.client.application.id if v.client else None, + real=real, + coins=coin_value + ) + elif vote_cls == CommentVote: + vote = CommentVote(user_id=v.id, + vote_type=new, + comment_id=target_id, + app_id=v.client.application.id if v.client else None, + real=real, + coins=coin_value + ) + g.db.add(vote) + g.db.flush() + + # this is hacky but it works, we should probably do better later + def get_vote_count(dir, real_instead_of_dir): + votes = g.db.query(vote_cls) + if real_instead_of_dir: + votes = votes.filter_by(real=True) + else: + votes = votes.filter_by(vote_type=dir) + + if vote_cls == Vote: + votes = votes.filter_by(submission_id=target.id) + elif vote_cls == CommentVote: + votes = votes.filter_by(comment_id=target.id) + else: + return 0 + return votes.count() + + target.upvotes = get_vote_count(1, False) + target.downvotes = get_vote_count(-1, False) + target.realupvotes = get_vote_count(0, True) # first arg is ignored here + + if target.author.progressivestack or (cls == Submission and (target.sub in ('space', 'istory', 'dinos') or target.domain.endswith('.win'))): + target.realupvotes *= 2 + g.db.add(target) + return "", 204 @app.post("/vote/post//") @limiter.limit("5/second;60/minute;1000/hour;2000/day") @limiter.limit("5/second;60/minute;1000/hour;2000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @is_not_permabanned def vote_post(post_id, new, v): - - if new == "-1" and DISABLE_DOWNVOTES: return {"error": "forbidden."}, 403 - - if new not in ["-1", "0", "1"]: abort(400) - - if request.headers.get("Authorization") and v.id != BBBB_ID: abort(403) - - new = int(new) - - post = get_post(post_id) - - coin_delta = 1 - if v.id == post.author.id: - coin_delta = 0 - - coin_mult = 1 - - g.db.flush() - existing = g.db.query(Vote).filter_by(user_id=v.id, submission_id=post.id).one_or_none() - - if DOUBLE_XP_ENABLED > 0: - if not existing and int(time.time()) > DOUBLE_XP_ENABLED: - coin_mult = 2 - elif existing and existing.created_utc > DOUBLE_XP_ENABLED: - coin_mult = 2 - - if existing and existing.vote_type == new: return "", 204 - - if existing: - if existing.vote_type == 0 and new != 0: - post.author.coins += coin_delta * coin_mult - post.author.truecoins += coin_delta - g.db.add(post.author) - existing.vote_type = new - g.db.add(existing) - elif existing.vote_type != 0 and new == 0: - post.author.coins -= coin_delta * coin_mult - post.author.truecoins -= coin_delta - g.db.add(post.author) - g.db.delete(existing) - else: - existing.vote_type = new - g.db.add(existing) - elif new != 0: - post.author.coins += coin_delta * coin_mult - post.author.truecoins += coin_delta - g.db.add(post.author) - - if new == 1 and (v.agendaposter or v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url.startswith('/e/') and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False - else: real = True - - vote = Vote(user_id=v.id, - vote_type=new, - submission_id=post_id, - app_id=v.client.application.id if v.client else None, - real = real - ) - g.db.add(vote) - - g.db.flush() - post.upvotes = g.db.query(Vote).filter_by(submission_id=post.id, vote_type=1).count() - post.downvotes = g.db.query(Vote).filter_by(submission_id=post.id, vote_type=-1).count() - post.realupvotes = g.db.query(Vote).filter_by(submission_id=post.id, real=True).count() - - if post.author.progressivestack \ - or post.sub in ('space','istory','dinos') \ - or post.domain.endswith('.win'): - post.realupvotes *= 2 - - g.db.add(post) - return "", 204 + return vote_post_comment(post_id, new, v, Submission, Vote) @app.post("/vote/comment//") @limiter.limit("5/second;60/minute;1000/hour;2000/day") @limiter.limit("5/second;60/minute;1000/hour;2000/day", key_func=lambda:f'{SITE}-{session.get("lo_user")}') @is_not_permabanned def vote_comment(comment_id, new, v): - - if new == "-1" and DISABLE_DOWNVOTES: return {"error": "forbidden."}, 403 - - if new not in ["-1", "0", "1"]: abort(400) - - if request.headers.get("Authorization") and v.id != BBBB_ID: abort(403) - - new = int(new) - comment = get_comment(comment_id) - - coin_delta = 1 - if v.id == comment.author_id: - coin_delta = 0 - - coin_mult = 1 - - g.db.commit() - existing = g.db.query(CommentVote).filter_by(user_id=v.id, comment_id=comment.id).one_or_none() - - if DOUBLE_XP_ENABLED > 0: - if not existing and int(time.time()) > DOUBLE_XP_ENABLED: - coin_mult = 2 - elif existing and existing.created_utc > DOUBLE_XP_ENABLED: - coin_mult = 2 - - if existing and existing.vote_type == new: return "", 204 - - if existing: - if existing.vote_type == 0 and new != 0: - comment.author.coins += coin_delta * coin_mult - comment.author.truecoins += coin_delta - g.db.add(comment.author) - existing.vote_type = new - g.db.add(existing) - elif existing.vote_type != 0 and new == 0: - comment.author.coins -= coin_delta * coin_mult - comment.author.truecoins -= coin_delta - g.db.add(comment.author) - g.db.delete(existing) - else: - existing.vote_type = new - g.db.add(existing) - elif new != 0: - comment.author.coins += coin_delta * coin_mult - comment.author.truecoins += coin_delta - g.db.add(comment.author) - - if new == 1 and (v.agendaposter or v.shadowbanned or (v.is_banned and not v.unban_utc) or (v.profile_url.startswith('/e/') and not v.customtitle and v.namecolor == DEFAULT_COLOR)): real = False - else: real = True - - vote = CommentVote(user_id=v.id, - vote_type=new, - comment_id=comment_id, - app_id=v.client.application.id if v.client else None, - real=real - ) - - g.db.add(vote) - - g.db.commit() - comment.upvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=1).count() - comment.downvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, vote_type=-1).count() - comment.realupvotes = g.db.query(CommentVote).filter_by(comment_id=comment.id, real=True).count() - if comment.author.progressivestack: comment.realupvotes *= 2 - g.db.add(comment) - return "", 204 + return vote_post_comment(comment_id, new, v, Comment, CommentVote) diff --git a/files/templates/admin/admin_home.html b/files/templates/admin/admin_home.html index 2bc0050e3..05f211f17 100644 --- a/files/templates/admin/admin_home.html +++ b/files/templates/admin/admin_home.html @@ -5,10 +5,10 @@ {% endblock %} +{% block customPadding %}px-3{% endblock %} + {% block content %} -
    
    -
    
    -

    Admin Tools

    +

    Admin Tools

    {% if (v.admin_level >= PERMS['SITE_SETTINGS_SIDEBARS_BANNERS_BADGES'] or v.admin_level >= PERMS['SITE_SETTINGS_SNAPPY_QUOTES']) and (SITE_NAME == 'rDrama' or SIDEBAR_THREAD or BANNER_THREAD or BADGE_THREAD or SNAPPY_THREAD) %}

    Add Stuff

    @@ -54,7 +54,7 @@ {% endif %}
  2. Permabanned Users
  3. {% if FEATURES['AWARDS'] -%} -
  4. Users with Chud Theme
  5. +
  6. Users with Chud Theme
  7. Currently Grassed Users
  8. {%- endif %} {% if FEATURES['PROCOINS'] and (not AEVANN_ID or v.id in (AEVANN_ID, CARP_ID, SNAKES_ID)) -%} @@ -82,11 +82,11 @@ {%- endif %} -{% if CASINO_ENABLED -%} +{% if FEATURES['GAMBLING'] -%}

    Casino

    • Participants
    • - +
    {%- endif %} @@ -100,7 +100,7 @@

    Configuration

    {% if v.admin_level >= PERMS['SITE_SETTINGS'] %} -
    
    -	
    +
    - - + +
    - - + +
    @@ -140,17 +139,17 @@
    {% endif %} {% if v.admin_level >= PERMS['SITE_CACHE_PURGE_CDN'] %} - + {% endif %}
    {% if SITE_NAME == 'PCM' and v.admin_level >= PERMS['PRINT_MARSEYBUX_FOR_KIPPY_ON_PCMEMES'] %} - + {% endif %} {% endif %}

    Server Status

    - Live Revision: {{ gitref }}
    + Live Revision: {{gitref}}
    {% endblock %} diff --git a/files/templates/admin/alt_votes.html b/files/templates/admin/alt_votes.html index b3a5c9aa2..6151df2cc 100644 --- a/files/templates/admin/alt_votes.html +++ b/files/templates/admin/alt_votes.html @@ -6,12 +6,8 @@ {% endblock %} {% block content %} -
     
    -
    -
    -
    -
    Vote Info
    +
    Vote Info
    @@ -31,7 +27,7 @@ - @{{u1.username}} only(% unique) + @{{u1.username}} only (% unique) Both @{{u2.username}} only (% unique) @@ -72,7 +68,7 @@

    Two accounts controlled by different people should have most uniqueness percentages at or above 70-80%

    A sockpuppet account will have its uniqueness percentages significantly lower.

    -Link Accounts + @@ -85,4 +81,4 @@ {% endif %} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/admin/app.html b/files/templates/admin/app.html index c7586130a..1d937c2a3 100644 --- a/files/templates/admin/app.html +++ b/files/templates/admin/app.html @@ -34,12 +34,12 @@
    {% if not app.client_id%} - Approve - Reject + + {% else %} - Revoke + {% endif %}
    @@ -47,6 +47,19 @@ + + {% if listing %} {% include "submission_listing.html" %} {% elif comments %} @@ -69,4 +82,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/admin/apps.html b/files/templates/admin/apps.html index a61e99855..27f025862 100644 --- a/files/templates/admin/apps.html +++ b/files/templates/admin/apps.html @@ -13,10 +13,11 @@ {% for app in apps %}
    - -
    + + +
    @@ -39,12 +40,12 @@
    {% if not app.client_id %} - Approve - Reject + + {% else %} - Revoke + {% endif %}
    @@ -69,4 +70,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/admin/badge_grant.html b/files/templates/admin/badge_admin.html similarity index 79% rename from files/templates/admin/badge_grant.html rename to files/templates/admin/badge_admin.html index 6b6a959bc..07ba0be90 100644 --- a/files/templates/admin/badge_grant.html +++ b/files/templates/admin/badge_admin.html @@ -1,20 +1,20 @@ {% extends "default.html" %} - -{% block title %} -Badge Grant -{% endblock %} - +{% if grant %} + {% set title="Badge Grant" %} +{% else %} + {% set title="Badge Remove" %} +{% endif %} +{% block pagetitle %}{{title}}{% endblock %} {% block pagetype %}message{% endblock %} {% block content %} - {% if error %} @@ -25,20 +25,23 @@ {{msg}} -
    {% endif %} -
    
    -
    
    -
    Badge Grant
    +
    {{title}}
    - +{% if grant %} + {% set form_action="/admin/badge_grant" %} +{% else %} + {% set form_action="/admin/badge_remove" %} +{% endif %} + + -
    @@ -62,7 +65,7 @@ {{badge.name}} @@ -70,13 +73,13 @@ {% endfor %} - +{% if grant %}

    - +{% endif %} diff --git a/files/templates/admin/badge_remove.html b/files/templates/admin/badge_remove.html deleted file mode 100644 index 79e24969a..000000000 --- a/files/templates/admin/badge_remove.html +++ /dev/null @@ -1,93 +0,0 @@ -{% extends "default.html" %} - -{% block title %} -Badge Remove -{% endblock %} - -{% block pagetype %}message{% endblock %} - -{% block content %} - - {% if error %} - - {% endif %} - {% if msg %} - - {% endif %} - -
    
    -
    
    -
    Badge Remove
    - -
    - - - -
    - - -
    - - - - - - - - - -{% for badge in badge_types %} - - - - - - -{% endfor %} -
    SelectImageNameDefault Description
    -
    - - -
    -
    - - {{badge.name}}{{badge.description}}
    - -
    - - -
    - - - - - - - - -{% endblock %} diff --git a/files/templates/admin/banned_domains.html b/files/templates/admin/banned_domains.html index f3f305560..1b2d8bbc9 100644 --- a/files/templates/admin/banned_domains.html +++ b/files/templates/admin/banned_domains.html @@ -6,32 +6,43 @@ {% block content %} -
    +
     
    -
    +
    + + + + + + + + -
    DomainBan reason
    - - - - - - - - {% for domain in banned_domains %} - - - - - {% endfor %} -
    DomainBan reason
    {{domain.domain}}{{domain.reason}}
    + + {% for domain in banned_domains %} + + {{domain.domain}} + {{domain.reason}} + + + + + {% endfor %} + + -
    - - - - -
    +
    + + + + +
    +
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/admin/lottery.html b/files/templates/admin/lottery.html index 70998ae3a..add67f366 100644 --- a/files/templates/admin/lottery.html +++ b/files/templates/admin/lottery.html @@ -1,9 +1,7 @@ {% extends "default.html" %} {% block content %} -
    
    -
    Admin — Lottery Info
    -
    
    +
    Admin — Lottery Info
    diff --git a/files/templates/admin/removed_comments.html b/files/templates/admin/removed_comments.html index 8399ee022..c471c66db 100644 --- a/files/templates/admin/removed_comments.html +++ b/files/templates/admin/removed_comments.html @@ -15,7 +15,7 @@
    -
    There are no comments here (yet).
    +

    There are no comments here (yet).

    @@ -23,4 +23,3 @@ {% endblock %} - diff --git a/files/templates/admin/reported_comments.html b/files/templates/admin/reported_comments.html index 3ee534eaf..f8442a73a 100644 --- a/files/templates/admin/reported_comments.html +++ b/files/templates/admin/reported_comments.html @@ -15,7 +15,7 @@
    -
    There are no comments here (yet).
    +

    There are no comments here (yet).

    @@ -23,4 +23,3 @@ {% endblock %} - diff --git a/files/templates/admins.html b/files/templates/admins.html index 4e65e4de8..fda6fb1b2 100644 --- a/files/templates/admins.html +++ b/files/templates/admins.html @@ -6,8 +6,7 @@
    Admins
    -
    
    -
    +
    diff --git a/files/templates/api.html b/files/templates/api.html index 1de23a226..1f97a6177 100644 --- a/files/templates/api.html +++ b/files/templates/api.html @@ -6,12 +6,7 @@ {% endblock %} {% block content %} -
    -
    -
    -
    -

    API Guide for Bots

    -
    
    +

    API Guide for Bots

    This page explains how to obtain and use an access token.

    Step 1: Create your Application

    In the apps tab of {{SITE_NAME}} settings, fill in and submit the form to request an access token. You will need:

    @@ -52,17 +47,8 @@ print(r.json())

    The expected result of this would be a JSON representation of unread notifications for your account

    -
     
    -
    -
    -
    -
    -
    -
    -
    -

    API Guide for Applications

    -
    
    +

    API Guide for Applications

    The OAuth2 authorization flow is used to enable users to authorize third-party applications to access their {{SITE_NAME}} account without having to provide their login information to the application.

    This page explains how to obtain API application keys, how to prompt a user for authorization, and how to obtain and use access tokens.

    Step 1: Create your Application

    @@ -109,4 +95,4 @@ print(r.json())

    The expected result of this would be a JSON representation of unread notifications for your account

    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/authforms.html b/files/templates/authforms.html index 84d326a8b..285aeb960 100644 --- a/files/templates/authforms.html +++ b/files/templates/authforms.html @@ -1,44 +1,8 @@ {%- import 'util/helpers.html' as help -%} +{%- import 'html_head.html' as html_head with context -%} - - - - - - - - - - - - - {% block pagetitle %}{{SITE_NAME}}{% endblock %} - - - {% if v %} - - - - {% if v.agendaposter %} - - {% elif v.css %} - - {% endif %} - {% else %} - - - - {% endif %} - - - +{{html_head.html_head(false, false, false, none, none, "", "")}}
    @@ -49,11 +13,7 @@
    -
    - -
    - -

    {% block authtitle %}{% endblock %}

    +

    {% block authtitle %}{% endblock %}

    {% block authtext %}{% endblock %}

    @@ -63,7 +23,7 @@ {{error}} -
    @@ -74,7 +34,7 @@ {{msg}} -
    @@ -89,7 +49,7 @@
    -
    +
    diff --git a/files/templates/award_modal.html b/files/templates/award_modal.html index 1a549f3b6..907526211 100644 --- a/files/templates/award_modal.html +++ b/files/templates/award_modal.html @@ -5,25 +5,25 @@
    diff --git a/files/templates/badges.html b/files/templates/badges.html index b426a0232..14245323e 100644 --- a/files/templates/badges.html +++ b/files/templates/badges.html @@ -1,16 +1,8 @@ {% extends "default.html" %} {% block content %} -
    -
    -
    -
    -

    User Badges

    +

    User Badges

    This page describes the requirements for obtaining all profile badges.
    -
    -
    -
    -
    -
    +
    @@ -28,12 +20,12 @@ {%- set ct = counts[badge.id] if badge.id in counts else (0, 0) %} - - + + {% endfor %}
    {{loop.index}} {{badge.name}} - {{badge.name}} + {{badge.name}} {{badge.description}}{{ ct[0] }}{{ "{:0.3f}".format(ct[1]) }}%{{ct[0]}}{{"{:0.3f}".format(ct[1])}}%
    @@ -41,4 +33,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/ban_modal.html b/files/templates/ban_modal.html index 4bae91ce1..a5ee7b7b3 100644 --- a/files/templates/ban_modal.html +++ b/files/templates/ban_modal.html @@ -4,7 +4,7 @@
    diff --git a/files/templates/blockers.html b/files/templates/blockers.html index 15cfc9078..ab17c83b4 100644 --- a/files/templates/blockers.html +++ b/files/templates/blockers.html @@ -1,17 +1,12 @@ {% extends "default.html" %} {% block content %} -
    -
    -	
    -
    -
    @{{u.username}}'s blockers
    -
    
    -
    +
    @{{u.username}}'s blockers
    +
    - + diff --git a/files/templates/blocks.html b/files/templates/blocks.html index c50738965..0820b51cf 100644 --- a/files/templates/blocks.html +++ b/files/templates/blocks.html @@ -4,8 +4,7 @@ {% block content %}

    Blocks

    -
    
    -
    # NameBlocking SinceBlocking since
    +
    diff --git a/files/templates/casino.html b/files/templates/casino.html index 82c1be41c..0801dbadf 100644 --- a/files/templates/casino.html +++ b/files/templates/casino.html @@ -33,7 +33,7 @@ Icon (fa-foo-bar), Color (#ff0000), URL (/post/12345/) #}

    Casino

    {% for game in GAME_INDEX %} - + -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/casino/blackjack_screen.html b/files/templates/casino/blackjack_screen.html index b8136fccc..189781d21 100644 --- a/files/templates/casino/blackjack_screen.html +++ b/files/templates/casino/blackjack_screen.html @@ -2,218 +2,218 @@ {% block script %} {% endblock %} @@ -225,74 +225,74 @@ {% block actions %}
    - - - - - + + + + +
    {% endblock %} @@ -302,4 +302,4 @@ Blackjack {% block feed %} Blackjack -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/casino/game_screen.html b/files/templates/casino/game_screen.html index 165a32e78..838cb4e50 100644 --- a/files/templates/casino/game_screen.html +++ b/files/templates/casino/game_screen.html @@ -2,468 +2,468 @@ {{game.capitalize()}} {% endblock %} {% block content %} {% block script %} {% endblock %}
    -
    -
    -

    {{game}}

    -
    -
    -
    {% block screen %} {% endblock %}
    -
    - -
    -
    -
    -
    -
    -
    Wager
    -
    -
    - -
    -
    -
    -
    Currency
    -
    -
    -
    - - - - -
    -
    -
    -
    -
    -
    -
    {% block actiontext %}Actions{% endblock %}
    -
    -
    - {% block actions %} {% endblock %} -
    -
    -
    -
    Feed
    -
    -
    -
      - -
      -
      -
      -
      Leaders
      -
      -
      -
      - -
      -
      - - -
      -
      - Biggest Winner (All Time) -

      -

      -
      -
      - -
      -
      - - -
      -
      - Biggest Winner (Last 24h) -

      -

      -
      -
      - -
      -
      - - -
      -
      - Biggest Loser (Last 24h) -

      -

      -
      -
      - -
      -
      - - -
      -
      - Biggest Loser (All Time) -

      -

      -
      -
      -
      -
      -
      +
      +
      +

      {{game}}

      +
      +
      +
      {% block screen %} {% endblock %}
      +
      + +
      +
      +
      +
      +
      +
      Wager
      +
      +
      + +
      +
      +
      +
      Currency
      +
      +
      +
      + + + + +
      +
      +
      +
      +
      +
      +
      {% block actiontext %}Actions{% endblock %}
      +
      +
      + {% block actions %} {% endblock %} +
      +
      +
      +
      Feed
      +
      +
      +
        + +
        +
        +
        +
        Leaders
        +
        +
        +
        + +
        +
        + + +
        +
        + Biggest Winner (All Time) +

        -

        +
        +
        + +
        +
        + + +
        +
        + Biggest Winner (Last 24h) +

        -

        +
        +
        + +
        +
        + + +
        +
        + Biggest Loser (Last 24h) +

        -

        +
        +
        + +
        +
        + + +
        +
        + Biggest Loser (All Time) +

        -

        +
        +
        +
        +
        +
        -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/casino/rehab.html b/files/templates/casino/rehab.html index 289b4aec0..cf024e8fa 100644 --- a/files/templates/casino/rehab.html +++ b/files/templates/casino/rehab.html @@ -1,11 +1,11 @@ {% extends "default.html" %} {% block content %}
        -
        -

        No one was there for Britney…

        -
        -
        -

        …but we’re here for you. You’ve been checked into Rehab.

        -
        - +
        +

        No one was there for Britney…

        +
        +
        +

        …but we’re here for you. You’ve been checked into Rehab.

        +
        +
        -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/casino/roulette_screen.html b/files/templates/casino/roulette_screen.html index 40d077668..80a6933d2 100644 --- a/files/templates/casino/roulette_screen.html +++ b/files/templates/casino/roulette_screen.html @@ -2,480 +2,480 @@ {% block script %} {% endblock %} {% block screen %}
        @@ -488,95 +488,95 @@ Bets {% block actions %}
        -
        -
        -
        - - -
        -

        111 is betting 4 and 4: -

        -
        -
          -
        • 2 coin that - the number will be black.
        • -
        • 2 coin that - the number will be even.
        • -
        -
        +
        +
        +
        + + +
        +

        111 is betting 4 and 4: +

        +
        +
          +
        • 2 coin that + the number will be black.
        • +
        • 2 coin that + the number will be even.
        • +
        +
        -
        How to Bet
        -
        +
        How to Bet
        +
        #
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        BetPayoutDescription
        Straight Up35:1 - Click any single number.
        - You win if the roulette lands on that number. -
        Line5:1 - Click Line 1, Line 2 ... Line 6.
        - You win if the roulette lands on any of the six numbers beneath the line. -
        Column2:1 - Click Col 1, Col 2 or Col 3.
        - You win if the roulette lands on any of the 12 numbers to the left of the column. -
        Dozen2:1 - Click 1st12, 2nd12 or 3rd12.
        - You win if the roulette lands on a number within 1-12, 13-24 or 25-36, respectively. -
        Even/Odd1:1 - Click EVEN or ODD.
        - You win if the roulette lands on a number that matches your choice. -
        Red/Black1:1 - Click RED or BLACK.
        - You win if the roulette lands on a number that is the same color as your choice. -
        High/Low1:1 - Click 1:18 or 19:36.
        - You win if the roulette lands on a number within your selected range. -
        BetPayoutDescription
        Straight Up35:1 + Click any single number.
        + You win if the roulette lands on that number. +
        Line5:1 + Click Line 1, Line 2 ... Line 6.
        + You win if the roulette lands on any of the six numbers beneath the line. +
        Column2:1 + Click Col 1, Col 2 or Col 3.
        + You win if the roulette lands on any of the 12 numbers to the left of the column. +
        Dozen2:1 + Click 1st12, 2nd12 or 3rd12.
        + You win if the roulette lands on a number within 1-12, 13-24 or 25-36, respectively. +
        Even/Odd1:1 + Click EVEN or ODD.
        + You win if the roulette lands on a number that matches your choice. +
        Red/Black1:1 + Click RED or BLACK.
        + You win if the roulette lands on a number that is the same color as your choice. +
        High/Low1:1 + Click 1:18 or 19:36.
        + You win if the roulette lands on a number within your selected range. +
        -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/casino/slots_screen.html b/files/templates/casino/slots_screen.html index 0fc88c555..dfc1c6261 100644 --- a/files/templates/casino/slots_screen.html +++ b/files/templates/casino/slots_screen.html @@ -2,124 +2,124 @@ {% block script %} {% endblock %} {% block screen %}
        -
        - coin -
        -
        - coin -
        -
        - coin -
        +
        + coin +
        +
        + coin +
        +
        + coin +
        {% endblock %} {% block actions %}
        - +
        {% endblock %} diff --git a/files/templates/chat.html b/files/templates/chat.html index d3e64dac2..1d5c01141 100644 --- a/files/templates/chat.html +++ b/files/templates/chat.html @@ -1,28 +1,13 @@ {%- import 'util/helpers.html' as help -%} +{%- import 'html_head.html' as html_head with context -%} - - - - - - - - - - Chat - - - - - {% if v.css %} - - {% endif %} - - - +{% if SITE == 'localhost' %} + {% set csp="script-src 'self' 'unsafe-inline' rdrama.net; connect-src 'self'; object-src 'none';" %} +{% else %} + {% set csp=none %} +{% endif %} +{{html_head.html_head(true, true, true, csp, "Chat", none, "", false)}} {% include "header.html" %} {% include "expanded_image_modal.html" %} @@ -41,8 +26,11 @@ data-hat="{{v.hat_active}}">
        - + {% if SITE == 'localhost' %} + + {% else %} + + {% endif %} - diff --git a/files/templates/agendaposters.html b/files/templates/chuds.html similarity index 100% rename from files/templates/agendaposters.html rename to files/templates/chuds.html diff --git a/files/templates/comments.html b/files/templates/comments.html index 6b6ae7803..aaf8769b1 100644 --- a/files/templates/comments.html +++ b/files/templates/comments.html @@ -21,17 +21,13 @@ {% set score=ups-downs %} {% if render_replies %} - {% if v and (v.shadowbanned or v.admin_level >= PERMS['USER_SHADOWBAN']) %} - {% set replies=c.replies3(sort) %} - {% else %} - {% set replies=c.replies(sort) %} - {% endif %} + {% set replies=c.replies(sort=sort, v=v) %} {% endif %} {% if c.is_blocking and not c.ghost or (c.is_banned or c.deleted_utc) and not (v and v.admin_level >= PERMS['POST_COMMENT_MODERATION']) and not (v and v.id==c.author_id) %}
        - +
        @@ -40,7 +36,7 @@
        @@ -52,7 +48,7 @@ {{single_comment(reply, level=level+1)}} {% endfor %} {% elif replies %} - + More comments {% endif %}
        @@ -75,7 +71,7 @@ {% endif %} {% if standalone and level==1 %} - -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/files/templates/errors/502.html b/files/templates/errors/rDrama/502.html similarity index 70% rename from files/templates/errors/502.html rename to files/templates/errors/rDrama/502.html index 2b8d07cc4..5f0c7d888 100644 --- a/files/templates/errors/502.html +++ b/files/templates/errors/rDrama/502.html @@ -1,9 +1,9 @@ - + - + - - + + - - + + - + - + 502 Bad Gateway - - - - + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - site banner + + site banner