class BaseConfigHandler(object):
    def __init__(self, data=None):
        self.data = data
        self.__form_cache = None

    @property
    def form(self):
        if self.__form_cache is None:
            self.__form_cache = self.get_form()
        return self.__form_cache

    def get_form(self):
        """Get form. MUST be a single-section form.

        :return:
        :rtype: fapi.ForisForm
        """
        raise NotImplementedError()

    def save(self, extra_callbacks=None):
        """

        :param extra_callbacks: list of extra callbacks to call when saved
        :return:
        """
        form = self.form
        form.validate()
        if extra_callbacks:
            for cb in extra_callbacks:
                form.add_callback(cb)
        if form.valid:
            form.save()
            return True
        else:
            return False class ForisAjaxForm(object):
class ForisFormElement(object):
class ForisForm(ForisFormElement):
class Section(ForisFormElement):
class Field(ForisFormElement):
    def make_form(self, data: typing.Optional[dict]):
    def convert_data_from_form_to_backend(self, *args, **kwargs):
    def convert_data_from_backend_to_form(self, *args, **kwargs):
    def __init__(self, data=None, controller_id=None):
    def __init__(self, name):
    def __iter__(self):
    def _add(self, child):
    def _remove(self, child):
    def sections(self):
    def __init__(self, name, data=None, validators=[]):
    def data(self):
    def current_data(self):
    def clean_data(self, data):
    def invalidate_data(self):
    def _form(self):
    def valid(self):
    def _get_all_fields(self, element=None, fields=None):
    def get_active_fields(self, element=None, data=None):
    def add_section(self, *args, **kwargs):
    def active_fields(self):
    def errors(self):
    def render_errors(self):
    def render(self):
    def save(self):
    def validate(self):
    def add_callback(self, cb):
    def process_callbacks(self, form_data):
    def __init__(self, main_form, name, title, description=None):
    def active_fields(self):
    def add_field(self, *args, **kwargs):
    def add_section(self, *args, **kwargs):
    def render(self):
    def __init__(
        self,
        main_form,
        type,
        name,
        label=None,
        required=False,
        preproc=None,
        validators=None,
        hint="",
        multifield=False,
        **kwargs
    ):
    def __str__(self):
    def _generate_html_classes(self):
    def _generate_html_data(self):
    def field(self):
    def html_id(self):
    def label_tag(self):
        def create_label(text):
    def errors(self):
    def hidden(self):
    def render(self):
    def requires(self, field, value=None):
    def has_requirements(self, data): class Validator(object):
class RegExp(Validator):
class NotEmpty(Validator):
class IPv4(Validator):
class IPv4Netmask(Validator):
class IPv6(Validator):
class AnyIP(Validator):
class IPv6Prefix(Validator):
class IPv4Prefix(Validator):
class PositiveInteger(Validator):
class Time(RegExp):
class Datetime(Validator):
class FloatRange(Validator):
class Domain(Validator):
class MacAddress(Validator):
class Duid(Validator):
class InRange(Validator):
class LenRange(Validator):
class ByteLenRange(Validator):
class EqualTo(Validator):
class RequiredWithOtherFields(Validator):
class DhcpRangeValidator:
class DhcpRangeRouterIpValidator:
    def __deepcopy__(self, memo):
    def __init__(self, msg):
    def valid(self, value):
def convert_to_anchored_pattern(pattern):
    def __init__(self, msg, reg_exp):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def __init__(self):
    def valid(self, value):
    def __init__(self, low, high):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self):
    def valid(self, value):
    def __init__(self, low, high):
    def valid(self, value):
    def __init__(self, low, high):
    def valid(self, value):
    def __init__(self, low, high):
    def valid(self, value):
    def __init__(self, field1, field2, message):
    def valid(self, data):
    def __init__(self, fields, message):
    def valid(self, data):
    def __init__(self, netmask_field, dhcp_start_field, dhcp_limit_field, msg, skip_conditions=[]):
    def valid(self, data):
    def __init__(
        self,
        router_ip_field,
        netmask_field,
        dhcp_start_field,
        dhcp_limit_field,
        msg,
        skip_conditions=[],
    ):
    def valid(self, data):
def validators_as_data_dict(validators): class ForisState(object):
    def __init__(self):
    def update_lang(self, lang):
    def set_app(self, app):
    def set_backend(self, backend):
    def set_websocket(self, ws_port, ws_path, wss_port, wss_path):
    def update_reboot_required(self, required):
    def update_notification_count(self, new_count):
    def repr(self):
    def set_updater_is_running(self, running):
    def set_turris_os_version(self, version):
    def set_device(self, device):
    def update_password_set(self, password_set):
    def update_guide(self, guide_data):
    def set_assets_path(self, assets_path):
    def set_sentry(self, running): class Checkbox(Input):
    """Checkbox input.

    >>> Checkbox('foo', value='bar', checked=True).render()
    u'<input type="hidden" name="foo" value="0"><input checked="checked" type="checkbox" id="field-foo_bar" value="bar" name="foo"/>'
    >>> Checkbox('foo', value='bar').render()
    u'<input type="hidden" name="foo" value="0"><input type="checkbox" id="field-foo_bar" value="bar" name="foo"/>'
    >>> c = Checkbox('foo', value='bar')
    >>> c.validate('on')
    True
    >>> c.render()
    u'<input type="hidden" name="foo" value="0"><input type="checkbox" id="field-foo_bar" value="bar" name="foo"/>'
    """

    def __init__(self, name, *validators, **attrs):
        self.checked = attrs.pop("checked", False)
        Input.__init__(self, name, *validators, **attrs)

    def get_default_id(self):
        value = safestr(self.value or "")
        return ID_TEMPLATE % self.name + "_" + value.replace(" ", "_")

    def render(self):
        attrs = self.attrs.copy()
        attrs["type"] = "checkbox"
        attrs["name"] = self.name
        attrs["value"] = self.value

        if self.checked:
            attrs["checked"] = "checked"
        return '<input type="hidden" name="%s" value="0">' "<input %s/>" % (attrs["name"], attrs)

    def set_value(self, value):
        self.checked = bool(value)

    def get_value(self):
        return self.checked class Dropdown(InputWithArgs):
    r"""Dropdown/select input.

        >>> Dropdown(name='foo', args=['a', 'b', 'c'], value='b').render()
        u'<input type="hidden" name="foo" value=""><select id="field-foo" name="foo">\n  <option value="a">a</option>\n  <option selected="selected" value="b">b</option>\n  <option value="c">c</option>\n</select>\n'
        >>> Dropdown(name='foo', args=[('a', 'aa'), ('b', 'bb'), ('c', 'cc')], value='b').render()
        u'<input type="hidden" name="foo" value=""><select id="field-foo" name="foo">\n  <option value="a">aa</option>\n  <option selected="selected" value="b">bb</option>\n  <option value="c">cc</option>\n</select>\n'
    """

    def render(self):
        attrs = self.attrs.copy()
        attrs["name"] = self.name
        # dummy value to post when no item is selected
        x = '<input type="hidden" name="%s" value="">' % self.name
        x += "<select %s>\n" % attrs

        for arg in self.args:
            x += self._render_option(arg)

        x += "</select>\n"
        return x

    def _render_option(self, arg, indent="  "):
        if isinstance(arg, (tuple, list)):
            value, desc = arg
        else:
            value, desc = arg, arg

        if self.value == value or (isinstance(self.value, list) and value in self.value):
            select_p = ' selected="selected"'
        else:
            select_p = ""
        return indent + '<option%s value="%s">%s</option>\n' % (
            select_p,
            websafe(value),
            websafe(desc),
        ) class Textbox(Input):
    """Textbox input.

        >>> Textbox(name='foo', value='bar').render()
        u'<input type="text" id="field-foo" value="bar" name="foo"/>'
        >>> Textbox(name='foo', value=0).render()
        u'<input type="text" id="field-foo" value="0" name="foo"/>'
    """

    def get_type(self):
        return "text" class Number(Input):
    """Number input.

        >>> Number(name='number', value='123').render()
        u'<input type="number" id="field-number" value="123" name="number"/>'
    """

    def get_type(self):
        return "number" class PasswordWithHide(Password):
    @property
    def render_extra_after(self):
        return "<span class='password-toggle'><i class='fas fa-eye'></i></span>" class _LangDict(collections.OrderedDict):
class SimpleDelayedTranslator(object):
class ForisInternationalizationExtension(InternationalizationExtension):
    def __missing__(self, key):
    def __init__(self, text):
    def __str__(self):
    def __add__(self, other):
def set_current_language(language):
    def __init__(self, environment):
from .base import BaseConfigHandler
from foris import fapi, validators
from foris.state import current_state
from foris.form import Checkbox, Dropdown, Textbox, Number, PasswordWithHide
from foris.utils.translators import gettext_dummy as gettext, _
        wan_main.add_field(
            Textbox, name="username", label=_("PAP/CHAP username"), required=True,
        ).requires("proto", WAN_PPPOE)
        wan_main.add_field(
            PasswordWithHide, name="password", label=_("PAP/CHAP password"), required=True,
        ).requires("proto", WAN_PPPOE)

        # IPv6 configuration
        wan_main.add_field(
            Dropdown,
            name="wan6_proto",
            label=_("IPv6 protocol"),
            args=WAN6_OPTIONS,
            default=WAN6_NONE,
        )
        wan_main.add_field(
            Textbox,
            name="ip6addr",
            label=_("IPv6 address"),
            validators=validators.IPv6Prefix(),
            required=True,
            hint=_(
                "IPv6 address and prefix length for WAN interface, " "e.g. 2001:db8:be13:37da::1/64"
            ),
        ).requires("wan6_proto", WAN6_STATIC)
        wan_main.add_field(
            Textbox,
            name="ip6gw",
            label=_("IPv6 gateway"),
            validators=validators.IPv6(),
            required=True,
        ).requires("wan6_proto", WAN6_STATIC)
        wan_main.add_field(
            Textbox,
            name="ip6prefix",
            label=_("IPv6 prefix"),
            validators=validators.IPv6Prefix(),
            hint=_("Address range for local network, " "e.g. 2001:db8:be13:37da::/64"),
        ).requires("wan6_proto", WAN6_STATIC)
        # DNS servers
        wan_main.add_field(
            Textbox,
            name="ipv6_dns1",
            label=_("DNS server 1 (IPv6)"),
            validators=validators.IPv6(),
            hint=_(
                "DNS server address is not required as the built-in "
                "DNS resolver is capable of working without it."
            ),
        ).requires("wan6_proto", WAN6_STATIC)
        wan_main.add_field(
            Textbox,
            name="ipv6_dns2",
            label=_("DNS server 2 (IPv6)"),
            validators=validators.IPv6(),
            hint=_(
                "DNS server address is not required as the built-in "
                "DNS resolver is capable of working without it."
            ),
        ).requires("wan6_proto", WAN6_STATIC)
        wan_main.add_field(
            Textbox,
            name="ip6duid",
            label=_("Custom DUID"),
            validators=validators.Duid(),
            placeholder=self.status_data["last_seen_duid"],
            hint=_("DUID which will be provided to the DHCPv6 server."),
        ).requires("wan6_proto", WAN6_DHCP)
        wan_main.add_field(
            Textbox,
            name="6to4_ipaddr",
            label=_("Public IPv4"),
            validators=validators.IPv4(),
            hint=_(
                "In order to use 6to4 protocol, you might need to specify your public IPv4 "
                "address manually (e.g. when your WAN interface has a private address which "
                "is mapped to public IP)."
            ),
            placeholder=_("use autodetection"),
            required=False,
        ).requires("wan6_proto", WAN6_6TO4)
        wan_main.add_field(
            Textbox,
            name="6in4_server_ipv4",
            label=_("Provider IPv4"),
            validators=validators.IPv4(),
            hint=_("This address will be used as a endpoint of the tunnel on the provider's side."),
            required=True,
        ).requires("wan6_proto", WAN6_6IN4)
        wan_main.add_field(
            Textbox,
            name="6in4_ipv6_prefix",
            label=_("Routed IPv6 prefix"),
            validators=validators.IPv6Prefix(),
            hint=_("IPv6 addresses which will be routed to your network."),
            required=True,
        ).requires("wan6_proto", WAN6_6IN4)
        wan_main.add_field(
            Number,
            name="6in4_mtu",
            label=_("MTU"),
            validators=validators.InRange(1280, 1500),
            hint=_("Maximum Transmission Unit in the tunnel (in bytes)."),
            required=True,
            default="1480",
        ).requires("wan6_proto", WAN6_6IN4)
        wan_main.add_field(
            Checkbox,
            name="6in4_dynamic_enabled",
            label=_("Dynamic IPv4 handling"),
            hint=_(
                "Some tunnel providers allow you to have public dynamic IPv4. "
                "Note that you need to fill in some extra fields to make it work."
            ),
            default=False,
        ).requires("wan6_proto", WAN6_6IN4)
        wan_main.add_field(
            Textbox,
            name="6in4_tunnel_id",
            label=_("Tunnel ID"),

            validators=validators.NotEmpty(),