#!/usr/bin/env python3
import re
import sys
import os
import glob

import matplotlib
matplotlib.use('TkAgg')  # Set the backend to TkAgg

import networkx as nx
import matplotlib.pyplot as plt

preprocessor_pattern = re.compile(r'^#[^\n]*|/\*.*?\*/|//.*?$|##|', re.MULTILINE | re.DOTALL)

def remove_preprocessor_content(c_code):
    # 使用正则表达式删除预处理内容
    c_code_cleaned = preprocessor_pattern.sub('', c_code)
    return c_code_cleaned

def remove_comments(c_code):
    # 删除多行注释
    c_code = re.sub(r'/\*.*?\*/', '', c_code, flags=re.DOTALL)
    # 删除单行注释
    c_code = re.sub(r'//.*?$', '', c_code, flags=re.MULTILINE)
    return c_code

def non_func_define_check(text):
    pattern = re.compile(r'\([^)]+\)', re.MULTILINE)
    matches = pattern.findall(text)
    #result = re.findall(r'\((.*?)\)', text)
    for item in matches:
        #print(item)
        items = item.split(',')
        for sub_item in items:
            sub_item = sub_item.strip()
            #print(sub_item)
            if sub_item == 'void' or sub_item == '(void)':
                continue
            elif ' ' in sub_item:
                continue
            else:
                #print("sub_item", sub_item)
                return False, matches
    return True, matches

def non_external_api_check(text):
    pattern = re.compile(r'\([^)]+\)', re.MULTILINE)
    matches = pattern.findall(text)
    #result = re.findall(r'\((.*?)\)', text)
    for item in matches:
        content_inside_brackets = item[1:-1]
        #print(item)
        items = content_inside_brackets.split(',')
        for sub_item in items:
            sub_item = sub_item.strip()
            #print(sub_item)
            if ' ' in sub_item:
                #print("sub_item has space:", sub_item)
                return False, matches
            # else:
            #     #print("sub_item", sub_item)
            #     return False, matches
    return True, matches

def get_external_api(c_code, own_funcs):
    external_api_pattern = re.compile(r'(\w+)\w*\((?:[^()]|\((?:[^()]|)*\))*\)', re.DOTALL)
    external_api_name_pattern = re.compile(r'(\w+)\w*\((?:[^()]|\((?:[^()]|)*\))*\)', re.DOTALL)
    # 使用正则表达式查找函数声明和定义
    external_apis_matches = external_api_pattern.finditer(c_code)

    # 提取函数名称
    external_apis = []
    external_apis_only_name = []
    for match in external_apis_matches:
        function_text = match.group()
        if(function_text.count('(') >= 2):
            #print(function_text)
            first_opening_bracket = function_text.find('(')
            last_closing_bracket = function_text.rfind(')')
            if first_opening_bracket != -1 and last_closing_bracket != -1 and first_opening_bracket < last_closing_bracket:
                content_between_brackets = function_text[first_opening_bracket + 1:last_closing_bracket]
                external_apis_inside, external_apis_only_name_ret = get_external_api(content_between_brackets, own_funcs)
                #print("inside external apis:", external_apis_inside)
                for item in external_apis_inside:
                    if all(func_name != item[0] for func_name, _ in external_apis):
                        if all(func_name != item[0] for func_name, _ in own_funcs):
                            external_apis.append(item)
                            external_apis_only_name.append(item[0])
                #external_apis.extend(external_apis_inside)
        ret, parameters = non_external_api_check(function_text)
        if not ret:
            #print("false:", function_text)
            continue
        #print(function_text)
        name_match = external_api_name_pattern.search(function_text)
        external_api_name = name_match.group(1)
        if all(func_name != external_api_name for func_name, _ in external_apis):
            if all(func_name != external_api_name for func_name, _ in own_funcs):
                external_apis.append((external_api_name, parameters))
                external_apis_only_name.append(external_api_name)
        #functions_inside = function_text

    return external_apis, external_apis_only_name

if len(sys.argv) != 2:
    print("Usage: python extract_functions.py your_c_file.c")
    sys.exit(1)

test_file = sys.argv[1]

# 用于匹配C函数声明和定义的正则表达式
#function_pattern = re.compile(r'\w+\s+\w+\s*\(.*?\)\s*{[^{}]*}', re.DOTALL)
#function_pattern = re.compile(r'(\w+)\S*\([^)]*\)\s*{', re.DOTALL)
function_pattern = re.compile(r'(\w+)\S*\((?:[^()]|\((?:[^()]|)*\))*\)\s*{', re.DOTALL)

# 用于从函数声明和定义中提取函数名称的正则表达式
#name_pattern = re.compile(r'\w+\s+(\w+)\s*\(.*?\)', re.DOTALL)
#name_pattern = re.compile(r'(\w+)\S*\([^)]*\)', re.DOTALL)
name_pattern = re.compile(r'(\w+)\S*\((?:[^()]|\((?:[^()]|)*\))*\)', re.DOTALL)

# 指定要枚举的目录路径
dir_files = ['/home/evers/jemalloc/src/*.c','/home/evers/jemalloc/include/jemalloc/*.h','/home/evers/jemalloc/include/jemalloc/internal/*.h']
#dir_files = ['/home/evers/jemalloc/src/*.c']

# 使用 os.listdir() 列出目录中的文件和子目录

depedences = []

for pattern in dir_files:
    matched_files = glob.glob(pattern)
    #print(matched_files)
    for source_file in matched_files:
        #print(source_file)
        parts = source_file.split('/')
        #module_name = parts[-2] +'-'+ parts[-1].replace('.', '_')
        #module_name = parts[-2] +'/'+ parts[-1]
        module_name = parts[-1]
        print(source_file, module_name)

        #sys.exit(1)
        try:
            # 打开C文件
            with open(source_file, 'r') as file:
                c_code = file.read()
                c_code = remove_comments(c_code)
                c_code = remove_preprocessor_content(c_code)
                #print(c_code)

            # 使用正则表达式查找函数声明和定义
            function_matches = function_pattern.finditer(c_code)

            # 提取函数名称
            #print(function_matches)
            function_names_with_para = []
            function_names = []
            for match in function_matches:
                #print(match)
                function_text = match.group()
                ret, parameters = non_func_define_check(function_text)
                if not ret:
                    continue
                #print(function_text)
                name_match = name_pattern.search(function_text)
                if name_match:
                    function_name = name_match.group(1)
                    if all(func_name != function_name for func_name, _ in function_names_with_para):
                        function_names_with_para.append((function_name, parameters))
                        function_names.append(function_name)
                    #print("Function Name:", function_name, "\n\n")

            external_apis, external_apis_only_name = get_external_api(c_code, function_names_with_para)

            #for name in function_names:
                #print("func impl: ", name)
            print("func impl len=", len(function_names))

            #for name in external_apis:
                #print("external api:", name)
            print("external api len=", len(external_apis))
            depedences.append((module_name, function_names, external_apis_only_name))
            print("")

        except FileNotFoundError:
            print(f"Error: File '{source_file}' not found.")
            sys.exit(1)

func_impls = []
for depedence in depedences:
    functions = depedence[1]
    for function in functions:
        matching_mods = [mod for func, mod in func_impls if func == function]
        if matching_mods:
            continue
            #print(function, "from " + depedence[0] + " already in func_impls from " + matching_mods[0])
        else:
            func_impls.append((function, depedence[0]))
            print(function, depedence[0])

print("func_impls len=", len(func_impls))
#print(func_impls)

# 创建一个有向图
G = nx.DiGraph()
mod_dependencies = []

parts = test_file.split('/')
module_name = parts[-1]
modules_g = []

with open(test_file, 'r') as file:
    c_code = file.read()
    c_code = remove_comments(c_code)
    c_code = remove_preprocessor_content(c_code)
external_apis, external_apis_only_names = get_external_api(c_code, function_names_with_para)
print(external_apis_only_names)
# for depedence in depedences:
#     external_apis = depedence[2]
for external_apis_only_name in external_apis_only_names:
    matching_mods = [mod for func, mod in func_impls if func == external_apis_only_name]
    print(external_apis_only_name, matching_mods)
    if matching_mods:
        if (module_name, matching_mods[0]) not in mod_dependencies:
            mod_dependencies.append((module_name, matching_mods[0]))
            modules_g.append(matching_mods[0])
        if module_name not in modules_g:
            modules_g.append(module_name)
    # else:
    #     print("ERROR:", external_api, "not found in func_impls")

# 添加模块节点

center_node = module_name

print("mod_dependencies len=", len(mod_dependencies))
print("modules_g len=", len(modules_g))
#print("func_impls", list(func_impls))
G.add_nodes_from(modules_g)
G.add_edges_from(mod_dependencies)

# 绘制图形
pos = nx.circular_layout(G, scale=1)

if len(pos) > 2:
    pos[center_node] = [0, 0]
    x_offset = 0
    y_offset = 0

    for node in pos:
        if node != center_node:
            x_offset += pos[node][0]
            y_offset += pos[node][1]

    x_offset = x_offset/(len(pos) -1)
    y_offset = y_offset/(len(pos) -1)
    pos[center_node] = [x_offset, y_offset]

print(pos)

nx.draw(G, pos, with_labels=True, node_size=2000, node_color='lightblue', font_size=10, font_weight='bold', arrows=True)
plt.title(module_name + '模块依赖图')
plt.show()


"""
132 Palindrome Partitioning II

Given a string s, partition s such that every substring of the partition is a palindrome.

Return the minimum cuts needed for a palindrome partitioning of s.

For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.
"""
class Solution:

    # The best solution is not using DP to get the palindrome matrix, but iterate all centers of substrings then check if the substring is palindrome
    # https://leetcode.com/problems/palindrome-partitioning-ii/discuss/42198/my-solution-does-not-need-a-table-for-palindrome-is-it-right-it-uses-only-on-space
    # time O(n^2), space O(n)
    def minCut(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        if n < 2:
            return 0

        minCuts = [l - 1 for l in range(n+1)]   # number of cuts for substring s[0:i] with lenth l, initialized with worst case

        for i in range(n):  # iterate all center letters

            # odd length substring with s[i] as center letter
            j = 0
            while j <= i and i + j < n and s[i-j] == s[i+j]:
                minCuts[i+j+1] = min(minCuts[i+j+1], 1 + minCuts[i-j])
                j += 1

            # even length substring with s[i] as last letter in left half
            j = 1
            while j <= i+1 and i + j < n and s[i-j+1]==s[i+j]:
                minCuts[i+j+1] = min(minCuts[i+j+1], 1 + minCuts[i-j+1])
                j += 1

        return minCuts[n]

    # 2nd try, DP, time O(n^2), space O(n^2), http://fisherlei.blogspot.com/2013/03/leetcode-palindrome-partitioning-ii.html
    def minCut2(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        if n < 2:
            return 0

        minCuts = [n - i - 1 for i in range(n+1)]   # minCuts[i] represents the min cuts for substring s[i:]. Initialize this list with worst case cuts

        # Get the palindrome matrix, see problem 5, longest palindromic substring
        P = [[True for j in range(n)] for i in range(n)]
        for i in range(n-2, -1, -1):
            for j in range(i+1, n):
                P[i][j] = P[i+1][j-1] and (s[i] == s[j])
                if P[i][j]:
                    minCuts[i] = min(minCuts[i], 1 + minCuts[j+1])  # here "1" represents the cut to separate string s[i, j] and s[j+1, n-1], we can cut here because s[i, j] is palindromic

        return minCuts[0]

    # 1st try, DP + BFS, got TLE
    def minCut4(self, s):
        """
        :type s: str
        :rtype: int
        """
        n = len(s)
        if n < 2:
            return 0

        # Get the palindrome matrix, see problem 5, longest palindromic substring
        P = [[True for j in range(n)] for i in range(n)]
        for i in range(n-2, -1, -1):
            for j in range(i+1, n):
                P[i][j] = P[i+1][j-1] and (s[i] == s[j])

        # BFS to find the minimum cuts
        cuts = 0
        queue = [0] # start index of next palindrome substring

        while len(queue) > 0:
            next_queue = []
            for i in queue:
                for j in range(i, n):
                    if P[i][j]:
                        if j == n-1:
                            return cuts
                        else:
                            next_queue.append(j+1)

            queue = next_queue
            cuts += 1

        return cuts # ideally this return statement should not be called, instead the function will return inside the while loop

obj = Solution()
test_cases = ['','a','ab','aaaa','aba','abda']
for case in test_cases:
    print(case + ' -> ', end='')
    print(obj.minCut2(case))


#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
@author RenMeng
@since 2022/4/17
'''

from typing import List
class Solution:
    def maxTrailingZeros(self, grid: List[List[int]]) -> int:
        m = len(grid)
        n = len(grid[0])

        dp_row = [[[0, 0, 0] for _ in range(n + 1)] for _ in range(m + 1)]
        dp_col = [[[0, 0, 0] for _ in range(n + 1)] for _ in range(m + 1)]

        for i in range(1, m+1):
            for j in range(1, n+1):
                cur = grid[i - 1][j - 1]
                while cur % 10 == 0:
                    dp_row[i][j][2] += 1
                    dp_col[i][j][2] += 1
                    cur = cur % 10
                while cur % 2 == 0:
                    cur = cur // 2
                    dp_row[i][j][0] += 1
                    dp_col[i][j][0] += 1
                while cur % 5 == 0:
                    cur = cur // 5
                    dp_row[i][j][1] += 1
                    dp_col[i][j][1] += 1

                for k in range(3):
                    dp_row[i][j][k] += dp_row[i][j - 1][k]
                    dp_col[i][j][k] += dp_col[i - 1][j][k]

                dp_row[i][j][2] += min(dp_row[i][j][0], dp_row[i][j][1])
                dp_row[i][j][1] -= min(dp_row[i][j][0], dp_row[i][j][1])
                dp_row[i][j][0] -= min(dp_row[i][j][0], dp_row[i][j][1])

                dp_col[i][j][2] += min(dp_col[i][j][0], dp_col[i][j][1])
                dp_col[i][j][1] -= min(dp_col[i][j][0], dp_col[i][j][1])
                dp_col[i][j][0] -= min(dp_col[i][j][0], dp_col[i][j][1])

        for i in range(m):
            for j in range(n):
                cur = grid[i][j]
                if cur % 10 == 0 or cur % 5 == 0:
                    for k in range(4):
                        pass


from django.contrib.auth import get_user_model
from django.core.files import temp
from django.core.serializers.json import DjangoJSONEncoder
from django.db.models import Count, Sum
from rest_framework import serializers
from rest_framework.utils import json

from yourstar.models import *
import math

class StarSerializer(serializers.ModelSerializer):
    type = serializers.StringRelatedField()

    class Meta:
        model = Star
        fields = ('id', 'name', 'type',  'image',  'description')

class ScoreNameSerializer(serializers.ModelSerializer):
    # type = serializers.StringRelatedField()

    class Meta:
        model = ScoreName
        fields = ('id', 'type', 'score_name')

class StarScoresSerializer(serializers.ModelSerializer):
    score_name = ScoreNameSerializer(many=False, read_only=True)

    class Meta:
        model = StarScores
        fields = '__all__'

class EvalScoreSerializer(serializers.ModelSerializer):
    score_list = serializers.SerializerMethodField()
    overall = serializers.SerializerMethodField()

    def get_score_list(self, obj):
        total_scores = []
        score_elements = ScoreName.objects.filter(type=obj.star.type_id)

        for element in score_elements:
            score_sum = StarScores.objects.filter(id=element.id).aggregate(total_score=Sum('score'))
            score_count = StarScores.objects.filter(score_name__id=element.id).aggregate(total_count=Count('score'))
            test = StarScores.objects.filter(star__id=obj.star.id).aggregate(total_count=Sum('score'))
            print(test)

            total_scores.append({
                "score": 90,
                "element": element.score_name,
                "element_id": element.id
            })

        return total_scores

    def get_overall(self, obj):
        score_sum = StarScores.objects.filter(star__id=obj.star.id).aggregate(total_score=Sum('score'))
        score_count = StarScores.objects.filter(star__id=obj.star.id).aggregate(total_count=Count('score'))

        if score_sum['total_score'] != None:
            overall = round(score_sum['total_score'] / score_count['total_count'])
        else:
            overall = 0

        return overall

    class Meta:
        model = StarScores
        fields = '__all__'

class EvaluationSerializer(serializers.ModelSerializer):
    star_score = EvalScoreSerializer(many=False, read_only=True)

    total_score = serializers.SerializerMethodField()
    total_count = serializers.SerializerMethodField()
    star = StarSerializer(many=False, read_only=True)

    class Meta:
        model = Evaluation
        fields = ('id', 'total_score', 'total_count', 'star_score', 'star', 'feed', 'user')

    def get_total_score(self, obj):
        total_score = StarScores.objects.all().aggregate(total_score=Sum('score'))
        return total_score["total_score"]

    def get_total_count(self, obj):
        total_count = StarScores.objects.all().aggregate(total_count=Count('score'))
        return total_count["total_count"]

class StarScoresIdSerializer(serializers.ModelSerializer):

    class Meta:
        model = StarScores
        fields = ('id', 'score', 'score_name', 'star')

class EventStarSerializer(serializers.ModelSerializer):

    class Meta:
        model = EventStarList
        fields = ('id', 'event', 'star')

class TypeSerializer(serializers.ModelSerializer):

    class Meta:
        model = StarType
        fields = ('id', 'type')

class EventSerializer(serializers.ModelSerializer):

    class Meta:
        model = Event
        fields = ('id', 'date', 'title', 'image', 'description')

class EventDetailSerializer(serializers.ModelSerializer):
    star_list = StarSerializer(many=True, read_only=True)

    class Meta:
        model = Event
        fields = ('id', 'date', 'title', 'image', 'description', 'star_list')

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        User = get_user_model()
        model = User
        fields = ('id', 'username')

class YourUserSerializer(serializers.ModelSerializer):
    user_star_score = serializers.SerializerMethodField()
    # user = UserSerializer(many=False, read_only=True)

    def get_user_star_score(self, obj):
        # total_scores = []

        user_star_scores = Evaluation.objects.filter(user__id=obj.id)[:3]
        # user_star_scores = User.objects.filter(id=obj.id)[:3]
        # total_scores.append(user_star_scores)
        serial = EvaluationSerializer(user_star_scores, many=True)
        return serial.data

    class Meta:
        model = YourUser
        # fields = '__all__'
        fields = ('id', 'username', 'image', 'description', 'user_star_score')

class SignUpSerializer(serializers.ModelSerializer):
    class Meta:
        model = YourUser
        fields = ('username', 'password')
        extra_kwargs = {
            'password': {'write_only': True},
        }

    def create(self, validated_data):
        user = YourUser(
            username=validated_data['username']
        )
        user.set_password(validated_data['password'])
        user.save()
        return user

class StarEvalSerializer(serializers.ModelSerializer):
    # score_name = ScoreNameSerializer(many=False, read_only=True)
    score_list = serializers.SerializerMethodField()
    overall = serializers.SerializerMethodField()
    user = UserSerializer(many=False, read_only=True)

    def get_score_list(self, obj):
        total_scores = []
        score_elements = ScoreName.objects.filter(type=obj.instance.type_id)

        for element in score_elements:
            score_sum = StarScores.objects.filter(score_name__id=element.id).aggregate(total_score=Sum('score'))
            score_count = StarScores.objects.filter(score_name__id=element.id).aggregate(total_count=Count('score'))
            test = StarScores.objects.filter(star__id=obj.instance.id).aggregate(total_count=Sum('score'))
            print(test)

            total_scores.append({
                "average": round(score_sum['total_score'] / score_count['total_count']),
                "total_score": score_sum['total_score'],
                "total_count": score_count['total_count'],
                "element": element.score_name,
                "id": element.id
            })

        return total_scores

    def get_overall(self, obj):
        score_sum = StarScores.objects.filter(star__id=obj.instance.id).aggregate(total_score=Sum('score'))
        score_count = StarScores.objects.filter(star__id=obj.instance.id).aggregate(total_count=Count('score'))

        if score_sum['total_score'] != None:
            overall = round(score_sum['total_score'] / score_count['total_count'])
        else:
            overall = 0

        return overall

    class Meta:
        model = StarScores
        fields = '__all__'

class StarDetailSerializer(serializers.ModelSerializer):

    events = EventSerializer(many=True, read_only=True)
    score_list = StarEvalSerializer(many=False, read_only=True)
    star_eval = serializers.SerializerMethodField()

    def get_star_eval(self, obj):
        star_evals = Evaluation.objects.filter(star__id=obj.id)[:3]
        serial = EvaluationSerializer(star_evals, many=True)
        return serial.data

    class Meta:
        model = Star
        fields = ('id', 'name', 'image', 'description', 'type', 'events', 'score_list', 'star_eval')


import html2tk
from time import sleep

html = '''

<title>Happiness Program</title>

Happiness Program

Background color of app:

<input id="color" type="color">

<input id="name" placeholder="Enter your name">

How would you rate your happiness?

<input id="happiness" type="range" increment="20" value="50">

Is what you just said true?

<input id="truth" type="checkbox" checked>

<button id="submitButton">Submit</button>

'''

css = '''
heading1 {
    font-size: 30;
    color: red;
}

heading2 {
    font-size: 20;
    color: blue;
}

paragraph {
    color: purple;
}

input {
    color: purple;
    background-color: green;
}

button {
    color: yellow;
}
'''

global app

def test_application():
    global app
    print('') # because pytest doesn't put a newline after their strings

    app = html2tk.Application()
    stylesheet = html2tk.Stylesheet(css=css)
    app.set_stylesheet(stylesheet)
    app.maximize()
    app.add_html(html) # add html after applying stylesheet

    app.get_element_by_id('submitButton').command = calc_happiness
    app.get_element_by_id('color').add_callback(update_background)

    app.mainloop()

def update_background():
    app.set_background(app.get_element_by_id('color').value)

def calc_happiness():
    app.get_element_by_id('output').text = 'Thinking...'
    app.update()
    sleep(1)

    happiness = app.get_element_by_id('happiness').value
    if app.get_element_by_id('truth').checked == False:
        happiness = 100 - happiness

    result = app.get_element_by_id('name').value.capitalize() + ', '
    if happiness < 10:
        result += 'you are EXTREMELY sad!'
    elif happiness < 25:
        result += 'you are pretty sad'
    elif happiness < 50:
        result += 'you might be a little bit sad, but you\'re probably just stressed'
    elif happiness < 75:
        result += 'you have an acceptable level of happiness'
    elif happiness < 90:
        result += 'you\'re pretty happy'
    else:
       result += 'you are too happy!'

    app.get_element_by_id('output').text = result

if __name__ == '__main__':
    test_application()


def count_even_odd_elements(arr):
    even_count = 0
    odd_count = 0

    for num in arr:
        if num % 2 == 0:
            even_count += 1
        else:
            odd_count += 1

    return even_count, odd_count

# Get the size of the array from the user
size = int(input("Enter the size of the array: "))

# Get the elements of the array from the user
print("Enter the elements:")
arr = list(map(int, input().split()))

# Count the number of even and odd elements
even_count, odd_count = count_even_odd_elements(arr)

# Print the result
print("Number of even elements:", even_count)
print("Number of odd elements:", odd_count)


import threading
import cv2
import numpy as np
from pykeyboard import PyKeyboardEvent
from PyQt5.QtCore import pyqtSignal, QObject

from image_detect.detect import Detector
from auto_position_label.crop_position import screen_position
from all_states import All_States, gun_next_mode
from press_gun.press import Press
from screen_capture import win32_cap

class Temp_QObject(QObject):
    state_str_signal = pyqtSignal(str)

class Key_Listener(PyKeyboardEvent):
    def __init__(self, all_states):
        PyKeyboardEvent.__init__(self)

        self.all_states = all_states
        self.mistake_counter = 0
        self.screen = None

        self.fire_mode_detect = Detector('fire_mode')
        self.in_tab_detect = Detector('in_tab')
        # self.in_scope_detect = Detector('in_scope')

        self.weapon1name_detect = Detector('weapon1name')
        self.weapon1scope_detect = Detector('weapon1scope')
        self.weapon1muzzle_detect = Detector('weapon1muzzle')
        self.weapon1grip_detect = Detector('weapon1grip')
        self.weapon1butt_detect = Detector('weapon1butt')

        self.weapon2name_detect = Detector('weapon2name')
        self.weapon2scope_detect = Detector('weapon2scope')
        self.weapon2muzzle_detect = Detector('weapon2muzzle')
        self.weapon2grip_detect = Detector('weapon2grip')
        self.weapon2butt_detect = Detector('weapon2butt')

        self.temp_qobject = Temp_QObject()

    def tap(self, keycode, character, press):
        if keycode == 9 and press:  # tab
            threading.Timer(0.001, self.tab_func).start()

        if keycode == 66 and press:  # b
            self.all_states.dont_press = False
            threading.Timer(0.2, self.b_func).start()

        if keycode == 49 and press:  # 1
            n_change = self.all_states.set_weapon_n(0)
            if n_change:
                self.print_state()

        if keycode == 50 and press:  # 2
            n_change = self.all_states.set_weapon_n(1)
            if n_change:
                self.print_state()

        if keycode == 71 and press:  # g
            self.all_states.dont_press = True

        if keycode == 119 and press:  # F8
            self.all_states.dont_press = True

        if keycode == 122 and press:  # F11
            if not self.all_states.dont_press:
                n = self.all_states.weapon_n
                self.press = Press(self.all_states.weapon[n].dist_seq, self.all_states.weapon[n].time_seq)
                self.press.start()

        if keycode == 123 and not press:  # F12
            if not self.all_states.dont_press:
                if self.press.is_alive():
                    self.press.stop()

    def escape(self, event):
        return False

    def tab_func(self):
        self.all_states.dont_press = True
        if 'in' == self.in_tab_detect.diff_sum_classify(get_screen('in_tab')):
            self.all_states.dont_press = False

            crop = get_screen('weapon1name')
            res = self.weapon1name_detect.diff_sum_classify(crop)
            w1n_change = self.all_states.weapon[0].set_name(res)

            crop = get_screen('weapon1scope')
            res = self.weapon1scope_detect.diff_sum_classify(crop, absent_return="1")
            w1s_change = self.all_states.weapon[0].set_scope(res)

            crop = get_screen('weapon1muzzle')
            res = self.weapon1muzzle_detect.diff_sum_classify(crop)
            w1m_change = self.all_states.weapon[0].set_scope(res)

            crop = get_screen('weapon1grip')
            res = self.weapon1grip_detect.diff_sum_classify(crop)
            w1g_change = self.all_states.weapon[0].set_scope(res)

            crop = get_screen('weapon1butt')
            res = self.weapon1butt_detect.diff_sum_classify(crop)
            w1b_change = self.all_states.weapon[0].set_scope(res)

            if w1n_change or w1s_change or w1m_change or w1g_change or w1b_change:
                self.all_states.weapon[0].set_seq()

            crop = get_screen('weapon2name')
            res = self.weapon2name_detect.diff_sum_classify(crop)
            w2n_change = self.all_states.weapon[1].set_name(res)

            crop = get_screen('weapon2scope')
            res = self.weapon2scope_detect.diff_sum_classify(crop, absent_return="1")
            w2s_change = self.all_states.weapon[1].set_scope(res)

            crop = get_screen('weapon2muzzle')
            res = self.weapon2muzzle_detect.diff_sum_classify(crop)
            w2m_change = self.all_states.weapon[1].set_scope(res)

            crop = get_screen('weapon2grip')
            res = self.weapon2grip_detect.diff_sum_classify(crop)
            w2g_change = self.all_states.weapon[1].set_scope(res)

            crop = get_screen('weapon2butt')
            res = self.weapon2butt_detect.diff_sum_classify(crop)
            w2b_change = self.all_states.weapon[1].set_scope(res)

            if w2n_change or w2s_change or w2m_change or w2g_change or w2b_change:
                self.all_states.weapon[1].set_seq()

            if w1n_change or w1s_change or w2n_change or w2s_change:
                self.print_state()

    def b_func(self):
        fire_mode_crop = get_screen('fire_mode')
        fire_mode = self.fire_mode_detect.canny_classify(fire_mode_crop)
        n = self.all_states.weapon_n
        fm_change =  self.all_states.weapon[n].set_fire_mode(fire_mode)
        if fm_change:
            self.print_state()

    def print_state(self):
        n = self.all_states.weapon_n
        w = self.all_states.weapon[0]
        gun1_state = str(w.name) + '-' + str(w.scope) + '-' + str(w.fire_mode)
        w = self.all_states.weapon[1]
        gun2_state = str(w.name) + '-' + str(w.scope) + '-' + str(w.fire_mode)
        if n == 0:
            emit_str = ' * ' + gun1_state + '\n' + gun2_state
        else:
            emit_str = gun1_state + '\n' + ' * ' + gun2_state

        print('----------------')
        print(emit_str)
        self.temp_qobject.state_str_signal.emit(emit_str)

def get_screen(name):
    pos = screen_position[name]
    temp_fold = 'D:/github_project/auto_press_down_gun/press_gun/temp_image/'
    im = win32_cap(temp_fold + name + '.png', pos)
    return im

if __name__ == '__main__':
    all_states = All_States()
    k = Key_Listener(all_states)
    k.run()


#!/usr/bin/env python3

# adapted from https://github.com/MycroftAI/mimic3/blob/be72c18/mimic3_tts/__main__.py

import argparse
import queue
import signal
import shlex
import shutil
import subprocess
import tempfile
import threading
import time

import mimic3_tts
import yarp
import roboticslab_speech

PLAY_PROGRAMS = ['paplay', 'play -q', 'aplay -q']

class TextToSpeechResponder(roboticslab_speech.SpeechSynthesis):
    def __init__(self, engine):
        super().__init__()
        self.engine = engine
        self.is_playing = False
        self.p = None
        self.result_queue = queue.Queue(maxsize=5)
        self.result_thread = threading.Thread(target=self._process_result, daemon=True)
        self.result_thread.start()

    def setLanguage(self, language):
        if language.startswith('#'):
            # same voice, different speaker
            self.engine.speaker = language[1:]
        else:
            # different voice
            self.engine.voice = language

        if self.engine.voice not in list(self.getSupportedLangs()):
            print('Voice not available: %s' % self.engine.voice)
            return False
        else:
            self.engine.preload_voice(self.engine.voice)
            print('Loaded voice: %s (speaker: %s)' % (self.engine.voice, self.engine.speaker or 'default'))
            return True

    def setSpeed(self, speed):
        self.engine.rate = float(speed) / 100
        return True

    def setPitch(self, pitch):
        return super().setPitch(pitch)

    def getSpeed(self):
        return int(self.engine.rate * 100)

    def getPitch(self):
        return super().getPitch()

    def getSupportedLangs(self):
        all_voices = sorted(list(self.engine.get_voices()), key=lambda v: v.key)
        local_voices = filter(lambda v: not v.location.startswith('http'), all_voices)
        available_voices = [v.key for v in local_voices]
        return yarp.SVector(available_voices)

    def say(self, text):
        self.engine.begin_utterance()
        self.engine.speak_text(text)

        for result in self.engine.end_utterance():
            self.result_queue.put(result)

        return True

    def play(self):
        return super().play()

    def pause(self):
        return super().pause()

    def stop(self):
        if self.p:
            self.p.terminate()

        return True

    def checkSayDone(self):
        return not self.is_playing

    def _process_result(self):
        while True:
            result = self.result_queue.get()

            if result is None:
                break

            wav_bytes = result.to_wav_bytes()

            if not wav_bytes:
                continue

            with tempfile.NamedTemporaryFile(mode='wb+', suffix='.wav') as wav_file:
                wav_file.write(wav_bytes)
                wav_file.seek(0)

                for play_program in reversed(PLAY_PROGRAMS):
                    play_cmd = shlex.split(play_program)

                    if not shutil.which(play_cmd[0]):
                        continue

                    play_cmd.append(wav_file.name)
                    self.is_playing = True

                    with subprocess.Popen(play_cmd) as self.p:
                        try:
                            self.p.wait()
                        except: # e.g. on keyboard interrupt
                            self.p.kill()

                    self.is_playing = False
                    break

parser = argparse.ArgumentParser(prog='speechSynthesis', description='TTS service running a Mimic 3 engine')
parser.add_argument('--voice', '-v', help='Name of voice (expected in <voices-dir>/<language>)', required=True)
parser.add_argument('--speaker', '-s', help='Name or number of speaker (default: first speaker)')
parser.add_argument('--noise-scale', type=float, help='Noise scale [0-1], default is 0.667')
parser.add_argument('--length-scale', type=float, help='Length scale (1.0 is default speed, 0.5 is 2x faster)')
parser.add_argument('--noise-w', type=float, help='Variation in cadence [0-1], default is 0.8')
parser.add_argument('--cuda', action='store_true', help='Use Onnx CUDA execution provider (requires onnxruntime-gpu)')
parser.add_argument('--port', '-p', default='/speechSynthesis', help='YARP port prefix')

args = parser.parse_args()

tts = mimic3_tts.Mimic3TextToSpeechSystem(
    mimic3_tts.Mimic3Settings(
        length_scale=args.length_scale,
        noise_scale=args.noise_scale,
        noise_w=args.noise_w,
        use_cuda=args.cuda,
    )
)

tts.voice = args.voice
tts.speaker = args.speaker

print('Preloading voice: %s' % args.voice)
tts.preload_voice(args.voice)

yarp.Network.init()

if not yarp.Network.checkNetwork():
    print('YARP network not found')
    raise SystemExit

rpc = yarp.RpcServer()
processor = TextToSpeechResponder(tts)

if not rpc.open(args.port + '/rpc:s'):
    print('Cannot open port %s' % rpc.getName())
    raise SystemExit

processor.yarp().attachAsServer(rpc)

quitRequested = False

def askToStop():
    global quitRequested
    quitRequested = True

signal.signal(signal.SIGINT, lambda signal, frame: askToStop())
signal.signal(signal.SIGTERM, lambda signal, frame: askToStop())

while not quitRequested:
    time.sleep(0.1)

rpc.interrupt()
rpc.close()

processor.result_queue.put(None)
processor.result_thread.join()


#!/usr/bin/env python

from tthAnalysis.HiggsToTauTau.configs.projectionConfig import projectionConfig, validate_pu
from tthAnalysis.HiggsToTauTau.jobTools import query_yes_no
from tthAnalysis.HiggsToTauTau.runConfig import tthAnalyzeParser, filter_samples
from tthAnalysis.HiggsToTauTau.common import logging, load_samples

import os
import sys
import getpass
import collections
import itertools

# E.g.: ./test/tthProjection.py -v 2018May09 -e 2017 -m all -p pileup
#       ./test/tthProjection.py -v 2018May09 -e 2017 -m all -p btagSF -j 4
#       ./test/tthProjection.py -v 2018May09 -e 2017 -m all -p count  j "4,cat:ttH:1,cat:TT:1,cat:EWK:1"

mode_choices = [ 'all', 'tth', 'tth_sync', 'hh', 'hh_bbww', 'hh_bbww_sync', 'hh_bbww_ttbar', 'hh_bbww_sync_ttbar' ]
projections = [ 'pileup', 'btagSF', 'btagSFSL', 'count', 'subjetCount' ]
default_output = '{projection}_{era}.root'

parser = tthAnalyzeParser(default_num_parallel_jobs = 100)
parser.add_modes(mode_choices)
parser.add_files_per_job(100)
parser.add_use_home()
parser.add_argument('-p', '--project',
  type = str, dest = 'project', metavar = 'choice', choices = projections, required = True,
  help = 'R|Type of job',
)
parser.add_argument('-P', '--plot',
  dest = 'plot', action = 'store_true', default = False,
  help = 'R|Make plots (not supported for btagSF projection)',
)
parser.add_argument('-V', '--validate',
  dest = 'validate', action = 'store_true', default = False,
  help = 'R|Validate the results',
)
parser.add_argument('-o', '--output-file',
  type = str, dest = 'output_file', metavar = 'filename', default = default_output,
  required = False,
  help = 'R|File name of the output file',
)
args = parser.parse_args()

# Common arguments
era                = args.era
version            = args.version
dry_run            = args.dry_run
no_exec            = args.no_exec
auto_exec          = args.auto_exec
check_output_files = not args.not_check_input_files
sample_filter      = args.filter
num_parallel_jobs  = args.num_parallel_jobs
running_method     = args.running_method
keep_logs          = args.keep_logs

# Additional arguments
mode          = args.mode
projection    = args.project
files_per_job = args.files_per_job
plot          = args.plot
validate      = args.validate
use_home      = args.use_home

# Custom arguments
output_file = args.output_file

# Use the arguments
if output_file == default_output:
  output_file = output_file.format(projection = projection, era = era)
version = "%s_%s" % (version, mode)

if projection == 'pileup':
  projection_module = "puHist"

  if mode == 'all':
    samples = load_samples(era, False, base = 'all')
  elif mode == 'tth':
    samples = load_samples(era, False)
  elif mode == 'tth_sync':
    samples = load_samples(era, False, suffix = 'sync')
  elif mode == 'hh':
    samples = load_samples(era, False, base = 'hh_multilepton')
  elif mode == 'hh_bbww':
    samples = load_samples(era, False, base = 'hh_bbww')
  elif mode == 'hh_bbww_ttbar':
    samples = load_samples(era, False, base = 'hh_bbww', suffix = 'ttbar')
  elif mode in ['hh_bbww_sync', 'hh_bbww_nonres_sync']:
    sync = 'sync' if mode == 'hh_bbww_sync' else 'nonres_sync'
    samples = load_samples(era, False, base = 'hh_bbww', suffix = sync)
  elif mode == 'hh_bbww_sync_ttbar':
    samples = load_samples(era, False, base = 'hh_bbww', suffix = 'sync_ttbar')
  else:
    raise ValueError('Invalid mode: %s' % mode)
elif projection in [ 'btagSF', 'btagSFSL', 'count', 'subjetCount' ]:
  if projection == 'btagSF':
    projection_module = "btagSFRatio"
  elif projection == 'btagSFSL':
    projection_module = "btagSFRatioSL"
  elif projection == 'count':
    projection_module = 'count'
  elif projection == 'subjetCount':
    projection_module = 'subJetBtagCounter'
  else:
    assert(False)

  if mode == 'all':
    samples = load_samples(era, True, base = 'all')
  elif mode == 'tth':
    samples = load_samples(era, True, suffix = 'base')
  elif mode == 'tth_sync':
    samples = load_samples(era, True, suffix = 'sync')
  elif mode == 'hh':
    samples = load_samples(era, True, base = 'hh_multilepton', suffix = 'hh')
  elif mode == 'hh_bbww':
    samples = load_samples(era, True, base = 'hh_bbww', suffix = 'hh')
  elif mode == 'hh_bbww_ttbar':
    samples = load_samples(era, True, base = 'hh_bbww', suffix = 'ttbar')
  elif mode == 'hh_bbww_sync':
    samples = load_samples(era, True, base = 'hh_bbww', suffix = 'sync')
  elif mode == 'hh_bbww_sync_ttbar':
    samples = load_samples(era, True, base = 'hh_bbww', suffix = 'sync_ttbar')
  else:
    raise ValueError('Invalid mode: %s' % mode)
else:
  raise ValueError('Invalid projection: %s' % projection)

for sample_name, sample_entry in samples.items():
  if sample_name == 'sum_events':
    continue
  sample_entry['use_it'] = sample_entry['type'] != 'data'

if __name__ == '__main__':
  if sample_filter:
    samples = filter_samples(samples, sample_filter)
  if 'sum_events' in samples:
    del samples['sum_events']

  projection_dir = 'ttH{}Projection'.format(projection.capitalize())
  configDir = os.path.join("/scratch/persistent", getpass.getuser(), projection_dir, era, version)
  localDir  = os.path.join("/home",               getpass.getuser(), projection_dir, era, version)
  outputDir = os.path.join("/local",              getpass.getuser(), projection_dir, era, version)

  if validate and projection == 'pileup':
    validation_result = validate_pu(os.path.join(outputDir, output_file), samples)
    sys.exit(validation_result)

  projectionJobs = projectionConfig(
    configDir          = configDir,
    localDir           = localDir,
    outputDir          = outputDir,
    output_file        = output_file,
    executable         = "projectHistogram.sh",
    projection_module  = projection_module,
    samples            = samples,
    max_files_per_job  = files_per_job,
    era                = era,
    plot               = plot,
    check_output_files = check_output_files,
    running_method     = running_method,
    num_parallel_jobs  = num_parallel_jobs,
    dry_run            = dry_run,
    use_home           = use_home,
    keep_logs          = keep_logs,
    submission_cmd     = sys.argv,
  )

  job_statistics = projectionJobs.create()
  for job_type, num_jobs in job_statistics.items():
    logging.info(" #jobs of type '%s' = %i" % (job_type, num_jobs))

  if auto_exec:
    run_projection = True
  elif no_exec:
    run_projection = False
  else:
    run_projection = query_yes_no("Start jobs ?")
  if run_projection:
    projectionJobs.run()
  else:
    sys.exit(0)


#**************************************************************************#
# This file is part of pymsc which is released under MIT License. See file #
# LICENSE or go to https://github.com/jam1garner/pymsc/blob/master/LICENSE #
# for full license details.                                                #
#**************************************************************************#
from msc import *
from sys import argv
from os.path import isfile, dirname

#Parse args
savePaths = []
isLib = False
scriptsFile = None
state = None
for arg in argv[1:]:
    if state == "script":
        scriptsFile = arg
    elif state == "lib" or state == "library":
        isLib = True
        state = None #The next passed value should be handled normally
    elif state == "saveas":
        savePaths.append(arg)
    if state == None:
        if arg[:2] == "--":
            state = arg[2:].lower()
        else:
            if scriptsFile == None:
                scriptsFile = arg
            else:
                savePaths.append(arg)
    else:
        state = None

if scriptsFile == None:
    scriptsFile = "Scripts"

if not isfile(scriptsFile):
    print('No "Scripts" file found or provided')
    quit()

with open(scriptsFile, 'r') as f:
    lines = f.read().split('\n')
scriptPaths = [line.split('#')[0].strip() for line in lines if line.split('#')[0].strip() != '' and line.strip()[0] != '>' and line.strip()[0] != '|']
globalPaths = [line.split('#')[0].strip()[1:] for line in lines if line.split('#')[0].strip() != '' and line.strip()[0] == '>' and line.strip()[0] != '|']
savePaths += [line.split('#')[0].strip()[1:] for line in lines if line.split('#')[0].strip() != '' and line.strip()[0] != '>' and line.strip()[0] == '|']
if len(savePaths) == 0:
    savePaths = [dirname(__file__)+".mscsb"]

print("Assembling to files:\n"+"\n".join(savePaths))

globalAliases = {}

if isLib:
    fileBytes = b'MSCLIB\x00'
    fileBytes += struct.pack('<L', len(scriptPaths))
    fileBytes += struct.pack('<L', len(globalPaths))
else:
    strings = []
    exports = {}
    imports = []
    for globalPath in globalPaths:
        if isfile(globalPath):
            with open(globalPath, 'r') as f:
                globalLines = [l.split('#')[0].strip() for l in f.read().split('\n') if l.split('#')[0].strip() != '']
            for globalLine in globalLines:
                instruction = globalLine[:globalLine.find(' ')]

                if instruction == '.string':
                    strings.append(globalLine[8:])
                elif instruction == '.alias':
                    globalParams = globalLine[7:].replace(' ','').split(',')
                    globalAliases[globalParams[1]] = int(globalParams[0], 0)
                elif instruction == '.export':
                    globalParams = globalLine[7:].strip().split(' ')
                    exports[globalParams[1]] = globalParams[0]
                    if not globalParams[0] in strings:
                        strings.append(globalParams[0])
                elif instruction == '.import':
                    importPath = globalLine[8:].strip().strip("'").strip('"').strip()
                    with open(importPath) as f:
                        pass

    entrypoint = 'script_0'

    for i,script in enumerate(scriptPaths):
        if script[0] == ":":
            script = script[1:]
            scriptPaths[i] = script
            entrypoint = 'script_%i' % i
        if not isfile(script):
            print('File "%s" not found' % (script))
            quit()

    scripts = []
    for script in scriptPaths:
        with open(script, 'r', encoding='utf-8') as f:
            tempScript = MscScript()
            tempScript.cmds = parseCommands(f.read(), globalAliases, strings)
            tempScript.name = script
            scripts.append(tempScript)

    scriptPositions = {}
    currentPos = 0x10
    for i,script in enumerate(scripts):
        scriptPositions['script_%i' % i] = currentPos
        scriptPositions[script.name[:script.name.find('.')]] = currentPos
        currentPos += script.size()

    scriptNames = scriptPositions.keys()
    for script in scripts:
        for cmd in script:
            for i in range(len(cmd.parameters)):
                if cmd.parameters[i] in scriptNames:
                    cmd.parameters[i] = scriptPositions[cmd.parameters[i]]

    for i,script in enumerate(scripts):
        script.offset(scriptPositions['script_%i' % i])

    maxStringLength = 0
    for string in strings:
        if len(string) > maxStringLength:
            maxStringLength = len(string)
    if maxStringLength % 0x10 != 0:
        maxStringLength += 0x10 - (maxStringLength % 0x10)

    fileBytes = MSC_MAGIC
    fileBytes += struct.pack('<L', currentPos)
    fileBytes += struct.pack('<L', scriptPositions[entrypoint])
    fileBytes += struct.pack('<L', len(scripts))
    fileBytes += struct.pack('<L', 0x16)#This probably doesn't matter?
    fileBytes += struct.pack('<L', maxStringLength)
    fileBytes += struct.pack('<L', len(strings))
    fileBytes += struct.pack('<L', 0)
    fileBytes += struct.pack('<L', 0)
    fileBytes += b'\x00' * 0x10

    for script in scripts:
        for cmd in script:
            fileBytes += cmd.write()

    if len(fileBytes) % 0x10 != 0:
        fileBytes += b'\x00' * (0x10 - (len(fileBytes) % 0x10))

    for i in range(len(scripts)):
        fileBytes += struct.pack('<L',scriptPositions['script_%i' % i])

    if len(fileBytes) % 0x10 != 0:
        fileBytes += b'\x00' * (0x10 - (len(fileBytes) % 0x10))

    for string in strings:
        fileBytes += string.encode('utf-8')
        fileBytes += b'\x00' * (maxStringLength - len(string))

    if len(fileBytes) % 0x10 != 0:
        fileBytes += b'\x00' * (0x10 - (len(fileBytes) % 0x10))

for savePath in savePaths:
    with open(savePath, 'wb') as f:
        f.write(fileBytes)


import base64
import json
import logging
import os
from shlex import quote as shq
from typing import Any, Dict, List, Optional

from gear.cloud_config import get_global_config
from hailtop.config import get_deploy_config

from ....batch_configuration import DEFAULT_NAMESPACE, DOCKER_PREFIX, DOCKER_ROOT_IMAGE, INTERNAL_GATEWAY_IP
from ....file_store import FileStore
from ....instance_config import InstanceConfig
from ...resource_utils import unreserved_worker_data_disk_size_gib
from ...utils import ACCEPTABLE_QUERY_JAR_URL_PREFIX
from ..resource_utils import azure_machine_type_to_worker_type_and_cores

log = logging.getLogger('create_instance')

BATCH_WORKER_IMAGE = os.environ['HAIL_BATCH_WORKER_IMAGE']

log.info(f'BATCH_WORKER_IMAGE {BATCH_WORKER_IMAGE}')
log.info(f'ACCEPTABLE_QUERY_JAR_URL_PREFIX {ACCEPTABLE_QUERY_JAR_URL_PREFIX}')

def create_vm_config(
    file_store: FileStore,
    resource_rates: Dict[str, float],
    location: str,
    machine_name: str,
    machine_type: str,
    activation_token: str,
    max_idle_time_msecs: int,
    local_ssd_data_disk: bool,
    data_disk_size_gb: int,
    preemptible: bool,
    job_private: bool,
    subscription_id: str,
    resource_group: str,
    ssh_public_key: str,
    max_price: Optional[float],
    instance_config: InstanceConfig,
    feature_flags: dict,
) -> dict:
    _, cores = azure_machine_type_to_worker_type_and_cores(machine_type)

    hail_azure_oauth_scope = os.environ['HAIL_AZURE_OAUTH_SCOPE']
    region = instance_config.region_for(location)

    if max_price is not None and not preemptible:
        raise ValueError(f'max price given for a nonpreemptible machine {max_price}')

    if job_private:
        unreserved_disk_storage_gb = data_disk_size_gb
    else:
        unreserved_disk_storage_gb = unreserved_worker_data_disk_size_gib(data_disk_size_gb, cores)
    assert unreserved_disk_storage_gb >= 0

    worker_data_disk_name = 'data-disk'

    if local_ssd_data_disk:
        data_disks = []
        disk_location = '/dev/disk/azure/resource'
    else:
        data_disks = [
            {
                "name": "[concat(parameters('vmName'), '-data')]",
                "lun": 2,  # because this is 2, the data disk will always be at 'sdc'
                "managedDisk": {"storageAccountType": "Premium_LRS"},
                "createOption": "Empty",
                "diskSizeGB": data_disk_size_gb,
                "deleteOption": 'Delete',
            }
        ]
        disk_location = '/dev/disk/azure/scsi1/lun2'

    make_global_config = ['mkdir /global-config']
    global_config = get_global_config()
    for name, value in global_config.items():
        make_global_config.append(f'echo -n {shq(value)} > /global-config/{name}')
    make_global_config_str = '\n'.join(make_global_config)

    assert instance_config.is_valid_configuration(resource_rates.keys())

    touch_commands: List[str] = []
    for jvm_cores in (1, 2, 4, 8):
        for _ in range(cores // jvm_cores):
            idx = len(touch_commands)
            log_path = f'/batch/jvm-container-logs/jvm-{idx}.log'
            touch_commands.append(f'sudo touch {log_path}')

    jvm_touch_command = '\n'.join(touch_commands)

    startup_script = r'''#cloud-config

mounts:
  - [ ephemeral0, null ]
  - [ ephemeral0.1, null ]

write_files:
  - owner: batch-worker:batch-worker
    path: /startup.sh
    content: |
      #!/bin/sh
      set -ex
      RESOURCE_GROUP=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/resourceGroupName?api-version=2021-02-01&format=text")
      NAME=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/name?api-version=2021-02-01&format=text")
      if [ -f "/started" ]; then
          echo "instance $NAME has previously been started"
          while true; do
          az vm delete -g $RESOURCE_GROUP -n $NAME --yes
          sleep 1
          done
          exit
      else
          touch /started
      fi
      curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-02-01&format=text" | \
        base64 --decode | \
        jq -r '.run_script' > ./run.sh
      nohup /bin/bash run.sh >run.log 2>&1 &

runcmd:
  - sh /startup.sh
'''
    startup_script = base64.b64encode(startup_script.encode('utf-8')).decode('utf-8')

    run_script = f'''
#!/bin/bash
set -x

WORKER_DATA_DISK_NAME="{worker_data_disk_name}"
UNRESERVED_WORKER_DATA_DISK_SIZE_GB="{unreserved_disk_storage_gb}"
ACCEPTABLE_QUERY_JAR_URL_PREFIX="{ACCEPTABLE_QUERY_JAR_URL_PREFIX}"

# format worker data disk
sudo mkfs.xfs -f -m reflink=1 -n ftype=1 {disk_location}
sudo mkdir -p /mnt/disks/$WORKER_DATA_DISK_NAME
sudo mount -o prjquota {disk_location} /mnt/disks/$WORKER_DATA_DISK_NAME
sudo chmod a+w /mnt/disks/$WORKER_DATA_DISK_NAME
XFS_DEVICE=$(xfs_info /mnt/disks/$WORKER_DATA_DISK_NAME | head -n 1 | awk '{{ print $1 }}' | awk  'BEGIN {{ FS = "=" }}; {{ print $2 }}')

# reconfigure docker to use data disk
sudo service docker stop
sudo mv /var/lib/docker /mnt/disks/$WORKER_DATA_DISK_NAME/docker
sudo ln -s /mnt/disks/$WORKER_DATA_DISK_NAME/docker /var/lib/docker
sudo service docker start

# reconfigure /batch and /logs to use data disk
sudo mkdir -p /mnt/disks/$WORKER_DATA_DISK_NAME/batch/
sudo ln -s /mnt/disks/$WORKER_DATA_DISK_NAME/batch /batch

sudo mkdir -p /batch/jvm-container-logs/
{jvm_touch_command}

sudo mkdir -p /mnt/disks/$WORKER_DATA_DISK_NAME/logs/
sudo ln -s /mnt/disks/$WORKER_DATA_DISK_NAME/logs /logs

sudo mkdir -p /mnt/disks/$WORKER_DATA_DISK_NAME/cloudfuse/
sudo ln -s /mnt/disks/$WORKER_DATA_DISK_NAME/cloudfuse /cloudfuse

# Forward syslog logs to Log Analytics Agent
cat >>/etc/rsyslog.d/95-omsagent.conf <<EOF
kern.warning       @127.0.0.1:25224
user.warning       @127.0.0.1:25224
daemon.warning     @127.0.0.1:25224
auth.warning       @127.0.0.1:25224
uucp.warning       @127.0.0.1:25224
authpriv.warning   @127.0.0.1:25224
ftp.warning        @127.0.0.1:25224
cron.warning       @127.0.0.1:25224
local0.warning     @127.0.0.1:25224
local1.warning     @127.0.0.1:25224
local2.warning     @127.0.0.1:25224
local3.warning     @127.0.0.1:25224
local4.warning     @127.0.0.1:25224
local5.warning     @127.0.0.1:25224
local6.warning     @127.0.0.1:25224
local7.warning     @127.0.0.1:25224
EOF

sudo service rsyslog restart

sudo mkdir -p /etc/netns

curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-02-01&format=text" | \
  base64 --decode > userdata

SUBSCRIPTION_ID=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/subscriptionId?api-version=2021-02-01&format=text")
RESOURCE_GROUP=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/resourceGroupName?api-version=2021-02-01&format=text")
LOCATION=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/location?api-version=2021-02-01&format=text")

CORES=$(nproc)
NAMESPACE=$(jq -r '.namespace' userdata)
ACTIVATION_TOKEN=$(jq -r '.activation_token' userdata)
IP_ADDRESS=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress?api-version=2021-02-01&format=text")

BATCH_LOGS_STORAGE_URI=$(jq -r '.batch_logs_storage_uri' userdata)
INSTANCE_ID=$(jq -r '.instance_id' userdata)
INSTANCE_CONFIG=$(jq -r '.instance_config' userdata)
MAX_IDLE_TIME_MSECS=$(jq -r '.max_idle_time_msecs' userdata)
NAME=$(curl -s -H Metadata:true --noproxy "*" "http://169.254.169.254/metadata/instance/compute/name?api-version=2021-02-01&format=text")

BATCH_WORKER_IMAGE=$(jq -r '.batch_worker_image' userdata)
DOCKER_ROOT_IMAGE=$(jq -r '.docker_root_image' userdata)
DOCKER_PREFIX=$(jq -r '.docker_prefix' userdata)
REGION=$(jq -r '.region' userdata)
HAIL_AZURE_OAUTH_SCOPE=$(jq -r '.hail_azure_oauth_scope' userdata)

INTERNAL_GATEWAY_IP=$(jq -r '.internal_ip' userdata)

# private job network = 172.20.0.0/16
# public job network = 172.21.0.0/16
# [all networks] Rewrite traffic coming from containers to masquerade as the host
iptables --table nat --append POSTROUTING --source 172.20.0.0/15 --jump MASQUERADE

# [public]
# Block public traffic to the metadata server
iptables --append FORWARD --source 172.21.0.0/16 --destination 169.254.169.254 --jump DROP
# But allow the internal gateway
iptables --append FORWARD --destination $INTERNAL_GATEWAY_IP --jump ACCEPT
# And this worker
iptables --append FORWARD --destination $IP_ADDRESS --jump ACCEPT
# Forbid outgoing requests to cluster-internal IP addresses
INTERNET_INTERFACE=eth0
iptables --append FORWARD --out-interface $INTERNET_INTERFACE ! --destination 10.128.0.0/16 --jump ACCEPT

cat >> /etc/hosts <<EOF
$INTERNAL_GATEWAY_IP batch-driver.hail
$INTERNAL_GATEWAY_IP batch.hail
$INTERNAL_GATEWAY_IP internal.hail
EOF

{make_global_config_str}

mkdir /deploy-config
cat >/deploy-config/deploy-config.json <<EOF
{ json.dumps(get_deploy_config().with_location('gce').get_config()) }
EOF

# retry once
az acr login --name $DOCKER_PREFIX
docker pull $BATCH_WORKER_IMAGE || \
(echo 'pull failed, retrying' && sleep 15 && docker pull $BATCH_WORKER_IMAGE)

BATCH_WORKER_IMAGE_ID=$(docker inspect $BATCH_WORKER_IMAGE --format='{{{{.Id}}}}' | cut -d':' -f2)

# So here I go it's my shot.
docker run \
--name worker \
-e CLOUD=azure \
-e CORES=$CORES \
-e NAME=$NAME \
-e NAMESPACE=$NAMESPACE \
-e ACTIVATION_TOKEN=$ACTIVATION_TOKEN \
-e IP_ADDRESS=$IP_ADDRESS \
-e BATCH_LOGS_STORAGE_URI=$BATCH_LOGS_STORAGE_URI \
-e INSTANCE_ID=$INSTANCE_ID \
-e SUBSCRIPTION_ID=$SUBSCRIPTION_ID \
-e RESOURCE_GROUP=$RESOURCE_GROUP \
-e LOCATION=$LOCATION \
-e REGION=$REGION \
-e HAIL_AZURE_OAUTH_SCOPE=$HAIL_AZURE_OAUTH_SCOPE \
-e DOCKER_PREFIX=$DOCKER_PREFIX \
-e DOCKER_ROOT_IMAGE=$DOCKER_ROOT_IMAGE \
-e INSTANCE_CONFIG=$INSTANCE_CONFIG \
-e MAX_IDLE_TIME_MSECS=$MAX_IDLE_TIME_MSECS \
-e BATCH_WORKER_IMAGE=$BATCH_WORKER_IMAGE \
-e BATCH_WORKER_IMAGE_ID=$BATCH_WORKER_IMAGE_ID \
-e INTERNET_INTERFACE=$INTERNET_INTERFACE \
-e UNRESERVED_WORKER_DATA_DISK_SIZE_GB=$UNRESERVED_WORKER_DATA_DISK_SIZE_GB \
-e ACCEPTABLE_QUERY_JAR_URL_PREFIX=$ACCEPTABLE_QUERY_JAR_URL_PREFIX \
-e INTERNAL_GATEWAY_IP=$INTERNAL_GATEWAY_IP \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/run/netns:/var/run/netns:shared \
-v /usr/bin/docker:/usr/bin/docker \
-v /batch:/batch:shared \
-v /logs:/logs \
-v /global-config:/global-config \
-v /deploy-config:/deploy-config \
-v /cloudfuse:/cloudfuse:shared \
-v /etc/netns:/etc/netns \
-v /sys/fs/cgroup:/sys/fs/cgroup \
--mount type=bind,source=/mnt/disks/$WORKER_DATA_DISK_NAME,target=/host \
--mount type=bind,source=/dev,target=/dev,bind-propagation=rshared \
-p 5000:5000 \
--device /dev/fuse \
--device $XFS_DEVICE \
--device /dev \
--privileged \
--cap-add SYS_ADMIN \
--security-opt apparmor:unconfined \
--network host \
--cgroupns host \
$BATCH_WORKER_IMAGE \
python3 -u -m batch.worker.worker >worker.log 2>&1

[ $? -eq 0 ] || tail -n 1000 worker.log

while true; do
az vm delete -g $RESOURCE_GROUP -n $NAME --yes
sleep 1
done
'''

    user_data = {
        'run_script': run_script,
        'activation_token': activation_token,
        'batch_worker_image': BATCH_WORKER_IMAGE,
        'docker_root_image': DOCKER_ROOT_IMAGE,
        'docker_prefix': DOCKER_PREFIX,
        'namespace': DEFAULT_NAMESPACE,
        'internal_ip': INTERNAL_GATEWAY_IP,
        'batch_logs_storage_uri': file_store.batch_logs_storage_uri,
        'instance_id': file_store.instance_id,
        'max_idle_time_msecs': max_idle_time_msecs,
        'instance_config': base64.b64encode(json.dumps(instance_config.to_dict()).encode()).decode(),
        'region': region,
        'hail_azure_oauth_scope': hail_azure_oauth_scope,
    }
    user_data_str = base64.b64encode(json.dumps(user_data).encode('utf-8')).decode('utf-8')

    tags = {'namespace': DEFAULT_NAMESPACE, 'batch-worker': '1'}

    vm_resources = []

    if feature_flags['oms_agent']:
        vm_resources.append(
            {
                'apiVersion': '2018-06-01',
                'type': 'extensions',
                'name': 'OMSExtension',
                'location': "[parameters('location')]",
                'tags': tags,
                'dependsOn': ["[concat('Microsoft.Compute/virtualMachines/', parameters('vmName'))]"],
                'properties': {
                    'publisher': 'Microsoft.EnterpriseCloud.Monitoring',
                    'type': 'OmsAgentForLinux',
                    'typeHandlerVersion': '1.13',
                    'autoUpgradeMinorVersion': False,
                    'enableAutomaticUpgrade': False,
                    'settings': {
                        'workspaceId': "[reference(resourceId('Microsoft.OperationalInsights/workspaces/', parameters('workspaceName')), '2015-03-20').customerId]"
                    },
                    'protectedSettings': {
                        'workspaceKey': "[listKeys(resourceId('Microsoft.OperationalInsights/workspaces/', parameters('workspaceName')), '2015-03-20').primarySharedKey]"
                    },
                },
            },
        )

    vm_config: Dict[str, Any] = {
        'apiVersion': '2021-03-01',
        'type': 'Microsoft.Compute/virtualMachines',
        'name': "[parameters('vmName')]",
        'location': "[parameters('location')]",
        'identity': {
            'type': 'UserAssigned',
            'userAssignedIdentities': {
                "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('userAssignedIdentityName'))]": {}
            },
        },
        'tags': tags,
        'dependsOn': ["[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"],
        'properties': {
            'hardwareProfile': {'vmSize': machine_type},
            'networkProfile': {
                'networkInterfaces': [
                    {
                        'id': "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]",
                        'properties': {'deleteOption': 'Delete'},
                    }
                ]
            },
            'storageProfile': {
                'osDisk': {
                    'name': "[concat(parameters('vmName'), '-os')]",
                    'createOption': 'FromImage',
                    'deleteOption': 'Delete',
                    'caching': 'ReadOnly',
                    'managedDisk': {'storageAccountType': 'Standard_LRS'},
                },
                'imageReference': "[parameters('imageReference')]",
                'dataDisks': data_disks,
            },
            'osProfile': {
                'computerName': "[parameters('vmName')]",
                'adminUsername': "[parameters('adminUsername')]",
                'customData': "[parameters('startupScript')]",
                'linuxConfiguration': {
                    'disablePasswordAuthentication': True,
                    'ssh': {
                        'publicKeys': [
                            {
                                'keyData': "[parameters('sshKey')]",
                                'path': "[concat('/home/', parameters('adminUsername'), '/.ssh/authorized_keys')]",
                            }
                        ]
                    },
                },
            },
            'userData': "[parameters('userData')]",
        },
        'resources': vm_resources,
    }

    properties = vm_config['properties']
    if preemptible:
        properties['priority'] = 'Spot'
        properties['evictionPolicy'] = 'Delete'
        properties['billingProfile'] = {'maxPrice': max_price if max_price is not None else -1}
    else:
        properties['priority'] = 'Regular'

    return {
        'tags': tags,
        'properties': {
            'mode': 'Incremental',
            'parameters': {
                'location': {'value': location},
                'vmName': {'value': machine_name},
                'sshKey': {'value': ssh_public_key},
                'subnetId': {
                    'value': f'/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/Microsoft.Network/virtualNetworks/default/subnets/batch-worker-subnet'
                },
                'adminUsername': {'value': 'batch-worker'},
                'userAssignedIdentityName': {'value': 'batch-worker'},
                'startupScript': {'value': startup_script},
                'userData': {'value': user_data_str},
                'imageReference': {
                    'value': {
                        'id': f'/subscriptions/{subscription_id}/resourceGroups/{resource_group}/providers/'
                        f'Microsoft.Compute/galleries/{resource_group}_batch/images/batch-worker-22-04/versions/0.0.13'
                    }
                },
                'workspaceName': {
                    'value': f'{resource_group}-logs',
                },
            },
            'template': {
                '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#',
                'contentVersion': '1.0.0.0',
                'parameters': {
                    'location': {'type': 'string', 'defaultValue': '[resourceGroup().location]'},
                    'vmName': {'type': 'string'},
                    'sshKey': {'type': 'securestring'},
                    'subnetId': {'type': 'string'},
                    'adminUsername': {'type': 'string', 'defaultValue': 'admin'},
                    'userAssignedIdentityName': {'type': 'string', 'defaultValue': 'batch-worker'},
                    'startupScript': {'type': 'string'},
                    'userData': {'type': 'string'},
                    'imageReference': {
                        'type': 'object',
                        'defaultValue': {
                            'publisher': 'Canonical',
                            'offer': 'UbuntuServer',
                            'sku': '18.04-LTS',
                            'version': 'latest',
                        },
                    },
                    'workspaceName': {'type': 'string'},
                },
                'variables': {
                    'ipName': "[concat(parameters('vmName'), '-ip')]",
                    'nicName': "[concat(parameters('vmName'), '-nic')]",
                    'ipconfigName': "[concat(parameters('vmName'), '-ipconfig')]",
                },
                'resources': [
                    {
                        'apiVersion': '2018-01-01',
                        'type': 'Microsoft.Network/publicIPAddresses',
                        'name': "[variables('ipName')]",
                        'location': "[parameters('location')]",
                        'tags': tags,
                        'dependsOn': [],
                        'properties': {'publicIPAllocationMethod': 'Static'},
                    },
                    {
                        'apiVersion': '2015-06-15',
                        'type': 'Microsoft.Network/networkInterfaces',
                        'name': "[variables('nicName')]",
                        'location': "[parameters('location')]",
                        'tags': tags,
                        'dependsOn': ["[concat('Microsoft.Network/publicIPAddresses/', variables('ipName'))]"],
                        'properties': {
                            'ipConfigurations': [
                                {
                                    'name': "[variables('ipconfigName')]",
                                    'properties': {
                                        'publicIPAddress': {
                                            'id': "[resourceId('Microsoft.Network/publicIpAddresses', variables('ipName'))]",
                                            'properties': {'deleteOption': 'Delete'},
                                        },
                                        'privateIPAllocationMethod': 'Dynamic',
                                        'subnet': {'id': "[parameters('subnetId')]"},
                                    },
                                }
                            ],
                            'networkSecurityGroup': {
                                'id': f'/subscriptions/{subscription_id}/resourceGroups/{resource_group}'
                                f'/providers/Microsoft.Network/networkSecurityGroups/batch-worker-nsg'
                            },
                        },
                    },
                    vm_config,
                ],
                'outputs': {},
            },
        },
    }


# this is an example of how to load:
# 1. Schema files into blank instances of Interfaces
# 2. Data into blank instances
# 3. A schema file and a data file and load them

# this is helpful for type checking data!! P.S. if someone wants to create something like TypeChat using this, I WOULD BE THRILLEDD!

#imports
import IF4
import json

#define paths
schema_path = "schema.json"
data_path = "data.json"

# generate_interfaces
# to load schema into blank Interfaces, you can use the IF4.generate_interfaces function
# it takes schema in a dictionary format, which you can do using something like json.load(open(schema_path))

schema_data = json.load(open(schema_path))
interfaces = IF4.generate_interfaces(schema_data)    #this will return  interfaces that are blank but have the types that are defined in the file

# now, we can load the data the same way

data_data = json.load(open(data_path))

# then, we use the load_data function to load the data decided in the file

objects = IF4.load_data(data_data, interfaces) # this will return a dictionary of defined interfaces with the data from the file

# now, to do this all in one step, you can use the getObjs function, which take the paths to both of your files. It will return
# a dictionary of defiend and loaded interfaces

objects_different = IF4.getObjs(schema_path, data_path)

# as a reminder, this will check the types as they are loaded


# Import necessary libraries
import streamlit as st
import openai
from io import BytesIO
from langchain.docstore.document import Document
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores.faiss import FAISS
from pypdf import PdfReader
from typing import List, Tuple
import re

# Set the title for the Streamlit app
st.title("Document Chat RAG App")

# Set up the OpenAI API key
openai.api_key = ''

def parse_pdf(file: BytesIO, filename: str) -> Tuple[List[str], str]:
    # Function to parse PDF and return text and filename
    pdf = PdfReader(file)
    output = []
    for page in pdf.pages:
        text = page.extract_text()
        text = re.sub(r"(\w+)-\n(\w+)", r"\1\2", text)
        text = re.sub(r"(?<!\n\s)\n(?!\s\n)", " ", text.strip())
        text = re.sub(r"\n\s*\n", "\n\n", text)
        output.append(text)
    return output, filename

def text_to_docs(text: List[str], filename: str) -> List[Document]:
    # Convert text to documents
    if isinstance(text, str):
        text = [text]
    page_docs = [Document(page_content=page) for page in text]
    for i, doc in enumerate(page_docs):
        doc.metadata["page"] = i + 1

    doc_chunks = []
    for doc in page_docs:
        text_splitter = RecursiveCharacterTextSplitter(
            chunk_size=4000,
            separators=["\n\n", "\n", ".", "!", "?", ",", " ", ""],
            chunk_overlap=0,
        )
        chunks = text_splitter.split_text(doc.page_content)
        for i, chunk in enumerate(chunks):
            doc = Document(
                page_content=chunk, metadata={"page": doc.metadata["page"], "chunk": i}
            )
            doc.metadata["source"] = f"{doc.metadata['page']}-{doc.metadata['chunk']}"
            doc.metadata["filename"] = filename  # Add filename to metadata
            doc_chunks.append(doc)
    return doc_chunks

def docs_to_index(docs, openai_api_key):
    # Convert documents to FAISS index
    index = FAISS.from_documents(docs, OpenAIEmbeddings(openai_api_key=openai_api_key))
    return index

# Update the create_vectordb function to read file contents properly
@st.cache_data
def create_vectordb(files, filenames):
    documents = []
    for pdf_file, pdf_name in zip(files, filenames):
        file_contents = pdf_file.read()  # Read the contents of the uploaded file
        text, filename = parse_pdf(BytesIO(file_contents), pdf_name)
        documents = documents + text_to_docs(text, filename)
    index = docs_to_index(documents, openai.api_key)
    return index

# Upload PDF files using Streamlit's file uploader
pdf_files = st.file_uploader("Upload PDF files", type="pdf", accept_multiple_files=True)

# If PDF files are uploaded, create the vectordb and store it in the session state
if pdf_files:
    pdf_file_names = [file.name for file in pdf_files]
    st.session_state["vectordb"] = create_vectordb(pdf_files, pdf_file_names)

# Define the template for the chatbot prompt
prompt_template = """
    You are a helpful Assistant who answers to users questions based on multiple contexts given to you.

    Keep your answer short and to the point.

    The evidence are the context of the pdf extract with metadata.

    Carefully focus on the metadata specially 'filename' and 'page' whenever answering.

    Make sure to add filename and page number at the end of sentence you are citing to.

    Reply "Not applicable" if text is irrelevant.

    The PDF content is:
    {pdf_extract}
"""

# Get the current prompt from the session state or set a default value
prompt = st.session_state.get("prompt", [{"role": "system", "content": "none"}])

# Display previous chat messages
for message in prompt:
    if message["role"] != "system":
        with st.chat_message(message["role"]):
            st.write(message["content"])

# Get the user's question using Streamlit's chat input
question = st.chat_input("Ask anything")

# Handle the user's question
if question:
    vectordb = st.session_state.get("vectordb", None)
    if not vectordb:
        with st.message("assistant"):
            st.write("You need to provide a PDF")
            st.stop()

    # Search the vectordb for similar content to the user's question
    search_results = vectordb.similarity_search(question, k=3)
    # search_results
    pdf_extract = "/n ".join([result.page_content for result in search_results])

    # Update the prompt with the pdf extract
    prompt[0] = {
        "role": "system",
        "content": prompt_template.format(pdf_extract=pdf_extract),
    }

    # Add the user's question to the prompt and display it
    prompt.append({"role": "user", "content": question})
    with st.chat_message("user"):
        st.write(question)

    # Display an empty assistant message while waiting for the response
    #with st.chat_message("assistant"):
    with st.chat_message("assistant"):
        botmsg = st.empty()

    # Call ChatGPT with streaming and display the response as it comes
    response = []
    result = ""
    for chunk in openai.ChatCompletion.create(
        model="gpt-3.5-turbo", messages=prompt, stream=True
    ):
        text = chunk.choices[0].get("delta", {}).get("content")
        if text is not None:
            response.append(text)
            result = "".join(response).strip()
            botmsg.write(result)

    # Add the assistant's response to the prompt
    prompt.append({"role": "assistant", "content": result})

    # Store the updated prompt in the session state
    st.session_state["prompt"] = prompt
    prompt.append({"role": "assistant", "content": result})

    # Store the updated prompt in the session state
    st.session_state["prompt"] = prompt


class Solution:
    def __init__(self):
        self.dic_roman={"I":1,"V":5,"X":10,"L":50,"C":100,"D":500,"M":1000}
        self.dic_int2roman={ value:key for key,value in self.dic_roman.items()}
    def int2roman(self,target):
        res =""
        if target//1000>0:
            m=target//1000
            target=target-m*1000
            res+="M"*m;
        if target>=300:
            if target>=500:
                target=target-500
                c=target//100
                res+="D"+c*"C"
            else:
                target=target-()


# pythonでDOTを使用する
import pydot
# Jupyter Notebookで画像を表示する
from IPython.display import Image,display_png
# グラフ理論でいうところのグラフを描く
from graphviz import Digraph

class Morph:
    def __init__(self, morph):
        (surface, attr) = morph.split("\t")
        attr = attr.split(",")
        self.surface = surface
        self.base = attr[6]
        self.pos = attr[0]
        self.pos1 = attr[1]

class Chunk():
    def __init__(self, morphs, dst):
        self.morphs = morphs
        # 自分から出る矢印は1本
        self.dst = dst
        self.srcs = []

# かかり先から逆向きに設定し、かかり関係をつける
class Sentence():
    def __init__(self, chunks):
        self.chunks = chunks
        for i, chunk in enumerate(self.chunks):
            # 係り受け先がある場合 : かかり元が自分であると示す
            if chunk.dst not in [None, -1]:
                self.chunks[chunk.dst].srcs.append(i)

def main():
    sentences = []
    chunks = []
    morphs = []
    with open("../../data/ai.ja/ai.ja.txt.paresd") as input_file:
        for line in input_file:
            # 係り受け関係を示すもの
            if line[0] == "*":
                if len(morphs) > 0:
                    chunks.append(Chunk(morphs, dst))
                    morphs = []
                # 係り先の単語のID
                dst = int(line.split(" ")[2].rstrip("D"))
            # 文末以外：形態素リスト追加
            elif line != "EOS\n":
                morphs.append(Morph(line))
            # 文末
            else:
                chunks.append(Chunk(morphs, dst))
                sentences.append(Sentence(chunks))
                morphs = []
                chunks = []
                dst = None

    # 追加
    sentence = sentences[2]
    edges = []
    for id, chunk in enumerate(sentence.chunks):
        if int(chunk.dst) != -1:
            kakarimoto = ''.join(
                [morph.surface if morph.pos != '記号' else '' for morph in chunk.morphs] + ['(' + str(id) + ')'])
            kakarisaki = ''.join(
                [morph.surface if morph.pos != '記号' else '' for morph in sentence.chunks[int(chunk.dst)].morphs] + [
                    '(' + str(chunk.dst) + ')'])
            edges.append([kakarimoto, kakarisaki])

    # ノードとエッジを追加
    n = pydot.Node('node')
    # directed=True: 矢印あり
    g = pydot.graph_from_edges(edges, directed=True)
    g.add_node(n)
    g.write_png('./ans44.png')
    display_png(Image('./ans44.png'))

if __name__ == '__main__':
    main()


# -*- coding: utf8 -*-

"""Test Parser"""

import pytest
from StringIO import StringIO
from pdf2text import parser

from pdfminer.pdfparser import PDFSyntaxError

def test_not_parsable():
    """Test if parser raises exception on invalid file"""
    with pytest.raises(PDFSyntaxError):
        parser.parse(StringIO('Contents'))

def test_parser():
    """Test if parser parses a simple pdf"""
    with open('tests/pdfs/hello.pdf', 'rb') as f:
        text = parser.parse(f)
    assert text.strip() == 'hello world', text.strip()

def test_parse_unicode():
    """Test if unicode is parsed correctly"""
    with open('tests/pdfs/unicode.pdf', 'rb') as f:
        text = parser.parse(f)
    assert "unicode čćç" in text, text

def test_parse_newlines():
    """Test if newlines are parsed correctly"""
    with open('tests/pdfs/newline.pdf', 'rb') as f:
        text = parser.parse(f)
    assert "\n" in text, text

@pytest.mark.parametrize("strings,count,expected", (
    ("", 7, "First,Second,Third,Fourth,Fifth,Sixth,Seventh"),
    ("1", 1, "First"),
    ("1-5", 5, "First,Second,Third,Fourth,Fifth"),
    ("1-3, 3, 6", 4, "First,Second,Third,Sixth")
))
def test_multipage_filtering(strings, count, expected):
    """Test page filtering"""
    with open('tests/pdfs/multipage.pdf', 'rb') as f:
        text = parser.parse(f, strings)
    actual = len(text.split())
    expected = expected.split(',')
    assert actual == count, "Parsed pages {}, but should be {}".format(
        actual, expected)
    for i, t in enumerate(text.split()):
        print(expected[i], t)
        assert expected[i] in t

def test_page_number_removal():
    """Test page number removal"""
    with open("tests/pdfs/numbers.pdf") as f:
        text = parser.parse(f)
    assert "321" not in text, "Page numbers not removed correctly" + text
    assert "1" not in text, "Page numbers not removed correctly" + text

@pytest.mark.parametrize("strings,expected", (
    ("", None),
    ("1", [0]),
    ("1,2,3", [0, 1, 2]),
    ("1, 3 , 3 , 7 ", [0, 2, 6]),
    ("1-5", [0, 1, 2, 3, 4]),
    ("4-6, 1,2,5-7", [0, 1, 3, 4, 5, 6])
))
def test_parse_pages(strings, expected):
    """Test parse pages"""
    res = parser.parse_pages(strings)
    assert res == expected, \
        "Result '{}' does not match expected '{}' for {}".format(
            res, expected, strings)

@pytest.mark.parametrize("strings", (
    "a", "a,b,c", "1-b", "c-6, 1,d,5-e"
))
def test_parse_pages_with_error(strings):
    """Test if parse_pages throws a ValueError on invalid input"""
    with pytest.raises(ValueError):
        parser.parse_pages(strings)


from fastai.text import *
import os

def pretrain_language_model(data_dir, lm_dir, bs=48, epochs=1):
    #Load in our text data:
    data_lm = TextLMDataBunch.from_folder(data_dir, bs=bs)

    # Initialize the AWD-LSTM lm
    learn = language_model_learner(data_lm, AWD_LSTM, drop_mult=0.5)

    #Pretrain language model
    learn.fit_one_cycle(epochs, 1e-2)

    # Save the pre-trained language model
    if not os.path.exists(lm_dir):
        os.makedirs(lm_dir)
    learn.save_encoder(os.path.join(lm_dir, 'pretrained_lm_encoder'))

if __name__ == '__main__':
    data_path = './data/imdb'  # Path to your dataset
    lm_path = './lm'  # Path to save the pre-trained language model
    pretrain_language_model(data_path, lm_path)


import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision.utils import make_grid
from app.model.generator import Generator
from app.model.discriminator import Discriminator
from app.model.loss_helpers import disc_loss, gen_loss

MODEL_FILENAME = 'cycleGANmodel.pth'

class CycleGANModel():
    def __init__(self,
                 device,
                 output_dir,
                 dim_A = 3,
                 dim_B = 3,
                 pretrained_path = None,
                 load_shape = 260,
                 target_shape = 256):
        self.device = device
        self.output_dir = output_dir
        self.load_shape = load_shape
        self.target_shape = target_shape
        self.gen_AB = Generator(dim_A, dim_B).to(device)
        self.gen_BA = Generator(dim_B, dim_A).to(device)
        self.dim_A = dim_A
        self.dim_B = dim_B

        self.disc_A = Discriminator(dim_A).to(device)

        self.disc_B = Discriminator(dim_B).to(device)

        def _weights_init(m):
            if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d):
                torch.nn.init.normal_(m.weight, 0.0, 0.02)
            if isinstance(m, nn.BatchNorm2d):
                torch.nn.init.normal_(m.weight, 0.0, 0.02)
                torch.nn.init.constant_(m.bias, 0)

        if pretrained_path is not None:
            self.pre_dict = torch.load(pretrained_path)
            self.gen_AB.load_state_dict(pre_dict['gen_AB'])
            self.gen_BA.load_state_dict(pre_dict['gen_BA'])
            self.gen_opt.load_state_dict(pre_dict['gen_opt'])
            self.disc_A.load_state_dict(pre_dict['disc_A'])
            self.disc_A_opt.load_state_dict(pre_dict['disc_A_opt'])
            self.disc_B.load_state_dict(pre_dict['disc_B'])
            self.disc_B_opt.load_state_dict(pre_dict['disc_B_opt'])
        else:
            self.gen_AB = self.gen_AB.apply(_weights_init)
            self.gen_BA = self.gen_BA.apply(_weights_init)
            self.disc_A = self.disc_A.apply(_weights_init)
            self.disc_B = self.disc_B.apply(_weights_init)

    def _train_step(self, real_A, real_B, adv_criterion, recon_criterion):
        real_A = nn.functional.interpolate(real_A, size=self.target_shape)
        real_B = nn.functional.interpolate(real_B, size=self.target_shape)
        cur_batch_size = len(real_A)
        real_A = real_A.to(self.device)
        real_B = real_B.to(self.device)

        # discriminators
        self.disc_A_opt.zero_grad()
        with torch.no_grad():
            fake_A = self.gen_BA(real_B)

        disc_A_loss = disc_loss(real_A, fake_A, self.disc_A, adv_criterion, self.device)
        disc_A_loss.backward(retain_graph=True)
        self.disc_A_opt.step()

        self.disc_B_opt.zero_grad()
        with torch.no_grad():
            fake_B = self.gen_AB(real_A)
        disc_B_loss = disc_loss(real_B, fake_B, self.disc_B, adv_criterion, self.device)
        disc_B_loss.backward(retain_graph=True)
        self.disc_B_opt.step()

        # generator
        self.gen_opt.zero_grad()
        gen_loss_val, fake_A, fake_B = gen_loss(
            real_A, real_B, self.gen_AB, self.gen_BA, self.disc_A, self.disc_B,
             adv_criterion, recon_criterion, recon_criterion
        )
        gen_loss_val.backward()
        self.gen_opt.step()

        return disc_A_loss, disc_B_loss, gen_loss_val, fake_A, fake_B

    def train(self, dataset, num_epochs, lr, batch_size, verbose=False, display_step=100):
        self.gen_opt = torch.optim.Adam(list(self.gen_AB.parameters()) + list(self.gen_BA.parameters()), lr=lr, betas=(0.5, 0.999))
        self.disc_A_opt = torch.optim.Adam(self.disc_A.parameters(), lr=lr, betas=(0.5, 0.999))
        self.disc_B_opt = torch.optim.Adam(self.disc_B.parameters(), lr=lr, betas=(0.5, 0.999))

        mean_gen_loss = 0
        mean_disc_loss = 0
        dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

        for epoch in range(num_epochs):
            cur_step = 0
            for real_A, real_B in dataloader:

                disc_A_loss, disc_B_loss, gen_loss, fa, fb = self._train_step(real_A,
                                                                      real_B,
                                                                      nn.MSELoss(),
                                                                      nn.L1Loss())

                if verbose:
                    mean_disc_loss += disc_A_loss.item() / display_step
                    mean_gen_loss += gen_loss.item() / display_step

                    if cur_step % display_step == 0:
                        print(f"epoch {epoch}: step {cur_step}")
                        print(f"gen_loss: {mean_gen_loss}, disc_loss: {mean_disc_loss}")

                        mean_generator_loss = 0
                        mean_discriminator_loss = 0

                cur_step += 1
            self.save()

    def save(self):
        path_to_save = self.output_dir + '/' + MODEL_FILENAME
        torch.save({
            'gen_AB': self.gen_AB.state_dict(),
            'gen_BA': self.gen_BA.state_dict(),
            'gen_opt': self.gen_opt.state_dict(),
            'disc_A': self.disc_A.state_dict(),
            'disc_A_opt': self.disc_A_opt.state_dict(),
            'disc_B': self.disc_B.state_dict(),
            'disc_B_opt': self.disc_B_opt.state_dict(),
        }, path_to_save)

    def infer(self, real, a2b = True):
        if a2b:
            with torch.no_grad():
                image_tensor = gen_AB(real)
        else:
            with torch.no_grad():
                image_tensor = gen_BA(real)
        image_tensor = (image_tensor + 1) / 2
        image_unflat = image_tensor.detach().cpu().view(-1, *size)
        image = image_unflat.permute(1, 2, 0).squeeze()
        return image


from operands import Operands

print("Welcome to My Python Calculator")

while True:
    print("\nEnter\t'a' for Addition\t's' for Substitution\t'm' for Multiplication\t'd' for Division")
    print("Enter q for Quit")

    c = input("Enter the Letter : ")

    if c.strip() == '':
        continue

    elif c == 'q':
        break

    try:
        a = float(input("Enter the First Operand : "))
        b = float(input("Enter the Second Operand : "))

    except ValueError:
        print("Error : Invalid input")

    operands = Operands(a, b)

    if c == 'a':
        operands.addition()

    elif c == 's':
        operands.substitution()

    elif c == 'm':
        operands.multiplication()

    elif c == 'd':
        operands.division()

    else:
        print("Sorry, Invalid Input\n")


def split_half(position, half):
    N = position.shape[0]
    assert(half == 'Upper' or half == 'Lower')
    assert(N > 1)

    split = int(N/2)
    if half == 'Lower':
        position = position[:split]
    elif half == 'Upper':
        position = position[-split:]
    return position

def find_row(string):
    assert(len(string) == 7)

    positions = np.arange(0,128,1)

    for s in string:

        if s == 'F':
            positions = split_half(positions, 'Lower')
        if s == 'B':
            positions = split_half(positions, 'Upper')
    return positions

def find_column(string):
    assert(len(string) == 3)

    positions = np.arange(0,8,1)

    for s in string:

        if s == 'L':
            positions = split_half(positions, 'Lower')
        if s == 'R':
            positions = split_half(positions, 'Upper')
    return positions

if __name__ == '__main__':

    import numpy as np
    with open('day5', 'r') as fd: # read file
        out = fd.read().splitlines()      # str

    max_ID = 0
    seat_IDs = np.zeros((len(out),1)).astype(np.int)
    i = 0
    for line in out:
        row = find_row(line[:7])
        column = find_column(line[-3:])

        # Part 2
        ID = row*8 + column
        seat_IDs[i] = int(ID)
        i += 1

        # Part 1
        if ID > max_ID:
            max_ID = ID

    # Part 2 cont.
    # Sort the IDs
    sorted_IDs = np.array(sorted(seat_IDs))         # All should be 1,2,3,4...
    difference = sorted_IDs[1:] - sorted_IDs[:-1]   # Should be 1,1,1,1,1,1...
    position = np.where(difference != 1)[0]         # Find the discrepency

    your_ID = (sorted_IDs[position] + sorted_IDs[position+1])/2 # Middle of two


#!/usr/bin/env python
"""
Min pages brute force.

######################################################################
# @author      : Linus Fernandes (linusfernandes at gmail dot com)
# @file        : minpagesbf
# @created     : Tuesday Mar 28, 2023 19:11:40 IST
# @description :
# https://www.codingninjas.com/codestudio/library/book-allocation-problem
# -*- coding: utf-8 -*-'
######################################################################
"""

def is_possible(arr, std_count, curr_min):
    """Check if possible."""
    size = len(arr)
    cnt_students = 1
    cursum = 0
    # iterate over all the books
    for i in range(size):
        # Increment student count by '1'
        if (cursum + arr[i]) > curr_min:
            cnt_students += 1
            # assign current book to next student and update curSum
            cursum = arr[i]
            # If count of students becomes greater than
            # given no. of students, return False
            if cnt_students > std_count:
                return False
        else:
            # update curSum.
            cursum += arr[i]
    return True

# function to find minimum number pages
def allocate_books(arr, students):
    """Allocate books."""
    size = len(arr)
    total = 0
    # If number student is more than number of books
    if size < students:
        return -1
    # Count total number of pages
    for i in range(size):
        total += arr[i]
    start = max(arr)
    for num_pages in range(start, total + 1):
        ans = is_possible(arr, students, num_pages)
        if ans:
            return num_pages
    return -1

# Number of pages in books
ARR = [10, 20, 30, 40]
M = 2  # No. of students
print(f"The minimum value of maximum number of pages is: {allocate_books(ARR, M)}")


from utils.openbis_utils import create_sample_identifier_string, create_project_identifier_string, create_experiment_identifier_string
from .update_parsers import CreationToUpdateParserFactory
from ..definition_to_creation import SampleDefinitionToCreationType, ScriptDefinitionToCreationType, \
    ProjectDefinitionToCreationType, ExperimentDefinitionToCreationType

class CreationToUpdateParser(object):

    @staticmethod
    def parse(creations_that_exist, existing_elements):
        updates = {}
        for creation_type, creations in creations_that_exist.items():
            parsers = CreationToUpdateParserFactory.get_parsers(creation_type)
            for creation in creations:
                existing_element = get_existing_element_based_on(creation_type, creation,
                                                                 existing_elements[creation_type])
                if existing_element:
                    for parser in parsers:
                        update = parser.parse(creation, existing_element)
                        update_type = parser.get_type()
                        if update_type not in updates:
                            updates[update_type] = []
                        updates[update_type].extend(update if type(update) == list else [update])

        return updates

def get_existing_element_based_on(creation_type, creation, existing_elements):
    if creation_type == SampleDefinitionToCreationType:
        existing_element = list(filter(
            lambda existing_element: create_sample_identifier_string(creation) == existing_element.identifier.identifier,
            existing_elements))
    elif creation_type == ProjectDefinitionToCreationType:
        existing_element = list(filter(
            lambda existing_element: create_project_identifier_string(creation) == str(existing_element.identifier),
            existing_elements))
    elif creation_type == ExperimentDefinitionToCreationType:
        existing_element = list(filter(
            lambda existing_element: create_experiment_identifier_string(creation) == str(existing_element.identifier),
            existing_elements))
    else:
        if creation_type == ScriptDefinitionToCreationType:
            attr = 'name'
        else:
            attr = 'code'
        existing_element = list(
            filter(lambda existing_element: getattr(creation, attr) == getattr(existing_element, attr),
                   existing_elements))
    return None if len(existing_element) == 0 else existing_element[0]