# Path: jetstream/templatetags/jetstream_tags.py
# @register.filter(name='custom_bleach')
# def custom_bleach(value, allowed_tags):
#     """
#     Works just like the 'bleach' tempalte filter, but takes an argument of a comma-separated string of the tags that
#     should be allowed through the filter. This list of tags *overrides* the list in the settings, so be thorough.
#     """
#     # Use the bleach_args built from the settings, but replace the 'tags' arg with the supplied comma-separated list.
#     bleach_args = get_bleach_default_options()
#     kwargs = dict(**bleach_args)
#     kwargs['tags'] = [tag.strip() for tag in allowed_tags.split(',')]
#     bleached_value = bleach.clean(value, **kwargs)
#     return mark_safe(bleached_value)
# 
# Path: jetstream/utils.py
# BACKGROUND_COLORS = [
#     (None,  'Transparent'),
#     ('white', 'White'),
#     ('black', 'Black'),
#     ('orange', 'Orange'),
#     ('ltgray', 'Light Gray'),
#     ('midgray', 'Mid Gray'),
#     ('darkergray', 'Dark Gray'),
#     ('dkgray', 'Very Dark Gray'),
#     ('olivegreen', 'Olive Green'),
#     ('purple', 'Purple'),
#     ('darkteal', 'Dark Teal'),
# ]
# 
# FOREGROUND_COLORS = [
#     (None, 'Default'),
#     ('dkgray', 'Dark Gray'),
#     ('black', 'Black'),
#     ('white', 'White')
# ]
# 
# def get_block_tuple(block_inst):
#     """
#     Returns the canned block tuple for use in StreamField and StreamBlock definitions (but NOT in StructBlocks!).
#     We use this everywhere so that our code consistently generates the same tuple at every organiziational level.
#     """
#     try:
#         return block_inst.get_block_tuple()
#     except AttributeError:
#         # If the block instance hasn't got a get_block_tuple() method, build the default tuple.
#         return (block_inst.__class__.__name__, block_inst)
# 
# class BlockTupleMixin(object):
#     """
#     All our custom block classes need to mixin this class so that our code consistently generates the same tuple at
#     every organiziational level (e.g. the Page.body level and the TwoColumnBlock level).
# 
#     Classes that need to use a custom string for their block tuple (e.g. TwoColumnBlock and BaseTwoColumnSubblock, which
#     both need the same tuple) can override get_block_tuple().
#     """
# 
#     @classmethod
#     def get_block_machine_name(cls):
#         return cls.__name__
# 
#     def get_block_tuple(self):
#         return (self.__class__.__name__, self)


from bs4 import BeautifulSoup
from collections import OrderedDict
from django import forms
from django.core.exceptions import ValidationError
from django.template.loader import render_to_string
from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from djunk.middleware import get_current_request
from wagtail.core import blocks, telepath
from wagtail.core.blocks import BaseStreamBlock
from wagtail.core.blocks.struct_block import StructBlockAdapter
from wagtail.core.models import Site
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtail.embeds.blocks import EmbedBlock
from .templatetags.jetstream_tags import custom_bleach
    from features.registry import register_feature, registry
from .utils import BACKGROUND_COLORS, FOREGROUND_COLORS, get_block_tuple, BlockTupleMixin
        label='Left column content',
        required=False
    )

    middle_column = FeatureCustomizedStreamBlock(
        COLUMN_PERMITTED_BLOCKS,
        icon='arrow-right',
        label='Middle column content',
        required=False
    )

    right_column = FeatureCustomizedStreamBlock(
        COLUMN_PERMITTED_BLOCKS,
        icon='arrow-right',
        label='Right column content',
        required=False
    )

    class Meta:
        template = 'jetstream/blocks/layout/three_column_block.html'
        form_classname = 'layout-three-column struct-block'
        label = 'Three Columns'

    @classmethod
    def get_block_machine_name(cls):
        """
        Overrides this method from BlockTupleMixin so that we use the same machine name as ThreeColumnSubBlock.
        """
        return 'three_column_layout'


# Path: jetstream/templatetags/jetstream_tags.py
# @register.filter(name='custom_bleach')
# def custom_bleach(value, allowed_tags):
#     """
#     Works just like the 'bleach' tempalte filter, but takes an argument of a comma-separated string of the tags that
#     should be allowed through the filter. This list of tags *overrides* the list in the settings, so be thorough.
#     """
#     # Use the bleach_args built from the settings, but replace the 'tags' arg with the supplied comma-separated list.
#     bleach_args = get_bleach_default_options()
#     kwargs = dict(**bleach_args)
#     kwargs['tags'] = [tag.strip() for tag in allowed_tags.split(',')]
#     bleached_value = bleach.clean(value, **kwargs)
#     return mark_safe(bleached_value)
# 
# Path: jetstream/utils.py
# BACKGROUND_COLORS = [
#     (None,  'Transparent'),
#     ('white', 'White'),
#     ('black', 'Black'),
#     ('orange', 'Orange'),
#     ('ltgray', 'Light Gray'),
#     ('midgray', 'Mid Gray'),
#     ('darkergray', 'Dark Gray'),
#     ('dkgray', 'Very Dark Gray'),
#     ('olivegreen', 'Olive Green'),
#     ('purple', 'Purple'),
#     ('darkteal', 'Dark Teal'),
# ]
# 
# FOREGROUND_COLORS = [
#     (None, 'Default'),
#     ('dkgray', 'Dark Gray'),
#     ('black', 'Black'),
#     ('white', 'White')
# ]
# 
# def get_block_tuple(block_inst):
#     """
#     Returns the canned block tuple for use in StreamField and StreamBlock definitions (but NOT in StructBlocks!).
#     We use this everywhere so that our code consistently generates the same tuple at every organiziational level.
#     """
#     try:
#         return block_inst.get_block_tuple()
#     except AttributeError:
#         # If the block instance hasn't got a get_block_tuple() method, build the default tuple.
#         return (block_inst.__class__.__name__, block_inst)
# 
# class BlockTupleMixin(object):
#     """
#     All our custom block classes need to mixin this class so that our code consistently generates the same tuple at
#     every organiziational level (e.g. the Page.body level and the TwoColumnBlock level).
# 
#     Classes that need to use a custom string for their block tuple (e.g. TwoColumnBlock and BaseTwoColumnSubblock, which
#     both need the same tuple) can override get_block_tuple().
#     """
# 
#     @classmethod
#     def get_block_machine_name(cls):
#         return cls.__name__
# 
#     def get_block_tuple(self):
#         return (self.__class__.__name__, self)


# Path: jetstream/blocks.py
from bs4 import BeautifulSoup
from collections import OrderedDict
from django import forms
from django.core.exceptions import ValidationError
from django.template.loader import render_to_string
from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from djunk.middleware import get_current_request
from wagtail.core import blocks, telepath
from wagtail.core.blocks import BaseStreamBlock
from wagtail.core.blocks.struct_block import StructBlockAdapter
from wagtail.core.models import Site
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtail.embeds.blocks import EmbedBlock
from .templatetags.jetstream_tags import custom_bleach
    from features.registry import register_feature, registry
from .utils import BACKGROUND_COLORS, FOREGROUND_COLORS, get_block_tuple, BlockTupleMixin

        label='Left column content',
        required=False
    )

    middle_column = FeatureCustomizedStreamBlock(
        COLUMN_PERMITTED_BLOCKS,
        icon='arrow-right',
        label='Middle column content',
        required=False
    )

    right_column = FeatureCustomizedStreamBlock(
        COLUMN_PERMITTED_BLOCKS,
        icon='arrow-right',
        label='Right column content',
        required=False
    )

    class Meta:
        template = 'jetstream/blocks/layout/three_column_block.html'
        form_classname = 'layout-three-column struct-block'
        label = 'Three Columns'

    @classmethod
    def get_block_machine_name(cls):
        """
        Overrides this method from BlockTupleMixin so that we use the same machine name as ThreeColumnSubBlock.
        """
        return 'three_column_layout'


    def get_block_tuple(self):