import json
from datetime import datetime as dt, datetime

import requests
from flask import jsonify
import jwt

from db_manager.config.agent_url import AGENT_ENDPOINT, AGENT_ATTRACTION_GET, AGENT_TAGS_GET
from db_manager.config.secrets import SERVER_SECRET_KEY, PROFILE_REMOVE_SP, PROFILE_RATE_SET_SP, \
                                      TRIP_UPDATE_RSRV_SP, UPSERT_TRIP_FLIGHT_SP, DEFAULT_STARS, DELETE_TRIP_SP
from db_manager.config.exteranl_apis import FLIGHTS_BASE_ENDPOINT, HOTELS_BASE_ENDPOINT, HOTELS_HEADER
from db_manager.location_code_matcher import LocationMatcher
from api.models.attraction import Attraction
from api.models.city import City
from api.models.tag import Tag
from api.models.tag_attraction import TagAttraction
from api.models.trip import Trip, TripAttraction
from api.models.user import User
from api.models.user_trip_profile import UserProfile, ProfileTag
from api.models.hotel import Hotel, TripHotel
from api.models.flight import TripFlight
from db_manager.pytheas_db_manager_base import PytheasDBManagerBase
from trip_builder.city_trip_builder import CityWalkTripBuilder
from trip_builder.routes_builder.basic_route_builder import BasicRoutesBuilder
from trip_builder.routes_builder.dfs_routes_builder import DFSRoutesBuilder

class SQLPytheasManager(PytheasDBManagerBase):
    # TODO: Refactor exceptions handling

    def __init__(self, db):
        super().__init__(db)

    def initialize(self):
        self.db.create_all()
        self.db.session.commit()
        return "success", 200

    @staticmethod
    def serialize_result(elements):
        serialized_result = []
        if type(elements) is not list:
            elements = [elements]
        for element in elements:
            element = vars(element)
            fields = {}
            for field in [x for x in list(element.keys()) if not x.startswith('_') and x != 'metadata']:
                data = element[field]
                try:
                    fields[field] = data
                except TypeError:
                    fields[field] = None
            serialized_result.append(fields)
        return jsonify(serialized_result)

    #  CREATES FUNCTIONS
    def _create(self, model, **kwargs):
        try:
            new_model = model(**kwargs)
            self.db.session.add(new_model)
            self.db.session.commit()
            return new_model, 200
        except Exception as e:
            return f"Error creating {model}: {e}", 500

    def create_user(self, username, full_name, email, google_token):
        email_exist = User.query.filter_by(email=email).first()
        username_exist = User.query.filter_by(username=username).first()
        if not email_exist and not username_exist:
            new_user, status = self._create(
                User,
                id=None,
                username=username,
                full_name=full_name,
                created=dt.now(),
                email=email,
                google_token=google_token
            )
            if status is not 200:
                return new_user, status
        return jsonify({"token": jwt.encode({'username': username}, SERVER_SECRET_KEY, algorithm='HS256').decode('utf8')}), 200

    def create_tag(self, tag_name):
        return self._create(
            Tag,
            name=tag_name
        )

    def create_attraction(self, name, rate, address, price, description, phone, website, city_id, attraction_id=None):
        return self._create(
            Attraction,
            id=attraction_id,
            name=name,
            rate=rate,
            address=address,
            price=price,
            description=description,
            phone_number=phone,
            website=website,
            city_id=city_id
        )

    def create_city(self, name, country, city_id=None):
        return self._create(
            City,
            name=name,
            country=country,
            id=city_id
        )

    def create_profile(self, username, profile_name, tags, image):
        try:
            # get tags id from name
            user = User.query.filter_by(username=username).first()
            # create new profile
            new_profile = UserProfile(
                user_id=user.id,
                name=profile_name,
                image=image
            )
            self.db.session.add(new_profile)
            self.db.session.commit()

            # create tags
            for tag in tags:
                db_tag = Tag.query.filter_by(name=tag).first()
                if db_tag:
                    new_profile_tag = ProfileTag(
                        tag_id=db_tag.id,
                        profile_id=new_profile.id
                    )
                    self.db.session.add(new_profile_tag)
                    self.db.session.commit()
        except Exception as e:
            print(e)
            self.db.session.rollback()
            return "Error creating new profile", 500
        else:
            return "success", 200

    def upsert_trip(self, username, profile_id, flight_rsrv, hotel_rsrv_code, trip_data):
        trip_id = int(trip_data['id'])
        trip = None
        if trip_id is not None and trip_id > 0:
            trip = Trip.query.filter_by(id=trip_id).first()

        if trip is None:
            return self.create_trip(username, profile_id, flight_rsrv, hotel_rsrv_code, trip_data)
        else:
            return self.update_trip(username, trip_id, flight_rsrv, hotel_rsrv_code)

    def create_trip(self, username, profile_id, flight_rsrv, hotel_rsrv_code, trip_data):
        try:
            user_id = User.query.filter_by(username=username).first().id
            profile_id = UserProfile.query.filter_by(user_id=user_id, id=profile_id).first().id
            if profile_id is None:
                raise Exception("No profile found")

            city_id = City.query.filter_by(name=trip_data['destination']).first().id
            if flight_rsrv is None or flight_rsrv == {} or hotel_rsrv_code is None:
                is_booked = False
            else:
                is_booked = True

            new_trip = Trip(
                user_id=user_id,
                profile_id=profile_id,
                currency=trip_data['currency'],
                price=int(trip_data['price']),
                days=int(trip_data['days']),
                start_date=datetime.strptime(trip_data['start_date'], '%d/%m/%Y'),
                end_date=datetime.strptime(trip_data['end_date'], '%d/%m/%Y'),
                is_booked=is_booked,
                people_number=int(trip_data['people_number']),
                city_id=city_id,
                hotel_rsrv_code=hotel_rsrv_code
            )
            self.db.session.add(new_trip)
            self.db.session.commit()

            if flight_rsrv is not None and flight_rsrv != {}:
                self._upsert_trip_flight(new_trip.id, flight_rsrv)

            attractions = self._add_trip_attractions(trip_data, new_trip)
            self._create_hotel(new_trip.id, trip_data['hotel'])
            return_trip = self._get_trip(new_trip.id)
            return return_trip, 200
        except Exception as e:
            print(e)
            self.db.session.rollback()
            return "Error creating new profile", 500

    def _add_trip_attractions(self, trip_full_data, trip):
        try:
            for day in range(0, len(trip_full_data['places'])):
                for i in range(1, len(trip_full_data['places'][day])):
                    attraction = trip_full_data['places'][day][i]
                    if attraction is None or attraction=={}:
                        continue
                    new_trip_attraction = TripAttraction(
                        trip_id=trip.id,
                        attraction_id=attraction['id'],
                        day=day + 1
                    )
                    self.db.session.add(new_trip_attraction)
                    self.db.session.commit()
        except Exception as e:
            print(e)
            self.db.session.rollback()
            raise e

    def _create_hotel(self, trip_id, hotel_data):
        hotel_id = 0
        hotel_name = hotel_data['name']
        hotel_url = hotel_data['url']
        hotel = Hotel.query.filter_by(name=hotel_name, url=hotel_url).first()
        if hotel is None:
            stars = hotel_data['stars'] if hotel_data['stars'] != DEFAULT_STARS else None
            new_hotel = Hotel(
                name=hotel_name,
                address=hotel_data['address'],
                main_photo_url=hotel_data['main_photo_url'],
                stars=stars,
                url=hotel_url,
                description=hotel_data['description'],
                facilities=""
            )
            self.db.session.add(new_hotel)
            self.db.session.commit()
            hotel_id = new_hotel.id
        else:
            hotel_id = hotel.id

        #Insert trip-hotel
        new_trip_hotel = TripHotel(
            trip_id=trip_id,
            hotel_id=hotel_id,
            start_date=hotel_data['start_date'],
            end_date=hotel_data['end_date'],
            price_per_night=int(hotel_data['price_per_night']),
            room_type=hotel_data['room_type'],
            currency=hotel_data['currency'],
        )
        self.db.session.add(new_trip_hotel)
        self.db.session.commit()

    def update_trip(self, username, trip_id, flight_rsrv_info, hotel_rsrv_code):
        try:
            user_id = User.query.filter_by(username=username).first().id

            trip = Trip.query.filter_by(id=trip_id, user_id=user_id).first()
            if trip is None:
                raise Exception("No trip found")

            trip_flight = TripFlight.query.filter_by(trip_id=trip_id).first()
            if not trip.hotel_rsrv_code:
                trip.hotel_rsrv_code = hotel_rsrv_code if hotel_rsrv_code else trip.hotel_rsrv
            if flight_rsrv_info:
                trip_flight = flight_rsrv_info

            is_booked = False if not trip_flight or not trip.hotel_rsrv_code else True

            self._upsert_trip_flight(trip_id, flight_rsrv_info)
            hotel_rsrv_code = f"'{trip.hotel_rsrv_code}'" if not trip.hotel_rsrv_code.startswith("'") else trip.hotel_rsrv_code
            params = [trip_id, hotel_rsrv_code, is_booked]
            self._exec_procedure(TRIP_UPDATE_RSRV_SP, params)
            self.db.session.commit()

            return_trip = self._get_trip(trip_id)
            return return_trip, 200
        except Exception as e:
            print(e)
            self.db.session.rollback()
            return "Error updating trip", 500

    def _upsert_trip_flight(self, trip_id, flight):
        if flight is not None and flight != {}:
            arrival_time = self._get_string_param(flight['arrival_time'])
            departure_time = self._get_string_param(flight['departure_time'])
            from_city = City.query.filter_by(name=flight['from_city']).first().id
            to_city = City.query.filter_by(name=flight['to_city']).first().id
            duration = self._get_string_param(flight['duration'])
            price = int(flight['price'])
            reservation_number = self._get_string_param(flight['reservation_number'])

            params = [trip_id, arrival_time, departure_time, from_city, to_city, duration, price, reservation_number]
            self._exec_procedure(UPSERT_TRIP_FLIGHT_SP, params)
            self.db.session.commit()

    def set_profile_attraction_rate(self, username, profile_id, attraction_id, rate):
        try:
            user_id = User.query.filter_by(username=username).first().id
            profile_id = UserProfile.query.filter_by(user_id=user_id, id=profile_id).first().id

            rate = int(rate)
            if rate < 1 or rate > 5:
                raise Exception("Rate is out of range")

            self._exec_procedure(PROFILE_RATE_SET_SP, [str(profile_id), str(attraction_id), str(rate)])
        except Exception as e:
            print(e)
            self.db.session.rollback()
            return "Error adding profile rate", 500
        return "success", 200

    #  DELETE FUNCTIONS

    def delete_trip(self, username, trip_id):
        try:
            user_id = User.query.filter_by(username=username).first().id
            if user_id is None:
                raise Exception("No user found")

            params = [trip_id]
            self._exec_procedure(DELETE_TRIP_SP, params)
            self.db.session.commit()
        except Exception as e:
            print(e)
            self.db.session.rollback()
            return "Error deleting trip", 500
        return "success", 200

    #  GET FUNCTIONS

    def get_profile(self, username):
        try:
            user_id = User.query.filter_by(username=username).first().id
            profiles = UserProfile.query.filter_by(user_id=user_id).\
                        with_entities(UserProfile.id, UserProfile.name, UserProfile.image).all()
            return jsonify({
                        'profiles': [{'id': profile.id, 'name': profile.name, 'image': profile.image} for profile in profiles]
                   }), 200
        except Exception as e:
            return f"Error getting user's profiles: {str(e)}", 500

    def get_cities(self):
        try:
            return self.serialize_result(City.query.all()), 200
        except Exception as e:
            return f'Error getting cities: {str(e)}', 500

    def get_tags(self):
        try:
            return self.serialize_result(Tag.query.all())
        except Exception as e:
            return str(e), 500

    def get_attractions(self, **kwargs):
        if kwargs:
            if 'name' in kwargs:
                try:
                    attraction = Attraction.query.filter_by(name=kwargs['name']).first()
                    return attraction
                except:
                    return None
        try:
            return self.serialize_result(Attraction.query.all()), 200
        except Exception as e:
            return f"Error getting attractions: {str(e)}", 500

    def add_to_attr_tags(self, att_id, tag_id):
        try:
            tag_att = TagAttraction(tag_id=tag_id, attraction_id=att_id)
            self.db.session.add(tag_att)
            self.db.session.commit()
            return tag_att, 200
        except Exception as e:
            self.db.session.rollback()
            return f"Error adding tag to attractions: {str(e)}", 500

    def get_trip_attraction(self, trip_id, hotel, city_name):
        attractions_trip = TripAttraction.query.filter_by(trip_id=trip_id)
        parsed_attractions = []
        day = -1
        parsed_hotel = {
            'id': -1,
            'name': hotel['name'],
            'rate': 5,
            'address': hotel['address'],
            'price': int(hotel['price_per_night']),
            'description': '',
            'phone number': '',
            'website': hotel['url'],
            'city': city_name,
            'photo_url': hotel['main_photo_url'],
            'suggested_duration': ''
        }
        for attraction_trip in attractions_trip:
            attraction = Attraction.query.get(attraction_trip.attraction_id)
            parsed_attraction = {
                'id': attraction.id,
                'name': attraction.name,
                'rate': attraction.rate,
                'address': attraction.address,
                'price': int(attraction.price),
                'description': attraction.description,
                'phone number': attraction.phone_number,
                'website': attraction.website,
                'city': City.query.get(attraction.city_id).name,
                'photo_url': attraction.photo_url,
                'suggested_duration': attraction.suggested_duration
            }
            if (attraction_trip.day - 1) is not day:
                parsed_attractions.append([parsed_hotel])
                day += 1
            parsed_attractions[day].append(parsed_attraction)
        return parsed_attractions

    def get_trip_hotel(self, trip_id):
        trip_hotel = TripHotel.query.filter_by(trip_id=trip_id).first()
        if trip_hotel is None:
            return None
        hotel_data = Hotel.query.filter_by(id=trip_hotel.hotel_id).first()
        if hotel_data is None:
            return None
        stars = str(hotel_data.stars) if hotel_data.stars is not None else DEFAULT_STARS
        hotel = {
            "address": hotel_data.address,
            "currency": trip_hotel.currency,
            "end_date": trip_hotel.end_date,
            "facilities": [],
            "main_photo_url": hotel_data.main_photo_url,
            "name": hotel_data.name,
            "price_per_night": trip_hotel.price_per_night,
            "room_type": trip_hotel.room_type,
            "start_date": trip_hotel.start_date,
            "url": hotel_data.url,
            "description": hotel_data.description,
            "stars": stars
        }
        return hotel

    def _get_trip_flight(self, trip_id):
        trip_flight = TripFlight.query.filter_by(trip_id=trip_id).first()
        if trip_flight is None:
            return {}

        from_city_name = City.query.get(trip_flight.from_city).name
        to_city_name = City.query.get(trip_flight.to_city).name

        flight = {
            "arrival_time": trip_flight.arrival_time,
            "departure_time": trip_flight.departure_time,
            "from_city": from_city_name,
            "from_city_code": LocationMatcher.get_iata_for_city(from_city_name),
            "to_city": to_city_name,
            "to_city_code":  LocationMatcher.get_iata_for_city(to_city_name),
            "duration": trip_flight.duration,
            "price": trip_flight.price,
            "reservation_number": trip_flight.reservation_number
        }
        return flight

    def _get_trip(self, trip_id):
        try:
            trip = Trip.query.filter_by(id=trip_id).first()
            city_name = City.query.get(trip.city_id).name
            new_flights = []

            hotel = self.get_trip_hotel(trip.id)
            flight = self._get_trip_flight(trip.id)
            if flight is None or flight == {}:
                date_start = trip.start_date.strftime("%d/%m/%Y")
                date_end = trip.end_date.strftime("%d/%m/%Y")
                new_flights = self._get_flights('tel aviv', city_name, date_start, date_end, trip.people_number)

            attractions = self.get_trip_attraction(trip.id, hotel, city_name)
            if flight is not None and flight != {} and hotel is not None:
                trip.price = int(int(flight['price']) + (int(hotel['price_per_night'])*(trip.days-1)))

            parsed_trip = {
                'id': trip.id,
                'profile': trip.profile_id,
                'destination': city_name,
                'start_date': trip.start_date,
                'end_date': trip.end_date,
                'days': trip.days,
                'price': trip.price,
                'currency': trip.currency,
                'people_number': int(trip.people_number),
                'pictures': [],
                'flights': new_flights,
                'hotel': hotel,
                'explore': False,
                'places': attractions,
                'flight_rsrv': flight,
                'hotel_rsrv_code': trip.hotel_rsrv_code,
                'is_booked': trip.is_booked
            }
        except Exception as e:
            print(e)
            return str(e)
        else:
            return jsonify(parsed_trip)

    def get_trips(self, username):
        try:
            print(datetime.now())
            user_id = User.query.filter_by(username=username).first().id
            trips = Trip.query.filter_by(user_id=user_id)
            print(datetime.now())
            all_trips = []
            new_flights = []
            for trip in trips:
                city_name = City.query.get(trip.city_id).name
                hotel = self.get_trip_hotel(trip.id)
                if hotel is None:
                    continue
                flight = self._get_trip_flight(trip.id)
                if flight is None or flight == {}:
                    date_start = trip.start_date.strftime("%d/%m/%Y")
                    date_end = trip.end_date.strftime("%d/%m/%Y")
                    new_flights = self._get_flights('tel aviv', city_name, date_start, date_end, trip.people_number)
                attractions = self.get_trip_attraction(trip.id, hotel, city_name)

                if flight is not None and flight != {} and hotel is not None:
                    trip.price = int(flight['price']) + (int(hotel['price_per_night']) * (trip.days - 1))

                parsed_trip = {
                    'id': trip.id,
                    'profile': trip.profile_id,
                    'destination': city_name,
                    'start_date': trip.start_date,
                    'end_date': trip.end_date,
                    'days': trip.days,
                    'price': trip.price,
                    'currency': trip.currency,
                    'people_number': int(trip.people_number),
                    'pictures': [],
                    'flights': new_flights,
                    'hotel': hotel,
                    'explore': False,
                    'places': attractions,
                    'flight_rsrv': flight,
                    'hotel_rsrv_code': trip.hotel_rsrv_code,
                    'is_booked': trip.is_booked
                }
                all_trips.append(parsed_trip)
        except Exception as e:
            print(e)
            return str(e), 500
        else:
            return jsonify(all_trips), 200

    def get_explore_trips(self, username, profile, from_date, to_date, city=None, travelers='2', budget=None):
        try:
            user_id = User.query.filter_by(username=username).first().id
            profile_id = UserProfile.query.filter_by(user_id=user_id, id=profile).first().id

            city_id = None
            if city:
                city_id = City.query.filter_by(name=city).first().id
            budget = None if budget == "" else budget
            if budget:
                budget = int(budget)
            fromdate = datetime.strptime(from_date, '%d/%m/%Y')
            todate = datetime.strptime(to_date, '%d/%m/%Y')
            days = (todate - fromdate).days
            estimated_requiired_attractions = days * 6
            agent_response = requests.get(url=(AGENT_ENDPOINT+AGENT_ATTRACTION_GET),
                                          params={'profile_id': profile_id, 'city_id': city_id, 'days': days})

            if agent_response.status_code is not 200:
                return agent_response.content, agent_response.status_code
            agent_results = json.loads(agent_response.content)

            trips = []
            for result in agent_results:
                attractions = []
                city = City.query.filter_by(id=result['city_id']).first().name

                flight_price = 0
                flights = self._get_flights('tel aviv', city, from_date, to_date, travelers)
                if flights is not None and len(flights) > 0 and flights[1] is not 502:
                    flight_price = int(flights[0]["price"])
                else:
                    continue

                hotels = self._get_hotels(city, from_date, to_date, travelers)
                if hotels is None or len(hotels) == 0:
                    continue

                if '5' in result['attractions']:
                    attractions = result['attractions']['5']
                if '4'in result['attractions'] and len(attractions) <= estimated_requiired_attractions:
                    attractions.extend(result['attractions']['4'])
                if '3'in result['attractions'] and len(attractions) <= estimated_requiired_attractions:
                    attractions.extend(result['attractions']['3'])
                if '2'in result['attractions'] and len(attractions) <= estimated_requiired_attractions:
                    attractions.extend(result['attractions']['2'])
                if '1'in result['attractions'] and len(attractions) <= estimated_requiired_attractions:
                    attractions.extend(result['attractions']['1'])
                if len(attractions) < estimated_requiired_attractions:
                    continue

                trip_builder = CityWalkTripBuilder(DFSRoutesBuilder())
                attractions = [Attraction.query.get(attraction_id) for attraction_id in attractions]
                for hotel in hotels:
                    price = int(int(flight_price) + (int(hotel["price_per_night"])*days)) #need to convert currencies
                    if budget is not None and price > budget:
                        continue

                    trips.append({
                        'id': -1,
                        'profile': profile_id,
                        'destination': city,
                        'start_date': from_date,
                        'end_date': to_date,
                        'days': days,
                        'price': price,
                        'currency': 'USD',
                        'people_number': travelers,
                        'pictures': [],
                        'flights': flights,
                        'hotel': hotel,
                        'explore': True,
                        'places': trip_builder.build_trip(days, attractions, city, hotel),
                        'flight_rsrv': None,
                        'hotel_rsrv_code': None,
                        'is_booked': False
                    })
            return jsonify(trips), 200
        except Exception as e:
            return str(e), 500

    def get_trip_config(self, city, username, profile):
        user_id = User.query.filter_by(username=username).first().id
        profile_id = UserProfile.query.filter_by(user_id=user_id, id=profile).first().id
        city_id = City.query.filter_by(name=city).first().id
        return {
            'user_id': user_id,
            'profile_id': profile_id,
            'city_id': city_id
        }

    def get_popular_tags(self):
        try:
            agent_response = requests.get(url=(AGENT_ENDPOINT+AGENT_TAGS_GET), params={})
            if agent_response.status_code is not 200:
                return agent_response.content, agent_response.status_code
            agent_results = json.loads(agent_response.content)
            tags = []
            for result in agent_results:
                id = result[0]
                tag = result[1]
                tags.append(
                    {"id": id, "name": tag}
                )
            return jsonify(tags), 200
        except Exception as e:
            return str(e), 500

    def _get_flights(self, from_city, to_city, from_date, to_date, travelers, max_stop_overs=3):
        max_returned_values = 2
        from_city_code = LocationMatcher.get_iata_for_city(from_city)
        to_city_code = LocationMatcher.get_iata_for_city(to_city)

        for stops in range(0, max_stop_overs):
            flight_url = FLIGHTS_BASE_ENDPOINT + 'flyFrom=' + from_city_code + '&to=' + to_city_code + '&dateFrom=' \
                         + str(from_date) + '&dateTo=' + str(to_date) + '&partner=picky&flight_type=return&' \
                         + 'max_stopovers=' + str(stops)

            api_response = requests.get(url=flight_url, params={})
            if api_response.status_code is not 200:
                return api_response.content, api_response.status_code
            api_results = json.loads(api_response.content)
            if len(api_results['data']) == 0:
                continue

            flights = []
            max_returned_values = min(max_returned_values, len(api_results['data']))
            for i in range(max_returned_values):
                flights.append(
                    {
                        "from_city": from_city,
                        "from_city_code": from_city_code,
                        "to_city": to_city,
                        "to_city_code": to_city_code,
                        "arrival_time": self._get_time_from_timestamp(api_results['data'][i]['aTime']),
                        "departure_time": self._get_time_from_timestamp(api_results['data'][i]['dTime']),
                        "price": int(api_results['data'][i]['price']),
                        "duration": api_results['data'][i]['fly_duration'],
                        "link": api_results['data'][i]['deep_link']
                    }
                )
            return flights

    def get_flights_for_trip(self, from_city, to_city, from_date, to_date, travelers, max_stop_overs=0):
        try:
            flights = self._get_flights(from_city, to_city, from_date, to_date, travelers, max_stop_overs)
            return jsonify(flights), 200
        except Exception as e:
            return str(e), 500

    def _get_hotels(self, city_name, from_date, to_date, travelers, rooms='1'):
        max_returned_values = 2

        city_code = LocationMatcher.get_booking_code_for_city(city_name)
        from_date = datetime.strptime(from_date, '%d/%m/%Y')
        to_date = datetime.strptime(to_date, '%d/%m/%Y')
        days = (to_date - from_date).days

        search_url = HOTELS_BASE_ENDPOINT + 'dest_ids=' + city_code + '&arrival_date=' \
                     + str(from_date.date()) + '&departure_date=' + str(to_date.date()) + '&guest_qty=' + str(travelers) \
                     + '&room_qty=' + rooms

        api_response = requests.get(url=search_url, headers=HOTELS_HEADER)
        if api_response.status_code is not 200:
            return api_response.content, api_response.status_code
        api_results = json.loads(api_response.content)
        hotels = []
        api_results_data = api_results['result']
        max_returned_values = min(max_returned_values, len(api_results_data))

        for i in range(max_returned_values):
            if 'price_breakdown' not in api_results_data[i].keys():
                continue
            row_data = api_results_data[i]
            address = str(row_data['address_trans']) + ',' + str(row_data['district']) + ',' + \
                      str(row_data['city_trans']) + ',' + str(row_data['zip']) + ',' + \
                      str(row_data['country_trans'])
            stars = str(row_data['class']) if row_data['class'] != 0 else DEFAULT_STARS

            hotels.append(
                {
                    "address": address,
                    "currency": row_data['price_breakdown']['currency'],
                    "end_date": to_date.date(),
                    "facilities": [],
                    "main_photo_url": row_data['main_photo_url'].replace('square60', 'square350'),
                    "name": row_data['hotel_name'],
                    "price_per_night": int((float(row_data['price_breakdown']['gross_price']) / days)),
                    "room_type": "",
                    "start_date": from_date.date(),
                    "url": row_data['url'],
                    "description": '',
                    "stars": stars
                }
            )
        return hotels

    def get_hotels(self, city_name, from_date, to_date, travelers, rooms='1'):
        try:
            hotels = self._get_hotels(city_name, from_date, to_date, travelers, rooms)
            return jsonify(hotels), 200
        except Exception as e:
            return str(e), 500

    #Delete functions

    def delete_profile(self, username, profile_id):
        try:
            user = User.query.filter_by(username=username).first()
            profile_id = UserProfile.query.filter_by(user_id=user.id, id=profile_id).first().id
            self._exec_procedure(PROFILE_REMOVE_SP, [str(profile_id)])
        except Exception as e:
            print(e)
            return "Error removing a profile", 500
        return "success", 200

    #Private functions

    def _get_time_from_timestamp(self,timestamp):
        dt = datetime.utcfromtimestamp(int(timestamp)).strftime('%H:%M')
        return dt

    def _exec_procedure(self, procedure_name, params):
        try:
            params_conc = self._join(params, ',')
            print(params_conc)
            query = 'CALL ' + procedure_name + "(" + params_conc + ")"
            results = self.db.session.execute(query, [])
            self.db.session.commit()
            return results
        except Exception as e:
            self.db.session.rollback()
            print(e)
            raise e

    def _join(self, l, sep):
        out_str = ''
        for el in l:
            if el is None:
                el = 'Null'
            out_str += '{}{}'.format(el, sep)
        return out_str[:-len(sep)]

    def _get_string_param(self, param):
        return "'" + str(param) + "'"


#!/usr/bin/python
import time
import sys
import argparse
from time import strftime
from os import system
from sys import platform as _platform

# Help String
description_string = "Tomaterminal is a terminal program based on the Pomodoro (Italian for Tomato) method of working. In the Pomodoro method, you take a timer ((frequently tomato shaped) historically used in kitchens) and you set a 25 minute timer for work. After 25 mintues are completed, you set a 5 minute timer for break. Tomaterminal emulates this exact behavior, alerting you after 25 minutes have elapsed, then after your 5 minute break has elapsed."

parser = argparse.ArgumentParser(description=description_string)
parser.add_argument('-t','--task_time', type=int, help='Task Interval (minutes)',required=False)
parser.add_argument('-b','--break_time', type=int, help='Break Interval (minutes)',required=False)
parser.add_argument('-m','--task_name', type=str, help='Task Name (in quotations. ex: "Hello World")',required=False)
parser.add_argument('-p','--pomo_num', type=str, help='Number of last Pomodoro (useful for taking breaks)',required=False)
parser.add_argument('-e','--pomo_est', type=str, help='Estimated number of Pomos',required=False)
args = parser.parse_args()

# Time Definitions
seconds_minute = 1
minutes_hour = 60
hours_day = 24

# Task Definitions
task_time = 25
break_time = 5
task_name = "Current Task"
pomo_num = 1
pomo_est = 1

# Override task/break time if command line arguments passed
if args.task_time is not None:
    task_time = args.task_time
if args.break_time is not None:
    break_time = args.break_time
if args.task_name is not None:
    task_name = args.task_name
if args.pomo_num is not None:
    pomo_num = int(args.pomo_num)
if args.pomo_est is not None:
    pomo_est = int(args.pomo_est)

# UI Definitions
progress_bar_length = 40

def alert():
    print ('\a')

def progress(count, total, suffix=''):
    filled_len = int(round(progress_bar_length * count / float(total)))
    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (progress_bar_length - filled_len)
    sys.stdout.write("\r[%s] %s%s %s" % (bar, percents, '%', suffix)),
    sys.stdout.flush()

# Initial Entry into Program; Clear Screen
while True:

    sys.stdout.write("Task: %sm -- Break: %sm -- Task: %s -- Est_Pomos: %s - Act_Pomos: %s -- Pause/unpause=ctrl-z;fg\n" % (task_time, break_time, task_name, pomo_est, pomo_num)),
    # Task Loop
    progress(0,task_time,'Working: %smin to go - Start-Time: %s' % (task_time, strftime("%Y-%m-%d %H:%M:%S")))
    for i in range(0, task_time):
        ellapsedTime = task_time - i
        if ellapsedTime < 10:
            ellapsedTime = str(ellapsedTime).zfill(2)
        time.sleep(seconds_minute)
        progress(i,task_time,'Working: %smin to go' % ellapsedTime)

    alert()
    if (_platform == "darwin") or (_platform == "linux2"):
        system('say %s minute break starting now. ' % str(break_time))

    # Break Loop
    progress(0,task_time,'Break: %smin left - Start-Time: %s' % (break_time, strftime("%Y-%m-%d %H:%M:%S")))
    for i in range(0, break_time):
        breakTimeEllapsed = break_time - i;
        breakTimeEllapsed = str(breakTimeEllapsed).zfill(2)
        time.sleep(seconds_minute)
        progress(i,break_time,'Break: %smin left' % breakTimeEllapsed)

    alert()
    pomo_num = pomo_num + 1
    print ('')
    if (_platform == "darwin") or (_platform == "linux2"):
        system('say %s minute work session starting now.' % str(task_time))


import json
import os
import argparse
import subprocess
from multiprocessing import Pool
import neurips23.common

def build(tag, args, dockerfile):
    print('Building %s...' % tag)
    if args is not None and len(args) != 0:
        q = " ".join(["--build-arg " + x.replace(" ", "\\ ") for x in args])
    else:
        q = ""

    try:
        command = 'docker build %s --rm -t %s -f' \
                   % (q, tag)
        command += ' %s .' % dockerfile
        print(command)
        subprocess.check_call(command, shell=True)
        return {tag: 'success'}
    except subprocess.CalledProcessError:
        return {tag: 'fail'}

def build_multiprocess(args):
    return build(*args)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        "--proc",
        default=1,
        type=int,
        help="the number of process to build docker images")
    parser.add_argument(
        '--algorithm',
        metavar='NAME',
        help='build only the named algorithm image',
        default=None)
    parser.add_argument(
        '--dockerfile',
        metavar='PATH',
        help='build only the image from a Dockerfile path',
        default=None)
    parser.add_argument(
        '--neurips23track',
        choices=['filter','ood','streaming','sparse','none'],
        default='none'
    )
    parser.add_argument(
        '--build-arg',
        help='pass given args to all docker builds',
        nargs="+")
    args = parser.parse_args()

    print('Building base image...')
    if args.neurips23track != 'none':
        subprocess.check_call(
            'docker build \
            --rm -t %s -f %s .' % (neurips23.common.docker_tag_base(), neurips23.common.dockerfile_path_base()), shell=True)
        track = args.neurips23track

        if args.algorithm: # build a specific algorithm
            algos = [args.algorithm]
        else: # build all algorithms in the track with Dockerfiles.
            algos = filter(lambda entry : os.path.exists(neurips23.common.dockerfile_path(track, entry)),
                            os.listdir(neurips23.common.track_path(track)))
        tags = [neurips23.common.docker_tag(track, algo) for algo in algos]
        dockerfiles = [neurips23.common.dockerfile_path(track, algo) for algo in algos]
    else: # NeurIPS'21
        track_prefix = 'billion-scale-benchmark'
        subprocess.check_call(
            'docker build \
            --rm -t %s -f install/Dockerfile .' % track_prefix, shell=True)
        if args.dockerfile:
            tags = [track_prefix + '-' + os.path.basename(os.path.dirname(args.dockerfile))]
            dockerfiles = args.dockerfile
        else:
            if args.algorithm:
                algos = [args.algorithm]
            elif os.getenv('LIBRARY'):
                algos = [os.getenv('LIBRARY')]
            else:
                algos = [fn.split('.')[-1] for fn in os.listdir('install') if fn.startswith('Dockerfile.') and not 'faissgpu' in fn]
            dockerfiles = ['install/Dockerfile.' +  algo for algo in algos]
            tags = [track_prefix + '-' + algo for algo in algos]

    print('Building algorithm images... with (%d) processes' % args.proc)

    if args.proc == 1:
        install_status = [build(tag, args.build_arg, dockerfile) for (tag, dockerfile) in zip(tags, dockerfiles)]
    else:
        pool = Pool(processes=args.proc)
        install_status = pool.map(build_multiprocess,
                                  [(tag, args.build_arg, dockerfile) for (tag, dockerfile) in zip(tags, dockerfiles)])
        pool.close()
        pool.join()

    print('\n\nInstall Status:\n' + '\n'.join(str(algo) for algo in install_status))


"""
# 387
Easy
First Unique Character in a String

https://leetcode.com/problems/first-unique-character-in-a-string/

Given a string s, find the first non-repeating character in it and return its index. If it does not exist, return -1.

Example 1:
Input: s = "leetcode"
Output: 0

Example 2:
Input: s = "loveleetcode"
Output: 2

Example 3:
Input: s = "aabb"
Output: -1

Constraints:
1 <= s.length <= 105
s consists of only lowercase English letters.
"""

def first_uniq_char(s: str) -> int:
    hm = {}
    uniq = []
    appeared = []

    for i in range(len(s)):
        char = s[i]

        if char not in appeared:
            uniq.append(i)
            appeared.append(char)

        else:
            prev = hm[char]
            if prev in uniq:
                uniq.remove(prev)

        hm[char] = i

    return -1 if not len(uniq) else uniq[0]

if __name__ == "__main__":
    assert first_uniq_char("leetcode") == 0
    assert first_uniq_char("loveleetcode") == 2
    assert first_uniq_char("aabb") == -1


import os
import yaml

def _parse_obj(obj):
    target = lambda: None
    if isinstance(obj, dict):
        for key, value in obj.items():
            setattr(target, key, _parse_obj(value))
    elif isinstance(obj, list):
        target = [_parse_obj(x) for x in obj]
    else:
        target = obj
    return target

commands_path = os.path.dirname(os.path.abspath(__file__)) + "/commands.yaml"
BashCommand = _parse_obj(yaml.load(open(commands_path).read()))


import math
from datetime import datetime
from pathlib import Path

import dgl
import numpy as np
import pandas as pd
from torch import from_numpy

from base import BaseDataset
from preprocess import TCGA_Project
from utils.api import get_filters_result_from_project, get_ppi_encoder, get_network_image, visualize_ppi
from utils.logger import get_logger
from utils.util import check_cache_files

PROJECT_MAX_COUNT = 1000

class TCGA_Program_Dataset(BaseDataset):
    '''
    TCGA Program Dataset, used for multi-task
    '''
    def __init__(self, project_ids, data_directory, cache_directory, chosen_features=dict(), genomic_type='tpm',
                 target_type='overall_survival', n_threads=1,
                 graph_dataset=False, ppi_score_name='escore', ppi_score_threshold=0.0):
        '''
        Initialize the TCGA Program Dataset with parameters.
        #for external DSs, I will probably need to create this directly from the data, not from the API

        Needed parameters
        :param project_id: Specify the project id.
        :param data_directory: Specify the directory for the downloaded files.
        :param cache_directory: Specify the directory for the cache files.

        Optional parameters
        :param chosen_features: Specify the features that you want to use.
        :param genomic_type: The genomic type that uses in this project.
        :param target_type: Specify the wanted target type that you want to use.
        :param n_threads: The number of threads to user for concatenating genomic data.
        :param graph_dataset: Whether to use graph or not.
        :param ppi_score_name: The name of the ppi score.
        :param ppi_score_threshold: The threshold of the ppi score.
        '''
        if project_ids not in ['ALL']:
            self.project_ids = project_ids
        else:
            project_filters = {
                '=': {'program.name': 'TCGA'}
            }
            self.project_ids = [
                project_metadata['id'] for project_metadata in get_filters_result_from_project(
                    filters=project_filters,
                    sort='summary.case_count:desc',
                    size=PROJECT_MAX_COUNT
                )
            ]

        # Logger
        self.logger = get_logger('preprocess.tcga_program_dataset')
        self.logger.info('Creating a TCGA Program Dataset with {} Projects...'.format(len(self.project_ids)))

        # Directory for data and cache files
        self.data_directory = Path(data_directory)
        self.cache_directory = Path(cache_directory)

        # Get chosen features
        self.chosen_gene_counts = chosen_features.get('gene_counts', 20)
        self.chosen_project_gene_ids = chosen_features.get('gene_ids', {})
        for project_id in self.project_ids:
            if project_id not in self.chosen_project_gene_ids:
                if project_ids not in ['ALL']:
                    raise ValueError(f'Gene ids is null for {project_id}')
                else:
                    self.chosen_project_gene_ids[project_id] = []
                    self.logger.debug(f'Gene ids is null for {project_id}')
        self.chosen_clinical_numerical_ids: list = chosen_features.get('clinical_numerical_ids', [])
        self.chosen_clinical_categorical_ids = chosen_features.get('clinical_categorical_ids', [])
        self.chosen_clinical_ids = self.chosen_clinical_numerical_ids + self.chosen_clinical_categorical_ids

        # Create TCGA_Project instances
        self.tcga_projects: dict[str, TCGA_Project] = {}
        for project_id in self.project_ids:
            self.tcga_project_init_kwargs = {
                'project_id': project_id,
                'download_directory': self.data_directory.joinpath(project_id),
                'cache_directory': self.cache_directory.joinpath(project_id),
                'genomic_type': genomic_type,
                'n_threads': n_threads
            }

            self.tcga_projects[project_id] = TCGA_Project(**self.tcga_project_init_kwargs)

        # Specify the target type
        self.target_type = target_type

        # Specify the genomic type (use graph or not).
        self.graph_dataset = graph_dataset
        self.ppi_score = ppi_score_name
        self.ppi_threshold = ppi_score_threshold

        # Get data from TCGA_Project instance
        self._getdata()

        # Log the information of the dataset.
        self.logger.info('Total {} patients, {} genomic features and {} clinical features'.format(
            len(self.patient_ids), len(self.genomic_ids), len(self.clinical_ids)
        ))
        self.logger.info('Target Type {}'.format(self.target_type)) #Target Type overall_survival
        self.logger.info('Overall survival imbalance ratio {} %'.format(
            sum(self.overall_survivals) / len(self.overall_survivals) * 100
        ))
        self.logger.info('Disease specific survival event rate {} %'.format(
            sum(self.disease_specific_survivals >= 0) / len(self.disease_specific_survivals) * 100
        ))
        self.logger.info('Disease specific survival imbalance ratio {} %'.format(
            sum(self.disease_specific_survivals[self.disease_specific_survivals >= 0]) / len(
                self.disease_specific_survivals[self.disease_specific_survivals >= 0]
            ) * 100
        ))
        self.logger.info('{} kinds of primary sites {}'.format(
            len(np.unique(self.primary_sites)), ' / '.join(self.primary_site_ids)
        ))

        # Initialize BaseDataset instance
        self.base_dataset_init_kwargs = {
            'data_root_directory': data_directory,
            'cache_root_directory': cache_directory
        }
        super().__init__(**self.base_dataset_init_kwargs)

    def _getdata(self):
        '''
        Get the data from TCGA Program
        '''
        #not really dfs, they are lists of dfs
        df_genomics = []
        df_clinicals = []
        df_vital_statuses = []
        df_overall_survivals = []
        df_disease_specific_survivals = []
        df_survival_times = []
        df_primary_sites = []
        df_project_ids = []
        train_patient_ids = []
        test_patient_ids = []

        for project_id, tcga_project in self.tcga_projects.items():
            df_genomic: pd.DataFrame = tcga_project.genomic.T
            if self.chosen_project_gene_ids[project_id] not in ['ALL']:
                df_genomic = df_genomic[self.chosen_project_gene_ids[project_id]]
            else:
                raise ValueError(f'No gene ids specified for {project_id}')

            df_clinical: pd.DataFrame = tcga_project.clinical.T[self.chosen_clinical_ids]

            if len(self.chosen_clinical_numerical_ids):
                # Setting copy=False will not work.
                df_clinical = df_clinical.astype(dict.fromkeys(self.chosen_clinical_numerical_ids, 'float64'))

                indices_latest_file_path = check_cache_files(
                    cache_directory=self.cache_directory.joinpath(project_id),
                    regex=r'indices_*'
                )

                if indices_latest_file_path:
                    indices_latest_file_created_date = indices_latest_file_path.name.split('.')[0].split('_')[-1]
                    self.logger.info('Using indices cache files created at {} from {}'.format(
                        datetime.strptime(indices_latest_file_created_date, "%Y%m%d%H%M%S"),
                        self.cache_directory.joinpath(project_id)
                    ))
                    self.logger.info('Normalize clinical numerical data using training samples only')

                    indices_cache = np.load(indices_latest_file_path)
                    train_indices = indices_cache['train']
                    test_indices = indices_cache['test']

                    clinical_mean = df_clinical[self.chosen_clinical_numerical_ids].iloc[train_indices].mean()
                    clinical_std = df_clinical[self.chosen_clinical_numerical_ids].iloc[train_indices].std()

                    train_patient_ids.extend(df_clinical.iloc[train_indices].index.to_list())
                    test_patient_ids.extend(df_clinical.iloc[test_indices].index.to_list())
                else:
                    self.logger.info('Normalize clinical numerical data using all samples')
                    clinical_mean = df_clinical[self.chosen_clinical_numerical_ids].mean()
                    clinical_std = df_clinical[self.chosen_clinical_numerical_ids].std()

                    train_patient_ids.extend(df_clinical.index.to_list())

                # Impute the missing values with mean
                df_clinical = df_clinical.fillna(clinical_mean.to_dict())

                # Normalize the numerical values
                df_clinical[self.chosen_clinical_numerical_ids] -= clinical_mean
                df_clinical[self.chosen_clinical_numerical_ids] /= clinical_std

            if len(self.chosen_clinical_categorical_ids):
                df_clinical = pd.get_dummies(df_clinical, columns=self.chosen_clinical_categorical_ids, dtype=float)

                all_tcga_clinical_categorical_ids_latest_file_path = check_cache_files(
                    cache_directory=self.cache_directory.joinpath(project_id),
                    regex=r'all_tcga_clinical_categorical_ids_*'
                )
                if all_tcga_clinical_categorical_ids_latest_file_path:
                    created_date = all_tcga_clinical_categorical_ids_latest_file_path.name.split('.')[0].split('_')[-1]
                    self.logger.info('Using all tcga clinical categorical ids cache files created at {} for {}'.format(
                        datetime.strptime(created_date, "%Y%m%d%H%M%S"),
                        project_id
                    ))

                    df_all_tcga_clinical_categorical_ids: pd.Series = pd.read_csv(
                        all_tcga_clinical_categorical_ids_latest_file_path,
                        sep='\t',
                        header=None
                    ).squeeze()
                    df_clinical = df_clinical.reindex(
                        columns=self.chosen_clinical_numerical_ids + df_all_tcga_clinical_categorical_ids.tolist()
                    ).fillna(0)

            df_vital_status = tcga_project.vital_status.T
            df_overall_survival = tcga_project.overall_survival.T
            df_disease_specific_survival = tcga_project.disease_specific_survival.T
            df_survival_time = tcga_project.survival_time.T
            df_primary_site = tcga_project.primary_site.T
            df_project_id = pd.DataFrame(
                data=[self.project_ids.index(project_id)] * len(df_primary_site),
                index=df_primary_site.index,
                columns=['project_id']
            )

            # Rename the gene ids to numbers for original multi-task.
            if not self.graph_dataset:
                df_genomic.rename(columns=dict(zip(df_genomic.columns, range(len(df_genomic.columns)))), inplace=True)

            df_genomics.append(df_genomic)
            df_clinicals.append(df_clinical)
            df_vital_statuses.append(df_vital_status)
            df_overall_survivals.append(df_overall_survival)
            df_disease_specific_survivals.append(df_disease_specific_survival)
            df_survival_times.append(df_survival_time)
            df_primary_sites.append(df_primary_site)
            df_project_ids.append(df_project_id)

        # NOTE: There's no missing values for the original multi-task. fillna() is only for graph dataset.
        df_genomics = pd.concat(df_genomics).fillna(0)
        df_clinicals = pd.concat(df_clinicals).fillna(0)
        df_vital_statuses = pd.concat(df_vital_statuses)
        df_overall_survivals = pd.concat(df_overall_survivals)
        df_disease_specific_survivals = pd.concat(df_disease_specific_survivals)
        df_survival_times = pd.concat(df_survival_times)
        df_primary_sites = pd.concat(df_primary_sites).astype('category')
        df_project_ids = pd.concat(df_project_ids)

        filtered_ids = get_filters_result_from_project(filters={'=': {'program.name': 'TCGA'}}, size=PROJECT_MAX_COUNT)
        if len(self.project_ids) == len(filtered_ids):
            all_tcga_clinical_categorical_columns = df_clinicals.columns[
                ~df_clinicals.columns.isin(self.chosen_clinical_numerical_ids)
            ].to_series()
            for project_id in self.project_ids:
                all_tcga_clinical_categorical_ids_latest_file_path = check_cache_files(
                    cache_directory=self.cache_directory.joinpath(project_id),
                    regex=r'all_tcga_clinical_categorical_ids_*'
                )

                if all_tcga_clinical_categorical_ids_latest_file_path:
                    all_cached_clinical_categorical_ids = pd.read_csv(
                        all_tcga_clinical_categorical_ids_latest_file_path,
                        sep='\t',
                        header=None
                    ).squeeze()
                    if not len(set(all_tcga_clinical_categorical_columns) - set(all_cached_clinical_categorical_ids)):
                        continue

                all_tcga_clinical_categorical_columns.to_csv(self.cache_directory.joinpath(
                    project_id,
                    f'all_tcga_clinical_categorical_ids_{datetime.now().strftime("%Y%m%d%H%M%S")}.tsv'
                ), sep='\t', index=False, header=False)
                self.logger.info('Saving all tcga clinical categorical ids to {}'.format(
                    self.cache_directory.joinpath(project_id)
                ))

        df_totals = pd.concat(
            [df_genomics, df_clinicals, df_vital_statuses, df_overall_survivals, df_disease_specific_survivals,
             df_survival_times, df_primary_sites, df_project_ids],
            axis=1
        )

        # Transform to graph if graph_dataset is True.
        if self.graph_dataset:
            self._num_nodes = df_genomics.shape[-1]
            self.logger.info(f'Number of nodes for the graph: {self._num_nodes}')
            df_ppis = get_ppi_encoder(df_genomics.columns.to_list(), score=self.ppi_score, threshold=self.ppi_threshold)
            #get_network_image(df_genomics.columns.to_list())

            self._genomics = self._process_genomic_as_graph(df_genomics, df_ppis)
        else:
            self._genomics = df_totals[df_genomics.columns].to_numpy(dtype=np.float32)

        self._clinicals = df_totals[df_clinicals.columns].to_numpy(dtype=np.float32)
        self._vital_statuses = df_totals[df_vital_statuses.columns].squeeze().to_numpy(dtype=np.float32)
        self._overall_survivals = df_totals[df_overall_survivals.columns].squeeze().to_numpy(dtype=np.float32)
        self._dss = df_totals[df_disease_specific_survivals.columns].squeeze().to_numpy(dtype=np.float32)
        self._survival_times = df_totals[df_survival_times.columns].squeeze().to_numpy(dtype=np.float32)
        self._primary_sites = df_totals[df_primary_sites.columns].squeeze().cat.codes.to_numpy()
        self._project_ids = df_totals[df_project_ids.columns].squeeze().to_numpy()
        self._primary_site_ids = tuple(df_totals[df_primary_sites.columns].squeeze().cat.categories.to_list())
        self._patient_ids = tuple(df_totals.index.to_list())
        self._genomic_ids = tuple(df_genomics.columns.to_list())
        self._clinical_ids = tuple(df_clinicals.columns.to_list())
        print("clinical ids training models", self._clinical_ids)

        indices = {
            'train': np.array([i for i, patient_id in enumerate(self._patient_ids) if patient_id in train_patient_ids]),
            'test': np.array([i for i, patient_id in enumerate(self._patient_ids) if patient_id in test_patient_ids])
        }

        for file_path in self.cache_directory.glob('indices_*'):
            if file_path.is_file():
                file_path.unlink()
                self.logger.debug('Removing redundant indices file {}'.format(file_path))

        np.savez(self.cache_directory.joinpath(f'indices_{datetime.now().strftime("%Y%m%d%H%M%S")}.npz'), **indices)
        self.logger.info('Saving train and test indices to {}'.format(self.cache_directory))
        return

    def _process_genomic_as_graph(self, df_genomic: pd.DataFrame, df_ppi: pd.DataFrame):
        src = from_numpy(df_ppi['src'].to_numpy())
        dst = from_numpy(df_ppi['dst'].to_numpy())
        graphs: list[dgl.DGLGraph] = []

        # Create a graph for each sample (patient).
        for _, row in df_genomic.iterrows():
            g = dgl.graph((src, dst), num_nodes=self._num_nodes)
            g.ndata['feat'] = from_numpy(row.to_numpy()).view(-1, 1).float()
            g = dgl.add_reverse_edges(g)
            graphs.append(g)
        return graphs

    def __getitem__(self, index):
        '''
        Support the indexing of the dataset
        '''
        return ((self._genomics[index], self._clinicals[index], index, self._project_ids[index]),
                (self.targets[index], self._survival_times[index], self._vital_statuses[index]))

    def __len__(self):
        '''
        Return the size of the dataset
        '''
        return len(self.targets)

    @property
    def data(self):
        '''
        Return the genomic and clinical data.
        '''
        if not self.graph_dataset:
            return np.hstack((self._genomics, self._clinicals))
        return np.hstack((np.expand_dims(self._genomics, 1), self._clinicals))

    @property
    def genomics(self):
        '''
        Return the genomic data.
        '''
        return self._genomics

    @property
    def clinicals(self):
        '''
        Return the clinical data.
        '''
        return self._clinicals

    @property
    def vital_statuses(self):
        '''
        Return the vital status data.
        '''
        return self._vital_statuses

    @property
    def overall_survivals(self):
        '''
        Return the 5 year overall survival data.
        '''
        return self._overall_survivals

    @property
    def disease_specific_survivals(self):
        '''
        Return the 5 year disease specific survival data.
        '''
        return self._dss

    @property
    def survival_times(self):
        '''
        Return the survival time data.
        '''
        return self._survival_times

    @property
    def primary_sites(self):
        '''
        Return the primary site data.
        '''
        return self._primary_sites

    @property
    def primary_site_ids(self):
        '''
        Return the primary site ids.
        '''
        return self._primary_site_ids

    @property
    def weights(self):
        '''
        Return the weights for each data.
        '''
        weights = np.zeros_like(self._project_ids, dtype='float64')
        for i in range(self._project_ids.min(), self._project_ids.max() + 1):
            weights[self._project_ids == i] = math.sqrt(1.0 / (self._project_ids == i).sum())
        return weights

    @property
    def targets(self):
        '''
        Return the target data according to target_type.
        '''
        if self.target_type == 'overall_survival':
            return self._overall_survivals
        elif self.target_type == 'disease_specific_survival':
            return self._dss
        elif self.target_type == 'primary_site':
            return self._primary_sites
        else:
            raise KeyError('Wrong target type')

    @property
    def patient_ids(self):
        '''
        Return the patient ids
        '''
        return self._patient_ids

    @property
    def genomic_ids(self):
        '''
        Return the genomic ids
        '''
        return self._genomic_ids

    @property
    def clinical_ids(self):
        '''
        Return the clinical ids
        '''
        return self._clinical_ids


PAD = 0
UNK = 1
BOS = 2
EOS = 3

# PAD_WORD = '<blank>'
# UNK_WORD = '<unk>'
# BOS_WORD = '<s>'
# EOS_WORD = '</s>'

UNK_WORD = '�'
PAD_WORD = '◌'
BOS_WORD = '▶'
EOS_WORD = '◀'


from sklearn.datasets import make_blobs

X,Y = make_blobs(random_state = 10)

# from sklearn.cluster import KMeans
# kmeans = KMeans(n_clusters = 3)
# k_predict = kmeans.fit_predict(X)
#
# from python_prac.adspy_shared_utilities import plot_labelled_scatter
# plot_labelled_scatter(X,k_predict,class_labels = ['cluster1','cluster2','cluster3'])

# from sklearn.cluster import KMeans
#
# k_means = KMeans(n_clusters = 3)
# k_means.fit(X)

from python_prac.adspy_shared_utilities import plot_labelled_scatter

# plot_labelled_scatter(X,k_means.labels_,['cluster1','cluster2','cluster3'])

# import pandas as pd
#
# fruits = pd.read_table('C:\\Users\\ASUS\\Desktop\\python_prac\\knn\\fruit_data_with_colors.txt')
# X_fruits = fruits[['mass','width','height','color_score']].as_matrix()
# Y_fruits = fruits[['fruit_label']] - 1
#
# from sklearn.preprocessing import MinMaxScaler
# X_fruits_normalized = MinMaxScaler().fit_transform(X_fruits)
#
# k_means2 = KMeans(n_clusters = 4,random_state = 0)
# k_means2.fit(X_fruits)
#
# plot_labelled_scatter(X,k_means2.labels_,['cluster1','cluster2','cluster3','cluster4'])

# AGGLOMERATIVE CLUSTERING
from sklearn.cluster import AgglomerativeClustering
cls = AgglomerativeClustering(n_clusters = 3)#n_clusters paramter that causesthe algo to stop when it has
#reach the number of clusters

# cls.fit(X)
#cls.predict(X)
cls_predict = cls.fit_predict(X)
plot_labelled_scatter(X = X,y = Y,class_labels = ['cluster1','cluster2','cluster3'])

#DENDOGRAM EXAPMPLE(IT IS USED TO FOR REPRESNTATION OF HEIRARICHAL CLUSTERING
from scipy.cluster.hierarchy import ward,dendrogram
# these ward function returns an array which can then be passed to the dendogram function to plot the tree
X,Y = make_blobs(random_state = 10,n_samples = 10)

import matplotlib.pyplot as plt
plt.figure()
dendrogram(ward(X))
plt.title('Dendogram')
plt.show()

from sklearn.cluster import DBSCAN

X1,Y1 = make_blobs(random_state = 9,n_samples = 25)
dbscan = DBSCAN(eps = 2,min_samples = 2)
cls = dbscan.fit_predict(X1)
print('cluster membership values : \n{}',format(cls))
print(cls)
plot_labelled_scatter(X1,cls + 1,['noise','cluster1','cluster2','cluster3'])


def checkio(field_map):
    c_point = (0, 0)
    e_point = (len(field_map) - 1, len(field_map[0]) - 1)
    # shortest way without drop box
    nodes = get_path(field_map, c_point, e_point, 2)
    drop_box = get_db(field_map)

    s_db = sorted(drop_box, key=lambda x:nodes[x]) [:2]

    e_nodes = get_path(field_map, e_point, c_point, 2)
    e_db = sorted(drop_box, key=lambda x:e_nodes[x]) [:2]

    #path
    current_min = nodes[e_point]
    db_nodes = []
    for s in s_db:
        for e in e_db:
            s_value = nodes[s]
            e_value = e_nodes[e]
            db_value = get_path(field_map, s, e, 1)[e]
            length = s_value + e_value + db_value + 2
            if length < current_min:
                current_min = length
                db_nodes = (s, e)
    if db_nodes:
        road = get_road(field_map, nodes, db_nodes[0], c_point)
        road += 'B'
        road += get_road(field_map, get_path(field_map, db_nodes[0], db_nodes[1], 1), db_nodes[1], db_nodes[0])
        road += 'B'
        road += get_road(field_map, get_path(field_map, db_nodes[1], e_point, 1), e_point, db_nodes[1])
    else:
        road = get_road(field_map, nodes, e_point, c_point)

    return road

def get_road(field_map, nodes, s_point, e_point):
    ACTIONS = {
        "L": (0, -1),
        "R": (0, 1),
        "U": (-1, 0),
        "D": (1, 0),
    }
    result = ''
    c_point = s_point
    while c_point != e_point:
        cell = get_available(field_map, c_point)

        step = min(cell, key=lambda x:nodes[x])
        move = (c_point[0] - step[0], c_point[1] - step[1])
        for label, move_t in ACTIONS.items():
            if move_t == move:
                result += label
        c_point = step
    return result[::-1]

def get_db(field_map):
    db = []
    for row in range(0, len(field_map)):
        for column in range(0, len(field_map[0])):
            if field_map[row][column]== 'B' and get_available(field_map, (row, column)):
                db.append((row, column))
    return db

def get_path(field_map, c_point, e_point, weight=2):
    nodes = {c_point: 0}
    l_cell = [c_point]

    visited = []
    #drop_box = []

    while l_cell:
        next_cell = l_cell
        l_cell = []
        for p in next_cell:
            if p in visited:
                continue
            cells = get_available(field_map, p)
            visited.append(p)
            #if field_map[p[0]][p[1]] == 'B':
            #    drop_box.append(p)

            for cell in cells:
                if cell in visited:
                    continue
                if nodes.get(cell, 999) > nodes[p] + weight:
                    nodes[cell] = nodes[p] + weight

            l_cell.extend(cells)
    return nodes

def get_available(field_map, point):
    x_max = len(field_map[0])
    y_max = len(field_map)
    ACTIONS = {
        "L": (0, -1),
        "R": (0, 1),
        "U": (-1, 0),
        "D": (1, 0),
    }
    y, x = point
    available = []
    for move_y, move_x in ACTIONS.values():
        if (0 <= y + move_y < y_max) and (0 <= x + move_x < x_max) and field_map[y + move_y][x + move_x] != 'W':
            available.append((y + move_y,x + move_x))
    return available

if __name__ == '__main__':
    #This part is using only for self-checking and not necessary for auto-testing
    ACTIONS = {
        "L": (0, -1),
        "R": (0, 1),
        "U": (-1, 0),
        "D": (1, 0),
        "B": (0, 0)
    }

    def check_solution(func, max_time, field):
        max_row, max_col = len(field), len(field[0])
        s_row, s_col = 0, 0
        total_time = 0
        hold_box = True
        route = func(field[:])
        for step in route:
            if step not in ACTIONS:
                print("Unknown action {0}".format(step))
                return False
            if step == "B":
                if hold_box:
                    if field[s_row][s_col] == "B":
                        hold_box = False
                        total_time += 1
                        continue
                    else:
                        print("Stephan broke the cargo")
                        return False
                else:
                    if field[s_row][s_col] == "B":
                        hold_box = True
                    total_time += 1
                    continue
            n_row, n_col = s_row + ACTIONS[step][0], s_col + ACTIONS[step][1],
            total_time += 2 if hold_box else 1
            if 0 > n_row or n_row >= max_row or 0 > n_col or n_row >= max_col:
                print("We've lost Stephan.")
                return False
            if field[n_row][n_col] == "W":
                print("Stephan fell in water.")
                return False
            s_row, s_col = n_row, n_col
            if field[s_row][s_col] == "E" and hold_box:
                if total_time <= max_time:
                    return True
                else:
                    print("You can deliver the cargo faster.")
                    return False
        print("The cargo is not delivered")
        return False

    assert check_solution(checkio, 12, ["S...", "....", "B.WB", "..WE"]), "1st Example"
    assert check_solution(checkio, 11, ["S...", "....", "B..B", "..WE"]), "2nd example"


from django.shortcuts import render, get_object_or_404, redirect
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ObjectDoesNotExist
from blog.views.search import get_query
from blog.models import Instrumentation, Type_Instrumentation, Supplier, Location
from blog.forms import InstrumentationForm

def instrumentation_list_type(request):
    """
    Instrumentation_list_type function docstring.

    This function shows the list of instrument types that are stored in this web app and they are
    ordered by creation date.

    @param request: HTML request page.

    @return: list of instrument types.
    """
    instrumentations = Type_Instrumentation.objects.all()

    return render(request, 'blog/instrumentation_list_type.html',
                  {'instrumentations': instrumentations})

@login_required(login_url='/accounts/signin/')
def instrumentation_list(request, pk):
    """
    Instrumentation_list function docstring.

    This function shows the list of instruments that are stored in this web app and they are
    ordered by creation date.

    @param request: HTML request page.
    @param pk: primary key of instrument types..

    @return: list of instrument types.
    """
    type_instrumentation = Type_Instrumentation.objects.get(pk=pk)
    instrumentation_list = Instrumentation.objects.filter(
        type_instrumentation=type_instrumentation).order_by('location')

    # Show 25 contacts per page
    paginator = Paginator(instrumentation_list, 10)

    page = request.GET.get('page')
    try:
        instrumentations = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        instrumentations = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        instrumentations = paginator.page(paginator.num_pages)

    instrumentBack = True
    type_instrumBack = False

    return render(request, 'blog/instrumentation_list.html', {'instrumentations': instrumentations,
                                                              'instrumentBack': instrumentBack,
                                                              'type_instrumBack': type_instrumBack})

word_to_search = None

@login_required(login_url='/accounts/signin/')
def instrumentation_search(request):
    """
    Instrumentation_search function docstring.

    This function search the instruments that are stored in this web app and they are
    ordered by name.

    @param request: HTML request page.

    @return: list of instruments.
    """
    global word_to_search
    query_string = ''
    found_entries = None

    page = request.GET.get('page')

    if (('searchfield' in request.GET) and request.GET['searchfield'].strip()) or page is not None:
        if page is not None:
            query_string = word_to_search

        else:
            query_string = request.GET['searchfield']
            word_to_search = query_string

        try:
            query_string = Type_Instrumentation.objects.get(name=query_string)
            instrumentation_list = Instrumentation.objects.filter(
                type_instrumentation=query_string.pk).order_by('type_instrumentation')
        except ObjectDoesNotExist:
            try:
                query_string = Supplier.objects.get(name=query_string)
                instrumentation_list = Instrumentation.objects.filter(
                    supplier=query_string.pk).order_by('type_instrumentation')
            except ObjectDoesNotExist:
                try:
                    query_string = Location.objects.get(name=query_string)
                    instrumentation_list = Instrumentation.objects.filter(
                        location=query_string.pk).order_by('type_instrumentation')
                except ObjectDoesNotExist:
                    entry_query = get_query(query_string, ['subtype_instrumentation', 'model', 'quantity',
                                                           'characteristics', 'manufacturer'])
                    instrumentation_list = Instrumentation.objects.filter(entry_query).order_by('type_instrumentation')

    # Show 25 contacts per page
    paginator = Paginator(instrumentation_list, 25)

    try:
        instrumentations = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        instrumentations = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        instrumentations = paginator.page(paginator.num_pages)

    return render(request, 'blog/instrumentation_list.html', {'instrumentations': instrumentations})

@login_required(login_url='/accounts/signin/')
def instrumentation_detail(request, pk):
    """
    Instrumentation_detail function docstring.

    This function shows the information of a instrument.

    @param request: HTML request page.

    @param pk: primary key of the instrument.

    @return: one instrument.

    @raise 404: instrument does not exists.
    """
    instrumentation = get_object_or_404(Instrumentation, pk=pk)
    instrumentBack = False
    type_instrumBack = True

    return render(request, 'blog/instrumentation_detail.html', {'instrumentation': instrumentation,
                                                                'instrumentBack': instrumentBack,
                                                                'type_instrumBack': type_instrumBack
                                                                })

@login_required(login_url='/accounts/signin/')
def instrumentation_new(request):
    """
    Instrumentation_new function docstring.

    This function shows the form to create a new instrument.

    @param request: HTML request page.

    @return: First time, this shows the form to a new instrument. If the form is completed, return
    the details of this new instrument.
    """
    if request.method == "POST":
        form = InstrumentationForm(request.POST)
        if form.is_valid():
            instrumentation = form.save(commit=False)
            instrumentation.author = request.user
            instrumentation_all = Instrumentation.objects.all()

            duplicates = False

            for data in instrumentation_all:
                if data.pk == instrumentation.pk:
                    duplicates = True
                    instrumentation_ex = data

                elif data.model == instrumentation.model and data.manufacturer == instrumentation.manufacturer:
                    if data.location == instrumentation.location:
                        duplicates = True
                        instrumentation_ex = data

            if not duplicates:
                messages.success(request, 'You have added your instrument successfully.')
                instrumentation.save()
            else:
                messages.warning(request,
                                 'Ups!! A instrument with these characteristics already exists. If you want to add a '
                                 'new to the stock, please edit it.')
                instrumentation = instrumentation_ex

            return redirect('blog:instrumentation_detail', pk=instrumentation.pk)
    else:
        form = InstrumentationForm()
    return render(request, 'blog/instrumentation_new.html', {'form': form})

@login_required(login_url='/accounts/signin/')
def instrumentation_edit(request, pk):
    """
    Instrumentation_edit function docstring.

    This function shows the form to modify a instrument.

    @param request: HTML request page.

    @param pk: primary key of the instrument to modify.

    @return: First time, this shows the form to edit the instrument information. If the form is
    completed, return the details of this instrument.

    @raise 404: instrument does not exists.
    """
    instrumentation = get_object_or_404(Instrumentation, pk=pk)
    if request.method == "POST":
        form = InstrumentationForm(data=request.POST, instance=instrumentation)
        if form.is_valid():
            instrumentation = form.save(commit=False)
            instrumentation.edited_by = request.user.username
            instrumentation_all = Instrumentation.objects.all()

            duplicates = False

            for data in instrumentation_all:
                if data.pk != instrumentation.pk:
                    if (data.model == instrumentation.model) and (data.manufacturer == instrumentation.manufacturer):
                        if data.location == instrumentation.location:
                            duplicates = True
                            instrumentation_ex = data

            if not duplicates:
                messages.success(request, 'You have updated your instrumentation.')
                instrumentation.save()
                return redirect('blog:instrumentation_detail', pk=instrumentation.pk)
            else:
                messages.warning(request, 'Already exists an instrumentation with this name.')
                return redirect('blog:instrumentation_edit', pk=instrumentation.pk)

    else:
        form = InstrumentationForm(instance=instrumentation)
    return render(request, 'blog/instrumentation_edit.html', {'form': form})

@login_required(login_url='/accounts/signin/')
def instrumentation_remove(request, pk):
    """
    Instrumentation_remove function docstring.

    This function removes a instrument.

    @param request: HTML request page.

    @param pk: primary key of the instrument to remove.

    @return: list of instruments.

    @raise 404: instrument does not exists.
    """
    instrumentation = get_object_or_404(Instrumentation, pk=pk)
    instrumentation.delete()
    return redirect('blog:instrumentation_list_type')


from fastapi import FastAPI
import requests

app = FastAPI()

@app.get("/")
async def index():
  return {
      "info": "Try /pokemon/pikachu for a quick demo.",}

@app.get("/pokemon/{pokemon}")
async def get_types(pokemon: str,):
  pokemon_response = requests.get(f'https://pokeapi.co/api/v2/pokemon/{pokemon}')

  body = pokemon_response.json()
  types_for_pokemon = []

  for type in body['types']:
      types_for_pokemon.append(type['type']['name'])

  types_pokemon_double_damage_from = set()
  types_pokemon_half_damage_from = set()
  types_pokemon_no_damage_from = set()

  for type in types_for_pokemon:
      type_response = requests.get(f'https://pokeapi.co/api/v2/type/{type}')
      type_response_json = type_response.json()
      types_pokemon_double_damage_from.update(type['name'] for type in type_response_json['damage_relations']['double_damage_from'])
      types_pokemon_half_damage_from.update(type['name'] for type in type_response_json['damage_relations']['half_damage_from'])
      types_pokemon_no_damage_from.update(type['name'] for type in type_response_json['damage_relations']['no_damage_from'])

  types_pokemon_double_damage_from = types_pokemon_double_damage_from - types_pokemon_half_damage_from
  types_pokemon_double_damage_from = types_pokemon_double_damage_from - types_pokemon_no_damage_from

  output = {
      'name': pokemon,
      'weaknesses': list(types_pokemon_double_damage_from),
      'resistances': list(types_pokemon_half_damage_from),
      'no_damage_from': list(types_pokemon_no_damage_from)
  }

  if pokemon:
    return f"{output}"

  return {
      "name": pokemon,}


def applyMask(currentMask, binValueStr):
    maskLen = len(currentMask)
    valueAfterMask = 0
    for i in range(maskLen):
        maskChar = currentMask[maskLen - 1 - i]

        if i < len(binValueStr):
            binChar = binValueStr[len(binValueStr) - 1 - i]
            if maskChar == '1' or (maskChar == 'X' and binChar == '1'):
                valueAfterMask += 2**i
        else:
            if maskChar == '1':
                valueAfterMask += 2**i

    return valueAfterMask

def applyMaskV2(currentMask, memValueStr):
    maskLen = len(currentMask)
    valueStrAfterMask = ""
    for i in range(maskLen):
        maskChar = currentMask[i]

        if maskLen - i <= len(memValueStr):
            memChar = memValueStr[i - maskLen]
            if maskChar == '1':
                valueStrAfterMask = valueStrAfterMask + maskChar
            if maskChar == 'X':
                valueStrAfterMask = valueStrAfterMask + maskChar
            if maskChar == '0':
                valueStrAfterMask = valueStrAfterMask + memChar
        else:
            valueStrAfterMask = valueStrAfterMask + maskChar

    return valueStrAfterMask

def getMemoryAdressesFromMask(memMask, currentMaskPart, memoryAdresses, indexesTodo):
    createdMask = currentMaskPart
    while len(createdMask) < len(memMask):
        char = memMask[len(createdMask)]
        if char == 'X':
            if len(createdMask) + 1 in indexesTodo:
                createdMask = createdMask + '1'
                indexesTodo.remove(len(createdMask))
            else:
                createdMask = createdMask + '0'
                indexesTodo.append(len(createdMask))
        else:
            createdMask += char

    memoryAdresses.append(createdMask)
    if not indexesTodo:
        return memoryAdresses
    else:
        lastIndexTodo = indexesTodo[-1]
        newMask = createdMask[:lastIndexTodo - 1]
        return getMemoryAdressesFromMask(memMask, newMask, memoryAdresses, indexesTodo)

dockingCode = []
input = open("input.txt")

for line in input:
    dockingCode.append(line.strip())

memory = {}
memoryV2 = {}
currentMask = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
maskValue = 0
for codeLine in dockingCode:
    if codeLine[:4] == "mask":
        currentMask = codeLine[7:]
    else:
        memAndValue = codeLine.split('=')
        mem = memAndValue[0][4:-2]
        value = int(memAndValue[1])
        binValueStr = str(bin(value))[2:]

        #Part 1
        valueAfterMask = applyMask(currentMask, binValueStr)
        memory[mem] = valueAfterMask

        #Part 2
        memStr = str(bin(int(mem)))[2:]
        memMask = applyMaskV2(currentMask, memStr)
        memAdresses = getMemoryAdressesFromMask(memMask, '', [], [])
        for memAdress in memAdresses:
            memoryV2[int(memAdress, 2)] = value

totalSum = 0
for value in memory.values():
    totalSum += value

print("Sum of all values in memory: " + str(totalSum))

totalSum = 0
for value in memoryV2.values():
    totalSum += value
print("Sum of all values in memory V2: " + str(totalSum))


import numpy as np

A = np.array([1, 2, 3])
B=np.array([3, 4, 5])
c=np.array([4,4,4])
d=np.multiply(A,B)
e=np.multiply(B,B)
f=np.divide(c,4)
g=np.multiply(4,e)
h=np.add(d,g)
i=np.subtract(h,f)
print(i)


""" Permutation """
def permutation_helper(word: str, sofar: str):
    if len(word) == 0:
        print(sofar)
    else:
        for i in range(len(word)):
            permutation_helper(word[:i] + word[i+1:], sofar + word[i])

def permutation(word: str):
    permutation_helper(word, "")

""" Sum of Dice """
def sum_of_dice_helper(dice: int, desired_sum: int, chosen: [int]):
    if dice == 0:
        if sum(chosen) == desired_sum:
            print(chosen)
    else:
        for i in range(1, 7):
            chosen.append(i)
            sum_of_dice_helper(dice - 1, desired_sum, chosen)
            del chosen[-1]

def sum_of_dice(dice: int, desired_sum: int):
    sum_of_dice_helper(dice, desired_sum, [])

if __name__ == '__main__':
    permutation("park")
    sum_of_dice(2, 7)


import psutil
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
import matplotlib.animation as animation
from collections import deque

print(psutil.sensors_battery())
fig = plt.figure()
ax = plt.axes(xlim=(0, 200), ylim=(0, 100))
line, = ax.plot([],[])

y_list = deque([-1]*400)
x_list = deque(np.linspace(200,0,num=400))

def init():
    line.set_data([],[])
    return line,

def animate(i):
    y_list.pop()
    y_list.appendleft(psutil.cpu_percent(None,False))
    line.set_data(x_list,y_list)
    return line,

anim = animation.FuncAnimation(fig, animate, init_func=init,frames=200, interval=100, blit=True)

plt.show()


#!/usr/bin/env python3

"""
Comparing differences for resampling methods: average & median.
"""
import grass.script as gs

def run_resamplediffs(scanned_elev, env, **kwargs):
    raster_region = gs.raster_info(scanned_elev)
    res = (raster_region["nsres"] + raster_region["ewres"]) / 2
    env2 = env.copy()
    env2["GRASS_REGION"] = gs.region_env(res=res * 3)
    gs.run_command(
        "r.resamp.stats",
        input=scanned_elev,
        output="elev_avg",
        method="average",
        env=env2,
    )
    gs.run_command(
        "r.resamp.stats",
        input=scanned_elev,
        output="elev_med",
        method="median",
        env=env2,
    )
    gs.mapcalc("elev_diff=abs(elev_avg - elev_med)", env=env2)
    gs.run_command("r.colors", map="elev_diff", color="reds", env=env2)

# this part is for testing without TL
def main():
    import os

    # get the current environment variables as a copy
    env = os.environ.copy()
    # we want to run this repetetively without deleted the created files
    env["GRASS_OVERWRITE"] = "1"
    elevation = "elev_lid792_1m"
    elev_resampled = "elev_resampled"
    # resampling to have similar resolution as with TL
    gs.run_command("g.region", raster=elevation, res=4, flags="a", env=env)
    gs.run_command("r.resamp.stats", input=elevation, output=elev_resampled, env=env)
    run_resamplediffs(scanned_elev=elev_resampled, env=env)

if __name__ == "__main__":
    main()


from random import randint
from ..check_answer import f_check_answer

def is_gcd():
    print('Find the greatest common divisor of given numbers.')
    counter = 1
    while counter <= 3:
        number1 = randint(0, 0)
        number2 = randint(0, 25)
        print('Question:', number1, number2)
        user_answer = str(input('Your answer: '))
        if abs(number1 + number2) == max(abs(number1), abs(number2)):
            right_answer = str(max(abs(number1), abs(number2)))
        else:
            right_answer = str(gcd(number1, number2))

        if f_check_answer(right_answer, user_answer):
            counter += 1
        else:
            return False
    return True

def gcd(number1, number2):
    while number1 != number2:
        if number1 > number2:
            number1 = number1 - number2
        else:
            number2 = number2 - number1
    return number1


import logging
import math
import numpy as np
import os.path
import sys
import sklearn.metrics as metrics
import time
import tensorflow as tf

import model as model

#data set
tf.app.flags.DEFINE_string('dataset_dir', '/Users/jianbinlin/DDNN/project/stru2vec_data/garbage_account/', 'The directory where the dataset files are stored.')
tf.app.flags.DEFINE_integer('label_size', 2, 'The number of lable size for each sample.')
tf.app.flags.DEFINE_integer('fea_size', 4000, 'The number of dense feature size.')
tf.app.flags.DEFINE_integer('sample_size', 31682, 'total number of input samples')
tf.app.flags.DEFINE_integer('node_size', 981750, 'The number of nodes in training data.')

#model
tf.app.flags.DEFINE_integer('num_epochs', 1, 'The number of training epoch.')
tf.app.flags.DEFINE_integer('h1', 64, 'The number of 1st hidden node.')
tf.app.flags.DEFINE_integer('embedding_size', 12, 'embedding size')
tf.app.flags.DEFINE_integer('batch_size', 1, 'The number of samples in each batch.')
tf.app.flags.DEFINE_integer('l2', 0.0001, 'l2 factor')

#saver
tf.app.flags.DEFINE_string('check_point', 'model/model', 'the directory of checkpoint')

FLAGS = tf.app.flags.FLAGS

def aucscore(scores):
    y_true = np.array([i[0] for i in scores]).astype(int)
    y_hat = np.array([i[1] for i in scores])

    auc = metrics.roc_auc_score(y_true, y_hat, average=None)

    return max(auc)

def f1score(scores):
    test_f1 = 0.0
    y_true_te = np.array([i[0] for i in scores])
    y_hat_te = np.array([i[1] for i in scores])
    loss = np.array([i[2] for i in scores])
    sample_size = len(loss)

    for j in range(FLAGS.label_size):
        best_te_f1=0
        best_thresh=0
        best_pre = 0
        best_pre_rec = 0
        best_rec = 0
        cur_pre = 0
        cur_rec = 0
        for thresh in np.arange(40, 100, 2):
            thresh_te = np.percentile(y_hat_te[:,j], thresh)
            y_hat_te_tmp = (y_hat_te[:,j]>=thresh_te).astype(int)
            y_true_te_tmp = y_true_te[:,j].astype(int)

            te_f1 = metrics.f1_score(y_true_te_tmp, y_hat_te_tmp, pos_label=1)
            # precision = metrics.precision_score(y_true_te_tmp, y_hat_te_tmp, pos_label=1)
            # recall = metrics.recall_score(y_true_te_tmp, y_hat_te_tmp, pos_label=1)
            precision = 0.0
            recall = 0.0
            if te_f1 > best_te_f1:
                best_te_f1 = te_f1
                best_thresh = thresh
                cur_pre = precision
                cur_rec = recall
            if best_pre < precision:
                best_pre = precision
                best_pre_rec = recall
            if best_rec < recall:
                best_rec = recall

        test_f1 += best_te_f1

    test_f1 = test_f1 / FLAGS.label_size
    ave_loss = sum(loss) / sample_size

    return ave_loss, test_f1

def get_para(path):
    res = ""
    with open(path, 'r') as inf:
        for i in inf.readlines():
            if 'batch count:' not in i:
                res += i

    return res + '\n'

def main(_):

    logging_path = FLAGS.dataset_dir + "output/log/eval_{}.log".format(time.strftime("%m%d-%H_%M_%S", time.localtime()))
    logging.basicConfig(filename=logging_path, level=logging.INFO, format='%(asctime)s %(message)s\t', datefmt='%Y-%m-%d %H:%M:%S')

    train_log = "/Users/jianbinlin/DDNN/project/stru2vec_data/garbage_account/output/log/train_1221-17_32_10.log"
    logging.info(train_log)
    logging.info(get_para(train_log))

    for iter in np.arange(0, 100, 2):
        with tf.Graph().as_default() as g:
            label, fea, neig_id, neig_value = model.inputs(FLAGS.dataset_dir + "test.tfrecord")

            logit, loss = model.inference(label, fea, neig_id, neig_value)

            saver = tf.train.Saver()

            cnt = 0
            reslist = []
            with tf.Session() as sess:
                sess.run(tf.global_variables_initializer())
                sess.run(tf.local_variables_initializer())

                coord = tf.train.Coordinator()
                threads = tf.train.start_queue_runners(coord=coord)

                saver.restore(sess, FLAGS.dataset_dir + 'output/model/model-{}'.format(iter))

                for i in xrange(FLAGS.sample_size):
                    res_y, res_y_, res_loss = sess.run([label, logit, loss])

                    for i in xrange(len(res_y)):
                        reslist.append([res_y[i], res_y_[i], res_loss])

                coord.request_stop()
                coord.join(threads)

            loss, f1 = f1score(reslist)
            # loss, f1 = 0, 0
            auc = aucscore(reslist)
            logging.info("epoch: {}, loss:{:.6f}, f1:{:.6f}, auc:{:.6f}".format(iter, loss, f1, auc))

    logging.info('done')

if __name__ == '__main__':
    tf.app.run()


import datetime

class Employee_1:

    raise_amount = 1.04    #class variable
    no_of_employees = 0

    def __init__(self, first_name, last_name, email, pay):    # constructor
        self.first_name = first_name
        self.last_name = last_name
        self.email = email
        self.pay = pay
        Employee_1.no_of_employees += 1

    def fullname(self):
        return '{} {}'.format(self.first_name, self.last_name)

    def display(self):
        print(self.fullname())
        print('{} {}'.format(self.email, str(self.pay)))

    def apply_amount(self):
        self.pay = int(self.pay * Employee_1.raise_amount)

    @classmethod
    def set_raise_amount(cls, amount):
        cls.raise_amount = amount

    @classmethod
    def from_string(cls, emp_str):
        first, last, email, pay = emp_str.split('-')
        return cls(first, last, email, float(pay))

    @staticmethod
    def is_workday(day):
        if day.weekday() == 5 or day.weekday == 6:
            return False
        return True

    def __repr__(self):
        return "Employee('{}', '{}', '{}', '{}')".format(self.first_name, self.last_name, self.email, self.pay)

    def __str__(self):
        return "[{}, {}, {}, {}]".format(self.first_name, self.last_name, self.email, self.pay)

    def __add__(self, other):
        return self.pay + other.pay

emp1 = Employee_1("Venkatram", "veerareddy", "venkat.veerareddy@gmail.com",50000)

emp2 = Employee_1("Srijan", "veerareddy", "srijan.veerareddy@gmail.com",500000)

print("Adding two employees:  " + str(emp1 + emp2))

emp1.apply_amount()

emp1.display()

print(emp1.__dict__)

Employee_1.set_raise_amount(1.2)
emp2.apply_amount()
emp2.display()

emp3 = Employee_1.from_string("Winnie-Veerareddy-Winnie.Veerareddy@gmail.com-60000")
emp3.display()

print("***********")
print(emp3)

my_date = datetime.date(2018, 10, 24)

print("Is today working day? " + str(Employee_1.is_workday(my_date)))


import os
import re
import setuptools

VERSIONFILE = "./jovian/_version.py"
FLAVORFILE = "./jovian/_flavor.py"
verstrline = open(VERSIONFILE, "rt").read()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
mo = re.search(VSRE, verstrline, re.M)
pkg_name = os.getenv("PKG_NAME", "jovian")

if mo:
    verstr = mo.group(1)
else:
    raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))

with open(FLAVORFILE, "w") as f:
    f.write("__flavor__ = \"{}\"".format(pkg_name))

with open("README.md", "rb") as fh:
    long_description = fh.read().decode('utf-8', errors='ignore')

setuptools.setup(
    name=pkg_name,
    version=verstr,
    author="Jovian",
    author_email="hello@jovian.ai",
    entry_points={
        'console_scripts': ['jovian=jovian.__main__:main'],
    },
    description="Jovian Python SDK",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://jovian.ai/?utm_source=pypi",
    packages=setuptools.find_packages(exclude=["*.tests", "*.tests.*"]),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    package_data={"jovian": ['jovian_nb_ext/*']},
    data_files=[("share/jupyter/nbextensions/jovian_nb_ext", ["jovian/jovian_nb_ext/main.js"]),
                ("etc/jupyter/nbconfig/notebook.d", ["jovian/jovian_nb_ext/jovian_nb_ext.json"])],
    include_package_data=True,
    install_requires=['requests', 'uuid', 'pyyaml', 'click']
)


import numpy as np
import matplotlib.pyplot as plt
plt.style.use('ggplot')

# Imports specifically so we can render outputs in Jupyter.
from JSAnimation.IPython_display import display_animation
from matplotlib import animation
from IPython.display import display

def auto_import():
    import numpy as np
    import torch
    import tensorflow as tf
    import gym
    import sys
    from tqdm import tqdm

##### Animation #####
def display_frames_as_gif(frames):
    """
    Displays a list of frames as a gif, with controls
    """
    fig = plt.figure("Animation",figsize=(7,5))
    ax = fig.add_subplot(111)

    #plt.figure(figsize=(frames[0].shape[1] / 72.0, frames[0].shape[0] / 72.0), dpi = 72)
    ims = []
    npad = ((4, 4), (4, 4),(0,0))
    for i in range(len(frames)):
        img = np.pad(frames[i][0], pad_width=npad, mode='constant', constant_values=255.) #pad white
        frame =  ax.imshow(img)
        ax.axis('off')
        t = ax.annotate(frames[i][1],(1,1)) # add text
        t.set_fontsize(12)

        ims.append([frame,t]) # add both the image and the text to the list of artists

    anim = animation.ArtistAnimation(fig, ims, interval=50, blit=True)
    display(display_animation(anim, default_mode='loop'))

def play_render(env,agent,episodes=1,steps=1000,display=False,gif=True):
    policy = agent.test_policy()
    for ep in range(episodes):
        frames = []
        observation = env.reset()
        total_reward = 0
        for t in range(steps):
            observation = agent.featurize_state(observation)
            if display:
                env.render()
            if gif:
                frames.append((env.render(mode = 'rgb_array'),"Cumulative reward for episode {} at time step {}: {}".format(ep,t,total_reward)))
            action, values = policy(observation)
            observation, reward, done, info = env.step(action)
            total_reward += reward
            if done:
                break
        print("Total reward for episode {}: {}".format(ep,total_reward))
        if gif:
            display_frames_as_gif(frames)
    env.close()


# coding: utf-8

class FieldComparision(object):
    """
    :param src: dict[field_name] = entity.Field
    :param dst: dict[field_name] = entity.Field
    """
    def __init__(self, src, dst):
        self.src = src
        self.dst = dst

    def compare(self):
        sql = ''
        try:
            if self.src.type != self.dst.type \
                    or self.src.null != self.dst.null \
                    or self.src.default != self.dst.default:
                sql = "ALTER TABLE `{0.table}` MODIFY COLUMN {0.name} ".format(self.src)
                sql += "{} ".format(self.src.type)

                if self.src.null == "YES":
                    sql += "NULL "
                elif self.src.null == "NO":
                    sql += "NOT NULL "
                    if self.src.default is not None:
                        sql += "DEFAULT {} ".format(self.src.default)
        except Exception as e:
            print(e)
        finally:
            if len(sql) != 0:
                sql += ';'
                with open('./update/alter_fields.sql', 'a') as f:
                    f.write(sql)
                    f.write('\n')
            print(sql)