# -*- coding: utf-8 -*-
# python 3
from collections import defaultdict,namedtuple
import copy
import sys
import gzip

CoNLLFormat=namedtuple("CoNLLFormat",["ID","FORM","LEMMA","POS","FEAT","HEAD","DEPREL"])

#Column lists for the various formats
formats={"conll09":CoNLLFormat(0,1,2,4,6,8,10),"conllu":CoNLLFormat(0,1,2,3,5,6,7)}

SHIFT=0
RIGHT=1
LEFT=2
SWAP=3

#DEPTYPES=u"acomp adpos advcl advmod amod appos aux auxpass ccomp compar comparator complm conj cop csubj csubj-cop dep det dobj gobj gsubj iccomp infmod intj mark name neg nommod nsubj num parataxis partmod poss prt punct rcmod voc xcomp xsubj xsubj-cop nsubj-cop nommod-own csubjpass nn cc number quantmod rel preconj ROOT".split() # TODO: collect these from data

def conllu_reader(f,lower,conll_format="conllu"):
    form=formats[conll_format]
    comments=[]
    sentence=[]
    for line in f:
        line=line.strip()
        if not line:
            if sentence:
                yield sentence
            comments=[]
            sentence=[]
        elif line.startswith("#"):
            comments.append(line)
        else:
            cols=line.split("\t")
            if "." in cols[0]: # null node
                continue
            if lower:
                cols[form.FORM]=cols[form.FORM].lower()
                cols[form.LEMMA]=cols[form.LEMMA].lower()
            sentence.append(cols)

def read_conll(inp):
    """ Read conll format file and yield one sentence at a time as a list of lists of columns. If inp is a string it will be interpreted as filename, otherwise as open file for reading in unicode"""
    if isinstance(inp,basestring):
        f=open(inp,"rt",encoding="utf-8")
    else:
        f=inp

    sent=[]
    for line in f:
        line=line.strip()
        if not line or line.startswith("#"): #Do not rely on empty lines in conll files, ignore comments
            continue
        if line.startswith("1\t") and sent: #New sentence, and I have an old one to yield
            yield sent
            sent=[]
        sent.append(line.split("\t"))
    else:
        if sent:
            yield sent

    if isinstance(inp,basestring):
        f.close() #Close it if you opened it

def fill_conll(sent,state,conll_format="conll09"):
    form=formats[conll_format]
    for i in range(0,len(sent)):
        token=state.tree.tokens[i]
#        if token not in state.tree.govs: # ROOT
#            sent[i][form.HEAD]=u"0"
#            sent[i][form.DEPREL]=u"ROOT"
#        else:
        sent[i][form.HEAD]=unicode(state.tree.govs[token].index+1)
        if state.tree.govs[token].index+1==0: # hard-code deprel to be ROOT
            sent[i][form.DEPREL]="ROOT"
        else:
            sent[i][form.DEPREL]=state.tree.dtypes[token]

def write_conll(f,sent):
    for line in sent:
        f.write("\t".join(c for c in line)+"\n")
    f.write("\n")

class Tree(object):

    @classmethod
    def new_from_conll(cls,conll,syn,conll_format="conllu"):
        t=cls()
        t.from_conll(conll,syn,conll_format)
        return t

    @classmethod
    def new_from_tree(cls,t):
        """Selectively copies only those parts that can change during parse"""
        newT=cls.__new__(cls) #Do not call the __init__() because we will fill the args by hand
        newT.tokens=t.tokens
        newT.childs=defaultdict(lambda:set())
        for tok,s in t.childs.iteritems():
            if tok in t.ready_nodes:
                newT.childs[tok]=s # this one is ready, no need to copy
            else:
                newT.childs[tok]=s.copy()
        newT.ready_nodes=t.ready_nodes.copy() # this needs to be copied
        newT.govs=t.govs.copy()
        newT.deps=t.deps[:]
        newT.dtypes=t.dtypes.copy()
        newT.root=t.root
        newT.projective_order=t.projective_order #no need to copy this one
        newT.ready=t.ready
        return newT

    def __init__(self):
        #If you add any new attributes, make sure you copy them over in new_from_tree()
        self.tokens=[] #[Token(),...]
        self.childs=defaultdict(lambda:set()) #{token():set(token())#
        self.ready_nodes=set() # set(token())
        self.govs={} #{token():govtoken()}
        self.dtypes={} #{token():dtype}
        self.deps=[] #[Dep(),...]
        self.root=None #?
        self.projective_order=None
        self.ready=False

    #Called from new_from_conll() classmethod
    def from_conll(self,lines,syn,conll_format="conllu"):
        """ Reads conll format and transforms it to a tree instance. `conll_format` is a format name
            which will be looked up in the formats module-level dictionary"""
        form=formats[conll_format] #named tuple with the column indices
        for i in range(0,len(lines)): # create tokens
            line=lines[i]
            token=Token(i,line[form.FORM],pos=line[form.POS],feat=line[form.FEAT],lemma=line[form.LEMMA])
            self.tokens.append(token)

        if syn: # create dependencies
            for line in lines:
                self.dtypes[self.tokens[int(line[form.ID])-1]]=line[form.DEPREL] # fill dtype for token
                gov=int(line[form.HEAD])
                if gov==0:
                    self.root=self.tokens[int(line[0])-1] # TODO: why I store this information?
                    continue
                gov=self.tokens[gov-1]
                dep=self.tokens[int(line[0])-1]
                dType=line[form.DEPREL]
                dependency=Dep(gov,dep,dType)
                self.add_dep(dependency)
            self.ready=True
            self.ready_nodes=set(self.tokens) # all nodes are ready
        else:
            self.ready=False

    def add_dep(self,dependency):
        self.deps.append(dependency)
        self.childs[dependency.gov].add(dependency.dep)
        self.govs[dependency.dep]=dependency.gov
        self.dtypes[dependency.dep]=dependency.dType
        self.ready_nodes.add(dependency.dep)

    def has_dep(self,g,d):
        for dependency in self.deps:
            if dependency.gov.index==g.index and dependency.dep.index==d.index:
                return dependency.dType
        return None

    def is_nonprojective(self):
        """ Return 'non-projective tokens' if tree is non-projective, else empty set"""
        non_projs=set()
        rootdep=Dep(Token(-1,""),self.root,"dummydep")
        for i in range(0,len(self.deps)):
            dep1=self.deps[i]
            if dep1.gov!=self.root and dep1.dep!=self.root:
                non_proj=dep1.is_crossing(rootdep)
                if non_proj is not None:
                    non_projs.add(dep1.dep)
            for j in range(i+1,len(self.deps)):
                dep2=self.deps[j]
                if dep1.gov==dep2.gov or dep1.dep==dep2.dep or dep1.gov==dep2.dep or dep1.dep==dep2.gov: continue
                non_proj=dep1.is_crossing(dep2)
                if non_proj is not None:
                    if self.part_of_subtree(dep1.dep,dep2.gov):
                        non_projs.add(dep1.dep)
                    elif self.part_of_subtree(dep2.dep,dep1.gov):
                        non_projs.add(dep2.dep)
                    elif dep1.dep.index<dep2.dep.index:
                        non_projs.add(dep1.dep)
                    else:
                        non_projs.add(dep2.dep)
        return non_projs

    def define_projective_order(self,tokens):
        tokens=list(tokens)
        order=self.tokens[:]
        while tokens:
            govIdx=None
            main=[]
            sub=[]
            idx=0
            for token in order:
                if self.part_of_subtree(token,tokens[0]):
                    sub.append(token)
                else:
                    main.append(token)
                if tokens[0] in self.childs[token]:
                    govIdx=idx
                idx+=1
            if govIdx<tokens[0].index: # gov > dep
                order=main[:govIdx+1]+sub+main[govIdx+1:]
            else: # dep < gov
                order=main[:govIdx-1]+sub+main[govIdx-1:]
            t=tokens.pop(0)
        self.projective_order=order

    def part_of_subtree(self,token,subtree_head):
        if token==subtree_head: return True
        if token in self.childs[subtree_head]: return True
        for child in self.childs[subtree_head]:
            if self.part_of_subtree(token,child):
                return True
        return False

    def is_proj(self,tok1,tok2):
        if tok1.index==-1 or tok2.index==-1: # artificial root token, not part of the self.projective order
            return False # TODO: do I ever want to SWAP root?
        if (tok1.index<tok2.index) and (self.projective_order.index(tok1)>self.projective_order.index(tok2)): return True
        elif (tok1.index>tok2.index) and (self.projective_order.index(tok1)<self.projective_order.index(tok2)): return True
        else: return False

class Token(object):

    def __init__(self,idx,text,pos="",feat="",lemma=""):
        self.index=idx
        self.text=text
        self.pos=pos
        self.feat=feat
        self.lemma=lemma

    def __str__(self):
        return self.text

    def __repr__(self):
        return "<"+self.text+">"

    def __eq__(self,other):
        return self.index==other.index

    def __hash__(self):
        return hash(self.index)

class Dep(object):

    def __init__(self,gov,dep,dType):
        self.gov=gov
        self.dep=dep
        self.dType=dType

    def is_crossing(self,another):
        if self.is_between(self.gov.index,self.dep.index,another.dep.index)==True and self.is_between(self.gov.index,self.dep.index,another.gov.index)==False:
            return another.dep
        elif self.is_between(another.gov.index,another.dep.index,self.dep.index)==True and self.is_between(another.gov.index,another.dep.index,self.gov.index)==False:
            return self.dep
        else:
            return None

    def is_between(self,i1,i2,target):
        if (i1<target<i2) or (i2<target<i1):
            return True
        else: return False

    def __str__(self):
        return "<Gov:"+str(self.gov.index)+",Dep:"+str(self.dep.index)+",dType:"+self.dType+">"

    def __repr__(self):
        return "<Gov:"+str(self.gov.index)+",Dep:"+str(self.dep.index)+",dType:"+self.dType+">"

class Transition(object):

    def __init__(self,move,dType=None):
        self.move=move
        self.dType=dType

    def __eq__(self,other):
        return self.move==other.move and self.dType==other.dType

    def __str__(self):
        return str(self.move)+":"+str(self.dType)

    def __unicode__(self):
        return unicode(self.move)+":"+unicode(self.dType)

    def __repr__(self):
        return str(self.move)+":"+str(self.dType)

class State(object):

    def __init__(self,sent=None,syn=False):
        if sent!=None:
            self.tree=Tree.new_from_conll(sent,syn)
            self.queue=self.tree.tokens[:]
        else:
            self.tree=None
            self.queue=[]
        self.stack=[]
        self.queue=[Token(-1,"*ROOT*",lemma="*ROOT*",pos="*ROOT*",feat="*ROOT*")]
        self.queue+=self.tree.tokens[:]
        self.score=0.0
        self.transitions=[]
        self.features=defaultdict(lambda:0.0)
        self.prev_state=None #The state from which this one was created, if any
        self.wrong_transitions=0 # number of wrong transitions, if 0 then same as gold

    @classmethod
    def _copy_and_point(cls,s):
        newS=copy.deepcopy(s)
        newS.features={}
        newS.prev_state=s
        return newS

    @classmethod
    def copy_and_point(cls,s):
        newS=cls.__new__(cls)
        newS.queue=s.queue[:]
        newS.stack=s.stack[:]
        newS.score=s.score
        newS.transitions=s.transitions[:] # TODO: we don't need the whole sequence anymore, just last 4 for feature generation
        newS.prev_state=s
        newS.wrong_transitions=s.wrong_transitions
        #newS.tree=copy.deepcopy(s.tree)
        newS.tree=Tree.new_from_tree(s.tree) ###MUST get rid of token.dtype first
        return newS

    def create_feature_dict(self):
        """
        Creates the full feature dictionary by assembling the dictionaries
        along the path of states
        """
        d={}
        self._populate_feature_dict(d,prefix=None) #TODO: What exactly we should do with the very last state, it doesn't have any transition prefix...
        return d

    def _populate_feature_dict(self,d,prefix):
        """
        Recursively populates `d`
        """
        if prefix!=None: #Will not extract information from the final state, but that probably makes no difference at all
            for f,w in self.features.iteritems():
                if f.startswith("grf"):
                    d[f]=d.get(f,0.0)+w
                else:
                    d[prefix+f]=d.get(f,0.0)+w
        if self.prev_state:
            self.prev_state._populate_feature_dict(d,unicode(self.transitions[-1])) #Use the last transition as the prefix for the state which resulted in this one

    def update(self,trans):
        if trans.move==SHIFT: # SHIFT
            self.shift(trans)
        elif trans.move==RIGHT: # RIGHT ARC
            self.add_arc(self.stack[-2],self.stack.pop(-1),trans)
        elif trans.move==LEFT: # LEFT ARC
            self.add_arc(self.stack[-1],self.stack.pop(-2),trans)
        elif trans.move==SWAP: # SWAP
            self.swap(trans)
        else:
            raise ValueError("Incorrect transition")
        self.transitions.append(trans)
        if len(self.queue)==0 and len(self.stack)==1:
            assert self.stack[-1].index==-1,("*ROOT* is not the last token in the stack.", self.stack)
            self.tree.ready=True

    def add_arc(self,gov,dep,trans):
        """ Gov and dep are Token class instances. """
        dependency=Dep(gov,dep,trans.dType)
        self.tree.add_dep(dependency)

    def shift(self,trans):
        self.stack.append(self.queue.pop(0))

    def swap(self,trans):
        self.queue.insert(0,self.stack.pop(-2))

    def valid_transitions(self):
        moves=set()
        if len(self.queue)>0: # SHIFT
            moves.add(SHIFT)
        if len(self.stack)>1: # ARCS
            if self.stack[-2].index!=-1: # if s2 is not root
                moves.add(LEFT)
            if  self.stack[-2].index!=-1 or len(self.queue)==0: # Only allow RIGHT from ROOT when queue is empty
                moves.add(RIGHT)
        if len(self.stack)>1 and self.stack[-1].index>self.stack[-2].index and self.stack[-2].index!=-1: # SWAP
            if len(self.queue)==0 and len(self.stack)==2: return moves # no need for swap, we can use simple LEFT or RIGHT
            moves.add(SWAP)
        return moves

    def __str__(self):
        return "Tree ready? "+str(self.tree.ready)+"\nStack: ["+" ".join(token.text for token in self.stack)+"]\nQueue: ["+" ".join(token.text for token in self.queue)+"]\nScore:"+str(self.score)+"\n"+"\n".join("("+dep.gov.text+" "+dep.dep.text+" "+dep.dType+")" for dep in self.tree.deps)

    def __repr__(self):
        return ",".join(str(t.move)+":"+str(t.dType) for t in self.transitions)


from django.shortcuts import render
import os
from django.conf import settings
from django.http import HttpResponse

def livelog(request):
    """""
    x = np.linspace(-3, 3, 50)
    y1 = 2 * x + 1

    fig, ax = plt.subplots()
    ax.plot(x, y1)
#    plt.show()
    mpld3.fig_to_html(fig)
    mpld3.save_html(fig, 'echo_example/templates/interactive_fig.js')

    f= open('echo_example/templates/interactive_fig.js', 'r')
    content = f.read()
    f.close();
    the_file= open('test.js', 'w')
    the_file.write(content)
    the_file.close()
    """""
    return render(request, 'index.html')

def upload_data(request):
    if request.method == 'POST' and request.FILES['myfile']:
        myfile = request.FILES['myfile']
        fs = FileSystemStorage()
        filename = fs.save(myfile.name, myfile)
        uploaded_file_url = fs.url(filename)
        return render(request, 'echo_example/templates/simple_upload.html', {
            'uploaded_file_url': uploaded_file_url
        })
    return render(request, 'echo_example/templates/simple_upload.html')

def download_data(request, path):
    file_path = os.path.join(settings.MEDIA_ROOT, path)
    if os.path.exists(file_path):
        with open(file_path, 'rb') as fh:
            response = HttpResponse(fh.read(), content_type="text/html")
            response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
            return response
    raise Http404
    return render(request, 'index.html')

def file_download(request):
    # do something...
    with open('echo_example/static/IndexTable_TX00.Txt') as f:
        c = f.read()
    return HttpResponse(c)


def fun_fibs(n: int):
    """
    :param n:返回斐波那契数列前n个数
    :return:
    """
    fibs = [1, 1]
    for m in range(3, n + 1):
        fibs.append(fibs[-1] + fibs[-2])
    return fibs

def formatFibs(data: list, rowCount: int):
    """
    :param data:传入列表
    :param rowCount:几个数换行
    """
    print("--------------------------------------")
    index = 0;
    for p in data:
        print(f"{p:10}", end=",")
        index += 1
        if index % rowCount == 0: print()
    print("--------------------------------------")

if __name__ == '__main__':
    fibsList = fun_fibs(36)
    formatFibs(fibsList, 6)

02函数的返回值与参数.py


file = open("members.txt","r")
members = {}
name=""
for line in file:
        line=tuple(line)
        pos=line.index(',')
        for i in range(pos):
                name=name+line[i]
        num=''
        element=()
        for i in range(3):
                if i!=2:
                        line=line[pos+1:]
                        pos=line.index(',')
                for j in range(pos):
                        num=num+line[j]
                print(num)
                if i==1:
                        element=element+(float(num), )
                else:
                        element=element+(int(num), )
                num=''
                members[name]=element
        name=""
print(members)
file.close()


import os
from django import template
from django.conf import settings
from django.template.loader import find_template_source
from django.template.loader import get_template_from_string
from django.utils.html import escape
from django.utils.safestring import mark_safe
try:
    from pygments import highlight
    from pygments.lexers import PythonLexer, HtmlDjangoLexer, HtmlLexer
    from pygments.formatters import HtmlFormatter
except ImportError:
    highlight = None
from examples import forms

register = template.Library()

def get_form(example_name):
    form_path = os.path.join(os.path.dirname(forms.__file__),
                             '%s.py' % example_name)
    form_code = open(form_path, 'rb').read()
    form_module = __import__('examples.forms.%s' % example_name,
                             globals(),
                             locals(),
                             ['ExampleForm'])
    return getattr(form_module, 'ExampleForm'), form_code

def get_template(example_name):
    template_name = 'examples/examples/%s.html' % example_name
    template_code, origin = find_template_source(template_name)
    template_obj = get_template_from_string(template_code, origin, example_name)
    return template_obj, template_code

@register.inclusion_tag('examples/_example.html')
def example(example_name):
    form, form_code = get_form(example_name)
    template_obj, template_code = get_template(example_name)
    rendered = template_obj.render(template.Context({'form': form(),
                                            'MEDIA_URL': settings.MEDIA_URL}))
    if highlight:
        formatter = HtmlFormatter()
        form_code = highlight(form_code, PythonLexer(), formatter)
        template_code = highlight(template_code, HtmlDjangoLexer(), formatter)
        rendered_code = highlight(rendered, HtmlLexer(), formatter)
    else:
        form_code = u'
%s
' % form_code
        tpl = u'
<form action="" method="POST">%s</form>
'
        template_code = tpl % template_code
        rendered_code = tpl % escape(rendered)
    return {
        'name': example_name,
        'form_code': mark_safe(form_code),
        'template': mark_safe(template_code),
        'rendered_code': mark_safe(rendered_code),
        'rendered': rendered,
    }


import unittest
import datetime
from datawinners.accountmanagement.models import Organization
from datawinners.submission.views import process_sms_counter
from datawinners.tests.data import TRIAL_ACCOUNT_ORGANIZATION_ID
from mock import patch
from datawinners.submission.views import check_quotas_and_update_users
from datawinners.settings import NEAR_SUBMISSION_LIMIT_TRIGGER, NEAR_SMS_LIMIT_TRIGGER
from django.core import mail
from django.contrib.auth.models import Group
from django.template.loader import render_to_string
from rest_framework.authtoken.models import Token
from dateutil.relativedelta import relativedelta
from django.contrib.sites.models import Site

class TestProcessSMSCounter(unittest.TestCase):
    def setUp(self):
        self.incoming_request ={}
        self.incoming_request['outgoing_message']=''
        self.incoming_request['incoming_message']=''
        organization = Organization.objects.get(pk=TRIAL_ACCOUNT_ORGANIZATION_ID)
        active_date = datetime.datetime.today()  - relativedelta(days=3)
        organization.active_date, organization.status_changed_datetime = active_date, active_date
        organization.save()
        self.incoming_request['organization'] = organization
        self.outgoing_message = "You have reached your 50 SMS Submission limit. Please upgrade to a monthly subscription to continue sending in SMS Submissions to your projects."
        users = self.incoming_request['organization'].get_related_users()
        self.user = users[0]
        self.group = Group.objects.get(name='NGO Admins')
        self.group.user_set.add(self.user)

    def tearDown(self):
        self.group.user_set.remove(self.user)

    def test_should_go_to_next_state_when_message_limit_does_not_exceeds(self):
        self.incoming_request = process_sms_counter(self.incoming_request)
        self.assertEquals(self.incoming_request['outgoing_message'], '')

    def test_should_return_outgoing_message_when_message_limit_exceeds(self):
        message_tracker = self._get_current_message_tracker_of_organization()
        message_tracker.incoming_sms_count = 50
        message_tracker.save()
        with patch('datawinners.submission.views.get_translated_response_message') as mock_get_translated_response_message:
            self.incoming_request.update({'outgoing_message': self.outgoing_message})
            mock_get_translated_response_message.return_value = self.incoming_request
            self.incoming_request = process_sms_counter(self.incoming_request)
            self.assertEquals(self.incoming_request['outgoing_message'], self.outgoing_message)

    def _get_current_message_tracker_of_organization(self):
        current_month = datetime.date(datetime.datetime.now().year, datetime.datetime.now().month, 1)
        message_tracker = self.incoming_request['organization']._get_message_tracker(current_month)
        return message_tracker

    def test_should_return_outgoing_message_when_organization_is_deactivated(self):
        self.incoming_request['organization'].status = 'Deactivated'
        self.assertEqual(self.incoming_request['organization'].status, 'Deactivated')
        self.incoming_request = process_sms_counter(self.incoming_request)
        self.assertEquals(self.incoming_request['outgoing_message'], '')

    def test_should_send_mail_when_ngo_about_to_reach_submission_limit(self):
        token = Token.objects.get_or_create(user=self.user)[0].key
        organization = self.incoming_request.get('organization')
        site = Site.objects.get_current()
        with patch.object(Organization, "get_total_submission_count") as patch_get_total_submission_count:
            patch_get_total_submission_count.return_value = NEAR_SUBMISSION_LIMIT_TRIGGER
            check_quotas_and_update_users(organization=organization)
            site = Site.objects.get_current()
            email = mail.outbox.pop()
            self.assertEqual(['chinatwu2@gmail.com'], email.to)
            ctx = {'username':'Trial User', 'organization':organization, 'site':site,
                   'token':token}
            self.assertEqual(render_to_string('email/basicaccount/about_to_reach_submission_limit_en.html', ctx), email.body)

    def test_should_send_mail_to_when_sms_limit_is_about_to_reached(self):
        token = Token.objects.get_or_create(user=self.user)[0].key
        organization = self.incoming_request.get('organization')
        with patch.object(Organization, "get_total_incoming_message_count") as patch_get_total_incoming_message_count:
            patch_get_total_incoming_message_count.return_value = NEAR_SMS_LIMIT_TRIGGER
            check_quotas_and_update_users(organization=organization, sms_channel=True)
            site = Site.objects.get_current()
            email = mail.outbox.pop()
            self.assertEqual(['chinatwu2@gmail.com'], email.to)
            ctx = {'username':'Trial User', 'organization':organization, 'site':site,
                   'token': token}
            self.assertEqual(render_to_string('email/basicaccount/about_to_reach_sms_limit_en.html', ctx), email.body)

    def test_should_send_all_email_type_when_all_limit_are_about_to_reached(self):
        organization = self.incoming_request.get('organization')
        with patch.object(Organization, "get_total_submission_count") as patch_get_total_submission_count:
            with patch.object(Organization, "get_total_incoming_message_count") as patch_get_total_incoming_message_count:
                patch_get_total_submission_count.return_value = NEAR_SUBMISSION_LIMIT_TRIGGER
                patch_get_total_incoming_message_count.return_value = NEAR_SMS_LIMIT_TRIGGER
                check_quotas_and_update_users(organization=organization, sms_channel=True)
                expected_subjects = [u'DataWinners | 50 SMS Submission Limit Almost Reached: Upgrade to Continue Collecting Data via SMS!',
                    u'Your DataWinners Submission Limit is Approaching!']
                msgs = [mail.outbox.pop() for i in range(len(mail.outbox))]
                for msg in msgs:
                    self.assertIn(msg.subject, expected_subjects)

    def test_should_return_empty_string_for_expired_account(self):
        with patch.object(Organization, 'is_expired') as patch_is_expired:
            patch_is_expired.return_value = True
            self.assertTrue(self.incoming_request.get('organization').is_expired())
            self.incoming_request = process_sms_counter(self.incoming_request)
            self.assertEqual(self.incoming_request['outgoing_message'], "")


#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
import json
import string
import xlwings
import requests
import threading
import subprocess
from lxml import etree
from time import sleep
from pathlib import Path
from random import randint
from urllib.parse import quote
from playsound import playsound
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Text, Boolean, create_engine

# 创建对象的基类:
Base = declarative_base()

# 定义Bank对象:
class Bank(Base):
    # 表的名字:
    __tablename__ = 'banks'
    '''表的结构:
        id | catagory | content | options[item0, item1, item2, item3] | answer | note | bounds
        序号 |  题型  |   题干   |                  选项               |  答案  | 注释 | 位置(保存时丢弃)
    '''
    id = Column(Integer, primary_key=True)
    catagory = Column(String(128), default='radio')  # radio check blank challenge
    content = Column(Text, default='content')
    # options的处理，每个item用空格分隔开，若item本身包含空格，则replace为顿号(、)
    options = Column(Text, default='')
    answer = Column(String(256), nullable=True, default='')
    note = Column(Text, nullable=True, default='')
    bounds = Column(String(128), nullable=True, default='')

    def __init__(self, catagory, content, options, answer, note, bounds):
        self.catagory = catagory or 'radio'  # 挑战答题-挑战题, 每日答题-单选题、多选题、填空题
        self.content = content or 'default content'
        self.options = options or ''
        self.answer = answer.upper() or ''
        self.note = note or ''
        self.bounds = bounds or ''

    def __repr__(self):
        return f'<Bank {self.content}>'

    def __str__(self):
        maxlen = 42
        if len(self.content) > maxlen:
            content = f'{self.content[:maxlen]}...'
        else:
            content = self.content
        content = re.sub(r'\s', '_', content)
        options = ''
        if self.options:
            options = f'O: {self.options}\n'
        return f'I: {self.id} {self.catagory}\nQ: {content:<50}\n{options}A: {self.answer}\n'

    def __eq__(self, other):
        return self.content == other.content

    @classmethod
    def from_challenge(cls, content, options='', answer='', note='', bounds=''):
        str_options = '|'.join(options)
        return cls(catagory='挑战题', content=content, options=str_options, answer=answer, note=note, bounds=bounds)

    @classmethod
    def from_daily(cls, catagory, content, options, answer, note):
        return cls(catagory=catagory, content=content, options=options, answer=answer, note=note, bounds='')

    def to_array(self):
        options = self.options.split('|')
        array_bank = [self.id, self.answer, self.content]
        array_bank.extend(options)
        # array_bank.append(self.note)
        return array_bank

    def to_dict(self):
        json_bank = {
            "id": self.id,
            "catagory": self.catagory,
            "content": self.content,
            "options": self.options,
            "answer": self.answer,
            "note": self.note
        }
        return json_bank

    @classmethod
    def from_dict(cls, data):
        return cls(data['catagory'], data['content'], re.sub(r'\s', '|', re.sub(r'|', '', data['options'])),
                   data['answer'], data['note'], '')

class Article(Base):
    __tablename__ = 'articles'
    id = Column(Integer, primary_key=True)
    title = Column(Text, index=True, default='title')

    def __repr__(self):
        return f'{self.title}'

    def __str__(self):
        return f'[{self.id}] {self.title}'

class Xlser(object):
    def __init__(self, paths):
        self.path = paths

    def load(self):
        data = []
        app = xlwings.App(visible=False, add_book=False)
        wb = app.books.open(self.path)
        ws = wb.sheets['bank']
        rng = ws.used_range
        print(rng.rows[0].value)
        for row in rng.rows[1:]:
            res = (row.value[1]).replace(u'\xa0', ' ')
            bank = Bank.from_challenge(content=res, answer=row.value[6])
            data.append(bank)
        wb.close()
        app.quit()
        return data

    def save(self, data):
        app = xlwings.App(visible=False, add_book=False)
        wb = app.books.add()
        ws = wb.sheets['Sheet1']
        # 写入数据
        print(f'{len(data)}条数据正在导出...')
        ws.range(1, 1).value = ['序号', '答案', '题干', '选项A', '选项B', '选项C', '选项D', '说明']
        try:
            for i, item in enumerate(data):
                ws.range(i + 2, 1).value = item.to_array()
        except Exception:
            print(f'xls写入失败')
        finally:
            wb.save(self.path)
            wb.close()
            app.quit()
        return 0

class Model():
    def __init__(self, database_uri):
        # 初始化数据库连接:
        engine = create_engine(database_uri)
        # 创建DBSession类型:
        Session = sessionmaker(bind=engine)

        Base.metadata.create_all(engine)
        self.session = Session()

    # 数据库检索记录
    def query(self, ids=None, content=None, catagory='挑战题 单选题 多选题 填空题'):
        catagory = catagory.split(' ')
        if ids and isinstance(id, int):
            return self.session.query(Bank).filter_by(id=id).one_or_none()
        if content and isinstance(content, str):
            content = re.sub(r'\s+', '%', content)
            return self.session.query(Bank).filter(Bank.catagory.in_(catagory)).filter(
                Bank.content.like(content)).one_or_none()
        return self.session.query(Bank).filter(Bank.catagory.in_(catagory)).all()

    # 数据库添加纪录
    def add(self, item):
        result = self.query(content=item.content, catagory=item.catagory)
        if result:
            print(f'数据库已存在此纪录，无需添加纪录！')
        else:
            self.session.add(item)
            self.session.commit()
            print(f'数据库添加记录成功！')

    def has_article(self, title):
        return self.session.query(Article).filter_by(title=title).one_or_none() is not None

    def print_arcitles(self):
        items = self.session.query(Article).all()
        for item in items:
            print(item)

    def len_articles(self):
        return len(self.session.query(Article).all())

    def add_article(self, title):
        if '' == title:
            raise ValueError('文章标题不能为空')
        if self.has_article(title):
            raise RuntimeError('文章标题已在数据库中')
        else:
            article = Article(title=title)
            self.session.add(article)
            self.session.commit()
            print(f'数据库添加成功！ {title}')

    def _to_json(self, path, catagory='挑战题 单选题 多选题 填空题'):
        datas = self.query(catagory=catagory)
        # print(len(datas))
        output = [data.to_dict() for data in datas]
        with open(path, 'w', encoding='utf-8') as fp:
            json.dump(output, fp, indent=4, ensure_ascii=False)
        print(f'JSON数据{len(datas)}条成功导出{path}')
        return True

    def _from_json(self, path, catagory='挑战题 单选题 多选题 填空题'):
        if path.exists():
            with open(path, 'r', encoding='utf-8') as fp:
                res = json.load(fp)
            for r in res:
                bank = Bank.from_dict(r)
                if '填空题' == bank.catagory:
                    if str(len(bank.answer.split(' '))) != bank.options:
                        continue
                self.add(bank)
            print(f'JSON数据成功导入{path}')
            return True
        else:
            print(f'JSON数据{path}不存在')
            return False

    def _to_md(self, paths, catagory='挑战题'):
        db = Model('sqlite:///./xuexi/data-dev.sqlite')
        items = db.query(catagory=catagory)
        with open(paths, 'w', encoding='utf-8') as fp:
            fp.write(f'# 学习强国 挑战答题 题库 {len(items):>4} 题\n')
            for item in items:
                content = re.sub(r'\s\s+', '\_\_\_\_', re.sub(r'[\(（]出题单位.*', '', item.content))
                options = "\n\n".join([f'+ **{x}**' if i == ord(item.answer) - 65 else f'+ {x}' for i, x in
                                       enumerate(item.options.split('|'))])
                fp.write(f'{item.id}. {content}  *{item.answer}*\n\n{options}\n\n')
        with open(paths.with_name('data-grid.md'), 'w', encoding='utf-8') as fp2:
            fp2.write(f'# 学习强国 挑战答题 题库 {len(items):>4} 题\n')
            fp2.write(f'|序号|答案|题干|选项A|选项B|选项C|选项D|\n')
            fp2.write(f'|:--:|:--:|--------|----|----|----|----|\n')
            for item in items:
                content = re.sub(r'\s\s+', '\_\_\_\_', re.sub(r'[\(（]出题单位.*', '', item.content))
                options = " | ".join([f'**{x}**' if i == ord(item.answer) - 65 else f'{x}' for i, x in
                                      enumerate(item.options.split('|'))])
                fp2.write(f'| {item.id} | {item.answer} | {content} | {options} |\n')

        return 0

    def _to_xls(self, paths, catagory='挑战题 单选题 多选题 填空题'):
        data = self.query(catagory=catagory)
        xs = Xlser(paths)
        xs.save(data)

    def upload(self, path, catagory='挑战题 单选题 多选题 填空题'):
        if '.json' == path.suffix:
            self._from_json(path, catagory)
        elif path.suffix not in ('.xls', '.xlsx'):
            print(f'不被支持的文件类型: {path.suffix}')

    def download(self, path, catagory='挑战题 单选题 多选题 填空题'):
        ext = path.suffix
        if '.json' == ext:
            self._to_json(path, catagory)
        elif ext in ('.xls', '.xlsx'):
            self._to_xls(path, catagory)
        elif '.md' == ext:
            self._to_md(path, catagory)
        else:
            print(f'不被支持的文件类型: {ext}')

# 提示语音
def attention(paths, repeat=2):
    # 语音提示：https://developer.baidu.com/vcast导出音频
    for i in range(repeat):
        playsound(paths)

class Alarm:
    def __init__(self, filename, repeat=2):
        paths = Path('./xuexi/src/sounds')
        t = threading.Thread(target=attention, args=(str(paths / filename), repeat))  # 创建线程
        t.start()

class ChallengeQuiz(object):
    def __init__(self, rules, ad, xm):
        self.rules = rules
        # filename是文件challenge.json的路径
        self.filename = Path('./xuexi/src/json/challenge.json')
        self.ad = ad
        self.xm = xm
        self.db = Model(r'E:\AutoXue-master\xuexi\data-dev.sqlite')
        self.has_bank = False
        self.is_user = True
        self.content = ''
        self.options = ''
        self.note = ''
        self.answer = ''
        self.pos = ''
        self.p_back = 0j
        self.p_return = 0j
        self.p_share = 0j

    # 开始答题
    def _enter(self):
        self._fresh()
        pos = self.xm.pos('//node[@text="挑战答题"]/@bounds')
        self.ad.tap(pos)
        print(f'挑战答题，开始！')
        sleep(2)

    def _fresh(self):
        self.ad.uiautomator()
        self.xm.load()

    # 加载json文件
    def _load(self):
        filename = self.filename
        res = []
        if self.filename.exists():
            with open(filename, 'r', encoding='utf-8') as fp:
                try:
                    res = json.load(fp)
                except Exception:
                    print(f'加载JSON数据失败')
            print(f'载入JSON数据{filename}')
            return res
        else:
            print('JSON文件{filename}不存在')
            return res

    # 保存json文件
    def _dump(self):
        filename = self.filename
        with open(filename, 'w', encoding='utf-8') as fp:
            json.dump(self.json_blank, fp, indent=4, ensure_ascii=False)
        print(f'导出JSON数据{filename}')
        return True

    # 去百度搜索
    def _search(self):
        print(f'search - {self.content}')
        Alarm('challenge.mp3', 1)
        # 搜索引擎检索题目
        content = re.sub(r'[\(（]出题单位.*', "", self.content)
        print(f'\n[挑战题] {content}')
        url = quote('https://www.baidu.com/s?wd=' + content, safe=string.printable)
        headers = {
            'User-Agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) "
                          "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
        }
        response = requests.get(url, headers=headers).text
        counts = []
        for i, option in zip(['A', 'B', 'C', 'D'], self.options):
            count = response.count(option)
            counts.append((count, i))
            print(f'{i}. {option}: {count}')
        counts = sorted(counts, key=lambda x: x[0], reverse=True)
        bank = None
        for item in self.json_blank:
            if item['content'] == self.content:
                bank = item
                break
            else:
                continue
        if bank:
            for c in counts:
                if c[1] in bank['note']:
                    continue
                else:
                    _, self.answer = c
                    break
        else:
            _, self.answer = counts[0]
        print(f'试探性提交答案 {self.answer} 延时10秒中...')
        sleep(5)
        return ord(self.answer)-65

    # 题目内容，返回值res
    def _content(self):
        res = self.xm.content('//node[@class="android.widget.ListView"]/preceding-sibling::node[1]/@text')
        print(res)
        return res

    # 选项
    def _options(self):
        res = self.xm.options('//node[@class="android.widget.ListView"]/node//node[@index="1" '
                              'and @class="android.view.View"]/@text')
        print(res)
        return res

    # 选项的坐标范围
    def _pos(self):
        res = self.xm.pos('//node[@class="android.widget.ListView"]/node/@bounds')
        print(res)
        return res

    # 提交
    def _submit(self):
        self._fresh()
        self.content = self._content()    # 答题内容
        self.options = self._options()    # 选项（文字）
        self.note = ''
        self.pos = self._pos()            # 选项的坐标
        # 去数据库检索
        bank = self.db.query(content=self.content, catagory='挑战题')
        # 如果数据库里面存在这个数据
        if bank is not None:
            # char()内置函数，把数字ASCII码转换为字符
            options = "\n".join([f'{chr(i+65)}. {x}' for i, x in enumerate(self.options)])
            # for i, x in enumerate(self.options):
            #     options = "\n".join(f'{chr(i + 65)}. {x}')
            # [挑战题]题干...
            # 选项的内容
            print(f'\n[挑战题] {self.content[:45]}...\n{options}')
            self.has_bank = True
            # ord()内置函数，返回ASCII值
            cursor = ord(bank.answer) - 65
            print(f'自动提交答案 {bank.answer}')

            # 延时功能
            challenge_delay = 0
            if 0 == challenge_delay:
                delay_seconds = randint(0, 5)
            else:
                delay_seconds = challenge_delay
            sleep(delay_seconds)

        # 如果bank是None则去百度搜索
        else:
            self.has_bank = False
            cursor = self._search()

        print(f'正确选项下标 {cursor}')
        # 点击正确选项
        while 0j == self.pos[cursor]:
            self.ad.draw('up')
            self._fresh()
            self.pos = self._pos()
        # 现在可以安全点击(触摸)
        self.ad.tap(self.pos[cursor])

    def _db_add(self):
        # from_challenge(cls, content, options, answer='',note='', bounds='')
        if not self.has_bank:
            bank = Bank.from_challenge(content=self.content, options=self.options,
                                       answer=self.answer, note='', bounds='')
            self.db.add(bank)
            if self.is_user:
                self.json_blank.append(bank.to_dict())

    def _reopened(self, repeat: bool = False) -> bool:
        # 默认使用复活权,不使用再来一局
        # sleep(2)
        self._fresh()
        # 本题答对否
        if not self.xm.pos('//node[@text="分享就能复活" or @text="再来一局"]/@bounds'):
            self._db_add()
            return True
        else:
            # 在note中追加一个错误答案，以供下次遇到排除
            temp = None
            for item in self.json_blank:
                if item['content'] == self.content:
                    temp = item
            if temp:
                temp['note'] += self.answer
            else:
                temp = Bank.from_challenge(content=self.content, options=self.options,
                                           answer='', note=self.answer, bounds='')
                self.json_blank.append(temp.to_dict())
                print(f'错题加入错题集JSON文件中')
            print(f'不要那么贪心，闪动的复活按钮不好点击，就此结束吧')
            return False

    def _commet(self):
        maxlen = len(self.options)
        try:
            ch = input(f'请输入正确的答案: ').upper()
            assert ch in 'NABCD'[:maxlen+1], f"输入的项目不存在，请输入A-DN"
        except Exception as ex:
            print(f"输入错误:", ex)
        if ch in 'ABCD':
            self.answer = ch
            self._db_add()
        return ch

    def _run(self, count):
        sub_count = count
        self._enter()
        while sub_count:
            self._submit()
            if self._reopened():   # 回答正确
                sub_count = sub_count - 1
            else:
                break
        else:
            print(f'已达成目标题数，延时30秒等待死亡中...')
            sleep(30)
        self.ad.back()
        return sub_count

    def run(self, count):
        while True:
            self.json_blank = self._load()
            if 0 == self._run(count):
                print(f'已达成目标题数 {count} 题，退出挑战')
                break
            else:
                sleep(3)
                print(f'未达成目标题数，再来一局')
            self._dump()

    def runonce(self, sub_count):
        while sub_count:
            self._submit()
            if self._reopened():   # 回答正确
                sub_count = sub_count - 1
            else:
                break

def str2complex(s):
    x0, y0, x1, y1 = [int(x) for x in re.findall(r'\d+', s)]
    print(f'({x0}, {y0}) -> ({x1}, {y1})')
    res = complex((x0+x1)//2, (y0+y1)//2)
    print(res)
    return res

class Xmler(object):
    def __init__(self, paths=Path('./xuexi/src/xml/reader.xml')):
        self.path = paths
        self.root = None

    def load(self):
        self.root = etree.parse(str(self.path))

    def texts(self, rule: str) -> list:
        # return list<str>
        res = [x.replace(u'\xa0', u' ') for x in self.root.xpath(rule)]
        res = [' ' if '' == x else x for x in res]
        print(res)
        return res

    def pos(self, rule: str) -> list:
        # return list<complex>
        print(rule)
        res = self.texts(rule)
        print(res)
        points = [str2complex(x) for x in res]
        if len(points) == 1:
            res = points[0]
        else:
            res = points
        print(res)
        return res

    def content(self, rule: str) -> str:
        # return str
        print(rule)
        # res = self.texts(rule) # list<str>
        # res = ' '.join([" ".join(x.split()) for x in self.texts(rule)])
        res = ''.join(self.texts(rule))
        print(res)
        return res

    def options(self, rule: str) -> list:
        res = [re.sub(r'\|', '_', x) for x in self.root.xpath(rule)]
        print(res)
        return res

    def count(self, rule: str) -> int:
        # return int
        print(rule)
        res = self.root.xpath(rule)
        return len(res)

class Adble(object):
    def __init__(self, paths=Path('./ui.xml'), is_virtual: bool = True, host='127.0.0.1', port=7555):
        # subprocess.Popen(f'adb version', shell=True)
        self.path = paths
        self.is_virtual = is_virtual
        self.host = host
        self.port = port
        if self.is_virtual:
            self._connect()
        else:
            print(f'请确保安卓手机连接手机并打开USB调试!')
        self.device = self._getDevice()
        if self.device is not None:
            print(f'当前设备 {self.device}')
            self.ime = self._getIME()
            self.wmsize = self._size()
            self._setIME('com.android.adbkeyboard/.AdbIME')
        else:
            print(f'未连接设备')
            raise RuntimeError(f'未连接任何设备')

    def _connect(self):
        # 连接模拟器adb connect host:port
        print(f'正在连接模拟器{self.host}:{self.port}')
        subprocess.check_call(f'adb connect {self.host}:{self.port}', shell=True, stdout=subprocess.PIPE)

    def _disconnect(self):
        # 连接模拟器adb connect host:port
        print(f'正在断开模拟器{self.host}:{self.port}')
        if 0 == subprocess.check_call(f'adb disconnect {self.host}:{self.port}', shell=True, stdout=subprocess.PIPE):
            print(f'断开模拟器{self.host}:{self.port} 成功')
        else:
            print(f'断开模拟器{self.host}:{self.port} 失败')

    def draw(self, orientation='down', distance=100, duration=500):
        height, width = max(self.wmsize), min(self.wmsize)  # example: [1024, 576]
        # 中点 三分之一点 三分之二点
        x0, x1, x2 = width // 2, width // 3, width // 3 * 2
        y0, y1, y2 = height // 2, height // 3, height // 3 * 2
        if 'down' == orientation:
            self.swipe(x0, y1, x0, y1 + distance, duration)
        elif 'up' == orientation:
            self.swipe(x0, y2, x0, y2 - distance, duration)
        elif 'left' == orientation:
            self.swipe(x2, y0, x2 - distance, y0, duration)
        elif 'right' == orientation:
            self.swipe(x1, y0, x1 + distance, y0, duration)
        else:
            print(f'没有这个方向 {orientation} 无法划动')
        return 0

    def _size(self):
        res = subprocess.check_output(f'adb -s {self.device} shell wm size', shell=False)
        if isinstance(res, bytes):
            wmsize = re.findall(r'\d+', str(res, 'utf-8'))
        else:
            wmsize = re.findall(r'\d+', res)
        print(f'屏幕分辨率：{wmsize}')
        res = [int(x) for x in wmsize]
        return res

    def _setIME(self, ime):
        print(f'设置输入法 {ime}')
        print(f'正在设置输入法 {ime}')
        if 0 == subprocess.check_call(f'adb -s {self.device} shell ime set {ime}', shell=True, stdout=subprocess.PIPE):
            print(f'设置输入法 {ime} 成功')
        else:
            print(f'设置输入法 {ime} 失败')

    def _getIME(self) -> list:
        print(f'获取系统输入法list')
        res = subprocess.check_output(f'adb -s {self.device} shell ime list -s', shell=False)
        if isinstance(res, bytes):
            # ime = re.findall(r'\d+', str(res, 'utf-8'))
            ime = re.findall(r'\S+', str(res, 'utf-8'))
        else:
            ime = re.findall('\S+', res)
        print(f'系统输入法：{ime}')
        return ime[0]

    def _getDevice(self) -> str:
        print(f'获取连接的设备信息')
        res = subprocess.check_output(f'adb devices')
        if isinstance(res, bytes):
            res = str(res, 'utf-8')
        devices = re.findall(r'(.*)\tdevice', res)
        print(f'已连接设备 {devices}')
        if self.is_virtual and f'{self.host}:{self.port}' in devices:
            return f'{self.host}:{self.port}'
        elif 0 == len(devices):
            return None
        else:
            return devices[0]

    def uiautomator(self, path=None, filesize=10240):
        if not path:
            path = self.path
        for i in range(3):
            if path.exists():
                path.unlink()
            else:
                print('文件不存在,无需删除')
            subprocess.check_call(f'adb -s {self.device} shell uiautomator dump /sdcard/ui.xml', shell=True,
                                  stdout=subprocess.PIPE)
            # sleep(1)
            subprocess.check_call(f'adb -s {self.device} pull /sdcard/ui.xml {path}', shell=True,
                                  stdout=subprocess.PIPE)
            if filesize < path.stat().st_size:
                break
            else:
                sleep(1)

    def screenshot(self, paths=None):
        if not paths:
            paths = self.path
        subprocess.check_call(f'adb -s {self.device} shell screencap -p /sdcard/ui.png', shell=True,
                              stdout=subprocess.PIPE)
        # sleep(1)
        subprocess.check_call(f'adb -s {self.device} pull /sdcard/ui.png {paths}', shell=True, stdout=subprocess.PIPE)

    def swipe(self, sx, sy, dx, dy, duration):
        #  swipe from (sx, xy) to (dx, dy) in duration ms
        # adb shell input swipe 500 500 500 200 500
        print(f'滑动操作 ({sx}, {sy}) --{duration}ms-> ({dx}, {dy})')
        res = subprocess.check_call(f'adb -s {self.device} shell input swipe {sx} {sy} {dx} {dy} {duration}',
                                    shell=True, stdout=subprocess.PIPE)
        # sleep(1)
        return res

    def slide(self, begin, end, duration=500):
        # 接收complex参数坐标
        print(f'滑动操作 {begin} --{duration}ms-> {end}')
        sx, sy = int(begin.real), int(begin.imag)
        dx, dy = int(end.real), int(end.imag)
        res = subprocess.check_call(f'adb -s {self.device} shell input swipe {sx} {sy} {dx} {dy} {duration}',
                                    shell=True, stdout=subprocess.PIPE)
        # sleep(1)
        return res

    def tap(self, x, y=None, duration=50):
        # subprocess.check_call(f'adb shell input tap {x} {y}', shell=True, stdout=subprocess.PIPE)
        # 改进tap为长按50ms，避免单击失灵'''
        if y is not None:
            if isinstance(x, int) and isinstance(y, int):
                dx, dy = int(x), int(y)
            else:
                print(f'输入坐标有误')
        else:
            try:
                dx, dy = int(x.real), int(x.imag)
            except Exception as e:
                raise AttributeError(f'{x} 不是可点击的坐标')
        print(f'触摸操作 ({dx}, {dy})')
        return self.swipe(dx, dy, dx, dy, duration)

    def back(self):
        # adb shell input keyevent 4
        print(f'adb 触发<返回按钮>事件')
        subprocess.check_call(f'adb -s {self.device} shell input keyevent 4', shell=True, stdout=subprocess.PIPE)

    def input(self, msg):
        print(f'输入文本 {msg}')
        # subprocess.check_call(f'adb shell input text {msg}', shell=True, stdout=subprocess.PIPE)
        subprocess.check_call(f'adb -s {self.device} shell am broadcast -a ADB_INPUT_TEXT --es msg {msg}', shell=True,
                              stdout=subprocess.PIPE)

    def close(self):
        self._setIME(self.ime)
        if self.is_virtual:
            self._disconnect()

if __name__ == "__main__":
    from argparse import ArgumentParser
    print('运行challenge.py')
    parse = ArgumentParser()
    parse.add_argument('-c', '--count', metavar='count', type=int, default=10, help='挑战答题题数')
    parse.add_argument('-v', '--virtual', metavar='virtual', nargs='?', const=True,
                       type=bool, default=False, help='是否模拟器')

    args = parse.parse_args()
    path = Path('./xuexi/src/xml/challenge.xml')
    ad = Adble(path, args.virtual)
    xm = Xmler(path)
    cg = ChallengeQuiz('nox', ad, xm)
    cg.runonce(args.count)
    ad.close()


from sklearn.utils import shuffle
import numpy as np
import nltk
from nltk.tokenize import RegexpTokenizer
from tensorflow.keras import preprocessing
from unicodedata import normalize
import collections
from operator import itemgetter

def build_word2index(word_list):
    """
    Takes a list of (unique!) word tokens. Returns a word-index dictionary, last index is assigned to '<UNK>'.
    """
    tokenizer_dict = {}
    i = 1
    for word in word_list:
        tokenizer_dict[word] = i
        i += 1
    tokenizer_dict["<UNK>"] = i
    return tokenizer_dict

def tokenize(clean_text):
    token_list = nltk.word_tokenize(clean_text)
    return token_list

def build_vocabulary(token_list, threshold=1, with_freq=True):
    """
    Takes a list of tokens (from corpus), counts them with frequencies and returns a list
    of (word, freq) with freq >= threshold, sorted from frequent to rare. If with_freq=False,
    returns a list of words, still sorted by frequency.
    """
    token_list_Counter = collections.Counter(token_list)
    token_list_over_threshold = []
    for key, value in token_list_Counter.items():
        token_list_over_threshold.append((key, value))
    token_list_over_threshold.sort(key=itemgetter(1), reverse=True)
    if with_freq:
        token_list_over_threshold = [(word, count) for (word, count) in token_list_over_threshold if count >= threshold]
    else:
        token_list_over_threshold = [word for (word, count) in token_list_Counter if count >= threshold]
    #token_list_over_threshold = sorted(token_list_over_threshold, key=lambda x: x[0])
    #vocabulary_size = len(token_list_over_threshold) + 1
    return token_list_over_threshold

def clean(sentences):
    """
    Takes the corpus, decodes into UTF-8, tokenizes on white space, puts everything in lowercase, removes numbers (!?)
    Returns string.
    """

    clean_txt = ''
    for line in sentences:

        line = normalize('NFD', line).encode('ascii', 'ignore')
        line = line.decode('UTF-8')
        # tokenize on white space
        line = line.split()
        # convert to lowercase
        line = [word.lower() for word in line]
        # remove punctuation from each token
        #line = [word.translate(table) for word in line]
        # remove non-printable chars form each token
        #line = [re_print.sub('', w) for w in line]
        # remove tokens with numbers in them
        line = [word for word in line if word.isalpha()]
        # store as string
        clean_txt += (' '.join(line))
    return clean_txt

def tokenizer(line):
    """
    Uses nltk RefexpTokenizer to tokenize wrt alphanumerics, normalizes, decodes UTF8, ensures lower case.
    Takes a Sentence(s) string as input.
    Returns a list of token words.
    """

    tokenizer = RegexpTokenizer(r'\w+')
    line = normalize('NFD', line).encode('ascii', 'ignore')
    line = line.decode('UTF-8')
    tokenized_line = tokenizer.tokenize(line)
    tokenized_line = [word.lower() for word in tokenized_line]
    return tokenized_line

def encoder(tokenized_line, token_dict, seq_len):
    """
    Takes a list of word tokens and translates it into a list of word indices using a dictionary.
    Returns an array of token words, of shape (?, seq_len). Post padding and post truncating is applied.
    """

    encoded_line = []
    for word in tokenized_line:
        encoded_line.append(token_dict.get(word, token_dict["<UNK>"]))
    encoded_line = preprocessing.sequence.pad_sequences(
    [encoded_line],
    maxlen=seq_len,
    padding="post",
    truncating="post")

    return encoded_line

def one_hot_encode_output(encoded_sentences, sentence_length_dst=50,vocabulary_size_dst=32119):      #, vocab_size):
    curr = encoded_sentences        #encoded_sentences
    number_samples = curr.shape[0]
    decoder_targets_one_hot = np.zeros((
            number_samples,
            sentence_length_dst,
            vocabulary_size_dst+1  # hm... why?
        ))
    for i, sentence in enumerate(curr):
        for t, word in enumerate(sentence):
            decoder_targets_one_hot[i, t, word] = 1
    return decoder_targets_one_hot

# def one_hot_encode_output(encoded_sentences, sentence_length_dst=50,vocabulary_size_dst=32119):      #, vocab_size):
#     for curr in encoded_sentences:         #encoded_sentences
#         number_samples = curr.shape[0]
#         decoder_targets_one_hot = np.zeros((
#                 number_samples,
#                 sentence_length_dst,
#                 vocabulary_size_dst+1  # hm... why?
#             ))
#         for i, sentence in enumerate(curr):
#             for t, word in enumerate(sentence):
#                 decoder_targets_one_hot[i, t, word] = 1
#         yield decoder_targets_one_hot

def generator(X_data, Y_data, batch_size, samples=30000, shf=True, onehot=True):
    """generates data for the fit_generator
    input X_data, Y_data, batch_size, samples=30000
    shf=False returns the first #samples of X_data, Y_data; otherwise shuffles first.
    onehot=True applies one hot encoding to y_batch
    yields x_batch, y_batch"""
    #from sklearn.utils import shuffle
    if shf:
        x_data, y_data = shuffle(X_data, Y_data, n_samples=samples)
    else:
        x_data = X_data[0:samples]
        y_data = Y_data[0:samples]
    samples_per_epoch = x_data.shape[0]
    number_of_batches = samples_per_epoch/batch_size
    counter=0

    while True:
        x_batch = np.array(x_data[batch_size*counter:batch_size*(counter+1)]).astype('float32')
        y_batch = np.array(y_data[batch_size*counter:batch_size*(counter+1)]).astype('float32')
        if onehot:
            y_batch = one_hot_encode_output(y_batch)
        counter += 1
        yield x_batch,y_batch

        #restart counter to yield data in the next epoch as well
        if counter >= number_of_batches:
            counter = 0

def get_word(n, token_dict):
    """
    Returns the work with index n from dictionary token_dict dictionary. Super slow.
    """
    for word, index in token_dict.items():
        if index == n:
            return word
    return None

def convert(preds, token_dict):
    """
    Converts a list of indices into a list of words using token_dict dictionary.
    """
    preds_text = []
    for i in preds:
        temp = []
        for j in range(len(i)):
            t = get_word(i[j], token_dict)
            if j > 0:
                if (t == get_word(i[j-1], token_dict)) or (t == None):
                    temp.append('')
                else:
                    temp.append(t)
            else:
                    if(t == None):
                        temp.append('')
                    else:
                        temp.append(t)

        preds_text.append(' '.join(temp))
    return preds_text

def predictor(model, enc_line):
    pred = model.predict_classes(enc_line)
    pass


# did u see this file in the README
# no right
# so y did u still check here?
# smh never follow instructions

import os

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

if not os.getenv("DATABASE_URL"):
    raise RuntimeError("DATABASE_URL is not set")

engine = create_engine(os.getenv("DATABASE_URL"))
db = scoped_session(sessionmaker(bind=engine))

movies = []
with open("movies.csv") as f:
    headers = f.readline().strip().split(";")
    for line in f:
        line_lst = line.strip().split(";")
        movie_dict = dict(zip(headers, line_lst))
        movies.append(movie_dict)

db.execute(
    """
    CREATE TABLE movies (
        "id" SERIAL PRIMARY KEY,
        "Title" TEXT NOT NULL,
        "Year" INT4 NOT NULL,
        "Runtime" INT4 NOT NULL,
        "imdbID" VARCHAR NOT NULL,
        "imdbRating" FLOAT8 NOT NULL,
        "cached_omdb" BOOL NOT NULL,
        "Rated" VARCHAR,
        "Release_Date" VARCHAR,
        "Production" VARCHAR,
        "Director" VARCHAR,
        "Writer" VARCHAR,
        "Actors" VARCHAR,
        "Website" VARCHAR,
        "Poster" VARCHAR,
        "Plot" VARCHAR,
        "Language" VARCHAR,
        "Metascore" VARCHAR,
        "Rotten_Tomatoes" VARCHAR,
        "Box_Office" VARCHAR,
        "Awards" VARCHAR,
        "Genre" VARCHAR
    )
    """
)
db.commit()

for movie in movies:
    db.execute(
        """
        INSERT INTO movies ("Title", "Year", "Runtime", "imdbID", "imdbRating", "cached_omdb")
            VALUES (:Title, :Year, :Runtime, :imdbID, :imdbRating, FALSE)
        """,
        movie
    )
    db.commit()

db.close()


#Kansas State University
#Electronics Design Club
#Interactive Display (Spring Open House, 2019)
#Author(s): Weston Harder

#############################################################################
#
#                               IMPORTANT!!!
#
#https://learn.sparkfun.com/tutorials/raspberry-pi-spi-and-i2c-tutorial/all
#See "SPI on Pi" "Configuration" section
#Need to enable SPI on the Pi before running this script!!!
#############################################################################

#Weston's public SSH key:
#ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDAMmVCC1zSJuSrtR1HT/uTa/eoovPUA3n6sTwzdcIJbqBEG7V6en++wL0C7Zfo4jz8+ZhlNDu9vCcrAjmJXP6LGyi4wPOdhiOBo0CY985dvl0mKFvFdf67wB7SxDa1kF1sLSN0DqGtS7ex6MiGYhqSg2AAxNJNMYG3KR9fxu6Zb3QBWfmwjP07EdnOgSs+JylN7LCu4KPvsSI+Io+z1ecltb46d1v5kIC0kHDjbM0vZvabHAQH9En6lbFY/ZPzmKuPOCghwp4pa+tSXLmwBpn4Izb82DHpQbdyqcqEk04/AG+2Fiwo4kYlm231HaY195Zuz7Y92/Mj1QrHZqzEwYSyAyOH8CZzWmffCJYnH976nl9sPLlBXJ7UDIERHBN0AAjC7uj6GPWKC57cHueJfrzdeATxh2scNY0SqsimmGc1bfGPm4aKETUfF97PeSJFip0PLTDCNp39bQeR4nS/MZxCAoSV9mtCzsLNdV6JLkRtcv24Lx7bi9SZqVzIKVvQ3G2gVAhd052LL0XIjpPvSH4JcBb1lSELHVeh+jHAO7KRs2Q9Oq5H/zExGCd8yymeYbaD8JRxLVdctS5MpWrV1AVX8ic9TbAIN/VipVfLlJQVA+U7As+KTbruNHak+7iZ7dCMGMFLXLoQKIzcEJo3g0R5hp2BQKljWIBanEvTu9mV6w== wmharder@ksu.edu

import paho.mqtt.client
import RPi.GPIO as GPIO
import spidev
from time import sleep

#GPIO pin numbers (board #, not BCM #)
CLK = 35
CS_IN = 33
RESET = 37

#SPI global variables
spi = None
#https://pypi.org/project/spidev/
#http://tightdev.net/SpiDev_Doc.pdf
#http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9570-AT42-QTouch-BSW-AT42QT1110-Automotive_Datasheet.pdf

working_touch_ics = list()

def main():
    global CLK
    global CS_IN
    global RESET
    global spi

    #GPIO setup
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(CLK, GPIO.OUT, initial=GPIO.LOW)
    GPIO.setup(CS_IN, GPIO.OUT, initial=GPIO.HIGH)
    GPIO.setup(RESET, GPIO.OUT, initial=GPIO.HIGH)

    #SPI setup
    spi = spidev.SpiDev()
    spi.open(0, 0) #Not really sure what this should be

    #Both of these come from section 4.1.2: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9570-AT42-QTouch-BSW-AT42QT1110-Automotive_Datasheet.pdf
    spi.max_speed_hz = 10000 #Max is 1.5 MHz, limit to 1.4 MHz to be safe
    spi.mode = 0b11 # Clock polarity = 1, Clock phase = 1

    tc = touch_controller()
    mqtt_pub = mqtt_publisher()

    #Wait until connected to MQTT server
    print("Waiting")
    while not mqtt_pub.connected:
        pass
    print("Done waiting")

    old_key_states = tc.get_key_states()

    loop = 0

    #Main loop
    while(True):
        #Go through every sensor and check for touch
        #print("{} Polling working touch ICs".format(loop))
        tc.scan()

        new_key_states = tc.get_key_states()

        #print("{} Looking for differing touch states".format(loop))
        #Go through each key number
        for key, new_state in enumerate(new_key_states):
            if(new_state != old_key_states[key]):
                mqtt_pub.publish_touch(key, new_state)

        old_key_states = new_key_states

        loop += 1

    return

class mqtt_publisher(object):
    def __init__(self):
        self.host = "127.0.0.1"
        self.port = 1883
        self.topic_template = "interactive_display/touch_events/{}"
        self.connected = False
        self.mqtt_client = paho.mqtt.client.Client()
        self.mqtt_client.on_connect = self.on_connect
        self.mqtt_client.on_disconnect = self.on_disconnect
        self.connect()
        self.mqtt_client.loop_start()

        return

    def connect(self):
        print("Attempting to connect to \"{}:{}\"".format(self.host, self.port))
        self.mqtt_client.connect_async(self.host, self.port)
        return

    def on_connect(self, client, userdata, flags, rc):
        if rc==0:
            self.connected = True
            print("Connected to MQTT server successfully.")
        else:
            print("Failed to connect to the MQTT server. rc = {}".format(rc))
            print("See http://www.steves-internet-guide.com/client-connections-python-mqtt/ or https://pypi.org/project/paho-mqtt/ for help.")
            self.connect()

        return

    def on_disconnect(self, client, userdata, rc):
        self.connected = False
        print("Disconnected from the MQTT server. rc = {}".format(rc))
        print("See http://www.steves-internet-guide.com/client-connections-python-mqtt/ or https://pypi.org/project/paho-mqtt/ for help.")
        self.connect()

        return

    def publish_touch(self, key, new_state):
        if new_state:
            msg = "on"
        else:
            msg = "off"
        print("Key {} {}".format(key, msg)) #Remove this after testing is done.

        topic = self.topic_template.format(key)
        rc = self.mqtt_client.publish(topic, msg)[0]

        if rc != 0:
            print("Failed to print message \"{}\" to \"{}\". rc = {}".format(msg, topic, rc))
            print("See https://pypi.org/project/paho-mqtt/ for help.")

        return

class selection_manager(object):
    def __init__(self):
        self.touch_ic_count = 16
        self.max_touch_ic = self.touch_ic_count - 1
        self.touch_ic = 0

        self.reset()

        return

    def get_max(self):
        return self.max_touch_ic

    def get_touch_ic_count(self):
        return self.touch_ic_count

    def get_selection(self):
        return self.touch_ic

    def increment(self):
        global CLK
        global CS_IN
        global RESET

        #Set CS_IN high
        GPIO.output(CS_IN, GPIO.HIGH)
        #Set CLK high
        GPIO.output(CLK, GPIO.HIGH)
        #Wait a few ms???
        sleep(0.001)
        #Set CLK low
        GPIO.output(CLK, GPIO.LOW)
        #Wait a few ms???
        sleep(0.001)
        self.touch_ic += 1
        return

    def reset(self):
        global CLK
        global CS_IN
        global RESET

        while self.touch_ic < self.touch_ic_count:
            self.increment()

        return

    def select(self, new_touch_ic):
        global CLK
        global CS_IN
        global RESET

        #If selection is valid
        if new_touch_ic >= 0 and new_touch_ic <= self.max_touch_ic:
            #If selection is below current selection
            if new_touch_ic < self.touch_ic:
                #Select touch IC 0
                self.reset() #Not the most efficient but whatever
                #Set CS_IN low
                GPIO.output(CS_IN, GPIO.LOW)
                #Set CLK high
                GPIO.output(CLK, GPIO.HIGH)
                #Wait a few ms???
                sleep(0.001)
                #Set CLK low
                GPIO.output(CLK, GPIO.LOW)
                #Set CS_IN high
                GPIO.output(CS_IN, GPIO.HIGH)
                #Wait a few ms???
                sleep(0.001)
                self.touch_ic = 0

            #While selection is above current selection
            while new_touch_ic > self.touch_ic:
                self.increment()
            #print("Selected {}".format(new_touch_ic))
            #raw_input()
            return True

        #If selection is invalid
        else:
            self.reset()
            return False

class touch_controller(object):
    def __init__(self):
        global working_touch_ics

        self.key_count = 11
        self.key_states = list()
        self.sm = selection_manager()

        #Initialize all keyy states to False
        for _ in range(0, self.get_touch_ic_count()):
            for _ in range(0, self.key_count):
                self.key_states.append(False)

        #Setup all touch ICs
        for i in range(0, self.get_touch_ic_count()):
            success = self.control_setup(i)
            if success:
                working_touch_ics.append(i)

        #Calibrate all touch ICs
        for i in range(0, self.get_touch_ic_count()):
            self.control_calibrate(i)

        return

    #def get_touch_status()

    def control_calibrate(self, touch_ic):
        global spi
        global working_touch_ics
        if touch_ic not in working_touch_ics:
            return False

        if self.sm.select(touch_ic):
            #SPI: Send 0x03 to calibrate all keys
            spi.writebytes([0x03])

            #Wait at least 150 us before communications can resume
            sleep(150.0/1000000.0)

            return True

        else:
            return False

    def control_erase_eeprom_and_reset(self, touch_ic):
        global spi

        if self.sm.select(touch_ic):
            #SPI: Send 0x0c to erase settings stored in EEPROM and reset touch IC (revert touch IC to default settings)
            spi.writebytes([0x0c])

            #Wait at least 50 ms before communications can resume
            sleep(50.0/1000.0)

            return True

        else:
            return False

    def control_reset(self, touch_ic):
        global spi

        if self.sm.select(touch_ic):
            #SPI: Send 0x04 to reset
            spi.writebytes([0x04])

            #Wait at least 160 ms before communications can resume
            sleep(160.0/1000.0)

            return True

        else:
            return False

    def control_restore_from_eeprom(self, touch_ic):
        global spi

        if self.sm.select(touch_ic):
            #SPI: Send 0x0b to restore RAM contents from EEPROM (revert to checkpoint without needing to do a full reset)
            spi.writebytes([0x0b])

            #Wait at least 150 ms before communications can resume
            sleep(150.0/1000.0)

            return True

        else:
            return False

    def control_setup(self, touch_ic):
        global spi

        #Perform initialization on all touch ICs
            #Set the MODE bit in the Device Mode setup
            #Use a timed trigger (specified length of time or 0 for free run mode)
            #No guard channel key
            #No SYNC pin
            #Possibly use detection integrator to make sure it is touched
            #Burst length limitation??? Probably no
            #Adjacent Key Suppression??? Probably no
            #Don't use CRC checking

        if self.sm.select(touch_ic):
            #SPI: Send 0x01 to start setup
            spi.writebytes([0x01])

            setup_data = [ #Start in section 7.4 page 30: http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-9570-AT42-QTouch-BSW-AT42QT1110-Automotive_Datasheet.pdf
                0b11100000, #0:  Device Mode
                0b00000010, #1:  Guard Key/Comms Options
                0b11111000, #2:  Detect Integrator Limit (DIL)/Drift Hold Time
                    #Note: Adjust these if there are false detections or not detecting
                0b01000010, #3:  Positive Threshold (PTHR)/Positive Hysteresis
                    #Note: Adjust these if there are false detections or not detecting
                0b00000110, #4:  Positive Drift Compensation (PDRIFT)
                    #Note: Just used default, adjustable
                0b00000110, #5:  Positive Recalibration Delay (PRD)
                    #Note: Just used default, adjustable
                0b00010010, #6:  Lower Burst Limit (LBL)
                    #Note: Adjust this if there are false detections or not detecting
                0b00000000, #7:  AKS Mask
                0b00000000, #8:  AKS Mask
                0b00000000, #9:  Detect0 PWM
                0b00000000, #10: Detect1 PWM
                0b00000000, #11: Detect2 PWM
                0b00000000, #12: Detect3 PWM
                0b00000000, #13: Detect4 PWM
                0b00000000, #14: Detect5 PWM
                0b00000000, #15: Detect6 PWM
                0b00000000, #16: LED Detect Hold Time
                0b00000000, #17: LED Fade/Key to LED
                0b00000000, #18: LED Latch
                0b00101010, #19: Key  0 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                    #Note: Adjust this if there are false detections or not detecting (same for keys 1-10)
                0b00101010, #20: Key  1 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #21: Key  2 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #22: Key  3 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #23: Key  4 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #24: Key  5 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #25: Key  6 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #26: Key  7 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #27: Key  8 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #28: Key  9 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00101010, #29: Key 10 Negative Threshold (NTHR) / Negative Hysteresis (NHYST)
                0b00000000, #30: Extend Pulse Time
                    #Note: No idea what this does. Left at 0.
                0b01111010, #31: Key  0 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                    #Note: Just used default, adjustable (same for keys 1-10)
                0b00000000, #32: Key  1 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #33: Key  2 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #34: Key  3 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #35: Key  4 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #36: Key  5 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #37: Key  6 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #38: Key  7 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #39: Key  8 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000, #40: Key  9 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                0b00000000  #41: Key 10 Negative Drift Compensation (NDRIFT) / Negative Recalibration Delay (NRD)
                ]

            #SPI: Send 42 bytes of setup data
            spi.writebytes(setup_data)
            #Wait 150 us
            sleep(150.0/1000000.0)
            #If concerned about setup working properly:
            #SPI: Request a dump of setup data
            print("Checking setup for touch IC {}".format(touch_ic))
            spi.writebytes([0xc8])
            received_setup_data = spi.readbytes(42)
            #Check to make sure setup data is correct
            success = True
            for index, byte in enumerate(setup_data):
                if byte != received_setup_data[index]:
                    print("Failed to setup touch IC {}".format(touch_ic))
                    print(setup_data)
                    print(received_setup_data)
                    success = False
                    break

            if success:
                print("  Success")

            #Wait at least 150 us before communications can resume
            sleep(150.0/1000000.0)

            return success

        else:
            return False

    def control_sleep(self, touch_ic):
        global spi

        if self.sm.select(touch_ic):
            #SPI: Send 0x05 to sleep
            spi.writebytes([0x05])

            #Wait at least 150 us after a low signal is applied to the SS_bar pin before communications can resume
            sleep(150.0/1000000.0)

            return True

        else:
            return False

    def control_store_to_eeprom(self, touch_ic):
        global spi

        if self.sm.select(touch_ic):
            #SPI: Send 0x0a to store RAM contents to EEPROM (basically a checkpoint that can be reached again by calling reset)
            spi.writebytes([0x0a])

            #Wait at least 200 ms before communications can resume
            sleep(200.0/1000.0)

            return True

        else:
            return False

    def get_active_keys(self):
        #Return the indices of all active (touched) keys
        return [index for index, key_state in enumerate(self.key_states) if key_state]

    def get_key_count(self):
        return self.key_count

    def get_key_state(self, key):
        return self.key_states[key]

    def get_key_states(self):
        return self.key_states[:]

    def get_touch_ic_key_state(self, touch_ic, key):
        return self.key_states[(touch_ic * self.get_key_count()) + key]

    def get_touch_ic_count(self):
        return self.sm.get_touch_ic_count()

    def report_all_keys(self, touch_ic):
        global spi
        global working_touch_ics
        if touch_ic not in working_touch_ics:
            return False

        if self.sm.select(touch_ic):
            #SPI: Send 0xc1 to request a binary report on all 11 keys
            spi.writebytes([0xc1])

            #SPI: Receive 2 bytes (byte 0 then byte 1)
            response = spi.readbytes(2)

            #           Bit 7   Bit 6   Bit 5   Bit 4   Bit 3   Bit 2   Bit 1   Bit 0
            # Byte 0                                            KEY_10  KEY_9   KEY_8
            # Byte 1    KEY_7   KEY_6   KEY_5   KEY_4   KEY_3   KEY_2   KEY_1   KEY_0

            #Parse data and store in self.key_states (For each key, store True if on/triggered and False if off/not triggered)
            touch_ic_key_states = list()
            touch_ic_key_states.append(response[1] & 0b00000001 > 0)
            touch_ic_key_states.append(response[1] & 0b00000010 > 0)
            touch_ic_key_states.append(response[1] & 0b00000100 > 0)
            touch_ic_key_states.append(response[1] & 0b00001000 > 0)
            touch_ic_key_states.append(response[1] & 0b00010000 > 0)
            touch_ic_key_states.append(response[1] & 0b00100000 > 0)
            touch_ic_key_states.append(response[1] & 0b01000000 > 0)
            touch_ic_key_states.append(response[1] & 0b10000000 > 0)
            touch_ic_key_states.append(response[0] & 0b00000001 > 0)
            touch_ic_key_states.append(response[0] & 0b00000010 > 0)
            touch_ic_key_states.append(response[0] & 0b00000100 > 0)

            for i, touch_ic_key_state in enumerate(touch_ic_key_states):
                self.key_states[(touch_ic * self.get_key_count()) + i] = touch_ic_key_state

            return True

        else:
            return False

    def scan(self):
        success = True

        for i in range(0, self.get_touch_ic_count()):
            success = self.report_all_keys(i) and success

        return success

if __name__ == "__main__":
    main()


#! python3
# -*- coding: utf-8 -*-
"""罗马数字共有7个，
即Ⅰ（1）、Ⅴ（5）、Ⅹ（10）、Ⅼ（50）、Ⅽ（100）、Ⅾ（500）和Ⅿ（1000）
1.按照下述的规则可以表示任意正整数。需要注意的是罗马数字中没有“0”，与进位制无关。一般认为罗马数字只用来记数，而不作演算

思路：只要去管左减这个规则，因为右加原则只要累加就行了
"""

def romanToInt(s):
    # res = 0
    numbers = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
    raw_s = [i for i in s]
    if s == 'IIII':  # 先考虑最简单的情况, 因此有时用IIII代替IV
        res = 4
        """
        右加左减
        在较大的罗马数字的右边记上较小的罗马数字，表示大数字加小数字
        在较大的罗马数字的左边记上较小的罗马数字，表示大数字减小数字
        左减数字必须为一位，左减数字有限制，仅限于I，X, C
        右加数字不可连续超过三位，<=3
        """
    else:
        """先考虑左减"""
        left_subtract_sum_holder = []
        for index, element in enumerate(raw_s):
            if element == 'I' or element == 'X' or element == 'C':
                if index+1 <= len(raw_s) - 1:
                    next_element = numbers[raw_s[index+1]]
                    correspond_value = numbers[element]
                    if next_element > correspond_value:
                        left_subtract_sum = next_element - correspond_value
                        left_subtract_sum_holder.append({'left': index, 'right': index+1,'sum': left_subtract_sum})
        if len(left_subtract_sum_holder) != 0:
            subtract_index = []
            subtract_sum = 0
            for d in left_subtract_sum_holder:
                subtract_index.append(d['left'])
                subtract_index.append(d['right'])
                subtract_sum += d['sum']
            raw_s_index = list(range(len(raw_s)))
            rest_index = [item for item in raw_s_index if item not in subtract_index]
            rest_sum = sum([numbers[raw_s[x]] for x in rest_index])
            print(subtract_sum)
            res = subtract_sum + rest_sum
        else:
            res = sum([numbers[x] for x in raw_s])
    return res

if __name__ == '__main__':
    # s = 'MDCCCLXXXIV'
    # s = 'MCMXCVI'
    result = romanToInt(s)
    print(result)


# https://stash.ihme.washington.edu/projects/VA/repos/business_rules/browse/doc/md/bite.md
from smartva.data.constants import *
from smartva.utils.utils import value_from_row, int_or_float

CAUSE_ID = 2

def logic_rule(row):
    value_of = value_from_row(row, int_or_float)

    bite = value_of(Child.BITE) == YES

    recent = value_of(Child.INJURY_DAYS) < INJURY_DURATION_CUTTOFF

    return bite and recent


MAX = 9999999999999

def solve(x,coins):
    if x < 0 : return MAX
    if x == 0 : return 0

    best = MAX

    for coin in coins:
        best = min(best,solve(x-coin,coins)+1)

    return best

if __name__ == '__main__':
    coins1 = [1,3,4]
    coins2 = [1,2,5]

    print(solve(6,coins1))
    print(solve(10,coins1))
    print(solve(12,coins2))


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

"""
Integration tests. Test input/output to conjugator
"""

from __future__ import unicode_literals
import unittest

from verbage.fr.conjugator import Conjugator

class BaseTest(object):

    def _test(self, tense, results):
        c = Conjugator.make(self.verb)
        self.assertEquals(
            c.first_person_singular(tense),
            results[0][0])
        self.assertEquals(
            c.first_person_plural(tense),
            results[0][1])
        self.assertEquals(
            c.second_person_singular(tense),
            results[1][0])
        self.assertEquals(
            c.second_person_plural(tense),
            results[1][1])
        self.assertEquals(
            c.third_person_singular(tense),
            results[2][0])
        self.assertEquals(
            c.third_person_plural(tense),
            results[2][1])

    def test_present_indicative(self):
        self._test('present_indicative', self.present_indicative)

    def test_imperfect_indicative(self):
        self._test('imperfect_indicative', self.imperfect_indicative)

    def test_conditional(self):
        self._test('conditional', self.conditional)

    def test_past_simple(self):
        self._test('past_simple', self.past_simple)

    def test_present_subjunctive(self):
        self._test('present_subjunctive', self.present_subjunctive)

    def test_future(self):
        self._test('future', self.future)

    def test_imperfect_subjunctive(self):
        self._test('imperfect_subjunctive', self.imperfect_subjunctive)

class TestAcheter(BaseTest, unittest.TestCase):
    """ Acheter - is one of the special cases that does not
    recieve a double 't' """

    verb = 'acheter'
    present_indicative = (
        ('achète', 'achetons'),
        ('achètes', 'achetez'),
        ('achète', 'achètent'))
    imperfect_indicative = (
        ('achetais', 'achetions'),
        ('achetais', 'achetiez'),
        ('achetait', 'achetaient'))
    conditional = (
        ('achèterais', 'achèterions'),
        ('achèterais', 'achèteriez'),
        ('achèterait', 'achèteraient'))
    past_simple = (
        ('achetai', 'achetâmes'),
        ('achetas', 'achetâtes'),
        ('acheta', 'achetèrent'))
    present_subjunctive = (
        ('achète', 'achetions'),
        ('achètes', 'achetiez'),
        ('achète', 'achètent'))
    future = (
        ('achèterai', 'achèterons'),
        ('achèteras', 'achèterez'),
        ('achètera', 'achèteront'))
    imperfect_subjunctive = (
        ('achetasse', 'achetassions'),
        ('achetasses', 'achetassiez'),
        ('achetât', 'achetassent'))

class TestAccorder(BaseTest, unittest.TestCase):
    verb = 'accorder'
    present_indicative = (
        ('accorde', 'accordons'),
        ('accordes', 'accordez'),
        ('accorde', 'accordent'))
    imperfect_indicative = (
        ('accordais', 'accordions'),
        ('accordais', 'accordiez'),
        ('accordait', 'accordaient'))
    conditional = (
        ('accorderais', 'accorderions'),
        ('accorderais', 'accorderiez'),
        ('accorderait', 'accorderaient'))
    past_simple = (
        ('accordai', 'accordâmes'),
        ('accordas', 'accordâtes'),
        ('accorda', 'accordèrent'))
    present_subjunctive = (
        ('accorde', 'accordions'),
        ('accordes', 'accordiez'),
        ('accorde', 'accordent'))
    future = (
        ('accorderai', 'accorderons'),
        ('accorderas', 'accorderez'),
        ('accordera', 'accorderont'))
    imperfect_subjunctive = (
        ('accordasse', 'accordassions'),
        ('accordasses', 'accordassiez'),
        ('accordât', 'accordassent'))


class Queue:

    def __init__(self, size=5):
        self.n = size + 1  # faktyczny rozmiar tablicy
        self.items = self.n * [None]
        self.head = 0  # pierwszy do pobrania
        self.tail = 0  # pierwsze wolne

    def is_empty(self):
        return self.head == self.tail

    def is_full(self):
        return (self.head + self.n - 1) % self.n == self.tail

    def put(self, data):
        if (self.head + self.n - 1) % self.n == self.tail:
            raise Exception("Queue is full")
        else:
            self.items[self.tail] = data
            self.tail = (self.tail + 1) % self.n

    def get(self):
        if self.head == self.tail:
            raise Exception("Queue is empty")
        else:
            data = self.items[self.head]
            self.items[self.head] = None  # usuwam referencję
            self.head = (self.head + 1) % self.n
            return data

    def print(self):
        q = "Queue: "
        for i in range(self.n):
            if self.items[i]:
                q = q + str(self.items[i]) + ", "
        print(q)

queue = Queue(4)
print("Created queue of size:", queue.n)

queue.put(5)
queue.print()

queue.put(8)
queue.print()

queue.put(13)
queue.print()

queue.put(1)
queue.print()

# Exception
# queue.put(0)

print("Removing:", queue.get())
queue.print()
print("Removing:", queue.get())
queue.print()
print("Removing:", queue.get())
queue.print()
print("Removing:", queue.get())
queue.print()

# Exception
# print("Removing:", queue.get())


#!/usr/bin/env python
# -*- coding:utf-8 -*-

"""
Created on 2018/10/28

@author: Gong
"""
import jieba
import pandas as pd

# segment
def token(content, stopwords):
    cut_result = jieba.cut(content.strip())
    out_str = ""
    for partition in cut_result:
        if partition != "\t" and partition not in stopwords:
            out_str += partition + " "
    return out_str

file_path = "data\\"
df = pd.read_csv(file_path + "all_news.csv", encoding="utf-8")

stopwords_list = []
with open("stopwords.txt", 'r') as f:
    for line in f.readlines():
        stopwords_list.append(line.strip())

contents = df["content"].tolist()
segments = []
i = 0
tot = len(df)
for line in contents:
    segments.append(token(line, stopwords_list))
    i += 1
    if i % 10000 == 0:
        print("progress: {:.2f}%".format(i * 100 / tot))
df["content"] = segments

# save result
df.to_csv(file_path + "all_news_tokenized.csv", encoding="utf-8", index=False)
print("Done.")


"""
    Automatic Speech Recognition (ASR) abstract dataset.
"""

__all__ = ['AsrDataset', 'NemoMelSpecExtractor', 'asr_test_transform']

import numpy as np
import torch.utils.data as data
import torchvision.transforms as transforms

class AsrDataset(data.Dataset):
    """
    Automatic Speech Recognition (ASR) abstract dataset.

    Parameters:
    ----------
    root : str
        Path to the folder stored the dataset.
    mode : str
        'train', 'val', 'test', or 'demo'.
    transform : func
        A function that takes data and transforms it.
    """
    def __init__(self,
                 root,
                 mode,
                 transform):
        super(AsrDataset, self).__init__()
        assert (mode in ("train", "val", "test", "demo"))
        self.root = root
        self.mode = mode
        self.transform = transform
        self.data = []
        self.preprocessor = NemoMelSpecExtractor(dither=0.0)

    def __getitem__(self, index):
        wav_file_path, label_text = self.data[index]

        audio_data_list = self.read_audio([wav_file_path])
        x_np, x_np_len = self.preprocessor(audio_data_list)

        return (x_np[0], x_np_len[0]), label_text

    def __len__(self):
        return len(self.data)

    @staticmethod
    def read_audio(audio_file_paths,
                   desired_audio_sample_rate=16000):
        """
        Read audio.

        Parameters:
        ----------
        audio_file_paths : list of str
            Paths to audio files.
        desired_audio_sample_rate : int, default 16000
            Desired audio sample rate.

        Returns:
        -------
        list of np.array
            Audio data.
        """
        from soundfile import SoundFile

        audio_data_list = []
        for audio_file_path in audio_file_paths:
            with SoundFile(audio_file_path, "r") as data:
                sample_rate = data.samplerate
                audio_data = data.read(dtype="float32")
            audio_data = audio_data.transpose()
            if desired_audio_sample_rate != sample_rate:
                from librosa.core import resample as lr_resample
                audio_data = lr_resample(y=audio_data, orig_sr=sample_rate, target_sr=desired_audio_sample_rate)
            if audio_data.ndim >= 2:
                audio_data = np.mean(audio_data, axis=1)
            audio_data_list.append(audio_data)

        return audio_data_list

class NemoMelSpecExtractor(object):
    """
    Mel-Spectrogram Extractor from NVIDIA NEMO toolkit.

    Parameters:
    ----------
    sample_rate : int, default 16000
        Sample rate of the input audio data.
    window_size_sec : float, default 0.02
        Size of window for FFT in seconds.
    window_stride_sec : float, default 0.01
        Stride of window for FFT in seconds.
    n_fft : int, default 512
        Length of FT window.
    n_filters : int, default 64
        Number of Mel spectrogram freq bins.
    preemph : float, default 0.97
        Amount of pre emphasis to add to audio.
    dither : float, default 1.0e-05
        Amount of white-noise dithering.
    """
    def __init__(self,
                 sample_rate=16000,
                 window_size_sec=0.02,
                 window_stride_sec=0.01,
                 n_fft=512,
                 n_filters=64,
                 preemph=0.97,
                 dither=1.0e-05,
                 **kwargs):
        super(NemoMelSpecExtractor, self).__init__(**kwargs)
        self.log_zero_guard_value = 2 ** -24
        win_length = int(window_size_sec * sample_rate)
        self.hop_length = int(window_stride_sec * sample_rate)

        from scipy import signal as scipy_signal
        from librosa import stft as librosa_stft
        from librosa.filters import mel as librosa_mel

        window_fn = scipy_signal.hann(win_length, sym=True)
        self.stft = lambda x: librosa_stft(
            x,
            n_fft=n_fft,
            hop_length=self.hop_length,
            win_length=win_length,
            window=window_fn,
            center=True)

        self.dither = dither
        self.preemph = preemph

        self.pad_align = 16

        self.filter_bank = librosa_mel(
            sample_rate,
            n_fft,
            n_mels=n_filters,
            fmin=0,
            fmax=(sample_rate / 2))

    def __call__(self, xs):
        """
        Preprocess audio.

        Parameters:
        ----------
        xs : list of np.array
            Audio data.

        Returns:
        -------
        np.array
            Audio data.
        np.array
            Audio data lengths.
        """
        x_eps = 1e-5

        batch = len(xs)
        x_len = np.zeros((batch,), dtype=np.long)

        ys = []
        for i, xi in enumerate(xs):
            x_len[i] = np.ceil(float(len(xi)) / self.hop_length).astype(np.long)

            if self.dither > 0:
                xi += self.dither * np.random.randn(*xi.shape)

            xi = np.concatenate((xi[:1], xi[1:] - self.preemph * xi[:-1]), axis=0)

            yi = self.stft(xi)
            yi = np.abs(yi)
            yi = np.square(yi)
            yi = np.matmul(self.filter_bank, yi)
            yi = np.log(yi + self.log_zero_guard_value)

            assert (yi.shape[1] != 1)
            yi_mean = yi.mean(axis=1)
            yi_std = yi.std(axis=1)
            yi_std += x_eps
            yi = (yi - np.expand_dims(yi_mean, axis=-1)) / np.expand_dims(yi_std, axis=-1)

            ys.append(yi)

        channels = ys[0].shape[0]
        x_len_max = max([yj.shape[-1] for yj in ys])
        x = np.zeros((batch, channels, x_len_max), dtype=np.float32)
        for i, yi in enumerate(ys):
            x_len_i = x_len[i]
            x[i, :, :x_len_i] = yi[:, :x_len_i]

        pad_rem = x_len_max % self.pad_align
        if pad_rem != 0:
            x = np.pad(x, ((0, 0), (0, 0), (0, self.pad_align - pad_rem)))

        return x, x_len

def asr_test_transform(ds_metainfo):
    assert (ds_metainfo is not None)
    return transforms.Compose([
        transforms.ToTensor(),
    ])