#!/usr/bin/python
# vim: set shiftwidth=4 tabstop=8 autoindent expandtab:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# For general fontforge documentation, see:
#   http://fontforge.sourceforge.net/
# For fontforge scripting documentation, see:
#   http://fontforge.sourceforge.net/scripting-tutorial.html
#   http://fontforge.sourceforge.net/scripting.html
# and most importantly:
#   http://fontforge.sourceforge.net/python.html

# To install what you need, on Ubuntu,
#   sudo apt-get install python-fontforge

import fontforge

em = 1000

def newMathFont(aName):
    print("Generating %s.otf..." % aName, end="")
    mathFont = fontforge.font()
    mathFont.fontname = aName
    mathFont.familyname = aName
    mathFont.fullname = aName
    mathFont.copyright = "Copyright (c) 2014 Mozilla Corporation"
    mathFont.encoding = "UnicodeFull"

    # Create a space character. Also force the creation of some MATH subtables
    # so that OTS will not reject the MATH table.
    g = mathFont.createChar(ord(" "), "space")
    g.width = em
    g.italicCorrection = 0
    g.topaccent = 0
    g.mathKern.bottomLeft = tuple([(0, 0)])
    g.mathKern.bottomRight = tuple([(0, 0)])
    g.mathKern.topLeft = tuple([(0, 0)])
    g.mathKern.topRight = tuple([(0, 0)])
    mathFont[ord(" ")].horizontalVariants = "space"
    mathFont[ord(" ")].verticalVariants = "space"
    return mathFont

def saveMathFont(aFont):
    aFont.em = em
    aFont.ascent = aFont.descent = em / 2
    aFont.hhea_ascent = aFont.os2_typoascent = aFont.os2_winascent = em / 2
    aFont.descent = aFont.hhea_descent = em / 2
    aFont.os2_typodescent = aFont.os2_windescent = em / 2
    aFont.hhea_ascent_add = aFont.hhea_descent_add = 0
    aFont.os2_typoascent_add = aFont.os2_typodescent_add = 0
    aFont.os2_winascent_add = aFont.os2_windescent_add = 0
    aFont.os2_use_typo_metrics = True
    aFont.generate(aFont.fontname + ".otf")
    print(" done.")

def createSquareGlyph(aFont, aCodePoint):
    g = aFont.createChar(aCodePoint)
    p = g.glyphPen()
    p.moveTo(0, 0)
    p.lineTo(em, 0)
    p.lineTo(em, em)
    p.lineTo(0, em)
    p.closePath()

def createLLTriangleGlyph(aFont, aCodePoint):
    g = aFont.createChar(aCodePoint)
    p = g.glyphPen()
    p.moveTo(0, 0)
    p.lineTo(em, 0)
    p.lineTo(0, em)
    p.closePath()

def createURTriangleGlyph(aFont, aCodePoint):
    g = aFont.createChar(aCodePoint)
    p = g.glyphPen()
    p.moveTo(em, 0)
    p.lineTo(em, em)
    p.lineTo(0, em)
    p.closePath()

def createDiamondGlyph(aFont, aCodePoint):
    g = aFont.createChar(aCodePoint)
    p = g.glyphPen()
    p.moveTo(0, em / 2)
    p.lineTo(em / 2, 0)
    p.lineTo(em, em / 2)
    p.lineTo(em / 2, em)
    p.closePath()

################################################################################
# Glyph variants and constructions
f = newMathFont("stretchy")
nvariants = 3

# Draw boxes for the size variants and glues
for i in range(0, nvariants):
    s = em * (i + 1)

    g = f.createChar(-1, "h%d" % i)
    p = g.glyphPen()
    p.moveTo(0, -em)
    p.lineTo(0, em)
    p.lineTo(s, em)
    p.lineTo(s, -em)
    p.closePath()
    g.width = s

    g = f.createChar(-1, "v%d" % i)
    p = g.glyphPen()
    p.moveTo(0, 0)
    p.lineTo(0, s)
    p.lineTo(2 * em, s)
    p.lineTo(2 * em, 0)
    p.closePath()
    g.width = 2 * em

# Draw some pieces for stretchy operators
s = em * nvariants

g = f.createChar(-1, "left")
p = g.glyphPen()
p.moveTo(0, -2 * em)
p.lineTo(0, 2 * em)
p.lineTo(s, em)
p.lineTo(s, -em)
p.closePath()
g.width = s

g = f.createChar(-1, "right")
p = g.glyphPen()
p.moveTo(0, -em)
p.lineTo(0, em)
p.lineTo(s, 2 * em)
p.lineTo(s, -2 * em)
p.closePath()
g.width = s

g = f.createChar(-1, "hmid")
p = g.glyphPen()
p.moveTo(0, -em)
p.lineTo(0, em)
p.lineTo(s, 2 * em)
p.lineTo(2 * s, em)
p.lineTo(2 * s, -em)
p.lineTo(s, -2 * em)
p.closePath()
g.width = 2 * s

g = f.createChar(-1, "bottom")
p = g.glyphPen()
p.moveTo(0, 0)
p.lineTo(0, s)
p.lineTo(2 * em, s)
p.lineTo(4 * em, 0)
p.closePath()
g.width = 4 * em

g = f.createChar(-1, "top")
p = g.glyphPen()
p.moveTo(0, 0)
p.lineTo(4 * em, 0)
p.lineTo(2 * em, -s)
p.lineTo(0, -s)
p.closePath()
g.width = 4 * em

g = f.createChar(-1, "vmid")
p = g.glyphPen()
p.moveTo(0, s)
p.lineTo(2 * em, s)
p.lineTo(4 * em, 0)
p.lineTo(2 * em, -s)
p.lineTo(0, -s)
p.closePath()
g.width = 3 * em

# Create small rectangle of various size for some exotic arrows that are
# unlikely to be stretchable with standard fonts.
hstretchy = [
    0x219C,  # leftwards wave arrow
    0x219D,  # rightwards wave arrow
    0x219E,  # leftwards two headed arrow
    0x21A0,  # rightwards two headed arrow
    0x21A2,  # leftwards arrow with tail
]
vstretchy = [
    0x219F,  # upwards two headed arrow
    0x21A1,  # downwards two headed arrow
    0x21A5,  # upwards arrow from bar
    0x21A7,  # downwards arrow from bar
    0x21A8,  # up down arrow with base
]
for i in range(0, 1 + nvariants + 1):
    s = (i + 1) * em / 10

    g = f.createChar(hstretchy[i])
    p = g.glyphPen()
    p.moveTo(0, -em / 10)
    p.lineTo(0, em / 10)
    p.lineTo(s, em / 10)
    p.lineTo(s, -em / 10)
    p.closePath()
    g.width = s

    g = f.createChar(vstretchy[i])
    p = g.glyphPen()
    p.moveTo(0, 0)
    p.lineTo(0, s)
    p.lineTo(2 * em / 10, s)
    p.lineTo(2 * em / 10, 0)
    p.closePath()
    g.width = 2 * em / 10

# hstretchy[0] and vstretchy[0] have all the variants and the components. The others only have one of them.
s = em * nvariants

f[hstretchy[0]].horizontalVariants = "uni219C h0 h1 h2"
f[hstretchy[0]].horizontalComponents = (
    ("left", False, 0, 0, s),
    ("h2", True, 0, 0, s),
    ("hmid", False, 0, 0, 2 * s),
    ("h2", True, 0, 0, s),
    ("right", False, 0, 0, s),
)

f[hstretchy[1]].horizontalVariants = "uni219D h0"
f[hstretchy[2]].horizontalVariants = "uni219E h1"
f[hstretchy[3]].horizontalVariants = "uni21A0 h2"
f[hstretchy[4]].horizontalVariants = "uni21A2 h2"
f[hstretchy[4]].horizontalComponents = f[hstretchy[0]].horizontalComponents

f[vstretchy[0]].verticalVariants = "uni219F v0 v1 v2"
f[vstretchy[0]].verticalComponents = (
    ("bottom", False, 0, 0, s),
    ("v2", True, 0, 0, s),
    ("vmid", False, 0, 0, 2 * s),
    ("v2", True, 0, 0, s),
    ("top", False, 0, 0, s),
)

f[vstretchy[1]].verticalVariants = "uni21A1 v0"
f[vstretchy[2]].verticalVariants = "uni21A5 v1"
f[vstretchy[3]].verticalVariants = "uni21A7 v2"
f[vstretchy[4]].verticalVariants = "uni21A8"
f[vstretchy[4]].verticalComponents = f[vstretchy[0]].verticalComponents

################################################################################
# Testing DisplayOperatorMinHeight
f.math.DisplayOperatorMinHeight = 8 * em
largeop = [0x2A1B, 0x2A1C]  # integral with overbar/underbar

# Draw boxes of size 1, 2, 7, 8, 9em.
for i in [1, 2, 7, 8, 9]:
    s = em * i
    if i == 1 or i == 2:
        g = f.createChar(largeop[i - 1])
    else:
        g = f.createChar(-1, "L%d" % i)
    p = g.glyphPen()
    p.moveTo(0, 0)
    p.lineTo(0, s)
    p.lineTo(s, s)
    p.lineTo(s, 0)
    p.closePath()
    g.width = s

f[largeop[0]].verticalVariants = "uni2A1B L7 L8 L9"
f[largeop[1]].verticalVariants = "uni2A1C L8"

saveMathFont(f)

################################################################################
# Testing AxisHeight
f = newMathFont("axis-height-1")
f.math.AxisHeight = 0
createSquareGlyph(f, ord("+"))
saveMathFont(f)

f = newMathFont("axis-height-2")
f.math.AxisHeight = 20 * em
createSquareGlyph(f, ord("+"))
saveMathFont(f)

################################################################################
# Testing Fraction Parameters
f = newMathFont("fraction-1")
f.math.FractionRuleThickness = 20 * em
f.math.FractionNumeratorShiftUp = 0
f.math.FractionNumeratorDisplayStyleShiftUp = 0
f.math.FractionDenominatorShiftDown = 0
f.math.FractionNumeratorGapMin = 0
f.math.FractionDenominatorGapMin = 0
f.math.FractionNumeratorDisplayStyleShiftUp = 0
f.math.FractionDenominatorDisplayStyleShiftDown = 0
f.math.FractionNumeratorDisplayStyleGapMin = 0
f.math.FractionDenominatorDisplayStyleGapMin = 0
saveMathFont(f)

################################################################################
# Testing Limits Parameters
f = newMathFont("limits-5")
f.math.UpperLimitGapMin = 0
f.math.UpperLimitBaselineRiseMin = 0
f.math.LowerLimitGapMin = 0
f.math.LowerLimitBaselineDropMin = 0
f.math.AccentBaseHeight = 6 * em
f.math.FlattenedAccentBaseHeight = 3 * em
createSquareGlyph(f, ord("~"))
saveMathFont(f)

f = newMathFont("dtls-1")
createSquareGlyph(f, ord("a"))
createLLTriangleGlyph(f, ord("b"))
createSquareGlyph(f, ord("c"))
createDiamondGlyph(f, 0x1D51E)  # mathvariant=fraktur a
createURTriangleGlyph(f, 0x1D51F)  # mathvariant=fraktur b
createDiamondGlyph(f, 0x1D520)  # mathvariant=fraktur c
f.addLookup("gsub", "gsub_single", (), (("dtls", (("latn", ("dflt")),)),))
f.addLookupSubtable("gsub", "gsub_n")
glyph = f["a"]
glyph.addPosSub("gsub_n", "b")
glyph2 = f[0x1D51F]
glyph2.glyphname = "urtriangle"
glyph3 = f[0x1D51E]
glyph3.addPosSub("gsub_n", "urtriangle")
saveMathFont(f)


# ------------------------------------------------------------------------------
#                 Julian Melendez make_ndx.py (2022)
#          make_index.py : Creates an index file from tinker xyz
# ------------------------------------------------------------------------------

import numpy as np
import readline
import os

logic_info = {"&": "Logical and operator (separated by white space)",
              "|": "Logical or operator (separated by white space)",
              "-": "Subtracts two groups (separated by white space)",
              ":": "Assign operator (no white space)"}

sele_info = {"a": "Atom name",
             "t": "Atom type",
             "i": "Index",
             "g": "Index group"}

other_info = {"n": "Rename selected group",
              "d": "Delete selected group",
              "q": "Quit and save the index",
              "Enter": "List groups"}

I = "\x1b[38;2;255;200;105;208m"    # Information color (Yellow)
G = "\x1b[38;2;120;255;105;208m"    # Selection color (Green)
O = "\x1b[38;2;120;105;235;208m"    # Not used (Blue)
E = "\x1b[38;2;255;55;50;208m"      # Error color (Red)
R = "\x1b[0m"                       # Reset color

def backup(fname: str, counter: int) -> str:
    '''
    Uses recursion to check if file name exists. If it exists then it
    checks if the backup also exists and so on. Returns a file name
    to create a backup with a name that does not exist
    '''
    exists = os.path.exists('{}'.format(fname))
    if exists == False:
        return fname
    else:
        fname = fname.split('#')[-1]
        fname = fname.split('_')[0]
        fname = '#' + fname + '_' + str(counter)
        counter += 1
        return backup(fname, counter)

def read_index(index: str) -> dict:
    '''
    Reads index file and converts it to a dicionary were the key
    is the name of the group and the value is a list of indeces
    '''
    dic = {}
    with open(index, 'r') as f:
        for line in f:
            if line.startswith("["):
                key = line[line.find('[')+1:line.find(']')].strip()
                dic[key] = []
            else:
                dic[key] += line.split()
    return dic

def write_index(index: dict, out: str) -> None:
    '''
    Uses backup to get an appropriate name for the output. Then it takes the
    index and prints it to the output file
    '''
    new_name = backup(out, 0)
    if out == new_name:
        os.system(f"touch {out}")
    else:
        print(
            I+f"Found a file with the same name backing it up to {new_name}"+R)
        os.system(f"mv {out} '{new_name}'")
        os.system(f"touch {out}")

    f = open(out, 'w')

    for key in index.keys():
        f.write(f"[ {key:^s} ]")
        for i, ind in enumerate(index[key]):
            ind = int(ind) + 1
            if i % 15 == 0:
                f.write(f"\n{ind:>4d}")
            else:
                f.write(f" {ind:>4d}")
        f.write("\n")
    return

def read_xyz(xyz: str) -> tuple[np.array(int), np.array(int)]:
    '''
    Reads input xyz and extracts the atom names and the atoms types
    '''
    # Gets the number of atoms
    with open(xyz, 'r') as f:
        for count, line in enumerate(f):
            if count == 0:
                num_atoms = int(line.split()[0])
                break

    # Count the number of lines
    with open(xyz, 'r') as f:
        for count, line in enumerate(f):
            pass
    count += 1

    # Checks if the box has 1 or 2 header lines
    print(80*"#")
    if num_atoms + 1 == count:
        print(I+"XYZ without box information"+R)
        ignore = 1
    elif num_atoms + 2 == count:
        print(I+"XYZ with box information"+R)
        ignore = 2
    else:
        print(E+"XYZ seems to be incorrected or not in tinker format"+R)
        exit(1)

    print(I+f"Number of atoms: {num_atoms:10d}"+R)

    # If files follows tinker format names and types
    # can be extracted as follows
    try:
        names = np.loadtxt(xyz, usecols=[1], dtype=str, skiprows=ignore)
        types = np.loadtxt(xyz, usecols=[5], dtype=int, skiprows=ignore)
    except:
        print(E+"XYZ seems to be incorrected or not in tinker format"+R)
        exit(1)

    return names, types

def get_index_values(command: str, selection: dict, index: dict) -> list:
    '''
    Based on the available options it computes the appropriate index list.
    if a: matches the name to the list of names or a letter to start with
          using the *
    if t: matches the atom type to the list of types
    if g: based on the current index returns the matching list
    '''
    if ":" not in command:
        print(E+"Delimiter separating selection and value not found"+R)
        return
    else:
        option = command.split(":")[0]
        value = command.split(":")[1]

    if option == 'a':
        tmp = value.split("*")
        if len(tmp) == 1:
            return list(np.array(np.where(names == value), dtype=str)[0])
        else:
            bool_arr = np.char.startswith(names, tmp[0])
            return list(np.array(np.where(bool_arr), dtype=str)[0])
    elif option == 't':
        try:
            value = int(value)
            return list(np.array(np.where(types == value), dtype=str)[0])
        except:
            print(E+"The type given cant be converted into an integer"+R)
            return
    elif option == 'g':
        num = int(value)
        if num in selection.keys():
            return index[selection[num]]
        else:
            print(E+f"Selection group {value:s} not found"+R)
            return
    elif option == 'i':
        numbers = value.split("-")
        if len(numbers) != 2:
            print(E+"Invalid range provided"+R)
            return
        try:
            begin = int(value.split("-")[0])
            end = int(value.split("-")[1])
        except:
            print(E+"The type given cant be converted into an integer"+R)
            return

        if begin < 1 or begin >= end:
            print(E+"Index provided too small or smaller than the end"+R)
        else:
            if end > MAX_INDEX:
                print(E+"Index provided to small or smaller than the end"+R)
            else:
                return list(range(begin - 1, end))
    else:
        print(E+f"Selection option {option:s} not available"+R)
        return

def evaluate_pair(group1: list, group2: list, operator) -> list:
    '''
    Takes two lists and one operator. Converts the list to sets and
    applies the operation between them. Returns the result as a sorted list
    '''
    if operator not in logic_info.keys():
        return
    expression = f"set(group1) {operator} set(group2)"
    result = list(eval(expression))
    result.sort(key=int)
    return result

def evaluate_expression(exp: str, selection: dict, index: dict) -> tuple[list, str]:
    '''
    Uses evaluate pair to evaluate any expression by splitting into expressions
    of two lists and one operator.
    '''
    elements = exp.split()
    name = ""
    if len(elements) % 2 == 0:  # Expressions should be uneven number of terms
        print(E+"Malformed expression"+R)
        return None, None
    else:
        # This two variables are needed to get the first case
        # since the empty set or any other set gives the other
        # set therefore for the first case the result is just the input set
        # after that it then evaluates the remaining operators
        group1 = []
        operator = '|'
        for i in range(0, len(elements), 2):
            group2 = get_index_values(elements[i], selection, index)
            if group2 == None:
                return None, None
            group1 = evaluate_pair(group1, group2, operator)
            name += elements[i]
            if i < len(elements) - 1:
                operator = elements[i + 1]
                name += "_" + operator + "_"
                if operator not in logic_info.keys():
                    print(E+f"Operator ({operator:s}) not available"+R)
                    return None, None

    return group1, name

def update_selection(index: dict) -> dict:
    '''
    Gets called everytime index changes. It updates the selection dictionary
    based on the modified index
    '''
    selection = {}
    for i, key in enumerate(index.keys()):
        selection[i] = key
    return selection

def print_options(index: dict) -> None:
    '''
    Outputs to stdout all the options of the program as well as the index
    groups
    '''
    print(80*"#")
    print(G+"Available selection groups:\n"+R)
    for i, key in enumerate(index.keys()):
        print(G+f"{i:3d}: {key:50s} ({len(index[key]):8d} Atoms)"+R)
    print("\n"+80*"#")
    print("Available logical operators:")
    for key, value in logic_info.items():
        print(f"({key:^5s}) {value:s}")
    print(80*"#")
    print("Available selection options:")
    for key, value in sele_info.items():
        print(f"({key:^5s}) {value:s}")
    print(80*"#")
    print("Other options:")
    for key, value in other_info.items():
        print(f"({key:^5s}) {value:s}")
    print(80*"#")

def print_examples():
    print(80*"#")
    print(O+"Examples:"+R)
    print(O+"g:0 | g:1     (group 0 or group 1)"+R)
    print(O+"a:N*          (all names that start with N)"+R)
    print(O+"a:O* & t:54   (start with O and type 54)"+R)
    print(O+"a:OW | a:HW   (selects all water)"+R)
    print(O+"g:0 - g:1     (all - water gives non water atoms)"+R)

if __name__ == "__main__":

    from argparse import ArgumentParser

    parser = ArgumentParser(
        description="Creates and index file based on a tinker xyz.")
    parser.add_argument("--xyz", "-f", help="tinker XYZ file",
                        type=str, required=True)
    parser.add_argument("--ndx", "-n", help="Index file",
                        type=str, default=None)
    parser.add_argument("--out", "-o", help="Output file",
                        type=str, default="index.ndx")
    args = parser.parse_args()

    names, types = read_xyz(args.xyz)
    if args.ndx != None:
        index = read_index(args.ndx)
    else:
        index = {}
        all = list(np.array(np.arange(0, len(names)), dtype=str))
        index["System"] = all

    MAX_INDEX = len(names)

    print_examples()

    selection = update_selection(index)
    print_options(index)

    while True:
        inp = input("")
        if inp.strip() == "q":
            write_index(index, args.out)
            break
        elif inp.strip() == "":
            print_options(index)
        elif inp.strip()[0:2] in ["n:", "d:"]:
            if inp.strip()[0:2] == "d:":
                try:
                    value = int(inp.split(":")[-1])
                except:
                    print(E+"Value given to delete cant be converted to an integer"+R)
                if value in selection.keys():
                    index.pop(selection[value])
                    selection = update_selection(index)
                else:
                    print(E+"Group to delete was not found"+R)
            else:
                tmp = inp.split()
                name = tmp[-1].strip()
                if len(tmp) == 1:
                    print(E+"No name given. Cant rename group"+R)
                else:
                    try:
                        value = int(tmp[0].split(":")[-1])
                    except:
                        print(
                            E+"Value given to delete cant be converted to an integer"+R)
                    if value in selection.keys():
                        old_keys = list(index.keys())
                        num = list(selection.keys())
                        for i, key in zip(num, old_keys):
                            if i == value:
                                index[name] = index.pop(selection[i])
                            else:
                                index[selection[i]] = index.pop(selection[i])
                        selection = update_selection(index)
                    else:
                        print(E+"Group to rename was not found"+R)
        else:
            new_group, name = evaluate_expression(inp, selection, index)
            if new_group != None:
                if len(new_group) == 0:
                    print(E+f"Empty group {name:s} not created"+R)
                else:
                    if name not in index.keys():
                        index[name] = new_group  # Adds new group to index
                        selection = update_selection(index)
                    else:
                        print(E+f"Repeated group {name:s} not created"+R)


from django.contrib import admin

from .models import GeoServerDomain, GeoserverWorkspace, OGCLayer, WebGISProject, Categories

class GeoServerDomainAdmin(admin.ModelAdmin):
    list_display = ["domain", "container_domain"]
    list_filter = ["publishing_date"]
    search_fields = ["domain"]
    fieldsets = [
        (None, {"fields": ["domain", "container_domain"]}),
    ]

    class Meta:
        model = GeoServerDomain

class GeoserverWorkspaceDomainAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["workspace"]}),
    ]

    class Meta:
        model = GeoserverWorkspace

class CategoriesAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug_category": ("category_name",)}
    fieldsets = [
                (None, {"fields": ["category_name", "slug_category"]}),
            ]

    class Meta:
        model = Categories

class OGCLayerAdmin(admin.ModelAdmin):
    list_display = ["title", "ogc_layer_name", "publishing_date", "ogc_bbox", "ogc_centroid", "complete_url_wms", "complete_url_wfs_wcs", "header_image"]
    list_filter = ["publishing_date"]
    search_fields = ["title"]
    prepopulated_fields = {"slug_post": ("title",)}
    fieldsets = [
                ("Meta description", {"fields": ["title", "slug_post", "description", "contents", "categories", "draft"]}),
                ("Geoserver", {"fields": ["geoserver_domain", "geoserver_workspace"]}),
                ("OGC Parameters", {"fields": [
                    "ogc_layer_name", "ogc_layer_style", "ogc_legend", "is_vector", "is_raster",
                ]}),
                ("OpenLayers Parameters",
                 {"fields": ["set_max_zoom", "set_min_zoom", "set_zindex", "set_opacity"]}
                 ),
            ]

    class Meta:
        model = OGCLayer

class WebGISProjectAdmin(admin.ModelAdmin):
    list_display = ["title", "description", "publishing_date", "updating_date", "highlighted", "draft", "meta_image"]
    list_filter = ["publishing_date"]
    search_fields = ["title"]
    prepopulated_fields = {"slug_post": ("title",)}
    fieldsets = [
                ("Meta description", {"fields": ["title", "slug_post", "header_image", "description"]}),
                ("Contents", {"fields": ["contents", "categories"]}),
                ("Options", {"fields": ["draft", "highlighted", "publishing_date"]}),
                ("OpenLayers Parameters",
                 {
                     "classes": ("collapse",),
                     "fields":
                      ["map_scaleline", "map_center_longitude", "map_center_latitude", "set_max_zoom", "set_min_zoom",
                       "set_zoom_level"
                       ]
                  }
                 ),
                ("OGC Layer",  {"fields": ["main_layer", "layers"]}),
            ]

    class Meta:
        model = WebGISProject

admin.site.register(GeoServerDomain, GeoServerDomainAdmin)
admin.site.register(GeoserverWorkspace, GeoserverWorkspaceDomainAdmin)
admin.site.register(Categories, CategoriesAdmin)
admin.site.register(OGCLayer, OGCLayerAdmin)
admin.site.register(WebGISProject, WebGISProjectAdmin)


# 과제
# 반복문과 조건문을 이용하여 달력 출력하기
# 출력 예시
# 1월은 31일까지 있습니다.
# 2월은 28일까지 있습니다.
# 3월은 30이까지 있습니다
i = 1
thirty_one = [1, 3, 5, 7, 8, 10, 12]
thirty = [4, 6, 9, 11]
for i in range(1,13):
    print("{0} 월은".format(i), end=' ')
    # 31일 까지 있는 경우
    if i in thirty_one:
        print("{0} 일까지 있습니다.".format(31))
    # 30일까지 있는 경우
    elif i in thirty:
        print("{0} 일까지 있습니다.".format(30))
    # 28일까지 있는 경우
    else:
        print("{0} 일까지 있습니다.".format(28))


"""Invert emf_class_2_need_def dictionary."""
import logging
from typing import Any, Dict, Optional

from pyecore.ecore import EClass

logger = logging.getLogger(__name__)

def get_emf_class_from_need(need: Dict[str, Any], emf_class_2_need_def, mm_root) -> Optional[str]:
    """
    Try to derive the ECore class from a need type.

    3 strategies are used:

    1. Check whether whether one of the emf_class_2_need_def need_static settings for 'type' matches
    2. Check whether the need type matches any lower case key in emf_class_2_need_def
    3. Check whether the need type matches any lower case ECore EClass name of the meta model

    If none is successful, the function returns None.
    """
    # first look in need_static
    for emf_type, definitions in emf_class_2_need_def.items():
        if "type" in definitions["need_static"]:
            if definitions["need_static"]["type"] == need["type"]:
                return emf_type
    # now match the dictionary key
    all_emf_types = list(emf_class_2_need_def.keys())
    for emf_type in all_emf_types:
        if emf_type.lower() == need["type"]:
            return emf_type
    # now go through all EClass items in the meta model
    for item in mm_root.eClassifiers.items:
        if item.name.lower() == need["type"] and isinstance(item, EClass):
            return item.name
    logger.error(f"Cannot derive the ECore class for need id '{need['id']}' (type '{need['type']}')")
    return None


import numpy as np
import matplotlib.pyplot as plt

np.seterr(invalid='ignore', over='ignore')  # suppress warning caused by division by inf

def f(x):
    return 1/(1 + np.exp(3*(x-3))) * 10 * x**2  + 1 / (1 + np.exp(-3*(x-3))) * (0.5*(x-10)**2 + 50)

def fprime(x):
    return 1 / (1 + np.exp((-3)*(x-3))) * (x-10) + 1/(1 + np.exp(3*(x-3))) * 20 * x + (3* np.exp(9))/(np.exp(9-1.5*x) + np.exp(1.5*x))**2 * ((0.5*(x-10)**2 + 50) - 10 * x**2)

x = np.linspace(-5,20,100)
plt.plot(x,f(x), 'k')
plt.show()

def test(lr, test_num, iter_num):

    for _ in range(test_num):
        # n one gradient descent
        x = np.random.rand() * 25 -5
        ylist = [x]
        xlist = np.arange(iter_num+1)
        for rep in range(iter_num):
            x = x - lr  * fprime(x)
            ylist.append(x)

        plt.plot(xlist, ylist)
    plt.show()

test(0.01, 100, 1000)
test(0.3, 100, 1000)
test(4, 100 , 1000)


from django.contrib.auth import get_user_model
from django.test import TestCase

from accounts.authentication import PasswordlessAuthenticationBackend as Auth
from accounts.models import Token

User = get_user_model()

class AuthenticateTest(TestCase):

    def test_returns_None_if_no_such_token(self):
        result = Auth().authenticate('no-such-token')
        self.assertIsNone(result)

    def test_returns_new_user_with_correct_email_if_token_exists(self):
        email = 'edith@example.com'
        token = Token.objects.create(email=email)
        user = Auth().authenticate(token.uid)
        new_user = User.objects.get(email=email)
        self.assertEqual(user, new_user)

    def test_returns_existing_user_with_correct_email_if_token_exists(self):
        email = 'edith@example.com'
        existing_user = User.objects.create(email=email)
        token = Token.objects.create(email=email)
        user = Auth().authenticate(token.uid)
        self.assertEqual(user, existing_user)

class GetUserTest(TestCase):

    def setUp(self):
        self.email = 'edith@example.com'

    def test_get_user_by_email(self):
        expected_user = User.objects.create(email=self.email)
        user = Auth().get_user(email=self.email)
        self.assertEqual(user, expected_user)

    def test_returns_None_if_cannot_get_user_with_THE_email(self):
        self.assertIsNone(Auth().get_user(email=self.email))


#Sanvenirtin
#roguelike game
#programming by Sanvenir
#ver 0.0.1
#map file
#Everyting about map is included
from config import *
from drawing import *

class CMapBrick:
    def __init__(self, x, y, rigidbody, ground):
        self.x = x
        self.y = y
        self.rigidbody = rigidbody
        self.ground = ground
        self.transform = 0
        self.transformMap = 0
        self.item = []

    def checkTransform(self):
        if(self.transform):
            return True
        else:
            return False

    def draw(self, cameraX, cameraY):
        if(self.rigidbody != 0):
            self.rigidbody.draw(cameraX, cameraY)
        else:
            try:
                self.ground.draw(cameraX, cameraY)
            except AttributeError:
                pass

    def undraw(self):
        try:
            self.ground.undraw()
        except AttributeError:
            pass
        try:
            self.rigidbody.undraw()
        except AttributeError:
            return

    def reset(self):
        try:
            self.rigidbody.reset()
        except AttributeError:
            pass
        try:
            if(self.rigidbody.movable):
                self.rigidbody = 0
        except AttributeError:
            pass
        try:
            self.ground.reset()
        except AttributeError:
            pass

class CLocalMap:
    def __init__(self, mapType, x, y, mainMap):
        self.mapType = mapType  #0:ocean
        self.mainMap = mainMap
        self.mapFile = [[CMapBrick(0, 0, 0, 0)]]
        self.layout = [[0]]
        self.x = x
        self.y = y

    def reset(self):
        for i in self.mapFile:
            for j in i:
                j.reset()

    def save(self):
        self.reset()
        localFile = open("sav//map//l%04d%04d.sav"%(self.x, self.y), 'wb')
        pickle.dump(self.layout, localFile)
        localFile.close()

    def load(self):
        try:
            localFile = open("sav//map//l%04d%04d.sav"%(self.x, self.y), 'rb')
            t = pickle.load(localFile)
            localFile.close()
            self.layout = t
            self.createBlankMap()
            self.createMapFromLayout()
            return True
        except FileNotFoundError:
            return False

    def createBlankMap(self):
        self.mapFile = []
        self.width = localMapWidth
        self.height = localMapHeight
        for i in range(self.width):
            self.mapFile.append([])
            self.layout.append([])
            for j in range(self.height):
                self.mapFile[i].append(CMapBrick(i, j, 0, CGround("(0)", i, j, self.mapType)))
                self.layout[i].append(0)
        for i in range(1, self.width - 1):
            self.mapFile[i][0].transformMap = self.mainMap.transformMap(self.x, self.y - 1)
            self.mapFile[i][0].transform = (i, localMapHeight - 2)
            self.mapFile[i][-1].transformMap = self.mainMap.transformMap(self.x, self.y + 1)
            self.mapFile[i][-1].transform = (i, 1)
        for i in range(1, self.height - 1):
            self.mapFile[0][i].transformMap = self.mainMap.transformMap(self.x - 1, self.y)
            self.mapFile[0][i].transform = (localMapWidth - 2, i)
            self.mapFile[-1][i].transformMap = self.mainMap.transformMap(self.x + 1, self.y)
            self.mapFile[-1][i].transform = (1, i)
        self.mapFile[0][0].transformMap = self.mainMap.transformMap(self.x - 1, self.y - 1)
        self.mapFile[0][0].transform = (localMapWidth - 2, localMapHeight - 2)
        self.mapFile[0][-1].transformMap = self.mainMap.transformMap(self.x - 1, self.y + 1)
        self.mapFile[0][-1].transform = (localMapWidth - 2, 1)
        self.mapFile[-1][0].transformMap = self.mainMap.transformMap(self.x + 1, self.y - 1)
        self.mapFile[-1][0].transform = (1, localMapHeight - 2)
        self.mapFile[-1][-1].transformMap = self.mainMap.transformMap(self.x + 1, self.y + 1)
        self.mapFile[-1][-1].transform = (1, 1)

    def createLayout(self):
        for i in range(self.width):
            for j in range(self.height):
                self.layout[i][j] = random.randrange(GROUNDTYPEMAX[self.mapType])

    def createRandomMap(self):
        self.createBlankMap()
        self.createLayout()
        self.createMapFromLayout()

    def createMapFromLayout(self):
        for i in range(self.width):
            for j in range(self.height):
                groundType = "(%d)"%self.layout[i][j]
                self.mapFile[i][j].ground.changeImage(groundType)

class CTownMap(CLocalMap):
    def __init__(self, identity, name, x, y, environment, mainMap):
        CLocalMap.__init__(self, 5, x, y, mainMap)
        self.identity = identity
        self.name = name
        self.layout = [[0]]
        self.house = []
        self.position = []
        self.regular = False
        self.environment = environment
        #layout instruction:
        #0:undefined
        #1x:ground
        #2x:ground sides
        #3x:roads
        #4x:house floor
        #5x:house outline
        #6x:house inline
        #7x:town wall
        #8x:decoration
        #9x:door

    def createLayoutHouse(self, cx, cy, width, height):
        left = cx - width
        right = cx + width
        top = cy + height
        bottom = cy - height
        if(CCalculate.checkInMapFile(left - 1,  top + 1,    self.layout) and \
           CCalculate.checkInMapFile(left - 1,  bottom - 1, self.layout) and \
           CCalculate.checkInMapFile(right + 1, top + 1,    self.layout) and \
           CCalculate.checkInMapFile(right + 1, bottom - 1, self.layout)):
            floorType = random.randrange(10)
            wallType = random.randrange(10)
            for i in range(left - 1, right + 2):
                for j in range(bottom - 1, top + 2):
                    if(self.layout[i][j] >= 30):
                        return False
            for i in range(left, right + 1):
                for j in range(bottom, top + 1):
                    self.layout[i][j] = 50 + wallType
            for i in range(left + 1, right):
                for j in range(bottom + 1, top):
                    self.layout[i][j] = 40 + floorType
            return True
        return False

    def createMapFromLayout(self):
        for i in range(localMapWidth):
            for j in range(localMapHeight):
                floorType = random.randint(10, 19)
                if(self.layout[i][j] < 10):
                    groundType =  "%s\\(%d)"%(MAPTYPESET[self.environment], self.layout[i][j])
                    self.mapFile[i][j].ground.changeImage(groundType)
                elif(self.layout[i][j] < 40):
                    groundType =  "ground\\(%d)"%(self.layout[i][j] % 10)
                    self.mapFile[i][j].ground.changeImage(groundType)
                else:#(self.layout[i][j] < 50):
                    groundType =  "floor\\(%d)"%(self.layout[i][j] % 10)
                    self.mapFile[i][j].ground.changeImage(groundType)

    def createRandomMap(self):
        self.createBlankMap()
        self.createLayout(20)
        self.createMapFromLayout()

    def createBlankMap(self):
        CLocalMap.createBlankMap(self)
        for i in range(0, self.width):
            for j in range(0, self.height):
                self.layout[i].append(0)
            self.layout.append([])

    def createLayout(self, houseNum):
        for i in range(localMapWidth):
            for j in range(localMapHeight):
                self.layout[i][j] = random.randrange(10)
        for i in range(houseNum):
            for j in range(1000):
                width = random.randint(2, 10)
                height = random.randint(2, 10)
                cx = random.randint(width + 1, localMapWidth - width - 1)
                cy = random.randint(height + 1, localMapHeight - height - 1)
                if(self.createLayoutHouse(cx, cy, width, height)):
                    break

class CTown:
    def __init__(self, identity, name, x1, y1, x2, y2, environment, mainMap):
        self.identity = identity
        self.environment = environment
        self.name = name
        self.mainMap = mainMap
        self.x = (x1 + x2) / 2
        self.y = (y1 + y2) / 2
        for i in range(x1, x2 + 1):
            for j in range(y1, y2 + 1):
                self.mainMap.mainMap[i][j] = CTownMap(identity, name, i, j, self.environment, mainMap)
        for i in range(x1, x2 + 1):
            self.mainMap.mainMap[i][y1].position.append(8)
            self.mainMap.mainMap[i][y2].position.append(2)
        for j in range(y1, y2 + 1):
            self.mainMap.mainMap[x1][j].position.append(4)
            self.mainMap.mainMap[x2][j].position.append(6)

class CMainMap:
    def loadLocalMap(self, x, y):
        t = self.mainMap[x][y].load()
        if(not t):
            self.mainMap[x][y].createRandomMap()
        return self.mainMap[x][y]

    def __init__(self):
        self.width = 0
        self.height = 0
        self.mainMap = []
        self.town = []

    def save(self):
        mapFile = open("sav//map//mainMap.sav", 'wb')
        pickle.dump(self, mapFile)
        mapFile.close()

    def load():
        try:
            mapFile = open("sav//map//mainMap.sav", 'rb')
            t = pickle.load(mapFile)
            mapFile.close()
            return t
        except FileNotFoundError:
            return False

    def transformMap(self, x, y):
        if(x >= len(self.mainMap)):
            rx = x - len(self.mainMap)
        elif(x < 0):
            rx = x + len(self.mainMap)
        else:
            rx = x
        if(y >= len(self.mainMap[rx])):
            ry = y - len(self.mainMap[rx])
        elif(y < 0):
            ry = y + len(self.mainMap[rx])
        else:
            ry = y
        return rx, ry

    #this function is not supposed to create land in empty mapFile
    def randomPositionCreateLand(self, landMinSize, landMaxSize, landType, complexity):
        left = random.randrange(0, len(self.mainMap))
        bottom = random.randrange(0, len(self.mainMap[left]))
        self.randomCreateLand(landMinSize, landMaxSize, landType[0], left, bottom)
        for i in range(complexity):
            l = random.randrange(left, left + landMinSize)
            b = random.randrange(bottom, bottom + landMinSize)
            self.randomCreateLand(2, landMaxSize, landType[random.randrange(len(landType))], l, b)

    def randomCreateLand(self, landMinSize, landMaxSize, landType, left, bottom):
        right = landMinSize + left
        top = landMinSize + bottom
        for i in range(left, right + 1):
            for j in range(bottom, top + 1):
                x, y = self.transformMap(i, j)
                self.mainMap[x][y] = CLocalMap(landType, x, y, self)
        side = []
        for i in range(left, right):
            x, y = self.transformMap(i, bottom)
            side.append(self.mainMap[x][y])
            x, y = self.transformMap(i + 1, top)
            side.append(self.mainMap[x][y])
        for i in range(bottom, top):
            x, y = self.transformMap(left, i)
            side.append(self.mainMap[x][y])
            x, y = self.transformMap(right, i + 1)
            side.append(self.mainMap[x][y])
        for i in range(landMaxSize - landMinSize):
            newside = []
            for j in side:
                expand = random.randrange(3)
                if(not expand):
                    for k in [1, 2, 3, 6, 9, 8, 7, 4]:
                        tx, ty = self.transformMap(j.x + DIRECTION[k].dx, j.y + DIRECTION[k].dy)
                        if(self.mainMap[tx][ty].mapType != landType):
                            self.mainMap[tx][ty] = CLocalMap(landType, tx, ty, self)
                            newside.append(self.mainMap[tx][ty])
            side = newside

    def randomCreateMap(self, totalWidth, totalHeight, landNum, landMinSize, landMaxSize, landTotalType, maxComplexity):
        self.mainMap = []
        self.width = totalWidth
        self.height = totalHeight
        for i in range(totalWidth):
            self.mainMap.append([])
            for j in range(totalHeight):
                self.mainMap[i].append(CLocalMap(0, i, j, self))
        for i in range(landNum):
            self.randomPositionCreateLand(landMinSize, landMaxSize, range(1, landTotalType), random.randrange(maxComplexity))

    def randomCreateTown(self, totalNum):
        self.town.append(CTown(0, "test", 0, 0, 2, 2, 1, self))
        for i in range(1, totalNum):
            name = ""
            namelength = random.randint(2, 5)
            sex = random.randrange(2)
            width = random.randint(1, 3)
            height = random.randint(1, 3)
            for j in range(namelength):
                if(sex):
                    name += randomMaleNameList[random.randrange(len(randomMaleNameList))]
                else:
                    name += randomFemaleNameList[random.randrange(len(randomFemaleNameList))]
            name += randomTownNameList[random.randrange(len(randomTownNameList))]
            for j in range(1000):
                x1 = random.randint(3, mainMapWidth - width - 3)
                x2 = x1 + width
                y1 = random.randint(3, mainMapHeight - height - 3)
                y2 = y1 + width
                checkPosition = random.randrange(4)
                if(checkPosition == 0):
                    x, y = x1, y1
                elif(checkPosition == 1):
                    x, y = x1, y2
                elif(checkPosition == 2):
                    x, y = x2, y1
                else:
                    x, y = x2, y2
                check = random.random()
                environment = self.mainMap[x][y].mapType
                if(check < TOWNRATIO[environment]):
                    print(i, name, x1, y1, x2, y2)
                    self.town.append(CTown(i, name, x1, y1, x2, y2, environment, self))
                    break


# -*-coding: utf-8 -*-
# __author__ : tinytiger
# __time__   : '2018/1/4 11:08'
# If this runs wrong, don't ask me, I don't know why;
# If this runs right, thank god, and I don't know why.
# Maybe the answer, my friend, is blowing in the wind.

import json
import tornado.web
from tornadoserver.app.biz import sess_field
from tornadoserver.app.biz import decode_inline
from tornadoserver.loginst import logger

class Translate(tornado.web.RequestHandler):
    def post(self):
        data = self.get_argument("args")
        datas = json.loads(data)
        if not isinstance(datas, list) or not all(map(lambda x: isinstance(x, str), datas)):
            logger.warn("[handler] Translate.post: invalid input")
            self.write(json.dumps({"result": "invalid input"}))
        else:
            logger.info("[handler] Translate.post: get sentence and put into input queue")
            # logger.info("[handler] Translate.post: " + data)
            try:
                result = []
                num_of_batch = (len(datas) - 1) // sess_field.batch_size + 1
                for k in range(num_of_batch):
                    lines = datas[k * sess_field.batch_size: (k + 1) * sess_field.batch_size]
                    src_lines, trans_lines = decode_inline(lines)
                    result += trans_lines
                self.write(json.dumps({"result": result}))
                logger.info("[handler] Translate.post: send translated sentence")
            except Exception as e:
                logger.warn("[handler] Translate.post: tornadoserver failed %s %s" % (e.__class__, e.__context__))
                self.write(json.dumps({"result": "tornadoserver failed"}))


import io
import sys

_INPUT = """\
6
1 1
10 11
"""

sys.stdin = io.StringIO(_INPUT)
case_no=int(input())
for __ in range(case_no):
  A,B=map(int,input().split())
  if A>B: A,B=B,A
  if B>A*2/(3**.5): print(A*2/(3**.5))
  else:
    l,r=0,2000
    for i in range(200):
      mid=(l+r)/2
      if mid<B: l=mid
      else:
        x,y=B-(mid**2-A**2)**.5,A-(mid**2-B**2)**.5
        if x<0 or y<0 or (x**2+y**2)**.5<mid: r=mid
        else: l=mid
    print(l)


from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import mean_squared_error, r2_score, confusion_matrix, accuracy_score
from sklearn import datasets
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd
import numpy as np

dataset_dict = {
    '와인': datasets.load_wine(),
    '유방암': datasets.load_breast_cancer(),
    '당뇨병': datasets.load_diabetes(),
    '붓꽃': datasets.load_iris(),
    '손글씨': datasets.load_digits()
}

def 데이터불러오기(data):
    if data in dataset_dict:
        dataset = dataset_dict[data]
    else:
        raise ValueError('지원하지 않는 데이터셋입니다.')

    # 데이터를 Pandas DataFrame으로 변환
    df = pd.DataFrame(data=dataset.data, columns=dataset.feature_names)
    df['target'] = dataset.target  # 클래스 정보를 추가
    return df

def 데이터분할하기(df):
    # 데이터를 특성(X)과 레이블(y)로 분할
    X = df.drop('target', axis=1)
    y = df['target']

    # 훈련 세트와 테스트 세트로 분할
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

    return X_train, X_test, y_train, y_test

def 모델_훈련(X_train, y_train, 모델명):
    # 모델 선택
    모델 = 모델_선택(모델명)

    # 모델 훈련
    모델.fit(X_train, y_train)

    return 모델

def 모델_평가(X_test, y_test, model):
    # 범주형이면 혼동행렬
    if len(y_test.unique())<5 :
        # 모델 예측
        y_pred = model.predict(X_test)
        y_pred_rounded = np.round(y_pred).astype(int)

        # 정확도 계산
        cm = confusion_matrix(y_test, y_pred_rounded)

        실제_라벨 = [f'실제{i}' for i in range(len(cm))]
        예측_라벨 = [f'예측{i}' for i in range(len(cm))]
        confusion_df = pd.DataFrame(cm, columns=예측_라벨, index=실제_라벨)
        print(y_pred_rounded.tolist()[:10], '>>>> target을 예측한 값의 일부에요!')
        print(y_test.tolist()[:10], '>>>> target의 실제 값의 일부에요!')
        print('혼동행렬(confusion matrix)')
        display(confusion_df)
        print('\n')

        # 대각선 상의 셀 값을 합산하여 올바른 예측 수를 구함
        correct_predictions = np.sum(np.diag(confusion_df))

        # 전체 샘플 수를 구함 (혼동 행렬의 모든 값을 합산)
        total_samples = np.sum(confusion_df).sum()

        # 정확도 계산
        accuracy = correct_predictions / total_samples
        return np.round(accuracy, 4)
    else:
        # 모델 예측
        y_pred = model.predict(X_test)
        print(y_pred.tolist()[:10], '>>>> target을 예측한 값의 일부에요!')
        print(y_test.tolist()[:10], '>>>> target의 실제 값의 일부에요!')

        # 평균 제곱 오차(Mean Squared Error) 계산
        mse = mean_squared_error(y_test, y_pred)

        # 결정 계수(R-squared) 계산
        r_squared = r2_score(y_test, y_pred)

        print(f'평균 제곱 오차(MSE): {mse:.4f}')
        print(f'결정 계수(R-squared): {r_squared:.4f}')
        print('\n')

        return np.round(r_squared, 4)

def 모델_선택(모델명):
    모델_딕셔너리 = {
        '선형': LinearRegression(),
        '이차식': make_pipeline(PolynomialFeatures(degree=2), LinearRegression()),
        '랜덤 포레스트': RandomForestClassifier(),
        '서포트 벡터 머신': SVC(),
        '최근접 이웃': KNeighborsClassifier(),

        # 다른 모델을 추가할 수 있습니다.
    }

    if 모델명 in 모델_딕셔너리:
        return 모델_딕셔너리[모델명]
    else:
        raise ValueError('지원하지 않는 모델입니다.')


from PIL import Image, ImageDraw

def create_checkerboard(image_size, square_size, color1=(0, 0, 0), color2=(255, 255, 255)):
    """
    Create a checkerboard image using Pillow.

    Parameters:
        image_size (tuple): The dimensions of the image (width, height).
        square_size (int): The size of each square in the checkerboard.
        color1 (tuple): RGB color for the first type of square (default is black).
        color2 (tuple): RGB color for the second type of square (default is white).

    Returns:
        Image: A PIL Image object representing the checkerboard.
    """

    # Create a new image with white background
    img = Image.new("RGB", image_size, "white")
    draw = ImageDraw.Draw(img)

    # Loop to draw the checkerboard
    for i in range(0, image_size[0], square_size):
        for j in range(0, image_size[1], square_size):
            color = color1 if (i // square_size) % 2 == (j // square_size) % 2 else color2
            draw.rectangle([i, j, i + square_size, j + square_size], fill=color)

    return img

# Example usage:
image_size = (1024, 1024)  # 256x256 pixels
square_size = 64  # Each square is 32x32 pixels

img = create_checkerboard(image_size, square_size,color1=(255,0,0),color2=(255,255,0))
img.show()  # This will display the image using the default image viewer


# SpawnTerror 2022
# Python 3.11.1
# AOC Day 6 Part 1

# Working with 4 letter in a row

setSize = 4

# Grab each letter and put into a list

def getData(fileName: str) -> list:
    with open(fileName, 'r') as f:
        initialData = [x for x in f.readline()]
    return initialData

# Part 1

def processData(data: list):

    # Create dictionary to count occurences
    # Marker is already on 4 as first set is 4 long

    dictionaryFours = {}
    markerPosition = 4

    # Itterate through every letter
    # (-3) to end on a full set of 4
    # Put 4 letters into a line

    for x in range(0, len(data)-3):
        dictionaryFours = {}
        line = data[x: x + setSize]

        # Count occurences of each letter
        # in the current dictionary of 4

        for letter in line:
            if letter in dictionaryFours:
                dictionaryFours[letter] += 1
            else:
                dictionaryFours[letter] =1

        # Check if all counts are equal to 1
        # If true, return the set and marker position

        if all(value == 1 for value in dictionaryFours.values()):
            return dictionaryFours, markerPosition
        else:
            markerPosition += 1

data = getData('day6/input.txt')
uniqueSet, markerPosition = processData(data)

print(f'Unique set found: ', uniqueSet, 'with a markerPosition at position: ', markerPosition)


from nltk.corpus import gutenberg

# INFO: https://www.nltk.org/book/ch02.html

if __name__ == '__main__':
    # nltk.download('gutenberg')

    ids = gutenberg.fileids()
    print(ids, '\n')

    emma = gutenberg.words('austen-emma.txt')
    print(emma, '\n')

    for fileid in gutenberg.fileids():
        num_chars = len(gutenberg.raw(fileid))
        num_words = len(gutenberg.words(fileid))
        num_sents = len(gutenberg.sents(fileid))
        num_vocab = len(set(w.lower() for w in gutenberg.words(fileid)))
        print(round(num_chars/num_words), round(num_words/num_sents), round(num_words/num_vocab), fileid)


from django.conf.urls import url
from django.core.urlresolvers import reverse_lazy
from django.db.models import Q
from django.db.models.deletion import Collector
from django.utils.text import slugify
from django.views.generic import ListView, CreateView, UpdateView, DetailView, DeleteView

class DynamicListView(ListView):
    template_name = 'django_dynamic_views/dynamic_list_view.html'
    ajax_template_name = None
    field_names = None
    order_fields = None
    verbose_names = None
    convert_field_values = None
    search_fields = None
    filter_fields = None
    annotate_fields = None
    prefetch_related = []
    distinct = True

    def get_ajax_template_name(self):
        """
        Hook for returning the ajax template.

        Returns self.ajax_template_name if it exists, else the normal template.

        :return:
        """
        if self.ajax_template_name:
            return self.ajax_template_name

        return super(DynamicListView, self).get_template_names()

    def get_template_names(self):
        """
        When a request is made with AJAX, it returns the ajax_template_name
        Else the normal listview behaviour

        :return:
        """
        if self.request.is_ajax():
            return self.get_ajax_template_name()
        return super(DynamicListView, self).get_template_names()

    def get_field_names(self):
        """
        Return the field names defined in field_names attribute.
        If field_names does not exists, automatically get all the field names in the model

        :return: list of fieldnames
        """
        if self.field_names:
            return self.field_names
        return []

    def get_convert_field_values(self):
        """
        Dict with methods to be called on the view to convert a certain value

        :return: method name
        """
        if self.convert_field_values:
            return self.convert_field_values
        else:
            return {}

    def get_order_fields(self):
        """
        Return the field names defined in order_fields attribute.

        All the field that a user can order on. If not specified it returns all
         the fields that are defined in get_field_names that are present in
         the model.

        :return: list of field names
        """
        if self.order_fields:
            return self.order_fields
        return []

    def get_field_verbose_names(self):
        """
        Returns a dict with the verbose name of a field.
        E.g.:
        { 'name': _("Name"), 'max_value': _("Maximum value") }

        :return: dict with field -> verbose name mapping
        """
        if self.verbose_names:
            return self.verbose_names
        else:
            field_verbose_names = {}
            for name in self.get_field_names():
                field_verbose_names[name] = name

            return field_verbose_names

    def get_search_fields(self):
        """
        Hook to returns all the fields where can be searched in. The fields shall
        be suffixed with __icontains in the query

        :return: All the field where can be searched in
        """
        if self.search_fields:
            return self.search_fields
        else:
            return False

    @property
    def get_paginate_url(self):
        """
        The url it should paginate on. By default an empty string

        :return: string url
        """
        return ''

    def get_paginate_by(self, queryset):
        """
        Returns the numbers of pages per page in the list.
        First tries the GET parameter, then the value defined
        in the class attribute

        :return:
        """

        return self.request.GET.get('paginate_by', self.paginate_by)

    @property
    def search_phrase(self):
        """
        Propery method to determine the search phrase.

        :return: string search phrase
        """
        if self.request.GET.get('search_phrase') or self.request.GET.get('search_phrase') == '':
            return self.request.GET.get('search_phrase')

        return ''

    def add_queryset_search(self, queryset):
        """
        Modifies the query set with the search parameter.
        Creates an OR filter argument for every self.search_fields with the searchphrase.

        :param queryset: current queryset
        :return: modified queryset
        """
        if self.search_phrase:
            queries = [Q(**{'{}__{}'.format(search_field, 'icontains'): self.search_phrase}) for search_field in
                       self.get_search_fields()]

            # Set up the query
            query = Q()

            # Or the Q object with the ones remaining in the list
            for item in queries:
                query |= item

            queryset = queryset.filter(query)

        return queryset

    @property
    def order_by(self):
        """
        Propery method to determine the order by.
        First check if it is used in the url, then retrieve the user setting and else it is an empty string

        :return: string order by
        """
        order_by = self.request.GET.get('order_by', None)
        if order_by in self.get_field_names():
            if order_by in self.get_order_fields():
                if self.request.GET.get('sort') == 'DESC':
                    return '-%s' % order_by
                else:
                    return order_by

        return ''

    def add_queryset_ordering(self, query_set):
        """
        Sets the ordering on a query.

        :param query_set:
        :return: modified queryset
        """
        if self.order_by:
            return query_set.order_by(self.order_by)
        else:
            return query_set

    def get_filter_fields(self):
        """
        Hook to determine the filter fields.  The format it expects
        is requires a tuple dict. The first argument is the key used in the database
        and to be used for grouping, the other is the name the user sees in the UI

        *Example*

        ::

            (
                ('category__pk', 'category__name'),
                ('author__pk', 'author__name'),
            )

        """
        return self.filter_fields or []

    def get_filter_values(self):
        """
        Queries the database for the values that shall be used in the filtering dropdowns

        :returns list with tuples with the first argument the filter key and the second the value used for
        displaying in the UI
        """
        filter_values = []

        for filter_key, filter_name in self.get_filter_fields():
            values = [(o[filter_key], o[filter_name]) for o in
                      self.get_queryset().values(filter_key, filter_name).order_by(filter_key)]

            values.sort(key=lambda tup: tup[1])  # Sort on the filter_name

            sel_key = self.filter_kwargs.get(filter_key, '')
            selected_verbose = ''
            if sel_key:
                selected_verbose = dict(values).get(sel_key)
                if not selected_verbose:
                    try:
                        selected_verbose = dict(values).get(int(sel_key))
                    except Exception as e:
                        pass

            filter_values.append(
                (filter_key, self.verbose_names.get(filter_name), values, selected_verbose)
            )

        return filter_values

    @property
    def filter_kwargs(self):
        """
        Helper method to create the keyword arguments used in the queryset to actual filter the list
        """
        filter_kwargs = {}

        for filter_key, filter_name in self.get_filter_fields():
            filter_value = self.request.GET.get('filter-{}'.format(filter_key))
            if filter_value and filter_value != '---':
                filter_kwargs[filter_key] = str(filter_value)

        return filter_kwargs

    def add_queryset_filtering(self, queryset):
        """
        Modifies the queryset with the filtering of the queryset

        :param queryset:
        :returns modified queryset
        """

        if self.filter_kwargs:
            queryset = queryset.filter(**self.filter_kwargs)

        return queryset

    def add_queryset_annotating(self, queryset):
        if self.annotate_fields:
            queryset = queryset.annotate(**self.annotate_fields)

        return queryset

    def get_queryset(self):
        """
        Modifies the query set with all the magic this class contains
        We will add searching, ordering and filtering, as well add distinct and
        prefetch related to the queryset
        """
        queryset = super(DynamicListView, self).get_queryset()
        queryset = self.add_queryset_search(queryset)
        queryset = self.add_queryset_filtering(queryset)
        queryset = self.add_queryset_annotating(queryset)
        queryset = self.add_queryset_ordering(queryset)

        if self.distinct:
            queryset = queryset.distinct()

        if self.prefetch_related:
            queryset = queryset.prefetch_related(*self.prefetch_related)

        return queryset

    @staticmethod
    def nice_page_range(page_range, current_page):
        """
        Returns a page range with only the needed pages in it.

        :param page_range:
        :param current_page:
        :return:
        """
        display_around = 2
        if len(page_range) > display_around:
            # determine new start in range
            start = current_page - display_around
            if start < 1:
                start = 1
            # determine new end in range
            end = current_page + display_around + 1
            if end > len(page_range):
                end = len(page_range) + 1
            page_range = range(start, end)
        return page_range

    def get_context_data(self, **kwargs):
        context = super(DynamicListView, self).get_context_data(**kwargs)
        context['field_names'] = self.get_field_names()
        context['field_verbose_names'] = self.get_field_verbose_names()
        context['order_fields'] = self.get_order_fields()
        context['convert_field_values'] = self.get_convert_field_values()
        context['filter_fields'] = self.get_filter_fields()
        context['filter_values'] = self.get_filter_values()
        context['filter_kwargs'] = self.filter_kwargs
        context['num_fields'] = len(self.get_field_names())
        context['paginate_url'] = self.get_paginate_url
        context['search'] = True if self.get_search_fields() else False
        context['search_phrase'] = self.search_phrase
        if context['paginator']:
            context['nice_page_range'] = self.nice_page_range(context['paginator'].page_range,
                                                              context['page_obj'].number)

        if self.order_by:
            context['order_by'] = self.order_by[1:] if self.order_by[0] == '-' else self.order_by
            context['sort'] = 'ASC' if self.order_by[0] == '-' else 'DESC'

        return context

class AdminDynamicListView(DynamicListView):
    template_name = 'django_dynamic_views/admin_dynamic_list_view.html'
    title = None

    links = ['create', 'read', 'update', 'delete']
    create_text = None
    create_link = None
    read_link = None
    update_link = None
    delete_link = None

    @property
    def link_names(self):
        return {link: 'get_{}_link'.format(link) for link in self.links}

    def object_links(self):
        return [link for link in self.links if link not in ('create', 'list', )]

    def get_update_link(self):
        if self.update_link:
            return self.update_link
        else:
            return False

    def get_read_link(self):
        if self.read_link:
            return self.read_link
        else:
            return False

    def get_create_link(self):
        if self.create_link:
            return self.create_link
        else:
            return False

    def get_delete_link(self):
        if self.delete_link:
            return self.delete_link
        else:
            return False

    def get_title(self):
        if self.title:
            return self.title
        else:
            return ''

    def get_create_text(self):
        if self.create_text:
            return self.create_text
        else:
            return 'New'

    def get_context_data(self, **kwargs):
        context = super(AdminDynamicListView, self).get_context_data(**kwargs)
        context['links'] = self.links
        context['object_links'] = self.object_links
        context['link_names'] = self.link_names
        context['create_link'] = self.get_create_link()
        context['read_link'] = self.get_read_link()
        context['update_link'] = self.get_update_link()
        context['delete_link'] = self.get_delete_link()
        context['title'] = self.get_title()
        context['create_text'] = self.get_create_text()
        return context

class DynamicReadView(DetailView):
    template_name = 'django_dynamic_views/dynamic_read_view.html'
    field_names = None
    verbose_names = None

    def get_field_names(self):
        """
        Return the field names defined in field_names attribute.

        :return: list of fieldnames
        """
        if self.field_names:
            return self.field_names
        return []

    def get_field_verbose_names(self):
        """
        Returns a dict with the verbose name of a field.
        E.g.:
        { 'name': _("Name"), 'max_value': _("Maximum value") }

        :return: dict with field -> verbose name mapping
        """
        if self.verbose_names:
            return self.verbose_names
        else:
            field_verbose_names = {}
            for name in self.get_field_names():
                field_verbose_names[name] = name

            return field_verbose_names

    def get_context_data(self, **kwargs):
        context = super(DynamicReadView, self).get_context_data(**kwargs)
        context['field_names'] = self.get_field_names()
        context['field_verbose_names'] = self.get_field_verbose_names()
        return context

class DynamicDeleteView(DeleteView):
    template_name = 'django_dynamic_views/dynamic_delete_form.html'

    def get_context_data(self, **kwargs):
        context = super(DynamicDeleteView, self).get_context_data(**kwargs)

        collector = Collector(using='default') # or specific database
        collector.collect([self.object])
        to_delete = collector.instances_with_model()
        context['to_delete_list'] = []

        for x, y in to_delete:
            context['to_delete_list'].append((x.__name__, y,))

        return context

class DynamicUpdateView(UpdateView):
    template_name = 'django_dynamic_views/dynamic_form.html'
    field_names = None

    @property
    def fields(self):
        return self.field_names

class DynamicCreateView(CreateView):
    template_name = 'django_dynamic_views/dynamic_form.html'
    field_names = None

    @property
    def fields(self):
        return self.field_names

class DynamicCRUDView(object):
    model = None
    links = ['list', 'update', 'read', 'delete', 'create']

    field_names = ['pk']
    verbose_names = None

    update_kwargs = 'pk'
    update_kwargs_regexp = '(?P<pk>[-\w]+)'
    read_kwargs = 'pk'
    read_kwargs_regexp = '(?P<pk>[-\w]+)'
    delete_kwargs = 'pk'
    delete_kwargs_regexp = '(?P<pk>[-\w]+)'

    def get_view_kwargs(self):
        return {'model': self.model}

    def get_list_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        kwargs['links'] = self.links
        kwargs['verbose_names'] = self.verbose_names
        kwargs['paginate_by'] = getattr(self, 'paginate_by', None)

        for link in self.links:
            if link != 'list':
                kwargs['{}_link'.format(link)] = self.link_name(link)

        return kwargs

    def get_read_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        return kwargs

    def get_update_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        kwargs['success_url'] = reverse_lazy(self.link_name('list'))
        return kwargs

    def get_create_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['field_names'] = self.field_names
        kwargs['success_url'] = reverse_lazy(self.link_name('list'))
        return kwargs

    def get_delete_view_kwargs(self):
        kwargs = self.get_view_kwargs()
        kwargs['success_url'] = reverse_lazy(self.link_name('list'))
        return kwargs

    @property
    def list_class(self):
        return AdminDynamicListView.as_view(**self.get_list_view_kwargs())

    @property
    def update_class(self):
        return DynamicUpdateView.as_view(**self.get_update_view_kwargs())

    @property
    def read_class(self):
        return DynamicReadView.as_view(**self.get_read_view_kwargs())

    @property
    def delete_class(self):
        return DynamicDeleteView.as_view(**self.get_delete_view_kwargs())

    @property
    def create_class(self):
        return DynamicCreateView.as_view(**self.get_create_view_kwargs())

    @property
    def model_name(self):
        return slugify(self.model.__name__)

    def link_name(self, link_name):
        return '{}_{}'.format(self.model_name, link_name)

    def urls(self):
        urls = []
        for link in self.links:
            if hasattr(self, '{}_link'.format(link)):
                link_name = getattr(self, '{}_link'.format(link))
            else:
                link_name = link

            url_check = r'{}/{}/'.format(self.model_name, link_name)

            if hasattr(self, '{}_kwargs'.format(link)):
                link_kwargs = getattr(self, '{}_kwargs_regexp'.format(link))
                url_check += '{}/'.format(link_kwargs)

            # Add start and end of line to regex pattern
            url_check = '^%s$' % url_check

            action_cls = getattr(self, '{}_class'.format(link))
            urls.append(url(url_check, action_cls, name=self.link_name(link)))

        return urls


""" Tests covering the pipeline schema code.
"""

import json
import os
import shutil
import tempfile
import unittest
from unittest import mock

import pytest
import requests
import yaml

import nf_core.create
import nf_core.schema

from .utils import with_temporary_file, with_temporary_folder

class TestSchema(unittest.TestCase):
    """Class for schema tests"""

    def setUp(self):
        """Create a new PipelineSchema object"""
        self.schema_obj = nf_core.schema.PipelineSchema()
        self.root_repo_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

        # Create a test pipeline in temp directory
        self.tmp_dir = tempfile.mkdtemp()
        self.template_dir = os.path.join(self.tmp_dir, "wf")
        create_obj = nf_core.create.PipelineCreate(
            "testpipeline", "", "", outdir=self.template_dir, no_git=True, plain=True
        )
        create_obj.init_pipeline()

        self.template_schema = os.path.join(self.template_dir, "nextflow_schema.json")

    def tearDown(self):
        if os.path.exists(self.tmp_dir):
            shutil.rmtree(self.tmp_dir)

    def test_load_lint_schema(self):
        """Check linting with the pipeline template directory"""
        self.schema_obj.get_schema_path(self.template_dir)
        self.schema_obj.load_lint_schema()

    def test_load_lint_schema_nofile(self):
        """Check that linting raises properly if a non-existant file is given"""
        with pytest.raises(AssertionError):
            self.schema_obj.get_schema_path("fake_file")

    def test_load_lint_schema_notjson(self):
        """Check that linting raises properly if a non-JSON file is given"""
        self.schema_obj.get_schema_path(os.path.join(self.template_dir, "nextflow.config"))
        with pytest.raises(AssertionError):
            self.schema_obj.load_lint_schema()

    @with_temporary_file
    def test_load_lint_schema_noparams(self, tmp_file):
        """
        Check that linting raises properly if a JSON file is given without any params
        """
        # write schema to a temporary file
        with open(tmp_file.name, "w") as fh:
            json.dump({"type": "fubar"}, fh)
        self.schema_obj.get_schema_path(tmp_file.name)
        with pytest.raises(AssertionError):
            self.schema_obj.load_lint_schema()

    def test_get_schema_path_dir(self):
        """Get schema file from directory"""
        self.schema_obj.get_schema_path(self.template_dir)

    def test_get_schema_path_path(self):
        """Get schema file from a path"""
        self.schema_obj.get_schema_path(self.template_schema)

    def test_get_schema_path_path_notexist(self):
        """Get schema file from a path"""
        with pytest.raises(AssertionError):
            self.schema_obj.get_schema_path("fubar", local_only=True)

    def test_get_schema_path_name(self):
        """Get schema file from the name of a remote pipeline"""
        self.schema_obj.get_schema_path("atacseq")

    def test_get_schema_path_name_notexist(self):
        """
        Get schema file from the name of a remote pipeline
        that doesn't have a schema file
        """
        with pytest.raises(AssertionError):
            self.schema_obj.get_schema_path("exoseq")

    def test_load_schema(self):
        """Try to load a schema from a file"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()

    def test_schema_docs(self):
        """Try to generate Markdown docs for a schema from a file"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        docs = self.schema_obj.print_documentation()
        assert self.schema_obj.schema["title"] in docs
        assert self.schema_obj.schema["description"] in docs
        for definition in self.schema_obj.schema.get("definitions", {}).values():
            assert definition["title"] in docs
            assert definition["description"] in docs

    @with_temporary_file
    def test_save_schema(self, tmp_file):
        """Try to save a schema"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()

        # Make a temporary file to write schema to
        self.schema_obj.schema_filename = tmp_file.name
        self.schema_obj.save_schema()

    @with_temporary_file
    def test_load_input_params_json(self, tmp_file):
        """Try to load a JSON file with params for a pipeline run"""
        # write schema to a temporary file
        with open(tmp_file.name, "w") as fh:
            json.dump({"input": "fubar"}, fh)
        self.schema_obj.load_input_params(tmp_file.name)

    @with_temporary_file
    def test_load_input_params_yaml(self, tmp_file):
        """Try to load a YAML file with params for a pipeline run"""
        # write schema to a temporary file
        with open(tmp_file.name, "w") as fh:
            yaml.dump({"input": "fubar"}, fh)
        self.schema_obj.load_input_params(tmp_file.name)

    def test_load_input_params_invalid(self):
        """Check failure when a non-existent file params file is loaded"""
        with pytest.raises(AssertionError):
            self.schema_obj.load_input_params("fubar")

    def test_validate_params_pass(self):
        """Try validating a set of parameters against a schema"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        self.schema_obj.input_params = {"input": "fubar.csv", "outdir": "results/"}
        assert self.schema_obj.validate_params()

    def test_validate_params_fail(self):
        """Check that False is returned if params don't validate against a schema"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        self.schema_obj.input_params = {"fubar": "input"}
        assert not self.schema_obj.validate_params()

    def test_validate_schema_pass(self):
        """Check that the schema validation passes"""
        # Load the template schema
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.load_schema()
        self.schema_obj.validate_schema(self.schema_obj.schema)

    def test_validate_schema_fail_noparams(self):
        """Check that the schema validation fails when no params described"""
        self.schema_obj.schema = {"type": "invalidthing"}
        with pytest.raises(AssertionError):
            self.schema_obj.validate_schema(self.schema_obj.schema)

    def test_validate_schema_fail_duplicate_ids(self):
        """
        Check that the schema validation fails when we have duplicate IDs in definition subschema
        """
        self.schema_obj.schema = {
            "definitions": {"groupOne": {"properties": {"foo": {}}}, "groupTwo": {"properties": {"foo": {}}}},
            "allOf": [{"$ref": "#/definitions/groupOne"}, {"$ref": "#/definitions/groupTwo"}],
        }
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.validate_schema(self.schema_obj.schema)
        assert exc_info.value.args[0] == "Duplicate parameter found in schema `definitions`: `foo`"

    def test_validate_schema_fail_missing_def(self):
        """
        Check that the schema validation fails when we a definition in allOf is not in definitions
        """
        self.schema_obj.schema = {
            "definitions": {"groupOne": {"properties": {"foo": {}}}, "groupTwo": {"properties": {"bar": {}}}},
            "allOf": [{"$ref": "#/definitions/groupOne"}],
        }
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.validate_schema(self.schema_obj.schema)
        assert exc_info.value.args[0] == "Definition subschema `groupTwo` not included in schema `allOf`"

    def test_validate_schema_fail_unexpected_allof(self):
        """
        Check that the schema validation fails when we an unrecognised definition is in allOf
        """
        self.schema_obj.schema = {
            "definitions": {"groupOne": {"properties": {"foo": {}}}, "groupTwo": {"properties": {"bar": {}}}},
            "allOf": [
                {"$ref": "#/definitions/groupOne"},
                {"$ref": "#/definitions/groupTwo"},
                {"$ref": "#/definitions/groupThree"},
            ],
        }
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.validate_schema(self.schema_obj.schema)
        assert exc_info.value.args[0] == "Subschema `groupThree` found in `allOf` but not `definitions`"

    def test_make_skeleton_schema(self):
        """Test making a new schema skeleton"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.pipeline_manifest["name"] = "nf-core/test"
        self.schema_obj.pipeline_manifest["description"] = "Test pipeline"
        self.schema_obj.make_skeleton_schema()
        self.schema_obj.validate_schema(self.schema_obj.schema)

    def test_get_wf_params(self):
        """Test getting the workflow parameters from a pipeline"""
        self.schema_obj.schema_filename = self.template_schema
        self.schema_obj.get_wf_params()

    def test_prompt_remove_schema_notfound_config_returntrue(self):
        """Remove unrecognised params from the schema"""
        self.schema_obj.pipeline_params = {"foo": "bar"}
        self.schema_obj.no_prompts = True
        assert self.schema_obj.prompt_remove_schema_notfound_config("baz")

    def test_prompt_remove_schema_notfound_config_returnfalse(self):
        """Do not remove unrecognised params from the schema"""
        self.schema_obj.pipeline_params = {"foo": "bar"}
        self.schema_obj.no_prompts = True
        assert not self.schema_obj.prompt_remove_schema_notfound_config("foo")

    def test_remove_schema_notfound_configs(self):
        """Remove unrecognised params from the schema"""
        self.schema_obj.schema = {
            "properties": {"foo": {"type": "string"}, "bar": {"type": "string"}},
            "required": ["foo"],
        }
        self.schema_obj.pipeline_params = {"bar": True}
        self.schema_obj.no_prompts = True
        params_removed = self.schema_obj.remove_schema_notfound_configs()
        assert len(self.schema_obj.schema["properties"]) == 1
        assert "required" not in self.schema_obj.schema
        assert len(params_removed) == 1
        assert "foo" in params_removed

    def test_remove_schema_notfound_configs_childschema(self):
        """
        Remove unrecognised params from the schema,
        even when they're in a group
        """
        self.schema_obj.schema = {
            "definitions": {
                "subSchemaId": {
                    "properties": {"foo": {"type": "string"}, "bar": {"type": "string"}},
                    "required": ["foo"],
                }
            }
        }
        self.schema_obj.pipeline_params = {"bar": True}
        self.schema_obj.no_prompts = True
        params_removed = self.schema_obj.remove_schema_notfound_configs()
        assert len(self.schema_obj.schema["definitions"]["subSchemaId"]["properties"]) == 1
        assert "required" not in self.schema_obj.schema["definitions"]["subSchemaId"]
        assert len(params_removed) == 1
        assert "foo" in params_removed

    def test_add_schema_found_configs(self):
        """Try adding a new parameter to the schema from the config"""
        self.schema_obj.pipeline_params = {"foo": "bar"}
        self.schema_obj.schema = {"properties": {}}
        self.schema_obj.no_prompts = True
        params_added = self.schema_obj.add_schema_found_configs()
        assert len(self.schema_obj.schema["properties"]) == 1
        assert len(params_added) == 1
        assert "foo" in params_added

    def test_build_schema_param_str(self):
        """Build a new schema param from a config value (string)"""
        param = self.schema_obj.build_schema_param("foo")
        assert param == {"type": "string", "default": "foo"}

    def test_build_schema_param_bool(self):
        """Build a new schema param from a config value (bool)"""
        param = self.schema_obj.build_schema_param("True")
        assert param == {"type": "boolean", "default": True}

    def test_build_schema_param_int(self):
        """Build a new schema param from a config value (int)"""
        param = self.schema_obj.build_schema_param("12")
        assert param == {"type": "integer", "default": 12}

    def test_build_schema_param_float(self):
        """Build a new schema param from a config value (float)"""
        param = self.schema_obj.build_schema_param("12.34")
        assert param == {"type": "number", "default": 12.34}

    def test_build_schema(self):
        """
        Build a new schema param from a pipeline
        Run code to ensure it doesn't crash. Individual functions tested separately.
        """
        param = self.schema_obj.build_schema(self.template_dir, True, False, None)

    @with_temporary_folder
    def test_build_schema_from_scratch(self, tmp_dir):
        """
        Build a new schema param from a pipeline with no existing file
        Run code to ensure it doesn't crash. Individual functions tested separately.

        Pretty much a copy of test_launch.py test_make_pipeline_schema
        """
        test_pipeline_dir = os.path.join(tmp_dir, "wf")
        shutil.copytree(self.template_dir, test_pipeline_dir)
        os.remove(os.path.join(test_pipeline_dir, "nextflow_schema.json"))

        param = self.schema_obj.build_schema(test_pipeline_dir, True, False, None)

    @mock.patch("requests.post")
    def test_launch_web_builder_timeout(self, mock_post):
        """Mock launching the web builder, but timeout on the request"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.Timeout()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    @mock.patch("requests.post")
    def test_launch_web_builder_connection_error(self, mock_post):
        """Mock launching the web builder, but get a connection error"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.ConnectionError()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    @mock.patch("requests.post")
    def test_get_web_builder_response_timeout(self, mock_post):
        """Mock checking for a web builder response, but timeout on the request"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.Timeout()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    @mock.patch("requests.post")
    def test_get_web_builder_response_connection_error(self, mock_post):
        """Mock checking for a web builder response, but get a connection error"""
        # Define the behaviour of the request get mock
        mock_post.side_effect = requests.exceptions.ConnectionError()
        with pytest.raises(AssertionError):
            self.schema_obj.launch_web_builder()

    def mocked_requests_post(**kwargs):
        """Helper function to emulate POST requests responses from the web"""

        class MockResponse:
            def __init__(self, data, status_code):
                self.status_code = status_code
                self.content = json.dumps(data)

        if kwargs["url"] == "invalid_url":
            return MockResponse({}, 404)

        if kwargs["url"] == "valid_url_error":
            response_data = {"status": "error", "api_url": "foo", "web_url": "bar"}
            return MockResponse(response_data, 200)

        if kwargs["url"] == "valid_url_success":
            response_data = {"status": "recieved", "api_url": "https://nf-co.re", "web_url": "https://nf-co.re"}
            return MockResponse(response_data, 200)

    @mock.patch("requests.post", side_effect=mocked_requests_post)
    def test_launch_web_builder_404(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_url = "invalid_url"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.launch_web_builder()
        assert exc_info.value.args[0] == "Could not access remote API results: invalid_url (HTML 404 Error)"

    @mock.patch("requests.post", side_effect=mocked_requests_post)
    def test_launch_web_builder_invalid_status(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_url = "valid_url_error"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.launch_web_builder()
        assert exc_info.value.args[0].startswith("Pipeline schema builder response not recognised")

    @mock.patch("requests.post", side_effect=mocked_requests_post)
    @mock.patch("requests.get")
    @mock.patch("webbrowser.open")
    def test_launch_web_builder_success(self, mock_post, mock_get, mock_webbrowser):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_url = "valid_url_success"
        # Assertion error comes from the get_web_builder_response() function
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.launch_web_builder()
        assert exc_info.value.args[0].startswith("Could not access remote API results: https://nf-co.re")

    def mocked_requests_get(*args, **kwargs):
        """Helper function to emulate GET requests responses from the web"""

        class MockResponse:
            def __init__(self, data, status_code):
                self.status_code = status_code
                self.content = json.dumps(data)

        if args[0] == "invalid_url":
            return MockResponse({}, 404)

        if args[0] == "valid_url_error":
            response_data = {"status": "error", "message": "testing URL failure"}
            return MockResponse(response_data, 200)

        if args[0] == "valid_url_waiting":
            response_data = {"status": "waiting_for_user", "message": "testing URL waiting"}
            return MockResponse(response_data, 200)

        if args[0] == "valid_url_saved":
            response_data = {"status": "web_builder_edited", "message": "testing saved", "schema": {"foo": "bar"}}
            return MockResponse(response_data, 200)

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_404(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "invalid_url"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.get_web_builder_response()
        assert exc_info.value.args[0] == "Could not access remote API results: invalid_url (HTML 404 Error)"

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_error(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "valid_url_error"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.get_web_builder_response()
        assert exc_info.value.args[0] == "Got error from schema builder: 'testing URL failure'"

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_waiting(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "valid_url_waiting"
        assert self.schema_obj.get_web_builder_response() is False

    @mock.patch("requests.get", side_effect=mocked_requests_get)
    def test_get_web_builder_response_saved(self, mock_post):
        """Mock launching the web builder"""
        self.schema_obj.web_schema_build_api_url = "valid_url_saved"
        with pytest.raises(AssertionError) as exc_info:
            self.schema_obj.get_web_builder_response()
        assert exc_info.value.args[0].startswith("Response from schema builder did not pass validation")
        assert self.schema_obj.schema == {"foo": "bar"}


import os
import cv2
import numpy as np
import app
from orangecontrib.imageanalytics.image_embedder import ImageEmbedder
import pickle
import keras.backend as k
k.set_image_dim_ordering('th')

APP_ROOT = os.path.dirname(os.path.abspath(__file__))

def get_result(image_name):
    print(image_name)
    model = pickle.load(open('oil2.pkcls', 'rb'))
    print("model loaded")
    image_file_paths = [image_name]
    print(image_file_paths)
    with ImageEmbedder(model='vgg16', layer='penultimate') as embedder:
        embeddings = embedder(image_file_paths)
    print(embeddings.shape)
    print("embedded")
    pred_ind = model(embeddings)
    pred_cls = [model.domain.class_var.str_val(i) for i in pred_ind]
    print(pred_ind)
    print(pred_cls)
    k.clear_session()
    return pred_cls


class DecodeWays:
    #Without Memo
    def numDecodings(self, s: str) -> int:
        return self.numDecodingsInner(s, 0)

    def numDecodingsInner(self, s, index):
        # Ideally, we should be able to do this if not for the '0' condition that's required
        if index == len(s):  # or index==len[s]-1:
            return 1
        if s[index] == '0':
            return 0
        if index == len(s) - 1:
            return 1

        ans = self.numDecodingsInner(s, index + 1)
        if int(s[index:index + 2]) <= 26:
            ans += self.numDecodingsInner(s, index + 2)

        return ans

    #With memo
    def numDecodings(self, s: str) -> int:
        memo = {}
        return self.numDecodingsInner(s, 0, memo)

    def numDecodingsInner(self, s, index, memo):
        # Ideally, we should be able to do this if not for the '0' condition that's required
        if index == len(s):  # or index==len[s]-1:
            return 1
        if s[index] == '0':
            return 0
        if index == len(s) - 1:
            return 1

        if index in memo:
            return memo[index]

        ans = self.numDecodingsInner(s, index + 1, memo)
        if int(s[index:index + 2]) <= 26:
            ans += self.numDecodingsInner(s, index + 2, memo)
        memo[index] = ans

        return memo[index]

if __name__ == '__main__':
    init = DecodeWays()
    print(init.numDecodings("12"))  # 2
    print(init.numDecodings("226"))  # 3
    print(init.numDecodings("132226"))  # 3


from django.shortcuts import render
from django.utils import timezone
from django.shortcuts import render, get_object_or_404
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from django.http import Http404
from ..forms import PostForm
from ..models import Post
from ..models import Category

# Create your views here.
def post_list(request):
    viewname = 'blog'
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
    entrys = posts.filter(tag__contains = 'Spikzettel')
    return render(request, 'blog/post_list.html', {'posts': posts,'viewname':viewname,'entrys':entrys,'box_title':'Python-Spikzettel'})

def home_list(request):
    viewname = 'home'
    posts = Post.objects.filter(category__name='Home').filter(published_date__lte=timezone.now()).order_by('-published_date')
    return render(request, 'blog/home_list.html', {'posts': posts,'viewname':viewname})

def projekt_list(request):
    viewname = 'projekte'
    posts = Post.objects.filter(category__name='Projekt').filter(published_date__lte=timezone.now()).order_by('-created_date')
    return render(request, 'blog/home_list.html', {'posts': posts,'viewname':viewname})

def post_detail(request, pk, title="ohne"):
    codes = False
    post = get_object_or_404(Post, pk=pk)
    if ("code:" in post.text):
        codes = post.text.split("--")
    return render(request, 'blog/post_detail.html', {'post': post, 'codes': codes})

def title_detail(request, pk, title):
    codes = False
    post = get_object_or_404(Post, pk=pk)
    if ("code:" in post.text):
        codes = post.text.split("--")
    return render(request, 'blog/post_detail.html', {'post': post, 'codes': codes})

@login_required
def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

@login_required
def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

@login_required
def post_remove(request, pk):
    post = get_object_or_404(Post, pk=pk)
    post.delete()
    return redirect('post_list')

def kontakt(request):
    viewname = 'kontakt'
    post = get_object_or_404(Post, tag__contains = 'Kontakt')
    return render(request, 'blog/post_detail.html', {'post': post,'viewname':viewname})


load("//:def.bzl", "project")

def _minikube_start_impl(ctx):
    executable = ctx.actions.declare_file(ctx.attr.name)
    contents = """
        set -o errexit
        export MINIKUBE="{minikube}"
        export K8S_VERSION="${{K8S_VERSION:-{k8s_version}}}"
        export VM_CPUS="${{VM_CPUS:-{vm_cpus}}}"
        export VM_MEMORY="${{VM_MEMORY:-{vm_memory}}}"
        export ISO_URL="${{ISO_URL:-{iso_url}}}"
        export VM_DISK_SIZE="${{VM_DISK_SIZE:-{vm_disk_size}}}"
        "{script}"
    """.format(
        minikube = ctx.executable._minikube.path,
        k8s_version = ctx.attr.k8s_version,
        vm_cpus = ctx.attr.vm_cpus,
        vm_memory = ctx.attr.vm_memory,
        vm_disk_size = ctx.attr.vm_disk_size,
        iso_url = ctx.attr.iso_url,
        script = ctx.executable._script.path,
    )
    ctx.actions.write(executable, contents, is_executable = True)
    runfiles = [
        ctx.executable._minikube,
        ctx.executable._script,
    ]
    return [DefaultInfo(
        executable = executable,
        runfiles = ctx.runfiles(files = runfiles),
    )]

attrs = {
    "k8s_version": attr.string(
        default = "v{}".format(project.kubernetes.version),
    ),
    "vm_cpus": attr.string(
        default = "4",
    ),
    "vm_memory": attr.string(
        default = "{}".format(1024 * 6),
    ),
    "vm_disk_size": attr.string(
        default = "40g",
    ),
    "iso_url": attr.string(
        default = "https://github.com/kubernetes/minikube/releases/download/v1.6.0/minikube-v1.6.0.iso",
    ),
    "_minikube": attr.label(
        allow_single_file = True,
        cfg = "host",
        default = "@minikube//:minikube",
        executable = True,
    ),
}

minikube_start_binary = rule(
    implementation = _minikube_start_impl,
    attrs = dict({
        "_script": attr.label(
            allow_single_file = True,
            cfg = "host",
            default = "//dev/minikube:start.sh",
            executable = True,
        ),
    }, **attrs),
    executable = True,
)

minikube_delete_binary = rule(
    implementation = _minikube_start_impl,
    attrs = dict({
        "_script": attr.label(
            allow_single_file = True,
            cfg = "host",
            default = "//dev/minikube:delete.sh",
            executable = True,
        ),
    }, **attrs),
    executable = True,
)


import streamlit as st
import numpy as np
import pandas as pd
from sklearn import datasets, neighbors

st.set_page_config(layout='wide')

st.header('IRIS FLOWER PREDICTION')

about = st.expander('About')
about.markdown("""
**This app predicts the Iris flower based on the settings adjusted by the user using the [KNN Classifier](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm) algorithm. The settings are adjusted based on tweaking the sepal length, sepal width,  petal length and petal width. The target flowers may be *Iris Setosa, Iris Versicolor or Iris Virginica.* The prediction is made using the [Iris Dataset in sklearn library](https://scikit-learn.org/stable/auto_examples/datasets/plot_iris_dataset.html)**
""")

iris = datasets.load_iris()
X = iris.data
Y  =iris.target
st.write('Target Guide')
st.write(iris.target_names)
st.markdown('---')
knn = neighbors.KNeighborsClassifier(11, weights='uniform')
knn.fit(X, Y)
predictions = {0: 'Iris Setosa',
                1: 'Iris Versicolor',
                2: 'Iris Virginica'
                }
st.sidebar.header('Adjust your flower settings')
s_len = st.sidebar.slider('SEPAL LENGTH', 4.0, 8.0, 4.7)
s_wid = st.sidebar.slider('SEPAL WIDTH', 2.5, 4.0, 3.0)
p_len = st.sidebar.slider('PETAL LENGTH', 1.0, 6.0, 3.0)
p_wid = st.sidebar.slider('PETAL WIDTH', 0.1, 3.0, 1.7)
data = {'sepal_length': s_len,
        'sepal_width': s_wid,
        'petal_length': p_len,
        'petal_width': p_wid
        }
input = pd.DataFrame(data, index=[0])

# if st.sidebar.button('PREDICT MY FLOWER'):
st.write('PREDICTED: ' + predictions[knn.predict(input)[0]])
st.write('PREDICTION SET FOR EACH TYPE: ')
st.write(knn.predict_proba(input))