mirror of
https://github.com/replicatedhq/ttl.sh.git
synced 2026-07-12 07:39:19 +00:00
Deploy an nginx proxy service to Heroku (#136)
Deploy an nginx proxy service to Heroku --------- Co-authored-by: Salah Al Saleh <sg.alsaleh@gmail.com>
This commit is contained in:
9
.github/workflows/main.yaml
vendored
9
.github/workflows/main.yaml
vendored
@@ -26,6 +26,15 @@ jobs:
|
||||
- name: release registry
|
||||
run: heroku container:release -a ttlsh web
|
||||
|
||||
- name: build nginx
|
||||
run: docker build -t registry.heroku.com/ttlsh/nginx nginx
|
||||
|
||||
- name: push nginx
|
||||
run: docker push registry.heroku.com/ttlsh/nginx
|
||||
|
||||
- name: release nginx
|
||||
run: heroku container:release -a ttlsh nginx
|
||||
|
||||
- name: build hooks
|
||||
run: docker build -f hooks/Dockerfile.hooks -t registry.heroku.com/ttlsh-hooks/web hooks
|
||||
|
||||
|
||||
7
nginx/Dockerfile
Normal file
7
nginx/Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM nginx:latest
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
COPY src/favicon.ico /usr/share/nginx/html/
|
||||
COPY src/index.htm /usr/share/nginx/html/
|
||||
COPY src/ttlsh_files /usr/share/nginx/html/ttlsh_files/
|
||||
23
nginx/nginx.conf
Normal file
23
nginx/nginx.conf
Normal file
@@ -0,0 +1,23 @@
|
||||
events {}
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
server_name staging.ttl.sh;
|
||||
|
||||
location /v2 {
|
||||
client_max_body_size 10000m;
|
||||
|
||||
proxy_pass https://ttl.sh;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.htm;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
nginx/src/favicon.ico
Normal file
BIN
nginx/src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
201
nginx/src/index.htm
Normal file
201
nginx/src/index.htm
Normal file
@@ -0,0 +1,201 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>ttl.sh | An anonymous & ephemeral (and free) Docker image registry</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="description" content="An anonymous & ephemeral (and free) Docker image registry.">
|
||||
<meta property="og:image" content="">
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
<link rel="shortcut icon" href="">
|
||||
<link href="./ttlsh_files/css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./ttlsh_files/AllTemplates.min.css">
|
||||
|
||||
<style>
|
||||
@keyframes popinpopup {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, 3px, 0)
|
||||
}
|
||||
|
||||
7%,
|
||||
93% {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0)
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate3d(0, -4px, 0)
|
||||
}
|
||||
}
|
||||
|
||||
.launchaco-promo-animate:hover {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="font-hacker">
|
||||
<div class="red-flat">
|
||||
<!---->
|
||||
<header class="header">
|
||||
<div class="container-lrg">
|
||||
<div class="flex col-12 spread"><a class="logo primary-color launchaco-builder-hoverable logo">ttl.sh</a> <a href="https://www.replicated.com" class="nav-link secondary-color mr0">Contributed by Replicated</a></div>
|
||||
</div>
|
||||
</header>
|
||||
<section class="section">
|
||||
<div class="container mb10">
|
||||
<div class="col-12 text-center">
|
||||
<h1 class="heading-lrg primary-color launchaco-builder-hoverable">Anonymous & ephemeral Docker image registry</h1>
|
||||
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class="container mt40">
|
||||
<div class="col-12">
|
||||
<div class="codeblock">
|
||||
<pre><code class="hljs bash">
|
||||
<table class="hljs-ln">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line">$ IMAGE_NAME=$(uuidgen)</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line">$ docker build -t ttl.<span class="hljs-keyword">sh</span>/${IMAGE_NAME}:1h .</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line">$ docker push ttl.<span class="hljs-keyword">sh</span>/${IMAGE_NAME}:1h</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line"> </div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line"> ................................................</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line"> image ttl.sh/xxxx-yyyy-nnnn-2a2222-4</span>b44 <span class="hljs-keyword">is</span> available <span class="hljs-keyword">for</span> 1 hour</div></td></tr><tr><td class="hljs-ln-code"><div class="hljs-ln-line"> </div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="hljs-ln-code"><div class="hljs-ln-line"> ttl.sh is contributed by <a href="https://www.replicated.com" target="_blank">Replicated (www.replicated.com)</a></div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</code></pre>
|
||||
</div>
|
||||
<h2 class="subheading secondary-color mt20 launchaco-builder-hoverable" align="center">Free to use. No need to sign-up. Open source.</h2>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<section id="checklist-1" class="section red-white" sitemeta="[object Object]" activepage="Landing">
|
||||
<div class="container text-center">
|
||||
<div class="col-12">
|
||||
<h3 class="heading primary-color launchaco-builder-hoverable">How to use ttl.sh</h3>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class="container flex">
|
||||
<ul class="checklist col-12">
|
||||
<li class="checklist-item flex center-horizontal spread pad20 launchaco-builder-hoverable">
|
||||
<p class="bold primary-color mr20">1. Tag your image with <span style="background-color:#f8f8f8;padding:3px 8px;border-radius:5px;color:#ED2D2D">ttl.sh</span>, a UUID, & time limit (i.e. <span style="background-color:#f8f8f8;padding:3px 8px;border-radius:5px;color:#ED2D2D">:2h</span>)</p> <svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="noshrink svg-fill">
|
||||
</svg>
|
||||
</li>
|
||||
<li class="checklist-item flex center-horizontal spread pad20 launchaco-builder-hoverable">
|
||||
<p class="bold primary-color mr20">2. Push your image</p> <svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="noshrink svg-fill">
|
||||
</svg>
|
||||
</li>
|
||||
<li class="checklist-item flex center-horizontal spread pad20 launchaco-builder-hoverable">
|
||||
<p class="bold primary-color mr20">3. Pull your image (before it expires)</p> <svg width="22px" height="22px" viewBox="0 0 22 22" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="noshrink svg-fill">
|
||||
</svg>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!---->
|
||||
</section>
|
||||
<section id="feature-2" class="section red-white" sitemeta="[object Object]" activepage="Landing">
|
||||
<div class="container-lrg flex">
|
||||
<div class="col-4 flex mobile-flex-wrap mobile-text-center"><i class="icon secondary-bg mr20 mobile-center-icon launchaco-builder-hoverable"><svg class="svg-fill" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25">
|
||||
<path d="M12.5 0A12.489 12.489 0 0 0 5 22.483a12.432 12.432 0 0 0 14.999 0q.5-.376.96-.799A12.487 12.487 0 0 0 12.5 0zm0 5A3.5 3.5 0 1 1 9 8.5 3.504 3.504 0 0 1 12.5 5zm0 19a11.443 11.443 0 0 1-7.393-2.704 7.489 7.489 0 0 1 14.786 0A11.443 11.443 0 0 1 12.5 24z"></path>
|
||||
</svg></i>
|
||||
<div>
|
||||
<h3 class="bold primary-color launchaco-builder-hoverable">Anonymous</h3>
|
||||
<p class="paragraph secondary-color launchaco-builder-hoverable" style="font-family: Helvetica Neue;font-size:16px">No login required. Image names provide the initial secrecy for access. Add a UUID to your image name to reduce discoverability.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 flex mobile-flex-wrap mobile-text-center"><i class="icon secondary-bg mr20 mobile-center-icon launchaco-builder-hoverable"><svg class="svg-fill" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25">
|
||||
<path d="M9 1.5a.5.5 0 0 1 .5-.5h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5zM22 5a1 1 0 1 0-1-1 1 1 0 0 0 1 1zm1 8.5A10.5 10.5 0 1 1 12.5 3 10.5 10.5 0 0 1 23 13.5zm-5.197-5.303a.5.5 0 0 0-.707 0l-3.953 3.953a1.514 1.514 0 1 0 .707.707l3.953-3.953a.5.5 0 0 0 0-.707z"></path>
|
||||
</svg></i>
|
||||
<div>
|
||||
<h3 class="bold primary-color launchaco-builder-hoverable">Ephemeral</h3>
|
||||
<p class="paragraph secondary-color launchaco-builder-hoverable" style="font-family: Helvetica Neue;font-size:16px">Image tags provide the time limit. The default is 24 hours, and the max is 24 hours (valid time tags :5m, :1600s, :4h, :1d)</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 flex mobile-flex-wrap mobile-text-center"><i class="icon secondary-bg mr20 mobile-center-icon launchaco-builder-hoverable"><svg class="svg-fill" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25">
|
||||
<path d="M13 20.5a.5.5 0 1 1-.5-.5.5.5 0 0 1 .5.5zm12-3a12.421 12.421 0 0 1-1.838 6.5H1.838A12.495 12.495 0 1 1 25 17.5zm-7.197-2.303a.5.5 0 0 0-.707 0l-3.953 3.953a1.514 1.514 0 1 0 .707.707l3.953-3.953a.5.5 0 0 0 0-.707zM23 17.5a10.5 10.5 0 0 0-21 0 .5.5 0 0 0 1 0 9.5 9.5 0 0 1 19 0 .5.5 0 0 0 1 0z"></path>
|
||||
</svg></i>
|
||||
<div>
|
||||
<h3 class="bold primary-color launchaco-builder-hoverable">Fast</h3>
|
||||
<p class="paragraph secondary-color launchaco-builder-hoverable" style="font-family: Helvetica Neue;font-size:16px">Pulling images is really quick, so it just works thanks to Cloudflare. Even if you aren't near us-east-1.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!---->
|
||||
</section>
|
||||
|
||||
|
||||
<section id="checklist-1" class="section red-white" sitemeta="[object Object]" activepage="Landing">
|
||||
<div class="container text-center">
|
||||
<div class="col-12">
|
||||
<h3 class="heading primary-color launchaco-builder-hoverable">How we're using it</h3>
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
<div class="container mt40">
|
||||
<h3 class="bold primary-color launchaco-builder-hoverable" style="font-family: Helvetica Neue">Workflows in CI</h3>
|
||||
<p class="paragraph launchaco-builder-hoverable" style="font-family: Helvetica Neue;font-size:18px">Many workflows in CI will build an image, and then subsequent steps will test that image in parallel. Docker registries are a commonly used storage mechanism for these intermediate build artifacts. One build step can push an image, and other distributed steps can pull. The challenge is that most registries require authentication to push and pull. A workflow can either bake credentials in and share them to build workers, or require forked builds to bring their own registry credentials. The first is insecure, the second creates friction for new contributors. </p>
|
||||
<br>
|
||||
<p class="paragraph launchaco-builder-hoverable" style="font-family: Helvetica Neue;font-size:18px">ttl.sh solves this by making an ephemeral and anonymous registry.</p>
|
||||
</div>
|
||||
<!---->
|
||||
</section>
|
||||
|
||||
<footer id="footer-3" class="section text-center red-white" sitemeta="[object Object]" activepage="Landing">
|
||||
<div class="container col-12">
|
||||
<nav class="mb10"><a target="_blank" href="http://www.replicated.com/" class="nav-link secondary-color">Contributed by Replicated</a></nav>
|
||||
<div><a href="https://twitter.com/replicatedhq" target="_blank" class="socialicons accent-bg twitter"></a><a href="https://github.com/replicatedhq/ttl.sh" target="_blank" class="socialicons accent-bg github"></a></div>
|
||||
<div class="mt50"><span class="span secondary-color">©</span> <span class="span secondary-color">Replicated Inc 2022</span></div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-61420213-9"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'UA-61420213-9');
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var _paq = _paq || [];
|
||||
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function() {
|
||||
var u="//data-2.replicated.com/";
|
||||
_paq.push(['setTrackerUrl', u+'data/']);
|
||||
_paq.push(['setSiteId', '7']);
|
||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'js/'; s.parentNode.insertBefore(g,s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body></html>
|
||||
1
nginx/src/ttlsh_files/AllTemplates.min.css
vendored
Normal file
1
nginx/src/ttlsh_files/AllTemplates.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
112
nginx/src/ttlsh_files/css
Normal file
112
nginx/src/ttlsh_files/css
Normal file
@@ -0,0 +1,112 @@
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfCRc4AMP6lbBP.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfABc4AMP6lbBP.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfCBc4AMP6lbBP.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfBxc4AMP6lbBP.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfCxc4AMP6lbBP.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfChc4AMP6lbBP.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
src: local('Roboto Black'), local('Roboto-Black'), url(https://fonts.gstatic.com/s/roboto/v19/KFOlCnqEu92Fr1MmYUtfBBc4AMP6lQ.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* cyrillic-ext */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhGq3-cXbKDO1w.woff2) format('woff2');
|
||||
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
|
||||
}
|
||||
/* cyrillic */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhPq3-cXbKDO1w.woff2) format('woff2');
|
||||
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
|
||||
}
|
||||
/* greek-ext */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhHq3-cXbKDO1w.woff2) format('woff2');
|
||||
unicode-range: U+1F00-1FFF;
|
||||
}
|
||||
/* greek */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhIq3-cXbKDO1w.woff2) format('woff2');
|
||||
unicode-range: U+0370-03FF;
|
||||
}
|
||||
/* vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhEq3-cXbKDO1w.woff2) format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhFq3-cXbKDO1w.woff2) format('woff2');
|
||||
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* latin */
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Roboto Mono'), local('RobotoMono-Regular'), url(https://fonts.gstatic.com/s/robotomono/v6/L0x5DF4xlVMF-BfR8bXMIjhLq3-cXbKD.woff2) format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
Reference in New Issue
Block a user