import core.config as config

from core.stats import StatisticFile
from core.translation import t, lang
from utils.utils import splitpath
from utils.date import format_date, now
from core.transition import current_user
from core import httpstatus
from core import Node
from core import db

q = db.query

try:
    from reportlab.platypus import Paragraph, XPreformatted, BaseDocTemplate, SimpleDocTemplate, FrameBreak, Table, TableStyle, Image as PdfImage, Frame, PageBreak, PageTemplate
    from reportlab.lib import colors
    from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
    from reportlab.lib.units import cm
    from reportlab.rl_config import defaultPageSize
    from reportlab.pdfgen import canvas
    reportlab = 1
except:
    reportlab = 0

def getPeriod(filename):
    filename = splitpath(filename)[-1]
    period = filename[:-4].split("_")[2]
    type = filename[:-4].split("_")[3]
    return period, type

def getContent(req, ids):
    if len(ids) > 0:
        ids = ids[0]

    user = current_user
    node = q(Node).get(ids)

    if "statsaccess" in user.hidden_edit_functions or not node.has_write_access():
        req.setStatus(httpstatus.HTTP_FORBIDDEN)
        return req.getTAL("web/edit/edit.html", {}, macro="access_error")

    if req.params.get("style", "") == "popup":
        getPopupWindow(req, ids)
        return ""

    statfiles = {}
    p = ""

    for file in node.files:
        if file.filetype == "statistic":
            period, type = getPeriod(file.abspath)
            if period > p:
                p = period

            if type not in statfiles.keys():
                statfiles[type] = {}

            if period not in statfiles[type].keys():
                statfiles[type][period] = []
            statfiles[type][period].append(file)

    v = {}
    v["id"] = ids
    v["files"] = statfiles
    v["current_period"] = req.params.get("select_period", "frontend_" + p)
    if len(statfiles) > 0:
        v["current_file"] = StatisticFile(statfiles[v["current_period"].split("_")[0]][v["current_period"].split("_")[1]][0])
    else:
        v["current_file"] = StatisticFile(None)
    v["nodename"] = node.name
    v["csrf"] = req.csrf_token.current_token
    return req.getTAL("web/edit/modules/statsaccess.html", v, macro="edit_stats")

def getPopupWindow(req, ids):
    v = {}
    v["id"] = ids
    if "update" in req.params:
        v["action"] = "doupdate"

    elif req.params.get("action") == "do":  # do action and refresh current month
        raise NotImplementedError("does not work, must be fixed")
        collection = q(Node).get(req.params.get("id"))
        collection.set("system.statsrun", "1")
        #buildStat(collection, ustr(format_date(now(), "yyyy-mm")))
        req.writeTAL("web/edit/modules/statsaccess.html", {}, macro="edit_stats_result")
        collection.removeAttribute("system.statsrun")
        return

    else:
        v["action"] = "showform"
        v["statsrun"] = q(Node).get(ids).get("system.statsrun")
        v["csrf"] = req.csrf_token.current_token
    req.writeTAL("web/edit/modules/statsaccess.html", v, macro="edit_stats_popup")

class StatsAccessPDF:

    def __init__(self, data, period, id, language):
        self.styleSheet = getSampleStyleSheet()
        self.stats = data
        self.period = period
        self.language = language
        self._pages = 1
        self.data = []
        self.collection = q(Node).get(id)

    def myPages(self, canvas, doc):
        doc.pageTemplate.frames = self.getStyle(self._pages)
        canvas.saveState()
        canvas.setFont('Helvetica', 8)
        canvas.restoreState()
        self._pages += 1

    def getStyle(self, page):
        frames = []

        if page == 1:  # first page
            # main header
            frames.append(Frame(1 * cm, 25.5 * cm, 19 * cm, 3 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            # top 10
            frames += self.getStatTop("frames")

        elif page == 2:  # page 2
            # main header pages >1
            frames.append(Frame(1 * cm, 27.5 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            # countries
            frames += self.getStatCountry("frames")

        elif page == 3:  # page 3
            # main header pages >1
            frames.append(Frame(1 * cm, 27.5 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            # date
            frames += self.getStatDate("frames")

        elif page == 4:  # page 4
            # main header pages >1
            frames.append(Frame(1 * cm, 27.5 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            # weekday
            frames += self.getStatDay("frames")

            # time
            frames += self.getStatTime("frames")

        return frames

    def getStatTop(self, type, namecut=0):
        # frames
        items = []
        d = self.stats.getIDs()
        max = float(d[0][1])
        if max == 0:
            max += 1
        if type == "frames":
            items.append(Frame(1 * cm, 24.0 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))  # header
            for i in range(0, 45):
                if i < len(d):
                    items.append(Frame(1 * cm,
                                       (22.9 - (i * 0.5)) * cm,
                                       8 * cm,
                                       25,
                                       leftPadding=0,
                                       rightPadding=0,
                                       id='normal',
                                       showBoundary=0))  # label
                    items.append(Frame(9 * cm,
                                       (23.0 - (i * 0.5)) * cm,
                                       d[i][1] * 280 / max,
                                       25,
                                       leftPadding=0,
                                       rightPadding=0,
                                       id='normal',
                                       showBoundary=0))  # bar
                    items.append(Frame(9 * cm + (d[i][1] * 280 / max) + 5, (22.9 - (i * 0.5)) * cm, 40,
                                       25, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))  # number

        # data
        if type == "data":
            items.append(Paragraph(t(self.language, "edit_stats_access"), self.chartheader))
            items.append((FrameBreak()))

            for i in range(0, 45):
                if i < len(d):
                    try:
                        nodename = q(Node).get(d[i][0]).name
                        suffix = " (" + ustr(d[i][0]) + ")"
                        n = nodename + suffix
                        if namecut > 0 and len(n) > namecut:
                            delta = len(n) - namecut
                            new_length = len(nodename) - delta - 3
                            n = nodename[0:new_length] + "..." + suffix
                    except:
                        n = ustr(d[i][0])
                    items.append(Paragraph(n, self.bv))
                    items.append((FrameBreak()))
                    items.append(PdfImage(config.basedir + "/web/img/stat_bar.png", width=d[i][1] * 280 / max, height=10))
                    items.append((FrameBreak()))
                    items.append(Paragraph(ustr(d[i][1]), self.bv))
                    items.append((FrameBreak()))
        return items

    def getStatCountry(self, type):
        items = []
        d = self.stats.getProgress('country')
        max = float(d[0]["max"])

        if type == "frames":
            # header country
            items.append(Frame(1 * cm, 26.0 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            i = 0
            for v in sorted([(len(d[k]['items']), k) for k in filter(lambda x:x != 0, d.keys())], reverse=True):
                if v[0] != 0:
                    items.append(Frame(1 * cm,
                                       (25.1 - (i * 0.5)) * cm,
                                       3 * cm,
                                       25,
                                       leftPadding=0,
                                       rightPadding=0,
                                       id='normal',
                                       showBoundary=0))  # label
                    items.append(Frame(4 * cm,
                                       (25.2 - (i * 0.5)) * cm,
                                       v[0] * 400 / max,
                                       25,
                                       leftPadding=0,
                                       rightPadding=0,
                                       id='normal',
                                       showBoundary=0))  # bar
                    items.append(Frame(4 * cm + (v[0] * 400 / max) + 5, (25.1 - (i * 0.5)) * cm, 40, 25,
                                       leftPadding=0, rightPadding=0, id='normal', showBoundary=0))  # number
                    i += 1

        if type == "data":
            items.append(Paragraph(t(self.language, "edit_stats_country"), self.chartheader))
            items.append((FrameBreak()))

            for v in sorted([(len(d[k]['items']), k) for k in filter(lambda x:x != 0, d.keys())], reverse=True)[:50]:
                if v[0] != 0:
                    items.append(Paragraph(ustr(v[1]), self.bv))
                    items.append((FrameBreak()))
                    items.append(PdfImage(config.basedir + "/web/img/stat_bar.png", width=v[0] * 400 / max, height=10))
                    items.append((FrameBreak()))
                    items.append(Paragraph(ustr(v[0]), self.bv))
                    items.append((FrameBreak()))

            items = items[:-1]
        return items

    def getStatDate(self, type):
        items = []
        d = self.stats.getProgress()
        max = d[0]

        if type == "frames":
            # header date
            items.append(Frame(1 * cm, 26.0 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            x = (32 - len(d)) * 8  # add left space if month with less than 31 days

            for k in d:
                if k == 0:
                    continue
                items.append(Frame(1 * cm + (k - 1) * 17 + 9 + x,
                                   18.9 * cm,
                                   5,
                                   len(d[k]["visitors"]) * (6 * cm) / max["max_u"] + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # col 1
                items.append(Frame(1 * cm + (k - 1) * 17 + 14 + x,
                                   18.9 * cm,
                                   5,
                                   len(d[k]["different"]) * (6 * cm) / max["max_p"] + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # col 2
                items.append(Frame(1 * cm + (k - 1) * 17 + 19 + x,
                                   18.9 * cm,
                                   5,
                                   len(d[k]["items"]) * (6 * cm) / max["max"] + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # col 3

            # legend table with days
            items.append(Frame(1 * cm, 17.8 * cm, 19 * cm, 1.5 * cm, leftPadding=4, rightPadding=0, id='normal', showBoundary=0))
            # table with values
            items.append(Frame(1 * cm, 1 * cm, 19 * cm, 16 * cm, leftPadding=4, rightPadding=0, id='normal', showBoundary=0))

        if type == "data":
            items.append(Paragraph(t(self.language, "edit_stats_spreading"), self.chartheader))
            items.append(FrameBreak())

            for k in d:
                if k == 0:
                    continue
                items.append(PdfImage(config.basedir + "/web/img/stat_baruser_vert.png", width=5,
                                      height=((len(d[k]["visitors"]) * (6 * cm) / max["max_u"] + 1) or 1)))
                items.append(FrameBreak())
                items.append(PdfImage(config.basedir + "/web/img/stat_barpage_vert.png", width=5,
                                      height=((len(d[k]["different"]) * (6 * cm) / max["max_p"] + 1) or 1)))
                items.append(FrameBreak())
                items.append(PdfImage(config.basedir + "/web/img/stat_bar_vert.gif", width=5,
                                      height=((len(d[k]["items"]) * (6 * cm) / max["max"] + 1) or 1)))
                items.append(FrameBreak())

            t_data = []
            weekend = []
            for k in d:
                if k > 0:  # first item holds max values
                    if self.stats.getWeekDay(k) > 4:
                        weekend.append(('BACKGROUND', (k - 1, 0), (k - 1, -1), colors.HexColor('#E6E6E6')))
                    t_data.append('%02d \n%s' % (k, t(self.language, "monthname_" + ustr(int(self.period[-2:])) + "_short")))

            tb = Table([t_data], 31 * [17], 30)
            tb.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'),
                                    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                    ('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
                                    ('BOX', (0, 0), (-1, -1), 1, colors.black),
                                    ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
                                    ('FONTSIZE', (0, 0), (-1, -1), 7),
                                    ] + weekend))
            items.append(tb)
            items.append(FrameBreak())

            t_data = [[t(self.language, "edit_stats_day"), t(self.language, "edit_stats_diffusers").replace(
                "<br/>", "\n"), t(self.language, "edit_stats_pages"), t(self.language, "edit_stats_access")]]  # +31*[4*[2]]
            weekend = []
            for k in d:
                if k > 0:  # first item holds max values
                    if self.stats.getWeekDay(k) > 4:
                        weekend.append(('BACKGROUND', (0, k), (-1, k), colors.HexColor('#E6E6E6')))
                    t_data.append(['%02d.%s %s' % (k, t(self.language, "monthname_" + ustr(int(self.period[-2:])) + "_short"),
                                                   self.period[:4]), len(d[k]["visitors"]), len(d[k]["different"]), len(d[k]["items"])])

            tb = Table(t_data, 4 * [100], [25] + (len(d) - 1) * [12])
            tb.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
                                    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                    ('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
                                    ('BOX', (0, 0), (-1, -1), 1, colors.black),
                                    ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
                                    ('FONTSIZE', (0, 0), (-1, -1), 7),
                                    ('BACKGROUND', (1, 0), (1, 0), colors.HexColor('#fff11d')),
                                    ('BACKGROUND', (2, 0), (2, 0), colors.HexColor('#2ea495')),
                                    ('BACKGROUND', (3, 0), (3, 0), colors.HexColor('#84a5ef')),
                                    ] + weekend))
            items.append(tb)
        return items

    def getStatDay(self, type):
        d = self.stats.getProgress('day')
        max = d[0]
        items = []

        h = 4 * cm  # max height
        l = 2 * cm  # left space
        b = 21.5 * cm  # bottom

        if type == "frames":
            # header weekday
            items.append(Frame(1 * cm, 26.0 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))
            for k in d:
                if k == 0:
                    continue
                items.append(Frame(l + (k - 1) * 17,
                                   b,
                                   16,
                                   len(d[k]["visitors"]) * h / max["max_u"] + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # col 1
                items.append(Frame(l + (k - 1) * 17 + 5,
                                   b,
                                   16,
                                   len(d[k]["different"]) * h / max["max_p"] + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # col 2
                items.append(Frame(l + (k - 1) * 17 + 10,
                                   b,
                                   16,
                                   len(d[k]["items"]) * h / max["max"] + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # col 3

            items.append(Frame(l + 5, b - 1.1 * cm, 119, 1.5 * cm, id='normal', showBoundary=0))
            items.append(Frame(8 * cm, b - 1.4 * cm, 11 * cm, 6 * cm, id='normal', showBoundary=0))

        if type == "data":
            items.append(Paragraph(t(self.language, "edit_stats_spreading_day"), self.chartheader))

            for k in d:
                if k == 0:
                    continue
                items.append(
                    PdfImage(
                        config.basedir +
                        "/web/img/stat_baruser_vert.png",
                        width=5,
                        height=len(
                            d[k]["visitors"]) *
                        h /
                        max["max_u"] +
                        1))
                items.append(FrameBreak())
                items.append(
                    PdfImage(
                        config.basedir +
                        "/web/img/stat_barpage_vert.png",
                        width=5,
                        height=len(
                            d[k]["different"]) *
                        h /
                        max["max_p"] +
                        1))
                items.append(FrameBreak())
                items.append(
                    PdfImage(config.basedir + "/web/img/stat_bar_vert.gif", width=6, height=len(d[k]["items"]) * h / max["max"] + 1))
                items.append(FrameBreak())

            tb = Table([[t(self.language, "dayname_" + ustr(x) + "_short") for x in range(0, 7)]], 7 * [17], 17)
            tb.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'),
                                    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                    ('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
                                    ('BOX', (0, 0), (-1, -1), 1, colors.black),
                                    ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
                                    ('FONTSIZE', (0, 0), (-1, -1), 7),
                                    ('BACKGROUND', (5, 0), (-1, -1), colors.HexColor('#E6E6E6')),
                                    ]))
            items.append(tb)
            items.append(FrameBreak())

            t_data = [[t(self.language, "dayname_" + ustr(x) + "_long")] for x in range(0, 7)]

            for k in d:
                if k == 0:
                    continue
                t_data[k - 1] += [len(d[k][key]) for key in d[k].keys()]
            t_data = [[t(self.language, "edit_stats_weekday"), t(self.language, "edit_stats_diffusers").replace(
                "<br/>", "\n"), t(self.language, "edit_stats_pages"), t(self.language, "edit_stats_access")]] + t_data

            tb = Table(t_data, 4 * [70], [25] + 7 * [16])
            tb.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
                                    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                    ('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
                                    ('BOX', (0, 0), (-1, -1), 1, colors.black),
                                    ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
                                    ('FONTSIZE', (0, 0), (-1, -1), 7),
                                    ('BACKGROUND', (1, 0), (1, 0), colors.HexColor('#fff11d')),
                                    ('BACKGROUND', (2, 0), (2, 0), colors.HexColor('#2ea495')),
                                    ('BACKGROUND', (3, 0), (3, 0), colors.HexColor('#84a5ef')),
                                    ]))
            items.append(tb)
        return items

    def getStatTime(self, type):
        d = self.stats.getProgress('time')
        max = d[0]
        items = []
        h = 4 * cm  # max height

        if type == "frames":
            # header time
            items.append(Frame(1 * cm, 19.3 * cm, 19 * cm, 1 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))

            for k in d:
                if k == 0:
                    continue
                items.append(Frame(1.67 * cm + (k - 1) * 21,
                                   14.8 * cm,
                                   6,
                                   (len(d[k]["visitors"]) * h / max["max_u"]) + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # row 1
                items.append(Frame(1.67 * cm + (k - 1) * 21 + 6,
                                   14.8 * cm,
                                   6,
                                   (len(d[k]["different"]) * h / max["max_p"]) + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # row 1
                items.append(Frame(1.67 * cm + (k - 1) * 21 + 12,
                                   14.8 * cm,
                                   6,
                                   (len(d[k]["items"]) * h / max["max"]) + 16,
                                   leftPadding=0,
                                   rightPadding=0,
                                   id='normal',
                                   showBoundary=0))  # row 1

            items.append(Frame(1 * cm, 13.2 * cm, 19 * cm, 2 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))  # legend
            # value table
            items.append(Frame(1 * cm, 1.0 * cm, 19 * cm, 12.5 * cm, leftPadding=0, rightPadding=0, id='normal', showBoundary=0))

        if type == "data":
            items.append(Paragraph(t(self.language, "edit_stats_spreading_time"), self.chartheader))

            for k in d:
                if k == 0:
                    continue
                items.append(
                    PdfImage(
                        config.basedir +
                        "/web/img/stat_baruser_vert.png",
                        width=6,
                        height=len(
                            d[k]["visitors"]) *
                        h /
                        max["max_u"] +
                        1))
                items.append(FrameBreak())
                items.append(
                    PdfImage(
                        config.basedir +
                        "/web/img/stat_barpage_vert.png",
                        width=6,
                        height=len(
                            d[k]["different"]) *
                        h /
                        max["max_p"] +
                        1))
                items.append(FrameBreak())
                items.append(
                    PdfImage(config.basedir + "/web/img/stat_bar_vert.gif", width=6, height=len(d[k]["items"]) * h / max["max"] + 1))
                items.append(FrameBreak())

            t_data = []
            for i in range(0, 24):
                im = PdfImage(config.basedir + "/web/img/stat_hr" + ustr(i % 12 + 1) + ".png", width=14, height=14)
                p = Paragraph((ustr(i) + "-" + ustr(i + 1)), self.bv)
                t_data.append([p, im])

            tb = Table([t_data], 24 * [21], [40])
            tb.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'TOP'),
                                    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                    ('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
                                    ('BOX', (0, 0), (-1, -1), 1, colors.black),
                                    ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
                                    ('FONTSIZE', (0, 0), (-1, -1), 7),
                                    ]))
            items.append(tb)

            t_data = [['%02d:00-%02d:00' % (i, i + 1)] for i in range(0, 24)]
            for k in d:
                if k == 0:
                    continue
                t_data[k - 1] += [len(d[k][key]) for key in d[k].keys()]
            t_data = [[t(self.language, "edit_stats_daytime"), t(self.language, "edit_stats_diffusers").replace(
                "<br/>", "\n"), t(self.language, "edit_stats_pages"), t(self.language, "edit_stats_access")]] + t_data

            tb = Table(t_data, 4 * [70], [25] + [13] * 24)
            tb.setStyle(TableStyle([('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
                                    ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                    ('INNERGRID', (0, 0), (-1, -1), 1, colors.black),
                                    ('BOX', (0, 0), (-1, -1), 1, colors.black),
                                    ('FONTNAME', (0, 0), (-1, -1), 'Helvetica'),
                                    ('FONTSIZE', (0, 0), (-1, -1), 7),
                                    ('BACKGROUND', (1, 0), (1, 0), colors.HexColor('#fff11d')),
                                    ('BACKGROUND', (2, 0), (2, 0), colors.HexColor('#2ea495')),
                                    ('BACKGROUND', (3, 0), (3, 0), colors.HexColor('#84a5ef')),
                                    ]))
            items.append(tb)
        return items

    def build(self, style=1):
        self.h1 = self.styleSheet['Heading1']
        self.h1.fontName = 'Helvetica'
        self.bv = self.styleSheet['BodyText']
        self.bv.fontName = 'Helvetica'
        self.bv.fontSize = 7
        self.bv.spaceBefore = 0
        self.bv.spaceAfter = 0

        self.chartheader = self.styleSheet['Heading3']
        self.chartheader.fontName = 'Helvetica'

        self.formatRight = self.styleSheet['Normal']
        self.bv.formatRight = 'Helvetica'
        self.formatRight.alignment = 2

        nameColl = self.collection.name

        while True:
            # page 1
            p = Paragraph("%s \n'%s'" % (t(self.language, "edit_stats_header"), nameColl), self.h1)
            p.wrap(defaultPageSize[0], defaultPageSize[1])

            if p.getActualLineWidths0()[0] < 19 * cm:
                break
            else:
                nameColl = nameColl[0:-4] + "..."

        self.data.append(p)

        self.data.append(Paragraph("%s: %s" % (t(self.language, "edit_stats_period_header"), self.period), self.chartheader))
        self.data.append(Paragraph(t(self.language, "edit_stats_pages_of") % ("1", "4"), self.formatRight))

        self.data.append((FrameBreak()))
        # top 10
        self.data += self.getStatTop("data", namecut=60)

        # page 2
        self.data.append(Paragraph("%s \n'%s' %s - " % (t(self.language, "edit_stats_header"), self.collection.name,
                                                        self.period) + t(self.language, "edit_stats_pages_of") % ("2", "4"), self.bv))
        self.data.append((FrameBreak()))
        # country
        self.data += self.getStatCountry("data")
        self.data.append(PageBreak())

        # page 3
        self.data.append(Paragraph("%s \n'%s' %s - " % (t(self.language, "edit_stats_header"), self.collection.name,
                                                        self.period) + t(self.language, "edit_stats_pages_of") % ("3", "4"), self.bv))
        self.data.append((FrameBreak()))
        # date
        self.data += self.getStatDate("data")
        self.data.append(PageBreak())

        # page 4
        self.data.append(Paragraph("%s \n'%s' %s - " % (t(self.language, "edit_stats_header"), self.collection.name,
                                                        self.period) + t(self.language, "edit_stats_pages_of") % ("4", "4"), self.bv))
        self.data.append((FrameBreak()))
        # weekday
        self.data += self.getStatDay("data")
        # time
        self.data += self.getStatTime("data")

        template = SimpleDocTemplate(config.get("paths.tempdir", "") + "statsaccess.pdf", showBoundary=0)
        tFirst = PageTemplate(id='First', onPage=self.myPages, pagesize=defaultPageSize)
        tNext = PageTemplate(id='Later', onPage=self.myPages, pagesize=defaultPageSize)

        template.addPageTemplates([tFirst, tNext])
        template.allowSplitting = 1
        BaseDocTemplate.build(template, self.data)

        template.canv.setAuthor(t(self.language, "main_title"))
        template.canv.setTitle("%s \n'%s' - %s: %s" % (t(self.language,
                                                         "edit_stats_header"),
                                                       self.collection.name,
                                                       t(self.language,
                                                         "edit_stats_period_header"),
                                                       self.period))
        return template.canv._doc.GetPDFData(template.canv)

def getPrintView(nid, p, req):
    node = q(Node).get(nid)
    for f in node.files:
        if f.filetype == "statistic":
            period, type = getPeriod(f.abspath)
            if type == p.split("_")[0] and period == p.split("_")[1]:
                data = StatisticFile(f)

    if data:
        pdf = StatsAccessPDF(data, p.split("_")[1], nid, lang(req))
        return pdf.build()


import numpy as np
import pdb

from modules.base import ModuleBase

class BinaryCrossEntropyLoss(ModuleBase):
    def __init__(self):
        super(BinaryCrossEntropyLoss, self).__init__()
    def forward(self, x, label):
        # label: batch_size
        # x: batch_size x 1
        batch_size = x.shape[0]
        blabel = label.reshape([batch_size, 1])
        bce = -(blabel * np.log(x) + (1 - blabel) * log(1 - x)) # batch_size  x 1
        self.results['blabel'] = blabel
        self.results['x'] = x
        return np.sum(bce) / batch_size
    def backward(self):
        blabel = self.results['blabel']
        batch_size = blabel.shape[0]
        x = self.results['x']
        grad_input = -(blabel / x - (1 - blabel) / (1 -  x))
        self.results = {}
        return grad_input / batch_size

class CrossEntropyLoss(ModuleBase):
    def __init__(self):
        super(CrossEntropyLoss, self).__init__()
    def forward(self, x, label):
        # label: batch_size
        # x:  batch_size  x num_classes
        batch_size = x.shape[0]
        num_classes = x.shape[1]
        onehot = np.eye(num_classes)[label]
        loss = -np.sum(np.log(x) * onehot)
        self.results['x'] = x
        self.results['onehot'] = onehot
        return loss / batch_size
    def backward(self):
        revx = 1 / self.results['x']
        batch_size = revx.shape[0]
        grad_input = -revx * self.results['onehot']
        self.results = {}
        return grad_input / batch_size

class L2Loss(ModuleBase):
    def __init__(self):
        super(L2Loss, self).__init__()
    def forward(self, x, groud_truth):
        # x: batch_size x dim
        batch_size = x.shape[0]
        diff = x - groud_truth # batch_size x dim
        self.result['diff'] = diff
        return np.sum(diff ** 2) / batch_size
    def backward(self):
        batch_size = self.results['diff'].shape[0]
        grad_input = 2 * self.results['diff']
        self.results = {}
        return grad_input / batch_size


import bw_conv_cb.python.breitWigner as breitWigner
import bw_conv_cb.python.crystalBall as crystalBall
import numpy as np
from scipy.optimize import minimize
from scipy.special import xlogy
from scipy.signal import fftconvolve
import matplotlib.pyplot as plt

def NLL(a,b):

    nll = xlogy(a,b)
    nll[nll==-np.inf] = 0
    nll = np.sum(nll)/len(nll)

    penalty = xlogy(np.sum(a) - a, 1 - b)
    penalty[penalty==-np.inf] = 0
    penalty = np.sum(penalty)/len(penalty)

    b = np.sum(a)*b/np.sum(b)
    chi_sqr = np.sum(np.divide(np.multiply(a-b,a-b),a))/(len(a)-1)

    return -2*(nll+penalty)*chi_sqr

def target(guess):
    global thisBW
    global thisCB
    global _DATA_

    thisCB.update(guess)
    y_vals = np.convolve(thisBW.y,thisCB.getY(),mode='same')
    y_vals = y_vals/np.sum(y_vals)

    return NLL(_DATA_,y_vals)

def scan(guess):
    global thisBW
    global thisCB
    global _DATA_

    ret = guess

    scan_alpha = np.arange(0.1,100,0.5)
    scan_n = np.arange(0.1,100,0.5)
    scan_mean = np.arange(-5,5,0.025)
    scan_width = np.arange(0.1,10,0.1)

    guesses_mean = [[ret[0],ret[1],x,ret[3]] for x in scan_mean]
    nll_mean = np.array([target(x) for x in guesses_mean])
    ret[2] = scan_mean[np.argmin(nll_mean)]

    guesses_width = [[ret[0],ret[1],ret[2],x] for x in scan_width]
    nll_width = np.array([target(x) for x in guesses_width])
    ret[3] = scan_width[np.argmin(nll_width)]

    guesses_alpha = [[x,ret[1],ret[2],ret[3]] for x in scan_alpha]
    nll_alpha = np.array([target(x) for x in guesses_alpha])
    ret[0] = scan_alpha[np.argmin(nll_alpha)]

    guesses_n = [[ret[0],x,ret[2],ret[3]] for x in scan_n]
    nll_n = np.array([target(x) for x in guesses_n])
    ret[1] = scan_n[np.argmin(nll_n)]

    return ret

def errors(result,min_chi):

    ret = []

    scan_mean = np.arange(-(2*abs(result[2])),2*abs(result[2]),0.0001)
    scan_width = np.arange(0.0001,2*result[3],0.0001)

    par_set_mean = [[result[0],result[1],x,result[3]] for x in scan_mean]
    par_set_width = [[result[0],result[1],result[2],x] for x in scan_width]

    chi_mean = np.array([target(x) for x in par_set_mean])
    chi_width = np.array([target(x) for x in par_set_width])

    sigma_mask_mean = chi_mean >= np.e * min_chi
    sigma_mask_width = chi_width >= np.e * min_chi

    val = []
    for i in range(len(sigma_mask_mean)-1):
        if sigma_mask_mean[i] and not sigma_mask_mean[i+1]:
            val.append(result[0]-scan_mean[i])
        if not sigma_mask_mean[i] and sigma_mask_mean[i+1]:
            val.append(scan_mean[i]-result[0])
    ret.append(val)

    val = []
    for i in range(len(sigma_mask_width)-1):
        if sigma_mask_width[i] and not sigma_mask_width[i+1]:
            val.append(result[0]-scan_width[i])
        if not sigma_mask_width[i] and sigma_mask_width[i+1]:
            val.append(scan_width[i]-result[0])
    ret.append(val)

    return ret

def fit(x,y):
    global thisBW
    global thisCB
    global _DATA_

    #make bw distribution
    _DATA_ = y
    mean = np.average(x,weights=y)-91.188
    width = np.sqrt(np.average(np.multiply(x-np.average(x,weights=y),x-np.average(x,weights=y)), weights=y))
    guess = [1.424,1.86,mean,width]

    bounds = [(0.01,100), (0.01,100), (-5,5), (0.1,10)]

    thisBW = breitWigner.bw(x)
    thisCB = crystalBall.cb(x, guess)
    guess = scan(guess)

    print(guess)
    result = minimize(target,
            np.array(guess),
            method="L-BFGS-B",
            bounds=bounds,
            options={"eps":0.0001}
            )

    print(result)
    thisCB.update(result.x)
    y_vals = np.convolve(thisBW.getY(),thisCB.getY(),mode='same')
    y_vals = np.sum(y)*y_vals/np.sum(y_vals)
    chi_sqr = np.sum(np.divide(np.multiply(y-y_vals,y-y_vals),y))/len(y)
    #uncertainties = errors(result.x, result.fun)
    uncertainties = np.zeros((5,5))

    mu = 91.188+result.x[2]
    dmu =  min(np.abs(uncertainties[0][0]),np.abs(uncertainties[0][1]))

    sigma = result.x[3]
    dsigma = min(np.abs(uncertainties[1][0]),np.abs(uncertainties[1][1]))

    print("minimization complete:")
    print("mu:", 91.188+result.x[2], "+/-", min(np.abs(uncertainties[0][0]),np.abs(uncertainties[0][1]) ))
    print("sigma:", result.x[3], "+/-", min(np.abs(uncertainties[1][0]),np.abs(uncertainties[1][1])))
    print("reduced chi squared:", chi_sqr)
    print()

    return mu-91.188, dmu, sigma, dsigma, chi_sqr

'''
    fig,axs = plt.subplots(ncols=1,nrows=1)
    axs.scatter(x,
            y,
            label='data',
            color='black',
            marker='o')
    axs.plot(x,
            y_vals,
            label='bw conv cb fit',
            color='darkred',
            linestyle='dashed')
    axs.legend(loc='best')
    fig.savefig("fit.png")
    plt.close(fig)
    return
'''


import numbers
from typing import List, Optional

# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def parseIntFromReversedLinkedList(self, reversedLinkedList:ListNode) -> int:
        values_in_reversed_linked_list = []
        current_element = reversedLinkedList
        result = 0
        while True:
            values_in_reversed_linked_list.append(current_element.val)

            if current_element.next == None:
                break
            current_element = current_element.next

        for i in range(len(values_in_reversed_linked_list) -1, -1, -1):
            result = result + (values_in_reversed_linked_list[i] * pow(10, i))

        return result

    def buildRevesedLinkedListFromInt(self, value) -> ListNode:
        value_as_string = str(value)
        result = ListNode()
        current_node = result
        for i in range(len(value_as_string) -1, -1, -1):
            current_node.val = value_as_string[i]

            if(i == 0):
                break

            current_node.next = ListNode()
            current_node =  current_node.next

        return result

    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        l1_as_int = self.parseIntFromReversedLinkedList(l1)
        l2_as_int = self.parseIntFromReversedLinkedList(l2)
        result_as_int = l1_as_int + l2_as_int
        return self.buildRevesedLinkedListFromInt(result_as_int)

list_a = ListNode(9, ListNode(9, ListNode(9, ListNode(5))))
list_b = ListNode(5, ListNode(6, ListNode(7)))
solution = Solution()
print(solution.addTwoNumbers(list_a, list_b))


#Ejercicio 10: Hacer una cadena por teclado, luego crear una lista sin repetir caracteres

cadena = input("Digitar una cadena: ")

lista = []

for i in cadena:
    if i not in lista:  #Si el caracter no esta en la lista, se agrega
        lista.append(i)

print(lista)


'''El número  e  tiene inmensa utilidad para el análisis y la estadística, es una de las super-estrellas de la matemática, y su utilidad radica en que la función  ex  es igual a su derivada, por definición de  e .

Gracias a las series de Taylor podemos obtener la siguiente definición del número  e :

e=1+1/1!+1/2!+1/3!+1/4!+1/5!+...
Se pide obtener una aproximación del número  e  calculando la suma de los primeros  20  términos de esta sucesión infinita.'''

def factorial(n):
    if (n == 0):
        return 1
    else:
        return n*factorial(n-1)

cantidadTerminos = 20
e = 0

for i in range(0,cantidadTerminos):
    e += 1/factorial(i)

print("el valor aproximado de e es: ", e)


import collections
import copy
import typing
import warnings

import comma.abstract
import comma.classes.slices
import comma.config
import comma.exceptions
import comma.helpers
import comma.methods

__author__ = "Jérémie Lumbroso <lumbroso@cs.princeton.edu>"

__all__ = [
    "CommaTable"
]

class CommaTable(collections.UserList, list, collections.UserDict, comma.abstract.CloneableCollection):
    """
    Contains a table from a CSV file. This is a subclass of
    `collections.UserList`, and it can be manipulated in many regards
    like a list, including in modifications.

    Let `table` be an instance of this class. You can access the items
    by index:
    ```
    table[0]  # => ["row1col1", "row1col2", "row1col3"]
    ````
    would be the first row.

    If the `CommaTable` has a header, it can be accessed at
    `table.header`, and should be a list of strings. When it is set
    it allow for a column-wise access:
    ```
    table.header = ["column1", "column2", "column3"]
    table["column1"]  # => ["row1col1", "row2col1", "row3col1", "row4col3"]
    table[0] = {
        "column1": "row1col1",
        "column2": "row1col2",
        "column3": "row1col3",
        "column4": "row1col4",
    }
    ```
    As shown with `table[0]`, individual rows can also be accessed as
    dictionaries, as another consequence of having the header specified.
    (Note: That the row indexing is still available, since the dictionary
    keys are strings.)

    The rows can be modified in place.
    """

    # parent CommaFile object from which to get settings and headers
    _parent = None

    # header override, when this class is not linked to a file
    _local_header = None

    # local primary key
    _local_primary_key = None

    # local cache for lookups { primary key value -> row number }
    _primary_key_dict = None

    def __init__(
        self,
        initlist=None,  #: typing.List[comma.classes.row.CommaRow] = None,
        parent=None,  #: comma.classes.file.CommaFile = None,
        *args,
        **kwargs,
    ):
        """
        Creates a row that can be tied to a `CommaFile`, which has
        properties such as the `header` or `dialect`. This is an internal
        constructor used to create a `CommaRow` row when converting
        data into a `CommaFile` object.

        `initlist` is the row to be store; `parent` is a reference to
        the parent `CommaFile` object, which provides the `header`,
        and some other parameters.
        """
        self._parent = parent
        super().__init__(initlist, *args, **kwargs)

    def to_html(self):
        """
        Returns an HTML string representation of the table data.
        """

        # NOTE: should we use tabulator or prettytable instead of reinventing?

        # contain all the rows
        table_rows = []

        if self.has_header:
            table_rows = [comma.helpers.zip_html_tag(data=self.header, in_pattern="{}	")]

        for row in self.data:
            table_rows += [comma.helpers.zip_html_tag(data=row, indent=4)]

        table_html = "
{}
".format("\n\n".join(table_rows))

        return table_html

    def _repr_html_(self):
        """
        Returns an HTML string representation of the table data, this is a magic
        helper method for IPython/Jupyter notebooks.
        """
        return self.to_html()

    def dump(
        self,
        filename: typing.Optional[str] = None,
        fp: typing.Optional[typing.IO] = None,
    ) -> str:
        """
        Outputs a serialization of this `CommaTable` object to a string, either
        as a return value, or written to a local file path `filename`, or a
        stream `fp`.
        """
        return comma.methods.dump(self, filename=filename, fp=fp)

    @property
    def has_header(self):
        """
        Checks whether the `CommaTable` has a header as provided in
        the data source, or as later provided by the user.
        """
        return ((not (self._parent is None) and not (self._parent.header is None)) or
                (not (self._local_header is None)))

    @property
    def header(self):
        """
        Property providing a header with column names for the columns of
        the data stored by this `CommaTable` object. The header may come
        either from the parent `CommaFile` object (and is sourced from the
        original data source), or can be user-provided, for instance by
        setting this property.
        """

        # if `CommaTable` is linked to a valid `CommaFile`, redirect
        # to that property, unless overridden
        if self._local_header is None and self._parent is not None:
            return self._parent.header

        return self._local_header

        # if self._parent is None:
        #     raise comma.exceptions.CommaOrphanTableException(
        #         "table not linked to parent structure")
        #
        # if self._parent.header is None:
        #     raise comma.exceptions.CommaNoHeaderException(
        #         "CSV file does not appear to have a header and "
        #         "none was provided; key-based access not possible")

    @header.setter
    def header(self, value):

        # equivalent to a delete
        if value is None:
            # redirect to that logic
            del self.header
            return

        if self._parent is not None:
            # handing it off to the CommaFile's setter to validate
            # and/or reject value
            self._parent.header = value
            return

        # NOTE: should this logic? the rationale is that the header is
        # both a property of the file (if the file, when created, had
        # a header) and should also be a property of a table that is not
        # (hypothetically) linked to a file

        validated_header = comma.helpers.validate_header(value)

        # if we are replacing an existing header, check length

        if self._local_header is not None:
            old_length = len(self._local_header)
            new_length = len(validated_header)

            if old_length != new_length:
                warnings.warn(
                    "changing length of local header; was {old}, now is {new}".format(
                        old=old_length,
                        new=new_length))

        self._local_header = value

    @header.deleter
    def header(self):
        """
        Deletes the header associated with this `CommaTable1`; this operation
        only affects the metadata, but does not modify any of the underlying
        rows.
        """
        if self._parent is not None:
            del self._parent.header
            try:
                self._parent.header
            except AttributeError:
                self._parent.header = None
            return

        self._local_header = None

    @property
    def primary_key(self):
        """
        Property controlling whether the `CommaTable` is indexed by one of its
        columns. This allows for using a column, for instance `username` or
        `userid` or `email`, as a primary key for the rows of the `CommaTable`.
        """

        if self._parent is not None:
            return self._parent.primary_key

        return self._local_primary_key

    def _update_primary_key_dict(self):
        """
        Updates the internal mapping that associated an index value
        with a row according to the value of a specific column (of which
        the name is the primary key field).
        """

        if self.primary_key is None:
            return

        pk = self.primary_key

        primary_key_dict = dict()
        for i, row in enumerate(self):

            if pk in row:  # pragma: no cover
                key_val_in_row = row[pk]

            else:
                # so the "pk in row" does not work
                # check if it quacks...
                try:
                    key_val_in_row = row[pk]
                except IndexError:
                    key_val_in_row = None
                except KeyError:  # pragma: no cover
                    key_val_in_row = None

            if key_val_in_row is None:
                # raise comma.exceptions.CommaPrimaryKeyMissing(
                #     "primary key `{pk}` not found in :\n{row}".format(
                #         pk=pk, row=row))
                warnings.warn(
                    "CommaTable._update_primary_key_dict():\n " +
                    "primary key `{pk}` not found in row".format(pk=pk))
                continue

            primary_key_dict[key_val_in_row] = i

        self._primary_key_dict = primary_key_dict

    @primary_key.setter
    def primary_key(self, value):

        # check if there are headers
        if not self.has_header:
            raise comma.exceptions.CommaNoHeaderException(
                "cannot use a primary key if the headers are not defined"
            )

        # check if primary key belongs to headers
        if value not in self.header:
            raise comma.exceptions.CommaKeyError(
                ("the specified primary key ({}) is not one of the header "
                 "column names: {}").format(value, self.header)
            )

        if self._parent is not None:
            self._parent.primary_key = value
            return

        self._local_primary_key = value

    def __getitem__(self, key):
        """
        Let `table` be an instance of this class. You can access the items
        by index:
        ```
        table[0]  # => ["row1col1", "row1col2", "row1col3"]
        ````
        would be the first row.

        If the `CommaTable` has a header, it can be accessed at
        `table.header`, and should be a list of strings. When it is set
        it allow for a column-wise access:
        ```
        table.header = ["column1", "column2", "column3"]
        table["column1"]  # => ["row1col1", "row2col1", "row3col1", "row4col3"]

        If `primary_key` is set, then it is also possible to access a record
        by the value of its primary key. This operation is slightly costly
        as, for accuracy reasons, a cache is recomputed at every access;
        but it can sometimes be convenient. (This will be improved if there
        is demand.)
        """
        ##print("CommaTable.__getitem__", hex(id(self)), key, type(key))

        # if getting a specific row: Return underlying CommaRow
        if type(key) is int:
            return super().__getitem__(key)

        # if getting a range of rows, create a new CommaTable to
        # serve the subset of rows.

        # by default, since the rows will be the same references,
        # any changes will propagate to the whole file (unlike when
        # creating a slice, which usually creates a copy); for this
        # purpose we have a global setting

        parent_ref = self._parent
        if comma.config.settings.SLICE_DEEP_COPY_PARENT:
            parent_ref = copy.deepcopy(parent_ref)

        if type(key) is slice:

            # slices can either be shallow or deep depending on
            # global settings

            data_subset = self.data[key]
            if comma.config.settings.SLICE_DEEP_COPY_DATA:
                data_subset = copy.deepcopy(data_subset)

            obj = self.clone(newdata=data_subset, _parent=parent_ref)

            return obj

        # field-slice or primary-key-query
        if type(key) is str:

            # field-slice, i.e. csv_table["street"]
            if self.header is not None and key in self.header:

                data_subset = self.data[:]
                if comma.config.settings.SLICE_DEEP_COPY_DATA:
                    data_subset = copy.deepcopy(data_subset)

                return comma.classes.slices.CommaFieldSlice(
                    initlist=data_subset,
                    parent=parent_ref,
                    field_name=key)

            # primary key query, i.e., csv_table["someperson@marcopolo.me"]
            elif self.primary_key is not None:
                self._update_primary_key_dict()
                id_of_key_row = self._primary_key_dict.get(key)
                if id_of_key_row is not None:
                    # recursive call, but change of type
                    return self.__getitem__(id_of_key_row)
                raise comma.exceptions.CommaKeyError(
                    "no record with that primary key: '{}'".format(key))

        raise comma.exceptions.CommaKeyError("invalid key")

    def __setitem__(self, key, value):
        """

        """
        if type(key) is int:

            value._parent = self._parent
            return super().__setitem__(key, value)

        if type(key) is slice:
            for row in value:
                row._parent = self._parent
            return super().__setitem__(key, value)

        # field-slice, i.e. csv_table["street"]
        if type(key) is str:

            # is this field slicing
            if key in self.header:
                # check size:
                if len(value) != len(self):
                    raise comma.exceptions.CommaBatchException(
                        "not right size")

                # copy each cell from the slice to the original list
                for i in range(len(self)):
                    self[i][key] = value[i]

                return self

            # is this primary key indexing
            elif self.primary_key is not None:
                self._update_primary_key_dict()
                id_of_key_row = self._primary_key_dict.get(key)
                if id_of_key_row is not None:
                    # recursive call, but change of type
                    return self.__setitem__(id_of_key_row, value)
                raise comma.exceptions.CommaKeyError(
                    "no record with that primary key: '{}'".format(key))

        raise comma.exceptions.CommaKeyError("invalid key")


from __future__ import generators
import re

escapedQuotesRE = re.compile(r"(\\\\|\\\"|\\\')")

# changess \" \' and \\ into ** so that text searches
# for " and ' won't hit escaped ones
def maskEscapedQuotes(src):
    return escapedQuotesRE.sub("**", src)

stringsAndCommentsRE =  \
      re.compile("(\"\"\".*?\"\"\"|'''.*?'''|\"[^\"]*\"|\'[^\']*\'|#.*?\n)", re.DOTALL)

import string
#transtable = string.maketrans('classdefifforwhiletry', "*********************")

# performs a transformation on all of the comments and strings so that
# text searches for python keywords won't accidently find a keyword in
# a string or comment
def maskPythonKeywordsInStringsAndComments(src):
    src = escapedQuotesRE.sub("**", src)
    allstrings = stringsAndCommentsRE.split(src)
    # every odd element is a string or comment
    for i in xrange(1, len(allstrings), 2):
        allstrings[i] = allstrings[i].upper()
        #allstrings[i] = allstrings[i].translate(transtable)
    return "".join(allstrings)

allchars = string.maketrans("", "")
allcharsExceptNewline = allchars[: allchars.index('\n')]+allchars[allchars.index('\n')+1:]
allcharsExceptNewlineTranstable = string.maketrans(allcharsExceptNewline, '*'*len(allcharsExceptNewline))

# replaces all chars in a string or a comment with * (except newlines).
# this ensures that text searches don't mistake comments for keywords, and that all
# matches are in the same line/comment as the original
def maskStringsAndComments(src):
    src = escapedQuotesRE.sub("**", src)
    allstrings = stringsAndCommentsRE.split(src)
    # every odd element is a string or comment
    for i in xrange(1, len(allstrings), 2):
        if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
            allstrings[i] = allstrings[i][:3]+ \
                           allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
                           allstrings[i][-3:]
        else:
            allstrings[i] = allstrings[i][0]+ \
                           allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
                           allstrings[i][-1]

    return "".join(allstrings)

# replaces all chars in a string or a comment with * (except newlines).
# this ensures that text searches don't mistake comments for keywords, and that all
# matches are in the same line/comment as the original
def maskStringsAndRemoveComments(src):
    src = escapedQuotesRE.sub("**", src)
    allstrings = stringsAndCommentsRE.split(src)
    # every odd element is a string or comment
    for i in xrange(1, len(allstrings), 2):
        if allstrings[i].startswith("'''")or allstrings[i].startswith('"""'):
            allstrings[i] = allstrings[i][:3]+ \
                           allstrings[i][3:-3].translate(allcharsExceptNewlineTranstable)+ \
                           allstrings[i][-3:]
        elif allstrings[i].startswith("#"):
            allstrings[i] = '\n'
        else:
            allstrings[i] = allstrings[i][0]+ \
                           allstrings[i][1:-1].translate(allcharsExceptNewlineTranstable)+ \
                           allstrings[i][-1]
    return "".join(allstrings)

implicitContinuationChars = (('(', ')'), ('[', ']'), ('{', '}'))
emptyHangingBraces = [0,0,0,0,0]
linecontinueRE = re.compile(r"\\\s*(#.*)?$")
multiLineStringsRE =  \
      re.compile("(^.*?\"\"\".*?\"\"\".*?$|^.*?'''.*?'''.*?$)", re.DOTALL)

#def splitLogicalLines(src):
#    src = multiLineStringsRE.split(src)

# splits the string into logical lines.  This requires the comments to
# be removed, and strings masked (see other fns in this module)
def splitLogicalLines(src):
    physicallines = src.splitlines(1)
    return [x for x in generateLogicalLines(physicallines)]

class UnbalancedBracesException: pass

# splits the string into logical lines.  This requires the strings
# masked (see other fns in this module)
# Physical Lines *Must* start on a non-continued non-in-a-comment line
# (although detects unbalanced braces)
def generateLogicalLines(physicallines):
    tmp = []
    hangingBraces = list(emptyHangingBraces)
    hangingComments = 0
    for line in physicallines:
        # update hanging braces
        for i in range(len(implicitContinuationChars)):
            contchar = implicitContinuationChars[i]
            numHanging = hangingBraces[i]
            hangingBraces[i] = numHanging+line.count(contchar[0]) - \
                               line.count(contchar[1])

        hangingComments ^= line.count('"""') % 2
        hangingComments ^= line.count("'''") % 2

        if hangingBraces[0] < 0 or \
           hangingBraces[1] < 0 or \
           hangingBraces[2] < 0:
            raise UnbalancedBracesException()

        if linecontinueRE.search(line):
            tmp.append(line)
        elif hangingBraces != emptyHangingBraces:
            tmp.append(line)
        elif hangingComments:
            tmp.append(line)
        else:
            tmp.append(line)
            yield "".join(tmp)
            tmp = []

# see above but yields (line,linenum)
#   needs physicallines to have linenum attribute
#   TODO: refactor with previous function
def generateLogicalLinesAndLineNumbers(physicallines):
    tmp = []
    hangingBraces = list(emptyHangingBraces)
    hangingComments = 0
    linenum = None
    for line in physicallines:
        if tmp == []:
            linenum = line.linenum

        # update hanging braces
        for i in range(len(implicitContinuationChars)):
            contchar = implicitContinuationChars[i]
            numHanging = hangingBraces[i]
            hangingBraces[i] = numHanging+line.count(contchar[0]) - \
                               line.count(contchar[1])

        hangingComments ^= line.count('"""') % 2
        hangingComments ^= line.count("'''") % 2

        if linecontinueRE.search(line):
            tmp.append(line)
        elif hangingBraces != emptyHangingBraces:
            tmp.append(line)
        elif hangingComments:
            tmp.append(line)
        else:
            tmp.append(line)
            yield "".join(tmp),linenum
            tmp = []

# takes a line of code, and decorates it with noops so that it can be
# parsed by the python compiler.
# e.g.  "if foo:"  -> "if foo: pass"
# returns the line, and the adjustment made to the column pos of the first char
# line must have strings and comments masked
#
# N.B. it only inserts keywords whitespace and 0's
notSpaceRE = re.compile("\s*(\S)")
commentRE = re.compile("#.*$")

def makeLineParseable(line):
    return makeLineParseableWhenCommentsRemoved(commentRE.sub("",line))

def makeLineParseableWhenCommentsRemoved(line):
    line = line.strip()
    if ":" in line:
        if line.endswith(":"):
            line += " pass"
        if line.startswith("try"):
            line += "\nexcept: pass"
        elif line.startswith("except") or line.startswith("finally"):
            line = "try: pass\n" + line
            return line
        elif line.startswith("else") or line.startswith("elif"):
            line = "if 0: pass\n" + line
            return line
    elif line.startswith("yield"):
        return ("return"+line[5:])
    return line


class Myclass:
    name = "Vinicius"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def suma(self, a, b):
        print(a + b)

x = Myclass("Vini", 40)
print(x.name)
x.suma(10, 20)
print(x.age)


#!/usr/bin/env python
# coding: utf-8

# # MadMiner particle physics tutorial
#
# # Part 4a: Limit setting
#
# Johann Brehmer, Felix Kling, Irina Espejo, and Kyle Cranmer 2018-2019

# In part 4a of this tutorial we will use the networks trained in step 3a and 3b to calculate the expected limits on our theory parameters.

# ## 0. Preparations

# In[1]:

from __future__ import absolute_import, division, print_function, unicode_literals

import six
import logging
import numpy as np
import matplotlib
matplotlib.use('Agg')
from matplotlib import pyplot as plt
#get_ipython().magic(u'matplotlib inline')

from madminer.limits import AsymptoticLimits
from madminer.sampling import SampleAugmenter
from madminer import sampling
from madminer.plotting import plot_histograms

# In[2]:

# MadMiner output
logging.basicConfig(
    format='%(asctime)-5.5s %(name)-20.20s %(levelname)-7.7s %(message)s',
    datefmt='%H:%M',
    level=logging.INFO
)

# Output of all other modules (e.g. matplotlib)
for key in logging.Logger.manager.loggerDict:
    if "madminer" not in key:
        # print("Deactivating logging output for", key)
        logging.getLogger(key).setLevel(logging.WARNING)

# ## 1. Preparations

# In the end, what we care about are not plots of the log likelihood ratio, but limits on parameters. But at least under some asymptotic assumptions, these are directly related. MadMiner makes it easy to calculate p-values in the asymptotic limit with the `AsymptoticLimits` class in the `madminer.limits`:

# In[3]:

#limits = AsymptoticLimits('data/lhe_data_shuffled.h5')
limits = AsymptoticLimits('data/delphes_data_shuffled.h5')

# This class provids two high-level functions:
# - `AsymptoticLimits.observed_limits()` lets us calculate p-values on a parameter grid for some observed events, and
# - `AsymptoticLimits.expected_limits()` lets us calculate expected p-values on a parameter grid based on all data in the MadMiner file.
#
# First we have to define the parameter grid on which we evaluate the p-values.

# In[4]:

grid_ranges = [(-20., 20.), (-20., 20.)]
grid_resolutions = [25, 25]

# What luminosity (in inverse pb) are we talking about?

# In[5]:

lumi = 10000.

# In[6]:

p_values = {}
mle = {}

# ## 2. Expected limits based on histogram

# First, as a baseline, let us calculate the expected limits based on a simple jet pT histogram. Right now, there are not a lot of option for this function; MadMiner even calculates the binning automatically. (We will add more functionality!)
#
# The keyword `include_xsec` determines whether we include information from the total rate or just use the shapes. Since we don't model backgrounds and systematics in this tutorial, the rate information is unrealistically large, so we leave it out here.

# In[7]:

theta_grid, p_values_expected_histo, best_fit_expected_histo, _, _, (histos, observed, observed_weights) = limits.expected_limits(
    mode="histo",
    hist_vars=["pt_j1"],
    theta_true=[0.,0.],
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
    return_asimov=True
)

p_values["Histogram"] = p_values_expected_histo
mle["Histogram"] = best_fit_expected_histo

# With `mode="rate"`, we could calculate limits based on only the rate -- but again, since the rate is extremely powerful when backgrounds and systematics are not taken into account, we don't do that in this tutorial.

# Let's visualize the likelihood estimated with these histograms:

# In[8]:

indices = [12 + i * 25 for i in [6,9,12,15,18]]

fig = plot_histograms(
    histos=[histos[i] for i in indices],
    observed=[observed[i] for i in indices],
    observed_weights=observed_weights,
    histo_labels=[r"$\theta_0 = {:.2f}$".format(theta_grid[i,0]) for i in indices],
    xlabel="Jet $p_T$",
    xrange=(0.,500.),
)

#plt.show()
plt.savefig("histoPlot.pdf")

# ## 3. Expected limits based on ratio estimators

# Next, `mode="ml"` allows us to calculate limits based on any `ParamterizedRatioEstimator` instance like the ALICES estimator trained above:

# In[ ]:

theta_grid, p_values_expected_alices, best_fit_expected_alices, _, _, _ = limits.expected_limits(
    mode="ml",
    model_file='models/alices',
    theta_true=[0.,0.],
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
)

p_values["ALICES"] = p_values_expected_alices
mle["ALICES"] = best_fit_expected_alices

# ## 4. Expected limits based on score estimators

# To get p-values from a SALLY estimator, we have to use histograms of the estimated score:

# In[ ]:

theta_grid, p_values_expected_sally, best_fit_expected_sally, _, _, (histos, observed, observed_weights) = limits.expected_limits(
    mode="sally",
    model_file='models/sally',
    theta_true=[0.,0.],
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
    return_asimov=True,
)

p_values["SALLY"] = p_values_expected_sally
mle["SALLY"] = best_fit_expected_sally

# Let's have a look at the underlying 2D histograms:

# In[ ]:

indices = [12 + i * 25 for i in [0,6,12,18,24]]

fig = plot_histograms(
    histos=[histos[i] for i in indices],
    observed=observed[0,:100,:],
    observed_weights=observed_weights[:100],
    histo_labels=[r"$\theta_0 = {:.2f}$".format(theta_grid[i,0]) for i in indices],
    xlabel=r'$\hat{t}_0(x)$',
    ylabel=r'$\hat{t}_1(x)$',
    xrange=(-3.,.5),
    yrange=(-3.,3.),
    log=True,
    zrange=(1.e-3,1.),
    markersize=10.
)

# As you see, the binning is the same for every parameter point. This is different for `mode="adaptive-sally"`, which optimizes the binning for every grid point differently:

# In[ ]:

theta_grid, p_values_expected_sally, best_fit_expected_sally, _, _, (histos, observed, observed_weights) = limits.expected_limits(
    mode="adaptive-sally",
    model_file='models/sally',
    theta_true=[0.,0.],
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
    return_asimov=True,
)

p_values["SALLY-adaptive"] = p_values_expected_sally
mle["SALLY-adaptive"] = best_fit_expected_sally

# In[ ]:

indices = [162, 168, 234, 306, 318, 462]

fig = plot_histograms(
    histos=[histos[i] for i in indices],
    observed=[observed[i, :100, :] for i in indices],
    observed_weights=observed_weights[:100],
    histo_labels=[r"$\theta = ({:.0f},{:.0f})$".format(theta_grid[i,0], theta_grid[i,1]) for i in indices],
    xlabel=r'$\hat{t}_0(x)$',
    ylabel=r'$\hat{t}_1(x)$',
    xrange=(-2.,2),
    yrange=(-2.,2.),
    log=True,
    zrange=(1.e-3,1.),
    markersize=10.
)

# We can also use the "SALLINO" strategy, which constructs 1D histogram of `theta * score` at every parameter point on the grid:

# In[ ]:

theta_grid, p_values_expected_sallino, best_fit_expected_sallino, _, _, histos = limits.expected_limits(
    mode="sallino",
    model_file='models/sally',
    theta_true=[0.,0.],
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
)

p_values["SALLINO"] = p_values_expected_sallino
mle["SALLINO"] = best_fit_expected_sallino

# ## 5. Expected limits based on likelihood estimators

# In[ ]:

theta_grid, p_values_expected_scandal, best_fit_expected_scandal, _, _, _ = limits.expected_limits(
    mode="ml",
    model_file='models/scandal',
    theta_true=[0.,0.],
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
)

p_values["SCANDAL"] = p_values_expected_scandal
mle["SCANDAL"] = best_fit_expected_scandal

# ## 6. Toy signal

# In addition to these expected limits (based on the SM), let us inject a mock signal. We first generate the data:

# In[ ]:

#sampler = SampleAugmenter('data/lhe_data_shuffled.h5')
sampler = SampleAugmenter('data/delphes_data_shuffled.h5')
sc = 1.#1./16.52
x_observed, _, _ = sampler.sample_test(
    #theta=sampling.morphing_point([5.,1.]),
    theta=sampling.morphing_point([15.2*sc,0.1*sc]),
    n_samples=1000,
    #n_samples=100000,
    folder=None,
    filename=None,
)

# In[ ]:

_, p_values_observed, best_fit_observed, _, _, _ = limits.observed_limits(
    x_observed=x_observed,
    mode="ml",
    model_file='models/alices',
    grid_ranges=grid_ranges,
    grid_resolutions=grid_resolutions,
    luminosity=lumi,
    include_xsec=False,
)

p_values["ALICES signal"] = p_values_observed
mle["ALICES signal"] = best_fit_observed

# ## 7. Plot

# Let's plot the results:

# In[ ]:

show = "SALLY"

bin_size = (grid_ranges[0][1] - grid_ranges[0][0])/(grid_resolutions[0] - 1)
edges = np.linspace(grid_ranges[0][0] - bin_size/2, grid_ranges[0][1] + bin_size/2, grid_resolutions[0] + 1)
centers = np.linspace(grid_ranges[0][0], grid_ranges[0][1], grid_resolutions[0])

fig = plt.figure(figsize=(6,5))
ax = plt.gca()

cmin, cmax = 1.e-2, 1.

pcm = ax.pcolormesh(
    edges, edges, p_values[show].reshape((grid_resolutions[0], grid_resolutions[1])).T,
    norm=matplotlib.colors.LogNorm(vmin=cmin, vmax=cmax),
    cmap='Greys_r'
)
cbar = fig.colorbar(pcm, ax=ax, extend='both')

for i, (label, p_value) in enumerate(six.iteritems(p_values)):
    plt.contour(
        centers, centers, p_value.reshape((grid_resolutions[0], grid_resolutions[1])).T,
        levels=[0.32],
        linestyles='-', colors='C{}'.format(i)
    )
    plt.scatter(
        theta_grid[mle[label]][0], theta_grid[mle[label]][1],
        s=80., color='C{}'.format(i), marker='*',
        label=label
    )

plt.legend()

plt.xlabel(r'$\theta_0$')
plt.ylabel(r'$\theta_1$')
cbar.set_label('Expected p-value ({})'.format(show))

plt.tight_layout()
#plt.show()
plt.savefig("4aResult.pdf")

# In[ ]:

# In[ ]:

print("All done...")


from urllib.parse import urlparse
import threading

from bw_plex import LOG

def media_to_chromecast_command(media, **kw):  # pragma: no cover
    """Create the message that chromecast requires."""
    # py3 only with cba ws pychromecast is 3.4

    server_url = urlparse(media._server._baseurl)
    content_type = ('video/mp4') if media.TYPE in ('movie', 'episode') else ('audio/mp3')
    g = kw.get

    plq = media._server.createPlayQueue(media).playQueueID

    d = {
        'type': g('type', 'LOAD'),
        'requestId': g('requestid', 1),
        'media': {
            'contentId': media.key,
            'streamType': 'BUFFERED',
            'contentType': content_type,
            'customData': {
                'offset': g('offset', 0),
                'directPlay': g('directplay', True),
                'directStream': g('directstream', True),
                'subtitleSize': g('subtitlesize', 100),
                'audioBoost': g('audioboost', 100),
                'server': {
                    'machineIdentifier': media._server.machineIdentifier,
                    'transcoderVideo': g('transcodervideo', True),
                    'transcoderVideoRemuxOnly': g('transcodervideovemuxonly', False),
                    'transcoderAudio': g('transcoderAudio', True),
                    'version': '1.4.3.3433',  # media._server.version
                    'myPlexSubscription': media._server.myPlexSubscription,
                    'isVerifiedHostname': g('isVerifiedHostname', True),
                    'protocol': server_url.scheme,
                    'address': server_url.hostname,
                    'port': server_url.port,
                    'accessToken': media._server._token,  # Create a server.transit-token() method.
                    'user': {
                        'username': media._server.myPlexUsername
                    }
                },
                'containerKey': '/playQueues/{}?own=1&window=200'.format(plq)
            },
            'autoplay': g('autoplay', True),
            'currentTime': g('currenttime', 0)
        }
    }

    return d

def get_chromecast_player(host=None, name=None):  # pragma: no cover
    """ Get a chromecast preferable using host direcly, if not we will use the name and mnds (slow),
        if that dont work we will grab the first one.

    """
    try:
        import pychromecast
    except ImportError:
        LOG.warning('Failed to import pychromecast')
        return None, None

    # All isnt used atm, lets keep it and
    # ill fix it later then i create a pr
    # for plexapi or pychromecast.
    MESSAGE_TYPE = 'type'
    TYPE_PLAY = 'PLAY'
    TYPE_PAUSE = 'PAUSE'
    TYPE_STOP = 'STOP'
    TYPE_STEPFORWARD = 'STEPFORWARD'
    TYPE_STEPBACKWARD = 'STEPBACK'
    TYPE_PREVIOUS = 'PREVIOUS'
    TYPE_NEXT = 'NEXT'
    TYPE_LOAD = 'LOAD'
    TYPE_DETAILS = 'SHOWDETAILS'
    TYPE_SEEK = 'SEEK'
    TYPE_MEDIA_STATUS = 'MEDIA_STATUS'
    TYPE_GET_STATUS = 'GET_STATUS'
    TYPE_EDIT_TRACKS_INFO = 'EDIT_TRACKS_INFO'

    from pychromecast.controllers import BaseController

    class PlexController(BaseController):
        """ Controller to interact with Plex namespace. """

        def __init__(self):
            super(PlexController, self).__init__('urn:x-cast:plex', '9AC194DC')
            self.app_id = '9AC194DC'
            self.namespace = 'urn:x-cast:plex'
            self.request_id = 0
            self.play_media_event = threading.Event()

        def _send_cmd(self, msg, namespace=None, inc_session_id=False,
                      callback_function=None, inc=True):
            """Wrapper the commands."""
            self.logger.debug('Sending msg %r %s %s %s %s',
                              msg, namespace, inc_session_id, callback_function, inc)

            if inc:
                self._inc_request()

            if namespace:
                old = self.namespace
                try:
                    self.namespace = namespace
                    self.send_message(msg, inc_session_id=inc_session_id, callback_function=callback_function)
                finally:
                    self.namespace = old
            else:
                self.send_message(msg, inc_session_id=inc_session_id,
                                  callback_function=callback_function)

        def _inc_request(self):
            self.request_id += 1
            return self.request_id

        def receive_message(self, message, data):
            """ Called when a messag from plex to our controller is received.

                I havnt seen any message for ut but lets keep for for now, the
                tests i have done is minimal.
            """

            self.logger.debug('Plex media receive function called.')
            if data[MESSAGE_TYPE] == TYPE_MEDIA_STATUS:
                self.logger.debug('(PlexController) MESSAGE RECEIVED: ' + data)
                return True

            return False

        def stop(self):
            """Send stop command."""
            self._send_cmd({MESSAGE_TYPE: TYPE_STOP})

        def pause(self):
            """Send pause command."""
            self._send_cmd({MESSAGE_TYPE: TYPE_PAUSE})

        def play(self):
            """Send play command."""
            self._send_cmd({MESSAGE_TYPE: TYPE_PLAY})

        def previous(self):
            """Send previous command."""
            self._send_cmd({MESSAGE_TYPE: TYPE_PREVIOUS})

        def next(self):
            self._send_cmd({MESSAGE_TYPE: TYPE_NEXT})

        def seek(self, position, resume_state='PLAYBACK_START'):
            """Send seek command"""
            self._send_cmd({MESSAGE_TYPE: TYPE_SEEK,
                            'currentTime': position,
                            'resumeState': resume_state})

        def rewind(self):
            """Rewind back to the start"""
            self.seek(0)

        def set_volume(self, percent):
            # Feels dirty..
            self._socket_client.receiver_controller.set_volume(float(percent / 100))

        def volume_up(self, delta=0.1):
            """ Increment volume by 0.1 (or delta) unless it is already maxed.
            Returns the new volume.
            """
            if delta <= 0:
                raise ValueError(
                    "volume delta must be greater than zero, not {}".format(delta))
            return self.set_volume(self.status.volume_level + delta)

        def volume_down(self, delta=0.1):
            """ Decrement the volume by 0.1 (or delta) unless it is already 0.
            Returns the new volume.
            """
            if delta <= 0:
                raise ValueError(
                    "volume delta must be greater than zero, not {}".format(delta))
            return self.set_volume(self.status.volume_level - delta)

        def mute(self, status=None):
            """ mute the sound.
                status is just a override.
            """
            if status is not None:
                st = status
            else:
                st = not status.volume_muted

            self._socket_client.receiver_controller.set_volume_muted(st)

        def show_media(self, media):
            """Show the media on the screen, but don't start it."""
            msg = media_to_chromecast_command(media, type=TYPE_DETAILS, requestid=self._inc_request())

            def cb():
                self._send_cmd(msg, inc_session_id=True, inc=False)

            self.launch(cb)

        def quit_app(self):
            """Quit the plex app"""
            self._socket_client.receiver_controller.stop_app()

        @property
        def status(self):
            # So to get this we could add a listener and update the data ourself
            # or get can just use socket_clients
            # status should get a own pr so we can grab the subtitle (episode title.)
            # Lets just patch this for now..
            def episode_title(self):
                return self.media_metadata.get('subtitle')
            mc = self._socket_client.media_controller.status
            mc.episode_title = property(episode_title)
            return self._socket_client.media_controller.status

        def disable_subtitle(self):  # Shit does not work.
            """Disable subtitle."""
            self._send_cmd({
                MESSAGE_TYPE: TYPE_EDIT_TRACKS_INFO,
                "activeTrackIds": []
            }, namespace='urn:x-cast:com.google.cast.media')

        def _send_start_play(self, media):
            msg = media_to_chromecast_command(media, requestid=self._inc_request())
            self._send_cmd(msg, namespace='urn:x-cast:com.google.cast.media',
                           inc_session_id=True, inc=False)

        def block_until_playing(self, item, timeout=None):
            """Helper just incase this is running as a script."""
            self.play_media_event.clear()
            self.play_media(item)
            self.play_media_event.wait(timeout)
            self.play_media_event.clear()

        def play_media(self, item):
            """Start playback in the chromecast using the
               selected media.
            """
            self.play_media_event.clear()

            def app_launched_callback():
                try:
                    self._send_start_play(item)
                finally:
                    self.play_media_event.set()

            self.launch(app_launched_callback)

        def join(self, timeout=None):
            self._socket_client.join(timeout=timeout)

        def disconnect(self, timeout=None, blocking=True):
            self._socket_client.disconnect()
            if blocking:
                self.join(timeout=timeout)

    cast = None

    try:
        cast = pychromecast.Chromecast(host=host)
    except pychromecast.ChromecastConnectionError:
        chromecasts = pychromecast.get_chromecasts()
        if len(chromecasts) == 1:
            cast = chromecasts[0]
        elif len(chromecasts) > 1:
            cast = next(cc for cc in chromecasts if cc.device.friendly_name == name)
        else:
            LOG.warning("Could'nt find any chromecast on you network")
            return None, None

    pc = PlexController()
    cast.register_handler(pc)

    return pc, cast


from __future__ import print_function, division

import re
import glob
import yaml
import sqlite3
import numpy as np
from collections import Counter
from nltk import word_tokenize, sent_tokenize

def process_text(body):
    d = Counter([w for s in map(word_tokenize, sent_tokenize(body))
                 for w in s])
    norm = np.sqrt(float(sum(v*v for v in d.values())))
    d = dict((k, c / norm) for k, c in d.iteritems())
    return d

def cosine_similarity(c1, c2):
    if len(c1) > len(c2):
        c1, c2 = c2, c1
    d2 = 0.0
    for w, c in c1.iteritems():
        d2 += c * c2.get(w, 0.0)
    return d2

# Load the license text.
licenses = []
for fn in glob.iglob("../choosealicense.com/_licenses/*.txt"):
    with open(fn, "r") as f:
        txt = f.read()
        _, head, body = txt.split("---\n")
    meta = yaml.load(head)
    meta["_CONTENTS"] = process_text(body)

    if meta["title"] == "No License":
        continue

    # Parse it to get the common name.
    nm = meta["title"].strip("v.0123456789").strip()
    if nm == "Public Domain (Unlicense)":
        nm = "Public Domain"
    elif nm.startswith("CC"):
        nm = "Creative Commons"
    elif nm.startswith("GNU "):
        nm = nm[4:]
    elif "BSD" in nm:
        nm = "BSD"
    meta["common_name"] = nm

    licenses.append(meta)

# Get the unique list of common names.
license_names = list(set(l["common_name"] for l in licenses))

# Pre-compile the regular expressions.
readme_search = re.compile(r"\blicense\b", re.I | re.S)
license_search = re.compile("|".join(map(r"(\b{0}\b)".format, license_names)),
                            re.I | re.S)

# # Add the extra columns.
# with sqlite3.connect("data.db") as conn:
#     c = conn.cursor()
#     c.execute("alter table github add column license_common")
#     c.execute("alter table github add column license_name")
#     c.execute("alter table github add column readme_license")
#     c.execute("alter table github add column readme_license_name")

with sqlite3.connect("data.db") as conn:
    c = conn.cursor()
    c.execute("""select rowid, license, readme from github
        where license is not NULL or readme is not NULL""")
    rows = c.fetchall()
    total = float(len(rows))
    print("{0:.0f} total repos".format(total))

    for j, (rowid, license, readme) in enumerate(rows):
        if j % 10000 == 0:
            print(j, j / total)
        nm = None
        license_name = None
        readme_license = 0
        readme_license_name = None
        if license is not None:
            v = process_text(license.strip())
            d = [cosine_similarity(v, li["_CONTENTS"]) for li in licenses]
            i = np.argmax(d)
            license_name = "unknown" if d[i] < 0.7 else licenses[i]["title"]
            nm = "unknown" if d[i] < 0.7 else licenses[i]["common_name"]
            c.execute("update github set license_name=? where rowid=?",
                      (license_name, rowid))

        if readme is not None:
            readme_license = len(readme_search.findall(readme))
            if readme_license > 0:
                base_counts = license_search.findall(readme)
                if len(base_counts):
                    counts = np.array(map(lambda x:
                                          map(lambda y: len(y) > 0, x),
                                          base_counts))
                    ind = np.argmax(np.sum(counts, axis=0))
                    readme_license_name = license_names[ind]
                c.execute("""update github set
                    readme_license=?, readme_license_name=?
                    where rowid=?""", (readme_license, readme_license_name,
                                       rowid))
        if readme_license_name is None:
            c.execute("""update github set
                readme_license=?, readme_license_name=?
                where rowid=?""", (0, None, rowid))

        if nm is None:
            nm = readme_license_name
        if nm is not None:
            c.execute("update github set license_common=? where rowid=?",
                      (nm, rowid))


'''
Created on 2022-11-22

@author: wf
'''
from tests.basetest import Basetest
from skg.doi import DOI
from skg.dblp import Dblp
from dataclasses import dataclass
from unittest import IsolatedAsyncioTestCase
import json

@dataclass
class DOIExample:
    doi: str
    isDoi: bool

class TestDOI(Basetest):
    """
    test DOI access
    """

    def testDOICheck(self):
        """
        check DOI regex
        """
        doi_examples=[
            DOIExample("10.1007/11581116_19",True),
            DOIExample("10.1109/TBDATA.2022.3224749",True),
            DOIExample("xyz",False)]
        for doi_example in doi_examples:
            self.assertTrue(DOI.isDOI(doi_example.doi)==doi_example.isDoi,doi_example.doi)

    def test_dblp_dois(self):
        """
        test dblp dois
        """
        dblp=Dblp()
        limit=5
        debug=True
        paper_records=dblp.get_paper_records("CEUR Workshop Proceedings","publishedin",limit=limit,debug=debug)
        for paper_record in paper_records:
            print(paper_record)

    def testDOILookup(self):
        """
        test DOI lookup
        """
        debug=True
        dois=["10.1109/TBDATA.2022.3224749"]
        expected=["@article{Li_2022,","@inproceedings{Faruqui_2015,"]
        for i,doi in enumerate(dois):
            doi_obj=DOI(doi)
            result=doi_obj.doi2bibTex()
            if debug:
                print(result)
            self.assertTrue(result.startswith(expected[i]))

    def testCiteproc(self):
        """
        cite proc lookup
        """
        dois=["10.3115/v1/N15-1184",
              "10.1007/s13042-022-01686-5",
              "10.3390/info13120562",
              "10.48550/arXiv.2211.16865"]
        debug=True
        for doi in dois:
            doi_obj=DOI(doi)
            json_data=doi_obj.doi2Citeproc()
            if debug:
                print(json.dumps(json_data,indent=2))
            self.assertTrue("DOI" in json_data)
            self.assertEqual(doi.lower(),json_data["DOI"].lower())

    def testDataCiteLookup(self):
        """
        test the dataCite Lookup api
        """
        debug=True
        dois=["10.5438/0012"]
        for doi in dois:
            doi_obj=DOI(doi)
            json_data=doi_obj.dataCiteLookup()
            if debug:
                print(json.dumps(json_data,indent=2))
            self.assertTrue("data" in json_data)
            data=json_data["data"]
            self.assertTrue("id" in data)
            self.assertEquals(doi,data["id"])
            pass

    def testScite(self):
        """
        test Semantic Cite conversion
        """
        dois=["10.1007/978-3-031-21595-7_17","10.48550/ARXIV.2211.16865"]
        debug=self.debug
        for doi in dois:
            doi_obj=DOI(doi)
            markup=doi_obj.asScite()
            if debug:
                print(markup)
            self.assertTrue(f"|doi={doi}" in markup)

#class TestDOILookup(IsolatedAsyncioTestCase):
#    """
#    test DOI lookup
#    """


'''
변수 선언 왼쪽에 이름 붙이는 건 전부 객체라고 보면 된다.

리스트는 데이터가 바뀌는지 안바귀는지 확인해줘야한다.
그래서 튜플을 쓴다. 튜플은 데이터를 보호한다. append 나 insert 함수가 없다.

리스트에 대한 튜플 버전을 만든 뒤에 외부에 공개한다. 튜플은 불가변성을 가지고 있기 때문에 외부에 공개해도 바뀌지 않는다.

del로 파이썬 객체 대부분을 제거할 수 있다.

튜플은 데이터를 상수처럼 쓰고자 할 때 주로 사용한다.

괄호가 아니라 콤마로 튜플을 생성할 수 있다.

dir은 사용가능한 함수를 보여준다.
ex: dir(tuple)

'''

'''
>>> tel = {'hgs' : 7042, 'lennox' : 7018}
>>> tel['cs'] = 7000
>>> tel
{'hgs': 7042, 'lennox': 7018, 'cs': 7000}

cs라는 키에 7000이라는 value를 추가한 것이다. 딕셔너리에

key는 불변형이고 values는 가변형이다.

'''

'''
collections 라는 라이브러리에 이걸 제공했다.

튜플은 이름이 없다. 라이브러리에 이름이 있는 튜플을 named tuple 이라고 자료구조를 제공해준다.
집합 - 순서가 유동적이다. 이걸 보완하기 위해 frozen set
딕셔너리는 순서가 뒤죽박죽이다. 이거를 보완하기 위해 나온 것이 순서를 지키는 dict이다. ordered dict

'''

mydict = {'b':3, 'a':75, 75:2.85, 'r':1}
키 = input("어떤 키를 차고 계십니까? >>>")
a = mydict.get(키,"찾는 키" +키+"가 없습니다.")
print(a)

# dictionary에서 get을 사용하게 되면 해당하는 키에 맞는 value 값을 찾아주고 없는 값일 경우에는 두번째 인자의 문자메시지를 출력한다.

'''
코딩을 할 때 파일의 타입을 잘 체크해야한다.

'''


# outlier dectection using IQR
import numpy as np
data = [1, 5, 13, 27, 35, 45, 56, 67, 78, 89, 100]
outliers = []
print("Original data: ", data)
data.sort()
print("Sorted data: ", data)
data = np.array(data)
Q1 = np.percentile(data, 25)
Q3 = np.percentile(data, 75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
for i in data:
    if i < lower_bound or i > upper_bound:
        outliers.append(i)
print("Outliers: ", outliers)


import sys
from queue import PriorityQueue
input = sys.stdin.readline

def convert(string):
    converted = []

    for i in string:
        if 'a' <= i <= 'z':
            converted.append(ord(i) - ord('a') + 1)
        elif 'A' <= i <= 'Z':
            converted.append(ord(i) - ord('A') + 27)
        else:
            converted.append(0)
    return converted

def find(a):
    if a == parent[a]:
        return a
    else:
        return find(parent[a])

def union(a, b):
    a = find(a)
    b = find(b)

    if a != b:
        parent[b] = a

n = int(input())
edges = PriorityQueue()
parent = [i for i in range(n+1)]
LANS = 0
count = 0
result = 0

for i in range(n):
    LAN = convert(input())
    LANS += sum(LAN)
    for j in range(n):
        if i != j and LAN[j] != 0:
            edges.put((LAN[j], i, j))

while edges.qsize() > 0:
    w, s, e = edges.get()
    if find(s) != find(e):
        union(s, e)
        count += 1
        result += w

if count == n-1:
    print(LANS - result)
else:
    print(-1)

08 그래프/08-7 최소 신장 트리/066 불우이웃돕기.py

066 불우이웃돕기.py


# coding: utf-8

# In[1]:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# In[2]:

data = pd.read_csv('titanic.csv')
data = data.dropna()
data['age'] = data['age'].astype(int)
data.head()

# In[3]:

data.head()
data.sex = data.sex.map(dict(female=1,male=0))
data.embarked = data.embarked.map(dict(C=0,Q=1,S=2))
data['embarked'] = data['embarked'].astype(int)
data=data.drop('name',axis=1)

# In[4]:

data.head()

# In[5]:

newdata=data

# In[6]:

newdata.head()

# In[7]:

from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report

# In[8]:

def splitdata1(data):
    X=data.values[:,1:8]
    Y=data.values[:,0]
    X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=100)
    return X_train,X_test,y_train,y_test

# In[9]:

X_train1,X_test1,y_train1,y_test1=splitdata1(newdata)

# In[10]:

X_train1

# In[11]:

# Using all features:
# Here, we use all the features of the given dataset to create the decision tree and check the accuracy

# In[12]:

def generateGiniClassifierObject(X_train,X_test,y_train):
    clf_gini = DecisionTreeClassifier(criterion="gini",random_state=100,max_depth=3,min_samples_leaf=5)
    clf_gini.fit(X_train, y_train)
    return clf_gini

# In[13]:

clf1 = generateGiniClassifierObject(X_train1, X_test1, y_train1)

# In[14]:

def findPredictionForY(X_test, clf_object):
    y_pred = clf_object.predict(X_test)
    print("Predicted values:")
    print(y_pred)
    return y_pred

# In[15]:

# Function to calculate accuracy
def findAccuracyOfModel(y_test, y_pred):
    print("Confusion Matrix: ",confusion_matrix(y_test, y_pred))
    print ("Accuracy : ",accuracy_score(y_test,y_pred)*100)
    print("Report : ",classification_report(y_test, y_pred))

# In[16]:

# Using a subset of features:
# Here, we use a subset of the features of the given dataset to create the decision tree and check the accuracy
# Selected subset attributes: survived, pclass, age, sex, sibsp, parch
# Ignored attributes: fare, embarked

# In[17]:

newdata1=data.drop(['fare','embarked'],axis=1)

# In[18]:

newdata1.head()

# In[19]:

def splitdata2(data):
    X=data.values[:,1:6]
    Y=data.values[:,0]
    X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=100)
    return X_train,X_test,y_train,y_test

# In[20]:

X_train2,X_test2,y_train2,y_test2=splitdata2(newdata1)

# In[21]:

X_train2

# In[22]:

clf2=generateGiniClassifierObject(X_train2,X_test2,y_train2)

# In[23]:

# Using a modified subset of features (Changing the values of features and adding new attributes):
# Here, we use a modified subset of the features of the given dataset to create the decision tree and check the accuracy
# Modification criteria is:
# new feature family = sibsp + parch
# new feature weighted_class = pclass*2 if pclass =1 ; pclass*3 if pclass =2 ; pclass*4 if pclass =3, etc

# In[24]:

newdata2=data

# In[25]:

newdata2.head()

# In[26]:

newdata2['family']=newdata2['sibsp']+newdata2['parch']

# In[27]:

newdata2['pclass'].unique()

# In[28]:

newdata2.weighted_class=int(0)

# In[29]:

newdata2.loc[newdata2.pclass==1,'weighted_class']=2
newdata2.loc[newdata2.pclass==2,'weighted_class']=6
newdata2.loc[newdata2.pclass==3,'weighted_class']=12

# In[30]:

newdata2['weighted_class'].unique()

# In[31]:

newdata2.head()

# In[32]:

def splitdata3(data):
    X=data.values[:,1:10]
    Y=data.values[:,0]
    X_train,X_test,y_train,y_test=train_test_split(X,Y,test_size=0.2,random_state=100)
    return X_train,X_test,y_train,y_test

# In[33]:

X_train3,X_test3,y_train3,y_test3=splitdata3(newdata2)

# In[34]:

X_train3

# In[35]:

clf3=generateGiniClassifierObject(X_train3,X_test3,y_train3)

# In[36]:

def main():
    print('Decision Tree Classifier:\n')
    print('Case 1: Using all attributes:\n')
    y_pred1=findPredictionForY(X_test1,clf1)
    findAccuracyOfModel(y_test1,y_pred1)
    print('--------------------------------\n')
    print('Case 2: Using a subset of attributes:\n')
    y_pred2=findPredictionForY(X_test2,clf2)
    findAccuracyOfModel(y_test2,y_pred2)
    print('--------------------------------\n')
    print('Case 3: Using modified atttributes:\n')
    y_pred3=findPredictionForY(X_test3,clf3)
    findAccuracyOfModel(y_test3,y_pred3)
    print('--------------------------------\n')

# In[37]:

if __name__=='__main__':
    main()