Repository: lucaceriani/ooo
Branch: main
Commit: 86bbc4b6b134
Files: 6
Total size: 15.0 KB
Directory structure:
gitextract_tuebg16q/
├── README.md
├── public/
│ ├── index.html
│ ├── index.js
│ ├── ooo.js
│ └── style.css
└── worker.js
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
# ooo
The ultimate url lengthner
================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Stop using boring short URLs, lengthen your URLs now!">
<title>ooooooooooooooooooooooo.ooo | URL Lengthner</title>
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;800&display=block" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/normalize.css@8.0.1/normalize.min.css">
<link rel="stylesheet" href="/style.css?v=2" />
<script defer src="/ooo.js?v=2"></script>
<script defer src="/index.js?v=2"></script>
</head>
<body>
<div class="container">
<div class="content">
<h1>Looooooooooooooooooooooonger</h1>
<div class="d-flex">
<input type="text" class="input-url" id="input-url" placeholder="Lengthen yooour URL!"
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<button id="ooo-button" onclick="oooify()">oOo</button>
</div>
<div id="output-div" style="display: none;">
<h2 style="margin-bottom: 1em;">Yooour new url:</h2>
<div style="word-wrap: break-word; font-size: 1.2em">
<a id="output-url" target="_blank"></a>
</div>
<div class="tooltip">
<button id="copy-button" onclick="copy()">
Cooopy
</button>
<span class="tooltip-text">Cooopied!</span>
</div>
</div>
</div>
</div>
<footer>
made with
<svg xmlns="http://www.w3.org/2000/svg" fill="#EF3E36" viewBox="0 0 16 16"
style="height: 1.2em; vertical-align: middle">
<path fill-rule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z" />
</svg>
by
<a target="_blank" href="https://luca.gg"> luca.gg </a>
<span style="margin: 0 0.4em;">|</span>
<a target="_blank" href="https://github.com/lucaceriani/ooo"> source </a>
<span style="margin: 0 0.4em;">|</span>
<a target="_blank" href="https://ko-fi.com/lucaceriani">buy me a coffee</a>
</footer>
</body>
</html>
================================================
FILE: public/index.js
================================================
const input = document.getElementById("input-url");
const output = document.getElementById("output-url");
const oooBtn = document.getElementById("ooo-button");
const copyBtn = document.getElementById("copy-button");
// init
input.addEventListener("keydown", e => e.code == "Enter" ? oooify() : null)
// mouse enter listener
let oooBtnInt;
oooBtn.addEventListener("mouseenter", () => oooBtnInt = setInterval(() => {
console.log("a");
if (oooBtn.innerText == "oOo") oooBtn.innerText = "OoO";
else oooBtn.innerText = "oOo";
}, 200));
oooBtn.addEventListener("mouseleave", () => {
clearInterval(oooBtnInt);
// oooBtn.innerText = "oOo";
});
function oooify() {
if (window.inBlinking) return
try {
new URL(input.value)
} catch (e) {
window.inBlinking = true
input.style.opacity = 1
input.disabled = true
let oldValue = input.value
input.value = "Invalid URL! Noooooooooooo D:"
let times = 0
let i = setInterval(async () => {
if (parseInt(input.style.opacity) == 1)
input.style.opacity = 0.2;
else
input.style.opacity = 1;
if (++times == 6) {
clearInterval(i)
input.value = oldValue
input.disabled = false
input.focus()
inBlinking = false
}
}, 150)
return
}
const domain = location.host;
let url = new OOO().encodeUrl(input.value.trim());
url = `${location.protocol}//${domain}/${url}`;
// show the output div
document.getElementById("output-div").style.display = "block";
output.innerHTML = url;
output.setAttribute("href", url);
input.value = "";
}
function copy() {
const el = document.createElement('textarea');
el.value = output.innerHTML;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
copyBtn.parentNode.setAttribute("data-showme", "");
setTimeout(() => copyBtn.parentNode.removeAttribute("data-showme"), 1000);
};
================================================
FILE: public/ooo.js
================================================
class OOO {
enc = ["o", "ο", "о", "ᴏ"]
// 006f 03bf 043e 1d0f
dec = {
"o": "0",
"ο": "1",
"о": "2",
"ᴏ": "3"
}
ver = {
"oooo": true
}
currVer = "oooo"
removeAndCheckVersion(ooo) {
if (this.ver[ooo.substring(0, 4)]) {
return ooo.substring(4)
} else {
return null
}
}
addVersion(ooo) {
return this.currVer + ooo
}
encodeUrl(url) {
// get utf8 array
let unversioned = this.toUTF8Array(url)
// convert to string with base 4
// padstart very important! otherwise missing leading 0s
.map(n => n.toString(4).padStart(4, "0"))
// convert to array of characters
.join("").split("")
// map to the o's
.map(x => this.enc[parseInt(x)])
// join into single string
.join("")
return this.addVersion(unversioned)
}
decodeUrl(ooo) {
ooo = this.removeAndCheckVersion(ooo)
if (ooo === null) return
// get the base 4 string representation of the url
let b4str = ooo.split("").map(x => this.dec[x]).join("")
let utf8arr = []
// parse 4 characters at a time (255 in b10 = 3333 in b4)
// remember adding leading 0s padding
for (let i = 0; i < b4str.length; i += 4)
utf8arr.push(parseInt(b4str.substring(i, i + 4), 4))
return this.Utf8ArrayToStr(utf8arr)
}
// from https://gist.github.com/joni/3760795
toUTF8Array(str) {
var utf8 = [];
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode >> 6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
charcode = ((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)
utf8.push(0xf0 | (charcode >> 18),
0x80 | ((charcode >> 12) & 0x3f),
0x80 | ((charcode >> 6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
// from https://gist.github.com/wumingdan/759564f6cb887a55bceb
Utf8ArrayToStr(array) {
var out, i, len, c;
var char2, char3;
out = "";
len = array.length;
i = 0;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
out += String.fromCharCode(c);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = array[i++];
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
return out;
}
}
================================================
FILE: public/style.css
================================================
:root {
--bright: #ffde03;
--light: #fff3a8;
--dark: #100700;
--fs: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
--br: 5px;
}
* {
box-sizing: border-box;
}
.container {
margin-left: auto;
margin-right: auto;
width: 100%;
max-width: 1200px;
padding: 1em;
}
.d-flex {
display: flex !important;
}
.input-url {
width: 100%;
margin-right: 1em;
display: inline-block;
padding: 0.6em 0.8em;
}
a {
text-decoration: underline;
color: inherit;
}
footer {
text-align: center;
margin: 1.5em 0;
font-size: 80%;
}
html {
overflow-x: hidden;
}
body {
overflow-x: hidden;
font-weight: 300;
background-color: var(--bright);
font-family: var(--fs);
}
/* footer sticky */
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
div.container {
flex: 1;
}
/* end footer */
h1 {
font-weight: 800;
font-size: 4em;
}
h2 {
font-size: 1.5em;
font-weight: 800;
}
input,
input:focus,
input:focus-visible,
.form-control,
button {
outline: none;
font-family: var(--fs);
background-color: var(--light);
border: 1px var(--dark);
border-radius: var(--br);
font-size: 1.2em;
}
::placeholder {
color: rgba(0, 0, 0, 0.5);
}
.form-control {
/* ovverride also :focus and :active */
background-color: var(--light) !important;
box-shadow: none !important;
font-size: 1.4em;
padding: 1em !important;
}
button {
border-radius: var(--br);
background-color: var(--dark);
color: var(--light);
margin: 1px;
cursor: pointer;
transition: 0.1s ease-in-out all;
}
button:hover {
box-shadow: 2px 2px 0px 0px rgba(0, 0, 0, 0.22);
transform: translate(-2px, -2px);
}
#ooo-button {
font-weight: 800;
width: 4em;
}
#copy-button {
font-weight: 800;
padding: 0.5em;
margin-top: 2em;
}
#output-div {
margin-top: 3em;
}
/* Tooltip container */
.tooltip {
position: relative;
display: inline-block;
}
/* Tooltip text */
.tooltip .tooltip-text {
visibility: hidden;
width: 120px;
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
text-align: center;
padding: 1em 0.5em;
border-radius: 6px;
position: absolute;
z-index: 1;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
}
/* Show the tooltip text when you mouse over the tooltip container */
.tooltip[data-showme] .tooltip-text {
visibility: visible;
}
.tooltip .tooltip-text::after {
content: " ";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent;
}
================================================
FILE: worker.js
================================================
/**
* V1 of OOO - cloudflare worker to redirect traffic to correct url
*/
class OOO {
enc = ["o", "ο", "о", "ᴏ"]
// 006f 03bf 043e 1d0f
dec = {
"o": "0",
"ο": "1",
"о": "2",
"ᴏ": "3"
}
ver = {
"oooo": true
}
currVer = "oooo"
removeAndCheckVersion(ooo) {
if (this.ver[ooo.substring(0, 4)]) {
return ooo.substring(4)
} else {
return null
}
}
addVersion(ooo) {
return this.currVer + ooo
}
encodeUrl(url) {
// get utf8 array
let unversioned = this.toUTF8Array(url)
// convert to string with base 4
// padstart very important! otherwise missing leading 0s
.map(n => n.toString(4).padStart(4, "0"))
// convert to array of characters
.join("").split("")
// map to the o's
.map(x => this.enc[parseInt(x)])
// join into single string
.join("")
return this.addVersion(unversioned)
}
decodeUrl(ooo) {
ooo = this.removeAndCheckVersion(ooo)
if (ooo === null) return
// get the base 4 string representation of the url
let b4str = ooo.split("").map(x => this.dec[x]).join("")
let utf8arr = []
// parse 4 characters at a time (255 in b10 = 3333 in b4)
// remember adding leading 0s padding
for (let i = 0; i < b4str.length; i += 4)
utf8arr.push(parseInt(b4str.substring(i, i + 4), 4))
return this.Utf8ArrayToStr(utf8arr)
}
// from https://gist.github.com/joni/3760795
toUTF8Array(str) {
var utf8 = [];
for (var i = 0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode >> 6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
charcode = ((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)
utf8.push(0xf0 | (charcode >> 18),
0x80 | ((charcode >> 12) & 0x3f),
0x80 | ((charcode >> 6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
// from https://gist.github.com/wumingdan/759564f6cb887a55bceb
Utf8ArrayToStr(array) {
var out, i, len, c;
var char2, char3;
out = "";
len = array.length;
i = 0;
while (i < len) {
c = array[i++];
switch (c >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
out += String.fromCharCode(c);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = array[i++];
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = array[i++];
char3 = array[i++];
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
return out;
}
}
async function handleRequest(request) {
let reqUrl = new URL(request.url)
let redirectLocation = new OOO().decodeUrl(decodeURI(reqUrl.pathname.replace("/", "")))
let response;
try {
response = Response.redirect(redirectLocation, 302)
} catch(e) {
response = new Response(null, {status: 400})
}
return response
}
addEventListener("fetch", async event => {
event.respondWith(handleRequest(event.request))
})
gitextract_tuebg16q/ ├── README.md ├── public/ │ ├── index.html │ ├── index.js │ ├── ooo.js │ └── style.css └── worker.js
SYMBOL INDEX (17 symbols across 3 files)
FILE: public/index.js
function oooify (line 25) | function oooify() {
function copy (line 74) | function copy() {
FILE: public/ooo.js
class OOO (line 1) | class OOO {
method removeAndCheckVersion (line 17) | removeAndCheckVersion(ooo) {
method addVersion (line 25) | addVersion(ooo) {
method encodeUrl (line 29) | encodeUrl(url) {
method decodeUrl (line 45) | decodeUrl(ooo) {
method toUTF8Array (line 65) | toUTF8Array(str) {
method Utf8ArrayToStr (line 93) | Utf8ArrayToStr(array) {
FILE: worker.js
class OOO (line 5) | class OOO {
method removeAndCheckVersion (line 21) | removeAndCheckVersion(ooo) {
method addVersion (line 29) | addVersion(ooo) {
method encodeUrl (line 33) | encodeUrl(url) {
method decodeUrl (line 49) | decodeUrl(ooo) {
method toUTF8Array (line 69) | toUTF8Array(str) {
method Utf8ArrayToStr (line 97) | Utf8ArrayToStr(array) {
function handleRequest (line 132) | async function handleRequest(request) {
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (17K chars).
[
{
"path": "README.md",
"chars": 33,
"preview": "# ooo\nThe ultimate url lengthner\n"
},
{
"path": "public/index.html",
"chars": 2491,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-wi"
},
{
"path": "public/index.js",
"chars": 2135,
"preview": "const input = document.getElementById(\"input-url\");\nconst output = document.getElementById(\"output-url\");\nconst oooBtn ="
},
{
"path": "public/ooo.js",
"chars": 3683,
"preview": "class OOO {\n enc = [\"o\", \"ο\", \"о\", \"ᴏ\"]\n // 006f 03bf 043e 1d0f\n dec = {\n \"o\": \"0\",\n \"ο"
},
{
"path": "public/style.css",
"chars": 2853,
"preview": ":root {\n --bright: #ffde03;\n --light: #fff3a8;\n --dark: #100700;\n --fs: Inter, -apple-system, BlinkMacSystem"
},
{
"path": "worker.js",
"chars": 4196,
"preview": "\n/**\n * V1 of OOO - cloudflare worker to redirect traffic to correct url\n */\nclass OOO {\n enc = [\"o\", \"ο\", \"о\", \"ᴏ\"]\n"
}
]
About this extraction
This page contains the full source code of the lucaceriani/ooo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (15.0 KB), approximately 4.5k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.