text:
from struct import pack as struct_pack
import binascii
import numpy as np
import matplotlib.pyplot as plt

from menpo.compatibility import unicode
from menpo.feature import glyph, sum_channels

def verify_ipython_and_kernel():
    r"""
    Verify that the current environment is a valid IPython environment that
    contains a communication kernel. There is no solid way of identifying a
    notebook vs. the QT console, but the QT console will at least visualise the
    matplotlib commands without the widget functionality.

    Raises
    ------
    ValueError
        Unable to import IPython, ipykernel or traitlets
    ValueError
        No valid IPython kernel found
    ValueError
        The IPython kernel does not contain a communication manager (the
        default IPython shell rather than a notebook or a QT console).
    """
    try:
        from IPython import get_ipython
        from ipykernel.comm import Comm
        from traitlets.traitlets import TraitError

        if get_ipython() is None:
            raise ValueError('menpowidgets can only be used from inside '
                             'a Jupyter notebook. We were unable to detect '
                             'an active IPython session. Please re-run your '
                             'code from inside a Jupyter Notebook.')
        try:
            Comm()
        except TraitError:
            raise ValueError('menpowidgets can only be used from inside '
                             'a Jupyter notebook. We were unable to detect '
                             'a valid active kernel. Please ensure your code '
                             'is running inside a Jupyter notebook and not '
                             'a standalone script or the default IPython '
                             'shell.')
    except ImportError:
        raise ValueError('menpowidgets can only be used from inside '
                         'a Jupyter notebook. We were unable to import '
                         'IPython, please ensure it is installed.')

def lists_are_the_same(a, b):
    r"""
    Function that checks if two `lists` have the same elements in the same
    order.

    Returns
    -------
    _lists_are_the_same : `bool`
        ``True`` if the lists are the same.
    """
    if len(a) == len(b):
        for i, j in zip(a, b):
            if i != j:
                return False
        return True
    else:
        return False

def rgb2hex(rgb):
    return '#' + binascii.hexlify(struct_pack('BBB', *rgb)).decode('ascii')

def decode_colour(colour):
    if not (isinstance(colour, str) or isinstance(colour, unicode)):
        # we assume that RGB was passed in. Convert it to unicode hex
        return rgb2hex(colour)
    else:
        return str(colour)

def str_is_int(s):
    r"""
    Function that returns ``True`` if a given `str` is a positive or negative
    integer.

    Parameters
    ----------
    s : `str`
        The command string.
    """
    return s.isdigit() or (s.startswith('-') and s[1:].isdigit())

def str_is_float(s):
    r"""
    Function that returns ``True`` if a given `str` is a positive or negative
    float.

    Parameters
    ----------
    s : `str`
        The command string.
    """
    return s.count(".") == 1 and str_is_int(s.replace('.', '', 1))

def parse_int_range_command_with_comma(cmd):
    r"""
    Function that parses a range/list command for which contains at least one
    comma (``,``). The function returns a `list` with the integer values that
    are included in the command. It also ignores any redundant whitespaces
    that may exist in the command. For example ::

        parse_int_range_command_with_comma([1, 2,-3 ])

    returns ::

        '[1, 2, -3]'

    Parameter
    ---------
    cmd : `str`
        The command string.

    Returns
    -------
    cmd_list : `list`
        The list of integers.

    Raises
    ------
    ValueError
        Command cannot start or end with ','.
    ValueError
        Command cannot contain ',,'.
    ValueError
        Only integers allowed.
    """
    if cmd.startswith(',') or cmd.endswith(','):
        # if cmd starts or ends with ',', raise an error
        raise ValueError("Command cannot start or end with ','.")
    else:
        # get the parts in between commas
        tmp_cmd = cmd.split(',')
        # for each part
        final_cmd = []
        for i in tmp_cmd:
            if len(i) == 0:
                # this means that there was the ',,' pattern
                raise ValueError("Command cannot contain ',,'.")
            elif str_is_int(i):
                # if it is a positive or negative integer convert it to int
                final_cmd.append(int(i))
            else:
                # else raise an error
                raise ValueError("Only integers allowed.")
        return final_cmd

def parse_int_range_command(cmd):
    r"""
    Function that parses a command for list/range. It is able to recognize any
    pattern and detect pattern errors. Some characteristic examples are "10",
    "[10, 20]", "10, 20", "range(10)", "range(10, 20)", "range(10, 20, 2)",
    "1, 5, -3", etc. The function returns a `list` with integers, after
    interpreting the given command. It also ignores any redundant whitespaces
    that may exist in the command.

    Parameters
    ----------
    cmd : `str`
        The command string.

    Returns
    -------
    cmd_list : `list`
        The list of integers.

    Raises
    ------
    ValueError
        Command cannot contain floats.
    ValueError
        Wrong range command.
    ValueError
        Wrong command.
    """
    # remove all redundant spaces from cmd
    cmd = cmd.replace(" ", "")

    # remove all brackets from cmd
    cmd = cmd.replace("[", "")
    cmd = cmd.replace("]", "")

    # if cmd has '.' then it contains at least a float
    if cmd.count(".") > 0:
        raise ValueError("Command cannot contain floats.")

    # cmd has the form of "range(1, 10, 2)" or "range(10)"
    if cmd.startswith("range("):
        n_comma = cmd.count(",")
        if cmd.endswith(")") and (n_comma == 0 or n_comma == 1 or n_comma == 2):
            return eval("list({})".format(cmd))
        else:
            raise ValueError("Wrong range command.")

    # empty command
    if cmd == "":
        return []

    # get number of ','
    n_comma = cmd.count(",")

    if n_comma > 0:
        # parse cmd given that it contains only ','
        return parse_int_range_command_with_comma(cmd)
    elif n_comma == 0 and str_is_int(cmd):
        # cmd has the form of "10"
        return [int(cmd)]
    else:
        raise ValueError("Wrong command.")

def parse_float_range_command_with_comma(cmd):
    r"""
    Function that parses a range/list command for which contains at least one
    comma (``,``). The function returns a `list` with the float values that
    are included in the command. It also ignores any redundant whitespaces
    that may exist in the command. For example ::

        parse_float_range_command_with_comma([1., 2.,-3.])

    returns ::

        '[1.0, 2.0, -3.0]'

    Parameter
    ---------
    cmd : `str`
        The command string.

    Returns
    -------
    cmd_list : `list`
        The list of floats.

    Raises
    ------
    ValueError
        Command cannot start or end with ','.
    ValueError
        Command cannot contain ',,'.
    ValueError
        Only integers allowed.
    """
    if cmd.startswith(',') or cmd.endswith(','):
        # if cmd starts or ends with ',', raise an error
        raise ValueError("Command cannot start or end with ','.")
    else:
        # get the parts in between commas
        tmp_cmd = cmd.split(',')
        # for each part
        final_cmd = []
        for i in tmp_cmd:
            if len(i) == 0:
                # this means that there was the ',,' pattern
                raise ValueError("Command cannot contain ',,'.")
            elif str_is_int(i) or str_is_float(i):
                # if it is a positive or negative integer convert it to float
                final_cmd.append(float(i))
            else:
                # else raise an error
                raise ValueError("Only floats allowed.")
        return final_cmd

def parse_float_range_command(cmd):
    r"""
    Function that parses a command for list/range. It is able to recognize any
    pattern and detect pattern errors. Some characteristic examples are "10.5",
    "[10., 20.]", "10., 20.", "range(10.)", "range(10., 20.)",
    "range(10., 20., 2.)", "1., 5., -3.2", etc. The function returns a `list`
    with integers, after interpreting the given command. It also ignores any
    redundant whitespaces that may exist in the command.

    Parameters
    ----------
    cmd : `str`
        The command string.

    Returns
    -------
    cmd_list : `list`
        The list of floats.

    Raises
    ------
    ValueError
        Wrong range command.
    ValueError
        Wrong command.
    """
    # remove all redundant spaces from cmd
    cmd = cmd.replace(" ", "")

    # remove all brackets from cmd
    cmd = cmd.replace("[", "")
    cmd = cmd.replace("]", "")

    # cmd has the form of "range(1, 10, 2)" or "range(10)"
    if cmd.startswith("range("):
        if cmd.endswith(")"):
            nums = cmd[6:-1].split(',')
            if len(nums) == 1:
                arg1 = 0.
                arg2 = float(nums[0])
                arg3 = 1.
            elif len(nums) == 2:
                arg1 = float(nums[0])
                arg2 = float(nums[1])
                arg3 = 1.
            elif len(nums) == 3:
                arg1 = float(nums[0])
                arg2 = float(nums[1])
                arg3 = float(nums[2])
            else:
                raise ValueError("Wrong range command.")
            return list(np.arange(arg1, arg2, arg3))
        else:
            raise ValueError("Wrong range command.")

    # empty command
    if cmd == "":
        return []

    # get number of ','
    n_comma = cmd.count(",")

    if n_comma > 0:
        # parse cmd given that it contains only ','
        return parse_float_range_command_with_comma(cmd)
    elif n_comma == 0 and (str_is_int(cmd) or str_is_float(cmd)):
        # cmd has the form of "10"
        return [float(cmd)]
    else:
        raise ValueError("Wrong command.")

def parse_slicing_command_with_comma(cmd, length):
    r"""
    Function that parses a command for slicing which contains at least one comma
    (``,``). The function returns a `list` with the integer values that are
    included in the command. It also ignores any redundant whitespaces that may
    exist in the command. For example ::

        parse_slicing_command_with_comma([1, 2,-3 ], 10)

    returns ::

        '[1, 2, -3]'

    Parameter
    ---------
    cmd : `str`
        The command string.
    length : `int`
        The length of the variable that will get sliced.

    Returns
    -------
    cmd_list : `list`
        The list that can be used for slicing after interpreting and evaluating
        the provided command.

    Raises
    ------
    ValueError
        Command cannot start or end with ','.
    ValueError
        Command cannot contain a pattern of the form ',,'.
    ValueError
        Command cannot contain numbers greater than {length}.
    ValueError
        Command must contain positive or negative integers.
    """
    if cmd.startswith(',') or cmd.endswith(','):
        # if cmd starts or ends with ',', raise an error
        raise ValueError("Command cannot start or end with ','.")
    else:
        # get the parts in between commas
        tmp_cmd = cmd.split(',')
        # for each part
        final_cmd = []
        for i in tmp_cmd:
            if len(i) == 0:
                # this means that there was the ',,' pattern
                raise ValueError("Command cannot contain a pattern of the "
                                 "form ',,'.")
            elif str_is_int(i):
                # if it is a positive or negative integer convert it to int
                n = int(i)
                if n >= length:
                    raise ValueError("Command cannot contain numbers greater "
                                     "than {}.".format(length))
                else:
                    final_cmd.append(n)
            else:
                # else raise an error
                raise ValueError("Command must contain positive or negative "
                                 "integers.")
        return final_cmd

def parse_slicing_command_with_one_colon(cmd, length):
    r"""
    Function that parses a command for slicing which contains exactly one colon
    (``:``). The function returns a `list` with the integer indices, after
    interpreting the slicing command. It also ignores any redundant whitespaces
    that may exist in the command. For example ::

        parse_slicing_command_with_one_colon(:3, 10)

    returns ::

        '[0, 1, 2]'

    Parameters
    ----------
    cmd : `str`
        The command string.
    length : `int`
        The length of the variable that will get sliced.

    Returns
    -------
    cmd_list : `list`
        The list that can be used for slicing after interpreting and evaluating
        the provided command.

    Raises
    ------
    ValueError
        Command cannot contain numbers greater than {length}.
    ValueError
        Command must contain positive or negative integers.
    """
    # this is necessary in order to return ranges with negative slices
    tmp_list = list(range(length))

    if cmd.startswith(':'):
        # cmd has the form ":3" or ":"
        if len(cmd) > 1:
            # cmd has the form ":3"
            i = cmd[1:]
            if str_is_int(i):
                n = int(i)
                if n > length:
                    raise ValueError("Command cannot contain numbers greater "
                                     "than {}.".format(length))
                else:
                    return tmp_list[:n]
            else:
                raise ValueError("Command must contain integers.")
        else:
            # cmd is ":"
            return tmp_list
    elif cmd.endswith(':'):
        # cmd has the form "3:" or ":"
        if len(cmd) > 1:
            # cmd has the form "3:"
            i = cmd[:-1]
            if str_is_int(i):
                n = int(i)
                if n >= length:
                    raise ValueError("Command cannot contain numbers greater "
                                     "than {}.".format(length))
                else:
                    return tmp_list[n:]
            else:
                raise ValueError("Command must contain integers.")
        else:
            # cmd is ":"
            return tmp_list
    else:
        # cmd has the form "3:10"
        # get the parts before and after colon
        tmp_cmd = cmd.split(':')
        start = tmp_cmd[0]
        end = tmp_cmd[1]

        if str_is_int(start) and str_is_int(end):
            start = int(start)
            end = int(end)
            if start >= length or end > length:
                raise ValueError("Command cannot contain numbers greater "
                                 "than {}.".format(length))
            else:
                return tmp_list[start:end]
        else:
            raise ValueError("Command must contain integers.")

def parse_slicing_command_with_two_colon(cmd, length):
    r"""
    Function that parses a command for slicing which contains exactly two colons
    (``:``). The function returns a `list` with the integer indices, after
    interpreting the slicing command. It also ignores any redundant whitespaces
    that may exist in the command. For example ::

        parse_slicing_command_with_two_colon(::3, 10)

    returns ::

        '[0, 3, 6, 9]'

    Parameters
    ----------
    cmd : `str`
        The command string.
    length : `int`
        The length of the variable that will get sliced.

    Returns
    -------
    cmd_list : `list`
        The list that can be used for slicing after interpreting and evaluating
        the provided command.

    Raises
    ------
    ValueError
        Command cannot contain numbers greater than {length}.
    ValueError
        Command must contain positive or negative integers.
    """
    # this is necessary in order to return ranges with negative slices
    tmp_list = list(range(length))

    if cmd.startswith('::'):
        # cmd has the form "::3" or "::"
        if len(cmd) > 2:
            # cmd has the form "::3"
            i = cmd[2:]
            if str_is_int(i):
                n = int(i)
                return tmp_list[::n]
            else:
                raise ValueError("Command must contain integers.")
        else:
            # cmd is "::"
            return tmp_list
    elif cmd.endswith('::'):
        # cmd has the form "3::" or "::"
        if len(cmd) > 2:
            # cmd has the form "3::"
            i = cmd[:-2]
            if str_is_int(i):
                n = int(i)
                if n >= length:
                    raise ValueError("Command cannot contain numbers greater "
                                     "than {}.".format(length))
                else:
                    return tmp_list[n::]
            else:
                raise ValueError("Command must contain integers.")
        else:
            # cmd is "::"
            return tmp_list
    else:
        # cmd has the form "1:8:2"
        # get the parts in between colons
        tmp_cmd = cmd.split(':')

        start = tmp_cmd[0]
        end = tmp_cmd[1]
        step = tmp_cmd[2]

        if str_is_int(start) and str_is_int(end) and str_is_int(step):
            start = int(start)
            end = int(end)
            step = int(step)
            if start >= length or end > length:
                raise ValueError("Command cannot contain numbers greater "
                                 "than {}.".format(length))
            else:
                return tmp_list[start:end:step]
        else:
            raise ValueError("Command must contain integers.")

def parse_slicing_command(cmd, length):
    r"""
    Function that parses a command for slicing. It is able to recognize any
    slicing pattern of Python and detect pattern errors. Some characteristic
    examples are ":3", ":-2", "3:", "::3", "3::", "1:8", "1:8:2", "1, 5, -3",
    "range(10)", "range("1, 10, 2)" etc. The function returns a `list` with the
    integer indices, after interpreting the slicing command. It also ignores any
    redundant whitespaces that may exist in the command.

    Parameters
    ----------
    cmd : `str`
        The command string.
    length : `int`
        The length of the variable that will get sliced.

    Returns
    -------
    cmd_list : `list`
        The list that can be used for slicing after interpreting and evaluating
        the provided command.

    Raises
    ------
    ValueError
        Command cannot contain numbers greater than {length}.
    ValueError
        Command must contain positive or negative integers.
    """
    # remove all redundant spaces from cmd
    cmd = cmd.replace(" ", "")

    # remove all brackets from cmd
    cmd = cmd.replace("[", "")
    cmd = cmd.replace("]", "")

    # cmd has the form of "range(1, 10, 2)" or "range(10)"
    if cmd.startswith("range("):
        if cmd.endswith(")"):
            cmd = cmd[6:-1]
            if cmd.count(",") > 0:
                cmd = cmd.replace(",", ":")
            else:
                cmd = "0:" + cmd
        else:
            raise ValueError("Wrong command.")

    # empty command
    if cmd == "":
        return []

    # get number of ':' and number of ','
    n_colon = cmd.count(":")
    n_comma = cmd.count(",")

    if n_comma > 0 and n_colon == 0:
        # parse cmd given that it contains only ','
        return parse_slicing_command_with_comma(cmd, length)
    elif n_comma == 0 and n_colon > 0:
        # parse cmd given that it contains only ':'
        if n_colon == 1:
            return parse_slicing_command_with_one_colon(cmd, length)
        elif n_colon == 2:
            return parse_slicing_command_with_two_colon(cmd, length)
        else:
            raise ValueError("More than 2 ':'.")
    elif n_comma == 0 and n_colon == 0:
        # cmd has the form of "10"
        if str_is_int(cmd):
            n = int(cmd)
            if n >= length:
                raise ValueError("Cannot contain numbers greater "
                                 "than {}".format(length))
            else:
                return [n]
        else:
            raise ValueError("Wrong command.")
    else:
        raise ValueError("Wrong command.")

def list_has_constant_step(l):
    r"""
    Function that checks if a list of integers has a constant step between them
    and returns the step.

    Parameters
    ----------
    l : `list`
        The list to check.

    Returns
    -------
    has_constant_step : `bool`
        ``True`` if the `list` elements have a constant step between them.
    step : `int`
        The step value. ``None`` if `has_constant_step` is ``False``.
    """
    if len(l) <= 1:
        return False, None
    step = l[1] - l[0]
    s = step
    i = 2
    while s == step and i < len(l):
        s = l[i] - l[i - 1]
        i += 1
    if i == len(l) and s == step:
        return True, step
    else:
        return False, None

def sample_colours_from_colourmap(n_colours, colour_map):
    import matplotlib.pyplot as plt
    cm = plt.get_cmap(colour_map)
    colours = []
    for i in range(n_colours):
        c = cm(1.*i/n_colours)[:3]
        colours.append(decode_colour([int(i * 255) for i in c]))
    return colours

def extract_group_labels_from_landmarks(landmark_manager):
    groups_keys = None
    labels_keys = None
    if landmark_manager.has_landmarks:
        groups_keys = landmark_manager.group_labels
        labels_keys = [landmark_manager[g].labels for g in groups_keys]
    return groups_keys, labels_keys

def extract_groups_labels_from_image(image):
    r"""
    Function that extracts the groups and labels from an image's landmarks.

    Parameters
    ----------
    image : :map:`Image` or subclass
       The input image object.

    Returns
    -------
    group_keys : `list` of `str`
        The list of landmark groups found.

    labels_keys : `list` of `str`
        The list of lists of each landmark group's labels.
    """
    groups_keys, labels_keys = extract_group_labels_from_landmarks(image.landmarks)
    return groups_keys, labels_keys

def render_image(image, renderer, render_landmarks, image_is_masked,
                 masked_enabled, channels, glyph_enabled, glyph_block_size,
                 glyph_use_negative, sum_enabled, group, with_labels,
                 render_lines, line_style, line_width, line_colour,
                 render_markers, marker_style, marker_size,
                 marker_edge_width, marker_edge_colour, marker_face_colour,
                 render_numbering, numbers_font_name, numbers_font_size,
                 numbers_font_style, numbers_font_weight,
                 numbers_font_colour, numbers_horizontal_align,
                 numbers_vertical_align, legend_n_columns,
                 legend_border_axes_pad, legend_rounded_corners,
                 legend_title, legend_horizontal_spacing, legend_shadow,
                 legend_location, legend_font_name, legend_bbox_to_anchor,
                 legend_border, legend_marker_scale,
                 legend_vertical_spacing, legend_font_weight,
                 legend_font_size, render_legend, legend_font_style,
                 legend_border_padding, figure_size, render_axes,
                 axes_font_name, axes_font_size, axes_font_style,
                 axes_font_weight, axes_x_limits, axes_y_limits, axes_x_ticks,
                 axes_y_ticks, interpolation, alpha, cmap_name):
    # This makes the code shorter for dealing with masked images vs non-masked
    # images
    mask_arguments = ({'masked': masked_enabled} if image_is_masked else {})

    # plot
    if render_landmarks and group is not None:
        # show image with landmarks
        if glyph_enabled:
            # image, landmarks, masked, glyph
            renderer = glyph(image, vectors_block_size=glyph_block_size,
                             use_negative=glyph_use_negative,
                             channels=channels).view_landmarks(
                group=group, with_labels=with_labels, without_labels=None,
                figure_id=renderer.figure_id, new_figure=False,
                render_lines=render_lines, line_colour=line_colour,
                line_style=line_style, line_width=line_width,
                render_markers=render_markers, marker_style=marker_style,
                marker_size=marker_size, marker_face_colour=marker_face_colour,
                marker_edge_colour=marker_edge_colour,
                marker_edge_width=marker_edge_width,
                render_numbering=render_numbering,
                numbers_horizontal_align=numbers_horizontal_align,
                numbers_vertical_align=numbers_vertical_align,
                numbers_font_name=numbers_font_name,
                numbers_font_size=numbers_font_size,
                numbers_font_style=numbers_font_style,
                numbers_font_weight=numbers_font_weight,
                numbers_font_colour=numbers_font_colour,
                render_legend=render_legend, legend_title=legend_title,
                legend_font_name=legend_font_name,
                legend_font_style=legend_font_style,
                legend_font_size=legend_font_size,
                legend_font_weight=legend_font_weight,
                legend_marker_scale=legend_marker_scale,
                legend_location=legend_location,
                legend_bbox_to_anchor=legend_bbox_to_anchor,
                legend_border_axes_pad=legend_border_axes_pad,
                legend_n_columns=legend_n_columns,
                legend_horizontal_spacing=legend_horizontal_spacing,
                legend_vertical_spacing=legend_vertical_spacing,
                legend_border=legend_border,
                legend_border_padding=legend_border_padding,
                legend_shadow=legend_shadow,
                legend_rounded_corners=legend_rounded_corners,
                render_axes=render_axes, axes_font_name=axes_font_name,
                axes_font_size=axes_font_size, axes_font_style=axes_font_style,
                axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
                axes_y_limits=axes_y_limits, axes_x_ticks=axes_x_ticks,
                axes_y_ticks=axes_y_ticks, figure_size=figure_size,
                interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
                **mask_arguments)
        elif sum_enabled:
            # image, landmarks, masked, sum
            renderer = sum_channels(image, channels=channels).view_landmarks(
                group=group, with_labels=with_labels, without_labels=None,
                figure_id=renderer.figure_id, new_figure=False,
                render_lines=render_lines, line_colour=line_colour,
                line_style=line_style, line_width=line_width,
                render_markers=render_markers, marker_style=marker_style,
                marker_size=marker_size, marker_face_colour=marker_face_colour,
                marker_edge_colour=marker_edge_colour,
                marker_edge_width=marker_edge_width,
                render_numbering=render_numbering,
                numbers_horizontal_align=numbers_horizontal_align,
                numbers_vertical_align=numbers_vertical_align,
                numbers_font_name=numbers_font_name,
                numbers_font_size=numbers_font_size,
                numbers_font_style=numbers_font_style,
                numbers_font_weight=numbers_font_weight,
                numbers_font_colour=numbers_font_colour,
                render_legend=render_legend, legend_title=legend_title,
                legend_font_name=legend_font_name,
                legend_font_style=legend_font_style,
                legend_font_size=legend_font_size,
                legend_font_weight=legend_font_weight,
                legend_marker_scale=legend_marker_scale,
                legend_location=legend_location,
                legend_bbox_to_anchor=legend_bbox_to_anchor,
                legend_border_axes_pad=legend_border_axes_pad,
                legend_n_columns=legend_n_columns,
                legend_horizontal_spacing=legend_horizontal_spacing,
                legend_vertical_spacing=legend_vertical_spacing,
                legend_border=legend_border,
                legend_border_padding=legend_border_padding,
                legend_shadow=legend_shadow,
                legend_rounded_corners=legend_rounded_corners,
                render_axes=render_axes, axes_font_name=axes_font_name,
                axes_font_size=axes_font_size, axes_font_style=axes_font_style,
                axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
                axes_y_limits=axes_y_limits, axes_x_ticks=axes_x_ticks,
                axes_y_ticks=axes_y_ticks, figure_size=figure_size,
                interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
                **mask_arguments)
        else:
            renderer = image.view_landmarks(
                channels=channels, group=group, with_labels=with_labels,
                without_labels=None, figure_id=renderer.figure_id,
                new_figure=False, render_lines=render_lines,
                line_colour=line_colour, line_style=line_style,
                line_width=line_width, render_markers=render_markers,
                marker_style=marker_style, marker_size=marker_size,
                marker_face_colour=marker_face_colour,
                marker_edge_colour=marker_edge_colour,
                marker_edge_width=marker_edge_width,
                render_numbering=render_numbering,
                numbers_horizontal_align=numbers_horizontal_align,
                numbers_vertical_align=numbers_vertical_align,
                numbers_font_name=numbers_font_name,
                numbers_font_size=numbers_font_size,
                numbers_font_style=numbers_font_style,
                numbers_font_weight=numbers_font_weight,
                numbers_font_colour=numbers_font_colour,
                render_legend=render_legend, legend_title=legend_title,
                legend_font_name=legend_font_name,
                legend_font_style=legend_font_style,
                legend_font_size=legend_font_size,
                legend_font_weight=legend_font_weight,
                legend_marker_scale=legend_marker_scale,
                legend_location=legend_location,
                legend_bbox_to_anchor=legend_bbox_to_anchor,
                legend_border_axes_pad=legend_border_axes_pad,
                legend_n_columns=legend_n_columns,
                legend_horizontal_spacing=legend_horizontal_spacing,
                legend_vertical_spacing=legend_vertical_spacing,
                legend_border=legend_border,
                legend_border_padding=legend_border_padding,
                legend_shadow=legend_shadow,
                legend_rounded_corners=legend_rounded_corners,
                render_axes=render_axes, axes_font_name=axes_font_name,
                axes_font_size=axes_font_size, axes_font_style=axes_font_style,
                axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
                axes_y_limits=axes_y_limits, axes_x_ticks=axes_x_ticks,
                axes_y_ticks=axes_y_ticks, figure_size=figure_size,
                interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
                **mask_arguments)
    else:
        # either there are not any landmark groups selected or they won't
        # be displayed
        if glyph_enabled:
            # image, not landmarks, masked, glyph
            renderer = glyph(image, vectors_block_size=glyph_block_size,
                             use_negative=glyph_use_negative,
                             channels=channels).view(
                render_axes=render_axes, axes_font_name=axes_font_name,
                axes_font_size=axes_font_size, axes_font_style=axes_font_style,
                axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
                axes_y_limits=axes_y_limits, figure_size=figure_size,
                interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
                **mask_arguments)
        elif sum_enabled:
            # image, not landmarks, masked, sum
            renderer = sum_channels(image, channels=channels).view(
                render_axes=render_axes, axes_font_name=axes_font_name,
                axes_font_size=axes_font_size, axes_font_style=axes_font_style,
                axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
                axes_y_limits=axes_y_limits, figure_size=figure_size,
                interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
                **mask_arguments)
        else:
            # image, not landmarks, masked, not glyph/sum
            renderer = image.view(
                channels=channels, render_axes=render_axes,
                axes_font_name=axes_font_name, axes_font_size=axes_font_size,
                axes_font_style=axes_font_style,
                axes_font_weight=axes_font_weight, axes_x_limits=axes_x_limits,
                axes_y_limits=axes_y_limits, figure_size=figure_size,
                interpolation=interpolation, alpha=alpha, cmap_name=cmap_name,
                **mask_arguments)

    # show plot
    plt.show()

    return renderer

def render_patches(patches, patch_centers, patches_indices, offset_index,
                   renderer, background, render_patches, channels,
                   glyph_enabled, glyph_block_size, glyph_use_negative,
                   sum_enabled, interpolation, cmap_name, alpha,
                   render_patches_bboxes, bboxes_line_colour,
                   bboxes_line_style, bboxes_line_width, render_centers,
                   render_lines, line_colour, line_style, line_width,
                   render_markers, marker_style, marker_size,
                   marker_face_colour, marker_edge_colour,
                   marker_edge_width, render_numbering,
                   numbers_horizontal_align, numbers_vertical_align,
                   numbers_font_name, numbers_font_size, numbers_font_style,
                   numbers_font_weight, numbers_font_colour, render_axes,
                   axes_font_name, axes_font_size, axes_font_style,
                   axes_font_weight, axes_x_limits, axes_y_limits,
                   axes_x_ticks, axes_y_ticks, figure_size):
    from menpo.transform import UniformScale
    from menpo.visualize import view_patches

    if glyph_enabled and render_patches:
        # compute glyph size
        glyph_patch0 = glyph(patches[0, offset_index, ...],
                             vectors_block_size=glyph_block_size,
                             use_negative=glyph_use_negative)
        # compute glyph of each patch
        glyph_patches = np.zeros((patches.shape[0], 1, 1, glyph_patch0.shape[1],
                                  glyph_patch0.shape[2]))
        glyph_patches[0, 0, ...] = glyph_patch0
        for i in range(1, patches.shape[0]):
            glyph_patches[i, 0, ...] = glyph(
                patches[i, offset_index, ...],
                vectors_block_size=glyph_block_size,
                use_negative=glyph_use_negative)
        # correct patch centers
        glyph_patch_centers = UniformScale(glyph_block_size, 2).apply(
            patch_centers)
        # visualize glyph patches
        renderer = view_patches(
            glyph_patches, glyph_patch_centers, patches_indices=patches_indices,
            offset_index=0, figure_id=renderer.figure_id, new_figure=False,
            background=background, render_patches=render_patches, channels=0,
            interpolation=interpolation, cmap_name=cmap_name, alpha=alpha,
            render_patches_bboxes=render_patches_bboxes,
            bboxes_line_colour=bboxes_line_colour,
            bboxes_line_style=bboxes_line_style,
            bboxes_line_width=bboxes_line_width,
            render_centers=render_centers, render_lines=render_lines,
            line_colour=line_colour, line_style=line_style,
            line_width=line_width, render_markers=render_markers,
            marker_style=marker_style, marker_size=marker_size,
            marker_face_colour=marker_face_colour,
            marker_edge_colour=marker_edge_colour,
            marker_edge_width=marker_edge_width,
            render_numbering=render_numbering,
            numbers_horizontal_align=numbers_horizontal_align,
            numbers_vertical_align=numbers_vertical_align,
            numbers_font_name=numbers_font_name,
            numbers_font_size=numbers_font_size,
            numbers_font_style=numbers_font_style,
            numbers_font_weight=numbers_font_weight,
            numbers_font_colour=numbers_font_colour,
            render_axes=render_axes, axes_font_name=axes_font_name,
            axes_font_size=axes_font_size,
            axes_font_style=axes_font_style,
            axes_font_weight=axes_font_weight,
            axes_x_limits=axes_x_limits, axes_y_limits=axes_y_limits,
            axes_x_ticks=axes_x_ticks, axes_y_ticks=axes_y_ticks,
            figure_size=figure_size)
    elif sum_enabled and render_patches:
        # compute sum of each patch
        sum_patches = np.zeros((patches.shape[0], 1, 1, patches.shape[3],
                                patches.shape[4]))
        for i in patches_indices:
            sum_patches[i, 0, ...] = sum_channels(
                patches[i, offset_index, ...], channels=channels)
        # visualize sum patches
        renderer = view_patches(
            sum_patches, patch_centers, patches_indices=patches_indices,
            offset_index=0, figure_id=renderer.figure_id, new_figure=False,
            background=background, render_patches=render_patches, channels=0,
            interpolation=interpolation, cmap_name=cmap_name, alpha=alpha,
            render_patches_bboxes=render_patches_bboxes,
            bboxes_line_colour=bboxes_line_colour,
            bboxes_line_style=bboxes_line_style,
            bboxes_line_width=bboxes_line_width,
            render_centers=render_centers, render_lines=render_lines,
            line_colour=line_colour, line_style=line_style,
            line_width=line_width, render_markers=render_markers,
            marker_style=marker_style, marker_size=marker_size,
            marker_face_colour=marker_face_colour,
            marker_edge_colour=marker_edge_colour,
            marker_edge_width=marker_edge_width,
            render_numbering=render_numbering,
            numbers_horizontal_align=numbers_horizontal_align,
            numbers_vertical_align=numbers_vertical_align,
            numbers_font_name=numbers_font_name,
            numbers_font_size=numbers_font_size,
            numbers_font_style=numbers_font_style,
            numbers_font_weight=numbers_font_weight,
            numbers_font_colour=numbers_font_colour,
            render_axes=render_axes, axes_font_name=axes_font_name,
            axes_font_size=axes_font_size,
            axes_font_style=axes_font_style,
            axes_font_weight=axes_font_weight,
            axes_x_limits=axes_x_limits, axes_y_limits=axes_y_limits,
            axes_x_ticks=axes_x_ticks, axes_y_ticks=axes_y_ticks,
            figure_size=figure_size)
    else:
        renderer = view_patches(
            patches, patch_centers, patches_indices=patches_indices,
            offset_index=offset_index, figure_id=renderer.figure_id,
            new_figure=False, background=background,
            render_patches=render_patches, channels=channels,
            interpolation=interpolation, cmap_name=cmap_name, alpha=alpha,
            render_patches_bboxes=render_patches_bboxes,
            bboxes_line_colour=bboxes_line_colour,
            bboxes_line_style=bboxes_line_style,
            bboxes_line_width=bboxes_line_width,
            render_centers=render_centers, render_lines=render_lines,
            line_colour=line_colour, line_style=line_style,
            line_width=line_width, render_markers=render_markers,
            marker_style=marker_style, marker_size=marker_size,
            marker_face_colour=marker_face_colour,
            marker_edge_colour=marker_edge_colour,
            marker_edge_width=marker_edge_width,
            render_numbering=render_numbering,
            numbers_horizontal_align=numbers_horizontal_align,
            numbers_vertical_align=numbers_vertical_align,
            numbers_font_name=numbers_font_name,
            numbers_font_size=numbers_font_size,
            numbers_font_style=numbers_font_style,
            numbers_font_weight=numbers_font_weight,
            numbers_font_colour=numbers_font_colour,
            render_axes=render_axes, axes_font_name=axes_font_name,
            axes_font_size=axes_font_size,
            axes_font_style=axes_font_style,
            axes_font_weight=axes_font_weight,
            axes_x_limits=axes_x_limits, axes_y_limits=axes_y_limits,
            axes_x_ticks=axes_x_ticks, axes_y_ticks=axes_y_ticks,
            figure_size=figure_size)

    # show plot
    plt.show()

    return renderer


text:
begin
  require 'iconv'
rescue Object
  puts "no iconv, you might want to look into it."
end

require 'digest/sha1'
module PermalinkFu
  class << self
    attr_accessor :translation_to
    attr_accessor :translation_from

    def escape(str)
      s = ((translation_to && translation_from) ? Iconv.iconv(translation_to, translation_from, str) : str).to_s
      s.gsub!(/\W+/, ' ') # all non-word chars to spaces
      s.strip!            # ohh la la
      s.downcase!         #
      s.gsub!(/\ +/, '-') # spaces to dashes, preferred separator char everywhere
      s
    end
  end

  def self.included(base)
    base.extend ClassMethods
    class << base
      attr_accessor :permalink_options
      attr_accessor :permalink_attributes
      attr_accessor :permalink_field
    end
  end

  module ClassMethods
    # Specifies the given field(s) as a permalink, meaning it is passed through PermalinkFu.escape and set to the permalink_field.  This
    # is done
    #
    #   class Foo < ActiveRecord::Base
    #     # stores permalink form of #title to the #permalink attribute
    #     has_permalink :title
    #
    #     # stores a permalink form of "#{category}-#{title}" to the #permalink attribute
    #
    #     has_permalink [:category, :title]
    #
    #     # stores permalink form of #title to the #category_permalink attribute
    #     has_permalink [:category, :title], :category_permalink
    #
    #     # add a scope
    #     has_permalink :title, :scope => :blog_id
    #
    #     # add a scope and specify the permalink field name
    #     has_permalink :title, :slug, :scope => :blog_id
    #   end
    #
    def has_permalink(attr_names = [], permalink_field = nil, options = {})
      if permalink_field.is_a?(Hash)
        options = permalink_field
        permalink_field = nil
      end
      self.permalink_attributes = Array(attr_names)
      self.permalink_field      = (permalink_field || 'permalink').to_s
      self.permalink_options    = options
      before_validation :create_unique_permalink
      evaluate_attribute_method permalink_field, "def #{self.permalink_field}=(new_value);write_attribute(:#{self.permalink_field}, PermalinkFu.escape(new_value));end", "#{self.permalink_field}="
    end
  end

protected
  def create_unique_permalink
    return unless should_create_permalink?
    if send(self.class.permalink_field).to_s.empty?
      send("#{self.class.permalink_field}=", create_permalink_for(self.class.permalink_attributes))
    end
    limit   = self.class.columns_hash[self.class.permalink_field].limit
    base    = send("#{self.class.permalink_field}=", send(self.class.permalink_field)[0..limit - 1])
    counter = 1
    # oh how i wish i could use a hash for conditions
    conditions = ["#{self.class.permalink_field} = ?", base]
    unless new_record?
      conditions.first << " and id != ?"
      conditions       << id
    end
    if self.class.permalink_options[:scope]
      conditions.first << " and #{self.class.permalink_options[:scope]} = ?"
      conditions       << send(self.class.permalink_options[:scope])
    end
    while self.class.exists?(conditions)
      suffix = "-#{counter += 1}"
      conditions[1] = "#{base[0..limit-suffix.size-1]}#{suffix}"
      send("#{self.class.permalink_field}=", conditions[1])
    end
  end

  def create_permalink_for(attr_names)
    attr_names.collect { |attr_name| send(attr_name).to_s } * " "
  end

private
  def should_create_permalink?
    if self.class.permalink_options[:if]
      evaluate_method(self.class.permalink_options[:if])
    elsif self.class.permalink_options[:unless]
      !evaluate_method(self.class.permalink_options[:unless])
    else
      true
    end
  end

  def evaluate_method(method)
    case method
    when Symbol
      send(method)
    when String
      eval(method, instance_eval { binding })
    when Proc, Method
      method.call(self)
    end
  end
end

if Object.const_defined?(:Iconv)
  PermalinkFu.translation_to   = 'ascii//translit//IGNORE'
  PermalinkFu.translation_from = 'utf-8'
end

redpajama_set_name: RedPajamaGithub


text:
+++
# About/Biography widget.
widget = "about"
active = true
date = "2016-04-20T00:00:00"

# Order that this section will appear in.
weight = 5

# List your academic interests.
[interests]
  interests = [
    "Artificial Intelligence",
    "Computational Linguistics",
    "Information Retrieval"
  ]

# List your qualifications (such as academic degrees).
[[education.courses]]
  course = "PhD in Artificial Intelligence"
  institution = "Stanford University"
  year = 2012

[[education.courses]]
  course = "MEng in Artificial Intelligence"
  institution = "Massachusetts Institute of Technology"
  year = 2009

[[education.courses]]
  course = "BSc in Artificial Intelligence"
  institution = "Massachusetts Institute of Technology"
  year = 2008

+++

# Biography

Lena Smith is a professor of artificial intelligence at the Stanford AI Lab. Her research interests include distributed robotics, mobile computing and programmable matter. She leads the Robotic Neurobiology group, which develops self-reconfiguring robots, systems of self-organizing robots, and mobile sensor networks.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.


text:
namespace WpfAnalyzers.DependencyProperties
{
    using System.Collections.Immutable;
    using System.Composition;
    using System.Threading;
    using System.Threading.Tasks;

    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CodeActions;
    using Microsoft.CodeAnalysis.CodeFixes;
    using Microsoft.CodeAnalysis.CSharp;
    using Microsoft.CodeAnalysis.CSharp.Syntax;

    [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(UseDependencyPropertyKeyCodeFixProvider))]
    [Shared]
    internal class UseDependencyPropertyKeyCodeFixProvider : CodeFixProvider
    {
        /// <inheritdoc/>
        public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(WPF0040SetUsingDependencyPropertyKey.DiagnosticId);

        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var syntaxRoot = await document.GetSyntaxRootAsync(context.CancellationToken)
                .ConfigureAwait(false);

            var semanticModel = await document.GetSemanticModelAsync(context.CancellationToken)
                                              .ConfigureAwait(false);
            foreach (var diagnostic in context.Diagnostics)
            {
                var token = syntaxRoot.FindToken(diagnostic.Location.SourceSpan.Start);
                if (string.IsNullOrEmpty(token.ValueText))
                {
                    continue;
                }

                var invocation = syntaxRoot.FindNode(diagnostic.Location.SourceSpan)
                                           .FirstAncestorOrSelf<InvocationExpressionSyntax>();

                if (invocation == null || invocation.IsMissing)
                {
                    continue;
                }

                ArgumentSyntax property;
                IFieldSymbol setField;
                ArgumentSyntax value;
                if (DependencyObject.TryGetSetValueArguments(
                      invocation,
                      semanticModel,
                      context.CancellationToken,
                      out property,
                      out setField,
                      out value))
                {
                    IFieldSymbol keyField;
                    if (DependencyProperty.TryGetDependencyPropertyKeyField(
                        setField,
                        semanticModel,
                        context.CancellationToken,
                        out keyField))
                    {
                        var keyArg = DependencyProperty.CreateArgument(keyField, semanticModel, token.SpanStart);
                        var setValue = invocation.ReplaceNode(property, keyArg);
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                invocation.ToString(),
                                cancellationToken => ApplyFixAsync(
                                    context,
                                    cancellationToken,
                                    invocation,
                                    setValue),
                                nameof(MakeFieldStaticReadonlyCodeFixProvider)),
                            diagnostic);
                    }

                    continue;
                }

                if (DependencyObject.TryGetSetCurrentValueArguments(
                      invocation,
                      semanticModel,
                      context.CancellationToken,
                      out property,
                      out setField,
                      out value))
                {
                    IFieldSymbol keyField;
                    if (DependencyProperty.TryGetDependencyPropertyKeyField(
                        setField,
                        semanticModel,
                        context.CancellationToken,
                        out keyField))
                    {
                        var keyArg = DependencyProperty.CreateArgument(keyField, semanticModel, token.SpanStart);
                        var setValue = invocation.WithExpression(SetValueExpression(invocation.Expression))
                                                 .ReplaceNode(property, keyArg);
                        context.RegisterCodeFix(
                            CodeAction.Create(
                                invocation.ToString(),
                                cancellationToken => ApplyFixAsync(
                                    context,
                                    cancellationToken,
                                    invocation,
                                    setValue),
                                nameof(MakeFieldStaticReadonlyCodeFixProvider)),
                            diagnostic);
                    }
                }
            }
        }

        private static async Task<Document> ApplyFixAsync(
            CodeFixContext context,
            CancellationToken cancellationToken,
            SyntaxNode oldNode,
            SyntaxNode newNode)
        {
            var syntaxRoot = await context.Document.GetSyntaxRootAsync(cancellationToken)
                                          .ConfigureAwait(false);
            return context.Document.WithSyntaxRoot(syntaxRoot.ReplaceNode(oldNode, newNode));
        }

        private static ExpressionSyntax SetValueExpression(ExpressionSyntax old)
        {
            var identifierNameSyntax = old as IdentifierNameSyntax;
            if (identifierNameSyntax != null)
            {
                return identifierNameSyntax.Identifier.ValueText == "SetCurrentValue"
                           ? identifierNameSyntax.WithIdentifier(SyntaxFactory.Identifier("SetValue"))
                           : identifierNameSyntax;
            }

            var memberAccessExpressionSyntax = old as MemberAccessExpressionSyntax;
            if (memberAccessExpressionSyntax != null)
            {
                var newName = SetValueExpression(memberAccessExpressionSyntax.Name) as SimpleNameSyntax;
                return memberAccessExpressionSyntax.WithName(newName);
            }

            return old;
        }
    }
}


text:
"""
Unit tests for the Evscaperoom

"""
import inspect
import pkgutil
from os import path
from evennia.commands.default.tests import CommandTest
from evennia import InterruptCommand
from evennia.utils.test_resources import EvenniaTest
from evennia.utils import mod_import
from . import commands
from . import state as basestate
from . import objects
from . import utils

class TestEvscaperoomCommands(CommandTest):

    def setUp(self):
        super().setUp()
        self.room1 = utils.create_evscaperoom_object(
            "evscaperoom.room.EvscapeRoom", key='Testroom')
        self.char1.location = self.room1
        self.obj1.location = self.room1

    def test_base_search(self):

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1

        self.assertEqual((self.obj1, None), cmd._search("Obj", True))
        self.assertEqual((None, "Obj"), cmd._search("Obj", False))
        self.assertEqual((None, "Foo"), cmd._search("Foo", False))
        self.assertEqual((None, "Foo"), cmd._search("Foo", None))
        self.assertRaises(InterruptCommand, cmd._search, "Foo", True)

    def test_base_parse(self):

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1

        cmd.obj1_search = None
        cmd.obj2_search = None
        cmd.args = "obj"
        cmd.parse()

        self.assertEqual(cmd.obj1, self.obj1)
        self.assertEqual(cmd.room, self.char1.location)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = False
        cmd.obj2_search = False
        cmd.args = "obj"
        cmd.parse()

        self.assertEqual(cmd.arg1, "obj")
        self.assertEqual(cmd.obj1, None)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = None
        cmd.obj2_search = None
        cmd.args = "obj"
        cmd.parse()

        self.assertEqual(cmd.obj1, self.obj1)
        self.assertEqual(cmd.arg1, None)
        self.assertEqual(cmd.arg2, None)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = True
        cmd.obj2_search = True
        cmd.args = "obj at obj"
        cmd.parse()

        self.assertEqual(cmd.obj1, self.obj1)
        self.assertEqual(cmd.obj2, self.obj1)
        self.assertEqual(cmd.arg1, None)
        self.assertEqual(cmd.arg2, None)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = False
        cmd.obj2_search = False
        cmd.args = "obj at obj"
        cmd.parse()

        self.assertEqual(cmd.obj1, None)
        self.assertEqual(cmd.obj2, None)
        self.assertEqual(cmd.arg1, "obj")
        self.assertEqual(cmd.arg2, "obj")

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = None
        cmd.obj2_search = None
        cmd.args = "obj at obj"
        cmd.parse()

        self.assertEqual(cmd.obj1, self.obj1)
        self.assertEqual(cmd.obj2, self.obj1)
        self.assertEqual(cmd.arg1, None)
        self.assertEqual(cmd.arg2, None)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = None
        cmd.obj2_search = None
        cmd.args = "foo in obj"
        cmd.parse()

        self.assertEqual(cmd.obj1, None)
        self.assertEqual(cmd.obj2, self.obj1)
        self.assertEqual(cmd.arg1, 'foo')
        self.assertEqual(cmd.arg2, None)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = None
        cmd.obj2_search = None
        cmd.args = "obj on foo"
        cmd.parse()

        self.assertEqual(cmd.obj1, self.obj1)
        self.assertEqual(cmd.obj2, None)
        self.assertEqual(cmd.arg1, None)
        self.assertEqual(cmd.arg2, 'foo')

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = None
        cmd.obj2_search = True
        cmd.args = "obj on foo"
        self.assertRaises(InterruptCommand, cmd.parse)

        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.obj1_search = None
        cmd.obj2_search = True
        cmd.args = "on obj"
        cmd.parse()
        self.assertEqual(cmd.obj1, None)
        self.assertEqual(cmd.obj2, self.obj1)
        self.assertEqual(cmd.arg1, "")
        self.assertEqual(cmd.arg2, None)

    def test_set_focus(self):
        cmd = commands.CmdEvscapeRoom()
        cmd.caller = self.char1
        cmd.room = self.room1
        cmd.focus = self.obj1
        self.assertEqual(self.char1.attributes.get(
            "focus", category=self.room1.tagcategory), self.obj1)

    def test_focus(self):
        # don't focus on a non-room object
        self.call(commands.CmdFocus(), "obj")
        self.assertEqual(self.char1.attributes.get(
            "focus", category=self.room1.tagcategory), None)
        # should focus correctly
        myobj = utils.create_evscaperoom_object(
            objects.EvscaperoomObject, "mytestobj", location=self.room1)
        self.call(commands.CmdFocus(), "mytestobj")
        self.assertEqual(self.char1.attributes.get(
            "focus", category=self.room1.tagcategory), myobj)

    def test_look(self):
        self.call(commands.CmdLook(), "at obj", "Obj")
        self.call(commands.CmdLook(), "obj", "Obj")
        self.call(commands.CmdLook(), "obj", "Obj")

    def test_speech(self):
        self.call(commands.CmdSpeak(), "", "What do you want to say?", cmdstring="")
        self.call(commands.CmdSpeak(), "Hello!", "You say: Hello!", cmdstring="")
        self.call(commands.CmdSpeak(), "", "What do you want to whisper?", cmdstring="whisper")
        self.call(commands.CmdSpeak(), "Hi.", "You whisper: Hi.", cmdstring="whisper")
        self.call(commands.CmdSpeak(), "Hi.", "You whisper: Hi.", cmdstring="whisper")
        self.call(commands.CmdSpeak(), "HELLO!", "You shout: HELLO!", cmdstring="shout")

        self.call(commands.CmdSpeak(), "Hello to obj",
                  "You say: Hello", cmdstring="say")
        self.call(commands.CmdSpeak(), "Hello to obj",
                  "You shout: Hello", cmdstring="shout")

    def test_emote(self):
        self.call(commands.CmdEmote(),
                  "/me smiles to /obj",
                  f"Char(#{self.char1.id}) smiles to Obj(#{self.obj1.id})")

    def test_focus_interaction(self):
        self.call(commands.CmdFocusInteraction(), "", "Hm?")

class TestUtils(EvenniaTest):

    def test_overwrite(self):
        room = utils.create_evscaperoom_object(
            "evscaperoom.room.EvscapeRoom", key='Testroom')
        obj1 = utils.create_evscaperoom_object(
            objects.EvscaperoomObject, key="testobj", location=room)
        id1 = obj1.id

        obj2 = utils.create_evscaperoom_object(
            objects.EvscaperoomObject, key="testobj", location=room)
        id2 = obj2.id

        # we should have created a new object, deleting the old same-named one
        self.assertTrue(id1 != id2)
        self.assertFalse(bool(obj1.pk))
        self.assertTrue(bool(obj2.pk))

    def test_parse_for_perspectives(self):

        second, third = utils.parse_for_perspectives("~You ~look at the nice book", "TestGuy")
        self.assertTrue(second, "You look at the nice book")
        self.assertTrue(third, "TestGuy looks at the nice book")
        # irregular
        second, third = utils.parse_for_perspectives("With a smile, ~you ~were gone", "TestGuy")
        self.assertTrue(second, "With a smile, you were gone")
        self.assertTrue(third, "With a smile, TestGuy was gone")

    def test_parse_for_things(self):

        string = "Looking at *book and *key."
        self.assertEqual(utils.parse_for_things(string, 0), "Looking at book and key.")
        self.assertEqual(utils.parse_for_things(string, 1), "Looking at |ybook|n and |ykey|n.")
        self.assertEqual(utils.parse_for_things(string, 2), "Looking at |y[book]|n and |y[key]|n.")

class TestEvScapeRoom(EvenniaTest):

    def setUp(self):
        super().setUp()
        self.room = utils.create_evscaperoom_object(
            "evscaperoom.room.EvscapeRoom", key='Testroom',
            home=self.room1)
        self.roomtag = "evscaperoom_{}".format(self.room.key)

    def tearDown(self):
        self.room.delete()

    def test_room_methods(self):

        room = self.room
        self.char1.location = room

        self.assertEqual(room.tagcategory, self.roomtag)
        self.assertEqual(list(room.get_all_characters()), [self.char1])

        room.tag_character(self.char1, "opened_door")
        self.assertEqual(self.char1.tags.get(
            "opened_door", category=self.roomtag), "opened_door")

        room.tag_all_characters("tagged_all")
        self.assertEqual(self.char1.tags.get(
            "tagged_all", category=self.roomtag), "tagged_all")

        room.character_cleanup(self.char1)
        self.assertEqual(self.char1.tags.get(category=self.roomtag), None)

class TestStates(EvenniaTest):

    def setUp(self):
        super().setUp()
        self.room = utils.create_evscaperoom_object(
            "evscaperoom.room.EvscapeRoom", key='Testroom',
            home=self.room1)
        self.roomtag = "evscaperoom_#{}".format(self.room.id)

    def tearDown(self):
        self.room.delete()

    def _get_all_state_modules(self):
        dirname = path.join(path.dirname(__file__), "states")
        states = []
        for imp, module, ispackage in pkgutil.walk_packages(
                path=[dirname], prefix="evscaperoom.states."):
            mod = mod_import(module)
            states.append(mod)
        return states

    def test_base_state(self):

        st = basestate.BaseState(self.room.statehandler, self.room)
        st.init()
        obj = st.create_object(objects.Edible, key="apple")
        self.assertEqual(obj.key, "apple")
        self.assertEqual(obj.__class__, objects.Edible)
        obj.delete()

    def test_all_states(self):
        "Tick through all defined states"

        for mod in self._get_all_state_modules():

            state = mod.State(self.room.statehandler, self.room)
            state.init()

            for obj in self.room.contents:
                if obj.pk:
                    methods = inspect.getmembers(obj, predicate=inspect.ismethod)
                    for name, method in methods:
                        if name.startswith("at_focus_"):
                            method(self.char1, args="dummy")

            next_state = state.next()
            self.assertEqual(next_state, mod.State.next_state)


text:
import os
import random
import string
from configparser import BasicInterpolation, ConfigParser

from office365.runtime.auth.client_credential import ClientCredential
from office365.runtime.auth.user_credential import UserCredential

def create_unique_name(prefix):
    return prefix + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8))

def create_unique_file_name(prefix, ext):
    return ".".join([create_unique_name(prefix), ext])

class SecEnvInterpolation(BasicInterpolation):
    secure_vars = os.environ.get('office365_python_sdk_securevars').split(';')

    def before_get(self, parser, section, option, value, defaults):
        value = super(SecEnvInterpolation, self).before_get(parser, section, option, value, defaults)
        if option == "password":
            return self.secure_vars[1]
        elif option == "client_secret":
            return self.secure_vars[3]
        else:
            return value

def load_settings():
    cp = ConfigParser(interpolation=SecEnvInterpolation())
    root_dir = os.path.dirname(os.path.abspath(__file__))
    config_file = os.path.join(root_dir, 'settings.cfg')
    cp.read(config_file)
    return cp

settings = load_settings()

# shortcuts
test_tenant = settings.get('default', 'tenant')

test_client_credentials = ClientCredential(settings.get('client_credentials', 'client_id'),
                                           settings.get('client_credentials', 'client_secret'))

test_user_credentials = UserCredential(settings.get('user_credentials', 'username'),
                                       settings.get('user_credentials', 'password'))

test_site_url = settings.get('default', 'site_url')
test_root_site_url = settings.get('default', 'root_site_url')
test_team_site_url = settings.get('default', 'team_site_url')
test_admin_site_url = settings.get('default', 'admin_site_url')

test_user_principal_name = settings.get('users', 'test_user1')
test_user_principal_name_alt = settings.get('users', 'test_user2')


text:
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>patio</title>
    <link rel="stylesheet" href="./assets/css/bootstrap.min.css">
    <link rel="stylesheet" href="./assets/css/prettify.css">

    <link rel="stylesheet" href="./assets/css/bootstrap-responsive.min.css">

            patio

                        Docs

Connecting

Models

Associations

Model Inheritance

Model Validation

Model Plugins

Querying

DDL

Migrations

Logging

Change Log

                        Namespaces

patio.sql

patio.sql.Constants

                        Classes

patio

patio.AlterTableGenerator

patio.AssociationError

patio.ConnectionPool

patio.Database

patio.DatabaseError

patio.Dataset

patio.DatasetError

patio.ExpressionError

patio.MigrationError

patio.Model

patio.ModelError

patio.NotImplemented

patio.PatioError

patio.QueryError

patio.SchemaGenerator

patio.Time

patio.associations.Association

patio.associations.ManyToMany

patio.associations.ManyToOne

patio.associations.ManyToOne

patio.associations.OneToMany

patio.dataset._Query

patio.migrations.IntegerMigrator

patio.migrations.Migrator

patio.migrations.TimestampMigrator

patio.plugins.CachePlugin

patio.plugins.ClassTableInheritancePlugin

patio.plugins.ColumnMapper

patio.plugins.TimeStampPlugin

patio.plugins.ValidatorPlugin

patio.sql.AliasMethods

patio.sql.AliasedExpression

patio.sql.BitWiseMethods

patio.sql.BooleanConstant

patio.sql.BooleanExpression

patio.sql.BooleanMethods

patio.sql.CaseExpression

patio.sql.Cast.constructor

patio.sql.CastMethods

patio.sql.ColumnAll

patio.sql.ComplexExpression

patio.sql.ComplexExpressionMethods

patio.sql.Constant

patio.sql.DateTime

patio.sql.Decimal

patio.sql.Expression

patio.sql.Float

patio.sql.GenericExpression

patio.sql.Identifier

patio.sql.InequalityMethods

patio.sql.JoinClause

patio.sql.JoinOnClause

patio.sql.JoinUsingClause

patio.sql.Json

patio.sql.JsonArray

patio.sql.LiteralString.constructor

patio.sql.NoBooleanInputMethods

patio.sql.NumericExpression

patio.sql.NumericMethods

patio.sql.OrderedExpression

patio.sql.OrderedMethods

patio.sql.PlaceHolderLiteralString

patio.sql.QualifiedIdentifier

patio.sql.QualifyingMethods

patio.sql.SQLFunction

patio.sql.StringConcatenationMethods

patio.sql.StringExpression

patio.sql.StringMethods

patio.sql.SubScript

patio.sql.SubscriptMethods

patio.sql.Time

patio.sql.TimeStamp

patio.sql.Year

github

Models

Models are an optional feature in patio that can be extended to encapsulate, query, and associate tables.

When defining a model it is assumed that the database table already exists. So before defining a model you must create the table/s that the model requires to function including associations. To create a model you must connect to a database.

An example model definition flow.

var comb = require("comb"),
    format = comb.string.format,
    patio = require("patio");
patio.camelize = true;

//if you want logging
patio.configureLogging();

//disconnect and error callback helpers
var disconnect = patio.disconnect.bind(patio);
var disconnectError = function(err) {
    patio.logError(err);
    patio.disconnect();
};

//create your DB
var DB = patio.connect("mysql://test:testpass@localhost:3306/sandbox");

//create an initial model. It cannot be used until it is synced.
//To sync call User.sync or patio.syncModels is called
var User = patio.addModel("user");

var createSchema = function(){
    return DB.forceCreateTable("user", function(){
                this.primaryKey("id");
                this.firstName(String)
                this.lastName(String);
                this.password(String);
                this.dateOfBirth(Date);
                this.created(sql.TimeStamp);
                this.updated(sql.DateTime);
    });
};

//connect and create schema
connectAndCreateSchema()
    .chain(function(){
        //sync the model so it can be used
        return patio.syncModels().chain(function(){
             var myUser = new User({
                 firstName : "Bob",
                 lastName : "Yukon",
                 password : "password",
                 dateOfBirth : new Date(1980, 8, 29)
             });
            //save the user
            return myUser.save().chain(function(user){
                console.log(format("%s %s's id is %d", user.firstName, user.lastName, user.id));
            });
        });
}).chain(disconnect, disconnectError);

The flow for the above example is as follows:

Connects to a database and creates the "user" table.

Sync the models. This gets the relevant table information from the "user" table

Create a new User

Save the user

Print out some user details, at this point the user is saved in the database

disconnect from the database

The final output should be "BobYukon's id is 1".

Options

Models some options that allow for the customization of the way a model be haves when interacting
with the database.

typecastOnLoad : Defaults to true. Set to false to prevent properties from being type casted when loaded from the database. See patio.Database.typecastValue

patio.addModel("user", {
    static : {
        //override default
        typecastOnLoad : false
    }
});

typecastOnAssignment : Defaults to true. Set to false to prevent properties from being type casted when set by something other than the return values from the database. See patio.Database.typecastValue

patio.addModel("user", {
    static : {
        //override default
        typecastOnAssignment : false
    }
});

So the following would not be typecasted.

var myUser = new User();
myUser.updated = new Date(2004, 1, 1, 12, 12, 12); //would not be auto converted to a patio.sql.DateTime
myUser.updated = "2004-02-01 12:12:12" //would not be auto converted to a patio.sql.DateTime

typecastEmptyStringToNull : Defaults to true. Set to false to prevent empty strings from being typecasted to null.

patio.addModel("user", {
    static : {
        //override default
        typecastEmptyStringToNull : false
    }
});

raiseOnTypecastError : Defaults to true. Set to false to prevent errors thrown while type casting a value from being propogated. USE WITH CARE

patio.addModel("user", {
    static : {
        //override default
        raiseOnTypecastError : false
    }
});

useTransactions :  Defaults to true. Set to false to prevent models from using transactions when saving, deleting, or updating. This applies to the model associations also.

patio.addModel("user", {
    static : {
        //override default
        useTransactions : false
    }
});

identifierOutputMethod : Defaults to null. Set this to override the Dataset default method of converting identifiers returned from the database. See patio.Dataset.identifierOutputMethod

patio.addModel("user", {
    static : {
        //override default
        identifierOutputMethod : "camelize"
    }
});

identifierInputMethod : Defaults to null. Set this to override the Dataset default method of converting identifiers when sending them to the database. See patio.Dataset.identifierInputMethod.

patio.addModel("user", {
    static : {
        //override default
        identifierInputMethod : "underscore"
    }
});

camelize : Defaults to null. Set this to true force this particular model's identifiers to be underscored when sent to the database and camelized when returned. This WILL override patio.camelize. USE WITH CARE

patio.addModel("user", {
    static : {
        //override default
        camelize : true
    }
});

underscore : Defaults to null. Set this to force this particular model's identifiers to be camelized when sent to the database and underscored when returned. This WILL override patio.underscore. USE WITH CARE

patio.addModel("user", {
    static : {
        //override default
        underscore : true
    }
});

reloadOnSave : Defaults to true. Set this to false to prevent the models properties from being reloaded from the database after a save operation. Note: If you set this to false and you have columns that have default values in the database and they are not explictly set they will NOT be loaded

patio.addModel("user", {
    static : {
        //override default
        reloadOnSave : false
    }
});

reloadOnUpdate : Defaults to true. Set this to false to prevent the model's properties from being reloaded from the database when a model is updated. Note: If you set this to false and you have columns that have default values in the database and they are not explictly set they will NOT be refreshed.

patio.addModel("user", {
    static : {
        //override default
        reloadOnUpdate : false
    }
});

Creating a model

To create a Model class to use within your code you use the patio.addModel method.

var User = patio.addModel("user")

//you must sync the model before using it
User.sync().chain(function(User){
    var myUser = new User({
        firstName : "Bob",
        lastName : "Yukon",
        password : "password",
        dateOfBirth : new Date(1980, 8, 29)
    });
    return myUser.save().chain(function(){
        console.log(format("%s %s was created at %s", myUser.firstName, myUser.lastName, myUser.created.toString()));
        console.log(format("%s %s's id is %d", myUser.firstName, myUser.lastName, myUser.id));
    });
}).chain(disconnect, disconnectError);

You may also use a dataset when adding a model. You might use this if you are using multiple databases. Or want to use a custom query as the base for a particular model.

var DB1 = patio.createConnection("my://connection/string");
var DB2 = patio.createConnection("my://connection/string2");
//user table in db1
var User1 = patio.addModel(DB1.from("user"));
//user table in db2
var User2 = patio.addModel(DB2.from("user"));
patio.syncModels().chain(function(User1,User2){
    var myUser1 = new User1({
        firstName : "Bob1",
        lastName : "Yukon1",
        password : "password",
        dateOfBirth : new Date(1980, 8, 29)
    });
    var myUser2 = new User2({
        firstName : "Bob2",
        lastName : "Yukon2",
        password : "password",
        dateOfBirth : new Date(1980, 8, 29)
    });
    return comb.when(myUser1.save(), myUser2.save()).chain(function(saved){
         console.log(format("%s %s was created at %s", myUser1.firstName, myUser1.lastName, myUser1.created.toString()));
         console.log(format("%s %s's id is %d", myUser1.firstName, myUser1.lastName, myUser1.id));

         console.log(format("%s %s was created at %s", myUser2.firstName, myUser2.lastName,myUser2.created.toString()));
         console.log(format("%s %s's id is %d", myUser2.firstName, myUser2.lastName, myUser2.id));
    });
});

Custom setters and getters

Setters

patio creates setters and getters for each column in the database if you want alter the value of a particular property before its set on the model you can use a custom setter.

For example if you wanted to ensure proper case and first and last name of a user:

var User = patio.addModel("user", {
    instance : {
        _setFirstName : function(firstName){
            return firstName.charAt(0).toUpperCase() + firstName.substr(1);
        },

        _setLastName : function(lastName){
            return lastName.charAt(0).toUpperCase() + lastName.substr(1);
        }
    }
});

patio.syncModels().chain(function(User){
    var myUser = new User({
        firstName : "bob",
        lastName : "yukon"
    });
    console.log(myUser.firstName); //Bob
    console.log(myUser.lastName);  //Yukon
});

Getters

Custom getters can be used to change values returned from the database but not alter the value when persisting.

For example if you wanted to return a value as an array but persist as a string you could do the following.

var User = patio.addModel("user", {
    instance : {
        _getRoles : function(roles){
            return roles.split(",");
        }
    }
});

patio.syncModels().chain(function(User){
    var myUser = new User({
        firstName : "bob",
        lastName : "yukon",
        roles : "admin,user,groupAdmin"
    });
    console.log(myUser.roles); //['admin', 'user','groupAdmin'];
});

You can also use the getters/setters in tandem.

Lets take the getters example from before but use a setter also

var User = patio.addModel("user", {
    instance : {
        _setRoles : function(roles){
            return roles.join(",");
        },

        _getRoles : function(roles){
            return roles.split(",");
        }
    }
});

patio.syncModels().chain(function(User){
    var myUser = new User({
        firstName : "bob",
        lastName : "yukon",
        roles : ["admin","user","groupAdmin"];
    });
    console.log(myUser.roles); //['admin', 'user','groupAdmin'];
    //INSERT INTO `user` (`first_name`, `last_name`, `roles`) VALUES ('bob', 'yukon', 'admin,user,groupAdmin')
    return myUser.save();
});

Model hooks

Each model has the following hooks

pre

save< : called right before the model is saved to the database

update : called right before the model is updated

remove : called right before a model is deleted

load : called right before a model is loaded with values from the database

post

save< : called right after the model is saved to the database

update : called right after the model is updated

remove : called right after a model is deleted

load : called right after a model is loaded with values from the database

var User = patio.addModel("user", {
    pre:{
        "save":function(next){
            console.log("pre save!!!")
            next();
        },

        "remove" : function(next){
            console.log("pre remove!!!")
            next();
        }
    },

    post:{
        "save":function(next){
            console.log("post save!!!")
            next();
        },

        "remove" : function(next){
            console.log("post remove!!!")
            next();
        }
    },
    instance:{
        _setFirstName:function(firstName){
            return firstName.charAt(0).toUpperCase() + firstName.substr(1);
        },

        _setLastName:function(lastName){
            return lastName.charAt(0).toUpperCase() + lastName.substr(1);
        }
    }
 });

Using a model

If you define a model you can either use the Models constructor directly.

//define the model
var User = patio.addModel("user");

patio.syncModels(function(err){
   if(err){
       console.log(err.stack);
   }else{
       var user = new User();
   }
})

or you can use patio.getModel

patio.addModel("user");

patio.syncModels(function(err){
   if(err){
       console.log(err.stack);
   }else{
       var User = patio.getModel("user");
       var user = new User();
   }
})

Mutli Database Models

If you are working with multiple databases and your model's table is not in the patio.defaultDatabase (the first database you connected to) then you will need to pass in the database the model's table is in.

var DB1 = patio.createConnection("my://connection/string");
var DB2 = patio.createConnection("my://connection/string2");
//user table in db1
var User1 = patio.addModel(DB1.from("user"));
//user table in db2
var User2 = patio.addModel(DB2.from("user"));
patio.syncModels(function(err){
   if(err){
      console.log(err.stack);
   }else{
       var user1 = new User1(),
           user2 = new User2();
   }
});

Creating

The static save can be used for saving a group of models at once. Note this method is not any more efficient than creating a model using new, just less verbose.

var Student = patio.getModel("student");
Student.save([
      {
          firstName:"Bob",
          lastName:"Yukon",
          gpa:3.689,
          classYear:"Senior"
      },
      {
          firstName:"Greg",
          lastName:"Horn",
          gpa:3.689,
          classYear:"Sophomore"
      },
      {
          firstName:"Sara",
          lastName:"Malloc",
          gpa:4.0,
          classYear:"Junior"
      },
      {
          firstName:"John",
          lastName:"Favre",
          gpa:2.867,
          classYear:"Junior"
      },
      {
          firstName:"Kim",
          lastName:"Bim",
          gpa:2.24,
          classYear:"Senior"
      },
      {
          firstName:"Alex",
          lastName:"Young",
          gpa:1.9,
          classYear:"Freshman"
      }
 ]).chain(function(users){
   //All users have been saved
 }, disconnectError);

When saving a group of models the save method will use a transaction unless the useTransactions property is set to false. You can manually override the useTransactions property by passing in an additional options parameter with a transaction value set to false.

var Student = patio.getModel("student");
Student.save([
      {
          firstName:"Bob",
          lastName:"Yukon",
          gpa:3.689,
          classYear:"Senior"
      },
      {
          firstName:"Greg",
          lastName:"Horn",
          gpa:3.689,
          classYear:"Sophomore"
      }
 ], {transaction : false}).chain(function(users){
     //work with the users
 });

If you have an instance of a model then you can use the save method on the instance of the model.

var myUser = new User({
     firstName : "Bob",
     lastName : "Yukon",
     password : "password",
     dateOfBirth : new Date(1980, 8, 29)
});
//save the user
myUser.save().chain(function(user){
    //the save is complete
}, disconnectError);

You can also pass in values into the save method to set before saving.

var myUser = new User();
//save the user
myUser.save({
     firstName : "Bob",
     lastName : "Yukon",
     password : "password",
     dateOfBirth : new Date(1980, 8, 29)
 }).chain(function(user){
    //the save is complete
}, disconnectError);

You can also pass in an options object to override options such as using a transaction.

var myUser = new User();
//save the user
myUser.save({
     firstName : "Bob",
     lastName : "Yukon",
     password : "password",
     dateOfBirth : new Date(1980, 8, 29)
 }, {transaction : false}).chain(function(user){
    //the save is complete
}, disconnectError);

Reading

The Model contains static methods for all of the datasets methods listed in patio.Dataset.ACTION_METHODS as well as all the methods listed in patio.Dataset.QUERY_METHODS.

Some of the most commonly used methods are:

forEach

User.forEach(function(user){
   console.log(user.firstName);
});

//you may also return the result of another query(or any promise) from a forEach block,
//this will prevent the forEach's promise from resolving until all actions that occured in the block have
//resolved.
var Blog = patio.addModel("blog");
User.forEach(funciton(user){
   //create a blog for each user
   return new Blog({userId : user.id}).save();

}).chain(function(users){
   //all users and blogs have been saved
}, disconnectError);

map

User.map(function(user){
   return user.firstName;
}).chain(function(names){
    console.log("User names are %s", names);
}, disconnectError);

all

User.all().chain(function(users){
   console.log(users.length);
}, disconnectError);

filter

//find all users where first names begin with bo case insensitive
User.filter({firstName : /^bo/i}).all().chain(function(){
}, disconnectError);

one

User.filter({id : 1}).one().chain(function(user){
   console.log("%d - %s %s", user.id, user.firstName, user.lastName);
}, disconnectError);

first

//SELECT * FROM user WHERE first_name = 'bob' ORDER BY last_name LIMIT 1
User.filter({firstName : "bob"}).order("lastName").first().chain(function(user){
   console.log("%d - %s %s", user.id, user.firstName, user.lastName);
}, disconnectError);

last

//SELECT * FROM user WHERE first_name = 'bob' ORDER BY last_name DESC LIMIT 1
User.filter({firstName : "bob"}).order("lastName").last().chain(function(user){
   console.log("%d - %s %s", user.id, user.firstName, user.lastName);
}, disconnectError);

isEmpty

User.isEmpty().chain(function(isEmpty){
   if(isEmpty){
      console.log("user table is empty");
   }else{
      console.log("user table is not empty");
   }
}, disconnectError);

Updating

The static update can be used for updating a batch of models.

 //BEGIN
 //UPDATE `user` SET `password` = NULL
 //COMMIT
 User.update({password : null});

You can also pass in a query to limit the models that are updated. The filter can be anything that filter accepts.

User.update({password : null}, function(){
    return this.lastAccessed.lte(comb.yearsAgo(1));
 });

//same as
User.update({password : null}, {lastAccess : {lte : comb.yearsAgo(1)}});

To prevent default transaction behavior you can pass in an additional transaction option

User.update({password : null}, {lastAccess : {lte : comb.yearsAgo(1)}}, {transaction : false});

If you have an instance of a model and you want to update it you can use the update instance method.

var updateUsers = User.forEach(function(user){
    //returning the promise from update will cause the forEach not to resolve
    //until all updates have completed
    return user.update({fullName : user.firstName + " " + user.lastName});
});
updateUsers.chain(function(){
    //updates finished
});

as with save you can pass in an options object to prevent default behavior such as transactions.

var updateUsers = User.forEach(function(user){
    //returning the promise from update will cause the forEach not to resolve
    //until all updates have completed
    return user.update({fullName : user.firstName + " " + user.lastName}, {transaction : false});
});
updateUsers.chain(function(){
    //updates finished
});

Deleting

The static remove can be used for removing a batch of models. Note this method is not anymore efficient just a convenience.

//remove all models
User.remove();

To limit the models removed you can pass in a query. The filter can be anything that filter accepts.

//remove models that start with m
User.remove({lastName : {like : "m%"}});`

The default behavior of remove is to load each model and call remove on it. If you wish to just do a mass delete and not load each model you can pass in an additional options object with a key called load set to false.
Note If you do this then the pre/post remove hooks will not be called.

//mass remove models without loading them
User.remove(null, {load : false});

To prevent the default transaction behavior pass in the transaction option.

//removing models, not using a transaction
User.remove(null, {transaction : false});

If you have an instance of a model and you want to remove it you can use the remove instance method.

User.forEach(function(user){
    return user.remove();
}).chain(function(){
    //removed
});

To prevent the default transaction behavior pass in the transaction option

User.forEach(function(user){
    return user.remove({transaction : false});
}).chain(function(){
    //removed
});

Documentation generated using coddoc.


text:
Entities in Effigy are defined and configured using annotations, the only required annotation being the `@Entity` annotation. The others are optional and used
to help configure the system to your needs.

## @Entity

The `@Entity` annotation is applied to an entity type, a POGO to denote that the object is an entity to be managed by Effigy.

The annotation has only one optional property, `table`, which is used to provide a custom name for the table containing the
entity data. By default, if not specified, the table name will be the name of the entity with an 's' added to the end of it.

Other than marking an object as an entity, the annotation causes some helper classes to be generated for the entity; a `RowMapper`
and two `ResultSetExtractor` implementations will be generated for each entity object. Each will be named with the prefix of the
class name of the entity. As an example for the entity class `Person` you would have three new classes:

* `PersonRowMapper` - maps a single row of the person entity table to a single `Person` object instance (no associations).
* `PersonAssociationExtractor` - maps a single row of the person entity table to a single `Person` object instance (with associations).
* `PersonCollectionAssociationExtractor` - maps a collection of rows of the person entity table to a collection of `Person` instances (with associations).

Each will be created in the same package as the entity itself. Also helper methods will be added to the entity class to retrieve
instances of each of these mappers and extractors. For the example above these would have the following signatures:

    static PersonRowMapper rowMapper(String prefix='')
    static PersonAssociationExtractor associationExtractor()
    static PersonCollectionAssociationExtractor collectionAssociationExtractor(Integer offset=null, Integer limit=null)

These mappers, extractors and helper methods are available for use by classes outside of Effigy itself, however, they are used extensively by internal code.

## @Column

The `@Column` annotation is an optional one applied to the entity properties. It is used to provide an alternate name for the database column associated
with the property. By default, if this annotation is not used, the property name will be converted from camel-case to underscore-case (e.g. firstName
becomes first_name).

The `@Column` annotation also provides an optional `type` property which allows the SQL type of the column to be explicitly specified as one of the
`java.sql.Types` value constants (Note: _only_ raw int values or references to `java.sql.Types` values will work due to complexities around AST annotation
 processing). If no value is provided, the default set of simple Java-to-SQL type mappings will be used.

The `@Column` annotation provides an optional `handler` property. This property allow the developer to specify a Class which will be used to convert
the column property value to and from the database value. The class is expected to have two static methods:

```groovy
static ENTITY readField(DATABASE db_value)
```

Which will be used to convert the database field value to that required by the entity property object.

```groovy
static DATABASE writeField(ENTITY domainValue)
```

Which will be used to convert the entity property object value to that required by the storage database.

These methods should be stateless and the conversion types on both sides of the read/write should match what is expected by the entity or database respectively.

## @Id

The `@Id` annotation is applied to an entity property that is to be defined as the unique identifier for an instance of the entity. While an id is not
explicitly required by Effigy, you will not benefit from most of the functionality without one. An entity id can be a property of any Object type, though
generally a Long is recommended.

The generating and management of ids is handled by your code and/or the database itself, Effigy does not take any action to generate ids. The DDL expected
could be something similar to the following:

```sql
id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY
```

Currently, Effigy does not support multiple properties annotated with the `@Id` annotation.

## @Version

The `@Version` annotation is an optional annotation applied to en entity property that is to be defined as the Optimistic versioning property for the entity.
The type of the property must be a Long, long, Integer or int.

The generated update methods (see documentation for the `@Update` annotation) will make use of the version property to determine whether or not the
update is allowed, based on the version being updated compared to the version in the database. The DDL expected could be something similar to the following:

```sql
version BIGINT NOT NULL,
```

Currently, Effigy does not support multiple properties annotated with the `@Version` annotation.

## @Transient

The `@Transient` annotation can be applied to an entity property to denote that the property will be ignored by the effigy processing framework. The
property will not participate in any database code generation.

## @Embedded

The `@Embedded` annotation is used to denote an embedded component property. The properties of the embedded object are mapped to fields of the entity table.
The database columns are named as specified by the embedded object property names following the standard name conversion rules, as well as any `@Column`
annotations. Also, a prefix will be prepended to the column names which will be the same as the name of the embedded property in the enclosing entity. The
annotation accepts an optional `prefix` property which allows the prefix to be specified explicitly.

The type of the embedded object may be an entity; however, it need not be. If the embedded object is an entity, any @Id or @Version annotations will **not** be
honored, since the table data is contained in the table for the enclosing entity. The `@Column` annotation will be honored.

The DDL expected for an embedded property is a set of prefixed columns in the main entity table. Consider the `Person` case, where there is an embedded
property `Name name`, the framework would expect the following:

```sql
CREATE TABLE people (
  -- other fields omitted
  name_first    VARCHAR(25)           NOT NULL,
  name_middle   VARCHAR(25)           NOT NULL,
  name_last     VARCHAR(25)           NOT NULL
);
```

> TBD: support for un-annotated embedded types?

## @Component

The `@Component` annotation is used to denote that a property has a one-to-one relationship with the enclosing entity. The one-to-one assocation expressed
by a Component is similar to that of an `@Embedded` object except that this relationship is contained in a separate lookup table, rather than being embedded
within the same table as the entity data.

The type of the annotated field may be an Entity-annotated class; however, the entity `table` property as well as any `@Id` or `@Version` annotated fields
will be ignored by the component association functionality.

The `@Component` annotation supports two configuration properties.

* The `lookupTable` property is used to specify the name of the lookup table used to link the component table with the entity table. If this property is not
specified, the table will be named as the table name of the component type.
* The `entityColumn` property is used to specify the name of the field used to identify the owning entity in the associated table. If this property is not
specified, the name will be the table name of the owning entity suffixed with '_id'.

The DDL expected for components is basically a 1-1 lookup table. Consider the case where a `Person` has a work address component defined as:

```groovy
@Component(lookupTable = 'employers') Address work
```

This would map the component to an `employers` table, by the id of the person, such as:

```sql
CREATE TABLE employers (
  people_id BIGINT REFERENCES people (id),
  line1     VARCHAR(30),
  line2     VARCHAR(30),
  city      VARCHAR(20),
  state     VARCHAR(2),
  zip       VARCHAR(10)
);
```

> TBD: support for un-annotated component types?

## @Association

The `@Association` annotation is used to denote that a collection property (Collection or Map implementation) represents an association between the enclosing
entity and another entity. The collection contents must be a type annotated with `@Entity`.

The `@Association` annotation supports three optional properties:

* The `joinTable` property is used to specify the name of the association reference table. If this property is not specified, the table name will be the entity
table name and the name of the entity association property separated by an underscore.
* The `entityColumn` property is used to specify the name of the id column for the owning entity. By default, the entity table name will be used, suffixed with '_id'.
* The `assocColumn` property is used to specify the name of the associated entity id. By default, the associated entity table name will be used, suffixed with '_id'.

The DDL expected for associations is that of an association table used to store the relationship between the two entities. Consider a `Pet` object associated
with a `Person`, the relationship would be defined in the entity as:

```groovy
@Association(joinTable = 'peoples_pets', entityColumn = 'person_id', assocColumn = 'pet_id')
Set<Pet> pets = [] as Set<Pet>
```

The DDL required by this association would be something like:

```sql
CREATE TABLE peoples_pets (
  person_id BIGINT REFERENCES people (id),
  pet_id    BIGINT REFERENCES pets (id),
  UNIQUE (person_id, pet_id)
);
```

which would contain the relationship information.

The CRUD annotations used by `@Repository` annotated classes will properly handle operations with associations, as will the `RowMapper` and `ResultSetExtractor`
implementations.

> TBD: support for un-annotated associations.

## @Mapped Association

Map associations are supported without additional annotations; however, the `@Mapped` annotation may be added to a property annotated with `@Association`
in order to specify the property to be used as the Map key. If the `keyProperty` is not specified, the map key will be the id property of the associated entity.

Care must be taken when using mapped associations - at this time there is no checking around the type of key used. It is on the developer to ensure that the
keys used are unique and defined in such a way that they will be appropriate for use as Map keys.

The DDL expected for mapped associations is the same as that for collection associations.


text:
\section{minted}

文書内にコードサンプルを表示したいときの環境です。
コンパイルする際には\texttt{-shell-escape}オプションが必要です。
(\mintinline{shell}{$ latexmk -pvc -shell-escape})

\begin{listing}[H]
\begin{minted}[linenos=true,showspaces]{python}
from dataclasses import dataclass
from pathlib import Path

@dataclass
class Config:
    path

    def __post_init__(self):
        self.path = Path(self.path)

if __name__ == "__main__":
    c = Config("config.toml")

\end{minted}
\caption{Pythonのサンプル}
\end{listing}

\begin{listing}[H]
\begin{minted}{latex}
\documentclass{jlreq}
\usepackage{minted}
\begin{document}

\end{document}
\end{minted}
\caption{LaTeXのサンプル}
\end{listing}