Creating a Small Utility Library with Multiple Functions

A comprehensive tutorial for building your own utility library using George Polya's problem-solving approach

Introduction

Welcome to this tutorial on creating a small utility library! In software development, utility libraries provide common, reusable functions that solve everyday programming tasks. Think of them as your personal toolkit - a collection of specialized tools ready to help you tackle different challenges efficiently.

In this tutorial, we'll use George Polya's famous 4-step problem-solving method to design and build our utility library:

  1. Understand the Problem - What exactly are we trying to build?
  2. Devise a Plan - How will we approach building this library?
  3. Execute the Plan - Writing the actual code
  4. Look Back and Reflect - Evaluating our solution and considering improvements

By the end of this tutorial, you'll have created a useful utility library you can use in future projects. Let's get started!

File Information

We'll be creating the following files:

Step 1: Understand the Problem

Our assignment is to "Create a small utility library with multiple functions." Let's break this down:

What is a utility library?

A utility library is a collection of functions that perform common, reusable operations. These functions are typically:

What types of functions should our library include?

Let's plan to include utilities for common programming tasks such as:

Requirements Analysis

Real-World Example

Popular utility libraries in JavaScript include Lodash and Underscore.js. These libraries provide hundreds of helper functions that make common tasks easier. Our library will be much smaller but follows the same principle - creating reusable functions that save time and reduce bugs.

Step 2: Devise a Plan

Whiteboard Plan

  1. Set up the directory structure for our utility library
  2. Define the categories of utility functions we'll create
  3. Design the API for each function (parameters, return values)
  4. Implement each utility function with error handling
  5. Create a main entry point to export all utilities
  6. Write examples to demonstrate each function
  7. Test the functions with various inputs

Function Categories and Specifications

String Utilities (stringutils.js)

Number Utilities (numberutils.js)

Array Utilities (arrayutils.js)

Validation Utilities (validation.js)

Organizing Functions Analogy

Think of our utility library like a well-organized kitchen. Each module (file) is like a drawer dedicated to a specific type of tool:

  • String utilities = Cutting tools drawer (knives, scissors, etc.)
  • Number utilities = Measuring tools drawer (measuring cups, scales, etc.)
  • Array utilities = Organizing containers (tupperware, bins, etc.)
  • Validation utilities = Safety equipment (oven mitts, fire extinguisher, etc.)

Each function is a specific tool in that drawer. Just as you wouldn't put a knife in the measuring drawer, we keep related functions together to make them easy to find when needed.

Step 3: Execute the Plan

Now let's start building our utility library, one module at a time.

Setting Up Directory Structure

First, create the necessary directories and files:

mkdir utils
touch utils/stringutils.js
touch utils/numberutils.js
touch utils/arrayutils.js
touch utils/validation.js
touch utils/index.js
touch examples.js

String Utilities Implementation

Let's implement our string utility functions:

File: utils/stringutils.js

/**
 * String utility functions for common string operations
 */

/**
 * Capitalizes the first letter of a string
 * @param {string} str - The input string
 * @returns {string} The string with first letter capitalized
 * @throws {TypeError} If input is not a string
 */
function capitalizeFirstLetter(str) {
    // Validate input is a string
    if (typeof str !== 'string') {
        throw new TypeError('Input must be a string');
    }
    
    // Handle empty string case
    if (str.length === 0) {
        return str;
    }
    
    // Capitalize first letter and concat with rest of string
    return str.charAt(0).toUpperCase() + str.slice(1);
}

/**
 * Truncates a string to specified length with optional ending
 * @param {string} str - The input string
 * @param {number} length - Maximum length of the result
 * @param {string} [ending='...'] - String to append at the end
 * @returns {string} Truncated string
 * @throws {TypeError} If inputs are invalid types
 */
function truncate(str, length, ending = '...') {
    // Input validation
    if (typeof str !== 'string') {
        throw new TypeError('First argument must be a string');
    }
    
    if (typeof length !== 'number' || length < 0) {
        throw new TypeError('Length must be a non-negative number');
    }
    
    if (typeof ending !== 'string') {
        throw new TypeError('Ending must be a string');
    }
    
    // Return original string if it's shorter than the specified length
    if (str.length <= length) {
        return str;
    }
    
    // Calculate truncation point accounting for ending length
    const truncateLength = length - ending.length;
    
    // If truncateLength is negative or zero, we can't fit the ending
    if (truncateLength <= 0) {
        return str.slice(0, length);
    }
    
    // Truncate and add ending
    return str.slice(0, truncateLength) + ending;
}

/**
 * Converts a string to a URL-friendly slug
 * @param {string} str - The input string
 * @returns {string} URL-friendly slug
 * @throws {TypeError} If input is not a string
 */
function slugify(str) {
    if (typeof str !== 'string') {
        throw new TypeError('Input must be a string');
    }
    
    return str
        .toLowerCase()
        .trim()
        .replace(/\s+/g, '-')        // Replace spaces with hyphens
        .replace(/[^\w\-]+/g, '')    // Remove non-word chars except hyphens
        .replace(/\-\-+/g, '-')      // Replace multiple hyphens with single hyphen
        .replace(/^-+/, '')          // Remove leading hyphens
        .replace(/-+$/, '');         // Remove trailing hyphens
}

/**
 * Reverses a string
 * @param {string} str - The input string
 * @returns {string} The reversed string
 * @throws {TypeError} If input is not a string
 */
function reverseString(str) {
    if (typeof str !== 'string') {
        throw new TypeError('Input must be a string');
    }
    
    // Converting to array, reversing, and joining is the clearest approach
    return str.split('').reverse().join('');
    
    // Alternative approach using array spread and reduce
    // return [...str].reduce((rev, char) => char + rev, '');
}

// Export all functions
module.exports = {
    capitalizeFirstLetter,
    truncate,
    slugify,
    reverseString
};

Code Explanation

Let's break down a couple of these functions to understand them better:

capitalizeFirstLetter

This function takes a string and makes its first character uppercase. It uses two string methods:

  • charAt(0) - Gets the first character of the string
  • slice(1) - Gets everything after the first character

We then apply toUpperCase() to the first character and concatenate it with the rest of the string.

slugify

This function creates a URL-friendly version of a string (a "slug") by:

  1. Converting to lowercase
  2. Removing extra spaces
  3. Replacing spaces with hyphens
  4. Removing special characters
  5. Cleaning up any extra hyphens

We use regular expressions to handle these string transformations efficiently.

Number Utilities Implementation

Now let's implement our number utility functions:

File: utils/numberutils.js

/**
 * Number utility functions for common number operations
 */

/**
 * Formats a number as currency
 * @param {number} num - The number to format
 * @param {string} [currency='USD'] - Currency code
 * @param {string} [locale='en-US'] - Locale code
 * @returns {string} Formatted currency string
 * @throws {TypeError} If num is not a number
 */
function formatCurrency(num, currency = 'USD', locale = 'en-US') {
    // Input validation
    if (typeof num !== 'number' || isNaN(num)) {
        throw new TypeError('First argument must be a valid number');
    }
    
    // Use Intl.NumberFormat for localized currency formatting
    return new Intl.NumberFormat(locale, {
        style: 'currency',
        currency: currency
    }).format(num);
}

/**
 * Rounds a number to specified decimal places
 * @param {number} num - The number to round
 * @param {number} [places=0] - Number of decimal places
 * @returns {number} Rounded number
 * @throws {TypeError} If inputs are invalid
 */
function roundToDecimalPlaces(num, places = 0) {
    // Input validation
    if (typeof num !== 'number' || isNaN(num)) {
        throw new TypeError('First argument must be a valid number');
    }
    
    if (!Number.isInteger(places) || places < 0) {
        throw new TypeError('Decimal places must be a non-negative integer');
    }
    
    // Calculate multiplier based on decimal places
    const multiplier = Math.pow(10, places);
    
    // Round to specified decimal places
    return Math.round(num * multiplier) / multiplier;
}

/**
 * Generates a random number within a range (inclusive)
 * @param {number} min - Minimum value (inclusive)
 * @param {number} max - Maximum value (inclusive) 
 * @returns {number} Random number within range
 * @throws {TypeError} If inputs are not numbers
 * @throws {Error} If min is greater than max
 */
function randomInRange(min, max) {
    // Input validation
    if (typeof min !== 'number' || typeof max !== 'number' || isNaN(min) || isNaN(max)) {
        throw new TypeError('Both arguments must be valid numbers');
    }
    
    if (min > max) {
        throw new Error('Minimum value must be less than or equal to maximum value');
    }
    
    // Formula: Math.random() * (max - min + 1) + min
    // Adding 1 to make max inclusive
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

/**
 * Checks if a number is even
 * @param {number} num - The number to check
 * @returns {boolean} True if even, false otherwise
 * @throws {TypeError} If input is not a number
 */
function isEven(num) {
    // Input validation
    if (typeof num !== 'number' || isNaN(num)) {
        throw new TypeError('Input must be a valid number');
    }
    
    // Check if number is even using modulo operator
    return num % 2 === 0;
}

// Export all functions
module.exports = {
    formatCurrency,
    roundToDecimalPlaces,
    randomInRange,
    isEven
};

Code Explanation

formatCurrency

This function utilizes the browser's built-in internationalization API (Intl.NumberFormat) to format numbers as currency strings with proper symbols and formatting conventions for different locales.

For example, calling formatCurrency(1234.56) would produce "$1,234.56" in the US, but "€1.234,56" in Germany if the locale was changed.

randomInRange

This function uses JavaScript's Math.random() to generate a random number within a specified inclusive range. The formula works by:

  1. Generating a random decimal between 0 (inclusive) and 1 (exclusive)
  2. Multiplying by the range size (plus 1 to include the max value)
  3. Adding the minimum value to shift the range
  4. Using Math.floor to convert to an integer

This gives us a random integer between min and max, inclusive.

Array Utilities Implementation

Let's implement our array utility functions:

File: utils/arrayutils.js

/**
 * Array utility functions for common array operations
 */

/**
 * Randomly shuffles array elements (Fisher-Yates algorithm)
 * @param {Array} array - The array to shuffle
 * @returns {Array} New shuffled array
 * @throws {TypeError} If input is not an array
 */
function shuffle(array) {
    // Input validation
    if (!Array.isArray(array)) {
        throw new TypeError('Input must be an array');
    }
    
    // Create a copy of the array to avoid modifying the original
    const result = [...array];
    
    // Fisher-Yates shuffle algorithm
    for (let i = result.length - 1; i > 0; i--) {
        // Generate random index from 0 to i
        const j = Math.floor(Math.random() * (i + 1));
        // Swap elements at i and j
        [result[i], result[j]] = [result[j], result[i]];
    }
    
    return result;
}

/**
 * Splits an array into chunks of specified size
 * @param {Array} array - The array to chunk
 * @param {number} size - Size of each chunk
 * @returns {Array} Array of chunks
 * @throws {TypeError} If inputs are invalid
 */
function chunk(array, size) {
    // Input validation
    if (!Array.isArray(array)) {
        throw new TypeError('First argument must be an array');
    }
    
    if (!Number.isInteger(size) || size <= 0) {
        throw new TypeError('Chunk size must be a positive integer');
    }
    
    // Initialize result array
    const result = [];
    
    // Create chunks using slice
    for (let i = 0; i < array.length; i += size) {
        result.push(array.slice(i, i + size));
    }
    
    return result;
}

/**
 * Returns array with duplicate elements removed
 * @param {Array} array - The input array
 * @returns {Array} Array with unique elements
 * @throws {TypeError} If input is not an array
 */
function unique(array) {
    // Input validation
    if (!Array.isArray(array)) {
        throw new TypeError('Input must be an array');
    }
    
    // Use Set to remove duplicates and convert back to array
    return [...new Set(array)];
    
    // Alternative implementation using filter
    // return array.filter((item, index) => array.indexOf(item) === index);
}

/**
 * Flattens a nested array structure (one level deep)
 * @param {Array} array - The array to flatten
 * @returns {Array} Flattened array
 * @throws {TypeError} If input is not an array
 */
function flatten(array) {
    // Input validation
    if (!Array.isArray(array)) {
        throw new TypeError('Input must be an array');
    }
    
    // Simple one-level flattening using concat and spread
    return [].concat(...array);
    
    // Modern alternative using flat
    // return array.flat();
}

// Export all functions
module.exports = {
    shuffle,
    chunk,
    unique,
    flatten
};

Code Explanation

shuffle

This function implements the Fisher-Yates (or Knuth) shuffle algorithm, which is an unbiased way to randomly reorder array elements. The algorithm works by:

  1. Starting from the last element
  2. Swapping it with a randomly selected element from the entire array (including itself)
  3. Moving to the second-to-last element and repeating
  4. Continuing until we reach the first element

We create a copy of the original array to avoid modifying it, following the principle of pure functions.

unique

This function removes duplicate elements from an array using JavaScript's Set object, which automatically eliminates duplicates. We then convert the Set back to an array using the spread operator.

An alternative approach using filter is included as a comment, which works by keeping only the first occurrence of each value based on its index.

Validation Utilities Implementation

Now let's implement our validation utility functions:

File: utils/validation.js

/**
 * Validation utility functions for common input validation
 */

/**
 * Validates if a string is a valid email address
 * @param {string} email - The email address to validate
 * @returns {boolean} True if valid, false otherwise
 */
function isValidEmail(email) {
    if (typeof email !== 'string') {
        return false;
    }
    
    // Email regex pattern
    // This is a simple pattern and doesn't cover all edge cases
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailPattern.test(email);
}

/**
 * Validates if a string is a valid URL
 * @param {string} url - The URL to validate
 * @returns {boolean} True if valid, false otherwise
 */
function isValidURL(url) {
    if (typeof url !== 'string') {
        return false;
    }
    
    try {
        // Using URL constructor for validation
        new URL(url);
        return true;
    } catch (error) {
        return false;
    }
}

/**
 * Validates if a string is a valid phone number
 * @param {string} phone - The phone number to validate
 * @param {string} [format='any'] - Expected format ('any', 'us', 'intl')
 * @returns {boolean} True if valid, false otherwise
 */
function isValidPhoneNumber(phone, format = 'any') {
    if (typeof phone !== 'string') {
        return false;
    }
    
    // Remove common formatting characters for consistency
    const cleanPhone = phone.replace(/[\s\-\(\)\.]/g, '');
    
    // Different validation patterns based on format
    switch (format.toLowerCase()) {
        case 'us':
            // US format: 10 digits
            return /^\d{10}$/.test(cleanPhone);
            
        case 'intl':
            // International format: + followed by 7-15 digits
            return /^\+\d{7,15}$/.test(cleanPhone);
            
        case 'any':
        default:
            // Any format: 7-15 digits, optionally with + prefix
            return /^(\+)?\d{7,15}$/.test(cleanPhone);
    }
}

/**
 * Checks if a password meets strength criteria
 * @param {string} password - The password to check
 * @returns {boolean} True if strong, false otherwise
 */
function isStrongPassword(password) {
    if (typeof password !== 'string') {
        return false;
    }
    
    // Password must be at least 8 characters and contain:
    // - At least one uppercase letter
    // - At least one lowercase letter
    // - At least one number
    // - At least one special character
    const hasMinLength = password.length >= 8;
    const hasUppercase = /[A-Z]/.test(password);
    const hasLowercase = /[a-z]/.test(password);
    const hasNumber = /\d/.test(password);
    const hasSpecialChar = /[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password);
    
    return hasMinLength && hasUppercase && hasLowercase && hasNumber && hasSpecialChar;
}

// Export all functions
module.exports = {
    isValidEmail,
    isValidURL,
    isValidPhoneNumber,
    isStrongPassword
};

Code Explanation

isValidEmail

This function uses a regular expression to validate email addresses. The pattern checks for:

  • At least one character before the @ symbol
  • The @ symbol
  • At least one character for the domain name
  • A dot
  • At least one character for the TLD (top-level domain)

Note that this is a simplified check. Complete email validation according to all RFCs is extremely complex.

isValidURL

This function leverages JavaScript's built-in URL constructor, which throws an error if the URL is invalid. Using a try/catch block, we can determine validity based on whether an error occurs.

This approach is more robust than using regex alone, as the URL constructor follows web standards for URL validation.

Creating the Main Entry Point

Now let's create the main entry point that combines all our utility modules:

File: utils/index.js

/**
 * Main entry point for utility library
 * Combines all utility modules into a single export
 */

// Import individual modules
const stringUtils = require('./stringutils');
const numberUtils = require('./numberutils');
const arrayUtils = require('./arrayutils');
const validation = require('./validation');

// Combine all utilities into a single object
const utils = {
    string: stringUtils,
    number: numberUtils,
    array: arrayUtils,
    validation: validation
};

// Export the combined utility object
module.exports = utils;

Code Explanation

This index.js file serves as the entry point for our utility library. It:

  1. Imports each utility module we've created
  2. Organizes them into a structured object with logical categories
  3. Exports the combined object for easy consumption

This approach allows users to access utilities through a clear, organized namespace structure like utils.string.capitalizeFirstLetter() or utils.array.unique().

Writing Examples

Let's create an examples file to demonstrate how to use our utility library:

File: examples.js

/**
 * Examples demonstrating the use of our utility library
 */

// Import the utility library
const utils = require('./utils');

// String Utilities Examples
console.log('\n--- String Utilities ---');

console.log("capitalizeFirstLetter('hello world'):");
console.log(utils.string.capitalizeFirstLetter('hello world'));
// Output: "Hello world"

console.log("\ntruncate('This is a long sentence that needs truncating', 20):");
console.log(utils.string.truncate('This is a long sentence that needs truncating', 20));
// Output: "This is a long sen..."

console.log("\nslugify('Hello World! This is a title'):");
console.log(utils.string.slugify('Hello World! This is a title'));
// Output: "hello-world-this-is-a-title"

console.log("\nreverseString('JavaScript'):");
console.log(utils.string.reverseString('JavaScript'));
// Output: "tpircSavaJ"

// Number Utilities Examples
console.log('\n--- Number Utilities ---');

console.log("formatCurrency(1234.56):");
console.log(utils.number.formatCurrency(1234.56));
// Output: "$1,234.56"

console.log("\nformatCurrency(1234.56, 'EUR', 'de-DE'):");
console.log(utils.number.formatCurrency(1234.56, 'EUR', 'de-DE'));
// Output: "1.234,56 €"

console.log("\nroundToDecimalPlaces(3.14159, 2):");
console.log(utils.number.roundToDecimalPlaces(3.14159, 2));
// Output: 3.14

console.log("\nrandomInRange(1, 10) - run 5 times:");
for (let i = 0; i < 5; i++) {
    console.log(utils.number.randomInRange(1, 10));
}
// Output: Random numbers between 1 and 10

console.log("\nisEven(42):");
console.log(utils.number.isEven(42));
// Output: true

// Array Utilities Examples
console.log('\n--- Array Utilities ---');

const sampleArray = [1, 2, 3, 4, 5];
console.log("shuffle([1, 2, 3, 4, 5]):");
console.log(utils.array.shuffle(sampleArray));
// Output: Randomly shuffled array

console.log("\nchunk([1, 2, 3, 4, 5, 6, 7, 8], 3):");
console.log(utils.array.chunk([1, 2, 3, 4, 5, 6, 7, 8], 3));
// Output: [[1, 2, 3], [4, 5, 6], [7, 8]]

console.log("\nunique([1, 2, 2, 3, 4, 4, 5]):");
console.log(utils.array.unique([1, 2, 2, 3, 4, 4, 5]));
// Output: [1, 2, 3, 4, 5]

console.log("\nflatten([[1, 2], [3, 4], [5]]):");
console.log(utils.array.flatten([[1, 2], [3, 4], [5]]));
// Output: [1, 2, 3, 4, 5]

// Validation Utilities Examples
console.log('\n--- Validation Utilities ---');

console.log("isValidEmail('user@example.com'):");
console.log(utils.validation.isValidEmail('user@example.com'));
// Output: true

console.log("\nisValidEmail('invalid-email'):");
console.log(utils.validation.isValidEmail('invalid-email'));
// Output: false

console.log("\nisValidURL('https://www.example.com'):");
console.log(utils.validation.isValidURL('https://www.example.com'));
// Output: true

console.log("\nisValidURL('not-a-url'):");
console.log(utils.validation.isValidURL('not-a-url'));
// Output: false

console.log("\nisValidPhoneNumber('(123) 456-7890', 'us'):");
console.log(utils.validation.isValidPhoneNumber('(123) 456-7890', 'us'));
// Output: true

console.log("\nisStrongPassword('Weak123'):");
console.log(utils.validation.isStrongPassword('Weak123'));
// Output: false

console.log("\nisStrongPassword('Strong123!'):");
console.log(utils.validation.isStrongPassword('Strong123!'));
// Output: true

Code Explanation

This examples.js file demonstrates how to use each function in our utility library. It's organized by module, showing:

  • How to import and access our utility functions
  • Example usage for each function with sample inputs
  • Expected outputs as comments

Running this file will execute all examples and print the results to the console, helping users understand how each utility works.

Step 4: Look Back and Reflect

Evaluating Our Solution

Let's review what we've accomplished and identify potential improvements.

Strengths of Our Implementation

Areas for Improvement

Alternative Implementations

Let's look at some alternative ways we could have implemented certain functions:

Reverse String

// Original implementation
function reverseString(str) {
    return str.split('').reverse().join('');
}

// Alternative using Array.from and reduce
function reverseStringAlt1(str) {
    return Array.from(str).reduce((rev, char) => char + rev, '');
}

// Alternative using a for loop (more performant for very long strings)
function reverseStringAlt2(str) {
    let reversed = '';
    for (let i = str.length - 1; i >= 0; i--) {
        reversed += str[i];
    }
    return reversed;
}

Unique Array

// Original implementation
function unique(array) {
    return [...new Set(array)];
}

// Alternative using filter and indexOf
function uniqueAlt1(array) {
    return array.filter((item, index) => array.indexOf(item) === index);
}

// Alternative using reduce (more verbose but illustrative)
function uniqueAlt2(array) {
    return array.reduce((result, item) => {
        if (!result.includes(item)) {
            result.push(item);
        }
        return result;
    }, []);
}

Currency Formatting

// Original implementation (using Intl API)
function formatCurrency(num, currency = 'USD', locale = 'en-US') {
    return new Intl.NumberFormat(locale, {
        style: 'currency',
        currency: currency
    }).format(num);
}

// Alternative without Intl API (limited functionality)
function formatCurrencyAlt(num, symbol = '$') {
    // Format number with two decimal places
    const formattedNum = num.toFixed(2);
    
    // Add commas for thousands
    const parts = formattedNum.split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    
    // Add symbol and join parts
    return symbol + parts.join('.');
}

Real-World Applications

Our utility library would be useful in many real-world scenarios:

Web Development

Content Management Systems

Data Processing Applications

Learning Outcomes

Through this project, we've learned several important concepts:

Running and Testing the Library

How to Run the Examples

To run the examples and see the utility library in action:

  1. Save all files with the structure and content described above
  2. Open a terminal in the project directory
  3. Run node examples.js
  4. You should see the results of all example function calls in the console

Incorporating Into Your Own Projects

To use this utility library in your own projects:

  1. Copy the utils directory into your project
  2. Import the library in your JavaScript files:
    const utils = require('./utils');
  3. Use the utilities as needed:
    const slug = utils.string.slugify('My Article Title');
    const formattedPrice = utils.number.formatCurrency(29.99);
    const uniqueIds = utils.array.unique(userIds);
    const isValid = utils.validation.isValidEmail(userEmail);

Extending the Library

You can easily extend this library with your own utility functions:

  1. Add new functions to existing modules
  2. Create new utility modules for different categories
  3. Update the index.js file to include your new modules

Example: Adding a dateutils.js module:

// utils/dateutils.js
function formatDate(date, format = 'MM/DD/YYYY') {
    // Implementation...
}

function isWeekend(date) {
    // Implementation...
}

module.exports = {
    formatDate,
    isWeekend
};

// Then update utils/index.js
const dateUtils = require('./dateutils');

const utils = {
    // Existing modules...
    date: dateUtils
};

Conclusion

In this tutorial, we've created a comprehensive utility library by following George Polya's 4-step problem-solving method:

  1. Understanding the problem: We defined what a utility library is and what types of functions it should include
  2. Devising a plan: We organized our functions into logical categories and designed their APIs
  3. Executing the plan: We implemented each utility function with proper documentation and error handling
  4. Looking back: We evaluated our solution, considered alternatives, and discussed real-world applications

The result is a modular, well-documented library of utility functions that can be used in various projects. While our library is relatively small, it demonstrates important principles of good software design:

You can use this library as a starting point for your own projects, extending it with additional utilities as needed. As you continue your programming journey, creating reusable libraries like this one will help you write more efficient, maintainable code.