import datetime
import html
import logging
import os
import uuid
import ntpath
import re

from PyQt4 import QtGui

from openlp.core.common import RegistryProperties, Settings, translate, AppLocation, md5_hash
from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, create_thumb
from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics
from openlp.plugins.songs.lib.chords import Chords

log = logging.getLogger(__name__)

class ServiceItemType(object):
    """
    Defines the type of service item
    """
    Text = 1
    Image = 2
    Command = 3

class ItemCapabilities(object):
    """
    Provides an enumeration of a service item's capabilities

    ``CanPreview``
            The capability to allow the ServiceManager to add to the preview tab when making the previous item live.

    ``CanEdit``
            The capability to allow the ServiceManager to allow the item to be edited

    ``CanMaintain``
            The capability to allow the ServiceManager to allow the item to be reordered.

    ``RequiresMedia``
            Determines is the service_item needs a Media Player

    ``CanLoop``
            The capability to allow the SlideController to allow the loop processing.

    ``CanAppend``
            The capability to allow the ServiceManager to add leaves to the
            item

    ``NoLineBreaks``
            The capability to remove lines breaks in the renderer

    ``OnLoadUpdate``
            The capability to update MediaManager when a service Item is loaded.

    ``AddIfNewItem``
            Not Used

    ``ProvidesOwnDisplay``
            The capability to tell the SlideController the service Item has a different display.

    ``HasDetailedTitleDisplay``
            Being Removed and decommissioned.

    ``HasVariableStartTime``
            The capability to tell the ServiceManager that a change to start time is possible.

    ``CanSoftBreak``
            The capability to tell the renderer that Soft Break is allowed

    ``CanWordSplit``
            The capability to tell the renderer that it can split words is
            allowed

    ``HasBackgroundAudio``
            That a audio file is present with the text.

    ``CanAutoStartForLive``
            The capability to ignore the do not play if display blank flag.

    ``CanEditTitle``
            The capability to edit the title of the item

    ``IsOptical``
            Determines is the service_item is based on an optical device

    ``HasDisplayTitle``
            The item contains 'displaytitle' on every frame which should be
            preferred over 'title' when displaying the item

    ``HasNotes``
            The item contains 'notes'

    ``HasThumbnails``
            The item has related thumbnails available

    """
    CanPreview = 1
    CanEdit = 2
    CanMaintain = 3
    RequiresMedia = 4
    CanLoop = 5
    CanAppend = 6
    NoLineBreaks = 7
    OnLoadUpdate = 8
    AddIfNewItem = 9
    ProvidesOwnDisplay = 10
    HasDetailedTitleDisplay = 11
    HasVariableStartTime = 12
    CanSoftBreak = 13
    CanWordSplit = 14
    HasBackgroundAudio = 15
    CanAutoStartForLive = 16
    CanEditTitle = 17
    IsOptical = 18
    HasDisplayTitle = 19
    HasNotes = 20
    HasThumbnails = 21

class ServiceItem(RegistryProperties):
    """
    The service item is a base class for the plugins to use to interact with
    the service manager, the slide controller, and the projection screen
    compositor.
    """
    log.info('Service Item created')

    def __init__(self, plugin=None):
        """
        Set up the service item.

        :param plugin: The plugin that this service item belongs to.
        """
        if plugin:
            self.name = plugin.name
            self.plugin = plugin
        else:
            self.name = '' # Added to stop crash when trying to edit template
        self.title = ''
        self.processor = None
        self.audit = ''
        self.items = []
        self.iconic_representation = None
        self.raw_footer = []
        self.foot_text = ''
        self.theme = None
        self.service_item_type = None
        self._raw_frames = []
        self._display_frames = []
        self.unique_identifier = 0
        self.notes = ''
        self.from_plugin = False
        self.capabilities = []
        self.is_valid = True
        self.icon = None
        self.theme_data = None
        self.main = None
        self.footer = None
        self.bg_image_bytes = None
        self.search_string = ''
        self.data_string = ''
        self.edit_id = None
        self.xml_version = None
        self.start_time = 0
        self.end_time = 0
        self.media_length = 0
        self.from_service = False
        self.image_border = '#000000'
        self.background_audio = []
        self.theme_overwritten = False
        self.temporary_edit = False
        self.auto_play_slides_once = False
        self.auto_play_slides_loop = False
        self.timed_slide_interval = 0
        self.will_auto_start = False
        self.has_original_files = True
        self.extra_data_dict = {}
        self._new_item()

    def _new_item(self):
        """
        Method to set the internal id of the item. This is used to compare service items to see if they are the same.
        """
        self.unique_identifier = str(uuid.uuid1())
        self.validate_item()

    def add_capability(self, capability):
        """
        Add an ItemCapability to a ServiceItem

        :param capability: The capability to add
        """
        self.capabilities.append(capability)

    def is_capable(self, capability):
        """
        Tell the caller if a ServiceItem has a capability

        :param capability: The capability to test for
        """
        return capability in self.capabilities

    def set_extra_data_dict(self, data_dict):
        self.extra_data_dict = data_dict

    def add_icon(self, icon):
        """
        Add an icon to the service item. This is used when displaying the service item in the service manager.

        :param icon: A string to an icon in the resources or on disk.
        """
        self.icon = icon
        self.iconic_representation = build_icon(icon)

    def render(self, provides_own_theme_data=False):
        """
        The render method is what generates the frames for the screen and obtains the display information from the
        renderer. At this point all slides are built for the given display size.

        :param provides_own_theme_data: This switch disables the usage of the item's theme. However, this is
            disabled by default. If this is used, it has to be taken care, that
            the renderer knows the correct theme data. However, this is needed
            for the theme manager.
        """
        log.debug('Render called')
        self._display_frames = []
        self.bg_image_bytes = None
        if not provides_own_theme_data:
            self.renderer.set_item_theme(self.theme)
            self.theme_data, self.main, self.footer = self.renderer.pre_render()
        if self.service_item_type == ServiceItemType.Text:
            log.debug('Formatting slides: %s' % self.title)
            # Save rendered pages to this dict. In the case that a slide is used twice we can use the pages saved to
            # the dict instead of rendering them again.
            if self.get_plugin_name() == 'songs':
                if not self.extra_data_dict:
                    self.extra_data_dict = {}
                    if not self.xml_version.startswith('<?xml') and not self.xml_version.startswith('<song'):
                        # This is an old style song, without XML.
                        verses = self.xml_version.split('\n\n')
                        for count, verse in enumerate(verses):
                            self.extra_data_dict['v' + str(count)] = str(verse).split('\n')

                    elif self.xml_version.startswith('<?xml'):
                        # New style song, output as XML.
                        song_xml_split = re.split('(<verse[\w"= ]*>)', self.xml_version)
                        current_section = ''

                        for song_part in song_xml_split:
                            if song_part.startswith("<verse name"):
                                current_section = song_part.replace('<verse name="', '').replace('">', '')
                            elif song_part.startswith("<lines"):
                                # New line needed between <lines> sections
                                song_part = song_part.replace('</lines><line', '</lines>
<line')
                                # Split out <lines>, </lines>, </verse>, </lyrics> and </song> tags
                                song_part = ''.join(re.split('<lines[\w"= ]*>', song_part))
                                song_part = song_part.replace('</lines>','').replace('</verse>', '')
                                song_part = song_part.replace('</lyrics>','').replace('</song>', '')
                                # Convert to list
                                self.extra_data_dict[current_section] = song_part.split('
')

                previous_pages = {}

                # Get key and transpose amount, if used in this song
                if "<key>" in self.xml_version:
                    current_key = self.xml_version[(self.xml_version.index('<key>') + 5):(self.xml_version.index('<key>')+7)]
                    if current_key[1] == '<':
                        current_key = current_key[0]
                else:
                    current_key = ''

                if "<transposition>" in self.xml_version:
                    current_transpose = self.xml_version[(self.xml_version.index('<transposition>') + 15):(self.xml_version.index('<transposition>')+18)]
                    # Possible options: 1,...,9, 10, 11, -1, ... -9, -10, -11
                    if current_transpose[1] == '<':
                        current_transpose = int(current_transpose[0])
                    elif current_transpose[2] == '<':
                        current_transpose = int(current_transpose[0:2])
                else:
                    current_transpose = 0

                # Calculate resultant key for musician oriented view
                if current_key != '':
                    resultant_key = Chords.transpose_chord(current_key, current_key, current_transpose)
                else:
                    resultant_key = ''

                for slide in self._raw_frames:
                    verse_tag = slide['verseTag']
                    if verse_tag in previous_pages and previous_pages[verse_tag][0] == slide['raw_slide']:
                        pages = previous_pages[verse_tag][1]
                    else:
                        pages = self.renderer.format_slide(slide['raw_slide'], self)
                        previous_pages[verse_tag] = (slide['raw_slide'], pages)

                    xml_lines = self.extra_data_dict[verse_tag.lower()]
                    xml_line_lower, xml_line_upper = 0, 0

                    subpage_count = 0
                    for page in pages:
                        subpage_count += 1

                        # Given the current page_lines, calculate the corresponding xml_lines
                        xml_line_lower = xml_line_upper
                        xml_segment = ''.join(re.split('<chord[\w\+#"=// ]*/>', xml_lines[xml_line_upper]))

                        while (xml_line_upper < len(xml_lines)) and not (xml_segment.strip() == page.strip()):
                            xml_line_upper += 1
                            xml_segment = xml_segment + '
' + ''.join(re.split('<chord[\w\+#"=// ]*/>', xml_lines[xml_line_upper]))

                        xml_line_upper += 1
                        page_xml = xml_lines[xml_line_lower: xml_line_upper]

                        # Exclude any [br] or [---] elements from the XML list
                        page_xml_short = []
                        for item in page_xml:
                            if item != '[br]' and item != '[---]':
								# split item by chord tags, then transpose each chord tag
                                if current_transpose != 0:
                                    item_sections = re.split('(<chord[\w\+#"=// ]*/>)', item)
                                    transposed_item = ''

                                    for item_section in item_sections:
                                        if item_section.startswith('<chord name'):
                                            transposed_item = transposed_item + Chords.transpose_chord_tag(item_section, current_key, current_transpose)
                                        else:
                                            transposed_item = transposed_item + item_section
                                    page_xml_short.append(transposed_item)
                                else:
                                    page_xml_short.append(item)

                        page = page.replace('
', '{br}')
                        html_data = expand_tags(html.escape(page.rstrip()))
                        self._display_frames.append({
                            'title': clean_tags(page),
                            'text': clean_tags(page.rstrip()),
                            'html': html_data.replace('&nbsp;', ' '),
                            'verseTag': verse_tag,
                            'verseSubpage': subpage_count,
                            'extraInfo': '
'.join(page_xml_short),
                            'playedKey': resultant_key
                        })

                        # Deal with any [br] or [---] tag in XML before processing next page
                        if xml_line_upper < len(xml_lines) and \
                            (xml_lines[xml_line_upper].strip() == '[br]' or xml_lines[xml_line_upper].strip() == '[---]'):
                            xml_line_upper += 1

            elif (self.get_plugin_name() == "custom") or (self.get_plugin_name() == ''):
                previous_pages = {}
                for slide in self._raw_frames:
                    verse_tag = slide['verseTag']
                    if verse_tag in previous_pages and previous_pages[verse_tag][0] == slide['raw_slide']:
                        pages = previous_pages[verse_tag][1]
                    else:
                        pages = self.renderer.format_slide(slide['raw_slide'], self)
                        previous_pages[verse_tag] = (slide['raw_slide'], pages)

                    for page in pages:
                        page = page.replace('
', '{br}')
                        html_data = expand_tags(html.escape(page.rstrip()))
                        self._display_frames.append({
                            'title': clean_tags(page),
                            'text': clean_tags(page.rstrip()),
                            'html': html_data.replace('&nbsp;', ' '),
                            'verseTag': verse_tag
                        })

            elif self.get_plugin_name() == "bibles":
                previous_pages = {}
                for slide in self._raw_frames:
                    verse_tag = slide['verseTag']
                    if verse_tag in previous_pages and previous_pages[verse_tag][0] == slide['raw_slide']:
                        pages = previous_pages[verse_tag][1]
                    else:
                        pages = self.renderer.format_slide(slide['raw_slide'], self)
                        previous_pages[verse_tag] = (slide['raw_slide'], pages)

                    for page in pages:
                        page = page.replace('
', '{br}')
                        html_data = expand_tags(html.escape(page.rstrip()))
                        if hasattr(self, 'simple_title'):
                            title = self.simple_title
                        else:
                            title = self.title
                        self._display_frames.append({
                            'title': clean_tags(page),
                            'text': clean_tags(page.rstrip()),
                            'html': html_data.replace('&nbsp;', ' '),
                            'verseTag': verse_tag,
                            'extraInfo': title
                        })

        elif self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command:
            pass
        else:
            log.error('Invalid value renderer: %s' % self.service_item_type)
        self.title = clean_tags(self.title)
        # The footer should never be None, but to be compatible with a few
        # nightly builds between 1.9.4 and 1.9.5, we have to correct this to
        # avoid tracebacks.
        if self.raw_footer is None:
            self.raw_footer = []
        self.foot_text = '
'.join([_f for _f in self.raw_footer if _f])

    def add_from_image(self, path, title, background=None, thumbnail=None):
        """
        Add an image slide to the service item.

        :param path: The directory in which the image file is located.
        :param title: A title for the slide in the service item.
        :param background:
        :param thumbnail: Optional alternative thumbnail, used for remote thumbnails.
        """
        if background:
            self.image_border = background
        self.service_item_type = ServiceItemType.Image
        if not thumbnail:
            self._raw_frames.append({'title': title, 'path': path})
        else:
            self._raw_frames.append({'title': title, 'path': path, 'image': thumbnail})
        self.image_manager.add_image(path, ImageSource.ImagePlugin, self.image_border)
        self._new_item()

    def add_from_text(self, raw_slide, verse_tag=None):
        """
        Add a text slide to the service item.

        :param raw_slide: The raw text of the slide.
        :param verse_tag:
        """
        if verse_tag:
            verse_tag = verse_tag.upper()
        self.service_item_type = ServiceItemType.Text
        title = raw_slide[:30].split('\n')[0]
        self._raw_frames.append({'title': title, 'raw_slide': raw_slide, 'verseTag': verse_tag})
        self._new_item()

    def add_from_command(self, path, file_name, image, display_title=None, notes=None):
        """
        Add a slide from a command.

        :param path: The title of the slide in the service item.
        :param file_name: The title of the slide in the service item.
        :param image: The command of/for the slide.
        :param display_title: Title to show in gui/webinterface, optional.
        :param notes: Notes to show in the webinteface, optional.
        """
        self.service_item_type = ServiceItemType.Command
        # If the item should have a display title but this frame doesn't have one, we make one up
        if self.is_capable(ItemCapabilities.HasDisplayTitle) and not display_title:
            display_title = translate('OpenLP.ServiceItem', '[slide %d]') % (len(self._raw_frames) + 1)
        # Update image path to match servicemanager location if file was loaded from service
        if image and not self.has_original_files and self.name == 'presentations':
            file_location = os.path.join(path, file_name)
            file_location_hash = md5_hash(file_location.encode('utf-8'))
            image = os.path.join(AppLocation.get_section_data_path(self.name), 'thumbnails',
                                 file_location_hash, ntpath.basename(image))
        self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
                                 'display_title': display_title, 'notes': notes})
        self._new_item()

    def get_item_xml(self):
        if self.xml_version:
            return self.xml_version
        else:
            return ''

    def get_plugin_name(self):
        if self.name:
            return self.name
        else:
            return ''

    def get_service_repr(self, lite_save):
        """
        This method returns some text which can be saved into the service file to represent this item.
        """
        service_header = {
            'name': self.name,
            'plugin': self.name,
            'theme': self.theme,
            'title': self.title,
            'icon': self.icon,
            'footer': self.raw_footer,
            'type': self.service_item_type,
            'audit': self.audit,
            'notes': self.notes,
            'from_plugin': self.from_plugin,
            'capabilities': self.capabilities,
            'search': self.search_string,
            'data': self.data_string,
            'xml_version': self.xml_version,
            'auto_play_slides_once': self.auto_play_slides_once,
            'auto_play_slides_loop': self.auto_play_slides_loop,
            'timed_slide_interval': self.timed_slide_interval,
            'start_time': self.start_time,
            'end_time': self.end_time,
            'media_length': self.media_length,
            'background_audio': self.background_audio,
            'theme_overwritten': self.theme_overwritten,
            'will_auto_start': self.will_auto_start,
            'processor': self.processor
        }
        service_data = []
        if self.service_item_type == ServiceItemType.Text:
            service_data = [slide for slide in self._raw_frames]
        elif self.service_item_type == ServiceItemType.Image:
            if lite_save:
                for slide in self._raw_frames:
                    service_data.append({'title': slide['title'], 'path': slide['path']})
            else:
                service_data = [slide['title'] for slide in self._raw_frames]
        elif self.service_item_type == ServiceItemType.Command:
            for slide in self._raw_frames:
                service_data.append({'title': slide['title'], 'image': slide['image'], 'path': slide['path'],
                                     'display_title': slide['display_title'], 'notes': slide['notes']})
        return {'header': service_header, 'data': service_data}

    def set_from_service(self, service_item, path=None):
        """
        This method takes a service item from a saved service file (passed from the ServiceManager) and extracts the
        data actually required.

        :param service_item: The item to extract data from.
        :param path: Defaults to *None*. This is the service manager path for things which have their files saved
        with them or None when the saved service is lite and the original file paths need to be preserved.
        """
        log.debug('set_from_service called with path %s' % path)
        header = service_item['serviceitem']['header']
        self.title = header['title']
        self.name = header['name']
        self.service_item_type = header['type']
        self.theme = header['theme']
        self.add_icon(header['icon'])
        self.raw_footer = header['footer']
        self.audit = header['audit']
        self.notes = header['notes']
        self.from_plugin = header['from_plugin']
        self.capabilities = header['capabilities']
        # Added later so may not be present in older services.
        self.search_string = header.get('search', '')
        self.data_string = header.get('data', '')
        self.xml_version = header.get('xml_version')
        self.start_time = header.get('start_time', 0)
        self.end_time = header.get('end_time', 0)
        self.media_length = header.get('media_length', 0)
        self.auto_play_slides_once = header.get('auto_play_slides_once', False)
        self.auto_play_slides_loop = header.get('auto_play_slides_loop', False)
        self.timed_slide_interval = header.get('timed_slide_interval', 0)
        self.will_auto_start = header.get('will_auto_start', False)
        self.processor = header.get('processor', None)
        self.has_original_files = True
        # TODO: Remove me in 2,3 build phase
        if self.is_capable(ItemCapabilities.HasDetailedTitleDisplay):
            self.capabilities.remove(ItemCapabilities.HasDetailedTitleDisplay)
            self.processor = self.title
            self.title = None
        if 'background_audio' in header:
            self.background_audio = []
            for filename in header['background_audio']:
                # Give them real file paths.
                filepath = filename
                if path:
                    # Windows can handle both forward and backward slashes, so we use ntpath to get the basename
                    filepath = os.path.join(path, ntpath.basename(filename))
                self.background_audio.append(filepath)
        self.theme_overwritten = header.get('theme_overwritten', False)
        if self.service_item_type == ServiceItemType.Text:
            for slide in service_item['serviceitem']['data']:
                self._raw_frames.append(slide)
        elif self.service_item_type == ServiceItemType.Image:
            settings_section = service_item['serviceitem']['header']['name']
            background = QtGui.QColor(Settings().value(settings_section + '/background color'))
            if path:
                self.has_original_files = False
                for text_image in service_item['serviceitem']['data']:
                    filename = os.path.join(path, text_image)
                    self.add_from_image(filename, text_image, background)
            else:
                for text_image in service_item['serviceitem']['data']:
                    self.add_from_image(text_image['path'], text_image['title'], background)
        elif self.service_item_type == ServiceItemType.Command:
            for text_image in service_item['serviceitem']['data']:
                if not self.title:
                    self.title = text_image['title']
                if self.is_capable(ItemCapabilities.IsOptical):
                    self.has_original_files = False
                    self.add_from_command(text_image['path'], text_image['title'], text_image['image'])
                elif path:
                    self.has_original_files = False
                    self.add_from_command(path, text_image['title'], text_image['image'],
                                          text_image.get('display_title', ''), text_image.get('notes', ''))
                else:
                    self.add_from_command(text_image['path'], text_image['title'], text_image['image'])
        self._new_item()

    def get_display_title(self):
        """
        Returns the title of the service item.
        """
        if self.is_text() or self.is_capable(ItemCapabilities.IsOptical) \
                or self.is_capable(ItemCapabilities.CanEditTitle):
            return self.title
        else:
            if len(self._raw_frames) > 1:
                return self.title
            else:
                return self._raw_frames[0]['title']

    def merge(self, other):
        """
        Updates the unique_identifier with the value from the original one
        The unique_identifier is unique for a given service item but this allows one to replace an original version.

        :param other: The service item to be merged with
        """
        self.unique_identifier = other.unique_identifier
        self.notes = other.notes
        self.temporary_edit = other.temporary_edit
        # Copy theme over if present.
        if other.theme is not None:
            self.theme = other.theme
            self._new_item()
        self.render()
        if self.is_capable(ItemCapabilities.HasBackgroundAudio):
            log.debug(self.background_audio)

    def __eq__(self, other):
        """
        Confirms the service items are for the same instance
        """
        if not other:
            return False
        return self.unique_identifier == other.unique_identifier

    def __ne__(self, other):
        """
        Confirms the service items are not for the same instance
        """
        return self.unique_identifier != other.unique_identifier

    def __hash__(self):
        """
        Return the hash for the service item.
        """
        return self.unique_identifier

    def is_media(self):
        """
        Confirms if the ServiceItem is media
        """
        return ItemCapabilities.RequiresMedia in self.capabilities

    def is_command(self):
        """
        Confirms if the ServiceItem is a command
        """
        return self.service_item_type == ServiceItemType.Command

    def is_image(self):
        """
        Confirms if the ServiceItem is an image
        """
        return self.service_item_type == ServiceItemType.Image

    def uses_file(self):
        """
        Confirms if the ServiceItem uses a file
        """
        return self.service_item_type == ServiceItemType.Image or \
            (self.service_item_type == ServiceItemType.Command and not self.is_capable(ItemCapabilities.IsOptical))

    def is_text(self):
        """
        Confirms if the ServiceItem is text
        """
        return self.service_item_type == ServiceItemType.Text

    def set_media_length(self, length):
        """
        Stores the media length of the item

        :param length: The length of the media item
        """
        self.media_length = length
        if length > 0:
            self.add_capability(ItemCapabilities.HasVariableStartTime)

    def get_frames(self):
        """
        Returns the frames for the ServiceItem
        """
        if self.service_item_type == ServiceItemType.Text:
            return self._display_frames
        else:
            return self._raw_frames

    def get_rendered_frame(self, row):
        """
        Returns the correct frame for a given list and renders it if required.

        :param row: The service item slide to be returned
        """
        if self.service_item_type == ServiceItemType.Text:
            return self._display_frames[row]['html'].split('\n')[0]
        elif self.service_item_type == ServiceItemType.Image:
            return self._raw_frames[row]['path']
        else:
            return self._raw_frames[row]['image']

    def get_frame_title(self, row=0):
        """
        Returns the title of the raw frame
        """
        try:
            return self._raw_frames[row]['title']
        except IndexError:
            return ''

    def get_frame_path(self, row=0, frame=None):
        """
        Returns the path of the raw frame
        """
        if not frame:
            try:
                frame = self._raw_frames[row]
            except IndexError:
                return ''
        if self.is_image() or self.is_capable(ItemCapabilities.IsOptical):
            path_from = frame['path']
        else:
            path_from = os.path.join(frame['path'], frame['title'])
        return path_from

    def remove_frame(self, frame):
        """
        Remove the specified frame from the item
        """
        if frame in self._raw_frames:
            self._raw_frames.remove(frame)

    def get_media_time(self):
        """
        Returns the start and finish time for a media item
        """
        start = None
        end = None
        if self.start_time != 0:
            start = translate('OpenLP.ServiceItem', 'Start: %s') % \
                str(datetime.timedelta(seconds=self.start_time))
        if self.media_length != 0:
            end = translate('OpenLP.ServiceItem', 'Length: %s') % \
                str(datetime.timedelta(seconds=self.media_length))
        if not start and not end:
            return ''
        elif start and not end:
            return start
        elif not start and end:
            return end
        else:
            return '%s
%s' % (start, end)

    def update_theme(self, theme):
        """
        updates the theme in the service item

        :param theme: The new theme to be replaced in the service item
        """
        self.theme_overwritten = (theme is None)
        self.theme = theme
        self._new_item()
        self.render()

    def remove_invalid_frames(self, invalid_paths=None):
        """
        Remove invalid frames, such as ones where the file no longer exists.
        """
        if self.uses_file():
            for frame in self.get_frames():
                if self.get_frame_path(frame=frame) in invalid_paths:
                    self.remove_frame(frame)

    def missing_frames(self):
        """
        Returns if there are any frames in the service item
        """
        return not bool(self._raw_frames)

    def validate_item(self, suffix_list=None):
        """
        Validates a service item to make sure it is valid
        """
        self.is_valid = True
        for frame in self._raw_frames:
            if self.is_image() and not os.path.exists(frame['path']):
                self.is_valid = False
                break
            elif self.is_command():
                if self.is_capable(ItemCapabilities.IsOptical):
                    if not os.path.exists(frame['title']):
                        self.is_valid = False
                        break
                else:
                    file_name = os.path.join(frame['path'], frame['title'])
                    if not os.path.exists(file_name):
                        self.is_valid = False
                        break
                    if suffix_list and not self.is_text():
                        file_suffix = frame['title'].split('.')[-1]
                        if file_suffix.lower() not in suffix_list:
                            self.is_valid = False
                            break


ocak, subat, mart, nisan, mayıs, haziran, temmuz, ağustos, eylül, ekim, kasım, aralık = 31,28,31,30,31,30,31,31,30,31,30,31

yılgün = ocak+subat+mart+nisan+mayıs+haziran+temmuz+ağustos+eylül+ekim+kasım+aralık

günsay = 0

for yıl in range(1991,2001):
    if yıl % 4 == 0 and yıl % 400 != 0:
        günsay += 1
    günsay += yılgün

print(günsay/7)


from collections import deque

def main():

    def musicProgram():
        result = []
        queue = deque()

        for i in range(1, N + 1):
            if indegree[i] == 0:
                queue.append(i)

        while queue:
            currS = queue.popleft()
            result.append(currS)
            for i in singer[currS]:
                indegree[i] -= 1
                if indegree[i] == 0:
                    queue.append(i)
        return result

    N, M = map(int, input().split())

    singer = [[] for _ in range(N + 1)]
    indegree = [0] * (N + 1)
    for _ in range(M):
        PD = list(map(int, input().split()))
        for s in range(1, PD[0]):
            before, after = PD[s], PD[s + 1]
            singer[before].append(after)
            indegree[after] += 1

    sequence = musicProgram()
    print(0) if len(sequence) != N else print(*sequence, sep='\n')

if __name__ == "__main__":
    main()


import random

first_string = open("C:\\Users\\makri\\Desktop\\hokku\\first.txt","r")
second_string = open("C:\\Users\\makri\\Desktop\\hokku\\second.txt","r")
third_string = open("C:\\Users\\makri\\Desktop\\hokku\\third.txt","r")
list_first = []
list_second = []
list_third = []
for line1 in first_string:
    list_first.append(line1)
for line2 in second_string:
    list_second.append(line2)
for line3 in third_string:
    list_third.append(line3)
choice_first_string = random.choice(list_first)
choice_second_string = random.choice(list_second)
choice_third_string = random.choice(list_third)

print(choice_first_string)
print(choice_second_string)
print(choice_third_string)


from django import template
from django.contrib.sites.shortcuts import get_current_site
from django.templatetags.static import static

from edd.describe.models import DescribeExampleSet

register = template.Library()

@register.simple_tag(takes_context=True)
def describe_preview_img(context):
    try:
        request = context.get("request", None)
        site = get_current_site(request)
        preview_url = DescribeExampleSet.objects.get(site=site).example_image_file.url
    except Exception:
        # if there is no configuration, show default image
        preview_url = static("edd/describe/example-image.png")
    return preview_url

@register.simple_tag(takes_context=True)
def describe_example_file(context):
    try:
        request = context.get("request", None)
        site = get_current_site(request)
        example_url = DescribeExampleSet.objects.get(site=site).example_file.url
    except Exception:
        # if there is no configuration, download default example file
        example_url = static("edd/describe/example_experiment_description.xlsx")
    return example_url


# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
from GeekHub.models import Article
import urllib2
from GeekHub import bitly

class ComptoirDuHardware :
    def __init__(self,nb_infos, bit_login,bit_apikey):
        self.url = 'http://www.comptoir-hardware.com/home.xml'
        self.source = "Le Comptoir du Hardware"
        self.get_infos(nb_infos, bit_login,bit_apikey)

    def get_infos(self, nb_infos, bit_login, bit_apikey):
        i = 0
        while i<10:
            try:
                page = urllib2.urlopen(self.url, timeout=10)
            except:
                i += 1
                continue
            break

        html = page.read()
        page_web = BeautifulSoup(html)
        #page_web.prettify() #Affichage source complete

        list_art = page_web.find_all("item", limit = nb_infos)
        for article in list_art :
            link = title = photo = date = None
            #link
            link = (article.find("guid")).text
            #title
            title = (article.find("title")).text
            title = title.encode('utf-8')
            title = title.replace("'", "'")
            #photo
            try :
                photo = article.find("enclosure").get("url")
            except :
                photo = None
                pass #if photo not exist
            #Bitly
            api = bitly.Api(login=bit_login, apikey=bit_apikey)
            i=0
            while i<10 :
                try:
                    bit_link = api.shorten(link)
                except:
                    i += 1
                    continue
                break
            #BDD
            bdd_article = Article(titre = title, lien = link, short_link = bit_link, origine = self.source, image = photo)
            try :
                bdd_article.save()
            except : pass
        page.close()


import matplotlib.pyplot as plt
import matplotlib.patches as patches
from PIL import Image

def create_diagram(rectangles, security, room_size, filename):

    fig,ax = plt.subplots(1, figsize=(10,10))
    room = plt.Rectangle((0, 0), room_size[0], room_size[1], linewidth=1, edgecolor='g', facecolor='none')
    ax.add_patch(room)

    for box in rectangles:
        width = box.width
        height = box.height
        x = box.x
        y = box.y
        x_table = x + security/2
        w_table = width - security
        y_table = y + security/2
        h_table = height - security

        if x == 0:
            x += security/2
            width -= security/2
        elif x==room_size[0]-width+security:
            width -= security/2
        if y == 0:
            y += security/2
            height -= security/2
        elif y==room_size[1]-height+security:
            height -= security/2

        x -= security/2
        y -= security/2
        x_table -= security/2
        y_table -= security/2

        sec = plt.Rectangle((x, y), width, height, linewidth=1, edgecolor='r', facecolor='none', alpha=0.2)
        ax.add_patch(sec)

        table = plt.Rectangle((x_table, y_table), w_table, h_table,
            linewidth=2, edgecolor='b', facecolor='none')
        ax.add_patch(table)
        w = round(box.width-security, 2)
        h = round(box.height-security, 2)
        plt.text(x + width/3, y + height/2, f'{w}, {h}')

    ax.scatter([1], [1],color="w")
    plt.savefig(str(filename)+'.png')


import logging
import os
from typing import Iterator

import spotipy, re
from progress.bar import Bar
from spotipy import SpotifyClientCredentials

from src.data.downloader import DataDownloader
from src.util import read_csv

SPOTIFY_MAX_TRACKS = 100
PARENS_REGEX = re.compile(r"\(.*\)")

def find_best_match(track: dict, search_results: list[dict]):
    best_match = search_results[0]
    best_score = 0.0

    title = track['title'].lower().strip()
    title_bare = PARENS_REGEX.sub("", title).strip()
    album = str(track['album']).lower().strip() if track['album'] is None else None

    heuristics = [
        (lambda i: title == i['title'], 1),
        (lambda i: (title + " ") in i['title'], .5),
        (lambda i: title_bare == i['title'], .3),
        (lambda i: (title_bare + " ") in i['title'], .3),
        (lambda i: album is not None and album == i['album'], 1),
        (lambda i: album is not None and (album + " ") in i['album'], .5)
    ]

    for result in search_results:
        candidate = {
            'title': result['name'].lower().strip(),
            'album': result['album']['name'].lower().strip()
        }
        score = sum([heuristic[1] for heuristic in heuristics if heuristic[0](candidate)])
        if score > best_score:
            best_score = score
            best_match = result

    return best_match

class FeatureDownloader(DataDownloader):
    def __init__(self, output_file: str, tracks_file: str):
        super().__init__(output_file)

        tracks = read_csv(tracks_file, strict=True)
        features = read_csv(self.output_file, strict=False)

        existing_ids = {feature['tt_id'] for feature in features}
        new_tracks = [track for track in tracks if track['id'] not in existing_ids]

        logging.info(f"{len(new_tracks)} new tracks found since last run")
        self.new_tracks = new_tracks

        credentials = SpotifyClientCredentials(
            client_id=os.getenv('SPOTIFY_CLIENT_ID'),
            client_secret=os.getenv('SPOTIFY_CLIENT_SECRET')
        )
        self.api = spotipy.Spotify(auth_manager=credentials)

    def download(self) -> Iterator[dict]:
        batch = []

        tracks = self.new_tracks

        bar = Bar('Downloading track features...', max=len(tracks))
        for i, track in enumerate(tracks):
            bar.next()

            search_results = self.api.search(q=track['title'], type='track', limit=50)

            if search_results['tracks']['total'] == 0:
                continue

            item = find_best_match(track, search_results['tracks']['items'])

            if item is None:
                continue

            batch.append({
                'id': item['id'],
                'tt_id': track['id'],  # Keep ID for cross-reference
                'title': item['name'],
                'album': item['album']['name'],
                'artist': ", ".join([artist['name'] for artist in item['artists']]),
                'popularity': item['popularity']
            })

            # Download audio features per batch or when reaching the last track, for efficiency
            if len(batch) % SPOTIFY_MAX_TRACKS == 0 or i == len(tracks) - 1:
                ids = [item['id'] for item in batch]
                feature_results = self.api.audio_features(ids)
                for idx, features in enumerate(feature_results):
                    if features is None:
                        continue

                    item = batch[idx]
                    yield {**item, **features}

                batch = []


# -*- coding: utf-8 -*-
"""
Created on Sat Jun 12 22:31:17 2021

@author: Tomas Pacheco
"""

# First I calculate the probability that at least two people share their birthday
# within a group of 30 people. The procedure is replicated 10.000 times in order
# to calculate the probability.

import random
from collections import Counter

days = list(range(1, 366))
times = []
it_times = range(0,10000)

for i in it_times:
    sample = random.choices(days, k = 30)
    reps = list(dict(Counter(sample)).values())
    for i in reps:
        if i > 1:
            times.append(1)
            break
        else:
            continue

prob = len(times)/len(it_times)
print(f"La probabilidad es {prob}.")

# Here I replicate the procedure explained before 1000 times so I can construct
# the density of the probability with a kernel.

import statistics
from scipy import stats
import matplotlib.pyplot as plt
import numpy as np

days = list(range(1, 366))
proba = []
repsl = 100
people = 30

for i in range(0,repsl):
    times = []
    it_times = range(0,10000)
    for i in it_times:
        sample = random.choices(days, k = people)
        reps = list(dict(Counter(sample)).values())
        for i in reps:
            if i > 1:
                times.append(1)
                break
            else:
                continue
    proba.append(len(times)/len(it_times))

density = stats.kde.gaussian_kde(proba)
m = statistics.mean(proba)
x = np.arange(min(proba)-0.01, max(proba)+0.01, .001)
plt.plot(x, density(x))
plt.vlines(m, 0, max(density(x))+5, colors = "red")
plt.text((statistics.mean(proba)+max(proba))/2, max(density(x))/2, f'mean = {m}')
plt.title(f'{repsl} reps with {people} people ')
plt.show()

# Finally, we study how does the probability evolve when we augment the
# number of people in the 'reunion'.

cardinal = list(range(1,61))
prob_cardinal = []
days = list(range(1, 366))

for j in cardinal:
    proba = []
    repsl = 100
    people = j

    for i in range(0,repsl):
        times = []
        it_times = range(0,10000)
        for i in it_times:
            sample = random.choices(days, k = people)
            reps = list(dict(Counter(sample)).values())
            for i in reps:
                if i > 1:
                    times.append(1)
                    break
                else:
                    continue
        proba.append(len(times)/len(it_times))
    prob_cardinal.append(statistics.mean(proba))
    print(j)

plt.plot(cardinal, prob_cardinal)
plt.xlabel("People in the 'reunion'")
plt.ylabel('Probability')
plt.title('Probability that at least two people share their birthday')

# Linear regression with the data.

import statsmodels.api as sm

x, y = np.array(cardinal), np.array(prob_cardinal)

x = sm.add_constant(x)
model = sm.OLS(y, x)
results = model.fit()
print(results.summary())


# loosely inspired by https://github.com/chengyangfu/pytorch-vgg-cifar10
import math
import torch.nn as nn

from layers import RealOpu, SimulatedOpu, Sign, Identity
from tinydfa import DFA, DFALayer

class CifarVGG16(nn.Module):

    def __init__(self, opu, binary_layer, opu_features, features, opu_input, sign_back, real_opu, device, dataset):
        super(CifarVGG16, self).__init__()
        self.features = features
        if dataset == 'cifar10':
            self.number_classes = 10
        if dataset == 'cifar100':
            self.number_classes = 100

        if binary_layer:
            if sign_back:
                print(f'- Binary layer = {binary_layer} but sign_back = {sign_back}--> attack method = FA!')
                self.dfa1 = Identity()
                self.dfa = Identity()
            else:
                self.training_method = 'DFA'
                print(f'- Binary layer = {binary_layer} --> training method = DFA!')
                self.dfa1 = DFALayer()
                self.dfa = DFA([self.dfa1], no_training=(self.training_method == 'SHALLOW'))
        else:
            if opu:
                print(f'- Binary layer = {binary_layer}, opu = {opu} --> training method = FA')
            else:
                print(f'- Binary layer = {binary_layer}, opu = {opu} --> training method = BP')
            self.dfa1 = nn.Dropout()
            self.dfa = Identity()

        if opu:
            print(f'- opu_input = {opu_input}, opu_output = {opu_features}')
            if real_opu:
                print('- VGG with real OPU')
                print(opu_input, opu_features)
                second_classifier_layer = RealOpu(in_features=opu_input, out_features=opu_features, device=device)
            else:
                print('- VGG with simulated OPU')
                second_classifier_layer = SimulatedOpu(in_features=opu_input, out_features=opu_features)

        else:
            print('- VGG without OPU')
            second_classifier_layer = nn.Linear(opu_input, opu_features)

        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(512, opu_input),
            nn.ReLU(True),
            self.dfa1,
            Sign(binary_layer, sign_back=sign_back),
            second_classifier_layer,
            nn.ReLU(True),
            nn.Linear(opu_features, self.number_classes),
            self.dfa
        )
        # Initialize weights
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
                m.bias.data.zero_()

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x

class AblationCifarVGG16(nn.Module):

    def __init__(self, opu, binary_layer, opu_features, features, opu_input, dataset, sign_back):
        super(AblationCifarVGG16, self).__init__()
        self.features = features
        print(f'OPU: {opu}, binary_layer: {binary_layer}, oo: {opu_features}, oi: {opu_input}, sign back: {sign_back}')

        if dataset == 'cifar10':
            self.number_classes = 10
        if dataset == 'cifar100':
            self.number_classes = 100

        if sign_back:
            self.dfa1 = Identity()
            self.dfa = Identity()
        else:
            self.training_method = 'DFA'
            self.dfa1 = DFALayer()
            self.dfa = DFA([self.dfa1], no_training=(self.training_method == 'SHALLOW'))

        if opu:
            second_classifier_layer = SimulatedOpu(in_features=opu_input, out_features=opu_features)
        else:
            second_classifier_layer = nn.Linear(opu_input, opu_features)

        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(512, opu_input),
            nn.ReLU(True),
            self.dfa1,
            Sign(binary_layer, sign_back=sign_back),
            second_classifier_layer,
            nn.ReLU(True),
            nn.Linear(opu_features, self.number_classes),
            self.dfa
        )
        # Initialize weights
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
                m.bias.data.zero_()

    def forward(self, x):
        x = self.features(x)
        x = x.view(x.size(0), -1)
        x = self.classifier(x)
        return x

def make_layers(cfg):
    layers = []
    in_channels = 3
    for v in cfg:
        if v == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
            in_channels = v
    return nn.Sequential(*layers)

cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M']

def cifar_vgg16(opu, binary_layer, opu_features, opu_input, sign_back, device, dataset, real_opu=False):
    return CifarVGG16(opu=opu, binary_layer=binary_layer, opu_features=opu_features, features=make_layers(cfg),
                      opu_input=opu_input, sign_back=sign_back, real_opu=real_opu, device=device, dataset=dataset)

def ablation_cifar_vgg16(opu, binary_layer, opu_features, opu_input, dataset, sign_back=False):
    return AblationCifarVGG16(opu=opu, binary_layer=binary_layer, opu_features=opu_features, features=make_layers(cfg),
                              opu_input=opu_input, dataset=dataset, sign_back=sign_back)


import sys
# First function example: Add 1 to a and store as b
def add(a):
    """
    add 1 to a
    """
    b = a + 1
    print(a, "if you add one", b)
    return(b)

c=add(10)
print(c)
# Get a help on add function

help(add)
#---------------------------------------------------------------
# Define a function for multiple two numbers
def Mult(a, b):
    c = a * b
    return (c)
    print('This is not printed')

result = Mult(100, 2.5)#INCLUSE WE CAN MULTIPLY FLOATS OR STR
print(result)
#----------------------------------------------------------------------------------
#Variables in functions
# Function Definition
def square(a):
    # Local variable b
    b = 1
    c = a * a + b
    print(a, "if you square + 1", c)
    return (c)
#--------------------------------------------------------------------------------
# Define functions, one with return value None and other without return value
def MJ():
    print('Michael Jackson')
#or cuold also be
def MJ1():
    print('Michael Jackson')
    return (None)
#---------------------------------------------------------------------------------
#predefined functions
# Build-in function print()
album_ratings = [10.0, 8.5, 9.5, 7.0, 7.0, 9.5, 9.0, 9.5]
print(album_ratings)
# Use sum() to add every element in a list or tuple together
sum(album_ratings)
# Show the length of the list or tuple
len(album_ratings)
#------------------------------------------------------------------------------------
# Function example

def type_of_album(artist, album, year_released):
    print(artist, album, year_released)
    if year_released > 1980:
        return "Modern"
    else:
        return "Oldie"

x = type_of_album("Michael Jackson", "Thriller", 1980)
print(x)
#--------------------------------------------------------------------------------------
#setting a default value in a function
# Example for setting param with default value
def isGoodRating(rating=4):
    if (rating < 7):
        print("this album sucks it's rating is", rating)

    else:
        print("this album is good its rating is", rating)

isGoodRating()
isGoodRating(10)
#---------------------------------------------------------------------------------------
artist = "Michael Jackson"
def funcprinter(artist):
    global internal_var #if you dont define this variable as global yu would print it in the main code
    internal_var= "Whitney Houston"
    print(artist,"is an artist")

funcprinter(artist)
funcprinter(internal_var)
#------------------------------------------------------------------------------------
def printAll(*args): # All the arguments are 'packed' into args which can be treated like a tuple
    print("No of arguments:", len(args))
    for argument in args:
        print(argument)
#printAll with 3 arguments
printAll('Horsefeather','Adonis','Bone')
#printAll with 4 arguments
printAll('Sidecar','Long Island','Mudslide','Carriage')
#----------------------------------------------------------------------------------------
def printDictionary(**args):#as dictorionary
    for key in args:
        print(key + " : " + args[key])

printDictionary(Country='Canada',Province='Ontario',City='Toronto')
#---------------------------------------------------------------------------------------
def addItems(list):#or as a list
    list.append("Three")
    list.append("Four")

myList = ["One", "Two"]

addItems(myList)

print(myList)


#! /usr/bin/env python3

from scipy.stats import pearsonr, norm
import statsmodels.regression.linear_model as lm
import numpy as np #type: ignore
import pandas as pd #type: ignore
from typing import List, Dict, Tuple, Optional
from collections import namedtuple

def weighted_cov(x: np.array, y: np.array, w: np.array) -> float:
    """Weighted covariance between vectors x and y, with weights w
    Args:
        x (np.array): numerical vector x
        y (np.array): numerical vector y
        w (np.array): weights for calculating weighted average of x
    Returns:
        (float): weighted covariance
    """
    return np.average( ( (x-np.average(x, weights=w) ) * (y - np.average(y, weights=w) ) ) , weights=w )

def weighted_pearsonr(x: np.array, y: np.array, w: np.array) -> float:
    return weighted_cov(x, y, w) / np.sqrt( weighted_cov(x, x, w) * weighted_cov(y, y, w) )

def calculate_r2(dataset: pd.DataFrame, x_label: str, y_label: str, stderr_label: str) -> Tuple[float, float, int, int]:
    """Calculate r2 values for dataset
    Args:
        dataset (pd.DataFrame): dataset
        x_label (str): x values column label in dataset
        y_label (str): y values column label in dataset
        stderr_label (str): standard error column label in dataset
    Returns:
        (Tuple[float,float,int,int]): Tuple of values: r^2 without weights, r^2 weighted by inverse stderr, N of r^2 calculation, N of r^2 weighted calculation
    """
    data_w=dataset[[x_label,y_label,stderr_label]].copy()
    data_r2 = data_w[[x_label,y_label]].copy()
    data_r2=data_r2.dropna(how="any")
    data_w=data_w.dropna(how="any")
    r_2=np.nan
    r_w=np.nan
    N_r=np.nan
    N_w=np.nan
    if data_r2.shape[0]>= 2:
        x_array = data_r2[x_label].values
        y_array = data_r2[y_label].values
        r,_=pearsonr(x_array,y_array)
        r_2=r**2
        N_r=data_r2.shape[0]
    if data_w.shape[0]>=2:
        x_array = data_w[x_label].values
        y_array = data_w[y_label].values
        stderr = data_w[stderr_label].values
        weight_array= 1/(stderr**2 + 1e-9) #weights as inverse of variance
        r_w=weighted_pearsonr(x_array,y_array,weight_array)
        r_w=r_w**2
        N_w=data_w.shape[0]
    return (r_2,r_w,N_r,N_w)

RegressionResults = namedtuple('RegressionResults',['slope', 'stderr', 'tstat', 'pval', 'rsquared'])

def calculate_regression(x: np.array,
                        y: np.array,
                        weights: Optional[np.array] = None)-> RegressionResults :
    """Calculate regression y=bx coefficients from data.
    Model uses statsmodels.regression.linear_model.WLS.
    Args:
        x (np.array): numpy array of x-coordinates
        y (np.array): numpy array of y-coordinates
        weights (Optional[np.array]): numpy array of point weights. These are passed directly to WSL.
    Returns:
        (RegressionResults): Named tuple with variables slope, stderr, t-statistic, pvalue, rsquared
    """
    weights = weights if type(weights) != type(None) else 1.0
    model = lm.WLS(y,x,weights)
    results = model.fit()
    slope=results.params[0]
    stderr = results.bse[0]
    tstat = results.tvalues[0]
    pval = results.pvalues[0]
    rsquared = results.rsquared_adj

    return RegressionResults(slope, stderr, tstat, pval,rsquared)


# 给定一个字符串，请你找出其中不含有重复字符的 最长子串 的长度。
#
# 示例 1:
#
# 输入: "abcabcbb"
# 输出: 3
# 解释: 因为无重复字符的最长子串是 "abc"，所以其长度为 3。
# 示例 2:
#
# 输入: "bbbbb"
# 输出: 1
# 解释: 因为无重复字符的最长子串是 "b"，所以其长度为 1。
# 示例 3:
#
# 输入: "pwwkew"
# 输出: 3
# 解释: 因为无重复字符的最长子串是 "wke"，所以其长度为 3。
#      请注意，你的答案必须是 子串 的长度，"pwke" 是一个子序列，不是子串。
class Solution:
    def lengthOfLongestSubstring(self, s):
        """
        :type s: str
        :rtype: int
        """

        maxlen = len(set(s))
        if maxlen <= 2:
            return maxlen

        for trylen in list(range(3,maxlen+1))[::-1]:
            maxtry = len(s) - trylen
            for i in range(maxtry+1):
                if len(s[i:i + trylen]) == len(set(s[i:i + trylen])):
                    print(s[i:i + trylen])
                    return trylen

so = Solution()
print(so.lengthOfLongestSubstring("ohvhjdml"))


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

APPNAME = 'cam'
VERSION = '8.0.0'

def configure(conf):

    if conf.is_mkspec_platform('linux'):

        errmsg = """not found, is available in the following packages:

            Debian/Ubuntu: apt-get install libudev-dev
            Fedora/CentOS: yum install systemd-devel
        """

        conf.check_cxx(header_name='libudev.h', errmsg=errmsg)

        if not conf.env['LIB_UDEV']:
            conf.check_cxx(lib='udev')

        errmsg = """not found, is available in the following packages:

            Debian/Ubuntu: apt-get install libv4l-dev
        """
        conf.check_cxx(header_name='linux/videodev2.h', errmsg=errmsg)

        errmsg = """not found, is available in the following packages:

            Debian/Ubuntu: apt-get install libusb-1.0-0-dev
        """
        conf.check_cxx(header_name='libusb-1.0/libusb.h', errmsg=errmsg)

        if not conf.env['LIB_USB-1.0']:
            conf.check_cxx(lib='usb-1.0')

def build(bld):

    bld.env.append_unique(
        'DEFINES_STEINWURF_VERSION',
        'STEINWURF_CAM_VERSION="{}"'.format(VERSION))

    bld.stlib(features='cxx',
              source=bld.path.ant_glob('src/**/*.cpp'),
              target='cam',
              use=['meta_includes',
              'boost_system',
              'boost_asio_includes',
              'nalu_includes',
              'platform_includes',
              'UDEV',
              'USB-1.0'],
              export_includes=['src'])

    if bld.is_toplevel():

        # Only build tests when executed from the top-level wscript,
        # i.e. not when included as a dependency
        bld.recurse('test')
        bld.recurse('examples/write_file')
        bld.recurse('examples/uvc_test')
        bld.recurse('examples/canon')


import time

import adafruit_esp32spi.adafruit_esp32spi_socket as socket
from adafruit_logging import Handler

class SyslogUDPHandler(Handler):
    """
    Provides a Handler for adafruit_logging that sends messages to a Syslog server
    """

    UDP_PORT = 514
    PRIORITIES = [5, 7, 6, 4, 3, 2]

    def __init__(self, app, server) -> None:
        """
        :param app: the GiveMeASign object this belongs to
        :param server: Syslog server IP address or name
        """
        super().__init__()
        self._facility = 16
        self._app = app
        self._server = server

        socket.set_interface(app.esp)

        self._socket = socket.socket(type=socket.SOCK_DGRAM)
        self._socketaddr = socket.getaddrinfo(server, SyslogUDPHandler.UDP_PORT)[0][4]
        self._socket.connect(self._socketaddr, conntype=app.esp.UDP_MODE)

    def emit(self, record) -> None:
        """
        Construct a Syslog message witht he contents of the logging record

        Syslog packet looks like <FACILITY*8 + SEVERITY>MMM DD HH:MM:SS IPADDRESS TAG MSG

        TAG is up to 32 alphanumeric characters identifying the device

        The ESP32 Airlift UDP implementation is a little weird... UDP is connectionless,
        so we want to just reuse the socket forever. If we don't close it and reopen
        it, it seems to accumulate data and will just tack new messages onto the end
        of old ones. So we'll do this awkward close and connect each time.

        :param record: The record (message object) to be logged
        """
        try:
            self._socket.close()
            self._socket.connect(self._socketaddr, conntype=self._app.esp.UDP_MODE)

            priority = (
                self._facility * 8
                + SyslogUDPHandler.PRIORITIES[int(record.levelno / 10)]
            )

            now = self._app.clock.get_local_time()
            now = time.localtime(now)

            months = [
                "Jan",
                "Feb",
                "Mar",
                "Apr",
                "May",
                "Jun",
                "Jul",
                "Aug",
                "Sep",
                "Oct",
                "Nov",
                "Dec",
            ]

            msg = f"<{priority}>{months[now.tm_mon-1]} {now.tm_mday} {now.tm_hour}:{now.tm_min}:{now.tm_sec} give-me-a-sign[{self._app.esp.pretty_ip(self._app.esp.ip_address)}] {record.msg}"  # pylint: disable=line-too-long
            print("SyslogUDPHandler: ", msg)
            self._socket.send(msg.encode("utf-8"))
        except ConnectionError:
            print("SyslogUDPHandler.emit failed")


import time
import random

random_weapons = ["sword", "axe", "spoon", "bow"]
monsters = ["dragon", "troll", "pirate", "elf"]
monster = ""

def print_pause(message):
    print(message)
    time.sleep(1.1)

def choose_between_two_options(option1, option2):
    choice = ""
    while choice != option1 and choice != option2:
        choice = str(input("(Please enter " + str(option1) +
                           " or " + str(option2) + ").\n")).lower()
    return choice

def play_again():
    print_pause("Would you like to play again? (y/n)")
    option = choose_between_two_options("y", "n")
    if option == "y":
        print_pause("Excellent! Restarting the game ...")
        intro()
    else:
        print_pause("Thanks for playing! See you next time.")

def intro():
    global monster
    monster = random.choice(monsters)
    print_pause("You find yourself standing in an open field, "
                "filled with grass and yellow wildflowers.")
    print_pause("Rumor has it that a " + monster + " is somewhere around here,"
                " and has been terrifying the nearby village.")
    house("dagger")

def fight(weapon):
    if weapon == "dagger":
        print_pause("You do your best...")
        print_pause("but your dagger is no match for the dragon.")
        print_pause("You have been defeated!")
    else:
        print_pause("As the dragon moves to attack, you unsheath your new " +
                    weapon + ".")
        print_pause("The " + weapon[:1].upper() + weapon[1:] + " of Ogoroth "
                    "shines brightly in your hand as you brace yourself"
                    "for the attack.")
        print_pause("But the " + monster +
                    " takes one look at your shiny new toy and runs away!")
        print_pause("You have rid the town of the " + monster +
                    ". You are victorious!")
    play_again()

def cave(weapon):
    if weapon == "dagger":
        weapon = random.choice(random_weapons)
        print_pause("You peer cautiously into the cave.")
        print_pause("It turns out to be only a very small cave.")
        print_pause("Your eye catches a glint of metal behind a rock.")
        print_pause("You have found the magical " + weapon[:1].upper() +
                    weapon[1:] + " of Ogoroth!")
        print_pause("You discard your silly old dagger and take the " +
                    weapon + " with you.")
    else:
        print_pause("You've been here before, and gotten all the good stuff."
                    " It's just an empty cave now.")
    print_pause("You walk back out to the field.\n")
    house(weapon)

def house(weapon):
    print_pause("Enter 1 to knock on the door of the house.")
    print_pause("Enter 2 to peer into the cave.")
    print_pause("What would you like to do? ")
    option = choose_between_two_options("1", "2")
    if option == "1":
        print_pause("You approach the door of the house.")
        print_pause("You are about to knock when the door opens "
                    "and out steps a " + monster + ".")
        print_pause("Eep! This is the " + monster + "'s house!")
        print_pause("The " + monster + " attacks you!")
        if weapon == "dagger":
            print_pause("You feel a bit under-prepared for this,"
                        " what with only having a tiny dagger.")
        print_pause("Would you like to (1) fight or (2) run away?")
        option = choose_between_two_options("1", "2")
        if option == "1":
            fight(weapon)
        else:
            print_pause("You run back into the field. Luckily,"
                        " you don't seem to have been followed.\n")
            house(weapon)
    else:
        cave(weapon)

intro()


import json

from telebot.types import InlineKeyboardButton as TelebotInlineKeyboardButton, ReplyKeyboardMarkup, KeyboardButton
from telebot.types import InlineKeyboardMarkup

from telegram_bot.crypt import encrypt

last_module = None
last_button = 0
button_targets = {}
button_targets_keys = {}

def register_button_function(fn):
    global last_button, button_targets, last_module
    if last_module and fn.__module__ != last_module:
        last_button += 100
    if fn.__module__ != last_module:
        last_module = fn.__module__
    last_button += 1
    button_targets[last_button] = fn
    button_targets_keys[fn] = last_button
    return fn

def get_button_function_key(fn):
    return button_targets_keys[fn]

def get_button_function(id):
    return button_targets[id]

class InlineKeyboardButton(TelebotInlineKeyboardButton):
    def __init__(self, main, text, url=None, callback_data=None, switch_inline_query=None, json_data=None,
                 callback=None, callback_kwargs=None):
        self.main = main
        callback_data = callback_data or self.generate_data(json_data) or self.generate_callback(callback,
                                                                                callback_kwargs)
        super(InlineKeyboardButton, self).__init__(text, url=url, callback_data=callback_data,
                                                   switch_inline_query=switch_inline_query)

    def generate_data(self, data):
        if data is None:
            return
        key = self.main.config['api_token'].split(':')[1][:16].encode('utf-8')
        data = json.dumps(data)
        encoded = encrypt(data, key)
        return encoded

    def generate_callback(self, fn, callback_kwargs):
        if fn is None:
            return
        return self.generate_data({'fn': get_button_function_key(fn), 'kw': callback_kwargs})

class InlineKeyboard(InlineKeyboardMarkup):
    def __init__(self, main, row_width=3):
        self.main = main
        super(InlineKeyboard, self).__init__(row_width=row_width)

    def add_button(self, text, url=None, callback_data=None, switch_inline_query=None, json_data=None,
                   callback=None, callback_kwargs=None):
        self.add(InlineKeyboardButton(self.main, text, url=url, callback_data=callback_data,
                                      switch_inline_query=switch_inline_query, json_data=json_data, callback=callback,
                                      callback_kwargs=callback_kwargs))

class ReplyKeyboard(ReplyKeyboardMarkup):
    def add_button(self, text, request_contact=None, request_location=None):
        self.add(KeyboardButton(text, request_contact, request_location))


from PIL import Image
from pylab import *

import matplotlib.pyplot as plt
from matplotlib import animation

import numpy as np
from numpy import interp

from math import tau
from scipy.integrate import quad

def create_close_loop(image_name, level=[200]):
    # Prepare Plot
    fig, ax = plt.subplots(1, 2, figsize=(10, 5))
    ax[0].set_aspect('equal', 'datalim')
    ax[1].set_aspect('equal', 'datalim')
    ax[0].set_title('Before Centered')
    ax[1].set_title('After Centered')

    # read image to array, then get image border with contour
    im = array(Image.open(image_name).convert('L'))
    contour_plot = ax[0].contour(im, levels=level, colors='black', origin='image')

    # Get Contour Path and create lookup-table
    contour_path = contour_plot.collections[0].get_paths()[0]
    x_table, y_table = contour_path.vertices[:, 0], contour_path.vertices[:, 1]
    time_table = np.linspace(0, tau, len(x_table))

    # Simple method to center the image
    x_table = x_table - min(x_table)
    y_table = y_table - min(y_table)
    x_table = x_table - max(x_table) / 2
    y_table = y_table - max(y_table) / 2

    # Visualization
    ax[1].plot(x_table, y_table, 'k-')

    return time_table, x_table, y_table

def f(t, time_table, x_table, y_table):
    return interp(t, time_table, x_table) + 1j*interp(t, time_table, y_table)

def DFT(t, coef_list, order=5):
    kernel = np.array([np.exp(-n*1j*t) for n in range(-order, order+1)])
    series = np.sum( (coef_list[:,0]+1j*coef_list[:,1]) * kernel[:])
    return np.real(series), np.imag(series)

def coef_list(time_table, x_table, y_table, order=5):
    coef_list = []
    for n in range(-order, order+1):
        real_coef = quad(lambda t: np.real(f(t, time_table, x_table, y_table) * np.exp(-n*1j*t)), 0, tau, limit=100, full_output=1)[0]/tau
        imag_coef = quad(lambda t: np.imag(f(t, time_table, x_table, y_table) * np.exp(-n*1j*t)), 0, tau, limit=100, full_output=1)[0]/tau
        coef_list.append([real_coef, imag_coef])
    return np.array(coef_list)

def visualize(x_DFT, y_DFT, coef, order, space, fig_lim):
    fig, ax = plt.subplots()
    lim = max(fig_lim)
    ax.set_xlim([-lim, lim])
    ax.set_ylim([-lim, lim])
    ax.set_aspect('equal')

    # Initialize
    line = plt.plot([], [], 'k-', linewidth=2)[0]
    radius = [plt.plot([], [], 'r-', linewidth=0.5, marker='o', markersize=1)[0] for _ in range(2 * order + 1)]
    circles = [plt.plot([], [], 'r-', linewidth=0.5)[0] for _ in range(2 * order + 1)]

    def update_c(c, t):
        new_c = []
        for i, j in enumerate(range(-order, order + 1)):
            dtheta = -j * t
            ct, st = np.cos(dtheta), np.sin(dtheta)
            v = [ct * c[i][0] - st * c[i][1], st * c[i][0] + ct * c[i][1]]
            new_c.append(v)
        return np.array(new_c)

    def sort_velocity(order):
        idx = []
        for i in range(1,order+1):
            idx.extend([order+i, order-i])
        return idx

    def animate(i):
        # animate lines
        line.set_data(x_DFT[:i], y_DFT[:i])
        # animate circles
        r = [np.linalg.norm(coef[j]) for j in range(len(coef))]
        pos = coef[order]
        c = update_c(coef, i / len(space) * tau)
        idx = sort_velocity(order)
        for j, rad, circle in zip(idx,radius,circles):
            new_pos = pos + c[j]
            rad.set_data([pos[0], new_pos[0]], [pos[1], new_pos[1]])
            theta = np.linspace(0, tau, 50)
            x, y = r[j] * np.cos(theta) + pos[0], r[j] * np.sin(theta) + pos[1]
            circle.set_data(x, y)
            pos = new_pos

    # Animation
    ani = animation.FuncAnimation(fig, animate, frames=len(space), interval=5)
    return ani


# List of guesses
guesses = []

# Ask you user to guess a letter and store it in guesses list
userinput: bool = True
while userinput:
    letter = input("Guess A Letter ")
    if not letter in guesses:               # Check if letter has already been guessed
        confirm_guess = input("Are you Sure? type 'YES' to Confirm, 'NO' to select a different letter ").upper()
        if confirm_guess == 'YES':
            userinput: bool = False
            guesses.append(letter)
    else:
        print('That letter has already guessed. Try another one')

print(guesses)


import itertools as iter

def solution(num_buns, num_required):
    """
    total keys = num_buns choose num_required-1

    no num_required-1 # of bunnies can have the ability
    to unlock the doors.
    this can lead us to how many times each key is held.
    looking at the examples, (5, 3) each key is held 3 times
    (3, 1) each key is held 3 times
    (2, 2) each key is held once
    (3, 2) each key is held twice
    (4, 4) each key is held once
    is it num_buns - num_required + 1?

    so each key in range(total_keys) needs to be held
    num_buns - num_required + 1 times.
    So we need to assign each key to num_required bunnies.

    this means each bunny holds (total_keys*dupe_keys)/num_buns keys

    for each of range(total_keys)
    choose dupe_keys num_bunnies to possess that key.
    are there always total_keys ways to select groups of dupe_keys bunnies?
    n = num_buns
    k = num_require
    j = n - k + 1 = dupe_keys
    n!/(k-1)!(n-(k-1))! = total_keys = C(n, k - 1)
    C(n, n-(k-1) = C(n, n - k + 1) = C(n, k - 1)

    yes, since we know C(n, k) = C(n, n-k)
    so it follows C(n, k - 1) = C(n, n - (k - 1)) = C(n, n - k + 1) = C(n, j)
    """

    dupe_keys = num_buns - num_required + 1
    sol = [[] for _ in range(num_buns)]

    # solve easy cases
    if num_buns == num_required:
        for i in range(num_required):
            sol[i] = [i]
        return sol
    if num_required == 1:
        for i in range(num_buns):
            sol[i] = [0]
        return sol
    if num_required == 0:
        return sol

    i = 0
    for l in iter.combinations(range(num_buns), dupe_keys):
        for j in l:
            sol[j].append(i)
        i += 1
    return sol

solution(5, 0)
solution(4, 1)
solution(4, 4)
solution(5, 3)


import sys
import time
import threading
from PyQt4 import QtCore, QtGui
from train import start_train

from split import get_status
from split import Spliter
from split import split_file
from constant import TMP_FILE, ICONS

class MainWindow(QtGui.QMainWindow):
    """main window"""
    def __init__(self, parent=None):

        self.sp = Spliter()

        # init
        super(MainWindow, self).__init__(parent)
        self.setWindowTitle("中文分词")
        self.resize(800, 500)
        # widget input...
        self.win_widget = WinWidget(self)
        widget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(widget)
        layout.addWidget(self.win_widget)
        self.setCentralWidget(widget)
        # status bar

        self.statusBar().showMessage("就绪")

        # menu bar
        menu_bar = self.menuBar()
        self.file = menu_bar.addMenu('&File')
        open = self.file.addAction('Open')
        self.connect(open, QtCore.SIGNAL('triggered()'), self.on_open)
        save = self.file.addAction('Save')
        self.connect(save, QtCore.SIGNAL('triggered()'), self.on_save)
        self.file.addSeparator()
        close = self.file.addAction("Close")
        self.connect(close, QtCore.SIGNAL('triggered()'), self.on_close)
        # when text changed do action
        self.connect(self.win_widget.text_input, QtCore.SIGNAL('textChanged(QString)'), self.on_changed)
        # check
        self.connect( self.win_widget.checkbox1, QtCore.SIGNAL( 'clicked()' ), self.check_mode1 )
        self.connect( self.win_widget.checkbox2, QtCore.SIGNAL( 'clicked()' ), self.check_mode2 )
        # button
        self.connect(self.win_widget.button, QtCore.SIGNAL( 'clicked()' ), self.clear)

        self.setWindowIcon(QtGui.QIcon(ICONS))
        self.show()

    def on_open(self):
        file = QtGui.QFileDialog.getOpenFileName(self, 'Open')
        try:
            self.statusBar().showMessage("准备中...")
            # do thread function
            self.bwThread = DealFile(file,
                self.win_widget.checkbox1.isChecked(),
                self.win_widget.checkbox2.isChecked())
            self.bwThread.finishSignal.connect(self.action_end)
            self.bwThread.statusSignal.connect(self.show_status)
            self.bwThread.start()

        except:
            self.statusBar().showMessage("Error!")

    def action_end(self, ls):
        self.win_widget.text_show.setText(ls)
        self.statusBar().showMessage("就绪")

    def show_status(self, s):
        self.statusBar().showMessage(s)

    def on_save(self):
        self.show_result()
        # self.label.setText("save")

    def on_close(self):
        self.close()

    def contextMenuEvent(self, event):
        self.file.exec_(event.globalPos())

    def show_result(self):
        result = split_sentence(self.win_widget.text_input.toPlainText())
        self.win_widget.text_show.setText(result)
        self.statusBar().showMessage(self.win_widget.text_input.toPlainText())
    def check_mode1(self):
        mode = self.win_widget.checkbox1.isChecked()
        test_mode = self.win_widget.checkbox2.isChecked()
        self.sp = Spliter(mode, test_mode)
        if self.win_widget.checkbox1.isChecked():
            self.statusBar().showMessage('使用大颗粒度模式')
        else:
            self.statusBar().showMessage('使用小颗粒度模式')
    def check_mode2(self):
        mode = self.win_widget.checkbox1.isChecked()
        test_mode = self.win_widget.checkbox2.isChecked()
        self.sp = Spliter(mode, test_mode)
        if self.win_widget.checkbox2.isChecked():
            self.statusBar().showMessage('使用检验模式')
        else:
            self.statusBar().showMessage('使用普通模式')

    def clear(self):
        self.win_widget.text_show.setText("")
        self.win_widget.text_input.setText("")
        self.statusBar().showMessage('清除成功')

    def on_changed(self, text):
        if text == "":
            self.win_widget.text_show.setText("")
            self.statusBar().showMessage("就绪")
        else:

            result = self.sp.start(text)
            self.statusBar().showMessage("正在分词...")
            self.win_widget.text_show.setText(result)
            self.statusBar().showMessage("完成")

            # # do thread function
            # self.bwThread2 = DealSentence(text, mode, test_mode)
            # self.bwThread2.finishSignal.connect(self.action_end)
            # self.bwThread2.start()

class WinWidget (QtGui.QWidget) :
    """text area"""
    def __init__(self, parent):
        super(WinWidget, self).__init__(parent)
        grid_layout = QtGui.QGridLayout()
        grid_layout.setSpacing(10)
        self.text_show = QtGui.QTextEdit()
        self.text_show.setText("")
        grid_layout.addWidget(self.text_show, 0, 0, 1, 3)

        self.checkbox1 = QtGui.QCheckBox( "较大颗粒模式" )
        self.checkbox2 = QtGui.QCheckBox( "检验模式" )
        self.button = QtGui.QPushButton( "清空内容")

        grid_layout.addWidget(self.checkbox1,1,0)
        grid_layout.addWidget(self.checkbox2,1,1)
        grid_layout.addWidget(self.button, 1,2)

        self.text_input = QtGui.QLineEdit(self)
        grid_layout.addWidget(self.text_input, 2, 0, 5, 3)

        self.setLayout(grid_layout)

class DealFile(QtCore.QThread):
    """ threading action """
    finishSignal = QtCore.pyqtSignal(str)
    statusSignal = QtCore.pyqtSignal(str)

    def __init__(self ,file , mode, test_mode, parent=None,):
        super(DealFile, self).__init__(parent)
        self.file = file
        self.mode = mode
        self.test_mode = test_mode
    def deal_file(self):
        try:
            split_file(self.file, self.mode, self.test_mode)
            with open(TMP_FILE, "r") as f:
                result = f.readlines()
            self.finishSignal.emit("".join(result))
        except:
            print("Error")

    def deal_status(self):
        last_status = -1
        status = 0
        while last_status != status:
            time.sleep(0.1)
            last_status = status
            status = get_status()
            self.statusSignal.emit("已经处理" + str(status) + "行")
        print("finish")

    def run(self):
        t1 = threading.Thread(target=self.deal_file, args=())
        t2 = threading.Thread(target=self.deal_status, args=())
        t1.start()
        t2.start()

class DealSentence(QtCore.QThread):
    """ threading action """
    finishSignal = QtCore.pyqtSignal(str)

    def __init__(self ,sentence , mode, test_mode, parent=None,):
        super(DealSentence, self).__init__(parent)

        self.sentence = sentence
        self.mode = mode
        self.test_mode = test_mode
    def deal_sentence(self):
        try:
            self.finishSignal.emit(split_sentence(self.sentence, self.mode, self.test_mode))
        except:
            print("Error")

    def run(self):
        t1 = threading.Thread(target=self.deal_sentence, args=())
        t1.start()

def main():

    app = QtGui.QApplication(sys.argv)
    win = MainWindow()
    win.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()


from contextlib import nested
import operator

from oslo.config import cfg

from quantum.db import api as db
# NOTE: this import is needed for correct plugin code work
from quantum.plugins.ryu.common import config
from quantum.plugins.ryu.db import api_v2 as db_api_v2
# NOTE: this import is needed for correct plugin code work
from quantum.plugins.ryu.db import models_v2 as ryu_models_v2
from quantum.tests.unit import test_db_plugin as test_plugin

class RyuDBTest(test_plugin.QuantumDbPluginV2TestCase):
    @staticmethod
    def _tunnel_key_sort(key_list):
        key_list.sort(key=operator.attrgetter('tunnel_key'))
        return [(key.network_id, key.tunnel_key) for key in key_list]

    def test_key_allocation(self):
        tunnel_key = db_api_v2.TunnelKey()
        session = db.get_session()
        with nested(self.network('network-0'),
                    self.network('network-1')
                    ) as (network_0,
                          network_1):
                network_id0 = network_0['network']['id']
                key0 = tunnel_key.allocate(session, network_id0)
                network_id1 = network_1['network']['id']
                key1 = tunnel_key.allocate(session, network_id1)
                key_list = tunnel_key.all_list()
                self.assertEqual(len(key_list), 2)

                expected_list = [(network_id0, key0), (network_id1, key1)]
                self.assertEqual(self._tunnel_key_sort(key_list),
                                 expected_list)

                tunnel_key.delete(session, network_id0)
                key_list = tunnel_key.all_list()
                self.assertEqual(self._tunnel_key_sort(key_list),
                                 [(network_id1, key1)])

                tunnel_key.delete(session, network_id1)
                self.assertEqual(tunnel_key.all_list(), [])


import json
import random
import numpy as np
import scipy
import seaborn as sns
import networkx as nx
import matplotlib.pyplot as plt
from DPC import DPClustering, pairwise_distance

def shortest_path_len(G, i, j):
    return nx.shortest_path_length(G, i, j)

def add_edges(ax, G, pos, **kwargs):
    nx.draw_networkx_edges(G, pos,
                           alpha=kwargs.get('alpha', 0.1),
                           width=kwargs.get('width', 1),
                           ax=ax[0, 0])
    nx.draw_networkx_edges(G, pos,
                           alpha=kwargs.get('alpha', 0.1),
                           width=kwargs.get('width', 1),
                           ax=ax[1, 0])

def cluster_plot(G, pos, true_tags, pred_tags, node_size=400, edge_width=1, label=True, show=True, desc='', **kwargs):
    # large plots
    fig, ax = plt.subplots(1, 2, figsize=(30, 15))
    nx.draw_networkx_edges(G, pos, alpha=0.2, width=edge_width, ax=ax[0])
    nx.draw_networkx_nodes(G, pos,
                           nodelist=G.nodes,
                           node_color=true_tags,
                           node_size=node_size,
                           cmap=plt.cm.jet,
                           alpha=0.8,
                           ax=ax[0])
    if label:
        nx.draw_networkx_labels(G, pos, dict(zip(G.nodes, G.nodes)), font_color="whitesmoke", ax=ax[0])
    ax[0].set_title('Truth')
    nx.draw_networkx_edges(G, pos, alpha=0.2, width=edge_width, ax=ax[1])
    nx.draw_networkx_nodes(G, pos,
                           nodelist=G.nodes,
                           node_color=pred_tags,
                           node_size=node_size,
                           cmap=plt.cm.jet,
                           alpha=0.8,
                           ax=ax[1])
    if label:
        nx.draw_networkx_labels(G, pos, dict(zip(G.nodes, G.nodes)), font_color="whitesmoke", ax=ax[1])
    ax[1].set_title(f'Prediction {desc}')
    # fig.savefig(f'results/{desc}_large.png')
    if show:
        fig.show()
    return fig, ax

def SpectralDP(G, pos, tags, N_communities, desc='Karate', **kwargs):

    laplacian = scipy.sparse.csr_matrix.todense(nx.normalized_laplacian_matrix(G, weight=1))
    u, s, v = scipy.linalg.svd(laplacian)
    # fig, ax = plt.subplots(figsize=(15, 6))
    # sns.scatterplot(x=np.arange(len(s)), y=s[::-1], ax=ax)
    # ax.set_title('Graph Spectrum')
    # fig.show()

    u = u[:, -N_communities:-1]  # truncated
    delta_dist = pairwise_distance(len(tags) - 1, lambda x, y: np.linalg.norm(u[x] - u[y]))

    # hop_dist = pairwise_distance(len(tags) - 1, lambda x, y: shortest_path_len(G, x, y))

    in_data = np.array([pos[i] for i in range(len(tags))])
    DP = DPClustering(in_data, tags)
    DP.run(rho_dist=delta_dist, delta_dist=delta_dist, max_clusters=N_communities, **kwargs)
    # run_fig.savefig(f'results/{desc}.png')
    #
    entropy, purity = DP.eval()
    fig, _ = cluster_plot(G, pos, tags, [DP.align[_] if _ != -1 else -1 for _ in DP.pred_tags], desc=f'DP: entropy={entropy:.3f}, purity={purity:.3f}', **kwargs)
    fig.savefig(f'results/{desc}_large.png')

    return DP, u

def paper_cluster():
    """
    data: can use gamma=True for hint
    'spiral', 8, 5
    'jain', 11, 10
    'flame', 4, 6
    'aggregation', 12, 6
    """
    data, rho_threshold, delta_threshold = 'spiral', 10, 5
    # data, rho_threshold, delta_threshold = 'jain', 13, 10
    # data, rho_threshold, delta_threshold = 'flame', 9, 6
    # data, rho_threshold, delta_threshold = 'aggregation', 16, 5

    pos = np.loadtxt(f'data/{data}.txt')
    tags = [int(_)-1 for _ in pos[:, 2]]
    pos = pos[:, :2]
    # dist_dict = {(int(i)-1, int(j)-1): d for i, j, d in np.loadtxt('data/spiral_distance.txt')}
    dist_dict = pairwise_distance(len(pos) - 1, lambda x, y: np.linalg.norm(pos[x] - pos[y]))

    N_communities = len(set(tags))

    dp = DPClustering(pos, tags)
    dp.run(rho_dist=dist_dict,
           delta_dist=dist_dict,
           max_clusters=N_communities,
           rho_threshold=rho_threshold,
           delta_threshold=delta_threshold,
           gamma=True,
           gauss=True)
    entropy, purity = dp.eval()
    print(f'DP: entropy={entropy:.3f}, purity={purity:.3f}')

    dp.plot(show=True, threshold=True, desc=f'DP: entropy={entropy:.3f}, purity={purity:.3f}')

    # compare to k-means
    dp.k_means(pos, N_communities)
    entropy, purity = dp.eval()
    dp.plot(show=True, threshold=False, desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')

def rand_cluster():
    G = nx.random_partition_graph([5, 10, 15, 15, 15], 0.7, 0.1, seed=0)
    # G = nx.planted_partition_graph(5, 10, 0.5, 0.1, seed=0)
    tags = [G.nodes[v]['block'] for v in G]

    # for plots only
    for e in G.edges:
        G.edges[e]['weight'] = 1 if tags[e[0]] == tags[e[1]] else 0.4

    N_communities = len(set(tags))
    pos = nx.spring_layout(G)

    # Spectral Density Peak Clustering
    dp, embed = SpectralDP(G, pos, tags, N_communities, desc='rand',
                           gamma=False, rho_threshold=1, delta_threshold=0.2)
    print(dp.eval())

    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'DP: entropy={entropy:.3f}, purity={purity:.3f}')
    add_edges(ax, G, pos)
    fig.show()
    fig.savefig(f'results/rand_dp.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')
    add_edges(ax, G, pos)
    fig.show()
    fig.savefig(f'results/rand_k_means.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, _ = cluster_plot(G, pos, tags, [dp.align[_] for _ in dp.pred_tags], desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')
    fig.savefig(f'results/rand_k_means_large.png')

def karate_cluster():
    """
    Karate Club network (2 clusters)
    """
    G = nx.karate_club_graph()
    tags = [0 if G.nodes[v]['club'] == 'Mr. Hi' else 1 for v in G]

    N_communities = len(set(tags))
    pos = nx.spring_layout(G)

    # Spectral Density Peak Clustering
    dp, embed = SpectralDP(G, pos, tags, N_communities, desc='karate',
                           gamma=True, rho_threshold=5, delta_threshold=0.15)
    print(dp.eval())

    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'DP: entropy={entropy:.3f}, purity={purity:.3f}')
    add_edges(ax, G, pos)
    fig.show()
    fig.savefig(f'results/karate_dp.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')
    add_edges(ax, G, pos)
    fig.show()
    fig.savefig(f'results/karate_k_means.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, _ = cluster_plot(G, pos, tags, [dp.align[_] for _ in dp.pred_tags], desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')
    fig.savefig(f'results/karate_k_means_large.png')

def email_cluster():
    with open('data/email_edges.txt', 'rb') as f:
        G = nx.read_adjlist(f, create_using=nx.DiGraph())
    G = G.to_undirected(reciprocal=True)
    G.remove_edges_from(nx.selfloop_edges(G))
    G.remove_nodes_from(list(nx.isolates(G)))

    str_nodes = list(G.nodes)
    str_nodes.sort(key=lambda x: int(x))
    str_nodes_int = {k: v for v, k in enumerate(str_nodes)}
    G = nx.relabel_nodes(G, str_nodes_int)

    communities = {}
    with open('data/email_labels.txt') as f:
        c, tag_set = 0, {}
        for l in f.readlines():
            k, v = l.split(' ')
            if k in str_nodes_int:
                if v not in tag_set:
                    tag_set[v] = c
                    c += 1
                communities[str_nodes_int[k]] = tag_set[v]  # int(v[:-1])
    N_communities = len(set(communities.values()))

    # for plots only
    for e in G.edges:
        G.edges[e]['weight'] = 0.05 if communities[e[0]] == communities[e[1]] else 0.001

    pos = nx.spring_layout(G)
    tags = [communities[v] for v in G]

    # Spectral Density Peak Clustering
    dp, embed = SpectralDP(G, pos, tags, N_communities, desc='email', node_size=10, label=False, plot_edge=False,
                           gamma=True,  percent=1., gauss=True, cut_gauss=True)
    print(dp.eval())

    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'DP: entropy={entropy:.3f}, purity={purity:.3f}')
    fig.show()
    fig.savefig(f'results/email_dp.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')
    fig.show()
    fig.savefig(f'results/email_k_means.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, _ = cluster_plot(G, pos, tags, [dp.align[_] for _ in dp.pred_tags],
                          desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}', node_size=10, label=False)
    fig.savefig(f'results/email_k_means_large.png')

def facebook_cluster():
    """
    too large...
    :return:
    """
    with open('data/facebook_combined.txt', 'rb') as f:
        G = nx.read_adjlist(f)

    # relabel
    str_nodes = list(G.nodes)
    str_nodes.sort(key=lambda x: int(x))
    str_nodes_int = {k: v for v, k in enumerate(str_nodes)}
    G = nx.relabel_nodes(G, str_nodes_int)

    with open('data/fb_tags.txt', 'r') as f:
        content = f.read()
        communities = eval(content)

    N_communities = len(set(communities.values()))

    # for plots only
    for e in G.edges:
        G.edges[e]['weight'] = 0.05 if communities[e[0]] == communities[e[1]] else 0.001

    pos = nx.spring_layout(G)
    tags = [communities[v] for v in G]

    # Spectral Density Peak Clustering
    dp, embed = SpectralDP(G, pos, tags, N_communities, desc='facebook', node_size=10, label=False, plot_edge=False,
                           gamma=True, percent=2., gauss=True, cut_gauss=True)
    print(dp.eval())

    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'DP: entropy={entropy:.3f}, purity={purity:.3f}')
    fig.show()
    fig.savefig(f'results/facebook_dp.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, ax = dp.plot(show=False, threshold=False, desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}')
    fig.show()
    fig.savefig(f'results/facebook_k_means.png')

    # compare to k-means
    dp.k_means(embed, N_communities)
    entropy, purity = dp.eval()
    fig, _ = cluster_plot(G, pos, tags, [dp.align[_] for _ in dp.pred_tags],
                          desc=f'K-means: entropy={entropy:.3f}, purity={purity:.3f}', node_size=10, label=False)
    fig.savefig(f'results/facebook_k_means_large.png')

if __name__ == '__main__':
    karate_cluster()


with open ("data.txt", "r") as myfile:
    lines = myfile.readlines()

all_name = []
for name in lines:
        if 'Name' in name:
            all_name.append(name)

n = [nm[7:-1] for nm in all_name]

print(n)


import yaml
import tarfile
from ansible.module_utils.basic import *
from functools import reduce
import operator

DOCUMENTATION = '''
---
module: get_value_from_yaml_in_tarball
description:
    - Return value from a YAML file that is in a tarball
options:
    tarball:
        description:
          - path to tarball that contains the target yaml file.
        required: true
    target_file:
        description:
          - Path of target YAML file
        required: true
    keys:
        description:
          - List of key(s) to find value in file. It can take multiple values for nested keys.
            For example: ["foreman_proxy", "dhcp"] or ["satellite_version"]
        required: true
    allow_null:
        description:
        - Allows the parameter to be null, defaulting to an empty string. Defaults to false.
        required: false
'''

EXAMPLES = '''
- name: Get puppet user from Satellite answers
  get_value_from_yaml_in_tarball:
    tarball: "/path/to/config_files.tar.gz"
    target_file: "etc/foreman-installer/scenarios.d/satellite-answers.yaml"
    keys: ["puppet", "user"]
  register: puppet_user

  then you can use puppet_user.value
'''

BACKUP_CONFIG = "config_files.tar.gz"

# Takes keys in the format ['foo', 'bar']
# when the dict looks like
# { "foo": { "bar": "hi" }}
# will return None if it a key doesn't exist
def get_value(data, keys):
    try:
        return reduce(operator.getitem, keys, data)
    except KeyError:
        return None

def get_value_from_tarball(params):
    config_tar = tarfile.open(params["tarball"])
    answers_file = config_tar.extractfile(params["target_file"])
    allow_null = params.get("allow_null", False)
    answers = yaml.load(answers_file.read())
    found_value = get_value(answers, params['keys'])
    # The value itself can be false, so only check for NoneType
    if found_value is not None:
        return True, dict(msg="Value found!", changed=False, value=found_value)
    elif allow_null:
        return True, dict(msg="Defaulting to \"\"", changed=False, value="")
    else:
        msg = "Keys {} were not found in {}!".format(
            params["keys"], params["target_file"])
        return False, dict(msg=msg)

def main():
    fields = {
        "tarball": {"required": True, "type": "str"},
        "target_file": {"required": True, "type": "str"},
        "keys": {"required": True, "type": "list"},
        "allow_null": {"required": False, "type": "bool", "default": False}
    }
    module = AnsibleModule(argument_spec=fields)
    success, result = get_value_from_tarball(module.params)
    if success:
        module.exit_json(**result)
    else:
        module.fail_json(**result)

if __name__ == '__main__':
    main()