# -*- coding: utf-8 -*-
__author__ = 'alansanders'
import ctypes as ct
import os

pvcam=PVCAM = ct.WinDLL(os.path.dirname(__file__) +"/DLL/Pvcam32.dll")

import nplab.instrument.ccd.pvcam_h as pv
import numpy as np
import time
from nplab.instrument.ccd import CCD
from nplab.instrument.camera import Camera
from nplab.utils.gui import *
from nplab.ui.ui_tools import UiTools
from nplab import inherit_docstring

class PixisError(Exception):
    def __init__(self, msg):
        print(msg)
        i = pvcam.pl_error_code()
        msg = ct.create_string_buffer(20)
        pvcam.pl_error_message(i, msg)
        print('self.pvcam Error:', i, msg)
        pvcam.pl_self.pvcam_uninit()

class Pixis256E(CCD,Camera):
    def __init__(self):
        super(Pixis256E, self).__init__()
        try:
            self.pvcam = PVCAM #ct.windll.pvcam32
        except WindowsError as e:
            print('pvcam not found')
        cam_selection = ct.c_int16()
        # Initialize the self.pvcam library and open the camera #
        self.open_lib()
        self.open_cam(cam_selection)
        self._sequence_set = False
        self._current_frame = None

        self.exposure = 50
        self.timing_mode = 'timed'  # also 'trigger'
        self.cont_clears = True
        self.latest_image = None
        self.latest_raw_image = None
        self.masked_image = None

        #print 'trying to allocate0', (ct.c_int16 * 10)()

    def __del__(self):
        print('deleting')
        if self.cam_open:
            self.close_cam()
        self.close_lib()

    def read_image(self, exposure, timing='timed', mode='kinetics', new=True, end=True, *args,
                   **kwargs):
        """
        Read an image.

        :param exposure: Exposure time
        :param timing: 'timed' or 'trigger'
        :param mode: 'kinetics'
        :param new: If it is the first sequence in a set then new (True) sets up the sequence
        :param end: If it is the last sequence in a set then end (True) finishes the sequence
        :param kwargs: k_size=1

        :return:
        """
        if new:  # only setup the first time in a set of sequences
            # setup sequence
            if mode == 'kinetics':
                k_size = kwargs['k_size'] if 'k_size' in kwargs else 1
                self.setup_kinetics(exposure, k_size, timing)
        self.start_sequence()  # start acquisition
        while not self.check_readout():  # wait for image
            continue
        image = self.readout_image()  # readout
        if end:  # shutdown sequence if it is the last one
            self.finish_sequence()
        return image

    def open_lib(self):
        if not self.pvcam.pl_pvcam_init():
            raise PixisError("failed to init self.pvcam")
        else:
            print('init self.pvcam complete')

    def close_lib(self):
        self.pvcam.pl_pvcam_uninit()
        print("pvcam closed")

    def open_cam(self, cam_selection):
        cam_name = ct.create_string_buffer(20)
        self._handle = ct.c_int16()
        if not self.pvcam.pl_cam_get_name(cam_selection, cam_name):
            raise PixisError("didn't get cam name")
        if not self.pvcam.pl_cam_open(cam_name, ct.byref(self._handle), pv.OPEN_EXCLUSIVE):
            raise PixisError("camera didn't open")
        self.cam_open = True

    def close_cam(self):
        if self._sequence_set:
            self.finish_sequence()
        self.pvcam.pl_cam_close(self._handle)
        self.cam_open = False
        print('cam closed')

    def set_any_param(self, param_id, param_value):
        b_status = ct.c_bool()
        b_param = ct.c_bool()
        param_access = ct.c_uint16()
        param_id = ct.c_uint32(param_id)

        if not isinstance(param_value, ct._SimpleCData):
            raise TypeError("The parameter value must be passed as a ctypes instance, not a python value.")

        b_status = self.pvcam.pl_get_param(self._handle, param_id,
                                      pv.ATTR_AVAIL, ct.cast(ct.byref(b_param), ct.c_void_p))
        if b_param:
            b_status = self.pvcam.pl_get_param(self._handle, param_id,
                                          pv.ATTR_ACCESS,
                                          ct.cast(ct.byref(param_access), ct.c_void_p))

            if param_access.value == pv.ACC_READ_WRITE or param_access.value == pv.ACC_WRITE_ONLY:
                if not self.pvcam.pl_set_param(self._handle, param_id,
                                          ct.cast(ct.byref(param_value), ct.c_void_p)):
                    print("error: param %d (value = %d) did not get set" % (
                    param_id.value, param_value.value))
                    return False
            else:
                print("error: param %d is not writable: %s" % (param_id.value, param_access.value))
                return False
        else:
            print("error: param %d is not available" % param_id.value)
            return False
        return True

    def get_any_param(self, param_id):
        pass

    def set_full_frame(self, region):
        ser_size = ct.c_uint16()
        self.pvcam.pl_get_param(self._handle, pv.PARAM_SER_SIZE,
                           pv.ATTR_DEFAULT, ct.cast(ct.byref(ser_size), ct.c_void_p))
        par_size = ct.c_uint16()
        self.pvcam.pl_get_param(self._handle, pv.PARAM_PAR_SIZE,
                           pv.ATTR_DEFAULT, ct.cast(ct.byref(par_size), ct.c_void_p))
        region.s1, region.s2, region.p1, region.p2 = (0, ser_size.value - 1,
                                                      0, par_size.value - 1)
        region.sbin, region.pbin = (1, 1)

    def setup_kinetics(self, exposure, k_size, timing='trigger'):
        if self._sequence_set:  # uninitialise all previous sequences
            self.finish_sequence()

        params = {
            pv.PARAM_PMODE: (ct.c_uint32(pv.PMODE_KINETICS), 'pmode'),
            pv.PARAM_KIN_WIN_SIZE: (ct.c_uint16(k_size), 'kinetics window size'),
            pv.PARAM_PAR_SHIFT_TIME: (ct.c_uint32(9200), 'parallel shift time'),
            # pv.PARAM_SER_SHIFT_TIME : (ct.c_uint32(9200), 'serial shift time'),
            pv.PARAM_EXP_RES_INDEX: (ct.c_uint16(pv.EXP_RES_ONE_MICROSEC), 'exposure resolution'),
            pv.PARAM_CLEAR_CYCLES: (ct.c_uint16(1), 'clear cycles'),
            pv.PARAM_NUM_OF_STRIPS_PER_CLR: (ct.c_uint16(1), 'number of clear strips'),
            pv.PARAM_SHTR_OPEN_MODE: (ct.c_uint16(pv.OPEN_PRE_SEQUENCE), 'shutter open mode'),
            pv.PARAM_EDGE_TRIGGER: (ct.c_uint32(pv.EDGE_TRIG_POS), 'edge trigger'),
            pv.PARAM_GAIN_INDEX: (ct.c_uint16(3), 'gain index'),
            # pv.PARAM_CONT_CLEARS : (ct.c_bool(True), 'continuous clears 1'),
        }
        for p in params:
            status = self.set_any_param(p, params[p][0])
            if not status: print('problem with %s' % params[p][1])

        read_params = [
            pv.PARAM_PIX_TIME,
        ]
        for p in read_params:
            self.get_any_param(p)

        if not self.pvcam.pl_exp_init_seq():
            raise PixisError("init_seq failed!")

        exp_time = ct.c_uint32(exposure)
        size = ct.c_uint32()
        region = pv.rgn_type()
        self.set_full_frame(region)

        if timing == 'trigger':
            timing_mode = pv.TRIGGER_FIRST_MODE
        elif timing == 'timed':
            timing_mode = pv.TIMED_MODE
        if self.pvcam.pl_exp_setup_seq(self._handle, 1, 1, ct.byref(region),
                                  timing_mode, exp_time, ct.byref(size)):
            # print "frame size = %d" % size.value
            pass
        else:
            raise PixisError("experiment setup failed!")
        self._sequence_set = True
        self.exposure = exposure
        self.size = size
        self.timing = timing

        if timing == 'trigger':
            # status = self.set_any_param(pv.PARAM_CLEAR_MODE, ct.c_uint16(pv.CLEAR_PRE_SEQUENCE))
            # if not status: print 'problem with clear mode'
            status = self.set_any_param(pv.PARAM_CONT_CLEARS, ct.c_bool(self.cont_clears))
            if not status:
                print('problem with continuous cleans 2')
            # status = self.set_any_param(pv.PARAM_CLN_WHILE_EXPO, ct.c_uint16(1))
            # if not status: print 'problem with clear while exposing'

            # frame = (ct.c_uint16 * (self.size.value//2))()
            # self.pvcam.pl_exp_start_seq(self._handle, frame)
            # self._current_frame = frame

    def start_sequence(self):
        """
        Create a frame and start the kinetics exposure sequence. Call this method
        after setting up the trigger and then wait until check_kinetics confirms
        readout.
        """
        frame = (ct.c_uint16 * (self.size.value // 2))()
        self.pvcam.pl_exp_start_seq(self._handle, frame)
        self._current_frame = frame

    def check_readout(self):
        """
        Poll the readout status and return if the readout is complete or if it
        fails.
        """
        status = ct.c_int16()
        self.pvcam.pl_exp_check_status(self._handle, ct.byref(status),
                                  ct.byref(ct.c_int32()))
        if status.value == pv.READOUT_FAILED:
            raise PixisError("Data collection error")
        elif status.value == pv.READOUT_COMPLETE:
            return True
        else:
            return False

    def readout_image(self):
        """If the readout is complete a valid frame is returned."""
        return np.array(list(self._current_frame)).reshape((256, 1024))

    def finish_sequence(self):
        self.pvcam.pl_exp_finish_seq(self._handle, self._current_frame, 0)
        self.pvcam.pl_exp_uninit_seq()
        self._sequence_set = False

    metadata_property_names = ('exposure',)

    def read_background(self):
        """Acquire a new spectrum and use it as a background measurement."""
        self.background = self.read_image(self.exposure, self.timing, self.mode,
                                          new=True, end=True)
        self.update_config('background', self.background)

    def read_reference(self):
        """Acquire a new spectrum and use it as a reference."""
        self.reference = self.read_image(self.exposure, self.timing, self.mode,
                                         new=True, end=True)
        self.update_config('reference', self.reference)

    def raw_snapshot(self):
        try:
            image = self.read_image(self.exposure, timing='timed', mode='kinetics', new=False, end= True, k_size=1)
            return 1, image
        except Exception as e:
            self._logger.warn("Couldn't Capture because %s" % e)

@inherit_docstring(Pixis256E)
class Pixis256EQt(Pixis256E, QtCore.QObject):
    """Pixis256E subclass with Qt signals for GUI interaction."""

    image_taken = QtCore.Signal(np.ndarray)

    @inherit_docstring(Pixis256E.__init__)
    def __init__(self):
        super(Pixis256EQt, self).__init__()

    @inherit_docstring(Pixis256E.read_image)
    def read_image(self, exposure, timing='timed', mode='kinetics', new=True, end=True, *args,
                   **kwargs):
        image = super(Pixis256EQt, self).read_image(exposure, timing='timed', mode='kinetics',
                                                    new=True, end=True, *args, **kwargs)
        self.image_taken.emit(image)
        return image

class Pixis256EUI(QtWidgets.QWidget, UiTools):
    def __init__(self, pixis):
        if not isinstance(pixis, Pixis256EQt):
            raise TypeError('pixis is not an instance of Pixis256EQt')
        super(Pixis256EUI, self).__init__()
        self.pixis = pixis

        # self.exposure.setValidator(QtWidgets.QIntValidator())
        # self.exposure.textChanged.connect(self.check_state)
        # self.exposure.textChanged.connect(self.on_text_change)
        # self.mode.activated.connect(self.on_activated)
        # self.timing.activated.connect(self.on_activated)
        # self.cont_clears.stateChanged.connect(self.on_state_change)
        # self.take_image_button.clicked.connect(self.on_click)
        # self.take_bkgd_button.clicked.connect(self.on_click)
        # self.clear_bkgd_button.clicked.connect(self.on_click)
        # self.take_ref_button.clicked.connect(self.on_click)
        # self.clear_ref_button.clicked.connect(self.on_click)

        # self.pixis.image_taken.connect()

    def on_text_change(self, text):
        sender = super(Pixis256EUI, self).on_text_change(text)
        if sender == False:
            return
        elif sender == self.exposure:
            self.pixis.exposure = float(sender)

    def on_click(self):
        sender = self.sender()
        if sender == self.take_image_button:
            self.pixis.read_image(self.pixis.exposure, self.pixis.timing, self.pixis.mode,
                                  new=True, end=True)
        elif sender == self.take_bkgd_button:
            self.pixis.read_background()
        elif sender == self.clear_bkgd_button:
            self.pixis.clear_background()
        elif sender == self.take_ref_button:
            self.pixis.read_reference()
        elif sender == self.clear_ref_button:
            self.pixis.clear_reference()

    def on_activated(self, item):
        sender = self.sender()
        if sender == self.mode:
            self.pixis.mode = item
        elif sender == self.timing:
            self.pixis.timing = item

    def on_state_change(self, state):
        sender = self.sender()
        if sender == self.cont_clears:
            if state == QtCore.Qt.Checked:
                self.pixis.cont_clears = True
            elif state == QtCore.Qt.Unchecked:
                self.pixis.cont_clears = False

if __name__ == '__main__':
    import matplotlib.pyplot as plt
    p = Pixis256EQt()
    p.exposure = 1

    def test():
        p.setup_kinetics(p.exposure, 1)
        print(p.check_readout())
        imgs = []
        print('ready')
        shots = 3
        for i in range(shots):
            print('shot {0}'.format(i+1))
            p.start_sequence()
            time.sleep(0.1)
            while not (p.check_readout()): continue
            print("triggered")
            img = p.readout_image()
            imgs.append(img)
        p.finish_sequence()
        time.sleep(0.1)
        img = p.read_image(p.exposure, timing='timed', mode='kinetics', k_size=1)
        imgs.append(img)
        #p.close_cam()
        print('finished')

        print('plotting data')
        fig, axes = plt.subplots(shots+1, sharex=True)
        for i, ax in enumerate(axes):
            img = ax.imshow(imgs[i])
        print('done')
        plt.show()

    print("one")
#    app = get_qt_app()
#    ui = Pixis256EUI(pixis=p)
#    print "two"

#    ui.show()
 #   sys.exit(app.exec_())

    # p.read_image(p.exposure, timing='timed', mode='kinetics', new=True, end= False, k_size=1)
    # img = p.read_image(p.exposure, timing='timed', mode='kinetics', new=False, end= True, k_size=1)
    # plt.imshow(img)
    # plt.show()


print("\n\n/===================================================/")
print("\\===================================================\\")
print("/=========  Tecplot 360 Video/GIF Creator  =========/ ")
print("\\=========       By: Oscar Alvarez         =========\\")
print("/=========             2021                =========/ ")
print("\\=========   mathoscaralvarez@gmail.com    =========\\")
print("/===================================================/ ")
print("\\---------------------------------------------------\\")
print("/----------- PRESS CTRL + 'C' TO EXIT --------------/ ")
print("\\---------------------------------------------------\\")

## Load files
import os

path = os.getcwd()
print("Current Directory: " + path)
f_found = False # Files found boolean
while(not f_found):
    f_begin = input("\nENTER THE FIRST SNAPSHOT NUMBER:  ")
    f_end = int(input("ENTER THE LAST SNAPSHOT NUMBER:  "))
    f_interval = int(input("ENTER THE SNAPSHOT INCREMENT NUMBER:  "))

    # f_begin = str(120100)
    # f_end = 121000
    # f_interval = 100

    snapshot = []
    f_num = f_begin
    f_count = 0
    for f in os.listdir():
        f_name, extension = os.path.splitext(f)
        if f_num in f_name:
            snapshot.append(f_name)
            f_count += 1
            f_num = str(int(f_num) + f_interval)
        if int(f_num) > f_end:
            break

    print("\nFiles Found: ")
    print(*snapshot, sep = '\n') # Printing files separated by new line character
    print("Number of files found:  " + str(f_count))

    confirm = input("\nCONTINUE? [Y/y for YES; ANY KEY to TRY AGAIN]:  ")
    f_found = (confirm.lower() == 'y') # Checks if the files were found

# Optional file for plotting stream traces
# seed_file = os.path.join(path, "seedpoints.txt")

## Starting up Tecplot
import logging
import sys
import tecplot as tp
from tecplot.plot import IsosurfaceGroup
from tecplot.constant import *

print("Opening Tecplot ...\n")
logging.basicConfig(level=logging.DEBUG)
if '-c' in sys.argv:
    tp.session.connect()

print("Tecplot Open.")

#### Creating Tecplot Images

## Creating Temporary Image Folder
img_fname = f_begin + '-' + str(f_end) + ' Images' # Image folder name

# Check if temporary folder already exists, if not create it.
if not os.path.isdir(img_fname) : os.mkdir(img_fname)
img_fpath = os.path.join(path, img_fname)

func_file = [None] * f_count
grid_file = [None] * f_count
for i in range(f_count):
    ## Read Files
    print("Reading " + snapshot[i] + " ...")

    ## Creating function (.fun) and grid (.xyz) files
    func_file[i] = os.path.join(path, snapshot[i] + '.fun')
    grid_file[i] = os.path.join(path, snapshot[i] + '.xyz')

    tp.new_layout() # Deleting old layout and starting a new one

    # Opening grid and function file in Tecplot
    dataset = tp.data.load_plot3d(grid_filenames=grid_file[i], function_filenames=func_file[i])
    print("\t" + snapshot[i] + " Loaded.")

    print("\tConfiguring Settings ...")
    ## Setup frame as Cartesinan 3D
    frame = tp.active_frame()
    frame.plot_type = tp.constant.PlotType.Cartesian3D
    plot = frame.plot()

    ## Camera View Settings
    #view = plot.view
    #view.psi = 65.777
    #view.theta = 166.415
    #view.alpha = -1.05394
    #view.position = (-23.92541680486183, 101.8931504712126, 47.04269529295333)
    #view.width = 1.3844

    ## Iso Surface / Contour Settings
    plot.show_isosurfaces = True
    contour = plot.contour(0)
    contour.colormap_name = 'Magma'
    contour.variable = dataset.variable('F1V11') # Set Liutex Magnitude as Iso-Surface
    contour.legend.show = True

    iso = plot.isosurface(0)
    iso.show = True
    iso.definition_contour_group = contour
    iso.isosurface_selection = IsoSurfaceSelection.OneSpecificValue
    iso.isosurface_values = 0.2 # Value of Iso surface that will be drawn
    iso.shade.use_lighting_effect = True
    iso.effects.lighting_effect = LightingEffect.Gouraud
    iso.contour.show = True
    iso.contour.contour_type = ContourType.Flood

    ## Liutex Lines (stream traces)
    #plot.show_streamtraces = True

    ## Set up plot stream trace variables
    #plot.vector.u_variable = dataset.variable('F1V8')   # Liutex_x
    #plot.vector.v_variable = dataset.variable('F1V9')   # Liutex_y
    #plot.vector.w_variable = dataset.variable('F1V10')  # Liutex_z

    ## Setup slices
    #plot.show_slices = True

    print("\tSettings Configured.")

    ## Saving as .png image
    print("\tSaving PNG Image ...")
    img_name = snapshot[i] + '.png'
    img_file = os.path.join(img_fpath, img_name)
    tp.export.save_png(img_file, 1200, supersample=3) # save_png(img_name, [SIZE in pixels] of the image, anti-aliasing)
    print(snapshot[i] + " PNG Image Saved.\n")

## Close Tecplot
tp.session.stop()
print("Tecplot closed.\n")

#### Creating Video from Images
import moviepy.editor

# Entering Folder that Contains Pictures
os.chdir(img_fpath)
print("New Current Folder: ")
print(os.getcwd())

#### Pictures per second
fps = 2
####

# Saving All Picture Names into a List
frames = []
pics = [ f for f in os.listdir() if f.lower().endswith('.png') ]

# Creating Temporary Video Clip Object
clip = moviepy.editor.ImageSequenceClip(pics, fps)

# Creating Video File Name
vid_name = f_begin + '-' + str(f_end) + ' Video.MP4'
vid_file = os.path.join(path, vid_name)

# Saving Video File
clip.write_videofile(vid_file)

# Creating Video File Name
gif_name = f_begin + '-' + str(f_end) + ' GIF.gif'
gif_file = os.path.join(path, gif_name)

# Saving a GIF File
clip.write_gif(gif_file, fps=4)


from rest_framework.serializers import ModelSerializer

from people.models import User

class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        lookup_field = 'username'

        exclude = (
            'groups',
            'is_staff',
            'is_superuser',
            'user_permissions',
            'password',
            'is_active',
            'date_joined',
            'birth_date'
        )
        extra_kwargs = {
            'url': {'lookup_field': 'username'},
            'ssn': {'write_only': True},
            'license': {'write_only': True},
        }


from selenium import webdriver

from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
import time

PATH= "../crawldata-shopee/chromedriver.exe"
driver= webdriver.Chrome(PATH)

driver.get("https://shopee.vn/")
time.sleep(5)

search = driver.find_element(By.CLASS_NAME,"shopee-searchbar-input__input")
search.send_keys('áo khoác')
search.send_keys(Keys.RETURN)
time.sleep(5)

show_topseller = driver.find_element(By.XPATH,'/html/body/div[1]/div/div[2]/div/div/div[2]/div[3]/div[1]/div[1]/div[3]')
show_topseller.click()
time.sleep(5)
#--------------------------Tên sản phẩm
#elems= driver.find_elements(By.XPATH, "//div[@class='FDn--+']")
#for elem in elems:
#    title= elem.text
#    print(title)

#--------------------------Link sản phẩm(!!!!!!)
elems_link= driver.find_elements(By.CLASS_NAME, 'col-xs-2-4.shopee-search-item-result__item')
#print(elems_link)

for elems in elems_link:
    link = elems.find_elements(By.XPATH, "//a[@href]")
    #a= link.__getattribute__("href")
    #print(a)
    #print(link)

#------------------------Tên shop(!!!!!!!)
#elems_shop= driver.find_elements(By.CSS_SELECTOR,'_3LoNDM')
#print(elems_shop)
#for elem in elems_shop:
#    shop= elem.text
#    print(shop)

#------------------------Số người mua
#elems_countbuyers = driver.find_elements(By.XPATH, "//div[@class='r6HknA uEPGHT']")
#for elem in elems_countbuyers:
#    countBuyers= elem.text
#    print(countBuyers)

time.sleep(120)
driver.quit()


from django.shortcuts import redirect, render, get_object_or_404
from .models import Movie
from django.http import JsonResponse
from django.contrib.auth import get_user_model

# Create your views here.
def index(request):
    if request.user.is_authenticated:
        movies = Movie.objects.all()
        context = {
            'movies': movies,
        }
        return render(request, 'movies/index.html', context)
    return redirect('accounts:login')

def detail(request, movie_pk):
    if request.user.is_authenticated:
        movie = get_object_or_404(Movie, pk=movie_pk)
        context = {
            'movie': movie,
        }
        return render(request, 'movies/detail.html', context)
    return redirect('accounts:login')

def search(request):
    if request.user.is_authenticated:
        if request.method == 'POST':
            searched = request.POST['search']
            User = get_user_model()
            users = User.objects.filter(username__contains=searched)
            movies = Movie.objects.filter(title__contains=searched)
            return render(request, 'movies/search.html', {'searched': searched, 'movies': movies, 'users': users,})
        return render(request, 'movies/search.html')
    return redirect('accounts:login')

def like(request, movie_pk):
    if request.user.is_authenticated:
        movie = get_object_or_404(Movie, pk=movie_pk)

        if movie.like_users.filter(pk=request.user.pk).exists():
            # 좋아요 취소
            movie.like_users.remove(request.user)
            liked = False
        else:
            # 좋아요 누름
            movie.like_users.add(request.user)
            liked = True

        data = {
            'liked':liked,
            'like_count':movie.like_users.count(),
        }
        return JsonResponse(data)
    return redirect('accounts:login')

def likelist(request, username):
    if request.user.is_authenticated:
        User = get_user_model()
        person = User.objects.get(username=username)
        context = {
            'person': person,
        }
        return render(request, 'movies/likelist.html', context)
    return redirect('accounts:login')


import copy
import typing

def read_input(filename):
    with open(filename) as f:
        return f.read().splitlines()

def acc(accumulator, instructions_now, value):
    accumulator += value
    instructions_now += 1
    return accumulator, instructions_now

def jmp(accumulator, instructions_now, value):
    instructions_now += value
    return accumulator, instructions_now

def nop(accumulator, instructions_now, value):
    instructions_now += 1
    return accumulator, instructions_now

actions = {
    "acc": acc,
    "jmp": jmp,
    "nop": nop,
}

def prep_instructions(file) -> typing.List[typing.List[typing.Union[str, int]]]:
    instructions = []
    for i in range(len(file)):
        foo = file[i].split(' ')
        instructions.append([foo[0], int(foo[1])])
    return instructions

def part1(instructions):
    len_inst = len(instructions)
    accumulator = 0
    no_repeats = True
    instructions_done = []
    instructions_now = 0
    while no_repeats:
        if instructions_now == len_inst:
            code = 'ok'
            break
        if instructions_now in instructions_done:
            code = 'inf'
            break
        instructions_done.append(instructions_now)
        instruction = instructions[instructions_now]
        accumulator, instructions_now = actions[instruction[0]](
            accumulator, instructions_now, instruction[1])
    return code, accumulator

def part2(instructions):
    for i in range(len(instructions)):
        instructions_copy = copy.deepcopy(instructions)
        if instructions_copy[i][0] == 'jmp':
            instructions_copy[i][0] = 'nop'
        elif instructions_copy[i][0] == 'nop':
            instructions_copy[i][0] = 'jmp'
        else:
            continue
        code, accu = part1(instructions_copy)
        if code == 'ok':
            break
    return code, accu

def main():
    file = read_input("input")
    instructions = prep_instructions(file)
    print('p1: ', part1(instructions))
    print('p2: ', part2(instructions))

if __name__ == "__main__":
    main()


#!/usr/bin/python3

import os
import telnetlib
import configparser
import textwrap
import time, datetime
import termios
import atexit
from select import select
import argparse
from pycrt import *
import base64
import ansimg
import re

import pdb

BBSLISTFILE = "https://www.telnetbbsguide.com/bbslist/bbslist.csv"

ZMODEMSTR = ""

KBENTER = chr(10)
KBBACK = chr(127)
KBTAB = chr(9)
KBESC = chr(27)
KBCTRLA = chr(1)
KBCTRLW = chr(23)
KBCTRLN = chr(14)
KBCTRLL = chr(12)
KBBACKSP = chr(8)

ANSICODES = ['A','B','C','D','E','F','G','l','N','O','P','m','n','s','u','J','H','f','h','K']

KBF1 = 'OP'
KBF2 = 'OQ'
KBF3 = 'OR'
KBF4 = 'OS'
KBF5 = '[15'
KBF6 = '[17'
KBF7 = '[18'
KBF8 = '[19'
KBF9 = '[20'
KBF10 = '[21'

KBPAGE_UP = '[5~'
KBPAGE_DOWN = '[6~'
KBHOME = '[H'
KBEND = '[F'
KBINSERT = '[2~'
KBDEL = '[3~'

KBUP = chr(27)+'[A'
KBDOWN = chr(27)+'[B'
KBLEFT = chr(27)+'[D'
KBRIGHT = chr(27)+'[C'

config_input = (12,23,64,255) #x, y, width, maxsize
config_input_gfx_lo = (1,22)
config_input_gfx_hi = config_input_gfx_lo
config_input_attr = 7+16
config_input_fillattr = 1

x,y=1,1
oldxy = [1,1]
WIDTH,HEIGHT=80,25
fattr = 7
mode = 0
CRLF = chr(10)+chr(13)
BEEP=False

opt = ''
esc = False

APPNAME = "telnite"
CONFIGDIR = os.path.join(os.path.expanduser("~"), ".config")+os.sep+APPNAME+os.sep
TMPDIR = '/tmp/'
CONFIG = configparser.ConfigParser(interpolation=None)

QUITEMODE = False
CAPTURE=False
CAPTUREFILE = ''
ENABLEKEYSOUND = False
KBKEYSOUND = ''
KBENTERSOUND = ''
MODEMSOUND = ''
STATUSBAR = '30'

HOST = ""
PORT = 23
BBS = {}
BBS['name'] = ''
BBS['username'] = ''
BBS['password'] = ''
BBS['comment'] = ''
BBS['sysop'] = ''
BBS['software'] = ''
BBS['sounds'] = False
BBS['address'] = ''
BBS['host'] = ''
BBS['www'] = ''
BBS['location'] = ''
BBS['sysop'] = ''
BBS['index'] = ''

REGEX = []
TEXT = ""

program_descripton = f'''
    Telnite v1.0
    -------------

    An ANSI-BBS telnet client for use in terminals like Gnome_terminal, xterm, etc.

    Created by XQTR of Another Droid BBS

    [] https://github.com/xqtr/telnite
    [] telnet://andr01d.zapto.org:9999

    Licensed under GPL3

    '''

cs_numbers = " 1234567890"
cs_phone = " 1234567890#+-/"
cs_upper = " QWERTYUIOPASDFGHJKLZXCVBNM"
cs_lower = " qwertyuiopasdfghjklzxcvbnm"
cs_symbols = " ~-=!@#$%^&*()_+[]}{;:'\"\|,<.>/?"
cs_printable = cs_lower+cs_upper+cs_symbols+cs_numbers
cs_email = cs_numbers+cs_lower+cs_upper+"@."
cs_email = cs_email.replace(" ", "")
cs_www = cs_numbers+cs_upper+cs_lower+"/-.:"

telnet = telnetlib.Telnet()

def termux():
  global CONFIGDIR,TMPDIR
  CONFIGDIR = os.path.join(os.path.expanduser("~"), ".config")+os.sep+APPNAME+os.sep
  s = os.path.expanduser("~")
  if "com.termux" in s:
    TMPDIR = '/data/data/com.termux/files/usr/tmp/'
  else:
    TMPDIR = '/tmp/'

class RawFormatter(argparse.HelpFormatter):
  def _fill_text(self, text, width, indent):
    return "\n".join([textwrap.fill(line, width) for line in textwrap.indent(textwrap.dedent(text), indent).splitlines()])

def statusbar(s):
  global WIDTH,HEIGHT,STATUSBAR
  writexy(1,HEIGHT,int(STATUSBAR),s.ljust(WIDTH))

def str2bool(v):
  return v.lower() in ("yes", "true", "t", "1")

def initoBBS(filename):
  global BBS
  parser = configparser.ConfigParser()
  parser.read(filename)

  for option in parser.options("BBS-Info"):
    BBS[option] = parser.get("BBS-Info", option)
  BBS['sounds'] = str2bool(BBS['sounds'])

def readconfigfile():
  global CONFIG,BEEP,WIDTH,HEIGHT,KBBACKSP,ENABLEKEYSOUND,KBKEYSOUND,KBENTERSOUND
  global MODEMSOUND,STATUSBAR,REGEX

  if not os.path.isdir(CONFIGDIR):
    os.makedirs(CONFIGDIR)

  all_config_files = [CONFIGDIR+APPNAME+'.ini', '/etc/'+APPNAME+'.ini', APPNAME+'.ini']
  CONFIG.read(all_config_files)

  BEEP = CONFIG.getboolean("system","beep",fallback=False)
  WIDTH = CONFIG.getint("system","width",fallback=80)
  HEIGHT = CONFIG.getint("system","height",fallback=25)
  KBBACKSP = chr(CONFIG.getint("system","backspace",fallback=8))
  STATUSBAR =  CONFIG.get("system","statusbar",fallback='30')

  ENABLEKEYSOUND = CONFIG.getboolean("sounds","enable",fallback=False)
  KBKEYSOUND = CONFIG.get("sounds","key",fallback='')
  KBENTERSOUND = CONFIG.get("sounds","enter",fallback='')
  MODEMSOUND = CONFIG.get("sounds","modem",fallback='')

  ind=1
  while True:
    if CONFIG.has_section("regex_"+str(ind)):
      section = "regex_"+str(ind)
      rx = {}
      rx['name'] = CONFIG.get(section,'name')
      rx['regex'] = CONFIG.get(section,'regex')
      rx['cmd'] = CONFIG.get(section,'command')
      REGEX.append(rx)
      ind+=1
    else:
      break

def downloadfile(url,filename):
  os.system("wget {} -O {}".format(url,filename))

def displayansi(screen):
  global utf
  if utf:
    print(''.join(str(screen,"cp437")))
  else:
    os.write(1, screen)

def bbslistselect(term):
  global HOST,PORT,BBS
  files = [f for f in os.listdir(CONFIGDIR) if f!=APPNAME+'.ini' and term.lower() in f.lower()]
  if len(files)==0:
    print("No matching BBSes!")
    return False

  print("Results:")
  print("{:>3}) {:30.30}".format('Num','Address'))
  for i,f in enumerate(files):
    print("{:>3}) {:30.30}".format(i,f[:-4]))

  try:
    a= int(input("Select:"))
  except:
    print("Invalid Selection.")
    return False

  #print(files[a])
  initoBBS(CONFIGDIR + files[a])

  HOST = BBS['address'].split(':')[0]
  PORT = BBS['address'].split(':')[1]
  return True

def bbstglistselect(term):
  global HOST,PORT,BBS,TMPDIR
  lf = TMPDIR + "bbslist.csv"
  if not os.path.isfile(lf):
    downloadfile(BBSLISTFILE,lf)
  if not os.path.isfile(lf):
    print("BBS List File not found. Perhaps download failed.")
    return False

  csv = open(lf,"r")
  lines = csv.readlines()
  csv.close()

  termt = term.upper()
  bbses = []

  for line in lines:
    if termt in line.upper():
      bbses.append(line)

  if len(bbses)==0:
    print("No matching BBS found.")
    return False

  print("Results:")
  print("{:>3}) {:30.30} {:30.30}:{:5}".format('Num','Name','Address','Port'))
  for i,bbs in enumerate(bbses):
    flds=bbs.split(',')
    print("{:>3}) {:30.30} {:30.30}:{:5}".format(i,flds[0],flds[3],flds[4]))

  try:
    a= int(input("Select:"))
  except:
    print("Invalid Selection.")
    return False

  flds = bbses[a].split(',')

  HOST = flds[3]
  if flds[4]!='':
    PORT = flds[4]
  else:
    PORT = 23

  BBS['name'] = flds[0]
  BBS['address'] = HOST
  BBS['sysop'] = flds[1]
  BBS['www'] = flds[6]
  BBS['location'] = flds[7]
  BBS['modem'] = flds[8]
  return True

def togglecapture():
  global CAPTURE,CAPTUREFILE
  CAPTURE=not CAPTURE
  if CAPTURE:
    CAPTUREFILE=time.strftime("capture_%Y%m%dT%H%M%SZ.ans", time.gmtime())
  return CAPTURE

def getfilename():
  global HOST
  ind = 0
  while True:
    if not os.path.isfile(HOST+'_'+str(ind).zfill(5)+'.ans'):
      return HOST+'_'+str(ind).zfill(5)+'.ans'
      break
    else:
      ind+=1

def approximate_size(size, flag_1024_or_1000=True):
  units = {1000: ['KB', 'MB', 'GB'], 1024: ['KiB', 'MiB', 'GiB']}
  mult = 1024 if flag_1024_or_1000 else 1000
  for unit in units[mult]:
    size = size / mult
    if size < mult:
      return '{0:.3f} {1}'.format(size, unit)

def createconfigfile(path):
  with open(os.path.join(path,APPNAME+".ini"),"w+") as fn:
    fn.write("[system]\n")
    fn.write("beep=0\n")
    fn.write("width=80\n")
    fn.write("height=25\n")
    fn.write("#ASCII key code for use in BACKSPACE press\n")
    fn.write("#8 is Backspace\n")
    fn.write("#127 is Delete\n")
    fn.write("backspace=8\n")
    fn.write("statusbar=30\n")
    fn.write("\n")
    fn.write("#Keyboard CLICK sounds\n")
    fn.write("[sounds]\n")
    fn.write("enable=0\n")
    fn.write("#Enter full path and filename to sound file\n")
    fn.write("key=\n")
    fn.write("enter=\n")
    fn.write("modem=\n")
    fn.write("\n")
    fn.write("[regex_1]")
    fn.write("Name=Email")
    fn.write("RegEx=[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}")
    fn.write("Command=")
    fn.write("\n")
    fn.write("[regex_2]")
    fn.write("Name=Date")
    fn.write("RegEx=\d{1,2}[-_/]\d{1,2}[-_/]\d{4}")
    fn.write("Command=")
    fn.write("\n")
    fn.write("[regex_3]")
    fn.write("Name=BBS Node Address")
    fn.write("RegEx=\d{1,3}:\d{1,4}\/\d{1,3}")
    fn.write("Command=%P/nodefinder/node.py '%M'")
    fn.write("\n")
    fn.write("[regex_4]")
    fn.write("Name=URL/HTTP")
    fn.write("RegEx=https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)")
    fn.write("Command=firefox %M")
    fn.write("\n")
    fn.write("[regex_5]")
    fn.write("Name=URL/Gopher")
    fn.write("RegEx=gopher:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)")
    fn.write("Command=lynx %M")
    fn.write("\n")
    fn.write("[regex_6]")
    fn.write("Name=Magnet Link")
    fn.write("RegEx=magnet:\?xt=urn:(btih:)?[A-Za-z0-9]{32,42}")
    fn.write("Command=transmission-gtk %M")
    fn.write("\n")
    fn.write("[regex_7]")
    fn.write("Name=ZIP Code")
    fn.write("RegEx=[0-9]\{5\}(-[0-9]\{4\})?")
    fn.write("Command=")

  print("")
  print("Config file created at path:")
  print(path)
  print("If this is the current folder you are in, consider moving it, at")
  print("the system config path, which is:")
  print(CONFIGDIR)
  print("All other config/app related files are saved there also.")
  print("")

def findregex():
  global screenbuffer,screenheight,screenwidth,REGEX,TEXT
  found = False
  results = []
  ui.savescreen()
  ix,iy = 3,3
  a = textattr
  textcolor(7)
  clrscr()
  writexy(1,1,7,"Results:")
  writexy(1,2,7,"{:2} {:15} {:50}".format('##','Type','Result'))

  i=0
  for rx in REGEX:
    res = re.findall(rx['regex'], TEXT)
    if res:
      #print("M>>>"+m.group())
      found = True
      for r in res:
        writexy(1,iy,7,"{:2} {:15} {:50}".format(str(i),rx['name'],str(r)))
        i+=1
        s = rx['cmd']
        s = s.replace('%M',str(r))
        results.append(s)
        iy+=1

  if not found:
    writexy(1,4,7,'No RegEx matches found... Press key to continue.')
    ui.kb.readkey()
  else:
    print("")
    try:
      a= int(input("Enter selection:"))
      os.system(results[int(a)])
    except:
      print("Invalid Selection.")

  ui.restorescreen()
  textcolor(a)

def clicksound(c):
  global ENABLEKEYSOUND,KBKEYSOUND,KBENTERSOUND

  if ENABLEKEYSOUND==False: return

  if c==chr(10):
    os.system("play -q "+KBENTERSOUND+" >> /dev/null 2>&1")
  else:
    os.system("play -q "+KBKEYSOUND+" >> /dev/null 2>&1")

def logopt(s):
  with open('opts.log','a+') as optfile:
    optfile.write(s+"\r\n")

def beep():
  if BEEP:
    os.system("play -n -c1 synth 0.2 sine 500")

def renderansi(ansi):
  global x,y,WIDTH,HEIGHT,TEXT,ZMODEMSTR
  global fattr,oldxy,mode,esc,opt

  def checkxy():
    global x,y,WIDTH,HEIGHT
    if x>WIDTH:
      x=1
      y+=1
    if y>HEIGHT:
      write(CRLF)
      x=1
      y=HEIGHT

  ansifg = range(30,38)
  ansibg = range(40,48)
  pipefg = [0,4,2,6,1,5,3,7]

  ansicolor = {30:0, 31:4, 32:2, 33:6, 34:1, 35:5, 36:3, 37:7, 38:0, 39:0, 40:0, 41:64, 42:32, 43:96, 44:16, 45:80, 46:48, 47:112}
  bottom = 0

  if len(ansi) == 0:
    return ''

  i = 0
  s=ansi

  while i<len(s):
    if not esc:
      if s[i] == chr(27):
        esc = True
      elif s[i] == chr(0):
        pass
      elif s[i] == chr(24): #zmodem?
        if len(s)-i>3:
          zstr = s[i+1:i+5]
          if zstr.strip() == 'B000': #download
            os.system(ZMODEMSTR)
          elif zstr.strip() == 'B001': #upload
            pass
        else:  #not enough chars to check if it's a zmodem request
          writexy(x,y,fattr,s[i])
          TEXT += s[i]
          esc=False
          x += 1
          checkxy()
      elif s[i] == chr(8): #backspace
        x = max(1,x-1)
        gotoxy(x,y)
      elif s[i] == chr(9):
        #x+=4
        x=min(x+4,WIDTH)
        gotoxy(x,y)
      elif s[i] == chr(7): #BEEP
        x+=1
        checkxy()
        beep()
      elif s[i] == chr(12):
        clrscr()
        TEXT = ''
        x=1
        y=1
      elif s[i]==chr(14):
        write('X')
      elif s[i]==chr(15):
        write('X')
      elif s[i]==chr(13):
        x = 1
        checkxy()
        gotoxy(x,y)
      elif s[i]==chr(10):
        #x = 1
        y+=1
        checkxy()
        gotoxy(x,y)
      else:
        writexy(x,y,fattr,s[i])
        TEXT += s[i]
        esc=False
        x += 1
        checkxy()
    else:
      if s[i] == '[':
        pass
      elif s[i] in ANSICODES:
        if s[i] == 'C': #forward
          tx = x
          if opt != '': d = int(opt)
          else: d =1
          x=min(x+d,WIDTH)
          gotoxy(x,y)
        elif s[i] == 'A': #up
          if opt != '': d = int(opt)
          else: d = 1
          y=max(y-d, 1)
          gotoxy(x,y)
        elif s[i] == 'B': #down
          if opt != '': d = int(opt)
          else: d =1
          y=min(y+d,HEIGHT)
          gotoxy(x,y)
        elif s[i] == 'D': #back
          if opt != '' :
            try:
              d = int(opt)
            except:
              d = 1
          else:
            d = 1
          x=max(x-d, 1)
          gotoxy(x,y)
        elif s[i] == 'G': # goto to column
          if opt != '':
            d = int(opt)
            x = d
            gotoxy(x,y)
        elif s[i] == 'h': # terminal codes -> https://man7.org/linux/man-pages/man4/console_codes.4.html
          write(chr(27)+'['+opt+'h')
        elif s[i] == 'l':
          write(chr(27)+'['+opt+'l')
        elif s[i] == 'n': #report cursor position
          if len(opt)==0:
            pass
          else:
            d = int(opt)
            if d == 6:
              telnet.write(str(chr(27)+ '[' + str(wherey) + ';' + str(wherex) + 'R').encode("ascii"))
            elif d == 5:
              telnet.write(str(chr(27)+'[0n').encode("ascii")) #terminal ok

        elif s[i] == 's': #save cursor
          oldxy = [x,y]
        elif s[i] == 'u': #restore cursor
          x,y = oldxy
        elif s[i] == 'J': #clear entire screen
          if opt == '': opt = '2'
          if int(opt)==2:
            x = 1
            y = 1
            clrscr()
            TEXT = ''
        elif s[i] == 'l': #reset mode? nope
          pass
        elif s[i] == 'K': #clear EOL
#          pdb.set_trace()
          if opt=="": opt="0"
          p = int(opt)
          if p == 2: #erase complete line
            for d in range(1,WIDTH+1):
              writexy(d,y,fattr,' ')
          elif p == 1: #from start to current pos
            for d in range(1,x+1):
              writexy(d,y,fattr,' ')
          elif p == 0 : #from current pos to EOL
            for d in range(x,WIDTH+1):
              writexy(d,y,fattr,' ')
        elif s[i] =='H' or s[i] == 'f': #gotoxy
          if len(opt)==0:
            x,y = [1,1]
          else:
            k=opt.split(';')
            if len(k)>2:
              pass
            elif len(k)==2:
              y=int(k[0])
              x=int(k[1])
              gotoxy(x,y)
            else:
              pass

        elif s[i]=='m': # set color mode!
          if opt=="":
            fattr = 7
            textcolor(fattr)
          else:
            codes=opt.split(';')

            for code in codes:
              num = int(code)
              if num == 0:
                mode = 0
                fattr=7
                textcolor(fattr)
              elif num == 1:
                mode = 1
                fattr = fattr | 0x08
                textcolor(fattr)
              elif num == 5:
                mode = 5
                fattr = fattr | 0x80
                textcolor(fattr)
              elif num == 7:
                fattr = fattr // 16 + ((fattr % 16)*16)
                textcolor(fattr)
              elif num == 8: #conceal
                fg = fattr % 16
                fattr = fg + (fg*16)
                textcolor(fattr)
              elif num in ansifg:
                fg = ansicolor[num]
                bg = fattr // 16
                if mode==1:
                  if fg<8: fg+=8
                fattr = fg + (bg*16)
                textcolor(fattr)
              elif num in ansibg:
                fattr = (fattr % 16 + ansicolor[num])
                textcolor(fattr)

        opt = ''
        esc=False
      else:
        if s[i] in "0123456789?;": opt += s[i]
    i+=1

class KBHit():

  def __init__(self):
    # Save the terminal settings
    self.fd = sys.stdin.fileno()
    self.new_term = termios.tcgetattr(self.fd)
    self.old_term = termios.tcgetattr(self.fd)

    # New terminal setting unbuffered
    self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
    termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)

    # Support normal-terminal reset at exit
    atexit.register(self.set_normal_term)

  def set_normal_term(self):
    ''' Resets to normal terminal.  On Windows this is a no-op.
    '''
    termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)

  def getch(self):
    ''' Returns a keyboard character after kbhit() has been called.
        Should not be called in the same program as getarrow().
    '''
    return sys.stdin.buffer.raw.read(4).decode(sys.stdin.encoding)
    #return sys.stdin.read(3)

  def readkey(self):
    return self.getch()

  def getarrow(self):
    ''' Returns an arrow-key code after kbhit() has been called. Codes are
    0 : up
    1 : right
    2 : down
    3 : left
    Should not be called in the same program as getch().
    '''
    c = sys.stdin.read(3)[2]
    vals = [65, 67, 66, 68]
    return vals.index(ord(c.decode('utf-8')))

  def kbhit(self):
    dr,dw,de = select([sys.stdin], [], [], 0)
    return dr != []

  def checkkey_nonblock(self):
    global x,BBS
    if self.kbhit():
      self.key = self.getch()

      clicksound(self.key)
      if self.key==chr(10):
        telnet.write(b'\r')
      elif self.key==chr(12): #CTRL-L
        telnet.write(BBS['username'].encode('cp437'))
        telnet.write(b'\r')
        telnet.write(BBS['password'].encode('cp437'))
        telnet.write(b'\r')
      elif self.key==chr(18): #CTRL-R find regex
        findregex()
      elif self.key==chr(1): #CTRL-A Save screen
        fn = getfilename()
        savescreen2ansi(fn)
        statusbar('Screen saved in: '+fn)
      elif self.key==chr(9):
        telnet.write(b'\t')
      #elif self.key==chr(8):
      elif self.key==chr(127):
        #telnet.write(b'\b')
        telnet.write(KBBACKSP.encode("ascii"))
        write(KBBACKSP)
      elif self.key==KBF10 or self.key==KBCTRLW:
        ui.menu()
      else:
        telnet.write(self.key.encode('cp437'))

class UserInterface:
  # Uses the curses terminal handling library to display a chat log,
  # a list of users in the current channel, and a command prompt for
  # entering messages and application commands.
  badwords = []
  hilites = []
  history = []
  history_index = 0

  def __init__(self):
    self.inputstring = ''
    self.colors = 16
    self.kb = KBHit()
    self.logintime = 0
    self.totaldatabytes = 0

  def getyesno(self,x,y,trueat,falseat,offat,default):
    """
    Function to get a Yes/No answer
    trueat  : color in byte value for the No button
    falseat : color in byte value for the Yes button
    default : True/False to begin with
    """
    key = ""
    val = {0:'No ',1:'Yes'}
    res = default
    while key != KBENTER:
        writexy(x,y,offat,val[True]+val[False])
        if res == True:
            writexy(x,y,trueat,val[res])
        else:
            writexy(x+3,y,falseat,val[res])
        gotoxy(1,HEIGT)
        key = self.kb.readkey()
        if key == KBLEFT or key == KBRIGHT or key == " ":
            res = not res
        elif key == KBESC:
            return None
            break
    #return val[res].lower().strip(" ")
    return res

  def xinput(self,x,y,att,fillatt,chars,length,maxc,fc,default):
    """
    Simple function to get an input from user
    att    : fg color
    fillatt: bg color
    chars  : string with valid characters.
    length : length for the input box
    maxc   : maximum size for the string to be entered
    fc     : fill character for the bg
    default: default value
    """
    pos = 0
    res = default
    key = ""
    while key != KBENTER:
        writexy(x,y,fillatt,fc*length)
        writexy(x,y,att,res[pos:length+pos])
        gotoxy(x+len(res[pos:length+pos]),y)
        key = self.kb.readkey()

        if key in chars:
            res = res + key
            if len(res)>length:
                if len(res)<maxc:
                    pos += 1
        elif key == " ":
            res = res + " "
            if len(res)>length:
                if len(res)<maxc:
                    pos += 1
        elif key == KBBACK:
            res = res[:-1]
            pos = pos - 1
            if pos < 0:
                pos = 0
        elif key == KBCTRLA:
            res = ""
        elif key == KBENTER:
            break
        elif key == KBESC:
            res = "-1"
            break
    writexy(x,y,fillatt,fc*length)
    writexy(x,y,fillatt,res[:length])
    return res

  def savescreen(self):
    print(chr(27)+"[?1049h")

  def restorescreen(self):
    print(chr(27)+"[?1049l")

  def savebbsmenu(self):
    global BBS,HOST,PORT
    clrscr()
    displayansi(ansimg.BGSCR)
    xx,yy = 17,10
    dd = 16
    aa = 15+16*3

    while True:
      writexy(xx,yy,7,"Enter BBS Name:")
      a = self.xinput(xx+dd,yy,aa,aa,cs_printable,35,35,' ',BBS['name'])
      if a!="-1": BBS["name"] = a
      yy+=1
      writexy(xx,yy,7,"Enter UserName:")
      a = self.xinput(xx+dd,yy,aa,aa,cs_printable,35,35,' ',BBS['username'])
      if a!="-1": BBS["username"] = a
      yy+=1
      writexy(xx,yy,7,"Enter Password:")
      a = self.xinput(xx+dd,yy,aa,aa,cs_printable,35,35,' ',BBS['password'])
      if a!="-1": BBS["password"] = a
      yy+=1
      writexy(xx,yy,7,"Enter Comment :")
      a = self.xinput(xx+dd,yy,aa,aa,cs_printable,35,35,' ',BBS['comment'])
      if a!="-1": BBS["comment"] = a
      yy+=1
      writexy(xx,yy,7,"Enter Software:")
      a = self.xinput(xx+dd,yy,aa,aa,cs_printable,35,35,' ',BBS['software'])
      if a!="-1": BBS["software"] = a
      yy+=1
      writexy(xx,yy,7,"Enter Location:")
      a = self.xinput(xx+dd,yy,aa,aa,cs_printable,35,35,' ',BBS['location'])
      if a!="-1": BBS["location"] = a
      yy+=1

      writexy(xx,yy,7,"Use Sound FXs?")
      BBS["sounds"] = self.getyesno(xx+dd,yy,aa,3*16,7,BBS["sounds"])
      yy+=1

      writexy(xx,yy,7,"Is the info entered correct?")
      a = self.getyesno(xx+dd+14,yy,aa,3*16,7,False)
      if a:
        BBS["address"] = HOST+":"+str(PORT)
        BBS['port'] = PORT
        parser = configparser.ConfigParser()
        parser.add_section('BBS-Info')
        for key in BBS.keys():
          parser.set('BBS-Info', key, str(BBS[key]))

        with open(CONFIGDIR + HOST+'.ini', 'w') as f:
          parser.write(f)

        break
      writexy(xx,yy,7," "*40)
      xx,yy = 17,10

    displayansi(ansimg.BGSCR)

  def menu(self):
    global ENABLEKEYSOUND,CAPTURE,CAPTUREFILE,BBS
    self.savescreen()

    displayansi(ansimg.BGSCR)
    while True:
      xx,yy = 4,8
      writexypipe(xx,yy,7,40-xx,'|14S|08: |07Save BBS'); yy+=1
      writexypipe(xx,yy,7,40-xx,'|14M|08: |07Toggle Sounds [Active:|15{:5}|07]'.format(str(ENABLEKEYSOUND))); yy+=1
      writexypipe(xx,yy,7,40-xx,'|14C|08: |07Toggle Capture [Active:|15{:5}|07]'.format(str(CAPTURE))); yy+=1

      yy = 19
      writexy(xx,yy,8,'CTRL-L: Send Login/Password');yy+=1
      writexy(xx,yy,8,'CTRL-R: Find RegEx matches');yy+=1
      writexy(xx,yy,8,'CTRL-C: Hangup and exit program');yy+=1
      writexy(xx,yy,8,'CTRL-A: Save screen to file');yy+=1
      writexy(xx,yy,8,'     B: Back')

      xx,yy = 42,8
      writexy(xx,yy,7,'Total Data Transf: {}'.format(str(approximate_size(self.totaldatabytes)))); yy+=1
      dt = datetime.datetime.now()-self.logintime
      writexy(xx,yy,7,'Total Time Logged: {}'.format(str(dt))); yy+=2
      writexy(xx,yy,7,'Name    : {:25.25}'.format(BBS['name'])); yy+=1
      writexy(xx,yy,7,'Address : {:25.25}'.format(BBS['address'])); yy+=1
      writexy(xx,yy,7,'Software: {:20.20}'.format(BBS['software'])); yy+=1
      writexy(xx,yy,7,'Location: {:20.20}'.format(BBS['location'])); yy+=2
      writexy(xx,yy,7,'Size    : {:3}x{:3}'.format(WIDTH,HEIGHT));

      c = self.kb.getch()
      if c in 'sS':
        self.savebbsmenu()
      elif c in 'mM':
        ENABLEKEYSOUND = not ENABLEKEYSOUND
      elif c in 'cC':
        togglecapture()
      elif c in 'bB':
        break

    self.restorescreen()

  def run(self):
    global QUITEMODE
    self.totaldatabytes = 0
    self.logintime = datetime.datetime.now()
    ansibuff=""
    data=""
    buff=""
    while True:
      try:
        data = telnet.read_very_eager().decode('cp437')
      except:
        print("\nConnection closed...")
        break
      self.totaldatabytes += len(data)
      if CAPTURE:
        with open(CAPTUREFILE,'a+') as logfile:
          logfile.write(data)
      renderansi(data)
      data=''

      try:
        self.kb.checkkey_nonblock()
      except KeyboardInterrupt:
        telnet.close()
        break
    if not QUITEMODE:
      textcolor(7)
      print("")
      print("Total data transfer : {}".format(str(approximate_size(self.totaldatabytes))))
      print("Connected at        : {}".format(self.logintime.strftime("%Y/%m/%d (y/m/d), %H:%M:%S")))
      dt = datetime.datetime.now()-self.logintime
      print("Stayed connected for: {}".format(str(dt)))
      print("Average bytes/sec   : {} per sec.".format(str(approximate_size(self.totaldatabytes // dt.total_seconds()))))

def parser():
  global HEIGHT,WIDTH,BEEP,CAPTURE,CAPTUREFILE,QUITEMODE,ENABLEKEYSOUND,KBBACKSP
  global HOST,PORT, utf
  res = True
  #parser = argparse.ArgumentParser(description="Telnite // Python3 ANSI-BBS Telnet client for terminal.")
  parser = argparse.ArgumentParser(description=program_descripton, formatter_class=RawFormatter)
  parser.add_argument('-a','--address', metavar='address[:port]',action='store', type=str, help="The telnet address to connect to.")
  parser.add_argument('-w', '--width', dest='width', action='store', metavar='width', help="Force terminal width in chars.")
  parser.add_argument('--height', dest='height', action='store', metavar='height', help="Force terminal height in chars.")
  parser.add_argument('--telnet-guide', dest='guide', action='store', metavar='term', help="Connect to a BBS from the TelnetBBSGuide.")
  parser.add_argument('-l','--list', dest='list', action='store', metavar='term', help="Filter and List saved BBSes to choose from.")
  parser.add_argument('-b','--beep', dest='beep', action='store_true', help="Enable BEEP sound, using SOX.")
  parser.add_argument('-d','--del', dest='delete', action='store_true', help="Use #127/DEL code for backspace.")
  parser.add_argument('--cp437', dest='cp437', action='store_true', help="Use CP437 encoding instead of UTF8")
  parser.add_argument('-c','--capture', dest='capture', action='store_true', help="Store all incoming ANSI data to file.")
  parser.add_argument('--create-config', dest='config', action='store_true', help="Create a default config file (.ini) in current dir.")
  parser.add_argument('-q','--quite', dest='quite', action='store_true', help="Don't display any app. related text")
  parser.add_argument('--no-sound', dest='nosound', action='store_true', help="Disable all sound FXs")
  args = parser.parse_args()

  if len(sys.argv) < 2:
    #parser.print_usage()
    parser.print_help()
    sys.exit(1)

  if args.cp437:
    utf = False

  if args.quite:
    QUITEMODE=True

  if args.config:
    createconfigfile("./")
    return False

  if args.address:
    if ":" in args.address:
      tmp = args.address.split(':')
      HOST = tmp[0]
      PORT = int(tmp[1])
    else:
      HOST = args.address
      PORT = 23

    if os.path.isfile(CONFIGDIR + HOST + '.ini'):
      initoBBS(CONFIGDIR + HOST + '.ini')

  if args.guide:
    bbstglistselect(args.guide)

  if args.list:
    bbslistselect(args.list)

  if args.nosound:
    ENABLEKEYSOUND=False

  if args.delete:
    KBBACKSP=chr(127)

  if args.capture:
    CAPTURE=True
    CAPTUREFILE=time.strftime("capture_%Y%m%dT%H%M%SZ.ans", time.gmtime())

  if args.width:
    try:
      WIDTH=int(args.width)
    except:
      WIDTH=80

  if args.height:
    try:
      HEIGHT=int(args.height)
    except:
      HEIGHT=25

  if args.beep:
    BEEP = True

  return res

clrscr()
termux()
readconfigfile()
if not parser(): exit()
if HOST=="": exit()

x,y=1,1
init()

WIDTH = screenwidth
HEIGHT = screenheight

ui = UserInterface()

if ENABLEKEYSOUND:
  os.system("play -q "+MODEMSOUND+" >> /dev/null 2>&1 &")

try:
  #telnet = telnetlib.Telnet(HOST,port=PORT,timeout=5)

  if not QUITEMODE:
    if BBS['name']!='':
      print("Connecting to {}".format(BBS['name']))
    else:
      print("Connecting to {}".format(HOST))

  print("Press CTRL-W for Options and Help...")

  telnet.open(HOST,port=PORT,timeout=5)
  #telnet.set_debuglevel(100)
  time.sleep(1)
except:
  telnet.close()
  exit()

ui.run()

telnet.close()


#!/usr/bin/env python
# coding: utf-8
import pandas as pd
import os
import copy
from functools import wraps,partial
base_dir = os.getcwd()
t = "HBOND,VDW,PICATION,IONIC,SSBOND,PIPISTACK"
l = "MC_MC,MC_SC,SC_MC,SC_SC"
item_key= []
item_key1=[]
dic_moudle = {"filename":""}
dic_moudle1 = {"filename":""}
for i in t.split(","):
    for j in l.split(","):
        dic_moudle[f"{i}:{j}"]=0
        item_key.append(f"{i}:{j}")

for i in t.split(","):
    dic_moudle1[f"{i}"]=0
    item_key1.append(f"{i}")

def scan(func=None, *, path=None):
    if func is None:
        return partial(scan, path=path)
    @wraps(func)
    def wrapper(path):
        ls_dir = os.listdir(path)
        for file_name in ls_dir:
            file_path = os.path.join(path,file_name)
            if os.path.isfile(file_path):
                if file_name.startswith("satpdb") and file_name.endswith(".txt"):
                    func(file_path)
            elif os.path.isdir(file_path):
                wrapper(file_path)
    return wrapper

out_list=[]
out_list1=[]
@scan
def satpdb2csv(file_path):
    dic_one = copy.deepcopy(dic_moudle)
    dic_one1 = copy.deepcopy(dic_moudle1)
    with open(file_path,'r') as f:
        lines = f.readlines()
    dic_one["filename"]=os.path.basename(file_path)
    dic_one1["filename"]=os.path.basename(file_path)
    for i in lines:
        for key in item_key:
            if key in i:
                dic_one[key] += 1
        for key in item_key1:
            if key in i:
                dic_one1[key] += 1
    out_list.append(dic_one)
    out_list1.append(dic_one1)

satpdb2csv(base_dir)

obj = pd.DataFrame(out_list)
obj.to_csv(f"satpdb2csv.csv")
obj1 = pd.DataFrame(out_list1)
obj1.to_csv(f"satpdb2csv_no.csv")


import json

### 按需加载数据
def prepare(ab_flag):
    if ab_flag == 'A':
        variants = [
            'llA',
            'slA',
            'ssA',
            # 'ssB',
            # 'slB',
            # 'llB',
        ]
    else:
        variants = [
            # 'ssA',
            'ssB',
            # 'slA',
            'slB',
            # 'llA',
            'llB',
        ]

    # maxlen = 300

    train_data,valid_data,test_data=[],[],[]
    for i,var in enumerate(variants):
        # i = 0
        key = 'labelA' if 'A' in var else 'labelB'
        if key == 'labelA':
            i = 0
        else:
            i = 1
        #  fs = [
        #     'data/round1/%s/train.txt'%var,
        #     'data/round2/%s.txt'%var,
        #     'data/round3/divided_20210419/%s/train.txt'%var,
        #     'data/rematch/%s/train.txt'%var,
        # ]
        fs = [
            'dataB/round1/%s/train.txt'%var,
            'dataB/round2/%s.txt'%var,
            'dataB/round3/divided_20210419/%s/train.txt'%var,
            'dataB/rematch/%s/train.txt'%var,
        ]
        for f in fs:
            with open(f,encoding='utf-8') as f:
                for l in f:
                    l = json.loads(l)
                    train_data.append((i,l['source'],l['target'],int(l[key])))
        f = 'dataB/rematch/%s/valid.txt'%var
        with open(f,encoding='utf-8') as f:
            for l in f:
                l = json.loads(l)
                valid_data.append((i,l['source'],l['target'],int(l[key])))
        f = 'dataB/rematch_test_with_id/%s/test_with_id.txt'%var
        with open(f,encoding='utf-8') as f:
            for l in f:
                l = json.loads(l)
                test_data.append((i,l['source'],l['target'],l['id']))
    print('训练集长度：',len(train_data))
    print('验证集长度：',len(valid_data))
    print('测试集长度：',len(test_data))
    return train_data,valid_data,test_data


from django.urls import path,include
from rest_framework import routers
from api import views

router = routers.DefaultRouter()
router2 = routers.DefaultRouter()
router.register(r'', views.companyViewsets)
router2.register(r'', views.EmployeeViewSets)

urlpatterns = [
    path('companies/', include(router.urls)),
    path('employees/', include(router2.urls))
]
# companies/{companies_id}/employees


import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

#Before clustering
df = pd.read_csv("new_mall_customers.csv")
df.plot(x="Annual Income (k$)", y="Spending Score (1-100)",kind="scatter")
plt.show()
#After clustering
df2 = pd.read_csv("output.csv")
sns.scatterplot(x=df2.x, y=df2.y,
                hue=df2.c,
                palette=sns.color_palette("hls", n_colors=5))
plt.xlabel("Annual income (k$)")
plt.ylabel("Spending Score (1-100)")
plt.title("Clustered: spending (y) vs income (x)")

plt.show()


import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="functionalstream", # Replace with your own username
    version="0.1.8",
    author="cjwcommuny",
    author_email="cjwcommuny@outlook.com",
    description="A functional interface for python iterator",
    packages=setuptools.find_packages(),
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/cjwcommuny/functionalstream",
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires='>=3.6',
)


import botlog
from Data import *
from bbot.Wishlist import Wishlist

def default_region_ratio(app, context):
    r = Regions()

    emergency = False

    # take care of emergency situations

    if app.metadata.low_cash:
        r.desert.number = 1
        emergency = True

    if app.metadata.low_food:
        r.agricultural.number = 1
        emergency = True

    if not emergency:
        r.desert.number = 1

    return r

class MetaData(dict):
    def __init__(self, app):
        self.data = app.data
        self.default_region_ratio_func = default_region_ratio
        self.get_region_ratio_func = default_region_ratio
        self.get_region_ratio_context = None
        self.waiting_to_record_first_turn_number = None
        self.first_played_turn = None
        self.used_all_turns = False
        self.last_ag_buy = None
        self.last_ag_buy_turn = None
        self.max_ammount = None
        self.wishlist = Wishlist(app)
        self.regions_left = None
        self.low_cash = False
        self.low_food = False


from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.template import loader
from django.urls import reverse_lazy
from django.views import generic

from . import forms
from . import gea_vars as gv
from . import models

class CounterMixin:
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["count"] = self.get_queryset().count()
        return context

class PaginateByMixin:
    def get_paginate_by(self, queryset):
        """
        Paginate by specified value in querystring, or use default class
        property value.
        """
        return self.request.GET.get("paginate_by", self.paginate_by)

class SuccessDeleteMessageMixin:
    def delete(self, request, *args, **kwargs):
        delete_message = self.success_message if hasattr(self, "success_message") else "Objeto eliminado con éxito"
        messages.success(self.request, delete_message)
        return super().delete(request, *args, **kwargs)

class SearchMixin(object):
    def get_queryset(self):
        qset = super().get_queryset()
        q = self.request.GET.get("search")
        if q:
            q = q.split(" ")
            for w in q:
                qset = qset.filter(
                    Q(id__contains=w)
                    | Q(orden_numero__contains=w)
                    | Q(inscripcion_numero__contains=w)
                    | Q(expedientepartida__partida__pii__contains=w)
                    | Q(expedientepersona__persona__nombres__icontains=w)
                    | Q(expedientepersona__persona__apellidos__icontains=w)
                    | Q(expedientelugar__lugar__nombre__icontains=w)
                ).distinct()
        return qset

class ExpedienteAbiertoMixin(object):
    def get_queryset(self):
        qset = super().get_queryset()
        qset = qset.filter(Q(inscripcion_numero__isnull=True) & Q(cancelado=False) & Q(sin_inscripcion=False))[:10]
        return qset

class Home(LoginRequiredMixin, CounterMixin, SearchMixin, ExpedienteAbiertoMixin, generic.ListView):
    template_name = "index.html"
    model = models.Expediente

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        # last 5 inscriptos
        context["insc_list"] = models.Expediente.objects.filter(
            Q(inscripcion_numero__isnull=False) & Q(inscripcion_fecha__isnull=False)
        ).order_by("-inscripcion_fecha", "inscripcion_numero")
        # ordenes pendientes
        context["ord_list"] = models.Expediente.objects.filter(
            Q(orden_numero__isnull=False) & Q(inscripcion_numero__isnull=True) & Q(orden_fecha__isnull=False)
        ).order_by("-orden_fecha", "orden_numero")
        # relevamientos
        context["relev_list"] = models.Expediente.objects.filter(fecha_medicion__isnull=False).order_by(
            "-fecha_medicion"
        )
        # altas
        context["open_list"] = models.Expediente.objects.filter(created__isnull=False).order_by("-created")
        return context

class About(generic.TemplateView):
    template_name = "about.html"

class ExpedienteMixin(object):
    def get_queryset(self):
        qset = super().get_queryset()
        q = self.request.GET.get("pendiente")
        if q:  # orden pendiente
            qset = qset.filter(Q(inscripcion_numero__isnull=q) & Q(orden_numero__isnull=not q))
        q = self.request.GET.get("inscripto")
        if q:  # plano inscripto
            qset = qset.filter(inscripcion_numero__isnull=False)
        else:
            qset = qset.filter(inscripcion_numero__isnull=True)
        q = self.request.GET.get("cancelado")
        if q:  # expediente cancelado
            qset = qset.filter(cancelado=q)
        q = self.request.GET.get("duplicado")
        if q:  # duplicado
            qset = qset.filter(duplicado=q)
        q = self.request.GET.get("sin_inscr")
        if q:  # sin inscripcion
            qset = qset.filter(sin_inscripcion=q)
        return qset

class ExpedienteListView(LoginRequiredMixin, PaginateByMixin, CounterMixin, SearchMixin, generic.ListView):
    model = models.Expediente
    paginate_by = 10

class ExpedienteDetailView(LoginRequiredMixin, generic.DetailView):
    model = models.Expediente

class NombreSearchMixin(object):
    def get_queryset(self):
        q = super().get_queryset()
        query = self.request.GET.get("search")
        query = "" if not query else query.split()
        for w in query:
            q = q.filter(
                Q(nombres__icontains=w)
                | Q(apellidos__icontains=w)
                | Q(nombres_alternativos__icontains=w)
                | Q(apellidos_alternativos__icontains=w)
                | Q(expedientepersona__expediente__id__contains=w)
                | Q(expedientepersona__expediente__inscripcion_numero__contains=w)
                | Q(expedientepersona__expediente__expedientepartida__partida__pii__contains=w)
                | Q(expedientepersona__expediente__expedientelugar__lugar__nombre__icontains=w)
            ).distinct()
        return q

class PersonaFilterMixin(object):
    def get_queryset(self):
        q = super().get_queryset()
        query = self.request.GET.get("search")
        query = "" if not query else query.split()
        for w in query:
            q = q.filter(
                Q(nombres__icontains=w)
                | Q(apellidos__icontains=w)
                | Q(nombres_alternativos__icontains=w)
                | Q(apellidos_alternativos__icontains=w)
                | Q(email__icontains=w)
                | Q(documento__contains=w)
                | Q(cuit_cuil__contains=w)
                | Q(telefono__contains=w)
                | Q(expedientepersona__expediente__id__contains=w)
            ).distinct()
        return q

# class PersonaListView(LoginRequiredMixin, NombreSearchMixin, CounterMixin, generic.ListView):
class PersonaListView(LoginRequiredMixin, PaginateByMixin, CounterMixin, PersonaFilterMixin, generic.ListView):
    model = models.Persona
    paginate_by = 10

class PersonaDetailView(LoginRequiredMixin, generic.DetailView):
    model = models.Persona

class PersonaCreateView(SuccessMessageMixin, LoginRequiredMixin, generic.CreateView):
    model = models.Persona
    form_class = forms.PersonaForm
    success_message = "¡Persona creada con éxito!"

class PersonaUpdateView(SuccessMessageMixin, LoginRequiredMixin, generic.UpdateView):
    model = models.Persona
    form_class = forms.PersonaForm
    success_message = "¡Persona modificada con éxito!"

class PersonaDeleteView(SuccessDeleteMessageMixin, LoginRequiredMixin, generic.DeleteView):
    model = models.Persona
    success_url = reverse_lazy("personas")
    success_message = "Persona eliminada con éxito."

class LugarSearchMixin(object):
    def get_queryset(self):
        queryset = super().get_queryset()
        q = self.request.GET.get("lugar")
        if q:
            return queryset.filter(expedientelugar__lugar__nombre=q)
        return queryset

class SeccionSearchMixin(object):
    def get_queryset(self):
        queryset = super().get_queryset()
        q = self.request.GET.get("seccion")
        if q:
            return queryset.filter(expedientelugar__catastrolocal__seccion=q)
        return queryset

class ManzanaSearchMixin(object):
    def get_queryset(self):
        queryset = super().get_queryset()
        q = self.request.GET.get("manzana")
        if q:
            return queryset.filter(expedientelugar__catastrolocal__manzana=q)
        return queryset

class ParcelaSearchMixin(object):
    def get_queryset(self):
        queryset = super().get_queryset()
        q = self.request.GET.get("parcela")
        if q:
            return queryset.filter(expedientelugar__catastrolocal__parcela=q)
        return queryset

class CLMixin(object):
    def get_queryset(self):
        qset = super().get_queryset()
        q = self.request.GET.get("lugar")
        if q is not None:
            qset = qset.filter(expedientelugar__lugar__nombre=q).distinct()
        q = self.request.GET.get("seccion")
        if q is not None:
            qset = qset.filter(expedientelugar__catastrolocal__seccion=q)
        q = self.request.GET.get("manzana")
        if q is not None:
            qset = qset.filter(expedientelugar__catastrolocal__manzana=q)
        q = self.request.GET.get("parcela")
        if q is not None:
            qset = qset.filter(expedientelugar__catastrolocal__parcela=q)
        return qset

class CatastroLocalListView(LoginRequiredMixin, CounterMixin, CLMixin, generic.ListView):
    template_name = "gea/catastros_locales.html"
    model = models.Expediente
    paginate_by = 10

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        lugar = self.request.GET.get("lugar")
        context["lugar"] = lugar
        s = self.request.GET.get("seccion")
        context["seccion"] = s
        m = self.request.GET.get("manzana")
        context["manzana"] = m
        p = self.request.GET.get("parcela")
        context["parcela"] = p
        context["lugares"] = models.Lugar.objects.values_list("nombre", flat=True).order_by("nombre")
        context["secciones"] = (
            models.CatastroLocal.objects.filter(expediente_lugar__lugar__nombre=lugar)
            .values_list("seccion", flat=True)
            .distinct()
            .order_by("seccion")
        )
        context["manzanas"] = (
            models.CatastroLocal.objects.filter(expediente_lugar__lugar__nombre=lugar)
            .filter(seccion=s)
            .values_list("manzana", flat=True)
            .distinct()
            .order_by("manzana")
        )
        context["parcelas"] = (
            models.CatastroLocal.objects.filter(expediente_lugar__lugar__nombre=lugar)
            .filter(Q(seccion=s) & Q(manzana=m))
            .values_list("parcela", flat=True)
            .distinct()
            .order_by("parcela")
        )
        return context

@login_required
def caratula(request):
    if request.method == "POST":  # If the form has been submitted...
        # CaratulaForm was defined in the previous section
        form = forms.CaratulaForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            # Process the data in form.cleaned_data
            #
            expediente_id = form.cleaned_data["expte_nro"]
            inmueble = form.cleaned_data["inmueble"]
            matricula = form.cleaned_data["matricula"]
            tomo = form.cleaned_data["tomo"]
            par = form.cleaned_data["par"]
            folio = form.cleaned_data["folio"]
            numero = form.cleaned_data["numero"]
            fecha = form.cleaned_data["fecha"]
            obs = form.cleaned_data["obs"]
            fmt = form.cleaned_data["fmt"]

            e = get_object_or_404(models.Expediente, id=expediente_id)
            template = loader.get_template("gea/tools/caratula.%s" % fmt)
            context = {
                "e": e,
                "inmueble": inmueble,
                "matricula": matricula,
                "tomo": tomo,
                "par": par,
                "folio": folio,
                "numero": numero,
                "fecha_dominio": fecha,
                "obs": obs,
                "fmt": fmt,
            }
            if fmt != "html":
                response = HttpResponse(template.render(context), content_type="image/x-%s" % fmt)
                cd = "attachment; filename=%04d-caratula.%s"
                response["Content-Disposition"] = cd % (expediente_id, fmt)
            else:
                return HttpResponse(template.render(context))
            return response
    else:
        form = forms.CaratulaForm()  # An unbound form

    return render(request, "gea/tools/caratula_form.html", {"form": form,})

@login_required
def solicitud(request):
    if request.method == "POST":  # If the form has been submitted...
        # SolicitudForm was defined in the previous section
        form = forms.SolicitudForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            expediente_id = form.cleaned_data["expte_nro"]
            circunscripcion = form.cleaned_data["circunscripcion"]
            domicilio_fiscal = form.cleaned_data["domicilio_fiscal"]
            # codigo_postal = form.cleaned_data['localidad']
            loc = form.cleaned_data["localidad"]
            localidad = gv.CP_dict[loc].split(" - ")[0]
            codigo_postal = gv.CP_dict[loc].split(" - ")[1]
            provincia = form.cleaned_data["provincia"]
            nota_titulo = form.cleaned_data["nota_titulo"]
            nota = form.cleaned_data["nota"]

            e = get_object_or_404(models.Expediente, id=expediente_id)
            template = loader.get_template("gea/doc/solic.html")
            context = {
                "e": e,
                "domfiscal": domicilio_fiscal,
                "circunscripcion": circunscripcion,
                "localidad": localidad,
                "cp": codigo_postal,
                "provincia": provincia,
                "nota_titulo": nota_titulo,
                "nota": nota,
            }
            return HttpResponse(template.render(context))
    else:
        form = forms.SolicitudForm()  # An unbound form

    return render(request, "gea/doc/solic_form.html", {"form": form,})

@login_required
def visacion(request):
    if request.method == "POST":  # If the form has been submitted...
        # VisacionForm was defined in the previous section
        form = forms.VisacionForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            eid = form.cleaned_data["expte_nro"]
            lugar = form.cleaned_data["lugar"]
            sr = gv.Lugar_dict[int(lugar)][0]
            localidad = gv.Lugar_dict[int(lugar)][1]

            e = get_object_or_404(models.Expediente, id=eid)
            # Redirect after POST
            return render(request, "gea/doc/visac.html", {"e": e, "sr": sr, "localidad": localidad},)
    else:
        form = forms.VisacionForm()  # An unbound form

    return render(request, "gea/doc/visac_form.html", {"form": form,})

@login_required
def plano(request):
    ftp_url = "ftp://zentyal.estudio.lan"
    if request.method == "POST":  # If the form has been submitted...
        form = forms.PlanoForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            circ = form.cleaned_data["circ"]
            nro = form.cleaned_data["n_insc"]
            return redirect("%s/planos/%s/%06d.pdf" % (ftp_url, circ, nro))
    else:
        form = forms.PlanoForm()  # An unbound form

    return render(request, "gea/search/plano_form.html", {"form": form,})

@login_required
def set(request):
    ftp_url = "ftp://zentyal.estudio.lan"
    if request.method == "POST":  # If the form has been submitted...
        form = forms.SetForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            pii = form.cleaned_data["partida"]
            sub_pii = form.cleaned_data["sub_pii"]
            url = "%s/set/%06d%04d.pdf" % (ftp_url, pii, sub_pii)
            return redirect(url)
    else:
        form = forms.SetForm()  # An unbound form

    return render(request, "gea/search/set_form.html", {"form": form,})

def get_dvapi(dp, ds, sd, pii, subpii):
    coef = "9731"
    _coef = coef + coef + coef + coef
    strpii = "%02d%02d%02d%06d%04d" % (dp, ds, sd, pii, subpii)
    suma = 0
    for i in range(0, len(strpii)):
        m = str(int(strpii[i]) * int(_coef[i]))
        suma += int(m[len(m) - 1])
    return (10 - (suma % 10)) % 10

def dvapi(request):
    if request.method == "POST":  # If the form has been submitted...
        form = forms.DVAPIForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            dp = form.cleaned_data["dp"]
            ds = form.cleaned_data["ds"]
            sd = form.cleaned_data["sd"]
            pii = form.cleaned_data["partida"]
            sub_pii = form.cleaned_data["sub_pii"]
            dv = get_dvapi(dp, ds, sd, pii, sub_pii)
            return render(request, "gea/tools/dvapi_form.html", {"dv": dv, "form": form},)
    else:
        form = forms.DVAPIForm()  # An unbound form

    return render(request, "gea/tools/dvapi_form.html", {"form": form,})

def sie(request):
    if request.method == "POST":  # If the form has been submitted...
        form = forms.SIEForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            mesa = form.cleaned_data["mesa"]
            nro = form.cleaned_data["nro"]
            dv = form.cleaned_data["digito"]
            # dv = get_dvsie(mesa, nro)
            base_url = "https://www.santafe.gov.ar/index.php/apps/sie"
            param = "?mesa=%d&numero=%d&digito=%d&tipoSIE=1" % (mesa, nro, dv)
            url = "".join([base_url, param])
            return redirect(url)
    else:
        form = forms.SIEForm()  # An unbound form

    return render(request, "gea/tools/sie_form.html", {"form": form,})

@login_required
def catastro(request):
    if request.method == "POST":  # If the form has been submitted...
        # VisacionForm was defined in the previous section
        form = forms.CLForm(request.POST)  # A form bound to the POST data
        if form.is_valid():  # All validation rules pass
            # Process the data in form.cleaned_data
            # ...
            lugar = form.cleaned_data["lugar"]
            seccion = form.cleaned_data["seccion"]
            manzana = form.cleaned_data["manzana"]
            parcela = form.cleaned_data["parcela"]

            filtro = "?"
            if lugar is not None:
                filtro = "%s%s%s" % (filtro, "&expedientelugar__lugar__nombre=", lugar,)
            if seccion != "":
                filtro = "%s%s%s" % (filtro, "&expedientelugar__catastrolocal__seccion=", seccion,)
            if manzana != "":
                filtro = "%s%s%s" % (filtro, "&expedientelugar__catastrolocal__manzana=", manzana,)
            if parcela != "":
                filtro = "%s%s%s" % (filtro, "&expedientelugar__catastrolocal__parcela=", parcela,)
            # Redirect after POST
            return redirect("/admin/gea/expediente/%s" % filtro)
    else:
        form = forms.CLForm()  # An unbound form

    return render(request, "gea/search/catastro_form.html", {"form": form,})

# #####
# ##### EXPERIMENTAL
# #####
# from calendar import HTMLCalendar
# from datetime import date
# from itertools import groupby
#
# from django.utils.html import conditional_escape as esc

# class QuerysetCalendar(HTMLCalendar):
#
#     def __init__(self, queryset, datefield):
#         self.datefield = datefield
#         super(QuerysetCalendar, self).__init__()
#         self.queryset_by_date = self.group_by_day(queryset)
#
#     def formatday(self, day, weekday):
#         if day != 0:
#             cssclass = self.cssclasses[weekday]
#             if date.today() == date(self.year, self.month, day):
#                 cssclass += ' today'
#             if day in self.queryset_by_date:
#                 cssclass += ' filled'
#                 body = ['<ul>']
#                 for item in self.queryset_by_date[day]:
#                     body.append('<li>')
#                     body.append('<a href="%s">' % item.get_absolute_url())
#                     body.append(esc(item))
#                     body.append('</a></li>')
#                 body.append('</ul>')
#                 return self.day_cell(cssclass, '%d %s' % (day, ''.join(body)))
#             return self.day_cell(cssclass, day)
#         return self.day_cell('noday', ' ')
#
#     def formatmonth(self, year, month):
#         self.year, self.month = year, month
#         return super(QuerysetCalendar, self).formatmonth(year, month)
#
#     def group_by_day(self, queryset):
#         field = lambda item: getattr(item, self.datefield).day
#         return dict(
#             [(day, list(items)) for day, items in groupby(queryset, field)]
#         )
#
#     def day_cell(self, cssclass, body):
#         return '<td class="%s">%s</td>' % (cssclass, body)

# ######
# from django.utils.safestring import mark_safe
#
#
# @login_required
# def calendar(request, year, month):
#     e = models.Expediente.objects.order_by('fecha_medicion').filter(
#         fecha_medicion__year=year, fecha_medicion__month=month
#         )
#     cal = QuerysetCalendar(e, 'fecha_medicion').formatmonth(int(year),
#                                                             int(month))
#     return render_to_response('gea/tools/calendar.html',
#                               {'calendar': mark_safe(cal), })


# facturation:login/urls.py
from django.urls import path
from . import views

app_name= 'facturation'
urlpatterns = [
    #login paths
    path('register/', views.register_user, name='register'),
    path('login/', views.login_view, name='login'),
    path('logout/', views.logout_view, name='logout'),
    #homepage paths
    path('', views.homepage, name='homepage'),
    path('homepage/', views.homepage, name='homepage'),
    #sidebar paths

    path('factures',views.homepage,name='factures'),
    path('fournisseurs/',views.fournisseurs,name='fournisseurs'),
    path('services/', views.services, name='services'),
    #CRUD for Factures
    path('add_facture/', views.add_facture, name='add_facture'),
    path('facture/<int:pk>/', views.view_facture, name='view_facture'),
    path('facture/<int:pk>/update/', views.update_facture, name='update_facture'),
    path('facture/<int:pk>/delete/', views.delete_facture, name='delete_facture'),
    # CRUD for Fournisseurs
    path('fournisseur/add/', views.add_fournisseur, name='add_fournisseur'),
    path('fournisseur/<int:pk>/', views.view_fournisseur, name='view_fournisseur'),
    path('fournisseur/<int:pk>/update/', views.update_fournisseur, name='update_fournisseur'),
    path('fournisseur/<int:pk>/delete/', views.delete_fournisseur, name='delete_fournisseur'),
    # CRUD for Services
    path('service/add/', views.add_service, name='add_service'),
    path('service/<int:pk>/', views.view_service, name='view_service'),
    path('service/<int:pk>/update/', views.update_service, name='update_service'),
    path('service/<int:pk>/delete/', views.delete_service, name='delete_service'),
    #exporting_importing
    path('export/', views.export_data, name="export_data"),

]


from app import create_app, db
from config import TestingConfig
from unittest import TestCase

class BaseTestCase(TestCase):

    def setUp(self):
        self.app = create_app(TestingConfig)
        self.app_context = self.app.app_context()
        self.app_context.push()
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()
        self.app_context.pop()


#!/usr/bin/python
# -*- coding: UTF-8 -*-

import requests
from html.parser import HTMLParser
import http.client
import json
import os
import datetime
from datetime import datetime as dt
import threading
import queue
import time
import sys
import csv

brokers = []
IDs=[]
buffer2 = 0
class Worker(threading.Thread):
    def __init__(self, queue,num):
        threading.Thread.__init__(self)
        self.num = num
        self.queue = queue
        # self.broker = queue.get()[0]
        # self.ID = queue.get()[1]
    def run(self):
        global buffer2

        while not self.queue.empty():
            buffer = self.queue.get()
            self.broker = buffer[0]
            self.ID = buffer[1]
            get_html = open(self.ID+'/'+self.broker+'.txt',encoding = "utf-8",mode = 'w')
            conn = http.client.HTTPSConnection("www.nvesto.com",timeout=10)
            payload = "fromdate=2018-01-01&todate=2018-11-13&broker="+str(self.broker)
            headers = {
                'content-type': "application/x-www-form-urlencoded",
                'cache-control': "no-cache",
                'User-Agent':"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0"
                }
            conn.request("POST", "/brokeranalysis/ajaxGetData/sotckType/tpe/stockId/"+self.ID, payload, headers)
            res = conn.getresponse()
            data = res.read()
            get_html.write(data.decode("utf-8"))
            get_html.close()

            # 解析
            shop_list = open(self.ID+'.csv',encoding = "utf-8",mode = 'a+',newline='')
            #print("被打開來")
            if buffer2 == 0:
                shop_list.write('Date'+','+'券商'+','+'buy'+','+'sell'+','+'buyPer'+','+'sellPer'+','+'netPer'+','+'buyWeek'+','+'sellWeek'+','+'netWeek'+','+'buyWeekPer'+','+'sellWeekPer'+','+'last_price'+','+'netWeekPer')
                buffer2 = 1
            try:

                data = data.decode("utf-8")
                res_data = json.loads(data)
                shop_list.write('\n')
                StartDate = time.strptime("2018/01/01", "%Y/%m/%d")
                EndDate = time.strptime("2018/11/13", "%Y/%m/%d")
                StartDate = datetime.date(StartDate[0], StartDate[1], StartDate[2])
                EndDate = datetime.date(EndDate[0], EndDate[1], EndDate[2])
                # EndDate =  datetime.date(EndDate[0], EndDate[1], EndDate[2])
                RangeDate = datetime.timedelta(days = 1)
                while StartDate <= EndDate:
                    z = StartDate + RangeDate
                    yearmonthday = str(z)
                    try:
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['date'])+',')
                        shop_list.write(str(self.broker)+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['buy'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['sell'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['buyPer'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['sellPer'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['netPer'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['buyWeek'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['sellWeek'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['netWeek'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['buyWeekPer'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['sellWeekPer'])+',')
                        shop_list.write(str(res_data['stockpriceData']['stockprice'][yearmonthday]['last_price'])+',')
                        shop_list.write(str(res_data['chartData']['ba'][yearmonthday]['netWeekPer'])+',')
                        shop_list.write('\n')
                    except Exception as e:
                        pass

                    StartDate = StartDate + RangeDate

                print("complete ID: "+str(self.ID)+" broker: "+str(self.broker)+" Worker %d" % (self.num))
                sys.stdout.flush()
            except Exception as e:
                print(e)
                print("out of range")
            #time.sleep(1)

# 建立佇列
my_queue = queue.Queue()

with open('123.csv', newline='') as csvfile:
  spamreader = csv.reader(csvfile)
  for row in spamreader:
    if row[0] != '':
        brokers.append(row[0])

    if row[1] != '':
        IDs.append(row[1])

for ID in IDs: # 證券代碼

    ID = str(ID)
    try:
        os.mkdir(ID) #創見目錄
    except Exception as e:
        print(e)
        print("File have exist "+ID)

    for broker in brokers: #卷商

        broker = str(broker)
        x = [broker,ID]
        my_queue.put(x)
    #print("All complete "+str(ID))

starttime = dt.now()
print("開始 "+str(starttime))
# 建立兩個 Worker
my_worker1 = Worker(my_queue, 1)
my_worker2 = Worker(my_queue, 2)
my_worker3 = Worker(my_queue, 3)
my_worker4 = Worker(my_queue, 4)
my_worker5 = Worker(my_queue, 5)
my_worker6 = Worker(my_queue, 6)
my_worker7 = Worker(my_queue, 7)
my_worker8 = Worker(my_queue, 8)

# 讓 Worker 開始處理資料
my_worker1.start()
my_worker2.start()
my_worker3.start()
my_worker4.start()
my_worker5.start()
my_worker6.start()
my_worker7.start()
my_worker8.start()

# 等待所有 Worker 結束
my_worker1.join()
my_worker2.join()
my_worker3.join()
my_worker4.join()
my_worker5.join()
my_worker6.join()
my_worker7.join()
my_worker8.join()

print("全部結束 "+str(dt.now()-starttime))


""":mod:`asuka.service` --- Service interface
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

"""
import re

from .build import BaseBuild
from .instance import Instance
from .logger import LoggerProviderMixin

__all__ = 'DomainService', 'Service'

class Service(LoggerProviderMixin):
    """The inteface of services.

    :param build: the build object
    :type build: :class:`~asuka.build.BaseBuild`
    :param name: the service name
    :type name: :class:`basestring`
    :param config: the config mapping object
    :type config: :class:`collections.Mapping`
    :param required_apt_repositories: the set of APT repositories
                                      the service uses
    :param required_apt_packages: the set of APT packages
                                  the service depends
    :type required_apt_packages: :class:`collections.Set`
    :param required_python_packages: the set of Python packages
                                     the service depends.
                                     elements have to be PyPI names
    :type required_python_packages: :class:`collections.Set`

    """

    #: (:class:`re.RegexObject`) The pattern of the valid service name.
    NAME_PATTERN = re.compile('^[a-z_][a-z0-9_]{1,50}$')

    #: (:class:`~asuka.build.Build`) The build object.
    build = None

    #: (:class:`~asuka.branch.Branch`) The branch object.
    branch = None

    #: (:class:`~asuka.commit.Commit`) The commit object.
    commit = None

    #: (:class:`~asuka.app.App`) The application object.
    app = None

    #: (:class:`str`) The service name e.g. ``'web'``.
    name = None

    #: (:class:`collections.Sequence`) The shell commands to be invoked
    #: before services are installed.
    pre_install = None

    #: (:class:`collections.Sequence`) The shell commands to be invoked
    #: after all services are installed.
    post_install = None

    #: (:class:`collections.Mapping`) The configuration dictionary.
    config = None

    def __init__(self, build, name, config={},
                 required_apt_repositories=frozenset(),
                 required_apt_packages=frozenset(),
                 required_python_packages=frozenset(),
                 pre_install=[],
                 post_install=[]):
        if not isinstance(build, BaseBuild):
            raise TypeError('build must be an instance of asuka.build.'
                            'BaseBuild, not ' + repr(build))
        elif not isinstance(name, basestring):
            raise TypeError('name must be a string, not ' + repr(name))
        elif not self.NAME_PATTERN.search(name):
            raise TypeError('invalid name: ' + repr(name))
        self.build = build
        self.app = build.app
        self.branch = build.branch
        self.commit = build.commit
        self.name = str(name)
        self.config = dict(config)
        self._required_apt_repositories = frozenset(required_apt_repositories)
        self._required_apt_packages = frozenset(required_apt_packages)
        self._required_python_packages = frozenset(required_python_packages)
        self.pre_install = list(pre_install)
        self.post_install = list(post_install)

    @property
    def required_apt_repositories(self):
        """(:class:`collections.Set`) The set of APT repository source lines
        to add.  It takes source lines :program:`apt-add-repository`
        can take e.g.::

            frozenset([
                'deb http://myserver/path/to/repo stable myrepo',
                'http://myserver/path/to/repo myrepo',
                'https://packages.medibuntu.org free non-free',
                'http://extras.ubuntu.com/ubuntu ',
                'ppa:user/repository'
            ])

        """
        return self._required_apt_repositories

    @property
    def required_apt_packages(self):
        """(:class:`collections.Set`) The set of APT package names
        to install e.g. ``frozenset(['python-dev', 'python-greenlet'])``.

        """
        return self._required_apt_packages

    @property
    def required_python_packages(self):
        """(:class:`collections.Set`) The set of PyPI_ package names
        to install e.g. ``frozenset(['Werkzeug', 'chardet'])``.

        .. _PyPI: http://pypi.python.org/

        """
        return self._required_python_packages

    def install(self, instance):
        """Installs the service into the ``instance``.

        :param instance: the instance to install the service
        :type instance: :class:`asuka.instance.Instance`
        :returns: values provided by the service.  this values are shared
                  to the app via :file:`/etc/<app>/values.json` file.
                  it must be able to be serialized into JSON

        """
        if not isinstance(instance, Instance):
            raise TypeError('instance must be an asuka.instance.Instance '
                            'object, not ' + repr(instance))
        elif instance.app is not self.app:
            raise TypeError('{0!r} is not an instance for {1!r} but {0.app!r}'
                            ''.format(instance, self.app))
        app_name = instance.app.name
        F = app_name, self.name
        with instance:
            # Make directories
            instance.do([
                'sudo', 'mkdir', '-p', '/etc/{0}/{1}'.format(*F),
                '/var/lib/{0}/{1}'.format(*F), '/var/run/{0}'.format(*F)
            ])
            instance.do([
                'sudo', 'chown', '-R', '{0}:{0}'.format(*F),
                '/etc/{0}'.format(*F), '/var/lib/{0}'.format(*F),
                '/var/run/{0}'.format(*F)
            ])

    def uninstall(self):
        """Uninstalls the service."""

    def __repr__(self):
        cls = type(self)
        return '<{0.__module__}.{0.__name__} {1!r}>'.format(cls, self.name)

class DomainService(Service):
    """The service subtype mixin which provides domain routing."""

    def route_domain(self, name, records):
        """Routes the service to the zone.

        :param name: the full domain name to map
        :type name: :class:`basestring`
        :param records: the record changeset
        :type records: :class:`boto.route53.record.ResourceRecordSets`

        """

    def remove_domain(self, name, records):
        """Removes the records for the service from the zone.

        :param name: the full domain name to deregister
        :type name: :class:`basestring`
        :param records: the record changeset
        :type records: :class:`boto.route53.record.ResourceRecordSets`

        """