;(function({ axios, faker, ejs } = { axios: globalThis.axios, faker: globalThis.faker, ejs: globalThis.ejs }) { //Load assets const cached = new Map() async function load(url) { if (!cached.has(url)) cached.set(url, (await axios.get(url)).data) return cached.get(url) } //Distribution function function distribution(length) { let probability = 1 const values = [] for (let i = 0; i < length - 1; i++) { const value = Math.random() * probability values.push(value) probability -= value } values.push(probability) return values.sort((a, b) => b - a) } //Placeholder function globalThis.placeholder = async function(set) { //Load templates informations let { image, style, fonts, partials } = await load(`/.templates/${set.templates.selected}`) await Promise.all(partials.map(async partial => await load(`/.templates/${set.templates.selected}/partials/${partial}.ejs`))) //Trap includes image = image.replace(/<%-\s*await include[(](`.*?[.]ejs`)[)]\s*%>/g, (m, g) => `<%- await $include(${g}) %>`) //Faked data const options = set.plugins.options const data = { //Template elements style, fonts, errors: [], partials: new Set([...(set.config.order || "").split(",").map(x => x.trim()).filter(x => partials.includes(x)), ...partials]), //Plural helper s(value, end = "") { return value !== 1 ? { y: "ies", "": "s" }[end] : end }, //Formatter helper f(n, { sign = false } = {}) { for (const { u, v } of [{ u: "b", v: 10 ** 9 }, { u: "m", v: 10 ** 6 }, { u: "k", v: 10 ** 3 }]) { if (n / v >= 1) return `${(sign) && (n > 0) ? "+" : ""}${(n / v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")}${u}` } return `${(sign) && (n > 0) ? "+" : ""}${n}` }, //Trap for includes async $include(path) { const partial = await load(`/.templates/${set.templates.selected}/${path}`) return await ejs.render(partial, data, { async: true, rmWhitespace: true }) }, //Meta-data meta: { version: set.version, author: "lowlighter", generated:new Date().toGMTString().replace(/GMT$/g, "").trim() }, //Animated animated: false, //Display size large: set.config.display === "large", columns: set.config.display === "columns", //Config config: set.config, //Base elements base: set.plugins.enabled.base, //Computed elements computed: { commits: faker.datatype.number(10000), sponsorships: faker.datatype.number(10), licenses: { favorite: [""], used: { MIT: 1 }, about:{} }, token: { scopes: [] }, repositories: { watchers: faker.datatype.number(1000), stargazers: faker.datatype.number(10000), issues_open: faker.datatype.number(1000), issues_closed: faker.datatype.number(1000), pr_open: faker.datatype.number(1000), pr_closed: { totalCount: faker.datatype.number(100) }, pr_merged: faker.datatype.number(1000), forks: faker.datatype.number(1000), releases: faker.datatype.number(1000), }, diskUsage: `${faker.datatype.float({ min: 1, max: 999 }).toFixed(1)}MB`, registration: `${faker.datatype.number({ min: 2, max: 10 })} years ago`, cakeday: false, calendar: new Array(14).fill(null).map(_ => ({ color: faker.random.arrayElement(["#ebedf0", "#9be9a8", "#40c463", "#30a14e", "#216e39"]) })), avatar: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", }, //User data account: "user", user: { databaseId: faker.datatype.number(10000000), name: "(placeholder)", login: set.user || "metrics", createdAt: `${faker.date.past(10)}`, avatarUrl: set.avatar, websiteUrl: options["pagespeed.url"] || "(attached website)", isHireable: false, twitterUsername: options["tweets.user"] || "(attached Twitter account)", repositories: { totalCount: faker.datatype.number(100), totalDiskUsage: faker.datatype.number(100000), nodes: [] }, packages: { totalCount: faker.datatype.number(10) }, starredRepositories: { totalCount: faker.datatype.number(1000) }, watching: { totalCount: faker.datatype.number(100) }, sponsorshipsAsSponsor: { totalCount: faker.datatype.number(10) }, sponsorshipsAsMaintainer: { totalCount: faker.datatype.number(10) }, contributionsCollection: { totalRepositoriesWithContributedCommits: faker.datatype.number(100), totalCommitContributions: faker.datatype.number(10000), restrictedContributionsCount: faker.datatype.number(10000), totalIssueContributions: faker.datatype.number(100), totalPullRequestContributions: faker.datatype.number(1000), totalPullRequestReviewContributions: faker.datatype.number(1000), }, calendar: { contributionCalendar: { weeks: [] } }, repositoriesContributedTo: { totalCount: faker.datatype.number(100) }, followers: { totalCount: faker.datatype.number(1000) }, following: { totalCount: faker.datatype.number(1000) }, issueComments: { totalCount: faker.datatype.number(1000) }, organizations: { totalCount: faker.datatype.number(10) }, }, //Plugins plugins: { //Tweets ...(set.plugins.enabled.tweets ? ({ tweets: { username: options["tweets.user"] || "(attached Twitter account)", profile: { profile_image_url: faker.image.people(), name: "", verified: false, id: faker.datatype.number(1000000).toString(), username: options["tweets.user"] || "(attached Twitter account)", profile_image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", }, list: [ { id: faker.datatype.number(100000000000000).toString(), created_at: faker.date.recent(), entities: { mentions: [{ start: 22, end: 33, username: "lowlighter" }], }, text: 'Checkout metrics from @lowlighter ! #GitHub ', mentions: ["lowlighter"], }, ...new Array(Number(options["tweets.limit"]) - 1).fill(null).map(_ => ({ id: faker.datatype.number(100000000000000).toString(), created_at: faker.date.recent(), text: faker.lorem.paragraph(), mentions: [], })), ], }, }) : null), //Lines ...(set.plugins.enabled.lines ? ({ lines: { added: `${faker.datatype.number(100)}.${faker.datatype.number(9)}k`, deleted: `${faker.datatype.number(100)}.${faker.datatype.number(9)}k`, }, }) : null), //Traffic ...(set.plugins.enabled.traffic ? ({ traffic: { views: { count: `${faker.datatype.number({ min: 10, max: 100 })}.${faker.datatype.number(9)}k`, uniques: `${faker.datatype.number(10)}.${faker.datatype.number(9)}k`, }, }, }) : null), //Follow-up ...(set.plugins.enabled.followup ? ({ followup: { sections: options["followup.sections"].split(",").map(x => x.trim()).filter(x => ["user", "repositories"].includes(x)), issues: { get count() { return this.open + this.closed }, open: faker.datatype.number(1000), closed: faker.datatype.number(1000), }, pr: { get count() { return this.open + this.merged }, open: faker.datatype.number(1000), closed: faker.datatype.number(1000), merged: faker.datatype.number(1000), }, user: { issues: { get count() { return this.open + this.closed }, open: faker.datatype.number(1000), closed: faker.datatype.number(1000), }, pr: { get count() { return this.open + this.merged }, open: faker.datatype.number(1000), closed: faker.datatype.number(1000), merged: faker.datatype.number(1000), }, }, }, }) : null), //Notable ...(set.plugins.enabled.notable ? ({ notable: { contributions: new Array(2 + faker.datatype.number(2)).fill(null).map(_ => ({ name: `${options["notable.repositories"] ? `${faker.lorem.slug()}/` : ""}${faker.lorem.slug()}`, avatar: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==" })), }, }) : null), //Gists ...(set.plugins.enabled.gists ? ({ gists: { totalCount: faker.datatype.number(100), stargazers: faker.datatype.number(1000), forks: faker.datatype.number(100), files: faker.datatype.number(100), comments: faker.datatype.number(1000), }, }) : null), //Reactions ...(set.plugins.enabled.reactions ? ({ reactions: { list: { HEART: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, THUMBS_UP: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, THUMBS_DOWN: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, LAUGH: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, CONFUSED: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, EYES: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, ROCKET: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, HOORAY: { value: faker.datatype.number(100), get percentage() { return this.score }, score: faker.datatype.number(100) / 100, }, }, comments: options["reactions.limit"], details: options["reactions.details"], days: options["reactions.days"], }, }) : null), //Achievements ...(set.plugins.enabled.achievements ? ({ achievements: { display: options["achievements.display"], list: new Array(8).fill(null).map(_ => ({ prefix: "", title: faker.lorem.word(), unlock: null, text: faker.lorem.sentence(), get icon() { const colors = {S:["#FF0000", "#FF8500"], A:["#B59151", "#FFD576"], B:["#7D6CFF", "#B2A8FF"], C:["#2088FF", "#79B8FF"], $:["#FF48BD", "#FF92D8"], X:["#7A7A7A", "#B0B0B0"]} return `` .replace(/#primary/g, colors[this.rank][0]) .replace(/#secondary/g, colors[this.rank][1]) }, rank: faker.random.arrayElement(["A", "B", "C", "X", "$"]), progress: faker.datatype.number(100) / 100, value: faker.datatype.number(1000), })) .filter(({ rank }) => options["achievements.secrets"] ? true : rank !== "$") .filter(({ rank }) => ({ S: 5, A: 4, B: 3, C: 2, $: 1, X: 0 }[rank] >= { S: 5, A: 4, B: 3, C: 2, $: 1, X: 0 }[options["achievements.threshold"]])) .sort((a, b) => ({ S: 5, A: 4, B: 3, C: 2, $: 1, X: 0 }[b.rank] + b.progress * 0.99) - ({ S: 5, A: 4, B: 3, C: 2, $: 1, X: 0 }[a.rank] + a.progress * 0.99)) .slice(0, options["achievements.limit"] || Infinity), }, }) : null), //Introduction ...(set.plugins.enabled.introduction ? ({ introduction: { mode: "user", title: options["introduction.title"], text: faker.lorem.sentences(), }, }) : null), //Code snippet ...(set.plugins.enabled.code ? ({ code: { snippet: { sha: faker.git.shortSha(), message: faker.lorem.sentence(), filename: 'docs/specifications.html', status: "modified", additions: faker.datatype.number(50), deletions: faker.datatype.number(50), patch: `@@ -0,0 +1,5 @@
//Imports
+ import app from "./src/app.mjs"
- import app from "./src/app.js"
//Start app
await app()
\\ No newline at end of file`, repo: `${faker.random.word()}/${faker.random.word()}`, }, } }) : null), //Sponsors ...(set.plugins.enabled.sponsors ? ({ sponsors: { sections: options["sponsors.sections"].split(",").map(x => x.trim()), about: "A new way to contribute to open source", list: new Array(Number(faker.datatype.number(40))).fill(null).map(_ => ({ login: faker.internet.userName(), amount: faker.datatype.number(10), avatar: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), count: faker.datatype.number(100), goal: { progress: faker.datatype.number(100), title: `$${faker.datatype.number(100)*10} per month`, description: "Invest in the software that powers your world" } } }) : null), //Languages ...(set.plugins.enabled.languages ? ({ languages: { unique: faker.datatype.number(50), sections: options["languages.sections"].split(", ").map(x => x.trim()).filter(x => /^(most-used|recently-used)$/.test(x)), details: options["languages.details"].split(",").map(x => x.trim()).filter(x => x), get colors() { return Object.fromEntries(Object.entries(this.favorites).map(([key, { color }]) => [key, color])) }, total: faker.datatype.number(10000), get stats() { return Object.fromEntries(Object.entries(this.favorites).map(([key, { value }]) => [key, value])) }, ["stats.recent"]:{ total: faker.datatype.number(10000), get lines() { return Object.fromEntries(Object.entries(this.favorites).map(([key, { value }]) => [key, value])) }, get stats() { return Object.fromEntries(Object.entries(this.favorites).map(([key, { value }]) => [key, value])) }, commits:faker.datatype.number(500), files:faker.datatype.number(1000), days:Number(options["languages.recent.days"]) }, favorites: distribution(7).map((value, index, array) => ({ name: faker.lorem.word(), color: faker.internet.color(), value, size: faker.datatype.number(1000000), x: array.slice(0, index).reduce((a, b) => a + b, 0) })), recent: distribution(7).map((value, index, array) => ({ name: faker.lorem.word(), color: faker.internet.color(), value, size: faker.datatype.number(1000000), x: array.slice(0, index).reduce((a, b) => a + b, 0) })), }, }) : null), //RSS ...(set.plugins.enabled.rss ? ({ rss: { source: faker.lorem.words(), description: faker.lorem.paragraph(), link: options["rss.source"], feed: new Array(Number(options["rss.limit"])).fill(null).map(_ => ({ title: faker.lorem.sentence(), date: faker.date.recent(), })), }, }) : null), //Stock price ...(set.plugins.enabled.stock ? ({ stock: { chart: "(stock chart is not displayed in placeholder)", currency: "USD", price: faker.datatype.number(10000) / 100, previous: faker.datatype.number(10000) / 100, get delta() { return this.price - this.previous }, symbol: options["stock.symbol"], company: faker.company.companyName(), interval: options["stock.interval"], duration: options["stock.duration"], }, }) : null), //Habits ...(set.plugins.enabled.habits ? ({ habits: { facts: options["habits.facts"], charts: options["habits.charts"], trim: options["habits.trim"], lines: { average: { chars: faker.datatype.number(1000)/10, } }, commits: { get hour() { return Object.keys(this.hours).filter(key => /^\d+$/.test(key)).map(key => [key, this.hours[key]]).sort((a, b) => b[1] - a[1]).shift()?.[0] }, hours: { [faker.datatype.number(24)]: faker.datatype.number(10), [faker.datatype.number(24)]: faker.datatype.number(10), [faker.datatype.number(24)]: faker.datatype.number(10), [faker.datatype.number(24)]: faker.datatype.number(10), [faker.datatype.number(24)]: faker.datatype.number(10), [faker.datatype.number(24)]: faker.datatype.number(10), [faker.datatype.number(24)]: faker.datatype.number(10), get max() { return Object.keys(this).filter(key => /^\d+$/.test(key)).map(key => [key, this[key]]).sort((a, b) => b[1] - a[1]).shift()?.[1] }, }, get day() { return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][Object.keys(this.days).filter(key => /^\d+$/.test(key)).map(key => [key, this.days[key]]).sort((a, b) => b[1] - a[1]).shift()?.[0]] }, days: { "0": faker.datatype.number(10), "1": faker.datatype.number(10), "2": faker.datatype.number(10), "3": faker.datatype.number(10), "4": faker.datatype.number(10), "5": faker.datatype.number(10), "6": faker.datatype.number(10), get max() { return Object.keys(this).filter(key => /^\d+$/.test(key)).map(key => [key, this[key]]).sort((a, b) => b[1] - a[1]).shift()?.[1] }, }, }, indents: { style: "spaces", spaces: 1, tabs: 0 }, linguist: { available: true, get ordered() { return Object.entries(this.languages) }, get languages() { return Object.fromEntries(distribution(4).map(value => [faker.lorem.word(), value])) }, }, }, }) : null), //People ...(set.plugins.enabled.people ? ({ get people() { const types = options["people.types"].split(",").map(x => x.trim()) .map(x => ({ followed: "following", sponsors: "sponsorshipsAsMaintainer", sponsored: "sponsorshipsAsSponsor", sponsoring: "sponsorshipsAsSponsor" })[x] ?? x) .filter(x => ["followers", "following", "sponsorshipsAsMaintainer", "sponsorshipsAsSponsor"].includes(x)) return { types, size: options["people.size"], ...(Object.fromEntries(types.map(type => [ type, new Array(Number(options["people.limit"])).fill(null).map(_ => ({ login: faker.internet.userName(), avatar: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), ]))), thanks: options["people.thanks"].split(",").map(x => x.trim()).map(login => ({ login, avatar: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), } }, }) : null), //Music ...(set.plugins.enabled.music ? ({ music: { provider: "(music provider)", mode: "Suggested tracks", tracks: new Array(Number(options["music.limit"])).fill(null).map(_ => ({ name: faker.random.words(5), artist: faker.random.words(), artwork: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), }, }) : null), //Nightscout ...(set.plugins.enabled.nightscout ? ({ nightscout: { url: options["nightscout.url"] != null && options["nightscout.url"] != "https://example.herokuapp.com" ? options["nightscout.url"] : "https://testapp.herokuapp.com/", data: new Array(12).fill(null).map(_ => ({ timeUTCHumanReadable: `${new Date().getUTCHours()}:${new Date().getUTCMinutes()}`, color: faker.random.arrayElement(["#9be9a8", "#40c463", "#30a14e", "#216e39"]), sgv: faker.datatype.number({ min: 40, max: 400 }), delta: faker.datatype.number({ min: -10, max: 10 }), direction: faker.random.arrayElement(["SingleUp", "DoubleUp", "FortyFiveUp", "Flat", "FortyFiveDown", "SingleDown", "DoubleDown"]), alert: faker.random.arrayElement(["Normal", "Urgent High", "Urgent Low", "High", "Low"]), arrowHumanReadable: faker.random.arrayElement(["↑↑", "↑", "↗", "→", "↘", "↓", "↓↓"]), })), }, }) : null), //Pagespeed ...(set.plugins.enabled.pagespeed ? ({ pagespeed: { url: options["pagespeed.url"] || "(attached website url)", detailed: options["pagespeed.detailed"] || false, scores: [ { score: faker.datatype.float({ max: 1 }), title: "Performance" }, { score: faker.datatype.float({ max: 1 }), title: "Accessibility" }, { score: faker.datatype.float({ max: 1 }), title: "Best Practices" }, { score: faker.datatype.float({ max: 1 }), title: "SEO" }, ], metrics: { observedFirstContentfulPaint: faker.datatype.number(500), observedFirstVisualChangeTs: faker.time.recent(), observedFirstContentfulPaintTs: faker.time.recent(), firstContentfulPaint: faker.datatype.number(500), observedDomContentLoaded: faker.datatype.number(500), observedFirstMeaningfulPaint: faker.datatype.number(1000), maxPotentialFID: faker.datatype.number(500), observedLoad: faker.datatype.number(500), firstMeaningfulPaint: faker.datatype.number(500), observedCumulativeLayoutShift: faker.datatype.float({ max: 1 }), observedSpeedIndex: faker.datatype.number(1000), observedSpeedIndexTs: faker.time.recent(), observedTimeOriginTs: faker.time.recent(), observedLargestContentfulPaint: faker.datatype.number(1000), cumulativeLayoutShift: faker.datatype.float({ max: 1 }), observedFirstPaintTs: faker.time.recent(), observedTraceEndTs: faker.time.recent(), largestContentfulPaint: faker.datatype.number(2000), observedTimeOrigin: faker.datatype.number(10), speedIndex: faker.datatype.number(1000), observedTraceEnd: faker.datatype.number(2000), observedDomContentLoadedTs: faker.time.recent(), observedFirstPaint: faker.datatype.number(500), totalBlockingTime: faker.datatype.number(500), observedLastVisualChangeTs: faker.time.recent(), observedFirstVisualChange: faker.datatype.number(500), observedLargestContentfulPaintTs: faker.time.recent(), estimatedInputLatency: faker.datatype.number(100), observedLoadTs: faker.time.recent(), observedLastVisualChange: faker.datatype.number(1000), firstCPUIdle: faker.datatype.number(1000), interactive: faker.datatype.number(1000), observedNavigationStartTs: faker.time.recent(), observedNavigationStart: faker.datatype.number(10), observedFirstMeaningfulPaintTs: faker.time.recent(), }, screenshot: options["pagespeed.screenshot"] ? "data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==" : null, }, }) : null), //Projects ...(set.plugins.enabled.projects ? ({ projects: { totalCount: options["projects.limit"] + faker.datatype.number(10), descriptions: options["projects.descriptions"], list: new Array(Number(options["projects.limit"])).fill(null).map(_ => ({ name: faker.lorem.sentence(), description: faker.lorem.paragraph(), updated: `${2 + faker.datatype.number(8)} days ago`, progress: { enabled: true, todo: faker.datatype.number(50), doing: faker.datatype.number(50), done: faker.datatype.number(50), get total() { return this.todo + this.doing + this.done }, }, })), }, }) : null), //Discussions ...(set.plugins.enabled.discussions ? ({ discussions: { categories: { stats: { '🙏 Q&A': faker.datatype.number(100), '📣 Announcements': faker.datatype.number(100), '💡 Ideas': faker.datatype.number(100), '💬 General': faker.datatype.number(100) }, favorite: '📣 Announcements' }, upvotes: { discussions:faker.datatype.number(1000), comments: faker.datatype.number(1000) }, started: faker.datatype.number(1000), comments: faker.datatype.number(1000), answers: faker.datatype.number(1000), }, }) : null), //Posts ...(set.plugins.enabled.posts ? ({ posts: { source: options["posts.source"], descriptions: options["posts.descriptions"], covers: options["posts.covers"], list: new Array(Number(options["posts.limit"])).fill(null).map(_ => ({ title: faker.lorem.sentence(), description: faker.lorem.paragraph(), date: faker.date.recent(), image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), }, }) : null), //Topics ...(set.plugins.enabled.topics ? ({ topics: { mode: options["topics.mode"], list: new Array(Number(options["topics.limit"]) || 20).fill(null).map(_ => ({ name: faker.lorem.words(2), description: faker.lorem.sentence(), icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), }, }) : null), //Stars ...(set.plugins.enabled.stars ? ({ stars: { repositories: [ { starredAt: faker.date.recent(), node: { description: "📊 An image generator with 20+ metrics about your GitHub account such as activity, community, repositories, coding habits, website performances, music played, starred topics, etc. that you can put on your profile or elsewhere !", forkCount: faker.datatype.number(100), isFork: false, issues: { totalCount: faker.datatype.number(100), }, nameWithOwner: "lowlighter/metrics", openGraphImageUrl: "https://repository-images.githubusercontent.com/293860197/7fd72080-496d-11eb-8fe0-238b38a0746a", pullRequests: { totalCount: faker.datatype.number(100), }, stargazerCount: faker.datatype.number(10000), licenseInfo: { nickname: null, name: "MIT License" }, primaryLanguage: { color: "#f1e05a", name: "JavaScript" }, }, starred: "1 day ago", }, ...new Array(Number(options["stars.limit"]) - 1).fill(null).map((_, i) => ({ starredAt: faker.date.recent(), node: { description: faker.lorem.sentence(), forkCount: faker.datatype.number(100), isFork: faker.datatype.boolean(), issues: { totalCount: faker.datatype.number(100), }, nameWithOwner: `${faker.random.word()}/${faker.random.word()}`, openGraphImageUrl: faker.internet.url(), pullRequests: { totalCount: faker.datatype.number(100), }, stargazerCount: faker.datatype.number(10000), licenseInfo: { nickname: null, name: "License" }, primaryLanguage: { color: faker.internet.color(), name: faker.lorem.word() }, }, starred: `${i + 2} days ago`, })), ], }, }) : null), //Repositories ...(set.plugins.enabled.repositories ? ({ repositories: { list: new Array(Number(options["repositories.featured"].split(",").length) - 1).fill(null).map((_, i) => ({ created: faker.date.past(), description: faker.lorem.sentence(), forkCount: faker.datatype.number(100), isFork: faker.datatype.boolean(), issues: { totalCount: faker.datatype.number(100), }, nameWithOwner: `${faker.random.word()}/${faker.random.word()}`, openGraphImageUrl: faker.internet.url(), pullRequests: { totalCount: faker.datatype.number(100), }, stargazerCount: faker.datatype.number(10000), licenseInfo: { nickname: null, name: "License" }, primaryLanguage: { color: faker.internet.color(), name: faker.lorem.word() }, })), }, }) : null), //Stargazers ...(set.plugins.enabled.stargazers ? ({ get stargazers() { const dates = [] let total = faker.datatype.number(1000) const result = { total: { dates: {}, get max() { return Math.max(...dates.map(date => this.dates[date])) }, get min() { return Math.min(...dates.map(date => this.dates[date])) }, }, increments: { dates: {}, get max() { return Math.max(...dates.map(date => this.dates[date])) }, get min() { return Math.min(...dates.map(date => this.dates[date])) }, }, months: ["", "Jan.", "Feb.", "Mar.", "Apr.", "May", "June", "July", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."], } for (let d = -14; d <= 0; d++) { const date = new Date(Date.now() - d * 24 * 60 * 60 * 1000).toISOString().substring(0, 10) dates.push(date) result.total.dates[date] = (total += (result.increments.dates[date] = faker.datatype.number(100))) } return result }, }) : null), //Wakatime ...(set.plugins.enabled.wakatime ? ({ get wakatime() { const stats = array => { const elements = [] let results = new Array(4 + faker.datatype.number(2)).fill(null).map(_ => ({ name: array ? faker.random.arrayElement(array) : faker.random.words(2).replace(/ /g, "-").toLocaleLowerCase(), percent: 0, total_seconds: faker.datatype.number(1000000), })) let percents = 100 for (const result of results) { result.percent = 1 + faker.datatype.number(percents - 1) percents -= result.percent result.percent /= 100 } results.filter(({ name }) => elements.includes(name) ? false : (elements.push(name), true)) return results.sort((a, b) => b.percent - a.percent) } return { sections: options["wakatime.sections"].split(",").map(x => x.trim()).filter(x => x), days: Number(options["wakatime.days"]) || 7, time: { total: faker.datatype.number(100000), daily: faker.datatype.number(24) }, editors: stats(["VS Code", "Chrome", "IntelliJ", "PhpStorm", "WebStorm", "Android Studio", "Visual Studio", "Sublime Text", "PyCharm", "Vim", "Atom", "Xcode"]), languages: stats(["JavaScript", "TypeScript", "PHP", "Java", "Python", "Vue.js", "HTML", "C#", "JSON", "Dart", "SCSS", "Kotlin", "JSX", "Go", "Ruby", "YAML"]), projects: stats(), os: stats(["Mac", "Windows", "Linux"]), } }, }) : null), //Anilist ...(set.plugins.enabled.anilist ? ({ anilist: { user: { stats: { anime: { count: faker.datatype.number(1000), minutesWatched: faker.datatype.number(100000), episodesWatched: faker.datatype.number(10000), genres: new Array(4).fill(null).map(_ => ({ genre: faker.lorem.word() })), }, manga: { count: faker.datatype.number(1000), chaptersRead: faker.datatype.number(100000), volumesRead: faker.datatype.number(10000), genres: new Array(4).fill(null).map(_ => ({ genre: faker.lorem.word() })), }, }, genres: new Array(4).fill(null).map(_ => ({ genre: faker.lorem.word() })), }, get lists() { const media = type => ({ name: faker.lorem.words(), type, status: faker.random.arrayElement(["FINISHED", "RELEASING", "NOT_YET_RELEASED", "CANCELLED", "HIATUS"]), release: faker.date.past(20).getFullYear(), genres: new Array(6).fill(null).map(_ => faker.lorem.word()), progress: faker.datatype.number(100), description: faker.lorem.paragraphs(), scores: { user: faker.datatype.number(100), community: faker.datatype.number(100) }, released: 100 + faker.datatype.number(1000), artwork: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", }) const sections = options["anilist.sections"].split(",").map(x => x.trim()).filter(x => x) const medias = options["anilist.medias"].split(",").map(x => x.trim()).filter(x => x) return { ...(medias.includes("anime") ? { anime: { ...(sections.includes("watching") ? { watching: new Array(Number(options["anilist.limit"]) || 4).fill(null).map(_ => media("ANIME")) } : {}), ...(sections.includes("favorites") ? { favorites: new Array(Number(options["anilist.limit"]) || 4).fill(null).map(_ => media("ANIME")) } : {}), }, } : {}), ...(medias.includes("manga") ? { manga: { ...(sections.includes("reading") ? { reading: new Array(Number(options["anilist.limit"]) || 4).fill(null).map(_ => media("MANGA")) } : {}), ...(sections.includes("favorites") ? { favorites: new Array(Number(options["anilist.limit"]) || 4).fill(null).map(_ => media("MANGA")) } : {}), }, } : {}), } }, characters: new Array(11).fill(null).map(_ => ({ name: faker.name.findName(), artwork: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", })), sections: options["anilist.sections"].split(",").map(x => x.trim()).filter(x => x), }, }) : null), //Activity ...(set.plugins.enabled.activity ? ({ activity: { timestamps: options["activity.timestamps"], events: new Array(Number(options["activity.limit"])).fill(null).map(_ => [ { type: "push", repo: `${faker.random.word()}/${faker.random.word()}`, size: 1, branch: "master", commits: [{ sha: faker.git.shortSha(), message: faker.lorem.sentence() }], timestamp: faker.date.recent(), }, { type: "comment", on: "commit", repo: `${faker.random.word()}/${faker.random.word()}`, content: faker.lorem.paragraph(), user: set.user, mobile: null, number: faker.git.shortSha(), title: "", timestamp: faker.date.recent(), }, { type: "comment", on: "pr", repo: `${faker.random.word()}/${faker.random.word()}`, content: faker.lorem.sentence(), user: set.user, mobile: null, number: faker.datatype.number(100), title: faker.lorem.sentence(), timestamp: faker.date.recent(), }, { type: "comment", on: "issue", repo: `${faker.random.word()}/${faker.random.word()}`, content: faker.lorem.sentence(), user: set.user, mobile: null, number: faker.datatype.number(100), title: faker.lorem.sentence(), timestamp: faker.date.recent(), }, { type: "issue", repo: `${faker.random.word()}/${faker.random.word()}`, action: faker.random.arrayElement(["opened", "closed", "reopened"]), user: set.user, number: faker.datatype.number(100), title: faker.lorem.sentence(), timestamp: faker.date.recent(), }, { type: "pr", repo: `${faker.random.word()}/${faker.random.word()}`, action: faker.random.arrayElement(["opened", "closed"]), user: set.user, number: faker.datatype.number(100), title: faker.lorem.sentence(), lines: { added: faker.datatype.number(1000), deleted: faker.datatype.number(1000) }, files: { changed: faker.datatype.number(10) }, timestamp: faker.date.recent(), }, { type: "wiki", repo: `${faker.random.word()}/${faker.random.word()}`, pages: [faker.lorem.sentence(), faker.lorem.sentence()], timestamp: faker.date.recent(), }, { type: "fork", repo: `${faker.random.word()}/${faker.random.word()}`, timestamp: faker.date.recent(), }, { type: "review", repo: `${faker.random.word()}/${faker.random.word()}`, user: set.user, number: faker.datatype.number(100), title: faker.lorem.sentence(), timestamp: faker.date.recent(), }, { type: "release", repo: `${faker.random.word()}/${faker.random.word()}`, action: "published", name: faker.random.words(4), draft: faker.datatype.boolean(), prerelease: faker.datatype.boolean(), timestamp: faker.date.recent(), }, { type: "ref/create", repo: `${faker.random.word()}/${faker.random.word()}`, ref: { name: faker.lorem.slug(), type: faker.random.arrayElement(["tag", "branch"]) }, timestamp: faker.date.recent(), }, { type: "ref/delete", repo: `${faker.random.word()}/${faker.random.word()}`, ref: { name: faker.lorem.slug(), type: faker.random.arrayElement(["tag", "branch"]) }, timestamp: faker.date.recent(), }, { type: "member", repo: `${faker.random.word()}/${faker.random.word()}`, user: set.user, timestamp: faker.date.recent(), }, { type: "public", repo: `${faker.random.word()}/${faker.random.word()}`, timestamp: faker.date.recent(), }, { type: "star", repo: `${faker.random.word()}/${faker.random.word()}`, action: "started", timestamp: faker.date.recent(), }, ][Math.floor(Math.random() * 15)] ), }, }) : null), //Isocalendar ...(set.plugins.enabled.isocalendar ? ({ isocalendar: { streak: { max: 30 + faker.datatype.number(20), current: faker.datatype.number(30) }, max: 10 + faker.datatype.number(40), average: faker.datatype.float(10), svg: "(isometric calendar is not displayed in placeholder)", duration: options["isocalendar.duration"], }, }) : null), //Support ...(set.plugins.enabled.support ? ({ support: { stats: { solutions: faker.datatype.number(100), posts: faker.datatype.number(1000), topics: faker.datatype.number(1000), received: faker.datatype.number(1000), hearts: faker.datatype.number(1000) }, badges: { uniques: [ ], multiples: [], count: faker.datatype.number(1000) } }, }) : null), //Screenshot ...(set.plugins.enabled.screenshot ? ({ screenshot: { image:"data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", title: options["screenshot.title"], height: 440, width: 454, }, }) : null), //Skyline ...(set.plugins.enabled.skyline ? ({ skyline: { animation:"data:image/jpg;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==", width: 454, height: 284, compatibility: false }, }) : null), //Stackoverflow ...(set.plugins.enabled.stackoverflow ? ({ stackoverflow: { sections: options["stackoverflow.sections"].split(",").map(x => x.trim()).filter(x => x), lines: options["stackoverflow.lines"], user: { reputation: faker.datatype.number(100000), badges: faker.datatype.number(1000), questions: faker.datatype.number(1000), answers: faker.datatype.number(1000), comments: faker.datatype.number(1000), views: faker.datatype.number(1000), }, "answers-top": new Array(options["stackoverflow.limit"]).fill(null).map(_ => ({ type: "answer", body: faker.lorem.paragraphs(), score: faker.datatype.number(1000), upvotes: faker.datatype.number(1000), downvotes: faker.datatype.number(1000), accepted: faker.datatype.boolean(), comments: faker.datatype.number(1000), author: set.user, created: "01/01/1970", link: null, id: faker.datatype.number(100000), question_id: faker.datatype.number(100000), question: { title: faker.lorem.sentence(), tags: [faker.lorem.slug(), faker.lorem.slug()], }, })), get ["answers-recent"]() { return this["answers-top"] }, "questions-top": new Array(options["stackoverflow.limit"]).fill(null).map(_ => ({ type: "question", title: faker.lorem.sentence(), body: faker.lorem.paragraphs(), score: faker.datatype.number(1000), upvotes: faker.datatype.number(1000), downvotes: faker.datatype.number(1000), favorites: faker.datatype.number(1000), tags: [faker.lorem.slug(), faker.lorem.slug()], answered: faker.datatype.boolean(), answers: faker.datatype.number(1000), comments: faker.datatype.number(1000), views: faker.datatype.number(1000), author: set.user, created: "01/01/1970", link: null, id: faker.datatype.number(100000), accepted_answer_id: faker.datatype.number(100000), answer: null, })), get ["questions-recent"]() { return this["questions-top"] }, }, }) : null), }, } //Formatters data.f.bytes = function(n) { for (const { u, v } of [{ u: "E", v: 10 ** 18 }, { u: "P", v: 10 ** 15 }, { u: "T", v: 10 ** 12 }, { u: "G", v: 10 ** 9 }, { u: "M", v: 10 ** 6 }, { u: "k", v: 10 ** 3 }]) { if (n / v >= 1) return `${(n / v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")} ${u}B` } return `${n} byte${n > 1 ? "s" : ""}` } data.f.percentage = function(n, { rescale = true } = {}) { return `${ (n * (rescale ? 100 : 1)).toFixed(2) .replace(/[.]([1-9]*)(0+)$/, (m, a, b) => `.${a}`) .replace(/[.]$/, "") }%` } data.f.ellipsis = function(text, { length = 20 } = {}) { text = `${text}` if (text.length < length) return text return `${text.substring(0, length)}…` } data.f.date = function(string, options) { if (options.date) { delete options.date Object.assign(options, {day:"numeric", month:"short", year:"numeric"}) } if (options.time) { delete options.time Object.assign(options, {hour:"2-digit", minute:"2-digit", second:"2-digit"}) } return new Intl.DateTimeFormat("en-GB", options).format(new Date(string)) } data.f.license = function(text) { return text?.name ?? text } //Render return await ejs.render(image, data, { async: true, rmWhitespace: true }) } //Reset globals contexts globalThis.placeholder.init = function(globals) { axios = globals.axios || axios faker = globals.faker || faker ejs = globals.ejs || ejs } })()