8 – Nested sidebar module

Is there a Drupal module that will display a sidebar like the one on https://vulkan-tutorial.com?

I have a website that has a lot of content that is nested like a textbook or legal codex. Think chapter, section, subsection, sub-subsection, etc. I’d like to be able to display this neatly as a sidebar. Key features include

  • Expanding to highlight the current page in the menu.
  • Allowing the user to expand to see any of the other pages
  • Nice arrow/triangle icon showing expandability of sections as applicable.

I’ve tried searching for nice sidebar modules but they’re surprisingly sparse.

8 – How can I determine which module is associated with a field plugin?

I’d like to implement an entity hook, and act on all fields defined by Computed Field FieldType plugins. So I either need a list of all FieldType plugins provided by the module or need to know which fields are associated with it in order to know which fields to work on (or avoid). Is this possible?

I’d rather not hard-code the list of plugins (computed_string, computed_decimal, etc.) because new ones could be added later, and then the list would have to change.

And I can’t use computed_* because another module, Computed Field Plugin, defines its own field type with that prefix, and I don’t want to touch it.

I was expecting something like FieldDefinitionInterface::getDefiningModule(), but that doesn’t seem to exist.

For those interested, I’m working on adding support for computed cardinality.

Free VMware ESXi WHMCS module


AutoVM is an open-source platform based on the GPL license to manage virtual machines(VM) on VMware ESXi virtualization. It allows VPS providers to manage full automation of support and sales process. AutoVM platform is a good choice for hosting companies or VPS providers to increase their service and support quality.

With AutoVM you can assign unique panel for each user to make them fulfilled all about VPS Related.

This must be noticeable as AutoVM additional tools, except Automatic Monitoring you can give your billing managements to AutoVM! So you can give more-fast services to your customers.

Some of the features

Bandwidth monitoring and manage VPS traffic usage.

Install easily without any changes on the ESXI servers.

Free modules for managing VPS on the WHMCS client area.

Auto Provisioning VM After Payment Successfully.

Auto-assign IP and Network adapter once VM created.

Auto installation of the operating system.

Ability to assign the existing VM created for WHMCS users.

Prerequisite

the AutoVM platform is designed to be compatible with default VMware ESXI settings and does not require any changes.

Do you like to try?

To get and set up the system, please visit the installation article. If you have any questions, please read the FAQ section. If you do not find your answer, please ask your question in the stack.

New Oxxa.com SSL reseller module for HostBill and two new payment modules!

In the latest HostBill release we’ve introduced new SSL reseller module: Oxxa.com and two new payment solutions Moneris Vault and Barion.

Oxxa SSL module

Oxxa is the ICANN accredited domain name registrar based in Netherlands, that also offers hosting services, dedicated servers, VPS, SSL Certificates and more. We already have Oxxa domain registrar module, which allows to automate domain provisioning and management, now we’re happy to introduce Oxxa SSL module!

Oxxa SSL module for HostBill is an all-in-one tool to sell Oxxa SSL certificates – either as separate products or as additions to or bundled with other services! Easily setup your products and let HostBill do the rest – automatically issue certificates, parse CSR and synchronize certificate info. Provide clients with user-friendly way to manage their certificates from client area, where they can enter CSR, select approval email or get certificate status. Control everything: account lifecycle, billing, certificate autorenew and more from admin panel!


Complement your existing product range and start selling SSL certificates with Oxxa and HostBill! And if you need more reasons to start selling SSL certificates read this blog post and hesitate no more!

Find out more at https://hostbillapp.com/products-services/oxxassl/

Moneris Vault payment gateway

The Moneris Gateway is a multi-functional online payment solution for business owners. HostBill already supports several payment methods offered by Moneris, we’re now happy to add Moneris Vault to the list!

Moneris Vault is the payment solution for online eCommerce merchants that do not wish to handle credit card numbers directly on their websites but want to store cardholder data in exchange for a token. With this solution you can register a customer profile for future use and transaction processing. Only credit card/ACH info is registered in the Vault in exchange for a token. Moneris Vault payment method helps to reduce risk by storing sensitive data on Moneris’ secure PCI‐certified servers and removes sensitive data from the merchant’s system. With no card storage the merchant has less PCI certification efforts. Merchants may process a transaction at any time without the cardholder or their payment details being present.

Barion payment module

This week we’re also adding Barion payment module. Barion is a company based in Budapest that provides electronic payment services from general online store payments to special payment services. The classic Barion payment gateway service redirects your customer from your checkout page to Barion payment page where Barion takes care of everything else. The payment gateway also supports quick and easy refunds. Now HostBill supports Barion to process payments out of the box!

Browse all payment gateways supported by HostBill at https://hostbillapp.com/hostbill/aut…ymentgateways/


***

Interested to hear more news from HostBill?

Read our blog at https://blog.hostbillapp.com/

***

About HostBill:

HostBill is a powerful and flexible, all-in-one automation, billing, client management and support platform for online businesses. HostBill handles all aspects of running a successful online business, from client acquisition, through invoicing and payment collection, automated service provisioning and management, to customer service and support. Extensive range of advanced features, multitude of modules and apps and integration with various control panels, domain registrars, payment gateways, order pages, client panels and more, make it the most comprehensive solution on the market for Hosting, Cloud/IaaS/VPS Solutions Providers, Domain name and SSL Resellers around the globe to automate and manage their online businesses.


If you don’t have your HostBill license yet, compare the licenses and check out the pricing at https://hostbillapp.com/pricing/

You can also sign up for our newsletter to be the first to know about special offers, promo codes, new product releases and more!

git – First published Python module, how is my project/code structure?

So I’ve just finished my first Python module (and published on Github), with this little project I’d like to learn how to distribute my code so that other users can use it as a plug in for their own projects.

Specifically I’m looking for feedback in the following direction:

  • Is the interface to the module designed correctly?
  • At the beginning of the code I check for completeness of the input, is this the best way to handle errors? (It looks chunky)
  • Is the repository set up correctly so that it is plug-and-play?
  • In general, is this the best way to design a module or should I work with classes instead of funtions?

Any other feedback is also welcome 🙂

Thanks in advance!


Link to Github repository: https://github.com/nick-van-h/cutlistcalculator

__main__.py:

from cutlist import getCutLists
import sys
import argparse

if __name__ == '__main__':
    #Argument parser
    text = "This program calculates the most optimal cutlist for beams and planks."
    parser = argparse.ArgumentParser(description=text)
    parser.add_argument("-i", "--input", help="custom location of input json file (e.g. 'localhost:8080/foo/bar.json'", default="")
    parser.add_argument("-o", "--output", help="custom location of output folder (e.g. 'localhost:8080/foo' -> 'localhost:8080/foo/cutlist_result.json'", default="")
    args = parser.parse_args()

    #Kick-off
    result = getCutLists(args.input, args.output)

    #Exit function with VS Code workaround
    try:
        sys.exit(result)
    except:
        print(result)

cutlist.py:

import json
from operator import itemgetter
import copy
from pathlib import Path
import os

def getSolution(reqs, combs):
    needs = copy.deepcopy(reqs)
    res = ()
    res.append(())
    for comb in combs:
        #As long as all items from comb(x) fulfill need
        combNeed = True
        while combNeed:
            #Check if comb(x) provides more than need (fail fast)
            for need in needs:
                if comb(need('Length')) > need('Qty'):
                    combNeed = False
            if not combNeed:
                break

            for need in needs:
                need('Qty') -= comb(need('Length'))

            #Append result
            res(0).append(comb.copy())

    #Calculate total price
    for sol in res:
        price = round(sum(x('Price') for x in sol),2)

    res.append((price))

    #Return result
    return res

def getCutLists(inputstr = "", outputstr = ""):
    if inputstr:
        jsonlocation = inputstr
    else:
        jsonlocation = './input/input.json' #default input location
    print(jsonlocation)
    errstr = ""

    #Get input
    try:
        with open(jsonlocation) as f:
            data = json.load(f)
    except:
        errstr += "JSON file not found. "
        return(f"Err: {errstr}")

    #Get variables from JSON object
    try:
        reqs = data('Required Lengths')
    except:
        errstr += "'Required Lengths' not found. "

    try:
        avail = data('Available base material')
    except:
        errstr += "'Available base material' not found. "

    try:
        cutwidth = data('Cut loss')
    except:
        errstr += "'Cut loss' not found. "

    if errstr:
        return(f"Err: {errstr}")

    #Test for required keys in array
    try:
        test = (x('Length') for x in reqs)
        if min(test) <= 0:
            errstr += f"Err: Required length ({min(test)}) must be bigger than 0."
    except:
        errstr += "'Length' not found in required lengths. "

    try:
        test = (x('Qty') for x in reqs)
        if min(test) <= 0:
            errstr += f"Err: Required quantity ({min(test)}) must be bigger than 0."
    except:
        errstr += "'Qty' not found in required lengths. "

    try:
        test = (x('Length') for x in avail)
        if min(test) <= 0:
            errstr += f"Err: Available length ({min(test)}) must be bigger than 0."
    except:
        errstr += "'Length' not found in available base material. "

    try:
        test = (x('Price') for x in avail)
        if min(test) < 0:
            errstr += f"Err: Available price ({min(test)}) can't be negative."
    except:
        errstr += "'Price' not found in available base material. "

    if errstr:
        return(f"Err: {errstr}")


    #Init other vars
    listreq = (x('Length') for x in reqs)
    listavail = (x('Length') for x in avail)
    minreq = min(listreq)
    res=()

    #Error handling on passed inputs
    if max(listreq) > max(listavail):
        return(f"Err: Unable to process, required length of {max(listreq)} is bigger than longest available base material with length of {max(listavail)}.")

    if cutwidth < 0:
        return(f"Err: Cut width can't be negative")

    #Make list of all available cut combinations
    combs = ()
    for plank in avail:
        myplank = plank.copy()
        for cut in reqs:
            myplank(cut('Length')) = 0

        #Increase first required plank length
        myplank(reqs(0)('Length')) += 1

        #Set other variables
        myplank('Unitprice') = myplank('Price') / myplank('Length')

        filling = True
        while filling:
            #Calculate rest length
            myplank('Rest') = myplank('Length')
            for i in reqs:
                length = i('Length')
                myplank('Rest') -= ((myplank(length) * length) + (myplank(length) * cutwidth))
            myplank('Rest') += cutwidth

            #Set rest of variables
            myplank('Baseprice') = (myplank('Price')) / ((myplank('Length') - myplank('Rest')))
            myplank('Optimal') = (myplank('Rest') <= minreq)


            #Check if rest length is positive
            if myplank('Rest') >= 0:
                combs.append(myplank.copy())
                myplank(reqs(0)('Length')) += 1
            else:
                for i in range(len(reqs)):
                    if myplank(reqs(i)('Length')) > 0:
                        myplank(reqs(i)('Length')) = 0
                        if i < len(reqs)-1:
                            myplank(reqs(i+1)('Length')) += 1
                            break
                        else:
                            filling = False

    #Sort combinations descending by remaining length, get solution
    combs = sorted(combs, key=lambda k: k('Rest'))
    res.append(getSolution(reqs, combs))

    #Sort combinations by getting biggest lengths first (largest to smallest), optimal pieces first, get solution
    listreq = sorted(listreq, reverse=True)
    listreq.insert(0,'Optimal')
    for x in reversed(listreq):
        combs.sort(key=itemgetter(x), reverse=True)
    res.append(getSolution(reqs, combs))

    #Sort combination by least effective price per unit, get solution
    combs = sorted(combs, key=lambda k: k('Baseprice'))
    res.append(getSolution(reqs, combs))

    #Get cheapest option & make readable format
    cheapest = min((x(1) for x in res))
    for x in res:
        if x(1) == cheapest:
            sol = {}
            sol('Required base material') = {}
            sol('Cut list') = ()
            i = 1
            for plank in x(0):
                if plank('Length') not in sol('Required base material'):
                    sol('Required base material')(plank('Length')) = 0
                sol('Required base material')(plank('Length')) += 1
                str = f"Plank {i}: Length {plank('Length')}, "
                for req in reqs:
                    if plank(req('Length')) > 0: str += f"{plank(req('Length'))}x {req('Length')}, "
                str += f"rest: {plank('Rest')}"
                sol('Cut list').append(str)
                i += 1

            sol('Total price') = cheapest
            break

    #Get output location
    if outputstr:
        outputfile = outputstr
        if outputfile(len(outputfile)-1) != "//":
            outputfile += "//"
        outputfile += "cutlist_result.json"
    else:
        outputfile = "./output/cutlist_result.json"

    #Make directories
    Path(os.path.dirname(outputfile)).mkdir(parents=True, exist_ok=True)

    #Output to file
    f = open(outputfile, "w")
    json.dump(sol, f, indent=4)
    f.close

    return("Success")

theme – Invalid template file in module ”

I just installed a new theme, and as soon as I go to the front-end I get this exception:

1 exception(s):
Exception #0 (MagentoFrameworkExceptionValidatorException): Invalid template file: 'Magento_Theme::newletter-popup.phtml' in module: '' block's name: 'home.script'

Exception #0 (MagentoFrameworkExceptionValidatorException): Invalid template file: 'Magento_Theme::newletter-popup.phtml' in module: '' block's name: 'home.script'
<pre>#1 MagentoFrameworkViewElementTemplate->_toHtml() called at (lib/internal/Magento/Framework/View/Element/AbstractBlock.php:1110)
#2 MagentoFrameworkViewElementAbstractBlock->MagentoFrameworkViewElement{closure}() called at (lib/internal/Magento/Framework/View/Element/AbstractBlock.php:1114)
#3 MagentoFrameworkViewElementAbstractBlock->_loadCache() called at (lib/internal/Magento/Framework/View/Element/AbstractBlock.php:674)
#4 MagentoFrameworkViewElementAbstractBlock->toHtml() called at (lib/internal/Magento/Framework/View/Layout.php:566)
#5 MagentoFrameworkViewLayout->_renderBlock('home.script') called at (lib/internal/Magento/Framework/View/Layout.php:542)
#6 MagentoFrameworkViewLayout->renderNonCachedElement('home.script') called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:206)
#7 MagentoFrameworkViewLayoutInterceptor->renderNonCachedElement('home.script') called at (lib/internal/Magento/Framework/View/Layout.php:497)
#8 MagentoFrameworkViewLayout->renderElement('home.script', false) called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:193)
#9 MagentoFrameworkViewLayoutInterceptor->renderElement('home.script', false) called at (lib/internal/Magento/Framework/View/Layout.php:594)
#10 MagentoFrameworkViewLayout->_renderContainer('page.wrapper', false) called at (lib/internal/Magento/Framework/View/Layout.php:544)
#11 MagentoFrameworkViewLayout->renderNonCachedElement('page.wrapper') called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:206)
#12 MagentoFrameworkViewLayoutInterceptor->renderNonCachedElement('page.wrapper') called at (lib/internal/Magento/Framework/View/Layout.php:497)
#13 MagentoFrameworkViewLayout->renderElement('page.wrapper', false) called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:193)
#14 MagentoFrameworkViewLayoutInterceptor->renderElement('page.wrapper', false) called at (lib/internal/Magento/Framework/View/Layout.php:594)
#15 MagentoFrameworkViewLayout->_renderContainer('root', false) called at (lib/internal/Magento/Framework/View/Layout.php:544)
#16 MagentoFrameworkViewLayout->renderNonCachedElement('root') called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:206)
#17 MagentoFrameworkViewLayoutInterceptor->renderNonCachedElement('root') called at (lib/internal/Magento/Framework/View/Layout.php:497)
#18 MagentoFrameworkViewLayout->renderElement('root', true) called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:193)
#19 MagentoFrameworkViewLayoutInterceptor->renderElement('root') called at (lib/internal/Magento/Framework/View/Layout.php:963)
#20 MagentoFrameworkViewLayout->getOutput() called at (lib/internal/Magento/Framework/Interception/Interceptor.php:58)
#21 MagentoFrameworkViewLayoutInterceptor->___callParent('getOutput', array()) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:138)
#22 MagentoFrameworkViewLayoutInterceptor->MagentoFrameworkInterception{closure}() called at (lib/internal/Magento/Framework/Interception/Interceptor.php:153)
#23 MagentoFrameworkViewLayoutInterceptor->___callPlugins('getOutput', array(), array(array('layout-model-cac...'))) called at (generated/code/Magento/Framework/View/Layout/Interceptor.php:494)
#24 MagentoFrameworkViewLayoutInterceptor->getOutput() called at (lib/internal/Magento/Framework/View/Result/Page.php:257)
#25 MagentoFrameworkViewResultPage->render(&MagentoFrameworkAppResponseHttpInterceptor#0000000060b00286000000003b09d81b#) called at (lib/internal/Magento/Framework/View/Result/Layout.php:170)
#26 MagentoFrameworkViewResultLayout->renderResult(&MagentoFrameworkAppResponseHttpInterceptor#0000000060b00286000000003b09d81b#) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:58)
#27 MGSMpanelBlockFrameworkPageInterceptor->___callParent('renderResult', array(&MagentoFrameworkAppResponseHttpInterceptor#0000000060b00286000000003b09d81b#)) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:138)
#28 MGSMpanelBlockFrameworkPageInterceptor->MagentoFrameworkInterception{closure}(&MagentoFrameworkAppResponseHttpInterceptor#0000000060b00286000000003b09d81b#) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:153)
#29 MGSMpanelBlockFrameworkPageInterceptor->___callPlugins('renderResult', array(&MagentoFrameworkAppResponseHttpInterceptor#0000000060b00286000000003b09d81b#), array(array('result-messages', 'result-builtin-c...', 'result-varnish-c...'))) called at (generated/code/MGS/Mpanel/Block/Framework/Page/Interceptor.php:156)
#30 MGSMpanelBlockFrameworkPageInterceptor->renderResult(&MagentoFrameworkAppResponseHttpInterceptor#0000000060b00286000000003b09d81b#) called at (lib/internal/Magento/Framework/App/Http.php:120)
#31 MagentoFrameworkAppHttp->launch() called at (generated/code/Magento/Framework/App/Http/Interceptor.php:24)
#32 MagentoFrameworkAppHttpInterceptor->launch() called at (lib/internal/Magento/Framework/App/Bootstrap.php:260)
#33 MagentoFrameworkAppBootstrap->run(&MagentoFrameworkAppHttpInterceptor#0000000060b0029d000000003b09d81b#) called at (index.php:39)
</pre>

When I try to go to admin, instead it gives me this:

1 exception(s):
Exception #0 (MagentoFrameworkExceptionLocalizedException): Invalid Document 
Element 'add': Duplicate key-sequence ('Magento_Backend::mgs') in unique identity-constraint 'uniqueAddItemId'.
Line: 25


Exception #0 (MagentoFrameworkExceptionLocalizedException): Invalid Document 
Element 'add': Duplicate key-sequence ('Magento_Backend::mgs') in unique identity-constraint 'uniqueAddItemId'.
Line: 25

<pre>#1 MagentoFrameworkConfigReaderFilesystem->read('adminhtml') called at (app/code/Magento/Backend/Model/Menu/Config.php:144)
#2 MagentoBackendModelMenuConfig->_initMenu() called at (app/code/Magento/Backend/Model/Menu/Config.php:111)
#3 MagentoBackendModelMenuConfig->getMenu() called at (app/code/Magento/Backend/Model/Url.php:365)
#4 MagentoBackendModelUrl->_getMenu() called at (app/code/Magento/Backend/Model/Url.php:325)
#5 MagentoBackendModelUrl->getStartupPageUrl() called at (app/code/Magento/Backend/App/AbstractAction.php:186)
#6 MagentoBackendAppAbstractAction->_processUrlKeys() called at (generated/code/Magento/Backend/Controller/Adminhtml/Index/Index/Interceptor.php:50)
#7 MagentoBackendControllerAdminhtmlIndexIndexInterceptor->_processUrlKeys() called at (app/code/Magento/Backend/App/Request/BackendValidator.php:175)
#8 MagentoBackendAppRequestBackendValidator->validate(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#, &MagentoBackendControllerAdminhtmlIndexIndexInterceptor#000000002dd89b3c0000000046a9b4a0#) called at (lib/internal/Magento/Framework/App/Request/CompositeValidator.php:40)
#9 MagentoFrameworkAppRequestCompositeValidator->validate(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#, &MagentoBackendControllerAdminhtmlIndexIndexInterceptor#000000002dd89b3c0000000046a9b4a0#) called at (lib/internal/Magento/Framework/App/FrontController.php:160)
#10 MagentoFrameworkAppFrontController->processRequest(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#, &MagentoBackendControllerAdminhtmlIndexIndexInterceptor#000000002dd89b3c0000000046a9b4a0#) called at (lib/internal/Magento/Framework/App/FrontController.php:118)
#11 MagentoFrameworkAppFrontController->dispatch(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:58)
#12 MagentoFrameworkAppFrontControllerInterceptor->___callParent('dispatch', array(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#)) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:138)
#13 MagentoFrameworkAppFrontControllerInterceptor->MagentoFrameworkInterception{closure}(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#) called at (lib/internal/Magento/Framework/Interception/Interceptor.php:153)
#14 MagentoFrameworkAppFrontControllerInterceptor->___callPlugins('dispatch', array(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#), array(array('default_store_se...', 'page_cache_from_...', 'storeCookieValid...', 'install', 'configHash'))) called at (generated/code/Magento/Framework/App/FrontController/Interceptor.php:26)
#15 MagentoFrameworkAppFrontControllerInterceptor->dispatch(&MagentoFrameworkAppRequestHttp#000000002dd898420000000046a9b4a0#) called at (lib/internal/Magento/Framework/App/Http.php:116)
#16 MagentoFrameworkAppHttp->launch() called at (generated/code/Magento/Framework/App/Http/Interceptor.php:24)
#17 MagentoFrameworkAppHttpInterceptor->launch() called at (lib/internal/Magento/Framework/App/Bootstrap.php:260)
#18 MagentoFrameworkAppBootstrap->run(&MagentoFrameworkAppHttpInterceptor#000000002dd898540000000046a9b4a0#) called at (index.php:39)
</pre>

Furthermore, when I run setup compile,

Fatal error:  Declaration of MGSMpanelControllerCategoryView::execute() must be compatible with MagentoCatalogControllerCategoryView::execute(): ?MagentoFrameworkControllerResultInterface in /var/www/html/Magento2/app/code/MGS/Mpanel/Controller/Category/View.php on line 129

magento2 – Is it acceptable to put lib folder inside module folder structure?

Before I used this code to include some packages:

require_once($this->dir->getPath('lib_internal') . '/vendor/module/nuevomailer/api.php');

Now Magento doesn’t allow to use require_once anymore so I thought that the simplest way without creating another packages just for third party libraries would be to just create lib folder inside existing vendorname/modulename folder and call it like this:

    class Subscriber extends MagentoFrameworkModelAbstractModel{
        protected $mailchimp;
        protected $phpmailer;
        ...
        public function _construct(
            VendornameModulenameLibMailchimp $mailchimp,
            VendornameModulenameLibPhpmailer $phpmailer,
            ...
        function subscribe(){
            $this->mailchimp->subscribe();
        }

Is that acceptable method? I checked Magento modul file structure (https://devdocs.magento.com/guides/v2.3/extension-dev-guide/build/module-file-structure.html) and I couldn’t find lib folder. Is it allowed to put any other folder into module directory?

networking – Missing 802.1q module from Ubuntu 18.04

I have just installed a fresh copy of Ubuntu 18.04 LTS and I needed to add support for vlan tagging. So I did follow the usual wiki and then did, apt install vlan and then when trying to load / activate the 802.1q, via modprobe 802.1q, I get the following error.

modprobe: FATAL: Module 802.1q not found in directory /lib/modules/4.15.0-101-generic

And I looked into this directory and there is no net folder with this 802.1q module as some searches suggested. I then upgraded the kernel to 5.4 and then even to 5.7 and the issue remains.

Can someone help resolve this issue please? Thanks so much.