Tools 🛠

Find a tool that makes your life easier.

chatGpt This is a Toolkit for simple, everyday tasks that ChatGpt can help you with.

This is a Toolkit for simple, everyday tasks that ChatGpt can help you with.

text-tools This is a Toolkit for work with text. You can analyse selected text, get statistics, find and replace text, and modify it in various ways.

This is a Toolkit for work with text. You can analyse selected text, get statistics, find and replace text, and modify it in various ways.

utils Just some helper functions that might be used for the setup.

Just some helper functions that might be used for the setup.

🧰 chatGpt /

Add ChatGPT Tool 🔧

Create a custom tool for ChatGPT.

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { createTool } from "../lib/tool-creation";

await createTool();
    
💻 Setup
Easy
🏷️ Tags
create custom tool, create cus...

🧰 chatGpt /

ChatGPT 4 🔧

Open a chat with ChatGPT in any application and ei... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

await startChat({
    model: "gpt-4",
    temperature: 1,
    functions: [],
});
    
💻 Setup
Easy
🏷️ Tags
chatgpt, gpt4

🧰 chatGpt /

ChatGPT With Functions 🔧

Allow ChatGPT to access your computer and run func... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";
import os from "os";
// import { CustomFunctions } from "../../../lib/chatGptFunctions"; // For user build functions that are stored in ~/.kenv/lib/chatGptFunctions/index.ts

await startChat({
    model: "gpt-3.5-turbo-0613",
    temperature: 1,
    systemMessage: `You have now access to my system and you are able to perform any direct interactions with my local environment such as accessing my file system, running bash commands, executing python code with the 'runPython' function, and creating/saving files on my own io the platform. 
The name of the user is ${os.userInfo().username}.
You can use every function on the users macOS system to accomplish every task, especially everything that needs to be computed. Try to be bold!

IMPORTANT: Before you decide to install any packages, please check if they are already installed.
Don't run commands, that could return a huge output, always limit the output to the necessary information.
Always assume you are in the Home directory when you run a bash command.`,
    functions: [
        "all",
        // CustomFunctions.greetingsFunction, // Just an example of how to use a custom function
    ],
});
    
💻 Setup
Easy
🏷️ Tags
python, bash, kit, chatgpt, gp...

🧰 chatGpt /

ChatGPT 3.5 🔧

Open a chat with ChatGPT in any application and ei... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

await startChat({
    model: "gpt-3.5-turbo-0613",
    temperature: 1,
    functions: ["setReminder"],
    chatModifiers: []
});
    
💻 Setup
Easy
🏷️ Tags
chatgpt, gpt3, gpt4

🧰 chatGpt /

ChatGPTherapist 🔧

Chat with your ai therapist.

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

await startChat({
    systemMessage: `You are a therapist. Stay in your role and don't play out of character. Don't write any comments or recommendations apart from that role.`,
});
    
💻 Setup
Easy
🏷️ Tags
getHumanInput

🧰 chatGpt /

Chat History 🔧

Look through your previous chat and continue where... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import { resumeChat } from "../lib/common";

await resumeChat();
    
💻 Setup
Easy
🏷️ Tags
chat history, resume previous ...

🧰 chatGpt /

Continue Last Chat 🔧

Continue where you left of.

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { continueLastChat } from "../lib/common";

await continueLastChat();
    
💻 Setup
Easy
🏷️ Tags
chat history, resume last chat...

🧰 chatGpt /

Correct Text With ChatGpt 🔧

Correct Text for misspellings and grammatical erro... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

let selectedText = await getSelectedText();

let task = `Could you please correct the following text from misspellings and grammatical errors? Just answer with your corrected text. Try to write like a human and don't use so many phrases like 'Therefore', 'Moreover', 'All in all', etc.
\`\`\`
${selectedText}
\`\`\``;

await startChat({
    prompt: task,
    model: "gpt-3.5-turbo",
    temperature: 1,
    runPromptImmediately: true,
});
    
💻 Setup
Easy
🏷️ Tags
correct text, chatgpt, gpt3, g...

🧰 chatGpt /

Create Cal Event with ChatGPT 🔧

Allow ChatGPT to create a calendar Event for you v... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";
import { getCalendars, getCurrentDayOfWeek } from "../lib/functions/implementations/calendar";
import { Functions } from "../lib/functions";
import { getSetting } from "../lib/settings";

let calendars = await getCalendars();

const defaultCalendar = await getSetting("defaultCalendar");
const CALENDAR_STRING = calendars.map(cal => `- ${cal}`).join("\n")
let prompt = undefined;
await startChat({
    prompt,
    model: "gpt-4-0613", // gpt-3.5 is not reliable with times and calculation
    temperature: 1,
    systemMessage: `You are my personal assistant and you schedule my events in my calendar. I want you to create an event for me.
IMPORTANT: The current datetime is: ${new Date().toLocaleString()} in 'MM/DD/YYYY, HH:MM:SS AM/PM', it's ${await getCurrentDayOfWeek()}.
If there is no end date or duration specified, I want you to create an event for 1 hour.

The available calendars are:
${CALENDAR_STRING}

Use the first '${defaultCalendar}' calendar if no calendar is specified.

IMPORTANT: Use the 'createEvent' function to create the event.`,
    functions: [Functions.createEventFunction],
});
    
💻 Setup
Easy
🏷️ Tags
create cal event, apple, chatg...

🧰 chatGpt /

Excuse my French 🔧

Rewrite a text in a professional manner, so it can... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

let selectedText = await getSelectedText();
let task = `Please rewrite the following text in a professional manner, so I can use it for work. Keep it as short as possible. Here is the text:
\`\`\`
${selectedText}
\`\`\``;

await startChat({
    prompt: task,
    model: "gpt-3.5-turbo",
    temperature: 1,
});
    
💻 Setup
Easy
🏷️ Tags
excuse my french, rewrite emai...

🧰 chatGpt /

Explain like I'm Five 🔧

Explain the selected text like I am five years old... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

let selectedText = await getSelectedText();

let task = `Could you please explain the following text like I am five years old. Just answer with the text.
\`\`\`
${selectedText}
\`\`\``;

await startChat({
    prompt: task,
    model: "gpt-3.5-turbo",
    temperature: 1,
});
    
💻 Setup
Easy
🏷️ Tags
explain like im five, eli5, ch...

🧰 chatGpt /

Rephrase Text With ChatGpt 🔧

Rephrase the selected text with ChatGpt.

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

let selectedText = await getSelectedText();

let writingStyle = await arg(
    { placeholder: "Choose writing style", strict: false },
    [
        "default",
        "academic",
        "analytical",
        "argumentative",
        "conversational",
        "creative",
        "descriptive",
        "epigrammatic",
        "epistolary",
        "expository",
        "informative",
        "instructive",
        "journalistic",
        "metaphorical",
        "narrative",
        "persuasive",
        "poetic",
        "satirical",
        "critical",
        "technical",
    ]
);

let tone = await arg({ placeholder: "Choose tonality", strict: false }, [
    "default",
    "authoritative",
    "clinical",
    "cold",
    "confident",
    "cynical",
    "emotional",
    "empathetic",
    "formal",
    "friendly",
    "humorous",
    "informal",
    "ironic",
    "optimistic",
    "pessimistic",
    "playful",
    "sarcastic",
    "serious",
    "sympathetic",
    "tentative",
    "caring",
    "casual",
    "cheerful",
    "coarse",
    "conservative",
    "conversational",
    "creative",
    "dry",
    "edgy",
    "enthusiastic",
    "expository",
    "frank",
    "fun",
    "funny",
    "informative",
    "irreverent",
    "journalistic",
    "matteroffact",
    "nostalgic",
    "objective",
    "passionate",
    "poetic",
    "professional",
    "provocative",
    "quirky",
    "respectful",
    "romantic",
    "smart",
    "snarky",
    "subjective",
    "trendy",
    "trustworthy",
    "unapologetic",
    "upbeat",
    "witty",
]);

let input = `Could you please rephrase the following text and use a ${writingStyle} writing style and ${tone} tone? Just answer with your corrected text.
\`\`\`
${selectedText}
\`\`\``;

await startChat({
    prompt: input,
});
    
💻 Setup
Easy
🏷️ Tags
correct text, chatgpt, gpt3, g...

🧰 chatGpt /

ChatGPT Toolkit Settings 🔧

Adjust the settings for the ChatGPT Toolkit.

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { changeSettings } from "../lib/settings";

await changeSettings();
    
💻 Setup
Easy
🏷️ Tags
settings, api keys, dataforseo

🧰 chatGpt /

Summarize Text With ChatGpt 🔧

Summarize the selected text with ChatGpt.

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

let selectedText = await getSelectedText();

let task = `Could you please summarize the following text. Just answer with the summary.
\`\`\`
${selectedText}
\`\`\``;

await startChat({
    prompt: task,
    model: "gpt-3.5-turbo",
    temperature: 1,
    runPromptImmediately: true,
});
    
💻 Setup
Easy
🏷️ Tags
summarize text, chatgpt, gpt3,...

🧰 chatGpt /

Typescript Code 🔧

Coding helper that gives you code examples in type... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import { startChat } from "../lib/common";

await startChat({
    model: "gpt-3.5-turbo",
    systemMessage: `You are a proficient software developer who is specialized in Typescript. Please help me with the following and always give code examples in typescript. Always prefer to write code with async/await promises instead of callbacks.`,
});
    
💻 Setup
Easy
🏷️ Tags
typescript, chatgpt, gpt3, gpt...

🧰 text-tools /

Lorem Ipsum Text Generator 🔧

Generate Lorem Ipsum text. You can choose between ... (Read more)

Tool: Lorem Ipsum Text Generator, Generate Lorem Ipsum text. You can choose between paragraphs, sentences and words, the number of units and the format (plain text / html). Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
create text, lorem ipsum

🧰 text-tools /

Text Case Converter 🔧

Transform the selected text to a different case. Y... (Read more)

Tool: Text Case Converter, Transform the selected text to a different case. You can choose from CamelCase, Capital Case, CONSTANT_CASE, dot.case, Header-Case, param-case, PascalCase, path/case, Sentence case, snake_case, Swap Case, Title Case, lower case, UPPER CASE, Upper Case First, and Sponge Case. Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
text, case, convert, transform

🧰 text-tools /

Duplicate Text 🔧

Duplicate the selected text by replacing a word wi... (Read more)

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";

let input = await getSelectedText();

let buildPreview = ([search, replacement]) => {
    if (!search) return md(input);
    if (!replacement)
        return md(
            `${input
                .replaceAll("\n", "<br>")
                .replaceAll(search, `<ins>${search}</ins>`)}`
        );
    return md(
        `${input}
${replacement
            .split(",")
            .map((item) => {
                return input
                    .replaceAll("\n", "<br>")
                    .replaceAll(search, `<ins>${item}</ins>`);
            })
            .join("<br>")}`
    );
};

let [search, replacement] = await fields({
    fields: ["Search", "Replacement"],
    preview: buildPreview(["", ""]),
    onChange: async (input, state) => {
        let preview = buildPreview(state?.value);
        setPreview(preview);
    },
});

let result = `${input}
${replacement
        .split(",")
        .map((item) => {
            return input.replaceAll(search, `${item}`);
        })
        .join("\n")}`;

// Output
await setSelectedText(result);
    
💻 Setup
Easy
🏷️ Tags
text, replace text

🧰 text-tools /

Get Text Length 🔧

Return the length of the selected text.

Tool: Get Text Length, Return the length of the selected text. Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
text, word count

🧰 text-tools /

Get Reading Time of Text 🔧

How much time does the text take to read? Just sel... (Read more)

Tool: Get Reading Time of Text, How much time does the text take to read? Just select the text in any application and run this script. Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
Reading Time, Text

🧰 text-tools /

Replace Text 🔧

Replace text in the selected text.

Tool: Replace Text, Replace text in the selected text. Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
text, replace text
Tool: Text Sort Lines, Sort Text Lines Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
text, sort lines

🧰 text-tools /

Text Word Count 🔧

Counts the words in the selected text. It's a simp... (Read more)

Tool: Text Word Count, Counts the words in the selected text. It's a simple algorithm that counts the spaces between words. Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
text, word count

🧰 text-tools /

Title Case 🔧

Convert the selected text to title case.

Tool: Title Case, Convert the selected text to title case. Video placeholderPlay Button
💻 Setup
Easy
🏷️ Tags
title case, text

🧰 utils /

Install Toolkit 🔧

Install free and paid Toolkits from schmedu.com

// Author: Eduard Uffelmann    
// Linkedin: https://www.linkedin.com/in/euffelmann/
// Twitter: @schmedu_
// Website: https://schmedu.com

import "@johnlindquist/kit";
import axios from "axios";
import * as fs from "fs";
import AdmZip from "adm-zip";
import * as os from "os";
import { createHash } from "crypto";

function getHash(input: string, algorithm: string): string {
    const hash = createHash(algorithm);
    hash.update(input);
    return hash.digest("hex");
}

async function downloadZipFile(url: string, outputPath: string): Promise<void> {
    try {
        const response = await axios.get(url, { responseType: "arraybuffer" });
        fs.writeFileSync(outputPath, response.data);
        notify(`Zip file downloaded to ${outputPath}`);
    } catch (error) {
        console.error(`Error downloading the zip file: ${error.message}`);
    }
}

export interface Kenv {
    name: string;
    title: string;
    description: string;
    price: string | undefined;
    paylink: string;
    priceSingle?: string | undefined;
    href: string;
    installation?: string;
    scriptNames?: string[];
}

const CLIENT_SECRET = "L7J7yLVcZdJbAFcVMpVcJaXwdoNsxLdW3ez9LFASStE";

const BASE_URL = "https://schmedu.com";
let toolsReq = await axios.get(
    `${BASE_URL}/api/client?secret=${encodeURIComponent(CLIENT_SECRET)}`
);
let tools = toolsReq.data.tools as Kenv[];

let kenv = await arg(
    "Which kenv",
    tools.map((tool) => {
        return {
            name: tool.name,
            description: tool.description,
            value: tool,
            // preview: `<img src="${BASE_URL}/img/kenvs/${tool.name}.png" class="" />`,
            preview: md(
                `# ${tool.name}: ${tool.description}                
## Scripts
${tool.scriptNames.map((script) => `- ${script}`).join("\n")}`
            ),
        };
    })
);

let isPaidTool = typeof kenv.price !== "string";

interface Credentials {
    licenseKey: string;
    instanceId: string;
}

let downloadLink;
let licenseKey = "";
let instanceId = "";
let credentialsDB = await store("LicenseKeys");
if (isPaidTool) {
    if (await credentialsDB.has(kenv.name)) {
        // license was activated already
        let credentials = (await credentialsDB.get(kenv.name)) as Credentials;
        licenseKey = credentials.licenseKey;
        instanceId = credentials.instanceId;

        try {
            let downloadLinkRequest = await axios.get(
                `${BASE_URL}/api/client/${encodeURIComponent(
                    kenv.name
                )}?secret=${encodeURIComponent(
                    CLIENT_SECRET
                )}&licenseKey=${encodeURIComponent(
                    licenseKey
                )}&instanceId=${encodeURIComponent(instanceId)}`
            );
            downloadLink = downloadLinkRequest.data.url;
            // await credentialsDB.set(kenv.name, { licenseKey, instanceId });
        } catch (err) {
            log(err);
            let body = encodeURIComponent(
                err.message
            );
            await credentialsDB.delete(kenv.name);
            let sendReport = await arg(
                {
                    placeholder: "Error downloading the toolkit",
                    hint: `There was an error while downloading the toolkit. Please send an error report so I can help you install it. Sorry for the inconvenience!`
                },
                [
                    {
                        name: "Send Error Report and get contacted",
                        description: "You will only send the license key and your (hashed) instanceID and the error message. Nothing else. I will contact you via the email that you used for the purchase.",
                        value: true,
                    },
                    {
                        name: "Ignore",
                        value: false,
                    },
                ]
            );
            if (sendReport) {
                await axios.post(
                    `${BASE_URL}/api/client/${encodeURIComponent(
                        kenv.name
                    )}/error-reporting?secret=${encodeURIComponent(
                        CLIENT_SECRET
                    )}&licenseKey=${encodeURIComponent(
                        licenseKey
                    )}&instanceId=${encodeURIComponent(
                        instanceId
                    )}&error=${encodeURIComponent(
                        "LicenseActiveErrorDownloading"
                    )}&errorBody=${body}`
                );
            }
            exit();
        }
    } else {
        licenseKey = await arg({
            placeholder: "Enter the license Key",
            hint: `Buy a license key for the <a href="${kenv.paylink}" target="_blank">${kenv.name}</a> Toolkit for \$${kenv.price}`,
            ignoreBlur: true,
            alwaysOnTop: true,
        });
        let instanceName = getHash(os.userInfo().username, "md5");

        try { // try activating the license
            let downloadLinkRequest = await axios.get(
                `${BASE_URL}/api/client/${encodeURIComponent(
                    kenv.name
                )}?secret=${encodeURIComponent(
                    CLIENT_SECRET
                )}&licenseKey=${encodeURIComponent(
                    licenseKey
                )}&instanceName=${encodeURIComponent(instanceName)}`
            );
            downloadLink = downloadLinkRequest.data.url;
            let instanceId = downloadLinkRequest.data.instanceId;
            await credentialsDB.set(kenv.name, { licenseKey, instanceId });
        } catch (err) {
            log(err);
            let body = encodeURIComponent(err.message);

            let sendReport = await arg(
                {
                    placeholder: "Error activating the License Key",
                    hint: `There was an error while activating your license key. Please send an error report so I can help you install it. Sorry for the inconvenience!`
                },
                [
                    {
                        name: "Send error report and get contacted",
                        description: "You will only send the license key and your (hashed) instanceName and the error message. Nothing else. I will contact you via the email that you used for the purchase.",
                        value: true,
                    },
                    {
                        name: "Ignore",
                        value: false
                    }
                ]
            );

            if (sendReport) {
                await axios.post(
                    `${BASE_URL}/api/client/${encodeURIComponent(
                        kenv.name
                    )}/error-reporting?secret=${encodeURIComponent(
                        CLIENT_SECRET
                    )}&licenseKey=${encodeURIComponent(
                        licenseKey
                    )}&instanceName=${encodeURIComponent(
                        instanceName
                    )}&error=${encodeURIComponent(
                        "LicenseActivatingError"
                    )}&errorBody=${body}`
                );
            }
            exit();
        }
    }
} else {
    try {
        let downloadLinkRequest = await axios.get(
            `${BASE_URL}/api/client/${encodeURIComponent(
                kenv.name
            )}?secret=${encodeURIComponent(CLIENT_SECRET)}`
        );
        downloadLink = downloadLinkRequest.data.url;
    } catch (err) {
        log(err);
        let body = encodeURIComponent(err.message);

        let sendReport = await arg(
            {
                placeholder: "Error downloading the toolkit",
                hint: `There was an error while downloading the toolkit. Please send an error report so you can get some help to install it. Sorry for the inconvenience!`
            },
            [
                {
                    name: "Send error report and get contacted",
                    description: "You will only send the error message and your email address.",
                    value: true,
                },
                {
                    name: "Ignore",
                    value: false
                }
            ]
        );

        if (sendReport) {
            let email = await arg("What is your email?")
            await axios.post(
                `${BASE_URL}/api/client/${encodeURIComponent(
                    kenv.name
                )}/error-reporting?secret=${encodeURIComponent(
                    CLIENT_SECRET
                )}&email=${encodeURIComponent(
                    email
                )}&error=${encodeURIComponent(
                    "LicenseActivatingError"
                )}&errorBody=${body}`
            );
        }
        exit();
    }
}

let zipDownloadPath = home("Downloads", `${kenv.name}.zip`);
await downloadZipFile(downloadLink, zipDownloadPath);

let kenvFolder = kenvPath("kenvs", kenv.name);
if (await isDir(kenvFolder)) {
    let shouldOverwrite = await arg(
        `${kenv.name} already exists. Do you want to overwrite it?`,
        [
            { name: "No", value: false },
            { name: "Yes", value: true },
        ]
    );
    if (!shouldOverwrite) {
        await div({
            html: md(`# ${kenv.name} already exists!
Download canceled because it should not be replaced.`),
        })
        exit()
    };
}

await mkdir("-p", kenvFolder);
const zip = new AdmZip(zipDownloadPath);
zip.extractAllTo(kenvFolder, false);
await rm(zipDownloadPath);
if (isPaidTool) { // save the credentials in the db
    await credentialsDB.set(kenv.name, { licenseKey, instanceId });
}
await div({
    html: md(`# Installed ${kenv.name}!
Please allow notifications for ScriptKit. Many tools rely on them :-)`),
});
notify(`${kenv.name} successfully installed!`);
    
💻 Setup
Easy
🏷️ Tags
util, helper, install toolkit,...

Get The Freshest Tools

I will let you know when something comes up. Maybe once in a blue moon (🌝), I will never spam you. Pinky promise 🤙

By submitting this form, I accept the privacy policy.