From 6692f41081fd26156d9df8f62be440651ed3609c Mon Sep 17 00:00:00 2001 From: Pavel Kitaiharodski Date: Tue, 21 May 2019 18:13:05 +0300 Subject: [PATCH 1/5] Working version of the project --- final_task/__init__.py | 0 final_task/setup.py | 9 + final_task/src/pycalc.py | 361 +++++++++++++++++++++++++++++++++ final_task/src/pycalc_tests.py | 171 ++++++++++++++++ 4 files changed, 541 insertions(+) delete mode 100644 final_task/__init__.py create mode 100644 final_task/src/pycalc.py create mode 100644 final_task/src/pycalc_tests.py diff --git a/final_task/__init__.py b/final_task/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/final_task/setup.py b/final_task/setup.py index e69de29b..f4eea10b 100644 --- a/final_task/setup.py +++ b/final_task/setup.py @@ -0,0 +1,9 @@ +from setuptools import setup, find_packages +setup( + name="pycalc", + packages=find_packages(), + version = "1.0.0", + entry_points = { + 'console_scripts':['pycalc = src.pycalc:main'] + } +) \ No newline at end of file diff --git a/final_task/src/pycalc.py b/final_task/src/pycalc.py new file mode 100644 index 00000000..b0fbd140 --- /dev/null +++ b/final_task/src/pycalc.py @@ -0,0 +1,361 @@ +import argparse +import os +import math +import sys + + +def chek_minus(list_of_elements): + """Checks the list of elements + and remove the extra plus and minus + """ + index = 0 + letters = set('qwertyuiopasdfghjklzxcvbnm') + previously = '' + while index < len(list_of_elements): + element = list_of_elements[index] + temp = str(element) + if element is "+" or element is "-": + if previously is "+" or previously is "-": + if previously is "+" and previously == element: + list_of_elements.pop(index) + elif previously is "-" and previously == element: + list_of_elements.pop(index) + list_of_elements.pop(index-1) + list_of_elements.insert(index-1, "+") + elif previously != element: + list_of_elements.pop(index) + list_of_elements.pop(index-1) + list_of_elements.insert(index-1, "-") + index -= 1 + previously = list_of_elements[index] + else: + previously = element + elif not letters.isdisjoint(temp) and previously is "-": + list_of_elements[index - 1] = -1 + list_of_elements.insert(index, '*') + index += 1 + else: + previously = "" + index += 1 + index = 0 + last_two = ["", ""] + while index < len(list_of_elements): + element = list_of_elements[index] + temp = str(element) + temp = temp.replace('-', '', 1) + if temp.replace('.', '', 1).isdigit(): + if last_two[1] is "+" or last_two[1] is "-": + temp = str(last_two[0]) + temp = temp.replace('-', '', 1).replace('.', '', 1) + if temp is '' or (temp.isdigit() is False and temp != ')'): + if last_two[1] is "-": + list_of_elements[index] = element*(-1) + list_of_elements.pop(index-1) + index -= 1 + if len(list_of_elements) > 1: + last_two[0] = last_two[1] + last_two[1] = list_of_elements[index] + index += 1 + return list_of_elements + + +def write_in_not(list_of_elements): + """writes the elements of the list in reverse Polish notation + required for the calculation by the function calculate() + """ + precedence = { + '+': 2, + '-': 2, + '*': 3, + '//': 3, + '/': 3, + '^': 4, + '%': 3, + '(': 0, + ')': 0 + } + comparison_operations = set('<=>!') + output = [] + stack = [] + list_of_elements = chek_minus(list_of_elements) + index = 0 + while index < len(list_of_elements): + element = list_of_elements[index] + temp = str(element) + temp = temp.replace('-', '', 1) + if element is '(': + stack.insert(0, element) + elif temp.replace('.', '', 1).isdigit(): + output.append(element) + elif not comparison_operations.isdisjoint(temp): + for operation in stack: + output.append(operation) + result = calculate(output) + stack.clear() + output.clear() + output.append(result) + new_list = list(list_of_elements[index+1:]) + notation2 = write_in_not(new_list) + result2 = calculate(notation2) + output.append(result2) + output.append(element) + index = len(list_of_elements) + elif element is ')'and len(stack) > 0: + while stack[0] != '(': + output.append(stack.pop(0)) + stack.pop(0) + elif element in precedence.keys(): + if len(stack) > 0 and precedence[element] == precedence[stack[0]]\ + and element != "^": + output.append(stack.pop(0)) + stack.insert(0, element) + elif len(stack) > 0 and precedence[element] < precedence[stack[0]]: + while len(stack) > 0 and\ + precedence[element] <= precedence[stack[0]]: + output.append(stack.pop(0)) + stack.insert(0, element) + else: + stack.insert(0, element) + else: + function = element + brackets = 1 + temp = "" + args = [] + index += 2 + while brackets != 0 and index < len(list_of_elements): + element = list_of_elements[index] + if element is ',' and brackets == 1: + args.append(testing(temp)) + temp = '' + elif element is ')' and brackets == 1: + args.append(testing(temp)) + temp = '' + brackets -= 1 + elif element is ')' and brackets != 1: + temp += str(element) + brackets -= 1 + elif element is '(': + brackets += 1 + temp += str(element) + else: + temp += str(element) + index += 1 + '#unpack all elements from list and ' + '# transferring them to the function' + if function != "abs" and function != "round": + function = getattr(math, function) + try: + result = function(*args) + except TypeError: + print("ERROR: invalid number or parameter types") + sys.exit(1) + elif function == "abs": + result = abs(*args) + else: + result = round(*args) + output.append(result) + '#because the current index points to the item' + '#after the closing parenthesis' + index -= 1 + index += 1 + for element in stack: + output.append(element) + return output + + +def tokenize(entered_string): + """Breaks a string into elements + """ + entered_string += " " + '#some problems with index out of range without it' + letters = set('qwertyuiopasdfghjklzxcvbnm') + list_of_elements = [] + single_character_operations = set('+-*%^,') + comparison_operations = set('<=>!') + numbers = set('.0123456789') + token = '' + number_of_brackets = 0 + for element in entered_string: + if element is '(': + number_of_brackets += 1 + elif element is ')': + number_of_brackets -= 1 + if number_of_brackets != 0: + print("ERROR: the number of opening and closing brackets must match") + sys.exit(1) + index = 0 + while index < len(entered_string): + element = entered_string[index] + if element in single_character_operations: + list_of_elements.append(element) + elif element in comparison_operations: + if entered_string[index + 1] not in comparison_operations: + list_of_elements.append(element) + else: + token = element + entered_string[index + 1] + list_of_elements.append(token) + index += 1 + token = '' + elif element in numbers: + token += element + while index+1 <= len(entered_string)-1 and \ + entered_string[index+1] in numbers: + token += entered_string[index+1] + if index != len(entered_string)-1: + index += 1 + else: + break + try: + if '.' not in token: + list_of_elements.append(int(token)) + else: + list_of_elements.append(float(token)) + token = '' + except ValueError: + print("ERROR: incomprehensible variable") + sys.exit(1) + elif element in letters: + token += element + index += 1 + element = entered_string[index] + while len(entered_string) > index + 1 and element in letters: + token += element + index += 1 + element = entered_string[index] + index -= 1 + if token == 'log' and element in numbers: + index += 1 + while len(entered_string) > index + 1 and element in numbers: + token += element + index += 1 + element = entered_string[index] + index -= 1 + if token != "log" and element is not '(': + try: + math_constant = getattr(math, token) + list_of_elements.append(math_constant) + token = '' + except AttributeError: + print("ERROR: unknown value " + token) + sys.exit(1) + elif token == "abs" or token == "round": + list_of_elements.append(token) + else: + try: + getattr(math, token) + list_of_elements.append(token) + except AttributeError: + print("ERROR: unknown function " + token) + sys.exit(1) + token = '' + elif element == '/': + if entered_string[index + 1] != '/': + list_of_elements.append(element) + else: + list_of_elements.append('//') + index += 1 + elif element in "()": + list_of_elements.append(element) + index += 1 + return list_of_elements + + +def get_function(str_function): + """Accepts the symbolic expression of the operation + and returns the operation itself + """ + dictionary = { + '+': lambda a, b: a + b, + '-': lambda a, b: a - b, + '*': lambda a, b: a * b, + '%': lambda a, b: a % b, + '/': lambda a, b: a / b, + '//': lambda a, b: a // b, + '^': lambda a, b: a ** b, + '>': lambda a, b: a > b, + '<': lambda a, b: a < b, + '!=': lambda a, b: a != b, + '==': lambda a, b: a == b, + '<=': lambda a, b: a <= b, + '>=': lambda a, b: a >= b + } + if str_function in dictionary.keys(): + return dictionary[str_function] + else: + try: + return getattr(str_function, math) + except: + print("ERROR: Please, check your expression") + sys.exit(1) + + +def calculate(notation): + """Calculates elements written in the form + of inverse Polish notation. + """ + index = 2 + while len(notation) > 1: + try: + temp = str(notation[index]) + except IndexError: + print("ERROR: not enough variables") + sys.exit(1) + temp = temp.replace('-', '', 1) + result = 0 + if not temp.replace('.', '', 1).isdigit(): + func = notation.pop(index) + function = get_function(func) + try: + a = notation.pop(index-2) + b = notation.pop(index-2) + result = function(a, b) + except TypeError: + print("ERROR: for selected elements operation " + + func + " doesn't work") + sys.exit(1) + notation.insert(index-2, result) + index = 2 + else: + index += 1 + try: + result = notation.pop(0) + temp = str(result).replace('-', '', 1).replace('.', '', 1) + if not temp.isdigit or temp in '+-': + print("ERROR: this is not an expression") + sys.exit(1) + return result + except IndexError: + print("ERROR: no expression") + sys.exit(1) + + +def testing(entered_string): + """A function that takes an expression as a string + and returns a result. Not to be confused with main + """ + list_of_elements = tokenize(entered_string) + notation = write_in_not(list_of_elements) + result = calculate(notation) + return result + + +def main(): + """Parser get string expression, tokenize() breaks a string into elements, + write_in_not writes() them in reverse Polish notation + and calculate() calculates the result. + """ + parser = argparse.ArgumentParser( + description='Pure-python command-line calculator.') + parser.add_argument('EXPRESSION', type=str, + help='expression string to evaluate') + args = parser.parse_args() + entered_string = args.EXPRESSION + list_of_elements = tokenize(entered_string) + notation = write_in_not(list_of_elements) + result = calculate(notation) + print(result) + return result + + +if __name__ == '__main__': + main() diff --git a/final_task/src/pycalc_tests.py b/final_task/src/pycalc_tests.py new file mode 100644 index 00000000..164fe589 --- /dev/null +++ b/final_task/src/pycalc_tests.py @@ -0,0 +1,171 @@ +import unittest +from pycalc import testing +import math +import sys + + +class TestUnaryOperators(unittest.TestCase): + + def test_minus(self): + self.assertEqual(testing("-33"), -33) + + def test_minus_with_brackets(self): + self.assertEqual(testing("6-((-13))"), 19) + + def test_four_minus(self): + self.assertEqual(testing("-1---1"), -2) + + def test_plus_minus(self): + self.assertEqual(testing("-+--1"), -1) + + +class TestOperationPriority(unittest.TestCase): + + def test_plus_multiply(self): + self.assertEqual(testing("2*3-4/5"), 2*3-4/5) + + def test_brackets_plus_multiply(self): + self.assertEqual(testing("1+(2+3*2)*3"), 25) + self.assertEqual(testing("10*(2+1)"), 30) + def test_power(self): + self.assertEqual(testing("10^(2+1)"), 1000) + + def test_division(self): + self.assertEqual(testing("100/3^2"), 100/3**2) + + +class TestFunctionsConstants(unittest.TestCase): + + def test_constants(self): + self.assertEqual(testing("pi+e"), math.pi + math.e) + + def test_log(self): + self.assertEqual(testing("log(e)"), math.log(math.e)) + + def test_sin(self): + self.assertEqual(testing("sin(pi/2)"), math.sin(math.pi/2)) + + def test_common(self): + self.assertEqual(testing("sin(pi/2)*111*6"), math.sin( math.pi/2)*111*6) + + def test_abs(self): + self.assertEqual(testing("abs(-5)"), abs(-5)) + + def test_round(self): + self.assertEqual(testing("round(123.456789)"), round(123.456789)) + + +class TestAssociative(unittest.TestCase): + + def test_modulo(self): + self.assertEqual(testing("102%12%7"), 102%12%7) + + def test_division(self): + self.assertEqual(testing("100/4/3"), 100/4/3) + + def test_power(self): + self.assertEqual(testing("2^3^4"), 2**3**4) + +class TestComparisonOperators(unittest.TestCase): + + + + def test_equally(self): + self.assertEqual(testing("1+2*3==1+2*3"), 1+2*3==1+2*3) + + def test_more_or_equal(self): + self.assertEqual(testing("e^5>=e^5+1"), pow(math.e, 5)>= pow(math.e, 5)+1) + + def test_not_equal(self): + self.assertEqual(testing("1+2*4/3+1!=1+2*4/3+2"), 1+2*4/3+1!=1+2*4/3+2) + +class TestCommon(unittest.TestCase): + + def test_number_with_brackets(self): + self.assertEqual(testing("(100)"), 100) + + def test_number(self): + self.assertEqual(testing("666"), 666) + + def test_number_with_floating_point(self): + self.assertEqual(testing("-.1"), -0.1) + + def test_division(self): + self.assertEqual(testing("1.0/3.0"), 1.0/3.0) + self.assertEqual(testing("1/3"), 1/3) + + def test_power_and_multiply(self): + self.assertEqual(testing(".1 * 2.0^56.0"), 0.1*pow(2.0, 56.0)) + + def test_power_exp(self): + self.assertEqual(testing("e^34"), pow(math.e, 34)) + + def test_expressions(self): + self.assertEqual(testing("(2.0^(pi/pi+e/e+2.0^0.0))"), + pow(2, 3)) + self.assertEqual(testing("(2.0^(pi/pi+e/e+2.0^0.0))^(1.0/3.0)"), 2.0) + self.assertEqual(testing("sin(pi/2^1) + log(1*4+2^2+1, 3^2)") , math.sin(math.pi/2**1) + math.log(1*4+2**2+1, 3**2)) + self.assertEqual(testing("10*e^0*log10(.4 -5/ -0.1-10) - -abs(-53/10) + -5") + , 10*pow(math.e, 0)*math.log10(.4 -5/ -0.1-10) - -abs(-53/10) + -5) + def test_function_in_function(self): + self.assertEqual(testing("sin(-cos(-sin(3.0)-cos(-sin(-3.0*5.0)-sin(cos(log10(43.0))))+cos(sin(sin(34.0-2.0^2.0))))--cos(1.0)--cos(0.0)^3.0)"), + math.sin(- math.cos(- math.sin(3.0)- math.cos(- math.sin(-3.0*5.0)- math.sin( math.cos( math.log10(43.0))))+ math.cos( math.sin( math.sin(34.0-2.0**2.0))))-- math.cos(1.0)-- math.cos(0.0)**3.0)) + def test_power(self): + self.assertEqual(testing("2.0^(2.0^2.0*2.0^2.0)"), pow(2, 16)) + + + +class TestErrorCases(unittest.TestCase): + def test_ee(self): + with self.assertRaises(SystemExit): + testing("abcd") + def test_multiply(self): + with self.assertRaises(SystemExit): + testing("6 * * 6") + def test_comparisaon(self): + with self.assertRaises(SystemExit): + testing("6 < = 6") + def test_division(self): + with self.assertRaises(SystemExit): + testing("5 / / 6") + + def test_only_plus(self): + with self.assertRaises(SystemExit): + testing("+") + + def test_not_enough_operands(self): + with self.assertRaises(SystemExit): + testing("1-") + + def test_no_operations(self): + with self.assertRaises(SystemExit): + testing("1 2") + + def test_comparison_error(self): + with self.assertRaises(SystemExit): + testing("==7") + + def test_missed_brackets(self): + with self.assertRaises(SystemExit): + testing("1 + 2(3*4))") + with self.assertRaises(SystemExit): + testing("((1+2)") + with self.assertRaises(SystemExit): + testing("))))") + with self.assertRaises(SystemExit): + testing(")1+1(") + + def test_not_enough_operations(self): + with self.assertRaises(SystemExit): + testing("1 + 1 2 3 4 5 6 ") + + def test_missed_operands(self): + with self.assertRaises(SystemExit): + testing("------") + + def test_too_many_arguments(self): + with self.assertRaises(SystemExit): + testing("pow(2, 3, 4)") + +if __name__ == '__main__': + unittest.main() \ No newline at end of file From a2b779ad3e6df4c1f1c110243e615a346e060d63 Mon Sep 17 00:00:00 2001 From: Pavel Kitaiharodski Date: Tue, 21 May 2019 18:52:06 +0300 Subject: [PATCH 2/5] trying to run travis --- final_task/{src => }/pycalc.py | 0 final_task/setup.py | 5 +- final_task/src/pycalc_tests.py | 171 --------------------------------- 3 files changed, 1 insertion(+), 175 deletions(-) rename final_task/{src => }/pycalc.py (100%) delete mode 100644 final_task/src/pycalc_tests.py diff --git a/final_task/src/pycalc.py b/final_task/pycalc.py similarity index 100% rename from final_task/src/pycalc.py rename to final_task/pycalc.py diff --git a/final_task/setup.py b/final_task/setup.py index f4eea10b..95cd95e6 100644 --- a/final_task/setup.py +++ b/final_task/setup.py @@ -2,8 +2,5 @@ setup( name="pycalc", packages=find_packages(), - version = "1.0.0", - entry_points = { - 'console_scripts':['pycalc = src.pycalc:main'] - } + version = "1.0.0" ) \ No newline at end of file diff --git a/final_task/src/pycalc_tests.py b/final_task/src/pycalc_tests.py deleted file mode 100644 index 164fe589..00000000 --- a/final_task/src/pycalc_tests.py +++ /dev/null @@ -1,171 +0,0 @@ -import unittest -from pycalc import testing -import math -import sys - - -class TestUnaryOperators(unittest.TestCase): - - def test_minus(self): - self.assertEqual(testing("-33"), -33) - - def test_minus_with_brackets(self): - self.assertEqual(testing("6-((-13))"), 19) - - def test_four_minus(self): - self.assertEqual(testing("-1---1"), -2) - - def test_plus_minus(self): - self.assertEqual(testing("-+--1"), -1) - - -class TestOperationPriority(unittest.TestCase): - - def test_plus_multiply(self): - self.assertEqual(testing("2*3-4/5"), 2*3-4/5) - - def test_brackets_plus_multiply(self): - self.assertEqual(testing("1+(2+3*2)*3"), 25) - self.assertEqual(testing("10*(2+1)"), 30) - def test_power(self): - self.assertEqual(testing("10^(2+1)"), 1000) - - def test_division(self): - self.assertEqual(testing("100/3^2"), 100/3**2) - - -class TestFunctionsConstants(unittest.TestCase): - - def test_constants(self): - self.assertEqual(testing("pi+e"), math.pi + math.e) - - def test_log(self): - self.assertEqual(testing("log(e)"), math.log(math.e)) - - def test_sin(self): - self.assertEqual(testing("sin(pi/2)"), math.sin(math.pi/2)) - - def test_common(self): - self.assertEqual(testing("sin(pi/2)*111*6"), math.sin( math.pi/2)*111*6) - - def test_abs(self): - self.assertEqual(testing("abs(-5)"), abs(-5)) - - def test_round(self): - self.assertEqual(testing("round(123.456789)"), round(123.456789)) - - -class TestAssociative(unittest.TestCase): - - def test_modulo(self): - self.assertEqual(testing("102%12%7"), 102%12%7) - - def test_division(self): - self.assertEqual(testing("100/4/3"), 100/4/3) - - def test_power(self): - self.assertEqual(testing("2^3^4"), 2**3**4) - -class TestComparisonOperators(unittest.TestCase): - - - - def test_equally(self): - self.assertEqual(testing("1+2*3==1+2*3"), 1+2*3==1+2*3) - - def test_more_or_equal(self): - self.assertEqual(testing("e^5>=e^5+1"), pow(math.e, 5)>= pow(math.e, 5)+1) - - def test_not_equal(self): - self.assertEqual(testing("1+2*4/3+1!=1+2*4/3+2"), 1+2*4/3+1!=1+2*4/3+2) - -class TestCommon(unittest.TestCase): - - def test_number_with_brackets(self): - self.assertEqual(testing("(100)"), 100) - - def test_number(self): - self.assertEqual(testing("666"), 666) - - def test_number_with_floating_point(self): - self.assertEqual(testing("-.1"), -0.1) - - def test_division(self): - self.assertEqual(testing("1.0/3.0"), 1.0/3.0) - self.assertEqual(testing("1/3"), 1/3) - - def test_power_and_multiply(self): - self.assertEqual(testing(".1 * 2.0^56.0"), 0.1*pow(2.0, 56.0)) - - def test_power_exp(self): - self.assertEqual(testing("e^34"), pow(math.e, 34)) - - def test_expressions(self): - self.assertEqual(testing("(2.0^(pi/pi+e/e+2.0^0.0))"), - pow(2, 3)) - self.assertEqual(testing("(2.0^(pi/pi+e/e+2.0^0.0))^(1.0/3.0)"), 2.0) - self.assertEqual(testing("sin(pi/2^1) + log(1*4+2^2+1, 3^2)") , math.sin(math.pi/2**1) + math.log(1*4+2**2+1, 3**2)) - self.assertEqual(testing("10*e^0*log10(.4 -5/ -0.1-10) - -abs(-53/10) + -5") - , 10*pow(math.e, 0)*math.log10(.4 -5/ -0.1-10) - -abs(-53/10) + -5) - def test_function_in_function(self): - self.assertEqual(testing("sin(-cos(-sin(3.0)-cos(-sin(-3.0*5.0)-sin(cos(log10(43.0))))+cos(sin(sin(34.0-2.0^2.0))))--cos(1.0)--cos(0.0)^3.0)"), - math.sin(- math.cos(- math.sin(3.0)- math.cos(- math.sin(-3.0*5.0)- math.sin( math.cos( math.log10(43.0))))+ math.cos( math.sin( math.sin(34.0-2.0**2.0))))-- math.cos(1.0)-- math.cos(0.0)**3.0)) - def test_power(self): - self.assertEqual(testing("2.0^(2.0^2.0*2.0^2.0)"), pow(2, 16)) - - - -class TestErrorCases(unittest.TestCase): - def test_ee(self): - with self.assertRaises(SystemExit): - testing("abcd") - def test_multiply(self): - with self.assertRaises(SystemExit): - testing("6 * * 6") - def test_comparisaon(self): - with self.assertRaises(SystemExit): - testing("6 < = 6") - def test_division(self): - with self.assertRaises(SystemExit): - testing("5 / / 6") - - def test_only_plus(self): - with self.assertRaises(SystemExit): - testing("+") - - def test_not_enough_operands(self): - with self.assertRaises(SystemExit): - testing("1-") - - def test_no_operations(self): - with self.assertRaises(SystemExit): - testing("1 2") - - def test_comparison_error(self): - with self.assertRaises(SystemExit): - testing("==7") - - def test_missed_brackets(self): - with self.assertRaises(SystemExit): - testing("1 + 2(3*4))") - with self.assertRaises(SystemExit): - testing("((1+2)") - with self.assertRaises(SystemExit): - testing("))))") - with self.assertRaises(SystemExit): - testing(")1+1(") - - def test_not_enough_operations(self): - with self.assertRaises(SystemExit): - testing("1 + 1 2 3 4 5 6 ") - - def test_missed_operands(self): - with self.assertRaises(SystemExit): - testing("------") - - def test_too_many_arguments(self): - with self.assertRaises(SystemExit): - testing("pow(2, 3, 4)") - -if __name__ == '__main__': - unittest.main() \ No newline at end of file From 6bb71f40d43d1931feb55b878f4b48a5f96e7ed4 Mon Sep 17 00:00:00 2001 From: Pavel Kitaiharodski Date: Tue, 21 May 2019 22:37:05 +0300 Subject: [PATCH 3/5] I don't know, maybe it should be here --- final_task/__init__.py | 0 final_task/pycalc-1.0.0.tar.gz | Bin 0 -> 2081 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 final_task/__init__.py create mode 100644 final_task/pycalc-1.0.0.tar.gz diff --git a/final_task/__init__.py b/final_task/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/final_task/pycalc-1.0.0.tar.gz b/final_task/pycalc-1.0.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..00d8b82a856995a249cf1eb8deae2a2e9cf5390f GIT binary patch literal 2081 zcmV++2;TP}iwFo#9^_mC|72-%bX;(GV_|G#Eio=IE-)^1VR8WNT5V6`ND}6Ar2L0E z*cBmz^Ws1>`vUmcKf>9K=#*PRoe~;gqfRL$m(=mBRRO; zUENjnJXP)Xqrk}G#c4ol*hmJ@BUzK)bI62eIMKVBpa~5u?8u$ zVG7_yj9fJCe?;=d_@Dp$7w_cs!`Umue>faI8-IT^d=!7*?+-Sh=i>kB@`)Q3F~hvS zaixXK4gjIhY@D)`A3zC?W@GUgJ-sZ_l&RSPd_Mj8^z84a&BkA4%DtRT`9j;f!o*TN zY4CW;M6%HQQG`6xizAP?4wcA_opauLo-i|!DqU#WaPpG;zc_w(^y#>hMr-B&a4;NL z{`Urhy}f}?{NL-19RJrLTW~%@R%URnW^fmaFvjsA7q?tP z%1n$|#|T_Qv%&9k#Wf`~&_>Zhm?w{VXq=#4t`vqBMw_E=Hn?6RX(m7Tvyx|yZ z0(B-0j2TWJ@`wz47&s}i@L^Dq-DL7E18TJkt)Ewp*&-Y-zz$^2l{HB(ga%SfKcI^| zm&!C7ZFr~97$lkqp%uIdb|LWS(xyw-UhMTpy8IgKV5eUL5V&;6!0lP&*e2JNBA% zPec5}Fk;O_$rR}Ch^eU7n98U~I0Qt-09uHusmv&;sM#(ga>}gfdKb6}J3F1)iKiIY zdY&gap$*70K?J8XCDn{zS|A<+1UdRZ^Prlya!ka>1Xt^JOdp}Vit;uL@ruApNW-(d47*9re&3rXj%*MJr-j@IippXK6gbT5Nx=@M4{QOdjic(ksB!!T_WO_m}acHRO*n*h-`TO@noI=GTd4sluB9!^L0^d zw3$&BXv2{V%d}IH@*%vq{{x1|L)gSJLa>Ah)0*QS%UG;@Fpqi}@lYyEN4d;w&B}TH z7Frf9xR`qSV7^eAOY>yng)t9rC|m$-pz0T5wLt5^CfbB&Q$kNpI`Q=d^ei2tQy%Ks zS-ujyzr-BpUTC9;QT|yrcV1d;_Si+H8kkj!nBpQ*Nwrwoa%KA)J98T@%d|pR`6^K< zQP-HMidDskz)J%_m4WA>o4l%1uv}=Qwa$9SBA~pl0l>nL=LP{vVb_RGT+QNyWu>Md zQ%@`vSO?%%FjDvBF@35OqB&DID91#iuUfG&xjyK2Bg9On9MO?#+8uOFfld@G>DFk7 zO`2@s?3E>6smLQmWq3b)%}?k81rb)CjL!iEF}vjui)oC{u%_XBh#c`y70GN;G)Y8g z$Z|5Lm`qBQRWhvXLQl`r@H}ERm;fhKP=zk_*5r9wRKK;=0C=d008h3X0AJm3;C%|8 z&W=8RJccjTZ>Q6_x+>TBpYBBfp52Z7*ZUEuaJNFE7w=XEE^0)V-IXr2PY|3ovDUka zYUoOHN!e&E-<&qpFOVpQ<+H<2pwX))88q z(tGtPV*!tN!7EV^-!5p6mxXc1Dt0gZ&%OVbHyu8mVhWnb?hC&Ef8Y7# z_`lG3@b{np?)Qg1cmCtff8F`-AIksBv(Fdrk1sps-n=UR`~GA8j|TgW|Lc(Xk$=O! z&f{LP@mv*Xd<7m)o<%(8S;Vt&c8#w9H+p3!BlGKo-}2=5BFxFF@PAbhUxELEdO69KYus>`@{W_`~K_r?_|CFFSmfhW!P zjED(k)8cKj+1POmbmGK`6DLlbIC0{{i4!MIoH%jf#EBCpPMkP#;>3v)Cr+F=`F-+l L&QBHm08jt`r3NKu literal 0 HcmV?d00001 From 525e92b4805b82830959f1334dd901fe26c5b9c8 Mon Sep 17 00:00:00 2001 From: Pavel Kitaiharodski Date: Wed, 22 May 2019 11:22:25 +0300 Subject: [PATCH 4/5] Following PEP8 --- final_task/pycalc-1.0.0.tar.gz | Bin 2081 -> 4840 bytes final_task/setup.py | 10 +++++++--- final_task/{ => src}/pycalc.py | 5 ++++- pycalc-1.0.0.tar.gz | Bin 0 -> 2081 bytes 4 files changed, 11 insertions(+), 4 deletions(-) rename final_task/{ => src}/pycalc.py (98%) create mode 100644 pycalc-1.0.0.tar.gz diff --git a/final_task/pycalc-1.0.0.tar.gz b/final_task/pycalc-1.0.0.tar.gz index 00d8b82a856995a249cf1eb8deae2a2e9cf5390f..c919bd3132637142d31c785bdecd7eeb27939658 100644 GIT binary patch literal 4840 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 L&QBHm08jt`r3NKu diff --git a/final_task/setup.py b/final_task/setup.py index 95cd95e6..b09d2364 100644 --- a/final_task/setup.py +++ b/final_task/setup.py @@ -1,6 +1,10 @@ from setuptools import setup, find_packages + setup( name="pycalc", - packages=find_packages(), - version = "1.0.0" -) \ No newline at end of file + version="1.0.0", + description="Pure-python command calculator", + packages=["src"], + entry_points={ + "console_scripts": ["pycalc=src.pycalc:main"]} +) diff --git a/final_task/pycalc.py b/final_task/src/pycalc.py similarity index 98% rename from final_task/pycalc.py rename to final_task/src/pycalc.py index b0fbd140..5ea91888 100644 --- a/final_task/pycalc.py +++ b/final_task/src/pycalc.py @@ -284,7 +284,10 @@ def get_function(str_function): else: try: return getattr(str_function, math) - except: + except AttributeError: + print("ERROR: Please, check your expression") + sys.exit(1) + except TypeError: print("ERROR: Please, check your expression") sys.exit(1) diff --git a/pycalc-1.0.0.tar.gz b/pycalc-1.0.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..00d8b82a856995a249cf1eb8deae2a2e9cf5390f GIT binary patch literal 2081 zcmV++2;TP}iwFo#9^_mC|72-%bX;(GV_|G#Eio=IE-)^1VR8WNT5V6`ND}6Ar2L0E z*cBmz^Ws1>`vUmcKf>9K=#*PRoe~;gqfRL$m(=mBRRO; zUENjnJXP)Xqrk}G#c4ol*hmJ@BUzK)bI62eIMKVBpa~5u?8u$ zVG7_yj9fJCe?;=d_@Dp$7w_cs!`Umue>faI8-IT^d=!7*?+-Sh=i>kB@`)Q3F~hvS zaixXK4gjIhY@D)`A3zC?W@GUgJ-sZ_l&RSPd_Mj8^z84a&BkA4%DtRT`9j;f!o*TN zY4CW;M6%HQQG`6xizAP?4wcA_opauLo-i|!DqU#WaPpG;zc_w(^y#>hMr-B&a4;NL z{`Urhy}f}?{NL-19RJrLTW~%@R%URnW^fmaFvjsA7q?tP z%1n$|#|T_Qv%&9k#Wf`~&_>Zhm?w{VXq=#4t`vqBMw_E=Hn?6RX(m7Tvyx|yZ z0(B-0j2TWJ@`wz47&s}i@L^Dq-DL7E18TJkt)Ewp*&-Y-zz$^2l{HB(ga%SfKcI^| zm&!C7ZFr~97$lkqp%uIdb|LWS(xyw-UhMTpy8IgKV5eUL5V&;6!0lP&*e2JNBA% zPec5}Fk;O_$rR}Ch^eU7n98U~I0Qt-09uHusmv&;sM#(ga>}gfdKb6}J3F1)iKiIY zdY&gap$*70K?J8XCDn{zS|A<+1UdRZ^Prlya!ka>1Xt^JOdp}Vit;uL@ruApNW-(d47*9re&3rXj%*MJr-j@IippXK6gbT5Nx=@M4{QOdjic(ksB!!T_WO_m}acHRO*n*h-`TO@noI=GTd4sluB9!^L0^d zw3$&BXv2{V%d}IH@*%vq{{x1|L)gSJLa>Ah)0*QS%UG;@Fpqi}@lYyEN4d;w&B}TH z7Frf9xR`qSV7^eAOY>yng)t9rC|m$-pz0T5wLt5^CfbB&Q$kNpI`Q=d^ei2tQy%Ks zS-ujyzr-BpUTC9;QT|yrcV1d;_Si+H8kkj!nBpQ*Nwrwoa%KA)J98T@%d|pR`6^K< zQP-HMidDskz)J%_m4WA>o4l%1uv}=Qwa$9SBA~pl0l>nL=LP{vVb_RGT+QNyWu>Md zQ%@`vSO?%%FjDvBF@35OqB&DID91#iuUfG&xjyK2Bg9On9MO?#+8uOFfld@G>DFk7 zO`2@s?3E>6smLQmWq3b)%}?k81rb)CjL!iEF}vjui)oC{u%_XBh#c`y70GN;G)Y8g z$Z|5Lm`qBQRWhvXLQl`r@H}ERm;fhKP=zk_*5r9wRKK;=0C=d008h3X0AJm3;C%|8 z&W=8RJccjTZ>Q6_x+>TBpYBBfp52Z7*ZUEuaJNFE7w=XEE^0)V-IXr2PY|3ovDUka zYUoOHN!e&E-<&qpFOVpQ<+H<2pwX))88q z(tGtPV*!tN!7EV^-!5p6mxXc1Dt0gZ&%OVbHyu8mVhWnb?hC&Ef8Y7# z_`lG3@b{np?)Qg1cmCtff8F`-AIksBv(Fdrk1sps-n=UR`~GA8j|TgW|Lc(Xk$=O! z&f{LP@mv*Xd<7m)o<%(8S;Vt&c8#w9H+p3!BlGKo-}2=5BFxFF@PAbhUxELEdO69KYus>`@{W_`~K_r?_|CFFSmfhW!P zjED(k)8cKj+1POmbmGK`6DLlbIC0{{i4!MIoH%jf#EBCpPMkP#;>3v)Cr+F=`F-+l L&QBHm08jt`r3NKu literal 0 HcmV?d00001 From 15f191846e789017665447c8405c530c1cd3256f Mon Sep 17 00:00:00 2001 From: Pavel Kitaiharodski Date: Thu, 23 May 2019 18:09:26 +0300 Subject: [PATCH 5/5] multiple comparison error resolved --- final_task/pycalc-1.0.0.tar.gz | Bin 4840 -> 4949 bytes final_task/src/pycalc.py | 16 ++++++++++++++++ pycalc-1.0.0.tar.gz | Bin 2081 -> 4949 bytes 3 files changed, 16 insertions(+) diff --git a/final_task/pycalc-1.0.0.tar.gz b/final_task/pycalc-1.0.0.tar.gz index c919bd3132637142d31c785bdecd7eeb27939658..722947dfeccfb3963777d563da2bea956ef00777 100644 GIT binary patch literal 4949 zcmV-b6RPYViwFpBx8_^||72-%bX;(GV_|G#Eio=IE-)^1VR8WN9cy#jxG|qKS)%+%HCATQB-du{F7YIHeT?f!6a`7FDUu~f+q#?n_wEAV8`Q%WJAH^ZCrfxN zb{G2sutfZoWjdDL>vTKa<7bcabm2KaKj(kpDgNc(d;OF1-f6#odIsgaUe7prMoynS z!4t923<&uuL}rQmFM0gz{9k_mNB#YW?>;`l{GXkjRnC9kI4#V-VHmwauLlx0G3d?S~wd zr1TQTnt8!8Q}k^AJV^gPy?g!k$9J9O^hx#qtbf+$`rqyMPfq#<>i;fWi?}<5itWw{J`@)MyDk7h`sb3 zx}ZpOGDKuBtuZ9E>c1$6+>@1%hwnsH>b4DFzH#;cKx_hF1B zu<6#GQUWNDnddm(9S#Z5X)rS_s)nfRP~an@xbc*wSNh_by!-3rr+1$}zyJ6F$GP0h zZq8VkDI4bz*c#KxU}%y7M>0>DM=;4TGZ0=(CX8w_O1v3xZAF$gXwwaF+;%y=88GqG zBwPUwkVOOt>j4E9G;shf4FZ^6=;fHM5W80E&JGu({_fMKkDmsl4jt*tzHhboEYW*A zB)oy^x%w|O@I;a2O)D6y^-fz27t{0Mt3By}-iUg(|XOU~A zog(+f_3m7Pr5w??UNYtor%hMP3I$3@Dmyk;eFF z+$LikKU(;4%s=?&3;g&pZbG9kV`2m9#P{xK(Ci?PH{Q}W1DgR>jqwFGy%^%>kbges zpRdH{SoAQ+B(j}QhiQ|t6w}29WNc2@n6rBvpgkD#F0UOYZNzIW_!63^HM78568t_j zgJ}$L=}jYtk})ddm^47D=AMg2C0MnIEpxj)9A{Qhlqznk)zs-<1)P#oT z-4~)I=pu*nGioKuJiP}kMzq8r3~>Q{U)U2HZAL?qp0L8PLD&FG&vjPKJg8O+)l14X z{J5tU{K&y8b^zRx_Mvw}UHcab1xj2Je!jI)p(hdYlf%pFB{1bKFnu4e2L<)WG}D~; zpeQ&xXU~|?F!DpsbC{5bpB6ZxY$CydDuZN`H$S{j41f!vC5Vzxt8s!C&J7D!Xa!p2 zt!D|dBa||oUI_Gv36ck5v+$-MES6(3M&V0d79|goSr;>Ic>$Os-*dUo@~QulG`O?? zGV$=^1W_D|QD>%G3u@iqbP>`b=>0747C=4WhSs6(9Hqxcm_4IQ*lIZerlkJtqpuX+ zpB5Cx&XnPdq5a8|o48hPJ=&nDAz4Wz=77Y~LtpH1cg5R>eB>7SEX)eZ%34K5LmkVE zbXHO$#`G|oF3k5k9F!zDocjs?K9Eb50Kpg8Req!X~o4k$b|PBOLx zR{?&2+}b9ByDF-WG$D+d0d(@gkg)5tI6j_&%ydMLju*_2`^RAfOteksIF^P* zxO5I-bV-RW0O<%wOz(H=_yjBn$P~PfOA`Sj3-gweg*{(D9r!dD45VAJlfZt2< z zh8ry>5D5%o6ap~QflE$|9C)P|XxQJkkBz2=<$NcgssZvQK>-`#0QttDy`+uiasRB_ zJvL6@?d z^j|Cit=atRjuGPB+3NT&2KGy=T5 zA&!I#{ICq{>&im5)V4OszZoUzm~<>73uKT^pw3` zSjN-`BT81Dc*;QgQTUVnf7`%UKm5jNP@+y8#Qd)iOt z|Kt?yfB*EfySM*O@ko0gr^_DHWP!($ub88j{9r34@)|MS$Xd{w(b9G!)^KbVj=b53 zii{l==O5MU^*5NV!$hJEwBmWQPMieE6QW#9uU~q%R3?pwfk}KPlBt{sKLIAbfLo&X zA~40D4h=(aJh*2?!-n?HI~s(m$o71bO=t7PKW>~~?ycL2yVRP}y9D&s_9Eu2ppT}B z!n=j-Pzm}1(>g1O;+{yp?=U3AR#zNECIu{{OCNCygNAI=Oe^h#8<_rCKdNIIV75fB z5AxY$&?AF?+Nn@j>Q~uUyzh{5WEhV>P^YmK3GVow-{3?y%N?jw9#enhG1qs{d)s!g zT?UdA_i7`vwxIC&e+MnPiWVXL`jGU>bvdQkDD;9ej1D#ck^r)b1??nm@jUUlT?-~Zxd+S^0xYZ_FODph7Ks(CuNkMIn(%5*Z`WFqF3HXF} z9+X_w>o8gM>u+hJWF`LT1k`s-i#9Y}1IEDry}U8YH|ivf_%zP#u+c1=vzXi~n4Hv} z6-$){ErWN`zI)xQY*P)S4BhKta5c z%=Kb@o$67mvAs#yY(-S&08v)S9eG81MI}sU1Z6NKw4xc;&5fd3)E$}NTk2$@v0WGoSGbg1dQgIIor&D!7!m#|$CST@fxY5oEvBtc zRw6AweqSuEqm5=ExbgA5Ma;Uut+!vx6Qdnz17frl6?#=g3o81misR$TnyQK~P;sKF zcv01(0To?UMH4I1@_&i1R`UAVDD%>sjO{Llub#)o*o#6xLhE)Vr2|5F>n8KNIM-0M zE@V}j;{SY$n+Xufl-l@lCoE?4EeZ7sVvePSLTc;;Q9PGiWrGj9FJFkr0Cwnz;0C z#Ep%RpoUtEj(UTlkBd!_0X=gDFNUZj)yUDBz-TI_ z1~}aUCxq1TYK(C()+<@yGMd7AVD!~(Dh-RMszS}pLaPs83klaO!T(l*8{?^ia@HZ z@qtrE?0d#W%qavBKrNmSq&G0AHeZ5O1=Esv zz6ajuseDn&1IfQZRn!HPLA{cw3Q@flF|++rP}9Zsla;^h{6BO(d{5j&vp$;%?7 zm_Q7j)+0=@x+1!XqVRK~opNmP*XS@uw)yh>Xa#uXyOcvC07@T5WU zZErdqiF*Mu+c|#-sCk1|EQCK!!UbAsz?HdUp50q(OP89OUa~c+-Xvac0Rz#w<&Ly<`xcX#Aw6$$%dVt z%os|^D=$z~c=JUs-!Sj zi5K>%f+uC*RFq)p8h4W5stMlO6y_KG1-XLNf1={KeU3_OH)Fh6EO)@X>SW%Y#WM|4 z?Rayoh<&wkuEXs?jH(`LJ7#S{YGJ?@6at2pIqxjyi(h8}{ zA*|E#9K_~2&Q@$G2z7rQifjCKSUbg6T;eTT6yo8dwfL`JFeM@?R-1S}nv_(oG)4`%wtFaoW`v9?QC_FUEDs|8?HK=6cm%MhyQWa^D({lQV~ z&PfI!PorcH1Gty`$gD_T^UDxLhJm;x(zdc!+sR~uB;3uWN8<1-Ukyu5yq~hLl%3k* zuGCDx&(^)Sc2}#*an_OjkOP5*D%d+8=P-4581<~eyFB|V|VFL4}?-H-trEPJyAKq^o zWE7(qXR2e&_4|WgYq%u$xpb78O?i$hS-O>rr?nw<X z3d$@%N?2T#dz;_pPE9+0X>PM%G?k<1szdO}_D#$C!M0m45u`O z@o8h_PWrz*&+>-Am3DRV243?#)Ye`k9gioo7UZz}4-U-YM5n@O z(NLVdXa8Z2{|xyPN}V&K3XudmH5%c|yrU6c7LG$g%#cD*cBs z^<3ZuiiZw|CA!M7y)Ulp+A4cD@1+!(1c4!m6$l_0KoU2V|DNud!95@;uO%lHz_k>K znd#~7>2t32H>Tm3`k>eE^^c!D&eMnI{QR8%g{SzJe;^bThNp$`9}fG&XQW?`|D!)Y z(a^Ar(9r)v17>^fn1Co89(*v?bWDVB93EuLu=I1ZUK_z?OfI8<>i#BNc`h+McOP(3KU(CON+oy_YWZIikz+wv`CW?=gv zMq|3AHZ{r0DKy|wkE`hPY$8*%;bk47gaqao`5N&mdo|EGA4 z$fZ!<%fMR(#(HhLOY)=PE+f!d@`D$-U>!i=2&!^uu$#k!zj_fd0!sYA^F2l_5_-g5 z`wm@GHza=9B|A%yPVz( zn0ROst^fzfDguP{fPxE}I{=pk0Sqs+atv39UAui}hbz)}_vzEePh--6hIC=yx7&P_ z=)D~hUcvQT{WltT;+5%H6^zver|stOv@?Lwk}&6iVct*}Y!qtO3(4Go?oDbTfoa1< zFj%Zvi8FPekoDnp1Bdv`Qw^$^G#Z|xg_%>b+B>;kJ^Oz?BU zKcDl@SK@OfS`5iNvYk+eVUw~H)5XSQX3W`)vwIexJ(%$(uN^0?#7j;15*nyAi@;kG z{B9Y66+>KmR^(7JLuH(iCP>xNbJ3^-n=Wy@rNK#OT|z^%*XqSg`~U+R_fxV7Z322` zqk^NE@`4SDX$0~(10e?pyayY-BR-(+)d(dJ;OLW2z7tr^WJ-5+jG$rW?D;yhy4Y2fFXVc1qYPV6n zq+G*~duqau9K2!!z%8jCdNB#DJVJhQczL}9rrZUF?*sOrpdPU@ z)rk*^g1vM0%oq(LKlD6@35oc5g+0nD5*(;9NH%%%IpZr4t19(JwC#O6o#lp!%GhGKZ>9W!+?`S+u9p?_00P#B(0K+t?AA*45urrWOz$V+F@YFcS zSQA_Y_yKZj8wl>Is6Nt!Flq$Q$Ol8huA8ec^x63M*aDg9i55LCSRRj#!w8sY8_sbo z4XbeN96|4r5?uh&5s(<(AGYxcSP&2kypKy00V6BpmXejdTtON5H0Tc`$4l8t~C zj%|iWIg%4C76PO+hLSGebYg~+5#xhN$a{3CHWP4T+L4jAIl6Fw=ocPKG(~N-@x|y>A~6TN=LSGXYfckoH+b25*&m#ok4D4M@O(IUnL$w3bqFqVmJhu$Sbp@{XpdtXg|ZH! zMbW&=RE7&Y$P0X;3PN^)F`jF#dK_?_^jGEo;zy4zmtcYx-tjlg{~tF0d(uB0*7LvL zef+=CeDK5Pe^0?I)bl^}{BJ$~`(5?_^T%I4y?OV!7v6`DssF?CK~ewDM`yMEKgE+w z`5*9f9%9LZDlc%bMLbGn7WJuXQPs|M&Yv{XaWBujBtGc|gf)y{`3N z=)Xt-&BgND_OaXl4~zRh&xfO0|DVMFgR!5YvA;e%2#w_w7a%Qg{^FNqgcN@8WuRJD z{!8@#o6oK6oc}*h^nZAQ^#;SUdj9We9uO>oZ$f72xk+qI^0OAkXMz~48; z(lTysm^6d{HM-*6tyn3TG`K*;Z>@CVe$v>!W)L@tJDprLAVg_g%h%bAbn=gMmAz3& zV;W;}B~hCc@|ec;KMxODwLMeme_%ew8KAE?|8sVJQm_Ahm+^mu3HI&we>6B7r1{@q zgyTOt9o6%{Px456A8(gEJdiIumVCuMYRM0_VPan+ZZ|Sl^k%xY-H0_En}t(vF{NV1 z4vY66H5!dKxLt>djXF?^@0)evO^|#;l#AQz*WN9ao5sVyAifjHt(*uy0VckHTcY>Ir? z&hI9J78(50MunH9c9m_#d54rEleqt}dK+7j;GXaKO-^*H+<-deKJ`cLb9)1Qux}IF zWgtm$t1dEY4+@|EXV9XnXc5w{PspHLmQ$LYLN7SO=y(Sp2_UOjz)su-Ew#F5Gs|Yb zV#wD-O==ZoM=9)T{D@8l*U+gx*j_uwtuE2pT7g#rS|`UR1+_U!W8b2;1k|? z@aC$~fWc~9e@`1F3-M1cpuS_6w5jPDFb4h`-H{udi|x`dcXgEx5UOzcgL5#dKUEPf0FTg7QDZd;#k z#J2qSyjWaDo2^1{{=v4)6C>W^|!2`q)EY?iL<*n`iatshAkDdOotjlv!$eWTbV>cbXKV1(z_|QAwn>kYU$_< z#zof^TbLoV%-OLRqLS2Mj@AUm9(ZrBQy%B6#weAeAQD+&ZE5Hwu@z@LdXRo$jD_~` zVss+tOiLnOMpKLg4(&K5m94HMtZPhcGOuGouK%X? zxBT>xL<4ATd};h1TKCicg#JA#x=<3Nz*CG}8S3Av!y9FPlYKjUH0CI?n0+j3sbS*& z6^Rc%$yxML1|~g1Hi_U86D(QAjgK=13{zQWH{c&e_(J5C9nl)}d> zjq!-$K`+}~3a?QSwMtgS^ExF#&)cByfktkq)!Ft=OrKX{%6slq#TLH@38nGP0qQ6L z?T=N3w(So42rGFK}$;oSy?%N8^c$4*ytjmI@HmQS=< zD|v@R&(Vq-b0#Lda&P%v3M%`au@OrOo*SseDcJOgyDGa4HWf@uVxPEmvyFnR;`}{7 zs{QlEr|<9{jtYSM=8k53A&2eW8jfudaq5&$LmGjx=4UTMfW#UVlE*fzhX-w&1C=jI zc_8_xKqjFK%9TV_h*HvykASk}9ub{(G^eJ4w+HY{FA4$?JD~8%)A&+MAZS~c1j|@( z4q;Qr!mg%SCw{UoW)13|6gB%vxg6t-43xYnL1l=|$O6+pm*35V z+XJMEByjj`9$*yBRo1+eOv=twUM<@B04HCkJR6lu9JYwjjtS}=sdT0frR0?p6cyg2 zgY(~*mhTDYVVG_)y0MJMbablm+aCiC^Z_A&O4(E#mMU8yL$vHvMD7{k>I^VxQOK7* z;No170I3+#!AapNgz`wKTPx#m!Jp?9IF7f?1$Qdq#LA#;j!vS$NM*1BcxgQ?7EVsr zzUyaF9QbS!7m0_(l~wQ-j%RFvsFI{i9Q7B&i7ErBVi1M87|<1UQLNIjTodod2P9bjA|PmQ?iN}W+wr!$xdP2-E1N*Pj>L)fO}If$)o zoUNEr5bFLq6!)Y(Aa{!I5X5VYD8$2^t@v+Gm=X~c*(NSPC2uM-&4>8aD!*PiQony> zs@nX1jwk8mS2KNQ7=hN}SbIoV_FUECn+0H1KyV3g&k(BUWE#y@C0ub0pKWIE4wI|7Nw}Nce}>(&d@-b&cmZG`m9=bf8D+4^ug~&z zS;tt!C@?9Y z@~T|rRldeWxyD7l#`8(J3TQ&E&O}jXQmAvGsB=-M^GZ?Y71Sv$L4%xUB@Bf<9rf~( zkd)oD%2l?tbeRRcEE`SG(^Z=+YSuXLE5Fu)isL7}kA zr96t6W&OC3jGW4>e2?#U^Ah7E>Uz;~l_UmiuMyjO7eO*5+RsgFV8;*M8GteikP;SG zZEnm@bEl>qzqIyA7!74F`cUD`=KEJI&zGa6Xem>?ZBym>A(VH?QWLKQPB#}Njt1h8 zs#Q_W&koeEJjz@xBzInLvv*>c-9wPy13K&y<-~SD2P#5}qWjJdQNqL=)B7#u?iY#0 z!*}InB~(fy4}AF!Js143u5HyTe*34)Lk#z!=1`hzfxR^GThzL!(iPn)O<}y+SUD5_ zI@P9dWdKX~CG0tx_$BvproJ5Z7?O@2`G6et#O2uTB4Y79n|O4pU@aBX=~asca$;Lb zLvb%l#ikL(ww=Td=Yqy~3}SvEuFVX4F7aqXz;8>I>klbkx+%^rF`^!D&P=@+dMr5v#qEFs`AKp{qxV`~a4X1aroxjwXQ%CR8*g$RfWkX*MjVp|G|z~ytAsXS~L-B@7e$J z!M}(638l`NQH4l?otjSZwB&Tk)57T#1#~)%t&S)%+%HCATQB-du{F7YIHeT?f!6a`7FDUu~f+q#?n_wEAV8`Q%WJAH^ZCrfxN zb{G2sutfZoWjdDL>vTKa<7bcabm2KaKj(kpDgNc(d;OF1-f6#odIsgaUe7prMoynS z!4t923<&uuL}rQmFM0gz{9k_mNB#YW?>;`l{GXkjRnC9kI4#V-VHmwauLlx0G3d?S~wd zr1TQTnt8!8Q}k^AJV^gPy?g!k$9J9O^hx#qtbf+$`rqyMPfq#<>i;fWi?}<5itWw{J`@)MyDk7h`sb3 zx}ZpOGDKuBtuZ9E>c1$6+>@1%hwnsH>b4DFzH#;cKx_hF1B zu<6#GQUWNDnddm(9S#Z5X)rS_s)nfRP~an@xbc*wSNh_by!-3rr+1$}zyJ6F$GP0h zZq8VkDI4bz*c#KxU}%y7M>0>DM=;4TGZ0=(CX8w_O1v3xZAF$gXwwaF+;%y=88GqG zBwPUwkVOOt>j4E9G;shf4FZ^6=;fHM5W80E&JGu({_fMKkDmsl4jt*tzHhboEYW*A zB)oy^x%w|O@I;a2O)D6y^-fz27t{0Mt3By}-iUg(|XOU~A zog(+f_3m7Pr5w??UNYtor%hMP3I$3@Dmyk;eFF z+$LikKU(;4%s=?&3;g&pZbG9kV`2m9#P{xK(Ci?PH{Q}W1DgR>jqwFGy%^%>kbges zpRdH{SoAQ+B(j}QhiQ|t6w}29WNc2@n6rBvpgkD#F0UOYZNzIW_!63^HM78568t_j zgJ}$L=}jYtk})ddm^47D=AMg2C0MnIEpxj)9A{Qhlqznk)zs-<1)P#oT z-4~)I=pu*nGioKuJiP}kMzq8r3~>Q{U)U2HZAL?qp0L8PLD&FG&vjPKJg8O+)l14X z{J5tU{K&y8b^zRx_Mvw}UHcab1xj2Je!jI)p(hdYlf%pFB{1bKFnu4e2L<)WG}D~; zpeQ&xXU~|?F!DpsbC{5bpB6ZxY$CydDuZN`H$S{j41f!vC5Vzxt8s!C&J7D!Xa!p2 zt!D|dBa||oUI_Gv36ck5v+$-MES6(3M&V0d79|goSr;>Ic>$Os-*dUo@~QulG`O?? zGV$=^1W_D|QD>%G3u@iqbP>`b=>0747C=4WhSs6(9Hqxcm_4IQ*lIZerlkJtqpuX+ zpB5Cx&XnPdq5a8|o48hPJ=&nDAz4Wz=77Y~LtpH1cg5R>eB>7SEX)eZ%34K5LmkVE zbXHO$#`G|oF3k5k9F!zDocjs?K9Eb50Kpg8Req!X~o4k$b|PBOLx zR{?&2+}b9ByDF-WG$D+d0d(@gkg)5tI6j_&%ydMLju*_2`^RAfOteksIF^P* zxO5I-bV-RW0O<%wOz(H=_yjBn$P~PfOA`Sj3-gweg*{(D9r!dD45VAJlfZt2< z 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 L&QBHm08jt`r3NKu