"""
Run year-end work statistics
"""

from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import translation
from django.db.models import Sum, Count

import arbeitsplan.models as models

class Command(BaseCommand):
    """Go through all Users and Aufgaben.
    Check whether at most one Meldung exist.
    """

    args = ""
    help = "Produce statistics for yearly analysis"

    def handle(self, *args, **options):
        # set the locale right, to get the dates represented correctly
        translation.activate(settings.LANGUAGE_CODE)

        # Leistungen

        with open('leistungen.csv', 'w') as csvfile:
            csvfile.write('#AufgabeNr, Aufgabe, Gruppe, Angefordert(h), Geleistet(h), #Personen, #Durchschnitt\n')
            l = (models.Leistung.objects
                 .filter(status='AK')
                 .values('aufgabe','aufgabe__aufgabe',
                                               'aufgabe__anzahl','aufgabe__stunden',
                                               'aufgabe__gruppe__gruppe')\
                 .annotate(geleistet=Sum('zeit'))\
                 .annotate(melder=Count('melder', distinct=True))
                 )

            # self.stdout.write('#'.join(['{}-{}'.format(x[0], x[1]) for x in l[0].items()]))

            for ll in l:
                csvfile.write('{},{},{},{},{},{},{}\n'.format(
                    ll['aufgabe'],
                    ll['aufgabe__aufgabe'].encode('utf8'),
                    ll['aufgabe__gruppe__gruppe'].encode('utf8'),
                    ll['aufgabe__anzahl'] * ll['aufgabe__stunden'],
                    int(ll['geleistet']),
                    ll['melder'],
                    float(ll['geleistet'])/ll['melder'],
                ))

        translation.deactivate()


import os
import sys
import string
from itertools import (
    product
)
from typing import (
    List,
    Tuple,
    Any,
    Optional,
)
import contextlib

CSV_FIELD_DELIMITER: str = ","
OS_EOL_CHARACTER = os.linesep

@contextlib.contextmanager
def smart_open(filename=None):
    if filename and filename != '-':
        fh = open(filename, 'w', encoding='utf-8')
    else:
        fh = sys.stdout

    try:
        yield fh
    finally:
        if fh is not sys.stdout:
            fh.close()

def generate_alphabet_combinations(length: int = 2) -> List[str]:
    """Generate cartesian product of alphabet characters of up to the length
    If n is 2, then ['a', 'b', 'c', ..., 'aa', ..., 'zz']
    Args:
        length: length of the string generated
    Returns: Combination of alphabet characters up to length.
    """
    assert length > 0
    alphabets = string.ascii_lowercase

    return [
        ''.join(combination)
        for n in range(1, length+1)
        for combination in product(alphabets, repeat=n)
    ]

def is_number(entity: Any) -> Tuple[bool, Optional[float]]:
    """Check if the input is a number
    Args:
        entity: input variable to test
    Returns: (result, value) where value is float if the input is the number or None.
    """
    try:
        number: float = float(entity)
        return True, number
    except ValueError:
        return False, None

def test_is_number():
    assert is_number("-.1")[0]
    assert not is_number("hoge")[0]


import sys
import os
import os.path
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QComboBox, QLineEdit, QPushButton, QGridLayout, \
    QCheckBox, QProgressBar, QFileDialog, QDialog

import tc_analize

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        """
        Графический интрейфей пользователя
        :return: None
        """
        self.setFixedSize(480, 300)
        self.setWindowTitle('DOS-XML-MDB Converter')

        self.inBase = QLabel('Конвертируемая база данных:', self)
        self.inMode = QComboBox(self)
        self.inMode.addItems(['dos', 'xml', 'MDB'])
        self.inPath = QLineEdit(os.getcwd(), self)
        self.inPathPushDialog = QPushButton('Выбрать...', self)
        self.inPathPushDialog.clicked.connect(self.inputPath)
        self.inInfo = QLabel('', self)

        self.outBase = QLabel('Сохраниеть как:', self)
        self.outMode = QComboBox(self)
        self.outMode.addItems(['xml', 'MDB'])
        self.outPath = QLineEdit(os.path.expandvars('%APPDATA%'), self)
        self.outPathPushDialog = QPushButton('Выбрать...', self)
        self.outPathPushDialog.clicked.connect(self.outputPath)
        self.outInfo = QLabel('', self)

        self.hmode = QCheckBox('Сохранить структуру базы данных?', self)
        self.start = QPushButton('Приступить', self)
        self.start.clicked.connect(self.startWork)
        self.progbar = QProgressBar(self)
        self.progbar.setValue(0)
        self.toInfo = QLabel('', self)

        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(self.inBase, 0, 0, 1, 3)
        grid.addWidget(self.inMode, 1, 0)
        grid.addWidget(self.inPath, 1, 1)
        grid.addWidget(self.inPathPushDialog, 1, 2)
        grid.addWidget(self.inInfo, 2, 0, 1, 3)

        grid.addWidget(self.outBase, 3, 0, 1, 3)
        grid.addWidget(self.outMode, 4, 0)
        grid.addWidget(self.outPath, 4, 1)
        grid.addWidget(self.outPathPushDialog, 4, 2)
        grid.addWidget(self.outInfo, 5, 0, 1, 3)

        grid.addWidget(self.hmode, 6, 0, 1, 3)
        grid.addWidget(self.start, 7, 0, 1, 3)
        grid.addWidget(self.progbar, 8, 0, 1, 3)
        grid.addWidget(self.toInfo, 9, 0, 1, 3)

        self.setLayout(grid)
        self.show()

    def inputPath(self):
        """
        Файловый диалог для выбора исходной директории
        :return: None
        """
        file = os.path.normpath(QFileDialog.getExistingDirectory(self))
        self.inPath.setText(file)

    def outputPath(self):
        """
        Файловый диалог для выбора папки сохранения
        :return: None
        """
        file = os.path.normpath(QFileDialog.getExistingDirectory(self))
        self.outPath.setText(file)

    def startWork(self):
        """
        Обработка сигнала по кнопке "Приступить"
        :return: None
        """
        self.start.blockSignals(True)
        intype = self.inMode.currentText()
        inpath = os.path.normpath(self.inPath.text()).replace('\\', '/')

        outtype = self.outMode.currentText()
        outpath = os.path.normpath(self.outPath.text()).replace('\\', '/')

        strapt = self.hmode.isChecked()

        analize = tc_analize.analize(inpath, intype)

        errorcount = 0
        errorpath = os.path.join(outpath, 'errors.log')
        ferror = open(errorpath, 'w', encoding='utf-8')
        ferror.close()
        size = 0
        self.progbar.setValue(1)
        p = analize.fullsize//99
        for f in analize.files:
            f.read(intype)
            if f.error:
                errorcount += 1
                ferror = open(errorpath, 'a', encoding='utf-8')
                if intype == 'dos':
                    ferror.write('{} {} {}\n'.format(f.dos_name, f.error.name, f.error.note))
                ferror.close()
            else:
                if strapt:
                    f.save(outtype, os.path.join(outpath, os.path.relpath(f.path, inpath)))
                else:
                    f.save(outtype, outpath)
            size += f.size
            self.progbar.setValue(1 + size//p)
        if errorcount == 0:
            os.remove(errorpath)
        self.infodialog(len(analize.files), errorcount)
        self.start.blockSignals(False)

    def infodialog(self, all, errors=None):
        """
        Окно в конце обрабокти, которое показывает сколько было обработано файлов
        :param all: всего файлов
        :param errors: файлов с ошибками
        :return: None
        """
        d = QDialog()
        d.setWindowTitle("info")
        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(QLabel('Обработано файлов: {}'.format(all)), 0, 0)
        if errors:
            grid.addWidget(QLabel('Успешно: {}'.format(all-errors)), 1, 0)
            grid.addWidget(QLabel('Список ошибок в errors.log'), 2, 0)
        else:
            grid.addWidget(QLabel('Ошибок нет', 1, 0))
        d.setLayout(grid)
        d.exec_()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


import neural_network_functions as nn_funcs
from neural_network import NeuralNetwork
from matplotlib import pyplot as plt
import random

nn = NeuralNetwork([3, 1], nn_funcs.sigmoid_act_f, nn_funcs.linear_cost_f)

# DATASET -> I'm trying to create a nn that detects if sum of 3 inputs are 1.5 or higher

dataset = []
expected_outputs = []

for i in range(2000):
    dataset.append([random.uniform(0, 1), random.uniform(0, 1), random.uniform(0, 1)])

    if dataset[i][0] > 0.8 or dataset[i][1] > 0.3 or dataset[i][2] > 0.3:
        expected_outputs.append([1])
    else:
        expected_outputs.append([0])

    # expected_outputs.append([1 if sum(dataset[i]) >= 1.5 else 0])

# Dividing data in two groups, training group and control group
training_data_len = int(len(dataset) * 0.7)

training_data = dataset[:training_data_len]
expected_training_data = expected_outputs[:training_data_len]

control_data = dataset[training_data_len:]
expected_control_data = expected_outputs[training_data_len:]

nn.train(training_data, expected_outputs[:training_data_len], 200, 0.01)

print(nn)

correct_predictions = 0
for data_index in range(len(control_data)):
    output = nn.get_output(control_data[data_index])
    if output[0] > 0.5:
        output = 1
    else:
        output = 0

    if output == expected_control_data[data_index][0]:
        correct_predictions += 1

print("Predicted correctly {}/{} inputs".format(correct_predictions, len(control_data)))

X = range(len(nn.historic))
Y = nn.historic
plt.scatter(X, Y)

plt.show()

print("Prueba introduciendo números del 0 al 1")

while True:
    _input = [float(input("x0: ")), float(input("x1: ")), float(input("x2: "))]
    print(nn.get_output(_input))


from kivy.app import App
from kivymd.app import MDApp
from kivy.lang import Builder
from kvdroid.tools import speech
from kvdroid.tools.audio import Player
import os
import datetime
from kivymd.uix.list import OneLineIconListItem, OneLineAvatarIconListItem, ImageLeftWidget, IconRightWidget
from kvdroid.tools import toast
from kivy.uix.screenmanager import Screen
from kvdroid.tools.contact import get_contact_details
from kivy.utils import platform
from android.config import ACTIVITY_CLASS_NAME, ACTIVITY_CLASS_NAMESPACE
from android.permissions import request_permissions, Permission
from kivy.uix.gridlayout import GridLayout

import vlc
import webbrowser
import pygame

pygame.mixer.init()

Code= '''
MDNavigationLayout:
	ScreenManager:
		MainScreen:
			BoxLayout:
				orientation: "vertical"
				spacing: dp(5)
				MDToolbar:
					title: "Tinsel Player"
					md_bg_color: (1, .5, 0, 1)
					specific_text_color: (1, 1, 1, 1)
					left_action_items: [["menu"]]
					right_action_items: [["magnify"]]

				RV:
					id: rv

				MDGridLayout:
					cols: 1
					rows: 2
					size_hint_y: None
					height: dp(80)
					id: grid
					md_bg_color: (1, .5, 0, 1)

					OneLineIconListItem:
						id: mist
						theme_text_color: "Custom"
						text_color: (1, 1, 1, 1)

					GridLayout:

						rows: 1
						cols: 3
						spacing: dp(self.width/6)

						MDIconButton:
							icon: "skip-previous"
							theme_text_color: "Custom"
							text_color: (1, 1, 1, 1)
							on_press: app.Previous()
							id: m_back

						MDIconButton:
							icon: "play"
							theme_text_color: "Custom"
							text_color: (1, 1, 1, 1)
							on_press: app.Play()
							id: m_play

						MDIconButton:
							icon: "skip-next"
							theme_text_color: "Custom"
							text_color: (1, 1, 1, 1)
							on_press: app.Next()
							id: m_next

<RV@RecycleView>

	viewclass:'CustomIconItem'
	RecycleBoxLayout:
		orientation: "vertical"
		size_hint_y:None
		height:self.minimum_height

'''
class CustomIconItem(OneLineAvatarIconListItem):
	pass
class MainScreen(Screen):
	pass

class DownLayout(GridLayout):
	pass

class app(MDApp):
    def __init__(self, **kwargs):
    	super().__init__(**kwargs)
    	self.x = 0

    def build(self):
        return Builder.load_string(Code)

    def on_start(self):
    	#I_R_W = IconRightWidget("play")
    	#self.root.ids.OneId.add_widget(I_R_W)

    	self.Music = []
    	self.Music1 = []

    	directory = []
    	path = "//storage//emulated//0"
    	for filename in os.listdir(path):
    		if filename.endswith(".mp3") or filename.endswith(".m4a"):
    			self.Music.append(os.path.join(path, filename))
    			self.Music1.append(filename)

    	directory = []
    	path = "//storage//emulated//0"
    	for filename in os.listdir(path):
    		if filename.endswith(".mp3") or filename.endswith("m4a") or filename.endswith(".mp4") or filename.endswith(".png") or filename.endswith(".jpg") or filename.endswith(".smi") or filename.endswith(".docx") or filename.endswith(".pdf") or filename.endswith(".zip") or "." in filename:
    			pass
    		else:
    			directory.append(os.path.join(path, filename))

    	directory = []
    	path = "//storage//emulated//0"
    	for filename in os.listdir(path):
    		if "." in filename:
    			pass
    		elif filename.endswith(".mp3") or filename.endswith(".m4a"):
    			self.Music.append(os.path.join(path, filename))
    			self.Music1.append(filename)
    		else:
    			directory.append(os.path.join(path, filename))

    	directory1 = []
    	x = len(directory)
    	for name in range(x):
    		path = directory[name]
    		for filename in os.listdir(path):
    			if "." in filename:
    				pass
    			else:
    				directory1.append(os.path.join(path, filename))

    	directory2 = []
    	x = len(directory1)
    	for name in range(x):
    		path = directory1[name]
    		for  filename in os.listdir(path):
    			if filename.endswith(".mp3") or filename.endswith(".m4a"):
    				self.Music.append(os.path.join(path, filename))
    				self.Music1.append(filename)
    			elif "." in filename or "_" in filename:
    				pass
    			else:
    				directory2.append(os.path.join(path, filename))

    	directory3 = []
    	x = len(directory2)
    	for name in range(x):
    		path = directory2[name]
    		for filename in os.listdir(path):
    			if filename.endswith(".mp3") or filename.endswith(".m4a"):
    				self.Music.append(os.path.join(path, filename))
    				self.Music1.append(filename)
    			elif "." in filename or "_" in filename:
    				pass
    			else:
    				directory3.append(os.path.join(path, filename))

    	data = [{'text':str(1+i)+": "+str(self.Music1[i]),  'size_hint_x':1,'id':str(self.Music[i]),  'on_release': lambda x= i: self.play_music(self.Music[x], self.Music1[x])  } for i in range(len(self.Music))]
    	self.root.ids.rv.data = data

    def play_music(self, text, text2):
          webbrowser.open(text)

          self.player = Player()
          self.player.play(text)

          self.root.ids.mist.text = str(text2)
          self.player.do_loop(True)
          self.name1 = str(text)
          self.name2 = text2
          self.root.ids.m_play.icon = "pause"

    def Play(self):
    	if self.root.ids.m_play.icon == "pause":
    		self.root.ids.m_play.icon = "play"
    		self.player.pause()
    		self.player.do_loop(True)

    	elif self.root.ids.m_play.icon == "play":
    		self.root.ids.m_play.icon = "pause"
    		self.player.resume()
    		self.player.do_loop(True)

    def Previous(self):
    	self.x -= 1
    	numx  = self.Music.index(self.name1) + self.x
    	num = numx
    	if num >= 0:
	    	self.player = Player()
	    	self.player.play(self.Music[num])
	    	self.root.ids.mist.text = str(self.Music1[num])
	    	self.player.do_loop(True)

    def Next(self):
    	self.x += 1
    	numx  = self.Music.index(self.name1) + self.x
    	num = numx
    	if num >= 1 or num <= (len(self.Music) - 1):
	    	self.player = Player()
	    	self.player.play(self.Music[num])
	    	self.root.ids.mist.text = str(self.Music1[num])
	    	self.player.do_loop(True)

app().run()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jul  9 10:03:22 2018

@author: Eduardo & Natalia
Here we implement several spectral & discrete compactness score.
"""

import networkx as nx
import numpy as np

def first_evalue(H):
    spectrum = nx.laplacian_spectrum(H)

    return spectrum[1]

def heat_kernel(H,t):
    e_values = nx.laplacian_spectrum(H)
    np.delete(e_values, 0)
    exp = [np.exp((-e_value)*t) for e_value in e_values]

    return np.sum(exp)

def log_span_trees(H):
    spectrum = nx.laplacian_spectrum(H)
    non_zero_spect = np.delete(spectrum, 0)

    return np.sum(np.log(non_zero_spect))

def discrete_pp(G,H,boundary_nodes):
    # Adding a supernode for proper perimeter calculation
    # Name of the supernode is -1
    boundary_edges = [(-1, node) for node in G.nodes if boundary_nodes[node] is True]
    G.add_edges_from(boundary_edges)

    nodes_H = {node for node in H.nodes}
    perimeter = nx.cut_size(G, nodes_H)
    area = len(H.nodes())
    # Remove supernode as to not alter the graph G
    G.remove_node(-1)

    return (perimeter**2)/area


from django.shortcuts import render

from .models import Article

# Create your views here.
def blog(request):

    articles = Article.objects.filter(online=True).order_by('last_update_date')
    categories = Article.get_categories_from(articles)

    context = {
        'articles': articles,
        'categories': categories,
    }

    return render(request, 'arteablog/blog/index.html', context)

def article(request, id):

    article = Article.objects.filter(id=id).first()

    context = {
        'article': article,
    }

    return render(request, 'arteablog/article/index.html', context)


N = int(input())
L = []
while True:
    try:
        a = list(map(int,input().split()))
    except:
        break
    else:
        L.append(a)

stk1 = [i for i in range(N,0,-1)]
stk2 = []
stk3 = []

for i in range(len(L)):
    if L[i][0] == 1:
        for j in range(L[i][1]):
            stk2.append(stk1.pop())
    else:
        for j in range(L[i][1]):
            stk3.append(stk2.pop())

for i in stk3[::-1]:
    print(i)


#!/usr/bin/env python3
"""
Created on Thu May 12 12:06:18 2022
@author: Fiona

To get ranges for plotting (for report, not necessary for running controllers)
add  <node pkg="f1tenth_mpc" name="plotter" type="plot_ftg.py" output="screen"></node>
to launch file
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sys
import csv
#ROS Imports
import rospy
from sensor_msgs.msg import LaserScan
from std_msgs.msg import String

class Plotter():
    """
    """
    def __init__(self, add_markers=True, time_step=0.1):
        self.setup_nodes()

    def  setup_nodes(self) :
        laser_topic= '/scan'
        laser_sub=rospy.Subscriber(laser_topic, LaserScan, self.lidar_callback)

        key_topic= '/key'
        key_sub=rospy.Subscriber(key_topic, String, self.key_callback)

    def key_callback(self, data:String):
        if data.data=="p":
            self.make_plots()
    def make_plots(self):
        self.preprocess_lidar(self.lidar_data)

    def preprocess_lidar(self, ranges):
        """ Preprocess the LiDAR scan array. Expert implementation includes:
            1.Setting each value to the mean over some window
            2.Rejecting high values (eg. > 3m)
        """
        cwd=sys.path[0]
        print(cwd)
        csv_filepath=cwd
        with open(cwd+"/ftg_ranges_example.csv", "w")as f:
            writer = csv.writer(f)

                 # write a row to the csv file
            writer.writerow(ranges)
        #print(ranges, file="ftg_ranges_example")
        print("done")

    def lidar_callback(self, data:LaserScan):
        """ Process each LiDAR scan as per the Follow Gap algorithm & publish an AckermannDriveStamped Message
        """
        self.amin=data.angle_min
        self.amax=data.angle_max
        self.angle_increment=data.angle_increment
        self.lidar_data=data.ranges

def main(args):

    rospy.init_node("mpc_node", anonymous=True)
    rospy.loginfo("starting up mpc node")

    plotter=Plotter()
    #rospy.Timer(rospy.Duration(30), model_predictive_control.plot_mpc)

    #rospy.sleep(time_step)
    rospy.spin()

if __name__=='__main__':
	main(sys.argv)


class Solution:
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums = sorted(nums)
        length = len(nums)
        res = []
        for i in range(length):
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            aim = nums[i] * -1
            start = i + 1
            end = length - 1
            while start < end:
                if nums[start] + nums[end] == aim:
                    res.append([nums[i], nums[start], nums[end]])
                    start += 1
                    while start < end and nums[start] == nums[start -1]:
                        start += 1
                elif nums[start] + nums[end] < aim:
                    start += 1
                else:
                    end -= 1
        return res

if __name__ == "__main__":
    a = Solution()
    nums = [-1,0,1,2,-1,-4]
    print(a.threeSum(nums))


VERSION = '0.2'
APPNAME = 'NDNlive'

from waflib import Build, Logs, Utils, Task, TaskGen, Configure

def options(opt):
    opt.load('compiler_c compiler_cxx gnu_dirs')
    opt.load('boost default-compiler-flags doxygen', tooldir=['.waf-tools'])

    ropt = opt.add_option_group('ndnlive Options')

def configure(conf):
    conf.load("compiler_c compiler_cxx gnu_dirs boost default-compiler-flags")

    conf.check_cfg(package='libndn-cxx', args=['--cflags', '--libs'],
                   uselib_store='NDN_CXX', mandatory=True)

    conf.check_cfg(package='gstreamer-1.0', args=['--cflags', '--libs'],
         uselib_store='GSTREAMER', mandatory=True)

    conf.env.LIB_PTHREAD = 'pthread'

    USED_BOOST_LIBS = ['system', 'iostreams', 'filesystem', 'random']
    conf.check_boost(lib=USED_BOOST_LIBS, mandatory=True)
#   ['system', 'filesystem', 'date_time', 'iostreams',
#                      'regex', 'program_options', 'chrono', 'random']

    try:
        conf.load("doxygen")
    except:
        pass

    conf.define('DEFAULT_CONFIG_FILE', '%s/ndn/next-ndnvideo.conf' % conf.env['SYSCONFDIR'])

    conf.write_config_header('src/config.hpp')

def build(bld):

    bld(target="producer",
        features=["cxx", "cxxprogram"],
        source= "src/producer.cpp src/video-generator.cpp src/producer-callback.cpp",
        use='GSTREAMER BOOST NDN_CXX PTHREAD',
        )

    bld(target="consumer",
        features=["cxx", "cxxprogram"],
        source= "src/consumer.cpp src/video-player.cpp src/consumer-callback.cpp src/video-frame.cpp",
        use='GSTREAMER BOOST NDN_CXX PTHREAD',
        )

    bld.install_files('${SYSCONFDIR}/ndn', 'next-ndnvideo.conf.sample')


import FWCore.ParameterSet.Config as cms

from Analysis.VLQAna.JetSelector_cfi import *

process = cms.Process("Demo")

process.load("FWCore.MessageService.MessageLogger_cfi")

process.MessageLogger.cerr.FwkReport.reportEvery = 1000

process.maxEvents = cms.untracked.PSet( input = cms.untracked.int32(-1) )

process.source = cms.Source("PoolSource",
    # replace 'myfile.root' with the source file you want to use
    fileNames = cms.untracked.vstring(

	'file:/home/t3-ku/erichjs/store/b2g/Spring15/TToTH/TprimeTToTH_M-1200_LH_TuneCUETP8M1_13TeV-madgraph-pythia8/TprimeTToTH_M-1200_LH/150620_211013/0000/B2GEDMNtuple_1.root'
    )
)

process.analyze = cms.EDAnalyzer('TprimeAna'
)
process.load ("UserCode.TprimeAna.presel_cfi")

process.TFileService = cms.Service("TFileService", fileName = cms.string('Tprime1200_LH_900trig.root') )

process.out = cms.OutputModule("PoolOutputModule",
    fileName = cms.untracked.string("SingleTprime800AnaEvts.root"),
    SelectEvents = cms.untracked.PSet(
      SelectEvents = cms.vstring('p')
      ),
    outputCommands = cms.untracked.vstring(
      "drop *",
      "keep *_genPart_*_*",
      "keep *_jetsAK4_*_*",
      "keep *_jetsAK8_*_*",
      "keep *_*_npv_*",
      "keep *_subjets*_*_*",
      "keep *_ana_*_*",
      "keep *_vjj_*_*",
      )
    )

process.p = cms.Path(process.presel*process.analyze)
#process.p = cms.Path(process.presel)

#process.p = cms.Schedule(p2)
#process.outpath = cms.EndPath(process.out)


import re
import urllib
import urllib2
import urlparse
import HTMLParser
import logging
from pprint import pprint, pformat

import html5charref

__version__ = '0.1.0'

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())

ESCAPABLE = '[!"#$%&\'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]'
ESCAPED_CHAR = '\\\\' + ESCAPABLE
IN_DOUBLE_QUOTES = '"(' + ESCAPED_CHAR + '|[^"\\x00])*"'
IN_SINGLE_QUOTES = '\'(' + ESCAPED_CHAR + '|[^\'\\x00])*\''
IN_PARENS = '\\((' + ESCAPED_CHAR + '|[^)\\x00])*\\)'
REG_CHAR = '[^\\\\()\\x00-\\x20]'
IN_PARENS_NOSP = '\\((' + REG_CHAR + '|' + ESCAPED_CHAR + ')*\\)'
TAGNAME = '[A-Za-z][A-Za-z0-9]*'

_block_tag_names = [
    'article', 'header', 'aside', 'hgroup', 'iframe', 'blockquote', 'hr',
    'body', 'li', 'map', 'button', 'object', 'canvas', 'ol', 'caption',
    'output', 'col', 'p', 'colgroup', 'pre', 'dd', 'progress', 'div',
    'section', 'dl', 'table', 'td', 'dt', 'tbody', 'embed', 'textarea',
    'fieldset', 'tfoot', 'figcaption', 'th', 'figure', 'thead', 'footer',
    'footer', 'tr', 'form', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'video',
    'script', 'style',
]
BLOCKTAGNAME = '(?:{0})'.format('|'.join(_block_tag_names))
ATTRIBUTENAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*'
UNQUOTEDVALUE = "[^\"'=<>`\\x00-\\x20]+"
SINGLEQUOTEDVALUE = "'[^']*'"
DOUBLEQUOTEDVALUE = '"[^"]*"'
ATTRIBUTEVALUE = "(?:" + UNQUOTEDVALUE + "|" + SINGLEQUOTEDVALUE + "|" + DOUBLEQUOTEDVALUE + ")"
ATTRIBUTEVALUESPEC = "(?:" + "\\s*=" + "\\s*" + ATTRIBUTEVALUE + ")"
ATTRIBUTE = "(?:" + "\\s+" + ATTRIBUTENAME + ATTRIBUTEVALUESPEC + "?)"
OPENTAG = "<" + TAGNAME + ATTRIBUTE + "*" + "\\s*/?>"
CLOSETAG = "</" + TAGNAME + "\\s*[>]"
OPENBLOCKTAG = "<" + BLOCKTAGNAME + ATTRIBUTE + "*" + "\\s*/?>"
CLOSEBLOCKTAG = "</" + BLOCKTAGNAME + "\\s*[>]"
HTMLCOMMENT = "<!--([^-]+|[-][^-]+)*-->"
PROCESSINGINSTRUCTION = "[<][?].*?[?][>]"
DECLARATION = "<![A-Z]+" + "\\s+[^>]*>"
CDATA = "<!\\[CDATA\\[([^\\]]+|\\][^\\]]|\\]\\][^>])*\\]\\]>"
HTMLTAG = "(?:" + OPENTAG + "|" + CLOSETAG + "|" + HTMLCOMMENT + "|" + PROCESSINGINSTRUCTION + "|" + DECLARATION + "|" + CDATA + ")"
HTMLBLOCKOPEN = "<(?:" + BLOCKTAGNAME + "[\\s/>]" + "|" + "/" + BLOCKTAGNAME + "[\\s>]" + "|" + "[?!])"

reHtmlTag = re.compile('^' + HTMLTAG, re.I)

reHtmlBlockOpen = re.compile('^' + HTMLBLOCKOPEN, re.I)

reLinkTitle = re.compile(
    '^(?:"(' + ESCAPED_CHAR + '|[^"\\x00])*"' +
    '|' +
    '\'(' + ESCAPED_CHAR + '|[^\'\\x00])*\'' +
    '|' +
    '\\((' + ESCAPED_CHAR + '|[^)\\x00])*\\))')

reLinkDestinationBraces = re.compile(
    '^(?:[<](?:[^<>\\n\\\\\\x00]' + '|' + ESCAPED_CHAR + '|' + '\\\\)*[>])')

reLinkDestination = re.compile(
    '^(?:' + REG_CHAR + '+|' + ESCAPED_CHAR + '|' + IN_PARENS_NOSP + ')*')

RE_ESCAPABLE = re.compile(ESCAPABLE)

reAllEscapedChar = re.compile('\\\\(' + ESCAPABLE + ')')

reEscapedChar = re.compile('^\\\\(' + ESCAPABLE + ')')

reHrule = re.compile('^(?:(?:\* *){3,}|(?:_ *){3,}|(?:- *){3,}) *$')

# Matches a character with a special meaning in markdown,
# or a string of non-special characters.
reMain = re.compile(r'(?:[\n`\[\]\\!<&*_]|[^\n`\[\]\\!<&*_]+)', re.M)

class ParseError(Exception):
    """
    Generic exception thrown when errors are encountered parsing markdown.
    """
    pass

# UTILITY FUNCTIONS
def unescape(s):
    """ Replace backslash escapes with literal characters.
    """
    return reAllEscapedChar.sub('\g<1>', s)

def unescape_html_entity(entity):
    html_escape_table = {
        "&": "&",
        '"': """,
        "'": "'",
        ">": ">",
        "<": "<",
     }

    char = html5charref.unescape(entity)
    if char == entity:
        if entity[1] == '#':
            char = u'\uFFFD'
        else:
            char = u'&' + entity[1:]

    elif char in html_escape_table:
        char = html_escape_table[char]

    return char

def unescape_html(s):

    def repl(m):
        return unescape_html_entity(m.group(0))

    return re.sub(
        r'&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});',
        repl,
        s,
        flags=re.I,
    )

def is_blank(s):
    """ Returns true if string contains only space characters.
    """
    return bool(re.match(r'^\s*$', s))

def normalize_reference(s):
    """
    Normalize reference label: collapse internal whitespace
    to single space, remove leading/trailing whitespace, case fold.

    """
    return re.sub(r'\s+', ' ', s.strip()).upper()

def match_at(regex, s, offset):
    """
    Attempt to match a regex in string s at offset offset.
    Return index of match or null.

    """
    match = regex.search(s[offset:])
    if match:
        return offset + match.start()
    return None

def detab_line(text):
    """ Convert tabs to spaces on each line using a 4-space tab stop.
    """
    if '\t' not in text:
        return text
    else:
        def repl(m):
            offset = m.start()
            result = '    '[(offset - repl.last_stop) % 4:]
            repl.last_stop = offset + 1
            return result
        repl.last_stop = 0
        return re.sub(r'\t', repl, text)

def parse_raw_label(s):
    """
    Parse raw link label, including surrounding [], and return
    inline contents.  (Note:  this is not a method of InlineParser.)

    """
    # Note: Parse without a refmap we don't want links to resolve
    # in nested brackets!
    return InlineParser().parse(s[1:-1], {})

def splice(inlist, index):
    while len(inlist) > index:
        inlist.pop()

def parse_list_marker(line, offset):
    """
    Parse a list marker and return data on the marker (type,
    start, delimiter, bullet character, padding) or null.

    """
    rest = line[offset:]
    spaces_after_marker = None
    data = ListData()
    if reHrule.search(rest):
        return None

    match = re.match(r'^[*+-]( +|$)', rest)
    if match:
        spaces_after_marker = len(match.group(1))
        data.type = 'Bullet'
        data.bullet_char = match.group(0)[0]

    else:
        match = re.match(r'^(\d+)([.)])( +|$)', rest)
        if match:
            spaces_after_marker = len(match.group(3))
            data.type = 'Ordered'
            data.start = int(match.group(1))
            data.delimiter = match.group(2)

        else:
            return None

    blank_item = len(match.group(0)) == len(rest)
    if spaces_after_marker >= 5 or spaces_after_marker < 1 or blank_item:
        data.padding = len(match.group(0)) - spaces_after_marker + 1
    else:
        data.padding = len(match.group(0))

    return data

def lists_match(list_data, item_data):
    """
    Returns true if the two list items are of the same type,
    with the same delimiter and bullet character.  This is used
    in agglomerating list items into lists.

    """
    return (list_data.type == item_data.type and
            list_data.delimiter == item_data.delimiter and
            list_data.bullet_char == item_data.bullet_char)

def ends_with_blank_line(block):
    """
    Returns true if block ends with a blank line, descending if needed
    into lists and sublists.

    """
    if block.last_line_blank:
        return True
    if block.t in ['List', 'ListItem'] and block.children:
        return ends_with_blank_line(block.children[-1])
    else:
        return False

def can_contain(parent_type, child_type):
    """ Returns true if parent block can contain child block.
    """
    return (parent_type in ['Document', 'BlockQuote', 'ListItem'] or
            (parent_type == 'List' and child_type == 'ListItem'))

def accepts_lines(block_type):
    """ Returns true if block type can accept lines of text.
    """
    return block_type in ['Paragraph', 'IndentedCode', 'FencedCode']

def url_fix(s, charset='utf-8'):
    """
    Sometimes you get an URL by a user that just isn't a real
    URL because it contains unsafe characters like ' ' and so on.  This
    function can fix some of the problems in a similar way browsers
    handle data entered by the user:

    >>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl�rung)')
    'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'

    :param charset: The target charset for the URL if the url was
                    given as unicode string.
    """
#     print 'URL', s
    if isinstance(s, unicode):
        s = s.encode(charset, 'ignore')
    scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
#     print 'BEFORE', scheme, '|', netloc, '|', path, '|', qs, '|', anchor
    if scheme in ['mailto']:
        return s
    else:
        netloc = urllib.quote(netloc, ':')
        path = urllib.quote(path, '/%()*:')
        qs = urllib.quote_plus(qs, ':&=*')
#         print 'AFTER', scheme, '|', netloc, '|', path, '|', qs, '|', anchor
        return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))

class Dumper(object):
    """ Debug printer. """

    def dump(self):
        d = {}
        for k, v in self.__dict__.items():
            if k == 'parent':
                d[k] = v
            elif isinstance(v, list):
                d[k] = [lv.dump() if hasattr(lv, 'dump') else lv for lv in v]
            else:
                d[k] = v.dump() if hasattr(v, 'dump') else v
        return (self.__class__.__name__, d)

class Block(Dumper):

    def __init__(self):
        super(Block, self).__init__()
        self.tag = ''
        self.t = ''
        self.open = True
        self.last_line_blank = False
        self.start_line = None
        self.end_line = None
        self.start_column = None
        self.inline_content = []
        self.string_content = ''
        self.strings = []
        self.children = []
        self.tight = False
        self.info = ''

    @staticmethod
    def makeBlock(tag, start_line, start_column):
        block = Block()
        block.t = tag
        block.open = True
        block.last_line_blank = False
        block.start_line = start_line
        block.start_column = start_column
        block.end_line = start_line
        block.children = []
        block.parent = None
        # string_content is formed by concatenating strings, in finalize.
        block.string_content = ''
        block.strings = []
        block.inline_content = []
        return block

class Inline(Dumper):

    def __init__(self, c=None, t=None, **kwargs):
        super(Inline, self).__init__()
        self.c = c
        self.t = t
        for k, v in kwargs.items():
            setattr(self, k, v)

class InlineParser(Dumper):
    """
    An InlineParser keeps track of a subject (a string to be
    parsed) and a position in that subject.

    """

    def __init__(self):
        super(InlineParser, self).__init__()
        self.subject = ''
        self.label_nest_level = 0
        self.pos = 0
        self.refmap = dict()

    def match(self, regex):
        """
        If regex matches at current position in the subject, advance
        position in subject and return the match otherwise return None.

        """
        m = regex.search(self.subject[self.pos:])
        if m:
            self.pos += (m.start() + len(m.group(0)))
            return m.group(0)
        else:
            return None

    def peek(self):
        """
        Returns the character at the current subject position, or None if
        there are no more characters.
        """
        try:
            return self.subject[self.pos]
        except IndexError:
            return None

    def spnl(self):
        """
        Parse zero or more space characters, including at most one newline.
        """
        self.match(re.compile(r'^ *(?:\n *)?'))
        return 1

    def parse_backticks(self, inlines):
        """
        All of the parsers below try to match something at the current position
        in the subject.  If they succeed in matching anything, they
        push an inline element onto the 'inlines' list.  They return the
        number of characters parsed (possibly 0).

        Attempt to parse backticks, adding either a backtick code span or a
        literal sequence of backticks to the 'inlines' list.

        """
        startpos = self.pos
        ticks = self.match(re.compile(r'^`+'))
        if not ticks:
            return 0

        after_open_ticks = self.pos

        match = self.match(re.compile(r'`+', re.M))
        while match:
            if match == ticks:
                inline = Inline(
                    t='Code',
                    c=re.sub(r'[ \n]+', ' ', self.subject[after_open_ticks:(self.pos - len(ticks))]).strip(),
                )
                inlines.append(inline)
                return self.pos - startpos

            match = self.match(re.compile(r'`+', re.M))

        inlines.append(Inline(t='Str', c=ticks))
        self.pos = after_open_ticks
        return self.pos - startpos

    def parse_escaped(self, inlines):
        """
        Parse a backslash-escaped special character, adding either the escaped
        character, a hard line break (if the backslash is followed by a newline),
        or a literal backslash to the 'inlines' list.

        """
        subj = self.subject
        pos = self.pos
        if subj[pos] == '\\':
            if pos < len(subj) - 1:
                if subj[pos + 1] == '\n':
                    inlines.append(Inline(t='Hardbreak'))
                    self.pos = self.pos + 2
                    return 2
                elif RE_ESCAPABLE.search(subj[pos + 1]):
                    inlines.append(Inline(t='Str', c=subj[pos + 1]))
                    self.pos = self.pos + 2
                    return 2

            self.pos += 1
            inlines.append(Inline(t='Str', c='\\'))
            return 1

        else:
            return 0

    def parse_autolink(self, inlines):
        """ Attempt to parse an autolink (URL or email in pointy brackets).
        """
        dest = None
        m = self.match(re.compile(r'^<([a-zA-Z0-9.!#$%&\'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>'))
        if m:
            dest = m[1:-1]
            inlines.append(
                Inline(
                    t='Link',
                    label=[Inline(t='Str', c=dest)],
                    destination='mailto:' + dest,
                    title='',
                )
            )
            return len(m)

        else:
            keys = [
                'coap', 'doi', 'javascript', 'aaa', 'aaas', 'about', 'acap',
                'cap', 'cid', 'crid', 'data', 'dav', 'dict', 'dns', 'file',
                'ftp', 'geo', 'go', 'gopher', 'h323', 'http', 'https', 'iax',
                'icap', 'im', 'imap', 'info', 'ipp', 'iris', 'iris.beep',
                'iris.xpc', 'iris.xpcs', 'iris.lwz', 'ldap', 'mailto', 'mid',
                'msrp', 'msrps', 'mtqp', 'mupdate', 'news', 'nfs', 'ni',
                'nih', 'nntp', 'opaquelocktoken', 'pop', 'pres', 'rtsp',
                'service', 'session', 'shttp', 'sieve', 'sip', 'sips', 'sms',
                'snmp', 'soap.beep', 'soap.beeps', 'tag', 'tel', 'telnet',
                'tftp', 'thismessage', 'tn3270', 'tip', 'tv', 'urn', 'vemmi',
                'ws', 'wss', 'xcon', 'xcon-userid', 'xmlrpc.beep',
                'xmlrpc.beeps', 'xmpp', 'z39.50r', 'z39.50s', 'adiumxtra',
                'afp', 'afs', 'aim', 'apt', 'attachment', 'aw', 'beshare',
                'bitcoin', 'bolo', 'callto', 'chrome', 'chrome-extension',
                'com-eventbrite-attendee', 'content', 'cvs', 'dlna-playsingle',
                'dlna-playcontainer', 'dtn', 'dvb', 'ed2k', 'facetime',
                'feed', 'finger', 'fish', 'gg', 'git', 'gizmoproject', 'gtalk',
                'hcp', 'icon', 'ipn', 'irc', 'irc6', 'ircs', 'itms', 'jar',
                'jms', 'keyparc', 'lastfm', 'ldaps', 'magnet', 'maps',
                'market', 'message', 'mms', 'ms-help', 'msnim', 'mumble',
                'mvn', 'notes', 'oid', 'palm', 'paparazzi', 'platform',
                'proxy', 'psyc', 'query', 'res', 'resource', 'rmi', 'rsync',
                'rtmp', 'secondlife', 'sftp', 'sgn', 'skype', 'smb', 'soldat',
                'spotify', 'ssh', 'steam', 'svn', 'teamspeak', 'things',
                'udp', 'unreal', 'ut2004', 'ventrilo', 'view-source',
                'webcal', 'wtai', 'wyciwyg', 'xfire', 'xri', 'ymsgr',
            ]
            m = self.match(re.compile(r'^<(?:{0}):[^<>\x00-\x20]*>'.format('|'.join(keys)), re.I))
            if m:
                dest = m[1:-1]
                inlines.append(Inline(t='Link', label=[Inline(t='Str', c=dest)], destination=dest, title=''))
                return len(m)

            else:
                return 0

    def parse_html_tag(self, inlines):
        """ Attempt to parse a raw HTML tag.
        """
        m = self.match(reHtmlTag)
        if m:
            inlines.append(Inline(t='Html', c=m))
            return len(m)
        else:
            return 0

    def scan_delims(self, c):
        """
        Scan a sequence of characters == c, and return information about
        the number of delimiters and whether they are positioned such that
        they can open and/or close emphasis or strong emphasis.  A utility
        function for strong/emph parsing.

        """
        numdelims = 0
        startpos = self.pos

        char_before = '\n' if self.pos == 0 else self.subject[self.pos - 1]
        while self.peek() == c:
            numdelims += 1
            self.pos += 1

        char_after = self.peek() or '\n'

        can_open = numdelims > 0 and numdelims <= 3 and not re.search(r'\s', char_after)
        can_close = numdelims > 0 and numdelims <= 3 and not re.search(r'\s', char_before)
        if c == '_':
            can_open = can_open and not re.search(r'[a-z0-9]', char_before, re.I)
            can_close = can_close and not re.search(r'[a-z0-9]', char_after, re.I)

        # Rewind pos.
        self.pos = startpos
        return {'numdelims': numdelims, 'can_open': can_open, 'can_close': can_close}

    def parse_emphasis(self, inlines):
        """
        Attempt to parse emphasis or strong emphasis in an efficient way,
        with no backtracking.

        """
        startpos = self.pos
        c = None
        first_close = 0
        nxt = self.peek()

        if nxt == '*' or nxt == '_':
            c = nxt
        else:
            return 0

        # Get opening delimiters.
        res = self.scan_delims(c)
        self.pos += res['numdelims']

        # We provisionally add a literal string.  If we match appropriate
        # closing delimiters, we'll change this to Strong or Emph.
        inlines.append(Inline(t='Str', c=self.subject[self.pos - res['numdelims']:self.pos]))

        # Record the position of this opening delimiter
        delimpos = len(inlines) - 1

        if not res['can_open'] or res['numdelims'] == 0:
            return 0

        first_close_delims = 0

        if res['numdelims'] == 1:
            while True:
                res = self.scan_delims(c)
#                 pprint([i.dump() for i in inlines])
#                 print 'RES', pformat(res)
                if res['numdelims'] >= 1 and res['can_close']:
                    self.pos += 1
                    # Convert the inline at delimpos, currently a string with the delim,
                    # into an Emph whose contents are the succeeding inlines.
                    inlines[delimpos].t = 'Emph'
                    inlines[delimpos].c = inlines[delimpos + 1:]
                    splice(inlines, delimpos + 1)
                    break
                else:
                    if self.parse_inline(inlines) == 0:
                        break
#             print 'END'
#             pprint([i.dump() for i in inlines])
            return self.pos - startpos

        elif res['numdelims'] == 2:  # We started with ** or __
            while True:
                res = self.scan_delims(c)
                if res['numdelims'] >= 2 and res['can_close']:
                    self.pos += 2
                    inlines[delimpos].t = 'Strong'
                    inlines[delimpos].c = inlines[delimpos + 1:]
                    splice(inlines, delimpos + 1)
                    break
                else:
                    if self.parse_inline(inlines) == 0:
                        break

            return self.pos - startpos

        elif res['numdelims'] == 3:
            while True:
                res = self.scan_delims(c)
#                 print 'RES', res
#                 print 'FCD', first_close_delims
                if res['numdelims'] >= 1 and res['numdelims'] <= 3 and res['can_close'] and res['numdelims'] != first_close_delims:
                    if first_close_delims == 1 and res['numdelims'] > 2:
                        res['numdelims'] = 2
                    elif first_close_delims == 2:
                        res['numdelims'] = 1
                    elif res['numdelims'] == 3:
                        # If we opened with ***, then we interpret *** as ** followed by *
                        # giving us <strong><em>
                        res['numdelims'] = 1

                    self.pos += res['numdelims']

                    if first_close > 0:  # If we've already passed the first closer.
                        inlines[delimpos].t = 'Strong' if first_close_delims == 1 else 'Emph'
                        inlines[delimpos].c = [Inline(
                            t='Emph' if first_close_delims == 1 else 'Strong',
                            c=inlines[delimpos + 1:first_close],
                        )]
                        inlines[delimpos].c.extend(inlines[first_close + 1:])
                        splice(inlines, delimpos + 1)
                        break

                    else:
                        # This is the first closer for now, add literal string.
                        # We'll change this when we hit the second closer.
                        inlines.append(Inline(t='Str', c=self.subject[self.pos - res['numdelims']:self.pos]))
#                         print 'Emph IL'
#                         pprint([i.dump() for i in inlines])
                        first_close = len(inlines) - 1
                        first_close_delims = res['numdelims']
                else:
                    if self.parse_inline(inlines) == 0:
                        break

            return self.pos - startpos

        else:
            return 1

        return 0

    def parse_link_title(self):
        """
        Attempt to parse link title (sans quotes), returning the string
        or null if no match.

        """
        title = self.match(reLinkTitle)
        if title:
            # Chop off quotes from title and unescape
            return unescape_html(unescape(title[1:-1]))
#             return unescape(title[1:-1])
        else:
            return None

    def parse_link_destination(self):
        """
        Attempt to parse link destination, returning the string or
        null if no match.

        """
        res = self.match(reLinkDestinationBraces)
        if res:
            return unescape(unescape_html(res[1:-1]))
        else:
            res = self.match(reLinkDestination)
            if res is not None:
                return unescape(unescape_html(res))
            else:
                return None

    def parse_link_label(self):
        """
        Attempt to parse a link label, returning number of characters parsed.

        """
        if self.peek() != '[':
            return 0

        startpos = self.pos
        nest_level = 0
        if self.label_nest_level > 0:
            # If we've already checked to the end of this subject
            # for a label, even with a different starting [, we
            # know we won't find one here and we can just return.
            # This avoids lots of backtracking.
            # Note:  nest level 1 would be: [foo [bar]
            #        nest level 2 would be: [foo [bar [baz]
            self.label_nest_level -= 1
            return 0

        self.pos += 1  # Advance past [ char.
        c = self.peek()
        while c and (c != ']' or nest_level > 0):
            if c == '`':
                self.parse_backticks([])
            elif c == '<':
                self.parse_autolink([]) or self.parse_html_tag([]) or self.parse_string([])
            elif c == '[':  # Nested []
                nest_level += 1
                self.pos += 1
            elif c == ']':  # Nested []
                nest_level -= 1
                self.pos += 1
            elif c == '\\':
                self.parse_escaped([])
            else:
                self.parse_string([])
            c = self.peek()

        if c == ']':
            self.label_nest_level = 0
            self.pos += 1  # Advance past ]
            return self.pos - startpos
        else:
            if not c:
                self.label_nest_level = nest_level
            self.pos = startpos
            return 0

    def parse_link(self, inlines):
        """ Attempt to parse a link.  If successful, add the link to inlines.
        """
#         print 'PARSING LINK'
        startpos = self.pos

        n = self.parse_link_label()
        if n == 0:
            return 0

        rawlabel = self.subject[startpos:startpos + n]
#         print 'RAWL', rawlabel
        # If we got this far, we've parse a label.
        # Try to parse an explicit link: [label](url "title")
        if self.peek() == '(':
#             print 'PEEK'
            self.pos += 1
            if self.spnl():
                dest = self.parse_link_destination()
#                 print 'DEST', dest
                if dest is not None and self.spnl():
                    # Make sure there's a space before the title
                    match = re.search(r'^\s', self.subject[self.pos - 1])
                    if match:
                        title = self.parse_link_title() or ''
                    else:
                        title = ''
                    if self.spnl() and self.match(re.compile(r'^\)')):
                        inlines.append(
                            Inline(
                                t='Link',
                                destination=dest,
                                title=title,
                                label=parse_raw_label(rawlabel),
                            )
                        )
                        return self.pos - startpos

            self.pos = startpos
            return 0

        # If we're here, it wasn't an explicit link. Try to parse a reference link.
        # first, see if there's another label
        savepos = self.pos
        self.spnl()
        beforelabel = self.pos
        n = self.parse_link_label()
        if n == 2:
            # Empty second label.
            reflabel = rawlabel
        elif n > 0:
            reflabel = self.subject[beforelabel:beforelabel + n]
        else:
            self.pos = savepos
            reflabel = rawlabel

        # Lookup rawlabel in refmap
        link = self.refmap.get(normalize_reference(reflabel))
        if link:
            inlines.append(
                Inline(
                    t='Link',
                    destination=link.destination,
                    title=link.title,
                    label=parse_raw_label(rawlabel),
                )
            )
            return self.pos - startpos

        else:
            self.pos = startpos
            return 0

        # Nothing worked, rewind
        self.pos = startpos
        return 0

    def parse_entity(self, inlines):
        """ Attempt to parse an entity, adding to inlines if successful.
        """
        m = self.match(re.compile(r'^&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});', re.I))
        if m:
            inlines.append(Inline(t='Entity', c=unescape_html_entity(m)))
            return len(m)
        else:
            return 0

    def parse_string(self, inlines):
        """
        Parse a run of ordinary characters, or a single character with
        a special meaning in markdown, as a plain string, adding to inlines.

        """
        m = self.match(reMain)
        if m:
            if inlines and inlines[-1].t == 'Softbreak':
                inlines.append(Inline(t='Str', c=m.lstrip()))
            else:
                inlines.append(Inline(t='Str', c=m))
            return len(m)
        else:
            return 0

    def parse_newline(self, inlines):
        """
        Parse a newline.  If it was preceded by two spaces, return a hard
        line break otherwise a soft line break.

        """
        if self.peek() == '\n':
            self.pos += 1
            last = inlines[-1] if inlines else None
            if last and last.t == 'Str' and last.c[-2:] == '  ':
                last.c = re.sub(r' *$', '', last.c)
                inlines.append(Inline(t='Hardbreak'))
            else:
                if last and last.t == 'Str' and last.c[-1] == ' ':
                    last.c = last.c[:-1]
                inlines.append(Inline(t='Softbreak'))

            return 1
        else:
            return 0

    def parse_image(self, inlines):
        """
        Attempt to parse an image.  If the opening '!' is not followed
        by a link, add a literal '!' to inlines.

        """
        if self.match(re.compile(r'^!')):
            n = self.parse_link(inlines)
            if n == 0:
                inlines.append(Inline(t='Str', c='!'))
                return 1
            elif inlines and inlines[-1] and inlines[-1].t == 'Link':
                inlines[-1].t = 'Image'
                return n + 1
            else:
                raise ParseError("Shouldn't happen: parsing Image.")

        else:
            return 0

    def parse_reference(self, s, refmap):
        """ Attempt to parse a link reference, modifying refmap.
        """
#         print 'PARSING REFER', s

        self.subject = s
        self.pos = 0
        startpos = self.pos

        # Label
        match_chars = self.parse_link_label()
        if match_chars == 0:
            return 0
        else:
            rawlabel = self.subject[:match_chars]

        # Colon
        if self.peek() == ':':
            self.pos += 1
        else:
            self.pos = startpos
            return 0

        # Consume optional spaces and newline
        self.spnl()

        # Link URL
        dest = self.parse_link_destination()
        if not dest:
            self.pos = startpos
            return 0

        beforetitle = self.pos

        # Consume optional spaces and newline
        self.spnl()

        title = self.parse_link_title()
        if title is None:
            title = ''
            # Rewind before spaces
            self.pos = beforetitle

        # Text after title, not a reference definition.
#         print 'AFTER REF', self.pos, repr(self.subject[self.pos:])
        if len(self.subject) - 1 > self.pos:
            for c in self.subject[self.pos:]:
                if c == '\n':
                    break
                elif re.match(r'\S', c):
                    self.pos = startpos
                    return 0

        normlabel = normalize_reference(rawlabel)

        if normlabel not in refmap:
            refmap[normlabel] = Inline(destination=dest, title=title)
#             print 'ADDING REF', normlabel, refmap[normlabel].dump()

        return self.pos - startpos

    def parse_inline(self, inlines):
        """
        Parse the next inline element in subject, advancing subject position
        and adding the result to 'inlines'.

        """
        c = self.peek()
#         print 'C', repr(c)
#         print 'POS', self.pos
#         print 'SUB', repr(self.subject)
#         pprint([i.dump() for i in inlines])
        r = None
        if c == '\n':
            r = self.parse_newline(inlines)
        elif c == '\\':
            r = self.parse_escaped(inlines)
        elif c == '`':
            r = self.parse_backticks(inlines)
        elif c == '*' or c == '_':
            r = self.parse_emphasis(inlines)
        elif c == '[':
            r = self.parse_link(inlines)
        elif c == '!':
            r = self.parse_image(inlines)
        elif c == '<':
            r = self.parse_autolink(inlines) or self.parse_html_tag(inlines)
        elif c == '&':
            r = self.parse_entity(inlines)

        if not r:
            r = self.parse_string(inlines)

#         print 'AfterSUB', repr(self.subject)
#         pprint([i.dump() for i in inlines])

        return r

    def parse(self, s, refmap):
        """ Parse s as a list of inlines, using refmap to resolve references.
        """
        self.subject = s
        self.pos = 0
        self.refmap = refmap or {}
        inlines = []
        while self.parse_inline(inlines):
#             pprint([i.dump() for i in inlines])
            pass
        return inlines

class ListData(Dumper):

    def __init__(self):
        super(ListData, self).__init__()
        self.type = None
        self.bullet_char = None
        self.start = None
        self.delimiter = None
        self.padding = None

class DocParser(Dumper):

    def __init__(self):
        super(DocParser, self).__init__()
        self.doc = Block.makeBlock('Document', 1, 1)
        self.tip = self.doc
        self.refmap = dict()
        self.inlineParser = InlineParser()
        self.top = 0

    def break_out_of_lists(self, block, line_number):
        """
        Break out of all containing lists, resetting the tip of the
        document to the parent of the highest list, and finalizing
        all the lists.  (This is used to implement the "two blank lines
        break of of all lists" feature.)

        """
        b = block
        last_list = None
        while True:
            if b.t == 'List':
                last_list = b
            b = b.parent
            if not b:
                break

        if last_list:
            while block != last_list:
                self.finalize(block, line_number)
                block = block.parent

            self.finalize(last_list, line_number)
            self.tip = last_list.parent

    def add_line(self, line, offset):
        """
        Add a line to the block at the tip.  We assume the tip
        can accept lines -- that check should be done before calling this.

        """
        s = line[offset:]
        if not self.tip.open:
            raise ParseError('Attempted to add line ({0}) to closed container.'.format(line))
        self.tip.strings.append(s)

    def add_child(self, tag, line_number, offset):
        """
        Add block of type tag as a child of the tip.  If the tip can't
        accept children, close and finalize it and try its parent,
        and so on til we find a block that can accept children.

        """
        while not can_contain(self.tip.t, tag):
            self.finalize(self.tip, line_number)

        column_number = offset + 1  # Offset 0 = column 1
        new_block = Block.makeBlock(tag, line_number, column_number)
        self.tip.children.append(new_block)
        new_block.parent = self.tip
        self.tip = new_block
        return new_block

    def incorporate_line(self, line, line_number):
        """
        Analyze a line of text and update the document appropriately.
        We parse markdown text by calling this on each line of input,
        then finalizing the document.

        """
        all_matched = True
        offset = 0
        CODE_INDENT = 4
        container = self.doc
        oldtip = self.tip
        blank = False

        # Convert tabs to spaces.
        line = detab_line(line)

        # For each containing block, try to parse the associated line start.
        # Bail out on failure: container will point to the last matching block.
        # Set all_matched to false if not all containers match.
        while container.children:
            last_child = container.children[-1]
            if not last_child.open:
                break
            container = last_child

            match = match_at(re.compile(r'[^ ]'), line, offset)
            if match is None:
                first_nonspace = len(line)
                blank = True
            else:
                first_nonspace = match
                blank = False
            indent = first_nonspace - offset

            if container.t == 'BlockQuote':
                matched = (indent <= 3 and first_nonspace < len(line) and line[first_nonspace] == '>')
                if matched:
                    offset = first_nonspace + 1
                    if offset < len(line) and line[offset] == ' ':
                        offset += 1
                else:
                    all_matched = False

            elif container.t == 'ListItem':
                if indent >= container.list_data.marker_offset + container.list_data.padding:
                    offset += container.list_data.marker_offset + container.list_data.padding
                elif blank:
                    offset = first_nonspace
                else:
                    all_matched = False

            elif container.t == 'IndentedCode':
                if indent >= CODE_INDENT:
                    offset += CODE_INDENT
                elif blank:
                    offset = first_nonspace
                else:
                    all_matched = False

            elif container.t in ['ATXHeader', 'SetextHeader', 'HorizontalRule']:
                # A header can never containe >1 line, so fail to match:
                all_matched = False

            elif container.t == 'FencedCode':
                # Skip optional spaces of fence offset.
                i = container.fence_offset
                while i > 0 and line[offset] == ' ':
                    offset += 1
                    i -= 1

            elif container.t == 'HtmlBlock':
                if blank:
                    all_matched = False

            elif container.t == 'Paragraph':
                if blank:
                    container.last_line_blank = True
                    all_matched = False
            else:
                pass

            if not all_matched:
                container = container.parent  # Back up to last matching block.
                break

        last_matched_container = container

        # This function is used to finalize and close any unmatched
        # blocks.  We aren't ready to do this now, because we might
        # have a lazy paragraph continuation, in which case we don't
        # want to close unmatched blocks.  So we store this closure for
        # use later, when we have more information.
        def closeUnmatchedBlocks(mythis):
            closeUnmatchedBlocks.oldtip = oldtip
            # finalize any blocks not matched
            while not closeUnmatchedBlocks.already_done and closeUnmatchedBlocks.oldtip != last_matched_container:
                mythis.finalize(closeUnmatchedBlocks.oldtip, line_number)
                closeUnmatchedBlocks.oldtip = closeUnmatchedBlocks.oldtip.parent
            closeUnmatchedBlocks.already_done = True

        closeUnmatchedBlocks.already_done = False

        # Check to see if we've hit 2nd blank line, if so break out of list.
        if blank and container.last_line_blank:
            self.break_out_of_lists(container, line_number)

        # Unless last matched container is a code block, try new container starts,
        # adding children to the last matched container.
        while (container.t not in ['FencedCode', 'IndentedCode', 'HtmlBlock'] and
               match_at(re.compile(r'^[ #`~*+_=<>0-9-]'), line, offset) is not None):

            match = match_at(re.compile(r'[^ ]'), line, offset)
            if match is None:
                first_nonspace = len(line)
                blank = True
            else:
                first_nonspace = match
                blank = False

            indent = first_nonspace - offset

            if indent >= CODE_INDENT:
                # Indented code
                if self.tip.t != 'Paragraph' and not blank:
                    offset += CODE_INDENT
                    closeUnmatchedBlocks.already_done = False
                    closeUnmatchedBlocks(self)
                    oldtip = closeUnmatchedBlocks.oldtip
                    container = self.add_child('IndentedCode', line_number, offset)
                else:  # Indent > 4 in a lazy paragraph continuation.
                    break

            elif first_nonspace < len(line) and line[first_nonspace] == '>':
                # Blockquote
                offset = first_nonspace + 1
                # Optional following space
                if offset < len(line) and line[offset] == ' ':
                    offset += 1
                closeUnmatchedBlocks.already_done = False
                closeUnmatchedBlocks(self)
                oldtip = closeUnmatchedBlocks.oldtip
                container = self.add_child('BlockQuote', line_number, offset)

            else:
                match = re.match(r'^#{1,6}(?: +|$)', line[first_nonspace:])
                if match:
                    # ATX Header
                    offset = first_nonspace + len(match.group(0))
                    closeUnmatchedBlocks.already_done = False
                    closeUnmatchedBlocks(self)
                    oldtip = closeUnmatchedBlocks.oldtip
                    container = self.add_child('ATXHeader', line_number, first_nonspace)
                    container.level = len(match.group(0).strip())  # Numver of #'s
                    # Remove trailing #'s
                    container.strings = [re.sub(r'(.*?)(?: *(?<!\\)#*)*$', '\g<1>', line[offset:])]
                    break

                else:
                    match = re.match(r'^`{3,}(?!.*`)|^~{3,}(?!.*~)', line[first_nonspace:])
                    if match:
                        # Fenced code block
                        fence_length = len(match.group(0))
                        closeUnmatchedBlocks.already_done = False
                        closeUnmatchedBlocks(self)
                        oldtip = closeUnmatchedBlocks.oldtip
                        container = self.add_child('FencedCode', line_number, first_nonspace)
                        container.fence_length = fence_length
                        container.fence_char = match.group(0)[0]
                        container.fence_offset = first_nonspace - offset
                        offset = first_nonspace + fence_length
                        break

                    elif match_at(reHtmlBlockOpen, line, first_nonspace) is not None:
                        # Html block
                        closeUnmatchedBlocks.already_done = False
                        closeUnmatchedBlocks(self)
                        oldtip = closeUnmatchedBlocks.oldtip
                        container = self.add_child('HtmlBlock', line_number, first_nonspace)
                        # Note, we don't adjsut offset because the tag is part of the text
                        break

                    else:
                        match = re.match(r'^(?:=+|-+) *$', line[first_nonspace:])
                        if container.t == 'Paragraph' and len(container.strings) == 1 and match:
                            # Setext header line
                            closeUnmatchedBlocks.already_done = False
                            closeUnmatchedBlocks(self)
                            oldtip = closeUnmatchedBlocks.oldtip
                            container.t = 'SetextHeader'  # Convert Paragraph to SetextHeader
                            container.level = 1 if match.group(0)[0] == '=' else 2
                            offset = len(line)

                        elif match_at(reHrule, line, first_nonspace) is not None:
                            # Hrule
                            closeUnmatchedBlocks.already_done = False
                            closeUnmatchedBlocks(self)
                            oldtip = closeUnmatchedBlocks.oldtip
                            container = self.add_child('HorizontalRule', line_number, first_nonspace)
                            offset = len(line) - 1
                            break

                        else:
                            data = parse_list_marker(line, first_nonspace)
                            if data:
                                # List item
                                closeUnmatchedBlocks.already_done = False
                                closeUnmatchedBlocks(self)
                                oldtip = closeUnmatchedBlocks.oldtip
                                data.marker_offset = indent
                                offset = first_nonspace + data.padding

                                # Add the list if needed
                                if container.t != 'List' or not lists_match(container.list_data, data):
                                    container = self.add_child('List', line_number, first_nonspace)
                                    container.list_data = data

                                # Add the list item
                                container = self.add_child('ListItem', line_number, first_nonspace)
                                container.list_data = data

                            else:
                                break

            if accepts_lines(container.t):
                # If it's a line container, it can't contain other containers.
                break

        # What remains at the offset is a text line.  Add the text to the
        # appropriate container.
        match = match_at(re.compile(r'[^ ]'), line, offset)
        if match is None:
            first_nonspace = len(line)
            blank = True
        else:
            first_nonspace = match
            blank = False
        indent = first_nonspace - offset

        # First check for a lazy paragraph continuation
        if self.tip != last_matched_container and not blank and self.tip.t == 'Paragraph' and self.tip.strings:
            # Lazy paragraph continuation
            self.last_line_blank = False
            self.add_line(line, offset)

        else:
            # Not a lazy continuation
            # Finalize any blocks not matched
            closeUnmatchedBlocks.already_done = False
            closeUnmatchedBlocks(self)
            oldtip = closeUnmatchedBlocks.oldtip

            # Block quote lines are never blank as they start with >
            # and we don't count blanks in fenced code for purposes of tight/loose
            # lists or breaking out of lists.  We also don't set last_line_blank
            # on an empty list item.
            container.last_line_blank = (
                blank and
                    not (container.t in ['BlockQuote', 'FencedCode'] or
                        (container.t == 'ListItem' and
                            not container.children and
                            container.start_line == line_number)))

            cont = container
            while cont.parent:
                cont.parent.last_line_blank = False
                cont = cont.parent

            if container.t in ['IndentedCode', 'HtmlBlock']:
                self.add_line(line, offset)

            elif container.t == 'FencedCode':
                # Check for closing code fence.
                match = re.match(r'^(?:`{3,}|~{3,})(?= *$)', line[first_nonspace:])
                if indent <= 3 and first_nonspace < len(line) and line[first_nonspace] == container.fence_char and match and len(match.group(0)) >= container.fence_length:
                    # Don't add closing fence to container instead, close it.
                    self.finalize(container, line_number)
                else:
                    self.add_line(line, offset)

            elif container.t in ['ATXHeader', 'SetextHeader', 'HorizontalRule']:
                # Nothing to do we already added the contents
                pass
            else:
                if accepts_lines(container.t):
                    self.add_line(line, first_nonspace)
                elif blank:
                    pass
                elif container.t not in ['HorizontalRule', 'SetextHeader']:
                    # Create Paragraph container for line.
                    container = self.add_child('Paragraph', line_number, first_nonspace)
                    self.add_line(line, first_nonspace)
                else:
                    logger.warning('Line {0} with container type {1} did not match any condition.'.format(line_number, container.t))

    def finalize(self, block, line_number):
        """
        Finalize a block.  Close it and do any necessary postprocessing,
        e.g. creating string_content from strings, setting the 'tight'
        or 'loose' status of a list, and parsing the beginnings
        of paragraphs for reference definitions.  Reset the tip to the
        parent of the closed block.

        """
        pos = None
        # Don't do anything if the block is already closed.
        if not block.open:
            return 0
        block.open = False
        if line_number > block.start_line:
            block.end_line = line_number - 1
        else:
            block.end_line = line_number

        if block.t == 'Paragraph':
            block.string_content = re.sub(r'^  *', '', '\n'.join(block.strings), re.M)
#             print 'CONTENT', block.string_content
            # Try parsing the beginning as link reference definitions.
            pos = self.inlineParser.parse_reference(block.string_content, self.refmap)
#             print 'AFTER', pos, block.string_content[0], repr(block.string_content[pos:])
            while block.string_content[0] == '[' and pos:
                block.string_content = block.string_content[pos:]
                if is_blank(block.string_content):
                    block.t = 'ReferenceDef'
                    break
                else:
                    while block.string_content[0] == '\n':
                        block.string_content = block.string_content[1:]

                pos = self.inlineParser.parse_reference(block.string_content, self.refmap)
#             print 'AFTER', pos, block.string_content

        elif block.t in ['ATXHeader', 'SetextHeader', 'HtmlBlock']:
            block.string_content = '\n'.join(block.strings)

        elif block.t == 'IndentedCode':
            block.string_content = re.sub(r'(\n *)*$', '\n', '\n'.join(block.strings))

        elif block.t == 'FencedCode':
            # First line becomes info string.
            block.info = unescape(unescape_html(block.strings[0].strip()))
            if len(block.strings) == 1:
                block.string_content = ''
            else:
                block.string_content = '\n'.join(block.strings[1:]) + '\n'

        elif block.t == 'List':
            block.tight = True  # Tight by default

            for i, item in enumerate(block.children):
                # Check for non-finallist item ending with blank line.
                last_item = (i == len(block.children) - 1)
                if ends_with_blank_line(item) and not last_item:
                    block.tight = False
                    break

                # Recurse into children of list item, to see if there are
                # spaces between any of them.
                for j, subitem in enumerate(item.children):
                    last_subitem = (j == len(item.children) - 1)
                    if ends_with_blank_line(subitem) and not (last_item and last_subitem):
                        block.tight = False
                        break

        else:
            pass

        self.tip = block.parent or self.top

    def process_inlines(self, block):
        """
        Walk through a block & children recursively, parsing string content
        into inline content where appropriate.

        """
        if block.t in ['Paragraph', 'SetextHeader', 'ATXHeader']:
            block.inline_content = self.inlineParser.parse(block.string_content.strip(), self.refmap)
            block.string_content = ''
        else:
            pass

        if block.children:
            for child in block.children:
                self.process_inlines(child)

    def parse(self, text):
        """ The main parsing function.  Returns a parsed document AST.
        """
        self.doc = Block.makeBlock('Document', 1, 1)
        self.tip = self.doc
        self.refmap = dict()
        lines = re.split(r'\r\n|\n|\r', re.sub(r'\n$', '', text))
        for i, line in enumerate(lines):
            self.incorporate_line(line, i + 1)
        while self.tip:
            self.finalize(self.tip, len(lines) - 1)
#         print 'PREINLINE'
#         pprint(self.doc.dump())
        self.process_inlines(self.doc)
        return self.doc

class HtmlRenderer(Dumper):

    def __init__(self):
        super(HtmlRenderer, self).__init__()
        self.blocksep = '\n'
        self.innersep = '\n'
        self.softbreak = '\n'

    @staticmethod
    def in_tags(tag, attrs, contents, selfclosing=False):
        result = '<' + tag
        if attrs:
            for attr in attrs:
                if attr is None:
                    break
                result += u' {0}="{1}"'.format(attr[0], attr[1])

        if contents:
            result += u'>{0}</{1}>'.format(contents, tag)
        elif selfclosing:
            result += u' />'
        else:
            result += u'></{0}>'.format(tag)
        return result

    def url_escape(self, s, preserve_entities=False):
        return self.escape(url_fix(s), preserve_entities)

    def escape(self, s, preserve_entities=False):
        if preserve_entities:
            s = re.sub(r'[&](?![#](x[a-f0-9]{1,8}|[0-9]{1,8};)|[a-z][a-z0-9]{1,31};)', '&', s, flags=re.I)
            s = re.sub(r'[<]', '<', s)
            s = re.sub(r'[>]', '>', s)
            s = re.sub(r'["]', '"', s)
            return s
        else:
            s = re.sub(r'[&]', '&', s)
            s = re.sub(r'[<]', '<', s)
            s = re.sub(r'[>]', '>', s)
            s = re.sub(r'["]', '"', s)
            return s

    def render_inline(self, inline):
        """ Render an inline element as HTML.
        """
        attrs = None
        if inline.t == 'Str':
            return self.escape(inline.c)
        elif inline.t == 'Softbreak':
            return self.softbreak
        elif inline.t == 'Hardbreak':
            return self.in_tags('br', [], "", True) + '\n'
        elif inline.t == 'Emph':
            return self.in_tags('em', [], self.render_inlines(inline.c))
        elif inline.t == 'Strong':
            return self.in_tags('strong', [], self.render_inlines(inline.c))
        elif inline.t == 'Html':
            return inline.c
        elif inline.t == 'Entity':
            return inline.c
        elif inline.t == 'Link':
            attrs = [['href', self.url_escape(inline.destination, True)]]
            if inline.title:
                attrs.append(['title', self.escape(inline.title, True)])
            return self.in_tags('a', attrs, self.render_inlines(inline.label))
        elif inline.t == 'Image':
            attrs = [
                ['src', self.escape(inline.destination, True)],
                ['alt', self.escape(self.render_inlines(inline.label))],
            ]
            if inline.title:
                attrs.append(['title', self.escape(inline.title, True)])
            return self.in_tags('img', attrs, "", True)
        elif inline.t == 'Code':
            return self.in_tags('code', [], self.escape(inline.c))
        else:
            logger.warning('Unknown inline type: {}'.format(inline.t))
            return ''

    def render_inlines(self, inlines):
        """ Render a list of inlines.
        """
        result = []
        for inline in inlines:
            result.append(self.render_inline(inline))
        return ''.join(result)

    def render_block(self, block, in_tight_list=False):
        """ Render a single block element.
        """
        tag = None
        attr = None
        info_words = None

        if block.t == 'Document':
            whole_doc = self.render_blocks(block.children)
            return '' if whole_doc == '' else whole_doc + '\n'

        elif block.t == 'Paragraph':
            if in_tight_list:
                return self.render_inlines(block.inline_content)
            else:
                return self.in_tags('p', [], self.render_inlines(block.inline_content))

        elif block.t == 'BlockQuote':
            filling = self.render_blocks(block.children)
            filling = self.innersep if filling == '' else self.innersep + filling + self.innersep
            return self.in_tags('blockquote', [], filling)

        elif block.t == 'ListItem':
            return self.in_tags('li', [], self.render_blocks(block.children, in_tight_list).strip())

        elif block.t == 'List':
            tag = 'ul' if block.list_data.type == 'Bullet' else 'ol'
            if not block.list_data.start or block.list_data.start == 1:
                attr = []
            else:
                attr = [['start', str(block.list_data.start)]]

            return self.in_tags(tag, attr, self.innersep +
                          self.render_blocks(block.children, block.tight) +
                          self.innersep)

        elif block.t in ['ATXHeader', 'SetextHeader']:
            tag = 'h{}'.format(block.level)
            return self.in_tags(tag, [], self.render_inlines(block.inline_content))

        elif block.t == 'IndentedCode':
            return self.in_tags('pre', [], self.in_tags('code', [], self.escape(block.string_content)))

        elif block.t == 'FencedCode':
            info_words = re.split(r' +', block.info)
            if not info_words or not len(info_words[0]):
                attr = []
            else:
                attr = [['class', 'language-' + self.escape(info_words[0], True)]]
            return self.in_tags('pre', [], self.in_tags('code', attr, self.escape(block.string_content)))

        elif block.t == 'HtmlBlock':
            return block.string_content

        elif block.t == 'ReferenceDef':
            return ""

        elif block.t == 'HorizontalRule':
            return self.in_tags('hr', [], "", True)

        else:
            logger.warning('Unknown block type: {}'.format(block.t))
            return ''

    def render_blocks(self, blocks, in_tight_list=False):
        """ Render a list of block elements, separated by this.blocksep.
        """
        result = []
        for block in blocks:
            if block.t != 'ReferenceDef':
                result.append(self.render_block(block, in_tight_list))
        return self.blocksep.join(result)


from sage.all import *
from polyrank import *

import unittest
import coverage

class TestPolyRankMMatrix(unittest.TestCase):
    def test_matrix_addition(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        m_2 = mmatrix.MMatrix(matrix([[5, 6], [7, 8]]))

        result = m_1 + m_2
        expected = matrix([[6, 8], [10, 12]])

        self.assertEqual(result.matrix, expected)

    def test_matrix_subtraction(self):
        m_1 = mmatrix.MMatrix(matrix([[5, 6], [7, 8]]))
        m_2 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))

        result = m_1 - m_2
        expected = matrix([[4, 4], [4, 4]])

        self.assertEqual(result.matrix, expected)

    def test_matrix_multiplication(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        m_2 = mmatrix.MMatrix(matrix([[5, 6], [7, 8]]))

        result = m_1 * m_2
        expected = matrix([[19, 22], [43, 50]])

        self.assertEqual(result.matrix, expected)

    def test_matrix_get_item(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))

        row = list(m_1[0])
        expected = [1, 2]

        self.assertEqual(row, expected)

    def test_matrix_set_item(self):
        m_1 = mmatrix.MMatrix(matrix([[0, 0], [3, 4]]))
        m_1[0] = [1, 2]

        expected = matrix([[1, 2], [3, 4]])

        self.assertEqual(m_1.matrix, expected)

    def test_matrix_row_size(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2, 3], [4, 5, 6]]))

        row_size = m_1.row_size()
        expected = 3

        self.assertEqual(row_size, expected)

    def test_matrix_column_size(self):
        m_1 = mmatrix.MMatrix(matrix([[1], [2], [3]]))

        column_size = m_1.column_size()
        expected = 3

        self.assertEqual(column_size, expected)

    def test_matrix_row_reduce(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))

        result = m_1.row_reduce()[0]
        expected = matrix([[1, 0], [0, -2]])

        self.assertEqual(result.matrix, expected)

    def test_matrix_scalar_mult(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        m_1.scalar_mult(2)

        expected = matrix([[2, 4], [6, 8]])

        self.assertEqual(m_1.matrix, expected)

    def test_matrix_swap_rows(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        m_1.swap_rows(0, 1)

        expected = matrix([[3, 4], [1, 2]])

        self.assertEqual(m_1.matrix, expected)

    def test_matrix_subtract_row(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        m_1.subtract_row(2, 0, 1)

        expected = matrix([[1, 2], [1, 0]])

        self.assertEqual(m_1.matrix, expected)

    def test_matrix_get_pivots(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        reduced = m_1.row_reduce()[0]

        pivots = reduced.get_pivots()
        expected = [1, -2]

        self.assertEqual(pivots, expected)

    def test_matrix_is_reduced(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        self.assertFalse(m_1._is_reduced())

        reduced = m_1.row_reduce()[0]
        self.assertTrue(reduced._is_reduced())

    def test_matrix_max_pivots(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4], [5, 6]]))

        max_pivots = m_1.max_pivots()
        expected = 2

        self.assertEqual(max_pivots, expected)

    def test_matrix_apply_fn(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))

        result = m_1.apply_fn(lambda x: x + 1)
        expected = matrix([[2, 3], [4, 5]])

        self.assertEqual(result.matrix, expected)

    def test_matrix_update_entry(self):
        m_1 = mmatrix.MMatrix(matrix([[1, 2], [3, 4]]))
        m_1.update_entry(0, 0, 0)

        expected = matrix([[0, 2], [3, 4]])

        self.assertEqual(m_1.matrix, expected)

if __name__ == "__main__":
    cov = coverage.coverage(source=["polyrank"])
    cov.start()

    unittest.main(exit=False)

    cov.stop()
    cov.save()


from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from class_automobiliaidb import AutomobiliaiDb
from class_autopard import AutoPard
import datetime
sie_metai = datetime.date.today().year

engine = create_engine('sqlite:///automobiliaidb.db')
Session = sessionmaker(bind=engine)
session = Session()
engine2 = create_engine('sqlite:///automobiliai_pardavimui.db')
Session2 = sessionmaker(bind=engine2)
session2 = Session2()

while True:
    prisijungimas = int(input("Pasirinkite veiksmą: \n"
                             "1 - Darbuotojo prisijungimas \n"
                             "2 - Vartotojo prisijungimas \n"))
    if prisijungimas == 1:
        pasirinkimas = int(input("Pasirinkite veiksmą: \n"
                             "--------Automobilių duomenų bazė--------------------\n"
                             "1 - Įrašyti automobilio duomenis į duomenų bazę \n"
                             "2 - Peržiūrėti automobilių sąrašą iš duomenų bazės\n"
                             "3 - Ištrinti įrašą iš duomenų bazės\n"
                             "\n--------Parduodamų automobilių parkas--------------------\n"
                             "4 - Pridėti automobilį į parduodamų automobilių parką\n"
                             "5 - Peržiūrėti automobilių parką\n"
                             "6 - Ištrinti parduotą automobilį\n"
                                 ))
        if pasirinkimas == 1:
            marke = input("Įveskite automobilio markę: ")
            modelis = input("Įveskite modelį: ")
            kebulas = input("Įveskite kėbulo tipą (sedanas/kupė/universalas/visureigis): ")
            rida = int(input("Įveskite ridą: "))
            if 150000 >= rida:
                nuvertejimas_rida = 1.5
            elif 150000 < rida <= 250000:
                nuvertejimas_rida = 1.25
            elif rida > 250000:
                nuvertejimas_rida = 1
            variklio_turis = float(input("Įveskite variklio tūrį: "))
            gamybos_metai = int(input("Įveskite gamybos metus: "))
            kuro_tipas = input("Įveskite kuro tipą (benzinas/dyzelinas/elektra): ")
            pavaru_deze = input("Įveskite pavarų dėžės tipą (mechaninė/automatinė): ")
            trukumai = input("Nurodykite automobilio trūkumus (variklio defektas/kėbulo defektai/nėra): ")
            if trukumai == "variklio defektas" and gamybos_metai >= 2015:
                trukumu_verte = 3000
            elif trukumai == "variklio defektas" and gamybos_metai < 2015:
                trukumu_verte = 1500
            elif trukumai == "kėbulo defektai" or trukumai == "kebulo defektai":
                trukumu_verte = 500
            elif trukumai == "nėra" or trukumai == "nera":
                trukumu_verte = 0
            kaina = int(input("Įveskite modelio kainą pagal katalogą: "))
            rinkos_verte = round(kaina * (0.78 * (0.85**(sie_metai - gamybos_metai - 1)))) * \
                           nuvertejimas_rida - trukumu_verte
            automobilis = AutomobiliaiDb(marke, modelis, kebulas, rida, variklio_turis, gamybos_metai, kuro_tipas,
                                  pavaru_deze, trukumai, kaina, rinkos_verte)
            session.add(automobilis)
            session.commit()
            print("--------------")

        if pasirinkimas == 2:
            automobiliai = session.query(AutomobiliaiDb).all()
            print("--------------")
            for automobilis in automobiliai:
                print(automobilis)
            print("--------------")

        if pasirinkimas == 3:
            automobiliai = session.query(AutomobiliaiDb).all()
            print("--------------")
            for automobilis in automobiliai:
                print(automobilis)
            print("--------------")
            auto_id = int(input("Pasirinkite norimą ištrinti ID: "))
            trinamas_id = session.query(AutomobiliaiDb).get(auto_id)
            session.delete(trinamas_id)
            session.commit()

        if pasirinkimas == 4:
            marke = input("Įveskite automobilio markę: ")
            modelis = input("Įveskite modelį: ")
            kebulas = input("Įveskite kėbulo tipą (sedanas/kupė/universalas/visureigis): ")
            rida = int(input("Įveskite ridą: "))
            if 150000 >= rida:
                nuvertejimas_rida = 1.5
            elif 150000 < rida <= 250000:
                nuvertejimas_rida = 1.25
            elif rida > 250000:
                nuvertejimas_rida = 1
            variklio_turis = float(input("Įveskite variklio tūrį: "))
            gamybos_metai = int(input("Įveskite gamybos metus: "))
            kuro_tipas = input("Įveskite kuro tipą (benzinas/dyzelinas/elektra): ")
            pavaru_deze = input("Įveskite pavarų dėžės tipą (mechaninė/automatinė): ")
            trukumai = input("Nurodykite automobilio trūkumus (variklio defektas/kėbulo defektai/nėra): ")
            if trukumai == "variklio defektas" and gamybos_metai >= 2015:
                trukumu_verte = 3000
            elif trukumai == "variklio defektas" and gamybos_metai < 2015:
                trukumu_verte = 1500
            elif trukumai == "kėbulo defektai" or trukumai == "kebulo defektai":
                trukumu_verte = 500
            elif trukumai == "nėra" or trukumai == "nera":
                trukumu_verte = 0
            kaina = int(input("Įveskite modelio kainą pagal katalogą: "))
            rinkos_verte = round(kaina * (0.76 * (0.85**(sie_metai - gamybos_metai - 1)))) * \
                           nuvertejimas_rida - trukumu_verte
            automobiliai_pardavimui = AutoPard(marke, modelis, kebulas, rida, variklio_turis, gamybos_metai, kuro_tipas,
                                  pavaru_deze, trukumai, kaina, rinkos_verte)
            session2.add(automobiliai_pardavimui)
            session2.commit()
            print("--------------")

        if pasirinkimas == 5:
            automobiliai_pardavimui = session2.query(AutoPard).all()
            print("--------------")
            for automobilis in automobiliai_pardavimui:
                print(automobilis)
            print("--------------")

        if pasirinkimas == 6:
            automobiliai_pardavimui = session2.query(AutoPard).all()
            print("--------------")
            for automobilis in automobiliai_pardavimui:
                print(automobilis)
            print("--------------")
            auto_id = int(input("Pasirinkite norimą ištrinti ID: "))
            trinamas_id = session2.query(AutoPard).get(auto_id)
            session2.delete(trinamas_id)
            session2.commit()

    if prisijungimas == 2:
        pasirinkimas = int(input("Pasirinkite veiksmą: \n"
                             "1 - Noriu parduoti automobilį \n"
                             "2 - Peržiūrėti automobilių sąrašą \n"
                             "3 - Noriu gauti paskolą automobiliui \n"))
        if pasirinkimas == 1:
            marke = input("Įveskite automobilio markę: ")
            modelis = input("Įveskite modelį: ")
            kebulas = input("Įveskite kėbulo tipą: ")
            rida = int(input("Įveskite ridą: "))
            variklio_turis = float(input("Įveskite variklio tūrį: "))
            gamybos_metai = int(input("Įveskite gamybos metus: "))
            kuro_tipas = input("Įveskite kuro tipą (benzinas/dyzelinas/elektra): ")
            pavaru_deze = input("Įveskite pavarų dėžės tipą (mechaninė/automatinė): ")
            trukumai = input("Nurodykite automobilio trūkumus (variklio defektas/kėbulo defektai/nėra): ")
            paieska = session.query(AutomobiliaiDb).filter(AutomobiliaiDb.marke.ilike(marke),
                                                      AutomobiliaiDb.modelis.ilike(modelis),
                                                      AutomobiliaiDb.kebulas.ilike(kebulas),
                                                      AutomobiliaiDb.variklio_turis == variklio_turis,
                                                      AutomobiliaiDb.gamybos_metai.ilike(gamybos_metai),
                                                      AutomobiliaiDb.kuro_tipas.ilike(kuro_tipas),
                                                      AutomobiliaiDb.pavaru_deze.ilike(pavaru_deze))
            for vartotojo_automobilis in paieska:
                kaina = vartotojo_automobilis.kaina
                if trukumai == "variklio defektas" and gamybos_metai >= 2015:
                    trukumu_verte = 3000
                elif trukumai == "variklio defektas" and gamybos_metai < 2015:
                    trukumu_verte = 1500
                elif trukumai == "kėbulo defektai" or trukumai == "kebulo defektai":
                    trukumu_verte = 500
                elif trukumai == "nėra" or trukumai == "nera":
                    trukumu_verte = 0
                if 150000 >= rida:
                    nuvertejimas_rida = 1.5
                elif 150000 < rida <= 250000:
                    nuvertejimas_rida = 1.25
                elif rida > 250000:
                    nuvertejimas_rida = 1
                rinkos_verte = round(kaina * (0.76 * (0.85 ** (sie_metai - gamybos_metai - 1)))) * \
                               nuvertejimas_rida - trukumu_verte
                print(f"\nJūsų automobilis {marke} {modelis} šiai dienai vertas {rinkos_verte} EUR\n")

        if pasirinkimas == 2:
            automobiliai_pardavimui = session2.query(AutoPard).all()
            print("--------------")
            for automobilis in automobiliai_pardavimui:
                print(automobilis)
            print("--------------")

        if pasirinkimas == 3:
            while True:
                paskolos_suma = int(input("Įveskite paskolos sumą: "))
                paskolos_terminas = int(input("Įveskite paskolos terminą (mėnesiais): "))
                darbo_trukme = input("Ar šiuo metu esate dirbantis ir dabartinėje darbovietėje dirbate ilgiau nei 4 "
                                     "mėnesius?(Taip/Ne): ")
                if darbo_trukme == "Ne":
                    print("Jūsų darbo stažas neatitinka paskolos suteikimui keliamų reikalavimų! "
                          "Privalote išdirbti ne mažiau kaip 4 mėn. toje pačioje darbovietėje. \n")
                    break
                pajamos = int(input("Nurodykite savo mėnesinių pajamų dydį: "))
                islaidos = int(input("Nurodyktie savo mėnesinių išlaidų dydį: "))
                paskolos_terminas_metais = float(paskolos_terminas / 12)
                metine_palukanu_norma = (paskolos_suma * 0.06) * paskolos_terminas_metais
                sutarties_sudarymo_mokestis = paskolos_suma * 0.04
                menesinis_administravimo_mokestis = (paskolos_suma * 0.004) * paskolos_terminas
                grazintina_suma = paskolos_suma + metine_palukanu_norma + sutarties_sudarymo_mokestis \
                                  + menesinis_administravimo_mokestis
                menesio_imokos_dydis = grazintina_suma / paskolos_terminas
                ar_virsija_pajamas = pajamos * 0.4
                print("--------------")
                if ar_virsija_pajamas < islaidos + menesio_imokos_dydis:
                    print("\nJūsų turimų įsipareigojimų dydis viršija nustatytą normą (40% visų pajamų) "
                          "ir paskola Jums negali būti suteikta!\n")
                    break
                elif ar_virsija_pajamas > islaidos + menesio_imokos_dydis:
                    print(f"\nSveikiname! Jums gali būti suteikta {paskolos_suma} EUR paskolos suma {paskolos_terminas}"
                          f" mėn. terminui. Bendra grąžintina paskolos suma: {grazintina_suma} EUR, "
                          f"mėnesinių įmokų dydis: {round(menesio_imokos_dydis, 2)} EUR/mėn.\n")
                    break


from recipes.tests.recipe_test_base import RecipeTestBase
from django.core.exceptions import ValidationError
from recipes.models import Category

class TestRecipesModelCategory(RecipeTestBase):
    def setUp(self):
        self.category = self.make_category()
        super().setUp()

    def test_recipe_category_name_max_length(self):
        max_length = 65
        self.category.name = 'a' * (max_length + 1)

        with self.assertRaises(ValidationError) as e:
            self.category.full_clean()
            self.category.save()

    def test_recipe_category_str_method_returns_recipe_title(self):
        self.category.name = 'Other Category'
        self.assertEqual(str(self.category), self.category.name)