<commit_before>#-------------------------------------------------------------------------------
# Name:         buzzbox.py
# Purpose:      Use PCA9533 to control FortiTo's BuzzBox
#               PCA9533 - 2 selectable, fully programmable blink rates
#               (frequency and duty cycle)
# Author:       Anasol Pena-Rios
# Created:      28/01/2014
# Copyright:    (c) FortiTo 2014
# Version:      1.0
#-------------------------------------------------------------------------------

#-----------------------------------------------------------------------
# NOTE1: To PWM allows to set a blinking light
#-----------------------------------------------------------------------
# The following example will show how to set LED0 to blink at 1 Hz at a 50 % duty cycle
# Set pre scaler PSC to achieve a period of 1 second:
#   Blink period = (PSC + 1)/152  Where 152 is the frequency (Hz) of the device
#   __PSC = Blink period = 1seg = (PSC + 1)/152
#   Then (1*152)-1 = PSC

# Set PWM duty cycle to 50 %:
#   PWM / 256 = 0.5
#   __PWM = 0.5 * 256
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# NOTE2: To PWM allows to set a dimming light
#-----------------------------------------------------------------------
# The LED brightness is controlled by setting the
# blink rate high enough (> 100 Hz) that the blinking cannot be seen and then using the duty
# cycle to vary the amount of time the LED is on and thus the average current through the LED
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# NOTE 3: KAU Project
#-----------------------------------------------------------------------
# FOR KAU Boxes values are inverted for lights 1 & 2 , fan and heater (e.g ON = 00 instead of original OFF = 00)

import smbus
import time
import math

class BuzzBox():
	#PIN DESCRIPTION
	#-------------------------------------------------------------------------------
	#Pin 1 = LED0   - LED driver 0
	#Pin 2 = LED1   - LED driver 1
	#Pin 3 = LED2   - LED driver 2
	#Pin 4 = Vss    - supply ground
	#Pin 5 = LED3   - LED driver 3
	#Pin 6 = SCL    - serial clock line (I2C)
	#Pin 7 = SDA    - serial data line  (I2C)
	#Pin 8 = Vdd    - supply voltage

	#I2C Addresses
	#-------------------------------------------------------------------------------
	#Default bus is 0. To change the bus assign it when initialising the object
	#Bus to be use depends on the model of the Raspberry Pi	used
	address     = 0x63              #PCA9550 address

	#Defining all sub addresses from Control Register Definition DataSheet
	#-------------------------------------------------------------------------------
	__INPUT  = 0x00      #Input register
	__PSC0   = 0x01      #pre-scaler 0
	__PWM0   = 0x02      #Pulse Width Modulator 0
	__PSC1   = 0x03      #pre-scaler 1
	__PWM1   = 0x04      #Pulse Width Modulator 1
	__LS0    = 0x05      #led selector

	#Attributes
	#-------------------------------------------------------------------------------
	status_fan = "OFF"
	status_light1 = "OFF"
	status_light2 = "OFF"
	status_heater = "OFF"

	#Global variables
	#-------------------------------------------------------------------------------
	bus = 0
	internal_val = 0
	val = "00000000"
	light1 = "00"
	light2 = "00"
	fan = "00"
	heater = "00"

	def __init__(self, busToUse = 0):
		# Initialise values
		self.bus = smbus.SMBus(busToUse) #open the bus on /dev/i2c-1

		#Internal value
		#-----------------------------------------------------------------------
		self.val = self.light2 + self.light1 + self.fan + self.heater
		self.internal_val = int(self.val, 2)

		self.setBlink1(1, 0.5, 152)		#blink_period=1, duty_cycle=0.5 (dim value (1-0)), frequency(Hz)=152 (taken from documentation)
		self.setBlink2(1, 0.05, 1)

		#Verify that all the devices are off
		#-----------------------------------------------------------------------
		#self.setLighting1 (False, 0, False)
		#self.setLighting2 (False, 0, False)
		#self.setFan (False)
		#self.setHeater (False)

	def clean(self):
		self.internal_val = int("00000000", 2)

		#Verify that all the devices are off
		#-----------------------------------------------------------------------
		self.setLighting1 (False, 0, False)
		self.setLighting2 (False, 0, False)
		self.setFan (False)
		self.setHeater (False)

	def setBlink1(self, blink_period=1, duty_cycle=0.5, frecuency=152):
		#-----------------------------------------------------------------------
		#Set pre-scaler PSC0 to achieve a certain blink period
		#-----------------------------------------------------------------------
		self.PSC0_value = blink_period * frecuency - 1
		self.PSC0_value = int(math.floor(self.PSC0_value))
		self.bus.write_byte_data(self.address, self.__PSC0, self.PSC0_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

		#-----------------------------------------------------------------------
		#Set PWM0 duty cycle to certain percentage
		#-----------------------------------------------------------------------
		self.PWM0_value =  duty_cycle * 256
		self.PWM0_value = int(math.floor(self.PWM0_value))
		self.bus.write_byte_data(self.address, self.__PWM0, self.PWM0_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

	def setBlink2(self, blink_period=1, duty_cycle=0.05, frecuency=1):
		#-----------------------------------------------------------------------
		#Set pre-scaler PCS1 to dim at maximum frequency // Blink period = max = 0
		#-----------------------------------------------------------------------
		self.PSC1_value = blink_period * frecuency - 1
		self.PSC1_value = int(math.floor(self.PSC1_value))
		self.bus.write_byte_data(self.address, self.__PSC1, self.PSC1_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

		#-----------------------------------------------------------------------
		#Set PWM1 duty cycle to certain percentage - dim value (1-0)
		#-----------------------------------------------------------------------
		self.PWM1_value =  duty_cycle * 256
		self.PWM1_value = int(math.floor(self.PWM1_value))
		self.bus.write_byte_data(self.address, self.__PWM1, self.PWM1_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

	def updateInternalVal(self, light2, light1, fan, heater, debug):
		self.light2 = light2
		self.light1 = light1
		self.fan = fan
		self.heater = heater

		#Concatenate string and convert to hex
		#-----------------------------------------------------------------------
		self.val = self.light2 + self.light1 + self.fan + self.heater
		self.internal_val = int(self.val, 2)

		if debug:
			print ("Light2: ", self.light2)
			print ("Light1: ", self.light1)
			print ("Fan: ", self.fan)
			print ("Heater: ", self.heater)
			print ("Internal byte: ", self.val)
			print ("Decimal value: ", self.internal_val)

		#Assign PWMOutput to __LS0 reg
		#-----------------------------------------------------------------------
		self.bus.write_byte_data(self.address, self.__LS0, self.internal_val)
		time.sleep(0.005) #at least 500 microseconds required for set

	def getLighting1 (self):
		#Get value
		return str(self.status_light1)

	def setLighting1 (self, on = False, dimValue = 1, blink = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			if blink:
				#Set PWM0 output duty cycle
				self.setBlink1(1, 0.5, 152)

				#Associate light1 to PWM0
				self.light1 = "10"
				self.status_light1 = "BLINK"

			elif dimValue > 0:
				#Set PWM0 output duty cycle
				self.setBlink1(1, dimValue, 1)

				#Associate light1 to PWM0
				self.light1 = "10"
				self.status_light1 = "DIM%" + str(int(dimValue*100))
			else:
				self.light1 = "00"
				self.status_light1 = "ON"
		else:
			self.light1 = "01"
			self.status_light1 = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def getLighting2 (self):
		#Get value
		return self.status_light2

	def setLighting2 (self, on = False, dimValue = 1, blink = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			if blink:
				#Set PWM1 output duty cycle
				self.setBlink2(1, 0.5, 152)

				#Associate light1 to PWM1
				self.light2 = "11"
				self.status_light2 = "BLINK"

			elif dimValue > 0:
				#Set PWM1 output duty cycle
				self.setBlink2(1, dimValue, 1)

				#Associate light2 to PWM1
				self.light2 = "11"
				self.status_light2 = "DIM%" + str(int(dimValue*100))
			else:
				self.light2 = "00"
				self.status_light2 = "ON"
		else:
			self.light2 = "01"
			self.status_light2 = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def getFan (self):
		#Get value
		return self.status_fan

	def setFan (self, on = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			self.fan = "00"
			self.status_fan = "ON"
		else:
			self.fan = "01"
			self.status_fan = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def getHeater (self):
		#Get value
		return self.status_heater

	def setHeater (self, on = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			self.heater = "00"
			self.status_heater = "ON"
		else:
			self.heater = "01"
			self.status_heater = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def showInfo (self):
		print ("----------------------------------------------------")
		print ("Status full device", self.bus.read_byte(self.address))
		print ("Status 0 - INPUT - input register =", self.bus.read_byte_data(self.address,self.__INPUT))
		print ("Status 1 - __PSC0 - frequency prescaler 0 =", self.bus.read_byte_data(self.address,self.__PSC0))
		print ("Status 2 - __PWM0 - PWM register 0 =", self.bus.read_byte_data(self.address,self.__PWM0))
		print ("Status 3 - __PSC1 - frequency prescaler 1 =", self.bus.read_byte_data(self.address,self.__PSC1))
		print ("Status 4 - __PWM1 - PWM register 1 =", self.bus.read_byte_data(self.address,self.__PWM1))
		print ("Status 5 - __LS0 - LED selector =", self.bus.read_byte_data(self.address,self.__LS0))
		print ("----------------------------------------------------")

if __name__ == "__main__":
	print ("----------------------------------------------------")
	print ("running - BUZZBOX test")
	print ("----------------------------------------------------")

	box = BuzzBox(1) 		#BUS 1

	#print ("Lighting set 1 ON")
	box.setLighting1 (True, 0, False)
	print "Lighting set 1 STATUS", box.getLighting1()
	time.sleep(5) 			#5 seconds wait

	#print ("Lighting set 1 BLINK")
	box.setLighting1 (True, 0, True)
	print "Lighting set 1 STATUS", box.getLighting1()
	time.sleep(5)

	#print ("Lighting set 1 DIMMABLE 50%")
	box.setLighting1 (True, 0.5, False)
	print "Lighting set 1 STATUS", box.getLighting1()
	time.sleep(5)

	#print ("Lighting set 2 ON")
	box.setLighting2 (True, 0, False)
	print "Lighting set 2 STATUS", box.getLighting2()
	time.sleep(5)

	#print ("Lighting set 2 BLINK")
	box.setLighting2 (True, 0, True)
	print "Lighting set 2 STATUS", box.getLighting2()
	time.sleep(5)

	#print ("Lighting set 2 DIMMABLE 5%")
	box.setLighting2 (True, 0.05, False)
	print "Lighting set 2 STATUS", box.getLighting2()
	time.sleep(5)

	#print ("Fan ON")
	box.setFan (True)
	print "Fan STATUS", box.getFan()
	time.sleep(2)

	#print ("Heater ON")
	box.setHeater (True)
	print "Heater STATUS", box.getHeater()
	time.sleep(2)

	#print ("Lighting set 1 OFF")
	box.setLighting1 (False, 0, False)
	print "Lighting set 1 STATUS", box.getLighting1()

	#print ("Lighting set 2 OFF")
	box.setLighting2 (False, 0, False)
	print "Lighting set 2 STATUS", box.getLighting2()

	#print ("Fan OFF")
	box.setFan (False)
	print "Fan STATUS", box.getFan()

	#print ("Heater OFF")
	box.setHeater (False)
	print "Heater STATUS", box.getHeater()

	print ("----------------------------------------------------")
	print("finished - BUZZBOX test")
	print ("----------------------------------------------------")<commit_msg>BuzzBox V2<commit_after>#-------------------------------------------------------------------------------
# Name:         buzzbox.py
# Purpose:      Use PCA9533 to control FortiTo's BuzzBox
#               PCA9533 - 2 selectable, fully programmable blink rates
#               (frequency and duty cycle)
# Author:       Anasol Pena-Rios
# Created:      28/01/2014
# Copyright:    (c) FortiTo 2014
# Version:      1.0
#-------------------------------------------------------------------------------

#-----------------------------------------------------------------------
# NOTE1: To PWM allows to set a blinking light
#-----------------------------------------------------------------------
# The following example will show how to set LED0 to blink at 1 Hz at a 50 % duty cycle
# Set pre scaler PSC to achieve a period of 1 second:
#   Blink period = (PSC + 1)/152  Where 152 is the frequency (Hz) of the device
#   __PSC = Blink period = 1seg = (PSC + 1)/152
#   Then (1*152)-1 = PSC

# Set PWM duty cycle to 50 %:
#   PWM / 256 = 0.5
#   __PWM = 0.5 * 256
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# NOTE2: To PWM allows to set a dimming light
#-----------------------------------------------------------------------
# The LED brightness is controlled by setting the
# blink rate high enough (> 100 Hz) that the blinking cannot be seen and then using the duty
# cycle to vary the amount of time the LED is on and thus the average current through the LED
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# NOTE 3: KAU Project
#-----------------------------------------------------------------------
# FOR KAU Boxes values are inverted for lights 1 & 2 , fan and heater (e.g ON = 00 instead of original OFF = 00)

import smbus
import time
import math

class BuzzBox():
	#PIN DESCRIPTION
	#-------------------------------------------------------------------------------
	#Pin 1 = LED0   - LED driver 0
	#Pin 2 = LED1   - LED driver 1
	#Pin 3 = LED2   - LED driver 2
	#Pin 4 = Vss    - supply ground
	#Pin 5 = LED3   - LED driver 3
	#Pin 6 = SCL    - serial clock line (I2C)
	#Pin 7 = SDA    - serial data line  (I2C)
	#Pin 8 = Vdd    - supply voltage

	#I2C Addresses
	#-------------------------------------------------------------------------------
	#Default bus is 0. To change the bus assign it when initialising the object
	#Bus to be use depends on the model of the Raspberry Pi	used
	address     = 0x63              #PCA9550 address

	#Defining all sub addresses from Control Register Definition DataSheet
	#-------------------------------------------------------------------------------
	__INPUT  = 0x00      #Input register
	__PSC0   = 0x01      #pre-scaler 0
	__PWM0   = 0x02      #Pulse Width Modulator 0
	__PSC1   = 0x03      #pre-scaler 1
	__PWM1   = 0x04      #Pulse Width Modulator 1
	__LS0    = 0x05      #led selector

	#Attributes
	#-------------------------------------------------------------------------------
	status_fan = "OFF"
	status_light1 = "OFF"
	status_light2 = "OFF"
	status_heater = "OFF"

	#Global variables
	#-------------------------------------------------------------------------------
	bus = 0
	internal_val = 0
	val = "00000000"
	light1 = "00"
	light2 = "00"
	fan = "00"
	heater = "00"

	def __init__(self, busToUse = 0):
		# Initialise values
		self.bus = smbus.SMBus(busToUse) #open the bus on /dev/i2c-1

		#Internal value
		#-----------------------------------------------------------------------
		self.val = self.light2 + self.light1 + self.fan + self.heater
		self.internal_val = int(self.val, 2)

		self.setBlink1(1, 0.5, 152)		#blink_period=1, duty_cycle=0.5 (dim value (1-0)), frequency(Hz)=152 (taken from documentation)
		self.setBlink2(1, 0.05, 1)

		#Verify that all the devices are off
		#-----------------------------------------------------------------------
		#self.setLighting1 (False, 0, False)
		#self.setLighting2 (False, 0, False)
		#self.setFan (False)
		#self.setHeater (False)

	def clean(self):
		self.internal_val = int("00000000", 2)

		#Verify that all the devices are off
		#-----------------------------------------------------------------------
		self.setLighting1 (False, 0, False)
		self.setLighting2 (False, 0, False)
		self.setFan (False)
		self.setHeater (False)

	def setBlink1(self, blink_period=1, duty_cycle=0.5, frequency=152):
		#-----------------------------------------------------------------------
		#Set pre-scaler PSC0 to achieve a certain blink period
		#-----------------------------------------------------------------------
		self.PSC0_value = blink_period * frequency - 1
		self.PSC0_value = int(math.floor(self.PSC0_value))
		self.bus.write_byte_data(self.address, self.__PSC0, self.PSC0_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

		#-----------------------------------------------------------------------
		#Set PWM0 duty cycle to certain percentage
		#-----------------------------------------------------------------------
		self.PWM0_value =  duty_cycle * 256
		self.PWM0_value = int(math.floor(self.PWM0_value))
		self.bus.write_byte_data(self.address, self.__PWM0, self.PWM0_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

	def setBlink2(self, blink_period=1, duty_cycle=0.05, frequency=1):
		#-----------------------------------------------------------------------
		#Set pre-scaler PCS1 to dim at maximum frequency // Blink period = max = 0
		#-----------------------------------------------------------------------
		self.PSC1_value = blink_period * frequency - 1
		self.PSC1_value = int(math.floor(self.PSC1_value))
		self.bus.write_byte_data(self.address, self.__PSC1, self.PSC1_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

		#-----------------------------------------------------------------------
		#Set PWM1 duty cycle to certain percentage - dim value (1-0)
		#-----------------------------------------------------------------------
		self.PWM1_value =  duty_cycle * 256
		self.PWM1_value = int(math.floor(self.PWM1_value))
		self.bus.write_byte_data(self.address, self.__PWM1, self.PWM1_value) #set value
		time.sleep(0.005) #at least 500 microseconds required for set

	def updateInternalVal(self, light2, light1, fan, heater, debug):
		self.light2 = light2
		self.light1 = light1
		self.fan = fan
		self.heater = heater

		#Concatenate string and convert to hex
		#-----------------------------------------------------------------------
		self.val = self.light2 + self.light1 + self.fan + self.heater
		self.internal_val = int(self.val, 2)

		if debug:
			print ("Light2: ", self.light2)
			print ("Light1: ", self.light1)
			print ("Fan: ", self.fan)
			print ("Heater: ", self.heater)
			print ("Internal byte: ", self.val)
			print ("Decimal value: ", self.internal_val)

		#Assign PWMOutput to __LS0 reg
		#-----------------------------------------------------------------------
		self.bus.write_byte_data(self.address, self.__LS0, self.internal_val)
		time.sleep(0.005) #at least 500 microseconds required for set

	def getLighting1 (self):
		#Get value
		return str(self.status_light1)

	def setLighting1 (self, on = False, dimValue = 1, blink = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			if blink:
				#Set PWM0 output duty cycle
				self.setBlink1(1, 0.5, 152)

				#Associate light1 to PWM0
				self.light1 = "10"
				self.status_light1 = "BLINK"

			elif dimValue > 0:
				#Set PWM0 output duty cycle
				self.setBlink1(1, dimValue, 1)

				#Associate light1 to PWM0
				self.light1 = "10"
				self.status_light1 = "DIM%" + str(int(dimValue*100))
			else:
				self.light1 = "00"
				self.status_light1 = "ON"
		else:
			self.light1 = "01"
			self.status_light1 = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def getLighting2 (self):
		#Get value
		return self.status_light2

	def setLighting2 (self, on = False, dimValue = 1, blink = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			if blink:
				#Set PWM1 output duty cycle
				self.setBlink2(1, 0.5, 152)

				#Associate light1 to PWM1
				self.light2 = "11"
				self.status_light2 = "BLINK"

			elif dimValue > 0:
				#Set PWM1 output duty cycle
				self.setBlink2(1, dimValue, 1)

				#Associate light2 to PWM1
				self.light2 = "11"
				self.status_light2 = "DIM%" + str(int(dimValue*100))
			else:
				self.light2 = "00"
				self.status_light2 = "ON"
		else:
			self.light2 = "01"
			self.status_light2 = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def getFan (self):
		#Get value
		return self.status_fan

	def setFan (self, on = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			self.fan = "00"
			self.status_fan = "ON"
		else:
			self.fan = "01"
			self.status_fan = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def getHeater (self):
		#Get value
		return self.status_heater

	def setHeater (self, on = False, debug = False):
		#Set value
		#-----------------------------------------------------------------------
		if on:
			self.heater = "00"
			self.status_heater = "ON"
		else:
			self.heater = "01"
			self.status_heater = "OFF"

		#Update value
		#-----------------------------------------------------------------------
		self.updateInternalVal(self.light2, self.light1, self.fan, self.heater, debug)

	def showInfo (self):
		print ("----------------------------------------------------")
		print ("Status full device", self.bus.read_byte(self.address))
		print ("Status 0 - INPUT - input register =", self.bus.read_byte_data(self.address,self.__INPUT))
		print ("Status 1 - __PSC0 - frequency prescaler 0 =", self.bus.read_byte_data(self.address,self.__PSC0))
		print ("Status 2 - __PWM0 - PWM register 0 =", self.bus.read_byte_data(self.address,self.__PWM0))
		print ("Status 3 - __PSC1 - frequency prescaler 1 =", self.bus.read_byte_data(self.address,self.__PSC1))
		print ("Status 4 - __PWM1 - PWM register 1 =", self.bus.read_byte_data(self.address,self.__PWM1))
		print ("Status 5 - __LS0 - LED selector =", self.bus.read_byte_data(self.address,self.__LS0))
		print ("----------------------------------------------------")

if __name__ == "__main__":
	print ("----------------------------------------------------")
	print ("running - BUZZBOX test")
	print ("----------------------------------------------------")

	box = BuzzBox(1) 		#BUS 1

	#print ("Lighting set 1 ON")
	box.setLighting1 (True, 0, False)
	print "Lighting set 1 STATUS", box.getLighting1()
	time.sleep(5) 			#5 seconds wait

	#print ("Lighting set 1 BLINK")
	box.setLighting1 (True, 0, True)
	print "Lighting set 1 STATUS", box.getLighting1()
	time.sleep(5)

	#print ("Lighting set 1 DIMMABLE 50%")
	box.setLighting1 (True, 0.5, False)
	print "Lighting set 1 STATUS", box.getLighting1()
	time.sleep(5)

	#print ("Lighting set 2 ON")
	box.setLighting2 (True, 0, False)
	print "Lighting set 2 STATUS", box.getLighting2()
	time.sleep(5)

	#print ("Lighting set 2 BLINK")
	box.setLighting2 (True, 0, True)
	print "Lighting set 2 STATUS", box.getLighting2()
	time.sleep(5)

	#print ("Lighting set 2 DIMMABLE 5%")
	box.setLighting2 (True, 0.05, False)
	print "Lighting set 2 STATUS", box.getLighting2()
	time.sleep(5)

	#print ("Fan ON")
	box.setFan (True)
	print "Fan STATUS", box.getFan()
	time.sleep(2)

	#print ("Heater ON")
	box.setHeater (True)
	print "Heater STATUS", box.getHeater()
	time.sleep(2)

	#print ("Lighting set 1 OFF")
	box.setLighting1 (False, 0, False)
	print "Lighting set 1 STATUS", box.getLighting1()

	#print ("Lighting set 2 OFF")
	box.setLighting2 (False, 0, False)
	print "Lighting set 2 STATUS", box.getLighting2()

	#print ("Fan OFF")
	box.setFan (False)
	print "Fan STATUS", box.getFan()

	#print ("Heater OFF")
	box.setHeater (False)
	print "Heater STATUS", box.getHeater()

	print ("----------------------------------------------------")
	print("finished - BUZZBOX test")
	print ("----------------------------------------------------")<|endoftext|>


<commit_before>import sys

def triangle_number(n):
    """Returns the nth triangular number"""
    res = 0
    for num in range (1, n+1):
        res += num

    return res

def number_of_divisors(n):
    """Returns the number of divisors of n"""
    res = 1

    for num in range (1, int(n+1/2)):
        if n % num == 0:
            res += 1

    return res

#test functions above
# print "tri_num\t", "|", "num_div"
# for index in range(1, 11):
#     print str(triangle_number(index)) + "\t", ":", number_of_divisors(triangle_number(index))

largest_tri_num = 0
largest_num_of_divisors = 0
index = 1

print number_of_divisors(45)

while largest_num_of_divisors <= int(sys.argv[1]):
    # print "----- largest_num_of_divisors:", largest_num_of_divisors

    tri_num = triangle_number(index)
    num_div = number_of_divisors(tri_num)
    # print "index, tri_num, num_div:", index, tri_num, num_div

    if num_div > largest_num_of_divisors:
        largest_num_of_divisors = num_div
        largest_tri_num = tri_num
        # print "New largest_num_of_divisors found: ", largest_num_of_divisors, "for tri_num", tri_num

    index += 1

print "index:", index, "largest_tri_num:", largest_tri_num, ", largest_num_of_divisors:", largest_num_of_divisors
<commit_msg>optimized solution to Challenge 12<commit_after>"""
Module to provide solution to Challenge 12
"""
import sys
import math

def triangle_number(nth):
    """Returns the nth triangular number"""
    return nth * (nth + 1) / 2

def number_of_divisors(input_number):
    """Returns the number of divisors of input_number"""
    res = 0

    # check for square root divisor
    if math.sqrt(input_number) % 1 == 0:
        res += 1

    # check for other integer divisors
    for num in range(1, int(math.ceil(math.sqrt(input_number)))):
        if input_number % num == 0:
            res += 2

    return res

# test functions above
print "index\t", "|", "tri_num\t", "|", "num_div"
for index in range(1, 11):
    print str(index) + "\t", ":", str(triangle_number(index)) + "\t\t", ":", number_of_divisors(triangle_number(index))

largest_tri_num = 0
largest_num_of_divisors = 0
index = 1

print number_of_divisors(45)

while largest_num_of_divisors <= int(sys.argv[1]):
    # print "----- largest_num_of_divisors:", largest_num_of_divisors

    tri_num = triangle_number(index)
    num_div = number_of_divisors(tri_num)
    # print "index, tri_num, num_div:", index, tri_num, num_div

    if num_div > largest_num_of_divisors:
        largest_num_of_divisors = num_div
        largest_tri_num = tri_num
        # print "New largest_num_of_divisors found: ", largest_num_of_divisors,
        # "for tri_num", tri_num

    index += 1

print "index:", index, "largest_tri_num:", largest_tri_num, ", largest_num_of_divisors:", largest_num_of_divisors
<|endoftext|>


<commit_before>from time import sleep
import numpy as np
from picamera import PiCamera
from picamera.array import PiRGBAnalysis
from sklearn.cluster import DBSCAN
scan = DBSCAN(eps=2, min_samples=3)

crosshair = np.zeros((480, 640, 3), dtype=np.uint8)
crosshair[240, 315:326, :] = 0xff
crosshair[235:246, 320, :] = 0xff

class Analysis(PiRGBAnalysis):
    def __init__(self, camera, size=None):
        #super(PiAnalysisOutput, self).__init__()
        self.camera = camera
        self.size = size
        self.x0 = np.array(0)
        self.i = 0
        self.t = self.camera.timestamp
        self.misc = []

    def analyse(self, x):
        x = x[:,:,1]
        d = self.x0-x
        d[self.x0<x] = 0
        xy = np.argwhere(d>10)
        if xy.shape[0]>2 and xy.shape[0]<1200:
            clust = scan.fit_predict(xy)
            ind = clust>-1
            clust = clust[ind]
            xy = xy[ind]
            denom = np.bincount(clust)
            numerx = np.bincount(clust, xy[:,0])
            numery = np.bincount(clust, xy[:,1])
            xc = numerx/denom
            yc = numery/denom
            #self.misc = [xc, yc]
        self.x0 = x
        self.i += 1
        if self.i % 10 == 0:
            td = self.camera.timestamp - self.t
            self.t += td
            #print("\r" + str(10/td), end="")
            print("\r" + str(self.camera.exposure_speed), end="")

rectime = 5
camera = PiCamera(resolution=(640, 480), framerate=25)
tracker = Analysis(camera)
camera.color_effects = (128,128)
camera.awb_mode = 'off'
camera.awb_gains = (1.5, 1.5)
camera.exposure_mode = 'night'
camera.shutter_speed = 32000
camera.video_denoise = False

#fullscreen=False, window = (20, 40, 640, 480)
camera.start_preview()
sleep(1)
ol = camera.add_overlay(crosshair, layer=3, alpha=64) #memoryview tobytes()
camera.start_recording(tracker, format='rgb')
#camera.start_recording('/home/pi/video2.h264')
camera.wait_recording(rectime)
camera.remove_overlay(ol)
camera.stop_recording()
camera.stop_preview()
print(camera.timestamp)
print("\n%s fps" % ((tracker.i)/rectime))
print(tracker.misc)

#omxplayer -o hdmi video2.h264
#avconv -i video2.h264 -s 640x480 -q:v 1 imgs2/v%04d.jpg

"""
import os
from scipy.misc import imread, imshow

path = '/home/pi/imgs2/'
files = os.listdir(path)
files.sort()

for f in files:
    x = imread(path+f)
    tracker.analyse(x)

"""
<commit_msg>added moving overlay but still getting buffer error<commit_after>from time import sleep
import numpy as np
from picamera import PiCamera
from picamera.array import PiRGBAnalysis
from sklearn.cluster import DBSCAN
scan = DBSCAN(eps=2, min_samples=3)

crosshair = np.zeros((480, 640, 3), dtype=np.uint8)

class Analysis(PiRGBAnalysis):
    def __init__(self, camera, size=None):
        #super(PiAnalysisOutput, self).__init__()
        self.camera = camera
        self.size = size
        self.x0 = np.array(0)
        self.i = 0
        self.t = self.camera.timestamp

    def analyse(self, x):
        x = x[:,:,1]
        d = self.x0-x
        d[self.x0<x] = 0
        xy = np.argwhere(d>20)
        if xy.shape[0]>2 and xy.shape[0]<1200:
            clust = scan.fit_predict(xy)
            ind = clust>-1
            if ind.any():
                clust = clust[ind]
                xy = xy[ind]
                denom = np.bincount(clust)
                numerx = np.bincount(clust, xy[:,0])
                numery = np.bincount(clust, xy[:,1])
                xc = np.rint((numerx/denom)[0]).astype(np.uint16)
                yc = np.rint((numery/denom)[0]).astype(np.uint16)
                print("\r" + str(xc), end="")
                crosshair[xc, (yc-2):(yc+3), :] = 0xff
                crosshair[(xc-2):(xc+3), yc, :] = 0xff
                ol.update(crosshair)
        self.x0 = x
        self.i += 1
        if self.i % 10 == 0:
            td = self.camera.timestamp - self.t
            self.t += td
            print("\r" + str(10/td), end="")

rectime = 3
camera = PiCamera(resolution=(640, 480), framerate=20)
camera.awb_mode = 'off'
camera.awb_gains = (1.5, 1.5)
camera.iso = 500
camera.color_effects = (128,128)
camera.exposure_mode = 'sports' #sports
#camera.shutter_speed = 32000
camera.video_denoise = False

#fullscreen=False, window = (20, 40, 640, 480)
camera.start_preview()
ol = camera.add_overlay(crosshair.tobytes(), layer=3, alpha=25) #memoryview tobytes()
tracker = Analysis(camera)
camera.start_recording(tracker, format='rgb')
#camera.start_recording('/home/pi/video2.h264')
camera.wait_recording(rectime)
camera.remove_overlay(ol)
camera.stop_recording()
camera.stop_preview()
#print(camera.timestamp)
print("\n%s fps" % ((tracker.i)/rectime))

#omxplayer -o hdmi video2.h264
#avconv -i video2.h264 -s 640x480 -q:v 1 imgs2/v%04d.jpg

"""
import os
from scipy.misc import imread, imshow

path = '/home/pi/imgs2/'
files = os.listdir(path)
files.sort()

for f in files:
    x = imread(path+f)
    tracker.analyse(x)

"""
<|endoftext|>


<commit_before># from analytics import Analytics
import datetime
from dateutil.parser import parse
import json
import pytz
import re
from slackbot.bot import Bot
from slackbot.bot import respond_to
from slackbot.bot import listen_to

from scrapers.analytics import GoogleAnalyticsScraper
from util.models import Story
from util.slack import SlackTools
slackTools = SlackTools()

# Set up analytics to handle inquiries
analytics = GoogleAnalyticsScraper()

LINGER_RATE_REGEX = 'slug ((\w*-*)+)'
START_TRACKING_REGEX = '[Tt]rack ((\w*-*)+)'

GRUBER_URLINTEXT_PAT = re.compile(ur'(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?\xab\xbb\u201c\u201d\u2018\u2019]))')

"""
Given a message, figure out what is being requested.def
"""
def parse_message(text):
    m = re.search('[Hh]ow many people donated on (\w*)?', text)
    if m:
        return 'donation'

    if 'slug' in text:
        m = re.search(LINGER_RATE_REGEX, text)
        if m:
            return 'linger'

    m = re.search(START_TRACKING_REGEX, text)
    if m:
        return 'track'

    m = GRUBER_URLINTEXT_PAT.findall(text)
    if m:
        print("Has URL")
        print(m[0])
        if 'doing' in text:
            return 'linger-update'

    return False

"""
Get information on how many people clicked the donate button on a story
"""
def get_donation_data(message, category):
    data = analytics.donation_data(category)

    if data.get('rows', []):
        row = data.get('rows')[0]
        return row[0]
    else:
        return False

def handle_donation_question(message):
    m = re.search('[Hh]ow many people donated on (\w*)?', message.body['text'])

    if not m:
        return False

    category = m.group(1)

    if category:
        count = get_donation_data(message, category)
        if count:
            message.reply(u"I don't know exactly how many people donated yet, but there were %s donation events on %s." % (count, category))
            return True
        else:
            message.reply("I wasn't able to figure out how many people donated on %s" % category)
            return False
    else:
        return False

def linger_histogram_link(rows):
    chdt='chd=t:' # Chart data
    chco='chco=' # Colors of each bar
    chxl='chxl=1:||0:|' # X-axis labels

    counts = []
    for row in rows:
        print (row)

        if row[0] == 300:
            chco += '3612b5' # color
            chxl += '5%2B'

        elif row[0] >= 60:
            chco +='12b5a3|' # color

            minutes = str(row[0] / 60)
            if minutes == '1':
                chxl += '1m|'
            else:
                chxl += minutes + '|'
        else:
            chco +='ffcc00|' # color

            # Set legend
            if row[0] == 10:
                chxl += '10s|'
            else:
                chxl += str(row[0]) + '|'

        counts.append(str(row[1]))

    chdt += ','.join(counts)

    # Uses the Google Chart API
    # Super deprecated but still running!
    # https://developers.google.com/chart/image/docs/chart_params
    base = 'http://chart.googleapis.com/chart?'
    base += '&'.join([
        chdt, # Data
        chco, # Colors
        chxl, # X-axis Labels
        'cht=bvg',
        'chs=400x200',
        'chxt=x,x,y',
        'chxs=0,b8b8b8,10,0,_|2,N*s*,b8b8b8,10,1,_',
        'chof=png',
        'chma=50,10,15,0', # Padding: l r t b
        'chxp=1,50',
        'chds=a' # Auto-scale
    ])

    # Append chof=validate to debug
    print(base)
    return base

def handle_linger_slug_question(message):
    m = re.search(LINGER_RATE_REGEX, message.body['text'])

    if not m:
        return False

    slug = m.group(1)

    if slug:
        rate = analytics.get_linger_rate(slug)
        if rate:
            people = "{:,}".format(rate['total_people'])
            time_text = humanist_time_bucket(rate)
            reply = u"%s people spent an average of %s on %s." % (people, time_text, slug)

            rows = analytics.get_linger_histogram(slug)
            histogram_url = linger_histogram_link(rows)
            attachments = [
                {
                    "fallback": slug + " update",
                    "text": 'Time users spent on graphic in number of sessions' % slug,
                    "color": "#eeeeee",
                    "title": slug,
                    "image_url": histogram_url
                }
            ]

            message.send_webapi(reply, json.dumps(attachments))

            # message.reply()
            return True
        else:
            message.reply("I wasn't able to figure out the linger rate of %s" % slug)
            return False
    else:
        return False

# SUPER HACKY -- ABSTRACT THIS AND TIME_BUCKET ASAP
def seconds_since(a):
    now = datetime.datetime.now(pytz.timezone('US/Eastern'))
    return (now - a).total_seconds()

def time_bucket(t):
    if not t:
        return False

    # For some reason, dates with timezones tend to be returned as unicode
    if type(t) is not datetime.datetime:
        t = parse(t)

    seconds = seconds_since(t)

    # 7th message, 2nd day midnight + 10 hours
    # 8th message, 2nd day midnight + 15 hours
    second_day_midnight_after_publishing = t + datetime.timedelta(days=2)
    second_day_midnight_after_publishing.replace(hour = 0, minute = 0, second=0, microsecond = 0)
    seconds_since_second_day = seconds_since(second_day_midnight_after_publishing)

    if seconds_since_second_day > 15 * 60 * 60: # 15 hours
        return 'day 2 hour 15'

    if seconds_since_second_day > 10 * 60 * 60: # 10 hours
        return 'day 2 hour 10'

    # 5th message, 1st day midnight + 10 hours
    # 6th message, 1st day midnight + 15 hours
    midnight_after_publishing = t + datetime.timedelta(days=1)
    midnight_after_publishing.replace(hour = 0, minute = 0, second=0, microsecond = 0)
    seconds_since_first_day = seconds_since(midnight_after_publishing)

    if seconds_since_second_day > 10 * 60 * 60: # 15 hours
        return 'day 1 hour 15'

    if seconds_since_second_day > 10 * 60 * 60: # 10 hours
        return 'day 1 hour 10'

    # 2nd message, tracking start + 4 hours
    # 3rd message, tracking start + 8 hours
    # 4th message, tracking start + 12 hours
    if seconds > 12 * 60 * 60: # 12 hours
        return 'hour 12'

    if seconds > 8 * 60 * 60: # 8 hours
        return 'hour 8'

    if seconds > 4 * 60 * 60: # 4 hours
        return 'hour 4'

    # Too soon to check
    return False

def humanist_time_bucket(linger):
    time = ''
    if linger['minutes'] > 0:
        time += str(linger['minutes'])
        if linger['minutes'] == 1:
            time += ' minute'
        else:
            time += ' minutes'

    if linger['seconds'] > 0:
        if linger['minutes'] > 0:
            time += ' '

        time += str(linger['seconds'])
        if linger['seconds'] == 1:
            time += ' second'
        else:
            time += ' seconds'

    return time

def handle_linger_update(message):
    m = GRUBER_URLINTEXT_PAT.findall(message.body['text'])

    if not m[0]:
        return False

    url = str(m[0][0])
    url = url.replace('&', '&')
    print("looking for url %s" % url)

    try:
        story = Story.select().where(Story.url == url).get()
    except:
        message.reply("Sorry, I don't have stats for %s" % url)
        return False

    # TODO -- refactor this copied code out from here and fabfile.py
    # Some stories have multiple slugs
    story_slugs = story.slug.split(',')
    story_slugs = [slug.strip() for slug in story_slugs]
    stats_per_slug = []
    story_time_bucket = time_bucket(story.article_posted)

    # Get the linger rate for each
    for slug in story_slugs:
        stats = analytics.get_linger_rate(slug)
        if stats:
            stats_per_slug.append({
                "slug": slug,
                "stats": stats
            })

        else:
            logger.info("No stats found for %s" % (slug))

    if len(stats_per_slug) is not 0:
        print(stats_per_slug)
        print(story_time_bucket)

        reply = ("Here's what I know about the graphics on _%s_:") % (
            story.name
        )

        fields = []
        for stat in stats_per_slug:
            time = humanist_time_bucket(stat['stats'])
            fields.append({
                "title": stat['slug'],
                "value": time,
                "short": True
            })

        rows = analytics.get_linger_histogram(slug)
        histogram_url = linger_histogram_link(rows)
        attachments = [
            {
                "fallback": story.name + " update",
                "color": "#eeeeee",
                "title": story.name,
                "title_link": story.url,
                "fields": fields
            }
        ]

        message.send_webapi(reply, json.dumps(attachments))

        # self.slack.chat.post_message(app_config.LINGER_UPDATE_CHANNEL, message, as_user=True, parse='full', attachments=attachments)

def start_tracking(message):
    m = re.search(START_TRACKING_REGEX, message.body['text'])

    if not m:
        return False

    slug = m.group(1)

    if slug:
        # Check if the slug is in the database.
        try:
            story = Story.select().where(Story.slug == slug).get()
            message.reply("Thanks! I'm already tracking %s, so you should start seeing results within a couple hours." % slug)
        except Story.DoesNotExist:
            # If it's not in the database, start tracking it.
            story = Story.create(slug=slug, tracking_started=datetime.datetime.now())
            story.save()
            message.reply("Ok, I've started tracking %s. The first stats will come in about 4 hours." % slug)
    else:
        message.reply("Sorry, I wasn't able to start tracking %s right now." % slug)

    return True

# We start out responding to everything -- there doesn't seem to be a way for a
# more specific regex to take precedence over the generic case.
@respond_to('.*', re.IGNORECASE)
def response_dispatcher(message, text=None):
    if not text:
        text = message.body['text']

    message_type = parse_message(text);
    print("Got message", text, message_type)

    if message_type == 'track':
        start_tracking(message)
    elif message_type == 'donation':
        handle_donation_question(message)
    elif message_type == 'help':
        pass
    elif message_type == 'linger':
        print("handling slug linger")
        handle_linger_slug_question(message)
    elif message_type == 'linger-update':
        print("Handling linger update")
        handle_linger_update(message)
    else:
        message.reply("Hi! I got your message, but I don't know enough yet to respond to it.")

# Listen passively for any mention of Carebot: at the beginning of the line
@listen_to('^@*[Cc]arebot[:|,]\s*(.*)', re.IGNORECASE)
def reply(message, text):
    response_dispatcher(message, text)

def main():
    bot = Bot()
    # bot._client.rtm_send_message('secret-carebot-test', 'hi there')
    bot.run()

if __name__ == "__main__":
    main()
<commit_msg>Fix string replacement error<commit_after># from analytics import Analytics
import datetime
from dateutil.parser import parse
import json
import pytz
import re
from slackbot.bot import Bot
from slackbot.bot import respond_to
from slackbot.bot import listen_to

from scrapers.analytics import GoogleAnalyticsScraper
from util.models import Story
from util.slack import SlackTools
slackTools = SlackTools()

# Set up analytics to handle inquiries
analytics = GoogleAnalyticsScraper()

LINGER_RATE_REGEX = 'slug ((\w*-*)+)'
START_TRACKING_REGEX = '[Tt]rack ((\w*-*)+)'

GRUBER_URLINTEXT_PAT = re.compile(ur'(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?\xab\xbb\u201c\u201d\u2018\u2019]))')

"""
Given a message, figure out what is being requested.def
"""
def parse_message(text):
    m = re.search('[Hh]ow many people donated on (\w*)?', text)
    if m:
        return 'donation'

    if 'slug' in text:
        m = re.search(LINGER_RATE_REGEX, text)
        if m:
            return 'linger'

    m = re.search(START_TRACKING_REGEX, text)
    if m:
        return 'track'

    m = GRUBER_URLINTEXT_PAT.findall(text)
    if m:
        print("Has URL")
        print(m[0])
        if 'doing' in text:
            return 'linger-update'

    return False

"""
Get information on how many people clicked the donate button on a story
"""
def get_donation_data(message, category):
    data = analytics.donation_data(category)

    if data.get('rows', []):
        row = data.get('rows')[0]
        return row[0]
    else:
        return False

def handle_donation_question(message):
    m = re.search('[Hh]ow many people donated on (\w*)?', message.body['text'])

    if not m:
        return False

    category = m.group(1)

    if category:
        count = get_donation_data(message, category)
        if count:
            message.reply(u"I don't know exactly how many people donated yet, but there were %s donation events on %s." % (count, category))
            return True
        else:
            message.reply("I wasn't able to figure out how many people donated on %s" % category)
            return False
    else:
        return False

def linger_histogram_link(rows):
    chdt='chd=t:' # Chart data
    chco='chco=' # Colors of each bar
    chxl='chxl=1:||0:|' # X-axis labels

    counts = []
    for row in rows:
        print (row)

        if row[0] == 300:
            chco += '3612b5' # color
            chxl += '5%2B'

        elif row[0] >= 60:
            chco +='12b5a3|' # color

            minutes = str(row[0] / 60)
            if minutes == '1':
                chxl += '1m|'
            else:
                chxl += minutes + '|'
        else:
            chco +='ffcc00|' # color

            # Set legend
            if row[0] == 10:
                chxl += '10s|'
            else:
                chxl += str(row[0]) + '|'

        counts.append(str(row[1]))

    chdt += ','.join(counts)

    # Uses the Google Chart API
    # Super deprecated but still running!
    # https://developers.google.com/chart/image/docs/chart_params
    base = 'http://chart.googleapis.com/chart?'
    base += '&'.join([
        chdt, # Data
        chco, # Colors
        chxl, # X-axis Labels
        'cht=bvg',
        'chs=400x200',
        'chxt=x,x,y',
        'chxs=0,b8b8b8,10,0,_|2,N*s*,b8b8b8,10,1,_',
        'chof=png',
        'chma=50,10,15,0', # Padding: l r t b
        'chxp=1,50',
        'chds=a' # Auto-scale
    ])

    # Append chof=validate to debug
    print(base)
    return base

def handle_linger_slug_question(message):
    m = re.search(LINGER_RATE_REGEX, message.body['text'])

    if not m:
        return False

    slug = m.group(1)

    if slug:
        rate = analytics.get_linger_rate(slug)
        if rate:
            people = "{:,}".format(rate['total_people'])
            time_text = humanist_time_bucket(rate)
            reply = u"%s people spent an average of %s on %s." % (people, time_text, slug)

            rows = analytics.get_linger_histogram(slug)
            histogram_url = linger_histogram_link(rows)
            attachments = [
                {
                    "fallback": slug + " update",
                    "text": 'Time users spent on graphic in number of sessions',
                    "color": "#eeeeee",
                    "title": slug,
                    "image_url": histogram_url
                }
            ]

            message.send_webapi(reply, json.dumps(attachments))

            # message.reply()
            return True
        else:
            message.reply("I wasn't able to figure out the linger rate of %s" % slug)
            return False
    else:
        return False

# SUPER HACKY -- ABSTRACT THIS AND TIME_BUCKET ASAP
def seconds_since(a):
    now = datetime.datetime.now(pytz.timezone('US/Eastern'))
    return (now - a).total_seconds()

def time_bucket(t):
    if not t:
        return False

    # For some reason, dates with timezones tend to be returned as unicode
    if type(t) is not datetime.datetime:
        t = parse(t)

    seconds = seconds_since(t)

    # 7th message, 2nd day midnight + 10 hours
    # 8th message, 2nd day midnight + 15 hours
    second_day_midnight_after_publishing = t + datetime.timedelta(days=2)
    second_day_midnight_after_publishing.replace(hour = 0, minute = 0, second=0, microsecond = 0)
    seconds_since_second_day = seconds_since(second_day_midnight_after_publishing)

    if seconds_since_second_day > 15 * 60 * 60: # 15 hours
        return 'day 2 hour 15'

    if seconds_since_second_day > 10 * 60 * 60: # 10 hours
        return 'day 2 hour 10'

    # 5th message, 1st day midnight + 10 hours
    # 6th message, 1st day midnight + 15 hours
    midnight_after_publishing = t + datetime.timedelta(days=1)
    midnight_after_publishing.replace(hour = 0, minute = 0, second=0, microsecond = 0)
    seconds_since_first_day = seconds_since(midnight_after_publishing)

    if seconds_since_second_day > 10 * 60 * 60: # 15 hours
        return 'day 1 hour 15'

    if seconds_since_second_day > 10 * 60 * 60: # 10 hours
        return 'day 1 hour 10'

    # 2nd message, tracking start + 4 hours
    # 3rd message, tracking start + 8 hours
    # 4th message, tracking start + 12 hours
    if seconds > 12 * 60 * 60: # 12 hours
        return 'hour 12'

    if seconds > 8 * 60 * 60: # 8 hours
        return 'hour 8'

    if seconds > 4 * 60 * 60: # 4 hours
        return 'hour 4'

    # Too soon to check
    return False

def humanist_time_bucket(linger):
    time = ''
    if linger['minutes'] > 0:
        time += str(linger['minutes'])
        if linger['minutes'] == 1:
            time += ' minute'
        else:
            time += ' minutes'

    if linger['seconds'] > 0:
        if linger['minutes'] > 0:
            time += ' '

        time += str(linger['seconds'])
        if linger['seconds'] == 1:
            time += ' second'
        else:
            time += ' seconds'

    return time

def handle_linger_update(message):
    m = GRUBER_URLINTEXT_PAT.findall(message.body['text'])

    if not m[0]:
        return False

    url = str(m[0][0])
    url = url.replace('&', '&')
    print("looking for url %s" % url)

    try:
        story = Story.select().where(Story.url == url).get()
    except:
        message.reply("Sorry, I don't have stats for %s" % url)
        return False

    # TODO -- refactor this copied code out from here and fabfile.py
    # Some stories have multiple slugs
    story_slugs = story.slug.split(',')
    story_slugs = [slug.strip() for slug in story_slugs]
    stats_per_slug = []
    story_time_bucket = time_bucket(story.article_posted)

    # Get the linger rate for each
    for slug in story_slugs:
        stats = analytics.get_linger_rate(slug)
        if stats:
            stats_per_slug.append({
                "slug": slug,
                "stats": stats
            })

        else:
            logger.info("No stats found for %s" % (slug))

    if len(stats_per_slug) is not 0:
        print(stats_per_slug)
        print(story_time_bucket)

        reply = ("Here's what I know about the graphics on _%s_:") % (
            story.name
        )

        fields = []
        for stat in stats_per_slug:
            time = humanist_time_bucket(stat['stats'])
            fields.append({
                "title": stat['slug'],
                "value": time,
                "short": True
            })

        rows = analytics.get_linger_histogram(slug)
        histogram_url = linger_histogram_link(rows)
        attachments = [
            {
                "fallback": story.name + " update",
                "color": "#eeeeee",
                "title": story.name,
                "title_link": story.url,
                "fields": fields
            }
        ]

        message.send_webapi(reply, json.dumps(attachments))

        # self.slack.chat.post_message(app_config.LINGER_UPDATE_CHANNEL, message, as_user=True, parse='full', attachments=attachments)

def start_tracking(message):
    m = re.search(START_TRACKING_REGEX, message.body['text'])

    if not m:
        return False

    slug = m.group(1)

    if slug:
        # Check if the slug is in the database.
        try:
            story = Story.select().where(Story.slug == slug).get()
            message.reply("Thanks! I'm already tracking %s, so you should start seeing results within a couple hours." % slug)
        except Story.DoesNotExist:
            # If it's not in the database, start tracking it.
            story = Story.create(slug=slug, tracking_started=datetime.datetime.now())
            story.save()
            message.reply("Ok, I've started tracking %s. The first stats will come in about 4 hours." % slug)
    else:
        message.reply("Sorry, I wasn't able to start tracking %s right now." % slug)

    return True

# We start out responding to everything -- there doesn't seem to be a way for a
# more specific regex to take precedence over the generic case.
@respond_to('.*', re.IGNORECASE)
def response_dispatcher(message, text=None):
    if not text:
        text = message.body['text']

    message_type = parse_message(text);
    print("Got message", text, message_type)

    if message_type == 'track':
        start_tracking(message)
    elif message_type == 'donation':
        handle_donation_question(message)
    elif message_type == 'help':
        pass
    elif message_type == 'linger':
        print("handling slug linger")
        handle_linger_slug_question(message)
    elif message_type == 'linger-update':
        print("Handling linger update")
        handle_linger_update(message)
    else:
        message.reply("Hi! I got your message, but I don't know enough yet to respond to it.")

# Listen passively for any mention of Carebot: at the beginning of the line
@listen_to('^@*[Cc]arebot[:|,]\s*(.*)', re.IGNORECASE)
def reply(message, text):
    response_dispatcher(message, text)

def main():
    bot = Bot()
    # bot._client.rtm_send_message('secret-carebot-test', 'hi there')
    bot.run()

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before># import os
import csv
import xlwt
import xlrd
# import openpyxl
# import xlutils

with open('../src/catalog.csv') as src_cat:             # открываем исходный каталог
    rdr = csv.DictReader(src_cat)                       # объявляем построчный итератор - читальщик
    fieldName = str.split(rdr.fieldnames[0], ';')       # выделяем список полей заголовков

    # настраиваем стиль будущего шаблона каталога
# ------------------------------------------------------
    aligment = xlwt.Alignment()
    aligment.wrap = 1
    aligment.horz = xlwt.Alignment.HORZ_LEFT
    aligment.vert = xlwt.Alignment.VERT_CENTER

    borders = xlwt.Borders()
    borders.left = xlwt.Borders.THIN
    borders.right = xlwt.Borders.THIN
    borders.bottom = xlwt.Borders.THIN
    borders.top = xlwt.Borders.THIN

    font0 = xlwt.Font()
    font0.name = 'Arial cyr'
    font0.bold = True
    style0 = xlwt.XFStyle()
    style0.font = font0
# ------------------------------------------------------

    # создаем шаблон каталога с пустым листом
    emptyBook = xlwt.Workbook()
    emptySheet = emptyBook.add_sheet('catalog')

    # записываем строку заголовков
    i = 0
    for field in fieldName:
        emptySheet.write(0, i, field, style0)
        i += 1

    # сохраняем шаблон
    emptyBook.save('../out/template_catalog.xls')

    # обрабатываем исходный каталог построчно
    # for row in rdr:
    srcRow = next(rdr)
    data = str.split(srcRow[rdr.fieldnames[0]], ';')

    if data[-1] == '':
        namePost = 'Поставщик не указан'
    else:
        namePost = data[-1]

    workB = xlrd.open_workbook('../out/template_catalog.xls', on_demand = True, formatting_info = True)
    workSh = workB.sheet_by_index(0)

    print('1')
    # firstRow = str.split(, ';')

<commit_msg>Add files via upload<commit_after># import os
import csv
import xlwt
import xlrd
# import openpyxl
# import xlutils

with open('../src/catalog.csv') as src_cat:             # открываем исходный каталог
    rdr = csv.DictReader(src_cat)                       # объявляем построчный итератор - читальщик
    fieldName = str.split(rdr.fieldnames[0], ';')       # выделяем список полей заголовков

    # настраиваем стиль будущего шаблона каталога
# ------------------------------------------------------
    aligment = xlwt.Alignment()
    aligment.wrap = 1
    aligment.horz = xlwt.Alignment.HORZ_LEFT
    aligment.vert = xlwt.Alignment.VERT_CENTER

    borders = xlwt.Borders()
    borders.left = xlwt.Borders.THIN
    borders.right = xlwt.Borders.THIN
    borders.bottom = xlwt.Borders.THIN
    borders.top = xlwt.Borders.THIN

    font0 = xlwt.Font()
    font0.name = 'Arial cyr'
    font0.bold = True
    style0 = xlwt.XFStyle()
    style0.font = font0
# ------------------------------------------------------

    # создаем шаблон каталога с пустым листом
    emptyBook = xlwt.Workbook()
    emptySheet = emptyBook.add_sheet('catalog')

    # записываем строку заголовков
    i = 0
    for field in fieldName:
        emptySheet.write(0, i, field, style0)
        i += 1

    # сохраняем шаблон
    emptyBook.save('../out/template_catalog.xls')

    postName = []

    # обрабатываем исходный каталог построчно
    # for row in rdr:
    srcRow = next(rdr)
    data = str.split(srcRow[rdr.fieldnames[0]], ';')

    if data[-1] == '':
        namePost = 'Поставщик не указан'
    else:
        namePost = data[-1]

    if postName.__contains__(namePost):
        workB = xlwt.Workbook('../out/catalog_'+namePost)
    else:
        emptyBook.save('../out/catalog_'+namePost+'.xls')
        postName.append(namePost)

    workB = xlwt.Workbook('../out/catalog_'+namePost+'.xls')
    workSh = workB.set_active_sheet(0)

    # emptyRow
    # i = 0
    # for fieldData in data:
    #     workSh.put_cell(emptyRow,i,0,fieldData)
    #     i += 1

    print('1')
    # firstRow = str.split(, ';')

<|endoftext|>


<commit_before>#!/usr/bin/env python

import argparse, hashlib, os, shutil, sys, tarfile, tempfile

parser = argparse.ArgumentParser(description='Receive and install files from a zipfile.')
parser.add_argument('--validate', dest='validate_command', action='store',
                   help='shell command to validate config before proceeding')
parser.add_argument('--reload', dest='reload_command', action='store',
                   help='shell command to execute after received file tree is installed')
parser.add_argument('target', type=str, nargs=1,
                   help='location to install received file tree')
args = parser.parse_args()

target = args.target[0]
if not os.path.exists(target):
    print 'target dir %s does not exist' % target
    sys.exit(1)

if args.validate_command and '{}' not in args.validate_command:
    args.validate_command += ' {}'

fd = tempfile.NamedTemporaryFile()
while True:
    data = sys.stdin.read(8192)
    if not data:
        break
    fd.write(data)
fd.seek(0)

temp = tempfile.mkdtemp()
tar = tarfile.open(fileobj=fd, mode='r|*')
tar.extractall(path=temp)

if args.validate_command:
    cmd = args.validate_command
    cmd = cmd.replace('{}', temp)
    res = os.system(cmd)
    if res > 0:
        print 'Validation failed - aborting'
        sys.exit(1)

shutil.move(target, target + '.old')
shutil.move(temp, target)

if args.reload_command:
    res = os.system(args.reload_command)
    if res > 0:
        print 'Reload failed'
        sys.exit(res)
<commit_msg>Dont perturp the target directory structure<commit_after>#!/usr/bin/env python

import argparse, hashlib, os, shutil, sys, tarfile, tempfile

parser = argparse.ArgumentParser(description='Receive and install files from a zipfile.')
parser.add_argument('--validate', dest='validate_command', action='store',
                   help='shell command to validate config before proceeding')
parser.add_argument('--reload', dest='reload_command', action='store',
                   help='shell command to execute after received file tree is installed')
parser.add_argument('target', type=str, nargs=1,
                   help='location to install received file tree')
parser.add_argument('-v', dest='verbose', action='store_true',
                   help='verbose output')
args = parser.parse_args()

target = args.target[0]
if not os.path.exists(target):
    print 'target dir %s does not exist' % target
    sys.exit(1)

if args.validate_command and '{}' not in args.validate_command:
    args.validate_command += ' {}'

fd = tempfile.NamedTemporaryFile()
while True:
    data = sys.stdin.read(8192)
    if not data:
        break
    fd.write(data)
fd.seek(0)

temp = tempfile.mkdtemp()
tar = tarfile.open(fileobj=fd, mode='r|*')
tar.extractall(path=temp)

if args.validate_command:
    cmd = args.validate_command
    cmd = cmd.replace('{}', temp)
    if args.verbose: print 'Executing %s' % cmd
    res = os.system(cmd)
    if res > 0:
        print >> sys.stderr, 'Validation failed - aborting'
        sys.exit(1)

backup = os.path.join(tempfile.gettempdir(), target.replace('/', '_'))
if os.path.exists(backup):
    print >> sys.stderr, 'Backup %s left from previous run. Please clean up.' % backup
    sys.exit(1)

# First, a backup
shutil.copytree(target, backup)

# Clean target directory without actually deleting target dir itself
for entry in os.listdir(target):
    dst = os.path.join(target, entry)
    if args.verbose: print 'Removing existing %s' % dst
    if os.path.isdir(dst):
        shutil.rmtree(dst)
    else:
        os.remove(dst)

# Install the contents of tarfile into target dir
for entry in os.listdir(temp):
    src = os.path.join(temp, entry)
    dst = os.path.join(target, entry)
    if args.verbose: print 'Installing %s' % dst
    if os.path.isdir(src):
        shutil.copytree(src, dst)
    else:
        shutil.copy2(src, dst)

if args.reload_command:
    res = os.system(args.reload_command)
    if res > 0:
        print >> sys.stderr, 'Reload failed'
        sys.exit(res)

shutil.rmtree(backup)
<|endoftext|>


<commit_before>import operator
import random
from functools import reduce

import acpc_python_client as acpc

from cfr.build_tree import GameTreeBuilder
from cfr.constants import NUM_ACTIONS
from cfr.game_tree import HoleCardsNode, TerminalNode, ActionNode, BoardCardsNode
from cfr.hand_evaluation import get_winners

try:
    from tqdm import tqdm
except ImportError:
    pass

class Cfr:
    def __init__(self, game):
        self.game = game

        game_tree_builder = GameTreeBuilder(game)

        try:
            with tqdm(total=1) as progress:
                progress.set_description('Building game tree')
                self.game_tree = game_tree_builder.build_tree()
                progress.update(1)
        except NameError:
            self.game_tree = game_tree_builder.build_tree()

        self.player_count = game.get_num_players()

    @staticmethod
    def _calculate_node_average_strategy(node):
        num_possible_actions = len(node.children)
        normalizing_sum = sum(node.strategy_sum)
        if normalizing_sum > 0:
            node.average_strategy = [
                node.strategy_sum[a] / normalizing_sum if a in node.children else 0
                for a in range(NUM_ACTIONS)
                ]
        else:
            action_probability = 1.0 / num_possible_actions
            node.average_strategy = [
                action_probability if a in node.children else 0
                for a in range(NUM_ACTIONS)
                ]

    @staticmethod
    def _calculate_tree_average_strategy(node):
        if type(node) == ActionNode:
            Cfr._calculate_node_average_strategy(node)
        if node.children:
            for child in node.children.values():
                Cfr._calculate_tree_average_strategy(child)

    def train(self, iterations, show_progress=True):
        if not show_progress:
            iterations_iterable = range(iterations)
        else:
            try:
                iterations_iterable = tqdm(range(iterations))
                iterations_iterable.set_description('CFR training')
            except NameError:
                iterations_iterable = range(iterations)

        deck = acpc.game_utils.generate_deck(self.game)
        for i in iterations_iterable:
            current_deck = list(deck)
            random.shuffle(current_deck)

            self._cfr(
                [self.game_tree] * self.player_count,
                [1] * self.player_count,
                None, [], current_deck,
                [False] * self.player_count)

        Cfr._calculate_tree_average_strategy(self.game_tree)

    def _cfr(self, nodes, reach_probs, hole_cards, board_cards, deck, players_folded):
        node_type = type(nodes[0])
        if node_type == TerminalNode:
            return self._cfr_terminal(
                nodes, hole_cards, board_cards, deck,
                players_folded)
        elif node_type == HoleCardsNode:
            return self._cfr_hole_cards(
                nodes, reach_probs,
                hole_cards, board_cards, deck,
                players_folded)
        elif node_type == BoardCardsNode:
            return self._cfr_board_cards(
                nodes, reach_probs,
                hole_cards, board_cards, deck,
                players_folded)
        return self._cfr_action(
            nodes, reach_probs,
            hole_cards, board_cards, deck,
            players_folded)

    def _cfr_terminal(self, nodes, hole_cards, board_cards, deck, players_folded):
        pot_commitment = nodes[0].pot_commitment
        flattened_board_cards = reduce(
            lambda res, cards: res + list(cards), board_cards, [])
        player_cards = [(list(hole_cards[p]) + flattened_board_cards) if not players_folded[p] else None
                        for p in range(self.player_count)]
        winners = get_winners(player_cards)
        winner_count = len(winners)
        value_per_winner = sum(pot_commitment) / winner_count
        return [value_per_winner - pot_commitment[p] if p in winners else -pot_commitment[p]
                for p in range(self.player_count)]

    def _cfr_hole_cards(self, nodes, reach_probs, hole_cards, board_cards, deck, players_folded):
        num_hole_cards = nodes[0].card_count
        next_hole_cards = []
        next_deck = list(deck)
        for p in range(self.player_count):
            next_hole_cards.append(tuple(sorted(next_deck[:num_hole_cards])))
            next_deck = next_deck[num_hole_cards:]

        next_nodes = [node.children[next_hole_cards[p]]
                      for p, node in enumerate(nodes)]
        return self._cfr(next_nodes, reach_probs, next_hole_cards, board_cards, next_deck, players_folded)

    def _cfr_board_cards(self, nodes, reach_probs, hole_cards, board_cards, deck, players_folded):
        num_board_cards = nodes[0].card_count
        selected_board_cards = tuple(sorted(deck[:num_board_cards]))
        next_nodes = [node.children[selected_board_cards]
                      for p, node in enumerate(nodes)]
        return self._cfr(next_nodes, reach_probs,
                         hole_cards, board_cards + [selected_board_cards], deck[num_board_cards:],
                         players_folded)

    @staticmethod
    def _update_node_strategy(node, realization_weight):
        normalizing_sum = 0
        for a in range(NUM_ACTIONS):
            node.strategy[a] = node.regret_sum[a] if node.regret_sum[a] > 0 else 0
            normalizing_sum += node.strategy[a]

        num_possible_actions = len(node.children)
        for a in range(NUM_ACTIONS):
            if normalizing_sum > 0:
                node.strategy[a] /= normalizing_sum
            elif a in node.children:
                node.strategy[a] = 1.0 / num_possible_actions
            else:
                node.strategy[a] = 0
            node.strategy_sum[a] += realization_weight * node.strategy[a]

    def _cfr_action(self, nodes, reach_probs,
                    hole_cards, board_cards, deck, players_folded):
        node_player = nodes[0].player
        node = nodes[node_player]
        Cfr._update_node_strategy(node, reach_probs[node_player])
        strategy = node.strategy
        util = [None] * NUM_ACTIONS
        node_util = [0] * self.player_count
        for a in range(NUM_ACTIONS):
            if a not in node.children:
                continue

            next_reach_probs = list(reach_probs)
            next_reach_probs[node_player] *= strategy[a]

            if a == 0:
                next_players_folded = list(players_folded)
                next_players_folded[node_player] = True
            else:
                next_players_folded = players_folded

            action_util = self._cfr(
                [node.children[a] for node in nodes],
                next_reach_probs,
                hole_cards, board_cards, deck, next_players_folded)
            util[a] = action_util
            for player in range(self.player_count):
                node_util[player] += strategy[a] * action_util[player]

        for a in range(NUM_ACTIONS):
            if not util[a]:
                continue
            regret = util[a][node_player] - node_util[node_player]

            opponent_reach_probs = reach_probs[0:player] \
                                   + reach_probs[player + 1:]
            reach_prob = reduce(operator.mul, opponent_reach_probs, 1)
            node.regret_sum[a] += regret * reach_prob

        return node_util
<commit_msg>Fix CFR bug<commit_after>import operator
import random
from functools import reduce

import acpc_python_client as acpc

from cfr.build_tree import GameTreeBuilder
from cfr.constants import NUM_ACTIONS
from cfr.game_tree import HoleCardsNode, TerminalNode, ActionNode, BoardCardsNode
from cfr.hand_evaluation import get_winners

try:
    from tqdm import tqdm
except ImportError:
    pass

class Cfr:
    def __init__(self, game):
        self.game = game

        game_tree_builder = GameTreeBuilder(game)

        try:
            with tqdm(total=1) as progress:
                progress.set_description('Building game tree')
                self.game_tree = game_tree_builder.build_tree()
                progress.update(1)
        except NameError:
            self.game_tree = game_tree_builder.build_tree()

        self.player_count = game.get_num_players()

    @staticmethod
    def _calculate_node_average_strategy(node):
        num_possible_actions = len(node.children)
        normalizing_sum = sum(node.strategy_sum)
        if normalizing_sum > 0:
            node.average_strategy = [
                node.strategy_sum[a] / normalizing_sum if a in node.children else 0
                for a in range(NUM_ACTIONS)
                ]
        else:
            action_probability = 1.0 / num_possible_actions
            node.average_strategy = [
                action_probability if a in node.children else 0
                for a in range(NUM_ACTIONS)
                ]

    @staticmethod
    def _calculate_tree_average_strategy(node):
        if type(node) == ActionNode:
            Cfr._calculate_node_average_strategy(node)
        if node.children:
            for child in node.children.values():
                Cfr._calculate_tree_average_strategy(child)

    def train(self, iterations, show_progress=True):
        if not show_progress:
            iterations_iterable = range(iterations)
        else:
            try:
                iterations_iterable = tqdm(range(iterations))
                iterations_iterable.set_description('CFR training')
            except NameError:
                iterations_iterable = range(iterations)

        deck = acpc.game_utils.generate_deck(self.game)
        for i in iterations_iterable:
            current_deck = list(deck)
            random.shuffle(current_deck)

            self._cfr(
                [self.game_tree] * self.player_count,
                [1] * self.player_count,
                None, [], current_deck,
                [False] * self.player_count)

        Cfr._calculate_tree_average_strategy(self.game_tree)

    def _cfr(self, nodes, reach_probs, hole_cards, board_cards, deck, players_folded):
        node_type = type(nodes[0])
        if node_type == TerminalNode:
            return self._cfr_terminal(
                nodes, hole_cards, board_cards, deck,
                players_folded)
        elif node_type == HoleCardsNode:
            return self._cfr_hole_cards(
                nodes, reach_probs,
                hole_cards, board_cards, deck,
                players_folded)
        elif node_type == BoardCardsNode:
            return self._cfr_board_cards(
                nodes, reach_probs,
                hole_cards, board_cards, deck,
                players_folded)
        return self._cfr_action(
            nodes, reach_probs,
            hole_cards, board_cards, deck,
            players_folded)

    def _cfr_terminal(self, nodes, hole_cards, board_cards, deck, players_folded):
        pot_commitment = nodes[0].pot_commitment
        flattened_board_cards = reduce(
            lambda res, cards: res + list(cards), board_cards, [])
        player_cards = [(list(hole_cards[p]) + flattened_board_cards) if not players_folded[p] else None
                        for p in range(self.player_count)]
        winners = get_winners(player_cards)
        winner_count = len(winners)
        value_per_winner = sum(pot_commitment) / winner_count
        return [value_per_winner - pot_commitment[p] if p in winners else -pot_commitment[p]
                for p in range(self.player_count)]

    def _cfr_hole_cards(self, nodes, reach_probs, hole_cards, board_cards, deck, players_folded):
        num_hole_cards = nodes[0].card_count
        next_hole_cards = []
        next_deck = list(deck)
        for p in range(self.player_count):
            next_hole_cards.append(tuple(sorted(next_deck[:num_hole_cards])))
            next_deck = next_deck[num_hole_cards:]

        next_nodes = [node.children[next_hole_cards[p]]
                      for p, node in enumerate(nodes)]
        return self._cfr(next_nodes, reach_probs, next_hole_cards, board_cards, next_deck, players_folded)

    def _cfr_board_cards(self, nodes, reach_probs, hole_cards, board_cards, deck, players_folded):
        num_board_cards = nodes[0].card_count
        selected_board_cards = tuple(sorted(deck[:num_board_cards]))
        next_nodes = [node.children[selected_board_cards]
                      for p, node in enumerate(nodes)]
        return self._cfr(next_nodes, reach_probs,
                         hole_cards, board_cards + [selected_board_cards], deck[num_board_cards:],
                         players_folded)

    @staticmethod
    def _update_node_strategy(node, realization_weight):
        normalizing_sum = 0
        for a in range(NUM_ACTIONS):
            node.strategy[a] = node.regret_sum[a] if node.regret_sum[a] > 0 else 0
            normalizing_sum += node.strategy[a]

        num_possible_actions = len(node.children)
        for a in range(NUM_ACTIONS):
            if normalizing_sum > 0:
                node.strategy[a] /= normalizing_sum
            elif a in node.children:
                node.strategy[a] = 1.0 / num_possible_actions
            else:
                node.strategy[a] = 0
            node.strategy_sum[a] += realization_weight * node.strategy[a]

    def _cfr_action(self, nodes, reach_probs,
                    hole_cards, board_cards, deck, players_folded):
        node_player = nodes[0].player
        node = nodes[node_player]
        Cfr._update_node_strategy(node, reach_probs[node_player])
        strategy = node.strategy
        util = [None] * NUM_ACTIONS
        node_util = [0] * self.player_count
        for a in range(NUM_ACTIONS):
            if a not in node.children:
                continue

            next_reach_probs = list(reach_probs)
            next_reach_probs[node_player] *= strategy[a]

            if a == 0:
                next_players_folded = list(players_folded)
                next_players_folded[node_player] = True
            else:
                next_players_folded = players_folded

            action_util = self._cfr(
                [node.children[a] for node in nodes],
                next_reach_probs,
                hole_cards, board_cards, deck, next_players_folded)
            util[a] = action_util
            for player in range(self.player_count):
                node_util[player] += strategy[a] * action_util[player]

        for a in range(NUM_ACTIONS):
            if not util[a]:
                continue
            regret = util[a][node_player] - node_util[node_player]

            opponent_reach_probs = reach_probs[0:node_player] + reach_probs[node_player + 1:]
            reach_prob = reduce(operator.mul, opponent_reach_probs, 1)
            node.regret_sum[a] += regret * reach_prob

        return node_util
<|endoftext|>


<commit_before>import json
import uuid

from contextlib import contextmanager

from sqlalchemy import and_
from sqlalchemy import String
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import ForeignKey
from sqlalchemy import create_engine
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.ext.declarative import declarative_base

from indexd import index

from indexd.index.driver import IndexDriverABC

from indexd.index.errors import NoRecordFound
from indexd.index.errors import MultipleRecordsFound
from indexd.index.errors import RevisionMismatch

Base = declarative_base()

class IndexRecord(Base):
    '''
    Base index record representation.
    '''
    __tablename__ = 'index_record'

    did = Column(String, primary_key=True)
    rev = Column(String)
    form = Column(String)
    size = Column(Integer)

    urls = relationship('IndexRecordUrl',
        backref='index_record',
        cascade='all, delete-orphan',
    )

    hashes = relationship('IndexRecordHash',
        backref='index_record',
        cascade='all, delete-orphan',
    )

class IndexRecordUrl(Base):
    '''
    Base index record url representation.
    '''
    __tablename__ = 'index_record_url'

    did = Column(String, ForeignKey('index_record.did'), primary_key=True)
    url = Column(String, primary_key=True)

class IndexRecordHash(Base):
    '''
    Base index record hash representation.
    '''
    __tablename__ = 'index_record_hash'

    did = Column(String, ForeignKey('index_record.did'), primary_key=True)
    hash_type = Column(String, primary_key=True)
    hash_value = Column(String)

class SQLAlchemyIndexDriver(IndexDriverABC):
    '''
    SQLAlchemy implementation of index driver.
    '''

    def __init__(self, conn, **config):
        '''
        Initialize the SQLAlchemy database driver.
        '''
        self.engine = create_engine(conn, **config)

        Base.metadata.bind = self.engine
        Base.metadata.create_all()

        self.Session = sessionmaker(bind=self.engine)

    @property
    @contextmanager
    def session(self):
        '''
        Provide a transactional scope around a series of operations.
        '''
        session = self.Session()

        yield session

        try: session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()

    def ids(self, limit=100, start=None, size=None, urls=None, hashes=None):
        '''
        Returns list of records stored by the backend.
        '''
        # TODO add dids to filter on
        with self.session as session:
            query = session.query(IndexRecord)

            if start is not None:
                query = query.filter(IndexRecord.did > start)

            if size is not None:
                query = query.filter(IndexRecord.size == size)

            if urls is not None and urls:
                query = query.join(IndexRecord.urls)
                for u in urls:
                    query = query.filter(IndexRecordUrl.url == u)

            if hashes is not None and hashes:
                for h,v in hashes.items():
                    sub = session.query(IndexRecord)
                    sub = sub.join(IndexRecord.hashes)
                    sub = sub.filter(and_(
                        IndexRecordHash.hash_type == h,
                        IndexRecordHash.hash_value == v,
                    ))
                    query = query.intersect(sub)

            query = query.order_by(IndexRecord.did)
            query = query.limit(limit)

            return [i.did for i in query]

    def hashes_to_urls(self, size, hashes, start=0, limit=100):
        '''
        Returns a list of urls matching supplied size and hashes.
        '''
        with self.session as session:
            query = session.query(IndexRecordUrl)

            query = query.join(IndexRecordUrl.index_record)
            query = query.filter(IndexRecord.size == size)

            for h,v in hashes.items():
                # Select subset that matches given hash.
                sub = session.query(IndexRecordUrl)
                sub = sub.join(IndexRecordUrl.index_record).join(IndexRecord.hashes)
                sub = sub.filter(and_(
                    IndexRecordHash.hash_type == h,
                    IndexRecordHash.hash_value == v,
                ))

                # Filter anything that does not match.
                query = query.intersect(sub)

            # Remove duplicates.
            query = query.distinct()

            # Return only specified window.
            query = query.offset(start)
            query = query.limit(limit)

            return [r.url for r in query]

    def add(self, form, size=None, urls=[], hashes={}):
        '''
        Creates a new record given urls and hashes.
        '''
        if form not in index.FORMS:
            raise ValueError('form must be one of: %s' % index.FORMS)

        if size is not None and size < 0:
            raise ValueError('size must be non-negative')

        with self.session as session:
            record = IndexRecord()

            record.did = str(uuid.uuid4())
            record.rev = str(uuid.uuid4())[:8]

            record.form = form
            record.size = size

            record.urls = [IndexRecordUrl(
                did=record,
                url=url,
            ) for url in urls]

            record.hashes = [IndexRecordHash(
                did=record,
                hash_type=h,
                hash_value=v,
            ) for h,v in hashes.items()]

            session.add(record)

            return record.did, record.rev

    def get(self, did):
        '''
        Gets a record given the record id.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == did)

            try: record = query.one()
            except NoResultFound as err:
                raise NoRecordFound('no record found')
            except MultipleResultsFound as err:
                raise MultipleRecordsFound('multiple records found')

            rev = record.rev

            form = record.form
            size = record.size

            urls = [u.url for u in record.urls]
            hashes = {h.hash_type: h.hash_value for h in record.hashes}

        ret = {
            'did': did,
            'rev': rev,
            'size': size,
            'urls': urls,
            'hashes': hashes,
            'form': form,
        }

        return ret

    def update(self, did, rev, size=None, urls=None, hashes=None):
        '''
        Updates an existing record with new values.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == did)

            try: record = query.one()
            except NoResultFound as err:
                raise NoRecordFound('no record found')
            except MultipleResultsFound as err:
                raise MultipleRecordsFound('multiple records found')

            if rev != record.rev:
                raise RevisionMismatch('revision mismatch')

            if size is not None:
                record.size = size

            if urls is not None:
                record.urls = [IndexRecordUrl(
                    did=record,
                    url=url
                ) for url in urls]

            if hashes is not None:
                record.hashes = [IndexRecordHash(
                    did=record,
                    hash_type=h,
                    hash_value=v,
                ) for h,v in hashes.items()]

            record.rev = str(uuid.uuid4())[:8]

            session.add(record)

            return record.did, record.rev

    def delete(self, did, rev):
        '''
        Removes record if stored by backend.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == did)

            try: record = query.one()
            except NoResultFound as err:
                raise NoRecordFound('no record found')
            except MultipleResultsFound as err:
                raise MultipleRecordsFound('multiple records found')

            if rev != record.rev:
                raise RevisionMismatch('revision mismatch')

            session.delete(record)

    def __contains__(self, record):
        '''
        Returns True if record is stored by backend.
        Returns False otherwise.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == record)

            return query.exists()

    def __iter__(self):
        '''
        Iterator over unique records stored by backend.
        '''
        with self.session as session:
            for i in session.query(IndexRecord):
                yield i.did

    def __len__(self):
        '''
        Number of unique records stored by backend.
        '''
        with self.session as session:
            return session.query(IndexRecord).count()
<commit_msg>feat(subquery): use subquery instead of join<commit_after>import json
import uuid

from contextlib import contextmanager

from sqlalchemy import and_
from sqlalchemy import String
from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import ForeignKey
from sqlalchemy import create_engine
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.ext.declarative import declarative_base

from indexd import index

from indexd.index.driver import IndexDriverABC

from indexd.index.errors import NoRecordFound
from indexd.index.errors import MultipleRecordsFound
from indexd.index.errors import RevisionMismatch

Base = declarative_base()

class IndexRecord(Base):
    '''
    Base index record representation.
    '''
    __tablename__ = 'index_record'

    did = Column(String, primary_key=True)
    rev = Column(String)
    form = Column(String)
    size = Column(Integer)

    urls = relationship('IndexRecordUrl',
        backref='index_record',
        cascade='all, delete-orphan',
    )

    hashes = relationship('IndexRecordHash',
        backref='index_record',
        cascade='all, delete-orphan',
    )

class IndexRecordUrl(Base):
    '''
    Base index record url representation.
    '''
    __tablename__ = 'index_record_url'

    did = Column(String, ForeignKey('index_record.did'), primary_key=True)
    url = Column(String, primary_key=True)

class IndexRecordHash(Base):
    '''
    Base index record hash representation.
    '''
    __tablename__ = 'index_record_hash'

    did = Column(String, ForeignKey('index_record.did'), primary_key=True)
    hash_type = Column(String, primary_key=True)
    hash_value = Column(String)

class SQLAlchemyIndexDriver(IndexDriverABC):
    '''
    SQLAlchemy implementation of index driver.
    '''

    def __init__(self, conn, **config):
        '''
        Initialize the SQLAlchemy database driver.
        '''
        self.engine = create_engine(conn, **config)

        Base.metadata.bind = self.engine
        Base.metadata.create_all()

        self.Session = sessionmaker(bind=self.engine)

    @property
    @contextmanager
    def session(self):
        '''
        Provide a transactional scope around a series of operations.
        '''
        session = self.Session()

        yield session

        try: session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()

    def ids(self, limit=100, start=None, size=None, urls=None, hashes=None):
        '''
        Returns list of records stored by the backend.
        '''
        # TODO add dids to filter on
        with self.session as session:
            query = session.query(IndexRecord)

            if start is not None:
                query = query.filter(IndexRecord.did > start)

            if size is not None:
                query = query.filter(IndexRecord.size == size)

            if urls is not None and urls:
                query = query.join(IndexRecord.urls)
                for u in urls:
                    query = query.filter(IndexRecordUrl.url == u)

            if hashes is not None and hashes:
                for h,v in hashes.items():
                    sub = session.query(IndexRecordHash.did)
                    sub = sub.filter(and_(
                        IndexRecordHash.hash_type == h,
                        IndexRecordHash.hash_value == v,
                    ))
                    query = query.filter(IndexRecord.did.in_(sub.subquery()))

            query = query.order_by(IndexRecord.did)
            query = query.limit(limit)

            return [i.did for i in query]

    def hashes_to_urls(self, size, hashes, start=0, limit=100):
        '''
        Returns a list of urls matching supplied size and hashes.
        '''
        with self.session as session:
            query = session.query(IndexRecordUrl)

            query = query.join(IndexRecordUrl.index_record)
            query = query.filter(IndexRecord.size == size)

            for h,v in hashes.items():
                # Select subset that matches given hash.
                sub = session.query(IndexRecordUrl)
                sub = sub.join(IndexRecordUrl.index_record).join(IndexRecord.hashes)
                sub = sub.filter(and_(
                    IndexRecordHash.hash_type == h,
                    IndexRecordHash.hash_value == v,
                ))

                # Filter anything that does not match.
                query = query.intersect(sub)

            # Remove duplicates.
            query = query.distinct()

            # Return only specified window.
            query = query.offset(start)
            query = query.limit(limit)

            return [r.url for r in query]

    def add(self, form, size=None, urls=[], hashes={}):
        '''
        Creates a new record given urls and hashes.
        '''
        if form not in index.FORMS:
            raise ValueError('form must be one of: %s' % index.FORMS)

        if size is not None and size < 0:
            raise ValueError('size must be non-negative')

        with self.session as session:
            record = IndexRecord()

            record.did = str(uuid.uuid4())
            record.rev = str(uuid.uuid4())[:8]

            record.form = form
            record.size = size

            record.urls = [IndexRecordUrl(
                did=record,
                url=url,
            ) for url in urls]

            record.hashes = [IndexRecordHash(
                did=record,
                hash_type=h,
                hash_value=v,
            ) for h,v in hashes.items()]

            session.add(record)

            return record.did, record.rev

    def get(self, did):
        '''
        Gets a record given the record id.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == did)

            try: record = query.one()
            except NoResultFound as err:
                raise NoRecordFound('no record found')
            except MultipleResultsFound as err:
                raise MultipleRecordsFound('multiple records found')

            rev = record.rev

            form = record.form
            size = record.size

            urls = [u.url for u in record.urls]
            hashes = {h.hash_type: h.hash_value for h in record.hashes}

        ret = {
            'did': did,
            'rev': rev,
            'size': size,
            'urls': urls,
            'hashes': hashes,
            'form': form,
        }

        return ret

    def update(self, did, rev, size=None, urls=None, hashes=None):
        '''
        Updates an existing record with new values.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == did)

            try: record = query.one()
            except NoResultFound as err:
                raise NoRecordFound('no record found')
            except MultipleResultsFound as err:
                raise MultipleRecordsFound('multiple records found')

            if rev != record.rev:
                raise RevisionMismatch('revision mismatch')

            if size is not None:
                record.size = size

            if urls is not None:
                record.urls = [IndexRecordUrl(
                    did=record,
                    url=url
                ) for url in urls]

            if hashes is not None:
                record.hashes = [IndexRecordHash(
                    did=record,
                    hash_type=h,
                    hash_value=v,
                ) for h,v in hashes.items()]

            record.rev = str(uuid.uuid4())[:8]

            session.add(record)

            return record.did, record.rev

    def delete(self, did, rev):
        '''
        Removes record if stored by backend.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == did)

            try: record = query.one()
            except NoResultFound as err:
                raise NoRecordFound('no record found')
            except MultipleResultsFound as err:
                raise MultipleRecordsFound('multiple records found')

            if rev != record.rev:
                raise RevisionMismatch('revision mismatch')

            session.delete(record)

    def __contains__(self, record):
        '''
        Returns True if record is stored by backend.
        Returns False otherwise.
        '''
        with self.session as session:
            query = session.query(IndexRecord)
            query = query.filter(IndexRecord.did == record)

            return query.exists()

    def __iter__(self):
        '''
        Iterator over unique records stored by backend.
        '''
        with self.session as session:
            for i in session.query(IndexRecord):
                yield i.did

    def __len__(self):
        '''
        Number of unique records stored by backend.
        '''
        with self.session as session:
            return session.query(IndexRecord).count()
<|endoftext|>