From 9a8669e84b981eae46bfe119a85bdccae52eca34 Mon Sep 17 00:00:00 2001 From: dilanbhat Date: Sat, 14 Oct 2023 20:51:31 -0700 Subject: [PATCH 01/11] Added direct python file --- passage_generator.py | 233 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 passage_generator.py diff --git a/passage_generator.py b/passage_generator.py new file mode 100644 index 0000000..8c6ab73 --- /dev/null +++ b/passage_generator.py @@ -0,0 +1,233 @@ + +import openai +import json +import time + +def generate(passions): + f = open("apikey.txt", "r") + key = f.readline() + f.close() + openai.api_key = key + + + + messages = [ {"role": "system","content": "You are an expert educator"} ] + + + message = ''' + Write me a passage about one or more people with random names at fourth-grade reading level based loosely on exactly one of my passions. Ask me 4 multiple choice question to demonstrate my reading comprehension, also fourth-grade level. The answers to these questions should not be explicitly stated in the text, but should also not be ambiguous. Also provide the answer. It should be in the following format: Passage: _passage_ Questions: _questions_ Answers: _answers: + + Example 1: + My passions: farms + + Passage: + Lisa and the Pigpen + Peter lived in a small town with his mama, papa, brothers, and sisters. Everyone had chores. Peter’s + job was to look after his youngest sister Lisa. Lisa was three years old and very curious. She liked to + wander out of the house and play outside. + One day Peter and Lisa were playing hide-and-seek in the house, and the game turned into a chase. + Crash! Bang! Peter tripped and landed in the clothes basket on the kitchen floor. + Lisa fell on the floor beside him and laughed. “Do it again,” begged Lisa. + “Oh, no,” said Mama. “You two go outside with your chasing and stay out of my way. Don’t get into + trouble.” + The children ran out the door into the sunshine. At that moment, Mr. Brown was leading his pig down + the road. He was going to Ms. Smith’s house to show her how big the pig had grown. + Lisa laughed and ran to catch up to Mr. Brown and his pig. Peter yelled after her. + “Where are you going?” Lisa asked Mr. Brown. + Mr. Brown turned around and saw the little girl following him. “I am going to show my friend, Ms. + Smith, how big my pig has grown.” + “I’m going, too,” said Lisa. She marched right along with Mr. Brown. + “Okay, I’m going, too,” Peter sighed, and followed behind them. + When they arrived at Ms. Smith’s house, Mr. Brown put his pig in the pigpen at the back of the + house. Lisa followed Mr. Brown and his pig. When she saw the other pigs, she squealed with delight. The + pigs squealed and oinked. + “Don’t go in the pigpen, children,” Mr. Brown said. Then he went in the house. + Lisa wanted to play with the pigs. She started across the pen to pet the pigs. On her way, she slipped + in the mud and fell in a puddle. Lisa was wet from her head to her toes with black, dirty pigpen water. + She splashed with her hands and kicked her feet, spreading mud all over her clothes. “I’m a pig! I’m a + pig!” she squealed. “Come out of there right now, Lisa!” screamed Peter. + At that moment, Mr. Brown and Ms. Smith came outside. They heard the children shouting and the + pigs squealing. + “Someone is in the pigpen with the pigs!” Ms. Smith exclaimed. + They went to the back of the house and found Lisa splashing in the water. + Peter was shouting at Lisa. “Lisa! Look at you! What will Mama say? You get out of there now!” + “I’m a pig!” said Lisa. She wouldn’t come out of the pigpen. + Peter crawled through the fence to get a hold of Lisa. Lisa ran from him. Peter slipped and fell in the + black, dirty pigpen puddle. + “Oh, no! Now we’re both wet and dirty and smell like a pigpen!” Peter said. + Peter took Lisa’s arm and pulled her out of the pigpen. He held her hand and walked her home. + Peter’s face was long and sad. He wondered what Mama would say. When they walked in the house, + Mama looked up from her laundry. Her eyes grew large and her mouth opened wide. Then she laughed. + “You look and smell like two little pigs. Take off your dirty clothes. I have just enough water to wash + the two of you. Your clothes are another matter. I will take care of those later.” + When the children were clean, Mama put Lisa in her bed for a nap. Peter went outside to sit and + think. How was he going to keep Lisa out of trouble? + + Questions: + + 1. In the first paragraph, what word helps the reader know the meaning of chores? + A. wander + B. curious + C. look + D. job + + 2. Why do Mama’s eyes grow large and her mouth open wide? + A. She was angry at the children. + B. She saw Lisa in the clothes basket. + C. She did not know who the children were. + D. She saw the children covered with mud. + + 3. Which word best describes Lisa? + A. naughty + B. honest + C. helpful + D. thoughtful + + 4. Which pair of words are compound words? + A. outside and laughed + B. sunshine and pigpen + C. laundry and pigpen + D. shouting and following + 5. What is the main idea of the passage? + A. Peter has a hard job watching his sister. + B. Ms. Smith likes to raise pigs. + C. Mama has a busy schedule. + D. Many people raise pigs. + + + Answers: + + 1. D + 2. D + 3. A + 4. B + + + Example 2: + My passions: wild animals + + Passage: + Wolves Home Again + Good things have come from bringing wolves back to Yellowstone National Park. One good thing is + the return of two kinds of trees, which grow only near streams. They had nearly disappeared since the + wolves were gone. There was a reason for this. + The wolves scare away elk, which are animals that eat trees growing out of the ground. Now elk avoid + spending time near streams in the park. They have no place to run from wolves there. The trees that + disappeared near streams now grow in the park. + Yellowstone National Park, “America’s first national park,” is in the northwest part of Wyoming. It + spreads into Idaho and Montana. It became a park in 1872. The park is beautiful and has many visitors. + The land was a home for wolves for a long time. + Wolves were common in the park at first. As time went on, the wolves began dying out. By 1926, no + wolves could be found. People who lived near Yellowstone killed them because the wolves would eat the + animals the people had raised to sell. + In 1995, many people joined forces to bring back the wolves. They were people who cared about + animals and the health of the land. At first, this was only a dream since there were no wolves in the park! + Wolves were in Canada, which is north of the United States. People went to Canada to capture wolves. + They brought them back to the park and let them go. They kept close track of the wolves’ actions. When + a wolf died, they would figure out the reason. A lot was done to protect the wolves from harm. + Yet, ranchers also complained that the wolves were eating their animals. In 1997, they tried to get rid + of the wolves by passing a law to remove them from the park. The law was never passed. + Now, there are many wolves in Yellowstone National Park. The land is healthier, and the wolves have + their home back. + + Questions: + + 1. What is the singular form of the word wolves? + A. wolf + B. wolfs + C. wolfes + D. wolve + + 2. What is the author informing the reader of in the passage? + A. wolves living in Canada + B. wolves bringing good things to Yellowstone National Park + C. wolves eating elk and ranch animals + D. wolves being hunted in Yellowstone National Park + + 3. According to the passage, Yellowstone National Park is located in what three states? + A. Wyoming, Idaho, and Montana + B. Wyoming, Colorado, and Utah + C. Wyoming, Nebraska, and Idaho + D. Wyoming, Montana, and Colorado + + 4. Why were wolves killed by people who lived near Yellowstone? + A. They were eating the ranchers’ animals. + B. Park visitors were hurt by them. + C. They became sick and died. + D. A law was passed to hunt them. + + Answers: + 1. A + 2. B + 3. A + 4. A + + + My passion: + ''' + + streamWords = False + + if(not streamWords): + if message: + messages.append( + {"role": "user", "content": message + passions}, + ) + chat = openai.ChatCompletion.create( + model="gpt-3.5-turbo", messages=messages + ) + reply = chat.choices[0].message.content + else: + messages.append( + {"role": "user", "content": message + passions}, + ) + + for chunk in openai.ChatCompletion.create( + model="gpt-3.5-turbo", + + messages=messages, + stream=True, + ): + content = chunk["choices"][0].get("delta", {}).get("content") + if content is not None: + for char in content: + print(char, end='', flush=True) + #print(char, end='', flush=True) + time.sleep(.05) + + + passage = reply[reply.find("Passage") + 8:reply.find("Questions")] + question = reply[reply.find("Questions") + 10:reply.find("Answers")] + answers = reply[reply.find("Answers") + 8:] + #print(question) + questionArr = question.split('\n') + while("" in questionArr): + questionArr.remove("") + + + q1 = questionArr[0:5] + q2 = questionArr[5:10] + q3 = questionArr[10:15] + q4 = questionArr[15:20] + + questionArr = [q1,q2,q3,q4] + + letters = answers.splitlines() + + while("" in letters): + letters.remove("") + + + for i in range(len(letters)): + letters[i] = letters[i][-1:] + + + + + data = {} + data['Passage'] = passage + data["Question"] = questionArr + data["Answers"] = letters + return data + #print(data) +generate("dancing") \ No newline at end of file From e0ba746e91316a8cdb414c9f3fac5380c31155f5 Mon Sep 17 00:00:00 2001 From: dilanbhat Date: Sat, 14 Oct 2023 21:36:56 -0700 Subject: [PATCH 02/11] Add files via upload --- src/api/passage_generator.py | 250 +++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 src/api/passage_generator.py diff --git a/src/api/passage_generator.py b/src/api/passage_generator.py new file mode 100644 index 0000000..93dda05 --- /dev/null +++ b/src/api/passage_generator.py @@ -0,0 +1,250 @@ + +import openai +import json +import time +def data_clean(data, types): + out = [] + for i in range(len(data["Question"])): + question = {} + question["question"] = data["Question"][i][0] + question["correct_answer"] = ord(data["Answers"][i].lower()) - 97 + question["answers"] = data["Question"][i][1:] + question["type"] = types[i] + + out.append(question) + data["Question"] = out + del data["Answers"] + +def generate(passions, categories): + f = open("apikey.txt", "r") + key = f.readline() + f.close() + openai.api_key = key + + + + + messages = [ {"role": "system","content": "You are an expert educator"} ] + + + message = ''' + Write me a passage about one or more people with random names at fourth-grade reading level based loosely on exactly one of my passions. Ask me 4 multiple choice question to demonstrate my reading comprehension, also fourth-grade level. The first question should be about ''' + categories[0] + '''; the second question should be about ''' + categories[1] + '''; the third question should be about ''' + categories[2] + '''; the fourth question should be about ''' + categories[3] + '''. The answers to these questions should not be explicitly stated in the text, but should also not be ambiguous. Also provide the answer. It should be in the following format: Passage: _passage_ Questions: _questions_ Answers: _answers: + + Example 1: + My passions: farms + + Passage: + Lisa and the Pigpen + Peter lived in a small town with his mama, papa, brothers, and sisters. Everyone had chores. Peter’s + job was to look after his youngest sister Lisa. Lisa was three years old and very curious. She liked to + wander out of the house and play outside. + One day Peter and Lisa were playing hide-and-seek in the house, and the game turned into a chase. + Crash! Bang! Peter tripped and landed in the clothes basket on the kitchen floor. + Lisa fell on the floor beside him and laughed. “Do it again,” begged Lisa. + “Oh, no,” said Mama. “You two go outside with your chasing and stay out of my way. Don’t get into + trouble.” + The children ran out the door into the sunshine. At that moment, Mr. Brown was leading his pig down + the road. He was going to Ms. Smith’s house to show her how big the pig had grown. + Lisa laughed and ran to catch up to Mr. Brown and his pig. Peter yelled after her. + “Where are you going?” Lisa asked Mr. Brown. + Mr. Brown turned around and saw the little girl following him. “I am going to show my friend, Ms. + Smith, how big my pig has grown.” + “I’m going, too,” said Lisa. She marched right along with Mr. Brown. + “Okay, I’m going, too,” Peter sighed, and followed behind them. + When they arrived at Ms. Smith’s house, Mr. Brown put his pig in the pigpen at the back of the + house. Lisa followed Mr. Brown and his pig. When she saw the other pigs, she squealed with delight. The + pigs squealed and oinked. + “Don’t go in the pigpen, children,” Mr. Brown said. Then he went in the house. + Lisa wanted to play with the pigs. She started across the pen to pet the pigs. On her way, she slipped + in the mud and fell in a puddle. Lisa was wet from her head to her toes with black, dirty pigpen water. + She splashed with her hands and kicked her feet, spreading mud all over her clothes. “I’m a pig! I’m a + pig!” she squealed. “Come out of there right now, Lisa!” screamed Peter. + At that moment, Mr. Brown and Ms. Smith came outside. They heard the children shouting and the + pigs squealing. + “Someone is in the pigpen with the pigs!” Ms. Smith exclaimed. + They went to the back of the house and found Lisa splashing in the water. + Peter was shouting at Lisa. “Lisa! Look at you! What will Mama say? You get out of there now!” + “I’m a pig!” said Lisa. She wouldn’t come out of the pigpen. + Peter crawled through the fence to get a hold of Lisa. Lisa ran from him. Peter slipped and fell in the + black, dirty pigpen puddle. + “Oh, no! Now we’re both wet and dirty and smell like a pigpen!” Peter said. + Peter took Lisa’s arm and pulled her out of the pigpen. He held her hand and walked her home. + Peter’s face was long and sad. He wondered what Mama would say. When they walked in the house, + Mama looked up from her laundry. Her eyes grew large and her mouth opened wide. Then she laughed. + “You look and smell like two little pigs. Take off your dirty clothes. I have just enough water to wash + the two of you. Your clothes are another matter. I will take care of those later.” + When the children were clean, Mama put Lisa in her bed for a nap. Peter went outside to sit and + think. How was he going to keep Lisa out of trouble? + + Questions: + + 1. In the first paragraph, what word helps the reader know the meaning of chores? + A. wander + B. curious + C. look + D. job + + 2. Why do Mama’s eyes grow large and her mouth open wide? + A. She was angry at the children. + B. She saw Lisa in the clothes basket. + C. She did not know who the children were. + D. She saw the children covered with mud. + + 3. Which word best describes Lisa? + A. naughty + B. honest + C. helpful + D. thoughtful + + 4. Which pair of words are compound words? + A. outside and laughed + B. sunshine and pigpen + C. laundry and pigpen + D. shouting and following + 5. What is the main idea of the passage? + A. Peter has a hard job watching his sister. + B. Ms. Smith likes to raise pigs. + C. Mama has a busy schedule. + D. Many people raise pigs. + + + Answers: + + 1. D + 2. D + 3. A + 4. B + + + Example 2: + My passions: wild animals + + Passage: + Wolves Home Again + Good things have come from bringing wolves back to Yellowstone National Park. One good thing is + the return of two kinds of trees, which grow only near streams. They had nearly disappeared since the + wolves were gone. There was a reason for this. + The wolves scare away elk, which are animals that eat trees growing out of the ground. Now elk avoid + spending time near streams in the park. They have no place to run from wolves there. The trees that + disappeared near streams now grow in the park. + Yellowstone National Park, “America’s first national park,” is in the northwest part of Wyoming. It + spreads into Idaho and Montana. It became a park in 1872. The park is beautiful and has many visitors. + The land was a home for wolves for a long time. + Wolves were common in the park at first. As time went on, the wolves began dying out. By 1926, no + wolves could be found. People who lived near Yellowstone killed them because the wolves would eat the + animals the people had raised to sell. + In 1995, many people joined forces to bring back the wolves. They were people who cared about + animals and the health of the land. At first, this was only a dream since there were no wolves in the park! + Wolves were in Canada, which is north of the United States. People went to Canada to capture wolves. + They brought them back to the park and let them go. They kept close track of the wolves’ actions. When + a wolf died, they would figure out the reason. A lot was done to protect the wolves from harm. + Yet, ranchers also complained that the wolves were eating their animals. In 1997, they tried to get rid + of the wolves by passing a law to remove them from the park. The law was never passed. + Now, there are many wolves in Yellowstone National Park. The land is healthier, and the wolves have + their home back. + + Questions: + + 1. What is the singular form of the word wolves? + A. wolf + B. wolfs + C. wolfes + D. wolve + + 2. What is the author informing the reader of in the passage? + A. wolves living in Canada + B. wolves bringing good things to Yellowstone National Park + C. wolves eating elk and ranch animals + D. wolves being hunted in Yellowstone National Park + + 3. According to the passage, Yellowstone National Park is located in what three states? + A. Wyoming, Idaho, and Montana + B. Wyoming, Colorado, and Utah + C. Wyoming, Nebraska, and Idaho + D. Wyoming, Montana, and Colorado + + 4. Why were wolves killed by people who lived near Yellowstone? + A. They were eating the ranchers’ animals. + B. Park visitors were hurt by them. + C. They became sick and died. + D. A law was passed to hunt them. + + Answers: + 1. A + 2. B + 3. A + 4. A + + + My passion: + ''' + + streamWords = True + + if(not streamWords): + if message: + messages.append( + {"role": "user", "content": message + passions}, + ) + chat = openai.ChatCompletion.create( + model="gpt-3.5-turbo", messages=messages + ) + reply = chat.choices[0].message.content + else: + messages.append( + {"role": "user", "content": message + passions}, + ) + + for chunk in openai.ChatCompletion.create( + model="gpt-3.5-turbo", + + messages=messages, + stream=True, + ): + content = chunk["choices"][0].get("delta", {}).get("content") + if content is not None: + for char in content: + print(char, end='', flush=True) + #print(char, end='', flush=True) + time.sleep(.05) + + + passage = reply[reply.find("Passage") + 8:reply.find("Questions")] + question = reply[reply.find("Questions") + 10:reply.find("Answers")] + answers = reply[reply.find("Answers") + 8:] + #print(question) + questionArr = question.split('\n') + while("" in questionArr): + questionArr.remove("") + + + q1 = questionArr[0:5] + q2 = questionArr[5:10] + q3 = questionArr[10:15] + q4 = questionArr[15:20] + + questionArr = [q1,q2,q3,q4] + + letters = answers.splitlines() + + while("" in letters): + letters.remove("") + + + for i in range(len(letters)): + letters[i] = letters[i][-1:] + + + + + data = {} + data['Passage'] = passage + data["Question"] = questionArr + data["Answers"] = letters + data_clean(data,categories) + return data + #print(data) + + + +generate("dancing", ["Inference", "Vocab", "Details", "Main Ideas"]) \ No newline at end of file From 406dc1dd6c380ceb922a7ba400384530969e3262 Mon Sep 17 00:00:00 2001 From: Will Feldman <13539982+willfeldman@users.noreply.github.com> Date: Sat, 14 Oct 2023 22:19:02 -0700 Subject: [PATCH 03/11] Frontend for interests and questions --- package-lock.json | 6 ++ src/app/page.tsx | 57 +++++++++-------- src/app/practice/page.tsx | 61 +++++++++++++++++++ src/components/Button.tsx | 26 ++++++++ .../{ToggleButton.tsx => InterestButton.tsx} | 4 +- src/components/Passage/PassageQuestion.tsx | 25 ++++++++ .../Passage/PassageSetOfQuestions.tsx | 26 ++++++++ src/components/Passage/ReadingPrompt.tsx | 20 ++++++ src/package-lock.json | 16 +++++ src/package.json | 1 + 10 files changed, 216 insertions(+), 26 deletions(-) create mode 100644 package-lock.json create mode 100644 src/app/practice/page.tsx create mode 100644 src/components/Button.tsx rename src/components/{ToggleButton.tsx => InterestButton.tsx} (82%) create mode 100644 src/components/Passage/PassageQuestion.tsx create mode 100644 src/components/Passage/PassageSetOfQuestions.tsx create mode 100644 src/components/Passage/ReadingPrompt.tsx diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f94e3b2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "groundbreakinglabs", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 07767f9..ff5fbec 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,37 +1,46 @@ -import Head from 'next/head'; -import ToggleButton from '@components/ToggleButton'; +import Head from "next/head"; +import InterestButton from "@components/InterestButton"; +import Link from 'next/link'; +import Button from "@components/Button"; export default function Home() { return ( -
+
Settle - + -
-

Welcome, Dilan

-

What are your interests?

+
+
+

+ Welcome, Dilan! +

+

What are your interests?

+
-
- - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + +
- +
); diff --git a/src/app/practice/page.tsx b/src/app/practice/page.tsx new file mode 100644 index 0000000..940a026 --- /dev/null +++ b/src/app/practice/page.tsx @@ -0,0 +1,61 @@ +import Head from "next/head"; +import ReadingPrompt from "@components/Passage/ReadingPrompt"; +import PassageSetOfQuestions from "@components/Passage/PassageSetOfQuestions"; +import Button from "@components/Button"; + +const question = "Why was Julia confident about winning the Bake-Off?"; +const answers = [ + "She practiced every day.", + "She was a renowned chef.", + "She had a secret family recipe.", + "She had won before." +]; + +const questions = [ + { + question: "Why was Julia confident about winning the Bake-Off?", + answers: ["She practiced every day.", "She was a renowned chef.", "She had a secret family recipe.", "She had won before."] + }, + { + question: "Which word in the passage is a synonym for 'scent'?", + answers: ["Echoed", "Texture", "Booth", "Aroma"] + }, + { + question: "Where did the Great Bake-Off take place?", + answers: ["At Julia's home", "In the town of Ovenville's square", "In a big hall", "At the judges' houses"] + }, + { + question: "What is the main idea of the passage?", + answers: ["Julia's grandmother was a great baker.", "The town of Ovenville loved to eat cookies.", "Julia wins the Great Bake-Off using her grandmother's secret recipe.", "The judges were from different parts of the country."] + }, + ]; + +export default function Home() { + return ( +
+ + Reading Practice + + +
+

Reading Practice

+

+ Read this passage and answer some questions. +

+ + +
+ +
+ +
+
+ ); +} diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..ac3e699 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,26 @@ +import Link from "next/link"; + +type CustomButtonProps = { + label: string; + onClick?: () => void; + link?: string; + className?: string; +}; + +const CustomButton: React.FC = ({ + label, + onClick, + link, + className, +}) => { + return ( + + ); +}; + +export default CustomButton; diff --git a/src/components/ToggleButton.tsx b/src/components/InterestButton.tsx similarity index 82% rename from src/components/ToggleButton.tsx rename to src/components/InterestButton.tsx index fa5d991..3bd77e7 100644 --- a/src/components/ToggleButton.tsx +++ b/src/components/InterestButton.tsx @@ -5,7 +5,7 @@ interface ToggleButtonProps { label: string; } -const ToggleButton: FC = ({ label }) => { +const InterestButton: FC = ({ label }) => { const [isActive, setIsActive] = useState(false); return ( @@ -20,4 +20,4 @@ const ToggleButton: FC = ({ label }) => { ); }; -export default ToggleButton; \ No newline at end of file +export default InterestButton; \ No newline at end of file diff --git a/src/components/Passage/PassageQuestion.tsx b/src/components/Passage/PassageQuestion.tsx new file mode 100644 index 0000000..331422c --- /dev/null +++ b/src/components/Passage/PassageQuestion.tsx @@ -0,0 +1,25 @@ +export type PassageQuestionProps = { + question: string; + answers: string[]; + name?: string; +}; + +const PassageQuestion: React.FC = ({ question, answers, name }) => { + const answerLabels = ['A', 'B', 'C', 'D', 'E', 'F']; + + return ( +
+

{question}

+
+ {answers.map((answer, index) => ( + + ))} +
+
+ ); +}; + +export default PassageQuestion; diff --git a/src/components/Passage/PassageSetOfQuestions.tsx b/src/components/Passage/PassageSetOfQuestions.tsx new file mode 100644 index 0000000..a49c229 --- /dev/null +++ b/src/components/Passage/PassageSetOfQuestions.tsx @@ -0,0 +1,26 @@ +import PassageQuestion, { + PassageQuestionProps, +} from "@components/Passage/PassageQuestion"; + +type PassageSetOfQuestionsProps = { + questions: PassageQuestionProps[]; +}; + +const PassageSetOfQuestions: React.FC = ({ + questions, +}) => { + return ( +
+ {questions.map((q, index) => ( + + ))} +
+ ); +}; + +export default PassageSetOfQuestions; diff --git a/src/components/Passage/ReadingPrompt.tsx b/src/components/Passage/ReadingPrompt.tsx new file mode 100644 index 0000000..c1539ec --- /dev/null +++ b/src/components/Passage/ReadingPrompt.tsx @@ -0,0 +1,20 @@ +interface ReadingPromptProps { + text: string; +} + +const ReadingPrompt: React.FC = ({ text }) => { + return ( +
+ {text.split("\n").map((para, idx) => ( +

+ {para} +

+ ))} +
+ ); +}; + +export default ReadingPrompt; diff --git a/src/package-lock.json b/src/package-lock.json index c1293e7..e733347 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -16,6 +16,7 @@ "eslint": "8.40.0", "eslint-config-next": "13.4.2", "next": "13.4.3", + "pnpm": "^8.9.0", "postcss": "8.4.23", "react": "18.2.0", "react-dom": "18.2.0", @@ -3101,6 +3102,21 @@ "node": ">= 6" } }, + "node_modules/pnpm": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/pnpm/-/pnpm-8.9.0.tgz", + "integrity": "sha512-74hZk44fBTe5/PAwkEQxE5Lzs4s0QXbmzU/e4hsiVSSwrCobCK4q4t3Vs/9LjKSW1neOlQ8+fJ9VW4EyWYJEHA==", + "bin": { + "pnpm": "bin/pnpm.cjs", + "pnpx": "bin/pnpx.cjs" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, "node_modules/postcss": { "version": "8.4.23", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", diff --git a/src/package.json b/src/package.json index d311227..9169064 100644 --- a/src/package.json +++ b/src/package.json @@ -19,6 +19,7 @@ "eslint": "8.40.0", "eslint-config-next": "13.4.2", "next": "13.4.3", + "pnpm": "^8.9.0", "postcss": "8.4.23", "react": "18.2.0", "react-dom": "18.2.0", From f0e20a4235acaf6a9e63fb4248f09d55873916a0 Mon Sep 17 00:00:00 2001 From: Alex Nikanov Date: Sat, 14 Oct 2023 23:30:50 -0700 Subject: [PATCH 04/11] backend kinda working now --- .gitignore | 3 +- passage_generator.py | 233 -------------------- src/api/index.py | 111 +++++++++- src/api/{passage_generator.py => prompt.py} | 21 +- src/requirements.txt | 3 +- 5 files changed, 122 insertions(+), 249 deletions(-) delete mode 100644 passage_generator.py rename src/api/{passage_generator.py => prompt.py} (98%) diff --git a/.gitignore b/.gitignore index e0b92af..7016039 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,5 @@ src/next-env.d.ts __pycache__ pythonvenv -*.env \ No newline at end of file +*.env +apikey.txt \ No newline at end of file diff --git a/passage_generator.py b/passage_generator.py deleted file mode 100644 index 8c6ab73..0000000 --- a/passage_generator.py +++ /dev/null @@ -1,233 +0,0 @@ - -import openai -import json -import time - -def generate(passions): - f = open("apikey.txt", "r") - key = f.readline() - f.close() - openai.api_key = key - - - - messages = [ {"role": "system","content": "You are an expert educator"} ] - - - message = ''' - Write me a passage about one or more people with random names at fourth-grade reading level based loosely on exactly one of my passions. Ask me 4 multiple choice question to demonstrate my reading comprehension, also fourth-grade level. The answers to these questions should not be explicitly stated in the text, but should also not be ambiguous. Also provide the answer. It should be in the following format: Passage: _passage_ Questions: _questions_ Answers: _answers: - - Example 1: - My passions: farms - - Passage: - Lisa and the Pigpen - Peter lived in a small town with his mama, papa, brothers, and sisters. Everyone had chores. Peter’s - job was to look after his youngest sister Lisa. Lisa was three years old and very curious. She liked to - wander out of the house and play outside. - One day Peter and Lisa were playing hide-and-seek in the house, and the game turned into a chase. - Crash! Bang! Peter tripped and landed in the clothes basket on the kitchen floor. - Lisa fell on the floor beside him and laughed. “Do it again,” begged Lisa. - “Oh, no,” said Mama. “You two go outside with your chasing and stay out of my way. Don’t get into - trouble.” - The children ran out the door into the sunshine. At that moment, Mr. Brown was leading his pig down - the road. He was going to Ms. Smith’s house to show her how big the pig had grown. - Lisa laughed and ran to catch up to Mr. Brown and his pig. Peter yelled after her. - “Where are you going?” Lisa asked Mr. Brown. - Mr. Brown turned around and saw the little girl following him. “I am going to show my friend, Ms. - Smith, how big my pig has grown.” - “I’m going, too,” said Lisa. She marched right along with Mr. Brown. - “Okay, I’m going, too,” Peter sighed, and followed behind them. - When they arrived at Ms. Smith’s house, Mr. Brown put his pig in the pigpen at the back of the - house. Lisa followed Mr. Brown and his pig. When she saw the other pigs, she squealed with delight. The - pigs squealed and oinked. - “Don’t go in the pigpen, children,” Mr. Brown said. Then he went in the house. - Lisa wanted to play with the pigs. She started across the pen to pet the pigs. On her way, she slipped - in the mud and fell in a puddle. Lisa was wet from her head to her toes with black, dirty pigpen water. - She splashed with her hands and kicked her feet, spreading mud all over her clothes. “I’m a pig! I’m a - pig!” she squealed. “Come out of there right now, Lisa!” screamed Peter. - At that moment, Mr. Brown and Ms. Smith came outside. They heard the children shouting and the - pigs squealing. - “Someone is in the pigpen with the pigs!” Ms. Smith exclaimed. - They went to the back of the house and found Lisa splashing in the water. - Peter was shouting at Lisa. “Lisa! Look at you! What will Mama say? You get out of there now!” - “I’m a pig!” said Lisa. She wouldn’t come out of the pigpen. - Peter crawled through the fence to get a hold of Lisa. Lisa ran from him. Peter slipped and fell in the - black, dirty pigpen puddle. - “Oh, no! Now we’re both wet and dirty and smell like a pigpen!” Peter said. - Peter took Lisa’s arm and pulled her out of the pigpen. He held her hand and walked her home. - Peter’s face was long and sad. He wondered what Mama would say. When they walked in the house, - Mama looked up from her laundry. Her eyes grew large and her mouth opened wide. Then she laughed. - “You look and smell like two little pigs. Take off your dirty clothes. I have just enough water to wash - the two of you. Your clothes are another matter. I will take care of those later.” - When the children were clean, Mama put Lisa in her bed for a nap. Peter went outside to sit and - think. How was he going to keep Lisa out of trouble? - - Questions: - - 1. In the first paragraph, what word helps the reader know the meaning of chores? - A. wander - B. curious - C. look - D. job - - 2. Why do Mama’s eyes grow large and her mouth open wide? - A. She was angry at the children. - B. She saw Lisa in the clothes basket. - C. She did not know who the children were. - D. She saw the children covered with mud. - - 3. Which word best describes Lisa? - A. naughty - B. honest - C. helpful - D. thoughtful - - 4. Which pair of words are compound words? - A. outside and laughed - B. sunshine and pigpen - C. laundry and pigpen - D. shouting and following - 5. What is the main idea of the passage? - A. Peter has a hard job watching his sister. - B. Ms. Smith likes to raise pigs. - C. Mama has a busy schedule. - D. Many people raise pigs. - - - Answers: - - 1. D - 2. D - 3. A - 4. B - - - Example 2: - My passions: wild animals - - Passage: - Wolves Home Again - Good things have come from bringing wolves back to Yellowstone National Park. One good thing is - the return of two kinds of trees, which grow only near streams. They had nearly disappeared since the - wolves were gone. There was a reason for this. - The wolves scare away elk, which are animals that eat trees growing out of the ground. Now elk avoid - spending time near streams in the park. They have no place to run from wolves there. The trees that - disappeared near streams now grow in the park. - Yellowstone National Park, “America’s first national park,” is in the northwest part of Wyoming. It - spreads into Idaho and Montana. It became a park in 1872. The park is beautiful and has many visitors. - The land was a home for wolves for a long time. - Wolves were common in the park at first. As time went on, the wolves began dying out. By 1926, no - wolves could be found. People who lived near Yellowstone killed them because the wolves would eat the - animals the people had raised to sell. - In 1995, many people joined forces to bring back the wolves. They were people who cared about - animals and the health of the land. At first, this was only a dream since there were no wolves in the park! - Wolves were in Canada, which is north of the United States. People went to Canada to capture wolves. - They brought them back to the park and let them go. They kept close track of the wolves’ actions. When - a wolf died, they would figure out the reason. A lot was done to protect the wolves from harm. - Yet, ranchers also complained that the wolves were eating their animals. In 1997, they tried to get rid - of the wolves by passing a law to remove them from the park. The law was never passed. - Now, there are many wolves in Yellowstone National Park. The land is healthier, and the wolves have - their home back. - - Questions: - - 1. What is the singular form of the word wolves? - A. wolf - B. wolfs - C. wolfes - D. wolve - - 2. What is the author informing the reader of in the passage? - A. wolves living in Canada - B. wolves bringing good things to Yellowstone National Park - C. wolves eating elk and ranch animals - D. wolves being hunted in Yellowstone National Park - - 3. According to the passage, Yellowstone National Park is located in what three states? - A. Wyoming, Idaho, and Montana - B. Wyoming, Colorado, and Utah - C. Wyoming, Nebraska, and Idaho - D. Wyoming, Montana, and Colorado - - 4. Why were wolves killed by people who lived near Yellowstone? - A. They were eating the ranchers’ animals. - B. Park visitors were hurt by them. - C. They became sick and died. - D. A law was passed to hunt them. - - Answers: - 1. A - 2. B - 3. A - 4. A - - - My passion: - ''' - - streamWords = False - - if(not streamWords): - if message: - messages.append( - {"role": "user", "content": message + passions}, - ) - chat = openai.ChatCompletion.create( - model="gpt-3.5-turbo", messages=messages - ) - reply = chat.choices[0].message.content - else: - messages.append( - {"role": "user", "content": message + passions}, - ) - - for chunk in openai.ChatCompletion.create( - model="gpt-3.5-turbo", - - messages=messages, - stream=True, - ): - content = chunk["choices"][0].get("delta", {}).get("content") - if content is not None: - for char in content: - print(char, end='', flush=True) - #print(char, end='', flush=True) - time.sleep(.05) - - - passage = reply[reply.find("Passage") + 8:reply.find("Questions")] - question = reply[reply.find("Questions") + 10:reply.find("Answers")] - answers = reply[reply.find("Answers") + 8:] - #print(question) - questionArr = question.split('\n') - while("" in questionArr): - questionArr.remove("") - - - q1 = questionArr[0:5] - q2 = questionArr[5:10] - q3 = questionArr[10:15] - q4 = questionArr[15:20] - - questionArr = [q1,q2,q3,q4] - - letters = answers.splitlines() - - while("" in letters): - letters.remove("") - - - for i in range(len(letters)): - letters[i] = letters[i][-1:] - - - - - data = {} - data['Passage'] = passage - data["Question"] = questionArr - data["Answers"] = letters - return data - #print(data) -generate("dancing") \ No newline at end of file diff --git a/src/api/index.py b/src/api/index.py index 6950a90..9a03040 100644 --- a/src/api/index.py +++ b/src/api/index.py @@ -7,10 +7,64 @@ from bson.json_util import dumps as bson_dumps from bson.raw_bson import RawBSONDocument from bson.objectid import ObjectId +import random +import bson + +from prompt import generate load_dotenv() app = Flask(__name__) +PROMPT = { + "Passage": " \nThe Grand Bake-Off\nIt was an exciting day in the small town of Sweetville. The annual Grand Bake-Off was about to begin! This event brought together the best bakers in the town to show off their delicious creations. People came from near and far to watch and taste the mouthwatering treats.\nOne of the participants was Emma, a 10-year-old girl with a passion for baking. She loved experimenting with different flavors and ingredients to create unique desserts. For the Bake-Off, Emma decided to make her famous chocolate chip cookies with a twist\u2013 she added a caramel filling.\nAs the judges took their seats at the front of the room, Emma nervously arranged her cookies on a beautifully decorated plate. She couldn't wait for the judges to taste her creation. The Bake-Off was about to begin!\nEach participant presented their dish one by one, explaining the ingredients and techniques used. There were pies, cakes, cookies, and even a towering chocolate fountain. The room filled with the sweet aroma of freshly baked goods.\nFinally, it was Emma's turn. She confidently described her caramel-filled chocolate chip cookies, showcasing her baking skills to the judges. As they took a bite, their faces lit up with delight. The judges were impressed by the combination of the gooey caramel and the soft, melt-in-your-mouth cookies.\nAfter tasting all the delicious treats, the judges had the difficult task of selecting the winners. The participants anxiously waited for the results. When the winners were announced, the room erupted with applause.\nEmma couldn't believe her ears when her name was called as the first-place winner in the Kids' Category! Her caramel-filled chocolate chip cookies had won the hearts of the judges and the crowd. She proudly accepted her prize, a shiny blue ribbon, and smiled from ear to ear.\nThe Grand Bake-Off was a great success, leaving everyone with smiles on their faces and full bellies. Emma knew that baking was not just about creating delicious food, but also about bringing joy to others through her sweet creations.\n\n", + "Question": [ + { + "question": "1. What was the special twist that Emma added to her chocolate chip cookies?", + "correct_answer": 0, + "answers": [ + "A. Caramel filling", + "B. Oreo crumbs", + "C. Lemon zest", + "D. Peanut butter" + ], + "type": "Inference" + }, + { + "question": "2. Why was the annual Grand Bake-Off exciting?", + "correct_answer": 3, + "answers": [ + "A. People came to watch a baking competition", + "B. The participants were the best bakers in town", + "C. Delicious treats were available to taste", + "D. All of the above" + ], + "type": "Vocab" + }, + { + "question": "3. How did the judges react to Emma's caramel-filled chocolate chip cookies?", + "correct_answer": 2, + "answers": [ + "A. They were unimpressed", + "B. They thought the cookies were too sweet", + "C. They liked the combination of caramel and cookies", + "D. They thought the cookies needed more flavor" + ], + "type": "Details" + }, + { + "question": "4. What prize did Emma receive for winning first place in the Kids' Category?", + "correct_answer": 0, + "answers": [ + "A. A shiny blue ribbon", + "B. A trophy", + "C. A gift card", + "D. A baking book" + ], + "type": "Main Ideas" + } + ] +} + # MongoDB connection setup client = MongoClient(os.getenv('MONGODB_URI'), server_api=ServerApi('1'), document_class=RawBSONDocument) coll = client.ted_ai.students @@ -24,6 +78,9 @@ def __init__(self, email, interests, sessions, fname, lname): self.fname = fname self.lname = lname +def get_student_by_id(id): + return coll.find_one({"_id": ObjectId(id)}) + # API endpoint to add a new student @app.route("/api/student/new", methods=["POST"]) def add_student(): @@ -46,12 +103,64 @@ def add_student(): # API endpoint to get student data by email @app.route("/api/student/", methods=["GET"]) def get_student(id): - student_data = coll.find_one({"_id": ObjectId(id)}) + student_data = get_student_by_id(id) if student_data: return jsonify(bsonjs.dumps(student_data.raw)), 200 else: return jsonify({"message": "Student not found"}), 404 +@app.route("/api/student/generate/", methods=["GET"]) +def generate_prompt(id): + data = get_student_by_id(id)["interests"] + # todo: this is random for right now + picked_interest = data[random.randint(0, len(data) - 1)] + + # default for now + question_types = ["Inference", "Vocab", "Details", "Main Ideas"] + + try: + prompt = generate(picked_interest, question_types) + + # todo: not putting stuff correctly + coll["sessions"].update_one({"_id": ObjectId(id)}, {"$push": {"rounds": [{ + "text": prompt["Passage"], + "questions": prompt["Question"] + }]}}) + + return jsonify({ + "text": prompt["Passage"], + "questions": prompt["Question"] + }), 200 + except Exception as e: + print(e) + +@app.route("/api/student/answer", methods=["POST"]) +def answer(): + data = request.get_json() + answers = data.get("answers") + student_id = data.get("student_id") + + student_data = bson.decode(get_student_by_id(student_id).raw) + + # returns whether or not the answers were answered right as an array of boolean values + ret = [] + if student_data: + for index, answer in enumerate(answers): + new_q = student_data["sessions"][-1]["rounds"][-1]["questions"][index] | { + "selected_answer": answer, + } + + sessions_len = len(student_data["sessions"]) - 1 + rounds_len = len(student_data["sessions"][-1]["rounds"]) - 1 + + coll.update_one({"_id": ObjectId(student_id)}, {"$set": {f"sessions.{ sessions_len }.rounds.{ rounds_len }.questions.{ index }": new_q}}) + + ret.append(answer == student_data["sessions"][-1]["rounds"][-1]["questions"][index]["correct_answer"]) + + return jsonify({"answer_validation": ret}), 200 + else: + return jsonify({"message": "Invalid student id"}), 404 + if __name__ == "__main__": app.run(debug=True) diff --git a/src/api/passage_generator.py b/src/api/prompt.py similarity index 98% rename from src/api/passage_generator.py rename to src/api/prompt.py index 93dda05..fb85362 100644 --- a/src/api/passage_generator.py +++ b/src/api/prompt.py @@ -2,6 +2,11 @@ import openai import json import time +from dotenv import load_dotenv +import os + +load_dotenv() + def data_clean(data, types): out = [] for i in range(len(data["Question"])): @@ -16,13 +21,7 @@ def data_clean(data, types): del data["Answers"] def generate(passions, categories): - f = open("apikey.txt", "r") - key = f.readline() - f.close() - openai.api_key = key - - - + openai.api_key = os.getenv('OPENAI_API_KEY') messages = [ {"role": "system","content": "You are an expert educator"} ] @@ -179,7 +178,7 @@ def generate(passions, categories): My passion: ''' - streamWords = True + streamWords = False if(not streamWords): if message: @@ -243,8 +242,4 @@ def generate(passions, categories): data["Answers"] = letters data_clean(data,categories) return data - #print(data) - - - -generate("dancing", ["Inference", "Vocab", "Details", "Main Ideas"]) \ No newline at end of file + #print(data) \ No newline at end of file diff --git a/src/requirements.txt b/src/requirements.txt index 34f9e47..6c0f479 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -1,4 +1,5 @@ Flask pymongo python-dotenv -python-bsonjs \ No newline at end of file +python-bsonjs +openai \ No newline at end of file From 235d46ceda031dd39e96c34384bcb88a8c0df8b3 Mon Sep 17 00:00:00 2001 From: Will Feldman <13539982+willfeldman@users.noreply.github.com> Date: Sun, 15 Oct 2023 00:23:04 -0700 Subject: [PATCH 05/11] Added review results page --- src/app/practice/page.tsx | 2 +- src/app/review/page.tsx | 107 +++++++++++++++++++++++++++++ src/components/OverviewSection.tsx | 17 +++++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 src/app/review/page.tsx create mode 100644 src/components/OverviewSection.tsx diff --git a/src/app/practice/page.tsx b/src/app/practice/page.tsx index 940a026..6171521 100644 --- a/src/app/practice/page.tsx +++ b/src/app/practice/page.tsx @@ -54,7 +54,7 @@ export default function Home() {
-
); diff --git a/src/app/review/page.tsx b/src/app/review/page.tsx new file mode 100644 index 0000000..2639d6c --- /dev/null +++ b/src/app/review/page.tsx @@ -0,0 +1,107 @@ +import OverviewSection from "@components/OverviewSection"; + +const Overview: React.FC = () => { + const questionExample = + "What does the librarian do before the library opens to the public?"; + + const questionOptionsExample = [ + "She organizes the bookshelves.", + "She sips herbal tea and enjoys the quiet.", + "She goes for a walk around the lake.", + "She meets with aging scholars for discussions.", + ]; + + return ( +
+

Overview

+

+ Let's review your practice session! +

+ +
+ {/* Main Idea section */} +
+ + +
+ + {/* Inference section */} +
+ + +
+ + {/* Inference section */} +
+ + +
+ + {/* Inference section */} +
+ + +
+
+
+ ); +}; + +interface QuestionProps { + title: string; + options: string[]; + correctOption?: number; + selectedOption?: number; +} + +const Question: React.FC = ({ + title, + options, + correctOption, + selectedOption, +}) => { + return ( +
+

{title}

+
+ {options.map((option, index) => ( + + ))} +
+
+ ); +}; + +export default Overview; diff --git a/src/components/OverviewSection.tsx b/src/components/OverviewSection.tsx new file mode 100644 index 0000000..ac0f993 --- /dev/null +++ b/src/components/OverviewSection.tsx @@ -0,0 +1,17 @@ +interface OverviewSectionProps { + name: string; + emoji: string; +} + +const OverviewSection: React.FC = ({ name, emoji }) => { + return ( +
+ + {emoji} + +

{name}

+
+ ); +}; + +export default OverviewSection; From 4e9b11f3f66d6792afa4ea304398c554290d92c4 Mon Sep 17 00:00:00 2001 From: Alex Nikanov Date: Sun, 15 Oct 2023 00:27:01 -0700 Subject: [PATCH 06/11] backend actually working now --- src/api/index.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/api/index.py b/src/api/index.py index 9a03040..eaba609 100644 --- a/src/api/index.py +++ b/src/api/index.py @@ -86,7 +86,7 @@ def get_student_by_id(id): def add_student(): data = request.get_json() # email = data.get("email") - # interests = data.get("interests") + interests = data.get("interests") # sessions = data.get("sessions") # fname = data.get("fname") # lname = data.get("lname") @@ -94,9 +94,16 @@ def add_student(): # # Create a new student object # new_student = Student(email=email, interests=interests, sessions=sessions, fname=fname, lname=lname) - bson_bytes = bsonjs.loads(bson_dumps(data)) + student = { + "email": "potter.harry@hogwarts.edu", + "interests": interests, + "rounds": [], + "fname": "Harry", + "lname": "Potter" + } + # Insert the new student into the MongoDB collection - inserted_id = coll.insert_one(RawBSONDocument(bson_bytes)).inserted_id + inserted_id = coll.insert_one(student).inserted_id return jsonify({"message": f"Student added successfully with id { inserted_id }!"}), 201 @@ -112,9 +119,10 @@ def get_student(id): @app.route("/api/student/generate/", methods=["GET"]) def generate_prompt(id): - data = get_student_by_id(id)["interests"] + data = bson.decode(get_student_by_id(id).raw) + interests = data["interests"] # todo: this is random for right now - picked_interest = data[random.randint(0, len(data) - 1)] + picked_interest = interests[random.randint(0, len(interests) - 1)] # default for now question_types = ["Inference", "Vocab", "Details", "Main Ideas"] @@ -122,18 +130,19 @@ def generate_prompt(id): try: prompt = generate(picked_interest, question_types) - # todo: not putting stuff correctly - coll["sessions"].update_one({"_id": ObjectId(id)}, {"$push": {"rounds": [{ + data["rounds"].append({ "text": prompt["Passage"], "questions": prompt["Question"] - }]}}) + }) + + coll.update_one({"_id": ObjectId(id)}, {"$set": data}) return jsonify({ "text": prompt["Passage"], "questions": prompt["Question"] }), 200 except Exception as e: - print(e) + return jsonify({"message": f"Error generating prompt {e}"}), 500 @app.route("/api/student/answer", methods=["POST"]) def answer(): @@ -147,16 +156,15 @@ def answer(): ret = [] if student_data: for index, answer in enumerate(answers): - new_q = student_data["sessions"][-1]["rounds"][-1]["questions"][index] | { + new_q = student_data["rounds"][-1]["questions"][index] | { "selected_answer": answer, } - sessions_len = len(student_data["sessions"]) - 1 - rounds_len = len(student_data["sessions"][-1]["rounds"]) - 1 + rounds_len = len(student_data["rounds"]) - 1 - coll.update_one({"_id": ObjectId(student_id)}, {"$set": {f"sessions.{ sessions_len }.rounds.{ rounds_len }.questions.{ index }": new_q}}) + coll.update_one({"_id": ObjectId(student_id)}, {"$set": {f"rounds.{ rounds_len }.questions.{ index }": new_q}}) - ret.append(answer == student_data["sessions"][-1]["rounds"][-1]["questions"][index]["correct_answer"]) + ret.append(answer == student_data["rounds"][-1]["questions"][index]["correct_answer"]) return jsonify({"answer_validation": ret}), 200 else: From 204efadef5a9e999bbae5cf8b630bbf80713292f Mon Sep 17 00:00:00 2001 From: Alex Nikanov Date: Sun, 15 Oct 2023 00:55:44 -0700 Subject: [PATCH 07/11] frontend skills connected to backend --- src/app/page.tsx | 168 +++++++++++++++++++++++------- src/components/Button.tsx | 3 + src/components/InterestButton.tsx | 8 +- 3 files changed, 137 insertions(+), 42 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index ff5fbec..9ebc8f2 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,47 +1,135 @@ -import Head from "next/head"; -import InterestButton from "@components/InterestButton"; +'use client'; +import { useState } from 'react'; +import Head from 'next/head'; +import InterestButton from '@components/InterestButton'; import Link from 'next/link'; -import Button from "@components/Button"; +import Button from '@components/Button'; export default function Home() { - return ( -
- - Settle - - + const [interests, setInterests] = useState([]); -
-
-

- Welcome, Dilan! -

-

What are your interests?

-
+ const handleSubmit = async (e: any) => { + e.preventDefault(); + const response = await fetch('/api/student/new', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ interests: interests }), + }); + const data = await response.json(); + console.log(data); + }; -
- - - - - - - - - - - - - - - -
+ const handleInterestClick = (interest: string) => { + if (interests.includes(interest)) { + setInterests(interests.filter((i) => i !== interest)); + } else { + setInterests([...interests, interest]); + } + }; -
-
- ); + return ( +
+ + Settle + + + +
+
+

+ Welcome, Dilan! +

+

+ What are your interests? +

+
+
+
+
+ handleInterestClick('Sports')} + /> + + handleInterestClick('Video Games') + } + /> + handleInterestClick('Art')} + /> + handleInterestClick('Theater')} + /> + handleInterestClick('Music')} + /> + + handleInterestClick('Technology') + } + /> + handleInterestClick('Fashion')} + /> + + handleInterestClick('Food and Drink') + } + /> + handleInterestClick('Travel')} + /> + handleInterestClick('Science')} + /> + handleInterestClick('Movies')} + /> + handleInterestClick('Fitness')} + /> + + handleInterestClick('Environment') + } + /> + handleInterestClick('History')} + /> + handleInterestClick('Politics')} + /> +
+
+
+
+
+ ); } diff --git a/src/components/Button.tsx b/src/components/Button.tsx index ac3e699..b181468 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -5,6 +5,7 @@ type CustomButtonProps = { onClick?: () => void; link?: string; className?: string; + type?: "button" | "submit"; }; const CustomButton: React.FC = ({ @@ -12,11 +13,13 @@ const CustomButton: React.FC = ({ onClick, link, className, + type }) => { return ( diff --git a/src/components/InterestButton.tsx b/src/components/InterestButton.tsx index 3bd77e7..487dc35 100644 --- a/src/components/InterestButton.tsx +++ b/src/components/InterestButton.tsx @@ -3,14 +3,18 @@ import { FC, useState } from 'react'; interface ToggleButtonProps { label: string; + callback: () => void; } -const InterestButton: FC = ({ label }) => { +const InterestButton: FC = ({ label, callback }) => { const [isActive, setIsActive] = useState(false); return ( ); }; diff --git a/src/package-lock.json b/src/package-lock.json index b467b4f..e6ad56e 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -16,7 +16,7 @@ "eslint": "8.40.0", "eslint-config-next": "13.4.2", "jotai": "^2.4.3", - "next": "13.4.3", + "next": "^13.5.4", "pnpm": "^8.9.0", "postcss": "8.4.23", "react": "18.2.0", @@ -181,9 +181,9 @@ } }, "node_modules/@next/env": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.3.tgz", - "integrity": "sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ==" + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz", + "integrity": "sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.4.2", @@ -194,9 +194,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz", - "integrity": "sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz", + "integrity": "sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==", "cpu": [ "arm64" ], @@ -209,9 +209,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz", - "integrity": "sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz", + "integrity": "sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==", "cpu": [ "x64" ], @@ -224,9 +224,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz", - "integrity": "sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz", + "integrity": "sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==", "cpu": [ "arm64" ], @@ -239,9 +239,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz", - "integrity": "sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz", + "integrity": "sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==", "cpu": [ "arm64" ], @@ -254,9 +254,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz", - "integrity": "sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz", + "integrity": "sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==", "cpu": [ "x64" ], @@ -269,9 +269,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz", - "integrity": "sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz", + "integrity": "sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==", "cpu": [ "x64" ], @@ -284,9 +284,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz", - "integrity": "sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz", + "integrity": "sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==", "cpu": [ "arm64" ], @@ -299,9 +299,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz", - "integrity": "sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz", + "integrity": "sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==", "cpu": [ "ia32" ], @@ -314,9 +314,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz", - "integrity": "sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz", + "integrity": "sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==", "cpu": [ "x64" ], @@ -366,9 +366,9 @@ "integrity": "sha512-6i/8UoL0P5y4leBIGzvkZdS85RDMG9y1ihZzmTZQ5LdHUYmZ7pKFoj8X0236s3lusPs1Fa5HTQUpwI+UfTcmeA==" }, "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", "dependencies": { "tslib": "^2.4.0" } @@ -1989,6 +1989,11 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, "node_modules/globals": { "version": "13.23.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", @@ -2778,39 +2783,37 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next": { - "version": "13.4.3", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.3.tgz", - "integrity": "sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/next/-/next-13.5.4.tgz", + "integrity": "sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==", "dependencies": { - "@next/env": "13.4.3", - "@swc/helpers": "0.5.1", + "@next/env": "13.5.4", + "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", + "postcss": "8.4.31", "styled-jsx": "5.1.1", - "zod": "3.21.4" + "watchpack": "2.4.0" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=16.8.0" + "node": ">=16.14.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.3", - "@next/swc-darwin-x64": "13.4.3", - "@next/swc-linux-arm64-gnu": "13.4.3", - "@next/swc-linux-arm64-musl": "13.4.3", - "@next/swc-linux-x64-gnu": "13.4.3", - "@next/swc-linux-x64-musl": "13.4.3", - "@next/swc-win32-arm64-msvc": "13.4.3", - "@next/swc-win32-ia32-msvc": "13.4.3", - "@next/swc-win32-x64-msvc": "13.4.3" + "@next/swc-darwin-arm64": "13.5.4", + "@next/swc-darwin-x64": "13.5.4", + "@next/swc-linux-arm64-gnu": "13.5.4", + "@next/swc-linux-arm64-musl": "13.5.4", + "@next/swc-linux-x64-gnu": "13.5.4", + "@next/swc-linux-x64-musl": "13.5.4", + "@next/swc-win32-arm64-msvc": "13.5.4", + "@next/swc-win32-ia32-msvc": "13.5.4", + "@next/swc-win32-x64-msvc": "13.5.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -2819,21 +2822,15 @@ "@opentelemetry/api": { "optional": true }, - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, "sass": { "optional": true } } }, "node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -2842,10 +2839,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -4096,6 +4097,18 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4259,14 +4272,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } } } } diff --git a/src/package.json b/src/package.json index 1aec3dd..1d70a8c 100644 --- a/src/package.json +++ b/src/package.json @@ -19,7 +19,7 @@ "eslint": "8.40.0", "eslint-config-next": "13.4.2", "jotai": "^2.4.3", - "next": "13.4.3", + "next": "^13.5.4", "pnpm": "^8.9.0", "postcss": "8.4.23", "react": "18.2.0", From 19108a4846d3242cffc1c5f6c1ce45b5f0c33a1d Mon Sep 17 00:00:00 2001 From: dilanbhat Date: Sun, 15 Oct 2023 08:20:54 -0700 Subject: [PATCH 10/11] Add files via upload --- src/api/passage.txt | 1 + src/api/passage_generator.py | 254 +++++++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+) create mode 100644 src/api/passage.txt create mode 100644 src/api/passage_generator.py diff --git a/src/api/passage.txt b/src/api/passage.txt new file mode 100644 index 0000000..bbdd918 --- /dev/null +++ b/src/api/passage.txt @@ -0,0 +1 @@ +{'Passage': "\n\nLily's First Ballet Recital\n\nLily had always loved to dance. From a young age, she would twirl and spin around the living room, pretending to be a ballerina. She dreamt of one day performing on a big stage in a beautiful costume. Finally, the day had come for Lily's first ballet recital.\n\nAs the music started playing, Lily felt a mix of excitement and nervousness. She lined up with the other ballerinas, all wearing matching pink tutus and ballet slippers. The lights dimmed, and the curtain slowly opened.\n\nLily gracefully moved across the stage, following the choreography she had practiced over and over. Her body moved with elegance and precision, as if she was floating on air. The audience watched in awe as Lily performed her routine flawlessly.\n\nAfter the performance, Lily's heart was racing with joy. Her parents rushed backstage to congratulate her. They were so proud of their little dancer. Lily couldn't stop smiling – her dream of being a ballerina had come true.\n\n", 'Question': [{'question': '1. What word best describes how Lily felt before her ballet recital?', 'correct_answer': 0, 'answers': ['A. Nervous', 'B. Angry', 'C. Bored', 'D. Sad'], 'type': 'Inference'}, {'question': '2. What did Lily dream of doing one day?', 'correct_answer': 3, 'answers': ['A. Playing the piano', 'B. Painting pictures', 'C. Writing a story', 'D. Performing on a stage'], 'type': 'Vocab'}, {'question': "3. What color were the ballerinas' costumes?", 'correct_answer': 2, 'answers': ['A. Blue', 'B. Yellow', 'C. Pink', 'D. Green'], 'type': 'Details'}, {'question': '4. How did Lily perform her ballet routine?', 'correct_answer': 0, 'answers': ['A. Flawlessly', 'B. Messily', 'C. Loudly', 'D. Slowly'], 'type': 'Main Ideas'}]} \ No newline at end of file diff --git a/src/api/passage_generator.py b/src/api/passage_generator.py new file mode 100644 index 0000000..9b2f6ec --- /dev/null +++ b/src/api/passage_generator.py @@ -0,0 +1,254 @@ + +import openai +import json +import time +def data_clean(data, types): + out = [] + for i in range(len(data["Question"])): + question = {} + question["question"] = data["Question"][i][0] + question["correct_answer"] = ord(data["Answers"][i].lower()) - 97 + question["answers"] = data["Question"][i][1:] + question["type"] = types[i] + + out.append(question) + data["Question"] = out + del data["Answers"] + +def generate(passions, categories): + f = open("apikey.txt", "r") + key = f.readline() + f.close() + openai.api_key = key + + + + + messages = [ {"role": "system","content": "You are an expert educator"} ] + + + message = ''' + Write me a passage about one or more people with random names at fourth-grade reading level based loosely on exactly one of my passions. Ask me 4 multiple choice question to demonstrate my reading comprehension, also fourth-grade level. The first question should be about ''' + categories[0] + '''; the second question should be about ''' + categories[1] + '''; the third question should be about ''' + categories[2] + '''; the fourth question should be about ''' + categories[3] + '''. The answers to these questions should not be explicitly stated in the text, but should also not be ambiguous. Also provide the answer. It should be in the following format: Passage: _passage_ Questions: _questions_ Answers: _answers: + + Example 1: + My passions: farms + + Passage: + Lisa and the Pigpen + Peter lived in a small town with his mama, papa, brothers, and sisters. Everyone had chores. Peter’s + job was to look after his youngest sister Lisa. Lisa was three years old and very curious. She liked to + wander out of the house and play outside. + One day Peter and Lisa were playing hide-and-seek in the house, and the game turned into a chase. + Crash! Bang! Peter tripped and landed in the clothes basket on the kitchen floor. + Lisa fell on the floor beside him and laughed. “Do it again,” begged Lisa. + “Oh, no,” said Mama. “You two go outside with your chasing and stay out of my way. Don’t get into + trouble.” + The children ran out the door into the sunshine. At that moment, Mr. Brown was leading his pig down + the road. He was going to Ms. Smith’s house to show her how big the pig had grown. + Lisa laughed and ran to catch up to Mr. Brown and his pig. Peter yelled after her. + “Where are you going?” Lisa asked Mr. Brown. + Mr. Brown turned around and saw the little girl following him. “I am going to show my friend, Ms. + Smith, how big my pig has grown.” + “I’m going, too,” said Lisa. She marched right along with Mr. Brown. + “Okay, I’m going, too,” Peter sighed, and followed behind them. + When they arrived at Ms. Smith’s house, Mr. Brown put his pig in the pigpen at the back of the + house. Lisa followed Mr. Brown and his pig. When she saw the other pigs, she squealed with delight. The + pigs squealed and oinked. + “Don’t go in the pigpen, children,” Mr. Brown said. Then he went in the house. + Lisa wanted to play with the pigs. She started across the pen to pet the pigs. On her way, she slipped + in the mud and fell in a puddle. Lisa was wet from her head to her toes with black, dirty pigpen water. + She splashed with her hands and kicked her feet, spreading mud all over her clothes. “I’m a pig! I’m a + pig!” she squealed. “Come out of there right now, Lisa!” screamed Peter. + At that moment, Mr. Brown and Ms. Smith came outside. They heard the children shouting and the + pigs squealing. + “Someone is in the pigpen with the pigs!” Ms. Smith exclaimed. + They went to the back of the house and found Lisa splashing in the water. + Peter was shouting at Lisa. “Lisa! Look at you! What will Mama say? You get out of there now!” + “I’m a pig!” said Lisa. She wouldn’t come out of the pigpen. + Peter crawled through the fence to get a hold of Lisa. Lisa ran from him. Peter slipped and fell in the + black, dirty pigpen puddle. + “Oh, no! Now we’re both wet and dirty and smell like a pigpen!” Peter said. + Peter took Lisa’s arm and pulled her out of the pigpen. He held her hand and walked her home. + Peter’s face was long and sad. He wondered what Mama would say. When they walked in the house, + Mama looked up from her laundry. Her eyes grew large and her mouth opened wide. Then she laughed. + “You look and smell like two little pigs. Take off your dirty clothes. I have just enough water to wash + the two of you. Your clothes are another matter. I will take care of those later.” + When the children were clean, Mama put Lisa in her bed for a nap. Peter went outside to sit and + think. How was he going to keep Lisa out of trouble? + + Questions: + + 1. In the first paragraph, what word helps the reader know the meaning of chores? + A. wander + B. curious + C. look + D. job + + 2. Why do Mama’s eyes grow large and her mouth open wide? + A. She was angry at the children. + B. She saw Lisa in the clothes basket. + C. She did not know who the children were. + D. She saw the children covered with mud. + + 3. Which word best describes Lisa? + A. naughty + B. honest + C. helpful + D. thoughtful + + 4. Which pair of words are compound words? + A. outside and laughed + B. sunshine and pigpen + C. laundry and pigpen + D. shouting and following + 5. What is the main idea of the passage? + A. Peter has a hard job watching his sister. + B. Ms. Smith likes to raise pigs. + C. Mama has a busy schedule. + D. Many people raise pigs. + + + Answers: + + 1. D + 2. D + 3. A + 4. B + + + Example 2: + My passions: wild animals + + Passage: + Wolves Home Again + Good things have come from bringing wolves back to Yellowstone National Park. One good thing is + the return of two kinds of trees, which grow only near streams. They had nearly disappeared since the + wolves were gone. There was a reason for this. + The wolves scare away elk, which are animals that eat trees growing out of the ground. Now elk avoid + spending time near streams in the park. They have no place to run from wolves there. The trees that + disappeared near streams now grow in the park. + Yellowstone National Park, “America’s first national park,” is in the northwest part of Wyoming. It + spreads into Idaho and Montana. It became a park in 1872. The park is beautiful and has many visitors. + The land was a home for wolves for a long time. + Wolves were common in the park at first. As time went on, the wolves began dying out. By 1926, no + wolves could be found. People who lived near Yellowstone killed them because the wolves would eat the + animals the people had raised to sell. + In 1995, many people joined forces to bring back the wolves. They were people who cared about + animals and the health of the land. At first, this was only a dream since there were no wolves in the park! + Wolves were in Canada, which is north of the United States. People went to Canada to capture wolves. + They brought them back to the park and let them go. They kept close track of the wolves’ actions. When + a wolf died, they would figure out the reason. A lot was done to protect the wolves from harm. + Yet, ranchers also complained that the wolves were eating their animals. In 1997, they tried to get rid + of the wolves by passing a law to remove them from the park. The law was never passed. + Now, there are many wolves in Yellowstone National Park. The land is healthier, and the wolves have + their home back. + + Questions: + + 1. What is the singular form of the word wolves? + A. wolf + B. wolfs + C. wolfes + D. wolve + + 2. What is the author informing the reader of in the passage? + A. wolves living in Canada + B. wolves bringing good things to Yellowstone National Park + C. wolves eating elk and ranch animals + D. wolves being hunted in Yellowstone National Park + + 3. According to the passage, Yellowstone National Park is located in what three states? + A. Wyoming, Idaho, and Montana + B. Wyoming, Colorado, and Utah + C. Wyoming, Nebraska, and Idaho + D. Wyoming, Montana, and Colorado + + 4. Why were wolves killed by people who lived near Yellowstone? + A. They were eating the ranchers’ animals. + B. Park visitors were hurt by them. + C. They became sick and died. + D. A law was passed to hunt them. + + Answers: + 1. A + 2. B + 3. A + 4. A + + + My passion: + ''' + + streamWords = False + + if(not streamWords): + if message: + messages.append( + {"role": "user", "content": message + passions}, + ) + chat = openai.ChatCompletion.create( + model="gpt-3.5-turbo", messages=messages + ) + reply = chat.choices[0].message.content + else: + messages.append( + {"role": "user", "content": message + passions}, + ) + + for chunk in openai.ChatCompletion.create( + model="gpt-3.5-turbo", + + messages=messages, + stream=True, + ): + content = chunk["choices"][0].get("delta", {}).get("content") + if content is not None: + for char in content: + print(char, end='', flush=True) + #print(char, end='', flush=True) + time.sleep(.05) + + + passage = reply[reply.find("Passage") + 8:reply.find("Questions")] + question = reply[reply.find("Questions") + 10:reply.find("Answers")] + answers = reply[reply.find("Answers") + 8:] + #print(question) + questionArr = question.split('\n') + while("" in questionArr): + questionArr.remove("") + + + q1 = questionArr[0:5] + q2 = questionArr[5:10] + q3 = questionArr[10:15] + q4 = questionArr[15:20] + + questionArr = [q1,q2,q3,q4] + + letters = answers.splitlines() + + while("" in letters): + letters.remove("") + + + for i in range(len(letters)): + letters[i] = letters[i][-1:] + + + + + data = {} + data['Passage'] = passage + data["Question"] = questionArr + data["Answers"] = letters + data_clean(data,categories) + with open('passage.txt', 'w') as f: + f.write(str(data)) + return data + #print(data) + + + +generate("dancing", ["Inference", "Vocab", "Details", "Main Ideas"]) +with open('passage.txt', 'r') as f: + print(f.read()) From ce3ec8d5599384da5707803a1efb71dff9b1075f Mon Sep 17 00:00:00 2001 From: Will Feldman <13539982+willfeldman@users.noreply.github.com> Date: Sun, 15 Oct 2023 09:06:21 -0700 Subject: [PATCH 11/11] UI improvement --- src/app/page.tsx | 246 +++++++++--------- src/app/practice/page.tsx | 59 +++-- src/app/review/page.tsx | 75 ++++-- src/components/Button.tsx | 11 +- src/components/Logo.tsx | 10 + src/components/OverviewSection.tsx | 2 +- .../Passage/PassageSetOfQuestions.tsx | 2 +- src/public/readu.png | Bin 0 -> 34128 bytes 8 files changed, 224 insertions(+), 181 deletions(-) create mode 100644 src/components/Logo.tsx create mode 100644 src/public/readu.png diff --git a/src/app/page.tsx b/src/app/page.tsx index 9ebc8f2..5dabf27 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,135 +1,129 @@ -'use client'; -import { useState } from 'react'; -import Head from 'next/head'; -import InterestButton from '@components/InterestButton'; -import Link from 'next/link'; -import Button from '@components/Button'; +"use client"; +import { useState } from "react"; +import Head from "next/head"; +import InterestButton from "@components/InterestButton"; +import Link from "next/link"; +import Button from "@components/Button"; +import Logo from "@components/Logo"; export default function Home() { - const [interests, setInterests] = useState([]); + const [interests, setInterests] = useState([]); - const handleSubmit = async (e: any) => { - e.preventDefault(); - const response = await fetch('/api/student/new', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ interests: interests }), - }); - const data = await response.json(); - console.log(data); - }; + const handleSubmit = async (e: any) => { + e.preventDefault(); + const response = await fetch("/api/student/new", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ interests: interests }), + }); + const data = await response.json(); + console.log(data); + }; - const handleInterestClick = (interest: string) => { - if (interests.includes(interest)) { - setInterests(interests.filter((i) => i !== interest)); - } else { - setInterests([...interests, interest]); - } - }; + const handleInterestClick = (interest: string) => { + if (interests.includes(interest)) { + setInterests(interests.filter((i) => i !== interest)); + } else { + setInterests([...interests, interest]); + } + }; - return ( -
- - Settle - - + return ( +
+ + ReadU + + -
-
-

- Welcome, Dilan! -

-

- What are your interests? -

-
-
-
-
- handleInterestClick('Sports')} - /> - - handleInterestClick('Video Games') - } - /> - handleInterestClick('Art')} - /> - handleInterestClick('Theater')} - /> - handleInterestClick('Music')} - /> - - handleInterestClick('Technology') - } - /> - handleInterestClick('Fashion')} - /> - - handleInterestClick('Food and Drink') - } - /> - handleInterestClick('Travel')} - /> - handleInterestClick('Science')} - /> - handleInterestClick('Movies')} - /> - handleInterestClick('Fitness')} - /> - - handleInterestClick('Environment') - } - /> - handleInterestClick('History')} - /> - handleInterestClick('Politics')} - /> -
-
-
+
+ +
+

+ Welcome, Dilan! +

+

+ What are your interests? +

+
+
+
+
+ handleInterestClick("Sports")} + /> + handleInterestClick("Video Games")} + /> + handleInterestClick("Art")} + /> + handleInterestClick("Theater")} + /> + handleInterestClick("Music")} + /> + handleInterestClick("Technology")} + /> + handleInterestClick("Fashion")} + /> + handleInterestClick("Food and Drink")} + /> + handleInterestClick("Travel")} + /> + handleInterestClick("Science")} + /> + handleInterestClick("Movies")} + /> + handleInterestClick("Fitness")} + /> + handleInterestClick("Environment")} + /> + handleInterestClick("History")} + /> + handleInterestClick("Politics")} + />
+
- ); +
+
+ ); } diff --git a/src/app/practice/page.tsx b/src/app/practice/page.tsx index 6171521..51ea913 100644 --- a/src/app/practice/page.tsx +++ b/src/app/practice/page.tsx @@ -2,33 +2,49 @@ import Head from "next/head"; import ReadingPrompt from "@components/Passage/ReadingPrompt"; import PassageSetOfQuestions from "@components/Passage/PassageSetOfQuestions"; import Button from "@components/Button"; +import Logo from "@components/Logo"; const question = "Why was Julia confident about winning the Bake-Off?"; const answers = [ "She practiced every day.", "She was a renowned chef.", "She had a secret family recipe.", - "She had won before." + "She had won before.", ]; const questions = [ - { - question: "Why was Julia confident about winning the Bake-Off?", - answers: ["She practiced every day.", "She was a renowned chef.", "She had a secret family recipe.", "She had won before."] - }, - { - question: "Which word in the passage is a synonym for 'scent'?", - answers: ["Echoed", "Texture", "Booth", "Aroma"] - }, - { - question: "Where did the Great Bake-Off take place?", - answers: ["At Julia's home", "In the town of Ovenville's square", "In a big hall", "At the judges' houses"] - }, - { - question: "What is the main idea of the passage?", - answers: ["Julia's grandmother was a great baker.", "The town of Ovenville loved to eat cookies.", "Julia wins the Great Bake-Off using her grandmother's secret recipe.", "The judges were from different parts of the country."] - }, - ]; + { + question: "Why was Julia confident about winning the Bake-Off?", + answers: [ + "She practiced every day.", + "She was a renowned chef.", + "She had a secret family recipe.", + "She had won before.", + ], + }, + { + question: "Which word in the passage is a synonym for 'scent'?", + answers: ["Echoed", "Texture", "Booth", "Aroma"], + }, + { + question: "Where did the Great Bake-Off take place?", + answers: [ + "At Julia's home", + "In the town of Ovenville's square", + "In a big hall", + "At the judges' houses", + ], + }, + { + question: "What is the main idea of the passage?", + answers: [ + "Julia's grandmother was a great baker.", + "The town of Ovenville loved to eat cookies.", + "Julia wins the Great Bake-Off using her grandmother's secret recipe.", + "The judges were from different parts of the country.", + ], + }, +]; export default function Home() { return ( @@ -37,7 +53,10 @@ export default function Home() { Reading Practice -
+
+
+ +

Reading Practice

Read this passage and answer some questions. @@ -51,7 +70,7 @@ export default function Home() { />

- +
@@ -27,3 +19,4 @@ const CustomButton: React.FC = ({ }; export default CustomButton; + diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx new file mode 100644 index 0000000..2fe48dc --- /dev/null +++ b/src/components/Logo.tsx @@ -0,0 +1,10 @@ +const Logo: React.FC = () => { + return ( +
+ ReadU Logo + ReadU +
+ ); +}; + +export default Logo; diff --git a/src/components/OverviewSection.tsx b/src/components/OverviewSection.tsx index ac0f993..42d7216 100644 --- a/src/components/OverviewSection.tsx +++ b/src/components/OverviewSection.tsx @@ -5,7 +5,7 @@ interface OverviewSectionProps { const OverviewSection: React.FC = ({ name, emoji }) => { return ( -
+
{emoji} diff --git a/src/components/Passage/PassageSetOfQuestions.tsx b/src/components/Passage/PassageSetOfQuestions.tsx index a49c229..76bd33e 100644 --- a/src/components/Passage/PassageSetOfQuestions.tsx +++ b/src/components/Passage/PassageSetOfQuestions.tsx @@ -10,7 +10,7 @@ const PassageSetOfQuestions: React.FC = ({ questions, }) => { return ( -
+
{questions.map((q, index) => ( 7wQilV3)nS{pYU_gsKaF@BZtI`}A#H zQbVN95ry8ciMY9ZgXCNt?^I^igEv|{-)!te_|~eIFIwcRe zigV~s^RY~7+dLy)(AuJZ)tKDfC(1T^Y*7Xmo6s|&-lT4;ijpso4m;=i=A=Owr!8 z!>n8*F&IH{^bd>4E7*>~?8HEa4jhdxnE4o0@a34#pP#+&N4^GE^ks}3I&l5=;O)zs zE}hA{pa1mCNs5}on?s2Kw@)4=O9?@TG6%OfAWtuuxMZBP%uurS_la^X8kL_+-~41| zHY;{=_*YE3=OWENB>vo>Y+J9%WUSo*m>7H%UPiRNza>py_OfpYR$*^4Uw7f-Rk-I(fvZYyFOUY`G;_U~*JE;+n1WuJQ`D^Yf`N6NLhrB)V1%=PR9*kqOLuXTRH#v^ygCpiv^b#Ps1x6iQPmm`?%qyA?1ihZZ|HSm?>E!xFVl;LitK~B z$6rd=EhYSuRJ^j z-|(D~*R}Sd-d2&-=hc!|A0@7i5xZL-vPUJOB6@$MUmmUb(RP1SIm*5fX*E;ZzP@sD z^~Z(#+WNO;Okuh6X@sqPgbT53v5wrOd=IXW=&ttT8tEhWvZv7``4We_c9Wt2-WZlwm^NV5o z<`+K=p00KHb^lw&sf%HiJn7ro-0AW-GfbPv>fc!rlTWoEfg{!`QT8qNaC4`a(!3Si zN-rtDIQ@rhf7aQ7(to>WF(2nnYs)6mM)zrE7;~DoVil5HnW(GA1iPXFhp6b7Q zj<}es`?@>aNevx|>8dHeI1`9SGHS9MLyD&Vh6$M@o4i{@3Zny?$YWga+iWJVytrJ> zM)o^Q6w2|!zr!^+-q{~=z@#B+7uSTNz_I2?7QVWHXsVropVuWpI@f)bIq~d@i>ZuO zMpgbLnE0?(YH2TxCphQ;Y{3@!qRUrbYM0t_<$TBoNromy@`mGVfT)Y3d$tx;3NF~x zl4AHJEc1Cd5xTI8E&9OAsn^n-XU5z_cts&hBg{_a%a!9;Qnxzg<^xe^0^2TREU#Z5 zE(7&(8?U%^)tAl+E}L))dcFi!_w5$aq}(Li!Ou#w-WJw0VE$}h67;@S_74#%;pDI* zQ=J`h`Vwg>U+x4eLQ}kyn><7Vo@hf_O|Cpf8QbBMqmfOlxG0Y=zN4{lUzHonp6hAj zFYvTp4taD2_In~$mXYnN#}Q&TEsql9L@LinS;NfE6P6$E1(|ura>Nm7ii)JJEs6R; z%|{957Q;7f3^ZfZSY3`w8j?|%XP zB67Ns-f~6n{D-zgsPF2DgC~Yh?P8Hw;w+iQyx+UV9x?12UnH}=0QDVEJ+9|(yD=BL zLN86IPm7-xeoeK4@=0F61G_57ZF78i?E7s<3edH(`n8)gkJuvS+#hX3D%nGLm|#qA zUScn^51zAAIUW4UyKnd0{-frao#zlLqJj*hjak9$$IsYlw;TSpd)B@~UwkRY@#UgB zA@gts$;MozGaO;C?N@s+as#>CF%9pGR4>cTa0kkGec2ABENM zp6`|y4s&W4r0-%7%zhVgr}{yoAkF7m9lasjQ6n(VS}G!2ODK)lfw_bC$J_HP1m|19 zOor%Gz?CR`GPaoThp%z#lBdd-mzUl%ZvlA_O6}IASdJ+B+cxE~(O?Mno3fs|a^+&P z%D*A(xlRq9Kh0Uco}7Eb{KR40CAh&S=#dr5+kadT3Ck z!GxP68@y`gEyMtMhikI7qLHD(Ag zW(y6QUK%V8!OZz3ESJK$!*=2`om7zPYju6hUW9`L;G4w!E6pR3LPYS;UQ%4m*o-PW=t6P}V5T73KWv_;Q=AIFx2^`|q|JQEUkZ|@~lL)pgbG$uM=Dlt>KFa~G*ypG zW)@^Vt@0yBfTN5cIgu9WO|w`fsE_sjQuC)dO@=x>l(d}Fqq3>bij`DRLp0d7Wa+(^ zMM0UVh&p$>D1@uS!EpE>&mq_A6sZ7>u3K#x<0AC_^4P0EL;C4JEcek;x%?23RoSq^ zDyMCStQTKjH{_tM*O^-pk05PWwTF)zQfdzesAI6h2V zd6-6`C6jEri7|3qf3|p}UZ{*EOq?%1%|8A89Zr>=3b&|sz6Ac^TANgHnW)KABrs#W zmPG+dj<08G1g@*jxfh=8qHlE|0j@5`n`1Sld8>fYMNBRAOa3y|VZa%{&e}3>T zl-Zg8`y-bK1$;R(^=(TsE=MWm+U8SJD+H6)HZRRNz7&z3 ze3KH9bnrx`FE&gJcsf4xeN-!e$huLd~*W~MbY zN4}Sd23ceEc?|iW41a$mtp~dj)ZF8*Ep*VliKLohkz+-(j2^;4WD(8yTC z!W2m)Z{I0sgdlV9BVX4+O$fg9&o-nA@k5*_D(geK>6bG2dh#-ep*UfD`qOscKGf(L zffB-ScA922=hsh(-ncFs%C@%426Ct%h7aH|JtP_#qD|7 z#5-7#l3Bx0Y$g$U5+vfSIW^HUsT>msp9ZSfq%T&cLiy#$@#SEqLgs+ENiGsF;cal^iO!nfYP%aQ$(2Ik3M;q z2uaa$9DBuAM7hbOS<}E8^l+k$bk?{l(tn>00SJ6AGRQDA`kD`=2Lk%fGqkFl;X9aK zzH``N))AQat*uS467y%<(u(8DkHKSSwt$>aK}^K7Wc^m@oj{?MIA3=R(JO!Te*J*T zm*(d&?8$=k@)fIyJ=_Ry5^8Z~nk&JW$Au@(q|;n_(xEt#XtM~96FKWxcdWY}swwgr zjS@TiI8AQA9pwP+Y^}A!a0e!opo^~$Mq`zF`i{_f?V&(EuB5MC1Q`V}m=P3(Lq)c6VVf^lP|2oNZr_uKyX9 z!LLfsOFq;1Z$*hJ{ULkX)?!bP$%ADcPFM|YqC^nGBv`^|=sDH^Q?r}m)H_Xs$IACn z22-pfc5_9i_)B7SH<+Kv#&uxyaFR*}P2qC;#?L+#&GHT9)FJ!+OGU)AJozJwTUWMl z^-8m7X>(`NT^}E|fn^zj6}(+H&J!W{L*uq3ITm5bBIX~V5*;@V8-rK zLLAs*KQ)yNn#1L~cUe9@dhLXzzzDkS2Ch zN5=+x%oR7@xXk97o392%4DKijHxcLPi}+Xc0)}6jF>Vce}U9)E!lzd8y6LxG3BYknJjH+i5wZ zAS+S~maFD1?LCLqfiO8<4{wHT<2455M18m%?J_B76DdZ3y9eZr6DTf1c^4ld@92*h zPSz^z0R@&PI0ioEN}UigivI_do%~h8QF5kHdMN;21CAr<^7xV!JjRH^HeeP5^A7_8 zC(as!Y+9!=xOYj-$6TTF6OxF1htr_$0h{B}an<;dobejB+a7$A6vQpS&Irk1)Xo%G00Gv<_IpcnEB|$3q4y6an9?q;w5=tTVVv7VSF}fT14_XV1AUY&jQEeOA}vjVwS zzH&gn!x<2luG^$9*J#9Fnk5KC*Ux5|=8XFwkLdU4YyT;Svm1GWQ9HTzOl+V7mJwc+ zo2z+9CM(>um@2BRoHYSUVAaYBisJ>dGaEk?s3uaYM zu8N5)tn7#T%ayG|`2VM_lCfxSPya(*3c8kRK53-oNDdV-_D=oJlh3E~disjy8)dUD z!K)hFJsb(|#d<0@iTqd&TUo6mZem&a4s0XF?B@0&nsoezSa5>0%k)XvR)7A$ot-{N zGPp=uZbTh1&49mgNMXP|n`MygYtP9xF-zlX(DOLmFq8k+riTG$P_6TA zX;xH&u+DB7{`}G&zpi!Yz6t}=5N8eC* ziN6j85NzJG3`uIiU6sY|zHX;D3n&I~##2I&*Rz3OG$TGxlcV{L&k>_CH zmECB{Z5E`*(@U&X-aQcRuTk^SxjxRrX=iwi`E{XYzWJz}@-CEL#@)K9G`y(Imp{LZ z$cHP&CJ4(6Y(x<|wEE6$eyk$5-0@}J^O)c1lS#Jba3RAUmvag&D`2HMp)fs`BsUb2 zS;|GkbS)rVK2zS+P5Nd3X|-6E5GNEZL)#agc1pGIFCe$%kwi}s>IS4qZC%H%?&98d zd}#*Q(^T`3ezU`LZ6|HVZ*w{?dW9iE_*471r#aD_H>Fu~L(jj7WV6z&eqBRK7$@jo z{*(X01n6a*oD(5(welWCA&1Uh# zGeU70&0E(T{yY4M?>1VQD^^&ubhR#bj3m&=YY9yfef9?Yz6dE0;e$K5$^- zrInrKOqWqBW(ga1=s!#-U)jNu(Z8J)VKJs=q89-+o3guaYU1VkHa0V-RN1-bML+-r z%a-LF4lq0k%hKlIjX3`b}9831F-CS)h|OMh$k9kp5p@?3?irsw6CEmJYu$w9(uA_UzLhPj7$x z=wr0xAPQZOr9VSd-T1y`-`W906493&`*qx%~0E5JF)@khe{bLXknUhKOYjzz$+Y=nNFeX56v!U5P( zK)2de^4Qt@N*Ord7vK$aSb&L>S=vUkas)^Aor#v`?&NSBU!JIXV)Jf)dJ@T1xFtDu zA_;&SBqe)|=Qy@ENY+=0P@CkCQ_?P>Uq;&kXhM-8e4JQ>3h9Q*`ZW_mfXh^&{j75u zs2qoTgOLV$O^&1Ipkde9&7Z9X$I7K2x+35c^UXtCqg=EdY~r4rn|?rs--u5?rP(2W z;}cDi*7@6=qN1$VqkS5`Pb}M4+&grmeuurWTJlSU#E$=c88G-Z>)xnv8{HOLz!$`4 z4EnB7(^}FxM-+WZv+}{cu5JAvRE9jAA^ZwH5$NUUX13M#)rkUD6+_Y89}PyfUJrhO zcL6wlh^(JEA%IvpCgV-OIO7Z)70&*NFt{1M|i`Nq)Tpw>|+-P*I+c+{#N`LEM zNmc}9T5DP-MbQUi&s)!HI%=4Ler*fqp*?&m`B1oa7v2Efh_+iu$eaIJO2i9X{ub0q zJ%$XsdInV1+#la{X(X`L!zsSC!uZ^3Y|q4A@zFq~#i}3or&s1|CYLi!{F<*7-aNIZM(6#s z?ZVB=HAemKa@FR3kDMy2(Q%anY#unfi?(lm&057QK-TZ}Eq#u4tsZx?Un1vy@3n95 zJf0NAv;V|pb`q-f&W>J^Gy19hvEyoc@aON+zY{*clWq<*Pi#y3*nWS~c0o!ycI0=F z+50iwg|$oC!C%95ni5Zy&D|P2Bz?YTFy3hy6Y#nH;$_Kl9ZP}5uAM64A<~bE^k!q` zl!x2eUaj)K8*4A>?6rW8Iy<&YExD;xKus2QSADeB)R5 zfX{PP=|o_k0F};50wcezN3^}gz59FSmtOfcd=weXb$gMpX_co@a1g7%#bt2Ltei-D zCyQKTfTBkPIJq$el$qd8slncse61|IR^2G)7@}Fh8%&~^v!A7%wC+0_w_TrCzdGyJ zMR1nOV-Q>qh_0KBMWao^jA##np#CE;xoL?01C3KVpz_BUsa*y zeOBO5kPiB^yI&@g|2SrpFTto&4pgGxHVzZJUEqs|JWd3-Y#aZoCU^f7|Id|&6lDlA zyg6>il8?%ln5rjq5?DEZ1de2!DDU642re;wU(c&@JCJG+74FI5h9G37N;|Or4mqvu z7Y!Zjo2d#=$yX8jHN1VGERUKGXw)Txr;8hoo_sUHE$QbIoe;74At6Z)sME8_x#0`BKo!EzQyah~uaiZz>L+PENsO zr$^XVbk)qDcM5bxpbn}xaaoWf1g@a16{)dSeP`q4^~GF3KR=;*bQtBFtYxjT&Le|~ z+u^dwLm*D7u>|M=?=R2EP#4&)F9y(?a1{Q6=rANP&e$RBVxW|D-_EA(`i)s|Q^G0K zt)$LC5)RHsjrm=8j4P=-p$p@sh}jLtko;GA50gNo-n#C)H_VvU{5g|>&nLj-O&Zv0 zJ~_i2#gp0S`B`uaX31pgv#b#Skcz~3N&VKWUn5QD%_S$U6Cv}8EKqjwf?DPx0H7%^ zL53dDb+2>i8B|T?_p*LPOr04tMJx~+$j4LWE4X_M<*v8VZm0tvQ7w%FmTknk*qj*g zgr7gUa$e(G0k;4>RSez=iugcAsH0x&NG)|Yw03e|m}J;~@QCBtp1YwrVwPi{f&I*G zZ^0?-JBwf^Xi7Yl@dIn0m#POIlVD~BxXdYqZRhUggaL$Eyqn{lK#zv?T9`|4${6IbScr=gBY^}XTPQ>O9Zr=oWhXAb!Y_6MjSs^`~~ zHq_DwYG=$f+#iCzSmXA_X24<9jEGF(xM*vf_=eVF3N4IAHiL$`NF`D_Q|jVSA&;9SMzmD#>~dMv;mG0n-ksV?i6$JA|EK3v16 z+p>MT-xr?``6}0X9*@%RBU-D-mlP?UGh*p*=j$&MyEB666vl%fI#(n}@oKgzoVvjg3+mL!$d=gRQN1m(!m^Ej7%1~dgV!MH zv`i{E-R8veKX(uX4h)!^f8m2XCMus>xu_0Q3-uqhZo)>Bxmcjud#GdFYX7z%h&l!A z_jgt;KsjU1G4?UG>8Nf7Qw}6U(@vj{aSj{Ysbx8iU{?9V$YHx!^}wA!o)hOfe~de@ z;f~<>@*2*RXO(Vf5ncz*rFA|;J~+PA_;~(+B}%;+Byzbh97{Y*D9n855ZvrbVv#$K zgU={!$DAz3Ki3S^!}oHhdo21mD?7rh8a%sDrLiqav%u9E+u+bkT0V{LO z12F9sa0YA#)){lJd@{>Q$^$$J0&0n>rNaWN65L>Kp)eZQ;^!mHSt1HP@>l&N`2Vv2 zKR1GmDF>1xV+CW*8s0C8Xs)@&GaeD=cOdys`5{$t6P;&k}?l!a0BhaQ4;3@7mCo%y#FeZG<3!)p9_#|G}n48GUNKrY{~S1|5Mu6y$(@1y?LeJfn?q!+FpuMwDU)khA(#|aOH>uR3d z*m-mLr+Mf!ou4g+d9MYOtODHAz@#>SC}PhLPG+IxK8_srlq*XT4ux(D&dR-_iFiAm2#& zK)O(^CCo>PiH6nP{9&fUQR`(A*NXE8nFMX12jQVMwXbZ7XU-m?J|(*1R^_;AoO1rC z8hjfrPHd?GykJJk*u#h2U_RWspvS?F+mAaY{+8gDIKHgViKzt#h(fw}PXS~6&6g?f z)Dc07%8yy97Sz{DjM>b^a`sHUxXJtz$;a9nZKd)hwLc!+5&<4GED`DQl{Yr;?lA7; zI3|p|^#%`X*5H}wE&J5N+|}7^cI+sh#-7sEPiKn(7+!LL&FKwT%idq5A=rdFS)XGB zV6r7#aQGv8IRU8!t%{HDXowPWt~6_?Z0-gG3C9aR=MiA!u;_@jh1X8 zRlr)MhFNrH<>P=W(Kf(n>hQGv%~^3-aD)wfim}e)_b~C<`AVFell8KPh^ISD25;wx zBz+%Z4jMvdz1I0wYqNe0elrG>140?ZL<^I}zyl(qe%rW%jxYUVm*fC65sk2txH(24 zQ198$dvs}QmHyui-++QQ5nZ##@ksvHVC;qSo{yDbnGa)&8AJdmUKo3Pg6&7^Lyqe% z1U38G<+DY=$p{{>38MyJ?vsWSgg6jrkxNA|xz<{x7;9=JE1Jpns>TZ!^oWCL2@K`e zktvUH>e`bZ@CsJmM!Wr=SW4dumC_cuM!Ciongp~MAqAN9+=aeMnE4IFB+gj! z4#|3riHWtFoKycgWAQH7RZG~jrfWBZ0|}Zp?(%t!E6nm*WUTBr4;V4Pz{V0wo7UWs=Pe4IYv>|}Bi2p)`uL@YX*IYJ z3zirg-rJe5-Gy!VYO5OI59xBdJCQ1!<=Dg9Cg}0eFqQoI9A4O_cJ8R$3L@UtUo6aV$oQacJtc z5`V!I{x^k~*oTt2o`d%al07KpV}zx^U893|aGE>>p4xfB_D`#w_*F(!{eLMlns0PI ztE#h7yo(tvOHT>D4yI4U3)9lq^P5@EScACe*y$}W`Ct!EHSa*ZutHk7bVY}mH1Mk5 z`(a#5j!IFNfw!Gqgf+Sf1jTgug>EQRsFKCiaM= zz;$xeAGJdo{GxH3iSU=HuHf+4DgX;c*d%*xIJ=O zEe+I@|u)>J%_HvQo@~qy=yO07%#K~bdj$gT!}5ZB_~gGeRuS4XsoP}} z+c~|!v`kU1_>}eKOpSc?ihBc&i(em!P;RnML+N}yj}yK6=bMR-9)PGZpN(g)rT%H4 zZK3kWG_@HSTV*xx?%ajEM?Md@5?(7IMyMD29JhAmYuT)iZM+pOLmiYAm@#}W3x?1r z@QiSrz~BQ~Hg@4F(LO--Abe@q613h&17#0MMYuaHPHr5_3xV{CIbPqR%`*b~zCwY= z<%Z+Ik9tASv|8VFRpb*i+usE2phkM1Wr(Y{oK`bG>CUkQ;oNt9Wpmh0jn}*8KY-{z zcpFS!T?8%nYYvmEcVmkR#-IL=7)Un4aSgy%UsPev6-Sq#6Iwm5f2~v~>)l%!$@Qh8 zMt#~Q+!YGc7D1t#D35?_TDeBUIjE)d-4da)u;yYovuKWrV0`kYpJU<;K4 zrVAvJnm|b&t@7-fHVjlaf%n3m!%AS?AJ`IwN>drdIgWBhe-2wdW>T$x1*v&Qp2l*k zJCAPzwS}F3FY6A*9hU>12Ziq4u+bKqV5E_SprZYSm&%(WiQE~K{p~j#HLxR_WC)d@ zEi84|9sfwF>0R~~a62s9-O0}`{VLheqy1M1b^-MNK7!_mP=3$I)pi~Yyzm)x{WP5~ z%dySm+yzCSzO6)qt@_e}E~@#s&|uUYV90^MNkxPJ{+Lf0D%n5}k|5~}Uy-RzgGyC( zR~wyR<8xyonZ#~j^2Ysk3; z``Ref4oN*Fvyw^`kLqy?*0tU<1Q6K={O#}7(Z{4M-;7IqQji5NPV2%l0v_+ddA{{! zMUgS>_oab@#1~=<0D|d$&45670r?=6FRI8Sqj=*?cSd1H8>s5W&|#sj0Ru8A)UNgc z8dusiybFXrlvoJJmmi(sNlfC9VRBiJGba>{79VhjBGVY@KTtZk`#@~QQX=+*ou8J; ztCv&`pSOmls&(i?AQ&!n;Q${daDkP{j`xWo7yS9T*{FVAfIz6HZKA$V>kv~q1_|?- zUZMOFt{t`e^%eb`;&H&lrR83@F!iRIj|ac1&;=`7(tE)rF_!JLTHZr&p#jM5#+SkL zxjt^m7MYF$x|b5ehU_T~;!jVa9wNP$Ys3f+vIa%|!?8ovnAtPHl@)jg6*?nWNmL%v z`_1~-nwyI*b&M)4zayr)17f?lkx1}<=Iqc8Fax(2%Erj^2?rEfnEdn|_S+9PfAU9O zqBgISqTD=eyMb({-2ENwTVJ1^CQ%344$AUJTHj`yv_BUs6aCkY!yMQJh5{MR4*_!E zXLZ>4=dZvimtNSOtxp6j5Q)o1oNrZ;XL?o-z-y>l4;-^@5?tD@;iO6H-{T#LvWd0< zPJ=ae-FVNBsMj=Jb8;?jtpW&SRmrOh?tGU#U}fB$hMrqWcC$gx)uFsxd#7vL)@wFa zfT2R4obgXcZllU_`5wf`P_WhtF006j;NzOHRgS`bKQzEdgirQ37O|vTRMnMN@ZmJk zNFWRvAOlEM)deeajs}==VQrKK-WJnpQ-X>4<1Exj`wPuKYR*v5HORLVDLbg1uZORm zT4)h}Y8UqhB+&pm!57N1BGkjSg}DOc+TxPjFS;*i;{|o*gZ`D@y$PV54dlksM8hnm zxAbiR4U#9MPO&M+X1<3#x7+4F6O-#v<$YB}^iXF)481MjWiZj#(lZq$k4X;(X9Z)q zBSb;e7qF4oFbE~n_$ab9mt^yVvl+Dkd5bXiPc!P)#L_HKwCdsBJp^vsNGlAa+$6Ze z?=Zb*3eE9fLXA|)~zG-80FOr@El*_2w9_@|>qm`jk6R7xRn33PD zZW5eeCq}>ff=-;<#wR78x$74yin9%(Sv>tvwt zjsXvpKolyHmX;KJlD~hyRW00X-&tQ(ccxqoGm^o40CXNd`wlsW(g>+cQoo;6@dNdB zk-;jOgiz@zx-we+#n0+`E6*CFWRW9N)zJw)2{0bX*U)qO*1{#CJDTd&?q)?O&p&xB z4Z7BZ!NKJ1*;?~88*kZTZvJmx4-uk+fkf=ddThd5ATT083m2x`{Qbd*p6QftqWEDkdLTARKK*bGylYIe|!{x!Clq5zX)hGdK4dm<6+kLBnjb%dlZ8&uTb)YU6vP5erlt zRJwtz!Qz02rb(<(eUE}I%Z!_YvL@do z>jDZ~GVQ^^k~3i+{rR_)zMv|?fZJnsB(#9<;mrmS z)7=+dsPYgdUl}fU%`3bg`54S&RuPTxlX!Qa5?ZHpW)O-{`#3m@zL_e*ESOmY(-OQM zn8x>2mpYFl;L#S)Rx8uEuTJ%Q-op=uty(jD4QK+l1$Ug;Zeq~+6A0ZW6KQyx9BXHJ zG?eJNDQ{rF;~Ngk8b6x}*x_ z5!`A5P@+r>1h=9FHmKbM@}=~t$)qN&dHHf+Zw7W=* zA#kIrBCUi9u8((a@DT?1Fe(x+n}vQwbFKpAUix#Zj&y-2qyy;1g0VeMc#JNBnFH}5 z^+9S;IFr08;b7L8L)MuUFMCgk*u)JlP}IP#LX+nFkks*1#y&t6AF_`NP{)thDTl-$ zWxyBW$4@}RT}S&^Zkxd<0k9|F^h6+k{{zx{;YQ40HBF+TcLv|m2<$c`np2+R7rHMj zjbzgg`#OQ5WEQ0`bsAb-+(q54{wxwHeZSpExl639f&%7wr1hC#`!#j!$N(_RJW?Mm z*GP76$0hji_h%7v`C8=l+rqa}w-_6CqB1)+5MB45;6FzNSdF2moZiRXLAhBrC5zU4 zR`~IMi5p<8@jm^$DX4}nSmA^AfyQeH<)-eQPAYgooV-rxvP15nVXxr|nG`=0$zkTY z?_0P?LdW`g8O{%Sb_tbFk_=d=Fn@h#;&?I?;xC1vO4B|LfiE?1U9R2)3PJaquP){*f;W553G3tIE5i=^BHS0bSA zMzo}sq64&j__a8^dK{I;A{J|g zZo+{!RW{2Zd)xqd1yp%>&h9fXyB>T`ahrB;~qm_+0KB%!7r@}0Tz;(E%I zSEy|*NGLG*ABgT$RyxZ{O8bjQ0WV3QVo;!#WMga4@&&wKUNubh>jmuWV#!bjxnKf7 zUr--C#A)Ga56%!~i`Zc`p3MEj3>g%r3|i^qQS61wN-?3JPXQYyNH#tM&}%jG7b&Qb z6eGk12te$9!4De7n!%zxM#_B|qhv(P$s3L@TLu@I*mz53kq$OT@Z z`>%rzq)DYEcx~Ay6??S#C{~o`+fIw~p-;Nj*6w?L*0PKB9~fEm3@mIPi@v53`snOU zla&v>bHny+82!73$xKo`p4;$t7g6ZLaqtMN{q_J;u93GFY! zM|%%};ccStdYALFS;8;7zA%2^jE?zdkR^J1x}1+DUuP%gHi>e@yvL^0z}gOv$$!8Y zn1NFiUwq-jA7SW8xUXM`i|j$iAFYy&xCRC5;HK23dWFA8m8qtJ#x;gX%=_*_OL4%S zYd3P;F*Q816+H^`FP?yDE_EFGuqYv$)$^iD z?{$#qb#hQKSIi$$td$NE2(ife5Mf|D+8j0;nuSv5h{PameWuw zu!@_EMc=p}XRyno%`k;I`?AZHzK<~vEN&99mt}uw*rWz@T$En0#VdY%UXy_(J`Nx& zz*VLml!U9bvg>&?ZjKs(Llt!VF{2pa@*ahX$dRI4BWGYdlicO=-m)?;cRdWY$om*P zNA5MbBGultYRtVmB?B8y%XrtM+&m_G$WhOCA{#ub1|R~@!kKMNqD!eM`jMVL&XR&~ zz7xq{R@_bd5jM0MNbBTD@BnjM0Ykw~W<@6LBCMosue$Uw$ww!zvjvmwY@Kf~E$)kO zyyYw6o$(!qpUy1D(@B*_{Mxo`M9qi`zkVf9M`unhc7`AI$f;XKj9!hepy_3yJ*R@S zj}H)gFU<2DcNg zmI-$i6HpsCuAjgL$%~2{=gS})Xh+6!qPw{5? zX$1+lv;#pdM{erYJtTOOEY)Bq)aJUAGPvD$;uo?=FT7i4C6yJW&ou8-)Q$}1u~o6we(`|2n-TJ#U0ag*~uOa}w$L1P6!^%>B| zEm<_+Xl_7AA@^W3l;-^DOIP3SLY~U{-STJnrEhhuYIWm_h{w*``!&nDNwK9bhg503MlFyq|og_WLYBa(OOEh$nryF60;{CnmBu=kxA7BIdrp~1OW zo0PWSuWb`*D`K}#6sHPA%ME=(BhL@s%){S|z1=zPslWcoW@VqAaAMSOWP@O(UOw%} zX`tZe$~wik8O)3quxV2%qhI0k2a9EIic6|?qq);AGRQK$_}PDg zQ~Gv)#Lr;k5**C_5gUNJh9#D;tO&5sjlRY};fJjI2!nd^`B@KdC2n!*Z~knSgzv;* z#Gd{T=(kT{$;z+V5je^jTcPpjEhv-U4{-cN!$)r?fV9GIYl5ut3^p3364h_d(-%>S zhPlf`&Q|YNQ=kG*{S14qIdJ$hU?xllJ{Djk^BGHqdmjjX`1AI>12Xr3;}A~n<0O5H11Imbv6Wbf;(P->K9nw#CqRy(pWVZ&azr|C0|1yy>_}M@z+5sFH@Q;I&>I!VAq2o+Q z$5eNu=9Y#xZC|SSmH?B2^0epH5b3*-R*sZ&xDjUnx~d~0K|HH+$_mzFwQAha{xzcJ zOu?nDICbuO5Z>(CWJbK==gO&_u!Ox|h)4ln0RSq{pSv>65LEn3?O!|O{8+-l&s2Wt zEKL}aVw5rxd%L#Xy+^Zx!>zwdgbwN7Q|hvD?bExAp6+(_>)Q$WO%{Kh1O1W(yReYZQi-ku@gJuVJy zDGhJN>nkXjHtHA8yzBw+qKk-tfqAJ*7!U#@>O@)xALBH=3b28X+#5FjIiZ#mWU3vh z$Wd;r)TFw|Q6hzsnfy7qk1%}r99-bGj*LqaC8FW)z``NX$z3|{cWFqEl|#<^R<^PgUF_-o{hQ}&V`b;Z6L797cC-VhL>)|D5c8+rZWS5aI#{Nk zOg<#324V4(!4eyjPfJR2K{uGejKp%`UEl0aPmCbDkZnjF0Lop>nmYb!oswZjpR>9) z=k5Jh6J$3?{IiC4eoEtg0Orrx>4kG(W-UH-%*veRcWCAz(F?i3GBZSn2D_=pIHy2( znYL2=dj$Rl;}p#Qaqa5B-}mvES0W2P?kZM_VteUeneW+3xBQZ zle;{LNCF?~OBxbQK5O;14dcNt;{r;k^4K#BV?efUr#AFstOF zL>(`o7C{$2mnQI@aa0*Ejd8bpIzw7JdBFp$4W`cG>gZ74ZP#r}(V(I`qa8`%;K`Z= z?g-PcjxJyCfOykMYC3wDgw2)5K!_Pml;+0l2P=1LM{Wb7#8TdMz=vK}39s6_dj%aC z64i;Mafo?yLg3YKMTm9J+>rU^WmhTv2j(7Ur*OrGAW#ryrZm>2Y3kp+!RqpmThav6 zgb#>vd@W6&$i~Ru%6&XBRd@791m|(R!1m3|Bou3>m-Z_`!TMw!Jv37slY6*}_5ZT~ zet+aS7Rd3<<4t+wPt|t}df0ilR-gUZ%54GR%@$Y16@%0_@8CCU8!0+tjs!dlC;lUg zgdieAtG8PENYe;)KHkcE37~};a9z>;9#V3v7|O7^OK#oQrP}OtM%QQ!$Uy0I8%^bz&vLV zM&>vuGMc+Kb5xz$hugJNnUi5TMDe7;#MJJ(btgwIrZ_7M?6#uPt~)VD|fIR02W(m5}7A5a?kJO$g~H_-<&tj5c(9DL2~9noNp zT&W|Jk$Knw`P(1Zt>JH1ta~ZIP@xwZh&w1fPGsiV^OzEbDRr&RedCSt`te7-TJ*rm zcX%-9><%nU_*$$T`3e+b&S-qE^H$?mA1T@v(db_3Q>lxeZCw1S1q!U@0xF3W&ovc3 zL!cIea&oU>?eHOl1(kHgZ}uPY#+XWRQG+X?ua{993vbx?==Wajxf|%}?A%xV1t;3U zkF>}YJy>DcW7rGnHNeh}NH}r;pe~r6I}jN)m<9xcboO2OBMth8lIU7o2(C!yrP#py z4OXu=Hj@d}8jif#-QDYhJV&r^4-mWikC8L2y>wsV2(lU=Ua*`W_ad#}KTo|*Peg(w zoJrJK7mg;djATc_bj{#fqDtrP9hQGn-syMKcka=vxHTgmj%q!0A+)! zf}b;A#&Z>&MMB%bIgh}5pY>sh8K1m4??)C-3&)l&6}mXQ>{4gQqvBV;myM=@P%O}% zb43y{ufYGBIX0ZD;oG#n?gzm=PcOzygGz#^o-N`(F$Gu+f6?Xqx&Z4gF<7aa#Q3@Mx?A5Rz_fGFBz{>D}>qIKC zV&5b#_VCjuz^wJY6WV0F{yCg3&+vIwS_d!ron?@ysL0hhY5OVbL4Q!SI*!f=v{V@; zv9r58b}X5)@GO1_t%^XgrLT>G+if`3E`AA{qC)}9_E{NYX2e8uKn0fll+9tS7ybTn z4!LqMoM=00K)$eEetHXNz^_?t|suUUW5JI&jW-K5a&aAyJ*JmKU5NpPrI?Y}ZS9hoqdgh(A6;7JF@>{i!VFPLcg{o4g$nl|Q4 z7+yBNC%AoUWs>dpdw+zvmEnn@P~X$@A&26?9T6?5<`+U%G<_q1zu zrv#WED*mv2DU7yB$l1?SWJ#AL3ak>^gYU`D!VylP`RX06SoYmwCXv|DIvW zB}JVays0qwsVA=TXug%>tB}8QpC))8TD@!7rTE+tM5`ua?5DOL)c02*-;9Haq05u& zx$ZbGyd014?sP>e*$$r|DVpdm>uaZ|X_4C`-yQ7?GCbAi9Cid$r)xR6nz%O0Ie{i# zo2fg3^g>XH^5qU$IfIyq1+{3JLxMc`amg^>%yv=dqkInQz7qsQnbA$J;u>6GJJ&HN z^w2|3lkYz13iiF{l)LQ0=~&_@L3u^ner~?+29VHqVu&6|7or}1y&_{VRnt$uLG6jN zE6B(Kz?oV`4<=u!(S)X2@0^~X+%qqi*PiP=(X=8e3)SBH3Dvn8tD= z`yR%=N0gX}G9^p4%p@vO)h=kq+z+0S{O z^C69C*DlSAu@AE~=*k?)NWV=MytX%)^-ghrE;c>m=&3YZu_n0&4>6?Fu(wD)c z_)I#%n3FNO3LOKoXcW4wN_akptmgjrI0zp9yc|1u&sh?$QI4zL9@I=cr2xdW`mwQB>)L(Xt=BosX`jg4gzkM+Ta8h+Av|I`NB8yo@o%8?*5RPrEUFL?vW?ua4 z;cm`hFzQQn-yBg}01k@X8yYAG)`L~Rn=gt#cprEBbvpA6&wVWJmcv>jUw0A3C`z=G z)K)lY08NngbG`xUymdW> z{7q`a=D!Hk87YiCi-UJ8J0PweASL3O7xtV^LGh4`OI$9LXI z%1|&rKSHmNAJ5@#cht20JZ+?%ptF4Y&RH|XrFTqr1AgHhcYCtuEx2f(zpvbifBz3M z;X@5l3m@!~{vLnRk%rbNW`@?gLjTX$JjLDG{V}+Px^GT8WQi_2uqx2-0@g5F7Qax& z-Og(1aK1>r{c)Kc&KA)2d6I7#F*PLa{ZS#ZGe{eww{d`&dLLI)FK!Pa@1kve2^itT z!8C?4ys61NXz%)#Dn;|P?|VDPT=W0D_E6V?FZdFp1^828(g}X?oE@+Fk0<;_#PSlO zz$WQ$Iqyjp8_#~@o3A})6!9qb!ZZ7f#@Rsk0QV%u>bb~V#Xq~xXM-;lXQuV-ct#QV z^Z_K{<3{je6nCYC2pYz5gDhFINiFW7^^4Xr%TFkBXxIUp8GE? zK*O@%0|K^b53ySRm5A9`-!h3aNAp4L>&Y9)HC~iCDHf{^;ioeC4eAFt?%X{T|1Wy+ zSDDl3gKVrh*=og5Zj~_qp1b{=PGnH0G%bOiM3eT-w+wV+QmpR(WKDj*{Bq?M?WqjB z@*1|;auxPwu|YKNhhZ@FgZ* zk?cPvpq*yp z0Sx_ZhcAwVw>XWza!yPgaaZAx@nQavxjOr;o;90BRN2DM&(Mm~&q=Jtk=AeNcE2@C zx%?q>((rjcTbAwVYul)f4#wu(-F5Q%w&z(z4Pz!+^HWLqh40)wLCGDX+0@Ams{s!{ z_h0=%e@xG&ZKG@XDWTmCE=9HWrwtjmJ+av#LG|CdzB%Gag^?D2+&TAznDtm8mfD4D zJzFa!ty@~w`nwhVL~m>f+%zMDhopp`lh@=vdJDt?{M5pT+#{P#$&AA zPIq-Xt?4QBYyURT4qHEq13x#TNZiFV0(UHf}bi>nL{$A_hH@^ zXIXqfIZjhO&3RBpJBhPgo&su6v_S|m)mGQmQ>jwp&G;}o__@R8?L^UNLT9uyK-IY$ zTvSGpan#HHG!23kI$^RIk0OrSG1t=AKARU!dli_Sa&sYPLMscp=U%Qo2@#J!Q_w$p zQ10`O$tE}M)w-CUXNGMz3d$DUBT?jDB9qS<7pp| z8VWFny6-MFlh@v^UBazz^s?Wv^{qqFZpHK}_$_o6OD3Jw48?bzcv8mPZH@o4Y>(5W zlG!h5Sr0C3d$jiROjp7EBa3fq2b~XAzF3#TTx)BUUu9(!E#KgA#^Zn45{jPf+(7sL z&Rbpx)PnrM;SQT}#m>GES~upy6~=T~>z3oxuA95OB64aPlHX0x#+dJ0Y)+%g9!c3| z^gjYef_9F0GJWKgn#cYOru5%tjj={he>*ZJ(3D1SDlDNrC5;GH?Lmj%2-{M$K?!AjDU`^ER z!>HdQgJMsr@#PO|D%F2g1Y-=GNixE*clDFBsdv%w1iV&Rg73e?lT^|=X1*BS(N$`g zQDoAPJ-KCW@uI#!n5(Ks>wKJetR<^oxdok1z^{NIjy7)VVPo&cHSFtr5|UBmcnuXV zhaa-VG8J;F&s<43(~O1}c)eQW^V8 zjeIq|Cac-PG-XT+?{WzYE=xe5OKgf^!TylSM4`6+wOlcXfaU*vdLf>1kw}!~*$~ye zJ~=*_93Tes1q`?3SwxuJL?Ml0*7Z6ao(|BiBMZ0Zp_)!} zH{&~#6a(!m%W>ONUP0vllqd2uNCFbkjx%(ch~D8-n{ ze{1EUSkCycz4JtO1DXCEhuQ1@$S=4r6VdF_N;!?xqes>DjP zt5Bd|o}-LOM&rz3&JbH#emsM_$Hh}XS{y(-RPp&mt_U}Wp)0E^9?dg<9b)o+;~L+u z9W!gr@pDo9O5c?VH{q9ql-^T$ys<(4c64!=Wn!PlTimR7N1xWHLR3e+=bynk+aep| zkT`eoVS$n9l`s+{*|TXtSs>4WaAZszU%(%CNbAoYf$9wHcxCj|(Ke5P!{4F6ta{xB zo9=k3Wa?>uh8>UeczdZrXSW~QhV67Y;@^wN4G35lsxT-z>seW0J@Q2R<$2RK)|>Nu3+jO%Q$f3=X>zCg?2UK$p1t5$c)Rz1;= z3w0?Pa6g`6?nj~0W}LGp<(UC}fbIsF`643HIjwPpAzj+~Z?MbU-6K$MhS^skfKtrv{yXo&{AOOVQMhoZ(EJOA?tOi;5AYs9 z{v9C4o-fB=0tS($x%ffOyr}tcGWE#JEqvI?$lM)Oi9#=N1Lz|0F}=N=7E+fOx_qm< zI|c1m#Nm#PHxgF&hkB9L!T#KWl`y94+_)_%rPTmjikdRGBgW{l2>zM3j8!Xm7F^>Y zYNeSL;W$?iz>(_2U|t;GGGApmOfIN+d};DSpC@tr9(RusaNNaNIwY%WUoE;zUGtj|KadLuQ#A90j0r{q`-ra#0$FkpbbQFIPJxAjJ;6Ym z)(Mb4wI4>2C?OM)Gw%$pqbO#aNOp--o8L44kpY$6+#SG52`V03={b!ad*ikc`ZZKb zIi$gpzwBmB?3znsXo&kr8dBcwsTT#FysJ;Us7$Q9!z4zTBL$&i720RoX_Gd)($-g^ zgJ+oyQdJ%ZiB~WZ;6J+)5=H=J^5%~AP*BreVzVvbC=|tifyAAQ*yyj~^_wA%pWs+< z%AwluaFaT}E$01J{D*tE!h_X`O9f8&fqkxdW&TM#(S;0tt6@vski|yaI~aV0u>{Fc6m!kU-NyX`QULkv>~78R#xEp{ zt2(0Wo}EFwXPtXpKp6v;HW|ksRXn^bPaf!kVOOq!=^kOAho5HwfcU9(Ke5~BT*&ZxFdfT>19y8o@j`emWJ=H+B@KgGTUrVuKhCbg+S z#;L)$?E<@{*GwU^C@hyRk2g@*a2L@+wX4t%F7)~cen9z}EjC@8Bd?t)s&OAjELr)A z=|T@;ms1!umlu8i1gt@4_MW9nie_Svh2*(^Yd9kpH1X0<5IbADmA0I+$!+z^PKrI0 zQMR~ef~8H4vm+dGOfRu3j6WP<>YDK`N)3?hlAYqDx_?gRDwenC+>*Smx^w{;>^!6r zdzu{8$U#6xG)%$x3qqwl6AJK+Td?to4=|f-p*a5!0zZVl$wlvVlP8}qrJ1xnwYGK` z2+OJ30I*z$dKqrJ+GS9}xdM4m?6aD>v1JC;q)&uGe&I4~{>^I!H`9O!rd9+{fPD6n z(f6Q?)1{Aoi;uP?#TM!&J5mLvHSFNVAW@TEEKlsZ)6hC~4HC|gU9Ie0+TEY?Mexe~ zFM4(&PlKy?oelE;Jap5%E~j){CZln}m6iO#j&J!AhY_( z7RRz4`Uc;YG>XS|Zhjm297f=QH`Cs+MBfHhSPf25mWmo=2VH`k?q-%&kq@T(3ga@2t-V1KRFEQ{@Fn<3c>;A$mr6lO}JKz`0 zS;@8p2MxdAyL~b{Vk}8bclEElcquw)37k(JcgIA22%wMowdX3J^Gvmxrk>*$8n}C; zG${55gIoxQ{Ck9~of?a}E;9fi)Vu!JpiDQl$WdTjxJqrlh_UJ#Cc6zhrM_iE3C75p zoeR_5Bc@vmcd9AO(}L0|mOLD93u|DClNq&(4fmA{mPXJzY1U0>hG*0s+T2&iaCv;H zm>Fq&^DA9}>Vxr&PW0s$QoEu3PU7%reTyS_9AYtKcE3-cuzT8V?DC!boD(?ocyQ zlRQMy=}HNTSZWQ^)?geQ<|$r->v&Vlz6=5>?qUV-)dw1=)0{C6E4TIYlTB0f)SE-+fpMM# zvtIuI_W7tEH+>_(_mTYj<8WaadW3pOlfMJ-$dX$!TxsCev-mK9c_GeuP)gz>e(VeE zWSPVFjXeaWCBQd%k-bOgIhI~QPX@ybK^m=$KBRlzH5t^OMzG0=51_aYGZ+SRBfnyC zgDXe5saiB?nw_rcvA&Ot@3OBu3}^$8n0tqs}~&alB1C^cddw1gh6pYrY(h8-(#S7{P)(b_~@R=pIiVn(2BTffZppQdp z>!uZOY@PjjZ*0oLMf7PSEw zoW@SrLScRf)3v$jAg|H@MouCu&65d$?P{z+i~E4!_Y?tbGa}wmVcNGziQY z${E+zk0SV8f~#+xWpKrk!c9|7qnt24P>^X$Ve1X-=!bzx8=?Q1dI1LGI(-E--J550 z^@NWDhYKDemSQjLHF+%hc+L0c*?YdErSb)%y6!=3c+?-5RTRXo+#1A=sp8R_#mE(E zl6{M*FV#uW_MOIPA-P>R{(LUtA36(UPKw~CP;UIeDyc-FVO0*46p**a**^xua64&! zAkNPf2YL6iXP}YcW)4;d5_fSRtqI7<*7}!K$PqwxS{>#(dIhPR`^LD>{kOw|uoY#% zVok~un>Raefi!ut_Fq4!lM|&z_kO?*svLj-#<;*Pd%sTWmJBauc0nWkUW%m&BEO)%oH{0HLfu9B=+7a8?iV0H@%_a*%WRPkSRID<-qiQt3h9)neI^nz}r zIeB(Fy9CNqbiGZh@zx39MSc$wBkifd{N=}Q82Q5-W>zsH8Wk;HwLjDede}^D`KYKQ zJM8flz{Yhhx+6;G;UC2D9{|e=0UQ&iX5T!Z*AjtyVV`w~E{*Vmi)?*Qsxcn(yVSc{ z&Xb3U{Zq>h+#i5!Mvfo~P~7EUBn(@5E`qniB=s2X%5wnxM}{)04kdRFE(KZk0$Bzg zm1B6p&0X%uiF~%Pruy%9bp(~R-h&pWF)ExI`i~UBsK5ZIvpo9{%!QW*D}q@74+(~c zoS>>>%B}x9mj7YW`j%DM&@hNF-C+n8U|*0dx{ttgrO?CH`3-)e_vjc?#)G9B2T zfg$qs@+SEV+&Jkk0^&Jynth(~EU-$agX|HjWP|@`8dPG850iteWEWt4*s7F8nIE15 zhqa-tZ>*M#@L)bR^XPVBvxU~lgqDo|#{yJuWFX6Dcmp$;Sg1I80p|>PBAgTcI7?eU zga_dsp})o1%7orqF+kI6ATH2{YdeX?QzEX`6fH!1&G%=@kFN}PXzMu(OyBHq77)z+{#?tWcaw3O z5TxlV=+l=0K%$8;AC0^{X7Iw1df z+cBr=YZx5ug{aat2IH)6*98{`Xcftg^t*Vf+zQGnu-^&rabCON7n0!YfUKG1@gYyt z><-;Ge+ypXDKISyCavw3j8(;iuX@J*8oCmu9nu%WFhzwBBNF?FR8`dFR`x<{u?|j_N${`1A0pBNzND<0T}@ONwHFVyON$% z>N8$+EB`xIZ3j%`9c+@Nbch5QJ{jFY&?S2UP;#$3mLM0@1beNvL6*R!h!KfY^nJ7} zL`Fid+O=1f2v8)N@D`ZPsYO@|#-?O`#<0^Me!$e|&Chhif=*7cJc0fD_M48rFv{)k z6U7YsI=~wqZ0{h@t?ANXD;Kma_VtdA)ESX<6?_23GcAs|rNGllW+dlB5vO}pSv^Y` zFFg0VD{}S&t!06X5b;{VvCVHXR{wy>{87l|+oIoJWkQ(W^N+(beIgW)ZOf1dMO4YW z@-!09Be*s%V~#LlUVXuN9D87k912=)ju^Mi(cMsXfD_`Me89HWTzn1hL1-9?&=45d z%V6tUq1AKHWa#^qFE#%i-<^CAC&YASfJV6_j`!g?cr)h6PQTbeOb*u7jX){{3L;%j zpBzo*kKLF*>TblT=5Ft0mkT%T(;6zl-R=R-{v9gE>?y$z$2W7-v@sZkl78)sD_$R zzvn&iS;x%MO1|j+u$lU;%k>o?);_Qq2^geuQ)mv_8j1H{Oz2pZ0bmt>=NU@QHXmAS z`Ur(8P#jyD{?r;mvXroqkCzbb+Sw-Pey8gaV_4frzY-u~LLHmg=b+f0aBn}*M7Iht z$13tCZ6RshCxO5FcX{Fs0LDt??xzK50km?vKcvi_LBs?ppE!_?{-8P3;4@0zov@M3 z-4~Z23-fKito2#c#8adGTjT?4=MS@GF=(epx`J3U!1-l;;B~Fyld@d2m4bg23cA!XrV%6PzaQUQ`q1Nf6mQINgZB{kW=G#sAyI z*u^sVk@}`1yR_B!sj7z_RCI1Pj5coR+>%1DFIWK}Dw)-h%`=57srZiNHn9&#| zGpU^Jp1`t}B18+mLErD}P=oVtz$T~3|1-2grX<5HO&EKD-#Zlu-8}yqbpAmg*qNh< zj0~ByJprPo*pXtdQMaw=f0ZYew*KXox~}=F7Y|t;Swv&w}5B zc95*6Qys@O2R#103ora~iB^|iW@#v_By@rV^L??QkqA*Xw!qlHbCDuHcfr*lR&8<| ziZ90qN3=rQcMy7`gElwmY1sh_o4~af`yheA@^x6jg@gqgOW#I!K!BLT=O;gKR&237 zh2T8ycccax(|KFnh@QpywRpt6-UBaTLj06ltG$Zf;apr7{{^;>mW)Z~7n-}~O0 zE6`M;n^cu(etRz>U|0Z$_kN4Dzuy0Mm^jj(?!n%=7s8jYjcD@!=|QnqIJB zNHi{`Wa1UoUIox*L%p78TfFIQS`CY)2HOy*_kdi_D;Qj9D3h^Z!&1>2!Q`wLvsWwF z1r<2W6Ugt6LEI>+B}u2;WPu= z&}NJx!oDkOMcnzFrM#|+1eeavghN(7hJr}@hW2(XU;bzNNi}Nro-p}V6^X&VUS=R& zGu$h3e>)S;T7lL&q{C~Ag-Z(>i2q1;J)vi)?DCoy|#8IM6}9)Ehm^>kM5igrYgP z_6dRiF^bwF#;Vl(UQQjtY7UaoRO*4d`lbcI-iN8`!lMGJ0JHQb^St?ug;R)hq8<E1r#P;mlSipU2)`i4dBv3h%Rq^Ue+w!a$%Sjq zxWNq$o5Kw*wf}_o(;cLB<)ZDV!M23rG}x5K91>81-@CoUuIpt)ac}*s$>K^^_CI*w zTmF}{(hvwX`-?;R$}e_S0_VTl!a;Kym}?!}J?FqQY`G3OL&xPGAhqA+iBwDhPZ#0_ zK_g=cyNB7}9GQFI0n$YhN#BO#5q^NrM1HcU$dXWNamq82VpY&0>5%gOB1W;_FKken z)>Q%2(qzdi; zEJ4C+GPAVxRJLOI;D4q-)~vVw3C!aLu3%_ye~fA=lI(q87MZJFoj4FK{P_FiJ|Mpk zh2+e)&X~-*T(mHJh1$L%U6ybPCUXxyLb%ce5)ZxG2}iX)weLVfyot>dYSPe>vnCV= zsCv{cLu$1aCbl6tc`8SxUeQsi?i}5TE(|vyWzsM4xKcMXv01JIIZqP8!8XL!iFw?Re8j%NgY8mcZAy<9kU z?3Y>*ki>KW@_IrA0A_k-Co_^E*)D7Yo-8$<)p9zd4A;w-Q^mt6%D8k&VH|p$tKs-#1{CpPD9`;J1CUM|x6H;-66jyptgN&tC?QA9D)s*Ab#dXhc zU7b528TmpVp~ILMz7D{iMS8|<73?r=%T0fjH;2H~Sm=5k4#=GM7AY%w7oL-D}8eV=gg%(2W)@fUSVG zGAuwBy+j?Jy@09(|KL4vH)j5Y^F2hl@dRT*20?B zl)dYuwm??ck`v}Mk~i{FWVJ-hf#L8|^_W=sot&bMU$~c{JIKi#0(caBNG4_Yk7&0@2Kl6b^g)OaCLbcZ*-0Ef$}!S@ z$@8Cdd%D+joXYsNmGX8K$^C-&nqK6m%bHy4?nXLFV9?W-j?rScaA;~R@Ih99ZYna~ zh8OPJ^5v~ieF=oe3U2_pSQQAVZe7|2(O-+_xd)aYi?UDtWCJ$*pK^Lg4rNE?>j4F)fy#PUXor!R?`xO zgtIv6?tr=cQab_QlYCI#dgpQU`PHhPu&rh;H89`1Lf9S=rCI_#9M`gHS|@q-*`&%Z zbq1c%mZJXer*O;32P_?0pGa2~hl`h3=3{1<%te2!Bp>DNrY*Qz28~g;5|~Dk)vt$N z*g7xeF3fq?4t}F&0=HMz&JM1W9&X>4-I+ z-5vzQxM+inY)t8nJu63$#d7x(wyMDH` zKlbVwFCUJ(y9c%TUR3TQ`)5ZB_l*RV?#oAu4}y3FU1n^9(ZoM#Hj#a%Pc$W>dFxfR z?hfJl_$hCFb>ZVo4l;PxbW?6ZGF_QI9RN?GD!b$6o8KLN=PnT7K>cd8#%s>(@mzmU$>(i##|HyYTp!M@ma*N(G7;orhp?3Cu{W#1Z zI^M~^v`^Jz_PX`|{@xs;G0($cy@QrdrjRPCtE1x@JVF5;AtPWtq{{d89>Bwn?t+kf zgHJcF`lwm2ZwKZp&!i94r;*~bVWPCh1SmFSLPAcrEf17la5;g*y;{QF%;Du&s`&U_ zQ7k`~vnMhI0BB2AB*R0yPQJvbsJy)T{Zll@pR?YPXJcRna|CB0Pz(543VPrF5(D5; z81W(KUG6x})@~m@mzl3v4nS{-Dj$RmWy@jJZUaGk!SWL1UFT@V>;mt}p4!$eP-#-% z_xUdga6OkCN#!V4f!MoI;w3&7@NJ6&ZU(Qa;6>rPZ#VvP>m6F5s@vGYU z2FEu#Zd_&FFCkF>$f=3~ZMOG~{CLSb=-*UKU;(W(wLsTxoTOa^3 zkuDP_NMtFbTJwV@H;C*vEbE-aduxMNsnvx3n^-D+W*vyDMozt&mIl-Hz3Z9-r&xt12B`MSe|b}nElUFwtxNyf$iCP(lyV|YVV z_EZ45Og6Cgkgx=L4eE*x!i^IIa~pjQ&!RH4FR2y=4({+fWx;Rpy5rgqu6i#}OLyCG zms8%q|J)>QpXifBE_^5*dT`G{t-JlW8bw&~d+Tt~BVPm9XKC>Wi!vM7{+t`Ip-YP8 z1Z3kmJRs{k$eGVMsHu3A1y;5M6vA}}b_`RmCMv!2L1HaPdu79JVs#YE!the(Uq;8- z8Zi2`k}#)v}2iwB-rmcil4T0^+$(86EPfBLQ?&8oUgop>ta; z7;dkvcsrhgVzcQSZGA0T63ucDrzzVl5MU3**&FHoYL@64;>n;{n9Lz56y^70hxgQ@ z%-tY4)E)DwjQR&r=?`QC0`d#pxvVlZ=*XMkk56j86h2m448#ke@<{aK9_*snF9PXV zW&U7zU#k;y08VwV5_*Q2dWXCwonS{GGBB0BaT4LM68YvM4x7J`X17~)=WPOaa|MpI z|G!5_Nn}#2F#LU@2e+t}A`kF6eqepoY$P8kk%TT8a z;NM3sTy$=a>};q_h_W!t`8qUN}Ej z5+6pX5J^qkJN@b%y6B=>9ke7Z@;eQ>9nxdRcz@QlD(K+-idKK!;qL+{2GyYip!oo3 zcfzuy`{vMdzYonngUfSKfgXAXge4%Z?9Tut(R3~RaP(>93A~>%>6X+<`d%LUXRObr zV98*|fN==nu{%CkVk&i`kp7&VCbBSIQ|LOxXujUc@#7R0##&SCBM@a? z4&$>xnVO3#KtJK;PKZyyLb0b|SqQsse7Mu;bkXQ2sG0)Lh5z{Y23D*2tl z-MVr#Em5&t54jO>#2lUz!=FY^9ghl%h){sP^Fn&S(_{fu1i#nhsbgnz8b6gH%yf6s zIw}xZ@^F%84w_s?;^ZmzT9cgaJB?HA$bvNDNy2;-M}boe_W8hYwq{jz)hzzcWFswS z;o`~|ZQ|$+O2%%mz4SDU0Vd$L(b(Ev@c4~p#4)FklL7%3r=RxkwJ^>q`hEawNY@f8 zI?lq4Li1YQ*x+@b&qtuoWe&tTgHwX z&=draV9J^uSMPLNdv_nb0CN^I7d#QGozl5v}ud2_wIM`x}J*w>pyvESv%EEMsikhkNw06PtNH<9MR*5qig z;=tQU*NjlAasrc(DTn(%o`p%ZdpUJ{&p9fpM^ z5)TuF;4_w$3+Yrc>n8YS$M9#-mBP@$|Ey#5&Ls(epWW|SyVc7JbBBur5QOD>T;7#< zA4*}ks`s1k!a6X)yXqtI{m8J($qMG7_%O+Nhj#6fyU3y3m8$-Tj;G4%%_IX-&qu)e zS~>66GGMlck@$t<9LM$xw~ChGYg@ePQp*W4Tzlc+3OOxAE49`5DENs==1s5ab5QPwK?3Dugq?+Ab+mkD{z(QbD)KI8S0J6= z4^o>vdk&4ANb>95DT6h`9H=VP5b5;(Qt(tfTLm#S)tjTENcC)|45eF0=g}_snokpG z%IQiz3skDC4B>%`jDU3NNM9MHIRJV!U#k!|FuDcRp5wo4Q{^MaoZ&k$Q&FF;11-R+ zH-0Jzz@{q*DHA6#A8rLY{fdUo4G}gq?bdR8^yC8!im;GZrc%V%-L&}oa1;HE2-+NG zWujW3#2ky-hg#H%XkU&k1ZG;U9Tli$k@Bgp9)^O zEhyU|DAj)4%%LC$c_)ESrq|H<*iXRIz47l64x_^`EWq*#KJm-LjwbpyF?DmD6`s2g z-+|ApkYYjoD!4A4o@F@~kGU^!r+8ha{vgq{`Hr%ls7@2O)#*`x>p?>rx8UiApFV#T zTM&c|c~wiLj&W1vX_Cw}uG;?BuOAM%} z_$POifo-NtbCn8Dn+{R+8Zko4h*I%*T6>#C_%3-OlKiTCSqca(bAXnlr zgF0O)8HPAKMjopKa0Hg7+Co6qkw<^nJMPWWUfYjZADCn#S0N2|-bGC)V$P-P9@OMvdK-x^&NwaHHf!hb2eg8@Uq@8o61 zee1y_mtzeKXVc+X^WJ49|0u30ph?5=nUn~=jNVdq!|2`l5LCPfJ^;Bo^FaIpr1%A8 zghqvAc-A*X-}c|*_s!uY6&L&{aqmX)K zpVs+xUFpj&H9m`E#>mS9|Crh*5Kk)3OL1PjbLc;tcDz^)dQ-_M3`YDNv*YWcp(3GT zRX6>2`i(msUR$ijQ|w!b;{xqfKd*(=yRMgcNTN^}V>0RRiO5)tu0FBZ1+JmQi8v0` zC?b5;!jk=z-O08r<c4Cfk+i;f0ce#PC!uQc4(Ltnj05>}tTu~@_ z480@xF!Y@(E@o>*zic_*OP>~9^4ZN{RY_?snsK`6G4`#oyUQJ;7+tYw!BBng#&ORqeD(0QLUQ4}V7tX_i7mxn zgWCi*1VF;EskgRP%hP|-f6~rjSGxI&PYB*qswj@tT>Xcm^FD134S5rr+9S}&lh|P> zvntm9v=(a}W$V0ohR;yg2V3Hlf4h7jo?q9msm4*wBh!@nm3OA|;z=D$E^emj_0Q7^@_^zjdA zYGB`+I^2Gs>@76x!p_V}9^A#Q*~u5A^Z7f8rTVqVd2zpBt^{5zjgdAxbLlX2ZUT*Ct*vb>&*$H#Sa!bZn^AK z?7rF%cb3PV-|)cdf`9wmo!Tsy!}qT+D0Rz3$R9(mqG>{{m$H@4;@c!m$K@IGxTa}_ zXNBj)XRM{QdYhf~(SHX2Qh)VQ-P=91W#ir1pFb@UC`zFXd)Z(t#&YNrb1(L0Dqmi$q$_s$AFg&6_QgeLqXv! z4O6Kr`<>1No-HtV|D!VgYjn4h8!Mi#{0gJ?#Bx0U(G>Seq0B!~@Q-Y4L8?6Be*XUe DKT%G~ literal 0 HcmV?d00001