<commit_before># -*- coding: utf-8 -*-

import logging
import random

logger = logging.getLogger(__name__)

class Messenger(object):
    def __init__(self, slack_clients):
        self.clients = slack_clients

    def send_message(self, channel_id, msg):
        # in the case of Group and Private channels, RTM channel payload is a complex dictionary
        if isinstance(channel_id, dict):
            channel_id = channel_id['id']
        logger.debug('Sending msg: %s to channel: %s' % (msg, channel_id))
        channel = self.clients.rtm.server.channels.find(channel_id)
        channel.send_message(msg)

    def write_help_message(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = '{}\n{}\n{}\n{}'.format(
            "I'm your friendly Slack bot written in Python.  I'll *_respond_* to the following commands:",
            "> `hi <@" + bot_uid + ">` - I'll respond with a randomized greeting mentioning your user. :wave:",
            "> `<@" + bot_uid + "> joke` - I'll tell you one of my finest jokes, with a typing pause for effect. :laughing:",
            "> `<@" + bot_uid + "> attachment` - I'll demo a post with an attachment using the Web API. :paperclip:")
        self.send_message(channel_id, txt)

    def write_greeting(self, channel_id, user_id):
        greetings = ['Hi', 'Hello', 'Nice to meet you', 'Howdy', 'Salutations']
        txt = '{}, <@{}>!'.format(random.choice(greetings), user_id)
        self.send_message(channel_id, txt)

    def write_prompt(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = "I'm sorry, I didn't quite understand... Can I help you? (e.g. `<@" + bot_uid + "> help`)"
        self.send_message(channel_id, txt)

    def write_joke(self, channel_id):
        question = "Why did the python cross the road?"
        self.send_message(channel_id, question)
        self.clients.send_user_typing_pause(channel_id)
        answer = "To eat the chicken on the other side! :laughing:"
        self.send_message(channel_id, answer)

    def write_error(self, channel_id, err_msg):
        txt = ":face_with_head_bandage: my maker didn't handle this error very well:\n>```{}```".format(err_msg)
        self.send_message(channel_id, txt)

    def demo_attachment(self, channel_id):
        txt = "Beep Beep Boop is a ridiculously simple hosting platform for your Slackbots."
        attachment = {
            "pretext": "We bring bots to life. :sunglasses: :thumbsup:",
            "title": "Host, deploy and share your bot in seconds.",
            "title_link": "https://beepboophq.com/",
            "text": txt,
            "fallback": txt,
            "image_url": "https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png",
            "color": "#7CD197",
        }
        self.clients.web.chat.post_message(channel_id, txt, attachments=[attachment], as_user='true')
<commit_msg>first commit to start the bot<commit_after># -*- coding: utf-8 -*-

import logging
import random

logger = logging.getLogger(__name__)

class Messenger(object):
    def __init__(self, slack_clients):
        self.clients = slack_clients

    def send_message(self, channel_id, msg):
        # in the case of Group and Private channels, RTM channel payload is a complex dictionary
        if isinstance(channel_id, dict):
            channel_id = channel_id['id']
        logger.debug('Sending msg: %s to channel: %s' % (msg, channel_id))
        channel = self.clients.rtm.server.channels.find(channel_id)
        channel.send_message(msg)

    def write_help_message(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = '{}\n{}\n{}\n{}'.format(
            "I'm your friendly Slack bot written in Python.  I'll *_respond_* to the following commands:",
            "> `hi <@" + bot_uid + ">` - I'll respond with a randomized greeting mentioning your user. :wave:",
            "> `<@" + bot_uid + "> joke` - I'll tell you one of my finest jokes, with a typing pause for effect. :laughing:",
            "> `<@" + bot_uid + "> attachment` - I'll demo a post with an attachment using the Web API. :paperclip:")
        self.send_message(channel_id, txt)

    def write_greeting(self, channel_id, user_id):
        greetings = ['Hi', 'Hello', 'Nice to meet you', 'Howdy', 'Salutations', 'Greetings']
        txt = '{}, <@{}>!'.format(random.choice(greetings), user_id)
        self.send_message(channel_id, txt)

    def write_prompt(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = "I'm sorry, I didn't quite understand... Can I help you? (e.g. `<@" + bot_uid + "> help`)"
        self.send_message(channel_id, txt)

    def write_joke(self, channel_id):
        question = "Why did the python cross the road?"
        self.send_message(channel_id, question)
        self.clients.send_user_typing_pause(channel_id)
        answer = "To eat the chicken on the other side! :laughing:"
        self.send_message(channel_id, answer)

    def write_error(self, channel_id, err_msg):
        txt = ":face_with_head_bandage: my maker didn't handle this error very well:\n>```{}```".format(err_msg)
        self.send_message(channel_id, txt)

    def demo_attachment(self, channel_id):
        txt = "Beep Beep Boop is a ridiculously simple hosting platform for your Slackbots."
        attachment = {
            "pretext": "We bring bots to life. :sunglasses: :thumbsup:",
            "title": "Host, deploy and share your bot in seconds.",
            "title_link": "https://beepboophq.com/",
            "text": txt,
            "fallback": txt,
            "image_url": "https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png",
            "color": "#7CD197",
        }
        self.clients.web.chat.post_message(channel_id, txt, attachments=[attachment], as_user='true')
<|endoftext|>


<commit_before>import time
import base64
import hmac
import sha
import urllib
import hashlib

from django.utils import timezone

from comics.serializers import ComicSerializer
from comics.models import Comic

from rest_framework import mixins
from rest_framework import generics

from rest_framework.authentication import (
    SessionAuthentication,
    BasicAuthentication,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework.views import APIView

from petroglyphs.models import Setting

class S3SignView(APIView):
    authentication_classes = (SessionAuthentication,)
    permission_classes = (IsAuthenticated,)
    renderer_classes = (JSONRenderer,)

    def get(self, request, format=None):
        AWS_ACCESS_KEY = str(Setting.objects.get(key='aws_access_key').value)
        AWS_SECRET_KEY = str(Setting.objects.get(key='aws_secret_key').value)
        S3_BUCKET = str(Setting.objects.get(key='s3_bucket').value)

        object_name = request.QUERY_PARAMS.get('s3_object_name')
        mime_type = request.QUERY_PARAMS.get('s3_object_type')

        hashcode = hashlib.sha1(
            str(object_name) + str(timezone.now())
        ).hexdigest()[:6]

        folder_name = request.user.username

        resource_name = "comics/%s/%s_%s" % (folder_name, hashcode, object_name)

        expires = int(time.time()+10)
        amz_headers = 'x-amz-acl:public-read'

        put_request = 'PUT\n\n%s\n%d\n%s\n/%s/%s' % (mime_type, expires, amz_headers, S3_BUCKET, resource_name)

        signature = base64.encodestring(hmac.new(AWS_SECRET_KEY, put_request, sha).digest())
        signature = urllib.quote_plus(signature.strip())
        url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, resource_name)

        data = {
            'signed_request': '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature),
            'url': url,
        }
        return Response(data)

class APIComicListView(generics.ListCreateAPIView):
    authentication_classes = (BasicAuthentication,)
    permission_classes = (IsAuthenticated,)
    serializer_class = ComicSerializer

    def get(self, request, *args, **kwargs):
        # import pdb; pdb.set_trace()
        return super(APIComicListView, self).get(request, *args, **kwargs)

    def get_queryset(self):
        return Comic.objects.get_comics_for_user(self.request.user)

class APIComicDetailView(generics.RetrieveUpdateDestroyAPIView):
    authentication_classes = (BasicAuthentication,)
    permission_classes = (IsAuthenticated,)
    serializer_class = ComicSerializer

    def get_queryset(self):
        return Comic.objects.get_comics_for_user(self.request.user)
<commit_msg>Let unauthenticated users browse public comics via api.<commit_after>import time
import base64
import hmac
import sha
import urllib
import hashlib

from django.utils import timezone

from comics.serializers import ComicSerializer
from comics.models import Comic

from rest_framework import mixins
from rest_framework import generics

from rest_framework.authentication import (
    SessionAuthentication,
    BasicAuthentication,
)
from rest_framework.permissions import (
    IsAuthenticated,
    IsAuthenticatedOrReadOnly,
)
from rest_framework.response import Response
from rest_framework.renderers import JSONRenderer
from rest_framework.views import APIView

from petroglyphs.models import Setting

class S3SignView(APIView):
    authentication_classes = (SessionAuthentication,)
    permission_classes = (IsAuthenticated,)
    renderer_classes = (JSONRenderer,)

    def get(self, request, format=None):
        AWS_ACCESS_KEY = str(Setting.objects.get(key='aws_access_key').value)
        AWS_SECRET_KEY = str(Setting.objects.get(key='aws_secret_key').value)
        S3_BUCKET = str(Setting.objects.get(key='s3_bucket').value)

        object_name = request.QUERY_PARAMS.get('s3_object_name')
        mime_type = request.QUERY_PARAMS.get('s3_object_type')

        hashcode = hashlib.sha1(
            str(object_name) + str(timezone.now())
        ).hexdigest()[:6]

        folder_name = request.user.username

        resource_name = "comics/%s/%s_%s" % (folder_name, hashcode, object_name)

        expires = int(time.time()+10)
        amz_headers = 'x-amz-acl:public-read'

        put_request = 'PUT\n\n%s\n%d\n%s\n/%s/%s' % (mime_type, expires, amz_headers, S3_BUCKET, resource_name)

        signature = base64.encodestring(hmac.new(AWS_SECRET_KEY, put_request, sha).digest())
        signature = urllib.quote_plus(signature.strip())
        url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, resource_name)

        data = {
            'signed_request': '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature),
            'url': url,
        }
        return Response(data)

class APIComicListView(generics.ListCreateAPIView):
    authentication_classes = (BasicAuthentication,)
    permission_classes = (IsAuthenticatedOrReadOnly,)
    serializer_class = ComicSerializer

    def get(self, request, *args, **kwargs):
        # import pdb; pdb.set_trace()
        return super(APIComicListView, self).get(request, *args, **kwargs)

    def get_queryset(self):
        if not self.request.user.is_anonymous:
            return Comic.objects.get_comics_for_user(self.request.user)
        return Comic.published_comics.all()

class APIComicDetailView(generics.RetrieveUpdateDestroyAPIView):
    authentication_classes = (BasicAuthentication,)
    permission_classes = (IsAuthenticatedOrReadOnly,)
    serializer_class = ComicSerializer

    def get_queryset(self):
        if not self.request.user.is_anonymous:
            return Comic.objects.get_comics_for_user(self.request.user)
        return Comic.published_comics.all()
<|endoftext|>


<commit_before># -*- coding: cp1252 -*-
import lib.operations as operations
from lib.schemas import *
from lib.textRepresentations import *
import copy

class Problem: #fields : structure, text
	def __init__(self,structure,text):
		self.structure=structure
		self.text=text

class ExpertSolver:
	def __init__(self,problem):
		self.problem=problem
		self.treeVIZ=""

	def recurcive_solve(self,movelist=[],newmove="",step=0,history=[],schemeToApply=0):
		if(step!=0):
			movelist.append(newmove)
		updater=Updater(self.problem)
		updater.applyMoveList(movelist)
		if (not updater.problemState.isProblemEnded()):
			for schem in updater.appliableSchemaList:
				newmove=Move(schem)
				#print(step,s,ml,schem.positions.keys())
				self.updateTree(step,schem.positions.keys())
				self.recurcive_solve(copy.deepcopy(movelist),newmove,step+1,copy.deepcopy(history))
		else:
			#print(history)
			step=0##problem here
	def updateTree(self,step,keys):
		line=step*"\t"+str(keys)+"\r\n"
		self.treeVIZ+=line

class Move:
	def __init__(self,move):
		classname=move.__class__.__name__
		if(classname=="Schema"):
			self.type="schema"
			self.move=move
		elif (classname=="Representation"):
			self.type="representation"
			self.move=move

class Updater: #fields : problem, problemState

	def __init__(self,problem):
		self.problem=problem
		self.appliableSchemaList=[]

	def startAsUnderstood(self):	#initialise all the quantities, goals and representations, as experts do
		goal=self.problem.text.goal.expertGoal
		quantitiesDic = QuantityDic(dict.fromkeys(self.problem.structure.objectSet,operations.unknown),startAsVoid=True)	#get all the objects, init with unknow																												  #note : maybe one day => necessary to consider multiple values for a single object
		representations=[]
		for info in self.problem.text.textInformations:
			quantitiesDic.addValue(info.expertRepresentation.quantity.object, info.expertRepresentation.quantity.value) # update the dic bind object to their values according the representations
			representations.append(0)	#0 indicate that the first (the good one) interpretation is selected

		self.problemState=ProblemState(quantitiesDic,goal,representations) # the most important line

		self.updateAppliableSchemas()

	def applyMoveList(self,movelist,startAsUnderstood=True):
		if(startAsUnderstood):
			self.startAsUnderstood()
		for move in movelist:
			if (move.type=="schema"):
				self.applySchema(move.move)
			if (move.type=="representation"):
				self.applyRepresentationMove(move.move)

	def applySchema(self,schema):
		if(self.isSchemaAppliable(schema)):
			dic=self.problemState.quantitiesDic
			n,unknow=findTheUnknown(schema,dic)
			if(schema.positions[unknow]=='qf'):
				if(schema.operation==operations.addition):
					dic.addValue(schema.objects['qf'],dic.get(schema.objects['q2'])+dic.get(schema.objects['q1']))
				else:
					dic.addValue(schema.objects['qf'],dic.get(schema.objects['q2'])-dic.get(schema.objects['q1']))
			if(schema.positions[unknow]=='q1'):
				if(schema.operation==operations.addition):
					dic.addValue(schema.objects['q1'],dic.get(schema.objects['qf'])-dic.get(schema.objects['q2']))
				else:
					dic.addValue(schema.objects['q1'],dic.get(schema.objects['qf'])+dic.get(schema.objects['q2']))
			if(schema.positions[unknow]=='q2'):
				if(schema.operation==operations.addition):
					dic.addValue(schema.objects['q2'],dic.get(schema.objects['qf'])-dic.get(schema.objects['q1']))
				else:
					dic.addValue(schema.objects['q2'],dic.get(schema.objects['qf'])+dic.get(schema.objects['q1']))
		self.updateAppliableSchemas()

	def applyRepresentationMove(self,representation):

		pass#TODO

	def updateAppliableSchemas(self):
		self.appliableSchemaList=[]
		schemasList=self.problem.structure.schemas
		for schema in schemasList:
			if(self.isSchemaAppliable(schema)):
				self.appliableSchemaList.append(schema)

	def isSchemaAppliable(self,schema):
		dic=self.problemState.quantitiesDic
		n,unknow=findTheUnknown(schema,dic)
		if(n==1):
			return True
		else:
			return False

	#def applySchema(self,schema):

class ProblemState:
	def __init__(self,quantitiesDic,goal,representations):
		self.quantitiesDic=quantitiesDic
		self.goal=goal
		self.representations=representations

	def isProblemEnded(self):
		return(not self.quantitiesDic.isUnknown(self.goal.obj))

def findTheUnknown (schema,quantitiesDic): #count the number of unknowns in the schema, and give the object of the last unknown found
	numberOfUnknow=0
	theLastUnknown=""
	for obj in schema.positions.keys():
		if(quantitiesDic.isUnknown(obj)):
			theLastUnknown=obj
			numberOfUnknow+=1
	return numberOfUnknow,theLastUnknown

schema1=Schema("PoissonEF","PoissonEI",operations.addition,"PoissonGAIN","change")
schema2=Schema("ViandeEF","ViandeEI",operations.addition,"ViandeGAIN","change")
struct=ProblemStructure()
struct.addSchema(schema1)
struct.addSchema(schema2)
struct.addBridgingSchemas(schema1,schema2)
struct.updateObjectList()

text=Text()
text.addTextInformation(TextInformation(Representation(Quantity("PoissonGAIN",5),'Au supermarch, le kilo de poisson a augment de 5 euros cette anne')))
text.addTextInformation(TextInformation(Representation(Quantity("PoissonEF",12),'Un kilo de poisson cote maintenant 12 euros.')))
text.addTextInformation(TextInformation(Representation(Quantity("PoissonEIminusViandeEI",0),'Au dbut de l\'anne, le kilo de viande cotait le mme prix que le kilo de poisson.')))
text.addTextInformation(TextInformation(Representation(Quantity("PoissonGAINminusViandeGAIN",3),'Le kilo de viande a augment de 3 euros de moins que le kilo de poisson')))
text.setGoal(TextGoal(Goal('ViandeEF','Combien cote le kilo de viande maintenant?')))

text.getTextInformation(0).addAlternativeRepresentation(Representation(Quantity("PoissonEI",5),'Au supermarch, le kilo de poisson tait de 5 euros'))
text.getTextInformation(0).addAlternativeRepresentation(Representation(Quantity("PoissonEF",5),'Au supermarch, le kilo de poisson coute 5 euros'))
text.getTextInformation(3).addAlternativeRepresentation(Representation(Quantity("PoissonGAIN",3),'Le kilo de viande a augment de 3 euros'))

probleme1=Problem(struct,text)
upD=Updater(probleme1)
upD.startAsUnderstood()
solver=ExpertSolver(probleme1)
move=Move(schema1)
solver.recurcive_solve()
print(upD.appliableSchemaList)
print(solver.treeVIZ)
upD.applySchema(upD.appliableSchemaList[2])
upD
print(upD.appliableSchemaList)
<commit_msg>RepresentationMove is now possible<commit_after># -*- coding: cp1252 -*-
import lib.operations as operations
from lib.schemas import *
from lib.textRepresentations import *
import copy

class Problem: #fields : structure, text
	def __init__(self,structure,text):
		self.structure=structure
		self.text=text

class ExpertSolver:
	def __init__(self,problem):
		self.history=[]
		self.problem=problem
		self.treeVIZ=""

	def recurcive_solve(self,movelist=[],newmove="",step=0,history=[],schemeToApply=0):
		if(step!=0):
			movelist.append(newmove)
		updater=Updater(self.problem)	#	we create each time a new updater
		updater.applyMoveList(movelist)	#	and we send the previous move list
		if (not updater.problemState.isProblemEnded()):
			for schem in updater.appliableSchemaList:
				newmove=Move(schem)
				#print(step,s,ml,schem.positions.keys())
				self.updateTree(step,schem.positions.keys())
				self.recurcive_solve(copy.deepcopy(movelist),newmove,step+1,copy.deepcopy(history))
		else:
			#print(history)
			step=0
	def updateTree(self,step,keys):
		line=step*"\t"+str(keys)+"\r\n"
		self.treeVIZ+=line

class Move:
	def __init__(self,move):
		classname=move.__class__.__name__
		if(classname=="Schema"):
			self.type="schema"
			self.move=move
		elif (classname=="RepresentationMove"):
			self.type="RepresentationMove"
			self.move=move

class RepresentationMove:
	def __init__(self,indexTextInformation, indexSelectedRepresentation):
		self.indexTextInformation=indexTextInformation
		self.indexSelectedRepresentation=indexSelectedRepresentation

class Updater: #fields : problem, problemState, representations, quantitiesDic

	def __init__(self,problem):
		self.problem=problem
		self.appliableSchemaList=[]
		self.possibleRepresentationChangeList=[]
		self.representations=[]

	def startAsUnderstood(self):	#initialise all the quantities, goals and representations, as experts do
		goal=self.problem.text.goal.expertGoal
		quantitiesDic = QuantityDic(dict.fromkeys(self.problem.structure.objectSet,operations.unknown),startAsVoid=True)	#get all the objects, init with unknow																												  #note : maybe one day => necessary to consider multiple values for a single object
		for info in self.problem.text.textInformations:
			quantitiesDic.addValue(info.expertRepresentation.quantity.object, info.expertRepresentation.quantity.value) # update the dic bind object to their values according the representations
			self.representations.append(0)	#0 indicate that the first (the good one) interpretation is selected

		self.problemState=ProblemState(quantitiesDic,goal,self.representations) # the most important line

		self.updateAppliableSchemas()

	def applyMoveList(self,movelist,startAsUnderstood=True):
		if(startAsUnderstood):
			self.startAsUnderstood()
		for move in movelist:
			if (move.type=="schema"):
				self.applySchema(move.move)
			if (move.type=="representationMove"):
				self.applyRepresentationMove(move.move)

	def applySchema(self,schema):
		if(self.isSchemaAppliable(schema)):
			dic=self.problemState.quantitiesDic
			n,unknow=findTheUnknown(schema,dic)
			if(schema.positions[unknow]=='qf'):
				if(schema.operation==operations.addition):
					dic.addValue(schema.objects['qf'],dic.get(schema.objects['q2'])+dic.get(schema.objects['q1']))
				else:
					dic.addValue(schema.objects['qf'],dic.get(schema.objects['q2'])-dic.get(schema.objects['q1']))
			if(schema.positions[unknow]=='q1'):
				if(schema.operation==operations.addition):
					dic.addValue(schema.objects['q1'],dic.get(schema.objects['qf'])-dic.get(schema.objects['q2']))
				else:
					dic.addValue(schema.objects['q1'],dic.get(schema.objects['qf'])+dic.get(schema.objects['q2']))
			if(schema.positions[unknow]=='q2'):
				if(schema.operation==operations.addition):
					dic.addValue(schema.objects['q2'],dic.get(schema.objects['qf'])-dic.get(schema.objects['q1']))
				else:
					dic.addValue(schema.objects['q2'],dic.get(schema.objects['qf'])+dic.get(schema.objects['q1']))
		self.updateAppliableSchemas()

	def applyRepresentationMove(self,representationMove):
		indexInfo=representationMove.indexTextInformation
		indexSelection=representationMove.indexSelectedRepresentation
		self.representations.remove(indexInfo)
		self.representations.insert(indexInfo, indexSelection)
		rep=self.problem.text.textInformations[indexInfo].representations[indexSelection]
		quanti=rep.quantity
		self.problemState.quantitiesDic.addValue(quanti.object, quanti.value)

	def updatePossibleRepresentationChange(self):
		currentReps=self.problemState.representations
		for t,textInfo in enumerate(self.problem.text.textInformations):
			for r,representation in enumerate(textInfo.representations):
				if(currentReps[t]!=r):
					self.possibleRepresentationChangeList.append(RepresentationMove(t,r))

	def updateAppliableSchemas(self):
		self.appliableSchemaList=[]
		schemasList=self.problem.structure.schemas
		for schema in schemasList:
			if(self.isSchemaAppliable(schema)):
				self.appliableSchemaList.append(schema)

	def isSchemaAppliable(self,schema):
		dic=self.problemState.quantitiesDic
		n,unknow=findTheUnknown(schema,dic)
		if(n==1):
			return True
		else:
			return False

	#def applySchema(self,schema):

class ProblemState:
	def __init__(self,quantitiesDic,goal,representations):
		self.quantitiesDic=quantitiesDic
		self.goal=goal
		self.representations=representations #une liste d'index !

	def isProblemEnded(self):
		return(not self.quantitiesDic.isUnknown(self.goal.obj))

def findTheUnknown (schema,quantitiesDic): #count the number of unknowns in the schema, and give the object of the last unknown found
	numberOfUnknow=0
	theLastUnknown=""
	for obj in schema.positions.keys():
		if(quantitiesDic.isUnknown(obj)):
			theLastUnknown=obj
			numberOfUnknow+=1
	return numberOfUnknow,theLastUnknown

schema1=Schema("PoissonEF","PoissonEI",operations.addition,"PoissonGAIN","change")
schema2=Schema("ViandeEF","ViandeEI",operations.addition,"ViandeGAIN","change")
struct=ProblemStructure()
struct.addSchema(schema1)
struct.addSchema(schema2)
struct.addBridgingSchemas(schema1,schema2)
struct.updateObjectList()

text=Text()
text.addTextInformation(TextInformation(Representation(Quantity("PoissonGAIN",5),'Au supermarch, le kilo de poisson a augment de 5 euros cette anne')))
text.addTextInformation(TextInformation(Representation(Quantity("PoissonEF",12),'Un kilo de poisson cote maintenant 12 euros.')))
text.addTextInformation(TextInformation(Representation(Quantity("PoissonEIminusViandeEI",0),'Au dbut de l\'anne, le kilo de viande cotait le mme prix que le kilo de poisson.')))
text.addTextInformation(TextInformation(Representation(Quantity("PoissonGAINminusViandeGAIN",3),'Le kilo de viande a augment de 3 euros de moins que le kilo de poisson')))
text.setGoal(TextGoal(Goal('ViandeEF','Combien cote le kilo de viande maintenant?')))

text.getTextInformation(0).addAlternativeRepresentation(Representation(Quantity("PoissonEI",5),'Au supermarch, le kilo de poisson tait de 5 euros'))
text.getTextInformation(0).addAlternativeRepresentation(Representation(Quantity("PoissonEF",5),'Au supermarch, le kilo de poisson coute 5 euros'))
text.getTextInformation(3).addAlternativeRepresentation(Representation(Quantity("PoissonGAIN",3),'Le kilo de viande a augment de 3 euros'))

probleme1=Problem(struct,text)
upD=Updater(probleme1)
upD.startAsUnderstood()
upD.updatePossibleRepresentationChange()
firstMove=upD.possibleRepresentationChangeList[2]
moveList=[Move(firstMove)]
solver=ExpertSolver(probleme1)
solver.recurcive_solve(moveList)
print(upD.appliableSchemaList)
print(solver.treeVIZ)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import logging
import random
import re
import weather_manager
from resource_manager import ResourceManager
from pkmn_manager import PokemonManager

SASS_FLAG = re.compile('sass[a-z]* ')
logger = logging.getLogger(__name__)

class Messenger(object):
    def __init__(self, slack_clients):
        self.clients = slack_clients
        self.help_manager = ResourceManager('help_text.txt')
        self.pkmn_manager = PokemonManager()
        self.blame_manager = ResourceManager('blames.txt')
        self.explanation_manager = ResourceManager('explanations.txt')
        self.sass_manager = ResourceManager('sass.txt')

    def send_message(self, channel_id, msg):
        # in the case of Group and Private channels, RTM channel payload is a complex dictionary
        if isinstance(channel_id, dict):
            channel_id = channel_id['id']
        channel = self.clients.rtm.server.channels.find(channel_id)
        self.clients.send_user_typing_pause(channel_id)
        channel.send_message(msg)

    def write_help_message(self, channel_id):
        help_txt = self.help_manager.get_all()
        count = self.help_manager.get_count()
        txt = (
            "I'm Flip Gunderson.  I'll *_respond_* to the following {} commands:\n{}"
        ).format(count, help_txt)
        self.send_message(channel_id, txt)

    def write_greeting(self, channel_id, user_id):
        greetings = ['Hi', 'Hello', 'Nice to meet you', 'Howdy', 'Salutations']
        txt = '{}, <@{}>!'.format(random.choice(greetings), user_id)
        self.send_message(channel_id, txt)

    def write_cast_pokemon(self, msg, channel_id):
        pkmn = self.pkmn_manager.cast_pkmn(msg)
        if pkmn is not None:
            self.send_message(channel_id, pkmn)

    def write_whos_that_pkmn(self, channel_id):
        txt = self.pkmn_manager.whos_that_pkmn(channel_id)
        self.send_message(channel_id, txt)

    def write_pkmn_guessed_response(self, msg_text, channel_id, user_id):
        txt = self.pkmn_manager.check_response(user_id, channel_id, msg_text)
        if txt is not None:
            self.send_message(channel_id, txt)

    def write_prompt(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = "I'm sorry, I didn't quite understand... Can I help you? (e.g. `<@" + bot_uid + "> help`)"
        self.send_message(channel_id, txt)

    def write_joke(self, channel_id):
        question = "Why did the python cross the road?"
        self.send_message(channel_id, question)
        self.clients.send_user_typing_pause(channel_id)
        answer = "To eat the chicken on the other side! :laughing:"
        self.send_message(channel_id, answer)

    def write_error(self, channel_id, err_msg):
        txt = ":face_with_head_bandage: my maker didn't handle this error very well:\n>```{}```".format(err_msg)
        self.send_message(channel_id, txt)

    def demo_attachment(self, channel_id):
        txt = "Beep Beep Boop is a ridiculously simple hosting platform for your Slackbots."
        attachment = {
            "pretext": "We bring bots to life. :sunglasses: :thumbsup:",
            "title": "Host, deploy and share your bot in seconds.",
            "title_link": "https://beepboophq.com/",
            "text": txt,
            "fallback": txt,
            "image_url": "https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png",
            "color": "#7CD197",
        }
        self.clients.web.chat.post_message(channel_id, txt, attachments=[attachment], as_user='true')

    def write_weather(self, channel_id):
        self.send_message(channel_id, weather_manager.getCurrentWeather())

    def write_flip(self, channel_id):
        self.send_message(channel_id, u"(╯°□°）╯︵ ┻━┻")

    def write_unflip(self, channel_id):
        self.send_message(channel_id, u"┬─┬ノ( º _ ºノ)")

    def write_blame(self, channel_id):
        self.send_message(channel_id, self.blame_manager.get_response())

    def write_explanation(self, channel_id):
        self.send_message(channel_id, self.explanation_manager.get_response())

    def write_sass(self, msg_txt, channel_id):
        target = self.__get_target(SASS_FLAG, msg_txt)
        if target == 'Flip Gunderson':
            prefix = 'Huh, nice try. '
            target = 'you'
        else:
            prefix = ''
        sass = '{}Hey, {}! {}'.format(prefix, target, self.sass_manager.get_response())
        self.send_message(channel_id, sass)

# PRIVATE METHODS:

    def __get_target(self, flag, msg_txt):
        token = re.split(flag, msg_txt.lower())
        target = ""
        if len(token) > 1:
            target = self.__format_target(token[1])
        return target

    def __format_target(self, target):
        if target == 'me':
            return 'you'
        elif target == 'yourself' or self.__is_flip_mention(target):
            return 'Flip Gunderson'
        elif '<@' in target:
            return target.upper()
        else:
            return target.title()

    def __is_flip_mention(self, msg_text):
        return re.search('flip', msg_text.lower())
<commit_msg>it ain't building. ermmmm...<commit_after># -*- coding: utf-8 -*-

import logging
import random
import re
import weather_manager
from resource_manager import ResourceManager
from pkmn_manager import PokemonManager

SASS_FLAG = re.compile('sass[a-z]* ')
logger = logging.getLogger(__name__)

class Messenger(object):
    def __init__(self, slack_clients):
        self.clients = slack_clients
        self.help_manager = ResourceManager('help_text.txt')
        self.pkmn_manager = PokemonManager()
        self.blame_manager = ResourceManager('blames.txt')
        self.explanation_manager = ResourceManager('explanations.txt')
        self.sass_manager = ResourceManager('sass.txt')

    def send_message(self, channel_id, msg):
        # in the case of Group and Private channels, RTM channel payload is a complex dictionary
        if isinstance(channel_id, dict):
            channel_id = channel_id['id']
        channel = self.clients.rtm.server.channels.find(channel_id)
        self.clients.send_user_typing_pause(channel_id)
        channel.send_message(msg)

    def write_help_message(self, channel_id):
        help_txt = self.help_manager.get_all()
        count = self.help_manager.get_count()
        txt = (
            "I'm Flip Gunderson.  I'll *_respond_* to the following {} commands:\n{}"
        ).format(count, help_txt)
        self.send_message(channel_id, txt)

    def write_greeting(self, channel_id, user_id):
        greetings = ['Hi', 'Hello', 'Nice to meet you', 'Howdy', 'Salutations']
        txt = '{}, <@{}>!'.format(random.choice(greetings), user_id)
        self.send_message(channel_id, txt)

    def write_cast_pokemon(self, msg, channel_id):
        pkmn = self.pkmn_manager.cast_pkmn(msg)
        if pkmn is not None:
            self.send_message(channel_id, pkmn)

    def write_whos_that_pkmn(self, channel_id):
        txt = self.pkmn_manager.whos_that_pkmn(channel_id)
        self.send_message(channel_id, txt)

    def write_pkmn_guessed_response(self, msg_text, channel_id, user_id):
        txt = self.pkmn_manager.check_response(user_id, channel_id, msg_text)
        if txt is not None:
            self.send_message(channel_id, txt)

    def write_prompt(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = "I'm sorry, I didn't quite understand... Can I help you? (e.g. `<@" + bot_uid + "> help`)"
        self.send_message(channel_id, txt)

    def write_joke(self, channel_id):
        question = "Why did the python cross the road?"
        self.send_message(channel_id, question)
        self.clients.send_user_typing_pause(channel_id)
        answer = "To eat the chicken on the other side! :laughing:"
        self.send_message(channel_id, answer)

    def write_error(self, channel_id, err_msg):
        txt = ":face_with_head_bandage: my maker didn't handle this error very well:\n>```{}```".format(err_msg)
        self.send_message(channel_id, txt)

    def demo_attachment(self, channel_id):
        txt = "Beep Beep Boop is a ridiculously simple hosting platform for your Slackbots."
        attachment = {
            "pretext": "We bring bots to life. :sunglasses: :thumbsup:",
            "title": "Host, deploy and share your bot in seconds.",
            "title_link": "https://beepboophq.com/",
            "text": txt,
            "fallback": txt,
            "image_url": "https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png",
            "color": "#7CD197",
        }
        self.clients.web.chat.post_message(channel_id, txt, attachments=[attachment], as_user='true')

    def write_weather(self, channel_id):
        self.send_message(channel_id, weather_manager.getCurrentWeather())

    def write_flip(self, channel_id):
        self.send_message(channel_id, u"(╯°□°）╯︵ ┻━┻")

    def write_unflip(self, channel_id):
        self.send_message(channel_id, u"┬─┬ノ( º _ ºノ)")

    def write_blame(self, channel_id):
        self.send_message(channel_id, self.blame_manager.get_response())

    def write_explanation(self, channel_id):
        self.send_message(channel_id, self.explanation_manager.get_response())

    def write_sass(self, msg_txt, channel_id):
        target = self.__get_target(SASS_FLAG, msg_txt)
        if target == 'Flip Gunderson':
            prefix = 'Huh, nice try. '
            target = 'you'
        else:
            prefix = ''
        sass = '{}Hey, {}! {}'.format(prefix, target, self.sass_manager.get_response())
        self.send_message(channel_id, sass)

# PRIVATE METHODS:

    def __get_target(self, flag, msg_txt):
        token = re.split(flag, msg_txt.lower())
        target = ""
        if len(token) > 1:
            target = self.__format_target(token[1])
        return target

    def __format_target(self, target):
        if target == 'me':
            return 'you'
        elif target == 'yourself' or self.__is_flip_mention(target):
            return 'Flip Gunderson'
        elif '<@' in target:
            return target.upper()
        else:
            return target.title()

    def __is_flip_mention(self, msg_text):
        return re.search('flip', msg_text.lower())
<|endoftext|>


<commit_before>#!/usr/bin/python3.5
# -*- coding: utf-8 -*-
import json
import datetime
import os
import os.path
import pathlib
import re
import uuid

import cherrypy
from cherrypy._cpdispatch import Dispatcher
import requests
import requests.exceptions

from classes.sitecfg import SiteConfig
from classes.template_engine import TemplateEngine
from classes.database import SiteDb, WHClass
from classes.sleeper import WHSleeper

def is_whsystem_name(name: str) -> bool:
    if name.lower() == 'thera': return True  # special case
    if len(name) != 7: return False  # must be 7 chars
    if name[0] not in ['j', 'J']: return False  # 1st letter should be j or J
    name = name[1:]  # other 6 characters must be numbers
    m = re.match(r'^[0123456789]+$', name)
    if m is None: return False
    return True

class WhdbxCustomDispatcher(Dispatcher):
    def __call__(self, path_info: str):
        path_info = path_info.lower()
        # check that requested path is in form 'J123456' ('/j170122')
        # redirects /J123456 to /ss/?jsystem=J123456
        if len(path_info) > 1:
            jsystem_name = path_info[1:]  # remove leading '/'
            if is_whsystem_name(jsystem_name):
                cherrypy.request.params['jsystem'] = jsystem_name
                return Dispatcher.__call__(self, '/ss')
        return Dispatcher.__call__(self, path_info)

class WhdbxMain:
    def __init__(self):
        self.rootdir = pathlib.Path(os.path.dirname(os.path.abspath(__file__))).as_posix()
        self.cfg = SiteConfig()
        self.tmpl = TemplateEngine(self.cfg)
        self.db = SiteDb(self.cfg)
        cherrypy.log('Whdbx started, rootdir=[{}]'.format(self.rootdir))

    def debugprint(self, msg: str = '') -> str:
        res = ''
        cherrypy.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
        res += 'use evekill: ' + str(self.cfg.ZKB_USE_EVEKILL) + '\n'
        res += str(os.environ) + '\n'
        res += msg
        return res

    # call this if any input error
    def display_failure(self, comment: str = None) -> str:
        if comment:
            self.tmpl.assign('error_comment', comment)
        return self.tmpl.render('failure.html')

    def init_session(self):
        # create all needed default values in session
        if 'sso_state' not in cherrypy.session:
            new_state = uuid.uuid4().hex
            cherrypy.session['sso_state'] = new_state
            cherrypy.log('Generated new sso_state = {}'.format(new_state))
        #
        needed_sso_vars = ['sso_token', 'sso_refresh_token', 'sso_expire_dt']
        for var_name in needed_sso_vars:
            if var_name not in cherrypy.session:
                cherrypy.session[var_name] = ''

    def setup_template_vars(self, page: str = ''):
        self.tmpl.unassign_all()
        self.tmpl.assign('title', 'WHDBX')
        self.tmpl.assign('error_comment', '')  # should be always defined!
        self.tmpl.assign('MODE', page)
        self.tmpl.assign('sitecfg', self.cfg)
        # TODO: assign crest data
        self.tmpl.assign('HAVE_SSO_LOGIN', 'false')
        self.tmpl.assign('SSO_LOGIN_URL', self.cfg.sso_login_url(cherrypy.session['sso_state']))
        self.tmpl.assign('char', {})
        self.tmpl.assign('ssys', {})
        self.tmpl.assign('corp', {})
        self.tmpl.assign('ship', {})
        self.tmpl.assign('station', {})
        # this can be used in any page showing header.html, so set default it here
        self.tmpl.assign('last_visited_systems', list())  # empty list
        # TODO: self.fill_last_visited_systems()

    @cherrypy.expose()
    def index(self):
        self.init_session()
        self.setup_template_vars('index')
        return self.tmpl.render('index.html')

    @cherrypy.expose()
    def effects(self):
        self.init_session()
        self.setup_template_vars('effects')
        effs = self.db.select_all_effects()
        self.tmpl.assign('effects', effs)
        self.tmpl.assign('title', 'Эффекты - WHDBX')
        return self.tmpl.render('effects.html')

    @cherrypy.expose()
    def sleepers(self, **params):
        self.init_session()
        self.setup_template_vars('sleepers')
        sleeper = WHSleeper()
        self.tmpl.assign('sleeper', sleeper)
        if 'id' in params:
            sleeper_id = int(params['id'])
            sleeper.load_info(sleeper_id, self.db)
            self.tmpl.assign('MODE', 'single_sleeper')
            self.tmpl.assign('title', sleeper.name + ' - WHDBX')
            self.tmpl.assign('class_sleepers', self.db.query_sleeper_by_class(sleeper.wh_class_str))
            self.tmpl.assign('sleepers_c12', list())
            self.tmpl.assign('sleepers_c34', list())
            self.tmpl.assign('sleepers_c56', list())
        else:
            self.tmpl.assign('title', 'Слиперы - WHDBX')
            self.tmpl.assign('class_sleepers', list())
            self.tmpl.assign('sleepers_c12', self.db.query_sleeper_by_class('1,2'))
            self.tmpl.assign('sleepers_c34', self.db.query_sleeper_by_class('3,4'))
            self.tmpl.assign('sleepers_c56', self.db.query_sleeper_by_class('5,6'))
        return self.tmpl.render('sleeper.html')

    @cherrypy.expose()
    def ss(self, jsystem):
        self.init_session()
        self.setup_template_vars('ss')
        return self.debugprint('/ss: requested info about: {}'.format(jsystem))

    @cherrypy.expose()
    def eve_sso_callback(self, code, state):
        self.init_session()
        self.tmpl.unassign_all()

        # verify that saved state == received state
        saved_state = cherrypy.session.get('sso_state')
        if saved_state != state:
            return self.display_failure('Error in EVE-SSO Auth: invalid state!')

        # s = 'code=' + code + ' state=' + state
        # Now we have an auth code, it's time to obtain an access token.
        # the authorization code is single use only.

        try:
            r = requests.post('https://login.eveonline.com/oauth/token',
                              auth=(self.cfg.SSO_CLIENT_ID, self.cfg.SSO_SECRET_KEY),
                              headers={'Content-Type': 'application/x-www-form-urlencoded'},
                              data={'grant_type': 'authorization_code', 'code': code},
                              timeout=10)
        except requests.exceptions.RequestException as req_e:
            return self.display_failure('Error during communication to '
                                        'login.eveonline.com:
' + str(req_e))

        # {"access_token":"kumuk...LAnz4RJZA2","token_type":"Bearer","expires_in":1200,
        #  "refresh_token":"MkMi5cGg...fIQisV0"}

        try:
            details = json.loads(r.text)
        except json.JSONDecodeError:
            return self.display_failure('Error decoding server response from login.eveonline.com!')

        access_token = details['access_token']
        refresh_token = details['refresh_token']
        expires_in = int(details['expires_in'])
        td = datetime.timedelta(seconds=expires_in)
        dt_now = datetime.datetime.now()
        dt_expire = dt_now + td

        # save those in session
        cherrypy.session['sso_token'] = access_token
        cherrypy.session['sso_refresh_token'] = refresh_token
        cherrypy.session['sso_expire_dt'] = dt_expire

        # Redirect to index
        raise cherrypy.HTTPRedirect('/', status=302)
        return 'Redirecting...'

    @cherrypy.expose()
    def ajax(self, **params):
        ret_print = 'ERROR'  # default return
        #
        if 'search_jsystem' in params:
            """
            params: search_jsystem - solarsystem name, like 'j170122' or 'J170122'
            This AJAX handler only checks that 'search_jsystem' exists.
            If it exists, it returns solarsystem name. 'ERROR' otherwise
            """
            search_jsystem = str(params['search_jsystem'])
            if is_whsystem_name(search_jsystem):
                jsys = self.db.find_ss_by_name(search_jsystem)
                if jsys:
                    # solarsystem was found, return its name
                    search_jsystem = search_jsystem.upper()
                    # ret_print = str(jsys['id'])
                    ret_print = search_jsystem
        #
        if 'search_hole' in params:
            hole_name = str(params['search_hole'])
            if hole_name != '':
                hole_name = hole_name.upper()
                wh = self.db.find_wormhole(hole_name)
                if wh is not None:
                    wh['in_class_str'] = ''
                    if wh['in_class'] != 0:
                        if wh['in_class'] == WHClass.THERA_WH_CLASS:
                            wh['in_class_str'] = 'Thera'
                        if wh['in_class'] == WHClass.FRIG_WH_CLASS:
                            wh['in_class_str'] = 'frig-WH'
                        if wh['in_class'] == WHClass.HISEC_WH_CLASS:
                            wh['in_class_str'] = 'High sec'
                        if wh['in_class'] == WHClass.LOW_WH_CLASS:
                            wh['in_class_str'] = 'Low sec'
                        if wh['in_class'] == WHClass.NULL_WH_CLASS:
                            wh['in_class_str'] = 'Null sec'
                        if (wh['in_class'] >= 1) and (wh['in_class'] <= 6):
                            wh['in_class_str'] = 'C' + str(wh['in_class'])
                        if (wh['in_class'] >= -6) and (wh['in_class'] <= -1):
                            wh['in_class_str'] = 'C' + str(wh['in_class']) + ' shattered'
                        if WHClass.is_drifters(wh['in_class']):
                            wh['in_class_str'] = 'Drifters WH'
                    ret_print = json.dumps(wh)
        return ret_print

if __name__ == '__main__':
    cherrypy.config.update({
        'server.socket_host': '0.0.0.0',
        'server.socket_port': 81,
        'engine.autoreload.on': True
    })

    rootdir = pathlib.Path(os.path.dirname(os.path.abspath(__file__))).as_posix()

    whdbx_config = {
        '/': {
            'request.dispatch': WhdbxCustomDispatcher(),
            'tools.sessions.on': True,
            'tools.sessions.storage_class': cherrypy.lib.sessions.FileSession,
            'tools.sessions.storage_path': rootdir + "/sessions",
            'tools.sessions.timeout': 30*24*3600,  # month
            'tools.staticdir.root': rootdir
        },
        '/static': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': './static'
        }
    }
    cherrypy.tree.mount(WhdbxMain(), '/', whdbx_config)

    # handle console Ctrl+C events
    cherrypy.engine.signals.subscribe()

    cherrypy.engine.start()
    cherrypy.engine.block()
<commit_msg>Router: convert /sleepers/12/ to /sleepers/?id=12<commit_after>#!/usr/bin/python3.5
# -*- coding: utf-8 -*-
import json
import datetime
import os
import os.path
import pathlib
import re
import uuid

import cherrypy
from cherrypy._cpdispatch import Dispatcher
import requests
import requests.exceptions

from classes.sitecfg import SiteConfig
from classes.template_engine import TemplateEngine
from classes.database import SiteDb, WHClass
from classes.sleeper import WHSleeper

def is_whsystem_name(name: str) -> bool:
    if name.lower() == 'thera': return True  # special case
    if len(name) != 7: return False  # must be 7 chars
    if name[0] not in ['j', 'J']: return False  # 1st letter should be j or J
    name = name[1:]  # other 6 characters must be numbers
    m = re.match(r'^[0123456789]+$', name)
    if m is None: return False
    return True

class WhdbxCustomDispatcher(Dispatcher):

    sleepers_id_match = re.compile(r'\/sleepers\/([0-9]+)\/')

    def __call__(self, path_info: str):
        path_info = path_info.lower()
        # check that requested path is in form 'J123456' ('/j170122')
        # redirects /J123456 to /ss/?jsystem=J123456
        if len(path_info) > 1:
            jsystem_name = path_info[1:]  # remove leading '/'
            if is_whsystem_name(jsystem_name):
                cherrypy.request.params['jsystem'] = jsystem_name
                return Dispatcher.__call__(self, '/ss')
            m = self.sleepers_id_match.match(path_info)
            if m is not None:
                cherrypy.request.params['id'] = m.group(1)
                return Dispatcher.__call__(self, '/sleepers/')
        return Dispatcher.__call__(self, path_info)

class WhdbxMain:
    def __init__(self):
        self.rootdir = pathlib.Path(os.path.dirname(os.path.abspath(__file__))).as_posix()
        self.cfg = SiteConfig()
        self.tmpl = TemplateEngine(self.cfg)
        self.db = SiteDb(self.cfg)
        cherrypy.log('Whdbx started, rootdir=[{}]'.format(self.rootdir))

    def debugprint(self, msg: str = '') -> str:
        res = ''
        cherrypy.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
        res += 'use evekill: ' + str(self.cfg.ZKB_USE_EVEKILL) + '\n'
        res += str(os.environ) + '\n'
        res += msg
        return res

    # call this if any input error
    def display_failure(self, comment: str = None) -> str:
        if comment:
            self.tmpl.assign('error_comment', comment)
        return self.tmpl.render('failure.html')

    def init_session(self):
        # create all needed default values in session
        if 'sso_state' not in cherrypy.session:
            new_state = uuid.uuid4().hex
            cherrypy.session['sso_state'] = new_state
            cherrypy.log('Generated new sso_state = {}'.format(new_state))
        #
        needed_sso_vars = ['sso_token', 'sso_refresh_token', 'sso_expire_dt']
        for var_name in needed_sso_vars:
            if var_name not in cherrypy.session:
                cherrypy.session[var_name] = ''

    def setup_template_vars(self, page: str = ''):
        self.tmpl.unassign_all()
        self.tmpl.assign('title', 'WHDBX')
        self.tmpl.assign('error_comment', '')  # should be always defined!
        self.tmpl.assign('MODE', page)
        self.tmpl.assign('sitecfg', self.cfg)
        # TODO: assign crest data
        self.tmpl.assign('HAVE_SSO_LOGIN', 'false')
        self.tmpl.assign('SSO_LOGIN_URL', self.cfg.sso_login_url(cherrypy.session['sso_state']))
        self.tmpl.assign('char', {})
        self.tmpl.assign('ssys', {})
        self.tmpl.assign('corp', {})
        self.tmpl.assign('ship', {})
        self.tmpl.assign('station', {})
        # this can be used in any page showing header.html, so set default it here
        self.tmpl.assign('last_visited_systems', list())  # empty list
        # TODO: self.fill_last_visited_systems()

    @cherrypy.expose()
    def index(self):
        self.init_session()
        self.setup_template_vars('index')
        return self.tmpl.render('index.html')

    @cherrypy.expose()
    def effects(self):
        self.init_session()
        self.setup_template_vars('effects')
        effs = self.db.select_all_effects()
        self.tmpl.assign('effects', effs)
        self.tmpl.assign('title', 'Эффекты - WHDBX')
        return self.tmpl.render('effects.html')

    @cherrypy.expose()
    def sleepers(self, **params):
        self.init_session()
        self.setup_template_vars('sleepers')
        sleeper = WHSleeper()
        self.tmpl.assign('sleeper', sleeper)
        if 'id' in params:
            sleeper_id = int(params['id'])
            sleeper.load_info(sleeper_id, self.db)
            self.tmpl.assign('MODE', 'single_sleeper')
            self.tmpl.assign('title', sleeper.name + ' - WHDBX')
            self.tmpl.assign('class_sleepers', self.db.query_sleeper_by_class(sleeper.wh_class_str))
            self.tmpl.assign('sleepers_c12', list())
            self.tmpl.assign('sleepers_c34', list())
            self.tmpl.assign('sleepers_c56', list())
        else:
            self.tmpl.assign('title', 'Слиперы - WHDBX')
            self.tmpl.assign('class_sleepers', list())
            self.tmpl.assign('sleepers_c12', self.db.query_sleeper_by_class('1,2'))
            self.tmpl.assign('sleepers_c34', self.db.query_sleeper_by_class('3,4'))
            self.tmpl.assign('sleepers_c56', self.db.query_sleeper_by_class('5,6'))
        return self.tmpl.render('sleeper.html')

    @cherrypy.expose()
    def ss(self, jsystem):
        self.init_session()
        self.setup_template_vars('ss')
        return self.debugprint('/ss: requested info about: {}'.format(jsystem))

    @cherrypy.expose()
    def eve_sso_callback(self, code, state):
        self.init_session()
        self.tmpl.unassign_all()

        # verify that saved state == received state
        saved_state = cherrypy.session.get('sso_state')
        if saved_state != state:
            return self.display_failure('Error in EVE-SSO Auth: invalid state!')

        # s = 'code=' + code + ' state=' + state
        # Now we have an auth code, it's time to obtain an access token.
        # the authorization code is single use only.

        try:
            r = requests.post('https://login.eveonline.com/oauth/token',
                              auth=(self.cfg.SSO_CLIENT_ID, self.cfg.SSO_SECRET_KEY),
                              headers={'Content-Type': 'application/x-www-form-urlencoded'},
                              data={'grant_type': 'authorization_code', 'code': code},
                              timeout=10)
        except requests.exceptions.RequestException as req_e:
            return self.display_failure('Error during communication to '
                                        'login.eveonline.com:
' + str(req_e))

        # {"access_token":"kumuk...LAnz4RJZA2","token_type":"Bearer","expires_in":1200,
        #  "refresh_token":"MkMi5cGg...fIQisV0"}

        try:
            details = json.loads(r.text)
        except json.JSONDecodeError:
            return self.display_failure('Error decoding server response from login.eveonline.com!')

        access_token = details['access_token']
        refresh_token = details['refresh_token']
        expires_in = int(details['expires_in'])
        td = datetime.timedelta(seconds=expires_in)
        dt_now = datetime.datetime.now()
        dt_expire = dt_now + td

        # save those in session
        cherrypy.session['sso_token'] = access_token
        cherrypy.session['sso_refresh_token'] = refresh_token
        cherrypy.session['sso_expire_dt'] = dt_expire

        # Redirect to index
        raise cherrypy.HTTPRedirect('/', status=302)
        return 'Redirecting...'

    @cherrypy.expose()
    def ajax(self, **params):
        ret_print = 'ERROR'  # default return
        #
        if 'search_jsystem' in params:
            """
            params: search_jsystem - solarsystem name, like 'j170122' or 'J170122'
            This AJAX handler only checks that 'search_jsystem' exists.
            If it exists, it returns solarsystem name. 'ERROR' otherwise
            """
            search_jsystem = str(params['search_jsystem'])
            if is_whsystem_name(search_jsystem):
                jsys = self.db.find_ss_by_name(search_jsystem)
                if jsys:
                    # solarsystem was found, return its name
                    search_jsystem = search_jsystem.upper()
                    # ret_print = str(jsys['id'])
                    ret_print = search_jsystem
        #
        if 'search_hole' in params:
            hole_name = str(params['search_hole'])
            if hole_name != '':
                hole_name = hole_name.upper()
                wh = self.db.find_wormhole(hole_name)
                if wh is not None:
                    wh['in_class_str'] = ''
                    if wh['in_class'] != 0:
                        if wh['in_class'] == WHClass.THERA_WH_CLASS:
                            wh['in_class_str'] = 'Thera'
                        if wh['in_class'] == WHClass.FRIG_WH_CLASS:
                            wh['in_class_str'] = 'frig-WH'
                        if wh['in_class'] == WHClass.HISEC_WH_CLASS:
                            wh['in_class_str'] = 'High sec'
                        if wh['in_class'] == WHClass.LOW_WH_CLASS:
                            wh['in_class_str'] = 'Low sec'
                        if wh['in_class'] == WHClass.NULL_WH_CLASS:
                            wh['in_class_str'] = 'Null sec'
                        if (wh['in_class'] >= 1) and (wh['in_class'] <= 6):
                            wh['in_class_str'] = 'C' + str(wh['in_class'])
                        if (wh['in_class'] >= -6) and (wh['in_class'] <= -1):
                            wh['in_class_str'] = 'C' + str(wh['in_class']) + ' shattered'
                        if WHClass.is_drifters(wh['in_class']):
                            wh['in_class_str'] = 'Drifters WH'
                    ret_print = json.dumps(wh)
        return ret_print

if __name__ == '__main__':
    cherrypy.config.update({
        'server.socket_host': '0.0.0.0',
        'server.socket_port': 81,
        'engine.autoreload.on': True
    })

    rootdir = pathlib.Path(os.path.dirname(os.path.abspath(__file__))).as_posix()

    whdbx_config = {
        '/': {
            'request.dispatch': WhdbxCustomDispatcher(),
            'tools.sessions.on': True,
            'tools.sessions.storage_class': cherrypy.lib.sessions.FileSession,
            'tools.sessions.storage_path': rootdir + "/sessions",
            'tools.sessions.timeout': 30*24*3600,  # month
            'tools.staticdir.root': rootdir
        },
        '/static': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': './static'
        }
    }
    cherrypy.tree.mount(WhdbxMain(), '/', whdbx_config)

    # handle console Ctrl+C events
    cherrypy.engine.signals.subscribe()

    cherrypy.engine.start()
    cherrypy.engine.block()
<|endoftext|>


<commit_before>import logging
import json
import random
import requests

logger = logging.getLogger(__name__)

def findIndexOfSequence(data, sequence, startIndex = 0):
	index = startIndex
	for token in sequence:
		index = data.find(token, index)
		if index == -1:
			return -1
	return index + len(sequence[-1])

def getCardValue(cardName, setCode):
	url = "http://www.mtggoldfish.com/widgets/autocard/%s [%s]" % (cardName, setCode)
	headers = {
		'Pragma': 'no-cache',
		'Accept-Encoding': 'gzip, deflate, sdch',
		'Accept-Language': 'en-US,en;q=0.8,de;q=0.6,sv;q=0.4',
		'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36',
		'Accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
		'Referer': 'http://www.mtggoldfish.com/widgets/autocard/%s' % cardName,
		'X-Requested-With': 'XMLHttpRequest',
		'Connection': 'keep-alive',
		'Cache-Control': 'no-cache'
	}
	response = requests.get(url, headers=headers)
	index = findIndexOfSequence(response.content, ["tcgplayer", "btn-shop-price", "$"])
	endIndex = response.content.find("\\n", index)
	try:
		value = float(response.content[index+2:endIndex].replace(",", ""))
	except ValueError:
		value = 0

	return value

def getCard(name):
	queryUrl = "http://api.deckbrew.com/mtg/cards?name=%s" % name
	print queryUrl
	r = requests.get(queryUrl)
	cards = r.json()

	if len(cards) < 1:
		return None

	card = cards[0]
	bestMatch = None
	for cardIter in cards:
		pos = cardIter["name"].lower().find(name)
		if bestMatch is None or (pos != -1 and pos < bestMatch):
			bestMatch = pos
			card = cardIter

	mostRecent = card["editions"][0]
	card["value"] = getCardValue(card["name"], mostRecent["set_id"])
	return card

def getSeasons(dciNumber):
    url = "http://www.wizards.com/Magic/PlaneswalkerPoints/JavaScript/GetPointsHistoryModal"
    headers = {
        'Pragma': 'no-cache',
        'Origin': 'http://www.wizards.com',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'en-US,en;q=0.8,de;q=0.6,sv;q=0.4',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Accept': '*/*',
        'Cache-Control': 'no-cache',
        'X-Requested-With': 'XMLHttpRequest',
        'Cookie': 'f5_cspm=1234; BIGipServerWWWPWPPOOL01=353569034.20480.0000; __utmt=1; BIGipServerWWWPool1=3792701706.20480.0000; PlaneswalkerPointsSettings=0=0&lastviewed=9212399887; __utma=75931667.1475261136.1456488297.1456488297.1456488297.1; __utmb=75931667.5.10.1456488297; __utmc=75931667; __utmz=75931667.1456488297.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)',
        'Connection': 'keep-alive',
        'Referer': 'http://www.wizards.com/Magic/PlaneswalkerPoints/%s' % dciNumber
    }
    data = {"Parameters":{"DCINumber":dciNumber,"SelectedType":"Yearly"}}
    response = requests.post(url, headers=headers, data=json.dumps(data))

    if response.status_code is 200:
        seasons = []

        responseData = json.loads(response.content)
        markup = responseData["ModalContent"]
        searchPosition = markup.find("SeasonRange")

        while searchPosition != -1:
            pointsvalue = "PointsValue\">"
            searchPosition = markup.find(pointsvalue, searchPosition)
            searchPosition += len(pointsvalue)
            endPosition = markup.find("
", searchPosition)
            if endPosition != -1:
                value = markup[searchPosition:endPosition]
                seasons.append(int(value))
            searchPosition = markup.find("SeasonRange", searchPosition)

        return {"currentSeason": seasons[0], "lastSeason": seasons[1]}
    else:
        return None

class Messenger(object):
    def __init__(self, slack_clients):
        self.clients = slack_clients

    def send_message(self, channel_id, msg):
        # in the case of Group and Private channels, RTM channel payload is a complex dictionary
        if isinstance(channel_id, dict):
            channel_id = channel_id['id']
        logger.debug('Sending msg: {} to channel: {}'.format(msg, channel_id))
        channel = self.clients.rtm.server.channels.find(channel_id)
        channel.send_message("{}".format(msg.encode('ascii', 'ignore')))

    def write_help_message(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = '{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}'.format(
            "I'm your friendly Slack bot written in Python.  I'll *_respond_* to the following commands:",
            "> `hi <@" + bot_uid + ">` - I'll respond with a randomized greeting mentioning your username. :wave:",
            "> `<@" + bot_uid + "> joke` - I'll tell you one of my finest jokes, with a typing pause for effect. :laughing:",
            "> `<@" + bot_uid + "> help` - I'll reply with this helpful text. :information_source:",
            "> `!card cardname` - I'll post a picture of the named card. :frame_with_picture:",
            "> `!price cardname` - I'll respond with the card's current market price. :moneybag:",
            "> `!oracle cardname` - I'll respond with the card's oracle text. :book:",
            "> `!pwp dcinumber` - I'll tell you a player's PWP score and bye eligibility. :trophy:")
        self.send_message(channel_id, txt)

    def write_greeting(self, channel_id, user_id):
        greetings = ['Hi', 'Hello', 'Nice to meet you', 'Howdy', 'Salutations']
        txt = '{}, <@{}>!'.format(random.choice(greetings), user_id)
        self.send_message(channel_id, txt)

    def write_prompt(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = "I'm sorry, I didn't quite understand... Can I help you? (e.g. `<@" + bot_uid + "> help`)"
        self.send_message(channel_id, txt)

    def write_joke(self, channel_id):
        question = "Why did the python cross the road?"
        self.send_message(channel_id, question)
        self.clients.send_user_typing_pause(channel_id)
        answer = "To eat the chicken on the other side! :laughing:"
        self.send_message(channel_id, answer)

    def write_error(self, channel_id, err_msg):
        txt = ":face_with_head_bandage: my maker didn't handle this error very well:\n>```{}```".format(err_msg)
        self.send_message(channel_id, txt)

    def write_card(self, channel_id, searchTerm):
        card = getCard(searchTerm)

        if card:
            mostRecentPrinting = card["editions"][0]
            txt = ""
            attachment = {
                "title": card["name"].replace("\"", "\\\""),
                "image_url": mostRecentPrinting["image_url"],
                "footer": "%s (%s)" % (mostRecentPrinting["set"], mostRecentPrinting["set_id"]),
            }
            self.clients.web.chat.post_message(channel_id, txt, attachments=[attachment], as_user='true')
        else:
            txt = 'Card not found.'
            self.send_message(channel_id, txt)

    def write_oracle(self, channel_id, searchTerm):
        card = getCard(searchTerm)

        if card:
            typeline = ""
            if card.has_key("supertypes"):
                for supertype in card["supertypes"]:
                    typeline += supertype.capitalize() + " "
            if card.has_key("types"):
                for cardtype in card["types"]:
                    typeline += cardtype.capitalize() + " "
                if card.has_key("subtypes"):
                    typeline += "- "
            if card.has_key("subtypes"):
                for subtype in card["subtypes"]:
                    typeline += subtype.capitalize() + " "
            txt = "*%s %s*\n%s\n%s" % (card["name"], card["cost"], typeline, card["text"])
            if card.has_key("power") and card.has_key("toughness"):
                txt += "\n*`%s/%s`*" % (card["power"], card["toughness"])
        else:
            txt = 'Card not found.'
        self.send_message(channel_id, txt)

    def write_price(self, channel_id, searchTerm):
        card = getCard(searchTerm)

        if card:
            mostRecentPrinting = card["editions"][0]
            txt = "Unable to find price information for %s" % card["name"]
            if card["value"] > 0:
                txt = "Current market price for most recent printing of %s (%s) - $%.1f" % (card["name"], mostRecentPrinting["set"], card["value"])
        else:
            txt = 'Card not found.'
        self.send_message(channel_id, txt)

    def write_pwp(self, channel_id, dciNumber):
        planeswalker = getSeasons(dciNumber)

        if planeswalker:
            txt = "DCI# %s has %s points in the current season, and %s points last season.\nCurrently " % (dciNumber, planeswalker["currentSeason"], planeswalker["lastSeason"])

            if planeswalker["currentSeason"] >= 2250 or planeswalker["lastSeason"] >= 2250:
                txt += "eligible for 2 GP byes."
            elif planeswalker["currentSeason"] >= 1300 or planeswalker["lastSeason"] >= 1300:
                txt += "eligible for 1 GP bye."
            else:
                txt += "not eligible for GP byes."
        else:
            txt = "DCI# %s not found." % dciNumber
        self.send_message(channel_id, txt)
<commit_msg>Edit formatting for PEP 8 style conformity<commit_after>import logging
import json
import random
import requests

logger = logging.getLogger(__name__)

def findIndexOfSequence(data, sequence, startIndex=0):
    index = startIndex
    for token in sequence:
        index = data.find(token, index)
        if index == -1:
            return -1
    return index + len(sequence[-1])

def getCardValue(cardName, setCode):
    url = "http://www.mtggoldfish.com/widgets/autocard/%s [%s]" % (cardName, setCode)
    headers = {
        'Pragma': 'no-cache',
        'Accept-Encoding': 'gzip, deflate, sdch',
        'Accept-Language': 'en-US,en;q=0.8,de;q=0.6,sv;q=0.4',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36',
        'Accept': 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01',
        'Referer': 'http://www.mtggoldfish.com/widgets/autocard/%s' % cardName,
        'X-Requested-With': 'XMLHttpRequest',
        'Connection': 'keep-alive',
        'Cache-Control': 'no-cache'
    }
    response = requests.get(url, headers=headers)
    index = findIndexOfSequence(response.content, ["tcgplayer", "btn-shop-price", "$"])
    endIndex = response.content.find("\\n", index)
    try:
        value = float(response.content[index + 2:endIndex].replace(",", ""))
    except ValueError:
        value = 0

    return value

def getCard(name):
    queryUrl = "http://api.deckbrew.com/mtg/cards?name=%s" % name
    print queryUrl
    r = requests.get(queryUrl)
    cards = r.json()

    if len(cards) < 1:
        return None

    card = cards[0]
    bestMatch = None
    for cardIter in cards:
        pos = cardIter["name"].lower().find(name)
        if bestMatch is None or (pos != -1 and pos < bestMatch):
            bestMatch = pos
            card = cardIter

    mostRecent = card["editions"][0]
    card["value"] = getCardValue(card["name"], mostRecent["set_id"])
    return card

def getSeasons(dciNumber):
    url = "http://www.wizards.com/Magic/PlaneswalkerPoints/JavaScript/GetPointsHistoryModal"
    headers = {
        'Pragma': 'no-cache',
        'Origin': 'http://www.wizards.com',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'en-US,en;q=0.8,de;q=0.6,sv;q=0.4',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Accept': '*/*',
        'Cache-Control': 'no-cache',
        'X-Requested-With': 'XMLHttpRequest',
        'Cookie': 'f5_cspm=1234; BIGipServerWWWPWPPOOL01=353569034.20480.0000; __utmt=1; BIGipServerWWWPool1=3792701706.20480.0000; PlaneswalkerPointsSettings=0=0&lastviewed=9212399887; __utma=75931667.1475261136.1456488297.1456488297.1456488297.1; __utmb=75931667.5.10.1456488297; __utmc=75931667; __utmz=75931667.1456488297.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)',
        'Connection': 'keep-alive',
        'Referer': 'http://www.wizards.com/Magic/PlaneswalkerPoints/%s' % dciNumber
    }
    data = {"Parameters": {"DCINumber": dciNumber, "SelectedType": "Yearly"}}
    response = requests.post(url, headers=headers, data=json.dumps(data))

    if response.status_code is 200:
        seasons = []

        responseData = json.loads(response.content)
        markup = responseData["ModalContent"]
        searchPosition = markup.find("SeasonRange")

        while searchPosition != -1:
            pointsvalue = "PointsValue\">"
            searchPosition = markup.find(pointsvalue, searchPosition)
            searchPosition += len(pointsvalue)
            endPosition = markup.find("
", searchPosition)
            if endPosition != -1:
                value = markup[searchPosition:endPosition]
                seasons.append(int(value))
            searchPosition = markup.find("SeasonRange", searchPosition)

        return {"currentSeason": seasons[0], "lastSeason": seasons[1]}
    else:
        return None

class Messenger(object):
    def __init__(self, slack_clients):
        self.clients = slack_clients

    def send_message(self, channel_id, msg):
        # in the case of Group and Private channels, RTM channel payload is a complex dictionary
        if isinstance(channel_id, dict):
            channel_id = channel_id['id']
        logger.debug('Sending msg: {} to channel: {}'.format(msg, channel_id))
        channel = self.clients.rtm.server.channels.find(channel_id)
        channel.send_message("{}".format(msg.encode('ascii', 'ignore')))

    def write_help_message(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = '{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}'.format(
            "I'm your friendly Slack bot written in Python.  I'll *_respond_* to the following commands:",
            "> `hi <@" + bot_uid + ">` - I'll respond with a randomized greeting mentioning your username. :wave:",
            "> `<@" + bot_uid + "> joke` - I'll tell you one of my finest jokes, with a typing pause for effect. :laughing:",
            "> `<@" + bot_uid + "> help` - I'll reply with this helpful text. :information_source:",
            "> `!card cardname` - I'll post a picture of the named card. :frame_with_picture:",
            "> `!price cardname` - I'll respond with the card's current market price. :moneybag:",
            "> `!oracle cardname` - I'll respond with the card's oracle text. :book:",
            "> `!pwp dcinumber` - I'll tell you a player's PWP score and bye eligibility. :trophy:")
        self.send_message(channel_id, txt)

    def write_greeting(self, channel_id, user_id):
        greetings = ['Hi', 'Hello', 'Nice to meet you', 'Howdy', 'Salutations']
        txt = '{}, <@{}>!'.format(random.choice(greetings), user_id)
        self.send_message(channel_id, txt)

    def write_prompt(self, channel_id):
        bot_uid = self.clients.bot_user_id()
        txt = "I'm sorry, I didn't quite understand... Can I help you? (e.g. `<@" + bot_uid + "> help`)"
        self.send_message(channel_id, txt)

    def write_joke(self, channel_id):
        question = "Why did the python cross the road?"
        self.send_message(channel_id, question)
        self.clients.send_user_typing_pause(channel_id)
        answer = "To eat the chicken on the other side! :laughing:"
        self.send_message(channel_id, answer)

    def write_error(self, channel_id, err_msg):
        txt = ":face_with_head_bandage: my maker didn't handle this error very well:\n>```{}```".format(err_msg)
        self.send_message(channel_id, txt)

    def write_card(self, channel_id, searchTerm):
        card = getCard(searchTerm)

        if card:
            mostRecentPrinting = card["editions"][0]
            txt = ""
            attachment = {
                "title": card["name"].replace("\"", "\\\""),
                "image_url": mostRecentPrinting["image_url"],
                "footer": "%s (%s)" % (mostRecentPrinting["set"], mostRecentPrinting["set_id"]),
            }
            self.clients.web.chat.post_message(channel_id, txt, attachments=[attachment], as_user='true')
        else:
            txt = 'Card not found.'
            self.send_message(channel_id, txt)

    def write_oracle(self, channel_id, searchTerm):
        card = getCard(searchTerm)

        if card:
            typeline = ""
            if "supertypes" in card:
                for supertype in card["supertypes"]:
                    typeline += supertype.capitalize() + " "
            if "types" in card:
                for cardtype in card["types"]:
                    typeline += cardtype.capitalize() + " "
                if "subtypes" in card:
                    typeline += "- "
            if "subtypes" in card:
                for subtype in card["subtypes"]:
                    typeline += subtype.capitalize() + " "
            txt = "*%s %s*\n%s\n%s" % (card["name"], card["cost"], typeline, card["text"])
            if "power" in card and "toughness" in card:
                txt += "\n*`%s/%s`*" % (card["power"], card["toughness"])
        else:
            txt = 'Card not found.'
        self.send_message(channel_id, txt)

    def write_price(self, channel_id, searchTerm):
        card = getCard(searchTerm)

        if card:
            mostRecentPrinting = card["editions"][0]
            txt = "Unable to find price information for %s" % card["name"]
            if card["value"] > 0:
                txt = "Current market price for most recent printing of %s (%s) - $%.1f" % (
                card["name"], mostRecentPrinting["set"], card["value"])
        else:
            txt = 'Card not found.'
        self.send_message(channel_id, txt)

    def write_pwp(self, channel_id, dciNumber):
        planeswalker = getSeasons(dciNumber)

        if planeswalker:
            txt = "DCI# %s has %s points in the current season, and %s points last season.\nCurrently " % (
            dciNumber, planeswalker["currentSeason"], planeswalker["lastSeason"])

            if planeswalker["currentSeason"] >= 2250 or planeswalker["lastSeason"] >= 2250:
                txt += "eligible for 2 GP byes."
            elif planeswalker["currentSeason"] >= 1300 or planeswalker["lastSeason"] >= 1300:
                txt += "eligible for 1 GP bye."
            else:
                txt += "not eligible for GP byes."
        else:
            txt = "DCI# %s not found." % dciNumber
        self.send_message(channel_id, txt)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import print_function

import sys

import signal
import click
import gevent
from gevent import Greenlet
import gevent.monkey
from ethereum import slogging
from pyethapp.jsonrpc import address_decoder

from raiden.accounts import AccountManager
from raiden.api.python import RaidenAPI
from raiden.api.rest import APIServer, RestAPI
from raiden.app import App
from raiden.constants import ROPSTEN_REGISTRY_ADDRESS, ROPSTEN_DISCOVERY_ADDRESS
from raiden.network.discovery import ContractDiscovery
from raiden.network.rpc.client import BlockChainService
from raiden.network.sockfactory import socket_factory
from raiden.settings import INITIAL_PORT
from raiden.ui.console import Console
from raiden.utils import split_endpoint

gevent.monkey.patch_all()

OPTIONS = [
    click.option(
        '--address',
        help=('The ethereum address you would like raiden to use and for which '
              'a keystore file exists in your local system.'),
        default=None,
        type=str,
    ),
    click.option(
        '--keystore-path',
        help=('If you have a non-standard path for the ethereum keystore directory'
              ' provide it using this argument.'),
        default=None,
        type=click.Path(exists=True),
    ),
    click.option(
        '--eth-rpc-endpoint',
        help='"host:port" address of ethereum JSON-RPC server.\n'
        'Also accepts a protocol prefix (http:// or https://) with optional port',
        default='127.0.0.1:8545',  # geth default jsonrpc port
        type=str,
    ),
    click.option(
        '--registry-contract-address',
        help='hex encoded address of the registry contract.',
        default=ROPSTEN_REGISTRY_ADDRESS,  # testnet default
        type=str,
    ),
    click.option(
        '--discovery-contract-address',
        help='hex encoded address of the discovery contract.',
        default=ROPSTEN_DISCOVERY_ADDRESS,  # testnet default
        type=str,
    ),
    click.option(
        '--listen-address',
        help='"host:port" for the raiden service to listen on.',
        default="0.0.0.0:{}".format(INITIAL_PORT),
        type=str,
    ),
    click.option(
        '--logging',
        help='ethereum.slogging config-string (\'<logger1>:<level>,<logger2>:<level>\')',
        default=':INFO',
        type=str,
    ),
    click.option(
        '--logfile',
        help='file path for logging to file',
        default=None,
        type=str,
    ),
    click.option(
        '--max-unresponsive-time',
        help=(
            'Max time in seconds for which an address can send no packets and '
            'still be considered healthy. Give 0 in order to disable healthcheck.'
        ),
        default=120,
        type=int,
    ),
    click.option(
        '--send-ping-time',
        help=(
            'Time in seconds after which if we have received no message from a '
            'node we have a connection with, we are going to send a PING message'
        ),
        default=60,
        type=int,
    ),
    click.option(
        '--console/--no-console',
        help=(
            'Start with or without the command line interface. Defualt is to '
            'start with the CLI disabled'
        ),
        default=False,
    ),
    click.option(
        '--rpc/--no-rpc',
        help=(
            'Start with or without the RPC server. Default is to start '
            'the RPC server'
        ),
        default=True,
    ),
    click.option(
        '--api-port',
        help=(
            'Port for the RPC server to run from'
        ),
        default=5001,
        type=int,
    ),
]

def options(func):
    """Having the common app options as a decorator facilitates reuse.
    """
    for option in OPTIONS:
        func = option(func)
    return func

@options
@click.command()
def app(address,  # pylint: disable=too-many-arguments,too-many-locals
        keystore_path,
        eth_rpc_endpoint,
        registry_contract_address,
        discovery_contract_address,
        listen_address,
        socket,
        logging,
        logfile,
        max_unresponsive_time,
        send_ping_time,
        api_port,
        rpc,
        console):

    slogging.configure(logging, log_file=logfile)

    # config_file = args.config_file
    (listen_host, listen_port) = split_endpoint(listen_address)

    config = App.default_config.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['max_unresponsive_time'] = max_unresponsive_time
    config['send_ping_time'] = send_ping_time
    config['console'] = console
    config['rpc'] = rpc
    config['api_port'] = api_port
    config['socket'] = socket

    accmgr = AccountManager(keystore_path)
    if not accmgr.accounts:
        raise RuntimeError('No Ethereum accounts found in the user\'s system')

    if not accmgr.address_in_keystore(address):
        addresses = list(accmgr.accounts.keys())
        formatted_addresses = [
            '[{:3d}] - 0x{}'.format(idx, addr)
            for idx, addr in enumerate(addresses)
        ]

        should_prompt = True

        print('The following accounts were found in your machine:')
        print('')
        print('\n'.join(formatted_addresses))
        print('')

        while should_prompt:
            idx = click.prompt('Select one of them by index to continue', type=int)

            if idx >= 0 and idx < len(addresses):
                should_prompt = False
            else:
                print("\nError: Provided index '{}' is out of bounds\n".format(idx))

        address = addresses[idx]

    unlock_tries = 3
    while True:
        try:
            privatekey_bin = accmgr.get_privkey(address)
            break
        except ValueError as e:
            # ValueError exception raised if the password is incorrect
            if unlock_tries == 0:
                print('Exhausted passphrase unlock attempts for {}. Aborting ...'.format(address))
                sys.exit(1)

            print(
                'Incorrect passphrase to unlock the private key. {} tries remaining. '
                'Please try again or kill the process to quit. '
                'Usually Ctrl-c.'.format(unlock_tries)
            )
            unlock_tries -= 1

    privatekey_hex = privatekey_bin.encode('hex')
    config['privatekey_hex'] = privatekey_hex

    endpoint = eth_rpc_endpoint

    if eth_rpc_endpoint.startswith("http://"):
        endpoint = eth_rpc_endpoint[len("http://"):]
        rpc_port = 80
    elif eth_rpc_endpoint.startswith("https://"):
        endpoint = eth_rpc_endpoint[len("https://"):]
        rpc_port = 443

    if ':' not in endpoint:  # no port was given in url
        rpc_host = endpoint
    else:
        rpc_host, rpc_port = split_endpoint(endpoint)

    # user may have provided registry and discovery contracts with leading 0x
    registry_contract_address = address_decoder(registry_contract_address)
    discovery_contract_address = address_decoder(discovery_contract_address)

    try:
        blockchain_service = BlockChainService(
            privatekey_bin,
            registry_contract_address,
            host=rpc_host,
            port=rpc_port,
        )
    except ValueError as e:
        # ValueError exception raised if:
        # - The registry contract address doesn't have code, this might happen
        # if the connected geth process is not synced or if the wrong address
        # is provided (e.g. using the address from a smart contract deployed on
        # ropsten with a geth node connected to morden)
        print(e.message)
        sys.exit(1)

    discovery = ContractDiscovery(
        blockchain_service.node_address,
        blockchain_service.discovery(discovery_contract_address)
    )

    return App(config, blockchain_service, discovery)

@options
@click.command()
@click.pass_context
def run(ctx, **kwargs):
    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.
    (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
    with socket_factory(listen_host, listen_port) as mapped_socket:
        kwargs['socket'] = mapped_socket.socket

        app_ = ctx.invoke(app, **kwargs)

        app_.discovery.register(
            app_.raiden.address,
            mapped_socket.external_ip,
            mapped_socket.external_port,
        )

        app_.raiden.register_registry(app_.raiden.chain.default_registry.address)

        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(rest_api)

            Greenlet.spawn(
                api_server.run,
                ctx.params['api_port'],
                debug=False,
                use_evalex=False
            )

            print(
                "The RPC server is now running at http://localhost:{}/.\n\n"
                "See the Raiden documentation for all available endpoints at\n"
                "https://github.com/raiden-network/raiden/blob/master/docs/api.rst".format(
                    ctx.params['api_port'],
                )
            )

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        # wait for interrupt
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)
        event.wait()

        app_.stop()
<commit_msg>Add default database path for console App<commit_after># -*- coding: utf-8 -*-
from __future__ import print_function

import sys
import os

import signal
import click
import gevent
from gevent import Greenlet
import gevent.monkey
from ethereum import slogging
from pyethapp.jsonrpc import address_decoder

from raiden.accounts import AccountManager
from raiden.api.python import RaidenAPI
from raiden.api.rest import APIServer, RestAPI
from raiden.app import App
from raiden.constants import ROPSTEN_REGISTRY_ADDRESS, ROPSTEN_DISCOVERY_ADDRESS
from raiden.network.discovery import ContractDiscovery
from raiden.network.rpc.client import BlockChainService
from raiden.network.sockfactory import socket_factory
from raiden.settings import INITIAL_PORT
from raiden.ui.console import Console
from raiden.utils import split_endpoint

gevent.monkey.patch_all()

OPTIONS = [
    click.option(
        '--address',
        help=('The ethereum address you would like raiden to use and for which '
              'a keystore file exists in your local system.'),
        default=None,
        type=str,
    ),
    click.option(
        '--keystore-path',
        help=('If you have a non-standard path for the ethereum keystore directory'
              ' provide it using this argument.'),
        default=None,
        type=click.Path(exists=True),
    ),
    click.option(
        '--eth-rpc-endpoint',
        help='"host:port" address of ethereum JSON-RPC server.\n'
        'Also accepts a protocol prefix (http:// or https://) with optional port',
        default='127.0.0.1:8545',  # geth default jsonrpc port
        type=str,
    ),
    click.option(
        '--registry-contract-address',
        help='hex encoded address of the registry contract.',
        default=ROPSTEN_REGISTRY_ADDRESS,  # testnet default
        type=str,
    ),
    click.option(
        '--discovery-contract-address',
        help='hex encoded address of the discovery contract.',
        default=ROPSTEN_DISCOVERY_ADDRESS,  # testnet default
        type=str,
    ),
    click.option(
        '--listen-address',
        help='"host:port" for the raiden service to listen on.',
        default="0.0.0.0:{}".format(INITIAL_PORT),
        type=str,
    ),
    click.option(
        '--logging',
        help='ethereum.slogging config-string (\'<logger1>:<level>,<logger2>:<level>\')',
        default=':INFO',
        type=str,
    ),
    click.option(
        '--logfile',
        help='file path for logging to file',
        default=None,
        type=str,
    ),
    click.option(
        '--max-unresponsive-time',
        help=(
            'Max time in seconds for which an address can send no packets and '
            'still be considered healthy. Give 0 in order to disable healthcheck.'
        ),
        default=120,
        type=int,
    ),
    click.option(
        '--send-ping-time',
        help=(
            'Time in seconds after which if we have received no message from a '
            'node we have a connection with, we are going to send a PING message'
        ),
        default=60,
        type=int,
    ),
    click.option(
        '--console/--no-console',
        help=(
            'Start with or without the command line interface. Defualt is to '
            'start with the CLI disabled'
        ),
        default=False,
    ),
    click.option(
        '--rpc/--no-rpc',
        help=(
            'Start with or without the RPC server. Default is to start '
            'the RPC server'
        ),
        default=True,
    ),
    click.option(
        '--api-port',
        help=(
            'Port for the RPC server to run from'
        ),
        default=5001,
        type=int,
    ),
]

def options(func):
    """Having the common app options as a decorator facilitates reuse.
    """
    for option in OPTIONS:
        func = option(func)
    return func

@options
@click.command()
def app(address,  # pylint: disable=too-many-arguments,too-many-locals
        keystore_path,
        eth_rpc_endpoint,
        registry_contract_address,
        discovery_contract_address,
        listen_address,
        socket,
        logging,
        logfile,
        max_unresponsive_time,
        send_ping_time,
        api_port,
        rpc,
        console):

    slogging.configure(logging, log_file=logfile)

    # config_file = args.config_file
    (listen_host, listen_port) = split_endpoint(listen_address)

    config = App.default_config.copy()
    config['host'] = listen_host
    config['port'] = listen_port
    config['max_unresponsive_time'] = max_unresponsive_time
    config['send_ping_time'] = send_ping_time
    config['console'] = console
    config['rpc'] = rpc
    config['api_port'] = api_port
    config['socket'] = socket

    accmgr = AccountManager(keystore_path)
    if not accmgr.accounts:
        raise RuntimeError('No Ethereum accounts found in the user\'s system')

    if not accmgr.address_in_keystore(address):
        addresses = list(accmgr.accounts.keys())
        formatted_addresses = [
            '[{:3d}] - 0x{}'.format(idx, addr)
            for idx, addr in enumerate(addresses)
        ]

        should_prompt = True

        print('The following accounts were found in your machine:')
        print('')
        print('\n'.join(formatted_addresses))
        print('')

        while should_prompt:
            idx = click.prompt('Select one of them by index to continue', type=int)

            if idx >= 0 and idx < len(addresses):
                should_prompt = False
            else:
                print("\nError: Provided index '{}' is out of bounds\n".format(idx))

        address = addresses[idx]

    unlock_tries = 3
    while True:
        try:
            privatekey_bin = accmgr.get_privkey(address)
            break
        except ValueError as e:
            # ValueError exception raised if the password is incorrect
            if unlock_tries == 0:
                print('Exhausted passphrase unlock attempts for {}. Aborting ...'.format(address))
                sys.exit(1)

            print(
                'Incorrect passphrase to unlock the private key. {} tries remaining. '
                'Please try again or kill the process to quit. '
                'Usually Ctrl-c.'.format(unlock_tries)
            )
            unlock_tries -= 1

    privatekey_hex = privatekey_bin.encode('hex')
    config['privatekey_hex'] = privatekey_hex

    endpoint = eth_rpc_endpoint

    if eth_rpc_endpoint.startswith("http://"):
        endpoint = eth_rpc_endpoint[len("http://"):]
        rpc_port = 80
    elif eth_rpc_endpoint.startswith("https://"):
        endpoint = eth_rpc_endpoint[len("https://"):]
        rpc_port = 443

    if ':' not in endpoint:  # no port was given in url
        rpc_host = endpoint
    else:
        rpc_host, rpc_port = split_endpoint(endpoint)

    # user may have provided registry and discovery contracts with leading 0x
    registry_contract_address = address_decoder(registry_contract_address)
    discovery_contract_address = address_decoder(discovery_contract_address)

    try:
        blockchain_service = BlockChainService(
            privatekey_bin,
            registry_contract_address,
            host=rpc_host,
            port=rpc_port,
        )
    except ValueError as e:
        # ValueError exception raised if:
        # - The registry contract address doesn't have code, this might happen
        # if the connected geth process is not synced or if the wrong address
        # is provided (e.g. using the address from a smart contract deployed on
        # ropsten with a geth node connected to morden)
        print(e.message)
        sys.exit(1)

    discovery = ContractDiscovery(
        blockchain_service.node_address,
        blockchain_service.discovery(discovery_contract_address)
    )

    # default database directory
    raiden_directory = os.path.join(os.path.expanduser('~'), '.raiden')
    if not os.path.exists(raiden_directory):
        os.makedirs(raiden_directory)
    database_path = os.path.join(raiden_directory, 'log.db')
    config['database_path'] = database_path

    return App(config, blockchain_service, discovery)

@options
@click.command()
@click.pass_context
def run(ctx, **kwargs):
    # TODO:
    # - Ask for confirmation to quit if there are any locked transfers that did
    # not timeout.
    (listen_host, listen_port) = split_endpoint(kwargs['listen_address'])
    with socket_factory(listen_host, listen_port) as mapped_socket:
        kwargs['socket'] = mapped_socket.socket

        app_ = ctx.invoke(app, **kwargs)

        app_.discovery.register(
            app_.raiden.address,
            mapped_socket.external_ip,
            mapped_socket.external_port,
        )

        app_.raiden.register_registry(app_.raiden.chain.default_registry.address)

        if ctx.params['rpc']:
            raiden_api = RaidenAPI(app_.raiden)
            rest_api = RestAPI(raiden_api)
            api_server = APIServer(rest_api)

            Greenlet.spawn(
                api_server.run,
                ctx.params['api_port'],
                debug=False,
                use_evalex=False
            )

            print(
                "The RPC server is now running at http://localhost:{}/.\n\n"
                "See the Raiden documentation for all available endpoints at\n"
                "https://github.com/raiden-network/raiden/blob/master/docs/api.rst".format(
                    ctx.params['api_port'],
                )
            )

        if ctx.params['console']:
            console = Console(app_)
            console.start()

        # wait for interrupt
        event = gevent.event.Event()
        gevent.signal(signal.SIGQUIT, event.set)
        gevent.signal(signal.SIGTERM, event.set)
        gevent.signal(signal.SIGINT, event.set)
        event.wait()

        app_.stop()
<|endoftext|>