├── LICENSE ├── Translation ├── languages │ ├── en.json │ └── pt.json └── translate.js ├── abbreviateNumber.js ├── applyLineBreaks.js ├── chunkArray.js ├── convertAbbreviatedNum.js ├── convertMilliseconds.js ├── cycleThroughArray.js ├── didYouMean.js ├── extendedSetTimeout.js ├── formatTime.js ├── levelingSystem.js ├── lovePercentage.js ├── numberToFraction.js ├── placeholders.js ├── progressBar.js ├── randomColor.js ├── randomWithChances.js ├── removeDupeChars.js ├── repeatAction.js ├── stringSimilarity.js ├── tileizeString.js └── timeToMilliseconds.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 5antos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Translation/languages/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "person": { 3 | "name": "5antos", 4 | "age": 19, 5 | "job": { 6 | "name": "Software Engineer", 7 | "role": "CEO", 8 | "company": "Google" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Translation/languages/pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "person": { 3 | "name": "5antos", 4 | "age": 19, 5 | "job": { 6 | "name": "Engenheiro Informático", 7 | "role": "CEO", 8 | "company": "Google" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Translation/translate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @requires Node.js version 14 or above 4 | * @note The error 'Unexpected end of JSON input' will be thrown if there is any empty JSON 5 | * @param {object} path Path to the languages' folder (from the project's root) 6 | * @param {string} topic Topic to translate 7 | * @param {string} language Language to translate the provided topic to 8 | * @param {object} [bindTo=null] Object to bind the languages' JSONs (as a cache method) 9 | * @returns {string|null} Translated topic. Returns null if an invalid language or topic is provided 10 | */ 11 | 12 | const { readdirSync, readFileSync } = require('fs') 13 | 14 | function getTranslation(path, topic, language, bindTo=null) { 15 | const languages = bindTo?.translation?.languages || readdirSync(path).map(l => [l.slice(0,2)]) 16 | 17 | if (!languages.flat().includes(language)) return null 18 | 19 | for (var i = 0; i < languages.length; i++) 20 | languages[i][1] = JSON.parse(readFileSync(`${path}/${languages[i][0]}.json`, { encoding: 'utf8' }).replace(/\s|\r|\n|\t/g, ' ')) 21 | 22 | if (bindTo) { 23 | bindTo.translation = bindTo?.translation || {} // For Node.js v15+, this can be replaced with: bindTo.translation ??= {} 24 | bindTo.translation.languages = languages 25 | } 26 | 27 | return topic.replace(/:/g, '.').split('.').reduce((obj, curr) => obj?.[curr], languages[languages.findIndex(l => l[0] === language)][1]) || null 28 | } 29 | 30 | 31 | // Example Outputs: 32 | 33 | const Client = {} 34 | getTranslation('Translation/languages', 'person:job.name', 'en', Client) // Software Engineer, Client: { translation: { languages: [ [Array], [Array] ] } } 35 | 36 | getTranslation('Translation/languages', 'person:job.name', 'pt') // Engenheiro Informático 37 | getTranslation('Translation/languages', 'person:job.salary', 'en') // null (property "salary" does not exist on person.job) 38 | getTranslation('Translation/languages', 'person:name', 'fr') // null (invalid language) -------------------------------------------------------------------------------- /abbreviateNumber.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {number} number Number to abbreviate 4 | * @param {number} [precision=2] Number of decimal digits to be displayed 5 | * @returns {string} Abbreviated number 6 | */ 7 | 8 | function abbreviateNumber(number, precision=2) { 9 | return number.toLocaleString('en-US', { notation: 'compact', maximumFractionDigits: precision }) 10 | } 11 | 12 | 13 | // Example Outputs: 14 | 15 | abbreviateNumber(30600000) // 30.60M 16 | abbreviateNumber(500) // 500 17 | abbreviateNumber(175050) // 175.05K 18 | abbreviateNumber(5006500000) // 5.01B 19 | abbreviateNumber(5006600000, 3) // 5.007B 20 | abbreviateNumber(15000) // 15K 21 | -------------------------------------------------------------------------------- /applyLineBreaks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {string} string Target string 4 | * @param {number} maxCharLengthPerLine Maximum number of characters allowed per line 5 | * @returns {string} String after all line breaks applied 6 | */ 7 | 8 | function applyLineBreaks(string, maxCharLengthPerLine) { 9 | const split = string.split(' ') 10 | const chunks = [] 11 | 12 | for (var i=0, j=0; i < split.length; i++) { 13 | if ((chunks[j] + split[i]).length > maxCharLengthPerLine) j++ 14 | 15 | chunks[j] = (chunks[j] || '') + split[i] + ' ' 16 | } 17 | 18 | return chunks.map(c => c.trim()).join('\n') 19 | } 20 | 21 | 22 | // Example Outputs: 23 | 24 | applyLineBreaks('Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 30) 25 | /* 26 | Lorem ipsum dolor sit amet, 27 | consectetur adipiscing elit. 28 | */ 29 | 30 | applyLineBreaks('Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 20) 31 | /* 32 | Lorem ipsum dolor 33 | sit amet, 34 | consectetur 35 | adipiscing elit. 36 | */ 37 | -------------------------------------------------------------------------------- /chunkArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {any[]} array Array to be chunked 4 | * @param {number} count Length of each chunk 5 | * @returns {any[][]} Chunked array 6 | */ 7 | 8 | function chunkArray(array, count) { 9 | const newArr = [] 10 | for (var i = 0; i < array.length; i+=count) 11 | newArr[i/count] = array.slice(i, i+count) 12 | return newArr 13 | } 14 | 15 | // One-line version ("prettier" but slower) 16 | function chunkArray(array, count) { 17 | return array.reduce((acc, _, i, arr) => !(i%count) ? [...acc, arr.slice(i, i+count)] : acc, []) 18 | } 19 | 20 | 21 | // Example Outputs: 22 | 23 | chunkArray([1,2,3,4,5,6,7,8,9], 3) // [ [1,2,3], [4,5,6], [7,8,9] ] 24 | chunkArray([1,2,3,4,5,6,7,8,9], 4) // [ [1,2,3,4], [5,6,7,8], [9] ] 25 | chunkArray([1,2,3,4,5,6,7,8,9], 5) // [ [1,2,3,4,5], [6,7,8,9] ] 26 | -------------------------------------------------------------------------------- /convertAbbreviatedNum.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {string} abbreviation Abbreviated number, such as 15K or 1.5M, for example. Returns the number itself if provided without any unit 4 | * @returns {number} Converted number 5 | */ 6 | 7 | function convertAbbreviatedNum(abbreviation) { 8 | const number = parseFloat(abbreviation.substr(0, abbreviation.length-1)) 9 | const unit = abbreviation.substr(-1) 10 | const zeros = { K:1e3, M:1e6, B:1e9, T:1e12 } // K: thousand, M: million, B: billion, T: trillion 11 | 12 | return !zeros[unit] ? parseFloat(abbreviation) : number*zeros[unit] 13 | } 14 | 15 | 16 | // Example Outputs: 17 | 18 | convertAbbreviatedNum('30.6M') // 30600000 19 | convertAbbreviatedNum('5000') // 5000 20 | convertAbbreviatedNum('175.05K') // 175050 21 | -------------------------------------------------------------------------------- /convertMilliseconds.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {number} ms Time value in milliseconds 4 | * @returns {object} Object with the converted time in days, hours, minutes and seconds 5 | */ 6 | 7 | function convertMilliseconds(ms) { 8 | const seconds = ~~(ms/1000) 9 | const minutes = ~~(seconds/60) 10 | const hours = ~~(minutes/60) 11 | const days = ~~(hours/24) 12 | 13 | return { days, hours: hours%24, minutes: minutes%60, seconds: seconds%60 } 14 | } 15 | 16 | 17 | // Example Outputs: 18 | 19 | convertMilliseconds(527988000) // { days: 6, hours: 2, minutes: 39, seconds: 48 } 20 | convertMilliseconds(1020000) // { days: 0, hours: 0, minutes: 17, seconds: 0 } 21 | convertMilliseconds(1.45e10) // { days: 167, hours: 19, minutes: 46, seconds: 40 } 22 | convertMilliseconds(1.42006167e12) // { days: 16435, hours: 21, minutes: 34, seconds: 30 } 23 | -------------------------------------------------------------------------------- /cycleThroughArray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @callback cb 3 | * @param {number} intervalID Created interval's timer ID, useful to clear the interval when desired 4 | * @param {*} arrayElement Array element each cycle 5 | */ 6 | 7 | /** 8 | * @author 5antos#4876 9 | * @param {any[]} array Array to cycle through 10 | * @param {number} delay Delay, in milliseconds, between each call on an array's element 11 | * @param {cb} callback Function to call on each array element 12 | * @returns {void} 13 | */ 14 | 15 | function cycle(array, delay, callback) { 16 | let i = 0 17 | const interval = setInterval(() => callback(interval, array[(i++) % (array.length)]), delay) 18 | } 19 | 20 | 21 | // Usage Examples: 22 | 23 | // Prints every element from the array with a delay of 1 second, cycling through 24 | cycle([1,2,3,4,5], 1000, (_, element) => { 25 | console.log(element) 26 | }) 27 | 28 | // Prints each element from the array with a delay of 3 seconds, cycling through, clearing the interval when the value 5 is found 29 | cycle([1,2,3,4,5], 3000, (intervalID, element) => { 30 | if (element === 5) clearInterval(intervalID) 31 | console.log(element) 32 | }) 33 | -------------------------------------------------------------------------------- /didYouMean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The checkSimilarity function can be found in this repository (https://github.com/5antos/JS-Randomness/blob/master/stringSimilarity.js). 3 | * You can also write your own checkSimilarity function, just make sure that the function's return type should be a number between 0 and 1 4 | * @author 5antos#4876 5 | * @param {string} str Input string 6 | * @param {string[]} array Array of strings corresponding to potential matches 7 | * @param {number} [threshold=60] This function will only consider strings with similarity values of % or more. Defaults to 60% (recommended) 8 | * @returns {string|null} String most similar to the input string. Returns null if no string is found according to the threshold value 9 | */ 10 | 11 | function didYouMean(str, array, threshold=60) { 12 | const acceptable = array 13 | .map(e => { return {e, v: checkSimilarity(str, e)} }) 14 | .filter(({v}) => v >= threshold/100) 15 | 16 | return !acceptable.length ? null : acceptable.reduce((acc, curr) => curr.v > acc.v ? curr : acc).e 17 | } 18 | 19 | 20 | // Example Outputs: 21 | 22 | didYouMean('hekp', ['goodbye', 'hello', 'help']) // help 23 | didYouMean('dodgeball', ['pencil', 'avocado', 'supermarket']) // null 24 | didYouMean('intsagrm', ['facebook', 'instagram', 'twitter', 'linkedin', 'github']) // instagram 25 | -------------------------------------------------------------------------------- /extendedSetTimeout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This method comes handy when you need to create time outs with a duration bigger than the maximum allowed 3 | * duration for the NodeJS in-built method setTimeout (2147483647 = (2^31)-1) 4 | * 5 | * @author 5antos#4876 6 | * @param {function} callback Function to run when the timer ends 7 | * @param {number} ms Time value in milliseconds (timer) 8 | * @returns {void} 9 | */ 10 | 11 | function extendedSetTimeout(callback, ms) { 12 | const biggestInt = (2**31)-1 13 | const max = ms > biggestInt ? biggestInt : ms 14 | 15 | setTimeout(() => ms > max ? extendedSetTimeout(callback, ms - max) : callback(), max) 16 | } 17 | 18 | 19 | // Example Outputs (extendedSetTimeout VS setTimeout): 20 | 21 | extendedSetTimeout(() => console.log('5 years later!'), 1.5778463e11) // [👍] Outputs '5 years later!' after 5 years... if your application remains online the entire time 22 | setTimeout(() => console.log('5 years later?'), 1.5778463e11) // [👎] Outputs a warning because the provided duration exceeds the maximum allowed duration for this method -------------------------------------------------------------------------------- /formatTime.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {object} time Object returned from the convertMilliseconds function (available in this repository) or equivalent 4 | * @param {string} [format="dd:hh:mm:ss"] Format to display 5 | * @returns {string} Formatted string 6 | */ 7 | 8 | function formatTime(time, format='dd:hh:mm:ss') { 9 | const formats = { dd:'days', hh:'hours', mm:'minutes', ss:'seconds' } 10 | 11 | const newFormat = format 12 | .replace(/dd|hh|mm|ss/g, match => time[formats[match]].toString().padStart(2, '0')) 13 | .replace(/^(00:)+/g, '') 14 | 15 | return newFormat.length > 2 ? newFormat : '00:'+newFormat 16 | } 17 | 18 | function autoFormatTime(time) { 19 | return Object.entries(time) 20 | .filter(e => e[1]) 21 | .map(e => ([e[0].slice(0, -1).padEnd(e[1] > 1 ? e[0].length : 0, 's'), e[1]])) 22 | .map((e,i,a) => (i === a.length-1 && a.length > 1) ? `and ${e[1]} ${e[0]}` : (i === a.length-2 || a.length === 1) ? `${e[1]} ${e[0]}` : `${e[1]} ${e[0]},`) 23 | .join(' ') 24 | || '0 seconds' 25 | } 26 | 27 | 28 | // Example Outputs: 29 | 30 | formatTime(convertMilliseconds(1_020_000)) // 17:00 31 | formatTime(convertMilliseconds(6_350_676)) // 01:45:50 32 | formatTime(convertMilliseconds(5_278_988_000), 'dd days, hh:mm:ss') // 61 days, 02:23:08 33 | formatTime({ days: 0, hours: 8, minutes: 0, seconds: 15 }) // 08:00:15 34 | 35 | autoFormatTime(convertMilliseconds(104_490_000)) // 1 day, 5 hours, 1 minute and 30 seconds 36 | autoFormatTime(convertMilliseconds(0)) // 0 seconds 37 | autoFormatTime({ days: 0, hours: 1, minutes: 30, seconds: 0 }) // 1 hour and 30 minutes 38 | autoFormatTime({ days: 14, hours: 8, minutes: 0, seconds: 1 }) // 14 days, 8 hours and 1 second 39 | -------------------------------------------------------------------------------- /levelingSystem.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {number} xp User's current amount of experience points (xp) 4 | * @note It's recommended to set the difficuly value as an integer bigger than 0. The bigger the difficulty value is, the harder is to level up 5 | * @note It's also recommended to set the xp amount given to the users as a constant number, or a number between two constant limits (Examples: 3xp, 0-10xp) 6 | * @returns {object} Object with information about the current level and the next level 7 | */ 8 | 9 | function calculateLevels(xp) { 10 | const difficulty = 50 11 | const startingLvl = 1 12 | const level = ~~(Math.log2(xp/difficulty+1))+startingLvl 13 | const nextLvlXp = difficulty*((2**level)-startingLvl) 14 | 15 | return { current:{ level: level, xp: xp }, next:{ level: level+1, xp: nextLvlXp }, toNextLevel: nextLvlXp-xp } 16 | } 17 | 18 | 19 | // Example Outputs: 20 | 21 | // Default level up (difficulty=50) 22 | calculateLevels(0) // { current:{ level: 1, xp: 0 }, next:{ level: 2, xp: 50 }, toNextLevel: 50 } 23 | calculateLevels(50) // { current:{ level: 2, xp: 50 }, next:{ level: 3, xp: 150 }, toNextLevel: 100 } 24 | calculateLevels(150) // { current:{ level: 3, xp: 150 }, next:{ level: 4, xp: 350 }, toNextLevel: 200 } 25 | 26 | // Harder level up (difficulty=100) 27 | calculateLevels(0) // { current:{ level: 1, xp: 0 }, next:{ level: 2, xp: 100 }, toNextLevel: 100 } 28 | calculateLevels(50) // { current:{ level: 1, xp: 50 }, next:{ level: 2, xp: 100 }, toNextLevel: 50 } 29 | calculateLevels(150) // { current:{ level: 2, xp: 150 }, next:{ level: 3, xp: 300 }, toNextLevel: 150 } 30 | -------------------------------------------------------------------------------- /lovePercentage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This method is inspired by a funny "algorithm" found in a video (https://i.imgur.com/TOgyKmM.mp4). 3 | * @author 5antos#4876 4 | * @param {string} name1 First person's name 5 | * @param {string} name2 Second person's name 6 | * @returns {number} Love percentage 7 | */ 8 | 9 | function getLovePercentage(name1, name2) { 10 | let concat = [name1, name2].sort((a,b) => a.localeCompare(b)).join('').toLowerCase() 11 | let counter = '' 12 | while(concat.length) { 13 | counter += concat.match(new RegExp(concat[0], 'gi')).length 14 | concat = concat.split('').filter(c => c !== concat[0]).join('') 15 | } 16 | return +_reduce(counter) 17 | } 18 | 19 | function _reduce(counter) { 20 | let result = '' 21 | while(counter.length >= 2) { 22 | result += (+counter[0] + (+counter[counter.length-1])) 23 | counter = counter.substring(1, counter.length-1) 24 | } 25 | result += counter 26 | return result <= 100 ? result : _reduce(result) 27 | } 28 | 29 | 30 | // Example Outputs: 31 | 32 | getLovePercentage('Rose', 'Jack') // 44 33 | getLovePercentage('Peter', 'Catherine') // 95 34 | getLovePercentage('Melman', 'Gloria') // 66 35 | getLovePercentage('Fiona', 'Shrek') // 64 36 | -------------------------------------------------------------------------------- /numberToFraction.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {number} num Number to convert to fraction 4 | * @param {number} [epsilon=1e-7] Conversion error (for irrational numbers). The smaller this value is, the more precise the result will be 5 | * @returns {string} Closest fraction for the the provided number 6 | */ 7 | 8 | function toFraction(num, epsilon=1e-7) { 9 | let signal = 1 10 | if (num < 0) num=-num, signal=-1 11 | 12 | let numerator, denominator, n, d, a=Math.trunc(num) 13 | let r=num-a, y, ratio, error 14 | const p=[1, a], q=[0, 1] 15 | 16 | if (r !== 0) y=1/r 17 | else return `${a*signal}/1` 18 | 19 | for(;;) { 20 | a=Math.trunc(y), n=p.shift()+a*p[0], d=q.shift()+a*q[0] 21 | ratio=n/d, error=Math.abs(num-ratio) 22 | 23 | if (error < epsilon) { 24 | numerator=n*signal, denominator=d 25 | break 26 | } 27 | 28 | r=y-a, y=1/r 29 | 30 | p.push(n) 31 | q.push(d) 32 | } 33 | 34 | return `${numerator}/${denominator}` 35 | } 36 | 37 | 38 | // Example Outputs: 39 | 40 | toFraction(1.25) // 5/4 41 | toFraction(-1.25) // -5/4 42 | toFraction(1.125) // 9/8 43 | toFraction(Math.PI) // 103993/33102 44 | toFraction(Math.PI, 1e-10) // 312689/99532 45 | -------------------------------------------------------------------------------- /placeholders.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {object} placeholders Object containing the strings that should replace each placeholder 4 | * @param {string} string String with placeholders 5 | * @param {string[]} [delimiters=['{','}']] Array with delimiters for the placeholders 6 | * @returns {string} Formatted string 7 | */ 8 | 9 | function applyPlaceholders(placeholders, string, delimiters=['{','}']) { 10 | return string.replace(new RegExp(Object.keys(placeholders).map(k => `${delimiters[0]}${k}${delimiters[1]}`).join('|'), 'g'), match => placeholders[match.replace(new RegExp(delimiters.join('|'), 'g'), '')]) 11 | } 12 | 13 | 14 | // Example Outputs: 15 | 16 | applyPlaceholders({ name: '5antos', age: 19 }, 'Hello, I\'m {name} and I\'m {age} years old.') // Hello, I'm 5antos and I'm 19 years old. 17 | applyPlaceholders({ result: 15 }, '10 + 5 = {{result}}', ['{{', '}}']) // 10 + 5 = 15 -------------------------------------------------------------------------------- /progressBar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {number} current Current progress of the bar 4 | * @param {number} total The value of the progress when the bar is totally filled 5 | * @param {number} barSize Fixed bar size 6 | * @returns {string} Progress bar 7 | */ 8 | 9 | function progressBar(current, total, barSize) { 10 | const progress = Math.round((barSize*current)/total) 11 | 12 | return '▮'.repeat(progress) + '▯'.repeat(barSize-progress) 13 | } 14 | 15 | function progressBarEnhanced(current, total, barSize) { 16 | const progress = Math.round((barSize*current)/total) 17 | 18 | return '—'.repeat(progress > 0 ? progress-1 : progress) + '•' + '-'.repeat(barSize-progress) 19 | } 20 | 21 | 22 | // Example Outputs: 23 | 24 | progressBar(50, 100, 10) // ▮▮▮▮▮▯▯▯▯▯ 25 | progressBar(100, 1000, 10) // ▮▯▯▯▯▯▯▯▯▯ 26 | progressBar(20, 20, 5) // ▮▮▮▮▮ 27 | 28 | progressBarEnhanced(50, 100, 10) // ————•----- 29 | progressBarEnhanced(100, 1000, 10) // •--------- 30 | progressBarEnhanced(20, 20, 5) // ————• 31 | -------------------------------------------------------------------------------- /randomColor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @returns {object} Object with a random color's code in HEX, RGB and decimal formats 4 | */ 5 | 6 | function randomColor() { 7 | const [R,G,B] = [~~(Math.random()*255), ~~(Math.random()*255), ~~(Math.random()*255)] 8 | const HEX = '#' + ((1<<24) + (R<<16) + (G<<8) + B).toString(16).slice(1) 9 | const decimal = (R<<16) + (G<<8) + B 10 | 11 | return { RGB: [R,G,B], HEX, decimal } 12 | } 13 | 14 | 15 | // Example Output: 16 | 17 | randomColor() // { RGB: [ 254, 219, 104 ], HEX: '#fedb68', decimal: 16702312 } -------------------------------------------------------------------------------- /randomWithChances.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {object[]} array Array with objects with a key named 'chance', representing the chance of that element to occur 4 | * @note An element with a chance value of zero (0) will never occur 5 | * @returns {any} Random element from the provided array, based on the different elements' chances 6 | */ 7 | 8 | function getRandom(array) { 9 | const auxArray = Array.from(array) 10 | auxArray.reduce((acc, curr, i, a) => a[i] = acc + curr.chance, 0) 11 | 12 | return array[auxArray.findIndex(w => w > Math.random()*auxArray[auxArray.length-1])] 13 | } 14 | 15 | 16 | // Usage Examples: 17 | 18 | getRandom([ 19 | { rarity: 'Common', chance: 60 }, 20 | { rarity: 'Uncommon', chance: 25 }, 21 | { rarity: 'Rare', chance: 10 }, 22 | { rarity: 'Very rare', chance: 5 } 23 | ]) 24 | 25 | getRandom([ 26 | { side: 'Heads', chance: 50 }, 27 | { side: 'Tails', chance: 50 } 28 | ]) 29 | -------------------------------------------------------------------------------- /removeDupeChars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @note Uppercase and lowercase letters are considered different characters 4 | * @param {string} string Input string to remove duplicated characters in a row 5 | * @param {boolean} [bool=false] Whether or not to allow two letters in a row. Useful for some words, like 'really', 'see', 'good', etc. 6 | * @returns {string} String without duplicated characters in a row 7 | */ 8 | 9 | function removeDupeChars(string, bool=false) { 10 | return string.split('').filter((_, i, a) => a[i] != a[bool ? i+2 : i+1]).join('') 11 | } 12 | 13 | 14 | // Example Outputs: 15 | 16 | removeDupeChars('Heeeeeyyyy guyssssss!!!!') // Hey guys! 17 | removeDupeChars('Wow, that code is really short!', true) // Wow, that code is really short! 18 | removeDupeChars('Ssssshhhhh, be quiet please!') // Ssh, be quiet please! 19 | -------------------------------------------------------------------------------- /repeatAction.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {number} amount Amount of times to run the callback 4 | * @param {function} callback Function to run every loop 5 | * @param {function} finishCallback Function to run after running all loops 6 | * @param {number} time Interval time, in milliseconds (defaults to 0, running every millisecond) 7 | * @returns {unknown} 8 | */ 9 | 10 | function repeatAction(amount, callback, finishCallback, time=0) { 11 | if (amount--) callback() 12 | if (amount > 0) return setTimeout(() => repeatAction(amount, callback, finishCallback, time), time) 13 | 14 | // Section for code to be executed when the action has repeated the provided amount of times 15 | finishCallback() 16 | } 17 | 18 | 19 | // Usage Examples: 20 | 21 | repeatAction( 22 | 5, 23 | () => console.log('Digging...'), 24 | () => console.log('You found a bone!') 25 | 3000 26 | ) 27 | -------------------------------------------------------------------------------- /stringSimilarity.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This method uses the Jaro similarity algorithm to measure the similarity between two strings (words or phrases). 3 | * Adapted from https://www.geeksforgeeks.org/jaro-and-jaro-winkler-similarity/ 4 | * @author 5antos#4876 5 | * @param {string} str1 First string 6 | * @param {string} str2 Second string 7 | * @returns {number} Number between 0 and 1, where 1 means the strings are equal and 0 means no similarity between the strings 8 | */ 9 | 10 | function checkSimilarity(str1, str2) { 11 | if (str1 === str2) return 1.0 12 | 13 | const len1 = str1.length 14 | const len2 = str2.length 15 | 16 | const maxDist = ~~(Math.max(len1, len2)/2)-1 17 | let matches = 0 18 | 19 | const hash1 = [] 20 | const hash2 = [] 21 | 22 | for(var i=0; i m.toUpperCase()) 9 | } 10 | 11 | 12 | // Example Outputs: 13 | 14 | tileize('hEy thEre') // Hey There 15 | tileize('thIS iS A mIXeD capITalIzEd STriNG') // This Is A Mixed Capitalized String 16 | tileize('HELLO WORLD') // Hello World 17 | -------------------------------------------------------------------------------- /timeToMilliseconds.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author 5antos#4876 3 | * @param {string} time Time (supports different formats) 4 | * @returns {number|null} Provided time, converted to milliseconds. Returns null if the provided time is invalid 5 | * @note The provided time can be invalid if does not follow the order days-hours-minutes-seconds, 6 | * the used format is not included in the "formats" array, any format is provided more than once, 7 | * an unit's value has symbols ('.', '-', ',', etc.), hours>23, minutes>59, seconds>59 or some weird and non-sense inputs 8 | */ 9 | 10 | function timeToMilliseconds(time) { 11 | const timeUnits = time.replace(/[\d\s]/g, _ => '').toLowerCase().split('') 12 | const formats = ['d', 'h', 'm', 's'] 13 | 14 | const isValid = timeUnits.length === new Set(timeUnits).size && timeUnits.every((u, i, a) => formats.includes(u) && formats.indexOf(a[i-1]) < formats.indexOf(u)) 15 | if (!isValid) return null 16 | 17 | const formatted = time.replace(/([a-zA-Z])/g, '$1 ').toLowerCase().trim().split(' ').filter(f => !!f) 18 | if (formatted.some(e => !/[0-9]/.test(e))) return null 19 | 20 | const invalid = { h:24, m:60, s:60 } 21 | for (const f of formatted) { 22 | const value = f.replace(/\D/g, '') 23 | const unit = f.replace(/\d/gi, '') 24 | 25 | if (value >= invalid[unit]) return null 26 | } 27 | 28 | const convertions = { d:86_400_000, h:3_600_000, m:60_000, s:1000 } 29 | 30 | return formatted.reduce((acc, curr, i, a) => acc + parseInt(curr.substring(0, curr.length-1))*convertions[curr[curr.length-1]], 0) 31 | } 32 | 33 | 34 | // Example Outputs: 35 | 36 | timeToMilliseconds('1d') // 86400000 37 | timeToMilliseconds('12h30m') // 45000000 38 | timeToMilliseconds('7d 12h 50m 30s') // 651030000 39 | timeToMilliseconds('1d6h60s') // null (seconds > 59) 40 | timeToMilliseconds('2d4h3s2m') // null (does not follow the order days-hours-minutes-seconds) 41 | timeToMilliseconds('asfjkafi') // null (weird and non-sense input) 42 | timeToMilliseconds('5a20b30c') // null (formats not included in the "formats" array) 43 | --------------------------------------------------------------------------------