import re
import requests
from bs4 import BeautifulSoup
from celery import current_app
from celery.contrib import rdb
from decouple import config
from django.db import models
from django.utils import timezone

class Platform(models.Model):
    name = models.CharField(max_length=50)
    url = models.URLField(max_length=500, blank=True)

    @classmethod
    def create(cls, name, url):
        platform = cls(name=name, url=url)
        return platform

class RequestLog(models.Model):
    STATUS_NEW = 1
    STATUS_PENDING = 2
    STATUS_COM = 5
    STATUS_ERROR = 6
    STATUS_CAN = 98
    STATUS_DELETED = 99
    PROCESSING = [STATUS_NEW, STATUS_PENDING]
    SCRAPED = [STATUS_PENDING, STATUS_COM]
    TERMINATED = [STATUS_COM, STATUS_ERROR]

    platform = models.ForeignKey(Platform, on_delete=models.DO_NOTHING)
    url = models.URLField(max_length=500, blank=True)
    title = models.CharField(max_length=250, blank=True)
    pub_date = models.DateTimeField(blank=True)
    status = models.SmallIntegerField()

    @classmethod
    def create(cls, platform, title, url, pub_date, status):
        log = cls(platform=platform, title=title, url=url, pub_date=pub_date, status=status)
        return log

    def is_status(self, *status):
        is_status = any(current_status == self.status for current_status in status)
        return is_status

    def scrape_complete(self):
        page_requests = PageRequest.objects.filter(request=self)
        if page_requests:
            pages = [page_request.page for page_request in page_requests]
            scrape_complete = all(page.is_status(Page.COMPLETED) for page in pages)
            return scrape_complete
        return False

    def update_status(self):
        import time
        if self.is_status(RequestLog.STATUS_NEW):
            print("Checking pages - status: " + str(self.status))
            pages_scraped = False
            while not pages_scraped:
                pages_scraped = self.scrape_complete()
                if not pages_scraped:
                    print('Idle: ' + str(self.status))
                    time.sleep(60)
            print('PEND: ' + self.url)
            self.status = RequestLog.STATUS_PENDING
            self.save()
        elif self.is_status(RequestLog.STATUS_PENDING):
            print('placeholder')

    @staticmethod
    def create_helper_search(request_url, platform, force):
        platform_model = platform
        request_log_model, created = RequestLog.objects.get_or_create(url=request_url,
                                                                      platform=platform_model,
                                                                      defaults={'title': request_url,
                                                                                'pub_date': timezone.now(),
                                                                                'status': RequestLog.STATUS_NEW
                                                                                }
                                                                      )
        playlist_model, created = Playlist.objects.get_or_create(platform=platform,
                                                                 request=request_log_model,
                                                                 )
        if not request_log_model.title == playlist_model.name:
            playlist_model.name = request_log_model.title
            playlist_model.save(update_fields=['name'])
        from .tasks import PROCESS_REQUEST
        current_app.send_task(
            PROCESS_REQUEST,
            args=[request_log_model.pk, force]
        )
        return playlist_model

    def create_search_for_request(self, force):
        request_log_model = self
        request_url = str(request_log_model.url)
        platform = request_log_model.platform
        if force:
            request_log_model.status = RequestLog.STATUS_PENDING
        # if request_log_model.is_status(*RequestLog.PROCESSING):
        if request_log_model.is_status(RequestLog.STATUS_NEW):
            # if created or request_log_model.is_status(RequestLog.PROCESSING):
            print('NEW')
            _response = requests.get(request_url, headers=Page.HEADER_DEFAULT)
            request_html = BeautifulSoup(_response.content, 'html.parser')
            # title = request_html.find('title').get_text()
            title = PageMetaInfo.title_from_html(request_html)
            request_log_model.title = title
            request_log_model.save(update_fields=['title'])
            playlist = Playlist.objects.get(request=request_log_model)
            playlist.name = title
            playlist.save(update_fields=['name'])
            page_meta_list = list()
            if request_url.__contains__('Category') or request_url.__contains__('brand'):
                print('Factory Pages URL setting: ' + platform.name)
                page_meta_list = PageMetaInfo.parse_from_html(platform.name, request_html)
            else:
                print(platform.name + ' page: ' + request_url)
                page_title = PageMetaInfo.title_from_html(request_html)
                page_meta_list.append(PageMetaInfo.factory(title=page_title, url=request_url))
            # page_list = [PageRequest.factory(page_meta, request_log_model) for page_meta in page_meta_list]
            page_list = [Page.repository(page_meta) for page_meta in page_meta_list]
            for page in page_list:
                PageRequest.factory(page_model=page, request_log=request_log_model)

            print(page.url for page in page_list)
            # Page.objects.bulk_create(page_list)
            search_list = list()
            print("PAGES: " + str(len(page_list)))
            from .tasks import REQUEST_STATUS_UPDATE
            current_app.send_task(
                REQUEST_STATUS_UPDATE,
                args=[self.pk]
            )
            for page_model in page_list:
                page_track_list = Search.objects.filter(page=page_model.id)
                if page_track_list:
                    search_list = search_list + list(page_track_list)
                else:
                    mode = request_log_model.platform.name  # rewrite async
                    # name, track_list = Search.factory(mode, page_model)
                    from .tasks import SCRAPE_PAGE_URL
                    current_app.send_task(
                        SCRAPE_PAGE_URL,
                        args=[mode, page_model.url]
                    )
                    # search_list = search_list + track_list
            # request_log_model.status = RequestLog.STATUS_PENDING
            # request_log_model.save()
            # print('PEND: ' + request_url)

        #return request_log_model

class Page(models.Model):
    NEW = 1
    PENDING = 2
    SCRAPED = 5
    EMPTY = 6
    RESCRAPE = 7
    CANCELLED = 98
    DELETED = 99
    COMPLETED = [SCRAPED, EMPTY]

    HEADER_DEFAULT = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) '}
    # 'AppleWebKit/537.36 (KHTML, like Gecko) ' \
    #  'Chrome/75.0.3770.80 Safari/537.36'}
    HEADER_MIXESDB = HEADER_DEFAULT

    url = models.URLField(max_length=500)
    title = models.CharField(max_length=250, blank=True)
    created_datetime = models.DateTimeField(default=timezone.now)
    modified_datetime = models.DateTimeField(blank=True, default=timezone.now)
    status = models.SmallIntegerField()

    @classmethod
    def create(cls, url, title, created_datetime, modified_datetime):
        page = cls(url=url, title=title, created_datetime=created_datetime, modified_datetime=modified_datetime)
        return page

    @classmethod
    def repository(cls, page_meta):
        page, created = Page.objects.get_or_create(
            url=page_meta.url,
            title=page_meta.title,
            status=Page.NEW
        )
        return page

    def is_status(self, *status):
        # return self.status == status
        is_status = any(current_status == self.status for current_status in status)
        return is_status

    def bbc_extract_tracklist(self):
        url = self.url
        print("PAGE TITLE: " + str(self.title))
        bbc_sounds_page_html = requests.get(str(url))
        bbc_sounds_soup = BeautifulSoup(bbc_sounds_page_html.content, 'html.parser')
        tracklist_tag = 'sc-u-flex-grow sc-c-basic-tile__text'
        bbc_tracklist = bbc_sounds_soup.find_all('div', class_=tracklist_tag)
        name = lambda track: track.get('title')
        tracklist = [name(track) for track in bbc_tracklist]
        if len(tracklist) == 0:
            print("NO TRACKS FOUND: " + self.url)
            self.status = Page.EMPTY
        else:
            search_list = [Search.create(track, page=self) for track in tracklist]
            Search.objects.bulk_create(search_list)
            self.status = Page.SCRAPED
        # from .tasks import SEARCH_LIST_CREATE
        # current_app.send_task(
        #     SEARCH_LIST_CREATE,
        #     args=[self.pk, tracklist]
        # )
        from .tasks import SEARCH_FOR_TRACK
        current_app.send_task(
            SEARCH_FOR_TRACK,
            args=[self.pk]
        )
        self.save()
        return self.title, []

    def mixesdb_extract_tracklist(self):
        # TODO retrieve any cached tracks once page status field added to model:
        # TODO remove logic that uses the page model directly
        mixesdb_html_page = requests.get(self.url, headers=Page.HEADER_MIXESDB)
        mixesdb_soup = BeautifulSoup(mixesdb_html_page.content, 'html.parser')
        # Mixipy.update_page_title(page_model, mixesdb_soup)
        print("PAGE TITLE: " + str(self.title))
        tracklist_h2_tag = mixesdb_soup.find('h2', id='Tracklist')
        current_page_element = tracklist_h2_tag
        search_raw_list = []
        while current_page_element:
            ol_section_tag = current_page_element.find_next('ol')
            if ol_section_tag:
                li_track_tags = ol_section_tag.find_all('li')
                if li_track_tags:
                    search_raw_list = search_raw_list + li_track_tags
            current_page_element = ol_section_tag
        if len(search_raw_list) == 0:
            print("PAGE " + self.url + " using fallback method")
            current_div_list_tag = mixesdb_soup.find('div', class_='list')
            while current_div_list_tag:
                class_list = ['list-track', 'aff-api-done', 'list-track aff-done aff-api-done',
                              'list-track aff-api-undone-search aff-done aff-api-done']
                div_list_track_tag = current_div_list_tag.find_next('div', {'class': class_list})
                if div_list_track_tag:
                    if div_list_track_tag.find_previous('h2', id='comments'):
                        current_div_list_tag = False
                    else:
                        search_raw_list.append(div_list_track_tag)
                        current_div_list_tag = div_list_track_tag
                else:
                    current_div_list_tag = False
        else:
            print("PAGE " + self.url + " using primary method")
        if len(search_raw_list) == 0:
            print("NO TRACKS FOUND: " + self.url)
            self.status = Page.EMPTY
        else:
            # TODO convert to listcomp
            format = lambda s: re.sub(r'\[[^\]]*\]', '', s.get_text()).strip().lower()
            valid = lambda s: Page.valid_mixesdb_search(s)
            formatted_search_results = [format(search_html_tag) for search_html_tag in search_raw_list]
            tracklist = [search for search in formatted_search_results if valid(search)]
            if len(tracklist) > 0:
                self.status = Page.PENDING
                from .tasks import SEARCH_LIST_CREATE
                # current_app.send_task(
                #     SEARCH_LIST_CREATE,
                #     args=[self.pk, tracklist]
                # )
                search_list = [Search.create(keywords=track, page=self) for track in tracklist]
                Search.objects.bulk_create(search_list)
                self.status = Page.SCRAPED
            else:
                self.status = Page.EMPTY
        self.save(update_fields=['status'])
        from .tasks import SEARCH_FOR_TRACK
        current_app.send_task(
            SEARCH_FOR_TRACK,
            args=[self.pk]
        )
        return self.title, []

    @staticmethod
    def valid_mixesdb_search(search_str):
        filt = ['?', 'intro', 'unknown']
        if filt.__contains__(search_str):
            return False
        else:
            if search_str.__contains__('-'):
                return True
            else:
                return False

class Search(models.Model):
    keywords = models.CharField(max_length=200)
    page = models.ForeignKey(Page, on_delete=models.DO_NOTHING)

    @classmethod
    def create(cls, keywords, page):
        search = cls(keywords=keywords, page=page)
        return search

    @staticmethod
    def extract_tracklist(mode, page):
        print([mode, page.url])
        name, search_list = '', []
        if mode == 'BBC':
            name, search_list = page.bbc_extract_tracklist()
        elif mode == 'MIXESDB':
            name, search_list = page.mixesdb_extract_tracklist()
        return name, search_list

    @staticmethod
    def create_search_for_page(page, mode):
        page_track_list = Search.objects.filter(page=page.id)
        if page_track_list:
            print("EXISTING TRACKS")
            return list(page_track_list)
        else:
            name, track_list = Search.extract_tracklist(mode, page)
            page.save(update_fields=['status'])
            print("NEW TRACKS")
            return track_list

    def has_been_searched(self):
        pk = self.pk
        page_track_list = Search.objects.filter(keywords=self.keywords).exclude(pk=pk)
        if page_track_list:
            print("ATTEMPTING KEYWORD MATCH")
            for search in list(page_track_list):
                exist_tracks = Track.objects.filter(search=search)
                if exist_tracks:
                    return exist_tracks.first()
        return False

class Track(models.Model):
    uri = models.CharField(max_length=50)
    search = models.ForeignKey(Search, on_delete=models.DO_NOTHING)

    @classmethod
    def create(cls, uri, search):
        track = cls(uri=uri, search=search)
        return track

    @classmethod
    def factory(cls, uri, search_model):
        return Track.create(uri=uri, search=search_model)

    @staticmethod
    def get_bulk(search_list):
        track_list = []
        for search_item in search_list:
            existing_track = Track.objects.filter(search=search_item)
            if existing_track:
                track_list.append(existing_track.first())
        print('TRACKS FOUND: ' + str(len(track_list)) + '/' + str(len(search_list)))  # TODO MOVE
        return track_list

class PageRequest(models.Model):
    request = models.ForeignKey(RequestLog, on_delete=models.DO_NOTHING)
    page = models.ForeignKey(Page, on_delete=models.DO_NOTHING)

    @classmethod
    def create(cls, request, page):
        page_request = cls(request=request, page=page)
        return page_request

    @classmethod
    def factory(cls, page_model, request_log):
        page_request = PageRequest.objects.get_or_create(page=page_model,
                                                         request=request_log)
        return page_request

class Playlist(models.Model):
    request = models.ForeignKey(RequestLog, on_delete=models.DO_NOTHING)
    name = models.CharField(max_length=250)
    platform = models.ForeignKey(Platform, on_delete=models.DO_NOTHING)
    uri = models.CharField(max_length=50, blank=True)
    description = models.CharField(max_length=250, blank=True)

    @classmethod
    def create(cls, request, name, platform, uri=None, description=None):
        playlist = cls(uri, platform, request, name, description)
        return playlist

    @staticmethod
    def facade(request, playlist, force):
        # rdb.set_trace()
        request.create_search_for_request(force)
        print(request.url + " STATUS " + str(request.status))
        playlist.add_available_tracks(force=force)
        return playlist

    def add_available_tracks(self, force):
        playlist = self
        request = self.request
        if force and request.is_status(RequestLog.STATUS_COM):
            request.status = RequestLog.STATUS_PENDING
        if request.is_status(RequestLog.STATUS_COM):
            print("RETURNED COMPLETED EXISTING")
            return playlist
        elif request.is_status(RequestLog.STATUS_PENDING):
            print("REQUEST IS PENDING: " + str(request.status))
            # TODO ONLY 100 tracks can be added at a time - batch api calls so that we search and add in chunks of 100
            linked_pages = PageRequest.objects.filter(request_id=playlist.request)
            page_id_list = [page_request.page_id for page_request in linked_pages]
            page_models = [Page.objects.get(pk=page_id) for page_id in page_id_list]
            page_search = set([Search.objects.filter(page=page) for page in page_models if
                               page.is_status(Page.SCRAPED)])
            track_list = list(set().union(*page_search))
            track_batch = []
            initial_trackList = track_list[0:100]
            remaining_tracks = []
            if len(initial_trackList) >= 100:
                remaining_tracks = track_list[100:]
                print("MORE THAN 100 tracks!")
            else:
                print("TRACKS: " + str(len(initial_trackList)))
            tracklist = Track.get_bulk(initial_trackList)
            playlist_pool = SpotipyPlaylistPool.getInstance()
            # playlist_endpoint = Spotipy.playlist_modify()
            playlist_endpoint = playlist_pool.getResource()
            playlist_uri = playlist.uri
            if not playlist_uri:
                # TODO add a link the playlist as viewed in Mixipy to the Spotify playlist
                request.refresh_from_db()
                title = request.title
                play_list_obj = playlist_endpoint.create_spotify_playlist(title)
                playlist_uri = play_list_obj['uri']
                playlist.uri = playlist_uri
                playlist.save()
            if len(tracklist) > 0:
                ready_batch = [track.uri for track in tracklist]
                print('READY: ' + str(len(ready_batch)) + ' TRACK BATCH: ' + str(len(track_batch)))
                ready_batch = set(ready_batch)
                # TODO we can only have a few of these at a time, maybe need to move to singleton task
                playlist_endpoint.post_tracks_to_playlist(playlist_uri, ready_batch)
            playlist_pool.returnResource(playlist_endpoint)
            if len(remaining_tracks) > 0:
                async_tracklist = [search.pk for search in remaining_tracks]
                from .tasks import TRACKS_TO_PLAYLIST
                current_app.send_task(
                    TRACKS_TO_PLAYLIST,
                    args=(playlist_uri, async_tracklist)
                )
            request.status = RequestLog.STATUS_COM
            request.save()
            print("COM - Playlist: " + str(playlist.id))
            return playlist
        else:
            print('ERR - Request Status: ' + str(request.status))

    def tracks_to_playlist(self, search_list):
        track_list = [Search.objects.get(pk=search_pk) for search_pk in search_list]
        search_chunks = [track_list[x: x + 100]
                         for x
                         in range(0, len(track_list), 100)]
        search_chunks_iter = iter(search_chunks)
        complete = False
        pool = SpotipyPlaylistPool.getInstance()
        spotipy_playlist = pool.getResource()
        print(spotipy_playlist.scope)
        # spotipy_playlist = Spotipy.playlist_modify()
        track_batch = []
        uri_cache = set()
        while not complete:
            next_batch = track_batch
            search_chunk = None
            if len(next_batch) < 100:
                search_chunk = next(search_chunks_iter, None)
                if search_chunk:
                    # TODO we can do the search elsewhere
                    spotify_track_uri_list = Track.get_bulk(search_chunk)
                    next_batch = next_batch + spotify_track_uri_list
            if len(next_batch) >= 100:
                track_batch = next_batch[100:]
                next_batch = next_batch[0:100]
            elif len(next_batch) < 100:
                if search_chunk:
                    track_batch = next_batch
                    next_batch = None
                else:
                    complete = True
            if next_batch:
                batch = [track.uri for track in next_batch]
                ready_batch = set(batch).difference(uri_cache)
                # print(ready_batch)
                print('READY: ' + str(len(ready_batch)) + ' TRACK BATCH: ' + str(len(track_batch)))
                spotipy_playlist.post_tracks_to_playlist(self.uri, ready_batch)
                uri_cache = uri_cache.union(ready_batch)
        pool.returnResource(spotipy_playlist)

class PageMetaInfo:

    def __init__(self, title, url):
        self.title = title
        self.url = url

    def __str__(self):
        return self.title + ', ' + self.url

    @classmethod
    def factory(cls, title, url):
        return cls(title, url)

    @staticmethod
    def title_from_html(html):
        return html.find('title').get_text()

    @staticmethod
    def html_from_url(url):
        return BeautifulSoup(requests.get(url, headers=Page.HEADER_DEFAULT).content, 'html.parser')

    def html(self):
        return BeautifulSoup(requests.get(self.url, headers=Page.HEADER_DEFAULT).content, 'html.parser')

    @staticmethod
    def parse_from_html(mode, html):
        if mode == 'BBC':
            return PageMetaInfo.bbc_brand_extract_page_urls(html)
        elif mode == 'MIXESDB':
            return PageMetaInfo.category_extract_page_urls(html)
        else:
            return []

    @staticmethod
    def bbc_brand_extract_page_urls(bbc_sounds_html):
        print("brand_extract_page_urls")
        bbc_brand = bbc_sounds_html.find_all('article')
        bbc_url = 'https://www.bbc.co.uk'
        title_tag = "sc-c-metadata__secondary gel-long-primer gs-u-mt-"
        url_tag = "sc-c-playable-list-card__link sc-o-link sc-u-flex-grow"
        # desc_tag = "sc-c-metadata__synopsis gel-brevier gs-u-mt- gs-u-mb"
        page_title = lambda e: e.find('p', class_=title_tag).get_text()
        url = lambda e: bbc_url + e.find('a', class_=url_tag).get('href')
        factory = lambda f: PageMetaInfo.factory(page_title(f), url(f))
        page_urls = [factory(mix_link) for mix_link in bbc_brand]
        return page_urls

    @staticmethod
    def category_extract_page_urls(mixesdb_html):
        page_urls = []
        page_html = mixesdb_html
        mixesdb_url = 'https://www.mixesdb.com'
        while page_html:
            urls = PageMetaInfo.mixesdb_extract_page_url_helper(page_html)
            page_urls = page_urls + urls
            # Find next page to parse
            pagination_links = page_html.find('div', class_='listPagination')
            if pagination_links:
                next200_pagination_element = pagination_links.find('a', string='next 200')
                if next200_pagination_element:
                    next200_hyperlink = next200_pagination_element.get('href')
                    next200_url = mixesdb_url + next200_hyperlink
                    next200_request = requests.get(next200_url, headers=Page.HEADER_MIXESDB)
                    print(next200_url)
                    page_html = BeautifulSoup(next200_request.content, 'html.parser')
                else:
                    page_html = ''
            else:
                page_html = ''
        return page_urls

    @staticmethod
    def mixesdb_extract_page_url_helper(mixesdb_html):
        ul_cat_mixes_list_tag = mixesdb_html.find('ul', id='catMixesList')
        page_meta_list = []
        if ul_cat_mixes_list_tag:
            li_cat_mixes_list = ul_cat_mixes_list_tag.find_all('li')
            if li_cat_mixes_list:
                mixlink_list = [mix_link.find('a') for mix_link in li_cat_mixes_list]
                mix_url = 'https://www.mixesdb.com'
                factory = lambda m: PageMetaInfo.factory(title=m.get_text(), url=mix_url + m.get('href'))
                page_meta_list = [factory(mix) for mix in mixlink_list]
        else:
            print("NONE FOUND")
        return page_meta_list

class Spotipy:
    client_id = config('SPOTIFY_CLIENT_ID')
    client_secret = config('SPOTIFY_CLIENT_SECRET')
    redirect_uri = config('REDIRECT_URI')
    search_port = config('REDIRECT_URI_SEARCH')
    playlist_port = config('REDIRECT_URI_PLAYLIST')

    def __init__(self, scope, instance):
        self.scope = scope
        self.instance = instance

    @staticmethod
    def factory(scope):
        if scope == "user-library-read":
            return Spotipy.search_instance()
        elif scope == "playlist-modify-public":
            return Spotipy.playlist_modify()
        elif scope == "playlist-modify-no-cred":
            return Spotipy.playlist_modify_test()
        else:
            print('ERR: OPTION NEEDED')

    @staticmethod
    def create_instance(scope):
        from spotipy import Spotify, SpotifyOAuth
        from spotipy.oauth2 import SpotifyClientCredentials
        if scope == "user-library-read":
            client_credentials_manager = SpotifyClientCredentials(client_id=Spotipy.client_id,
                                                                  client_secret=Spotipy.client_secret)
            return Spotify(client_credentials_manager=client_credentials_manager)
        elif scope == "playlist-modify-public":
            return Spotify(auth_manager=SpotifyOAuth(client_id=Spotipy.client_id,
                                                     client_secret=Spotipy.client_secret,
                                                     redirect_uri=Spotipy.redirect_uri,
                                                     scope="playlist-modify-public"))
        elif scope == 'playlist-modify-second':
            return Spotify(auth_manager=SpotifyOAuth(client_id=Spotipy.client_id,
                                                     client_secret=Spotipy.client_secret,
                                                     redirect_uri=Spotipy.playlist_port,
                                                     scope="playlist-modify-public"))
        elif scope == "playlist-modify-no-cred":
            client_credentials_manager = SpotifyClientCredentials(client_id=Spotipy.client_id,
                                                                  client_secret=Spotipy.client_secret,
                                                                  )
            return Spotify(client_credentials_manager=client_credentials_manager)

    def reset(self):
        self.instance = Spotipy.create_instance(scope=self.scope)

    @classmethod
    def search_instance(cls):
        return cls("user-library-read", Spotipy.create_instance("user-library-read"))

    @classmethod
    def playlist_modify(cls):
        return cls("playlist-modify-public", Spotipy.create_instance("playlist-modify-public"))

    @classmethod
    def playlist_second(cls):
        return cls("playlist-modify-second", Spotipy.create_instance("playlist-modify-second"))

    @classmethod
    def playlist_modify_test(cls):
        return cls("playlist-modify-no-cred", Spotipy.create_instance("playlist-modify-no-cred"))

    # TODO investigate: creating the playlist is a user action, but maybe we can use cred-manage for adding?
    def create_spotify_playlist(self, title):
        user_id = self.instance.me()['id']
        instance = self.instance
        playlist_obj = instance.user_playlist_create(user_id, title)
        return playlist_obj

    def post_tracks_to_playlist(self, playlist_uri, tracks):
        self.instance.playlist_add_items(playlist_id=playlist_uri, items=tracks, position=None)

    # @staticmethod
    # def search_spotify_track(search, sp, limit=10):
    #     if search:
    #         kw = search.keywords.lower()
    #         results = sp.search(q=kw, limit=limit)
    #         # for idx, track in enumerate(results['tracks']['items']):
    #         #     if str(search.keywords.lower()).__contains__(track['artists'][0].get('name').lower()):
    #         #         uri = track['uri']
    #         #         return SpotifyTrack.factory(spotify_track=track, uri=uri)
    #         search_result = [track for idx, track in enumerate(results['tracks']['items'])]
    #         validate = lambda s: kw.__contains__(s['artists'][0].get('name').lower())
    #         factory = lambda t: SpotifyTrack.factory(spotify_track=t, uri=t['uri'])
    #         filtered_search = [factory(track) for track in search_result if validate(track)]
    #         return filtered_search
    #         # else:
    #         # TODO log near-matches
    #         #    print([search, track['artists'][0].get('name')])

    def create_tracks_for_page(self, search_list):
        db_track_list = []
        for search_item in search_list:
            spotify_track_matches = self.search_track(search_item, 1)
            spotify_track = next((track for track in spotify_track_matches), None)
            if spotify_track:
                uri = spotify_track.uri
                if uri:
                    track_model = Track.factory(uri=uri, search_model=search_item)
                    db_track_list.append(track_model)
        Track.objects.bulk_create(db_track_list)

    def search_track(self, search, limit=10):
        if search:
            kw = search.keywords.lower()
            results = self.instance.search(q=kw, limit=limit)
            search_result = [track for idx, track in enumerate(results['tracks']['items'])]
            validate = lambda s: kw.__contains__(s['artists'][0].get('name').lower())
            factory = lambda t: SpotifyTrack.factory(spotify_track=t, uri=t['uri'])
            filtered_search = [factory(track) for track in search_result if validate(track)]
            return filtered_search

class SpotipyPlaylistPool:
    from queue import Queue
    __instance = None
    __resources = Queue()
    __resources.put(Spotipy.playlist_modify())
    __resources.put(Spotipy.playlist_second())

    def __init__(self):
        if SpotipyPlaylistPool.__instance is not None:
            raise NotImplemented("singleton class")

    @staticmethod
    def getInstance():
        if SpotipyPlaylistPool.__instance is None:
            SpotipyPlaylistPool.__instance = SpotipyPlaylistPool()

        return SpotipyPlaylistPool.__instance

    def getResource(self):
        if not self.__resources.empty():
            print("Using existing resource")
            return self.__resources.get(True)
        else:
            print("Waiting for new resource indefinitely")

    def returnResource(self, resource):
        resource.reset()
        self.__resources.put(resource)

# class SpotipyQueue:
#     _q = None
#     o = None
#
#     def __init__(self, dQ, autoGet=False):
#         self._q = dQ
#
#         if autoGet:
#             self.o == self._q.get()
#
#     def __enter__(self):
#         if self.o == None:
#             self.o = self._q.get()
#             return self.o
#         else:
#             return self.o
#
#     def __exit__(self, type, value, traceback):
#         if self.o is None:
#             self._q.put(self.o)
#             self.o = None
#
#     def __del__(self):
#         if self.o is None:
#             self._q.put(self.o)
#             self.o = None

class SpotifyTrack:

    def __init__(self, spotify_track, uri):
        self.spotify_track = spotify_track
        self.uri = uri

    def __str__(self):
        return str({**{'uri': self.uri}, **self.spotify_track})

    @classmethod
    def factory(cls, spotify_track, uri):
        return cls(spotify_track, uri)

class SearchQuery(models.Model):
    key = models.CharField(max_length=200, primary_key=True)


@dataclass
class DebugVisitor(Visitor[T]):
    tree_depth: int = 0

    def visit_default(self, node: LN) -> Iterator[T]:
        indent = ' ' * (2 * self.tree_depth)
        if isinstance(node, Node):
            _type = type_repr(node.type)
            out(f'{indent}{_type}', fg='yellow')
            self.tree_depth += 1
            for child in node.children:
                yield from self.visit(child)

            self.tree_depth -= 1
            out(f'{indent}/{_type}', fg='yellow', bold=False)
        else:
            _type = token.tok_name.get(node.type, str(node.type))
            out(f'{indent}{_type}', fg='blue', nl=False)
            if node.prefix:
                # We don't have to handle prefixes for `Node` objects since
                # that delegates to the first child anyway.
                out(f' {node.prefix!r}', fg='green', bold=False, nl=False)
            out(f' {node.value!r}', fg='blue', bold=False)

    @classmethod
    def show(cls, code: str) -> None:
        """Pretty-prints a given string of `code`.

        Convenience method for debugging.
        """
        v: DebugVisitor[None] = DebugVisitor()
        list(v.visit(lib2to3_parse(code)))


import streamlit as st
import pandas as pd
import numpy as np
import time

st.title('📊 Demonstration: Loading Air BnB Clean Data with Caching 📊')

st.markdown("""🌐 Source Data [Kaggle](https://www.kaggle.com/datasets/arianazmoudeh/airbnbopendata)""")

# Ini buat nambahin cache biar dia ga reload ulang
@st.cache_data
def load_data(nrow):

    ### Simulating Loading a Large Dataset
    data = pd.read_csv('dataset/Visualization_AirBnB.csv', nrows=nrow)

    chunk_1 = data[0:200]
    chunk_2 = data[200:400]
    chunk_3 = data[400:600]
    chunk_4 = data[600:800]
    chunk_5 = data[800:]

    all_chunk = [chunk_1, chunk_2, chunk_3, chunk_4, chunk_5]

    new_data = pd.DataFrame()
    counter_text = st.text('Processing...')
    for i, chunk in enumerate(all_chunk):
        counter_text.text(f"Processing Part {i+1}/{len(all_chunk)}")
        time.sleep(0.6)
        new_data = new_data.append(chunk).reset_index(drop = True)
    del counter_text
    return data

data_load_state = st.text('Loading data...')
data = load_data(1000)
data_load_state.text('Done!')

# Nilai default checkbox adalah false
if st.checkbox('Show raw data'):
    st.subheader('Raw data') # Kalau diklik muncul ini
    st.write(data)

# Cache Demo
st.markdown(
    """
Now, let's jazz up the app! 🔄 Ideally, the app shouldn't have to redownload the dataset.

Caching allows us to store the results of a function in Streamlit. So, when the app is refreshed and there are
no changes to a particular function, the cached results are retrieved, preventing the function from being rerun
every time the app is refreshed. 🚀
    """
)

# Penjelasan
st.markdown("""This is the dataset we will use for visualization and machine learning later
            🧹The dataset has already been cleaned, as I have completed the:""")

st.markdown("- Data Cleaning")

st.image('1.png', caption='Database Source', use_column_width=True)

st.markdown("- Missing Values")

st.image('2.png', caption='Missing Values', use_column_width=True)

st.markdown("- Handling Outlier")

st.image('3.png', caption='Handling Outlier', use_column_width=True)


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# Import data
from tensorflow.examples.tutorials.mnist import input_data
from datetime import datetime
import numpy as np
import sys
sys.path.append("/data")
import tensorflow as tf

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

sess = tf.InteractiveSession()

# Create the model
x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b)

# Define loss and optimizer
y_ = tf.placeholder(tf.float32, [None, 10])
#MUTATION#
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

# Train
tf.train.write_graph(sess.graph_def, '/data/scripts/study_case/pbtxt_files', 'tensorflow_examples_tutorials_mnist.pbtxt')
tf.initialize_all_variables().run()

batch_size = 100

'''inserted code'''
from scripts.utils.tf_utils import TensorFlowScheduler
scheduler = TensorFlowScheduler(name="tensorflow-examples-tutorials-mnist")
'''inserted code'''

while True:
    batch_xs, batch_ys = mnist.train.next_batch(100)

    loss_val= sess.run(cross_entropy,feed_dict={x: batch_xs, y_: batch_ys})

    x_val, y_val = sess.run([x, y_], feed_dict={x: batch_xs, y_: batch_ys})
    # print("x val:(", np.max(x_val), np.min(x_val), ")\ty val:(", np.max(y_val), np.min(y_val), ")")

    '''inserted code'''
    scheduler.loss_checker(loss_val)
    '''inserted code'''
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

    '''inserted code'''
    scheduler.check_time()
    '''inserted code'''


import gymnasium as gym
from stable_baselines3 import A2C, DQN, PPO

from envs.hmarl_central_env import CentralAgentEnv
from envs.hmarl_slice_env import ElasticSliceAgentEnv

slice_class = "C3"
algo = "PPO"
model_type = "agent"

if model_type == "central":
    env = CentralAgentEnv()
    models_dir = f"hmarl2/models/{model_type}_{algo}"
    log_file_name = f"central_{algo}"
else:
    env = ElasticSliceAgentEnv(slice_class=slice_class)
    models_dir = f"hmarl2/models/agent_{algo}_{slice_class}"
    log_file_name = f"{algo}_{slice_class}"

log_dir = "hmarl2/logs"

if algo == "PPO":
    model = PPO("MultiInputPolicy", env, verbose=1, tensorboard_log=log_dir)
elif algo == "A2C":
    model = A2C("MultiInputPolicy", env, verbose=1, tensorboard_log=log_dir)
else:
    model = DQN("MultiInputPolicy", env, verbose=1, tensorboard_log=log_dir)

TIMESTEPS = 100000

env.reset()
for i in range(1, 30):
    model.learn(total_timesteps=TIMESTEPS, reset_num_timesteps=False, tb_log_name=log_file_name)
    model.save(f"{models_dir}/{TIMESTEPS*i}")
env.close()


# main.py
import torch
import torchvision.transforms as transforms
from torch.optim.lr_scheduler import StepLR
from torchvision.datasets import CIFAR10
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

# Определение модели
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
        self.fc1 = nn.Linear(128 * 8 * 8, 512)
        self.fc2 = nn.Linear(512, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 128 * 8 * 8)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return x

if torch.cuda.is_available():
    device = torch.device("cuda")
    print("GPU доступна")
else:
    device = torch.device("cpu")
    print("GPU не доступна")

# Загрузка данных
transform = transforms.Compose([
    transforms.RandomHorizontalFlip(),
    transforms.RandomRotation(10),
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),])
train_dataset = CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)

# Инициализация модели
model = SimpleCNN().to(device)

# Определение функции потерь и оптимизатора
criterion = nn.CrossEntropyLoss()
optimizer = optim.AdamW(model.parameters(), lr=0.001)

# Обучение модели
epochs = 5
for epoch in range(epochs):
    scheduler = StepLR(optimizer, step_size=5, gamma=0.1)
    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        inputs, labels = data

        optimizer.zero_grad()

        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        if i % 100 == 99:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 100))
            running_loss = 0.0

torch.save(model.state_dict(), 'CIFAR10_cnn_model.pth')


# Plots the results produced by run_ensemble_size_tests.py (Figures 5-7 in the
# paper).

from pylab import *
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import pickle
from pysteps.verification import ensscores, probscores

#domain = "fmi"
domain = "mch"
linecolors = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b",
              "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]
ensemble_size = 48
upscale_factor = 1

leadtimes = {0.1: [5, 11, 23, 35],
             1.0: [5, 11, 23, 35],
             5.0: [2, 5, 8],
             10.0: [2, 5, 8]}

infn = "ensemble_size_results_%s" % domain
if upscale_factor > 1:
    infn += "_%d" % upscale_factor
with open(infn + ".dat", "rb") as f:
    results = pickle.load(f)

for R_thr in results[ensemble_size]["ROC"].keys():
    fig = figure(figsize=(10, 3.5))

    ax = fig.add_subplot(121)

    iax = inset_axes(ax, width="35%", height="20%", loc=2, borderpad=2.0)

    sample_size_min = []
    sample_size_max = []

    for i,lt in enumerate(leadtimes[R_thr]):
        reldiag = results[ensemble_size]["reldiag"][R_thr][lt]

        f = 1.0 * reldiag["Y_sum"] / reldiag["num_idx"]
        r = 1.0 * reldiag["X_sum"] / reldiag["num_idx"]

        mask = np.logical_and(np.isfinite(r), np.isfinite(f))

        ax.plot(r[mask], f[mask], color=linecolors[i], linestyle='-', marker='D',
                label="%d minutes" % ((lt+1)*5))

        bd = 0.5 * (reldiag["bin_edges"][1] - reldiag["bin_edges"][0])
        iax.plot(reldiag["bin_edges"][:-1] + bd, reldiag["sample_size"],
                 color=linecolors[i], linestyle='-', marker='D', ms=3)

        sample_size_min.append(int(max(floor(log10(min(reldiag["sample_size"]))), 1)))
        sample_size_max.append(int(ceil(log10(max(reldiag["sample_size"])))))

    iax.set_yscale("log", basey=10)
    iax.set_xticks(reldiag["bin_edges"][::2])
    iax.set_xticklabels(["%.1f" % max(v, 1e-6) for v in reldiag["bin_edges"][::2]])
    yt_min = min(sample_size_min)
    yt_max = max(sample_size_max)
    t = [pow(10.0, k) for k in range(yt_min, yt_max)]
    iax.set_yticks([int(t_) for t_ in t])
    iax.set_xlim(0.0, 1.0)
    iax.set_ylim(0.5*t[0], 5*t[-1])
    iax.set_ylabel("$\log_{10}$(samples)")
    iax.yaxis.tick_right()
    iax.yaxis.set_label_position("right")
    iax.tick_params(axis="both", which="major", labelsize=6)
    iax.grid(axis='y')

    ax.plot([0, 1], [0, 1], "k--")

    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.grid(True)
    ax.legend(fontsize=12, loc=4, framealpha=1.0)
    ax.set_title("a)", loc="left", fontsize=12)
    ax.set_xlabel("Forecast probability", fontsize=12)
    ax.set_ylabel("Observed relative frequency", fontsize=12)

    ax = fig.add_subplot(122)

    ax.plot([0, 1], [0, 1], "k--")

    for i,lt in enumerate(leadtimes[R_thr]):
        ROC = results[ensemble_size]["ROC"][R_thr][lt]
        POFD,POD,area = probscores.ROC_curve_compute(ROC, compute_area=True)
        ax.plot(POFD, POD, color=linecolors[i], lw=2, #linestyle='-', marker='D',
                label="%d minutes (area=%.2f)" % (((lt+1)*5), area))

        opt_prob_thr_idx = np.argmax(np.array(POD) - np.array(POFD))
        #opt_prob_thr_idx = np.argmin((1-np.array(POD))**2 + np.array(POFD)**2)
        x = POFD[opt_prob_thr_idx]
        y = POD[opt_prob_thr_idx]
        ax.scatter([x], [y], c='k', marker='+', s=50, facecolors=None, zorder=1000)
        ax.text(x+0.02, y-0.02, "%.2f" % ROC["prob_thrs"][opt_prob_thr_idx],
                fontsize=7)

    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    ax.set_title("b)", loc="left", fontsize=12)
    ax.set_xlabel("False alarm rate (POFD)", fontsize=12)
    ax.set_ylabel("Probability of detection (POD)", fontsize=12)
    ax.grid(True)
    ax.legend(fontsize=12, loc=4, framealpha=1.0)

    outfn = "reldiags_and_ROCs_%s" % domain
    if upscale_factor > 1:
        outfn += "_%d" % upscale_factor
    outfn += "_%.1f" % R_thr
    fig.savefig(outfn + ".pdf", bbox_inches="tight")

for R_thr in results[ensemble_size]["rankhist"].keys():
    fig = figure(figsize=(5, 3.5))

    r_max = 0.0
    for i,lt in enumerate(leadtimes[R_thr]):
        rankhist = results[ensemble_size]["rankhist"][R_thr][lt]
        r = ensscores.rankhist_compute(rankhist)
        r_max = max(r_max, np.max(r))
        x = np.linspace(0, 1, rankhist["num_ens_members"] + 1)
        x += 0.5 * (x[1] - x[0])
        plot(x, r, color=linecolors[i], label="%d minutes" % ((lt+1)*5), lw=2)

    xticks(x[::3] + (x[1] - x[0]), np.arange(1, len(x))[::3])
    xlim(0.5*(x[1]-x[0]), 1+1.0/len(x)-0.5*(x[1]-x[0]))
    ylim(0, r_max*1.1)
    xlabel("Rank of observation (among ensemble members)", fontsize=12)
    ylabel("Relative frequency", fontsize=12)
    grid(True, axis='y')
    legend(fontsize=12, loc=10, framealpha=1.0)

    outfn = "rankhists_%s" % domain
    if upscale_factor > 1:
        outfn += "_%d" % upscale_factor
    outfn += "_%.1f" % R_thr
    fig.savefig(outfn + ".pdf", bbox_inches="tight")


from collections import OrderedDict
import pathlib
from fuse.utils.utils_logger import fuse_logger_start
import os
import yaml

import pandas as pd
from fuse.dl.models import ModelMultiHead
from fuse.dl.models.backbones.backbone_resnet_3d import BackboneResnet3D
from fuse.dl.models.heads.heads_3D import Head3D
from fuseimg.datasets.knight import KNIGHT
import torch.nn.functional as F
import torch.nn as nn
from torch.utils.data.dataloader import DataLoader
from fuse.data.utils.collates import CollateDefault
from fuse.data.utils.samplers import BatchSamplerDefault

from fuse.eval.metrics.classification.metrics_classification_common import (
    MetricAUCROC,
    MetricAccuracy,
    MetricConfusion,
)
from fuse.eval.metrics.classification.metrics_thresholding_common import (
    MetricApplyThresholds,
)
import torch.optim as optim
import fuse.utils.gpu as GPU
from fuse.utils.rand.seed import Seed
import logging
import time
import copy
import shutil
from fuse.dl.losses.loss_default import LossDefault
from fuse.dl.lightning.pl_module import LightningModuleDefault
import pytorch_lightning as pl
from omegaconf import DictConfig

## Parameters:
##############################################################################
# Data sources to use in model. Set {'imaging': True, 'clinical': False} for imaging only setting,
# and vice versa, or set both to True to use both.
# allocate gpus
# uncomment if you want to use specific gpus instead of automatically looking for free ones

def make_model(
    use_data: dict, num_classes: int, imaging_dropout: float, fused_dropout: float
) -> nn.Module:
    if use_data["imaging"]:
        backbone = BackboneResnet3D(in_channels=1, pretrained=False)
        conv_inputs = [("model.backbone_features", 512)]
    else:
        backbone = nn.Identity()
        conv_inputs = None
    if use_data["clinical"]:
        append_features = [("data.input.clinical.all", 11)]
    else:
        append_features = None

    model = ModelMultiHead(
        conv_inputs=(("data.input.img", 1),),
        backbone=backbone,
        heads=[
            Head3D(
                head_name="head_0",
                mode="classification",
                conv_inputs=conv_inputs,
                dropout_rate=imaging_dropout,
                num_outputs=num_classes,
                append_features=append_features,
                append_layers_description=(256, 128),
                fused_dropout_rate=fused_dropout,
            ),
        ],
    )
    return model

def main(cfg_path: DictConfig) -> None:
    # read config params
    cfg = yaml.safe_load(open(cfg_path))
    task_num = cfg["task_num"]
    num_classes = cfg[task_num]["num_classes"]
    target_name = cfg[task_num]["target_name"]
    class_names = (
        None if not cfg[task_num]["class_names"] else cfg[task_num]["class_names"]
    )
    if cfg["num_gpus"] == 0:
        use_gpu = False
    else:
        use_gpu = True

    # read train/val splits file. for convenience, we use the one
    # auto-generated by the nnU-Net framework for the KiTS21 data
    dir_path = pathlib.Path(__file__).parent.resolve()
    splits = pd.read_pickle(os.path.join(dir_path, "splits_final.pkl"))
    # For this example, we use split 0 out of the 5 available cross validation splits
    split = splits[0]
    if cfg["testing"]:
        split["train"] = split["train"][:10]
        split["val"] = split["val"][:10]
    # read environment variables for data, cache and results locations
    data_path = os.environ["KNIGHT_DATA"]
    cache_path = os.path.join(os.environ["KNIGHT_CACHE"], str(cfg["experiment_num"]))
    results_path = os.environ["KNIGHT_RESULTS"]

    ## Basic settings:
    ##############################################################################
    # create model results dir:
    # we use a time stamp in model directory name, to prevent re-writing
    timestr = time.strftime("%Y%m%d-%H%M%S")
    model_dir = os.path.join(results_path, timestr)
    if not os.path.isdir(model_dir):
        os.makedirs(model_dir)
    shutil.copy(cfg_path, model_dir)
    # start logger
    fuse_logger_start(output_path=model_dir, console_verbose_level=logging.INFO)
    print("Done")

    # set constant seed for reproducibility.
    os.environ[
        "CUBLAS_WORKSPACE_CONFIG"
    ] = ":4096:8"  # required for pytorch deterministic mode
    rand_gen = Seed.set_seed(1234, deterministic_mode=True)

    # select gpus
    if use_gpu:
        GPU.choose_and_enable_multiple_gpus(cfg["num_gpus"], force_gpus=None)

    ## Model definition
    ##############################################################################

    model = make_model(
        cfg["use_data"], num_classes, cfg["imaging_dropout"], cfg["fused_dropout"]
    )

    ## FuseMedML dataset preparation
    ##############################################################################

    train_ds, valid_ds = KNIGHT.dataset(
        data_path=data_path,
        cache_dir=cache_path,
        split=split,
        reset_cache=cfg["reset_cache"],
        resize_to=cfg["resize_to"],
    )

    ## Create dataloader

    sampler = BatchSamplerDefault(
        dataset=train_ds,
        balanced_class_name=target_name,
        num_balanced_classes=num_classes,
        batch_size=cfg["batch_size"],
        balanced_class_weights=[1.0 / num_classes] * num_classes
        if task_num == "task_2"
        else None,
        mode="approx",
    )

    train_dl = DataLoader(
        dataset=train_ds,
        shuffle=False,
        drop_last=False,
        batch_sampler=sampler,
        collate_fn=CollateDefault(),
        num_workers=8,
    )

    valid_dl = DataLoader(
        dataset=valid_ds,
        shuffle=False,
        drop_last=False,
        batch_sampler=None,
        batch_size=cfg["batch_size"],
        num_workers=8,
        collate_fn=CollateDefault(),
        generator=rand_gen,
    )

    # Loss definition:
    ##############################################################################
    losses = {
        "cls_loss": LossDefault(
            pred="model.logits.head_0",
            target=target_name,
            callable=F.cross_entropy,
            weight=1.0,
        ),
    }

    # Metrics definition:
    ##############################################################################
    train_metrics = OrderedDict(
        [
            (
                "op",
                MetricApplyThresholds(pred="model.output.head_0"),
            ),  # will apply argmax
            (
                "auc",
                MetricAUCROC(
                    pred="model.output.head_0",
                    target=target_name,
                    class_names=class_names,
                ),
            ),
            (
                "accuracy",
                MetricAccuracy(pred="results:metrics.op.cls_pred", target=target_name),
            ),
            (
                "sensitivity",
                MetricConfusion(
                    pred="results:metrics.op.cls_pred",
                    target=target_name,
                    metrics=("sensitivity",),
                ),
            ),
        ]
    )
    val_metrics = copy.deepcopy(
        train_metrics
    )  # use the same metrics in validation as well

    best_epoch_source = dict(
        monitor=cfg[task_num][
            "target_metric"
        ],  # can be any key from losses or metrics dictionaries
        mode="max",  # can be either min/max
    )

    # Optimizer definition:
    ##############################################################################
    optimizer = optim.Adam(
        model.parameters(), lr=cfg["learning_rate"], weight_decay=0.001
    )

    # Scheduler definition:
    ##############################################################################
    lr_scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer)
    lr_sch_config = dict(scheduler=lr_scheduler, monitor="validation.losses.total_loss")
    optimizers_and_lr_schs = dict(optimizer=optimizer, lr_scheduler=lr_sch_config)

    ## Training
    ##############################################################################

    # create instance of PL module - FuseMedML generic version
    pl_module = LightningModuleDefault(
        model_dir=model_dir,
        model=model,
        losses=losses,
        train_metrics=train_metrics,
        validation_metrics=val_metrics,
        best_epoch_source=best_epoch_source,
        optimizers_and_lr_schs=optimizers_and_lr_schs,
    )
    # create lightning trainer.
    pl_trainer = pl.Trainer(
        default_root_dir=model_dir,
        max_epochs=cfg["num_epochs"],
        accelerator="gpu" if use_gpu else "cpu",
        devices=cfg["num_gpus"] if use_gpu else None,
        num_sanity_val_steps=-1,
        # auto_scale_batch_size="binsearch",  # should use Tuner -  https://lightning.ai/pages/releases/2.0.0/#tuner
    )

    # train
    pl_trainer.fit(pl_module, train_dl, valid_dl, ckpt_path=None)

if __name__ == "__main__":
    config_path = os.path.join(
        os.path.dirname(os.path.abspath(__file__)), "config.yaml"
    )
    main(config_path)


'''
Author: cijliu
Date: 2020-11-26 21:22:09
LastEditTime: 2020-12-01 10:36:59
'''
import tengine
id = tengine.OCR #目前支持OCR和FACE两个AI应用
models_path = "/root/app/models/crnn_lite_dense.tmfile"
keys_path = "/root/app/models/keys.txt"
input_type = tengine.IMAGE
tengine.load(models_path, id, input_type)#加载模型文件，指定输入数据为图片
res = tengine.detect("/root/app/res/ocr.jpg", keys_path)
print(res)


#!/bin/python
# -*- coding: utf-8 -*-
# https://adventofcode.com/2021/day/1

###################################################################################################################################################################
#
#  Solution to day XX part 1: 1266
#
#  Solution to day XX part 2: 1217
#
###################################################################################################################################################################

import unittest

###################################################################################################################################################################
############################################################################ PROBLEM 1 ############################################################################
#
#   --- Day 1: Sonar Sweep ---
#   You're minding your own business on a ship at sea when the overboard alarm goes off! You rush to see if you can help. Apparently,
#   one of the Elves tripped and accidentally sent the sleigh keys flying into the ocean!
#
#   Before you know it, you're inside a submarine the Elves keep ready for situations like this. It's covered in Christmas lights
#   (because of course it is), and it even has an experimental antenna that should be able to track the keys if you can boost its signal
#   strength high enough; there's a little meter that indicates the antenna's signal strength by displaying 0-50 stars.
#
#   Your instincts tell you that in order to save Christmas, you'll need to get all fifty stars by December 25th.
#
#   Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent calendar; the second puzzle is unlocked
#   when you complete the first. Each puzzle grants one star. Good luck!
#
#   As the submarine drops below the surface of the ocean, it automatically performs a sonar sweep of the nearby sea floor. On a small
#   screen, the sonar sweep report (your puzzle input) appears: each line is a measurement of the sea floor depth as the sweep looks
#   further and further away from the submarine.
#
#   For example, suppose you had the following report:
#
#           199
#           200
#           208
#           210
#           200
#           207
#           240
#           269
#           260
#           263
#
#   This report indicates that, scanning outward from the submarine, the sonar sweep found depths of 199, 200, 208, 210, and so on.
#
#   The first order of business is to figure out how quickly the depth increases, just so you know what you're dealing with - you
#   never know if the keys will get carried into deeper water by an ocean current or a fish or something.
#
#   To do this, count the number of times a depth measurement increases from the previous measurement. (There is no measurement
#   before the first measurement.) In the example above, the changes are as follows:
#
#       199 (N/A - no previous measurement)
#       200 (increased)
#       208 (increased)
#       210 (increased)
#       200 (decreased)
#       207 (increased)
#       240 (increased)
#       269 (increased)
#       260 (decreased)
#       263 (increased)
#
#   In this example, there are 7 measurements that are larger than the previous measurement.
#
#   How many measurements are larger than the previous measurement?

sample_input_file_1 = "2021_sample_1.txt"
sample_input_file_2 = "2021_sample_2.txt"
input_file          = "2021_input.txt"

def read_file_into_array(filename, asInt):
    lines = []
    with open(filename) as f:
        for line in f:
            line = line.strip()
            if asInt:
                lines.append(int(line))
            else:
                lines.append(line)

    return lines
### read_file_into_array

def count_depth_increases(depth_array):
    count = 0
    for i in range(len(depth_array) -1):
        if depth_array[i] < depth_array[i+1]:
            count += 1

    return count
### count_depth_increases

class Day01PartOneTests(unittest.TestCase):

    def test__part_1__sample_input(self):
        depth_array = read_file_into_array(sample_input_file_1, True)
        depth_increases = count_depth_increases(depth_array)
        self.assertEqual(7, depth_increases)

depth_array = read_file_into_array(input_file, True)
depth_increases = count_depth_increases(depth_array)
print("Solution to day 1 part 1: {0}".format(depth_increases))

###################################################################################################################################################################
############################################################################ PROBLEM 2 ############################################################################
#
#  --- Part Two ---
#  Considering every single measurement isn't as useful as you expected: there's just too much noise in the data.
#
#  Instead, consider sums of a three-measurement sliding window. Again considering the above example:
#
#          199  A
#          200  A B
#          208  A B C
#          210    B C D
#          200  E   C D
#          207  E F   D
#          240  E F G
#          269    F G H
#          260      G H
#          263        H
#
#  Start by comparing the first and second three-measurement windows. The measurements in the first window are marked A (199, 200, 208);
#  their sum is 199 + 200 + 208 = 607. The second window is marked B (200, 208, 210); its sum is 618. The sum of measurements in the second
#  window is larger than the sum of the first, so this first comparison increased.
#
#  Your goal now is to count the number of times the sum of measurements in this sliding window increases from the previous sum. So,
#  compare A with B, then compare B with C, then C with D, and so on. Stop when there aren't enough measurements left to create a new
#  three-measurement sum.
#
#  In the above example, the sum of each three-measurement window is as follows:
#
#          A: 607 (N/A - no previous sum)
#          B: 618 (increased)
#          C: 618 (no change)
#          D: 617 (decreased)
#          E: 647 (increased)
#          F: 716 (increased)
#          G: 769 (increased)
#          H: 792 (increased)
#
#  In this example, there are 5 sums that are larger than the previous sum.
#
#  Consider sums of a three-measurement sliding window. How many sums are larger than the previous sum?

def build_sliding_deltas(depth_array, window_size):
    windowed_depth_array = []
    for n in range(len(depth_array) - window_size +1):
        s = 0
        for i in range(window_size):
            s += depth_array[n + i]
        windowed_depth_array.append(s)

    return windowed_depth_array

class Day01PartTwoTests(unittest.TestCase):

    def test__part_2__sample_input(self):
        depth_array = read_file_into_array(sample_input_file_1, True)
        windowed_depth_array = build_sliding_deltas(depth_array, 3)
        depth_increases = count_depth_increases(windowed_depth_array)
        self.assertEqual(5, depth_increases)

#     def test__part_2__challenge_input(self):
#         print("")
#         print("Solution to day 1 part 2: {0}".format(-1))

depth_array = read_file_into_array(input_file, True)
windowed_depth_array = build_sliding_deltas(depth_array, 3)
depth_increases = count_depth_increases(windowed_depth_array)
print("Solution to day 1 part 2: {0}".format(depth_increases))

###################################################################################################################################################################
########################################################################## RUN THE TESTS ##########################################################################

# print ('Number of arguments:', len(sys.argv), 'arguments.')
# print ('Argument List:', str(sys.argv))

# run then unit tests "last"
if __name__ == '__main__':
    unittest.main()


# -*- coding: utf-8 -*-

import glob, os, sys
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.style as style
import seaborn as sns
import pandas as pd
from collections import OrderedDict
from matplotlib.colors import LogNorm

fileDirectory = "/home/karpouzi/Research/Eukaryote-mountdir/"

sns.set_context("paper")

wList = [0.0,4.0]
colorList=["b","m","y","r"]
filePaths = []

for w in wList:
    filePath = fileDirectory + "REPS_AGRE_T_4000.0_dtp_0.1_n_40.0_a0_0.2_d0_0.0_ksi_1.2_sar_0.25_a_0.0_w_" + str(w) + "_Tag_0.1_Tab_50.0_Tr_5.0_Td_50.0_d_1.0_dtsave_1.0.csv"
    filePaths.append(filePath)

fig, axs = plt.subplots(nrows=2, ncols=2, figsize=(6.5, 4.5))

#space foor w=0 before transition
vec0=np.arange(0,220,30)
vec2=np.arange(950,1150,30)
# plot for w=0
dataFrame = pd.read_csv(filePaths[0], sep=" ", header=0, usecols = ["t","maxSize","nFrag"], nrows=8000)
dataFrame = dataFrame[dataFrame['t']<1100]
dataFrame['t'] = np.around(dataFrame['t'], decimals=0)

df0=dataFrame.loc[dataFrame["t"].isin(vec0)]
df00=df0.groupby(['t']).mean(numeric_only=True)
df1=dataFrame.loc[(dataFrame["t"]>220)&(dataFrame["t"]<950)]
df11=df1.groupby(['t']).mean(numeric_only=True)
df2=dataFrame.loc[dataFrame["t"].isin(vec2)]
df22=df2.groupby(['t']).mean(numeric_only=True)

df=dataFrame.groupby(['t']).mean(numeric_only=True)
dfLegend = df
dfLegend['maxSize'] = np.around(dfLegend['maxSize'], decimals=2)
print(dfLegend["maxSize"])
dfLegend = dfLegend.loc[(dfLegend["maxSize"]==0.5)]
print(dfLegend["maxSize"])

sns.set_palette("colorblind")
sns.set_color_codes("colorblind")

sns.scatterplot(x="t",y="nFrag",size="maxSize", color='w', sizes=(dfLegend['maxSize'].min()*200, dfLegend['maxSize'].max()*200), ax=axs[0,1], data=dfLegend)

sns.scatterplot(x="t",y="nFrag",size="maxSize", color='w', sizes=(df['maxSize'].min()*200, df['maxSize'].max()*200), ax=axs[0,1], data=df, legend=False)
sns.scatterplot(x="t",y="nFrag",size="maxSize", color='b', sizes=(df00['maxSize'].min()*200, df00['maxSize'].max()*200), ax=axs[0,1], data=df00,legend=False)
sns.scatterplot(x="t",y="nFrag",size="maxSize", color='b', sizes=(df11['maxSize'].min()*200, df11['maxSize'].max()*200), ax=axs[0,1], data=df11,legend=False, edgecolor='face')
sns.scatterplot(x="t",y="nFrag",size="maxSize", color='b', sizes=(df22['maxSize'].min()*200, df22['maxSize'].max()*200), ax=axs[0,1], data=df22,legend=False)

#space foor w=4.0
vec0=np.arange(0,1150,30)
# plot for w=0
dataFrame = pd.read_csv(filePaths[1], sep=" ", header=0, usecols = ["t","maxSize","nFrag"], nrows=8000)
dataFrame = dataFrame[dataFrame['t']<1100]
dataFrame['t'] = np.around(dataFrame['t'], decimals=0)

df0=dataFrame.loc[dataFrame["t"].isin(vec0)]
df00=df0.groupby(['t']).mean(numeric_only=True)
sns.scatterplot(x="t",y="nFrag",size="maxSize", color='r', sizes=(df00['maxSize'].min()*200, df00['maxSize'].max()*200), ax=axs[1,1], data=df00,legend=False)

axs[0,1].annotate(r"$\omega=0$", xy=(970,140), size=10)
axs[1,1].annotate(r"$\omega=4$", xy=(970,140), size=10)

axs[0,1].set_title(r"$\bf{b}$"+"   Fragmentation measures dynamics")

axs[0,1].set_ylim(-10,160)
axs[1,1].set_ylim(-10,160)
axs[0,1].set_xlim(-150,1200)
axs[1,1].set_xlim(-150,1200)
axs[0,1].legend(title="Frag. Size",loc='upper left')
axs[0,1].set_xlabel("")
axs[1,1].set_xlabel("Time")
axs[1,1].xaxis.labelpad = 5
axs[0,1].set_ylabel("Number of fragments")
axs[0,1].yaxis.labelpad = 5
axs[1,1].set_ylabel("Number of fragments")
axs[1,1].yaxis.labelpad = 5

dataFrameTheo = pd.read_csv("/home/karpouzi/Research/Eukaryote-mountdir/experimentA0W-040821.csv")
wList = [0.0,1.0,2.0,4.0]

dataFrameTheo['normalMax'] = dataFrameTheo['maxSize'].div(dataFrameTheo['N']*1600)

for ix, w in enumerate(wList):
    sns.lineplot(x="N",y="maxSize", ax=axs[0,0], color = colorList[ix], linewidth=3.0 ,label = str(w), data=dataFrameTheo[dataFrameTheo['w']==w] )
    sns.lineplot(x="N",y="nFrag", ax=axs[1,0], color = colorList[ix], linewidth=3.0 ,data=dataFrameTheo[dataFrameTheo['w']==w] )

axs[1,0].axvline(0.59,linewidth=4, color='k', alpha=0.4)
axs[0,0].axvline(0.59,linewidth=4, color='k', alpha=0.4)
axs[0,0].set_title(r"$\bf{a}$   Fragmentation measures")
axs[0,0].set_xlabel("")
axs[1,0].set_xlabel("Fraction of natural land")
axs[1,0].xaxis.labelpad = 5
axs[0,0].set_ylabel("Largest fragment size")
axs[0,0].yaxis.labelpad = 5
axs[1,0].set_ylabel("Number of fragments")
axs[1,0].yaxis.labelpad = 5
axs[0,0].invert_xaxis()
axs[1,0].invert_xaxis()
axs[0,0].legend(title = r'$\omega$')
plt.tight_layout()

plt.savefig('Figure3-clustering-revision.pdf', format='pdf', dpi = 1200, bbox_inches='tight')

plt.show()

# filePathextra = "/home/karpouzi/Research/Eukaryote-mountdir/REPS_AGRE_T_100.0_dtp_0.1_n_40.0_a0_0.35_d0_0.0_ksi_1.2_sar_0.25_a_0.0_w_0.0_Tag_0.1_Tab_50.0_Tr_5.0_Td_50.0_d_1.0_dtsave_0.01.csv"
# dfextra = pd.read_csv(filePathextra, sep=" ", header=0, usecols = ["t","N","maxSize","nFrag"])
# dfextra['N'] = np.around(dfextra['N'], decimals=2)

#
# sns.lineplot(x="N",y="maxSize", ax=axs[0], color = "tab:purple", data=dfextra )
# sns.lineplot(x="N",y="nFrag", ax=axs[1], color = "tab:purple", data=dfextra )

# for ix, file in enumerate(filePaths):
#     print("begin import file " + str(ix) )
#     dataFrame = pd.read_csv(file, sep=" ", header=0, usecols = ["t","N","maxSize","nFrag"], nrows = 12000)
#     # dataFrame=dataFrame[(dataFrame['t']>1500) & (dataFrame['t']<3000)]
#     dataFrame['t'] = np.around(dataFrame['t'], decimals=0)
#     sns.lineplot(x="t",y="N", ax=axs[0], label = wList[ix], data=dataFrame)
#     sns.lineplot(x="t",y="maxSize", ax=axs[1], label = wList[ix], data=dataFrame)
#     # dataFrame['N'] = np.around(dataFrame['N'], decimals=2)
#     print("import done")
#
#     # dataFrame=dataFrame.iloc[:6000,:]
#     print(dataFrame)

    # # plot of connectance over time
    # sns.lineplot(x="t",y="maxSize", ax=axs[0,0], label = wList[ix], data=dataFrame)
    # sns.lineplot(x="t",y="nFrag", ax=axs[1,0], label = wList[ix], data=dataFrame)
    # plot of connectance versus natural land
    # sns.lineplot(x="N",y="maxSize", ax=axs[0], color = colorList[ix], data=dataFrameTheo[dataFrameTheo['w']==wList[ix]] )
    # sns.lineplot(x="N",y="maxSize", ax=axs[0], color = colorList[ix], label = wList[ix], data=dataFrame)
    # sns.lineplot(x="N",y="nFrag", ax=axs[1], color = colorList[ix], data=dataFrameTheo[dataFrameTheo['w']==wList[ix]] )
    # sns.lineplot(x="N",y="nFrag", ax=axs[1], color = colorList[ix], label = wList[ix], data=dataFrame)

# aList = [0.25,0.05,0.1,0.15]
# colorList=["b","m","y","r"]
# filePaths = []
#
# for a in aList:
#     filePath = fileDirectory + "REPS_AGRE_T_3000.0_dtp_0.1_n_40.0_a0_0.25_d0_0.0_ksi_1.2_sar_0.25_a_"+str(a)+"_w_0.0_Tag_0.1_Tab_50.0_Tr_5.0_Td_50.0_d_1.0_dtsave_1.0.csv"
#     filePaths.append(filePath)
#
# fig, axs = plt.subplots(nrows=1, ncols=1)
#
# for ix, file in enumerate(filePaths):
#     dataFrame = pd.read_csv(file, sep=" ", header=0, usecols = ["t","N"])
#     dataFrame['t'] = np.around(dataFrame['t'], decimals=0)
#     sns.lineplot(x="t",y="N", ax=axs, label = aList[ix], data=dataFrame)
#


n_recommendations = 5

watch_index = np.random.randint(0, len(movies_df["Title"]))
watch_title = movies_df.iloc[watch_index]['Title']
print("Suggested movies for user (without history) currently watching", watch_title,'\n')

# ----- #

movies_sim = movies_similarities[watch_index, :]
suggestions = np.argsort(-movies_sim)[1:n_recommendations + 1]

suggested_movies = pd.DataFrame(columns = ['Title', 'Genre', 'Similarity'])

for i in suggestions:
    suggest = {'Title':movies_df.iloc[i]['Title'],
            'Similarity':movies_sim[i],
            'Genre':movies_df.iloc[i]['Genre']}
    suggest = pd.DataFrame([suggest])
    suggested_movies = pd.concat([suggested_movies, suggest], axis=0, ignore_index=True)

suggested_movies


'''
Write a Python function to check whether the given year is leap year or not.
Write a Python function to find and display the maximum of three given numbers.
Write a Python function to check the given number is prime number or not.
Write a Python function to print first n Fibonacci numbers.
'''

print("What do you want to do?")
print("1. Find leap year")
print("2. Find highest of 3 numbers")
print("3. Check if a number is Prime or not")
print("4. Print first n Fibonacci numbers")

def leap_year(year):
    if year % 4 == 0:
        print("Year " + str(year) + " is a leap Year")
    else:
        print("Year " + str(year) + " is not a leap year")

def max_number(num1, num2, num3):
    print("The entered numbers are : " + str(num1) + ", " + str(num2) + ", " + str(num3))
    if (num1 > num2) & (num1 > num3):
        print(str(num1) + ' is the highest number')
    elif (num2 > num1) & (num2 > num3):
        print(str(num2) + ' is the Highest number')
    elif (num3 > num1) & (num3 > num2):
        print(str(num3) + ' is the Highest number')
    else:
        print('There is no clear Highest number')

def isPrime(num1):
    prime = 0
    for x in range(2, num1):
        if num1 % x == 0:
            prime = 1
            break
        else:
            continue
    if prime == 0:
        print(str(num1) + " is a prime Number")
    else:
        print(str(num1) + " is not a prime Number")

def fibonacci(num1):
    prev = 0
    curr = 1
    next = 1
    i = 0
    print(str(curr))
    while i < num1:
        next = curr + prev
        print(str(next))
        prev = curr
        curr = next
        i = i+1

option = int(input('Enter the option: '))
if option == 1:
    print('---------------------')
    year = int(input('Enter the year: '))
    leap_year(year)
elif option == 2:
    print('---------------------')
    print("Program to find highest of 3 numbers")
    num1 = int(input('Enter the first number: '))
    num2 = int(input('Enter the second number: '))
    num3 = int(input('Enter the third number: '))
    max_number(num1, num2, num3)
elif option == 3:
    print('---------------------')
    num1 = int(input('Enter the number to check prime: '))
    isPrime(num1)
elif option == 4:
    print('---------------------')
    num1 = int(input('Enter the number for Fibonacci Series: '))
    fibonacci(num1)


from django.shortcuts import redirect, render

from modules.video.forms import VideoForm
from modules.video.services import VideoService
from modules.views import VideoModuleCMSBaseView

class VideoModuleCMSAddView(VideoModuleCMSBaseView):
    template_name_form = "video/video_add_form.html"
    form_class = VideoForm
    service = VideoService()

    def get(self, request, *args, **kwargs):
        super().get(request, *args, **kwargs)
        self.clear_context(["active_page"])
        return render(request, self.get_template_to_render(), self.get_context())

    def post(self, request, *args, **kwargs):
        form = self.form_class(data=request.POST, files=request.FILES)
        if form.is_valid():
            self.service.save_video(
                filepath=form.cleaned_data["filepath"], name=form.cleaned_data["name"]
            )
        self.add_context({"errors": form.errors})
        return redirect("videos")

class VideoModuleCMSEditView(VideoModuleCMSBaseView):
    template_name_form = "video/video_edit_form.html"
    form_class = VideoForm
    service = VideoService()

    def get(self, request, *args, **kwargs):
        super().get(request, *args, **kwargs)
        video = self.get_video_obj_by_pk_from_request(request, *args, **kwargs)
        self.add_context({"video": video, "active_page": video.id})
        return render(request, self.get_template_to_render(), self.get_context())

    def post(self, request, *args, **kwargs):
        video = self.get_video_obj_by_pk_from_request(request, *args, **kwargs)
        form = self.form_class(data=request.POST, files=request.FILES, instance=video)
        if form.is_valid():
            if not self.service.validate_filepath(
                filepath_cleaned=form.cleaned_data["filepath"]
            ):
                self.add_context({"errors": {"Plik ": "Nie poprawny format filmu!"}})
                return redirect("video-edit", *args, **kwargs)

            self.service.update_video(
                instance=video,
                filepath=form.cleaned_data["filepath"],
                name=form.cleaned_data["name"],
            )
        self.add_context({"errors": form.errors})
        return redirect("video-edit", *args, **kwargs)


def reverse_number(n):
	rem = 0
	rev = 0
	while n != 0:
		rem = n%10
		rev = rev * 10 + rem
		n = int(n//10)
	return rev

def palindrome(n, rev_num):
	if n == rev_num:
		print("The number is palindrome..",rev_num)
	else:
		print("The number is not palindrome..",rev_num)

def main():
	n = eval(input("Enter number :: "))
	rev_num = reverse_number(n)
	palindrome(n, rev_num)

if __name__ == '__main__':
	main()


from graphics import *
import time

class State:

    def __init__(self):
        self.state = []  # init_state
        self.hole_X = None
        self.hole_Y = None
        self.weight = 0

    def load(self, file):
        text = file.read().split('\n')
        text = text[:len(text) - 1]

        for elm in range(len(text)):
            text[elm] = text[elm].split(' ')[:len(text)]

        print(text)
        self.state.append(text)
        self.find_X()
        self.print_state()
        return text

    def move(self, move):
        X = self.hole_X
        Y = self.hole_Y

        N = move.split(',')
        N=N[0]
        loc_N = self.find_N(N)        #Find number to move to hole

        print("Block: ",N, "in",loc_N)

        # Make the move
        tmp = self.state[len(self.state) - 1][self.hole_X][self.hole_Y]
        self.state[len(self.state) - 1][self.hole_X][self.hole_Y] = self.state[len(self.state) - 1][loc_N[0]][loc_N[1]]
        self.state[len(self.state) - 1][loc_N[0]][loc_N[1]] = tmp
        self.hole_X = loc_N[0]
        self.hole_Y = loc_N[1]

        self.weight = self.weight + int(self.state[len(self.state) - 1][X][Y][-2])

        self.print_state()

    def find_X(self):
        state = self.state[len(self.state) - 1]
        X = 0
        Y = 0
        for i in range(len(state)):
            for j in range(len(state)):
                if(self.state[len(self.state) - 1][i][j][0] == 'X'):
                    self.hole_X = i
                    self.hole_Y = j
                    continue
        print('X at: ({}, {})'.format(self.hole_X, self.hole_Y, end=""))

    def find_N(self, N):
        state = self.state[len(self.state) - 1]
        X = 0
        Y = 0
        for i in range(len(state)):
            for j in range(len(state)):
                B = self.state[len(self.state) - 1][i][j].split("(")
                if(B[0] == N):
                    X = i
                    Y = j
                    continue
        # print('X at: ({}, {})'.format(self.hole_X, self.hole_Y, end=""))
        return (X,Y)

    def print_state(self):
        print('State: ')
        for row in range(len(self.state[len(self.state) - 1])):
            print(self.state[len(self.state) - 1][row])
        print('\n')

def parse_element(element, State):

    print("Parsing Atom: " + element)
    stack = []
    op = ""
    for ch in element:
        op = op + ch
        if(ch == '('):
            if(op == "occurs("):
                # print_data(stack, op)
                stack.append(op)
                op = ""

            elif(op == "move("):
                stack.append(op)
                stack.append("loc(")
                op = ""

            elif(op == "total_weight("):
                stack.append(op)
                # print_data(stack, op)
                op = ""

        if(ch == ')'):

            # Get Move Data
            if(stack[len(stack) - 1] == "loc("):
                stack.pop()
                # print_data(stack, op)
                # remove last ')' and split into  block and location
                params = op[:len(op) - 1].split(",")
                block = params[0]
                location = (params[1],params[2])
                print("Move: " + block + " to " + location[0]+','+location[1]+ ')')
                State.move(block +','+location[0]+','+location[1]+ ')')     #loc(X,Y)
                op = ""

            # Get occurs data
            elif(stack[len(stack) - 1] == "occurs("):
                stack.pop()
                # print_data(stack, op)
                print("operation: ", op)
                step = len(State.state)
                print("Step: " + str(step))
                op = ""

            # Get Total Weight Data
            elif(stack[len(stack) - 1] == "total_weight("):
                stack.pop()
                # print_data(stack, op)
                print("Weight: " + op[0:len(op) - 1])
                op = ""

class GUI:

    def __init__(self, step):
        self.states = 0
        self.win = GraphWin("Arrange Game", 1240, 720)

    # Set State and Print
    def define_state(self, state):
        self.state = state
        self.draw_board(self.states)
        self.states = self.states + 1

    def draw_line(self, X1, Y1, X2, Y2):
        line = Line(Point(X1, Y1), Point(X2, Y2))
        line.draw(self.win)

    def draw_text(self, point, text):
        block = Text(point, text)
        if(text[0] == 'X'):
            block.setTextColor("red")
        block.draw(self.win)

    def draw_border(self, X1, Y1, X2, Y2):
        border = Rectangle(Point(X1, Y1), Point(X2, Y2))
        border.setWidth(3)
        border.draw(self.win)

    def draw_total_weight(self,weight):
        text = Text(Point(620,20), "Total Weight: " + weight)
        text.setSize(24)
        text.draw(self.win)

    def draw_board(self, steps):
        # Constants
        SIZE = len(self.state[0])
        LEVEL = 0
        edge = 10
        cell_size = 50
        board_size = (cell_size * SIZE)

        # animate
        time.sleep(.5)

        # Iterate through state steps
        for step in range(steps + 1):
            # Move down one Board Size when no more step boards fit on screen
            if(((board_size + edge) * step) > 1200 * (LEVEL + 1)):
                LEVEL = LEVEL + 1

            # Point References
            top_left_x = (board_size * step + edge) - (1200 * LEVEL)
            top_left_y = edge + ((board_size + edge) * LEVEL)
            bottom_right_x = board_size + (board_size * step) - (1200 * LEVEL)
            bottom_right_y = (edge + board_size) + \
                ((board_size + edge) * LEVEL)

            #Upper bound for weight
            top_left_y = top_left_y + 50
            bottom_right_y = bottom_right_y + 50

            for i in range(SIZE):
                # Draw Board Edges
                self.draw_border(top_left_x, top_left_y,
                                 bottom_right_x, bottom_right_y)

                # Horizontal Lines
                self.draw_line(top_left_x, top_left_y + (cell_size * i),
                               bottom_right_x, top_left_y + (cell_size * i))

                # Vertical Lines
                self.draw_line(top_left_x + (cell_size * i), edge + (board_size + edge) * LEVEL + 50, top_left_x + (
                    cell_size * i), edge + (cell_size * (SIZE)) + ((board_size + edge) * LEVEL) + 50)

        # Print Text
        for x in range(SIZE):
            for y in range(SIZE):
                self.draw_text(Point((top_left_x + 25) + cell_size * x,
                                     (top_left_y + 25) + cell_size * y), self.state[y][x])

def main():
    with open('out/solution.txt', 'r') as sol:
        with open('out/initial_state.txt', 'r') as init_state:
            state = State()
            state.load(init_state)

            # Find First Answer Set
            lines = sol.read().split('\n')

            if(lines[3] == "UNSATISFIABLE"):
                print(lines[3])
                exit(-1)

            lines = lines[3:len(lines) - 9]  # Remove Generic Clingo Print outs

            # Get Last answer set into list['Answer: #', Answer Set,
            # 'Optimization: #']
            AS = lines[len(lines) - 2:len(lines) - 1][0].split(" ")

            # Number of Steps to Solution
            steps = len(AS) - 1

            # Initialize GUI
            gui = GUI(steps)

            # Parse each element in the answer set
            for element in range(len(AS)):
                # Feed state to GUI
                gui.define_state(state.state[len(state.state) - 1])

                # Parse Actions
                parse_element(AS[element], state)

            #Draw total weight
            gui.draw_total_weight(str(state.weight))

            # Handle Closing
            try:
                gui.win.getMouse()
            except KeyboardInterrupt as err:
                sys.exit(0)

main()


my_list = [1,2,3,4]
your_list = [10,20,30]
their_list = [50,100,300]

def only_odd(item):
    return item % 2 != 0

def accumalator(acc,item):
    print(acc,item)
    return acc + item

multiply_by2 = list(map(lambda item: item*2, my_list))
print(multiply_by2)

check_odd = list(filter(lambda item: item % 2 != 0, their_list))

check_leaf_year_ = lambda year: True if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0 else False
print(check_leaf_year_(2002))


from torch_geometric.data import Data
import matplotlib.pyplot as plt
from borders import Point, convexHull
import openmesh
import numpy as np
from functions import area, f1, f2, f3, read_obj, write_obj
from problem import Problem
from evolution import Evolution

#Leer archivo .obj
vertices, faces=read_obj("/Users/isabella/Desktop/Universidad/QuintoSemestre/Optimizacion_II/Proyecto/Caras 3D/Final/Hombre.obj")

#Buscar puntos del borde
points=[]
x=[]
y=[]
z=[]

for i in range(len(vertices)):
    vertices[i][1], vertices[i][2] = vertices[i][2], vertices[i][1]
    points.append(Point(vertices[i][0], vertices[i][1]))
    x.append(vertices[i][0])
    y.append(vertices[i][1])
    z.append(vertices[i][2])

#Encontrar los puntos que están en el borde
border=convexHull(points,len(points))

xb=[]
yb=[]
for i in range(len(border)):
    xb.append(points[border[i]].x)
    yb.append(points[border[i]].y)
    #print(border[i], points[border[i]].x, points[border[i]].y)

#BORDE: 9786 9787 9725 4094 9892 9688 9909 9935 9990 9697 9953 9860 2389 9666

p1=x.index(max(x))
p2=x.index(min(x))
p3=y.index(max(y))
p4=y.index(min(y))

#Area malla original
initial_area=0
for i in range(len(faces)):
    t=[vertices[faces[i][0]], vertices[faces[i][1]], vertices[faces[i][2]]]
    initial_area+=area(t)

print(initial_area)

#Agregar puntos fijos al final
fp=[9786, 9787, 9725, 4094, 9892, 9688, 9909, 9935, 9990, 9697, 9953, 9860, 2389, 9666]
fixed_vertices=vertices[fp]
new_vertices=np.delete(vertices, fp, 0)
vertices=np.concatenate((new_vertices, fixed_vertices))

#NSGA-II función 2: error en el área superficial
problem1 = Problem(num_of_variables=2, objectives=[f1, f2], variables_range=vertices, initial_area=initial_area)
evo1 = Evolution(problem1, num_of_generations=100, num_of_individuals=50, crossover_param=0.5, mutation_prob=0.01, mutation_param=0.05)
evol1 = evo1.evolve()

for i in range(len(evol1)-1):
    func=[j.objectives for j in evol1[i]]

    function1=[k[0] for k in func]
    function2=[k[1] for k in func]

    plt.scatter(function1, function2, label="Frente "+str(i+1))

plt.xlabel('Cantidad de triángulos', fontsize=15)
plt.ylabel('Error del área superficial', fontsize=15)
plt.legend()
plt.title('Frontera de Pareto', fontsize=20)

plt.show()

print('vert', len(evol1[0][0].features[0]), 'triang', len(evol1[0][0].features[1].simplices))
print('f1', evol1[0][0].objectives[0], 'f2', evol1[0][0].objectives[1])

write_obj(evol1[0][0].features[0], evol1[0][0].features[1].simplices, '/Users/mariajosebernal/Documents/EAFIT/2022-2/Optimización/Proyecto/Caras 3D/Final/HombreNuevo1.obj')

#NSGA-II función 3: error en los valores de las alturas
problem2 = Problem(num_of_variables=2, objectives=[f1, f3], variables_range=vertices, initial_area=initial_area)
evo2 = Evolution(problem2, num_of_generations=100, num_of_individuals=50, crossover_param=0.5, mutation_prob=0.01, mutation_param=0.05)
evol2 = evo2.evolve()

for i in range(len(evol2)-1):
    func=[j.objectives for j in evol2[i]]

    function1=[k[0] for k in func]
    function2=[k[1] for k in func]

    plt.scatter(function1, function2, label="Frente "+str(i+1))

plt.xlabel('Cantidad de triángulos', fontsize=15)
plt.ylabel('Error', fontsize=15)
plt.legend()
plt.title('Frontera de Pareto', fontsize=20)

plt.show()

print('vert', len(evol2[0][0].features[0]), 'triang', len(evol2[0][0].features[1].simplices))
print('f1', evol2[0][0].objectives[0], 'f2', evol2[0][0].objectives[1])

write_obj(evol2[0][0].features[0], evol2[0][0].features[1].simplices, '/Users/mariajosebernal/Documents/EAFIT/2022-2/Optimización/Proyecto/Caras 3D/Final/HombreNuevo2.obj')

Simplificación de mallas 3D con algoritmos genéticos/Código/main.py


import streamlit as st
import pandas as pd
import numpy as np

st.title("Adherence")

chart_data=pd.DataFrame(
    np.random.randn(3,3),
    columns=["Taken On Time","Taken Late","Missed"]
)
st.bar_chart(chart_data, use_container_width=True)

# df = pd.DataFrame({"Category": ["A", "B", "C"], "Values": [10, 20, 30]})
#
# st.bar_chart(df, x="Category", y="Values", height=300, width=600, title="Bar Chart", x_label="Category", y_label="Values")

st.text("Total Reminder: 145, Late: 47, Missed: 72")

st.write("Current Medication", align='right')

# st.bullet("VITAMIN A AND VITAMIN D; 929.3mg/g OINTMENT",align='right')
# st.bullet("IBUPROFEN; 100mg/5ml SUSPENSION",align='right')
# st.bullet("TYLENOL COLD; 325mg.15ml LIQUID",align='right')
# st.bullet("PREDNISONE; 20mg/1 TABLET",align='right')

# st.sidebar.markdown("
- VITAMIN A AND VITAMIN D; 929.3mg/g OINTMENT\n- IBUPROFEN; 100mg/5ml SUSPENSION\n- TYLENOL COLD; 325mg.15ml LIQUID\n - PREDNISONE; 20mg/1 TABLET
", unsafe_allow_html=True)

st.markdown("- VITAMIN A AND VITAMIN D; 929.3mg/g OINTMENT\n- IBUPROFEN; 100mg/5ml SUSPENSION\n- TYLENOL COLD; 325mg.15ml LIQUID\n- PREDNISONE; 20mg/1 TABLET", unsafe_allow_html=True)


import asyncio
import http.server
import json
import os
import socketserver
import threading
import time

import pyautogui
import websockets

PORT = 8000
WS_PORT = 8001

LIVE2D_FULL_PATH = ''
SERVER_ROOT = ''
LIVE2D_MODEL = ''

file_server = None

stop_event = threading.Event()

initialized = False
should_reload_page = False

def update_path(path, level):
    global SERVER_ROOT, LIVE2D_MODEL

    root = path

    while level > 0:
        root = os.path.dirname(root)
        level -= 1

    SERVER_ROOT = root
    LIVE2D_MODEL = path[len(root):]

    if LIVE2D_MODEL.startswith('/'):
        LIVE2D_MODEL = LIVE2D_MODEL[1:]

    # print('update_path ', SERVER_ROOT, '|', LIVE2D_MODEL)

try:
    import obspython as obs
except ModuleNotFoundError:
    with open(os.path.dirname(__file__) + '/private.json', 'r') as p_file:
        p_json = json.load(p_file)
        update_path(p_json['live2dModel'], p_json['rootLevel'])

def script_description():
    return 'Displays a cursor-focusing Live2D model'

def script_load(settings):
    pass

def prop_modified(props, prop, settings):
    # print('prop_modified ', obs.obs_property_name(prop))

    status = 'Invalid Path' if not SERVER_ROOT else 'Invalid Port' if PORT == WS_PORT else 'OK'

    obs.obs_data_set_string(settings, 'info', '''Server Root:
%s

Page URL:
http://127.0.0.1:%d

Status:
%s
''' % (SERVER_ROOT or '<empty>', PORT, status))

    level_p = obs.obs_properties_get(props, 'root_level')

    obs.obs_property_int_set_limits(level_p, 1, total_levels(LIVE2D_FULL_PATH), 1)

    return True

def total_levels(path):
    level = 1

    while 1:
        if os.path.dirname(path) == path:
            return level

        path = os.path.dirname(path)
        level += 1

def script_properties():
    # print('script_properties')

    props = obs.obs_properties_create()

    model_p = obs.obs_properties_add_path(props, 'live2d_model', 'Live2D Model',
                                          obs.OBS_PATH_FILE, 'Live2D Model(*.json)', '')

    level_p = obs.obs_properties_add_int(props, 'root_level', 'Server Root Level', 1, total_levels(LIVE2D_FULL_PATH), 1)

    port_p = obs.obs_properties_add_int(props, 'port', 'Server Port', 1024, 65535, 1)
    ws_port_p = obs.obs_properties_add_int(props, 'ws_port', 'Websocket Port', 1024, 65535, 1)

    info_p = obs.obs_properties_add_text(props, 'info', 'Info', obs.OBS_TEXT_MULTILINE)
    obs.obs_property_set_enabled(info_p, False)

    obs.obs_properties_add_button(props, 'start', 'Apply Settings', apply_settings)

    obs.obs_property_set_modified_callback(model_p, prop_modified)
    obs.obs_property_set_modified_callback(level_p, prop_modified)
    obs.obs_property_set_modified_callback(port_p, prop_modified)
    obs.obs_property_set_modified_callback(ws_port_p, prop_modified)

    return props

def script_defaults(settings):
    obs.obs_data_set_default_int(settings, 'root_level', 1)
    obs.obs_data_set_default_int(settings, 'port', PORT)
    obs.obs_data_set_default_int(settings, 'ws_port', WS_PORT)

def script_update(settings):
    global initialized, PORT, WS_PORT, LIVE2D_FULL_PATH

    # print('script_update')

    PORT = obs.obs_data_get_int(settings, "port")
    WS_PORT = obs.obs_data_get_int(settings, "ws_port")
    LIVE2D_FULL_PATH = obs.obs_data_get_string(settings, "live2d_model")
    level = obs.obs_data_get_int(settings, "root_level")

    update_path(LIVE2D_FULL_PATH, level)

    if not initialized:
        initialized = True
        start_server()

def script_unload():
    shutdown_server()

# Static file server

class RequestHandler(http.server.SimpleHTTPRequestHandler):

    def log_request(self, code='-', size='-'):
        pass

    def log_error(self, _format, *args):
        self.log_message('%s ' + _format, self.path, *args)

    def do_GET(self):
        if self.path == '/setup':
            res_json = json.dumps({
                'model': LIVE2D_MODEL,
                'wsPort': WS_PORT
            }).encode('utf-8')

            self.send_response(http.HTTPStatus.OK)
            self.send_header("Content-type", "application/json; charset=utf-8")
            self.send_header("Content-Length", str(len(res_json)))
            self.end_headers()

            self.wfile.write(res_json)
        else:
            super().do_GET()

    def translate_path(self, path):
        if path == '/index.html':
            return os.path.normpath(os.path.dirname(__file__) + '/index.html')

        result = super().translate_path(path)

        rel_path = os.path.relpath(result, os.getcwd())

        return os.path.join(SERVER_ROOT, rel_path)

def run_file_server():
    global file_server

    with socketserver.TCPServer(("", PORT), RequestHandler) as httpd:
        file_server = httpd
        httpd.serve_forever()

# Socket server

def run_ws_server():
    async def ws_handler(websocket, path):
        global should_reload_page

        try:
            if should_reload_page:
                should_reload_page = False
                await websocket.send('reload')

            while 1:
                await asyncio.sleep(0.02)
                await websocket.send(','.join(map(str, pyautogui.position())))
        except websockets.exceptions.ConnectionClosedOK:
            pass

    asyncio.set_event_loop(asyncio.new_event_loop())

    async def run_server(_stop):
        async with websockets.serve(ws_handler, 'localhost', WS_PORT):
            await _stop

    stop = asyncio.get_event_loop().run_in_executor(None, stop_event.wait)

    asyncio.get_event_loop().run_until_complete(run_server(stop))
    asyncio.get_event_loop().run_forever()

def apply_settings(*args):
    global should_reload_page

    should_reload_page = True
    start_server()

def start_server():
    if PORT == WS_PORT:
        print('Tow ports must not be the same (%s)' % PORT)
        return

    shutdown_server()

    time.sleep(0.5)

    server_thread = threading.Thread(target=run_file_server)
    server_thread.setDaemon(True)
    server_thread.start()

    ws_server_thread = threading.Thread(target=run_ws_server)
    ws_server_thread.setDaemon(True)
    ws_server_thread.start()

    print("Serving at port %d and %d" % (PORT, WS_PORT))

def shutdown_server():
    if file_server:
        file_server.shutdown()

    stop_event.set()
    stop_event.clear()

    print('Shutdown')

try:
    obs
except NameError:
    start_server()

    while 1:
        pass


import sys
from collections import deque

input = sys.stdin.readline

# m = 상자의 가로칸
# n = 상자의 세로칸
# h = 상자의 수
m,n,h = map(int, input().split())

dx = [1, -1, 0, 0, 0, 0]
dy = [0, 0, 1, -1, 0, 0]
dz = [0, 0, 0, 0, 1, -1]

box = [[] for _ in range (h)]

# visited = [[[False]*m for _ in range (n)] for _ in range (h)]

def bfs():
    count = -1
    q = deque([])
    full_grown = True

    for i in range (h):
        for j in range (n):
            for k in range (m):
                if box[i][j][k] == 1:
                    q.append((i, j, k))
                # elif box[i][j][k] == 0:
                #     # 토마토가 다 익으면
                #     num_tomato += 1

    while q:
        for _ in range (len(q)):
            ez, ey, ex = q.popleft()

            for i in range (6):
                # set new coordinate
                nx = ex + dz[i]
                ny = ey + dy[i]
                nz = ez + dx[i]

                if 0<=nx<m and 0<=ny<n and 0<=nz<h:
                    if box[nz][ny][nx] == 0: # and visited[nz][ny][nx] == False:
                        box[nz][ny][nx] = 1
                        #visited[nz][ny][nx] = True
                        q.append((nz, ny, nx))

        count+=1

    #depth
    for i in range (h):
        # 세로
        for j in range (n):
            # 가로
            for k in range (m):
                if box[i][j][k] == 0:
                    count = -1

    return count

for i in range (h):
    for j in range (n):
        box[i].append(list(map(int, input().split())))

print(bfs())


from imageai.Prediction.Custom import ModelTraining

model_trainer = ModelTraining()
model_trainer.setModelTypeAsResNet()

# 数据集
model_trainer.setDataDirectory("/Users/zhusheng/WorkSpace/Tmp/dataset/idenprof")

# 开始训练模型
"""
num_objects:
num_experiments:迭代次数
batch_size：批处理大小
show_network_summary：在控制台输出神经网络概要
"""
model_trainer.trainModel(num_objects=10,
                         num_experiments=100
                         ,enhance_data=True,
                         batch_size=32,
                         show_network_summary=True)


'''
Create a mask image from the spatial coordinates.
'''
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")

## _initialize_mask
def CreateMaskImage(adata, scale_factor=1):
    adata_copy = adata.copy()
    A = 'spatial' in adata_copy.uns.keys()
    B = 'array_col' in adata_copy.obs.keys()
    C = 'array_row' in adata_copy.obs.keys()
    if A and B and C:
        coordinates = adata_copy.obs[['array_row', 'array_col']]
    else:
        coordinates = pd.DataFrame(adata_copy.obsm['spatial'], index=adata_copy.obs.index,
                                   columns=['array_col', 'array_row'])

    if (coordinates.max()>1000).any():
        coordinates = (coordinates/scale_factor).astype(int)

    evencol = coordinates[coordinates['array_col'] % 2 == 0]['array_row']
    oodcol = coordinates[coordinates['array_col'] % 2 != 0]['array_row']
    aligned = len(set(evencol).intersection(oodcol)) != 0
    coordinates = coordinates - coordinates.min()

    if aligned:
        nrow = int(coordinates['array_row'].max()) + 1
        ncol = int(coordinates['array_col'].max()) + 1
        Mask = np.zeros((nrow, ncol))
        spotID = []
        for i in range(coordinates.shape[0]):
            Mask[coordinates['array_row'][i], coordinates['array_col'][i]] = 1
            spotID.append(coordinates['array_row'][i]*ncol+coordinates['array_col'][i])
    else:
        nrow = coordinates['array_row'].max() + 1
        ncol = int((coordinates['array_col'].max() + 1)/2) + 1
        Mask = np.zeros((nrow, ncol))
        spotID = []
        for i in range(coordinates.shape[0]):
            Mask[coordinates['array_row'][i], coordinates['array_col'][i] // 2] = 1
            spotID.append(coordinates['array_row'][i]*ncol+(coordinates['array_col'][i] // 2))

    adata_copy.uns['Mask'] = Mask
    coordinates['spotID'] = spotID
    coordinates = coordinates.loc[adata_copy.obs.index,:]
    adata_copy.obs[['array_col', 'array_row', 'spotID']] = coordinates
    plt.imshow(adata_copy.uns['Mask'], cmap="binary")
    plt.xticks([])
    plt.yticks([])
    plt.title('Mask Image',fontsize=20)
    plt.show()
    return adata_copy