diff --git a/2-python_basics/problems.md b/2-python_basics/problems.md deleted file mode 100644 index c4630a7..0000000 --- a/2-python_basics/problems.md +++ /dev/null @@ -1,157 +0,0 @@ - - -# Variables and Data Types -## Basic Math -* addThem(int, int) -> int - * 20 - * return the sum of the two given values -* remainder(int, int) -> int - * 20 - * return the remainder of two vals... -* divideThem(int, int) -> float - * 20 - * return the floating point value of a divided by b -* divideThemInt(int, int) -> (int, int) - * 21 - * return the integer result of a divided by b AND the modulues result of a mod b. -```python -def divideThemInt(a, b): - #... - div_result = - mod_result = - return (div_result, mod_result) -``` -* convertCToF(int) -> int - * 20 - * given a temperature in Centigrade, return the equiv. temperature in F. (c/5 + 32/9 = f) - -## Strings -* returnWithQuotes() -> string - * 21 - * return a string containing both types of quote: ", ' -* strUpper(string) -> string - * 21 - * return a given string converted to all upper case. -* firstHalfLower(string) -> string - * 22 - * convert first half of string to lower case. -* justEvenChars - * 22 - * return only even numbered characters from a string. -* reverseOrder(string) -> string - * 22 - * return the string with it's order reversed. -* listToCSV(string) -> string - * 22 - * return a list of words from a string containing comma separated values. -* undToShortCSV(string) -> string - * 23 - * conver _sv to 3 words of csv. -* getIndexOf(word, my_string) -> int - * 23 - * return the index of a given word in teh given string. - - - -## Lists and Tuples -* sumAllItems(list of number) -> number - * 21 - * sum all of the items in a list and return the value -* smallestOfList(list of number) -> number - * 21 - * find and return the smallest number in teh given list. - - -## Sets -* convTupleUnique(list) -> tuple - * 21 - * given a list of objects, return a tuple with only unique items from the given list. -* convTupleUniqueOrder(list) -> tuple - * 22 - * given list of objects, return tuple with only unique items, preserving order of original list, so the first time an object appears, it will be found int he resulting tuple. subsequent occurences of the objcet in the given list are ignored. -* createSet(obj, obj, obj, obj, obj) -> set - * 21 - * given several args, add each of them to a set and return the set. -* removeFromSet(set, obj) -> set - * 20 - * given a set and an object, remove the object from the set and retunr teh set. - -## Dictionaries -* 10 (6, 'dict_example_1', 'pocketContents() -> dict') -* 11 (6, 'dict_example_2', 'myPricesDict() -> dict') -* 12 (6, 'dict_example_3', 'mergeToDict(list, list) -> dict') -* listsToDict(keys, values) -> dict - * 21 - * given a list of keys and another list of corresponding values, convert them into a dictionary and return it. -* getDictKeys(dict) -> list - * 21 - * given a dictoinary, return a list of it's keys (only), no values. -* checkKeyExists(dict, key) -> bool - * 20 - * given a ditionary and a key, return true or false to indicate whether or not the key is in the dictionary. -* checkKeysExist(dict, list) -> dict - * 23 - * given a list of keys and a dictionary, check if each key exists in the dictionary, return a dictionary consisting - of the list of keys and boolean values indicating whether or not they exist. -* printGivenKeys(dict, list) - * 22 - * given a dictionary and a list of keys, for each key in teh list, print the key name and the value assocaited with it. - -# Syntax and Namespace -## Truthiness -## Branching -* getTruthiness(obj) -> string - * 21 - * Given an object, return "tequilla" if the object evaluates True, or "margarita" if it evaluates false. -* twosTruthiness(bool, bool, bool, bool) -> string - * 22 - * Given four boolean values, if any two of them are true, return "twos", if any three of them are true, return "threes", or otherwise return "foobar". -* carmenFound(dict) -> string - * 23 - * given a dictionary of cities with corresponding boolean values indicating whether or not carmen is in teh city, return the name of the city if carmen is in the city. Reuturn only the first city where carmen is found. If carmen is in none of hte cities, return the string "false". -## Loops -https://www.w3resource.com/python-exercises/python-conditional-statements-and-loop-exercises.php -* loopStarPyramid() - * 24 - * use nested for loops to produce the following pattern: -``` -* -* * -* * * -* * * * -* * * * * -* * * * -* * * -* * -* -``` -* getFibThrough(int) -> list - * 24 - * return a list of fibonacci series up to the given number. -* returnNoneArray(int, int) -> list of lists - * 24 - * given two non-zero integers, return a list of lists of "None" with the dimmensions given. -* convStrToDict(list of string) -> dict - * 25 - * given a list of string values like "Key : value", iterate over each string, split out the key and value, and add them - into a dictionary. Return the dictionary. -* countDigitAndLetter(string) -> (int, int) - * 25 - * given a string, count the number of numbers and the number of letters in the string and return them in a tuple. (num_numbers, num_letters). -* lastNumForSum(list of int, int) -> int - * 24 - * iterate over a list of integers and return the last number before the sume of all previous numbers is more than the second arg given int. - -## List Comprehensions -* convertToAllCaps(list of words) -> list of words - * 22 - * Use a list comprehension to convert the list of words to a list of all-caps words and return it. -* getEvenNums(list of integers) -> list of integers - * 23 - * Given a list of integers, use a list comprehension to return a new list contianing only the positive numbers from the first list. -* onlyCoolStuff(dictionary of product coolness, integer) -> list of products - * 24 - * Given a dictionary containing products and a numeric rating of their coolness, and an integer value, return a list of products that are as cool or more cool than the integer value given. -* wordsHasBees(list of words) -> list of bool - * 24 - * Given a list of words, use a list comprehension to return a list of boolean values indicating whether or not the corresponding words have the lower case character "b" in them. "b" is for boolean! diff --git a/2-python_basics/problems.yml b/2-python_basics/problems.yml deleted file mode 100644 index e41dd8d..0000000 --- a/2-python_basics/problems.yml +++ /dev/null @@ -1,761 +0,0 @@ -basic_math_1: - imports: from random import randint, seed - posttest: '' - pretest: '' - seed: 0 - setup: seed({seed}) - signature: addThem(int, int) -> int - solution: "def addThem(num_a, num_b):\n return num_a + num_b\n" - tags: '' - teardown: 'print(''foobar'') - - self.test_results = [True, True, True]' - text: "Write a function that takes 2 integers as parameter\nIt should return the\ - \ sum of the 2 integers.\n\nE.g. \ndef addThem(num_a, num_b):\n #your code\ - \ here\n return the_sum\n" - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -basic_math_2: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: remainder(int, int) -> int - solution: "def remainder(a, b):\n the_remainder = a%b\n return the_remainder\n" - tags: '' - teardown: '' - text: "Write a function that takes 2 integers as parameters and returns the remainder\n\ - from dividing the first number, \"a\", into the second number, \"b\". \n\nE.g:\n\ - def remainder(a, b):\n #your code here\n return the_remainder\n" - unittests: - test1: - - int(3) - - int(5) - test2: - - int(10) - - int(1) - test3: - - randint(100,500) - - randint(100,200) - test4_x4: - - randint(1000,2000) - - randint(1,10) -basic_math_3: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: toInt(float) -> int - solution: "def toInt(a_float):\n an_int = int(a_float)\n return an_int\n" - tags: '' - teardown: '' - text: "Write a function that takes a floating point number and returns it\nas an\ - \ integer.\n\nE.g:\ndef toInt(a_float):\n #your code here\n return an_int\n" - unittests: - test1: - - int(7.2) - test2: - - int(-3.4) - test3: - - randint(100,1000)/randint(100,1000) - test4_x4: - - (randint(1000,10000) * -1) /randint(100,1000) -basic_math_4: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: divideThemInt(int, int) -> (int, int) - solution: "def divideThemInt(num_a, num_b):\n return (num_a // num_b, num_a %\ - \ num_b)\n" - tags: '' - teardown: '' - text: "Write a function that divides two integers and returns a tuple with the first\ - \ value equal to the integer diviion result, and teh second value equal to the\ - \ remainder. \n\nE.g:\ndef divideThemInt(num_a, num_b):\n #your code here\n\ - \ return (sum_of_them, remainder)\n" - unittests: - test1: - - int(7) - - int(5) - test2: - - int(-3) - - int(1) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -basic_math_5: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: divideThem(int, int) -> float - solution: "def divideThem(num_a, num_b):\n return float(num_a) / float(num_b)\n" - tags: '' - teardown: '' - text: "Write a function that divides two integers and returns a floating point result.\n\ - Note: the result should be a float even if the division has no remainder...\n\n\ - E.g:\ndef divideThem(num_a, num_b):\n #your code here\n return the_result\n" - unittests: - test1: - - int(7) - - int(5) - test2: - - int(-3) - - int(6) - test3: - - randint(1,100) - - randint(1,100) - test4_x4: - - randint(1,1000) - - randint(1,5) -basic_math_6: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: convertCToF(int) -> float - solution: "def convertCToF(temp_in_c):\n return temp_in_c/5.0 + 32.0/9.0\n" - tags: '' - teardown: '' - text: "Write a function that accepts a temperature in Centigrade and returns an\n\ - equivelant temperature in Farenheight. \n\nThe equation for this is (f = c/5 +\ - \ 32/9)\n\nE.g:\ndef convertCToF(temp_in_c):\n #your code here\n return\ - \ temp_in_f\n" - unittests: - test1: - - int(7) - test2: - - int(-3) - test3: - - randint(-100,-1) - test4_x4: - - randint(-1000,-1) -branching_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: getTruthiness(obj) -> string - solution: "def getTruthiness(obj):\n if obj:\n resulting_word = \"tequilla\"\ - \n else:\n resulting_word = \"margarita\"\n return resulting_word\n" - tags: '' - teardown: '' - text: "Create a function called getTruthiness that is given an objct and, if\nthat\ - \ object evaluates True, returns \"tequilla\", otherwise it returns,\n\"margarita\"\ - . \n\nE.g:\ndef getTruthiness(obj):\n #your code here\n return resulting_word\n" - unittests: - test1: - - true - test2: - - '""' - test3: - - '"a"' - test4: - - '"()"' -branching_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: twosTruthiness(bool, bool, bool, bool) -> string - solution: "def twosTruthiness(obj0, obj1, obj2, obj3):\n items = (obj0, obj1,\ - \ obj2, obj3)\n count = len([o for o in items if o == True])\n if count\ - \ == 2:\n resulting_word = \"twos\"\n elif count == 3:\n resulting_word\ - \ = \"threes\"\n else:\n resulting_word = \"foobar\"\n return resulting_word\n" - tags: '' - teardown: '' - text: "Create a function called twosTruthiness that is given four boolean values.\n\ - if any two of the four are True, then return \"twos\". If any three of them are\n\ - True, then return \"threes\", if less than two or four of them are True, then\n\ - return \"foobar\"\n\nE.g:\ndef twosTruthiness(obj, obj, obj, obj):\n #your\ - \ code here\n return resulting_word\n" - unittests: - test1: - - (True, True, False, False) - test2: - - (False, True, False, True) - test3: - - (True, True, False, True) - test4: - - (True, True, True, True) -branching_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: carmenFound(dict) -> string - solution: "def carmenFound(cities):\n for city in cities:\n if cities[city]\ - \ == True:\n return city\n" - tags: '' - teardown: '' - text: "Create a function called carmenFound that is given a dictionary with a list\ - \ of\ncity names as keys, each associated with a boolean value indicating whether\n\ - or not Carmen is in the city. Return the name of the city Carmen is found in!\n\ - \nE.g:\ndef carmenFound(cities):\n #your code here\n return city_name\n" - unittests: - test1: - - atlanta: true - menphis: false - redding: false - test2: - - atlanta: false - menphis: true - redding: false -dictionaries_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: pocketContents() -> dict - solution: "def pocketContents():\n inventory = {\n 'gold' : 500,\n \ - \ 'pouch' : ['flint', 'twine', 'gemstone'],\n 'backpack' : ['xylophone','dagger',\ - \ 'bedroll','bread loaf']\n }\n inventory['pocket'] = ['seashell']\n \ - \ return inventory\n" - tags: '' - teardown: '' - text: "Given the following dictionary called \"inventory\", modify the pocketContents\n\ - function to add a 'pocket' into the dictionary with contents 'seashell'\n(a single\ - \ string in a list).\n\nE.g:\ndef pocketContents():\n inventory = {\n \ - \ 'gold' : 500,\n 'pouch' : ['flint', 'twine', 'gemstone'],\n \ - \ 'backpack' : ['xylophone','dagger', 'bedroll','bread loaf']\n }\n\n return\ - \ inventory\n" - unittests: - test1: - - '" rofl this is cool "' - test2: - - '" ABCDS"' - test3: - - '"zABCDS "' -dictionaries_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: myPricesDict() -> dict - solution: "def myPricesDict():\n my_prices = {\"bananna\": 4, \"apple\": 2, \"\ - orange\": 1.5, \"pear\": 3}\n return my_prices\n" - tags: '' - teardown: '' - text: "Put the following items into a prices dictionary and return it:\n \"bananna\"\ - : 4,\n \"apple\": 2,\n \"orange\": 1.5,\n \"pear\": 3\n\nE.g:\ndef myPricesDict():\n\ - \ #your code here\n return my_prices\n" - unittests: - test1: null -dictionaries_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: mergeToDict(list, list) -> dict - solution: "def mergeToDict(keys, values):\n resulting_dict = dict(zip(keys, values))\n\ - \ return resulting_dict\n" - tags: '' - teardown: '' - text: "Given a list of keys and a list of corresponding values, create a dictionary\n\ - containing them and return it as output. You may assume that both lists will\n\ - always be the same length.\n\nFor example, if the keys were ('color', 'flavor',\ - \ 'texture') and the values\nwere ('red', 'sour', and 'rough'), the dictionary\ - \ would look like:\n{'color': 'red', 'flavor': 'sour', 'texture': 'rough'}\n\n\ - E.g:\ndef mergeToDict(keys, values):\n #your code here\n return resulting_dict\n" - unittests: - test1: - - (1, 2, 3, 4) - - (5, 6, 7, 8) - test2: - - ('1', '2', '3', '4') - - ('a', 'b', 'c', 'd') - test3: - - ('1', '2', '3', '4') - - ([1,], [2,], [3,], [4,]) -dictionaries_4: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: getDictKeys(dict) -> list - solution: "def getDictKeys(a_dictionary):\n return a_dictionary.keys()\n" - tags: '' - teardown: '' - text: "Write a function called getDictKeys that is given a dictionary and returns\ - \ a \nlist of keys in the given dictionary. \n\nE.g:\ndef getDictKeys(a_dictionary):\n\ - \ # do stuff here\n return all_the_keys\n" - unittests: - test1: - - a: 1 - b: 2 - c: 3 - test2: - - 1: 1 - c: None - ('a': null - ): 2 - b: {} - a: [] -dictionaries_5: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: checkKeyExists(dict, key) -> bool - solution: "def getDictKeys(a_dictionary):\n return a_dictionary.keys()\n" - tags: '' - teardown: '' - text: "Write a function called checkKeyExists that is given a dictionary and a key\ - \ and\nreturns True if the key exists in the dictionary or False if it does not.\ - \ \n\nE.g:\ndef checkKeyExists(a_dictionary, the_key):\n # do stuff here\n\ - \ return exists_bool\n" - unittests: - test1: - - a: 1 - b: 2 - - a - test2: - - a: 1 - b: 2 - - 1 - test3: - - a: 1 - b: 2 - - b - test4: - - a: 1 - b: 2 - - c - test5: - - a: 1 - b: 2 - - '2' -dictionaries_6: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: checkKeysExist(dict, keys) -> dict - solution: "def checkKeysExists(the_dict, keys):\n out = {}\n for key in keys:\n\ - \ out[key] = key in the_dict\n return out\n" - tags: '' - teardown: '' - text: "Write a function called checkKeysExists that is given a dictionary and a\ - \ list\nof keys to look for in teh dictionary. The function returns a new dictionary\n\ - containing each key in the provided list with an associated boolean value\nindicating\ - \ whether or not the key from the list was found in the given\ndictionary.\n\n\ - As an example, if given {'a': 0, 'b': 1} and ['a', 'c'] for keys, the output\n\ - would be {'a': True, 'c': False}. \n\nE.g:\ndef checkKeysExists(a_dictionary,\ - \ some_keys):\n # do stuff here\n return exists_dict\n" - unittests: - test1: - - a: 12 - b: 2 - - - a - - c - - d - test2: - - a: 1 - b: 2 - - () -dictionaries_7: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: printGivenKeys(dict, list) - solution: "def checkKeysExists(the_dict, keys):\n out = {}\n for key in keys:\n\ - \ out[key] = key in the_dict\n return out\n" - tags: '' - teardown: '' - text: "Write a function called printGivenKeys that is given a dictionary and a list\n\ - of keys to look for in teh dictionary. For each item in the list, the function\n\ - prints the item and the value associated with it in the provided dictionary.\n\ - If the item is not in the dictionary, None is used for the value. \n\nAs an example,\ - \ if given {'a': 0, 'b': 1} and ['a', 'c'] for keys, it would \nprint:\na, 0\n\ - c, None\n\nE.g:\ndef printGivenKeys(a_dictionary, some_keys):\n # do stuff\ - \ here\n # return nothing\n" - unittests: - test1: - - a: 12 - b: 2 - - - a - - c - - d - test2: - - a: 1 - b: 2 - - () -lists_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: sumAllItems(list of num) -> number - solution: "def sumAllItmes(some_nums):\n the_sum = 0\n for num in some_nums:\n\ - \ the_sum += num\n return the_sum\n" - tags: '' - teardown: '' - text: "write a function called sumAllItems that accepts a list or tuple of numbers,\ - \ \nsumms them, and returns the sum. \n\nE.g:\ndef sumAllItmes(some_nums):\n \ - \ # do stuff here\n return the_sum\n" - unittests: - test1: - - - 1 - - 2 - - 3 - - 4 - - 5 - test2: - - - -5 - - 2.2 - - 999 - - -1000.0 - test3: - - - 1 - - -2 - - 4 - - -6 - - 123.1 -lists_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: smallestOfList(list of numbers) -> number - solution: "def smallestOfList(some_nums):\n smallest = some_nums[0]\n for\ - \ num in some_nums:\n if num tuple - solution: "def convTupleUnique(some_items):\n return tuple(set(some_items))\n" - tags: '' - teardown: '' - text: "Write a function called convTupleUnique(list) that accepts a list of objects\n\ - and returns a tuple (not a list) with only the unique items from the list. \n\ - Order of the returned list is not important.\n\nE.g:\ndef convTupleUnique(some_items):\n\ - \ # do stuff here\n return unique_items\n" - unittests: - test1: - - asfd - - b - - b - - c - - b - - '1' - - '2' - - b - - a -sets_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: convTupleUniqueOrder(list) -> tuple - solution: "def convTupleUniqueOrder(some_items):\n out = []\n for item in\ - \ some_items:\n if item in out:\n continue\n out.append(item)\n\ - \ return tuple(out)\n" - tags: '' - teardown: '' - text: "Write a function called convTupleUniqueOrder(list) that accepts a list of\n\ - objects and returns a tuple (not a list) with only the unique items from the\n\ - list. Order of the returned tuple IS important. Order from the original list\n\ - should be preserved; the first time an object is observed in the given list, \n\ - it is in the returned tuple, and subsequent occurences are ignored. \n\nE.g:\n\ - def convTupleUniqueOrder(some_items):\n # do stuff here\n return unique_items\n" - unittests: - test1: - - asfd - - b - - b - - c - - b - - '1' - - '2' - - b - - a -sets_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: createSet(obj, obj, obj, obj, obj) -> set - solution: "def createSet(obj1=None, obj2=None, obj3=None, obj4=None, obj5=None):\n\ - \ new_set = set()\n for obj in (obj1, obj2, obj3, obj4, obj5):\n \ - \ if obj != None:\n new_set.add(obj)\n return new_set\n" - tags: '' - teardown: '' - text: "Write a function called createSet that accepts up to five objects, adds them\n\ - into a set, and returns a set of those objects. Hint: \"set\" is a data type.\ - \ \nDo not add any of the objects fo the set if the object is equal to the None\n\ - object.\n\nE.g:\ndef createSet(obj1=None, obj2=None, obj3=None, obj4=None, obj5=None):\n\ - \ # do stuff here\n return new_set\n" - unittests: - test1: - - asfd - - b - - b - - c - - b - - '1' - - '2' - - b - - a -sets_4: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: removeFromSet(set, obj) -> tuple - solution: "def removeFromSet(a_set, an_obj):\n if an_obj in a_set:\n a_set.remove(an_obj)\n\ - \ return tuple(a_set)\n" - tags: '' - teardown: '' - text: "Write a function called removeFromSet that accepts a set and an object. \ - \ If\nthe object exists in the set, then it is removed. The resulting set is\n\ - converted to a tuple and returned. \n\nE.g:\ndef removeFromSet(a_set, an_obj):\n\ - \ # do stuff here\n return new_tuple\n" - unittests: - test1: - - asfd - - b - - b - - c - - b - - '1' - - '2' - - b - - a -strings_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: returnWithQuotes() -> string - solution: "def returnWithQuotes():\n my_string = \"\"\"'It's modulus, \"%\",\ - \ not division, \"/\", or escaping \"\\\"!'\"\"\"\n return my_string\n \n" - tags: '' - teardown: '' - text: "Write a function called returnWithQuotes that takes no arguments and, when\n\ - called, returns the following text (no whitespace on the ends), but with all quotes\ - \ shown included in the string:\n\n 'It's modulus, \"%\", not division, \"\ - /\", or escaping \"\\\"!'\n\nE.g:\ndef returnWithQuotes():\n # do stuff here\n\ - \ return my_silly_string\n" - unittests: null -strings_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: strUpper(string) -> string - solution: "def strUpper(foo):\n return foo.strip().upper()\n" - tags: '' - teardown: '' - text: "Write a function called \"strUpper\" that takes a string as an argument and\n\ - returns the string without any whitespace on the ends and all upper case.\n\n\ - E.g:\ndef strUpper(foo):\n # do stuff here\n return foo\n" - unittests: - test1: - - str(' rofl this is cool ') - test2: - - str(' ABCDS') - test3: - - str('zABCDS ') -strings_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: firstHalfLower(string) -> string - solution: "def firstHalfLower(foo):\n length = int(len(foo) / 2)\n result\ - \ = foo[:length].lower()\n assert(len(result) * 2 <= len(foo))\n return\ - \ result\n" - tags: '' - teardown: '' - text: "Write a function called \"firstHalfLower\" that takes a string as an argument\ - \ and\nreturns the first half of the string, all lower case. When calculating\ - \ how many\ncharacters of the string to return, round down - an 11 character string\ - \ would\nresult in 5 characters being returned.\n\nE.g:\ndef firstHalfLower(foo):\n\ - \ # do stuff here\n return foo\n" - unittests: - test1: - - str(' ro3! T2is is cool ') - test2: - - str(' ABCDS') - test3: - - str('zABCDS ') - test4: - - str('123456789') -strings_4: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: justEvenChars(string) -> (string) - solution: "def justEvenChars(foo):\n return foo[::2]\n" - tags: '' - teardown: '' - text: "Write a function called \"justEvenChars\" that takes a string as an argument\ - \ and\nreturns only even numbered characters from the string. If the string is\ - \ \"coolio\", the result would be \"coi\", treating the zeroth characte as even\ - \ (0%2==0). \n\nE.g:\ndef justEvenChars(foo):\n # do stuff here\n return\ - \ foo\n" - unittests: - test1: - - str(' ro3! T2is is cool ') - test2: - - str(' ABCDS') - test3: - - str('zABCDS ') - test4: - - str('123456789') -strings_5: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: reverseOrder(string) -> string - solution: "def reverseOrder(foo):\n foo = foo.strip()\n foo.split()\n foo\ - \ = foo[::-1]\n foo = \" \".join(foo)\n return foo\n" - tags: '' - teardown: '' - text: "Write a function called \"reverseOrder\" that takes a string as an argument\ - \ and\nreturns another string with all of the whitespace delimetered words in\ - \ the\nreverse order, not taking any special consideration for number/symbols.\ - \ KISS.\nIf the string, \" one1 tw_o thREE four!\" is passed in, \"four! thREE\ - \ tw_0 one1\"\nwould be returned. Strip any whitespace from the ends of hte given\ - \ string.\n\nE.g:\ndef reverseOrder(foo):\n # do stuff here\n return foo\n" - unittests: - test1: - - str('ro3! T2is is cool') - test2: - - str(' ABCDS') - test3: - - str('zABCDS one two three!') - test4: - - str('123456789 asdf ASDF 4 _ 123 nine? \"\"') -strings_6: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: listToCSV(list) -> string - solution: "def listToCSV(words_list):\n csv_string = ','.join(words_list)\n \ - \ return csv_string\n" - tags: '' - teardown: '' - text: "Write a function called \"listToCSV\" that takes a list of strings and combines\n\ - them into a single string with all words separated by a comma: \",\". For\nexample,\ - \ [\"one\", 'two', 'three'] becomes \"one,two,three\".\n\nE.g:\ndef listToCSV(words_list):\n\ - \ # do stuff here\n return csv_string\n" - unittests: - test1: - - - one - - two - - three - test2: - - - '1' - - ',' - - ':' - - fiftyfive -strings_7: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: undToShortCSV(string) -> string - solution: "def listToCSV(words_list):\n csv_string = ','.join(words_list)\n \ - \ return csv_string\n" - tags: '' - teardown: '' - text: "Write a function called \"undToShortCSV\" that takes a string with words\n\ - separated by underscores, \"_\", changes the underscores to commas, \",\", and\n\ - returns only the first three words. You can assume that there will always\nbe\ - \ more than three words separated by underscore given. \n\nFor exmaple, \"one_two_three_four_five\"\ - \ becomes \"one,two,three\".\n\nE.g:\ndef undToShortCSV(und_sep_words):\n #\ - \ do stuff here\n return csv_sep_words\n" - unittests: - test1: - - str('one_two_three_four_five') - test2: - - _______ - test3: - - str('1_2_3__five_six!\'\'_seven') -strings_8: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: getIndexOf(string, string) -> int - solution: "def getIndexOf(word, search_string):\n if word in search_string:\n\ - \ return search_string.index(word)\n else:\n return -1\n" - tags: '' - teardown: '' - text: "Wirte a functuion called \"getIndexOf\" that returns the index of a given\ - \ word\ninside of a given string. If the word is not present, it returns a -1.\ - \ \n\nFor exmaple, if the word is \"pizza\", and the search_string is \"there\ - \ is pizza on the plate\", then the index is 9.\n\nE.g:\ndef getIndexOf(word,\ - \ search_string):\n # do stuff here\n return index \n" - unittests: - test1: - - str('one_two_three_four_five') - test2: - - str('_______') - test3: - - str('1_2_3__five_six!\'\'_seven') -strings_9: - imports: '' - posttest: '' - pretest: '' - seed: 0 - setup: '' - signature: fooBarString(foo) -> bar - solution: "def getIndexOf(word, search_string):\n if word in search_string:\n\ - \ return search_string.index(word)\n else:\n return -2\n" - tags: '' - teardown: 'print(''foobar'') - - self.test_results = [True, True, True]' - text: "Wirte a functuion called \"getIndexOf\" that returns the index of a given\ - \ word\ninside of a given string. If the word is not present, it returns a -1.\ - \ \n\nFor exmaple, if the word is \"pizza\", and the search_string is \"there\ - \ is pizza\non the plate\", then the index is 9.\n\nE.g:\ndef getIndexOf(word,\ - \ search_string):\n # do stuff here\n return index \n" - unittests: skip diff --git a/3-files_and_paths/problems.md b/3-files_and_paths/problems.md deleted file mode 100644 index 696a6e4..0000000 --- a/3-files_and_paths/problems.md +++ /dev/null @@ -1,57 +0,0 @@ -Tier, description... - -# Opening, reading, writing -* readFileToString(path_to_file) -> string - * 30 - * Given a path to a file, read it's contents and return the contents as a string. - -* readLinesfromFiles(path_to_file) -> list of strings - * 30 - * Given a path to a file, read it's contents and return each line as a string in a list of all lines. - -* appendLinetoFile(path_to_file, content) - * 30 - * Given a path to a file and a string value, "content", write the content to a new line at the end of the file. - -* truncateWriteFile(path_to_file, content) - * 30 - * Given a path to a file and a string value, "content", write the content to the file, replacing anything that is - already there. If the fle doesnt' exist, it is assumend that it would be created. - -* rewriteInLower(source_file, dest_file): - * 31 - * given a source file path and a destination file path, read the file from the source and then write it out to the - dest path in all lower-case. - -* removeWhitespace(file_path): - * 32 - * given a file path, read in the file content. remove whitespace from the start and end of each line. remove any empty - or whitespace-only lines. Then write the content back to the file replacing the original content. - -# os module -## os basics -* moveAFile(source_path, dest_path) - * 30 - * Given a source path and destination path, move the file from source to destination. -* cdAndWrite(dir_path, file_name, content) - * 34 - * Change directory to the given "dir_path", then write the given content to the given file_name. -* listDirFilter(dir_path, filter) - * 34 - * return a list of files at a given path whos names match the given filter. -* createTmpDir(dir_name) - * 33 - * create a directory in /tmp with the given name and return the path to the new directory -* realPath(path) - * 34 - * given a path, find out if it contains a symlink. If so, return the actual path to where the given path points. If no symlinks, return the given path. -* filePaths(dir_path, files_list) - * 34 - * given a directory path and a list of file, create a list of complete paths to each file (dir_path + file path) - -## permissions -* tarDir(src_dir, dst_tar) - * 34 - * given a source directory containing files, create a tar file at the given dst_tar (e.g. /tmp/my_stuff.tar) and add the - directory and its contents into the tar file. -# Tar diff --git a/3-files_and_paths/problems.yml b/3-files_and_paths/problems.yml deleted file mode 100644 index 2a37326..0000000 --- a/3-files_and_paths/problems.yml +++ /dev/null @@ -1,372 +0,0 @@ -os_basics_1: - imports: 'import shutil - - import random - - import string - - import os' - posttest: '' - pretest: '' - seed: 0 - setup: '' - signature: moveAFile(src_path, dst_path) - solution: "\ndef moveAFile(src_path, dst_path):\n shutil.move(src_path, dst_path)\n" - tags: - - sample - - arithmatic - teardown: "\nf0 = './{{}}'.format(''.join(random.choices(string.ascii_uppercase,\ - \ k=10)))\nf1 = './{{}}'.format(''.join(random.choices(string.ascii_uppercase,\ - \ k=10)))\nopen(f0, 'w').write('asdf\\n123')\n\n#try:\nmoveAFile(f0, f1)\n#except\ - \ Exception as e:\n# print(\"Exception: {{}}\".format(e))\n\nprint(\"SRC:\"\ - , f0)\nprint(\"DST:\", f1)\n\nif os.path.isfile(f1):\n self.test_results.append('pass')\n\ - else:\n self.test_results.append('failed to copy file to dst')\n\nif not os.path.isfile(f0):\n\ - \ self.test_results.append('pass')\nelse: \n self.test_results.append('failed\ - \ to rm src file')\n\nif ( self.test_results[0] == 'pass'\n and open(f1,\ - \ 'r').read() == 'asdf\\n123' ):\n self.test_results.append('pass')\nelse:\n\ - \ self.test_results.append('failed preserver file contents')\n\n#cleanup\n\ - if os.path.isfile(f0):\n os.remove(f0)\nif os.path.isfile(f1):\n os.remove(f0)\n" - text: "Write a function called moveAFile that accepts a source file path and a dest\ - \ file path and\nmoves the file to the destination. \n\nE.g.\ndef moveAFile(src_path,\ - \ dst_path):\n #your code here\n #return nothing\n" - tier: 30 - unittests: skip -os_basics_1b: - imports: 'import shutil - - import random - - import string - - import os' - posttest: '' - pretest: '' - setup: 'f0 = ''./{{}}''.format(''''.join(random.choices(string.ascii_uppercase, - k=10))) - - f1 = ''./{{}}''.format(''''.join(random.choices(string.ascii_uppercase, k=10))) - - open(f0, ''w'').write(''asdf\n123'') - - ' - signature: moveAFile(src_path, dst_path) - solution: "\ndef moveAFile(src_path, dst_path):\n shutil.move(src_path, dst_path)\n" - tags: - - sample - - arithmatic - teardown: "\nf0 = './{{}}'.format(''.join(random.choices(string.ascii_uppercase,\ - \ k=10)))\nf1 = './{{}}'.format(''.join(random.choices(string.ascii_uppercase,\ - \ k=10)))\nopen(f0, 'w').write('asdf\\n123')\n\n#try:\nmoveAFile(f0, f1)\n#except\ - \ Exception as e:\n# print(\"Exception: {{}}\".format(e))\n\nprint(\"SRC:\"\ - , f0)\nprint(\"DST:\", f1)\n\nif os.path.isfile(f1):\n self.test_results.append('pass')\n\ - else:\n self.test_results.append('failed to copy file to dst')\n\nif not os.path.isfile(f0):\n\ - \ self.test_results.append('pass')\nelse: \n self.test_results.append('failed\ - \ to rm src file')\n\nif ( self.test_results[0] == 'pass'\n and open(f1,\ - \ 'r').read() == 'asdf\\n123' ):\n self.test_results.append('pass')\nelse:\n\ - \ self.test_results.append('failed preserver file contents')\n\n#cleanup\n\ - if os.path.isfile(f0):\n os.remove(f0)\nif os.path.isfile(f1):\n os.remove(f0)\n" - text: "Write a function called moveAFile that accepts a source file path and a dest\ - \ file path and\nmoves the file to the destination. \n\nE.g.\ndef moveAFile(src_path,\ - \ dst_path):\n #your code here\n #return nothing\n" - unittests: skip -os_basics_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: cdAndWrite(dir_path, file_name, content) -> file_size - solution: "\ndef cdAndWrite(dir_path, file_name, content):\n import os\n os.chdir(dir_path)\n\ - \ open(file_name, 'w').write(content)\n return os.stat(file_name).st_size\n" - tags: - - sample - - arithmatic - teardown: "\nimport random\nimport string\nimport os\ncwd = os.getcwd()\nd0 = ''.join(random.choices(string.ascii_uppercase,\ - \ k=10))\np0 = './{{}}'.format(d0)\nf0 = './{{}}'.format(''.join(random.choices(string.ascii_uppercase,\ - \ k=10)))\ncontent = 'asdf\\n123\\nfoobar\\n\\n'\nos.mkdir(d0)\n\ntry:\n cdAndWrite(d0,\ - \ f0, content)\nexcept:\n pass\n\nif os.getcwd().endswith(d0):\n self.test_results.append('pass')\n\ - else:\n self.test_results.append('failed cd to given directory')\n\nif ( self.test_result[0]\ - \ == 'pass'\n\t and if os.path.isfile(f0) ):\n self.test_results.append('pass')\n\ - else:\n self.test_results.append('failed to write file...')\n\nif ( self.test_result[0]\ - \ == 'pass'\n\t\tand self.test_result[1] == 'pass' \n and open(f0, 'r').read()\ - \ == content ):\n self.test_results.append('pass')\nelse:\n self.test_results.append('failed\ - \ preserver file contents')\n\n# cleanup\nif os.path.isfile(f0):\n\tos.remove(f0)\n\ - os.chdir(cwd)\nif os.path.isdir(p0):\n os.rmdir(p0)\n" - text: "Write a function called cdAndWrite that changes directory to the given path,\ - \ then edits a file\nand writes the given content to it. Return the size of the\ - \ file in bytes! \n\nE.g.\ndef cdAndWrite(dir_path, file_name, content):\n \ - \ #your code here\n return file_size\n" - tier: 35 - unittests: skip -os_basics_3: - imports: import random\nimport string\nimport os\nimport re\n - posttest: '' - pretest: '' - seed: 0 - setup: '' - signature: listDirFilter(dir_path, regex_filter) - solution: "\ndef listDirFilter(dir_path, regex_filter):\n import re\n out\ - \ = []\n for name in os.listdir(dir_path):\n if re.match(regex_filter,\ - \ name):\n out.append(name)\n return out\n\n" - tags: - - sample - - arithmatic - teardown: "\nimport random\nimport string\nimport os\nimport re\ne0 = ''.join(random.choices(string.ascii_uppercase,\ - \ k=4))\ne1 = ''.join(random.choices(string.ascii_uppercase, k=4))\nfor e in (e0,\ - \ e1):\n for n in range(5):\n f = \"{{}}.{{}}\".format(n, e)\n \ - \ open(f, 'w')\nreg_filter = '(./){0,1}[0-9].' + e0\ntry:\n out = listDirFilter('./',\ - \ reg_filter)\nexcept:\n out = []\n\nif len(out) == 5:\n self.test_results.append('pass')\n\ - else:\n self.test_results.append('failed wrong num files returned')\n\nif len(set(out))\ - \ == 5:\n self.test_results.append('pass')\nelse:\n self.test_results.append('failed\ - \ duplicate files returned')\n\nself.test_results.append('failed wrong files returned')\n\ - for f in out:\n if not re.match(reg_filter, f):\n break\nelse:\n \ - \ self.test_results[-1] = 'pass'\n\nfor e in (e0, e1):\n for n in range(5):\n\ - \ f = \"{{}}.{{}}\".format(n, e)\n if os.path.exists(f):\n \ - \ os.remove(f)\n\n" - text: "Write a function called listDirFilter that accepts a directory path and a\n\ - regex filter. It retuns a list of files at the directory path whos names\nmatch\ - \ the given regex. Return only the file names, not their complete path. \n\n\ - E.g.\ndef listDirFilter(dir_path, regex_filter):\n #your code here\n return\ - \ files_list\n" - tier: 35 - unittests: skip -os_basics_4: - imports: import random\nimport string\nimport os\nimport re\n - posttest: '' - pretest: '' - seed: 0 - setup: '' - signature: createTmpDir(dir_name) -> dir_path - solution: "\ndef createTmpDir(dir_name):\n #os.umask(0077)\n dir_path = '/tmp/{}'.format(dir_name)\n\ - \ print('creating dir: {}'.format(dir_path))\n os.mkdir(dir_path)\n return\ - \ dir_path\n" - tags: - - sample - - arithmatic - teardown: "\nimport random\nimport string\nimport os\nimport re\nd0 = ''.join(random.choices(string.ascii_uppercase,\ - \ k=4))\np0 = '/tmp/{{}}'.format(d0)\n\ntry:\n out = createTmpDir(d0)\nexcept:\n\ - \ out = ''\n\nprint('p0:', p0)\nif out.strip() == p0:\n self.test_results.append('pass')\n\ - else:\n self.test_results.append('failed return path was not /tmp/')\n\ - \nif os.path.isdir(p0):\n self.test_results.append('pass')\n os.rmdir(p0)\n\ - else:\n self.test_results.append('failed tmp directory was not created')\n\n" - text: "Write a function called createTmpDir that accepts a directory name and\n\ - creates it in /tmp. Set the permissions so that only the directory owner\ncan\ - \ read/write/execute it. Return the complete path to the directory. \n\nBonus:\ - \ Can you do this in a way that avoids a race condition security\nvulnerability?\ - \ \n\nE.g.\ndef createTmpDir(dir_name):\n #your code here\n return dir_path\n" - tier: 35 - unittests: skip -os_basics_5: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: realPath(path) - solution: "\ndef realPath(dir_name):\n return os.path.realpath(dir_name)\n" - tags: - - sample - - arithmatic - teardown: ' - - ' - text: "Write a function called realPath that accepts a path, checks if it has any\ - \ symlinks in it,\nand returns the actual path (wihout symlinks) to the file or\ - \ directory the original path\npointed to. \n\nE.g.\ndef realPath(dir_name):\n\ - \ # your code here\n return real_path\n" - tier: 31 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -os_basics_6: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: filePaths(dir_path, files_list) -> file_paths list - solution: "\ndef filePaths(dir_path, files_list):\n out = []\n for fname in\ - \ files_list:\n fpath = os.path.realpath(os.path.join(dir_path, fname))\n\ - \ out.append(fpath)\n return out\n" - tags: - - sample - - arithmatic - teardown: '' - text: "Write a function called filePaths that accepts a directory path and a list\ - \ of files. It\nreturns a list of full paths to those files. \n\nFor example,\ - \ if dir_path is '/tmp/' and files list is ['./foobar.txt', 'diddun.txt'], the\ - \ output would be ['/tmp/foobar.txt', '/tmp/diddun.txt'].\n\nE.g.\ndef filePaths(dir_path,\ - \ files_list):\n # your code here\n return files_paths\n" - tier: 34 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -readwrite_1: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: readFileToString(path) -> string - solution: "\ndef readFileToString(path):\n with open(path, 'r') as f:\n \ - \ contents = f.read()\n return contents\n" - tags: - - sample - - arithmatic - teardown: ' - - ' - text: "Write a function called readFileToString that accepts a path, opens the path,\n\ - and returns the contents of the file as a string value. You can assume that \n\ - you'll have access to the file, it won't be binary data, you don't need to do\n\ - anything to the given path to open it. \n\nE.g.\ndef readFileToString(path_to_file):\n\ - \ #your code here\n return contents\n" - tier: 30 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -readwrite_2: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: readLiensFromFile(path) -> list of strings - solution: "\ndef readLinesFromFile(path):\n with open(path, 'r') as f:\n \ - \ contents = f.readlines()\n return contents\n" - tags: - - sample - - arithmatic - teardown: '' - text: "Write a function called readLinesFromFiles that accepts a path, reads the\ - \ contents, and\nreturns a list of stings for each line in the file. \n\nE.g.\n\ - def readLinesFromFile(path_to_file):\n #your code here\n return contents\n" - tier: 30 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -readwrite_3: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: appendLineToFile(path, string) - solution: "\ndef appendLineToFile(path, content):\n with open(path, 'a') as f:\n\ - \ f.write(content)\n" - tags: - - sample - - arithmatic - teardown: '' - text: "Write a function called appendLineToFile that accepts a path and a string,\ - \ and writes the\nstring to the end of the file (without modifying the existing\ - \ contents in the file).\n\nE.g.\ndef appendLineToFile(path, content):\n #your\ - \ code here\n #return nothing\n" - tier: 30 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -readwrite_4: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: truncateWriteFile(path, content) - solution: "\ndef truncateWriteFile(path, content):\n with open(path, 'w') as\ - \ f:\n f.write(content)\n" - tags: - - sample - - arithmatic - teardown: '' - text: "Write a function called truncateWriteFile that accepts a path and a string,\ - \ and writes the\nstring to the file, truncating (overwriting) any existing content\ - \ in the file. \n\nE.g.\ndef truncateWriteFile(path, content):\n #your code\ - \ here\n #return nothing\n" - tier: 30 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -readwrite_5: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: rewriteInLower(source_path, dest_path) - solution: "def rewriteInLower(source_path, dest_path):\n contents = open(source_path,\ - \ 'r').read().lower()\n open(dest_path, 'w').write(contents)\n" - tags: - - sample - - arithmatic - teardown: '' - text: "Write a function called rewriteInLower that accepts a source and destination\ - \ path. It reads\nin the source path, converts the contents to all lower case,\ - \ and writes them to the\ndestination path. \n\nE.g.\ndef rewriteInLower(source_path,\ - \ dest_path):\n #your code here\n #return nothing\n" - tier: 31 - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) diff --git a/4-system_and_env/problems.md b/4-system_and_env/problems.md deleted file mode 100644 index f04fb63..0000000 --- a/4-system_and_env/problems.md +++ /dev/null @@ -1,56 +0,0 @@ -# os module -* def getEnvironVariable(string) -> string - * 40 - * Given the name of an env variable, return the value of that environment variable. -* setEnvironVariable(string, string) - * 40 - * Given the name of an env variable and a value to set it to, set the value to the var. -* nPendEnvPath([paths], prepend=False, append=False) - * 41 - * Given a list of paths, either prepend them to the environment PATH variable or append them, depending on which - arg is true, and do nothing of neither prepend or append is True. -* - - -# sys module -* getScriptLocName() -> (real_path, file_name) - * 41 - * Use sys.argv to get and return the path to the program that's being run and the name of the program as a tuple. -* checkDebugArg() -> bool - * 41 - * Check the progam args (sys.argv) to see if the user passed in a -d or --debug flag. if so, return True, otherwise - return false. -* parseArgs1() -> dictionary - * 42 - * Write a functoin that will parse the arguments for some fine program. The program allows the following argumetns: - our_prog.py \[--num_tries ] [--user_name ] [--fail_message dictionary - * 42 - * Redo parseArgs1 but use the argparse module. Put your function in its own script to test, check the output you get - for --help. - -# platform -* n/a - -# subprocess -* runGetOutputShell(command) -> string - * 43 - * use subprocess check_output to run the given command and return its output. - Assume that the command will be a string. - and set shell=True. - If there is an exception (any), return None. -* runGetOutput(command) -> string - * 44 - * check if command is a string or a list. Set shell=True if it is a list, otherwise, leave it as false (unset). - Same as above, catch any exceptoins and return None, or return the ouptut of the given command as a string. -* runGetStatus(command) -> bool - * 44 - * run the given command and return True if the exit status is 0, or False if the exit status is not zero. - * Return None for any exceptions. - * Assume tha the command will be a list and keep shell=False. - diff --git a/4-system_and_env/problems.yml b/4-system_and_env/problems.yml deleted file mode 100644 index 607b1a5..0000000 --- a/4-system_and_env/problems.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Using a uuid to uniquely identify questions -4464b29f-86a1-4e4c-9261-f581d1b1c8e8: - # This is an example question - # It shows off the format used - title: addition_example - text: | - Write a function that takes 2 integers as parameter - It should return the sum of the 2 ints - signature: "add(number1: int, number2:int ) -> int" - # I'm putting this in base64, I think it might help readability. This codes to: - # def add(num_1, num_2): - # return num_1 + num_2 - solution: !!binary "ZGVmIGFkZChudW1fMSwgbnVtXzIpOgogICAgcmV0dXJuIG51bV8xICsgbnVtXzI=" - tier: 1 - unittests: - test1: - - "int(3)" - - "int(5)" - test2: - - "int(-3)" - - "int(0)" - test3: - - "randint(-100,100)" - - "randint(-100,100)" - # The x4 will mean repeat this test 4 times - test4_x4: - - "randint(-1000,1000)" - - "randint(-1,1)" - - # Used for any outside module dependancies - imports: "from random import randint, seed" - # Setup scripts to prep an environment. Run before unittests - setup: "seed({seed})" - # Teardown scripts to clean up the environment. Run after unittests - teardown: "" - # Scripts to be run before individual tests take place - pretest: "" - # Scripts to be run after infividual tests take place - posttest: "" - # Tags can be used to sort and filter questions - tags: - - sample - - arithmatic - # This is how many times the challenge has been solved - successes: 1 - # These are derived from user ratings, the data can be used as question feedback - # think of them like upvotes/downvotes, but more category specific - ratings: - challenging: 0 - useful: 0 - interesting: 0 - # The solution history, every success can be stored here. - history: - ab7511ee456ce56e64d69141b7e2241b: - code: !!binary "ZGVmIGFkZChhYWEsYmJiKToKICAgIHg9IGFhYStiYmIKICAgIHJldHVybiB4" - pep8: 0 - size: 0 - speed: 0 - memory: 0 - likes: 0 \ No newline at end of file diff --git a/5-data_manipulation/problems.md b/5-data_manipulation/problems.md deleted file mode 100644 index c969ce9..0000000 --- a/5-data_manipulation/problems.md +++ /dev/null @@ -1,50 +0,0 @@ -# csv -* csvFileToArray(file_path) -> array - * 50 - * read csv text data in from the given file and return it as an array (list of lists), aka list of rows. -* arrayToCsvFile(file_path, array) - * 50 - * convert array (list of lists) to csv and write to file. -* dictToCsvFile(file_path, dict) - * 51 - * use dict keys as column one, values (list) as other columns, sort by key and write to file. - -# json -* jsonFiletoData(file_path) -> data - * 50 - * use json module to read json content from the given file, convert it to python data, and return the data. -* dataToJsonFile(file_path, data) - * 50 - * use json module to convert a given data structure to json format and write it to file. - -# yaml -* yamlFiletoData(file_path) -> data - * 50 - * use yaml module to read json content from the given file, convert it to python data, and return the data. -* dataToYamlFile(file_path, data) - * 50 - * use yaml module to convert a given data structure to json format and write it to file. - -# regex -* simpleReTest(value, regex_string) -> bool - * 50 - * given a value and a regex string, return True of the value matches the regex string or False if it - does not. -* filteredList(list, regex_string) -> list - * 51 - * Given a list of strings, use the "re" modudule to regex match the regex_string against values - in the list and return a list of matching strings. Preserve order of the orignial list. - -# sql and sqlite -* createSqliteTable(db_file, table_name, table_columns, rows) - * 54 - * given a filename, open a sqlite db using that file and create a new table using the given name and - columns. Then insert each of the provided rows of data and commit the change. If "rows" is an empty - list, then do not insert any rows to the table you just created. -* sqlitReadRows(db_file, table_name) -> array - * 51 - * given a sqlite db file, query all of the rows in the given table, and return them as an array. -* sqlitReadRowsDict(db_file, table_name) -> list of dicts - * 52 - * given a sqlite db file, query all of the rows in the given table, and a list of dictionaries, with - each row being a dictionary with keys equal to the column names and values each value for that row. diff --git a/A-Getting_Started_and_Data_Types.ipynb b/A-Getting_Started_and_Data_Types.ipynb new file mode 100644 index 0000000..2f9a09d --- /dev/null +++ b/A-Getting_Started_and_Data_Types.ipynb @@ -0,0 +1,975 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section A - Start here!\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**: Intro, Data types incl numeric, strings, lists, tuples, sets, if else. \n", + "\n", + "The first program most folks make in any language is a hello world. \n", + "\n", + "#### *Exercise*:\n", + "Type the following in the code cell below and press shift + enter to run it!\n", + " \n", + "`print('Hello World!')`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "BTW, you're looking at a Python Notebook, aka ipython notebook or jupyter notebook. There are \"markdown\" text cells and code cells. You can press shift + enter to render a text cell or to run a code cell. And you can insert a new cell anywhere you want.\n", + "\n", + "You can learn more about markdown at https://www.markdownguide.org/basic-syntax/ - it's a way to make nice looking documents from plain text. You can even use LaTeX in markdown!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## About Python\n", + "Python is an interpreted language - you don't have to compile your code before running it. It's disigned to be readable and maintainable, and to do a lot of tasks efficiently. It's one of the most popular languages for good reason.\n", + "\n", + "It may not run as fast as a compiled language like c, c++, fortran, but it has a lot of libraries that are written in c and make specific tasks very fast. We'll work with pandas later in this class. Pandas is built on numpy, a very performant library for manipulating lots of numbers. \n", + "\n", + "## What can we do with Python?\n", + "* Machine learning - Look into \"SciPy\" and many other libraries that make ML simple-ish to use.\n", + "* Analytics and data processing - find trends, do analysis, make graphs!\n", + "* Automate the boring stuff - office tasks like mail merges, filling out document templates over and over, processing spreadsheet and data\n", + "* Web scraping - Look into BeautifulSoup or many other libraries\n", + "* Embeded systems and Robotics - look at micropython and circuitpython, which run on many small microconrtollers\n", + "* Games - Look into PyGame, Pygame Zero, Turtle, or even Godot engine, which uses a python-like language and can build very advanced games. \n", + "* Systems automation - read config files, run commands on computers, collect data, do stuff. \n", + "* And more!\n", + "\n", + "#### *Exercise*:\n", + "Run \"import this\", without the quotes, in the next cell!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Libraries\n", + "You'll learn pretty quickly that learing python is as much about understanding how the language works as getting familiar with libraries to do the things you want to do. A few examples:\n", + "* import math\n", + " * it has functions for rounding, trig, and a lot more\n", + "* from datetime import datetime\n", + " * datetime has tools for manipulating datetime objects! This is one that's weirdly complex in practice.\n", + " * Why are we importing datetime from datetime? \n", + "* import pandas as pd\n", + " * Using a short name is a common convention for some library. pandas is pd, numpy is np, ...\n", + " * Pandas is a bit like excel, except you do it all with commands in a reproducible way, rather than one off editing a file manually in excel.\n", + "* import json\n", + " * you'll use json a lot for web queries with the \"requests\" libray, for rest api stuff, and config files \n", + "... " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Syntax\n", + "Reference this page: https://en.wikipedia.org/wiki/Python_syntax_and_semantics\n", + "\n", + "### Keywords\n", + "Some words cannot be used as variables because they have special meaning in the python language: \n", + "\n", + " and as assert async await break case class continue \n", + " def del elif else except False finally for from global \n", + " if import in is lambda match None nonlocal not or pass \n", + " raise return True try while with yield _.*\n", + "\n", + "### Indentation\n", + "Python uses indentation to group code inside of functions, classes, and control blocks. Other languages often use { } for the same purpose.\n", + "* Be consistent with your indentation. \n", + "* **Four spaces per indentation level** is recommended. It can be hard to see which code aligns with which above it when using only two spaces per indentation level.\n", + "* Many editors can be configured to intent four spaces each time you press the tab key. \n", + "* Technically you can use tab characters or any number of spaces per indentaton level. Above all, **be consistent**.\n", + "\n", + "Here's an example function named \"foo\" that has an if else condition block inside of it. Everything indented after the def line is part of the function, and the lines after the if and else blocks each have additional indentation. When the indentation ends, the block ends. \n", + "\n", + " def foo(x):\n", + " if x > 9000:\n", + " print(\"x is big!\")\n", + " else:\n", + " print(\"x is small!\")\n", + " print(\"This is in the function. We checked if x is big.\")\n", + "\n", + " print(\"This print statement is outside of the function.\")\n", + "\n", + "An equivelant function in c could be written like this:\n", + "\n", + " void foo(int x)\n", + " {\n", + " if (x > 9000) {\n", + " printf(\"x is big!\");\n", + " } else {\n", + " printf(\"x is small!\");\n", + " }\n", + " printf(\"This is in the function. We checked if x is big.\");\n", + " }\n", + " print(\"This print statement is outside of the function.\");\n", + "\n", + "The indentation in c code is functionally unnecessary, but makes it readable. The { and } group the code.\n", + "\n", + "### Quoting\n", + "Strings, non-numeric values, are quoted with ', \", ''', \"\"\". We'll look at this more in the strings section below. Just note this. Variable names are not quoted, but values are treated as strings if they are quoted when assigned to variables or passed as arguments to a function.\n", + "\n", + "Examples:\n", + "* x = \"Hasn't seen it\"\n", + "* y = '''He said, \"it isn't there.\"'''\n", + "* ...\n", + "\n", + "#### *Exercise*:\n", + "Fill out the print statements in the following code cell so that when the print statement runs, it prints exactly the text on each comment line, including quotes and back-slashes '\\'. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# It's Pretty Cool\n", + "print()\n", + "# He is called 'Johnny'.\n", + "print()\n", + "# Johnny said, \"That's some crazy quoting!\"\n", + "print()\n", + "# We can escape quotes with a backslash: \\\"\n", + "print()\n", + "# But how do we print the \\? Escape it with another \\!\n", + "print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Describing data types\n", + "We use symbols like [], (), {} to say what type of data things are:\n", + "\n", + "* To define a list:\n", + " * x = [1, 2, 3, '1', '2', 'c']\n", + "* To define a tuple:\n", + " * y = (4, 5, 6, 'a', 'b')\n", + "* To define a set we use comma separated things between curly braces.\n", + " * w = {'one', 'two', 3}\n", + "* To define a dictionary we use the : to relate things between the curlyl braces.\n", + " * z = {1: 'a', 2: 'b', 'c': 'foo'}\n", + "\n", + "## Variables and Functions\n", + "We'll look deeper at each of these later, but just note how we write them for now. We'll get into the intricacies of how they work later. \n", + "\n", + "**Variables** are created by assigning a value to a name with an = symbol. For examble:\n", + "* valid_dogs = ['terrier', 'minpin', 'labrador']\n", + "* pets_age = 15\n", + "\n", + "\"valid_dogs\" and \"pets_age\" are the variables that refer to a list of strings and an integer, respectively. \n", + "\n", + " >>> pets_age = 15\n", + " >>> print(\"My dogs age is:\", pets_age)\n", + " My dogs age is: 15\n", + " >>> \n", + "\n", + "**Functions** are are created with the keyword \"def\", short for \"define\":\n", + "\n", + " def prompt_user_for_age(user_name):\n", + " prompt_message = f'{user_name}, enter your age: '\n", + " user_age = input(prompt_message)\n", + " return user_age\n", + "\n", + "This defines a function called \"prompt_user_for_age\" that takes an argument, \"user_name\", and it returns the response from the user, \"user_age\"." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Syntax Errors\n", + "Recent versions of python 3 are pretty good at giving you error messages that help! \n", + " \n", + "#### *Exercise*:\n", + "Run the following code cells, check the error messages, and fix the code to resolve the errors!\n", + "* Look at what line the error message refers to\n", + "* Think about the error\n", + "* Think about the code and compare whatever you do to fix it to error message." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "a = \"The quick brown fox jumps over the lazy dog'\n", + "# Hint, something should be the same at the start and end of the string\n", + "# a is a variable that holds a string! A string is a data type!\n", + "print(a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b == 5\n", + "print('b is:', b)\n", + "# hint, an = does an assignment, and an == does a comparison" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if b == 5\n", + " print('b is five')\n", + "else:\n", + " print('b is not five')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if b % 2: # a less succinct way to write this is 'if b % 2 == 1'\n", + " print('b is odd')\n", + " else:\n", + " print('b is even')\n", + "# hint, if and else need the same level of indentation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = 2\n", + "if x = 1:\n", + " print(\"x is 1\")\n", + "else:\n", + " print(f'x is not 1, it is {x}')\n", + "# Hint, a single equals sign is used to assign a value to a variable and the following\n", + "# are used to compare values: ==, !=, >, <, >=, <=" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Data Types\n", + "You may have heard the saying that everything in Python is an object. This means that every *thing* in python has properties and built in methods/functions for interacting with it. \n", + "\n", + "Following are the built in data types we need to know how to work with. But also keep in mind that we can define a *class* to make any type of object suited to our specific need. \n", + "\n", + "You can check the type of an object with the **type** function:\n", + "\n", + " >>> type('a')\n", + " \n", + "\n", + "#### *Exercise*:\n", + "Check the type of each of these things using the **type** function:\n", + "* -10\n", + "* 0\n", + "* 50.1\n", + "* '123'\n", + "* '10.2'\n", + "* 'a'\n", + "* True\n", + "* None\n", + "* 3+2j\n", + "* (1, 2, 3)\n", + "* ('a', 'b', 3)\n", + "* [4, 5, 'e']\n", + "* {'a': 2, 'b': 6}\n", + "* set((1, 1, 2, 3, 4))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can check the built in methods of any type of object using the **dir** function: \n", + "\n", + " >>> dir([1, 2, 3])\n", + " ['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']\n", + " >>> \n", + "\n", + "Anything listed without an __ is intended to be called directly to interact with the object. For example:\n", + "\n", + " >>> x = [1, 2, 3]\n", + " >>> x.append(4)\n", + " >>> x\n", + " [1, 2, 3, 4]\n", + "\n", + "Anything listed with __ at the start and end is a special method that you don't directly access, but works with the Python language naturally, making code more readable. For example, if I want to know if the number 2 is in the list [1, 2, 3], I can use:\n", + "\n", + " >>> 2 in [1, 2, 3]\n", + " True\n", + "\n", + "And in the background, python is running this:\n", + "\n", + " >>> [1, 2, 3].__contains__(2)\n", + " True\n", + "\n", + "#### *Exercise*\n", + "Use **dir** to check the built in methods for each ot the thinkgs from the above **type** exercise:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Integers and Floats\n", + "Python has different data types for integers, whole numbers, and floating point values, but will automaticaly convert to using floats when doing division unless you tell it not to. \n", + "\n", + "## Arithmatic Operations\n", + "Most of these should look familiar. We start by assigning values to a and b, and them do some math with them. A few things to note:\n", + "* '/' is for division and will give a floating point value\n", + "* '//' is for division but will drop the remainder and give an integer result\n", + "* '%' is called a modulus and gives the remainder of the division.\n", + "* '^' is a little unusual, doing a *not* operation on the binary form of both numbers.\n", + "* '**' does an exponent, a to the power of b in this example.\n", + "\n", + "Examples:\n", + "\n", + " >>> a = 2\n", + " >>> b = 3\n", + " >>> a + b\n", + " 5\n", + " >>> a - b\n", + " -1\n", + " >>> a * b\n", + " 6\n", + " >>> a / b\n", + " 0.6666666666666666\n", + " >>> a ^ b\n", + " 1\n", + " >>> a ** b\n", + " 8\n", + " >>> a // b\n", + " 0\n", + " >>> a % b\n", + " 2\n", + "\n", + "## Typecasting Ints and Floats\n", + "There are a few cases where you'd want to **cast** objects to and from int or float.\n", + "* round a floating point value down by converting it to an int\n", + "* convert a string to an int - this can be done for strings like '5', '-256', '999', but not '5.0'.\n", + "* convert a string to a float - this can be done for any numeric values like '5.0', '990', etc.\n", + "\n", + "Examples:\n", + "\n", + " >>> x = '7.9' # a string because it is quoted\n", + " >>> x\n", + " '7.9'\n", + " >>> float(x)\n", + " 7.9 # a number/floating point\n", + " >>> int(x)\n", + " ValueError: invalid literal for int() with base 10: '7.9'\n", + " >>> int(float(x))\n", + " 7\n", + "\n", + "#### *Exercise*\n", + "Calculate the length of the hypotenuse of a right triangle. Store the side lengths in variables, and use the pythagorean theorem to calculate the long side. You can use math.sqrt() to perform a square root, just make sure to 'import math' first. Or you can use an exponent, to the power of 0.5, to do the same thing." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Store your side lenghts in variables:\n", + "\n", + "\n", + "# Calculate the hypotenuse of the triangle:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Strings\n", + "**Just a plain string**:\n", + "\n", + " foo = \"Nothing exciting here\"\n", + "\n", + "## Formatting\n", + "\n", + "**f-strings!**\n", + "\n", + " name = 'Lisa'\n", + " weekday = 'Thursday'\n", + " greeting = f'Good morning, {name}! Today is {weekday}.'\n", + "\n", + "**Using format**\n", + "\n", + " greeting = 'Good morning, {}! Today is {}.'.format(name, weekday)\n", + "\n", + "format doesn't have to be done immediately... So a template string can be re-used.\n", + "\n", + " greet_names = ['Peter', 'Joan', 'Zeeke']\n", + " greeting = 'Good morning, {}! Today is {}.'\n", + " for name in greet_names:\n", + " print(greeting.format(name, weedkay))\n", + "\n", + "\n", + "## String Operations\n", + "String objects have a bunch of built in operations for manipulating them:\n", + "* .upper(), .lower(), .capitalize(), .title()\n", + "* .strip(), .lstrip(), .rstrip()\n", + "* .replace('match_this', 'with_this')\n", + "\n", + "Convert strings to lists of words and vice-versa\n", + "* .split() and .join()\n", + "\n", + "Test strings to see if they are completely anphabetic, numeric, have upper/loqer case, etc.\n", + "* .isupper(), .isdigit(), .isalpha() ...\n", + "\n", + "\n", + "#### *Exercise*\n", + "Let's see if we can sanitize user input... What will our code do if the user types \" red\" with spaces at the front? Or if they type RED? We can use the strip and upper/lower, etc functions to clean up whatever is typed. Make the following changes to the below code:\n", + "* Try running the cell below and entering a color, a capitilized color, or a coloro with a space before/after it. What happens?\n", + "* Uncomment the Add something here line and use the strip and lower options to sanitize user input.\n", + "* Uncomment the elif line ad add \n", + "* Change the strings in the print statements to f strings to include the entered color" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I don't know that color.\n" + ] + } + ], + "source": [ + "known_colors = ('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet')\n", + "\n", + "# Prompt the user to enter their favorite color\n", + "fav_color = input('Enter your favorite color: ')\n", + "\n", + "# Sanitize whatever was entered by the user\n", + "# fav_color = # Add something here...\n", + "\n", + "# Check if the user's favorite color is in the list of known colors\n", + "if fav_color in known_colors:\n", + " print('I know that color!')\n", + "# elif ... # Check if there are numbers in the user input and print a message about it if so\n", + "# print...\n", + "else:\n", + " print(\"I don't know that color.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## split and join\n", + "Sometimes we want to take a single string and split it into lines, or words, or something else and work on each part of it one at a time. For example, we might use split or splitlines to:\n", + "* Print one line at a time\n", + "* Check each word one a time\n", + "\n", + "And we might use join to combine a list of strings into one string with *something* between each one. An example of both of these operations:\n", + "\n", + " >>> foo = 'red green blue'\n", + " >>> bar = foo.split()\n", + " >>> print(bar)\n", + " ['red', 'green', 'blue']\n", + " >>> baz = ', '.join(bar)\n", + " >>> print(baz)\n", + " red, green, blue\n", + " >>> \n", + "\n", + "**Note**\n", + "\n", + "Split and join are string operations... \n", + "\n", + "When when we split, we put .split on our string varlable and the split function returns a list. In this example, foo is a string, and we use it's split function to return a list that we store in the bar variable. \n", + "\n", + "Then we use a new string, **', '** and its join function to join all of the items in the bar list we pass to it. When we join. we don't put .join on the list, we but it on the string that we want to use to join all of the things in the list.\n", + "\n", + "#### *Exercise*\n", + "Let's convert values in a string which are separated by double colons, '::', into a list of values and then into a string with commas between the values. Replace the two '...' below with the needed operations.\n", + "Look at the Syntax section at https://www.w3schools.com/python/ref_string_split.asp to see how to specify the separator to split on specific characters." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "colon_separated = 'one::two::word::foo'\n", + "\n", + "# Split the string into a list of words\n", + "list_of_words = ...\n", + "print('This is the list of words:', list_of_words)\n", + "\n", + "# Join the list of words into a string separated by commas\n", + "comma_separated = ...\n", + "print('Now the words are separated by commas:', comma_separated)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a little more complicated example using a for loop to do something to each line from a file one at a time. If you don't have the sample.csv file at the same path, either update the path to where you put it, or comment out the file read lines, and add:\n", + "\n", + " content = '''Age,Name,Fav_Color \n", + " 40,Dan,Blue \n", + " 9,James,Green \n", + " 25,Frank,Black''' \n", + "\n", + "in place of it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is in the file:\n", + "Age,Name,Fav_Color\n", + "40,Dan,Blue\n", + "9,James,Green\n", + "25,Frank,Black\n", + "\n", + "\n", + "And this is each line in the file:\n", + "The line is: Age,Name,Fav_Color\n", + " And each field in the line:\n", + " ['Age', 'Name', 'Fav_Color']\n", + "The line is: 40,Dan,Blue\n", + " And each field in the line:\n", + " ['40', 'Dan', 'Blue']\n", + "The line is: 9,James,Green\n", + " And each field in the line:\n", + " ['9', 'James', 'Green']\n", + "The line is: 25,Frank,Black\n", + " And each field in the line:\n", + " ['25', 'Frank', 'Black']\n" + ] + } + ], + "source": [ + "# First we read in the file:\n", + "csv_file = \"../SAMPLE_DATA/simple.csv\"\n", + "with open(csv_file) as f:\n", + " content = f.read()\n", + "\n", + "print(\"This is in the file:\")\n", + "print(content)\n", + "print()\n", + "\n", + "# Then we split the file into lines, so \"lines\" is a list of strings\n", + "print(\"And this is each line in the file:\")\n", + "lines = content.splitlines()\n", + "\n", + "# And we can iterate over each line in the file. \n", + "for line in lines:\n", + " print(\"The line is:\", line)\n", + " print(\" And each field in the line:\")\n", + " print(f' {line.split(\",\")}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## String Slicing\n", + "Strings, lists, and tuples can be \"sliced\" similarly. We put brackest at the end of the varialbe name and use numbers and : to select some number of elements from the string. Given [a:b:c]\n", + "* a is the starting character and is optional. If omitted, we start at the very ferst character of the string. If given, it is inclusive, and counting starts at zero. [0:2] is the same as [:2]. \n", + "* b is the ending character and is exclucive, meaning we take up to but not including this character. \n", + "* c is used to skip characters. [:4:1] is the same as [:4]. [:4:2] will give everey other character up to but not uncluding the character at address 4 in the string. [::3] will give every third character in the string. \n", + "\n", + "Example:\n", + "\n", + " >>> foo = 'some stuff la bar'\n", + " >>> foo[:6]\n", + " 'some s'\n", + " >>> foo[-2:]\n", + " 'ar'\n", + " >>> foo[1:3]\n", + " 'om'\n", + " >>> foo[::2]\n", + " 'sm tf abr'\n", + " >>> foo[::3]\n", + " 'setfaa'\n", + " >>> \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lists\n", + "List are a type of collection that may contain any type of object - numbers, strings, even lists of lists! The order of things in a list is preserved. Like strings, list objects have built in functions to work with them:\n", + "\n", + " >>> my_list = ['some', 'words', 'and', 'numbers', 4, 5, 6, 'and a list', ['foo', 'too']]\n", + " >>> my_list.\n", + " my_list.append( my_list.count( my_list.insert( my_list.reverse() \n", + " my_list.clear() my_list.extend( my_list.pop( my_list.sort( \n", + " my_list.copy() my_list.index( my_list.remove( \n", + "\n", + "* 'append' will add an object to the list\n", + "* 'remove' will remove a specific object from the list\n", + "* 'pop' will return the last object in the list and remove it from the list\n", + "* 'extend' is used to combine lists.\n", + "* 'sort' can sort them, but watch out for mixed data types using this.\n", + "* etc!\n", + "\n", + "#### *Exercise*\n", + "Complete the three 'some_colors...' lines below to make the code work:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_colors = ['red', 'bananna', 'orange']\n", + "print(\"I know of these colors:\", some_colors)\n", + "\n", + "wrong_color = input('Enter the word that is not a coolor: ')\n", + "wrong_color = wrong_color.strip().lower()\n", + "\n", + "# use remove to take the wrong color from the list\n", + "some_colors...\n", + "\n", + "print(\"I know of these colors now:\", some_colors)\n", + "new_color = input(\"Enter a new color that I don't know about: \")\n", + "\n", + "# use append to add the new color to the list\n", + "some_colors...\n", + "\n", + "print(\"I know of these colors now:\", some_colors)\n", + "\n", + "print(\"Sometimes I forget colors...\")\n", + "\n", + "# use pop to remove a color from the list and store it in a variable\n", + "forgotten_color = some_colors...\n", + "\n", + "print(f\"I forgot about {forgotten_color}.\")\n", + "print(\"I know of these colors now:\", some_colors)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tuples\n", + "Tuples are another type of collection, like lists, but cannot be changed once defined - they are **immutable**. When you see a tuple, it implies finality. Tuple objects only have a couple of built in functions:\n", + "\n", + " >>> all_colors = ('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet')\n", + " >>> all_colors.\n", + " all_colors.count( all_colors.index( \n", + "\n", + "* count tells you how many of something are in the tuple. all_colors.count('yellow') -> 1\n", + "* index tells you the position of something in the tuble. all_colors.index('green') -> 3\n", + "\n", + "Tuples can be sliced just like strings and lists:\n", + "\n", + " >>> all_colors[3:] # colors starting with green\n", + " ('green', 'blue', 'indigo', 'violet')\n", + " >>> all_colors[1:3] # colors from index 1 up to green.\n", + " ('orange', 'yellow')\n", + " >>> all_colors[-1] # only the last color\n", + " 'violet'\n", + " >>> all_colors[-3:] # the last three colors\n", + " ('blue', 'indigo', 'violet')\n", + " >>> all_colors[::2] # every other color\n", + " ('red', 'yellow', 'blue', 'violet')\n", + " >>> \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all_colors = ('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Where did the word *tuple* come from? Tuples are sequences of numbers (although in python the can contain any objects). \n", + "\n", + "1-tuple, 2-tuple, 3-tuple, n-tuple:\n", + "* single\n", + "* double\n", + "* tripple\n", + "* quadruple\n", + "* pentuple\n", + "* ...\n", + "* n-tuple!\n", + "https://en.wikipedia.org/wiki/Tuple" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Sets\n", + "\n", + "Sets are another type of collection where only unique items are saved. Order is not preserved, and you can put anything into a set, but if the same thing is added twice, only one exists in the set. Sets have functions to comapare sets for uniqueness and intersection.\n", + "\n", + " >>> berries = {'blueberry', 'strawberry'}\n", + " >>> fruits = set()\n", + " >>> fruits.add('apple')\n", + " >>> fruits.add('strawberry')\n", + " >>> fruits.intersection(berries)\n", + " {'strawberry'} \n", + " >>> fruits.difference(berries)\n", + " {'apple'}\n", + " >>> fruits.\n", + " fruits.add( fruits.issubset(\n", + " fruits.clear( fruits.issuperset(\n", + " fruits.copy( fruits.pop(\n", + " fruits.difference( fruits.remove(\n", + " fruits.difference_update( fruits.symmetric_difference(\n", + " fruits.discard( fruits.symmetric_difference_update(\n", + " fruits.intersection( fruits.union(\n", + " fruits.intersection_update( fruits.update(\n", + " fruits.isdisjoint(\n", + "\n", + "#### *Exercise*:\n", + "TODO" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# if/elif/else conditional statements\n", + "Python supports the usual logical conditions from mathematics:\n", + "\n", + "* Equals: a == b\n", + "* Not Equals: a != b\n", + "* Less than: a < b\n", + "* Less than or equal to: a <= b\n", + "* Greater than: a > b\n", + "* Greater than or equal to: a >= b\n", + "\n", + "And test/comparisons like this can be used to run different code/operations in each case. \n", + "\n", + " if a > b:\n", + " print('a is larger than b')\n", + " elif a == b: \n", + " print('a is eqlal to b')\n", + " else:\n", + " print('a must be less than b')\n", + "\n", + "## Non-numeric conditional tests\n", + "We can use a lot more variety of conditions in our code:\n", + "**String tests**\n", + "word = input('Enter a word: ')\n", + "if not word.isalpha():\n", + " print('Invalid, words do not have numbers')\n", + "if word.islower():\n", + " print('The word is all lower case')\n", + "if word.endswith('poluza'):\n", + " print('Sounds like a party!')\n", + "if 'a' in word.lower():\n", + " print('found a vowell!')\n", + "\n", + "**List, Tuple, Set, etc container tests**\n", + "things = ['apple', 'bananna', 'pear']\n", + "if 'apple' in things:\n", + " print('I have an apple')\n", + "if not things:\n", + " print('Things is an empty list')\n", + "\n", + "## Truthiness\n", + "Most objects can be evaluated as True or False. \n", + "\n", + "**Examples of True things:**\n", + "* Lists, Tuples, Sets that are not empty\n", + "* Strings with at least one character in them\n", + "* Positive or negative numbers\n", + "* True # true evaluates true\n", + "\n", + "**Examples of False things:**\n", + "* Empty lists, tuples, sets\n", + "* 0 (zero)\n", + "* Empty strings: ''\n", + "\n", + "This means that we can simplify some expressions:\n", + "* if len(some_string) > 0\n", + " * if some_string\n", + "* if len(my_list_of_things) > 0\n", + " * if my_list_of_things\n", + "\n", + "#### *Exercise*\n", + "Foo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# First Turtle Challenge!\n", + "Turtle is a simple python graphics library. You tell the turtle which directon to walk, how far to walk, and what color to draw, and the turtle draws lines for you!\n", + "\n", + "This week, we'll get turtle working, and make some simple patterns. \n", + "\n", + "If you're working in google colab, you can use the following code to start using turtle:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip3 install ColabTurtle\n", + "from ColabTurtle.Turtle import *\n", + "initializeTurtle()\n", + "home()\n", + "pos()\n", + "color('red')\n", + "forward(200)\n", + "right(90)\n", + "color('blue')\n", + "forward(30)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And if you're working in notebook locally installed on your laptop, you can use the following code:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from turtle import *\n", + "home()\n", + "pos()\n", + "clearscreen()\n", + "color('red')\n", + "forward(200)\n", + "right(90)\n", + "color('blue')\n", + "forward(30)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "Copy the turtle code from above to new cells below and make changes to accomplish each of the following tasks:\n", + "* Draw a square with each side a different color\n", + "* Draw an octogon with alternating colors on each side\n", + "* Rework your code from the above two challenges to use a variable for the side length, so you only have to change one number in the cell to make all of the sides longer or shorter. \n", + "* Use a variable to count the number of sides drawn. Each time you draw a side, add one to the counter. If the counter is odd, make the next side green. If the counter is even, make the next side blue. You can use an if statement to do this. And you can test to see if the counter is odd with simply \"counter % 2 > 0\". This uses the modulus operator to say, if the remainder after dividing counter by 2 is greater than zeri. If it is, then it evaluates True. If it is, it evaluates False. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/A1-Built_in_Operations.ipynb b/A1-Built_in_Operations.ipynb new file mode 100644 index 0000000..7f4d0fd --- /dev/null +++ b/A1-Built_in_Operations.ipynb @@ -0,0 +1,342 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section A1 - Built-in Operations\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**: Python built-in functions for:\n", + "* Mathematical Operations\n", + "* Collection Functions\n", + " * Creation and manipulation\n", + " * \n", + "\n", + "There's a list of built-in functions here: https://docs.python.org/3/library/functions.html. It's just an alphabetical list, and there's a lot there, so we'll try to break things into some useful categories here!\n", + "\n", + "## Mathematical Operations\n", + "These are the basic mathematical functoins that are included in python without importing any libraries.\n", + "\n", + "* `pow()`: Returns a number raised to a power.\n", + "* `round()`: Rounds a number to a specified precision.\n", + "* `sum()`: Adds all items in an iterable.\n", + "* `min()` and `max()`: Return the minimum and maximum values in an iterable.\n", + "* `divmod()`: Returns the quotient and remainder of a division.\n", + "\n", + "There is no built in square root, but recall from math class that `sqrt(x)` is the same as `pow(x, 0.5)`, x to the 1/2 power.\n", + "\n", + "#### *Exercise*:\n", + "Replace the ... in the following code cell using the above functions to perform the needed calculations. Recall that the formula to calculate the hypotenuse length of a right triangle is the square root of (a squared plus b squared)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# \n", + "some_numbers = [2, 5, 13, 4, 7, 22]\n", + "sum_of_some_numbers = ...\n", + "average_of_some_numbers = ...\n", + "print(f'The sum and average of {some_numbers} are {sum_of_some_numbers} and {average_of_some_numbers}, respectively.')\n", + "smallest_number = ...\n", + "print(f'And the smallest number in the list is {smallest_number}.')\n", + "\n", + "# Calculate the length of the hypotenuse of a right triangle:\n", + "side_a_len = 3\n", + "side_b_len = 4\n", + "hypotenuse_len = ...\n", + "print(f'The hypotenuse of a right triangle with side lengths of {side_a_len} and {side_b_len} is {hypotenuse_len}.')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Collection Interaction Functions\n", + "These groups are for creating and working with collections of things, including lists, sets, dictionaries, tuples, etc!\n", + "\n", + "### Collection Creation and Conversion\n", + "We've seen many of these already. Aside from range(), everythong on this list can initialize a collection of some type and/or type-cast an object to the given type:\n", + "\n", + "* `range()`: Generates a range of numbers. \n", + "* `list()`: Creates or converts an iterable to a list.\n", + "* `tuple()`: Creates or converts an iterable to a tuple.\n", + "* `set()`: Creates or converts an iterable to a set.\n", + "* `dict()`: Creates a dictionary.\n", + "* `frozenset()`: Converts an iterable to an immutable set.\n", + "* `bytes()`: Converts to bytes, often from a collection of integers.\n", + "* `bytearray()`: Creates a mutable byte array from a collection.\n", + "\n", + "### Inspection and Ordering\n", + "Some of these do exactly what you'd expect:\n", + "* Max, min, and sum require your iterator to contain numeric types. \n", + "* Sorted and reverse sort and reverse the order of your collection. \n", + "* Any and all are especially interested when combined with list comprehinsions. Examples below. \n", + "* Enumerate and zip have examples below as well.\n", + "\n", + "And the functions:\n", + "* `len()`: Returns the number of items in a collection.\n", + "* `max()` and `min()`: Return the maximum and minimum values in a collection.\n", + "* `sum()`: Adds all items in a collection of numbers.\n", + "* `all()`: Checks if all elements in a collection evaluate as True.\n", + "* `any()`: Checks if any element in a collection is evaluate as True.\n", + "* `sorted()`: Returns a sorted list from the items in a collection.\n", + "* `reversed()`: Returns a reversed iterator for a collection. Fwiw, reversed(x) is equivelant to x[::-1] in many cases.\n", + "* `enumerate()`: Adds an index to each item in a collection, useful for loops.\n", + "* `zip()`: Aggregates elements from multiple collections into tuples, useful for creating dictoinaries.\n", + "\n", + "#### *Exercise*:\n", + "* Try each of len, max, min, sum, sorted, reversed on the following 'some_numbers' list. \n", + "* Compute the average of some_numbers using len and sum:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_numbers = [1, 5, 9, 2, 4, 8]\n", + "print('some_numbers:', some_numbers)\n", + "print('len of some_numbers:', ...)\n", + "...\n", + "print('average of some_numbers:', ...)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Example with any and all**:\n", + "These both evaluate truthiness of items in the given collection, which can be useful for checking if any/all items in a collection are empty, zero, etc. They can be even more useful when combined with generator expressions (like list comprehensions) to perform a specific evaluation on each element of a collection. See below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "all nonzero? False True\n", + "any even? True False\n", + "all odd? False True\n" + ] + } + ], + "source": [ + "numbers = [0, 2, 3, 4, 5]\n", + "numbers2 = [1, 3, 5, 7]\n", + "\n", + "# Check if all numbers are non-zero\n", + "all_nonzero = all(numbers)\n", + "all_nonzero2 = all(numbers2)\n", + "print('all nonzero?', all_nonzero, all_nonzero2)\n", + "\n", + "# Check if any numbers are even\n", + "any_even = any(x % 2 == 0 for x in numbers)\n", + "any_even2 = any(x % 2 == 0 for x in numbers2)\n", + "print('any even?', any_even, any_even2)\n", + "\n", + "# Check if all numbers are odd\n", + "all_odd = all(x % 2 == 1 for x in numbers)\n", + "all_odd2 = all(x % 2 == 1 for x in numbers2)\n", + "print('all odd?', all_odd, all_odd2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "We'll try a variation of the above using strings instead of numbers. Using the list provided below, check the following conditions:\n", + "* Are all items lower case? Any items?\n", + "* Are any items UPPER case?\n", + "* Do all items have two words?\n", + "* Are any items zero length? Are all items non-zero length? Try these with and without generator expressions.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fruit = ['red apple', 'green bananna', 'CHERRY', 'orange orange', '']\n", + "all_lower = ...\n", + "any_upper = ...\n", + "all_two_words = ...\n", + "any_zero_len = ...\n", + "#...\n", + "print(\"The Fruit list values are:\")\n", + "for description, value in (('all_lower', all_lower), \n", + " ('any_upper', any_upper), \n", + " ('all_two_words', all_two_words), \n", + " ('any_zero_len', any_zero_len)):\n", + " print(f'{description}: {value}')\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "These two are a little more complicated, but reasonably fall into the same category with sorted() and reversed(). \n", + "\n", + "\n", + "**Enumerate** pairs each item in a a collection with a number indicating it's position in the collection and is very useful for for loops where you need to know the position of items that you iterate over. \n", + "\n", + "**Zip** takes two collections and pairs their elements into a new collection and is useful for, among other things, creating dictionaries. \n", + "\n", + "An Example using both of these with some print statements to show the results of enumerate and zip, as well as how they're often used. \n", + "\n", + "*Note that when we **print** the output of stuff like zip and enumerate, we wrap them in list() because they return a lazy-evaluating-iterator thing that doesn't print well otherwise. It's a python performance optimization thing. Try removing the list() and see what you get.*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Enumerate:\n", + "some_stuff = ['apple', 'berry', 'car', 'cat']\n", + "print('some_stuff:', some_stuff)\n", + "print('some_stuff enumerated:', list(enumerate(some_stuff)))\n", + "for n, thing in enumerate(some_stuff):\n", + " print(f'The position of {thing} in some_stuff is: {n}')\n", + "\n", + "# Zip:\n", + "colors = ['red', 'green', 'blue', 'black']\n", + "print('stuff zipped with colors:', list(zip(some_stuff, colors)))\n", + "stuff_colors = dict(zip(some_stuff, colors))\n", + "print('and as a dictoinary:', stuff_colors)\n", + "print('The color of the cat is:', stuff_colors['cat'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Iteration and Access Control:\n", + "\n", + "iter(): Returns an iterator for a collection.\n", + "next(): Retrieves the next item from an iterator.\n", + "slice(): Defines a slice, often used to access parts of collections.\n", + "aiter() and anext(): Used for asynchronous iteration (for async generators)\n", + "\n", + "These are probably out of scope for us... a good example will be added here some day." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Filtering and Transformation (Functional stuff)\n", + "These functions are pretty special ...\n", + "\n", + "* `filter()`: Filters items in a collection based on a function.\n", + "* `map()`: Applies a function to each item in a collection, returning an iterator.\n", + "* `lambda`: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + ">>> rands = [random.random() for x in range(5)]\n", + ">>> sorted(rands)\n", + "[0.09589797654338261, 0.26042754570361837, 0.5768146165592276, 0.683793382265455, 0.9427230358114427]\n", + ">>> sorted(rands,)\n", + "\n", + ">>> sorted(rands, key=lambda x: str(x)[3])\n", + "[0.9427230358114427, 0.26042754570361837, 0.5768146165592276, 0.683793382265455, 0.09589797654338261]\n", + ">>> def third(x):\n", + "... return str(x)[3]\n", + "... \n", + ">>> sorted(rands, key=third)\n", + "[0.9427230358114427, 0.26042754570361837, 0.5768146165592276, 0.683793382265455, 0.09589797654338261]\n", + ">>> \n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What else?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/B-Dictionaries_and_Loops.ipynb b/B-Dictionaries_and_Loops.ipynb new file mode 100644 index 0000000..a390719 --- /dev/null +++ b/B-Dictionaries_and_Loops.ipynb @@ -0,0 +1,1034 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section B - Dictionaries and Loops\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**: Dictionaries and advanced control flow - for and while loops - and list comprehinsions.\n", + "\n", + "This is a very exciting week. Dictionaries are so useful for organizing things, and with the introductin of loops, we become real programmers who can perform large tasks with concise bits of code. The Exercises below for the loops are hopefully kind of challenging requring you to use conditoinals, variables, lists, and if else branching!\n", + "\n", + "# Dictionaries\n", + "Dictionaries are for key: value collections.\n", + "\n", + "This could be useful for many reasons! Here's asimple example, and below a more complex example. Some exersices will follow breaking this stuff down. \n", + "\n", + "## Defining dictionaries with content ready to reference:\n", + "We follow the {key: value, key2: value2, ... } pattern for this." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "colors = {\n", + " \"white\": \"#FFFFFF\",\n", + " \"black\": \"#000000\",\n", + " \"red\": \"#FF0000\"\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that keys can be any immutable object!\n", + "* strings\n", + "* numbers\n", + "* tuples\n", + "\n", + "You **cannot use lists** as dictionary keys, and you cannot use dictionaries as dictionary keys.\n", + "\n", + "## Using/Accessing dictionary data\n", + "We have a few ways to use dictionaries:\n", + "* Look values up by key\n", + "* See what keys are in the directory\n", + "* See what values ar in the dictionary\n", + "* See all key:value pairs in the dictionary\n", + "* And some other more obscure stuff to read about later." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The color code for white is #fffffff\n", + "The colors in this dictionary are: dict_keys(['white', 'black', 'red', 'blue'])\n", + "The values in this dictionary are: dict_values(['#fffffff', '#000000', '#FF0000', '#0000FF'])\n", + "And the k:v pairs, aka items, in the dictionary are: dict_items([('white', '#fffffff'), ('black', '#000000'), ('red', '#FF0000'), ('blue', '#0000FF')]) \n", + "\n", + "It can be helpful to iterate ovr the items in a dictionary like this:\n", + " The color \"white\" has the code \"#fffffff\"\n", + " The color \"black\" has the code \"#000000\"\n", + " The color \"red\" has the code \"#FF0000\"\n", + " The color \"blue\" has the code \"#0000FF\"\n" + ] + } + ], + "source": [ + "print('The color code for white is', colors['white'])\n", + "print('The colors in this dictionary are:', colors.keys())\n", + "print('The values in this dictionary are:', colors.values())\n", + "print('And the k:v pairs, aka items, in the dictionary are:', colors.items(), '\\n')\n", + "\n", + "print('It can be helpful to iterate ovr the items in a dictionary like this:')\n", + "for color, code in colors.items():\n", + " print(f' The color \"{color}\" has the code \"{code}\"')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overwriting keys or adding new data to a dictionary:\n", + "Assigmint is the same whether or not the key is already in the dictionary. If it exists already, it will be overwritten with the new value:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current colors: dict_items([('white', '#FFFFFF'), ('black', '#000000'), ('red', '#FF0000')])\n", + "Colors now: dict_items([('white', '#fffffff'), ('black', '#000000'), ('red', '#FF0000'), ('blue', '#0000FF')])\n" + ] + } + ], + "source": [ + "print('Current colors:', colors.items())\n", + "colors[\"blue\"] = \"#0000FF\"\n", + "colors[\"white\"] = \"#fffffff\"\n", + "print('Colors now:', colors.items())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "In the first cell below, we initialize an empty dictionary. In the cell afterward:\n", + "* Let's prompt the user for a color and for a thing.\n", + "* Then put the color and thing into the dictionary as a key value pair.\n", + "* Finally print out the dictionary. \n", + "\n", + "Each time you run the cell, it should add another thing into the dictionary." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Initializing an empty dictionary:\n", + "things_by_color = {}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here:\n", + "# Prompt the user for a color:\n", + "color = input('Enter the color of a thing: ')\n", + "\n", + "# Prompt the user for a thing:\n", + "thing = input...\n", + "\n", + "# Store the thing in the dictionary using the color as the key:\n", + "...\n", + "\n", + "# Print the dictionary:\n", + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Accessing or calling values in dictionaries\n", + "When we use a dictionary to access an oject, it is the same as having a separate variable pointing to the object. Let's explain with an example:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cars: ['toyota'] ['toyota']\n", + "Bicycles: ['schwinn'] ['schwinn']\n" + ] + } + ], + "source": [ + "cars = []\n", + "bicycles = []\n", + "\n", + "vehicles = {\n", + " \"motorcars\": cars,\n", + " \"pedalbikes\": bicycles\n", + "}\n", + "\n", + "cars.append('toyota')\n", + "vehicles[\"pedalbikes\"].append('schwinn')\n", + "\n", + "print('Cars:', cars, vehicles['motorcars'])\n", + "print('Bicycles:', bicycles, vehicles['pedalbikes'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There are a few notable things happening here:\n", + "* We create cars and bicycles variables pointing to lists\n", + "* We create a dictionary with string keys and associated the keys with whatever the variables were associated with. In this case, the very same lists the variables refer to.\n", + "* We add something to the cars list using the variable\n", + "* We add something to the bicycles list using it's key in the dictionary\n", + "* Demonstrate that when we print using the variables and the dictionary, we see the same updated list in both cases. \n", + "\n", + "This concept can be expanded in lots of ways:\n", + "* lists of lists\n", + "* nested dictionaries\n", + "\n", + "And it raises need for discussion about what is passing by reference, what is passing by value, and when do we need to think about this? But that's too much for now!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "# TODO \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "And we can use variables and loops (explanation of loops below) to be more dynamic:\n", + "\n", + "\n", + "**Mapping human readable values to hex codes**\n", + "In this example, we pre-define a bunch of colors and hex values they represent.\n", + "\n", + "\n", + " \"green\": \"#008000\",\n", + " \"blue\": \n", + " \"yellow\": \"#FFFF00\",\n", + " \"cyan\": \"#00FFFF\",\n", + " \"magenta\": \"#FF00FF\"\n", + " }\n", + "\n", + " text_color_code = colors[\"blue\"]\n", + "\n", + "**Grouping files for processing by analysis type**\n", + "This jumps ahead a little by using a for loop, but this is really helpful use case for dictionies. Imagine you have a bunch of data files that use similar processing overall, but with small differences depeding on the particlar analyte beig looked at. We can group common data files in a dictionary and then use the same code on them all later. We'll expand on later, but try to internalize what's happening here:\n", + "\n", + " all_files = {'chloraphyl': [], 'nitrogen': [], 'salinity': []}\n", + " for file_name in os.listdir():\n", + " if 'chloraphyl' in file_name:\n", + " all_files['chloraphyl'].append(file_name)\n", + " elif 'nitrogen' in file_name:\n", + " all_files['nitrogen'].append(file_name)\n", + " elif 'ph' in file_name:\n", + " all_files['salinity'].append(file_name)\n", + " else:\n", + " print('Warning, unknown file:', file_name)\n", + "\n", + "* all_files is a dictionary with three key: value pairs. \n", + "* the key is teh analyte name that we're looking for in the file names\n", + "* the value is a list that we will append each matching file name to. \n", + "* os.listdir() returns a list of all of the files in the current working directory. You could also pass it a path to another directory if needed. \n", + "\n", + "We'll get a dictionary that looks like this afterward:\n", + "\n", + " >>> all_files\n", + " {'chloraphyl': ['chloraphyl_20240202.xlsx', 'chloraphyl_20240202.xlsx', 'chloraphyl_20240202.xlsx',],\n", + " 'nitrogen': ['nitrogen_20240202.xlsx', 'nitrogen20240202.xlsx',],\n", + " 'salinity': ['salinity_20240202.xlsx', 'salinity_20240202.xlsx'] }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# For Loops\n", + "This is really where things start to get interesting. Anything that we did previously that was repetetive can be wrapped into a loop to make a single chunk of code do things over and over. \n", + "\n", + "## basic structure:\n", + "\n", + " for each_thing in many_things:\n", + " # do something with each thing\n", + " print(each_thing)\n", + "\n", + "* \"many_things\" is any iterable - a list, a dictionary, a tuple, a function that yields multiple things, etc.\n", + "* \"each_thing\" is the name that we use to refer to each item from many_things, one at a time. \n", + "* The indented do something block contains all of the code we want to run for each_thing.\n", + "\n", + "## control commands - continue and break\n", + "* Inside the loop, we can call \"break\" to exit the loop, even if there are more things in many_things.\n", + "* And we can call \"continue\" to skip to the next item without running any more code on the current thing.\n", + "\n", + "Let's see an example where we are trying to **find five animals from a list names with three or fewer letters** and then stop when done:\n", + " all_animals = ()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all_animals = ('dog', 'mouse', 'rat', 'squirrel', 'cat', 'rabbit', \n", + " 'hamster', 'gerbil', 'guinea pig', 'pig', 'cow', 'horse',\n", + " 'chinchilla', 'ferret', 'hedgehog', 'sugar glider', 'bat')\n", + "short_animals = []\n", + "for animal in all_animals:\n", + " if len(animal) > 3:\n", + " # skip this one\n", + " continue\n", + " print('found one!', animal)\n", + " short_animals.append(animal)\n", + " \n", + " if len(short_animals) == 5:\n", + " print('all done, found enough')\n", + " break\n", + "print('These are the first five short animals:', short_animals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It's worth noting that we could have done this without continue and break, but using them reduces need for indentaton and helps with concise, readble, code. \n", + "\n", + "#### *Exercise*:\n", + "\n", + "Write a for loop that will try three times to prompt the user for a four letter word. It should break when a valid word is entered. And after the loop, it should print out the given word. Something to consider:\n", + "* What do we do if the user doesn't give a valid word for any of the three tries? How do we avoid an error in the print statement? \n", + "* What are three different ways to make the for loop do the thing three times?\n", + "* Remember that we can use \"input\" to prompt the user: word = input('tell me a word')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Note that _ is a valid variable name in Python, but it is used to indicate that the variable is not used in the loop.\n", + "# if you wanted to print an error message and give a count of tries each time, using something like \"count\" in place of \"_\"\n", + "# would be more appropriate.\n", + "\n", + "for _ in ...:\n", + " ...\n", + "print(...)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## for else\n", + "One last thing to mention about for loops is that we can have an else clause that gets calles only if break is not called from within the for loop. This is like our contingency code for what to do if what we expect doens't happen in the for loop, like we don't find something we're looking for:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " for widgit in suitible_widgets:\n", + " supplier_stock_qty = check_supplier_stock(widget)\n", + " if supplier_stock_qty > 2:\n", + " print('Great, we can order', widget)\n", + " order_widget = widget\n", + " break\n", + " else:\n", + " print(\"Supplier didn't have any suitible widgets in stock!\")\n", + " order_widget = None\n", + " notify_supplier(suitible_widgets)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You could implement this without the for else functionality, but this reduces the numbers of variables needed and helps to show the intent of your code by using it. \n", + "\n", + "The check_supplier_stock and notify_supplier functinos might make rest calls to the supplier web site to check their stock or place an order automatically. \n", + "\n", + "#### *Exercise*:\n", + "\n", + "Modify your user prompt for loop above so that if the user doesn't give a valid response and break is never calles, the else block prints an error message." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for _ in ...:\n", + " ...\n", + " print(...) \n", + " break\n", + "else:\n", + " print(...) # error message here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# While Loops\n", + "Much like for loops, we use while loops to do things over and over, but instead of doing it once for each item in a list of objects passed to the loop, we do it until a condition is met. \n", + "\n", + "## General Structure\n", + "\n", + "while condition:\n", + " do something\n", + "\n", + "* Like with for loops, we can call continue and break.\n", + "* while True: will loop forever becaues True is never False. We'd have to use break to exit the loop in this case. \n", + "\n", + "Let's try our animal example again:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "found one! bat\n", + "found one! cow\n", + "found one! pig\n", + "found one! cat\n", + "found one! rat\n", + "These are some short animals: ['bat', 'cow', 'pig', 'cat', 'rat']\n" + ] + } + ], + "source": [ + "\n", + "all_animals = ['dog', 'mouse', 'rat', 'squirrel', 'cat', 'rabbit', \n", + " 'hamster', 'gerbil', 'guinea pig', 'pig', 'cow', 'horse',\n", + " 'chinchilla', 'ferret', 'hedgehog', 'sugar glider', 'bat']\n", + "short_animals = []\n", + "while len(short_animals) < 5:\n", + " if len(all_animals) == 0:\n", + " print('no more animals to check')\n", + " break\n", + " animal = all_animals.pop() # take one from the list and remove it from the list\n", + " if len(animal) > 3:\n", + " # skip this one\n", + " continue\n", + " print('found one!', animal)\n", + " short_animals.append(animal)\n", + "\n", + "print('These are some short animals:', short_animals)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What would happen if we didn't check the lengte of all_animals before calling pop? \n", + "What would happen if there weren't five short animalis in the list?\n", + "\n", + "#### *Exercise*:\n", + "\n", + "Let's use a while loop to make a guessing game! We'll generate a random number from 1 to 100 and, in the loop, prompt the user for a guess. Tell the user if the number is higher or lower than the mystery number. Use a condition on the loop to have it exit automatically when the user has guessed correctly and print a congratulations after the loop!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "mystery_number = random.randint(1, 100)\n", + "user_guess = -1 # start with an invalid guess\n", + "while ...:\n", + " ...\n", + "print('You got it!')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# List Comprehensions\n", + "You can get by without these, but they're a nice tool for doing simple operations to lists of things that reduces code bloat and improves readabiity if you don't get too crazy.\n", + "\n", + "Consider this very standard for loop:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Jaon', 'Maude', 'Henrietta']\n" + ] + } + ], + "source": [ + "people = ['joan', 'maude', 'henrietta']\n", + "tmp_list = []\n", + "for name in people:\n", + " tmp_list.append(name.capitalize())\n", + "people = tmp_list\n", + "print(people)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can replace it with this simple structure:\n", + "\n", + "**[expression for item in iterable]**\n", + "\n", + "* expression: This is the value that will be included in the new list. It uses the item to do something.\n", + "* item: This is a variable that takes the value of each element in the iterable.\n", + "* iterable: This is any Python object capable of returning its members one at a time, such as a list, range, string, etc." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Jaon', 'Maude', 'Henrietta']\n" + ] + } + ], + "source": [ + "people = ['joan', 'maude', 'henrietta']\n", + "people = [name.capitalize() for name in people]\n", + "print(people)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## With A filter:\n", + "Use a filter to select specific items from the source list:\n", + "\n", + "**[expression for item in iterable if condition]**\n", + "\n", + "* condition lets us select specific items from the source list" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['hangman.py', 'args.py', 'writefile.py']\n" + ] + } + ], + "source": [ + "# In practice, you would list files from a directory like this:\n", + "# all_files = os.listdir('optional/path/to/directory')\n", + "# But for this example, we'll just use a pretend listing:\n", + "all_files = ['readme.md', 'data.csv', 'event.log', 'config.json', 'config.yaml', 'hangman.py', 'args.py', 'writefile.py']\n", + "python_files = [file_name for file_name in all_files if file_name.endswith('.py')]\n", + "print(python_files)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Let's try this for ourselves!\n", + "\n", + "#### *Exercise*:\n", + "\n", + "Write list comprehensions in the code cell to modify each source list per the instructions in the comment. Replace each '...'." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# String manipulation - convert the list of signs to all upper case:\n", + "street_signs = ['stop', 'yield', 'one way', 'speed limit', 'wrong way']\n", + "street_signs = [...] # use a list comprehension to convert the signs to upper case\n", + "print(street_signs)\n", + "\n", + "# String slicing - truncate the names to the first 4 characters:\n", + "names = ['Clarice', 'Fernando', 'Xavier', 'Mildred']\n", + "# names = ['Clarice', 'Fernando', 'Ed', 'Tim'] # Challenge mode, make it not error on short names\n", + "names = [...] # use a list comprehension to truncate the names to the first 4 characters\n", + "\n", + "# Conditional - use the if condition to select which values will be kept\n", + "actual_berries = ('blueberry', 'raspberry', 'strawberry', 'blackberry')\n", + "found_fruit = ['strawberry', 'banana', 'kiwi', 'blueberry', 'raspberry', 'blackberry', 'yuzu']\n", + "found_berries = [...] # use a list comprehension to create a list of berries from the found_fruit list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## For loops with multiple variables\n", + "\n", + "A very common use case for this is when we want to iterate over key:value pairs of a dictionary. An example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "animal_sounds = {\n", + " 'dog': 'bark', 'cat': 'meow', 'cow': 'moo',\n", + "}\n", + "for animal, sound in animal_sounds.items():\n", + " print(f'The {animal} says \"{sound}\"')\n", + " \n", + "# An alternative way to do this is:\n", + "for animal in animal_sounds:\n", + " print(f'Again, the {animal} says \"{animal_sounds[animal]}\"')\n", + " \n", + "# Or even:\n", + "for animal_and_sound in animal_sounds.items():\n", + " animal, sound = animal_and_sound\n", + " print(f'And again, the {animal} says \"{sound}\"')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Nested loops\n", + "\n", + "Nesting loops can make code complicated very quickly, but it's very useful to do. Here's an example where we have a dictionary with the values being lists of things. We can iterate through the dictoinary and then itereate throug it's items before going to the next key in the dictinoary." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Chardonnay pairs well with:\n", + " fish\n", + " chicken\n", + " pork\n", + "Merlot pairs well with:\n", + " beef\n", + " lamb\n", + " pasta\n", + "Sauvignon Blanc pairs well with:\n", + " salad\n", + " veggies\n", + " pasta\n" + ] + } + ], + "source": [ + "wine_pairings = {\n", + " 'chardonnay': ['fish', 'chicken', 'pork'],\n", + " 'merlot': ['beef', 'lamb', 'pasta'],\n", + " 'sauvignon blanc': ['salad', 'veggies', 'pasta'],\n", + "}\n", + "for wine, pairings in wine_pairings.items():\n", + " print(f'{wine.title()} pairs well with:')\n", + " for pairing in pairings:\n", + " print(f' {pairing}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "No we see how loops can be both useful and delicious!\n", + "\n", + "#### *Exercise*:\n", + "\n", + "Let's make a tool that collects students grades in several subjects, stores then in a dictionary, and then summarizes them for us. To keep this simple, we can start by storing just a list of grades for each student, but to make things more complicated, we could:\n", + "* Use nested dictinoaries to store each student's grades for each subject separately.\n", + "* Report which student did the best in each subject\n", + "* Improve input validation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello World\n" + ] + } + ], + "source": [ + "students = {'Stanley': [], 'Casey': [], 'Taylor': []}\n", + "subjects = ['math', 'science', 'history']\n", + "\n", + "# First iterate through the students, getting their name and a reference to the list to store their grades in:\n", + "for student, grades in ...:\n", + " # Then iterate through the subjects and prompt for a grade for the student for each subject:\n", + " for subject in ...:\n", + " grade = input(...)\n", + " # convert it to float\n", + " # Store the grade in the list of grades for the student\n", + " \n", + "# And now summarize the grades for each student:\n", + "for ...:\n", + " average = ...\n", + " best = ...\n", + " worst = ...\n", + " # Print stats for the student:\n", + " print(...)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Writing files\n", + "Let's start with writing a file so we have something to read afterward. We can read/write a few types of data:\n", + "* Text data can be read/written direclty. String data is text. And a list of dictionaries could be converted to text if each dict has the same keys in it. \n", + "* Structured data, like a dictionary, can be written by converting it to json or another format.\n", + "* Binary data, like most python objects, can be serialized with \"pickle\" and writen as binary data.\n", + "\n", + "## Simple string/text data\n", + "First simple example! A note on newline charcters:\n", + "* Linux and Mac (any unix flavor OS) uses '\\n' as a newline\n", + "* Windows uses '\\r\\n' as a newline character\n", + "* You can \"import os\" and use os.linesep to get the newline character appropriate for whatever OS your code is running on. \n", + "* Python has writelines and readlines functions that will figure out the newline characters for you.\n", + "* I'll use '\\n' in these examples as it shouldn't matter for any of the examples here, but if you save a file to windows to look at it... ymmv. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "some_text = 'The quick brown fox jumps over the lazy dog!'\n", + "output_file = './simple_text.txt'\n", + "with open(output_file, 'w') as f:\n", + " # f is a file handle that we can write to. f could be any variable name.\n", + " f.write(some_text)\n", + " f.write('\\n') # it's good form to include a newline at the end of the file\n", + "# The file is automatically closed when the with indented block ends" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using \"with\"\n", + "**with** helps us make sure things get cleaned up when we'r done with them. In the example above:\n", + "* \"f\" is the return value of open(output_file, 'w')\n", + "* We can use \"f\", short for file handle, for as many lines as we need, indented below the with line. \n", + "\n", + "The general format is as follows. \n", + "\n", + " with some_function() as variable_name:\n", + " do stuff with variable_name\n", + " ...\n", + " variable_name.close() is called automatically\n", + "\n", + "A few examples of things that support using with:\n", + "* opening zip files, like with the zipfile library.\n", + "* some database connecions, like with the sqlite3 library.\n", + "* temporary files with the tempfile library\n", + "* network calls with requests.get\n", + "* ... lots more\n", + "\n", + "Below is an alternate way to do the same thing without using **with**. You should always use with if you can, but there are occasions where you need to keep a file handle open for a longer time, like if your program opens a mutex file to ensure that it doesn't get run twice at the same time and step on it's own feet. It would only close the mutex when it is done running, and then another instance can open the mutex. \n", + "\n", + "We don't want to forget to close files because:\n", + "* If our program opens a lot of files and never closes them, it can cause performance or stability problems on the computer.\n", + "* While we have the file open, other tools may not be able to access it. Excel, in particular, will complain if you still have an xlsx open." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "f = open(output_file, 'w')\n", + "f.write(some_text)\n", + "f.write('\\n')\n", + "f.close()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Writing structured data\n", + "You can convert data to json, yaml, or ahother format to write to file and easily read it back in later. \n", + "\n", + "**Json** is a format you'll use a lot for web queries. You'll notice that json looks very similar to python code. It's more strict though - no comments allowed, less flexible about quoting, etc. \n", + "**Yaml** is a format that's friendly for editing with a text editor, like for a config file." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import json\n", + "\n", + "data = [{'name': 'Stanley', 'math': '85', 'science': '90', 'history': '92'},\n", + " {'name': 'Casey', 'math': '75', 'science': '80', 'history': '85'},\n", + " {'name': 'Taylor', 'math': '95', 'science': '100', 'history': '100'}]\n", + "\n", + "text_data = json.dumps(data) # dumps is \"dump string\"\n", + "output_file = './stundent_grades.json'\n", + "with open(output_file, 'w') as f:\n", + " f.write(text_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can actually skip the intermediary step of calling json.dumps and let json work directly with the file handle. Either way is okay, but the above is nice to see since it looks like the first simple text example and you can use that dumps funcion for web stuff too. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with open(output_file, 'w') as f:\n", + " json.dump(data, f)\n", + " # notice we're using \"data\", not \"text_data\" here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reading Files\n", + "Reading file data works almost exactly like writing the data.\n", + "\n", + "Note that pandas has it's own functions for reading in .csv, .dat, .xlsx files that we'll look at next week. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "We read this from the file:\n", + "The quick brown fox jumps over the lazy dog!\n", + "\n" + ] + } + ], + "source": [ + "input_file = './simple_text.txt'\n", + "with open(input_file, 'r') as f:\n", + " text = f.read()\n", + "# The file is automatically closed when the with indented block ends\n", + "print(\"We read this from the file:\")\n", + "print(text)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "We read this from the file:\n", + "{'name': 'Stanley', 'math': '85', 'science': '90', 'history': '92'}\n", + "{'name': 'Casey', 'math': '75', 'science': '80', 'history': '85'}\n", + "{'name': 'Taylor', 'math': '95', 'science': '100', 'history': '100'}\n" + ] + } + ], + "source": [ + "input_file = './stundent_grades.json'\n", + "with open(input_file, 'r') as f:\n", + " new_data = json.load(f)\n", + "print(\"We read this from the file:\")\n", + "for student_dict in new_data:\n", + " print(student_dict)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "\n", + "Let's make a journaling tool that we can use to record things we've learned each day in class. We'll use two cells for this.\n", + "\n", + "In the first cell, we can create new jornal entries. Use `open(journam_file, 'a')` with an **a** to append to the file so that if you are making multiple entries on the same date, you don't overwrite one. An entry is a single line of text from the input function.\n", + "\n", + "In the second cell, get a list of journal files using os.listdir and open them one at a time to print out the journal entries. \n", + "\n", + "For extra credit, store the journal entries in json format - you might need to open the file, read the data, add to the data, and rewrite the entire file to store an entry... O_O " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# ADDING NEW JOURNAL ENTRIES\n", + "from datetime import datetime\n", + "\n", + "# We use a file with today's date in the name\n", + "todays_date = datetime.now().strftime(\"%Y-%m-%d\")\n", + "journal_file = f'./journal_{todays_date}.txt'\n", + "# We write some text to the file\n", + "\n", + "# open the file for writing and write the text to it. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# READING JOURNAL ENTRIES\n", + "import os\n", + "\n", + "all_files = os.listdir('.')\n", + "\n", + "# use a list comprehension to filter the files to only the journal files\n", + "journal_files = ...\n", + "\n", + "# iterate over each of the files, open them, print the date from the filename, and print the contents of the file" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Week 2 Turtle Challenge\n", + "Note - you can find example code for running \"turtle\" in the A-Getting_Started notebook. \n", + "\n", + "This time, let's use the power of loops to make shapes of arbitrary numbers of sides with only a few lines of code!\n", + "\n", + "#### *Exercise*:\n", + "**Level 1**\n", + "* Create variables for number of sides and size. \n", + "* Calculate the turn angle based on the number of sides.\n", + "* Use a loop to draw the shape described by the variables\n", + "\n", + "**Level 2**\n", + "* Create a dictionary that describes a variety of shapes, like {'big square': (4, 100), 'small triangle': (3, 50), ...}\n", + "* Create a list that holds a few of the shapes listed ['big square', 'small square', ...]\n", + "* Use a loop to go through the list of shapes to make, looks up the values needed to make the shape, and then draws each shape one at a time. \n", + "\n", + "**Level 3**\n", + "* Create a config file for storing different shapes. Read it in to get the shapes data. \n", + "* Use the list of shapes as above to say which to make from the config file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copy the base turtle code from last week's notebook to start." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/C-Functions_and_Module_Imports.ipynb b/C-Functions_and_Module_Imports.ipynb new file mode 100644 index 0000000..c53c13c --- /dev/null +++ b/C-Functions_and_Module_Imports.ipynb @@ -0,0 +1,417 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section C - Functions and Module Imports\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**: Introducing functions and modules in Python. Basic introduction to pandas for data analysis, focusing on importing data and initial data exploration.\n", + "\n", + "## Functions\n", + "A function is a grouping of code that we assign a name and can pass specific data to (arguments) and return data from (return value)\n", + "\n", + "We use functions for a few things:\n", + "* Reduce dupliation in code - use the same function in multiple places in your code.\n", + "* Simplify code - breaking down complex code into smaller, separate, problems make the entire code more managable and maintainable. \n", + "* Readability - named functions say specifically what they're going to do, so our program is less cluttered and easier to follow. \n", + "\n", + "A note about programming in notebooks like this... breaking code up into cells helps to organize it like a function might in a script. And the most improvemint I've seen in notbooks on duplicated code is by organizing data into dictionaries and using loops to work on each group of data one at a time. Functions are very important when writing scripts and larger programs, but a little less so in notebooks, except that when we import libraries, we call functions in the librar" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### General Format of a Function\n", + "Here's how we define a function:\n", + "\n", + " def function_name(arg1, arg2, ...):\n", + " '''function description in tripple quoted block of text.\n", + " This is not mandatory, but is good practice.'''\n", + " function\n", + " code\n", + " here\n", + " some_value = foo\n", + " return some_value\n", + "\n", + "We can only return one object, but because that object can be a collection like a list or dictionary, we can bundle things to pass them all out. Examples:\n", + "\n", + " return {'a': 'dictionary', 'is': 'okay}\n", + " return 'this', 'will', 'return', 'a', 'tuple'\n", + " x = ['a', 'list', 'works', 'too']\n", + " return x\n", + "\n", + "Here's an example returning a tuple:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def compute_stats_on_numbers(list_of_numbers):\n", + " sum_of_numbers = sum(list_of_numbers)\n", + " count_of_numbers = len(list_of_numbers)\n", + " average_of_numbers = sum_of_numbers / count_of_numbers\n", + " return sum_of_numbers, count_of_numbers, average_of_numbers # This is a tuple. The () around it are implied\n", + "\n", + "numbers = [1, 2, 3, 4, 5]\n", + "num_sum, num_count, num_avg = compute_stats_on_numbers(numbers)\n", + "\n", + "print(f'The function says - Sum: {num_sum}, Count: {num_count}, Average: {num_avg}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scope\n", + "This is a new concept for us - there are certain places where variables can be defined that they will be unaccessible externally. The variables have a specific scope in which they can be used. \n", + "* **Global** - variables defined outside of functinos, classes, etc, in your program are accessible from everywhere. However, it's bad practice to use global variables from inside of functions as it makes it hard to follow what data is used by the function. Side effects can be introduced.\n", + "* **Functions** - variables defined inside of functions are not visible outside of the function. This means we don't neeed to worry about accidentally using a variable from a(nother) function when we don't mean to. \n", + "* **Classes/Objects** - objects (instances of a class) have thier own variables/properties and functions that aren't accessible externally.\n", + "* **Modules** - modules imported like, \"import pandas\", have their own scope inside of \"pandas\" that we access via the module name, like \"pandas.DataFrame\". If we were to do \"from pandas import *\", then all things in the pandas namespace would be populated into our global namespace and we could directly access DataFrame. This can introduce problems, e.g., if multiple modules have things with the same name inside of them. It's better to import specific things to our global namespace if wanted... \"from pandas import DataFrame\" will only add the DataFrame class to our global namespace.\n", + "* And a few other places. Try except blocks, inside of list comprehensions, etc.\n", + "\n", + "What this means to us with regard to functions is that we should pass data the function needs in as arguments, create any variables in the function that we need without worrying about them polluting the namespace of our greater program, and then return the important data from the function with a return call.\n", + "\n", + "#### *Exercise*\n", + "Let's investigate the nuances of global and local variables in a function. Do this:\n", + "\n", + "* Run the cell below and not the values of x inside and outside of the function.\n", + "* Uncomment the x=3 line and see what changes\n", + "* Uncomment the global declaration in the function ans run it again to see what changes.\n", + "\n", + "At first, x only exists in the global namespace, so when we call print, python finds it there. \n", + "\n", + "When we uncomment the x=3, we define x in the function's local namespace, so that is what gets printed. The function's namespace will always be used before the global namespace. Note that we don't overwrite the global namespace x value when we set x in the function. \n", + "\n", + "When we uncomment the global line, we are declaring that the x in the function is in the global namespace, so when we set x=3, we are able to change the global x. There are times when this is useful, but in general we should try not to do this because it makes it harder to debug code and hides interaction between stuff. We should pass data the function needs in as arguments. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "global x is 2\n", + "x in func is: 2\n", + "foo in func is: 2\n", + "now global x is 2\n" + ] + } + ], + "source": [ + "x = 2\n", + "def print_a_value(foo):\n", + " # global x\n", + " # x = 3\n", + " print('x in func is:', x)\n", + " print('foo in func is:', foo)\n", + "print('global x is', x)\n", + "print_a_value(x)\n", + "print('now global x is', x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Positional Arguments\n", + "When we define a function with multiple arguments like this:\n", + "\n", + " def do_the_thing(pos1, pos2, pos3, ..., posN):\n", + "\n", + "We must pass the function N arguments with positions corresponding with the function definition.\n", + "\n", + " return_value = do_the_thing('stuff1', 'stuff2', 'stuff3', ..., 'stuffN')\n", + "\n", + "### Optional Arguments\n", + "We can also set default values for arguments, startning with argument N and working backward. We cannot set a default values for pos1 but not for pos2.\n", + "\n", + " def do_the_thing(arg1, arg2, arg3=False, arg4=True)\n", + "\n", + "In this case, we must pass arg1 and arg2, but we can omit arg3 and arg4 if we don't need them. \n", + "\n", + "Consider this example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "import pandas as pd\n", + "\n", + "def generate_random_data(num_rows, num_cols, to_dataframe=False):\n", + " '''Thes function accepts a number of rows and number of columns and\n", + " generates a table of random data. If to_dataframe is True, it will\n", + " return a pandas DataFrame. Otherwise, it will return a list of dictionaries.'''\n", + " data = [\n", + " {f'col_{j+1}': random.random() for j in range(num_cols)}\n", + " for i in range(num_rows)\n", + " ]\n", + " \n", + " if to_dataframe:\n", + " data = pd.DataFrame(data)\n", + " \n", + " return data\n", + "\n", + "# Example usage\n", + "random_data_list = generate_random_data(5, 3) # not necessary to specify to_dataframe=False\n", + "random_data_df = generate_random_data(5, 3, to_dataframe=True)\n", + "\n", + "print(random_data_list)\n", + "print(random_data_df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the two lines from Example usage, the fist line skipps passing to_dataframe because the default value is acceptable.\n", + "\n", + "#### *Exercise*\n", + "Write a functon called **prompt_user** that accepts two arguments, **choices**, and **num_tries**. \n", + "\n", + "It should ask the user to chose one of the choices, and then try num_tries times to let them type in a choice. If what they type in doesn't match any choices, then have them try again. If they don't do it successfully in num_tries, then return False. If they do chose one, then return that choice. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def prompt_user(...):\n", + " ...\n", + " return user_input" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's test it!\n", + "choices = ['red', 'green', 'blue']\n", + "choice = prompt_user(choices, 2)\n", + "if choice:\n", + " print(f'You chose {choice}')\n", + "else:\n", + " print('You did not choose a valid option')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Keyword Arguments\n", + "Finally, some functions have lots of optional arguments. Often with default values of False for skipping some functionality in the function, or they could have sane defaults like a function to read_a_csv_file might have a default header_row=0 to use the first row of the file as the column headers. You'd only change it when you call the function if you have padding rows at the top of your file. \n", + "\n", + "Let's look at some examples of the pandas read_excel function with different combinations of arguments given. Compare to the function documentation here: https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html\n", + "\n", + "If we have an excel file with multiple sheets, but we want specifically to load the data from sheet2, we can do:\n", + "\n", + " df = pd.read_excel('data.xlsx', sheet_name='Sheet2')\n", + "\n", + "Or if it is only one sheet, but we want to load specific columns and skip the top two rows in the file:\n", + "\n", + " df = pd.read_excel('data.xlsx', usecols=['A', 'C', 'E'], skip_rows=2)\n", + "\n", + "\n", + "### Arbitrary Arguments\n", + "We won't get into this, but look into *args and **kwargs. You can make a funcation accept any arguments. An example use for this is cerating your own version of the print function:\n", + "\n", + " DEBUG = True\n", + "\n", + " def debug_print(*args, **kwargs):\n", + " if DEBUG:\n", + " print(*args, **kwargs)\n", + "\n", + "#### *Exercise*\n", + "Let's make a \"greeting_generator\" function that accepts a few arguments and returns a string with the generated greeting message. Arguments:\n", + "* name - required argument, so it should not have a default value. \n", + "* greeting - optional argument with a default value of \"Hello\". \n", + "* punctuation - optional argument with default value of \"!\".\n", + "* height_in_feet - optional argument with default value of False. If given, we append the string with something witty about the user's height." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def greeting_generator(...):\n", + " ...\n", + " return greeting\n", + "\n", + "# Let's test it!\n", + "print(greeting_generator('Bob'))\n", + "print(greeting_generator('Alice', 'Good morning'))\n", + "print(greeting_generator('Charlie', height=6))\n", + "print(greeting_generator('Diane', punctuation='!', height=4))\n", + "print(greeting_generator('Eve', 'Good night', '!', 5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modules\n", + "We've used a few modules so far. Here's a summary of some common modules:\n", + "\n", + "* **Data analysis and math**\n", + " * pandas - Manipulate structured data in DataFrames. Built on numpy. Sort of like excel but less tedious. \n", + " * matplotlib - Data visualization tool. We use it to generate axis and subplots for more interesting plots. \n", + " * seaborn - Advanced data visualization and analysis tools. \n", + " * numpy - Work with arrays of data. Vectorize data operations for performance. \n", + " * math - Trig functions, sqrt, etc. Used for individual values. x = math.tan(y)\n", + " * datetime - Convert string data to datetime objects and vice-versa. Perform time operations, like adding hours, days, etc. \n", + "* **OS and file handing**\n", + " * sys - Access environment variables, \"exit\", get system information.\n", + " * os - List files (os.listdir), modify permissions, filesystem stats, user account stuff. \n", + " * shutil - Helper funcions for moving and copying files, few other things.\n", + " * tar, zip - Open or create zip and tar archive files with these. tar is more common on linux systems. \n", + " * subprocess - Execute programs or commands outside of python.\n", + "* **Data encapsulation and databases...**\n", + " * json - Structured text format of the web and many things. Use format=\"pretty\"\n", + " * yaml - Like json, but more friedly for humans to edit the files. More flexible allowing in line comments in the file.\n", + " * pickle - pickle and unpickle nearly any python object to save in a file. \n", + " * sqlite3 - file based database\n", + " * mysql - open source mysql database connections...\n", + " * pyodbc - odbc based database connections\n", + "* **Network stuff**\n", + " * requests - talk to web servers\n", + "\n", + "### Conventional short names\n", + "Some modules have accepeted conventions for short names to reduce typing and whatnot. Here are a few common ones:\n", + "* import pandas as pd\n", + "* import numpy as np\n", + "* import subprosess as sp\n", + "\n", + "### Importing modules or parts of modules\n", + "\n", + "We can import modules and access their tools my module name like:\n", + "\n", + " import math\n", + " x = math.sqrt(50)\n", + "\n", + "Or we can import specific components of a module:\n", + "\n", + " from math import sqrt,cos,sin\n", + " x = cos(30)\n", + "\n", + "You can import all things from a module into your global namespace, but it's discouraged. What if you import two modules that have components with the same names in them?\n", + "\n", + " from math import *\n", + "\n", + "When we do \"import math\", all of the variables and functions in that module are protected in a private namespace that we access via math.something(). \n", + "\n", + "#### *Exercise*\n", + "Let's start getting more familiar with pandas.\n", + "* Read through this: https://pandas.pydata.org/docs/user_guide/10min.html\n", + "* Import the pandas module and use dir(pd) to see what functionality is built into it. Or if you have python running in a terminal, type 'pd.' and hit the tab key to show a list of functions built into it. \n", + "* Create an empty pandas dataframe and do the same as above to see what functionality is built into it. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "df = pd.DataFrame() # An empty dataframe" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Installing Modules\n", + "Many python modules are available to be installed from the Python Package Index - PyPI: https://pypi.org/. And anyone can contribute a module for other people to use. \n", + "\n", + "Official documentation on installing packages, incuding instructions on how to install pip, if needed: https://packaging.python.org/en/latest/tutorials/installing-packages/ \n", + "Official pip documintation: https://pip.pypa.io/en/stable/\n", + "\n", + "We use **pip** to install packages in most cases. A couple of exceptions:\n", + "* If you're using anaconda python, you should generally try to `conda install numpy` before using pip. \n", + "* If you're on linux, many packages will be available via your distro's package manager. For example in debian flavored distros, you can:\n", + " * `sudo apt install python3-numpy`\n", + " * `apt search python3 | grep some_package_i_need`\n", + "* If you're on mac using brew, you may want to `brew install python3-numpy`. I'm less familiar with mac, so test this. \n", + "\n", + "Also note that in some cases, you must create a virtual environment (venv) to install packages. See the V-Virtual_Environments notebook for more info about this. \n", + "\n", + "**Basic pip install command**:\n", + "\n", + " pip install numpy\n", + "\n", + "**When pip is not in your path, but it is installed:**\n", + "\n", + " python3 -m pip install numpy\n", + "\n", + "**Pip install from inside a notebook** !!!\n", + "\n", + " %pip install numpy\n", + "\n", + "Pip may prompt you to update pip. This is normal and you should do it. When you run pip (or conda), it checks the dependencies of all installed modules, each of which may have dependencies on specific versions of other modules, and tries to find a combination of all of your installed modules that work well together. You'll sometimes be prompted about changes to installed package versions when you add a new package, as well as being prompted to install dependencies of your requested packaegs. For example, if you install pandas, pip will also install numpy. \n", + "\n", + "A final thing to keep in mind is that because PyPI is a public resource with contributions from many thousands of people, there can be malicious code included with packages. Just be cautious. Most packages include source code and if it's something simple without too many other users, you might want to read through te source to see how it works. If you use python at work, it's a very good idea for you to ensure your organization has a strategy for code scanning and approving modules for use. Bark up the chain a bit and advocate for stuff like this if it isn't already in place. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Turtle Challenge with Functions\n", + "Note - you can find example code for running \"turtle\" in the A-Getting_Started notebook. \n", + "\n", + "This week, we can use functions to isolate complex operations into little chunks that are used by other code to perform complex behavior with simple, readable, code.\n", + " \n", + "#### *Exercise*:\n", + "Streamline your turtle code from the Dictionaries and Loops notebook by moving the functionality to draw arbitrary shapes into a function. The function should take arguments for numbers of sides and size and will be called from the ret of your code from last time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/C1-Classes.ipynb b/C1-Classes.ipynb new file mode 100644 index 0000000..9919278 --- /dev/null +++ b/C1-Classes.ipynb @@ -0,0 +1,177 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section C1 - Classes\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**: Introducing classes.\n", + "\n", + "## Classes\n", + "Everything in python is an object, and creating a class is how we define a new type object. We can encapsulate any behavior and data into a class that we want, and classes can inherit other classes in order to expand on their functionality. \n", + "\n", + "This is a classic example. We are at a school and need to keep records of people at the school. There are properties that all people have and properties that only specific people, students, teachers, administrators, will have. So weu can create a generic people class and inherit that into separate student and teacher classes. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Person:\n", + " def __init__(self, name, age):\n", + " self.name = name\n", + " self.age = age\n", + "\n", + " def introduce(self):\n", + " return f\"Hi, I'm {self.name} and I'm {self.age} years old.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can extend the person class into separate Student and Teacher classes:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Student(Personef __init__(self, name, age, grade):\n", + " super().__init__(name, age) # Call the parent constructor\n", + " self.grade = grade\n", + "\n", + " def introduce(self):\n", + " \n", + " return f\"Hi, I'm {self.name}, a student in grade {self.grade}.\"):\n", + " d" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Teacher(Person):\n", + " def __init__(self, name, age, subject):\n", + " super().__init__(name, age)\n", + " self.subject = subject\n", + "\n", + " def introduce(self):\n", + " return f\"Hello, I'm {self.name}, and I teach {self.subject}.\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And using them to create new objects:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Creating objects\n", + "s1 = Student(\"Alice\", 14, \"8th\")\n", + "t1 = Teacher(\"Mr. Smith\", 40, \"Math\")\n", + "\n", + "# Calling methods\n", + "print(s1.introduce()) # Output: Hi, I'm Alice, a student in grade 8th.\n", + "print(t1.introduce()) # Output: Hello, I'm Mr. Smith, and I teach Math." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Data validation/consistency\n", + "In the __init__ function, we have the opportunity to look at the values being passed in and raise an error if they don't meet our criteria. For example, we might want to make sure the name passd in is:\n", + "\n", + "* a string\n", + "* at least two words long (first and last name)\n", + "\n", + "And we might want to capitalize it automatically for consistency. \n", + "\n", + "**Exercise** " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "v1 line one\n", + "v1 line two\n", + "v1 line three\n", + "line one\n", + "line two\n", + "line three\n", + "v2 line one\n", + "v2 line two\n", + "v2 line three\n", + "line one\n", + "line two\n", + "line three\n" + ] + } + ], + "source": [ + "import time\n", + "chorus = ['line one', 'line two', 'line three']\n", + "verses = {\n", + " 'verse1': [ 'v1 line one', 'v1 line two', 'v1 line three'],\n", + " 'verse2': [ 'v2 line one', 'v2 line two', 'v2 line three'] \n", + "}\n", + "\n", + "for verse, vlines in verses.items():\n", + " for line in vlines:\n", + " print(line)\n", + " time.sleep(1)\n", + " for line in chorus:\n", + " print(line)\n", + " time.sleep(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D0-Pandas_Example.ipynb b/D0-Pandas_Example.ipynb new file mode 100644 index 0000000..d61e7f0 --- /dev/null +++ b/D0-Pandas_Example.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section D0 - Pandas Example\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "The name \"Pandas\" comes from \"Panel Data\" and \"Python Data Analysis\". \"Panel Data\" refers to two dimensoinal data, often including measurements over time - time series - or collections of things/events. The term \"Pandas\" is a blend of these concepts, reflecting the library's purpose of providing data structures and data analysis tools in Python.\n", + "\n", + "**Pandas** are playfull and memorable, just like **Pandas**!\n", + "\n", + "Pandas has two types of objects, **DataFrames** and **Series**. A dataframe has rows and columns, like a spreadsheet - two dimensional. A single row or column from a dataframe is a Series. If we select a single column from a DataFrame, we get a series, a single dimensional object, and a series can be inserted into a df column. \n", + "\n", + "By convention, we'll import pandas as \"pd\" to save us some typing.\n", + "\n", + " import pandas as pd\n", + "\n", + "**This notebook has an example workflow of importing some data into a pandas dataframe and then graphing it** to get a feel for how things work with pandas. Don't worry if not everything here makes sense. **The D1 and following notebooks will go through everything in detail.**\n", + "\n", + "So let's see what we dan do with a list of metiorites from Nasa. The data is is pretty clean (no missing values, bad data, etc), so it doesn't require much cleaning/prep to use. It shouldn't take too many steps to make some nice plots and make some observtions.\n", + "\n", + "First thing is importing. We use requests to query the url, get the json data, and convert it to a **dataframe**. A few useful funtions for viewing data in a dataframe are .head(), .tail(), and .info(). \n", + "\n", + "*There's more info on this meteorite dataset here: https://data.nasa.gov/Space-Science/Meteorite-Landings/gh4g-9sfh/about_data*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "import pandas as pd\n", + "# meteorites = requests.get('https://data.nasa.gov/resource/y77d-th95.json').json()\n", + "meteorites = requests.get('https://raw.githubusercontent.com/a8ksh4/python_workshop/refs/heads/main/SAMPLE_DATA/y77d-th95.json').json()\n", + "mets = pd.DataFrame(meteorites)\n", + "mets.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Great, so we have geolocation, mass, and datetime info for each meteor. Let's try graphing mass per date to see if there's any obvious trend. \n", + "\n", + "We need each column to be the correct datatype before we can generate a plot.\n", + "* To simplify the datetime 'year' column, we use a string operation to split it on the 'T' ang take just the year, month and day. Then we can use pd.to_datetime do convert it to a datetime object by passing in the format to use to convert it. Info on datetime conversion: https://www.w3schools.com/python/gloss_python_date_format_codes.asp\n", + "* We need the mass to be a numeric value so we overwrite the column with itself converted using pd.to_numeric. Similarly, there ar pd.to_int, pd.to_float, pd.to_string operatoins that we might want to use in other cases. \n", + "\n", + "Finally, pandas has a built in plot function that can generate a bunch of different graph types. Setting 'logy' says to graph the y axis in log scale. **Try changing logy between True/False and see what happens to the data points and y axis scale.**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Graph the meteorites by date and mass\n", + "mets['ymd'] = mets['year'].str.split('T').str[0]\n", + "mets['ymd'] = pd.to_datetime(mets['ymd'], format='%Y-%m-%d', errors='coerce')\n", + "mets['mass'] = pd.to_numeric(mets['mass'])\n", + "mets.plot.scatter(x='ymd', y='mass', logy=True, title='Meteorite Mass by Date')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's neat, but doesn't show much of a trend except that we probably have better records of meteorites found since the late 1800s. Maybe it would be interesting to see where on earth we are finding the meteorites. \n", + "\n", + "Let's plot them on a map of the earth. First thing for that is to get a map of the earth. We can use some geopandas stuff for that. Below, \"world\" is a dataframe with rows for each landmass on a map. **Try printing world.head() to see some of the actual data.** The geometry column has a polygon with a list of points making the shape of each continent.\n", + "\n", + "https://geopandas.org/en/stable/docs/user_guide.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas\n", + "from geodatasets import get_path\n", + "\n", + "path = get_path(\"naturalearth.land\")\n", + "world = geopandas.read_file(path)\n", + "world.plot()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now lets put it together! Plotting can get complicated fast... I think that's a weakness of this stuff in python with the pandas, matplotlib libraries, but it's very powerful at least. \n", + "\n", + "To combine plots, we initialize an axis that we pass to the .plot function when we call it for the world and our meteorite dataframes so that the can draw themselves on the same graph. 'ax=ax' looks a littele weird. We'r passing a variable named ax to an argument with the same name. It's just sort of convention to do it this way. Maybe it would be better to use axis for the variable name and pass that to the plot function. \n", + "\n", + "Often when we import data, numeric columns will be imported as string data, so we need to convert the reclong and reclat (longitude and latitude) to numeric values to plot them. **We use .astype(float) to do a type conversion from string to float.**\n", + "\n", + "**Try changing the colormap** - if you put in a bad value, it'll print a bunch of valid color maps you can try in the error message. Also note that the norm=... is to convert the mass to log scale here so that we get nice colors for all of the meteorite masses. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", + "\n", + "fig, ax = plt.subplots(figsize=(12,6)) # create a figure and axis\n", + "\n", + "world.plot(ax=ax) # plot the world on the axis\n", + "\n", + "mets['reclong'] = mets['reclong'].astype(float) # convert reclong column from string to float\n", + "mets['reclat'] = mets['reclat'].astype(float) # convert reclat column from string to float\n", + "\n", + "# plot the meteorites on the same axis\n", + "mets.plot(x=\"reclong\", y=\"reclat\", kind=\"scatter\", \n", + " c=\"mass\", colormap=\"Accent_r\", \n", + " title=f\"Meteors around the world!\", \n", + " ax=ax, norm=matplotlib.colors.LogNorm())\n", + "\n", + "ax.grid(True) # turn on the grid\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Well that's neat. I extected to see more concentration around the equator. We might need to normalize for population density (people who could see and find an asteroid to report on) to get an idea of were most asteroids actually fall. There is a larger version of this dataset at: \n", + "\n", + "We'll look at more actual numerical analysis stuff in Week 4.\n", + "\n", + "#### *Exercise*\n", + "Open a new notebook and download the dataset for observed meteors from here: https://www.kaggle.com/datasets/ramjasmaurya/fireballsbolides-1988-april-2022. Save it in the same directory as your notebook. If you're working in Google Colab, you should be able to go to File -> Locate notebook in Drive, and then upload the dataset csv file to the same directory in Google drive. \n", + "\n", + "Copy over the following code to get started, and use the above example for the meteorites to make a couple of graphs for this new dataset.\n", + "* radiated energy vs time\n", + "* altitude vs radiated energy\n", + "* try using .corr(numeric_only=True) on the dataframe to see which numeric columns have the strongest correlation. What can we say about these boloids when they enter our atmosphere?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "csv_file_name = 'nasas fireballs.csv'\n", + "nfb = pd.read_csv(csv_file_name)\n", + "# nfb.head() # Uncomment to see the first few rows of the data\n", + "# nfb.info() # Uncomment to see the column names and data types of each column\n", + "\n", + "# the date/time ... column is a string that we want to convert to a datetime object\n", + "# we're creating a 'date' column for this. We could also overwrite the existing column\n", + "# nfb['date'] = pd.to_datetime(nfb['date/time for peak brightness'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "#### *Exercise*\n", + "Go through some of these datasets and find something that looks interesting to you that we can work on in the following notebooks. \n", + "\n", + "* https://github.com/jdorfman/awesome-json-datasets - we can direcly query these using requests and the url as we did for the meteorite data. \n", + "* https://catalog.data.gov/dataset/\n", + "* https://data.fivethirtyeight.com/ - they have zip files with csv data\n", + "* https://www.kaggle.com/datasets - click all data sets and you'll see loads of stuff. looks like they have large csv files to download.\n", + "\n", + "At the end of the Pandas series of notebooks, you should be able to prepare and analyze some data that you find interesting. So spend some time finding data that's interesting to you. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D1-Pandas_Intro_and_Data_Selection.ipynb b/D1-Pandas_Intro_and_Data_Selection.ipynb new file mode 100644 index 0000000..e0f13f4 --- /dev/null +++ b/D1-Pandas_Intro_and_Data_Selection.ipynb @@ -0,0 +1,725 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section D1 - Pandas Intro and Data Selection\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Index**\n", + "* General Info\n", + "* Creating a Dataframe\n", + "* Selecting Columns by Name\n", + "* Selecting Rows and Columns with loc and iloc\n", + "* Using .iterrows\n", + "* Selecting Rows with a mask\n", + "* Selecting Rows with .query\n", + "\n", + "## General Info\n", + "Pandas has two types of objects, **DataFrames** and **Series**. A dataframe has rows and columns, like a spreadsheet - two dimensional. A single row or column from a dataframe is a Series. If we select a single column from a DataFrame, we get a series, a single dimensional object, and a series can be inserted into a df column. \n", + "\n", + "By convention, we'll import pandas as \"pd\" to save us some typing.\n", + "\n", + " import pandas as pd\n", + "\n", + " It's also common to call a single dataframe that we're working on \"df\", but it's a good idea to use a longer more descriptive name for complex tasks.\n", + "\n", + " df = pd.read_csv('my_data.csv')\n", + "\n", + "There is functionality built into pd, as well as the dataframe and series objects that we create that we will use to manipulate the dataframe and series. For example, we use these DataFrame functions a lot to view our data:\n", + "\n", + " df.info() # show a summary of columns and data types in the dataframe. \n", + " df.head() # show the top few rows of the dataframe.\n", + " df.tail() # few bottom rows\n", + " df.describe()\n", + " ...and more\n", + "\n", + "And there are functions we call from pd to manipulate the dataframes:\n", + "\n", + " big_df = pd.concat(a_list_of_small_dataframes) # concatenate dataframes together\n", + " ...and more\n", + "\n", + "**A note regarding inplace operations** - Many pandas functions take an argument \"inplace=True/False\". Setting it to true means that the change will be made on the existing dataframe that your variable points to and the function will return None. Setting it to false (or omiting the option) means that the function will return a modified copy of the dataframe that you need to assign to your variable to see the changes. These are roughly equivelant:\n", + " \n", + " df = df.foo() # inplace=False is default\n", + " df.foo(inplace=True)\n", + "\n", + "\n", + "## Creating a Dataframe\n", + "We can create an empty dataframe:\n", + "\n", + " df = pd.DataFrame()\n", + "\n", + "But generally (or always) we'll want to load some data to make a dataframe. Common ways to do this follow. Reference the documentation to see optional arguments to use, like \"skip_rows\" to skip padding rows at the top of an excel or csv file, or use_cols to only import specific columns. \n", + "\n", + "**Excel Files** - https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html\n", + "\n", + " df = pd.read_excel(file_name, ... engine ...)\n", + "\n", + "**CSV Files or dat Files** - https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html\n", + "You may need to set the delimeter for some csv files. \n", + "\n", + " df = pd.read_csv(file_name, ...)\n", + " df = pd.read_table(file_name, ...)\n", + "\n", + "**json Data** - https://pandas.pydata.org/docs/reference/api/pandas.read_json.html\n", + "Useful for data loaded from the web. This is what we use in the D1-Pandas_Example notebook.\n", + "\n", + " df = pd.read_json(json_data, ...)\n", + "\n", + "The json data would need to be structured as a dictionary of lists or a list of dictionaries, as described in the next two examples!\n", + "\n", + "**Dictionary of Lists to DataFrame**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "data = {\n", + " 'Name': ['Alice', 'Bob', 'Charlie'],\n", + " 'Age': [25, 30, 35],\n", + " 'City': ['New York', 'Los Angeles', 'Chicago']\n", + "}\n", + "\n", + "df = pd.DataFrame(data)\n", + "print(df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**list of dictionaries to DataFrame**\n", + "Same idea as above, but slightly different format." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = [\n", + " {'Name': 'Alice', 'Age': 25, 'City': 'New York'},\n", + " {'Name': 'Bob', 'Age': 30, 'City': 'Los Angeles'},\n", + " {'Name': 'Charlie', 'Age': 35, 'City': 'Chicago'}\n", + "]\n", + "df = pd.DataFrame(data)\n", + "print(df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "\n", + "In the following code cell, use these functions to look at information about the dataframe:\n", + "\n", + " .info(), .describe(), and .head() \n", + "\n", + "And print thef following properties of the dataframe, like: `df.shape`\n", + "\n", + " .columns, .size, .shape\n", + "\n", + "* What data type is each of the columns?\n", + "* How many rows and columns are there?\n", + "* What's the relationship between shape and size?\n", + "* Use a list comprehension to overwrite df.columns and make the comlumn names upper case. `df.columns = [... ... df.comumns]`\n", + "\n", + "Scroll through the DataFrame documentation to get an idea of what methods are built into it: https://pandas.pydata.org/pandas-docs/stable/reference/frame.html" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# *We'll use this flowers dataframe for a few exercises below, so make sure to run this cell before continuing.*\n", + "flowers = pd.read_csv(\"https://raw.githubusercontent.com/a8ksh4/python_workshop/main/SAMPLE_DATA/iris.csv\")\n", + "# You can also try saving iris.csv in the directory with your notebook and opening it from a local path." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here. You can re-run the above cell if you mess up your dataframe.\n", + "# print(flowers....)\n", + "flowers.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "flowers.info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## DataFrame Index and Columns\n", + "**df.index** and **df.columns** are identifiers for rows and columns of a dataframe. They can both be numeric or descriptive. It's common to have descriptive column names and an index matching the row numbers, but we can re-assign the index to a column, like a primary-key, before we join two dataframes or perform similar operations between dataframes that reference the index. As we'll look at below, we can also use .iloc to access and modify rows based on their index and columns, so we should know how to set them.\n", + "set to a column that has a sort of primary key for each row of the data. \n", + "Let's create a new dataframe for this example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fruits = pd.DataFrame({'fruit': ['apple', 'banana', 'cherry', 'date'],\n", + " 'color': ['red', 'yellow', 'red', 'brown'],\n", + " 'weight kg': [0.2, 0.3, 0.05, 0.1]})\n", + "print(fruits)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Right now, the index matches the row numbers. Let's do a few manipulations of the index to see how that works:\n", + "* Change the index to the fruit column\n", + "* Modify the index after changing it. \n", + "* Reset the index back to numeric\n", + "\n", + "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.set_index.html#pandas.DataFrame.set_index\n", + "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.reset_index.html#pandas.DataFrame.reset_index" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fruits = fruits.set_index('fruit')\n", + "print(fruits)\n", + "fruits.index = fruits.index.str.capitalize()\n", + "print(fruits)\n", + "fruits = fruits.reset_index()\n", + "print(fruits)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And let's do something similar with the columns:\n", + "* We'll capitalize the columns\n", + "* and replace any spaces in the column names with an underscore character" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fruits.columns = fruits.columns.str.capitalize()\n", + "fruits.columns = fruits.columns.str.replace(' ', '_')\n", + "print(fruits)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selecting Columns by name:\n", + "We can select a single column by passing it's name in brackets, like: `df['column_name']`\n", + "\n", + "And we can select multiple columns by passing a list of column names in nested brackets: `df[['column1', 'column2', ...]]`\n", + "\n", + "This is a bit like string or list slicing, but using names or lists of names to take a selection of the available columns.\n", + "\n", + "We can use this to both get values from columns or to assign values directly into one or more columns, or to create new columns of some name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# a single column is a series object, so sepal_lenghts is a series.\n", + "sls = flowers['sepal_length']\n", + "print('Some of the sepal lenghths are:\\n', sls)\n", + "print('All the lenghts are:\\n', list(sls))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "Just like we did for the dataframe above, let's explore this \"sls\" series object.\n", + "\n", + "* Use the `.info(), .shape, .size` properties to learn about the object. \n", + "* And Let's try some more interesting functions built into series objects: `.sum(), .value_counts(), .mean()`\n", + "* Check if the series is greater than 3. What is returned? This list of True/False values is important for a future concept, \"masks\", for selecting rows.\n", + "* Scroll through some of the methods listed in the series documentation here: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating and manipulating columns of data:\n", + "We can perform mathematical operations on columns of data and put the result into a new or overwrite an existing column. For example, if we want to add a column with units inches instead of cm:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "flowers['sepal_length_inches'] = flowers['sepal_length'] * 0.393701\n", + "\n", + "length_columns = sorted([c for c in flowers.columns if 'length' in c])\n", + "print('length comparison:\\n', flowers[length_columns])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When you perform operations on a column, like multiplying the 'sepal_length' column by 0.393, that operation is broadcast across all rows in the column. \n", + "\n", + "And when we perform operation aginst two columns, each row in the columns is matched with the same index row in the other column for the operation, as with the width_differenc calculation below.\n", + "\n", + "We can also select multiple columns py passing the columns in [], like: `df[['petal_length', 'petal_width']]`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "flowers['width_difference'] = (flowers['sepal_width'] - flowers['petal_width']).abs()\n", + "\n", + "# Alternate ways of selecting and printing columns are commented out below:\n", + "\n", + "# width_columns = flowers.columns[df.columns.str.contains('width')]\n", + "# width_columns = ['sepal_width', 'petal_width', 'width_difference']\n", + "width_columns = sorted([c for c in flowers.columns if 'width' in c])\n", + "\n", + "print('Widths:')\n", + "# print(flowers[['sepal_width', 'petal_width', 'width_difference']])\n", + "print(flowers[width_columns])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selecting Rows with loc and iloc\n", + "**.loc** vs **.iloc**\n", + "* .loc selects rows with particular labels in the series or dataframe index\n", + " * https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.iloc.html\n", + "* .iloc selects rows at integer locations within the series or dataframe.\n", + " * https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.loc.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "df = pd.DataFrame({\n", + " 'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', \n", + " 'Grace', 'Hannah', 'Isaac', 'Jack'],\n", + " 'Age': [25, 30, 35, 40, 45, 50, 55, 60, 65, 70],\n", + " 'SSN': ['123-45-6789', '234-56-7890', '345-67-8901', '456-78-9012', \n", + " '567-89-0123', '678-90-1234', '789-01-2345', '890-12-3456', \n", + " '901-23-4567', '123-45-5789'],\n", + " 'City': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix', \n", + " 'Philadelphia', 'San Antonio', 'San Diego', 'Dallas', 'San Jose'],\n", + "})\n", + "df = df.set_index('SSN')\n", + "print(df.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since we set the index of our dataframe to the 'SSN' column, we can use loc to print rows with a specific SSN, or lists of SSNs:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('A single row:\\n', \n", + " df.loc['345-67-8901'])\n", + "print('A list of rows by SSN and a slice of columns from Age to City:\\n', \n", + " df.loc[['345-67-8901','456-78-9012'], 'Age':'City'])\n", + "print('A range of rows by SSN:\\n',\n", + " df.loc['345-67-8901':'567-89-0123', 'City'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can include a column name to print specific values or to set them:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "some_ssn = '345-67-8901'\n", + "print(f'{some_ssn} lives in:', df.loc[some_ssn, 'City'])\n", + "df.loc[some_ssn, 'City'] = 'Saskatoon'\n", + "print('Or was it:', df.loc[some_ssn, 'City'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "A few people have moved, please update their addresses:\n", + "* People with SSNs '678-90-1234' and '789-01-2345' didn't pay their taxes and are singing the blues in 'Folsom'. \n", + "* People with SSNs '890-12-3456', '901-23-4567', and '123-45-5789' are retiring and moved to 'Palm Beach'.\n", + "How would you do each of these one at a time with a loop, or all at once in a single operation? " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### loc selection of rows and columns\n", + "Rather than selecting by index value with loc, we can use iloc to select by row address, like 0, 1 or 2, a list of addresses, [1, 2, 3], or a range of addresses, [2:6]. And same for the columns returned. A few examples:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('Row 0:\\n', \n", + " df.iloc[0])\n", + "print('\\nRows 2 and 5 and Age column:\\n', \n", + " df.iloc[[2,5], 1])\n", + "print('\\nRows 2:6 and columns 0 and 1 using slices:\\n', \n", + " df.iloc[2:7, :2])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Just like with loc, we can assign values to rows and columns selected using .loc, and we can capture those selections in new dataframes as needed. \n", + "\n", + "Also notice that the SSN index is shown... if you do a .reset_index, you'd instead see a new numerical index instead of the SSNs. \n", + "We'll look more at the index below.\n", + "\n", + "#### *Exercise*\n", + "Studies have shown that older people tend to be more fun than younger people. \n", + "* Use iloc to creat two new dataframes called 'top_five' and 'bottom_five' from the top and bottom five rows from 'df'. \n", + "* Calculate the average age of each group and determine which group is likely to be the most fun! You can compute the average of a column using .mean()... something like foo['col_name'].mean(). \n", + "\n", + "Do the cities that each group of people live in corroborate the results of the study, or is this silly?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using .iterrows() to iterate over rows\n", + ".iterrows() returns an iterator that we can pair with a for loop to look at each row one at a time. This isn't in the spirit of pandas, which would prefer that we do something to all of the rows at the same time, but it can be very useful. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for row_index, row_vals in df.iterrows():\n", + " # print out the name, city, and age of the person in this row:\n", + " # print(row[1]['Name'], 'lives in', row[1]['City'], 'and is', row[1]['Age'], 'years old.')\n", + " # the [1] is \n", + " print('Row_index:', row_index)\n", + " print(row_vals['Name'], 'lives in', row_vals['City'], 'and is', row_vals['Age'], 'years old.')\n", + " \n", + " if row_vals['Name'].startswith('A'):\n", + " df.loc[row_index, 'Name'] = df.loc[row_index, 'Name'] + ' was here'\n", + " \n", + " print('We can use loc to get the name from the same row:', df.loc[row_index, 'Name'])\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "Use .reset_index() on the df and then iterrows again to see what is changed. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Selecting rows with a mask\n", + "A mask is a way to say \"give me the rows where this condition is true.\" In pandas, you create the mask by writing a conditional statement resulting in a list of true/false values. Each true/false corresponds with a row in the dataframe. Applying the mask gives you only the rows with a corresponding true value.\n", + "\n", + "We'll look at conditional statements and then a mask example.\n", + "\n", + "### Conditional statements\n", + "Here are a few examples of conditional statements:\n", + "* Their age is greater than 30:\n", + " * `df['Age'] > 30`\n", + "* Their name contains the letter 'a' and they are older than 40:\n", + " * `df['Name'].str.lower().str.contains('a') & (df['Age'] > 40)`\n", + "* They are older than 50 or younger than 30:\n", + " * `(df['Age'] > 50) | (df['Age'] <= 30)`\n", + "\n", + "Note that rather than \"and\" and \"or\" in regular python code, we use \"&\" and \"|\" when comparing pandas series. These are python bitwise operators. \n", + "\n", + "* Bitwise And: `a & b`\n", + "* Bitwise Exclusive Or: `a ^ b`\n", + "* Bitwise Inversion (not): `~ a`\n", + "* Bitwise Or: `a | b`\n", + "\n", + "And when using & and |, we need to put parenthesees around the other expressions to make sure they are evaluated before the bitwise operators. \n", + "* This will error:\n", + " * `df['Age'] > 50 | df['Age'] <= 30`\n", + "* This is correct:\n", + " * `(df['Age'] > 50) | (df['Age'] <= 30)`\n", + "\n", + "https://introcs.cs.princeton.edu/python/appendix_precedence/#:~:text=Order%20of%20Evaluation,the%20and%20or%20or%20operators.\n", + "https://docs.python.org/3/library/operator.html#mapping-operators-to-functions\n", + "\n", + "### Example use of a mask to select some rows:\n", + "Let's select all people/rows from our dataframe where their age is > 45:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mask_over_45 = df['Age'] > 45\n", + "# mask_under_eq_45 = ~mask_over_45 # example of inverting/negating a mask\n", + "# mask_under_eq_45 = df['Age'] <= 45 # this is equivelant to the line above\n", + "df_over_45 = df[mask_over_45]\n", + "# df_over_45 = df[df['Age'] > 45] # this is equivelant to above.\n", + "print(mask_over_45)\n", + "print(df_over_45)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "Use conditional statements to make a mask and check .value_counts() on it to see how many people:\n", + "* Are older than 60\n", + "* Have social security numbers starting with '4'\n", + "* Live in Philatelphia or are named Hannah\n", + "* Do not live in Dallas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using .query to select rows\n", + ".query lets us use a sql like syntax to select rows. This is nice becaues it can be more readable than a conditional statement for a mask, it might be better to use a mask for cases like:\n", + "* Your column names have special characters\n", + "* You are generating your query/condition programatically\n", + "* You are using operations like .str.contains or other functions in your query.\n", + "\n", + "Documentation and a few good examples: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html. This shows an example with quoting a column name with a space in it. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "filtered_df = df.query('Age > 30 and City == \"Chicago\"')\n", + "print(filtered_df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exporting files\n", + "If we want to output our data to a file, there are some built in tools to do this. For excel files, we need to make sure the \"openpyxl\" package is installed - this is the default engine that pandas uses to generate the file. \n", + "\n", + "### Single Sheet Excel\n", + "This is pretty simple, just using the to_excel function and giveng it a filename to write to:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# you can comment out the pip line after running it once\n", + "%pip install openpyxl\n", + "out_file = 'flowers.xlsx'\n", + "flowers.to_excel(out_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Multiple Sheets Excel\n", + "For a multi-sheet excel, we need to open a writer and write in each sheet. We use a with statement so the writer is closed automtically after we add our sheets:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "out_file = 'all_data.xlsx'\n", + "sheets = {'flowers': flowers, 'fruits': fruits, 'df': df}\n", + "with pd.ExcelWriter(out_file) as writer:\n", + " for sheet_name, data in sheets.items():\n", + " data.to_excel(writer, sheet_name=sheet_name)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Other\n", + "There are many other built in options for generating output from a dataframe. A few examples:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# csv\n", + "flowers.to_csv('flowers.csv')\n", + "\n", + "# json\n", + "flowers.to_json('flowers.json')\n", + "\n", + "# html - this generates a table that can be viewed in a web browser\n", + "flowers.to_html('flowers.html')\n", + "\n", + "# sql - note that you need to remove the .db file to re-run this cell\n", + "import sqlite3\n", + "conn = sqlite3.connect('flowers.db')\n", + "flowers.to_sql('flowers', conn)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "Hopefully you've found some data that you find interesting and you would like to anaylze, make graphs for, and build a note book to present. Start a new notebook for this and import your data. You may want to clean up column names and/or make a selection of the data to look at. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D2-Data_Cleaning.ipynb b/D2-Data_Cleaning.ipynb new file mode 100644 index 0000000..63807ce --- /dev/null +++ b/D2-Data_Cleaning.ipynb @@ -0,0 +1,394 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section D2 - Data Cleaning with Pandas\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "Topics:\n", + "* Setting column data types\n", + "* Dropping rows with NaN values\n", + "* Removoing rows with invalid values. \n", + "\n", + "Sometimes you'll need to pre-process your data before you can analyze it or present it for analysis. A few scenarios:\n", + "* Excluding rows or columns with missing or invalid data:\n", + " * You have a dataset os several measurments made on many samples. Some of the samples don't have all measurements done, so you need to exclude them. You can use dropna to remove rows or columns that are missing the needed measurements. \n", + " * Some samples have negative values reported, but this is impossible and would have been the result of a transcription error. We can exclude these rows. \n", + "\n", + "* Interpolation:\n", + " * You have time series data collected at irregular intervals and need to interpolate it to a regular interval. \n", + " * You have spectoscopy data for many samples that are measured at regular but not precise wavelengths for each sample, and you need to interpolate each sample so the wavelengths all align.\n", + "* Filling Gaps in data\n", + " * You have time series data with small gaps - you dan forward fill, backward fill, \n", + "* Smoothing out noise in data\n", + " * It is common to use a rolling median to smooth out an analog signal - it might be noisy from second to second, but a rolling median over 20 seconds will smooth it. Often the noise is from the mesurement and not the sample, so the noise should be removed.\n", + " * If you have low frequency, e.g. tidal, data with regular high frequency noise in it, you can use a butterworth filter to exclude the high freqency signal (low pass filter) and preserve the signal you want to analyse. " + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Duration Pulse Maxpulse Calories\n", + "0 60 110 130 409.1\n", + "1 60 117 145 479.0\n", + " Duration Pulse Maxpulse Calories\n", + "169 75 125 150 330.4\n", + "170 a b c d\n", + "\n", + "RangeIndex: 171 entries, 0 to 170\n", + "Data columns (total 4 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 Duration 170 non-null object\n", + " 1 Pulse 170 non-null object\n", + " 2 Maxpulse 170 non-null object\n", + " 3 Calories 166 non-null object\n", + "dtypes: object(4)\n", + "memory usage: 5.5+ KB\n", + "None\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "# df = pd.read_csv('https://raw.githubusercontent.com/a8ksh4/python_workshop/main/SAMPLE_DATA/pulse_calories_modified.csv')\n", + "df = pd.read_csv('./SAMPLE_DATA/pulse_calories_modified.csv')\n", + "print(df.head(2))\n", + "print(df.tail(2))\n", + "print(df.info())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting correct data type for columns\n", + "Right now, df.info is reporting a data type of \"object\" for all columns. Also note the invalid string characters in df.tail output. We can use `.astype(...)` to convert the data to numeric. astype will raise an exception if any of the values in the column(s) cannot be converted to the given data type(s). When this happens, we can either identify and fix those values first or we can include `errors='ignore'` as an argument. \n", + "\n", + "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.astype.html\n", + "\n", + "#### *Exercise*\n", + "Run the folowing cell to convert the columns to numerc data types and modify it as needed resolve the error from astype. Add a print statement for df_numeric.info to verify the new data types of each of the columns.\n", + "What happenend to the string values in the last row of the dataframe?\n", + "\n", + "Also take note of the different usage examples commented out. " + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
DurationPulseMaxpulseCalories
16660110145300.0
16760-115145310.2
16875120150320.4
16975125150330.4
170abcd
\n", + "
" + ], + "text/plain": [ + " Duration Pulse Maxpulse Calories\n", + "166 60 110 145 300.0\n", + "167 60 -115 145 310.2\n", + "168 75 120 150 320.4\n", + "169 75 125 150 330.4\n", + "170 a b c d" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Single column method:\n", + "# df['Duration'] = df['Duration'].astype('int')\n", + "\n", + "# Multiple columns method:\n", + "# df = df.astype('float')\n", + "\n", + "# Multiplue columns method:\n", + "df_numeric = df.astype({'Duration': 'int', \n", + " 'Pulse': 'int', \n", + " 'Maxpulse': 'int', \n", + " 'Calories': 'float'}, \n", + " errors='ignore')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since the string values we want to drop are still inculded, we can try using to_numeric rather than astype. To_numeric accepts an option, errors='coerce', that will tell it to convert incompatible values to NaN rather than preserving the invalid value as astype does. \n", + "\n", + "But to_numeric works only on series data (a single column), so we need to do it once per column or use .apply to run it against all columns. \n", + "\n", + "https://pandas.pydata.org/docs/reference/api/pandas.to_numeric.html#pandas.to_numeric" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "# If I didn't know about .apply, I would use this to convert each column:\n", + "# df_numeric = df.copy()\n", + "# for col in df_numeric.columns:\n", + "# df_numeric[col] = pd.to_numeric(df_numeric[col], errors='coerce')\n", + "\n", + "# But this is much more efficient, and in the spirit of how pandas is intended to be used:\n", + "df_numeric = df.apply(pd.to_numeric, errors='coerce')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A helpful way to see what was changed is to make a mask indicating which rows in df_numeric have NaN values now, and use the mask to see the original rows still preserved in df. Below, .isnull() returns a boolean dataframe of the same shape as the df it's called against with true/false indicating if each cell is NaN. And .any looks along the given axis and reports true for any row that has a true in it, returning a series object that we use as a mask. axis=1 means check each row, and axis=0 would mean check each column." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Duration Pulse Maxpulse Calories\n", + "8 NaN 109 133 195.1\n", + "17 45 90 112 NaN\n", + "27 60 103 132 NaN\n", + "91 45 107 137 NaN\n", + "118 60 105 125 NaN\n", + "135 20 NaN 156 189.0\n", + "141 60 97 127 NaN\n", + "146 60 107 NaN 400.0\n", + "153 'foo' 'bar' 'bla' 'asd'\n", + "170 a b c d\n" + ] + } + ], + "source": [ + "# print rows which will cause errors in astype conversoin to numeric types:\n", + "numeric_na_rows = df_numeric.isnull().any(axis=1)\n", + "print(df[numeric_na_rows])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Removing rows with NaN values\n", + "Now that we have only numeric values and NaN values, we can pretty simply call df.dropna() to drop rows (or cols if we specify the axis argument) that have a NaN in them. \n", + "\n", + "https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.dropna.html\n", + "\n", + "#### *Exescise*:\n", + "Run df_numeric.dropna() in the following cell and use .info() to see how many rows we are left with. How many were removed from the original df dataframe?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Identifying bad data analytically\n", + "We have a bunch of numeric data in our dataframe now, but we might want to sanity check that it looks correct. After all, our interns who transcribed this data are overworked, underpaid, and distracted, so there could be mistakes. \n", + "\n", + "#### *Exercise*:\n", + "Use masks to identify data meeting each of the following conditions. Print and remove the identified rows from our dataset:\n", + "* Rows with Pulse or Maxpulse <30 or >220, as these would be impossible for normal humans\n", + "* Rows with Pulse greater than Maxpulse, as the average can't possibly be greater than the max observed\n", + "* Duration or Calories < 0 as this is not possible\n", + "\n", + "Remember that `~mask` is the inverse of mask, so if your mask matches the condition you want to remove, then you want to set your dataframe to `df[~mask]` to remove the rows that met the criteria.\n", + "\n", + "You can check each condition on by one, or you could check them in a loop and in each iteration of the loop, \"or\" the previous mask and new mask together with \"|\" (the pipe symbol). Then after the loop, your mask will include all of the conditions and you can remove all matching rows at once from df. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your code here\n", + "foo = ...\n", + "df_numeric = df_numeric[foo]\n", + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ahother thing we can do is check that the calories burned per unit time are reasonable. We'll do this by calculating normalized calories per duration and identifying outliers which are more than two standard deviations from the average:\n", + "\n", + "#### *Exercise*\n", + "* Create a \"NormalizedCalories\" column equal to Calories divided by Duration\n", + "* Calculate the average and standard deviation of this new column. \n", + "* Create a mask for abs(NormalizedCalories - Average) > (2 * Stdev)\n", + "* Print the rows identified and remove them from the dataset. Does this seem like a reasonable filter for outliers?\n", + "\n", + "A couple helpful functions you can use for this are:\n", + "* np.abs(...) to calculate the absolute value\n", + "* df['col_name'].describe() will return a **dictionary** of statistics describing the column. You can use 'std' and 'mean' from this dictionary for the standard deviation and the average. Try printing it to see what all is included. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "# your code here:\n", + "df['NormalizedCalories'] = ...\n", + "stats = df['NormalizedCalories'].describe()\n", + "..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting data type of columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inerpolatoin of time series data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# drop columns with missing values\n", + "d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D3-Pandas_Graphing.ipynb b/D3-Pandas_Graphing.ipynb new file mode 100644 index 0000000..5ef586b --- /dev/null +++ b/D3-Pandas_Graphing.ipynb @@ -0,0 +1,374 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section D3 - Graphing with Pandas (and Matplotlib)\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "## DataFrame.plot\n", + "The built-in pandas plotting is based on matplotlib by default and gives a simple inteface to make a lot of plot types. You'll notice that there are a couple of variations of the plot commands that work fairly interchangably:\n", + "* `df.plot.box(by='dayofyear')`\n", + "* `df.plot(kind='box', by='dayofyear')`\n", + "* `df.boxplot(by='dayofyear')`\n", + "\n", + "df.plot.box and df.plot(kind='box') are equivelant and use the pandas plot wrapper to call plt.boxplot. df.boxplot is a more direct call to plt.boxplot - and not all plot types have this call available directly in the dataframe. In any case, you'll notice that plt.box and plt.boxplot don't have a \"by\" argument. There's a bit of code in the pandas wrapper that the above three meuthods use to groupby the data for you. There's a comparison with the plt.box function in the boxplot example below.\n", + "\n", + "The plot function built into the Pandas DataFrame object works with matplotlib to generate plots for you using a few standard arguments:\n", + "\n", + "* **data** is the dataframe object to work on. If you call df.plot, this is implied, and if you call pd.DataFrame.plot(data=df, ...) it must be given as an argument. \n", + "* **x** is a label or position, defaulting to None.\n", + "* **y** is a label, position, or list of balel, positions, defaulting to None.\n", + "* **kind** is the type of plot to make: line, bar, hist, scatter, etc... \n", + "\n", + "As well as a bunch of more detailed options for the plot axis, subplots, style options etc. Read over the documintation for a few min to see what options are available: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.plot.html\n", + "\n", + "Many of the arguments you can pass into df.plot can also be called in some form against `plt`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Let's make a few types of charts!** We'll start by pulling some data that we can work with. This is from the USGS gauging station at Toland Landing in Rio Vista, CA. This data clearly shows the tide, includes a lot of parameters to play with.\n", + "\n", + "Note that we're importing numpy and pyplot here, as these are needed in a couple examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "data_url = 'https://waterservices.usgs.gov/nwis/iv/?sites=11455485&startDT=2024-09-15T20:55:29.967-07:00&endDT=2024-10-15T20:55:29.967-07:00&format=rdb'\n", + "tol_all= pd.read_csv(data_url, sep='\\t', comment='#', header=0)\n", + "tol_all = tol_all.drop(tol_all.index[0])\n", + "\n", + "# If you open the above url in your web browser, you'll see information on what the numeric pcodes represent.\n", + "\n", + "# regression/scatter of specific conductivity and salinity\n", + "# time series with nitrate and chlorophyll; ph,do and chlorophyll...\n", + "# Boxplot of daily temperature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "cols = {'datetime': 'datetime',\n", + " '288768_00065': 'gage height ft',\n", + " '288432_00010': 'temperature C',\n", + " '288434_00095': 'specific conductance uS/cm',\n", + " '291459_00300': 'dissolved oxygen mg/L',\n", + " '291463_00400': 'pH',\n", + " '304254_32295': 'dom ug/L',\n", + " '305297_90860': 'salinity ppt',\n", + " '291460_32316': 'fchl mg/L', # chlorophyll\n", + " '313341_99133': 'nitrate mg/L'\n", + " } \n", + "tol = tol_all[cols.keys()].rename(columns=cols)\n", + "tol['datetime'] = pd.to_datetime(tol['datetime'])\n", + "tol = tol.set_index('datetime')\n", + "tol = tol.apply(pd.to_numeric, errors='coerce')\n", + "print(tol.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Time series\n", + "Since the datetime values in our df are set as the index, plot will automatically use them for the x axis. We specify which column we want to use for the y axis, and the plot type, and we get a decent looking graph:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tol.plot(y='gage height ft', kind='line')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What a nice view showing impact of the tides on the gage height... we can see the high-highs, low-highs, high-lows, and low-lows!\n", + "\n", + "#### *Exercise*:\n", + "Set a few plot parameters to inprove the plot:\n", + "* title, xlabel, ylabel\n", + "* use figsize to make the plot wider. Try (10,5) to start.\n", + "* change y='...' to a list y=['...', '...'] and add the specific conductance column\n", + "* sharing an axis between gauge height and specific conductance doesn't work very well, so set secondary_y='specific conductance uS/cm'. \n", + "What migh twe say aobut the tide cycle at this station, seen via gauge height, and the conductance? \n", + "\n", + "## Scatter\n", + "Scatter plots are useful for visualizing correlation, distribution, and clustering of data. Let's see if there's a relatinship between salinity and conductance in our data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# tol.plot(kind='scatter', y='specific conductance uS/cm', x='salinity ppt')\n", + "tol.plot.scatter(y='specific conductance uS/cm', x='salinity ppt')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "Let's make a few cosmetic changes:\n", + "* Set the color to green with `c='green'`\n", + "* set the point size and transparency with `s=50, alpha=0.7`\n", + "* set the title and axis labels if you like.\n", + "\n", + "Let's see what happens if we use another column to set the color of our points.\n", + "* add `cmap='viridis'` to your plot command\n", + "* set `c=tol['temperature C']` in the plot commmand\n", + "* also try `c=tol['gage height ft']`\n", + "\n", + "What observations can we make about the relationships between temperature, gage height, and salinity?\n", + "\n", + "## Overlaying a Regression Line\n", + "When we run a cell and make a plot, matplotlib creates a figure that the plot is rendered on. We can follow with a second plot in the same cell and it will be drawn on the same figure. This can be useful to add a regression line over our scatter plot.\n", + "\n", + "There are some Nan values in the conductance and salinity columns in our dataframe, so we need to use dropna to clean those up before using np.polyfit. So we create a tol_cleaned dataframe.\n", + "\n", + "Then we generate our y values as `regression_line` using our x values with the slope and intercept... this is a y=mx+b equation, but since x is a series, the mutiplication and addition operations are broadcast through the series and we get a series result that we save as regression_line. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Scatter plot\n", + "tol.plot(kind='scatter', y='specific conductance uS/cm', x='salinity ppt')\n", + "\n", + "# Fit a regression line\n", + "tol_cleaned = tol[['specific conductance uS/cm', 'salinity ppt']].dropna()\n", + "y = tol_cleaned['specific conductance uS/cm']\n", + "x = tol_cleaned['salinity ppt']\n", + "slope, intercept = np.polyfit(x, y, 1)\n", + "print('slope:', slope, 'intercept:', intercept)\n", + "\n", + "# Generate line points and plot it over the scatter plot\n", + "regression_line = slope * x + intercept\n", + "plt.plot(x, regression_line, color='red')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "An alternative way to generate a regressiono line, rather than generating a list of points on it to plot, is to use plt.axline. axline() accepts arguments xy1, a point the line passes through, and either a second point xy2 or the slope.\n", + "* Comment out the two lines generating and plotting regression_line\n", + "* Add a plt.axline() line\n", + "* set xy1=(0, intercept)\n", + "* set slope=slope\n", + "* set color='r'\n", + "And re-run the cell. Docs on axline: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axline.html\n", + "\n", + "As mentioned above, both plots share the same figure. We can generate two separate plots by adding `plt.show()` before the second plt.plot command. Try doing this to see the result.\n", + "\n", + "## Box and Whiskers Plot\n", + "The df.plot.box function from pandas includes a convenient 'by=\"col_name\"' option that isn't part of plt.boxplot - it will group your data by the given column automatically. There's an example commented out below of grouping the data before passing to plt.boxplot for comparison.\n", + "\n", + "For our plot, let's group our 15 minute data by day and show the temperature each day. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tol['dayofyear'] = tol.index.dayofyear\n", + "\n", + "# These three are all pretty much equivelant:\n", + "tol[['dayofyear', 'temperature C']].plot.box(by='dayofyear')\n", + "# tol[['dayofyear', 'temperature C']].plot(kind='box', by='dayofyear')\n", + "# tol[['dayofyear', 'temperature C']].boxplot(by='dayofyear')\n", + "\n", + "# An example using pyplot directly:\n", + "# grouped_data = tol.groupby('dayofyear')['temperature C'].apply(list)\n", + "# plt.boxplot(grouped_data, tick_labels=grouped_data.index)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "* The labels are kind of hard to see... use the `figsize` argument to make the plot wider and the `rot` argument to rotate the labels. \n", + "* Day of year works, but isn't very understandable. The dataframe index is made up of datetime objects, so we can use the strftime function built into datetime objects to get a formatted date. Use the following line for a month_day column and update the plot command to use it instead of dayofyear:\n", + "\n", + " tol['month_day'] = tol.index.strftime('%B %d')\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Just for fun, we can sort of graph the data used to generate a simplified boxplot using a bunch of plots:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "min_max_field = 'temperature C'\n", + "gate_max = tol.groupby('dayofyear')[min_max_field].apply(np.max)\n", + "gate_min = tol.groupby('dayofyear')[min_max_field].apply(np.min)\n", + "gate_avg = tol.groupby('dayofyear')[min_max_field].apply(np.mean)\n", + "stdev = tol.groupby('dayofyear')[min_max_field].apply(np.std)\n", + "\n", + "gate_max.plot(label='max', figsize=(10, 5), style='.')\n", + "gate_min.plot(label='min', style='.')\n", + "gate_avg.plot(label='avg', style='--')\n", + "(gate_avg + stdev).plot(label='avg+stdev')\n", + "(gate_avg - stdev).plot(label='avg+stdev')\n", + "plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Histogram\n", + "We can use a histogram to \"bucket\" values and see which buckets are most common. Let's try this with the temperature data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# histogram\n", + "tol['temperature C'].plot.hist(bins=20)\n", + "\n", + "# group by day of year and generate the histogram again:\n", + "# tol.groupby('dayofyear')['temperature C'].apply(np.mean).plot.hist(bins=20)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multi Axis\n", + "\n", + "We need to pay more attion to matplotlib for multi-axis plots. Let's say we wanted do show plots of several parameters on separate graphs - we can define subplots using plt.subplots and tell each plot we make which axis to draw on. It's a convention to call multiple axis \"axs\". fig, axs = plt.subplots... is equiv to fig, (ax0, ax1, ...) = plt.subplots..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, axs = plt.subplots(3)\n", + "tol['temperature C'].plot(ax=axs[0])\n", + "tol['salinity ppt'].plot(ax=axs[1])\n", + "tol['fchl mg/L'].plot(ax=axs[2])\n", + "\n", + "for n, ax in enumerate(axs):\n", + " ax.set_title(f'Plot/ax {n}')\n", + " ax.label_outer()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "Let's take this to the next level and do a 3x2 plot so we can show the correlation between each of these metrics with gage height alongside the time-series graph. \n", + "* edit the first line with subplots(3, 2). Now axs will be of the format `[[ax00, ax01], [ax10, ax11], [ax20, ax21]]`.\n", + "* Cange the ax=... for each of the current plots to add a [0] on the end of each one, like axs[1][0]\n", + "* Update the loop over axs to a nested loop and adjust the title text to show both. E.g:\n", + "\n", + " for row_num, ax_row in enumerate(axs):\n", + " for col_num, ax in enumerate(ax_row):\n", + " ax.set_title(f'Plot/ax {row_num}-{col_num}')\n", + " ax.label_outer()\n", + "\n", + "Go ahead and re-run the cell now and you should have three plots on the left and three empty boxes on the right side. \n", + "* Add three more scatter plots with axis locations `[0][1]`, `[1][1]`, and `[2][1]`. Each should have `x='gage height ft'` and `y=...` matching either temperature, salinity, or fchl.\n", + "\n", + "Wow, no correlation at all. Maybe there's something we can do to visually see which parameters might correliate... \n", + " \n", + "Finally, let's resize the subplots a bit. We can pass arguments to the subplots command set the overall plot size with figsize, and use gridspec_kw to set the horizontal width ratios for the columns of subplots:\n", + "* `figsize=(8, 8), gridspec_kw={'width_ratios': [2, 1]}`\n", + "\n", + "#### *Exercise*:\n", + "If you one more fun challenge, try making an n*n matrix of scatter plots with regression lines comparing n different parameters. This is vaguely templated below. Figure out how to put set appropriate axis labels, etc!\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "params = ['col1', 'col2', ...]\n", + "# ... generate subplots and whatnot\n", + "for c in range(len(params)):\n", + " for r in range(len(params)):\n", + " # do stuff with each axis" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D4-Advanced_Pandas.ipynb b/D4-Advanced_Pandas.ipynb new file mode 100644 index 0000000..d1ac246 --- /dev/null +++ b/D4-Advanced_Pandas.ipynb @@ -0,0 +1,47 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section D4 - Advanced Pandas\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "Topics:\n", + "* Join and Concatenate\n", + "* groupby\n", + "* stack, unstack, pivot, ...\n", + "\n", + "## Join and Concatenate\n", + "\n", + "## Wide Format vs Long Format\n", + "\n", + "## stack, unstack, and pivot\n", + "**Stack** - This function pivots the columns of a DataFrame into its index, effectively \"stacking\" the data vertically. It converts a DataFrame from a wide format to a long format.\n", + "**Unstack** - This is the reverse of stack. It pivots the index of a DataFrame back into columns, converting it from a long format to a wide format.\n", + "\n", + "## where\n", + "\n", + "## interpolation\n", + "\n", + "## groupby\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D5-Exmaple_Data_Sources.ipynb b/D5-Exmaple_Data_Sources.ipynb new file mode 100644 index 0000000..709db76 --- /dev/null +++ b/D5-Exmaple_Data_Sources.ipynb @@ -0,0 +1,320 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# D5 - Example Data Sources\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Index**:\n", + "* API Keys\n", + "* Water Data\n", + " * CIMIS\n", + " * NWIS Waterdata via web\n", + " * NWIS data via module\n", + "\n", + "\n", + "## API Keys\n", + "When you get an API key for a website, it's associated with your account and not something you want to share. So, it's **not** a good idea to keep API keys in your scripts if you're going to share them, post them on github, etc. \n", + "\n", + "A good strategy is to put them in an environment variable so that you can get the key from the env variable inside your script. In the examples below you'll see checks for os.environ - this is looking for an environment variable with your key.\n", + "\n", + "In linux, you can set an environment variable by adding a line to your ~/.bashrc file like follows, and the log back into your computer:\n", + "\n", + " export CIMIS_API_KEY=\"your key here\"\n", + "\n", + "And in windows, you can run the following in a cmd window:\n", + "\n", + " setx OPENAI_API_KEY “”\n", + "\n", + "Theres more info on this stuff here: https://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cimis Data\n", + "Create an account at https://cimis.water.ca.gov. Once you log, click the \"Account\" button in the top right corner. Scroll down and you'll see an API key that you'll need for queries.\n", + "\n", + "We can query the Cimis data from: https://et.water.ca.gov... \n", + "* There are example queries at: https://et.water.ca.gov/Rest/Index\n", + "\n", + "Here's some example code for querying it:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Request url is: https://et.water.ca.gov/api/data?appKey=46f5b53b-3adc-4a4d-a660-474c010a26f4&startDate=2010-01-01&endDate=2010-01-05&targets=2,8,127\n" + ] + } + ], + "source": [ + "import json\n", + "import os\n", + "import requests\n", + "import pandas as pd\n", + "\n", + "if 'CIMIS_API_KEY' in os.environ:\n", + " api_key = os.environ['CIMIS_API_KEY']\n", + "else:\n", + " api_key = 'your_api_key_here'\n", + "url_base = 'https://et.water.ca.gov/api'\n", + "options = [f'appKey={api_key}', 'startDate=2010-01-01', 'endDate=2010-01-05', 'targets=2,8,127']\n", + "options = '&'.join(options)\n", + "url = f'{url_base}/data?{options}'\n", + "\n", + "print(\"Request url is: \", url)\n", + "response = requests.get(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "response_data = json.loads(response.text)\n", + "# for record in response['Data']['Providers'][0]['Records']:\n", + "# print(record)\n", + "df = pd.DataFrame(response_data['Data']['Providers'][0]['Records'])\n", + "# print(df.info())\n", + "# print(df.head())\n", + "\n", + "# The values all have this dictionary format:\n", + "# DayAirTmpAvg: {'Value': '39', 'Qc': ' ', 'Unit': '(F)'}\n", + "\n", + "# So we need to break them out into separate columns:\n", + "value_cols = [c for c in df.columns if c.startswith('Day')]\n", + "for c in value_cols:\n", + " df[f'{c}_Units'] = df[c].apply(lambda x: x['Unit'])\n", + " # You may also want to preserve the Qc value\n", + " df[c] = df[c].apply(lambda x: x['Value'])\n", + "\n", + "print(df.head())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## USGS NWIS Waterdata via Web\n", + "https://waterdata.usgs.gov/\n", + "\n", + "Example site data: https://waterdata.usgs.gov/nwis/uv?site_no=05056241&legacy=1\n", + "There's a new version page at: https://waterdata.usgs.gov/monitoring-location/05056241/\n", + "This one has download data button -> select primary time series -> retreive, and this opens another page with this url:\n", + "https://waterservices.usgs.gov/nwis/iv/?sites=05056241&startDT=2024-09-19T20:57:15.477-05:00&endDT=2024-09-26T20:57:15.477-05:00¶meterCd=00065&format=rdb\n", + "\n", + "Change `format=rdb` to `format=json` and we get some easy to work with data. View it in the browser... usually there's a pretty print check box at the top of the browser for json data like this that will make it easier to read. \n", + "\n", + "The data returned has a lot of meta-data and the time series data we're interested in: \n", + "\n", + " data['value']['timeSeries'][0]['values'][0]['value']\n", + "\n", + "Look through the meta data as some of it is useful... time zone, query info, and meaning of the pcodes in the output data:\n", + "\n", + " \"variable\": {\n", + " \"variableCode\": [\n", + " {\n", + " \"value\": \"00065\",\n", + " \"network\": \"NWIS\",\n", + " \"vocabulary\": \"NWIS:UnitValues\",\n", + " \"variableID\": 45807202,\n", + " \"default\": true\n", + " }\n", + " ],\n", + " \"variableName\": \"Gage height, ft\",\n", + " \"variableDescription\": \"Gage height, feet\",\n", + " \"valueType\": \"Derived Value\",\n", + " \"unit\": {\n", + " \"unitCode\": \"ft\"\n", + " },\n", + " \"options\": {\n", + " \"option\": [\n", + " {\n", + " \"name\": \"Statistic\",\n", + " \"optionCode\": \"00000\"\n", + " }\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#https://waterservices.usgs.gov/nwis/iv/?sites=05056241&startDT=2024-09-19T20:57:15.477-05:00&endDT=2024-09-26T20:57:15.477-05:00¶meterCd=00065&format=rdb\n", + "# midnight to midnight\n", + "startDT = '2024-09-19T00:00:00-05:00'\n", + "endDt = '2024-09-26T00:00:00-05:00'\n", + "# I suspect the 05:00 is the time zone offset\n", + "sites = '05056241' # presumably this could be a comma separated list\n", + "parameterCd = '00065' # discharge in cubic feet per second\n", + "format = 'json'\n", + "base_url = 'https://waterservices.usgs.gov/nwis/iv'\n", + "params = [f'sites={sites}', f'startDT={startDT}', f'endDT={endDt}', f'parameterCd={parameterCd}', f'format={format}']\n", + "params = '&'.join(params)\n", + "url = f'{base_url}/?{params}'\n", + "print(url)\n", + "response = requests.get(url)\n", + "data = json.loads(response.text)\n", + "# print(response.text)\n", + "df = pd.DataFrame(data['value']['timeSeries'][0]['values'][0]['value'])\n", + "print(df.head())\n", + "print(df.info())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Often, you'll be limited in the date range, number of sites, or number of parameters you can query at once, so you can play around and see what works and what gives an error. The json output should have an error code or explanation. Once you know the limits, use a loop to increment the dates and collect all of the data needed:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "chunk_size_days = 7\n", + "from datetime import datetime, timedelta\n", + "start_date = datetime(2024, 1, 1)\n", + "end_date = datetime(2024, 3, 31)\n", + "delta = timedelta(days=chunk_size_days)\n", + "working_date = start_date\n", + "dataframes = []\n", + "while working_date <= end_date:\n", + " end_working_date = working_date + delta\n", + " if end_working_date > end_date:\n", + " end_working_date = end_date\n", + " startDT = working_date.strftime('%Y-%m-%dT00:00:00-05:00')\n", + " endDT = end_working_date.strftime('%Y-%m-%dT00:00:00-05:00')\n", + " params = [f'sites={sites}', f'startDT={startDT}', f'endDT={endDT}', f'parameterCd={parameterCd}', f'format={format}']\n", + " params = '&'.join(params)\n", + " url = f'{base_url}/?{params}'\n", + " print(url)\n", + " response = requests.get(url)\n", + " data = json.loads(response.text)\n", + " df = pd.DataFrame(data['value']['timeSeries'][0]['values'][0]['value'])\n", + " dataframes.append(df)\n", + " working_date = end_working_date + timedelta(days=1)\n", + "df = pd.concat(dataframes)\n", + "\n", + "df.to_csv(f'site_{sites}.csv', index=False)\n", + "print(df.info())\n", + "print(df.head())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## NWIS Data\n", + "This data uses PCodes. You'll need to look up " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd \n", + "%pip install hydrofunctions\n", + "import hydrofunctions as hf\n", + "\n", + "#Example Sites:\n", + "# 'CCH':'11455350', # old CCH41\n", + "# 'CCH41':'11455385', # now called RYF\n", + "# 'CFL':'11455508', # now called CONFL\n", + "# 'DEC':'11455478', # old TOL\n", + "# 'TOL': '11455485',\n", + "\n", + "startDT = '2022-01-01'\n", + "endDT = '2024-02-02'\n", + "site_name = 'CCH41'\n", + "site_code = '11455385'\n", + "\n", + "NWIS_request = hf.NWIS(site_code,'iv',startDT,endDT)\n", + " \n", + "df = NWIS_request.df()\n", + "\n", + "headers = {}\n", + "lines = str(NWIS_request).split('\\n') #treates NWIS_request as a string - this gives us one long string of original col names\n", + "for line in lines[1:-2]: #ignore the first line (which is the site name) and the last two lines (are the strt and end dates)\n", + " line = line.strip() #remove white space\n", + " identifier = line.split(':')[0].strip() \n", + " headers[identifier] = line #put this into the dictionary as the identifier\n", + "\n", + "cols = list(df.columns) #creates a list of original column names\n", + "new_cols = []\n", + "\n", + "for column in cols:\n", + " qual = 'qualifier' in column #creates a bool based on whether the column is a qualifer column, as opposed to a data column\n", + " scol = column.split(':')\n", + "\n", + "df['site_code'] = site_code\n", + "df['site_name'] = site_name\n", + "\n", + "df = df.reset_index()\n", + "\n", + "df['datetimeUTC'] = pd.to_datetime(df['datetimeUTC'], format='%Y-%m-%d %H:%M:%S')\n", + "df['TS Timestamp (PST)'] = df['datetimeUTC'].dt.strftime('%Y-%m-%d %H:%M:%S')\n", + "df['TS Timestamp (PST)'] = pd.to_datetime(df['TS Timestamp (PST)'], format='%Y-%m-%d %H:%M:%S') - pd.Timedelta(hours = 8)\n", + "\n", + "df = df.set_index('TS Timestamp (PST)')\n", + "\n", + "df.columns = [col.split(':')[2] if ':' in col else col for col in df.columns]\n", + "df.columns = [col.split('-')[0] if '-' in col else col for col in df.columns]\n", + "\n", + "print(df.columns)\n", + "print(df.head())\n", + "\n", + "#fname = f'TS_{field_id}_{site}.csv' \n", + "fname = f'TS_{site_code}_{site_name}.csv'\n", + "print('saving to', fname)\n", + "df.to_csv(fname)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/D6-Plotly_Express_and_Dash.ipynb b/D6-Plotly_Express_and_Dash.ipynb new file mode 100644 index 0000000..2340178 --- /dev/null +++ b/D6-Plotly_Express_and_Dash.ipynb @@ -0,0 +1,234 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section D6 - Plotly Express and Dash\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "Plotly is a graphing library, and Plotly Express is a wrapper for it that provides a consistent experience for making a wide variety of plots. It's the recommended starting point for plotly. If you run into a configuration that is'nt supported in express, then you can try using plotly directly.\n", + "\n", + "And Dash is a framework for making interactive visualizations using Plotly (Express). It can pop up an interactive window, a browser tab, or inline graph inside your notebook with interactive elements. Dash is also designed to build elements of larger web pages/dashboards for business/whatever.\n", + "\n", + "**Our Plan**:\n", + "* We'll dive into Plotly Express to learn about how to make and customize plots\n", + "* We'll look at a simple Dash app\n", + "* And we'll make a more complex Dash app\n", + "\n", + "**References**: \n", + "* [Dash in Jupyter](https://dash.plotly.com/dash-in-jupyter)\n", + "* [Plotly Tutorial](https://dash.plotly.com/tutorial)\n", + "* [Python Decorators](https://peps.python.org/pep-0318/)\n", + "* [Plotly Express](https://plotly.com/python/plotly-express/)\n", + "\n", + "## Anatomy of a simple Dash App:\n", + "Let's go through tke example code from the https://dash.plotly.com/minimal-app. The code is in the next cell. Here's a sumarry:\n", + "\n", + "* import statements\n", + "* read in a file as a pandas dataframe\n", + "* initialize the app\n", + "* define the **layout** - this is a list of elements to be shown - The **id** of these is used further down\n", + " * A heading\n", + " * A droptown menue with unique countries from our dataframe, including a default selection\n", + " * The graph we want to show\n", + "* The **update_graph** function\n", + " * The **@callback** stuff above it is a *decorator* that lets us specify the inputs and outputs our function has. \n", + " * These need to use the **id** from each item in our layout. \n", + " * Each **Input** each generate an argument to be passed to our update_graph function. \n", + " * The sequence of the arguments to update_graph matches the seqence that Inputs are listed in the decorator\n", + " * The code inside of the **update_graph** function handles any inputs (like drop down menus) and generates a graph.\n", + "* app.run starts the app. It calls update_graph once automaticaly, and ensures that update_graph gets called again when any of our inputs are interacted with. E.g. if we change the country drop down selction, it gets called. The if __name__ line is a convention in scripts, but behaves the same in a notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from dash import Dash, html, dcc, callback, Output, Input\n", + "import plotly.express as px\n", + "import pandas as pd\n", + "\n", + "df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder_unfiltered.csv')\n", + "\n", + "app = Dash()\n", + "\n", + "app.layout = [\n", + " html.H1(children='Title of Dash App', style={'textAlign':'center'}),\n", + " dcc.Dropdown(df.country.unique(), 'Canada', id='dropdown-selection'),\n", + " \n", + " dcc.Graph(id='graph-content')\n", + "]\n", + "\n", + "@callback(\n", + " Output('graph-content', 'figure'),\n", + " Input('dropdown-selection', 'value')\n", + ")\n", + "def update_graph(value):\n", + " dff = df[df.country==value]\n", + " return px.line(dff, x='year', y='pop')\n", + "\n", + "if __name__ == '__main__':\n", + " app.run(debug=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotly Express" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install dash\n", + "\n", + "from dash import Dash, html, dcc, callback, Output, Input\n", + "app = Dash(__name__)\n", + "import plotly.express as px\n", + "import pandas as pd" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can set the display mode for the plots to one of:\n", + "* \"external\" to pop up a window with the plot\n", + "* \"tab\" to open a separate browser tab\n", + "* \"jupyterlab\" to open the plot in line below the cell in the notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "app.run(jupyter_mode=\"jupyterlab\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's import the same data we used n the Pandas_Graphing notebook to play with here:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " gage height ft temperature C \\\n", + "datetime \n", + "2024-09-15 20:00:00 5.37 20.4 \n", + "2024-09-15 20:15:00 5.58 20.4 \n", + "2024-09-15 20:30:00 5.75 20.3 \n", + "2024-09-15 20:45:00 5.99 20.3 \n", + "2024-09-15 21:00:00 6.21 20.3 \n", + "\n", + " specific conductance uS/cm dissolved oxygen mg/L pH \\\n", + "datetime \n", + "2024-09-15 20:00:00 159.0 8.6 7.8 \n", + "2024-09-15 20:15:00 165.0 8.6 7.8 \n", + "2024-09-15 20:30:00 165.0 8.6 7.8 \n", + "2024-09-15 20:45:00 166.0 8.6 7.8 \n", + "2024-09-15 21:00:00 166.0 8.6 7.9 \n", + "\n", + " dom ug/L salinity ppt fchl mg/L nitrate mg/L \n", + "datetime \n", + "2024-09-15 20:00:00 14.7 0.1 NaN NaN \n", + "2024-09-15 20:15:00 16.6 0.1 NaN NaN \n", + "2024-09-15 20:30:00 16.5 0.1 NaN NaN \n", + "2024-09-15 20:45:00 16.7 0.1 NaN NaN \n", + "2024-09-15 21:00:00 16.7 0.1 NaN NaN \n" + ] + } + ], + "source": [ + "data_url = 'https://waterservices.usgs.gov/nwis/iv/?sites=11455485&startDT=2024-09-15T20:55:29.967-07:00&endDT=2024-10-15T20:55:29.967-07:00&format=rdb'\n", + "tol_all= pd.read_csv(data_url, sep='\\t', comment='#', header=0)\n", + "tol_all = tol_all.drop(tol_all.index[0])\n", + "\n", + "cols = {'datetime': 'datetime',\n", + " '288768_00065': 'gage height ft',\n", + " '288432_00010': 'temperature C',\n", + " '288434_00095': 'specific conductance uS/cm',\n", + " '291459_00300': 'dissolved oxygen mg/L',\n", + " '291463_00400': 'pH',\n", + " '304254_32295': 'dom ug/L',\n", + " '305297_90860': 'salinity ppt',\n", + " '291460_32316': 'fchl mg/L', # chlorophyll\n", + " '313341_99133': 'nitrate mg/L'\n", + " } \n", + "tol = tol_all[cols.keys()].rename(columns=cols)\n", + "tol['datetime'] = pd.to_datetime(tol['datetime'])\n", + "tol = tol.set_index('datetime')\n", + "tol = tol.apply(pd.to_numeric, errors='coerce')\n", + "print(tol.head())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/E-Writing_Scripts.ipynb b/E-Writing_Scripts.ipynb new file mode 100644 index 0000000..13f2d2c --- /dev/null +++ b/E-Writing_Scripts.ipynb @@ -0,0 +1,268 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section E - Writing Scripts / Programs\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics** - Python Editors, Writing and runnig scripts, argparse library\n", + "\n", + "So far, we've been working in python notebooks - these are great for workflows or data centered presentations where you want to mix text, code, and graphs/plots and a human will be interacting with it. \n", + "\n", + "But some times we want to make a tool that we can run, maybe part of an automated process, and don't want to see the code to do it. We can write a script - a text file that the python interpreter runs for us. \n", + "\n", + "**Script** vs **Program** - call it what you want. Calling something a program implies that it's compiled, or at least that its more complicated than a script. Python works just as well for short utility scripts as for gigantic programs, but it's not really\n", + "\\* compiled. In computationaly intensive programs, you might write moudles in C or or another compiled language to handle the cpu-heavy tasks, and call those modules from python, keeping all of the complex program logic in python so that it's more human friendly to work on. \n", + "\n", + "\\* *When you run a python .py script, it is converted to a .pyc bytecode file which is executed by the interpreted. The bytecode is obfuscated, but is trivial to convert back to python code, unlike a truely compiled language. sometimes you'll see people/companies distribute .pyc files to obfuscate their tools somewhat.*\n", + "\n", + "## Installing Python\n", + "You need to have a python interpreter installed on your computer in order to run a python script. You should **select the option during install to add the interpreter to the system PATH** so that when you open up a cmd or powershell window, you can directly run a .py file with \"python3\" in the shebang line and it just runs, or you can say \"pyhon my_script.py\" and python is in your path so it just works. \n", + "\n", + "https://www.python.org/downloads/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Editors (IDEs)\n", + "It's important to use a good editor for writing scripts. Some features of a good editor include:\n", + "* Syntax highlighting\n", + "* Linting - A Linter is a tool that looks at your code for issues like missing variables, misspelled stuff, and any time you diverge from standards and conventions that the rest of the world thinks are a good idea. \n", + "* You make like for your ide to be able to run your code from the editor and give you the output. Or you may prefer to run it from a terminal window separately. \n", + "* Debugging - If you run your code from the editor, you should be able to set breakpoints to pause your script and see what variables are set, etc. \n", + "\n", + "A few good ones are:\n", + "* VS Code\n", + "* IntelliJ or PyCharm\n", + "* Atom\n", + "* Sublime\n", + "* VIM, NeoVIM, or Emacs (there are more of a Linux thing)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "Open a cmd (windows) or xterm (linux) an try running `python --version` or `python3 --version`. if you don't have python installed, you'll get an error. Windows might pop up a windows store page to instal python. That'll probably work. Install python if you need to and get this working. \n", + "\n", + "Install an IDE - I recommend VS Code, but use what you want. The instructions here will all be for VS Code. once installed, go into the extensions menu and search for \"python microsoft\". Install the \"python\", \"Pylance\", \"Pylint\", \"autopep8\" extensions specifically from microsoft. You may also like the \"Jupyter\" extension for notebooks. \"Copilot\" is great too, but requires signing up for it at github.com. \n", + "\n", + "Make a folder in your home directory for python scripts and open that folder with Code. Use the exploror winodw pane on the left to create a new file caled hello.py. Add the following to the file and save it (ctrl+s is a shortcut to save):\n", + "\n", + " #! pyhon3\n", + "\n", + " print(\"Hello World!\")\n", + "\n", + "Pretty Simple! Now cd to that directory in your command window and run the script by typing it's name and hitting enter! You should see the hello world in the cmd window. \n", + "\n", + "We can run it from the IDE too. Use the little triangle in the top right corner of the window to run it and you should see a console pop up on the bottom showing the hello world message. \n", + "\n", + "Finally, if you have any hilighted lines in the script indicating issues, try to resolve them. For example, I see, \"Missing module docstring\" and \"Final newline missing\". A module docstring is a tripple quoted string at the top of the file, just below the shebang line, that says what the file/module does. For example:\n", + "\n", + " #! python3\n", + " '''Simple hello world test script'''\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Template for a script" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#!/usr/bin/env python\n", + "'''Short note about the script/module'''\n", + "\n", + "import stuff\n", + "\n", + "GLOBAL_VAR = 'foo'\n", + "\n", + "def funcDefinition(some, args):\n", + " '''foo'''\n", + " return 'bar'\n", + "\n", + "def main(some, args):\n", + " print('Hello, world!')\n", + "\n", + "if __name__ == '__main__':\n", + " main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**The #! shebang line**\n", + "\n", + "Shebang is short for hash bang. This line says which interpreter to use to run the script. A couple of common entries are:\n", + "* In linux for python3:\n", + " * `#!/usr/bin/env python3`\n", + "* In windows, this would be common:\n", + " * `#! python3`\n", + "\n", + "In both cases the system PATH variable will be checked to find the given interpreter. \n", + "\n", + "You can also specify the complete path to the interpreter you want to use. I might do this to make sure it uses a virtual env that I've configured:\n", + "* `#!/home/my_user/venv/bin/python3`\n", + "\n", + "**module description**\n", + "\n", + "You can add a short documentation abou the purpose of the script/module below the shebang line. \n", + "\n", + "**import statements**\n", + "\n", + "They go at the top.\n", + "\n", + "**global variables**\n", + "\n", + "Things like paths to tools that are called by the script, directories. Global variables should be in ALL_CAPS with underscores between the words if they are multi-word. It's common to have a VERBOSE or DEBUG boolean global that's referenced elsewhere do decide whether or not to print debug messages for troubleshooting issues. \n", + "\n", + "**function definitions**\n", + "\n", + "This is the main body of the script. It's not uncommon to have a \"main\" function that is the first thing called when the script starts. You don't have to define any functions if you don't want to. \n", + "\n", + "**the if __name__ ... condition**\n", + "\n", + "This is something that is important if your script might be used as a module that could be imported by another script or module in order to access your scripts functions and global variables. If your script is imported, then it's __name__ will not be \"__main__\", but if it is called as a script, it's name will be \"__main__\", so the code below here gets executed. \n", + "\n", + "You can also skip this section and just start writing code that will run. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helpful Libraries for Scripts\n", + "\n", + "### sys\n", + "The sys module provides access to some variables and functions that interact with the Python interpreter.\n", + "* **sys.argv** - A list of command-line arguments passed to the script. sys.argv[0] is the script name, and if len(sys.argv) > 1, then it was passed some arguments when it was run. \n", + "* **sys.exit()** - Exits the program with an optional exit code. Exit code zero says that everything worked as expected, and non-zero (positive) says there was an error. You might return different numbers for different errors so if another tool calls your script, it can do something different depending on the exit codes. \n", + "* sys.stdin, sys.stdout, sys.stderr - File objects corresponding to the interpreter’s standard input, output, and error streams.\n", + "\n", + "### os\n", + "The os module provides a way of interacting with the operating system. These are a few essential functions to view current working dir and change directories; list or remove files and directories; create directories. \n", + "\n", + "* os.getenv() - Retrieves the value of an environment variable.\n", + "* os.environ - A dictionary representing the environment variables.\n", + "* os.chdir() - Changes the current working directory.\n", + "* os.getcwd() - Returns the current working directory.\n", + "* os.listdir() - Lists the contents of a directory.\n", + "* os.mkdir() and os.makedirs() - Create directories.\n", + "* os.remove() and os.rmdir() - Remove files and directories.\n", + "* os.path - A submodule for working with file and directory paths, providing functions like:\n", + " * os.path.join()\n", + " * os.path.exists()\n", + " * os.path.isfile()\n", + " * os.path.isdir().\n", + "\n", + "These modules are essential for performing system-level tasks and interacting with the environment in which your Python code is running." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*\n", + "Create a whats_here.py script that does the following:\n", + "* Prints the current working directory. This is the directory that the process that called your script has as its CWD. \n", + "* Gets the current user and saves it to a variable\n", + "* Make a directory called \"foo\" if it does not exist. \n", + "* Checks if a file called f\"foo/{current_user}_was_here.txt\" exists and creates it if not. You should see this in the file explorer and in your command window (run dir foo or ls foo for windows/linux) after it's created. \n", + "* Change directory to f\"C:/Users/{current_user}/Desktop\" and list out the files here. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Script Arguments and sys.argv\n", + "Some times we need scripts to take some parameters to change their behavior. Any arguments you pass to your script when running it get stored in sys.argv so you can check them from the script. This is just like passing arguments to a function. \n", + "\n", + "#### *Exercise*\n", + "Put the following code into a script called \"show_args.py\" and run it with different combinations of arguments passed to it:\n", + "\n", + " #! python3\n", + " '''A simple tool to see what arguments are set when running.'''\n", + " import sys\n", + "\n", + " VERBOSE = False\n", + "\n", + " if '-v' in sys.argv or '--verbose' in sys.argv:\n", + " print('Verbose is set, so I will give detailed messages about what is happening.)\n", + " VERBOSE = True\n", + "\n", + " for n, arg in enumerate(sys.argv):\n", + " if n == 0:\n", + " print(f\"The name of the script is: {arg}\")\n", + " else:\n", + " print(f'arg {n} is: {arg})\n", + " if VERBOSE:\n", + " print(f\"This arg was {len(arg)} characters long!\")\n", + " \n", + " if VERBOSE:\n", + " print(\"Number of args received:\", len(sys.argv) - 1)\n", + "\n", + "For example, you could run: `show_args.py foo bar omg-wow`\n", + "\n", + "For 10 points extra credit, you can make the following modification to the args script: Check if each arg has an '=' character in it. If an = is present, split the arg on the = to keg a key=value pair and assign it to an args_kv dictionary. Then print all of the key value pair given in addition to the other non-kv arguments. \n", + "\n", + "And for an additional 5 points extra credit, handle all of the argument checkin in a function called checkArguments() which returns a tuple with args and args_kv. The function should not print anything. The script should call the function, save the return values, and then print a summary. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Argparse\n", + "The previous exercise hopefully proved that we can simply pass data into a script and check for it, but a really high quality script is able to also provide documentaion about what it does, what arguments are allowed, verify that correct arguments are given and that the values set with them are valid, and return them all in a simple data structure that can be used by the script. It would require a lot of code to do this ourselves, so thankfully we have the \"argparse\" library. \n", + "\n", + "Argparse lets you define what arguments the script accepts, say which of them are required, if any, set default values, set required data types, etc etc. You can find documentation for it here: https://docs.python.org/3/library/argparse.html\n", + "\n", + "Here's an example script utilizing argparse:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Logging" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/EXAMPLES/.hangman.py.swp b/EXAMPLES/.hangman.py.swp deleted file mode 100644 index 6c3c56e..0000000 Binary files a/EXAMPLES/.hangman.py.swp and /dev/null differ diff --git a/F-Flask_Web_Server.ipynb b/F-Flask_Web_Server.ipynb new file mode 100644 index 0000000..bce260c --- /dev/null +++ b/F-Flask_Web_Server.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section F - Flask Web Server\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "Flask is a lightweight WSGI web application framework. It is designed to make getting started quick and easy, with the ability to scale up to complex applications.\n", + "\n", + "We'll make a simple web page mixing flask and dash to make a dashboard and render some cool graphs! See the Plotly_Express notebook for some info on generating nice graphs.\n", + "\n", + "**Our Plan**:\n", + "* We'll dive into Plotly Express to learn about how to make and customize plots\n", + "* We'll look at a simple Dash app\n", + "* And we'll make a more complex Dash app\n", + "\n", + "**References**: \n", + "* [Flask User Guide](https://flask.palletsprojects.com/en/stable/)\n", + "\n", + "## A Minimal First Flask Page:\n", + "Put the following code into a python file and run it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from flask import Flask\n", + "\n", + "app = Flask(__name__)\n", + "\n", + "@app.route(\"/\")\n", + "def hello_world():\n", + " return \"

Hello, World!

\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Routing\n", + "Using the route decorator lets us specify which function is used to generate a page at each URL path. E.g. below for mypage.com/ and mypage.com/hello:\n", + "\n", + " @app.route('/')\n", + " def index():\n", + " return 'Index Page'\n", + "\n", + " @app.route('/hello')\n", + " def hello():\n", + " return 'Hello, World'\n", + "\n", + "\n", + "## Templates\n", + "We can create an html file with our page content and propagate each part of using labels like \"plot0_html\" and \"plot1_html\". Then use matching arguments in the render_template function in your script to pass in the needed code for each graph.\n", + "\n", + "Create ./templates/index.html with the following contents:\n", + "\n", + " \n", + " \n", + " \n", + " Plotly Example\n", + " \n", + " \n", + "

Plotly Graph

\n", + " {{ plot0_html | safe }}\n", + "\n", + "

Another Plotly Graph

\n", + " {{ plot1_html | safe }}\n", + " \n", + " \n", + "\n", + "And a python script with the following code:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#!/usr/bin/env python3\n", + "\n", + "from flask import Flask, render_template\n", + "import plotly.offline as pyo\n", + "import plotly.graph_objs as go\n", + "\n", + "app = Flask(__name__)\n", + "\n", + "@app.route('/')\n", + "def index():\n", + " # Create a Plotly figure\n", + " data0 = [go.Scatter(x=[1, 2, 3], y=[4, 2, 7])]\n", + " fig0 = go.Figure(data=data0)\n", + "\n", + " data1 = [go.Line(x=[1, 2, 3], y=[4, 5, 7])]\n", + " fig1 = go.Figure(data=data1)\n", + "\n", + " # Generate HTML representation of the plot\n", + " plot0_html = pyo.plot(fig0, output_type='div')\n", + " plot1_html = pyo.plot(fig1, output_type='div')\n", + "\n", + " # Render the template with the plot\n", + " return render_template('index.html',\n", + " plot0_html=plot0_html,\n", + " plot1_html=plot1_html)\n", + "\n", + "if __name__ == '__main__':\n", + " app.run(debug=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Run the script and open the printed URL with your browser and you should see two graphs. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/G-Databases_Working_With.ipynb b/G-Databases_Working_With.ipynb new file mode 100644 index 0000000..b3a6418 --- /dev/null +++ b/G-Databases_Working_With.ipynb @@ -0,0 +1,215 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2685a53c", + "metadata": {}, + "source": [ + "# Section G - Working with Databasese\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**:\n", + "* Basics\n", + "* Sqlite\n", + " * Pandas DB Functions\n", + "* Create Table\n", + "* Drop Table\n", + "* Update Rows\n", + "\n", + "There are many types of database: \n", + "* SQl Flavors - Sqlite, MariaDB, PosgreSQL, MySQL, MS SQL, ...\n", + "* NoSQL Flavors - Mongo DB, Elastic, Redis, ...\n", + "\n", + "**Why use databases?**\n", + "* In a business enveronment, a database hosted on a server can be shared by multiple people with updates and queries happenning in parallel. Databases are disigned to host and interacte with large volumes of data and can provide baked-in solutions like [ACID transactions](https://www.mongodb.com/resources/basics/databases/acid-transactions#what-are-acid-transactions).\n", + "* You may need to save your own data when not working with it and storing it in sqlite is one of many ways to serialize it and save it in a file. Pandas dataframes can contain datasets so large they cannot be exported as xlxs (or csv?) files. \n", + "\n", + "## Basics\n", + "To work with a database from python, we do a couple of things:\n", + "* import database library\n", + "* Create a connection to the database - this could be a file path for sqlite, or a server name with login and password for a hosted database like Postgres. \n", + "* Create a cursor from the connection - The cursor is what we use to run commands, inserts, updates, queries and retreive results. \n", + "* Alternatively, pass the connection to a tool like pandas and let it generate queries/updates/inserts for you. \n", + "\n", + "A couple examples:\n", + "\n", + "**Sqlite**\n", + "\n", + " import sqlite3\n", + " \n", + " with sqlite3.connect('example.db') as conn:\n", + " cursor = conn.cursor()\n", + " cursor.execute('SELECT name FROM sqlite_master WHERE type=\"table\";')\n", + " print(cursor.fetchall())\n", + "\n", + "**Postgres**\n", + "\n", + " import psycopg2\n", + "\n", + " with psycopg2.connect(\n", + " dbname=\"your_db\",\n", + " user=\"your_user\",\n", + " password=\"your_password\",\n", + " host=\"localhost\",\n", + " port=\"5432\"\n", + " ) as conn:\n", + " with conn.cursor() as cursor:\n", + " cursor.execute(\"SELECT * FROM your_table LIMIT 5;\")\n", + " print(cursor.fetchall())\n", + "\n", + "\n", + "\n", + "## Mathematical Operations\n", + "These are the basic mathematical functoins that are included in python without importing any libraries." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "3afc46da", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " sepal_length sepal_width petal_length petal_width species\n", + "0 5.1 3.5 1.4 0.2 setosa\n", + "1 4.9 3.0 1.4 0.2 setosa\n", + "2 4.7 3.2 1.3 0.2 setosa\n", + "3 4.6 3.1 1.5 0.2 setosa\n", + "4 5.0 3.6 1.4 0.2 setosa\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "import sqlite3\n", + "iris_web = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')\n", + "\n", + "print(iris_web.head())\n", + "\n", + "# Save the DataFrame to a SQLite database\n", + "with sqlite3.connect('iris_web.db') as conn:\n", + " iris_web.to_sql('iris', conn, if_exists='replace', index=False)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "715d6f0d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " sepal_length sepal_width petal_length petal_width species\n", + "0 5.1 3.5 1.4 0.2 setosa\n", + "1 4.9 3.0 1.4 0.2 setosa\n", + "2 4.7 3.2 1.3 0.2 setosa\n", + "3 4.6 3.1 1.5 0.2 setosa\n", + "4 5.0 3.6 1.4 0.2 setosa\n" + ] + } + ], + "source": [ + "import pandas as pd\n", + "\n", + "with sqlite3.connect('iris_web.db') as conn:\n", + " query = \"SELECT * FROM iris\"\n", + " df = pd.read_sql_query(query, conn)\n", + "\n", + "print(df.head())\n", + "\n", + "# Without the \"with\" statemen:\n", + "# conn = sqlite3.connect('your_database.db')\n", + "# query = \"SELECT * FROM your_table\"\n", + "# df = pd.read_sql_query(query, conn)\n", + "# conn.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d5b02b1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(5.1, 3.5, 1.4, 0.2, 'setosa')\n", + "(4.9, 3.0, 1.4, 0.2, 'setosa')\n", + "(4.7, 3.2, 1.3, 0.2, 'setosa')\n", + "(4.6, 3.1, 1.5, 0.2, 'setosa')\n", + "(5.0, 3.6, 1.4, 0.2, 'setosa')\n", + "(5.4, 3.9, 1.7, 0.4, 'setosa')\n", + "(4.6, 3.4, 1.4, 0.3, 'setosa')\n", + "(5.0, 3.4, 1.5, 0.2, 'setosa')\n", + "(4.4, 2.9, 1.4, 0.2, 'setosa')\n", + "(4.9, 3.1, 1.5, 0.1, 'setosa')\n" + ] + } + ], + "source": [ + "# Without pandas, query the database directly\n", + "with sqlite3.connect('iris_web.db') as conn:\n", + " cursor = conn.cursor()\n", + " cursor.execute(\"SELECT * FROM iris\")\n", + " rows = cursor.fetchall()\n", + "for row in rows[:10]:\n", + " print(row)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fa0e5146", + "metadata": {}, + "outputs": [], + "source": [ + "# Update 2nd row in the df and update it in the database\n", + "df.loc[1, 'sepal_length'] = 99999\n", + "df.head()\n", + "\n", + "with sqlite3.connect('iris_web.db') as conn:\n", + " df.to_sql('iris', conn, if_exists='replace', index=False)\n", + "# Verify the update\n", + "with sqlite3.connect('iris_web.db') as conn:\n", + " query = \"SELECT * FROM iris\"\n", + " updated_df = pd.read_sql_query(query, conn)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9412e892", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/H-Multithreading.ipynb b/H-Multithreading.ipynb new file mode 100644 index 0000000..560c62f --- /dev/null +++ b/H-Multithreading.ipynb @@ -0,0 +1,354 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "88d53049", + "metadata": {}, + "source": [ + "# H - Multi-Threading\n", + "\n", + "\n", + "## What is it?\n", + "Multi-threading enables us to do more than one thing at the same time.\n", + "* One multi-core CPUs, multiple threads can run on multiple cores and perform work concurrently. \n", + "* Even on a single core, threads can take turns running so that if one thread is waiting for a response (network, user input, disk read, etc) another thread can still be productive. \n", + "\n", + "**Options:**\n", + "* Single thread (a process with a single thread)\n", + "* Multiple threads (a process with multiple threads)\n", + "* Multiple processes (multiple processes each having one or more threads)\n", + "* Single thread using asyncio (library enabling single thread to manage multiple io-bound tasks consurrenty)\n", + "* Stackless python - uses greenlets (like threads in a thread) to manage multiple tasks pseudo-concurrently like asyncio.\n", + "* Native Libraries that handle concurrency on their own - numpy, pytorch, etc\n", + "\n", + "\n", + "\n", + "## Reasons for needing threading/concurrency\n", + "* Performance - get things done faster\n", + " * Avoid doing nothing while waiting for a long io bound operation to complete\n", + "* Responsiveness - one thread can check for user input while other threads do the work efficiently\n", + "\n", + "## Pitfalls of threading\n", + "* Python GIL limits actuall parallelism and limits performance.\n", + " * Use multiprocessing or native extensions (e.g., NumPy, PyTorch) for parallel computation.\n", + "* Race Conditions - Multiple threads try to use the same resources at the same time.\n", + " * Use threading.Lock() or higher-level synchronization primitives.\n", + "* Deadlocks - if threads don't release resources then work in other threads can be blocked.\n", + " * Prefer context managers (with lock:) over lock.acquire() / lock.release() manually\n", + "\n", + "## Threading library \n", + "\n", + "**Create a new thread**\n", + "Pass it the functiion that it will execute and the arguments to pass to the function\n", + "```\n", + "import threading\n", + "\n", + "def worker(name_of_worker):\n", + " work()\n", + " work_more()\n", + " print(f'{name_of_worker} is done')\n", + "\n", + "t1 = threading.Thread(target=worker, args=(\"Thread-A\",))\n", + "```\n", + "\n", + "**Start the thread**\n", + "Threads don't start running until told to.\n", + "```\n", + "t1.start()\n", + "```\n", + "\n", + "**Check if the thread is still running**\n", + "```\n", + "if t.is_alive():\n", + " print(\"Thread is still running...\")\n", + "```\n", + "\n", + "**End the thread**\n", + "This is a blocking call that waits for the thread to finish. Don't call this if you need to run other code in the main thread while the worker thread is still running.\n", + "```\n", + "t1.join()\n", + "```\n", + "\n", + "### Locks\n", + "We need to take precautions to avoid reading/changing memory at the same time between threads using locks and/or mutexes. \n", + "\n", + "```\n", + "lock = threading.Lock()\n", + "...\n", + "with lock:\n", + " do_something_with_shared_resource()\n", + "```\n", + "\n", + "## Processes vs threads\n", + "Processes are allocated by the operating system and have their own protected memory. It is expensive to create and destroy processes and sharing data between processes is difficult. Eace process can start multiple threads that all share the process' memory, so threads can communicate, e.g. worker threads can take turns retreiving tasks from a queue in \"shared memory\" to work on them in parallel. \n", + "\n", + "\n", + "\n", + "\n", + "## What is the GIL?\n", + "The GIL - Global Interpreter Lock - is a sort of mutex that only lets one thread execute at a time. Python was designed using the gil initially to make the language more simple and maintainable and to focus on single threaded performance. Many python programs are slowed more by I/O wait than cpu and don't see performance penalty from the gil. \n", + "\n", + "Work is ongoing now to remove the gil, and even standard python can be compiled now without it if you have need for truly concurrent multi-threading with python. Just note that some libraries are not thread safe or not yet updated to work without the gil. \n", + "\n", + "https://py-free-threading.github.io/running-gil-disabled/\n", + "\n", + "\n", + "\n", + "\n", + "# Simple first example\n", + "Let's create two threads that each execute the worker function. \n", + "* threading.Thread returns a handle for a new thread\n", + " * target= specifies the function it will run\n", + " * args= specifies any arguments that should be passed to the function\n", + "* t.start() tells the thread to start running.\n", + "* t.join() waits for the thread to complete. This is \"blocking\". " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "698765cd", + "metadata": {}, + "outputs": [], + "source": [ + "import threading\n", + "import time\n", + "\n", + "def worker(name):\n", + " for i in range(3):\n", + " print(f\"{name} is working on step {i}\")\n", + " time.sleep(1)\n", + "\n", + "# Create threads\n", + "t1 = threading.Thread(target=worker, args=(\"Thread-A\",))\n", + "t2 = threading.Thread(target=worker, args=(\"Thread-B\",))\n", + "\n", + "# Start threads\n", + "t1.start()\n", + "t2.start()\n", + "\n", + "# Wait for threads to finish\n", + "t1.join()\n", + "t2.join()\n", + "\n", + "print(\"All threads are done.\")" + ] + }, + { + "cell_type": "markdown", + "id": "c01345f2", + "metadata": {}, + "source": [ + "## Working with shared memory\n", + "What happens when more than one thread each try to use a counter variable/object with no coordination? In this example, each thread should add 10000 to our counter, so the conter should increment up to 50000 with 5 threads. \n", + "\n", + "Run it couple of times and then uncomment the time.sleep line and run it a few more times. Time.sleep forces a context switch to another thread. This is something that always has a chance of happening at any point in our code but may be infrequent and hard to observe without adding the time.sleep to make it obvious. \n", + "\n", + "Why does the counter total change from 50000 to 10000 or 10001, 10002, 10003, ... when addding the sleep? \n", + "\n", + "Each thread checks the counter and adds to it in it's own variable. If another thread context switches in before the first thread puts its change back on the counter, the second thread will try to make the same change, e.g. both of them try to add 1 to the same number.\n", + "\n", + "With more complicated code these interactins can cause all kinds of unintended behavior." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfccad59", + "metadata": {}, + "outputs": [], + "source": [ + "import threading\n", + "\n", + "counter = 0\n", + "\n", + "def increment():\n", + " global counter\n", + " for _ in range(10000):\n", + " new_value = counter + 1\n", + " # time.sleep(0)\n", + " counter = new_value\n", + "\n", + "threads = [threading.Thread(target=increment) for _ in range(5)]\n", + "\n", + "for t in threads:\n", + " t.start()\n", + "for t in threads:\n", + " t.join()\n", + "\n", + "print(\"Final counter value:\", counter) # Usually not 50000!" + ] + }, + { + "cell_type": "markdown", + "id": "79a5e01b", + "metadata": {}, + "source": [ + "Let's fix this unexpected behavior using a lock that only lets one thread at a time execute the contentious bit of code. This ensures that, even with a task switch in the middle, no thread is able to read the counter between the time that another thread reads it and increments it. The read & update block is atomic. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "62ecb28b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Final counter value: 50000\n" + ] + } + ], + "source": [ + "import threading\n", + "\n", + "counter = 0\n", + "lock = threading.Lock()\n", + "\n", + "def increment():\n", + " global counter\n", + " for _ in range(10000):\n", + " with lock:\n", + " # only one thread at a time can execute this code block\n", + " new_value = counter + 1\n", + " time.sleep(0)\n", + " counter = new_value\n", + "\n", + "# Create 5 threads\n", + "threads = [threading.Thread(target=increment) for _ in range(5)]\n", + "\n", + "for t in threads:\n", + " t.start()\n", + "for t in threads:\n", + " t.join()\n", + "\n", + "print(\"Final counter value:\", counter) # Always 50000!" + ] + }, + { + "cell_type": "markdown", + "id": "f641e652", + "metadata": {}, + "source": [ + "## Problem\n", + "The following code downloads several URLs in a single thread using a loop. Re-write this in the cell below using threads and measure how long it takes to complete compared to the single threaded version. \n", + "\n", + "**Bonus tasks**\n", + "* Add print statements to the thread function to say what each one is doing. Add a name argument so they can say which thread they are.\n", + "* Have the thread function get a lock on the \"urls\" list and pop a url off rather than initializing the threads each with a url." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9767c387", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Working on: https://example.com\n", + "Working on: https://httpbin.org/delay/2\n", + "Working on: https://httpbin.org/uuid\n", + "Working on: https://httpbin.org/ip\n", + "Working on: https://httpbin.org/image/png\n", + "Working on: https://httpbin.org/image/svg\n", + "Single-threaded execution time: 4.17 seconds\n" + ] + } + ], + "source": [ + "# Example single threaded code:\n", + "import requests\n", + "import time\n", + "\n", + "urls = [\n", + " 'https://example.com',\n", + " 'https://www.iana.org/help/example-domains',\n", + " 'https://httpbin.org/delay/2',\n", + " 'https://httpbin.org/uuid',\n", + " 'https://httpbin.org/ip',\n", + " 'https://httpbin.org/image/png',\n", + " 'https://httpbin.org/image/svg',\n", + "]\n", + "\n", + "def save_url(url, number):\n", + " response = requests.get(url)\n", + " with open(f'result_{number}.txt', 'w') as f:\n", + " f.write(response.text)\n", + " \n", + "start_time = time.time()\n", + "for i, url in enumerate(urls):\n", + " print(\"Working on:\", url)\n", + " save_url(url, i)\n", + "end_time = time.time()\n", + "print(f\"Single-threaded execution time: {end_time - start_time:.2f} seconds\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5ac7244", + "metadata": {}, + "outputs": [], + "source": [ + "# Your multi-threaded code here:\n", + "import requests\n", + "import time\n", + "import threading\n", + "\n", + "urls = [\n", + " 'https://example.com',\n", + " 'https://www.iana.org/help/example-domains',\n", + " 'https://httpbin.org/delay/2',\n", + " 'https://httpbin.org/uuid',\n", + " 'https://httpbin.org/ip',\n", + " 'https://httpbin.org/image/png',\n", + " 'https://httpbin.org/image/svg',\n", + "]\n", + "\n", + "def save_url(url, number):\n", + " response = requests.get(url)\n", + " with open(f'result_{number}.txt', 'w') as f:\n", + " f.write(response.text)\n", + "\n", + "# Create threads for each url\n", + "...\n", + "\n", + "start_time = time.time()\n", + "# Start the threads and see how long until are all done\n", + "...\n", + "\n", + "# Wait for the threads to finish\n", + "...\n", + "\n", + "end_time = time.time()\n", + "print(f\"Multi-threaded execution time: {end_time - start_time:.2f} seconds\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/L-LLM.ipynb b/L-LLM.ipynb new file mode 100644 index 0000000..51f8336 --- /dev/null +++ b/L-LLM.ipynb @@ -0,0 +1,1429 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Let's build a Language Model like Chat GPT!\n", + "We'll follow along with this youtube video:\n", + "https://www.youtube.com/watch?v=l-CjXFmcVzY&t=2197s\n", + "\n", + "## Starting out with inputs and weights\n", + "Is the light on or off? x# represent the switches on the wall and w# represent training data. We can cross the inputs with training data to find if the light is on:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "off\n" + ] + } + ], + "source": [ + "x1 = 0\n", + "x2 = 1\n", + "x3 = 0\n", + "\n", + "w1 = 1\n", + "w2 = 0\n", + "w3 = 1\n", + "\n", + "y = (x1 * w1) + (x2 * w2) + (x3 * w3)\n", + "if y > 0:\n", + " light = 'on'\n", + "else:\n", + " light = 'off'\n", + "print(light)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can use numpy arrays instead of having loads of variables for inputs and weights:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "on\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "\n", + "xs = np.asarray([0, 1, 0, 1, 0])\n", + "ws = np.asarray([1, 0, 1, 0, -1])\n", + "y = np.dot(xs, ws) # y = xs @ ws\n", + "\n", + "if y > 0:\n", + " light = 'on'\n", + "else:\n", + " light = 'off'\n", + "print(light)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to automatically adjust the weights if we want our model to learn, so let's add additional events to xs and some known outputs ys. Our weights are unknown/hidden. \n", + "\n", + "We'll start with a random guess at the weights and track our error over 5k tries at guessing propper weights. Do we even find a solution over 5k tries?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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AQOwYsUKhISEyFdqIiIi8lqSg4/Bgwc7bY4zmUyYMWMGZsyY4VHBSJ+MMgsnkdFxRFVSkua9XYiIyL7MvEuabXvr8TzNtq1HGw6d07oIPoXBB0nG7rZEvo/5ptYemLdN6yL4FAYfJAkDDyIi8pTknA8ytrMFpThbwInliIjIfWz5ICIir1FdzedBvoDBBxEReY3J33LMDV/A4IOIiLzG8jT7k5SSd2HwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBREREqmLwQURERKpi8EFERESqYvBBRERkMP/o30rT7TP4ICIiMpjmDUM13T6DDyIiIlIVgw8iIiJSFYMPIiIiUhWDDyIiIoMxmUyabt8wwceF4jKti0BERKQLgiBoun3DBB/5lyu0LgIRERHBQMGHtg1MRERE+nE4t1jT7Rsn+ND4+RYREZFebD52QdPtGyb4ICIiohpa344bJvjQekcTERHphbbppkYKPhh9EBER6YJxgg+2fRAREemC7MHHK6+8ApPJZPXXsWNHuTcjGVs+iIiI9CFAiZV27twZq1evvrqRAEU2Q0RERG7Q+n5ckaggICAAcXFxSqyaiIiIPOSTCaeHDx9GfHw8WrdujbFjxyIzM1OJzUjCxy5ERET6IHvLR2JiIhYsWIAOHTrg7NmzePXVVzFw4ECkp6cjPDy8zvJlZWUoK7s670phYaHcRQLAQcaIiIj0QvbgY8SIEeb/79atGxITE9GiRQt8//33mDBhQp3lZ86ciVdffVXuYtTB0IOIiEgfFO9qGxUVhfbt2+PIkSN23582bRoKCgrMf1lZWUoXiYiIiDSkePBRXFyMo0ePokmTJnbfDw4ORkREhNWfEvjUhYiISB9kDz6eeuoppKSk4MSJE9i0aRPuvPNO+Pv7Y8yYMXJvShIOMkZERKQPsud8nDp1CmPG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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "\n", + "xs = np.asarray([[0, 1, 0, 1, 0],\n", + " [0, 0, 1, 1, 0],\n", + " [1, 1, 0, 1, 0],\n", + " [1, 1, 1, 0, 1],\n", + " [0, 0, 0, 1, 0]])\n", + "\n", + "# ws is now hidden\n", + "ys = np.asarray([[0],\n", + " [1],\n", + " [1],\n", + " [1],\n", + " [0]])\n", + "\n", + "ins = 5\n", + "outs = 1\n", + "\n", + "def weights(ins, outs):\n", + " ws = np.random.randn(ins, outs)\n", + " return ws\n", + "\n", + "ws = weights(ins, outs)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " yh = xs @ ws\n", + " e = yh - ys\n", + " e = np.sum(np.abs(e))\n", + " if e < 0.05:\n", + " print(\"found solution\")\n", + " print(ws)\n", + " else:\n", + " ws = weights(ins, outs)\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "No Solution! We need better learning! we'll adopt a strategy where instead of guessing all new eights, we make changes to our weights and if our changes make an improvement, we keep them. We'll iterate like this. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "found solution\n", + "[[ 1.0280221 ]\n", + " [ 0.01183635]\n", + " [ 1.01485508]\n", + " [-0.01320741]\n", + " [-1.05673078]]\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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rr32Wu3bty/hPQb6PVmxYkXCPiOt7YMd8+uvv/6YNi1YsCBhn3Q85oO1e6C/d4/Ho3vvvTe+Tzoeb0mSyQCrV682gUDAPPjgg+a9994zN954oykqKjJNTU1OlzYk8+fPNw899JDZvn272bp1q/na175mqqqqTEdHR3yfiy66yNx4442moaEhfmttbY0/39vba6ZNm2ZqamrMli1bzLPPPmuKi4vN8uXLnWjSSbvrrrvM2WefndCu/fv3x5+/6aabTGVlpVmzZo3ZtGmT+eIXv2i+9KUvxZ9P13Y3NzcntPnFF180kswrr7xijMmc4/3ss8+an/zkJ+aJJ54wksyTTz6Z8PyKFStMYWGheeqpp8w777xjrrjiCjNp0iRz+PDh+D4LFiwwM2fONBs2bDCvvfaamTx5srnmmmviz7e2tprS0lKzePFis337dvPHP/7R5OTkmFWrVqWqmQM6UdtbWlpMTU2Neeyxx8yHH35o1q9fb2bPnm1mzZqV8B4TJ04099xzT8LvwdH/LozEtg92zK+77jqzYMGChDYdOnQoYZ90POaDtfvo9jY0NJgHH3zQeDwes2vXrvg+6Xi8jTEmI4LF7NmzzZIlS+KP+/r6THl5uamtrXWwKus0NzcbSebVV1+Nb7vooovMrbfeetzXPPvss8br9ZrGxsb4tpUrV5qCggITCoXsLHdY7rrrLjNz5swBn2tpaTF+v988/vjj8W0ffPCBkWTWr19vjEnfdn/erbfeak477TQTiUSMMZl5vD//j20kEjFlZWXm3nvvjW9raWkxwWDQ/PGPfzTGGPP+++8bSeatt96K7/Pcc88Zj8djPv30U2OMMf/xH/9hRo8endDuZcuWmalTp9rcopM30BfN57355ptGktmzZ09828SJE80vfvGL475mpLf9eMFi0aJFx31NJhzzkzneixYtMpdccknCtnQ93ml/KqSnp0ebN29WTU1NfJvX61VNTY3Wr1/vYGXWaW1tlSSNGTMmYfujjz6q4uJiTZs2TcuXL1dXV1f8ufXr12v69OkqLS2Nb5s/f77a2tr03nvvpabwIdqxY4fKy8t16qmnavHixdq7d68kafPmzQqHwwnH+owzzlBVVVX8WKdzu2N6enr0yCOP6O///u8TFurL1OMds3v3bjU2NiYc38LCQs2ZMyfh+BYVFencc8+N71NTUyOv16uN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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "\n", + "xs = np.asarray([[0, 1, 0, 1, 0],\n", + " [0, 0, 1, 1, 0],\n", + " [1, 1, 0, 1, 0],\n", + " [1, 1, 1, 0, 1],\n", + " [0, 0, 0, 1, 0]])\n", + "\n", + "# ws = np.asarray([1, 0, 1, 0, -1]) # hidden!\n", + "\n", + "ys = np.asarray([[0],\n", + " [1],\n", + " [1],\n", + " [1],\n", + " [0]])\n", + "\n", + "ins = 5\n", + "outs = 1\n", + "\n", + "def weights(ins, outs):\n", + " ws = np.random.randn(ins, outs)\n", + " return ws\n", + "\n", + "ws = weights(ins, outs)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " yh = xs @ ws\n", + " e = yh - ys\n", + " e = np.sum(np.abs(e))\n", + " if e < 0.05:\n", + " print(\"found solution\")\n", + " print(ws)\n", + " break\n", + " else:\n", + " # mutation = weights(ins, outs) * 0.1\n", + " mutation = weights(ins, outs) * 0.03\n", + " cw = ws + mutation\n", + "\n", + " yh = xs @ cw\n", + " ce = yh - ys\n", + " ce = np.sum(np.abs(ce))\n", + "\n", + " if ce < e:\n", + " ws = cw\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That looks better, but it still doesn't find a solution. \n", + "\n", + "**Exercise**\n", + "Reduce the scaling factor on the mutation from 0.1 to 0.03 and re-run it. It should find a solution now! So we can add a break after our print statements. \n", + "\n", + "Verify that the identified weights are close to our commented out hidden weights!\n", + "\n", + "Change ys to 0, 0, 0, 3, 3 and re-run. No solution found, right? Even if we increase our number of tries? Might take a long time. \n", + "\n", + "## Non-liner stuff\n", + "\n", + "For these output values, we need to add a bias term because our data is not centered on zero. These are additional ones added on the end of the inputs and are necessare to model the shifts in the data. " + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "found solution\n", + "[[ 3.79725462e-03]\n", + " [-2.97033251e+00]\n", + " [-2.96683902e+00]\n", + " [-5.54670775e-01]\n", + " [ 5.41157497e+00]\n", + " [ 3.52382778e+00]]\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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yWbVqlVm2bJl5sc//rHp0qWLqa6uDl9zww03mKKiIjNjxgyzaNEic9ppp5nTTz89fL6xsdH069fPjBo1yixdutR88MEHJjc319x3333hazZs2GBSU1PNnXfeaVavXm2effZZ43K5zEcffRTX9rZkwYIFplu3buaUU04xt912W/i4XdteVlZmunbtaq666iozf/58s2HDBvPxxx+bb775JnzN448/brKyssy//vUvs3z5cnPhhRea7t27m7q6uvA15557rhkwYICZN2+e+eKLL0zPnj3N5ZdfHj5fUVFh8vPzzdixY82qVavM1KlTTUpKinnhhRfi2t7vevTRR01OTo557733zMaNG82bb75p0tPTzTPPPBO+xi7t/+CDD8z9999v3nrrLSPJvP322xHn49XOOXPmGJfLZZ588kmzevVq89vf/tYkJSWZlStXWtL28vJyM2rUKPP666+bNWvWmLlz55phw4aZwYMHR7xGW2374dq/v7feessMGDDAFBYWmj/96U8R59pS+20RLIYNG2bGjRsX/j4QCJjCwkIzYcIEC6s6NqWlpUaS+fzzz40xoX98SUlJ5s033wxf8/XXXxtJZu7cucaY0F9ep9NpSkpKwtdMmjTJZGZmGp/PZ4wx5u677zZ9+/aNeK/LLrvMjB49OtZNOqyqqirTq1cvM336dPP9738/HCzs3PZ77rnHnHHGGS2eDwaDpqCgwPzxj38MHysvLzder9dMnTrVGGPM6tWrjSSzcOHC8DUffvihcTgcZtu2bcYYY/73f//XtGvXLvyzaH7v3r17R7tJrTJmzBhzzTXXRBz76U9/asaOHWuMsW/7v/vhEs92/vznPzdjxoyJqGf48OHm+uuvj2obW3KoD9ZmCxYsMJLM5s2bjTH2absxLbd/69atplOnTmbVqlWma9euEcGirbW/zd8KaWho0OLFizVq1KjwMafTqVGjRmnu3LkWVnZsKioqJEnt27eXJC1evFh+vz+inX369FGXLl3C7Zw7d6769++v/Pz88DWjR49WZWWlvvrqq/A1+79G8zXHw89q3LhxGjNmzAH12bnt7777roYMGaJLL71UeXl5GjhwoF566aXw+Y0bN6qkpCSi7qysLA0fPjyi7dnZ2RoyZEj4mlGjRsnpdGr+/Pnha84880x5PJ7wNaNHj9batWu1d+/eWDezRaeffrpmzJihdevWSZKWL1+u2bNn67zzzpNk//Y3i2c7j8d/B99VUVEhh8Oh7OxsSfZvezAY1BVXXKHx48erb9++B5xva+1v88Fi9+7dCgQCER8okpSfn6+SkhKLqjo2wWBQt99+u0aOHKl+/fpJkkpKSuTxeML/0Jrt386SkpKD/hyazx3qmsrKStXV1cWiOUdk2rRpWrJkiSZMmHDAOTu3fcOGDZo0aZJ69eqljz/+WDfeeKNuvfVWTZkyRdK+2g/197ukpER5eXkR591ut9q3b9+qn48V7r33Xv3iF79Qnz59lJSUpIEDB+r222/X2LFjI2qza/ubxbOdLV1zPPwcpNB4qnvuuUeXX355eJMtu7f9iSeekNvt1q233nrQ822t/XHf3RSHN27cOK1atUqzZ8+2upS4KC4u1m233abp06crOTnZ6nLiKhgMasiQIXrsscckSQMHDtSqVav0l7/8RVdeeaXF1cXeG2+8oVdffVWvvfaa+vbtq2XLlun2229XYWFhQrQfkfx+v37+85/LGKNJkyZZXU5cLF68WM8884yWLFkih8NhdTlR0eZ7LHJzc+VyuQ6YIbBz504VFBRYVNXRu/nmm/Xee+9p5syZEdvLFxQUqKGhQeXl5RHX79/OgoKCg/4cms8d6prMzEylpKREuzlHZPHixSotLdWgQYPkdrvldrv1+eef689//rPcbrfy8/Nt2/aOHTvq5JNPjjh20kknacuWLZL21X6ov98FBQUqLS2NON/Y2KiysrJW/XysMH78+HCvRf/+/XXFFVfojjvuCPdc2b39zeLZzpausfrn0BwqNm/erOnTp0dsCW7ntn/xxRcqLS1Vly5dwr//Nm/erLvuukvdunWT1Pba3+aDhcfj0eDBgzVjxozwsWAwqBkzZmjEiBEWVtY6xhjdfPPNevvtt/Xpp5+qe/fuEecHDx6spKSkiHauXbtWW7ZsCbdzxIgRWrlyZcRfwOZ/oM0fXiNGjIh4jeZrrPxZnX322Vq5cqWWLVsW/hoyZIjGjh0bfmzXto8cOfKAacXr1q1T165dJUndu3dXQUFBRN2VlZWaP39+RNvLy8u1ePHi8DWffvqpgsGghg8fHr5m1qxZ8vv94WumT5+u3r17q127djFr3+HU1tbK6Yz8NeRyuRQMBiXZv/3N4tnO4/HfQXOoWL9+vT755BPl5OREnLdz26+44gqtWLEi4vdfYWGhxo8fr48//lhSG2x/VIeCWmTatGnG6/Wav/3tb2b16tXmuuuuM9nZ2REzBI53N954o8nKyjKfffaZ2bFjR/irtrY2fM0NN9xgunTpYj799FOzaNEiM2LECDNixIjw+eYpl+ecc45ZtmyZ+eijj0yHDh0OOuVy/Pjx5uuvvzbPP/+85VMuD2b/WSHG2LftCxYsMG632zz66KNm/fr15tVXXzWpqanmlVdeCV/z+OOPm+zsbPPOO++YFStWmIsuuuig0xAHDhxo5s+fb2bPnm169eoVMRWtvLzc5OfnmyuuuMKsWrXKTJs2zaSmplo+3fTKK680nTp1Ck83feutt0xubq65++67w9fYpf1VVVVm6dKlZunSpUaSefrpp83SpUvDMx/i1c45c+YYt9ttnnrqKfP111+bhx56KOZTLg/V9oaGBnPhhReazp07m2XLlkX8/tt/hkNbbfvh2n8w350VYkzbar8tgoUxxjz77LOmS5cuxuPxmGHDhpl58+ZZXVKrSDro1+TJk8PX1NXVmZtuusm0a9fOpKammp/85Cdmx44dEa+zadMmc95555mUlBSTm5tr7rrrLuP3+yOumTlzpjn11FONx+MxPXr0iHiP48V3g4Wd2/7vf//b9OvXz3i9XtOnTx/z4osvRpwPBoPmgQceMPn5+cbr9Zqzzz7brF27NuKaPXv2mMsvv9ykp6ebzMxMc/XVV5uqqqqIa5YvX27OOOMM4/V6TadOnczjjz8e87YdTmVlpbnttttMly5dTHJysunRo4e5//77Iz5Q7NL+mTNnHvTf+JVXXmmMiW8733jjDXPiiScaj8dj+vbta95///2YtduYQ7d948aNLf7+mzlzZptvuzGH/7P/roMFi7bUfrZNBwAAUdPmx1gAAIDjB8ECAABEDcECAABEDcECAABEDcECAABEDcECAABEDcECAABEDcECAABEDcECAABEDcECAABEDcECAABEDcECAABEzf8HcnzHRSCLWyIAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "\n", + "xs = np.asarray([[0, 1, 0, 1, 0],\n", + " [0, 0, 1, 1, 0],\n", + " [1, 1, 0, 1, 0],\n", + " [1, 1, 1, 0, 1],\n", + " [0, 0, 0, 1, 0]])\n", + "\n", + "# ws = np.asarray([1, 0, 1, 0, -1]) # hidden!\n", + "\n", + "ys = np.asarray([[0],\n", + " [0],\n", + " [0],\n", + " [3],\n", + " [3]])\n", + "\n", + "xs = np.hstack((xs, np.ones([xs.shape[0], 1])))\n", + "\n", + "ins = 5\n", + "outs = 1\n", + "\n", + "def weights(ins, outs):\n", + " ws = np.random.randn(ins, outs)\n", + " return ws\n", + "\n", + "ws = weights(ins+1, outs)\n", + "\n", + "ers = []\n", + "for i in range(15000):\n", + " yh = xs @ ws\n", + " e = yh - ys\n", + " e = np.sum(np.abs(e))\n", + " if e < 0.05:\n", + " print(\"found solution\")\n", + " print(ws)\n", + " break\n", + " else:\n", + " # mutation = weights(ins, outs) * 0.1\n", + " mutation = weights(ins+1, outs) * 0.03\n", + " cw = ws + mutation\n", + "\n", + " yh = xs @ cw\n", + " ce = yh - ys\n", + " ce = np.sum(np.abs(ce))\n", + "\n", + " if ce < e:\n", + " ws = cw\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We're still not narrowing in on a solution. Our simple network can only find linear solutions, but if our problem is non-linear, we can't find a solutin because we cannot fit a line to a curve, no matter what slope we give it. \n", + "\n", + "To solve this, we add two things:\n", + "* Another layer of weights connected to some middle nodes\n", + "* Apply an non-linear activation function to the middle neurons. Sigmoid, tanh, ReLU, Leaky ReLU, Maxout, ELU, \n", + "\n", + "We'll use a sin wave. We know from forie transform that we can approximate any signal by adding together sin waves. " + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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Fh9raGgwW7ZsMVu2bDGSzP3332+2bNli9u3bZ4yJLTctLCw0f/jDH8y2bdvMlVde2eNy03PPPde8/vrr5tVXXzWTJk3qtty0vr7elJeXm2984xtmx44dZsWKFSY7O9tVy02/+93vmoKCArN27dpuy8aam5sTba6//nozduxY8+KLL5o333zTzJs3z8ybNy/xeteysUsvvdRs3brVrFq1ypSWlva4bOzWW2817777rnn44YddtTzvtttuM+vWrTN79+4127ZtM7fddpvxeDzmL3/5izGGPrbSyatCjKGvU+UHP/iBWbt2rdm7d6957bXXTFVVlSkpKTF1dXXGmKHfz44IFsYY89BDD5mxY8eaQCBgLrjgArNhwwa7SxqyXnrpJSPptMe1115rjIktOb399ttNeXm5CQaD5pJLLjE7d+7s9jOOHTtmvva1r5nc3FyTn59vFi9ebBoaGrq1eeutt8ynP/1pEwwGzejRo829996brq84JPTUx5LM448/nmjT0tJivve975mioiKTnZ1tvvzlL5tDhw51+zkffvihueyyy0xWVpYpKSkxP/jBD0x7e3u3Ni+99JKZNWuWCQQC5owzzuj2GU73zW9+04wbN84EAgFTWlpqLrnkkkSoMIY+ttKpwYK+To2rr77ajBo1ygQCATN69Ghz9dVXm927dydeH+r9zLHpAAAgZYb9HAsAADB0ECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDKECwAAEDK/H+Z24z3yzNRHQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "\n", + "xs = np.asarray([[0, 1, 0, 1, 0],\n", + " [0, 0, 1, 1, 0],\n", + " [1, 1, 0, 1, 0],\n", + " [1, 1, 1, 0, 1],\n", + " [0, 0, 0, 1, 0]])\n", + "\n", + "# ws = np.asarray([1, 0, 1, 0, -1]) # hidden!\n", + "\n", + "ys = np.asarray([[0],\n", + " [0],\n", + " [0],\n", + " [3],\n", + " [3]])\n", + "\n", + "xs = np.hstack((xs, np.ones([xs.shape[0], 1])))\n", + "\n", + "ins = 5\n", + "outs = 1\n", + "nodes = 15\n", + "\n", + "def weights(ins, outs):\n", + " ws = np.random.randn(ins, outs)\n", + " return ws\n", + "\n", + "wi = weights(ins+1, nodes)\n", + "ws = weights(nodes, outs)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " x = xs @ wi\n", + " x = np.sin(x)\n", + " yh = x @ ws\n", + " e = yh - ys\n", + " e = np.sum(np.abs(e))\n", + " if e < 0.05:\n", + " print(\"found solution\")\n", + " print(ws)\n", + " break\n", + " else:\n", + " # mutation = weights(ins, outs) * 0.1\n", + " mutation = weights(nodes, outs) * 0.03\n", + " cw = ws + mutation\n", + "\n", + " x = xs @ wi\n", + " x = np.sin(x)\n", + " yh = x @ cw\n", + " ce = yh - ys\n", + " ce = np.sum(np.abs(ce))\n", + "\n", + " if ce < e:\n", + " ws = cw\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Yay, we found a solution. \n", + "\n", + "**Exercise**:\n", + "Reduce the number of intermediary nodes to 5. What happens? \n", + "\n", + "Five is not enough if we want to find a solutino in 5k attempts, but if we use a better search algorithm. \n", + "\n", + "E.g. we can do a bredth first search where we make multiple children and then explore multiple childrens family lines at a time in parallel. \n", + "\n", + "This sacrifices many children. There is another way - we can check explore the optoin which has the steepest slope toward our goal. We take the derivative " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "found solution\n", + "[[ 1.84319933]\n", + " [ 0.36640227]\n", + " [-0.45447801]\n", + " [ 0.1995179 ]\n", + " [ 0.20053693]\n", + " [-1.12094583]\n", + " [ 0.56073044]\n", + " [ 0.73116379]\n", + " [-1.00306465]\n", + " [ 1.20739363]\n", + " [ 1.63687894]\n", + " [-0.39957122]\n", + " [ 1.22854594]\n", + " [ 0.36304141]\n", + " [-1.53689375]]\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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AADAUoQRAABgKcIIAACwVMaEkccee0yjRo1Sdna2Zs6cqQ8++MDqkhJq8eLFmjFjhgoKClReXq5rrrlGW7du7XFOd3e35s+fr9LSUuXn5+vb3/62GhsbLao4OR544AEZhqEFCxbE9mVSO+zfv1/f+973VFpaqpycHE2ePFkbNmyIHTdNU/fcc4+GDRumnJwczZkzR9u3b7ew4vgLBoNatGiRamtrlZOTozFjxujee+/tcT+NdG2Hd999V1deeaWqqqpkGIZeeeWVHsfP5Hu3tLRo7ty5KiwsVHFxsf7+7/9e7e3tSfwWA3eqdvD7/brrrrs0efJk5eXlqaqqSt///vd14MCBHu+R7u1wvB/96EcyDENLlizpsT9e7ZARYeTFF1/U7bffrp///OfatGmTpkyZoksvvVRNTU1Wl5Ywq1at0vz587V27VotX75cfr9fX//619XR0RE757bbbtOf//xnvfTSS1q1apUOHDiga6+91sKqE2v9+vX63e9+p3PPPbfH/kxphyNHjmj27NnKysrSG2+8oc2bN+vXv/61SkpKYuc89NBDWrp0qZ544gmtW7dOeXl5uvTSS9Xd3W1h5fH14IMP6vHHH9ejjz6qL774Qg8++KAeeughPfLII7Fz0rUdOjo6NGXKFD322GO9Hj+T7z137lx9/vnnWr58uV577TW9++67uummm5L1FeLiVO3Q2dmpTZs2adGiRdq0aZNefvllbd26VVdddVWP89K9HY61bNkyrV27VlVVVScci1s7mBngggsuMOfPnx97HQwGzaqqKnPx4sUWVpVcTU1NpiRz1apVpmmaZmtrq5mVlWW+9NJLsXO++OILU5K5Zs0aq8pMmLa2NnPs2LHm8uXLza9+9avmrbfeappmZrXDXXfdZV500UUnPR4KhczKykrzV7/6VWxfa2ur6XK5zOeffz4ZJSbFFVdcYf7gBz/ose/aa681586da5pm5rSDJHPZsmWx12fyvTdv3mxKMtevXx8754033jANwzD379+ftNrj6fh26M0HH3xgSjL37NljmmZmtcO+ffvM4cOHm5999pk5cuRI8ze/+U3sWDzbIe17Rnw+nzZu3Kg5c+bE9tlsNs2ZM0dr1qyxsLLkcrvdkqQhQ4ZIkjZu3Ci/39+jXSZMmKCampq0bJf58+friiuu6PF9pcxqh1dffVXTp0/Xd77z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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "\n", + "xs = np.asarray([[0, 1, 0, 1, 0],\n", + " [0, 0, 1, 1, 0],\n", + " [1, 1, 0, 1, 0],\n", + " [1, 1, 1, 0, 1],\n", + " [0, 0, 0, 1, 0]])\n", + "\n", + "# ws = np.asarray([1, 0, 1, 0, -1]) # hidden!\n", + "\n", + "ys = np.asarray([[0],\n", + " [0],\n", + " [0],\n", + " [3],\n", + " [3]])\n", + "\n", + "xs = np.hstack((xs, np.ones([xs.shape[0], 1])))\n", + "\n", + "ins = 5\n", + "outs = 1\n", + "nodes = 15\n", + "\n", + "def weights(ins, outs):\n", + " ws = np.random.randn(ins, outs)\n", + " return ws\n", + "\n", + "wi = weights(ins+1, nodes)\n", + "ws = weights(nodes, outs)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " x = xs @ wi\n", + " x = np.sin(x)\n", + " yh = x @ ws\n", + " e = (yh - ys) * 1\n", + " ws -= (x.T @ e) * 0.03\n", + " e = np.sum(np.abs(e))\n", + " if e < 0.05:\n", + " print(\"found solution\")\n", + " print(ws)\n", + " break\n", + "\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wow we found a solution in just a couple hundred iterations. \n", + "\n", + "**Exercise**:\n", + "* Remove the break and see how close we get to the actual solution.\n", + "* Try using 5 nodes. Do we find a solution? \n", + "* How about 2 nodes?\n", + "\n", + "Two nodes doesn't work because we can get stuck on a local maximum. We need additoinal dimensionality from more nodes. \n", + "\n", + "So far we've only fine-tuned the outer layer of nodes. If we tune the inner layer, we might capture hierarchical structures and be able to model with fewer parameters. \n", + "\n", + "Example, we need 15 parameters to model 5 trippel leters, but with middle layers to model repeated patters across the tripples, we can use fewer parameters. \n", + "\n", + "We need to train the middle layers with back propagation!" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "\n", + "# Problem 0\n", + "# xs = np.asarray([[0, 1, 0, 1, 0],\n", + "# [0, 0, 1, 1, 0],\n", + "# [1, 1, 0, 1, 0],\n", + "# [1, 1, 1, 0, 1],\n", + "# [0, 0, 0, 1, 0]])\n", + "\n", + "# ys = np.asarray([[0],\n", + "# [0],\n", + "# [0],\n", + "# [3],\n", + "# [3]])\n", + "\n", + "# Problem 1\n", + "# xs = np.asarray([[1, 0], [0, 1], [1, 1], [0, 0]])\n", + "# ys = np.asarray([[1], [1], [0], [0]])\n", + "\n", + "# Problem 2\n", + "xs = np.asarray([[-10], [-8], [-6], [-4], [-2], [0], [2], [4], [6], [8], [10]])\n", + "# ys = 0.5 * xs + 7\n", + "ys = xs ** 2\n", + "\n", + "xs = np.hstack((xs, np.ones([xs.shape[0], 1])))\n", + "\n", + "ins = 1 # 2 # 5\n", + "outs = 1\n", + "nodes = 100 # 20 # 2\n", + "lr = 0.0000005 # 0.03\n", + "\n", + "def weights(ins, outs):\n", + " ws = np.random.randn(ins, outs)\n", + " return ws\n", + "\n", + "w0 = weights(ins+1, nodes)\n", + "w1 = weights(nodes, nodes)\n", + "w2 = weights(nodes, outs)\n", + "\n", + "ers = []\n", + "for i in range(35000):\n", + " x0 = xs\n", + "\n", + " z0 = (x0 @ w0); x1 = np.sin(z0)\n", + " z1 = (x1 @ w1); x2 = np.sin(z1)\n", + " yh = (x2 @ w2)\n", + "\n", + " e = (yh - ys)\n", + "\n", + " e2 = (e) * 1\n", + " e1 = (e @ w2.T) * np.cos(z1)\n", + " e0 = (e1 @ w1.T) * np.cos(z0)\n", + "\n", + " w2 -= (x2.T @ e) * lr\n", + " w1 -= (x1.T @ e1) * lr\n", + " w0 -= (x0.T @ e0) * lr\n", + "\n", + " e = np.sum(np.abs(e))\n", + "\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)\n", + "\n", + "plt.figure(2)\n", + "plt.plot(ys, label='ys')\n", + "plt.plot(yh, label='yh')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Yadda yadda, lots of work to approximate a simple function. Like using a tank to kill a fly. Anyway, we're going to do stuff with more layers and need to install pytorch.\n", + "\n", + "https://pytorch.org/get-started/locally/" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 246631.640625\n", + "loss: 69992.8046875\n", + "loss: 31578.111328125\n", + "loss: 13223.3251953125\n", + "loss: 5160.99169921875\n", + "loss: 2281.835693359375\n", + "loss: 782.9633178710938\n", + "loss: 201.0695343017578\n", + "loss: 47.200313568115234\n", + "loss: 4.3181257247924805\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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RETE6+kMj4iIiHg9FR4RERHxeio8IiIi4vVUeERERMTrqfBUs1dffZUWLVoQEBBASkoKK1eutDqSV5kyZQrJycmEhoYSGRlJ//792bp1q9WxvN7UqVMxDINRo0ZZHcXrHDhwgEGDBhEREUFgYCAJCQmsXr3a6lhexel08uijjxIXF0dgYCCtWrVi8uTJF/R9TPLzvv76a2644QZiYmIwDIP58+dXWm+aJo899hiNGzcmMDCQPn36sH379hrJpsJTjebOnUt6ejqPP/44a9eupXPnzqSlpXH48GGro3mNr776iuHDh7N8+XIyMjIoLy+nb9++FBUVWR3Na61atYq//e1vdOrUyeooXufEiRNceuml+Pv78+mnn7J582ZmzJhB/fr1rY7mVZ599llee+01XnnlFbZs2cKzzz7LtGnTePnll62OVusVFRXRuXNnXn311fOunzZtGi+99BIzZ85kxYoVBAcHk5aWRklJSfWHM6XadO/e3Rw+fLh73ul0mjExMeaUKVMsTOXdDh8+bALmV199ZXUUr1RYWGi2adPGzMjIMC+//HJz5MiRVkfyKuPGjTN79epldQyv169fP/Puu++utOzmm28277jjDosSeSfA/OCDD9zzLpfLjI6ONqdPn+5edvLkSdNut5tvv/12tefRGZ5qUlZWxpo1a+jTp497mY+PD3369CEzM9PCZN6toKAAgAYNGlicxDsNHz6cfv36Vfr3WqrOhx9+SFJSErfeeiuRkZF06dKFv//971bH8jo9e/ZkyZIlbNu2DYD169fz7bffcu2111qczLvt3r2bvLy8Sn9/hIeHk5KSUiPHRX15aDU5evQoTqeTqKioSsujoqLIycmxKJV3c7lcjBo1iksvvZSOHTtaHcfrvPPOO6xdu5ZVq1ZZHcVr7dq1i9dee4309HQefvhhVq1axUMPPYTNZmPIkCFWx/Ma48ePx+Fw0K5dO3x9fXE6nTz99NPccccdVkfzanl5eQDnPS7+sK46qfCI1xg+fDjZ2dl8++23VkfxOvv27WPkyJFkZGQQEBBgdRyv5XK5SEpK4plnngGgS5cuZGdnM3PmTBWeKvTuu+/y1ltvMWfOHDp06EBWVhajRo0iJiZG77MX0yWtatKwYUN8fX3Jz8+vtDw/P5/o6GiLUnmvESNGsHDhQpYuXUrTpk2tjuN11qxZw+HDh+natSt+fn74+fnx1Vdf8dJLL+Hn54fT6bQ6oldo3Lgx8fHxlZa1b9+e3NxcixJ5p7FjxzJ+/HgGDBhAQkICgwcPZvTo0UyZMsXqaF7th2OfVcdFFZ5qYrPZ6NatG0uWLHEvc7lcLFmyhNTUVAuTeRfTNBkxYgQffPABX3zxBXFxcVZH8kpXX301GzduJCsryz0lJSVxxx13kJWVha+vr9URvcKll156zmMVtm3bRvPmzS1K5J2Ki4vx8al8+PP19cXlclmUqG6Ii4sjOjq60nHR4XCwYsWKGjku6pJWNUpPT2fIkCEkJSXRvXt3XnjhBYqKirjrrrusjuY1hg8fzpw5c1iwYAGhoaHu68Dh4eEEBgZanM57hIaGnnNfVHBwMBEREbpfqgqNHj2anj178swzz/CHP/yBlStXMmvWLGbNmmV1NK9yww038PTTT9OsWTM6dOjAunXreO6557j77rutjlbrnTp1ih07drjnd+/eTVZWFg0aNKBZs2aMGjWKp556ijZt2hAXF8ejjz5KTEwM/fv3r/5w1f45sDru5ZdfNps1a2babDaze/fu5vLly62O5FWA806zZ8+2OprX08fSq8dHH31kduzY0bTb7Wa7du3MWbNmWR3J6zgcDnPkyJFms2bNzICAALNly5bmI488YpaWllodrdZbunTpef9OHjJkiGmaZz6a/uijj5pRUVGm3W43r776anPr1q01ks0wTT1aUkRERLyb7uERERERr6fCIyIiIl5PhUdERES8ngqPiIiIeD0VHhEREfF6KjwiIiLi9VR4RERExOup8IiIiIjXU+ERERERr6fCIyIiIl5PhUdERES8ngqPiIiIeL3/D7Y7HRsIyeA8AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "import torch\n", + "from torch.nn import functional as F\n", + "\n", + "# Problem 0\n", + "# xs = np.asarray([[0, 1, 0, 1, 0],\n", + "# [0, 0, 1, 1, 0],\n", + "# [1, 1, 0, 1, 0],\n", + "# [1, 1, 1, 0, 1],\n", + "# [0, 0, 0, 1, 0]])\n", + "\n", + "# ys = np.asarray([[0],\n", + "# [0],\n", + "# [0],\n", + "# [3],\n", + "# [3]])\n", + "\n", + "# Problem 1\n", + "# xs = np.asarray([[1, 0], [0, 1], [1, 1], [0, 0]])\n", + "# ys = np.asarray([[1], [1], [0], [0]])\n", + "\n", + "# Problem 2\n", + "xs = np.asarray([[-10], [-8], [-6], [-4], [-2], [0], [2], [4], [6], [8], [10]])\n", + "# ys = 0.5 * xs + 7\n", + "# ys = xs ** 2\n", + "ys = xs ** 3 - xs**2 + xs - 3\n", + "\n", + "xs = np.hstack((xs, np.ones([xs.shape[0], 1])))\n", + "\n", + "xs = torch.tensor(xs).float()\n", + "ys = torch.tensor(ys).float()\n", + "\n", + "ins = 1\n", + "outs = 1\n", + "nodes = 200\n", + "lr = 0.003\n", + "\n", + "def weights(ins, outs):\n", + " ws = torch.randn(ins, outs)\n", + " ws = ws.requires_grad_(True)\n", + " return ws\n", + "\n", + "w0 = weights(ins+1, nodes)\n", + "w1 = weights(nodes, nodes)\n", + "w2 = weights(nodes, outs)\n", + "\n", + "optimizer = torch.optim.Adam([w0, w1, w2], lr)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " x0 = xs\n", + "\n", + " z0 = (x0 @ w0); x1 = torch.sin(z0)\n", + " z1 = (x1 @ w1); x2 = torch.sin(z1)\n", + " yh = (x2 @ w2)\n", + "\n", + " loss = F.mse_loss(yh, ys)\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " e = loss.item()\n", + "\n", + " if i % 500 == 0:\n", + " print('loss:', e)\n", + "\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)\n", + "\n", + "plt.figure(2)\n", + "plt.plot(ys, label='ys')\n", + "plt.plot(yh.detach(), label='yh')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 2859.491943359375\n", + "loss: 0.0003213828313164413\n", + "loss: 1.1633167559921276e-05\n", + "loss: 0.0007853857823647559\n", + "loss: 0.10190165787935257\n", + "loss: 8.44282767502591e-05\n", + "loss: 0.00013280313578434289\n", + "loss: 1.0274457054038066e-05\n", + "loss: 3.554864917987288e-07\n", + "loss: 1.3268711427372182e-06\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjAAAAGiCAYAAAD5t/y6AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAxhElEQVR4nO3de3RUVZ728acqoYpwqYRbUkQCQqNc5KKihhqV1iZNwHgb8X1FaWFa1Bcn+DbGQWTGQdReHQdbba84vRyNvUa80K/YCgrEIMFLAEkTuahp0TjBhkpoMSlAyPW8f9h1oBSFc1LJTsj3s1atldTZObXPFsnDPr99tseyLEsAAAAdiNd0BwAAAJwiwAAAgA6HAAMAADocAgwAAOhwCDAAAKDDIcAAAIAOhwADAAA6HAIMAADocAgwAACgwyHAAACADsdRgFmyZInGjBmjQCCgQCCgUCikN9980z5++PBh5ebmqk+fPurRo4emTp2qqqqqmHNUVlYqJydH3bp1U2pqqubNm6fGxsaYNuvWrdPZZ58tv9+voUOHqqCgwP0VAgCAk46jADNgwADdf//9Ki0t1ebNm/Wzn/1MV1xxhXbs2CFJuu222/T6669r2bJlKi4u1u7du3XVVVfZP9/U1KScnBzV19fr/fff13PPPaeCggItXLjQblNRUaGcnBxdfPHFKisr09y5c3XjjTdq9erVcbpkAADQ0Xlauplj79699cADD+jqq69Wv379tHTpUl199dWSpE8++UQjRoxQSUmJxo8frzfffFOXXnqpdu/erbS0NEnSU089pfnz52vv3r3y+XyaP3++Vq5cqe3bt9ufMW3aNNXU1GjVqlUt6SoAADhJJLr9waamJi1btkwHDx5UKBRSaWmpGhoalJWVZbcZPny4Bg4caAeYkpISjR492g4vkpSdna1bbrlFO3bs0FlnnaWSkpKYc0TbzJ0790f7U1dXp7q6Ovv75uZm7du3T3369JHH43F7mQAAoA1ZlqX9+/crPT1dXu8P3yhyHGC2bdumUCikw4cPq0ePHlq+fLlGjhypsrIy+Xw+paSkxLRPS0tTOByWJIXD4ZjwEj0ePfZjbSKRiA4dOqSkpKRj9is/P1/33HOP08sBAADt0K5duzRgwIAfPO44wAwbNkxlZWWqra3VH//4R82cOVPFxcUt6mQ8LFiwQHl5efb3tbW1GjhwoHbt2qVAIGCwZwAA4ERFIhFlZGSoZ8+eP9rOcYDx+XwaOnSoJGncuHH64IMP9Mgjj+iaa65RfX29ampqYmZhqqqqFAwGJUnBYFCbNm2KOV90ldLRbb67cqmqqkqBQOAHZ18kye/3y+/3f+/96IopAADQcRyv/KPFz4Fpbm5WXV2dxo0bpy5duqioqMg+Vl5ersrKSoVCIUlSKBTStm3bVF1dbbcpLCxUIBDQyJEj7TZHnyPaJnoOAAAARzMwCxYs0JQpUzRw4EDt379fS5cu1bp167R69WolJydr1qxZysvLU+/evRUIBHTrrbcqFApp/PjxkqRJkyZp5MiRuv7667V48WKFw2Hdddddys3NtWdPZs+erccff1x33HGHbrjhBq1du1Yvv/yyVq5cGf+rBwAAHZKjAFNdXa0ZM2Zoz549Sk5O1pgxY7R69Wr9/Oc/lyQ9/PDD8nq9mjp1qurq6pSdna0nn3zS/vmEhAStWLFCt9xyi0KhkLp3766ZM2fq3nvvtdsMHjxYK1eu1G233aZHHnlEAwYM0NNPP63s7Ow4XTIAAOjoWvwcmPYqEokoOTlZtbW11MAAANBBnOjvb/ZCAgAAHQ4BBgAAdDgEGAAA0OEQYAAAQIdDgAEAAB0OAQYAAHQ4BBgAANDhEGAAAECH43gzx87uj6VfavtfazV5VFDjh/Qx3R0AADolZmAcKv7LXhW8/4U+2h0x3RUAADotAoxD0c29m0/OHRgAAOgQCDAOeT3HbwMAAFoXAcYhj+fbBMMMDAAA5hBgHIpOwJBfAAAwhwDjUHQGhvwCAIA5BBiH/p5fuIUEAIBBBBiHokW85BcAAMwhwDjk+XsVjEWCAQDAGAKMQx5mYAAAMI4A4xBFvAAAmEeAcYgiXgAAzCPAOEQRLwAA5hFgHKKIFwAA8wgwDtlFvGa7AQBAp0aAccgbLeIlwQAAYAwBxiWKeAEAMIcA45CXZdQAABhHgHGIZdQAAJhHgHHIE/2C/AIAgDEEGIe8Xm4hAQBgGgHGoegMTHMzEQYAAFMIMA6xFxIAAOYRYByiiBcAAPMIMA6xFxIAAOYRYBzyHFmHBAAADCHAOMQtJAAAzCPAOORhLyQAAIwjwDhkL6MmwQAAYAwBxiH2QgIAwDwCjEMeViEBAGAcAcah6C0kiwQDAIAxBBiH7L2QyC8AABhDgHGJIl4AAMwhwDhEES8AAOYRYByiiBcAAPMIMA5RxAsAgHkEGIe4hQQAgHkEGIfYCwkAAPMcBZj8/Hyde+656tmzp1JTU3XllVeqvLw8ps1FF10kj8cT85o9e3ZMm8rKSuXk5Khbt25KTU3VvHnz1NjYGNNm3bp1Ovvss+X3+zV06FAVFBS4u8I4Yy8kAADMcxRgiouLlZubqw0bNqiwsFANDQ2aNGmSDh48GNPupptu0p49e+zX4sWL7WNNTU3KyclRfX293n//fT333HMqKCjQwoUL7TYVFRXKycnRxRdfrLKyMs2dO1c33nijVq9e3cLLbTm7BsZoLwAA6NwSnTRetWpVzPcFBQVKTU1VaWmpJkyYYL/frVs3BYPBY55jzZo1+uijj/TWW28pLS1NZ555pu677z7Nnz9fixYtks/n01NPPaXBgwfrwQcflCSNGDFC7777rh5++GFlZ2c7vca44hYSAADmtagGpra2VpLUu3fvmPeff/559e3bV6NGjdKCBQv0zTff2MdKSko0evRopaWl2e9lZ2crEolox44ddpusrKyYc2ZnZ6ukpOQH+1JXV6dIJBLzag1eex11q5weAACcAEczMEdrbm7W3Llzdf7552vUqFH2+9ddd50GDRqk9PR0bd26VfPnz1d5ebleeeUVSVI4HI4JL5Ls78Ph8I+2iUQiOnTokJKSkr7Xn/z8fN1zzz1uL+eEMQMDAIB5rgNMbm6utm/frnfffTfm/Ztvvtn+evTo0erfv78mTpyozz77TD/5yU/c9/Q4FixYoLy8PPv7SCSijIyMuH8ORbwAAJjn6hbSnDlztGLFCr399tsaMGDAj7bNzMyUJO3cuVOSFAwGVVVVFdMm+n20buaH2gQCgWPOvkiS3+9XIBCIebWGI0W8JBgAAExxFGAsy9KcOXO0fPlyrV27VoMHDz7uz5SVlUmS+vfvL0kKhULatm2bqqur7TaFhYUKBAIaOXKk3aaoqCjmPIWFhQqFQk662yqiNTDN5BcAAIxxFGByc3P13//931q6dKl69uypcDiscDisQ4cOSZI+++wz3XfffSotLdUXX3yh1157TTNmzNCECRM0ZswYSdKkSZM0cuRIXX/99frwww+1evVq3XXXXcrNzZXf75ckzZ49W59//rnuuOMOffLJJ3ryySf18ssv67bbbovz5TvHXkgAAJjnKMAsWbJEtbW1uuiii9S/f3/79dJLL0mSfD6f3nrrLU2aNEnDhw/X7bffrqlTp+r111+3z5GQkKAVK1YoISFBoVBIv/jFLzRjxgzde++9dpvBgwdr5cqVKiws1NixY/Xggw/q6aefNr6EWmIvJAAA2gNHRbzH+6WdkZGh4uLi455n0KBBeuONN360zUUXXaQtW7Y46V6bYC8kAADMYy8kp+xbSEQYAABMIcA4RBEvAADmEWAcYi8kAADMI8A45OEWEgAAxhFgHPLyJF4AAIwjwDh0ZC9HEgwAAKYQYByK7oXU3Gy4IwAAdGIEGIfYCwkAAPMIMA5FbyGxjBoAAHMIMA55jxTBAAAAQwgwDnELCQAA8wgwDnl4Ei8AAMYRYBziQXYAAJhHgHEoeguJGRgAAMwhwDhkP4nXcD8AAOjMCDAOeewqXiIMAACmEGAc8lLECwCAcQQYp9gLCQAA4wgwDnnZCwkAAOMIMA4deZAdAAAwhQDjEM+BAQDAPAKMQ/YyavILAADGEGAcYi8kAADMI8A4xF5IAACYR4BxiBoYAADMI8A4xCokAADMI8A45PVSxAsAgGkEGIeObIVEggEAwBQCjEMU8QIAYB4BxiEPeyEBAGAcAcahI7eQjHYDAIBOjQDjEE/iBQDAPAKMQzwHBgAA8wgwDnkp4gUAwDgCjEsU8QIAYA4BxqEjt5DM9gMAgM6MAOMQt5AAADCPAONQdAaG3ZAAADCHAOMQMzAAAJhHgHGIvZAAADCPAONQdC8k4gsAAOYQYByK1sA0cw8JAABjCDAO2beQjPYCAIDOjQDjEHshAQBgHgHGIfZCAgDAPAKMQ16KeAEAMI4A41IzMzAAABhDgHGIvZAAADDPUYDJz8/Xueeeq549eyo1NVVXXnmlysvLY9ocPnxYubm56tOnj3r06KGpU6eqqqoqpk1lZaVycnLUrVs3paamat68eWpsbIxps27dOp199tny+/0aOnSoCgoK3F1hnFHECwCAeY4CTHFxsXJzc7VhwwYVFhaqoaFBkyZN0sGDB+02t912m15//XUtW7ZMxcXF2r17t6666ir7eFNTk3JyclRfX6/3339fzz33nAoKCrRw4UK7TUVFhXJycnTxxRerrKxMc+fO1Y033qjVq1fH4ZJbxp6BoQoGAABjPFYLltPs3btXqampKi4u1oQJE1RbW6t+/fpp6dKluvrqqyVJn3zyiUaMGKGSkhKNHz9eb775pi699FLt3r1baWlpkqSnnnpK8+fP1969e+Xz+TR//nytXLlS27dvtz9r2rRpqqmp0apVq47Zl7q6OtXV1dnfRyIRZWRkqLa2VoFAwO0lfk9V5LAyf1OkRK9HO39zSdzOCwAAvv39nZycfNzf3y2qgamtrZUk9e7dW5JUWlqqhoYGZWVl2W2GDx+ugQMHqqSkRJJUUlKi0aNH2+FFkrKzsxWJRLRjxw67zdHniLaJnuNY8vPzlZycbL8yMjJacmk/KPogO4p4AQAwx3WAaW5u1ty5c3X++edr1KhRkqRwOCyfz6eUlJSYtmlpaQqHw3abo8NL9Hj02I+1iUQiOnTo0DH7s2DBAtXW1tqvXbt2ub20H2ffQgIAAKYkuv3B3Nxcbd++Xe+++248++Oa3++X3+9v9c+hiBcAAPNczcDMmTNHK1as0Ntvv60BAwbY7weDQdXX16umpiamfVVVlYLBoN3mu6uSot8fr00gEFBSUpKbLseN56iveRovAABmOAowlmVpzpw5Wr58udauXavBgwfHHB83bpy6dOmioqIi+73y8nJVVlYqFApJkkKhkLZt26bq6mq7TWFhoQKBgEaOHGm3Ofoc0TbRc5gUnYGRmIUBAMAUR7eQcnNztXTpUv3pT39Sz5497ZqV5ORkJSUlKTk5WbNmzVJeXp569+6tQCCgW2+9VaFQSOPHj5ckTZo0SSNHjtT111+vxYsXKxwO66677lJubq59C2j27Nl6/PHHdccdd+iGG27Q2rVr9fLLL2vlypVxvnznjsovarYseWPmZAAAQFtwNAOzZMkS1dbW6qKLLlL//v3t10svvWS3efjhh3XppZdq6tSpmjBhgoLBoF555RX7eEJCglasWKGEhASFQiH94he/0IwZM3TvvffabQYPHqyVK1eqsLBQY8eO1YMPPqinn35a2dnZcbjklvEcFViYgAEAwIwWPQemPTvRdeSOz3u4QWMWrZEklf96svyJCXE7NwAAnV2bPAemM4ot4jXWDQAAOjUCjENHF/ECAAAzCDAOfbeIFwAAtD0CjEMsowYAwDwCTAswAwMAgBkEGIeOvoVEfAEAwAwCjEPcQgIAwDwCjEPshQQAgHkEGIeYgQEAwDwCjEMsowYAwDwCjEMeD3shAQBgGgHGhWiGYQIGAAAzCDAuROdgKOIFAMAMAowL0UJe4gsAAGYQYFyI3kKiiBcAADMIMC54/n4TifwCAIAZBBgX7CJes90AAKDTIsC4YN9CaibCAABgAgHGhaOfxgsAANoeAcaFaHyhiBcAADMIMC5En8ZLfgEAwAwCjAssowYAwCwCjAv2k3iN9gIAgM6LAOOC1xu9hUSEAQDABAKMC0f2QjLaDQAAOi0CjAvshQQAgFkEGBco4gUAwCwCjAssowYAwCwCjAs8yA4AALMIMC54mYEBAMAoAowL3uhu1AQYAACMIMC4EK2B4RYSAABmEGBciK5CIr4AAGAGAcYFllEDAGAWAcYFingBADCLAOPCka0ESDAAAJhAgHGBrQQAADCLAONGtAammQgDAIAJBBgXmIEBAMAsAowLbCUAAIBZBBgXvDwIBgAAowgwLhx5DozZfgAA0FkRYFzw2DUwJBgAAEwgwLjgZQYGAACjCDAusJUAAABmEWBcoIgXAACzCDAusIwaAACzHAeY9evX67LLLlN6ero8Ho9effXVmOP/9E//JI/HE/OaPHlyTJt9+/Zp+vTpCgQCSklJ0axZs3TgwIGYNlu3btWFF16orl27KiMjQ4sXL3Z+da3Ew2aOAAAY5TjAHDx4UGPHjtUTTzzxg20mT56sPXv22K8XXngh5vj06dO1Y8cOFRYWasWKFVq/fr1uvvlm+3gkEtGkSZM0aNAglZaW6oEHHtCiRYv0+9//3ml3WwU1MAAAmJXo9AemTJmiKVOm/Ggbv9+vYDB4zGMff/yxVq1apQ8++EDnnHOOJOmxxx7TJZdcot/+9rdKT0/X888/r/r6ej3zzDPy+Xw644wzVFZWpoceeigm6JjCVgIAAJjVKjUw69atU2pqqoYNG6ZbbrlFX331lX2spKREKSkpdniRpKysLHm9Xm3cuNFuM2HCBPl8PrtNdna2ysvL9fXXXx/zM+vq6hSJRGJerSVaA2MxAwMAgBFxDzCTJ0/WH/7wBxUVFek//uM/VFxcrClTpqipqUmSFA6HlZqaGvMziYmJ6t27t8LhsN0mLS0tpk30+2ib78rPz1dycrL9ysjIiPel2bzUwAAAYJTjW0jHM23aNPvr0aNHa8yYMfrJT36idevWaeLEifH+ONuCBQuUl5dnfx+JRFovxPAgOwAAjGr1ZdRDhgxR3759tXPnTklSMBhUdXV1TJvGxkbt27fPrpsJBoOqqqqKaRP9/odqa/x+vwKBQMyrtXjtx8CQYAAAMKHVA8yXX36pr776Sv3795ckhUIh1dTUqLS01G6zdu1aNTc3KzMz026zfv16NTQ02G0KCws1bNgw9erVq7W7fFyev0/BMAMDAIAZjgPMgQMHVFZWprKyMklSRUWFysrKVFlZqQMHDmjevHnasGGDvvjiCxUVFemKK67Q0KFDlZ2dLUkaMWKEJk+erJtuukmbNm3Se++9pzlz5mjatGlKT0+XJF133XXy+XyaNWuWduzYoZdeekmPPPJIzC0ik7x/HzWKeAEAMMNxgNm8ebPOOussnXXWWZKkvLw8nXXWWVq4cKESEhK0detWXX755Tr99NM1a9YsjRs3Tu+88478fr99jueff17Dhw/XxIkTdckll+iCCy6IecZLcnKy1qxZo4qKCo0bN0633367Fi5c2C6WUEtHZmDILwAAmOG4iPeiiy760ZmH1atXH/ccvXv31tKlS3+0zZgxY/TOO+847V6b4EF2AACYxV5ILrCMGgAAswgwLjADAwCAWQQYF9hKAAAAswgwLrCVAAAAZhFgXPBQAwMAgFEEGBc8bCUAAIBRBBgX2EoAAACzCDAusJUAAABmEWBciG4lQBEMAABmEGBcYAYGAACzCDAuRIt4WUYNAIAZBBgXosuomYEBAMAMAowLR1YhAQAAEwgwLhzZzJEIAwCACQQYF6JbCbCZIwAAZhBgXGArAQAAzCLAuMBWAgAAmEWAcYGtBAAAMIsA40L0QXbcQgIAwAwCjAvRrQRYhQQAgBkEGFd4kB0AACYRYFywa2AIMAAAGEGAceHIKiQSDAAAJhBgXLCfxGu4HwAAdFYEGBeiT+KliBcAADMIMC7wJF4AAMwiwLhADQwAAGYRYFyI1sCwjBoAADMIMC6wlQAAAGYRYFygBgYAALMIMC547AfZkWAAADCBAOOCh60EAAAwigDjAlsJAABgFgHGBZZRAwBgFgHGhegyagAAYAYBxoVofGEGBgAAMwgwLrCMGgAAswgwLlADAwCAWQQYF6I1MMQXAADMIMC4EK2B4UF2AACYQYBxweulBgYAAJMIMC5QAwMAgFkEGBfYSgAAALMIMC6wlQAAAGYRYFxgN2oAAMwiwLjAMmoAAMwiwLQARbwAAJhBgHHBy1YCAAAY5TjArF+/XpdddpnS09Pl8Xj06quvxhy3LEsLFy5U//79lZSUpKysLH366acxbfbt26fp06crEAgoJSVFs2bN0oEDB2LabN26VRdeeKG6du2qjIwMLV682PnVtRKWUQMAYJbjAHPw4EGNHTtWTzzxxDGPL168WI8++qieeuopbdy4Ud27d1d2drYOHz5st5k+fbp27NihwsJCrVixQuvXr9fNN99sH49EIpo0aZIGDRqk0tJSPfDAA1q0aJF+//vfu7jE+KMGBgAAsxKd/sCUKVM0ZcqUYx6zLEu/+93vdNddd+mKK66QJP3hD39QWlqaXn31VU2bNk0ff/yxVq1apQ8++EDnnHOOJOmxxx7TJZdcot/+9rdKT0/X888/r/r6ej3zzDPy+Xw644wzVFZWpoceeigm6JjCKiQAAMyKaw1MRUWFwuGwsrKy7PeSk5OVmZmpkpISSVJJSYlSUlLs8CJJWVlZ8nq92rhxo91mwoQJ8vl8dpvs7GyVl5fr66+/PuZn19XVKRKJxLxai4caGAAAjIprgAmHw5KktLS0mPfT0tLsY+FwWKmpqTHHExMT1bt375g2xzrH0Z/xXfn5+UpOTrZfGRkZLb+gHxDdzJEaGAAAzDhpViEtWLBAtbW19mvXrl2t9lmsQgIAwKy4BphgMChJqqqqinm/qqrKPhYMBlVdXR1zvLGxUfv27Ytpc6xzHP0Z3+X3+xUIBGJereXIKqRW+wgAAPAj4hpgBg8erGAwqKKiIvu9SCSijRs3KhQKSZJCoZBqampUWlpqt1m7dq2am5uVmZlpt1m/fr0aGhrsNoWFhRo2bJh69eoVzy67Et0LiXVIAACY4TjAHDhwQGVlZSorK5P0beFuWVmZKisr5fF4NHfuXP3617/Wa6+9pm3btmnGjBlKT0/XlVdeKUkaMWKEJk+erJtuukmbNm3Se++9pzlz5mjatGlKT0+XJF133XXy+XyaNWuWduzYoZdeekmPPPKI8vLy4nbhLREt4mUGBgAAMxwvo968ebMuvvhi+/toqJg5c6YKCgp0xx136ODBg7r55ptVU1OjCy64QKtWrVLXrl3tn3n++ec1Z84cTZw4UV6vV1OnTtWjjz5qH09OTtaaNWuUm5urcePGqW/fvlq4cGG7WEItUcQLAIBpHuskfZhJJBJRcnKyamtr414P8/9Kv9Ttyz7UT0/vp+duOC+u5wYAoDM70d/fJ80qpLbEVgIAAJhFgHEhuowaAACYQYBxgRkYAADMIsC4wFYCAACYRYBxgVVIAACYRYBxga0EAAAwiwDjQrQGhgADAIAZBBgXolsJWGwlAACAEQQYV9hKAAAAkwgwLtgzMNxDAgDACAKMC2zmCACAWQQYF5iBAQDALAKMC/YyasP9AACgsyLAuMFWAgAAGEWAcYEH2QEAYBYBxoUjWwkY7QYAAJ0WAcaFIzMwJBgAAEwgwLjAVgIAAJhFgHHBw1YCAAAYRYBxwcNWAgAAGEWAcYEH2QEAYBYBxgUPy6gBADCKAOOCPQNjthsAAHRaBBgXPDyJFwAAowgwLnALCQAAswgwLkQfZMcMDAAAZhBgXIhuJUB+AQDADAKMC2wlAACAWQQYF44U8ZrtBwAAnRUBxgW2EgAAwCwCjAtsJQAAgFkEGBe8fx81SmAAADCDAONCdAaGIl4AAMwgwLjAVgIAAJhFgHGBrQQAADCLAOMCWwkAAGAWAcaF6JN4mYEBAMAMAowLXg9FMAAAmESAcYEaGAAAzCLAuHBkN2rDHQEAoJMiwLjAVgIAAJhFgHHBwwwMAABGEWBciD7IjgkYAADMIMC4cGQzRxIMAAAmEGBcYCsBAADMIsC4wTJqAACMIsC44GUrAQAAjCLAuOA56muLFAMAQJuLe4BZtGiRPB5PzGv48OH28cOHDys3N1d9+vRRjx49NHXqVFVVVcWco7KyUjk5OerWrZtSU1M1b948NTY2xrurrtlbCYhZGAAATEhsjZOeccYZeuutt458SOKRj7ntttu0cuVKLVu2TMnJyZozZ46uuuoqvffee5KkpqYm5eTkKBgM6v3339eePXs0Y8YMdenSRb/5zW9ao7uOHZVf1GxZ8sbMyQAAgNbWKgEmMTFRwWDwe+/X1tbqv/7rv7R06VL97Gc/kyQ9++yzGjFihDZs2KDx48drzZo1+uijj/TWW28pLS1NZ555pu677z7Nnz9fixYtks/na40uO+I5egbGYD8AAOisWqUG5tNPP1V6erqGDBmi6dOnq7KyUpJUWlqqhoYGZWVl2W2HDx+ugQMHqqSkRJJUUlKi0aNHKy0tzW6TnZ2tSCSiHTt2/OBn1tXVKRKJxLxay3dnYAAAQNuKe4DJzMxUQUGBVq1apSVLlqiiokIXXnih9u/fr3A4LJ/Pp5SUlJifSUtLUzgcliSFw+GY8BI9Hj32Q/Lz85WcnGy/MjIy4nthR6EGBgAAs+J+C2nKlCn212PGjFFmZqYGDRqkl19+WUlJSfH+ONuCBQuUl5dnfx+JRFotxHiPmoEhwAAA0PZafRl1SkqKTj/9dO3cuVPBYFD19fWqqamJaVNVVWXXzASDwe+tSop+f6y6mii/369AIBDzai2eo4p2uYUEAEDba/UAc+DAAX322Wfq37+/xo0bpy5duqioqMg+Xl5ersrKSoVCIUlSKBTStm3bVF1dbbcpLCxUIBDQyJEjW7u7J+ToGhjiCwAAbS/ut5D+5V/+RZdddpkGDRqk3bt36+6771ZCQoKuvfZaJScna9asWcrLy1Pv3r0VCAR06623KhQKafz48ZKkSZMmaeTIkbr++uu1ePFihcNh3XXXXcrNzZXf7493d12hiBcAALPiHmC+/PJLXXvttfrqq6/Ur18/XXDBBdqwYYP69esnSXr44Yfl9Xo1depU1dXVKTs7W08++aT98wkJCVqxYoVuueUWhUIhde/eXTNnztS9994b7666RhEvAABmeayT9Fn4kUhEycnJqq2tjXs9TGNTs4b+25uSpLKFP1dKN/PPpgEA4GRwor+/2QvJBWZgAAAwiwDjAjUwAACYRYBxga0EAAAwiwDjUjTDMAMDAEDbI8C4ZNfBkF8AAGhzBBiXojeRmgkwAAC0OQKMS9EZGIspGAAA2hwBxi27BsZsNwAA6IwIMC5Fd6RuJsEAANDmCDAu2beQyC8AALQ5AoxL39Q3SZJ+9dIWwz0BAKDzIcC00JbKGtNdAACg0yHAxMFJuh8mAADtFgEmDqK3kwAAQNsgwMQBAQYAgLZFgImDQwQYAADaFAEmDr5paDTdBQAAOhUCTBxwCwkAgLZFgImDb+oIMAAAtCUCjEtXnJluf/1NPbeQAABoSwQYlxZfPUbBQFdJ0qEGZmAAAGhLBBiX/IkJGnVKQBI1MAAAtDUCTAsk+RIlEWAAAGhrBJgW6NYlQZJ0iBoYAADaFAGmBZJ83waY3675iw5TBwMAQJshwLTA0Zs4rvmoymBPAADoXAgwLdC7u9/+esdfaw32BACAzoUA0wL/56dD5Ev8dgg/Ce833BsAADoPAkwLdO2SoBduypQkbf2yxmxnAADoRAgwLXR6Wk9J0tffNGjJus8M9wYAgM6BANNCPbt2UWhIH0nSk+t2av/hBsM9AgDg5EeAiYPnb8zUkL7dtf9wox5bu9N0dwAAOOkRYOLA6/Xo9knDJEm/X/+53t/5N8M9AgDg5EaAiZOcMf31i/EDJUnzX9nKDtUAALQiAkwc3TllhE5JSdKufYf0SNGnprsDAMBJiwATRz38ibr3ijMkSf/1ToU+CUcM9wgAgJMTASbOJo5I0+QzgmpstvSvr2xTc7N1/B8CAACOEGBawd2Xj1R3X4L+XFmjZaW7THcHAICTDgGmFfRPTtLcrNMlSQ8V/kWH6tmpGgCAeCLAtJIZ/zBIp6QkqSpSp+dKvjDdHQAATioEmFbiT0zQbT//dhbmybd3KsITegEAiBsCTCv6x7NO0dDUHoocbtQf3v/CdHcAADhpEGBaUYLXo1t/NlSS9PS7FTpQx8PtAACIBwJMK7t0TLqG9O2umm8a9ByzMAAAxAUBppUleD36vxNPkyQ9VfyZvj5Yb7hHAAB0fASYNnD52HSN6B/Q/sONeuJtdqsGAKClCDBtwOv16M4pwyVJz77/hTZ/sc9wjwAA6NgIMG1kwml9dfnYdDU1W5qzdIs+33vAdJcAAOiw2nWAeeKJJ3Tqqaeqa9euyszM1KZNm0x3yTWPx6PfXDVaP+nXXeHIYV3++Hv6/frPdJCVSQAAONZuA8xLL72kvLw83X333frzn/+ssWPHKjs7W9XV1aa75loPf6JevDmkcwb10oG6Rv3mjU+U+Zsi5b1cpmWbd2nXvm9kWWz+CADA8XisdvobMzMzU+eee64ef/xxSVJzc7MyMjJ066236s477/xe+7q6OtXV1dnfRyIRZWRkqLa2VoFAoM36fSKami39vz9/qafWfabP/3Yw5ljXLl6l9uyqnl0T1d2fqJ7+RPXomqikLgnyeDzyeiSPR/J6PPJ6PIau4IiW/vFp6R++lv7ptVrYg5Z/fgt/vsX/95q7fv7btfTzW/5Xtz8xQV7775NvZ4rbwV8r6ECmnj1Ao05Jjus5I5GIkpOTj/v7OzGunxon9fX1Ki0t1YIFC+z3vF6vsrKyVFJScsyfyc/P1z333NNWXWyRBK9H//ucDP2vcQO0sWKf3vl0r0o++0pbv6zV4YZmVe77xnQXAQA4rrMG9op7gDlR7TLA/O1vf1NTU5PS0tJi3k9LS9Mnn3xyzJ9ZsGCB8vLy7O+jMzDtmcfj0fghfTR+SB9J0uGGJoVrD2vvgTodqGvUwbpGHTjcqAN1jTpU36Rm69t/dVnWtzMflqRmy5JHLf8nUzz+1RWXf7jFoSPx6Ed8xuPk+e/S0n542sk/6/nvekSzJTU0Ncuyvv17JPoCnDgttYexz26XAcYNv98vv99vuhst0rVLgk7t212n9u1uuisAALRr7bKIt2/fvkpISFBVVVXM+1VVVQoGg4Z6BQAA2ot2GWB8Pp/GjRunoqIi+73m5mYVFRUpFAoZ7BkAAGgP2u0tpLy8PM2cOVPnnHOOzjvvPP3ud7/TwYMH9ctf/tJ01wAAgGHtNsBcc8012rt3rxYuXKhwOKwzzzxTq1at+l5hLwAA6Hza7XNgWupE15EDAID240R/f7fLGhgAAIAfQ4ABAAAdDgEGAAB0OAQYAADQ4RBgAABAh0OAAQAAHQ4BBgAAdDgEGAAA0OG02yfxtlT0+XyRSMRwTwAAwImK/t4+3nN2T9oAs3//fklSRkaG4Z4AAACn9u/fr+Tk5B88ftJuJdDc3Kzdu3erZ8+e8ng8cTtvJBJRRkaGdu3axRYFrYyxbhuMc9tgnNsG49w2WnOcLcvS/v37lZ6eLq/3hytdTtoZGK/XqwEDBrTa+QOBAP9ztBHGum0wzm2DcW4bjHPbaK1x/rGZlyiKeAEAQIdDgAEAAB0OAcYhv9+vu+++W36/33RXTnqMddtgnNsG49w2GOe20R7G+aQt4gUAACcvZmAAAECHQ4ABAAAdDgEGAAB0OAQYAADQ4RBgAABAh0OAceiJJ57Qqaeeqq5duyozM1ObNm0y3aV2bf369brsssuUnp4uj8ejV199Nea4ZVlauHCh+vfvr6SkJGVlZenTTz+NabNv3z5Nnz5dgUBAKSkpmjVrlg4cOBDTZuvWrbrwwgvVtWtXZWRkaPHixa19ae1Gfn6+zj33XPXs2VOpqam68sorVV5eHtPm8OHDys3NVZ8+fdSjRw9NnTpVVVVVMW0qKyuVk5Ojbt26KTU1VfPmzVNjY2NMm3Xr1unss8+W3+/X0KFDVVBQ0NqX164sWbJEY8aMsZ8+GgqF9Oabb9rHGef4u//+++XxeDR37lz7PcY5PhYtWiSPxxPzGj58uH283Y+zhRP24osvWj6fz3rmmWesHTt2WDfddJOVkpJiVVVVme5au/XGG29Y//Zv/2a98sorliRr+fLlMcfvv/9+Kzk52Xr11VetDz/80Lr88sutwYMHW4cOHbLbTJ482Ro7dqy1YcMG65133rGGDh1qXXvttfbx2tpaKy0tzZo+fbq1fft264UXXrCSkpKs//zP/2yryzQqOzvbevbZZ63t27dbZWVl1iWXXGINHDjQOnDggN1m9uzZVkZGhlVUVGRt3rzZGj9+vPUP//AP9vHGxkZr1KhRVlZWlrVlyxbrjTfesPr27WstWLDAbvP5559b3bp1s/Ly8qyPPvrIeuyxx6yEhARr1apVbXq9Jr322mvWypUrrb/85S9WeXm59a//+q9Wly5drO3bt1uWxTjH26ZNm6xTTz3VGjNmjPWrX/3Kfp9xjo+7777bOuOMM6w9e/bYr71799rH2/s4E2AcOO+886zc3Fz7+6amJis9Pd3Kz8832KuO47sBprm52QoGg9YDDzxgv1dTU2P5/X7rhRdesCzLsj766CNLkvXBBx/Ybd58803L4/FYf/3rXy3Lsqwnn3zS6tWrl1VXV2e3mT9/vjVs2LBWvqL2qbq62pJkFRcXW5b17Zh26dLFWrZsmd3m448/tiRZJSUllmV9GzS9Xq8VDoftNkuWLLECgYA9rnfccYd1xhlnxHzWNddcY2VnZ7f2JbVrvXr1sp5++mnGOc72799vnXbaaVZhYaH105/+1A4wjHP83H333dbYsWOPeawjjDO3kE5QfX29SktLlZWVZb/n9XqVlZWlkpISgz3ruCoqKhQOh2PGNDk5WZmZmfaYlpSUKCUlReecc47dJisrS16vVxs3brTbTJgwQT6fz26TnZ2t8vJyff311210Ne1HbW2tJKl3796SpNLSUjU0NMSM8/DhwzVw4MCYcR49erTS0tLsNtnZ2YpEItqxY4fd5uhzRNt01j//TU1NevHFF3Xw4EGFQiHGOc5yc3OVk5PzvbFgnOPr008/VXp6uoYMGaLp06ersrJSUscYZwLMCfrb3/6mpqammP9QkpSWlqZwOGyoVx1bdNx+bEzD4bBSU1NjjicmJqp3794xbY51jqM/o7Nobm7W3Llzdf7552vUqFGSvh0Dn8+nlJSUmLbfHefjjeEPtYlEIjp06FBrXE67tG3bNvXo0UN+v1+zZ8/W8uXLNXLkSMY5jl588UX9+c9/Vn5+/veOMc7xk5mZqYKCAq1atUpLlixRRUWFLrzwQu3fv79DjHNii34aQLuSm5ur7du369133zXdlZPWsGHDVFZWptraWv3xj3/UzJkzVVxcbLpbJ41du3bpV7/6lQoLC9W1a1fT3TmpTZkyxf56zJgxyszM1KBBg/Tyyy8rKSnJYM9ODDMwJ6hv375KSEj4XgV2VVWVgsGgoV51bNFx+7ExDQaDqq6ujjne2Nioffv2xbQ51jmO/ozOYM6cOVqxYoXefvttDRgwwH4/GAyqvr5eNTU1Me2/O87HG8MfahMIBDrEX3bx4vP5NHToUI0bN075+fkaO3asHnnkEcY5TkpLS1VdXa2zzz5biYmJSkxMVHFxsR599FElJiYqLS2NcW4lKSkpOv3007Vz584O8eeZAHOCfD6fxo0bp6KiIvu95uZmFRUVKRQKGexZxzV48GAFg8GYMY1EItq4caM9pqFQSDU1NSotLbXbrF27Vs3NzcrMzLTbrF+/Xg0NDXabwsJCDRs2TL169WqjqzHHsizNmTNHy5cv19q1azV48OCY4+PGjVOXLl1ixrm8vFyVlZUx47xt27aYsFhYWKhAIKCRI0fabY4+R7RNZ//z39zcrLq6OsY5TiZOnKht27aprKzMfp1zzjmaPn26/TXj3DoOHDigzz77TP379+8Yf55bXAbcibz44ouW3++3CgoKrI8++si6+eabrZSUlJgKbMTav3+/tWXLFmvLli2WJOuhhx6ytmzZYv3P//yPZVnfLqNOSUmx/vSnP1lbt261rrjiimMuoz7rrLOsjRs3Wu+++6512mmnxSyjrqmpsdLS0qzrr7/e2r59u/Xiiy9a3bp16zTLqG+55RYrOTnZWrduXcxyyG+++cZuM3v2bGvgwIHW2rVrrc2bN1uhUMgKhUL28ehyyEmTJlllZWXWqlWrrH79+h1zOeS8efOsjz/+2HriiSc63bLTO++80youLrYqKiqsrVu3Wnfeeafl8XisNWvWWJbFOLeWo1chWRbjHC+33367tW7dOquiosJ67733rKysLKtv375WdXW1ZVntf5wJMA499thj1sCBAy2fz2edd9551oYNG0x3qV17++23LUnfe82cOdOyrG+XUv/7v/+7lZaWZvn9fmvixIlWeXl5zDm++uor69prr7V69OhhBQIB65e//KW1f//+mDYffvihdcEFF1h+v9865ZRTrPvvv7+tLtG4Y42vJOvZZ5+12xw6dMj653/+Z6tXr15Wt27drH/8x3+09uzZE3OeL774wpoyZYqVlJRk9e3b17r99tuthoaGmDZvv/22deaZZ1o+n88aMmRIzGd0BjfccIM1aNAgy+fzWf369bMmTpxohxfLYpxby3cDDOMcH9dcc43Vv39/y+fzWaeccop1zTXXWDt37rSPt/dx9liWZbV8HgcAAKDtUAMDAAA6HAIMAADocAgwAACgwyHAAACADocAAwAAOhwCDAAA6HAIMAAAoMMhwAAAgA6HAAMAADocAgwAAOhwCDAAAKDD+f8vnQ6SuXHeZgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "import torch\n", + "from torch.nn import functional as F\n", + "\n", + "\n", + "xs = np.asarray([[-10], [-8], [-6], [-4], [-2], [0], [2], [4], [6], [8], [10]])\n", + "# ys = xs ** 3 - xs**2 + xs - 3\n", + "ys = xs ** 2\n", + "\n", + "xs = np.hstack((xs, np.ones([xs.shape[0], 1])))\n", + "\n", + "xs = torch.tensor(xs).float()\n", + "ys = torch.tensor(ys).float()\n", + "\n", + "ins = 1\n", + "outs = 1\n", + "nodes = 200\n", + "lr = 0.003\n", + "\n", + "params = []\n", + "def weights(ins, outs):\n", + " ws = torch.randn(ins, outs) * 0.1\n", + " ws = ws.requires_grad_(True)\n", + " params.append(ws)\n", + " return ws\n", + "\n", + "class Model():\n", + " def __init__(self):\n", + " self.w0 = weights(ins+1, nodes)\n", + " self.w1 = weights(nodes, nodes)\n", + " self.w2 = weights(nodes, outs)\n", + "\n", + " def forward(self, x):\n", + " x = torch.relu(x @ self.w0)\n", + " x = torch.relu(x @ self.w1)\n", + " yh = (x @ self.w2)\n", + " return yh\n", + "\n", + "model = Model()\n", + "optimizer = torch.optim.Adam(params, lr)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " yh = model.forward(xs)\n", + "\n", + " loss = F.mse_loss(yh, ys)\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " e = loss.item()\n", + "\n", + " if i % 500 == 0:\n", + " print('loss:', e)\n", + "\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)\n", + "\n", + "plt.figure(2)\n", + "plt.plot(ys, label='ys')\n", + "plt.plot(yh.detach(), label='yh')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([1444.6680], grad_fn=)\n" + ] + } + ], + "source": [ + "value = 100\n", + "value = torch.tensor([value, 1]).float()\n", + "result = model.forward(value)\n", + "print(result)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can fit any data with enough nodes. \n", + "Poor interpolation, but we can mitigate this with more data, more training, and more constraints. \n", + "Experiment and see what works!\n", + "\n", + "we can use anything as input and output. Images, medical data, dogs, text. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "text = '''\n", + "Cats, cats, everywhere\n", + "Furry balls without a care\n", + "Purring, meowing, licking fur\n", + "Hunting mice, they always purr\n", + "\n", + "Cats, cats, on the prowl\n", + "Jumping high, never a scowl\n", + "Whiskers twitching, eyes alert\n", + "Tail in air, ready to assert\n", + "\n", + "Cats, cats, so much fun\n", + "Cuddling close in the sun\n", + "Stretching out, napping long\n", + "Playing with string, never wrong\n", + "\n", + "Cats, cats, always cool\n", + "Lapping milk, acting like a fool\n", + "Mysterious, charming, full of grace\n", + "Cats are simply ace\n", + "\n", + "Cats, cats, with silky fur\n", + "Making biscuits, they always purr\n", + "Sitting high, looking down\n", + "Claiming everything as their crown\n", + "\n", + "Cats, cats, with eyes so bright\n", + "Chasing shadows, day or night\n", + "Curled up warm, on your lap\n", + "Purring gently, taking a nap\n", + "\n", + "Cats, cats, with playful paws\n", + "Hiding, stalking, never pause\n", + "Jumping, leaping, so agile\n", + "Graceful creatures, never fragile\n", + "\n", + "Cats, cats, our feline friends\n", + "Bringing joy that never ends\n", + "Loving us, without a doubt\n", + "Cats are what life's all about\n", + "\n", + "Cats, cats, everywhere I see\n", + "Furry creatures, cute as can be\n", + "Rubbing against our legs\n", + "Asking for treats, without begs\n", + "\n", + "Cats, cats, with their regal stance\n", + "Graceful movements, they enhance\n", + "But we love them all the same\n", + "Our little friends, never tame\n", + "\n", + "Cats, cats, so full of love\n", + "Watching over us from above\n", + "Protecting us from any harm\n", + "Always there, with their charm\n", + "\n", + "Cats, cats, with their curious ways\n", + "Exploring nooks, and hiding in bays\n", + "Living life with style and grace\n", + "Cats are always in first place\n", + "\n", + "Cats, cats, so full of fun\n", + "Chasing toys, never done\n", + "Hiding in boxes, or paper bags\n", + "Making us laugh, never drags\n", + "\n", + "Cats, cats, with their own minds\n", + "Sitting in the sun, never blinds\n", + "Chasing strings, and balls of yarn\n", + "They never tire, oh what a charm\n", + "\n", + "Cats, cats, with calming purrs\n", + "Cuddling close, to be yours\n", + "Giving love, without any fuss\n", + "Their presence, a comfort to us\n", + "\n", + "Cats, cats, always at ease\n", + "Living life, as they please\n", + "Bringing joy, to all they meet\n", + "Cats, our furry friends, so sweet\n", + "\n", + "Cats, cats, with eyes so bright\n", + "Guiding us through the darkest night\n", + "Purring softly, by our side\n", + "Comforting us, as we hide\n", + "\n", + "Cats, cats, with softest fur\n", + "Nuzzling close, making a purr\n", + "In our lap, they take a rest\n", + "We're lucky to have, such a guest\n", + "\n", + "Cats, cats, with their playful ways\n", + "Entertaining us, on the laziest days\n", + "Chasing shadows, or a feather\n", + "Making us smile, always together\n", + "\n", + "Cats, cats, with hearts so pure\n", + "Bringing love, that will endure\n", + "Their presence, a blessing indeed\n", + "Cats, our friends, we shall never need\n", + "\n", + "Cats, cats, with their little quirks\n", + "Scratching posts, and tiny perks\n", + "Licking paws, cleaning their face\n", + "Chasing tails, all over the place\n", + "\n", + "Cats, cats, with their playful hearts\n", + "Chasing toys, and little carts\n", + "Their antics, bringing us joy\n", + "Cats, our little angels, oh so coy\n", + "\n", + "Cats, cats, with their gentle souls\n", + "Lifting spirits, making us whole\n", + "In their eyes, we see the light\n", + "Bringing peace, that feels so right\n", + "\n", + "Cats, cats, with their gentle purr\n", + "Calming us, when we're feeling a stir\n", + "Snuggling close, to keep us warm\n", + "Cats, our little cuddle storm\n", + "\n", + "Cats, cats, with their playful heart\n", + "Jumping high, right from the start\n", + "Bouncing around, like little springs\n", + "Cats, our little entertainers, with wings\n", + "\n", + "Cats, cats, with their loving grace\n", + "Their soft purrs, caress our face\n", + "In their embrace, we feel at peace\n", + "Cats, our little comfort, never to cease\n", + "\n", + "Cats, cats, with their loving ways\n", + "Cuddling close, on the darkest days\n", + "In the garden, or up in a tree\n", + "Cats, our little explorers, always free'''" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "loss: 15.538918495178223\n", + "loss: 0.6973809003829956\n", + "loss: 0.009146902710199356\n", + "loss: 0.0025379888247698545\n", + "loss: 0.001624523545615375\n", + "loss: 0.000958576041739434\n", + "loss: 0.0005740119377151132\n", + "loss: 0.00047716841800138354\n", + "loss: 0.00028826287598349154\n", + "loss: 0.0002343075757380575\n" + ] + }, + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "import matplotlib.pylab as plt\n", + "import torch\n", + "from torch.nn import functional as F\n", + "\n", + "%matplotlib widget\n", + "\n", + "text = text.lower()\n", + "chars = sorted(list(set(text)))\n", + "stoi = {ch:i for i, ch in enumerate(chars)}\n", + "itos = {i:ch for i, ch in enumerate(chars)}\n", + "data = [stoi[c] for c in text]\n", + "vocab_size = len(chars)\n", + "\n", + "ins = 64\n", + "outs = vocab_size\n", + "nodes = 200\n", + "lr = 0.003\n", + "\n", + "data = torch.tensor(data).float()\n", + "\n", + "params = []\n", + "def weights(ins, outs):\n", + " ws = torch.randn(ins, outs) * 0.1\n", + " ws = ws.requires_grad_(True)\n", + " params.append(ws)\n", + " return ws\n", + "\n", + "class Model():\n", + " def __init__(self):\n", + " self.w0 = weights(ins, nodes)\n", + " self.w1 = weights(nodes, nodes)\n", + " self.w2 = weights(nodes, outs)\n", + "\n", + " def forward(self, x):\n", + " x = torch.relu(x @ self.w0)\n", + " x = torch.relu(x @ self.w1)\n", + " yh = (x @ self.w2)\n", + " return yh\n", + "\n", + "model = Model()\n", + "optimizer = torch.optim.Adam(params, lr)\n", + "\n", + "ers = []\n", + "for i in range(5000):\n", + " # Take 100 random samples from the data:\n", + " b = torch.randint(len(data)-ins, (100, ))\n", + " xs = torch.stack([data[i:i+ins] for i in b])\n", + " ys = torch.stack([data[i+ins:i+ins+1] for i in b])\n", + "\n", + " yh = model.forward(xs)\n", + "\n", + " # loss = F.mse_loss(yh, ys)\n", + " loss = F.cross_entropy(yh.view(-1, vocab_size), ys.long().view(-1))\n", + " optimizer.zero_grad()\n", + " loss.backward()\n", + " optimizer.step()\n", + "\n", + " e = loss.item()\n", + "\n", + " if i % 500 == 0:\n", + " print('loss:', e)\n", + "\n", + " ers.append(e)\n", + "\n", + "plt.figure(1)\n", + "plt.plot(ers)\n", + "\n", + "plt.figure(2)\n", + "plt.plot(ys)\n", + "yh = torch.argmax(yh, dim=-1)\n", + "plt.plot(yh.detach())\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "l\n", + "lapping milk, acting like a fool\n", + "mysterious, charming, full of grace\n", + "cats are simply ace\n", + "\n", + "cats, cats, with silky fur\n", + "making biscuits, they always purr\n", + "sitting high, looking down\n", + "claiming everything as their crown\n", + "\n", + "cats, cats, with eyes so bright\n", + "chasing shadows, day or night\n", + "curled up warm, on your lap\n", + "purring gently, taking a nap\n", + "\n", + "cats, cats, with playful paws\n", + "hiding, stalking, never pause\n", + "jumping, leaping, so agile\n", + "graceful creatures, never fragile\n", + "\n", + "cats, cats, our feline friends\n", + "bringing joy that never ends\n", + "loving us, without a doubt\n", + "cats are what life's all about\n", + "\n", + "cats, cats, everywhere i see\n", + "furry creatures, cute as can be\n", + "rubbing against our legs\n", + "asking for treats, without begs\n", + "\n", + "cats, cats, with their regal stance\n", + "graceful movements, they enhance\n", + "but we love them all the same\n", + "our little friends, never tame\n", + "\n", + "cats, cats, so full of love\n", + "watching over us from above\n", + "protecting us from any harm\n", + "always there, with their charm\n", + "\n", + "cats, cats, with their curious ways\n", + "exploring nooks, and hiding in bays\n", + "living life with style and grace\n", + "cats are always in first place\n", + "\n", + "cats, cats, so full of fun\n", + "chasing toys, never done\n", + "hiding in boxes, or paper bags\n", + "making us laugh, never drags\n", + "\n", + "cats, cats, with their own minds\n", + "sitting in the sun, never blinds\n", + "chasing strings, and balls of yarn\n", + "they never tire, oh what a charm\n", + "\n", + "cats, cats, with calming purrs\n", + "cuddling close, to be yours\n", + "giving love, without any fuss\n", + "their presence, a comfort to us\n", + "\n", + "cats, cats, always at ease\n", + "living life, as they please\n", + "bringing joy, to all they meet\n", + "cats, our furry friends, so sweet\n", + "\n", + "cats, cats, with eyes so bright\n", + "guiding us through the darkest night\n", + "purring softly, by our side\n", + "comforting us, as we hide\n", + "\n", + "cats, cats, with softest fur\n", + "nuzzling close, making a purr\n", + "in our lap, they take a rest\n", + "we're lucky to have, such a guest\n", + "\n", + "cats, cats, with their playful ways\n", + "entertaining us, on the laziest days\n", + "chasing shadows, or a feather\n", + "making us smile, always together\n", + "\n", + "cats, cats, with hearts so pure\n", + "bringing love, that will endure\n", + "their presence, a blessing indeed\n", + "cats, our friends, we shall never need\n", + "\n", + "cats, cats, with their little quirks\n", + "scratching posts, and tiny perks\n", + "licking paws, cleaning their face\n", + "chasing tails, all over the place\n", + "\n", + "cats, cats, with their playful hearts\n", + "chasing toys, and little carts\n", + "their antics, bringing us joy\n", + "cats, our little angels, oh so coy\n", + "\n", + "cats, cats, with their gentle souls\n", + "lifting spirits, making us whole\n", + "in their eyes, we see the light\n", + "bringing peace, that feels so right\n", + "\n", + "cats, cats, with their gentle purr\n", + "calming us, when we're feeling a stir\n", + "snuggling close, to keep us warm\n", + "cats, our little cuddle storm\n", + "\n", + "cats, cats, with their playful heart\n", + "jumping high, right from the start\n", + "bouncing around, like little springs\n", + "cats, our little entertainers, with wings\n", + "\n", + "cats, cats, with their loving grace\n", + "their soft purrs, caress our face\n", + "in their embrace, we feel at peace\n", + "cats, our little comfort, never to cease\n", + "\n", + "cats, cats, with their loving ways\n", + "cuddling close, on the d\n" + ] + } + ], + "source": [ + "\n", + "s = xs[0]\n", + "\n", + "gen_text = \"\"\n", + "for i in range(3000):\n", + " yh = model.forward(s)\n", + " prob = F.softmax(yh, dim=0)\n", + " # pred = torch.argmax(yh).item()\n", + " pred = torch.multinomial(prob, num_samples=1).item()\n", + "\n", + " s = torch.roll(s, -1)\n", + " s[-1] = pred\n", + " \n", + " gen_text += itos[pred]\n", + "\n", + "print(gen_text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/M-Microcontrollers_and_Circuitpython.ipynb b/M-Microcontrollers_and_Circuitpython.ipynb new file mode 100644 index 0000000..68553cd --- /dev/null +++ b/M-Microcontrollers_and_Circuitpython.ipynb @@ -0,0 +1,357 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section M - Microcontrollers\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics:** Programming microcontrollers with CircuitPython\n", + "\n", + "We'll look at circuitpython here - circuitpython is a version of micropython customized by Adafruit. They have a ton of guides, libraries, etc available and circuitpython is the best place to start. \n", + "\n", + "\n", + "\n", + "## Circuitpython vs. Micropython vs. Standard Python\n", + "Regular/standard pything runs as software on windows, mac, linux, etc. It interprets code and runs it, and includes libraries like sys, os, fsutil to interact with the operating system of the computer it's running on. \n", + "\n", + "Circuitpython and Micropython are firmware (the os) that you can load onto a microcontroller like a Pi Pico or a number of newer Arduino, Esp32, and other boards. These microcontroller boards have a small amount of storage for .py files and compiled libraries.\n", + "\n", + "Micropython offers some advanced features like multi-threading and has better/earlier hardware support for wifi, bluetooth, etc than Circuitpython, but it doesn't usually present a storage drive to drop code into directly. \n", + "\n", + "Circuitpython has more user friendly documentation and libraries, always presents the micocontroller as a storage device, has better usb hid (keyboard, mouse, gamepad) support, and is generally easier to start with. \n", + "\n", + "Both micropython and circuitpython present a serial console when you plug them into a computer that can be used to interact with the python prompt and see the text output from running code.\n", + "\n", + "Micropython runs \"main.py\" when it starts, and circuitpython runs \"code.py\" when it starts.\n", + "\n", + "## Hardware test setup\n", + "We'll practice on a pi pico microcontroller with a button, display, and accelerometer. The pi pico has a built in LED we can blink.\n", + "* Pi Pico: https://www.adafruit.com/product/4864\n", + "* SSD1306 OLED Display: https://www.amazon.com/dp/B0837DLWVH\n", + "* ADXL345 Accelerometer: https://www.amazon.com/dp/B08HLP1MPY\n", + "* Pin Reference: https://www.adafruit.com/product/4901\n", + "* 3D printed jig: https://raw.githubusercontent.com/a8ksh4/python_workshop/refs/heads/main/images/pico_proto_bracket_rev0.stl\n", + "\n", + "Total cost for this setup is about $8 each if you're making five of them at a time.\n", + "\n", + "Adafruit has an option for USPS shipping at around $5 usually, so it's a much better place to by raspberry pi boards than amazon, but they have high pricese on some other components. \n", + "\n", + "The SSD1306 and ADXL345 can be found cheaper on Ali Express than amazon if you don't mind waiting a couple of weeks for shipping. \n", + "\n", + "\n", + "\n", + "\n", + "## Getting Started\n", + "Download and install the \"Mu\" editor. There are other options, but mu just works - it knows where to look for code on the circuitpython microcontroller and has a button to open a serial terminal. https://codewith.mu/\n", + "\n", + "You can also use https://code.circuitpython.org/ to program circuitpython just like with mu. Most browsers now support serial passthrough specifically for this type of use.\n", + "\n", + "Flash micropython onto your microcontroller board. If you have a new board, it will present a storage device called UF2 something when you plug it into the computer. If it doesn't, then hold the boot button on the board while you plug it into the computer and it should go into uf2 flash mode.\n", + "\n", + "**Download a uf2 file from circuitpython for your board**\n", + "https://circuitpython.org/board/raspberry_pi_pico/\n", + "https://circuitpython.org/board/raspberry_pi_pico_w/\n", + "And **drag the file to the UF2 storage device presented by the board**. It'll automatically flash and reboot when you drop the file on it and present a CIRCUITPY storage device where you can modify the code.py.\n", + "\n", + "**Open Mu, click the Load button, and find code.py on the CIRCUITPY drive**. Now you can modify it and each time you save a change, the board will reboot and run the code. \n", + "\n", + "**Click the Serial button to see the serial console** for any print output, error messages, and for an interactive python prompt\n", + "* You can always press ` + ` in the serial terminal to quit the running code and get an interactive prompt \">>>\"\n", + "* You can press ` + ` at the prompt to reboot teh board and run code.py.\n", + "\n", + "#### *Exercise:*\n", + "* Per above, ensure you have circuitpython flashed to your board and the CIRCUITPY drive shows up when you plug it into the computer.\n", + "* Open Mu and click the Serial button at the top to open the serial terminal. \n", + "* Access the python terminal and run the following by typing/pasting it in. A pretty fool-proof way reach the interactive terminal is to Press ` + `, then ` + `, and then ` + ` one more time. \n", + " * `print('hi world!')`\n", + " * `import board`\n", + " * `dir(board)`\n", + "* Now use Mu to open code.py on the CIRCUITPY drive. Add a print statement that you'll recognize at the top of the file, below the import statements, and and save your change. Now press ` + ` in the serial terminal to switch from the interactive prompt to running code.py and ensure that you see the result of your print statement in the output.\n", + "\n", + "## Built-in Modules\n", + "https://docs.circuitpython.org/en/latest/shared-bindings/index.html\n", + "\n", + "There are a lot of built-in modules that you can import immediately on a new board wthout copying in any additional files. Here are a few that you're likely to use at some point:\n", + "* alarm\n", + "* analogio\n", + "* board - Analog and Digital Pins, Stemma I2C\n", + "* busio - I2C, SPI, UART (serial)\n", + "* digitalio\n", + "* time\n", + "* math - sin, ..., log, pow, ... https://docs.circuitpython.org/en/latest/shared-bindings/math/index.html\n", + "* ... many more... audio, camera, gc, etc...\n", + "\n", + "Just **import** these to use them. \n", + "\n", + "## Installing Libraries\n", + "There is no pip install for circuitpython libraries. But many libraries are provided as .mpy files (micropython bytecode) in a bundle you can download here: https://circuitpython.org/libraries\n", + "\n", + "You can check the version of circuitpython on your device by restarting the board and checking output ` + `, ` + `, ` + `, or looking at the boot_out.txt on the CIRCUITPY drive. \n", + "\n", + "We're interested in the ssd1306 and adxl345 libraries - you'll find them in the library bundle inside the lib directory. The framebuf lib is a depency of ssd1306.\n", + "* adafruit_adxl34x.mpy\n", + "* adafruit_ssd1306.mpy\n", + "* adafruit_framebuf.mpy\n", + "\n", + "Copy them into your CIRCUITPY/lib directory. When you import and start using them, they may complain about additional libraries you need to copy from the bundle." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basics\n", + "\n", + "For most things here, we'll use the board library to refer to the GPIO pins and LED on our board. E.g:\n", + "\n", + " >>> import board\n", + " >>> dir(board)\n", + " ['__class__', '__name__', 'A0', 'A1', 'A2', 'A3', 'GP0', 'GP1', 'GP10', 'GP11', 'GP12', 'GP13', 'GP14', 'GP15', 'GP16', 'GP17', 'GP18', 'GP19', 'GP2', 'GP20', 'GP21', 'GP22', 'GP26', 'GP26_A0', 'GP27', 'GP27_A1', 'GP28', 'GP28_A2', 'GP3', 'GP4', 'GP5', 'GP6', 'GP7', 'GP8', 'GP9', 'LED', 'SMPS_MODE', 'STEMMA_I2C', 'VBUS_SENSE', 'VOLTAGE_MONITOR', '__dict__', 'board_id']\n", + "\n", + "It's also helpful to use the time library to measure elapsed time or to \"sleep\", or wait for some period of time. We can use:\n", + "\n", + "* time.monotonic() to get the number of seconds since the board was powered up\n", + "* time.monotonic_ns() to get the number of nanoseconds since the board was powered up\n", + "* time.sleep(seconds) to sleep for some number of seconds. \n", + "\n", + "Example:\n", + "\n", + " >>> import time\n", + " >>> time.sleep(2)\n", + " >>> time.monotonic()\n", + " 47255.3\n", + " >>> time.monotonic_ns()\n", + " 47260617889414\n", + "\n", + "\n", + "### Digital pins\n", + "Digital pins can either be inputs or outputs. An LED would be an output, or if you needed to drive a pin low/high on another device, you would use an output to do that. An input could be a button.\n", + "\n", + " import board\n", + " import digitalio\n", + "\n", + " led = digitalio.DigitalInOut(board.LED)\n", + " led.direction = digitalio.Direction.OUTPUT\n", + "\n", + " button = digitalio.DigitalInOut(board.GP20)\n", + " button.direction = digitalio.Direction.INPUT\n", + " button.pull = digitalio.Pull.UP\n", + "\n", + "\"led\" in this example is the LED built into the Pico board. We can turn it on and off with:\n", + "\n", + " led.value = True # on\n", + " time.sleep(2)\n", + " led.value = False # off\n", + "\n", + "The button in this example has one leg wired to ground and the other leg wired to pin GP20. We set GP20 to pull UP, so the board internally connects the pin to 3.3v through a resistor. Whe the button is not pressed, we measure 3.3v on the pin and button.value is True. Whe the button is pressed, it shorts the pin to ground so the voltage measured is zero (0) so button.value is False:\n", + "\n", + " if not button.value: # voltage is zero\n", + " print(\"button is pressed\")\n", + " else:\n", + " #print(\"button is not pressed\")\n", + " pass\n", + "\n", + "#### *Exercise:*\n", + "* Use a while loop to make the LED blink once every second.\n", + "* Check the button and print a message when it's pressed. \n", + "* Check the button and print a message whenever its states changes between pressed and unpressed. \n", + "* Check the button and turn the LED on if the button is pressed, and turn it off when the button is released. Print a message when changing the states of the LED." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## I2C Devices\n", + "https://learn.adafruit.com/circuitpython-essentials/circuitpython-i2c\n", + "\n", + "I2C is a bus protocol enabling communication and control of multiple devices with a single pair of wires (in addition to power and groud). Each I2C device has an address on the bus that it will reply with when we scan the bus and which is used when sending a command to the device. \n", + "\n", + "Many devices have resistors that can be moved/changed to tell them to use a different address if you want to have multiple on teh same bus. And some microcontroller boards, like the Pi Pico, have multile I2C buses that can be used if there are address conflicts or perhaps if you need more bandwidth for devices than one bus can provide.\n", + "\n", + "### Scanning for Devices\n", + "The first thing we want to do is initialize i2c and scan for devices to ensure that our hadware is connected to and communicating on the bus:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import board\n", + "import busio\n", + "\n", + "i2c = busio.I2C(board.GP27, board.GP26)\n", + "i2c.try_lock()\n", + "print(i2c.scan())\n", + "print([hex(addr) for addr in i2c.scan()])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You should see something like this:\n", + "\n", + " [60, 83]\n", + " ['0x3c', '0x53']\n", + "\n", + "* 60 is the display - this is hex value 0x3c\n", + "* 83 is the adxl345 - this is hex value 0x53\n", + "\n", + "NOTE - **comment out this i2c try_lock and scan code when done**. It will break other i2c stuff in your code." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The SSD1306 Display\n", + "These little displays are very common on custom keyboards and are cheap and easy to work with. They typically use i2c address 0x3c, and this can be changed by fiddling with the surface mount resistors on the board if you wanted more than one on your project. \n", + "\n", + "Ensure you have a couple of libraries in you lib folder:\n", + "* adafruit_ssd1306.mpy\n", + "* adafruit_framebuf.mpy\n", + "\n", + "And copy this font file to the main CIRCUITPY folder:\n", + "* https://raw.githubusercontent.com/a8ksh4/python_workshop/refs/heads/main/circuitpy/font5x8.bin\n", + "* You can also google for adafruit font5x8.bin to find it online. \n", + "\n", + "Example code to start with:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import adafruit_ssd1306\n", + "i2c = busio.I2C(board.GP27, board.GP26)\n", + "\n", + "display = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)\n", + "\n", + "# Blank the display\n", + "display.fill(0)\n", + "display.show()\n", + "\n", + "# Draw three pixeles on a diagonal line:\n", + "display.pixel(0, 31, 1)\n", + "display.pixel(64, 47, 1)\n", + "display.pixel(127, 63, 1)\n", + "# And draw some text in the corner:\n", + "display.text('Hello', 0, 0, 1)\n", + "display.text('World', 0, 10, 1)\n", + "display.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We Start by initializing the i2c bus and using that to initialize the display. \n", + "* You can optionally pas a specific i2c address here.\n", + "* And you can specify 128x32 if you're using the smaller version of this display.\n", + "\n", + "Any time we call fill, pixel, or text, we can use '0' or '1' for the color. \n", + "* display.fill takes (color)\n", + "* display.pixel takes (xloc, yloc, color)\n", + "* display.text takes (text, xloc, yloc, color)\n", + "\n", + "And if you're updating the display with new content, be sure to call .fill first to wipe previous content. \n", + "\n", + "There are a few other control and draw functoins for shapes, etc:\n", + "\n", + "`['__class__', '__init__', '__module__', '__qualname__', 'format', '__dict__', 'blit', 'buffer', 'fill', 'height', 'i2c_device', 'invert', 'rotation', 'show', 'width', 'pixel', 'text', 'addr', 'external_vcc', 'page_addressing', 'reset_pin', 'pages', '_power', 'pagebuffer', 'page_column_start', 'poweron', 'init_display', 'power', 'write_cmd', 'poweroff', 'contrast', 'rotate', 'write_framebuf', 'temp', 'stride', 'buf', 'rect', 'fill_rect', '_font', '_rotation', 'hline', 'vline', 'circle', 'line', 'scroll', 'image']`\n", + "\n", + "#### *Exercise*:\n", + "* use print(dir(display)) in your code to see all of it's built in functions. \n", + "* Test a few of the draw functions to make a square, circle, and line. \n", + "* Rotate the display 90 degrees and write some text to it. \n", + "* Basically just draw some fun stuff on the display! \n", + "* Draw a box and put your name in the middle of it. \n", + "* Store a paragraph of text in a string. Figure out how many characters you can put on the display at one time and write one \"page\" at a time, changing to the next page each time the button is pressed!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The ADXL345 Accelerometer\n", + "The ADXL345 is a cheap and easy to use I2C accelerometer. The library provides raw values for force in the x, y, z directions as well as helpers for motoin, freefall, and tap detection. I've only used the raw values so far YMMV on the other stuff!\n", + "\n", + "Ensure you have the adafruit_adxl34x.mpy library in your lib folder. \n", + "\n", + "Ensure that you set the accelerometer.data_rate or you'll see very slow changes. You might want a higher rate than 20!\n", + "\n", + "Example code to start with:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import adafruit_adxl34x\n", + "import time\n", + "i2c = busio.I2C(board.GP27, board.GP26)\n", + "accelerometer = adafruit_adxl34x.ADXL345(i2c)\n", + "\n", + "accelerometer.data_rate = 20\n", + "print(accelerometer.data_rate)\n", + "for _ in range(5):\n", + " print(accelerometer.raw_x,accelerometer.raw_y, accelerometer.raw_z)\n", + " print(accelerometer.acceleration)\n", + " time.sleep(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here are the built-in functions in the library we're using. You've seen raw_x, raw_y, raw_z so far.\n", + "\n", + "`['__class__', '__init__', '__module__', '__qualname__', 'range', '__dict__', 'events', 'offset', 'data_rate', 'raw_x', 'raw_y', 'raw_z', 'acceleration', '_i2c', '_buffer', '_write_register_byte', '_enabled_interrupts', '_event_status', '_read_register', '_read_clear_interrupt_source', 'enable_motion_detection', '_read_register_unpacked', 'disable_motion_detection', 'enable_freefall_detection', 'disable_freefall_detection', 'enable_tap_detection', 'disable_tap_detection']`\n", + "\n", + "#### *Exercise*:\n", + "* Write a functoin that uses the pythagorean theorem to convert raw_x, raw_y, raw_z into a single value showing the magnitude of acceleration at any time. \n", + "* Write a function that converts raw_x, raw_y, raw_z to an angular value indicating which direction is down. Gravity is always pulling on the sensor, so as you rotate it, the x, y, z values will change to point down. \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Putting it all together:\n", + "We should be able to do some fun things with a button, display, and accelerometer. A few project ideas to work on might be:\n", + "\n", + "* Make a game where you have to balance the device to keep a ball/pixel centered on the display. Add walls to the display and make the player tilt the device to roll the ball through a course. \n", + "\n", + "* Make a pedometer that tracks cadence by recording periodic acceleration and counting the bumps. Press the button to reset the counter. \n", + "\n", + "* You could really get crazy with the pixel graphics and do something like make a pinball game or something where you tap the device on one side or the other to activate a flipper. \n", + "\n", + "* Make a computer mouse by using the following libraries to make a usb mouse device. You should be able to plug the device into the computer, set it on the desk to zero the accelerometer, and then tilt it to move the cursor. Click the button to left click the mouse. https://learn.adafruit.com/circuitpython-essentials/circuitpython-hid-keyboard-and-mouse\n", + " * usb_hid\n", + " * adafruit_hid.mouse\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/N-Numpy.ipynb b/N-Numpy.ipynb new file mode 100644 index 0000000..5f8df4d --- /dev/null +++ b/N-Numpy.ipynb @@ -0,0 +1,552 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section N - Numpy\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "Numpy is the library that pandas and many other scientific and big-data python libraries are built on. It provides support for arrays (especially multi-dimensional arrays or \"ndarrays\") and a large collection of mathematical functions to operate on these arrays efficiently. Key features of NumPy include:\n", + "\n", + "* **N-dimensional Arrays (ndarray):** NumPy offers a data structure for working with large multi-dimensional arrays and matrices, which are more efficient than Python's built-in lists for numerical operations.\n", + "* **Mathematical Functions:** It provides a wide range of mathematical functions (like trigonometric, statistical, and algebraic functions) that operate on entire arrays at once, making code more concise and faster.\n", + "* **Vectorization / Broadcasting:** NumPy allows vectorized operations, meaning that operations on arrays are applied element-wise without the need for explicit loops, avoiding unnecessary copies, leading to more readable, memory efficient, and faster code.\n", + "* **Integration with Other Libraries:** Many scientific libraries, such as SciPy, pandas, and matplotlib, rely on NumPy for array operations.\n", + "* **Efficiency:** NumPy is implemented in C, which makes it highly efficient for performing large-scale computations compared to Python's native lists.\n", + "\n", + "Overall, NumPy is a cornerstone of scientific computing in Python, making it essential for tasks involving data analysis, machine learning, simulations, and other numerical applications.\n", + "\n", + "Let's do a simple example comparing addition of numbers in two lists/arrays in native Python vs Numpy:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "listc: [5, 7, 9, 11, 13]\n", + "listc: [ 5 7 9 11 13]\n" + ] + } + ], + "source": [ + "# Regular python\n", + "lista = range(5)\n", + "listb = range(5, 10)\n", + "listc = [a + b for a, b in zip(lista, listb)]\n", + "print('listc:', listc)\n", + "\n", + "# Using numpy\n", + "import numpy as np\n", + "lista = np.arange(5)\n", + "listb = np.arange(5, 10)\n", + "listc = lista + listb\n", + "print('listc:', listc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Numpy Basics\n", + "It is typical to import numpy as \"np\". Numpy has a few functions for creating numpy arrays of one or more dimmensions:\n", + "\n", + " np.array([1, 2, 3, 4]) # convert python list to np array \n", + " np.zeros((3, 5)) # 3x5 matrix of zeros\n", + " np.ones((2, 4)) # 2x4 matrix of ones\n", + " np.arange(0, 10, 2) # Numbers from 0 to 10 with a step of 2\n", + " np.linspace(0, 1, 5) # 5 numbers evenly spaced between 0 and 1\n", + "\n", + "So we can convert lists to np array, we can make arrays of ones or zeros, or generate ranges of numbers.\n", + "\n", + "#### *Exercise*:\n", + "Let's create and print a few arrays to see what they look like:\n", + "* Use np.zeros to make arrays of one, two, and three dimmensions:\n", + " * (3)\n", + " * (3, 4)\n", + " * (3, 4, 5)\n", + "* An array with the numbers 0 through 9, stepping by 1 - ten total numbers.\n", + "* An array with the numbers 10 through 100, stepping by 10 - ten total numbers.\n", + "* An array of 20 numbers spaced equally from 10 to 15. \n", + "* A 5x5 array with the following values of col_number * pow(5, row_num) in each row:\n", + " * 0, 1, 2, ...\n", + " * 0, 5, 10, ...\n", + " * 0, 25, 125, ...\n", + " * ...\n", + " * ..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Array indexing and Slicing\n", + "We can print or set elements of arrays, or ranges of elements of arrays:\n", + "* First element: `arr[0]`\n", + "* Last element: `arr[-1]`\n", + "* Elements 1 through 3: `arr[1:4]`\n", + "\n", + "Multi-dimmensional arrays have each dimmensino separated by a comma, and can use the same method of referring to a single element or a slice with a colon:\n", + "* First element of first element in a 2d array: `arr[0, 0]`\n", + "* First four elements of the second element of an array: `arr[:4, 1]`\n", + "\n", + "Let's look at a 1, 2, and 3 dimmensional array:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "arr_1d = np.array([1, 2, 3])\n", + "arr_2d = np.array([[1, 2, 3], [4, 5, 6]])\n", + "arr_3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "* What shape is each of these arrays?\n", + "* Print the firstt element of each of the arrays. Notice anything interesting? \n", + "* Print just 3 in each of the arrays.\n", + "* Set the 3 in each of the arrays to 99\n", + "* Print the first to values of the first item in the second item ni the 3d array. \n", + "* Create a 1D array of numbers from 10 to 20 and extrace a slice containing the numbers [12, 13, 14]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Array Operations\n", + "\n", + "**Basic Arithmetic Operations:**\n", + "\n", + " arr = np.array([1, 2, 3, 4])\n", + " print(arr + 2) # Add 2 to every element\n", + " print(arr * 3) # Multiply every element by 3\n", + "\n", + "**Element-wise Operations:**\n", + "\n", + " arr1 = np.array([1, 2, 3])\n", + " arr2 = np.array([4, 5, 6])\n", + " print(arr1 + arr2) # Add corresponding elements\n", + "\n", + "#### *Exescise*:\n", + "Create two arrays of the same size, one with even numbers and one with odd numbers. Perform addition and multiplication on these arrays." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mathematical Functions and Axis\n", + "\n", + "Numpy has some useful functions built in:\n", + "\n", + " np.sum(), np.mean(), np.max(), np.min(), np.std()\n", + "\n", + "These each will apply to an entire array if called without any arguments, but can also be given an axis to work against if, for example, you wanted to see the sum of each row or column in a 2d array.\n", + "\n", + "https://numpy.org/doc/stable/reference/generated/numpy.sum.html" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "arr = np.array([[0, 1], [2, 3]])\n", + "sum_all = arr.sum()\n", + "sum_rows = arr.sum(axis=1)\n", + "sum_cols = arr.sum(axis=0)\n", + "# sum_coles = np.sum(arr, axis=0) # this is equivalent to the previous line\n", + "\n", + "print('arr:', arr)\n", + "print('sum_all:', sum_all)\n", + "print('sum_rows:', sum_rows)\n", + "print('sum_cols:', sum_cols)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that sum_rows and sum_cols are each 1 dimensinoal arrays. Check the values in sum_rows and sum_cols to verify which numbers in the original array they came from.\n", + "\n", + "The idea of rows and columns sort of breaks down when we have 3 or more dimmensions/axis in our array. Numpy really contrasts with pandas in this regard. Pandas has very clear rows and columns and is limited to two dimmensinal data, but numpy is more abstract and it's better to pay attention to which axis number is which in an array rather than thinking in rows/cols. \n", + "\n", + "#### *Exercise*:\n", + "Create a 3d array similar to the above 2d array that contains the values 4 through 7 \n", + "* What shape is this array?\n", + "* Sum values on eac of the three axis. You shuold see some values correspond with the sums in the above example, and have some new values on axis 0 and 1. Axis 2 is all new. Think about which axix is which, counting outward from the sets of [ ] that contain the numbers in the array. \n", + "* Sum the values on multiple axis. E.g. array.sum(axis=(1,2)). What's happening when you do this? What combination of axis will include the value \"6\" that we saw in \"sum_all\" from the above 2d array example?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reshaping and Transposing Arrays\n", + "\n", + "A numpy array is just a block of memory of a size large enough to hold all of the values of our chosen data type in the quantity of the cells per the size of the array in all dimmensions. So a 2 x 3 x 4 array of four-byte float values would be 24 x 4 bytes. The values are consecutive, so there is really no difference between:\n", + "\n", + "* A 24 cell, single dimmensional, array\n", + "* A 6 x 4 array (24 cells)\n", + "* A 2 x 2 x 2 x 3 array (24 cells)\n", + "\n", + "Aside from the metadata describing the shape of the array. Thes means that we can do stuff like generate a sequence and then **reshape** it into a multi-dimmensional array like we were doing manually above." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "arr = np.arange(24)\n", + "print('arr:', arr)\n", + "arr = arr.reshape(6, 4)\n", + "print('arr:', arr)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can transpose data with the .T operator. This flips the data so rows become columns and columns become rows. Here's an example using the above 6x4 array:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "arr = arr.T\n", + "print('arr:', arr)\n", + "arr = arr.reshape(24)\n", + "print('arr:', arr)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So arr changes from 6 x 4 to 4 x 6, and when we reshape it back to a 1d array, we can see how the values have been shuffuled from the transpose operation. \n", + "\n", + "#### *Exercise*\n", + "* Create a 3 x 3 array with values 0 through 8. \n", + "* Check the mean on axis 0.\n", + "* Transpose the array and verify that the mean on axis 1 matches what we had originally on axis 0. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Broadcasting\n", + "\n", + "This term, \"broadcasting\" describes how numpy handles numerical operations between arrays of different shapes. We use it to avoid looping on on operations in python and instead do it in C via numpy's functionality. Any time we add, multiply, etc an array, we're using this functionality. We'll cover the basict, but there are loads of examples in the official documentation:\n", + "\n", + "https://numpy.org/devdocs/user/basics.broadcasting.html\n", + "\n", + "When looking at the shape of two arrays to be broadcast, we have the following conditions on the right-most dimmension(s) of the arrays:\n", + "\n", + "* they must be equal\n", + "* one of them must be 1\n", + "\n", + "Let's look at an example where we multiply a (3x3) array with a sequence of 0-8 in it, and we multiply it by 4. We print four instances of this which have an equivelant result:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "arr = np.arange(9).reshape(3, 3)\n", + "print('arr - shape (3x3):\\n', \n", + " arr)\n", + "print('arr * 3 - shapes (3x3) and (1):\\n', \n", + " arr * 4)\n", + "print('arr * [3] - shapes (3x3) and (1):\\n', \n", + " arr * np.array([4]))\n", + "print('arr * [3, 3, 3] - shapes (3x3) and (3):\\n', \n", + " arr * np.array([4, 4, 4]))\n", + "print('arr * [[3, 3,3], [3...], []] - shapes (3x3) and (3x3):\\n', \n", + " arr * np.array([[4, 4, 4], [4, 4, 4], [4, 4, 4]]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try a slight modification of this and broadcast a (3x3) array of ones into a (3) 1d array of [0, 1, 2]. The 1d array is broadcast across the 3x3. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "arr = np.ones((3, 3))\n", + "print('arr:\\n', arr)\n", + "arr = arr * np.arange(3)\n", + "print('arr * [0, 1, 2]:\\n', arr)\n", + "arr = arr.T * np.arange(3)\n", + "print('arr.T * [0, 1, 2]:\\n', arr)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### *Exercise*:\n", + "Try to add a (3x3) array to each of the following shape arrays: \n", + "* (1), (2), (3)\n", + "* (1x3), (3x1), (2x3), (3x2)?, (3x3), (3x3x3)?\n", + "\n", + "I'd suggest using np.ones and np.arange with .shape to make arrays of each shape. What're the differences between (3), (1x3), and (3x1) arrays?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Accelerating Numpy\n", + "If you have an Nvidia GPU, you can install Cuda and the python \"cupy\" library. It is almost a drop in replacement for numpy and can greatly accelerate large data operations. It's a little different from regular numpy in that you need to be aware of whether the array you're working on is stored in the GPU (cupy array) or on the system/CPU memory (numpy arrray) and copy the array between CPU and GPU depending on needs of the other libraries that need to use it. \n", + "\n", + "Here's a simple bit of code to compare numpy and cupy performance on your system:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import gc\n", + "import time\n", + "import cupy as cp\n", + "import numpy as np\n", + "\n", + "start_time = time.time()\n", + "# Create a sample array\n", + "gpu_array = cp.random.uniform(0, 1, (500000000,))\n", + "cp.cuda.Stream.null.synchronize() # Synchronize to ensure the transfer completes\n", + "gpu_time = time.time()\n", + "\n", + "# Transfer to CPU and back to GPU\n", + "cpu_array = cp.asnumpy(gpu_array)\n", + "# cpu_array = np.array(gpu_array.get())\n", + "cp.cuda.Stream.null.synchronize()\n", + "cpu_time = time.time()\n", + "\n", + "gpu_array_back = cp.array(cpu_array)\n", + "cp.cuda.Stream.null.synchronize()\n", + "gpu_back_time = time.time()\n", + "\n", + "# Compare values on GPU\n", + "gpu_consistent = cp.allclose(gpu_array, gpu_array_back)\n", + "cp.cuda.Stream.null.synchronize()\n", + "gpu_consistent_time = time.time()\n", + "\n", + "# Compare values on CPU\n", + "cpu_consistent = np.allclose(gpu_array.get(), gpu_array_back.get())\n", + "cp.cuda.Stream.null.synchronize()\n", + "cpu_consistent_time = time.time()\n", + "\n", + "print(f\"Time to init in GUP: {gpu_time - start_time:.6f} seconds\")\n", + "print(f\"Time to transfer from GPU to CPU: {cpu_time - gpu_time:.6f} seconds\")\n", + "print(f\"Time to transfer from CPU to GPU: {gpu_back_time - cpu_time:.6f} seconds\")\n", + "print(f\"Time to check consistency on GPU: {gpu_consistent_time - gpu_back_time:.6f} seconds\")\n", + "print(f\"Time to check consistency on CPU: {cpu_consistent_time - gpu_consistent_time:.6f} seconds\")\n", + "\n", + "print(f\"Via GPU - transfer consistency: {gpu_consistent}\") # Should print True\n", + "print(f\"Via CPU - transfer consistency: {cpu_consistent}\") # Should print True" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Practice Problems\n", + "\n", + "**Advanced Slicing:**\n", + "\n", + "Given a 4x4 matrix, extract:\n", + "* The main diagonal.\n", + "* The lower-left 2x2 block.\n", + "\n", + "**Array Manipulation Challenge:**\n", + "\n", + "Create an array of size 20 with random integers between 1 and 100. Reshape the array into a 5x4 matrix and sort each row.\n", + "\n", + "**Data Analysis:**\n", + "\n", + "Given two 1D arrays representing time (in hours) and distance (in km) from a running event, calculate the average speed at each time point using NumPy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Vectorization Problem\n", + "\n", + "The following python code uses loops to compute euclidean distances between two sets of points using the pythagorean theorem. Rewrite this using numpy wituhout using any loops. \n", + "\n", + "Remember that ** is exponent (not ^), and you can use np.sqrt rather than math.sqrt in your vectorized code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "# Two sets of 2D points (x, y)\n", + "points_a = [[1, 2], [3, 4], [5, 6]]\n", + "points_b = [[7, 8], [9, 10], [11, 12]]\n", + "\n", + "# List to store the results\n", + "distances = []\n", + "\n", + "# Calculate Euclidean distance between corresponding points\n", + "for a, b in zip(points_a, points_b):\n", + " distance = math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2)\n", + " distances.append(distance)\n", + "\n", + "print(\"Distances (with loops):\", distances)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Your vectorized solution here\n", + "import numpy as np\n", + "\n", + "points_a = np.array(points_a)\n", + "...\n", + "\n", + "\n", + "print(\"Distances (vectorized):\", distances)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Challenge Problem\n", + "**Game of life:**\n", + "\n", + "This is a very involved project... implement Conway's Game of Life (https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) in numpy. Create a board of 20x20 cells with a randomized values of 0 or 1. \"1\" is alive, and \"0\" is dead.\n", + "\n", + "Iteratively apply the rules of GoL to increment the state of the board:\n", + "* Any live cell with fewer than two live neighbours dies, as if by underpopulation.\n", + "* Any live cell with two or three live neighbours lives on to the next generation.\n", + "* Any live cell with more than three live neighbours dies, as if by overpopulation.\n", + "* Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.\n", + "\n", + "You can print the board at each step to see its progression, or you can plot it as a heatmap, or some other method to visualize it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/P-Project-Sudoku_Solver.ipynb b/P-Project-Sudoku_Solver.ipynb new file mode 100644 index 0000000..417f00b --- /dev/null +++ b/P-Project-Sudoku_Solver.ipynb @@ -0,0 +1,421 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Project: Sudoku Solver\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "Write a program to solve a suduku puzzle. It should accept a list of 81 values, with '.' representing unknown numbers, and return a completed puzzle. Print an error message of a solution cannot be found. \n", + "\n", + "## Sudoku Rules\n", + "The objective is to fill a 9x9 grid so that each cell contains a digit from 1 to 9, following these rules:\n", + "* Unique in Row: Each row must contain the digits 1 to 9 without any repetition.\n", + "* Unique in Column: Each column must also contain the digits 1 to 9 without repetition.\n", + "* Unique in 3x3 Sub-grid: The grid is divided into nine 3x3 sub-grids (also known as \"boxes\" or \"regions\"). Each sub-grid must contain the digits 1 to 9, with no repeats.\n", + "\n", + "In every Sudoku puzzle:\n", + "* Some cells are pre-filled with numbers to give clues and create a unique solution.\n", + "* The player can only place numbers in empty cells.\n", + "* The puzzle is solved when every cell is filled and all the rules are satisfied.\n", + "\n", + "Additional Points:\n", + "* A valid Sudoku puzzle will have only one solution.\n", + "* The puzzle’s difficulty depends on the number and placement of given numbers, which influences the logical techniques needed to solve it.\n", + "\n", + "## Strategy\n", + "This is a search problem, but we need to use optimizations to reduce the search space so it doesn't take too long to solve each problem!\n", + "\n", + "**Search** - starting at one corner and stepping through cell by cell, place a number, and then check that it is valid. E.g. if you place a 3, check that there are no threes in the same row, column, and square. If a conflict is found, try another number. If none of 1-9 are without conflicts, step back to the previous cell you placed a number in and increment it. This strategy can take a long time to complete as there are many combinations of numbers to try, but is a path to solving every possible puzzle. We may need to introduce optimizations to reduce time required to find a solution. \n", + "\n", + "**Checking cells with fewest number of possibilities first** - compute a list of possible values for all unknown cells and start checking values of cells with the fewest possible values first. \n", + "\n", + "**Look for naked singles and hidden singles** - A naked single is a cell that only has one possible solution based on the values of cells in it's row, column, and square. A hidden single is a cell that has multiple possibilities, but one of it's possibilities is not possible for any other cell in its row, column, or square, so it must belong to this cell.\n", + "\n", + "**Set theory optimizations** - E.g. the Phistomefel Ring can be used in addition to the rows, columns, squares checks to ruduce numbers of possibilities for cells. \n", + "\n", + "### Search Strategies\n", + "There are a number of strategies for searching potential solution space for a problem. \n", + "\n", + "* Uninformed Search - when we are searching blindly for the goal.\n", + " * Bredth First\n", + " * Depth First\n", + " * Uniform Cost Search\n", + "* Informed Search - when we have a heuristic to tell is how close a state/node is to the goal.\n", + " * Greedy/Best-First Search\n", + " * A* Search\n", + " * Graph Search\n", + "\n", + "**Bredth First** explores all nodes at the present depth before exploring deeper and is helpful when you're trying to find the shortest path to something, but can be memory intensive.\n", + "* A\n", + "* B\n", + "* C\n", + "* D\n", + "\n", + "For this sudoku problem, a bredth first search would be akin to making copies of the puzzle for each possibility for a cell, and then making copies of each of those copies for each possibility for the next cell. This would result in us having as many as 9^(81-17) copies of the puzzle in memory:\n", + "* 81 being the total number of cells\n", + "* 17 being the minimum number of cells required to create a valid sudoku puzzle\n", + "* 9 being the number of possibilities for each cell\n", + "\n", + "**Depth First** is helpful when we need depth to test/eliminate possibilities and minimizes memory use. It may not work if the search space is very deep. \n", + "* A\n", + " * AA\n", + " * AAA\n", + " * AAB\n", + "\n", + "A depth first approach would result in having a maximum of only 81-17 copies of the puzzle in memory and works better for sudoku.\n", + "\n", + "**Greedy Search** could be used to explore nodes that are the most constrained first in order to reduce the search space.\n", + "\n", + "**Heuristics for Informed Search**\n", + "* Minimum Remaining Values (MRV) Heuristic - solve cells that have the fewest possibilities first\n", + "* Degree Heuristic - work on cells that have the most impact on empty cells in the same row/column/sub-grid\n", + "* Least Constraining Value (LCV) Heuristic - try values for cells that impose the least restriction on other cells to avoid conflicts.\n", + "\n", + "**Constraint propagation** - whenever a cell is solved, it removes that number as a possibility from all cells in the same row, column, and sub-grid. Constraint propagation is often used in tandem with backtracking, as it can simplify the puzzle and reduce the search space\n", + "\n", + "\n", + "## Sample Problems\n", + "There's a big dataset of sample problems here: https://www.kaggle.com/datasets/radcliffe/3-million-sudoku-puzzles-with-ratings\n", + "\n", + "A sample problem is a list of numbers and '.', with '.' being any value that we need to find. For example:\n", + "\n", + " ...81.....2........1.9..7...7..25.934.2............5...975.....563.....4......68.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "...81.....2........1.9..7...7..25.934.2............5...975.....563.....4......68.\n", + "['.', '.', '.', '8', '1', '.', '.', '.', '.']\n", + "['.', '2', '.', '.', '.', '.', '.', '.', '.']\n", + "['.', '1', '.', '9', '.', '.', '7', '.', '.']\n", + "['.', '7', '.', '.', '2', '5', '.', '9', '3']\n", + "['4', '.', '2', '.', '.', '.', '.', '.', '.']\n", + "['.', '.', '.', '.', '.', '.', '5', '.', '.']\n", + "['.', '9', '7', '5', '.', '.', '.', '.', '.']\n", + "['5', '6', '3', '.', '.', '.', '.', '.', '4']\n", + "['.', '.', '.', '.', '.', '.', '6', '8', '.']\n", + "\n", + "1..5.37..6.3..8.9......98...1.......8761..........6...........7.8.9.76.47...6.312\n", + "['1', '.', '.', '5', '.', '3', '7', '.', '.']\n", + "['6', '.', '3', '.', '.', '8', '.', '9', '.']\n", + "['.', '.', '.', '.', '.', '9', '8', '.', '.']\n", + "['.', '1', '.', '.', '.', '.', '.', '.', '.']\n", + "['8', '7', '6', '1', '.', '.', '.', '.', '.']\n", + "['.', '.', '.', '.', '.', '6', '.', '.', '.']\n", + "['.', '.', '.', '.', '.', '.', '.', '.', '7']\n", + "['.', '8', '.', '9', '.', '7', '6', '.', '4']\n", + "['7', '.', '.', '.', '6', '.', '3', '1', '2']\n", + "\n", + "..5...74.3..6...19.....1..5...7...2.9....58..7..84......3.9...2.9.4.....8.....1.3\n", + "['.', '.', '5', '.', '.', '.', '7', '4', '.']\n", + "['3', '.', '.', '6', '.', '.', '.', '1', '9']\n", + "['.', '.', '.', '.', '.', '1', '.', '.', '5']\n", + "['.', '.', '.', '7', '.', '.', '.', '2', '.']\n", + "['9', '.', '.', '.', '.', '5', '8', '.', '.']\n", + "['7', '.', '.', '8', '4', '.', '.', '.', '.']\n", + "['.', '.', '3', '.', '9', '.', '.', '.', '2']\n", + "['.', '9', '.', '4', '.', '.', '.', '.', '.']\n", + "['8', '.', '.', '.', '.', '.', '1', '.', '3']\n", + "\n", + "........5.2...9....9..2...373..481.....36....58....4...1...358...42.......978...2\n", + "['.', '.', '.', '.', '.', '.', '.', '.', '5']\n", + "['.', '2', '.', '.', '.', '9', '.', '.', '.']\n", + "['.', '9', '.', '.', '2', '.', '.', '.', '3']\n", + "['7', '3', '.', '.', '4', '8', '1', '.', '.']\n", + "['.', '.', '.', '3', '6', '.', '.', '.', '.']\n", + "['5', '8', '.', '.', '.', '.', '4', '.', '.']\n", + "['.', '1', '.', '.', '.', '3', '5', '8', '.']\n", + "['.', '.', '4', '2', '.', '.', '.', '.', '.']\n", + "['.', '.', '9', '7', '8', '.', '.', '.', '2']\n", + "\n" + ] + } + ], + "source": [ + "samples = [\n", + " '...81.....2........1.9..7...7..25.934.2............5...975.....563.....4......68.',\n", + " '1..5.37..6.3..8.9......98...1.......8761..........6...........7.8.9.76.47...6.312',\n", + " '..5...74.3..6...19.....1..5...7...2.9....58..7..84......3.9...2.9.4.....8.....1.3',\n", + " '........5.2...9....9..2...373..481.....36....58....4...1...358...42.......978...2',\n", + "]\n", + "for sample in samples:\n", + " print(sample)\n", + " sample = list(sample)\n", + " # Convert it to a 2D list\n", + " puzzle = [sample[i:i+9] for i in range(0, 81, 9)]\n", + " for row in puzzle:\n", + " print(row)\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example code using plain python\n", + "Using plain python loops and lists, we can step through rows and columns using for loops pretty easily, but things quickly get complex when looking at columns and the squares:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cell 0 0 {'5', '.'} {'7', '5', '.'} {'2', '9', '.'}\n", + "cell 0 1 {'5', '.'} {'.', '9', '8', '1', '3', '2'} {'2', '9', '.'}\n", + "cell 0 2 {'5', '.'} {'9', '4', '.'} {'2', '9', '.'}\n", + "cell 0 3 {'5', '.'} {'7', '2', '.', '3'} {'9', '2', '.'}\n", + "cell 0 4 {'5', '.'} {'6', '.', '8', '4', '2'} {'9', '2', '.'}\n", + "cell 0 5 {'5', '.'} {'9', '.', '3', '8'} {'9', '2', '.'}\n", + "cell 0 6 {'5', '.'} {'1', '4', '.', '5'} {'5', '.', '3'}\n", + "cell 0 7 {'5', '.'} {'.', '8'} {'5', '.', '3'}\n", + "cell 1 0 {'2', '9', '.'} {'7', '5', '.'} {'2', '9', '.'}\n", + "cell 1 2 {'2', '9', '.'} {'9', '4', '.'} {'2', '9', '.'}\n", + "cell 1 3 {'2', '9', '.'} {'7', '2', '.', '3'} {'9', '2', '.'}\n", + "cell 1 4 {'2', '9', '.'} {'6', '.', '8', '4', '2'} {'9', '2', '.'}\n", + "cell 1 6 {'2', '9', '.'} {'1', '4', '.', '5'} {'5', '.', '3'}\n", + "cell 1 7 {'2', '9', '.'} {'.', '8'} {'5', '.', '3'}\n", + "cell 1 8 {'2', '9', '.'} {'2', '.', '5', '3'} {'5', '.', '3'}\n", + "cell 2 0 {'9', '2', '.', '3'} {'7', '5', '.'} {'2', '9', '.'}\n", + "cell 2 2 {'9', '2', '.', '3'} {'9', '4', '.'} {'2', '9', '.'}\n", + "cell 2 3 {'9', '2', '.', '3'} {'7', '2', '.', '3'} {'9', '2', '.'}\n", + "cell 2 5 {'9', '2', '.', '3'} {'9', '.', '3', '8'} {'9', '2', '.'}\n", + "cell 2 6 {'9', '2', '.', '3'} {'1', '4', '.', '5'} {'5', '.', '3'}\n", + "cell 2 7 {'9', '2', '.', '3'} {'.', '8'} {'5', '.', '3'}\n", + "cell 3 2 {'8', '1', '4', '3', '7', '.'} {'9', '4', '.'} {'.', '8', '3', '7', '5'}\n", + "cell 3 3 {'8', '1', '4', '3', '7', '.'} {'7', '2', '.', '3'} {'6', '8', '4', '3', '.'}\n", + "cell 3 7 {'8', '1', '4', '3', '7', '.'} {'.', '8'} {'1', '4', '.'}\n", + "cell 3 8 {'8', '1', '4', '3', '7', '.'} {'2', '.', '5', '3'} {'1', '4', '.'}\n", + "cell 4 0 {'6', '.', '3'} {'7', '5', '.'} {'.', '8', '3', '7', '5'}\n", + "cell 4 1 {'6', '.', '3'} {'.', '9', '8', '1', '3', '2'} {'.', '8', '3', '7', '5'}\n", + "cell 4 2 {'6', '.', '3'} {'9', '4', '.'} {'.', '8', '3', '7', '5'}\n", + "cell 4 5 {'6', '.', '3'} {'9', '.', '3', '8'} {'6', '8', '4', '3', '.'}\n", + "cell 4 6 {'6', '.', '3'} {'1', '4', '.', '5'} {'1', '4', '.'}\n", + "cell 4 7 {'6', '.', '3'} {'.', '8'} {'1', '4', '.'}\n", + "cell 4 8 {'6', '.', '3'} {'2', '.', '5', '3'} {'1', '4', '.'}\n", + "cell 5 2 {'4', '.', '5', '8'} {'9', '4', '.'} {'.', '8', '3', '7', '5'}\n", + "cell 5 3 {'4', '.', '5', '8'} {'7', '2', '.', '3'} {'6', '8', '4', '3', '.'}\n", + "cell 5 4 {'4', '.', '5', '8'} {'6', '.', '8', '4', '2'} {'6', '8', '4', '3', '.'}\n", + "cell 5 5 {'4', '.', '5', '8'} {'9', '.', '3', '8'} {'6', '8', '4', '3', '.'}\n", + "cell 5 7 {'4', '.', '5', '8'} {'.', '8'} {'1', '4', '.'}\n", + "cell 5 8 {'4', '.', '5', '8'} {'2', '.', '5', '3'} {'1', '4', '.'}\n", + "cell 6 0 {'.', '8', '1', '3', '5'} {'7', '5', '.'} {'1', '4', '.', '9'}\n", + "cell 6 2 {'.', '8', '1', '3', '5'} {'9', '4', '.'} {'1', '4', '.', '9'}\n", + "cell 6 3 {'.', '8', '1', '3', '5'} {'7', '2', '.', '3'} {'.', '8', '3', '7', '2'}\n", + "cell 6 4 {'.', '8', '1', '3', '5'} {'6', '.', '8', '4', '2'} {'.', '8', '3', '7', '2'}\n", + "cell 6 8 {'.', '8', '1', '3', '5'} {'2', '.', '5', '3'} {'2', '.', '5', '8'}\n", + "cell 7 0 {'2', '4', '.'} {'7', '5', '.'} {'1', '4', '.', '9'}\n", + "cell 7 1 {'2', '4', '.'} {'.', '9', '8', '1', '3', '2'} {'1', '4', '.', '9'}\n", + "cell 7 4 {'2', '4', '.'} {'6', '.', '8', '4', '2'} {'.', '8', '3', '7', '2'}\n", + "cell 7 5 {'2', '4', '.'} {'9', '.', '3', '8'} {'.', '8', '3', '7', '2'}\n", + "cell 7 6 {'2', '4', '.'} {'1', '4', '.', '5'} {'2', '.', '5', '8'}\n", + "cell 7 7 {'2', '4', '.'} {'.', '8'} {'2', '.', '5', '8'}\n", + "cell 7 8 {'2', '4', '.'} {'2', '.', '5', '3'} {'2', '.', '5', '8'}\n", + "cell 8 0 {'.', '9', '8', '7', '2'} {'7', '5', '.'} {'1', '4', '.', '9'}\n", + "cell 8 1 {'.', '9', '8', '7', '2'} {'.', '9', '8', '1', '3', '2'} {'1', '4', '.', '9'}\n", + "cell 8 5 {'.', '9', '8', '7', '2'} {'9', '.', '3', '8'} {'.', '8', '3', '7', '2'}\n", + "cell 8 6 {'.', '9', '8', '7', '2'} {'1', '4', '.', '5'} {'2', '.', '5', '8'}\n", + "cell 8 7 {'.', '9', '8', '7', '2'} {'.', '8'} {'2', '.', '5', '8'}\n" + ] + } + ], + "source": [ + "# Example in plain python using loops and lists\n", + "for row_num, row in enumerate(puzzle):\n", + " for col_num, cell in enumerate(row):\n", + " if cell != '.':\n", + " continue\n", + " row_set = set(row)\n", + " col_set = set([puzzle[i][col_num] for i in range(9)])\n", + " row_lower, row_upper = row_num//3*3, row_num//3*3+3\n", + " col_lower, col_upper = col_num//3*3, col_num//3*3+3\n", + " square_set = set([puzzle[i][j] for i in range(row_lower, row_upper) for j in range(col_lower, col_upper)])\n", + "\n", + " print('cell', row_num, col_num, row_set, col_set, square_set)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example code using Numpy\n", + "For problems like this, numpy has a lot of advantages over regular python. We can still use loops to step through cells in the puzzle if we want, but many opereations can be vectorized to reduce the need for loops, and numpy array slicing makes it easier to select a row, column, or a square from the array than using plain python lists. " + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cell 0 0 [0 5] [0 5 7] [0 2 9]\n", + "cell 0 1 [0 5] [0 1 2 3 8 9] [0 2 9]\n", + "cell 0 2 [0 5] [0 4 9] [0 2 9]\n", + "cell 0 3 [0 5] [0 2 3 7] [0 2 9]\n", + "cell 0 4 [0 5] [0 2 4 6 8] [0 2 9]\n", + "cell 0 5 [0 5] [0 3 8 9] [0 2 9]\n", + "cell 0 6 [0 5] [0 1 4 5] [0 3 5]\n", + "cell 0 7 [0 5] [0 8] [0 3 5]\n", + "cell 1 0 [0 2 9] [0 5 7] [0 2 9]\n", + "cell 1 2 [0 2 9] [0 4 9] [0 2 9]\n", + "cell 1 3 [0 2 9] [0 2 3 7] [0 2 9]\n", + "cell 1 4 [0 2 9] [0 2 4 6 8] [0 2 9]\n", + "cell 1 6 [0 2 9] [0 1 4 5] [0 3 5]\n", + "cell 1 7 [0 2 9] [0 8] [0 3 5]\n", + "cell 1 8 [0 2 9] [0 2 3 5] [0 3 5]\n", + "cell 2 0 [0 2 3 9] [0 5 7] [0 2 9]\n", + "cell 2 2 [0 2 3 9] [0 4 9] [0 2 9]\n", + "cell 2 3 [0 2 3 9] [0 2 3 7] [0 2 9]\n", + "cell 2 5 [0 2 3 9] [0 3 8 9] [0 2 9]\n", + "cell 2 6 [0 2 3 9] [0 1 4 5] [0 3 5]\n", + "cell 2 7 [0 2 3 9] [0 8] [0 3 5]\n", + "cell 3 2 [0 1 3 4 7 8] [0 4 9] [0 3 5 7 8]\n", + "cell 3 3 [0 1 3 4 7 8] [0 2 3 7] [0 3 4 6 8]\n", + "cell 3 7 [0 1 3 4 7 8] [0 8] [0 1 4]\n", + "cell 3 8 [0 1 3 4 7 8] [0 2 3 5] [0 1 4]\n", + "cell 4 0 [0 3 6] [0 5 7] [0 3 5 7 8]\n", + "cell 4 1 [0 3 6] [0 1 2 3 8 9] [0 3 5 7 8]\n", + "cell 4 2 [0 3 6] [0 4 9] [0 3 5 7 8]\n", + "cell 4 5 [0 3 6] [0 3 8 9] [0 3 4 6 8]\n", + "cell 4 6 [0 3 6] [0 1 4 5] [0 1 4]\n", + "cell 4 7 [0 3 6] [0 8] [0 1 4]\n", + "cell 4 8 [0 3 6] [0 2 3 5] [0 1 4]\n", + "cell 5 2 [0 4 5 8] [0 4 9] [0 3 5 7 8]\n", + "cell 5 3 [0 4 5 8] [0 2 3 7] [0 3 4 6 8]\n", + "cell 5 4 [0 4 5 8] [0 2 4 6 8] [0 3 4 6 8]\n", + "cell 5 5 [0 4 5 8] [0 3 8 9] [0 3 4 6 8]\n", + "cell 5 7 [0 4 5 8] [0 8] [0 1 4]\n", + "cell 5 8 [0 4 5 8] [0 2 3 5] [0 1 4]\n", + "cell 6 0 [0 1 3 5 8] [0 5 7] [0 1 4 9]\n", + "cell 6 2 [0 1 3 5 8] [0 4 9] [0 1 4 9]\n", + "cell 6 3 [0 1 3 5 8] [0 2 3 7] [0 2 3 7 8]\n", + "cell 6 4 [0 1 3 5 8] [0 2 4 6 8] [0 2 3 7 8]\n", + "cell 6 8 [0 1 3 5 8] [0 2 3 5] [0 2 5 8]\n", + "cell 7 0 [0 2 4] [0 5 7] [0 1 4 9]\n", + "cell 7 1 [0 2 4] [0 1 2 3 8 9] [0 1 4 9]\n", + "cell 7 4 [0 2 4] [0 2 4 6 8] [0 2 3 7 8]\n", + "cell 7 5 [0 2 4] [0 3 8 9] [0 2 3 7 8]\n", + "cell 7 6 [0 2 4] [0 1 4 5] [0 2 5 8]\n", + "cell 7 7 [0 2 4] [0 8] [0 2 5 8]\n", + "cell 7 8 [0 2 4] [0 2 3 5] [0 2 5 8]\n", + "cell 8 0 [0 2 7 8 9] [0 5 7] [0 1 4 9]\n", + "cell 8 1 [0 2 7 8 9] [0 1 2 3 8 9] [0 1 4 9]\n", + "cell 8 5 [0 2 7 8 9] [0 3 8 9] [0 2 3 7 8]\n", + "cell 8 6 [0 2 7 8 9] [0 1 4 5] [0 2 5 8]\n", + "cell 8 7 [0 2 7 8 9] [0 8] [0 2 5 8]\n" + ] + } + ], + "source": [ + "# Example in numpy using numpy arrays and broadcasting/vectorization\n", + "import numpy as np\n", + "puzzle = '........5.2...9....9..2...373..481.....36....58....4...1...358...42.......978...2'\n", + "puzzle = puzzle.replace('.', '0')\n", + "puzzle = np.array(list(puzzle)).astype(np.int8).reshape(9, 9)\n", + "\n", + "for row_num in range(9):\n", + " for col_num in range(9):\n", + " cell = puzzle[row_num, col_num]\n", + " if cell != 0:\n", + " continue\n", + " row_set = np.unique(puzzle[row_num])\n", + " col_set = np.unique(puzzle[:, col_num])\n", + " row_lower, row_upper = row_num//3*3, row_num//3*3+3\n", + " col_lower, col_upper = col_num//3*3, col_num//3*3+3\n", + " square_set = np.unique(puzzle[row_lower:row_upper, col_lower:col_upper])\n", + "\n", + " print('cell', row_num, col_num, row_set, col_set, square_set)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# And if we wanted to get a little more weird with numpy, we could make a 3d array\n", + "# having boolean values for possible values of each cell, and a shape of (9, 9, 9):\n", + "import numpy as np\n", + "puzzle = '........5.2...9....9..2...373..481.....36....58....4...1...358...42.......978...2'\n", + "puzzle = puzzle.replace('.', '0')\n", + "puzzle = np.array(list(puzzle)).astype(np.int8).reshape(9, 9)\n", + "possible_values = np.ones((9, 9, 9), dtype=bool)\n", + "\n", + "for row_num in range(9):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Recursion\n", + "A side effect of using search, or optimized search, to solve a sudoku puzzle is that we require\n", + "recursion to evaluate a changing board while tracking our progress and what has been tried so far. \n", + "\n", + "### Stack based approach \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recursive function approach" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/P-Project_Solutions/P-Sudoku_Solver.ipynb b/P-Project_Solutions/P-Sudoku_Solver.ipynb new file mode 100644 index 0000000..d9ece76 --- /dev/null +++ b/P-Project_Solutions/P-Sudoku_Solver.ipynb @@ -0,0 +1,258 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "import copy\n", + "\n", + "SAMPLES = [\n", + " '...81.....2........1.9..7...7..25.934.2............5...975.....563.....4......68.',\n", + " '1..5.37..6.3..8.9......98...1.......8761..........6...........7.8.9.76.47...6.312',\n", + " '..5...74.3..6...19.....1..5...7...2.9....58..7..84......3.9...2.9.4.....8.....1.3',\n", + " '........5.2...9....9..2...373..481.....36....58....4...1...358...42.......978...2',\n", + "]\n", + "NUMBERS = '123456789'" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def checkIfValid(puzzle):\n", + " '''Check rows for duplicates,\n", + " Check cols for duplicates,\n", + " Check boxes for duplicates'''\n", + " # Check rows\n", + " for n in range(9):\n", + " row = puzzle[n]\n", + " if len(row) != len(set(row)):\n", + " return False\n", + " # Check cols\n", + " for n in range(9):\n", + " col = [puzzle[i][n] for i in range(9)]\n", + " if len(col) != len(set(col)):\n", + " return False\n", + " # Check boxes\n", + " for i in range(0, 9, 3):\n", + " for j in range(0, 9, 3):\n", + " box = [puzzle[i + x][j + y] for x in range(3) for y in range(3)]\n", + " if len(box) != len(set(box)):\n", + " return False\n", + " return True" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def mostBasicDepthSearch(parent_puzzle, depth=0):\n", + " '''Solve the puzzle'''\n", + " # Make a unique copy of the puzzle so we don't modify paren't version\n", + " puzzle = copy.deepcopy(parent_puzzle)\n", + "\n", + " # Find the first cell that is empty\n", + " for row_num, row in enumerate(parent_puzzle):\n", + " for col_num, cell in enumerate(row):\n", + " # Skip known cells\n", + " if cell != 0:\n", + " continue\n", + " \n", + " row_set = set(row)\n", + " col_set = set([puzzle[i][col_num] for i in range(9)])\n", + " row_lower, row_upper = row_num//3*3, row_num//3*3+3\n", + " col_lower, col_upper = col_num//3*3, col_num//3*3+3\n", + " square_set = set([puzzle[i][j] for i in range(row_lower, row_upper) for j in range(col_lower, col_upper)])\n", + "\n", + " # Check for missing numbers\n", + " combined_set = row_set.union(col_set).union(square_set)\n", + " missing_set = set(NUMBERS).difference(combined_set)\n", + "\n", + " # Try each valid number\n", + " for number in missing_set:\n", + " puzzle[row_num][col_num] = number\n", + " child_puzzle = mostBasicDepthSearch(puzzle, depth+1)\n", + " if child_puzzle:\n", + " return child_puzzle\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def doTheThing(parent_puzzle, depth=0):\n", + " '''Solve the puzzle'''\n", + " # Make a unique copy of the puzzle so we don't modify paren't version\n", + " puzzle = copy.deepcopy(parent_puzzle)\n", + "\n", + " # Compute the set of all possible numbers for each cell\n", + " possible_numbers = [[set() for _ in range(9)] for _ in range(9)]\n", + " for row_num, row in enumerate(parent_puzzle):\n", + " for col_num, cell in enumerate(row):\n", + " # Skip known cells\n", + " if cell != 0:\n", + " continue\n", + " \n", + " row_set = set(row)\n", + " col_set = set([puzzle[i][col_num] for i in range(9)])\n", + " row_lower, row_upper = row_num//3*3, row_num//3*3+3\n", + " col_lower, col_upper = col_num//3*3, col_num//3*3+3\n", + " square_set = set([puzzle[i][j] for i in range(row_lower, row_upper) \n", + " for j in range(col_lower, col_upper)])\n", + "\n", + " # Check for missing numbers\n", + " combined_set = row_set.union(col_set).union(square_set)\n", + " missing_set = set(NUMBERS).difference(combined_set)\n", + " possible_numbers[row_num][col_num] = missing_set\n", + " \n", + " # Check for naked singles\n", + " for row_num, row in enumerate(possible_numbers):\n", + " for col_num, possible in enumerate(row):\n", + " if len(possible) == 1:\n", + " # We found a naked single\n", + " puzzle[row_num][col_num] = possible.pop()\n", + "\n", + " # Check for hidden singles\n", + " for row_num, row in enumerate(possible_numbers):\n", + " for col_num, possible in enumerate(row):\n", + " # Check each number to see if it is not possible for each of...\n", + " for number in possible:\n", + " # Check the row\n", + " row_set = set.union(*[possible_numbers[row_num][i] \n", + " for i in range(9) if i != col_num])\n", + " if number not in row_set:\n", + " puzzle[row_num][col_num] = number\n", + " break\n", + " # Check the col\n", + " col_set = set.union(*[possible_numbers[i][col_num] \n", + " for i in range(9) if i != row_num])\n", + " if number not in col_set:\n", + " puzzle[row_num][col_num] = number\n", + " break\n", + " # Check the square\n", + " row_lower, row_upper = row_num//3*3, row_num//3*3+3\n", + " col_lower, col_upper = col_num//3*3, col_num//3*3+3\n", + " square_set = set.union(*[possible_numbers[i][j] \n", + " for i in range(row_lower, row_upper) \n", + " for j in range(col_lower, col_upper) \n", + " if i != row_num and j != col_num])\n", + " if number not in square_set:\n", + " puzzle[row_num][col_num] = number\n", + " break\n", + "\n", + " # Make a guess for a cell with the fewest possible numbers\n", + " min_possible = 10\n", + " min_loc = None\n", + " for row_num, row in enumerate(possible_numbers):\n", + " for col_num, possible in enumerate(row):\n", + " if len(possible) == 0:\n", + " continue\n", + " if len(possible) < min_possible:\n", + " min_possible = len(possible)\n", + " min_loc = (row_num, col_num)\n", + "\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "...81.....2........1.9..7...7..25.934.2............5...975.....563.....4......68.\n", + "[0, 0, 0, 8, 1, 0, 0, 0, 0]\n", + "[0, 2, 0, 0, 0, 0, 0, 0, 0]\n", + "[0, 1, 0, 9, 0, 0, 7, 0, 0]\n", + "[0, 7, 0, 0, 2, 5, 0, 9, 3]\n", + "[4, 0, 2, 0, 0, 0, 0, 0, 0]\n", + "[0, 0, 0, 0, 0, 0, 5, 0, 0]\n", + "[0, 9, 7, 5, 0, 0, 0, 0, 0]\n", + "[5, 6, 3, 0, 0, 0, 0, 0, 4]\n", + "[0, 0, 0, 0, 0, 0, 6, 8, 0]\n", + "\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[15], line 10\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(row)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28mprint\u001b[39m()\n\u001b[0;32m---> 10\u001b[0m solution \u001b[38;5;241m=\u001b[39m \u001b[43mmostBasicDepthSearch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpuzzle\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m row \u001b[38;5;129;01min\u001b[39;00m solution:\n\u001b[1;32m 12\u001b[0m \u001b[38;5;28mprint\u001b[39m(row)\n", + "Cell \u001b[0;32mIn[14], line 26\u001b[0m, in \u001b[0;36mmostBasicDepthSearch\u001b[0;34m(parent_puzzle, depth)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m number \u001b[38;5;129;01min\u001b[39;00m missing_set:\n\u001b[1;32m 25\u001b[0m puzzle[row_num][col_num] \u001b[38;5;241m=\u001b[39m number\n\u001b[0;32m---> 26\u001b[0m child_puzzle \u001b[38;5;241m=\u001b[39m \u001b[43mmostBasicDepthSearch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpuzzle\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdepth\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m child_puzzle:\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m child_puzzle\n", + "Cell \u001b[0;32mIn[14], line 26\u001b[0m, in \u001b[0;36mmostBasicDepthSearch\u001b[0;34m(parent_puzzle, depth)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m number \u001b[38;5;129;01min\u001b[39;00m missing_set:\n\u001b[1;32m 25\u001b[0m puzzle[row_num][col_num] \u001b[38;5;241m=\u001b[39m number\n\u001b[0;32m---> 26\u001b[0m child_puzzle \u001b[38;5;241m=\u001b[39m \u001b[43mmostBasicDepthSearch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpuzzle\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdepth\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m child_puzzle:\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m child_puzzle\n", + " \u001b[0;31m[... skipping similar frames: mostBasicDepthSearch at line 26 (48 times)]\u001b[0m\n", + "Cell \u001b[0;32mIn[14], line 26\u001b[0m, in \u001b[0;36mmostBasicDepthSearch\u001b[0;34m(parent_puzzle, depth)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m number \u001b[38;5;129;01min\u001b[39;00m missing_set:\n\u001b[1;32m 25\u001b[0m puzzle[row_num][col_num] \u001b[38;5;241m=\u001b[39m number\n\u001b[0;32m---> 26\u001b[0m child_puzzle \u001b[38;5;241m=\u001b[39m \u001b[43mmostBasicDepthSearch\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpuzzle\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdepth\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m child_puzzle:\n\u001b[1;32m 28\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m child_puzzle\n", + "Cell \u001b[0;32mIn[14], line 4\u001b[0m, in \u001b[0;36mmostBasicDepthSearch\u001b[0;34m(parent_puzzle, depth)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m'''Solve the puzzle'''\u001b[39;00m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;66;03m# Make a unique copy of the puzzle so we don't modify paren't version\u001b[39;00m\n\u001b[0;32m----> 4\u001b[0m puzzle \u001b[38;5;241m=\u001b[39m \u001b[43mcopy\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdeepcopy\u001b[49m\u001b[43m(\u001b[49m\u001b[43mparent_puzzle\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;66;03m# Find the first cell that is empty\u001b[39;00m\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m row_num, row \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(parent_puzzle):\n", + "File \u001b[0;32m/usr/lib/python3.12/copy.py:136\u001b[0m, in \u001b[0;36mdeepcopy\u001b[0;34m(x, memo, _nil)\u001b[0m\n\u001b[1;32m 134\u001b[0m copier \u001b[38;5;241m=\u001b[39m _deepcopy_dispatch\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;28mcls\u001b[39m)\n\u001b[1;32m 135\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m copier \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 136\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[43mcopier\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmemo\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 137\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 138\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28missubclass\u001b[39m(\u001b[38;5;28mcls\u001b[39m, \u001b[38;5;28mtype\u001b[39m):\n", + "File \u001b[0;32m/usr/lib/python3.12/copy.py:196\u001b[0m, in \u001b[0;36m_deepcopy_list\u001b[0;34m(x, memo, deepcopy)\u001b[0m\n\u001b[1;32m 194\u001b[0m append \u001b[38;5;241m=\u001b[39m y\u001b[38;5;241m.\u001b[39mappend\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m x:\n\u001b[0;32m--> 196\u001b[0m append(\u001b[43mdeepcopy\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmemo\u001b[49m\u001b[43m)\u001b[49m)\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m y\n", + "File \u001b[0;32m/usr/lib/python3.12/copy.py:136\u001b[0m, in \u001b[0;36mdeepcopy\u001b[0;34m(x, memo, _nil)\u001b[0m\n\u001b[1;32m 134\u001b[0m copier \u001b[38;5;241m=\u001b[39m _deepcopy_dispatch\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;28mcls\u001b[39m)\n\u001b[1;32m 135\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m copier \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 136\u001b[0m y \u001b[38;5;241m=\u001b[39m \u001b[43mcopier\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmemo\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 137\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 138\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28missubclass\u001b[39m(\u001b[38;5;28mcls\u001b[39m, \u001b[38;5;28mtype\u001b[39m):\n", + "File \u001b[0;32m/usr/lib/python3.12/copy.py:196\u001b[0m, in \u001b[0;36m_deepcopy_list\u001b[0;34m(x, memo, deepcopy)\u001b[0m\n\u001b[1;32m 194\u001b[0m append \u001b[38;5;241m=\u001b[39m y\u001b[38;5;241m.\u001b[39mappend\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m a \u001b[38;5;129;01min\u001b[39;00m x:\n\u001b[0;32m--> 196\u001b[0m \u001b[43mappend\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdeepcopy\u001b[49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmemo\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m y\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "# test_function = mostBasicDepthSearch\n", + "test_function = doTheThing\n", + "\n", + "for sample in SAMPLES:\n", + " print(sample)\n", + " sample = list(sample)\n", + " sample = [int(n) if n in NUMBERS else 0 for n in sample]\n", + " # Convert it to a 2D list\n", + " puzzle = [sample[i:i+9] for i in range(0, 81, 9)]\n", + " for row in puzzle:\n", + " print(row)\n", + " print()\n", + " solution = test_function(puzzle)\n", + " for row in solution:\n", + " print(row)\n", + " is_valid = checkIfValid(solution)\n", + " print('Valid:', is_valid)\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/R-Regex.ipynb b/R-Regex.ipynb new file mode 100644 index 0000000..7752b8b --- /dev/null +++ b/R-Regex.ipynb @@ -0,0 +1,272 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c48fc4fb", + "metadata": {}, + "source": [ + "# Section R - Regex\n", + "\n", + "Regex is a text matching language that can be used with python\n", + "* Advanced pattern matching when looking for a fixed set of characters won't help\n", + "* Matching repeating groups with specific permutations\n", + "* Matching sub-groups of patterns in a string\n", + "* Input validation - use regex to facilitate pass-lists of options/input\n", + " * email address validation\n", + " * phone number validation\n", + " * ...\n", + "* Advanced text replacement.\n", + "\n", + "Resources for learning:\n", + "* http://regex101.com – live testing with explanation\n", + "* http://pythex.org – Python-flavored regex testing\n", + "\n", + "Let's do an email input validation example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79184851", + "metadata": {}, + "outputs": [], + "source": [ + "import re\n", + "\n", + "valid_email = r'[a-zA-Z0-9_\\-.]+@[a-zA-Z0-9\\-]+.(com|org)'\n", + "print(\"What's your email address?\")\n", + "email = input()\n", + "print(\"You entered:\", email)\n", + "if re.match(valid_email, email):\n", + " print(\"This is a valid email address!\")\n", + "else:\n", + " print(\"This is NOT a valid email address!\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "9c2e04ba", + "metadata": {}, + "source": [ + "## Example regex patterns/characters\n", + "Regex uses special characters or patterns to match types of characters, whitespace, boundaries, and groups.\n", + "\n", + "* **Pattern**\n", + " * Meaning\n", + " * Example Match \n", + "* **.**\n", + " * Any character except newline\n", + " * a.b → acb, a7b \n", + "* **^ / $**\n", + " * Start / end of line\n", + " * ^Hi matches lines starting with \"Hi\" \n", + "* **\\d / \\w**\n", + " * Digit / Word char\n", + " * \\d = 0–9, \\w = a–z, A–Z, _ \n", + "* **\\s**\n", + " * Whitespace (space, tab, etc.)\t\n", + "* **+**, **\\***, **?**\n", + " * 1+ / 0+ / 0 or 1 repeats \n", + " * a+, a*, a? \n", + "* **{n}** / **{m,n}**\n", + " * Exactly n / Between m and n\n", + " * \\d{4} → 4 digits \n", + "* **[abc]**\n", + " * a, b, or c\n", + " * gr[ae]y → gray, grey \n", + "* **[^abc]**\n", + " * Not a, b, or c\n", + "* **( )**\n", + " * Grouping\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b90e4b2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello\n" + ] + } + ], + "source": [ + "# Search for a pattern in a string\n", + "m = re.search(r'\\d+', 'There are 15 cats')\n", + "print(m.group()) # '15'\n", + "\n", + "# Find all occurrences of a pattern in a string\n", + "nums = re.findall(r'\\d+', 'There are 15 cats and 7 dogs')\n", + "print(nums) # ['15', '7']\n", + "\n", + "# Substitute a pattern in a string\n", + "clean = re.sub(r'\\s+', ' ', 'Too many spaces')\n", + "print(clean) # 'Too many spaces'\n", + "\n", + "# Grouping data to pick out specific parts\n", + "m = re.match(r'(\\w+): (\\d+)', 'Age: 30')\n", + "print(m.group(1)) # 'Age'\n", + "print(m.group(2)) # '30'\n", + "\n", + "# Using flags to modify regex behavior\n", + "re.findall(r'dog', 'Dog DOG dog', flags=re.IGNORECASE)\n", + "# ['Dog', 'DOG', 'dog']" + ] + }, + { + "cell_type": "markdown", + "id": "de24bfee", + "metadata": {}, + "source": [ + "## Problem Set\n", + "It can help to copy the text to the regex101 site and play with regex there to get things to match and then move the working regex to your code here." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec3b252e", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract All Numbers From a String\n", + "text = \"In 2023, there were 150 cats and 30 dogs.\"\n", + "\n", + "# your solution here\n", + "# hint \\d+\n", + "\n", + "print(\"The numbers are:\", all_numbers)\n", + "if set(all_numbers) == {'2023', '150', '30'}:\n", + " print(\"All numbers extracted correctly!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e65cc4fe", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract All Words Starting with a Capital Letter\n", + "text = \"Alice went to Wonderland with Bob and Charlie.\"\n", + "\n", + "# your solution here\n", + "# hint \\b[A-Z][a-z]*\\b\n", + "\n", + "print(\"The capitalized words are:\", capitalized_words)\n", + "if set(capitalized_words) == {'Alice', 'Bob', 'Charlie', 'Wonderland'}:\n", + " print(\"All capitalized words extracted correctly!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e05aafe2", + "metadata": {}, + "outputs": [], + "source": [ + "# Find all words ending with 'ing'\n", + "text = \"I am singing while walking and then running.\"\n", + "\n", + "# your solution here\n", + "# hint \\b\\w+ing\\b\n", + "\n", + "print(\"The words ending with 'ing' are:\", ing_words)\n", + "if set(ing_words) == {'singing', 'walking', 'running'}:\n", + " print(\"All 'ing' words extracted correctly!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b45f29ae", + "metadata": {}, + "outputs": [], + "source": [ + "# Replace all dashes with underscores\n", + "text = \"this-is_some-kind_of-text\"\n", + "\n", + "# your solution here\n", + "# hint re.sub\n", + "\n", + "print(\"The modified text is:\", modified_text)\n", + "if modified_text == \"this_is_some_kind_of_text\":\n", + " print(\"Dashes replaced with underscores correctly!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e480a88d", + "metadata": {}, + "outputs": [], + "source": [ + "# Validate US zip codes\n", + "codes = [\"12345\", \"9876\", \"123456\"]\n", + "\n", + "# your solution here\n", + "\n", + "print(\"Valid zip codes are:\", valid_zip_codes)\n", + "if set(valid_zip_codes) == {'12345'}:\n", + " print(\"All valid zip codes extracted correctly!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd17ef9f", + "metadata": {}, + "outputs": [], + "source": [ + "# Use regex to pick the email addresses out from the following text\n", + "text = \"Contact me at test@example.com or foo.bar99@domain.co\"\n", + "\n", + "# your soultion here\n", + "\n", + "print(\"The emails are:\", emails)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f5e0ff6", + "metadata": {}, + "outputs": [], + "source": [ + "# Replace dates like MM/DD/YYYY with YYYY-MM-DD.\n", + "dates = (\"01/15/2020, 12/31/2019, 07/04/2021\")\n", + "\n", + "# your solution here\n", + "\n", + "print(\"The reformatted dates are:\", reformatted_dates)\n", + "if set(reformatted_dates) == {'2020-01-15', '2019-12-31', '2021-07-04'}:\n", + " print(\"The dates were reformatted correctly!\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/README.md b/README.md index 405f982..fb4eb5f 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,121 @@ -# python_class -Python Learning @ Everywhere +# Python Programming Workshop -## This page: goto/python +Welcome to the Library Python Programming Workshop! -## Pre-Work: -* Most of this content is designed for & tested on linux. It is recommended to run it in linux or in a linux VM (ubuntu?). -* Download and install the Anaconda Python distribution from: http://continuum.io/downloads (Unless you have another distribution you prefer. Anaconda is stronly recommended.) -* Install git: +We meet once a week to learn how to program in the Python progamming language. This is a work at your own pace and collaborate with others environment; Just bring any questions and stuff you'd like to look at each week and we all benefit as a group looking at it. + +We have a bunch of coureswork ready to use, including: +* Python Basics +* Data analysis with "Pandas" + +See the Notebooks list below for a more detailed list. + +## Current Schedule: +We were meeting on wednesdays during October, but due to a scheduling conflict, we'll bo moving to Thursdays. +* Thursday Jun 12 - 5:30PM +* Thursday Jun 19 - NO MEETING (writers group) +* Thursday Jun 26 - 5:30PM +* Thursday Jul 03 - 5:30PM +* Thursday Jul 10 - 5:30PM +* Thursday Jul 17 - NO MEETING (writers group) +* Thursday Jul 24 - NO MEETING (schedule conflict) +* Thursday Jul 30 - NO MEETING (schedule conflict) +* Thursday Aug 07 - 5:30PM +* Thursday Aug 14 - 5:30PM +* THE END, doing other stuff for a while... + +Please check the library calendar here to confirm dates/times: **https://engagedpatrons.org/EventsCalendar.cfm?SiteID=7839** +* Set "limit by location" to "Cameron Park Library". + +## Getting Started +You need a place to run python code and open "ipython notebooks". Let us know if you need a laptop to use during class. + +Our recommended mode of work will be in notebooks on google Colab: https://colab.research.google.com/ +* Sign up for a google account if you don't have one. +* Log in to https://colab.research.google.com and skim over the readme info +* Open the week one notebook that we'll be working from: + * Go to File -> Open Notebook -> Github, and paste in "a8ksh4/python_workshop". + * Open the Library Week 1 notebook file +* There's a nice intro video for colab here: https://www.youtube.com/watch?v=inN8seMm7UI + +If you're working from your own laptop and want to open notebooks locally rather than in colab, I'd recommend insalling the the Anaconda Python distribution from here: https://www.anaconda.com/products/distribution + * In windows, I'd recommend NOT running the installer as administrator - Install for only a single user when prompted. It's easier to install packages if it is installed in your home directory rather than a shared area for all users. + * Anaconda is available for Windows, Mac, and Linux! + * You can use any python distribution, but Anaconda is highly recommended becuase its package manager works so well and it has support for so many libraries out-of-the-box. + +It's also nice editing notebooks and code in VS Code. I think that works well with a plain python instal on your computer, so you'd want to use these: +* Python: +* VS Code: + * Install extensions + +## Notebooks Summary +We have a series of python notebooks ready to work through to learn from. They include all of the information you need to learn, links to additional resources, and programming problems to work through for each topic. + +* A-Getting_Started.ipynb - Introduction to Python and Google Colab. Covering variables and data types (numeric, strings, boolean), truthiness, and basic control flow (if-else statements). +* B-Dictionaries_and_Loops.ipynb - Exploring more complex data types (lists, tuples, dictionaries) and advanced control flow (loops: for and while). Opening files and intro to json. +* C-Functions_and_Module_Imports.ipynb - Introducing functions and modules in Python. +* D0-Pandas_Example.ipynb - An example of importing data and doing some anaylsis and graphing to get a feel for how pandas works. +* D1-Pandas_Intro_and_Data_selection.ipynb - Some pandas basics including imoprting data, manipulating columns of data, learning ways to select rows and columns of data, and exporting data to file. +* D3-Pandas_Graphing.ipynb - Goes over a bunch of plot types multi-axis plots, and graphs with multiple plots using pd.plot (wrapper for matplotlib pyplot) +* N-Numpy - Basics using numpy. Need to add some vectorization problems where we convert python code to numpy code... + +**In Development** +* D2-Data_Cleaning.ipynb - Setting column data types, removing missing or invalid data, interpolation, etc tools for preparing data for analysis. + +* D4-Advanced_Pandas.ipynb - Pivot, stack, unstack, join, concatenate, etc. +* D5-Machine_Learning.ipynb - Methods to use machine learning to model data using pandas and common ML libraries. Building on pandas skills with more advanced data manipulation and introduction to data visualization using pandas and matplotlib for generating graphs. +* E-Writing_Scripts.ipynb - Installing python locally, environment, structure of a script, and argparse +* F-Microcontrollers_Intro.ipynb - Circuitpython and Micropython on common microcontroller boards. +* G-Exception_Handling.ipynb - Try/Except blocks and Error Handing. +* H-Unit_Tests.ipynb - Writing test cases to verify your code works as designed. +* S-Subprocess_and_System_Calls.ipynb - Usage of the subprocess module for running commands outside of python +* T-Datetime.ipynb - Python Datetime Objects +* V-Virtual_Environments.ipynb - + +## Resources +**Documentation** +* https://docs.python.org/3/ - Python Documentation +* https://www.w3schools.com/python/default.asp - Great documentation and Examples +* https://peps.python.org/pep-0008/ - "Pep 8" style guide +* https://google.github.io/styleguide/pyguide.html - Google style guide +* https://github.com/jsantarc/cognitiveclass.ai-Python-for-Data-Science - Data science notebooks + +**Online Programming Tools** +* https://replit.com/ + +**Online Classes, videos, etc*** +* Kaggle Courses; e.g. Intro to Programming: + * https://www.kaggle.com/learn +* Many Youtube Python Programming tutorials: + * https://www.youtube.com/watch?v=eWRfhZUzrAc&list=PLWKjhJtqVAbnqBxcdjVGgT3uVR10bzTEB + * https://www.youtube.com/watch?v=K5KVEU3aaeQ + * ... search ... +* More structured fancy courses/programs. This one is assembled by a great instructor at GATech and is recommended pre-cursor to their online Masters in Comp Sci program + * https://www.edx.org/certificates/professional-certificate/the-georgia-institute-of-technology-introduction-to-python-programming + +### Notes on AI like ChatGPT +These tools are **very** helpful for learning. For this course, use them to explain how things work, but don't ask them to write code for you. If you don't experiment and learn for yourself, you won't retain as much. Keep all of your code and use your past code as the start for each more complicated problem. You'll build a toolkit of libraries and code bits that you understand and make all kinds of things from. + +* https://chat.openai.com/chat +* Example questions: + * How do I use for loops in python? + * How do I configure VS Code to use my Anaconda python interpreter? + * etc! + +## Github +This content is hosted here in a Git repository. You can check out a copy to your computer and "pull" updates with a git client: +* Make a github.com account and install git. * Linux: sudo apt-get install git * Windows: https://git-scm.com/download/win -* Download and install a text editor with syntax highlighting, like Notepad ++: http://notepad-plus-plus.org/ -* Print out this python cheat sheet: http://www.astro.up.pt/~sousasag/Python_For_Astronomers/Python_qr.pdf - -## Quick Links: -1. [Git and Github](./1-git_and_github/README.md) (start here) -2. [Python Basics](./2-python_basics/README.md) -3. [Files and Paths](./3-files_and_paths/README.md) -4. [System and Environment](./4-system_and_env/README.md) -5. [Data Manipulation](./5-data_manipulation/README.md) -6. [Exception Handling](./6-exception_handling/README.md) -7. ... - -## Topics Overview: -### 1 - Git and Github -### 2 - Python Basics -* python installations -* data types -* prompts & getpass -* recursion & iteration -* functions -* scope -* file handling -* sorting -* regex -### 3 - Files and Paths -* create, rm, copy, move, chmod, chown -* tar, gzip -* logging -### 4 - System and Environment -* argparse -* os & os.environ -* sys & sys.args -* setuid, setgid -* nis & nodes -* platform -* subprocess -### 5 - Data Manipulation -* csv, json, yaml, pickle, xlsx -* regex -* sql & sqlitle -### 6 - Exception Handling -* methodology -* Examles -### 7 - Debugging -* examples -### 8 - QA and Unit Testing -* http://docs.python-guide.org/en/latest/writing/tests/ - -### Windows Examples + * Check out this repository in your project area: git clone https://github.com/a8ksh4/python_workshop.git` + +Feel free to open "bug reports" in this repo for content you'd like to see added, changes needed, or corrections. Or make an improvement and submit a pull request and I'll merge your changes into the repo. + +## Code Editors +Install a text editor with code highlighting or an IDE for writing code in: +* Notepad ++: http://notepad-plus-plus.org/ +* VS Code: https://code.visualstudio.com/ + +If you're programming circuitpython or micropython on a microcontroller, Thonny is the best editor to start with. It has a built in serial console for seeing output from your code, and helps handle updating the code files on the board for you. An IDE like VS Code or IntelliJ with a Micropython or Circuitpython extension would be more powerful, but more complicated to set up. +* https://thonny.org/ diff --git a/SAMPLE_DATA/AAPL Historical Data.csv b/SAMPLE_DATA/AAPL Historical Data.csv new file mode 100644 index 0000000..4cbb9bc --- /dev/null +++ b/SAMPLE_DATA/AAPL Historical Data.csv @@ -0,0 +1,640 @@ +"Date","Price","Open","High","Low","Vol.","Change %" +"07/19/2024","224.31","224.82","226.80","223.27","49.15M","0.06%" +"07/18/2024","224.18","230.28","230.44","222.27","66.03M","-2.05%" +"07/17/2024","228.88","229.45","231.46","226.64","57.35M","-2.53%" +"07/16/2024","234.82","235.00","236.27","232.33","43.23M","0.18%" +"07/15/2024","234.40","236.48","237.23","233.09","62.63M","1.67%" +"07/12/2024","230.54","228.92","232.64","228.68","53.05M","1.31%" +"07/11/2024","227.57","231.39","232.39","225.77","64.71M","-2.32%" +"07/10/2024","232.98","229.30","233.08","229.25","62.63M","1.88%" +"07/09/2024","228.68","227.93","229.40","226.37","48.17M","0.38%" +"07/08/2024","227.82","227.09","227.85","223.25","59.09M","0.65%" +"07/05/2024","226.34","221.65","226.45","221.65","60.41M","2.16%" +"07/03/2024","221.55","220.00","221.55","219.03","37.37M","0.58%" +"07/02/2024","220.27","216.15","220.38","215.10","58.05M","1.62%" +"07/01/2024","216.75","212.09","217.51","211.92","60.40M","2.91%" +"06/28/2024","210.62","215.77","216.07","210.30","82.54M","-1.63%" +"06/27/2024","214.10","214.69","215.74","212.35","49.77M","0.40%" +"06/26/2024","213.25","211.50","214.86","210.64","66.21M","2.00%" +"06/25/2024","209.07","209.15","211.38","208.61","56.71M","0.45%" +"06/24/2024","208.14","207.72","212.70","206.59","80.73M","0.31%" +"06/21/2024","207.49","210.39","211.89","207.11","246.42M","-1.04%" +"06/20/2024","209.68","213.93","214.24","208.85","86.17M","-2.15%" +"06/18/2024","214.29","217.59","218.63","213.00","79.94M","-1.10%" +"06/17/2024","216.67","213.37","218.95","212.72","93.73M","1.97%" +"06/14/2024","212.49","213.85","215.17","211.30","70.12M","-0.82%" +"06/13/2024","214.24","214.74","216.75","211.60","97.86M","0.55%" +"06/12/2024","213.07","207.37","220.20","206.90","198.13M","2.86%" +"06/11/2024","207.15","193.65","207.16","193.63","172.37M","7.26%" +"06/10/2024","193.12","196.90","197.30","192.15","97.26M","-1.91%" +"06/07/2024","196.89","194.65","196.94","194.14","53.10M","1.24%" +"06/06/2024","194.48","195.68","196.50","194.17","41.18M","-0.71%" +"06/05/2024","195.87","195.40","196.90","194.87","54.16M","0.78%" +"06/04/2024","194.35","194.63","195.32","193.03","47.47M","0.16%" +"06/03/2024","194.03","192.90","194.99","192.52","50.08M","0.93%" +"05/31/2024","192.25","191.44","192.57","189.91","75.16M","0.50%" +"05/30/2024","191.29","190.76","192.18","190.63","49.95M","0.53%" +"05/29/2024","190.29","189.61","192.25","189.51","53.07M","0.16%" +"05/28/2024","189.99","191.51","193.00","189.10","52.28M","0.01%" +"05/24/2024","189.98","188.82","190.58","188.04","36.33M","1.66%" +"05/23/2024","186.88","190.98","191.00","186.63","51.01M","-2.11%" +"05/22/2024","190.90","192.26","192.82","190.27","34.65M","-0.75%" +"05/21/2024","192.35","191.09","192.73","190.92","42.31M","0.69%" +"05/20/2024","191.04","189.32","191.92","189.01","44.36M","0.62%" +"05/17/2024","189.87","189.51","190.81","189.18","41.28M","0.02%" +"05/16/2024","189.84","190.47","191.10","189.66","52.85M","0.06%" +"05/15/2024","189.72","187.91","190.65","187.37","70.40M","1.22%" +"05/14/2024","187.43","187.51","188.30","186.29","52.39M","0.62%" +"05/13/2024","186.28","185.43","187.10","184.62","72.04M","1.76%" +"05/10/2024","183.05","184.90","185.09","182.13","50.76M","-0.82%" +"05/09/2024","184.57","182.56","184.66","182.11","48.98M","1.00%" +"05/08/2024","182.74","182.85","183.07","181.45","45.06M","0.19%" +"05/07/2024","182.40","183.45","184.90","181.32","77.31M","0.38%" +"05/06/2024","181.71","182.35","184.20","180.42","78.57M","-0.91%" +"05/03/2024","183.38","186.65","187.00","182.66","163.22M","5.98%" +"05/02/2024","173.03","172.51","173.41","170.89","94.21M","2.20%" +"05/01/2024","169.30","169.58","172.71","169.11","50.38M","-0.60%" +"04/30/2024","170.33","173.33","174.99","170.00","65.93M","-1.83%" +"04/29/2024","173.50","173.37","176.03","173.10","68.17M","2.48%" +"04/26/2024","169.30","169.88","171.34","169.18","44.84M","-0.35%" +"04/25/2024","169.89","169.52","170.61","168.15","50.56M","0.51%" +"04/24/2024","169.02","166.54","169.30","166.21","48.25M","1.27%" +"04/23/2024","166.90","165.35","167.05","164.92","49.54M","0.64%" +"04/22/2024","165.84","165.51","167.26","164.77","48.12M","0.51%" +"04/19/2024","165.00","166.21","166.40","164.07","68.15M","-1.22%" +"04/18/2024","167.04","168.03","168.64","166.55","43.12M","-0.57%" +"04/17/2024","168.00","169.61","170.65","168.00","50.90M","-0.81%" +"04/16/2024","169.38","171.75","173.76","168.27","73.71M","-1.92%" +"04/15/2024","172.69","175.36","176.63","172.50","73.53M","-2.19%" +"04/12/2024","176.55","174.26","178.36","174.21","101.67M","0.86%" +"04/11/2024","175.04","168.34","175.46","168.16","91.07M","4.33%" +"04/10/2024","167.78","168.80","169.09","167.11","49.71M","-1.11%" +"04/09/2024","169.67","168.70","170.08","168.35","42.45M","0.72%" +"04/08/2024","168.45","169.03","169.20","168.24","37.43M","-0.67%" +"04/05/2024","169.58","169.59","170.39","168.95","42.10M","0.45%" +"04/04/2024","168.82","170.29","171.92","168.82","53.70M","-0.49%" +"04/03/2024","169.65","168.79","170.68","168.58","47.69M","0.48%" +"04/02/2024","168.84","169.08","169.34","168.23","49.33M","-0.70%" +"04/01/2024","170.03","171.19","171.25","169.48","46.24M","-0.85%" +"03/28/2024","171.48","171.75","172.23","170.51","65.67M","-1.06%" +"03/27/2024","173.31","170.41","173.60","170.11","60.27M","2.12%" +"03/26/2024","169.71","170.00","171.42","169.58","57.39M","-0.67%" +"03/25/2024","170.85","170.57","171.94","169.45","54.29M","-0.83%" +"03/22/2024","172.28","171.76","173.05","170.06","71.16M","0.53%" +"03/21/2024","171.37","177.05","177.49","170.84","106.18M","-4.09%" +"03/20/2024","178.67","175.72","178.67","175.09","53.42M","1.47%" +"03/19/2024","176.08","174.34","176.60","173.03","55.22M","1.36%" +"03/18/2024","173.72","175.57","177.71","173.52","75.60M","0.64%" +"03/15/2024","172.62","171.17","172.62","170.29","121.75M","-0.22%" +"03/14/2024","173.00","172.91","174.31","172.05","72.91M","1.09%" +"03/13/2024","171.13","172.77","173.18","170.76","52.49M","-1.21%" +"03/12/2024","173.23","173.15","174.03","171.01","59.83M","0.28%" +"03/11/2024","172.75","172.94","174.38","172.05","60.14M","1.18%" +"03/08/2024","170.73","169.00","173.70","168.94","76.27M","1.02%" +"03/07/2024","169.00","169.15","170.73","168.49","71.77M","-0.07%" +"03/06/2024","169.12","171.06","171.24","168.68","68.59M","-0.59%" +"03/05/2024","170.12","170.76","172.04","169.62","95.13M","-2.84%" +"03/04/2024","175.10","176.15","176.90","173.79","81.51M","-2.54%" +"03/01/2024","179.66","179.55","180.53","177.38","73.56M","-0.60%" +"02/29/2024","180.75","181.27","182.57","179.53","136.68M","-0.37%" +"02/28/2024","181.42","182.51","183.12","180.13","48.95M","-0.66%" +"02/27/2024","182.63","181.10","183.92","179.56","54.32M","0.81%" +"02/26/2024","181.16","182.24","182.76","180.65","40.87M","-0.75%" +"02/23/2024","182.52","185.01","185.04","182.23","45.12M","-1.00%" +"02/22/2024","184.37","183.48","184.96","182.46","52.29M","1.12%" +"02/21/2024","182.32","181.94","182.89","180.66","41.53M","0.42%" +"02/20/2024","181.56","181.79","182.43","180.00","53.67M","-0.41%" +"02/16/2024","182.31","183.42","184.85","181.66","49.75M","-0.84%" +"02/15/2024","183.86","183.55","184.49","181.35","65.43M","-0.16%" +"02/14/2024","184.15","185.32","185.53","182.44","54.63M","-0.48%" +"02/13/2024","185.04","185.77","186.21","183.51","56.53M","-1.13%" +"02/12/2024","187.15","188.41","188.67","186.79","41.78M","-0.90%" +"02/09/2024","188.85","188.65","189.99","188.00","45.16M","0.28%" +"02/08/2024","188.32","189.38","189.54","187.35","40.96M","-0.58%" +"02/07/2024","189.41","190.64","191.05","188.61","53.44M","0.06%" +"02/06/2024","189.30","186.86","189.31","186.77","43.49M","0.86%" +"02/05/2024","187.68","188.15","189.25","185.84","69.67M","0.98%" +"02/02/2024","185.85","179.86","187.33","179.25","102.55M","-0.54%" +"02/01/2024","186.86","183.99","186.95","183.82","64.89M","1.33%" +"01/31/2024","184.40","187.04","187.10","184.35","55.47M","-1.94%" +"01/30/2024","188.04","190.94","191.80","187.47","55.86M","-1.92%" +"01/29/2024","191.73","192.01","192.20","189.58","47.15M","-0.36%" +"01/26/2024","192.42","194.27","194.76","191.94","44.59M","-0.90%" +"01/25/2024","194.17","195.22","196.27","193.11","54.82M","-0.17%" +"01/24/2024","194.50","195.42","196.38","194.34","53.63M","-0.35%" +"01/23/2024","195.18","195.02","195.75","193.83","42.36M","0.67%" +"01/22/2024","193.89","192.30","195.33","192.26","60.13M","1.22%" +"01/19/2024","191.56","189.33","191.95","188.82","68.90M","1.55%" +"01/18/2024","188.63","186.09","189.14","185.83","78.01M","3.26%" +"01/17/2024","182.68","181.27","182.93","180.30","47.32M","-0.52%" +"01/16/2024","183.63","182.16","184.26","180.93","65.60M","-1.23%" +"01/12/2024","185.92","186.06","186.74","185.19","40.48M","0.18%" +"01/11/2024","185.59","186.54","187.05","183.62","49.13M","-0.32%" +"01/10/2024","186.19","184.35","186.40","183.92","46.79M","0.57%" +"01/09/2024","185.14","183.92","185.15","182.73","42.84M","-0.23%" +"01/08/2024","185.56","182.09","185.60","181.50","59.14M","2.42%" +"01/05/2024","181.18","181.99","182.76","180.17","62.38M","-0.40%" +"01/04/2024","181.91","182.15","183.09","180.88","71.98M","-1.27%" +"01/03/2024","184.25","184.22","185.88","183.43","58.41M","-0.75%" +"01/02/2024","185.64","187.15","188.44","183.88","82.49M","-3.58%" +"12/29/2023","192.53","193.90","194.40","191.73","42.67M","-0.54%" +"12/28/2023","193.58","194.14","194.66","193.17","34.05M","0.22%" +"12/27/2023","193.15","192.49","193.50","191.09","48.09M","0.05%" +"12/26/2023","193.05","193.61","193.89","192.83","28.92M","-0.28%" +"12/22/2023","193.60","195.18","195.41","192.97","37.15M","-0.55%" +"12/21/2023","194.68","196.10","197.08","193.50","46.48M","-0.08%" +"12/20/2023","194.83","196.90","197.68","194.83","52.24M","-1.07%" +"12/19/2023","196.94","196.16","196.95","195.89","40.71M","0.54%" +"12/18/2023","195.89","196.09","196.63","194.39","55.75M","-0.85%" +"12/15/2023","197.57","197.53","198.40","197.00","128.54M","-0.27%" +"12/14/2023","198.11","198.02","199.62","196.16","66.83M","0.08%" +"12/13/2023","197.96","195.09","198.00","194.85","70.40M","1.67%" +"12/12/2023","194.71","193.08","194.72","191.72","52.70M","0.79%" +"12/11/2023","193.18","193.11","193.49","191.42","60.94M","-1.29%" +"12/08/2023","195.71","194.20","195.99","193.67","53.41M","0.74%" +"12/07/2023","194.27","193.63","195.00","193.59","47.48M","1.01%" +"12/06/2023","192.32","194.45","194.76","192.11","41.09M","-0.57%" +"12/05/2023","193.42","190.21","194.40","190.18","66.63M","2.11%" +"12/04/2023","189.43","189.98","190.05","187.45","43.39M","-0.95%" +"12/01/2023","191.24","190.33","191.56","189.23","45.70M","0.68%" +"11/30/2023","189.95","189.84","190.32","188.19","48.79M","0.31%" +"11/29/2023","189.37","190.90","192.09","188.97","43.01M","-0.54%" +"11/28/2023","190.40","189.78","191.08","189.40","38.42M","0.32%" +"11/27/2023","189.79","189.92","190.67","188.90","40.55M","-0.09%" +"11/24/2023","189.97","190.87","190.90","189.25","24.05M","-0.70%" +"11/22/2023","191.31","191.49","192.93","190.82","39.63M","0.35%" +"11/21/2023","190.64","191.41","191.52","189.74","38.13M","-0.42%" +"11/20/2023","191.45","189.89","191.90","189.88","46.54M","0.93%" +"11/17/2023","189.69","190.25","190.38","188.57","50.94M","-0.01%" +"11/16/2023","189.71","189.57","190.96","188.65","54.41M","0.90%" +"11/15/2023","188.01","187.85","189.50","187.78","53.79M","0.30%" +"11/14/2023","187.44","187.70","188.11","186.30","60.11M","1.43%" +"11/13/2023","184.80","185.82","186.03","184.21","43.63M","-0.86%" +"11/10/2023","186.40","183.97","186.57","183.53","66.18M","2.19%" +"11/09/2023","182.41","182.96","184.12","181.81","53.76M","-0.26%" +"11/08/2023","182.89","182.35","183.45","181.59","49.34M","0.59%" +"11/07/2023","181.82","179.18","182.44","178.97","70.53M","1.45%" +"11/06/2023","179.23","176.38","179.43","176.21","63.84M","1.46%" +"11/03/2023","176.65","174.24","176.82","173.35","79.83M","-0.52%" +"11/02/2023","177.57","175.52","177.78","175.46","77.33M","2.07%" +"11/01/2023","173.97","171.00","174.23","170.12","56.93M","1.87%" +"10/31/2023","170.77","169.35","170.90","167.90","44.85M","0.28%" +"10/30/2023","170.29","169.02","171.17","168.87","51.13M","1.23%" +"10/27/2023","168.22","166.91","168.96","166.83","58.50M","0.80%" +"10/26/2023","166.89","170.37","171.38","165.67","70.63M","-2.46%" +"10/25/2023","171.10","171.88","173.06","170.65","57.16M","-1.35%" +"10/24/2023","173.44","173.05","173.67","171.45","43.82M","0.25%" +"10/23/2023","173.00","170.91","174.01","169.93","55.98M","0.07%" +"10/20/2023","172.88","175.31","175.42","172.64","64.24M","-1.47%" +"10/19/2023","175.46","176.04","177.84","175.19","59.30M","-0.22%" +"10/18/2023","175.84","175.58","177.57","175.11","54.76M","-0.74%" +"10/17/2023","177.15","176.65","178.42","174.80","57.55M","-0.88%" +"10/16/2023","178.72","176.75","179.07","176.51","52.52M","-0.07%" +"10/13/2023","178.85","181.42","181.93","178.14","51.46M","-1.03%" +"10/12/2023","180.71","180.07","182.34","179.04","56.74M","0.51%" +"10/11/2023","179.80","178.20","179.85","177.60","47.55M","0.79%" +"10/10/2023","178.39","178.10","179.72","177.95","43.70M","-0.34%" +"10/09/2023","178.99","176.81","179.05","175.80","42.39M","0.85%" +"10/06/2023","177.49","173.80","177.99","173.18","57.27M","1.48%" +"10/05/2023","174.91","173.79","175.45","172.68","48.53M","0.72%" +"10/04/2023","173.66","171.09","174.21","170.97","53.02M","0.73%" +"10/03/2023","172.40","172.26","173.63","170.82","49.59M","-0.78%" +"10/02/2023","173.75","171.22","174.30","170.93","52.16M","1.48%" +"09/29/2023","171.21","172.02","173.07","170.34","51.86M","0.30%" +"09/28/2023","170.69","169.34","172.03","167.62","56.29M","0.15%" +"09/27/2023","170.43","172.62","173.04","169.05","66.92M","-0.89%" +"09/26/2023","171.96","174.82","175.20","171.66","64.59M","-2.34%" +"09/25/2023","176.08","174.20","176.97","174.15","46.17M","0.74%" +"09/22/2023","174.79","174.67","177.08","174.05","56.73M","0.49%" +"09/21/2023","173.93","174.55","176.30","173.86","63.15M","-0.89%" +"09/20/2023","175.49","179.26","179.70","175.40","58.44M","-2.00%" +"09/19/2023","179.07","177.52","179.63","177.13","51.83M","0.62%" +"09/18/2023","177.97","176.48","179.38","176.17","67.26M","1.69%" +"09/15/2023","175.01","176.48","176.49","173.82","109.26M","-0.42%" +"09/14/2023","175.74","174.00","176.10","173.58","60.90M","0.88%" +"09/13/2023","174.21","176.51","177.30","173.98","84.27M","-1.19%" +"09/12/2023","176.30","179.49","180.13","174.82","90.37M","-1.71%" +"09/11/2023","179.36","180.07","180.30","177.34","58.95M","0.66%" +"09/08/2023","178.18","178.35","180.24","177.79","65.60M","0.35%" +"09/07/2023","177.56","175.18","178.21","173.54","112.49M","-2.92%" +"09/06/2023","182.91","188.40","188.85","181.47","81.76M","-3.58%" +"09/05/2023","189.70","188.28","189.98","187.61","45.28M","0.13%" +"09/01/2023","189.46","189.49","189.92","188.28","45.77M","0.85%" +"08/31/2023","187.87","187.84","189.12","187.48","60.79M","0.12%" +"08/30/2023","187.65","184.94","187.85","184.74","60.81M","1.92%" +"08/29/2023","184.12","179.70","184.90","179.50","53.00M","2.18%" +"08/28/2023","180.19","180.09","180.59","178.54","43.82M","0.88%" +"08/25/2023","178.61","177.38","179.15","175.82","51.45M","1.26%" +"08/24/2023","176.38","180.67","181.10","176.01","54.95M","-2.62%" +"08/23/2023","181.12","178.52","181.55","178.32","52.72M","2.19%" +"08/22/2023","177.23","177.06","177.68","176.25","42.08M","0.79%" +"08/21/2023","175.84","175.07","176.13","173.74","46.31M","0.77%" +"08/18/2023","174.49","172.30","175.10","171.96","61.17M","0.28%" +"08/17/2023","174.00","177.14","177.51","173.48","66.06M","-1.46%" +"08/16/2023","176.57","177.13","178.54","176.50","46.96M","-0.50%" +"08/15/2023","177.45","178.88","179.48","177.05","43.62M","-1.12%" +"08/14/2023","179.46","177.97","179.69","177.30","43.68M","0.94%" +"08/11/2023","177.79","177.32","178.62","176.55","52.04M","-0.10%" +"08/10/2023","177.97","179.48","180.75","177.60","54.69M","-0.12%" +"08/09/2023","178.19","180.87","180.93","177.01","60.38M","-0.90%" +"08/08/2023","179.80","179.69","180.27","177.58","67.82M","0.53%" +"08/07/2023","178.85","182.13","183.13","177.35","97.58M","-1.73%" +"08/04/2023","181.99","185.52","187.38","181.92","115.96M","-4.80%" +"08/03/2023","191.17","191.57","192.37","190.69","62.24M","-0.73%" +"08/02/2023","192.58","195.04","195.18","191.85","50.39M","-1.55%" +"08/01/2023","195.60","196.24","196.73","195.28","35.28M","-0.43%" +"07/31/2023","196.45","196.06","196.49","195.26","38.82M","0.32%" +"07/28/2023","195.83","194.67","196.63","194.14","48.29M","1.35%" +"07/27/2023","193.22","196.02","197.20","192.55","47.46M","-0.66%" +"07/26/2023","194.50","193.67","195.64","193.32","47.47M","0.45%" +"07/25/2023","193.62","193.33","194.44","192.91","37.28M","0.45%" +"07/24/2023","192.75","193.41","194.91","192.25","45.51M","0.42%" +"07/21/2023","191.94","194.10","194.97","191.23","71.95M","-0.62%" +"07/20/2023","193.13","195.09","196.47","192.49","59.58M","-1.01%" +"07/19/2023","195.10","193.10","198.23","192.65","80.51M","0.71%" +"07/18/2023","193.73","193.35","194.33","192.41","48.35M","-0.13%" +"07/17/2023","193.99","191.90","194.32","191.81","50.52M","1.73%" +"07/14/2023","190.69","190.23","191.18","189.63","41.62M","0.08%" +"07/13/2023","190.54","190.50","191.19","189.78","41.34M","0.41%" +"07/12/2023","189.77","189.68","191.70","188.47","60.75M","0.90%" +"07/11/2023","188.08","189.16","189.30","186.60","46.64M","-0.28%" +"07/10/2023","188.61","189.26","189.99","187.04","59.92M","-1.09%" +"07/07/2023","190.68","191.41","192.67","190.24","46.82M","-0.59%" +"07/06/2023","191.81","189.84","192.02","189.20","45.16M","0.25%" +"07/05/2023","191.33","191.57","192.98","190.62","46.92M","-0.59%" +"07/03/2023","192.46","193.78","193.88","191.76","31.46M","-0.78%" +"06/30/2023","193.97","191.63","194.48","191.26","85.21M","2.31%" +"06/29/2023","189.59","189.08","190.07","188.94","46.35M","0.18%" +"06/28/2023","189.25","187.93","189.90","187.60","51.22M","0.63%" +"06/27/2023","188.06","185.89","188.39","185.67","50.73M","1.51%" +"06/26/2023","185.27","186.83","188.05","185.23","48.09M","-0.76%" +"06/23/2023","186.68","185.55","187.56","185.01","53.12M","-0.17%" +"06/22/2023","187.00","183.74","187.04","183.67","51.25M","1.65%" +"06/21/2023","183.96","184.90","185.41","182.59","49.52M","-0.57%" +"06/20/2023","185.01","184.41","186.10","184.41","49.80M","0.05%" +"06/16/2023","184.92","186.73","186.99","184.27","101.26M","-0.59%" +"06/15/2023","186.01","183.96","186.52","183.78","65.43M","1.12%" +"06/14/2023","183.95","183.37","184.39","182.02","57.46M","0.35%" +"06/13/2023","183.31","182.80","184.15","182.44","54.93M","-0.26%" +"06/12/2023","183.79","181.27","183.89","180.97","54.76M","1.56%" +"06/09/2023","180.96","181.50","182.23","180.63","48.90M","0.22%" +"06/08/2023","180.57","177.90","180.84","177.46","50.21M","1.55%" +"06/07/2023","177.82","178.44","181.21","177.32","61.94M","-0.78%" +"06/06/2023","179.21","179.96","180.12","177.43","64.85M","-0.21%" +"06/05/2023","179.58","182.63","184.95","178.04","121.95M","-0.76%" +"06/02/2023","180.95","181.03","181.78","179.26","62.00M","0.48%" +"06/01/2023","180.09","177.70","180.12","176.93","68.90M","1.60%" +"05/31/2023","177.25","177.32","179.35","176.76","99.63M","-0.03%" +"05/30/2023","177.30","176.96","178.99","176.57","55.96M","1.07%" +"05/26/2023","175.43","173.32","175.77","173.11","54.84M","1.41%" +"05/25/2023","172.99","172.41","173.90","171.69","56.06M","0.67%" +"05/24/2023","171.84","171.09","172.42","170.52","45.14M","0.16%" +"05/23/2023","171.56","173.13","173.38","171.27","50.75M","-1.52%" +"05/22/2023","174.20","173.98","174.71","173.45","43.57M","-0.55%" +"05/19/2023","175.16","176.39","176.39","174.94","55.81M","0.06%" +"05/18/2023","175.05","173.00","175.24","172.58","65.50M","1.37%" +"05/17/2023","172.69","171.71","172.93","170.42","57.95M","0.36%" +"05/16/2023","172.07","171.99","173.14","171.80","42.11M","0.00%" +"05/15/2023","172.07","173.16","173.21","171.47","37.27M","-0.29%" +"05/12/2023","172.57","173.62","174.06","171.00","45.53M","-0.68%" +"05/11/2023","173.75","173.85","174.59","172.17","49.51M","0.11%" +"05/10/2023","173.55","173.02","174.03","171.90","53.72M","1.04%" +"05/09/2023","171.77","173.05","173.54","171.60","45.33M","-1.00%" +"05/08/2023","173.50","172.48","173.85","172.11","55.96M","-0.04%" +"05/05/2023","173.57","170.98","174.30","170.76","113.45M","4.69%" +"05/04/2023","165.79","164.89","167.04","164.31","81.24M","-0.99%" +"05/03/2023","167.45","169.50","170.92","167.16","65.14M","-0.65%" +"05/02/2023","168.54","170.09","170.35","167.54","48.43M","-0.62%" +"05/01/2023","169.59","169.28","170.45","168.64","52.47M","-0.05%" +"04/28/2023","169.68","168.49","169.85","167.88","55.28M","0.75%" +"04/27/2023","168.41","165.19","168.56","165.19","64.90M","2.84%" +"04/26/2023","163.76","163.05","165.28","162.80","45.50M","-0.01%" +"04/25/2023","163.77","165.19","166.30","163.73","48.71M","-0.94%" +"04/24/2023","165.33","165.00","165.60","163.89","41.95M","0.19%" +"04/21/2023","165.02","165.05","166.45","164.49","58.34M","-0.98%" +"04/20/2023","166.65","166.09","167.87","165.56","52.46M","-0.58%" +"04/19/2023","167.63","165.80","168.16","165.54","47.72M","0.70%" +"04/18/2023","166.47","166.10","167.41","165.65","49.92M","0.75%" +"04/17/2023","165.23","165.09","165.39","164.03","41.52M","0.01%" +"04/14/2023","165.21","164.59","166.32","163.82","49.39M","-0.21%" +"04/13/2023","165.56","161.63","165.80","161.42","68.45M","3.41%" +"04/12/2023","160.10","161.22","162.06","159.78","50.13M","-0.44%" +"04/11/2023","160.80","162.35","162.36","160.51","47.64M","-0.76%" +"04/10/2023","162.03","161.42","162.03","160.08","47.72M","-1.60%" +"04/06/2023","164.66","162.43","164.96","162.00","45.39M","0.55%" +"04/05/2023","163.76","164.74","165.05","161.80","51.51M","-1.13%" +"04/04/2023","165.63","166.60","166.84","165.11","46.28M","-0.32%" +"04/03/2023","166.17","164.27","166.29","164.22","56.98M","0.77%" +"03/31/2023","164.90","162.44","165.00","161.91","68.75M","1.56%" +"03/30/2023","162.36","161.53","162.47","161.27","49.50M","0.99%" +"03/29/2023","160.77","159.37","161.05","159.35","51.31M","1.98%" +"03/28/2023","157.65","157.97","158.49","155.98","45.99M","-0.40%" +"03/27/2023","158.28","159.94","160.77","157.87","52.39M","-1.23%" +"03/24/2023","160.25","158.86","160.34","157.85","59.26M","0.83%" +"03/23/2023","158.93","158.83","161.55","157.68","67.62M","0.70%" +"03/22/2023","157.83","159.30","162.14","157.81","75.70M","-0.91%" +"03/21/2023","159.28","157.32","159.40","156.54","73.94M","1.19%" +"03/20/2023","157.40","155.07","157.82","154.15","73.64M","1.55%" +"03/17/2023","155.00","156.08","156.74","154.28","98.94M","-0.55%" +"03/16/2023","155.85","152.16","156.46","151.64","76.25M","1.87%" +"03/15/2023","152.99","151.19","153.24","149.92","77.17M","0.26%" +"03/14/2023","152.59","151.28","153.40","150.10","73.70M","1.41%" +"03/13/2023","150.47","147.80","153.14","147.70","84.46M","1.33%" +"03/10/2023","148.50","150.21","150.94","147.61","68.57M","-1.39%" +"03/09/2023","150.59","153.56","154.54","150.23","53.83M","-1.49%" +"03/08/2023","152.87","152.81","153.47","151.83","47.20M","0.84%" +"03/07/2023","151.60","153.70","154.03","151.13","56.18M","-1.45%" +"03/06/2023","153.83","153.79","156.30","153.46","87.56M","1.85%" +"03/03/2023","151.03","148.04","151.11","147.33","70.73M","3.51%" +"03/02/2023","145.91","144.38","146.71","143.90","52.28M","0.41%" +"03/01/2023","145.31","146.83","147.23","145.01","55.48M","-1.42%" +"02/28/2023","147.41","147.05","149.08","146.83","50.55M","-0.34%" +"02/27/2023","147.92","147.71","149.17","147.45","45.00M","0.82%" +"02/24/2023","146.71","147.11","147.19","145.72","55.47M","-1.80%" +"02/23/2023","149.40","150.09","150.34","147.24","48.39M","0.33%" +"02/22/2023","148.91","148.87","149.95","147.16","51.01M","0.29%" +"02/21/2023","148.48","150.20","151.30","148.40","58.87M","-2.67%" +"02/17/2023","152.55","152.35","153.00","150.85","59.14M","-0.75%" +"02/16/2023","153.71","153.51","156.33","153.35","68.17M","-1.04%" +"02/15/2023","155.33","153.11","155.50","152.88","65.67M","1.39%" +"02/14/2023","153.20","152.12","153.77","150.86","61.71M","-0.42%" +"02/13/2023","153.85","150.95","154.26","150.92","62.20M","1.88%" +"02/10/2023","151.01","149.46","151.34","149.22","57.45M","0.09%" +"02/09/2023","150.87","153.77","154.33","150.42","56.01M","-0.69%" +"02/08/2023","151.92","153.88","154.58","151.17","64.12M","-1.77%" +"02/07/2023","154.65","150.64","155.23","150.64","83.32M","1.92%" +"02/06/2023","151.73","152.57","153.10","150.78","69.86M","-1.79%" +"02/03/2023","154.50","148.03","157.38","147.83","154.36M","2.44%" +"02/02/2023","150.82","148.90","151.18","148.17","118.34M","3.71%" +"02/01/2023","145.43","143.97","146.61","141.32","77.66M","0.79%" +"01/31/2023","144.29","142.70","144.34","142.28","65.87M","0.90%" +"01/30/2023","143.00","144.96","145.55","142.85","64.02M","-2.01%" +"01/27/2023","145.93","143.15","147.23","143.08","70.56M","1.37%" +"01/26/2023","143.96","143.17","144.25","141.90","54.11M","1.48%" +"01/25/2023","141.86","140.89","142.43","138.81","65.80M","-0.47%" +"01/24/2023","142.53","140.30","143.16","140.30","66.44M","1.01%" +"01/23/2023","141.11","138.12","143.32","137.90","81.76M","2.35%" +"01/20/2023","137.87","135.28","138.02","134.22","80.22M","1.92%" +"01/19/2023","135.27","134.08","136.25","133.77","58.28M","0.04%" +"01/18/2023","135.21","136.82","138.61","135.03","69.67M","-0.54%" +"01/17/2023","135.94","134.83","137.29","134.13","63.65M","0.88%" +"01/13/2023","134.76","132.03","134.92","131.66","57.81M","1.01%" +"01/12/2023","133.41","133.88","134.26","131.44","71.38M","-0.06%" +"01/11/2023","133.49","131.25","133.51","130.46","69.46M","2.11%" +"01/10/2023","130.73","130.26","131.26","128.12","63.90M","0.45%" +"01/09/2023","130.15","130.46","133.41","129.89","70.79M","0.41%" +"01/06/2023","129.62","126.01","130.29","124.89","87.75M","3.68%" +"01/05/2023","125.02","127.13","127.77","124.76","80.96M","-1.06%" +"01/04/2023","126.36","126.89","128.66","125.08","89.11M","1.03%" +"01/03/2023","125.07","130.28","130.90","124.17","112.12M","-3.74%" +"12/30/2022","129.93","128.41","129.95","127.43","77.03M","0.25%" +"12/29/2022","129.61","127.99","130.48","127.73","75.70M","2.83%" +"12/28/2022","126.04","129.67","131.03","125.87","85.44M","-3.07%" +"12/27/2022","130.03","131.38","131.41","128.72","69.01M","-1.39%" +"12/23/2022","131.86","130.92","132.41","129.64","63.81M","-0.28%" +"12/22/2022","132.23","134.35","134.56","130.30","77.85M","-2.38%" +"12/21/2022","135.45","132.98","136.81","132.75","85.93M","2.38%" +"12/20/2022","132.30","131.39","133.25","129.89","77.43M","-0.05%" +"12/19/2022","132.37","135.11","135.20","131.32","79.59M","-1.59%" +"12/16/2022","134.51","136.68","137.65","133.73","160.16M","-1.46%" +"12/15/2022","136.50","141.11","141.80","136.02","98.93M","-4.69%" +"12/14/2022","143.21","145.35","146.65","141.16","82.29M","-1.55%" +"12/13/2022","145.47","149.50","149.97","144.24","93.89M","0.68%" +"12/12/2022","144.49","142.70","144.50","141.06","70.46M","1.64%" +"12/09/2022","142.16","142.34","145.57","140.90","76.10M","-0.34%" +"12/08/2022","142.65","142.36","143.52","141.10","62.13M","1.21%" +"12/07/2022","140.94","142.19","143.37","140.00","69.72M","-1.38%" +"12/06/2022","142.91","147.07","147.30","141.92","64.73M","-2.54%" +"12/05/2022","146.63","147.77","150.92","145.77","68.83M","-0.80%" +"12/02/2022","147.81","145.96","148.00","145.65","65.45M","-0.34%" +"12/01/2022","148.31","148.21","149.13","146.61","71.25M","0.19%" +"11/30/2022","148.03","141.40","148.72","140.55","111.38M","4.86%" +"11/29/2022","141.17","144.29","144.81","140.35","83.76M","-2.11%" +"11/28/2022","144.22","145.14","146.64","143.38","69.35M","-2.63%" +"11/25/2022","148.11","148.30","148.88","147.12","35.20M","-1.96%" +"11/23/2022","151.07","149.45","151.83","149.34","58.30M","0.59%" +"11/22/2022","150.18","148.13","150.42","146.93","51.80M","1.47%" +"11/21/2022","148.01","150.16","150.37","147.71","58.72M","-2.17%" +"11/18/2022","151.29","152.30","152.70","149.97","74.83M","0.38%" +"11/17/2022","150.72","146.43","151.48","146.15","80.39M","1.30%" +"11/16/2022","148.79","149.13","149.87","147.29","64.22M","-0.83%" +"11/15/2022","150.04","152.21","153.59","148.56","89.87M","1.19%" +"11/14/2022","148.28","148.97","150.28","147.43","73.37M","-0.95%" +"11/11/2022","149.70","145.82","150.01","144.37","93.98M","1.93%" +"11/10/2022","146.87","141.24","146.87","139.50","118.85M","8.90%" +"11/09/2022","134.87","138.50","138.55","134.59","74.92M","-3.32%" +"11/08/2022","139.50","140.41","141.43","137.49","89.91M","0.42%" +"11/07/2022","138.92","137.11","139.15","135.67","83.37M","0.39%" +"11/04/2022","138.38","142.09","142.67","134.38","140.81M","-0.36%" +"11/03/2022","138.88","142.06","142.80","138.75","97.92M","-4.24%" +"11/02/2022","145.03","148.95","152.17","145.00","93.60M","-3.73%" +"11/01/2022","150.65","155.08","155.45","149.13","80.38M","-1.75%" +"10/31/2022","153.34","153.15","154.24","151.92","97.94M","-1.54%" +"10/28/2022","155.74","148.20","157.50","147.82","164.76M","7.56%" +"10/27/2022","144.80","148.07","149.05","144.13","109.18M","-3.05%" +"10/26/2022","149.35","150.96","151.99","148.04","88.44M","-1.96%" +"10/25/2022","152.34","150.09","152.49","149.36","74.73M","1.93%" +"10/24/2022","149.45","147.18","150.23","146.00","75.98M","1.48%" +"10/21/2022","147.27","142.87","147.85","142.65","86.55M","2.71%" +"10/20/2022","143.39","143.02","145.89","142.65","64.52M","-0.33%" +"10/19/2022","143.86","141.69","144.95","141.50","61.76M","0.08%" +"10/18/2022","143.75","145.49","146.70","140.61","99.14M","0.94%" +"10/17/2022","142.41","141.07","142.90","140.27","85.25M","2.91%" +"10/14/2022","138.38","144.31","144.52","138.19","88.60M","-3.22%" +"10/13/2022","142.99","134.99","143.59","134.37","113.22M","3.36%" +"10/12/2022","138.34","139.13","140.36","138.16","70.43M","-0.46%" +"10/11/2022","138.98","139.90","141.35","138.22","77.03M","-1.03%" +"10/10/2022","140.42","140.42","141.89","138.57","74.90M","0.24%" +"10/07/2022","140.09","142.54","143.10","139.45","85.93M","-3.67%" +"10/06/2022","145.43","145.81","147.54","145.22","68.40M","-0.66%" +"10/05/2022","146.40","144.07","147.38","143.01","79.47M","0.21%" +"10/04/2022","146.10","145.03","146.22","144.26","87.83M","2.56%" +"10/03/2022","142.45","138.21","143.07","137.68","114.31M","3.08%" +"09/30/2022","138.20","141.28","143.10","138.00","124.93M","-3.00%" +"09/29/2022","142.48","146.10","146.72","140.68","128.14M","-4.91%" +"09/28/2022","149.84","147.64","150.64","144.84","146.69M","-1.27%" +"09/27/2022","151.76","152.74","154.72","149.95","84.44M","0.66%" +"09/26/2022","150.77","149.66","153.77","149.64","93.34M","0.23%" +"09/23/2022","150.43","151.19","151.47","148.56","96.03M","-1.51%" +"09/22/2022","152.74","152.38","154.47","150.91","86.65M","-0.64%" +"09/21/2022","153.72","157.34","158.74","153.60","101.70M","-2.03%" +"09/20/2022","156.90","153.40","158.08","153.08","107.69M","1.57%" +"09/19/2022","154.48","149.31","154.56","149.10","81.47M","2.51%" +"09/16/2022","150.70","151.21","151.35","148.37","162.28M","-1.10%" +"09/15/2022","152.37","154.65","155.24","151.38","90.48M","-1.89%" +"09/14/2022","155.31","154.79","157.10","153.61","87.97M","0.96%" +"09/13/2022","153.84","159.90","160.54","153.37","122.66M","-5.87%" +"09/12/2022","163.43","159.59","164.26","159.30","104.96M","3.85%" +"09/09/2022","157.37","155.47","157.82","154.75","68.08M","1.88%" +"09/08/2022","154.46","154.64","156.36","152.68","84.92M","-0.96%" +"09/07/2022","155.96","154.82","156.67","153.61","87.45M","0.93%" +"09/06/2022","154.53","156.47","157.09","153.69","73.71M","-0.82%" +"09/02/2022","155.81","159.75","160.36","154.96","76.96M","-1.36%" +"09/01/2022","157.96","156.64","158.42","154.67","74.23M","0.47%" +"08/31/2022","157.22","160.30","160.58","157.14","87.99M","-1.06%" +"08/30/2022","158.91","162.13","162.56","157.72","77.91M","-1.53%" +"08/29/2022","161.38","161.15","162.90","159.82","73.31M","-1.37%" +"08/26/2022","163.62","170.57","171.05","163.56","78.96M","-3.77%" +"08/25/2022","170.03","168.78","170.14","168.35","51.22M","1.49%" +"08/24/2022","167.53","167.32","168.11","166.24","53.84M","0.18%" +"08/23/2022","167.23","167.08","168.71","166.65","54.15M","-0.20%" +"08/22/2022","167.57","169.69","169.86","167.13","69.03M","-2.30%" +"08/19/2022","171.52","173.03","173.74","171.31","70.35M","-1.51%" +"08/18/2022","174.15","173.75","174.90","173.12","62.29M","-0.23%" +"08/17/2022","174.55","172.77","176.15","172.57","79.54M","0.88%" +"08/16/2022","173.03","172.78","173.71","171.66","56.38M","-0.09%" +"08/15/2022","173.19","171.52","173.39","171.35","54.09M","0.63%" +"08/12/2022","172.10","169.82","172.17","169.40","68.04M","2.14%" +"08/11/2022","168.49","170.06","170.99","168.19","57.15M","-0.44%" +"08/10/2022","169.24","167.68","169.34","166.90","70.17M","2.62%" +"08/09/2022","164.92","164.02","165.82","163.25","63.14M","0.03%" +"08/08/2022","164.87","166.37","167.81","164.20","60.36M","-0.29%" +"08/05/2022","165.35","163.21","165.85","163.00","56.70M","-0.28%" +"08/04/2022","165.81","166.01","167.19","164.43","55.47M","-0.19%" +"08/03/2022","166.13","160.84","166.59","160.75","82.51M","3.82%" +"08/02/2022","160.01","160.10","162.41","159.63","59.91M","-0.93%" +"08/01/2022","161.51","161.01","163.59","160.89","67.83M","-0.62%" +"07/29/2022","162.51","161.24","163.63","159.50","101.79M","3.28%" +"07/28/2022","157.35","156.98","157.64","154.41","81.38M","0.36%" +"07/27/2022","156.79","152.58","157.33","152.16","78.62M","3.42%" +"07/26/2022","151.60","152.26","153.09","150.80","55.14M","-0.88%" +"07/25/2022","152.95","154.01","155.04","152.28","53.62M","-0.74%" +"07/22/2022","154.09","155.39","156.28","153.41","66.68M","-0.81%" +"07/21/2022","155.35","154.50","155.57","151.94","65.09M","1.51%" +"07/20/2022","153.04","151.12","153.72","150.37","64.82M","1.35%" +"07/19/2022","151.00","147.92","151.23","146.91","82.98M","2.67%" +"07/18/2022","147.07","150.74","151.57","146.70","81.42M","-2.06%" +"07/15/2022","150.17","149.78","150.86","148.20","76.26M","1.15%" +"07/14/2022","148.47","144.08","148.95","143.25","78.14M","2.05%" +"07/13/2022","145.49","142.99","146.45","142.12","71.19M","-0.25%" +"07/12/2022","145.86","145.76","148.45","145.05","77.59M","0.68%" +"07/11/2022","144.87","145.67","146.64","143.78","63.31M","-1.48%" +"07/08/2022","147.04","145.26","147.55","145.00","64.55M","0.47%" +"07/07/2022","146.35","143.29","146.55","143.28","66.25M","2.40%" +"07/06/2022","142.92","141.35","144.12","141.08","74.06M","0.96%" +"07/05/2022","141.56","137.77","141.61","136.93","73.43M","1.89%" +"07/01/2022","138.93","136.04","139.04","135.66","71.05M","1.62%" +"06/30/2022","136.72","137.25","138.37","133.77","98.96M","-1.80%" +"06/29/2022","139.23","137.46","140.67","136.67","66.24M","1.30%" +"06/28/2022","137.44","142.13","143.42","137.32","67.32M","-2.98%" +"06/27/2022","141.66","142.70","143.49","140.96","70.21M","0.00%" +"06/24/2022","141.66","139.90","141.91","139.77","89.12M","2.45%" +"06/23/2022","138.27","136.82","138.59","135.63","72.43M","2.16%" +"06/22/2022","135.35","134.79","137.76","133.91","73.41M","-0.38%" +"06/21/2022","135.87","133.42","137.06","133.32","81.00M","3.28%" +"06/17/2022","131.56","130.07","133.08","129.81","134.52M","1.15%" +"06/16/2022","130.06","132.08","132.39","129.04","107.96M","-3.97%" +"06/15/2022","135.43","134.29","137.34","132.16","91.53M","2.01%" +"06/14/2022","132.76","133.13","133.89","131.48","84.78M","0.67%" +"06/13/2022","131.88","132.87","135.20","131.44","122.21M","-3.83%" +"06/10/2022","137.13","140.28","140.76","137.06","91.57M","-3.86%" +"06/09/2022","142.64","147.08","147.95","142.53","69.47M","-3.60%" +"06/08/2022","147.96","148.58","149.87","147.46","53.95M","-0.50%" +"06/07/2022","148.71","144.35","149.00","144.10","67.81M","1.76%" +"06/06/2022","146.14","147.03","148.57","144.90","71.60M","0.52%" +"06/03/2022","145.38","146.90","147.97","144.46","88.57M","-3.86%" +"06/02/2022","151.21","147.83","151.27","146.86","72.35M","1.68%" +"06/01/2022","148.71","149.90","151.74","147.68","74.29M","-0.09%" +"05/31/2022","148.84","149.07","150.66","146.84","103.72M","-0.53%" +"05/27/2022","149.64","145.39","149.68","145.26","90.98M","4.08%" +"05/26/2022","143.78","137.39","144.34","137.14","90.60M","2.32%" +"05/25/2022","140.52","138.43","141.78","138.34","92.48M","0.11%" +"05/24/2022","140.36","140.81","141.97","137.33","104.13M","-1.92%" +"05/23/2022","143.11","137.79","143.26","137.65","117.73M","4.01%" +"05/20/2022","137.59","139.09","140.70","132.61","137.43M","0.17%" +"05/19/2022","137.35","139.88","141.66","136.60","136.10M","-2.46%" +"05/18/2022","140.82","146.85","147.36","139.90","109.74M","-5.64%" +"05/17/2022","149.24","148.86","149.77","146.68","78.34M","2.54%" +"05/16/2022","145.54","145.55","147.52","144.18","86.64M","-1.07%" +"05/13/2022","147.11","144.59","148.10","143.11","113.99M","3.19%" +"05/12/2022","142.56","142.77","146.20","138.80","182.60M","-2.69%" +"05/11/2022","146.50","153.50","155.45","145.81","142.69M","-5.18%" +"05/10/2022","154.51","155.52","156.74","152.93","115.37M","1.61%" +"05/09/2022","152.06","154.93","155.83","151.49","131.58M","-3.32%" +"05/06/2022","157.28","156.01","159.44","154.18","116.12M","0.33%" +"05/05/2022","156.77","163.85","164.08","154.95","130.53M","-5.57%" +"05/04/2022","166.02","159.67","166.48","159.26","108.26M","4.10%" +"05/03/2022","159.48","158.15","160.71","156.32","88.97M","0.96%" +"05/02/2022","157.96","156.71","158.23","153.27","123.06M","0.20%" +"04/29/2022","157.65","161.84","166.20","157.25","131.75M","-3.66%" +"04/28/2022","163.64","159.25","164.51","158.93","130.22M","4.52%" +"04/27/2022","156.57","155.91","159.79","155.38","88.06M","-0.15%" +"04/26/2022","156.80","162.25","162.34","156.72","95.62M","-3.73%" +"04/25/2022","162.88","161.12","163.17","158.46","96.05M","0.67%" +"04/22/2022","161.79","166.46","167.87","161.50","84.88M","-2.78%" +"04/21/2022","166.42","168.91","171.53","165.91","87.23M","-0.48%" +"04/20/2022","167.23","168.76","168.88","166.10","67.93M","-0.10%" +"04/19/2022","167.40","165.02","167.82","163.91","67.72M","1.41%" +"04/18/2022","165.07","163.92","166.60","163.57","69.02M","-0.13%" +"04/14/2022","165.29","170.62","171.27","165.04","75.33M","-3.00%" +"04/13/2022","170.40","167.39","171.04","166.77","70.62M","1.63%" +"04/12/2022","167.66","168.02","169.87","166.64","79.27M","1.15%" +"04/11/2022","165.75","168.71","169.03","165.50","72.25M","-2.55%" +"04/08/2022","170.09","171.78","171.78","169.20","76.58M","-1.19%" +"04/07/2022","172.14","171.16","173.36","169.85","77.59M","0.18%" +"04/06/2022","171.83","172.36","173.63","170.13","89.06M","-1.85%" +"04/05/2022","175.06","177.50","178.30","174.41","73.40M","-1.89%" +"04/04/2022","178.44","174.57","178.49","174.44","76.55M","2.37%" +"04/01/2022","174.31","174.03","174.88","171.94","78.75M","-0.17%" +"03/31/2022","174.61","177.84","178.03","174.40","103.05M","-1.78%" +"03/30/2022","177.77","178.55","179.61","176.70","92.63M","-0.66%" +"03/29/2022","178.96","176.69","179.01","176.34","100.59M","1.91%" +"03/28/2022","175.60","172.17","175.73","172.00","90.37M","0.50%" +"03/25/2022","174.72","173.88","175.28","172.75","80.55M","0.37%" +"03/24/2022","174.07","171.06","174.14","170.21","90.13M","2.27%" +"03/23/2022","170.21","167.99","172.64","167.65","98.06M","0.82%" +"03/22/2022","168.82","165.51","169.42","164.91","81.53M","2.08%" +"03/21/2022","165.38","163.51","166.35","163.01","95.81M","0.85%" +"03/18/2022","163.98","160.51","164.48","159.76","123.51M","2.09%" +"03/17/2022","160.62","158.61","161.00","157.63","75.62M","0.65%" +"03/16/2022","159.59","157.05","160.00","154.46","102.30M","2.90%" +"03/15/2022","155.09","150.90","155.57","150.38","92.96M","2.97%" +"03/14/2022","150.62","151.45","154.12","150.10","108.73M","-2.66%" +"03/11/2022","154.73","158.93","159.28","154.50","96.97M","-2.39%" +"03/10/2022","158.52","160.20","160.39","155.98","105.34M","-2.72%" +"03/09/2022","162.95","161.47","163.41","159.41","91.45M","3.50%" +"03/08/2022","157.44","158.82","162.88","155.80","131.15M","-1.17%" +"03/07/2022","159.30","163.36","165.02","159.04","96.42M","-2.37%" +"03/04/2022","163.17","164.49","165.55","162.10","83.82M","-1.84%" +"03/03/2022","166.23","168.47","168.91","165.55","76.68M","-0.20%" +"03/02/2022","166.56","164.39","167.36","162.95","79.72M","2.06%" +"03/01/2022","163.20","164.69","166.60","161.97","83.47M","-1.16%" +"02/28/2022","165.12","163.06","165.42","162.43","95.06M","0.16%" +"02/25/2022","164.85","163.84","165.12","160.87","91.97M","1.30%" +"02/24/2022","162.74","152.58","162.85","152.00","141.15M","1.67%" +"02/23/2022","160.07","165.54","166.15","159.75","90.01M","-2.59%" +"02/22/2022","164.32","164.98","166.69","162.15","91.16M","-1.78%" +"02/18/2022","167.30","169.82","170.54","166.19","82.77M","-0.94%" +"02/17/2022","168.88","171.03","171.91","168.47","69.59M","-2.13%" +"02/16/2022","172.55","171.85","173.34","170.05","61.18M","-0.14%" +"02/15/2022","172.79","170.97","172.95","170.25","64.29M","2.32%" +"02/14/2022","168.88","167.37","169.58","166.56","86.19M","0.14%" +"02/11/2022","168.64","172.33","173.08","168.04","98.67M","-2.02%" +"02/10/2022","172.12","174.14","175.48","171.55","90.87M","-2.36%" +"02/09/2022","176.28","176.05","176.65","174.90","71.29M","0.83%" +"02/08/2022","174.83","171.73","175.35","171.43","74.83M","1.85%" +"02/07/2022","171.66","172.86","173.95","170.95","77.25M","-0.42%" +"02/04/2022","172.39","171.68","174.10","170.68","82.47M","-0.29%" +"02/03/2022","172.90","174.48","176.24","172.12","89.42M","-1.67%" +"02/02/2022","175.84","174.75","175.88","173.33","84.91M","0.70%" +"02/01/2022","174.61","174.01","174.84","172.31","86.21M","-0.10%" +"01/31/2022","174.78","170.16","175.00","169.51","115.54M","2.61%" +"01/28/2022","170.33","165.71","170.35","162.80","179.94M","6.98%" +"01/27/2022","159.22","162.45","163.84","158.28","121.95M","-0.29%" +"01/26/2022","159.69","163.50","164.39","157.82","108.28M","-0.06%" +"01/25/2022","159.78","158.98","162.76","157.02","115.80M","-1.14%" +"01/24/2022","161.62","160.02","162.30","154.70","162.71M","-0.49%" +"01/21/2022","162.41","164.41","166.33","162.30","122.85M","-1.28%" +"01/20/2022","164.51","166.98","169.68","164.18","91.42M","-1.03%" +"01/19/2022","166.23","170.00","171.08","165.94","94.81M","-2.10%" +"01/18/2022","169.80","171.51","172.54","169.41","91.17M","-1.89%" +"01/14/2022","173.07","171.34","173.78","171.09","80.44M","0.51%" +"01/13/2022","172.19","175.78","176.62","171.79","84.51M","-1.90%" +"01/12/2022","175.53","176.12","177.18","174.82","74.81M","0.26%" +"01/11/2022","175.08","172.32","175.18","170.82","76.14M","1.68%" +"01/10/2022","172.19","169.08","172.50","168.17","106.77M","0.01%" +"01/07/2022","172.17","172.89","174.14","171.03","86.71M","0.10%" +"01/06/2022","172.00","172.70","175.30","171.64","96.90M","-1.67%" +"01/05/2022","174.92","179.61","180.17","174.64","94.54M","-2.66%" +"01/04/2022","179.70","182.63","182.94","179.12","99.31M","-1.27%" +"01/03/2022","182.01","177.83","182.88","177.71","104.70M","2.50%" \ No newline at end of file diff --git a/SAMPLE_DATA/GME Historical Data.csv b/SAMPLE_DATA/GME Historical Data.csv new file mode 100644 index 0000000..b37d96b --- /dev/null +++ b/SAMPLE_DATA/GME Historical Data.csv @@ -0,0 +1,640 @@ +"Date","Price","Open","High","Low","Vol.","Change %" +"07/19/2024","24.97","25.55","26.39","24.85","12.76M","-3.52%" +"07/18/2024","25.88","27.98","28.38","25.61","16.97M","-7.51%" +"07/17/2024","27.98","28.40","29.79","27.24","23.78M","-1.96%" +"07/16/2024","28.54","27.75","28.83","27.37","25.59M","5.70%" +"07/15/2024","27.00","25.98","27.20","25.65","17.14M","3.65%" +"07/12/2024","26.05","25.76","26.89","25.42","16.24M","1.88%" +"07/11/2024","25.57","25.43","26.02","25.02","13.03M","2.40%" +"07/10/2024","24.97","25.00","26.45","24.90","22.33M","1.50%" +"07/09/2024","24.60","24.60","25.18","24.00","9.52M","0.61%" +"07/08/2024","24.45","24.12","25.14","23.85","11.82M","1.12%" +"07/05/2024","24.18","24.18","25.08","23.82","11.78M","-0.78%" +"07/03/2024","24.37","24.03","24.89","23.65","11.83M","1.63%" +"07/02/2024","23.98","23.24","24.32","23.10","13.70M","2.79%" +"07/01/2024","23.33","23.35","23.78","22.31","30.69M","-5.51%" +"06/28/2024","24.69","25.02","26.17","24.31","20.21M","-1.59%" +"06/27/2024","25.09","24.10","26.69","24.06","34.87M","3.68%" +"06/26/2024","24.20","24.60","25.38","24.04","17.90M","-2.93%" +"06/25/2024","24.93","23.60","24.97","22.55","27.63M","5.41%" +"06/24/2024","23.65","23.26","24.83","23.24","22.16M","-1.17%" +"06/21/2024","23.93","25.24","25.81","23.51","28.00M","-6.49%" +"06/20/2024","25.59","24.25","25.93","23.65","36.03M","3.60%" +"06/18/2024","24.70","24.58","25.97","23.61","38.08M","-2.06%" +"06/17/2024","25.22","28.55","29.18","23.79","90.35M","-12.13%" +"06/14/2024","28.70","29.23","30.66","27.41","82.87M","-1.44%" +"06/13/2024","29.12","26.56","29.58","25.56","107.31M","14.38%" +"06/12/2024","25.46","29.17","33.70","24.83","147.99M","-16.50%" +"06/11/2024","30.49","24.40","30.92","22.79","146.91M","22.80%" +"06/10/2024","24.83","28.97","29.34","23.06","131.57M","-12.01%" +"06/07/2024","28.22","37.69","48.00","26.12","279.05M","-39.38%" +"06/06/2024","46.55","31.57","47.50","31.28","206.69M","47.45%" +"06/05/2024","31.57","26.30","31.84","26.11","73.16M","19.13%" +"06/04/2024","26.50","26.26","28.01","25.20","51.66M","-5.36%" +"06/03/2024","28.00","40.19","40.50","26.40","165.81M","21.00%" +"05/31/2024","23.14","22.58","23.72","21.68","22.17M","2.34%" +"05/30/2024","22.61","21.02","22.70","20.10","24.51M","6.45%" +"05/29/2024","21.24","22.00","22.98","21.05","26.92M","-10.68%" +"05/28/2024","23.78","23.10","26.66","21.15","105.08M","25.16%" +"05/24/2024","19.00","18.42","19.68","17.70","43.02M","3.71%" +"05/23/2024","18.32","21.40","21.40","18.26","30.56M","-13.26%" +"05/22/2024","21.12","21.56","22.25","20.76","43.52M","-4.52%" +"05/21/2024","22.12","22.24","22.85","20.04","49.25M","-4.41%" +"05/20/2024","23.14","21.54","23.40","18.94","55.26M","4.19%" +"05/17/2024","22.21","21.86","22.41","19.70","96.08M","-19.73%" +"05/16/2024","27.67","33.98","35.24","27.59","76.18M","-30.04%" +"05/15/2024","39.55","40.31","42.35","31.00","131.79M","-18.87%" +"05/14/2024","48.75","64.83","64.83","36.00","206.98M","60.10%" +"05/13/2024","30.45","26.34","38.20","24.77","187.24M","74.40%" +"05/10/2024","17.46","17.93","20.20","16.88","36.83M","-3.05%" +"05/09/2024","18.01","15.90","18.51","15.35","25.76M","13.13%" +"05/08/2024","15.92","16.05","17.24","15.33","24.78M","-2.39%" +"05/07/2024","16.31","15.85","17.29","14.93","24.31M","0.00%" +"05/06/2024","16.31","14.99","17.40","13.62","48.02M","-0.97%" +"05/03/2024","16.47","12.42","17.45","12.31","36.29M","29.08%" +"05/02/2024","12.76","11.11","12.88","10.96","8.65M","16.96%" +"05/01/2024","10.91","11.03","11.32","10.70","2.66M","-1.62%" +"04/30/2024","11.09","11.18","11.30","10.91","2.87M","-1.77%" +"04/29/2024","11.29","11.84","11.96","11.18","3.84M","-5.13%" +"04/26/2024","11.90","11.18","12.19","11.00","7.69M","6.16%" +"04/25/2024","11.21","10.70","11.21","10.48","4.90M","2.56%" +"04/24/2024","10.93","10.16","10.94","10.16","4.83M","7.58%" +"04/23/2024","10.16","10.05","10.28","10.01","2.51M","1.50%" +"04/22/2024","10.01","10.41","10.44","10.01","3.26M","-3.93%" +"04/19/2024","10.42","10.20","10.49","10.20","2.46M","1.07%" +"04/18/2024","10.31","10.32","10.63","10.27","2.18M","0.10%" +"04/17/2024","10.30","10.44","10.59","10.30","2.10M","-0.68%" +"04/16/2024","10.37","10.00","10.55","9.95","4.16M","3.08%" +"04/15/2024","10.06","10.81","10.84","10.06","5.09M","-6.59%" +"04/12/2024","10.77","11.21","11.23","10.76","3.21M","-4.61%" +"04/11/2024","11.29","10.91","11.39","10.80","3.80M","4.06%" +"04/10/2024","10.85","10.90","11.07","10.75","3.55M","-1.45%" +"04/09/2024","11.01","10.85","11.18","10.73","3.51M","1.66%" +"04/08/2024","10.83","11.30","11.36","10.83","3.66M","-3.73%" +"04/05/2024","11.25","11.30","11.50","10.97","4.76M","-2.43%" +"04/04/2024","11.53","11.50","11.82","11.38","4.35M","1.32%" +"04/03/2024","11.38","11.22","11.50","10.90","4.33M","0.89%" +"04/02/2024","11.28","11.84","11.99","11.26","6.33M","-5.92%" +"04/01/2024","11.99","12.63","12.67","11.55","9.21M","-4.23%" +"03/28/2024","12.52","13.19","13.19","12.47","8.47M","-4.94%" +"03/27/2024","13.17","13.05","13.72","12.80","17.87M","-15.03%" +"03/26/2024","15.50","15.15","15.63","14.75","17.25M","2.51%" +"03/25/2024","15.12","13.42","15.15","13.31","10.42M","15.42%" +"03/22/2024","13.10","13.76","13.95","13.01","4.41M","-4.10%" +"03/21/2024","13.66","13.56","14.02","13.48","3.38M","1.34%" +"03/20/2024","13.48","13.47","13.79","13.21","3.92M","0.52%" +"03/19/2024","13.41","13.76","13.89","13.30","3.89M","-3.59%" +"03/18/2024","13.91","14.25","14.30","13.90","3.49M","-2.32%" +"03/15/2024","14.24","14.55","14.83","14.21","4.48M","-2.67%" +"03/14/2024","14.63","14.80","15.02","14.40","2.53M","-1.61%" +"03/13/2024","14.87","14.69","15.20","14.62","2.90M","1.02%" +"03/12/2024","14.72","14.35","14.84","14.09","2.38M","2.01%" +"03/11/2024","14.43","14.64","14.94","14.36","2.11M","-1.50%" +"03/08/2024","14.65","15.40","15.63","14.52","3.17M","-4.00%" +"03/07/2024","15.26","15.26","15.51","15.05","2.11M","0.00%" +"03/06/2024","15.26","15.22","15.89","14.94","3.82M","1.73%" +"03/05/2024","15.00","14.95","15.28","14.78","3.15M","-1.45%" +"03/04/2024","15.22","14.93","15.59","14.83","4.37M","1.81%" +"03/01/2024","14.95","14.18","15.09","13.99","4.90M","4.77%" +"02/29/2024","14.27","14.34","14.65","14.03","2.64M","0.21%" +"02/28/2024","14.24","14.00","14.47","13.89","2.44M","0.21%" +"02/27/2024","14.21","13.70","14.29","13.68","2.80M","3.87%" +"02/26/2024","13.68","13.31","13.74","13.20","2.28M","1.26%" +"02/23/2024","13.51","13.30","13.79","13.12","2.32M","1.12%" +"02/22/2024","13.36","13.50","13.65","13.34","1.82M","-0.37%" +"02/21/2024","13.41","13.46","13.67","13.23","1.73M","-0.59%" +"02/20/2024","13.49","13.96","14.05","13.16","3.78M","-4.46%" +"02/16/2024","14.12","14.46","14.53","14.10","2.30M","-2.69%" +"02/15/2024","14.51","14.54","14.75","14.23","2.40M","0.69%" +"02/14/2024","14.41","14.33","14.43","14.05","2.50M","1.69%" +"02/13/2024","14.17","14.20","14.40","13.77","3.79M","-3.80%" +"02/12/2024","14.73","14.58","15.22","14.53","2.75M","0.48%" +"02/09/2024","14.66","14.37","15.23","14.30","3.58M","2.16%" +"02/08/2024","14.35","14.01","14.44","13.89","1.84M","1.99%" +"02/07/2024","14.07","14.12","14.30","13.78","1.95M","-0.21%" +"02/06/2024","14.10","13.60","14.30","13.43","3.05M","4.75%" +"02/05/2024","13.46","14.50","14.61","13.40","4.36M","-8.62%" +"02/02/2024","14.73","14.15","14.92","14.08","2.92M","2.15%" +"02/01/2024","14.42","14.34","14.42","14.02","2.22M","1.34%" +"01/31/2024","14.23","14.40","14.83","14.22","2.68M","-2.20%" +"01/30/2024","14.55","14.54","14.82","14.51","1.65M","-1.56%" +"01/29/2024","14.78","14.50","14.81","14.31","2.16M","2.00%" +"01/26/2024","14.49","14.44","14.72","14.41","2.29M","-0.21%" +"01/25/2024","14.52","13.97","14.54","13.92","3.64M","4.09%" +"01/24/2024","13.95","14.28","14.38","13.82","2.51M","-1.62%" +"01/23/2024","14.18","15.00","15.02","14.05","3.50M","-4.83%" +"01/22/2024","14.90","14.50","15.16","14.30","3.61M","2.69%" +"01/19/2024","14.51","14.36","14.60","14.09","2.40M","1.54%" +"01/18/2024","14.29","14.20","14.77","14.05","3.91M","1.49%" +"01/17/2024","14.08","13.86","14.11","13.71","2.71M","0.72%" +"01/16/2024","13.98","14.60","14.62","13.93","3.58M","-5.22%" +"01/12/2024","14.75","15.30","15.62","14.73","2.48M","-3.28%" +"01/11/2024","15.25","15.65","15.80","15.24","2.99M","-3.05%" +"01/10/2024","15.73","15.12","15.76","14.97","3.19M","3.76%" +"01/09/2024","15.16","15.59","15.62","15.12","3.11M","-3.99%" +"01/08/2024","15.79","15.78","16.12","15.70","3.03M","-1.07%" +"01/05/2024","15.96","16.16","16.52","15.96","2.62M","-2.44%" +"01/04/2024","16.36","16.51","16.75","16.31","2.67M","-1.98%" +"01/03/2024","16.69","16.30","16.83","15.90","4.19M","0.12%" +"01/02/2024","16.67","17.25","17.59","16.58","4.43M","-4.91%" +"12/29/2023","17.53","18.04","18.16","17.46","4.54M","-2.99%" +"12/28/2023","18.07","18.05","18.32","17.85","3.57M","-1.63%" +"12/27/2023","18.37","17.43","18.37","17.37","4.80M","5.82%" +"12/26/2023","17.36","16.98","17.41","16.82","3.08M","2.30%" +"12/22/2023","16.97","16.78","17.20","16.45","3.33M","-0.06%" +"12/21/2023","16.98","17.19","17.34","16.59","3.98M","0.30%" +"12/20/2023","16.93","17.53","18.38","16.89","5.55M","-4.46%" +"12/19/2023","17.72","17.89","18.59","17.23","5.45M","-0.78%" +"12/18/2023","17.86","17.24","18.51","17.10","7.35M","3.48%" +"12/15/2023","17.26","17.40","17.58","17.01","7.12M","-1.03%" +"12/14/2023","17.44","17.14","17.88","16.80","10.75M","4.49%" +"12/13/2023","16.69","15.22","16.80","15.19","9.09M","9.66%" +"12/12/2023","15.22","15.12","15.36","14.84","4.21M","1.00%" +"12/11/2023","15.07","15.45","15.69","14.98","4.96M","-3.09%" +"12/08/2023","15.55","15.83","16.48","15.47","10.40M","-4.95%" +"12/07/2023","16.36","13.71","16.52","13.56","19.84M","10.24%" +"12/06/2023","14.84","15.36","15.70","14.64","12.69M","-0.47%" +"12/05/2023","14.91","16.47","16.72","14.87","14.22M","-12.19%" +"12/04/2023","16.98","15.29","17.41","14.91","20.10M","10.98%" +"12/01/2023","15.30","14.52","15.99","14.50","13.38M","5.15%" +"11/30/2023","14.55","16.29","16.33","14.31","16.54M","-10.46%" +"11/29/2023","16.25","15.49","17.56","14.70","61.17M","20.46%" +"11/28/2023","13.49","11.90","13.55","11.89","14.19M","13.27%" +"11/27/2023","11.91","12.18","12.33","11.89","3.71M","-2.38%" +"11/24/2023","12.20","12.22","12.41","12.18","1.23M","-0.73%" +"11/22/2023","12.29","12.56","12.71","12.19","2.36M","-2.07%" +"11/21/2023","12.55","12.65","12.72","12.26","3.71M","-1.95%" +"11/20/2023","12.80","13.00","13.20","12.80","2.30M","-1.77%" +"11/17/2023","13.03","12.52","13.06","12.52","3.42M","3.99%" +"11/16/2023","12.53","13.14","13.19","12.52","3.43M","-5.58%" +"11/15/2023","13.27","13.15","13.50","13.03","4.12M","2.87%" +"11/14/2023","12.90","12.75","13.39","12.69","5.19M","6.26%" +"11/13/2023","12.14","12.50","12.53","11.82","4.32M","-3.19%" +"11/10/2023","12.54","12.81","12.97","12.35","3.88M","-1.26%" +"11/09/2023","12.70","13.25","13.32","12.70","2.75M","-4.37%" +"11/08/2023","13.28","13.51","13.76","13.28","1.71M","-2.64%" +"11/07/2023","13.64","13.47","13.79","13.23","2.35M","0.81%" +"11/06/2023","13.53","13.99","14.05","13.48","2.16M","-2.45%" +"11/03/2023","13.87","13.90","14.40","13.83","2.97M","1.69%" +"11/02/2023","13.64","13.37","13.69","13.27","3.57M","4.84%" +"11/01/2023","13.01","13.78","13.80","13.01","3.43M","-5.52%" +"10/31/2023","13.77","12.85","13.90","12.82","4.57M","7.58%" +"10/30/2023","12.80","13.15","13.27","12.59","3.48M","-2.44%" +"10/27/2023","13.12","13.51","13.61","13.02","2.48M","-2.81%" +"10/26/2023","13.50","13.73","13.80","13.41","2.04M","-1.53%" +"10/25/2023","13.71","14.01","14.01","13.60","1.97M","-2.35%" +"10/24/2023","14.04","13.59","14.30","13.55","3.74M","4.46%" +"10/23/2023","13.44","13.28","13.59","13.04","2.79M","0.00%" +"10/20/2023","13.44","13.18","13.80","13.12","3.66M","2.13%" +"10/19/2023","13.16","13.80","13.85","12.90","5.81M","-4.98%" +"10/18/2023","13.85","14.00","14.25","13.81","4.05M","-1.91%" +"10/17/2023","14.12","14.25","14.83","14.10","3.84M","-2.15%" +"10/16/2023","14.43","14.81","14.93","14.15","3.51M","-3.28%" +"10/13/2023","14.92","14.92","15.10","14.78","1.84M","-1.13%" +"10/12/2023","15.09","15.77","15.80","14.82","3.18M","-4.61%" +"10/11/2023","15.82","16.01","16.08","15.74","2.10M","-1.13%" +"10/10/2023","16.00","15.50","16.19","15.40","2.92M","3.90%" +"10/09/2023","15.40","14.77","15.50","14.72","2.28M","2.12%" +"10/06/2023","15.08","14.59","15.26","14.58","2.47M","2.52%" +"10/05/2023","14.71","14.70","14.98","14.58","1.95M","-1.08%" +"10/04/2023","14.87","14.77","14.94","14.44","2.59M","1.85%" +"10/03/2023","14.60","15.29","15.29","14.57","4.51M","-5.13%" +"10/02/2023","15.39","16.30","16.31","15.26","6.09M","-6.50%" +"09/29/2023","16.46","17.05","17.26","16.40","3.40M","-2.26%" +"09/28/2023","16.84","18.02","18.10","16.44","7.43M","-1.81%" +"09/27/2023","17.15","16.87","17.26","16.81","1.68M","2.20%" +"09/26/2023","16.78","17.38","17.82","16.78","2.73M","-5.04%" +"09/25/2023","17.67","17.00","17.72","16.85","2.18M","2.85%" +"09/22/2023","17.18","17.18","17.35","17.00","2.10M","0.94%" +"09/21/2023","17.02","17.28","17.32","16.65","2.91M","-2.85%" +"09/20/2023","17.52","17.63","17.93","17.45","2.13M","0.00%" +"09/19/2023","17.52","17.59","17.64","17.13","2.58M","-0.17%" +"09/18/2023","17.55","17.99","18.10","17.35","3.69M","-3.68%" +"09/15/2023","18.22","18.36","18.61","18.15","6.17M","-0.60%" +"09/14/2023","18.33","17.80","18.52","17.60","3.08M","2.92%" +"09/13/2023","17.81","17.31","17.93","17.27","3.01M","3.37%" +"09/12/2023","17.23","17.53","18.50","17.19","5.18M","1.23%" +"09/11/2023","17.02","17.85","17.85","16.90","3.54M","-3.90%" +"09/08/2023","17.71","18.15","18.50","17.35","4.69M","-6.25%" +"09/07/2023","18.89","19.13","19.48","17.61","5.02M","0.75%" +"09/06/2023","18.75","19.06","19.15","18.42","6.11M","-2.50%" +"09/05/2023","19.23","18.45","19.34","18.26","3.78M","4.40%" +"09/01/2023","18.42","18.66","18.73","18.32","2.14M","-0.70%" +"08/31/2023","18.55","18.41","19.42","18.15","4.67M","0.98%" +"08/30/2023","18.37","18.20","18.52","17.91","1.88M","0.71%" +"08/29/2023","18.24","17.60","18.55","17.60","2.71M","3.81%" +"08/28/2023","17.57","17.35","18.11","17.25","3.01M","2.57%" +"08/25/2023","17.13","16.50","17.18","16.45","3.42M","4.71%" +"08/24/2023","16.36","16.94","16.98","16.18","3.62M","-3.14%" +"08/23/2023","16.89","17.25","17.34","16.88","2.91M","-2.14%" +"08/22/2023","17.26","18.62","18.62","17.25","3.79M","-6.60%" +"08/21/2023","18.48","18.30","18.82","18.20","2.86M","0.65%" +"08/18/2023","18.36","18.18","18.66","18.14","2.03M","-0.11%" +"08/17/2023","18.38","18.79","18.81","18.30","2.06M","-1.13%" +"08/16/2023","18.59","19.18","19.34","18.55","3.02M","-3.83%" +"08/15/2023","19.33","19.77","19.78","19.09","2.29M","-3.16%" +"08/14/2023","19.96","19.75","20.01","19.08","3.33M","-1.14%" +"08/11/2023","20.19","20.03","20.38","19.97","1.52M","0.00%" +"08/10/2023","20.19","20.00","20.29","19.87","1.43M","1.30%" +"08/09/2023","19.93","20.85","20.85","19.82","2.93M","-3.91%" +"08/08/2023","20.74","20.70","20.90","20.28","1.43M","-1.57%" +"08/07/2023","21.07","20.90","21.24","20.48","1.44M","0.43%" +"08/04/2023","20.98","20.95","21.89","20.89","2.41M","0.24%" +"08/03/2023","20.93","20.88","21.18","20.74","1.32M","0.48%" +"08/02/2023","20.83","21.15","21.15","20.34","2.63M","-3.12%" +"08/01/2023","21.50","21.95","22.00","21.26","2.57M","-3.15%" +"07/31/2023","22.20","22.00","22.38","21.85","1.98M","1.23%" +"07/28/2023","21.93","22.02","22.49","21.79","2.65M","-1.31%" +"07/27/2023","22.22","22.94","23.49","22.13","3.37M","-2.11%" +"07/26/2023","22.70","22.70","22.99","22.48","1.49M","-0.66%" +"07/25/2023","22.85","23.10","23.10","22.53","1.67M","-0.82%" +"07/24/2023","23.04","22.42","23.04","22.20","2.97M","3.88%" +"07/21/2023","22.18","23.05","23.22","22.16","3.17M","-3.19%" +"07/20/2023","22.91","23.01","23.22","22.66","2.26M","-1.12%" +"07/19/2023","23.17","23.42","23.58","22.96","2.25M","0.39%" +"07/18/2023","23.08","22.72","23.80","22.68","2.35M","1.14%" +"07/17/2023","22.82","22.88","23.31","22.70","2.03M","-0.65%" +"07/14/2023","22.97","23.49","23.72","22.94","2.18M","-2.09%" +"07/13/2023","23.46","23.54","23.98","23.42","1.91M","0.09%" +"07/12/2023","23.44","24.25","24.31","23.44","1.74M","-1.97%" +"07/11/2023","23.91","23.20","24.44","23.20","3.06M","1.57%" +"07/10/2023","23.54","22.61","23.56","22.00","3.32M","3.65%" +"07/07/2023","22.71","22.97","23.53","22.67","2.45M","-0.53%" +"07/06/2023","22.83","23.52","23.57","22.82","2.39M","-4.48%" +"07/05/2023","23.90","24.64","24.85","23.79","2.27M","-4.05%" +"07/03/2023","24.91","24.29","25.11","24.21","1.81M","2.72%" +"06/30/2023","24.25","24.97","25.13","24.25","2.80M","-2.61%" +"06/29/2023","24.90","24.96","25.47","24.62","3.10M","-0.32%" +"06/28/2023","24.98","23.44","25.10","23.40","3.49M","5.94%" +"06/27/2023","23.58","23.29","23.60","23.00","2.14M","2.43%" +"06/26/2023","23.02","23.38","24.03","22.91","2.53M","-2.87%" +"06/23/2023","23.70","23.78","24.15","23.68","2.26M","-2.55%" +"06/22/2023","24.32","24.13","24.33","23.76","1.90M","-0.45%" +"06/21/2023","24.43","24.84","25.10","24.10","2.40M","-0.61%" +"06/20/2023","24.58","24.41","24.65","23.72","3.25M","0.08%" +"06/16/2023","24.56","25.02","25.11","24.42","4.44M","-1.13%" +"06/15/2023","24.84","25.41","26.17","24.64","5.50M","-3.35%" +"06/14/2023","25.70","26.72","27.08","24.90","7.24M","-4.64%" +"06/13/2023","26.95","26.20","27.65","25.03","17.16M","10.91%" +"06/12/2023","24.30","22.84","24.30","22.74","7.14M","7.14%" +"06/09/2023","22.68","21.78","23.43","21.50","10.34M","5.78%" +"06/08/2023","21.44","20.30","22.00","20.10","19.21M","-17.89%" +"06/07/2023","26.11","26.20","26.55","25.07","18.00M","5.75%" +"06/06/2023","24.69","24.01","25.25","24.00","3.98M","1.56%" +"06/05/2023","24.31","24.53","25.84","24.16","4.98M","-1.34%" +"06/02/2023","24.64","24.29","24.93","24.28","3.30M","2.24%" +"06/01/2023","24.10","24.04","24.66","23.78","3.84M","0.21%" +"05/31/2023","24.05","24.51","24.80","23.88","4.27M","-2.12%" +"05/30/2023","24.57","23.35","24.69","23.30","5.04M","5.68%" +"05/26/2023","23.25","23.47","23.71","23.06","2.26M","-0.43%" +"05/25/2023","23.35","23.50","23.69","22.71","2.49M","0.34%" +"05/24/2023","23.27","23.13","23.52","22.73","1.90M","0.47%" +"05/23/2023","23.16","23.89","23.90","22.80","3.79M","-4.34%" +"05/22/2023","24.21","22.10","24.36","21.99","6.25M","9.75%" +"05/19/2023","22.06","22.94","22.99","21.75","2.67M","-4.30%" +"05/18/2023","23.05","22.90","23.30","22.68","2.14M","0.79%" +"05/17/2023","22.87","21.99","23.25","21.90","4.57M","4.00%" +"05/16/2023","21.99","21.50","22.10","21.42","2.50M","1.71%" +"05/15/2023","21.62","20.62","21.63","20.49","2.60M","4.49%" +"05/12/2023","20.69","20.83","20.98","20.23","2.01M","-0.91%" +"05/11/2023","20.88","20.69","21.16","20.51","1.65M","0.58%" +"05/10/2023","20.76","20.45","20.96","20.38","2.14M","2.57%" +"05/09/2023","20.24","20.16","20.65","20.12","1.52M","-1.32%" +"05/08/2023","20.51","20.46","20.99","20.09","2.40M","0.44%" +"05/05/2023","20.42","19.62","20.88","19.51","4.36M","5.53%" +"05/04/2023","19.35","19.25","19.48","18.92","2.04M","2.38%" +"05/03/2023","18.90","18.56","19.20","18.53","3.18M","1.72%" +"05/02/2023","18.58","18.45","18.58","18.06","1.92M","0.16%" +"05/01/2023","18.55","19.16","19.25","18.46","2.36M","-3.84%" +"04/28/2023","19.29","18.92","19.72","18.88","2.84M","1.85%" +"04/27/2023","18.94","18.75","19.34","18.72","2.24M","1.55%" +"04/26/2023","18.65","18.98","19.23","18.65","2.29M","-1.84%" +"04/25/2023","19.00","19.74","20.04","18.91","2.56M","-4.67%" +"04/24/2023","19.93","20.15","20.41","19.81","2.74M","-2.73%" +"04/21/2023","20.49","20.20","20.62","20.10","2.09M","1.34%" +"04/20/2023","20.22","20.88","21.57","20.06","2.98M","-5.11%" +"04/19/2023","21.31","21.28","21.87","20.96","2.54M","-1.39%" +"04/18/2023","21.61","22.14","22.32","21.50","2.75M","-3.01%" +"04/17/2023","22.28","22.27","22.68","22.14","2.07M","-0.80%" +"04/14/2023","22.46","22.74","23.25","22.32","2.31M","-0.40%" +"04/13/2023","22.55","22.50","22.85","22.33","1.80M","1.30%" +"04/12/2023","22.26","22.90","23.28","22.26","2.14M","-1.90%" +"04/11/2023","22.69","22.57","23.17","22.42","2.54M","1.43%" +"04/10/2023","22.37","21.85","22.43","21.82","2.18M","-0.13%" +"04/06/2023","22.40","22.00","22.67","21.77","2.51M","1.50%" +"04/05/2023","22.07","22.47","22.47","21.23","3.64M","-1.25%" +"04/04/2023","22.35","22.75","23.14","22.09","3.42M","-3.54%" +"04/03/2023","23.17","22.94","23.85","22.66","4.27M","0.65%" +"03/31/2023","23.02","22.35","23.07","22.15","3.88M","2.31%" +"03/30/2023","22.50","22.60","22.83","22.11","3.48M","0.18%" +"03/29/2023","22.46","23.08","23.70","22.22","4.16M","-2.98%" +"03/28/2023","23.15","22.97","23.54","22.22","5.71M","0.65%" +"03/27/2023","23.00","23.99","24.01","22.69","4.58M","-4.09%" +"03/24/2023","23.98","22.32","23.99","22.10","8.77M","6.20%" +"03/23/2023","22.58","22.57","24.59","22.13","11.17M","-5.40%" +"03/22/2023","23.87","26.60","27.00","23.05","66.76M","35.24%" +"03/21/2023","17.65","17.15","18.35","17.14","15.88M","4.62%" +"03/20/2023","16.87","16.65","17.27","16.25","4.46M","1.63%" +"03/17/2023","16.60","16.62","16.72","15.92","5.11M","-0.95%" +"03/16/2023","16.76","16.00","16.77","15.53","4.09M","5.08%" +"03/15/2023","15.95","16.50","16.69","15.69","4.54M","-5.68%" +"03/14/2023","16.91","17.37","17.41","16.40","3.08M","0.96%" +"03/13/2023","16.75","16.77","17.35","16.52","2.96M","-2.90%" +"03/10/2023","17.25","17.53","17.77","16.85","2.85M","-1.54%" +"03/09/2023","17.52","18.07","18.38","17.48","2.65M","-3.58%" +"03/08/2023","18.17","18.05","18.38","17.63","3.28M","0.61%" +"03/07/2023","18.06","18.54","18.83","18.06","2.38M","-3.16%" +"03/06/2023","18.65","18.52","19.50","18.52","2.82M","-0.27%" +"03/03/2023","18.70","18.19","19.10","18.10","2.51M","2.80%" +"03/02/2023","18.19","18.15","18.40","17.62","2.63M","0.22%" +"03/01/2023","18.15","18.92","19.09","18.14","4.21M","-5.62%" +"02/28/2023","19.23","19.06","19.52","18.95","3.37M","0.68%" +"02/27/2023","19.10","19.61","19.70","18.89","4.01M","-2.25%" +"02/24/2023","19.54","19.71","20.08","19.54","2.28M","-2.98%" +"02/23/2023","20.14","20.66","20.87","19.53","2.86M","-1.85%" +"02/22/2023","20.52","20.53","21.19","20.33","2.16M","-0.68%" +"02/21/2023","20.66","21.33","21.83","20.63","3.10M","-6.05%" +"02/17/2023","21.99","21.27","22.07","21.15","2.85M","1.81%" +"02/16/2023","21.60","21.25","22.42","20.85","3.88M","-0.92%" +"02/15/2023","21.80","19.80","21.80","19.59","7.15M","9.71%" +"02/14/2023","19.87","19.31","20.01","19.10","2.75M","0.91%" +"02/13/2023","19.69","19.30","19.94","19.01","2.30M","2.18%" +"02/10/2023","19.27","19.56","20.04","19.05","2.90M","-2.03%" +"02/09/2023","19.67","21.25","21.65","19.67","4.50M","-6.78%" +"02/08/2023","21.10","21.43","21.55","20.61","2.85M","-0.57%" +"02/07/2023","21.22","23.00","23.05","20.50","9.09M","-11.06%" +"02/06/2023","23.86","21.88","24.88","21.77","8.71M","7.24%" +"02/03/2023","22.25","22.01","23.93","21.80","4.94M","-1.98%" +"02/02/2023","22.70","22.44","24.40","22.22","7.66M","3.99%" +"02/01/2023","21.83","21.49","22.12","20.55","4.52M","-0.18%" +"01/31/2023","21.87","21.41","22.05","21.30","3.13M","2.92%" +"01/30/2023","21.25","22.50","23.48","21.13","4.95M","-6.88%" +"01/27/2023","22.82","19.80","23.31","19.41","11.90M","14.04%" +"01/26/2023","20.01","20.61","21.17","19.38","3.52M","-1.09%" +"01/25/2023","20.23","20.59","20.84","19.53","3.52M","-5.47%" +"01/24/2023","21.40","21.30","22.09","21.00","2.38M","-1.20%" +"01/23/2023","21.66","19.50","22.49","19.37","7.18M","10.45%" +"01/20/2023","19.61","19.05","20.07","18.90","3.56M","2.99%" +"01/19/2023","19.04","20.44","20.45","18.82","4.52M","-8.42%" +"01/18/2023","20.79","22.01","22.15","20.50","5.63M","-4.63%" +"01/17/2023","21.80","20.49","21.94","20.37","5.41M","6.39%" +"01/13/2023","20.49","19.88","21.11","19.80","5.49M","-0.68%" +"01/12/2023","20.63","19.04","20.63","18.34","5.88M","8.35%" +"01/11/2023","19.04","18.19","20.05","17.86","8.41M","7.15%" +"01/10/2023","17.77","16.30","18.09","16.25","4.40M","8.49%" +"01/09/2023","16.38","16.65","17.13","16.36","3.52M","-0.49%" +"01/06/2023","16.46","16.00","16.57","15.41","4.82M","1.48%" +"01/05/2023","16.22","17.06","17.26","15.89","6.07M","-6.35%" +"01/04/2023","17.32","17.25","17.93","16.90","3.94M","0.70%" +"01/03/2023","17.20","18.64","19.26","17.09","5.14M","-6.83%" +"12/30/2022","18.46","17.95","18.58","17.90","2.67M","0.71%" +"12/29/2022","18.33","18.12","18.57","17.75","3.44M","2.29%" +"12/28/2022","17.92","18.29","18.70","16.98","5.67M","-1.54%" +"12/27/2022","18.20","19.91","19.99","18.00","4.23M","-9.36%" +"12/23/2022","20.08","20.00","20.63","19.65","3.17M","1.36%" +"12/22/2022","19.81","20.50","20.50","18.50","5.34M","-3.65%" +"12/21/2022","20.56","20.40","20.90","20.18","2.79M","1.48%" +"12/20/2022","20.26","19.86","21.32","19.62","4.48M","1.71%" +"12/19/2022","19.92","20.55","20.89","19.59","3.70M","-4.23%" +"12/16/2022","20.80","20.48","21.11","20.01","9.38M","1.07%" +"12/15/2022","20.58","20.74","21.44","20.24","6.44M","-2.23%" +"12/14/2022","21.05","21.19","22.00","21.01","4.60M","0.24%" +"12/13/2022","21.00","23.55","23.70","20.83","6.31M","-7.37%" +"12/12/2022","22.67","22.66","23.15","22.18","3.75M","0.18%" +"12/09/2022","22.63","24.59","24.59","22.59","5.33M","-8.71%" +"12/08/2022","24.79","22.00","25.00","21.97","10.25M","11.37%" +"12/07/2022","22.26","23.40","23.61","21.97","10.08M","-4.83%" +"12/06/2022","23.39","25.41","25.58","23.11","7.70M","-8.49%" +"12/05/2022","25.56","27.31","27.48","25.44","4.97M","-7.12%" +"12/02/2022","27.52","26.25","27.87","26.11","4.58M","3.46%" +"12/01/2022","26.60","26.00","27.50","25.18","7.62M","1.49%" +"11/30/2022","26.21","25.90","26.23","24.91","3.73M","2.38%" +"11/29/2022","25.60","25.58","26.35","25.32","2.03M","1.23%" +"11/28/2022","25.29","25.79","26.44","25.21","2.45M","-3.36%" +"11/25/2022","26.17","26.50","27.05","26.14","1.12M","-1.99%" +"11/23/2022","26.70","25.92","27.14","25.92","2.74M","1.52%" +"11/22/2022","26.30","25.13","26.45","24.70","4.24M","4.53%" +"11/21/2022","25.16","26.66","27.83","24.85","4.44M","-8.84%" +"11/18/2022","27.60","28.16","28.70","26.83","3.09M","-0.58%" +"11/17/2022","27.76","26.30","27.76","26.15","2.48M","2.28%" +"11/16/2022","27.14","26.62","27.35","26.37","2.45M","-1.63%" +"11/15/2022","27.59","26.59","28.24","26.27","5.39M","5.91%" +"11/14/2022","26.05","26.30","27.38","25.61","4.35M","-0.19%" +"11/11/2022","26.10","24.78","26.12","24.15","3.99M","4.90%" +"11/10/2022","24.88","24.62","25.70","23.91","6.11M","7.66%" +"11/09/2022","23.11","24.55","24.67","21.89","8.46M","-8.07%" +"11/08/2022","25.14","25.33","25.85","24.11","4.70M","-2.41%" +"11/07/2022","25.76","26.25","26.30","24.80","3.30M","-2.83%" +"11/04/2022","26.51","26.60","27.03","25.34","4.14M","0.84%" +"11/03/2022","26.29","26.00","27.28","26.00","3.38M","-1.24%" +"11/02/2022","26.62","27.90","28.75","26.50","4.14M","-6.23%" +"11/01/2022","28.39","29.40","29.69","27.62","5.15M","0.28%" +"10/31/2022","28.31","31.22","34.99","27.91","24.03M","0.50%" +"10/28/2022","28.17","26.88","28.79","26.42","8.09M","8.64%" +"10/27/2022","25.93","25.75","26.33","25.20","2.42M","2.01%" +"10/26/2022","25.42","26.37","27.48","25.32","3.87M","-5.40%" +"10/25/2022","26.87","24.82","27.79","24.80","7.79M","8.74%" +"10/24/2022","24.71","25.00","25.19","24.11","3.11M","-2.33%" +"10/21/2022","25.30","24.15","25.33","24.10","3.04M","3.65%" +"10/20/2022","24.41","24.65","25.45","24.07","5.15M","-0.53%" +"10/19/2022","24.54","26.00","26.18","24.27","5.32M","-7.99%" +"10/18/2022","26.67","27.10","27.74","26.13","4.40M","2.73%" +"10/17/2022","25.96","25.37","26.41","25.24","3.17M","5.40%" +"10/14/2022","24.63","25.77","26.37","24.63","2.78M","-3.64%" +"10/13/2022","25.56","24.42","26.59","23.91","3.52M","0.79%" +"10/12/2022","25.36","25.96","26.89","25.27","3.28M","0.36%" +"10/11/2022","25.27","24.87","26.30","23.95","4.20M","1.08%" +"10/10/2022","25.00","25.37","26.50","24.75","2.92M","-1.38%" +"10/07/2022","25.35","25.84","25.84","24.42","3.27M","-2.46%" +"10/06/2022","25.99","26.29","27.00","25.80","2.42M","-1.52%" +"10/05/2022","26.39","26.77","26.98","25.43","2.99M","-4.38%" +"10/04/2022","27.60","25.95","27.83","25.95","4.58M","8.75%" +"10/03/2022","25.38","25.14","25.63","24.21","2.65M","0.99%" +"09/30/2022","25.13","25.03","25.82","24.44","3.15M","-1.30%" +"09/29/2022","25.46","27.08","27.69","24.69","4.12M","-6.77%" +"09/28/2022","27.31","25.89","27.50","25.62","2.63M","4.52%" +"09/27/2022","26.13","25.47","26.39","25.13","4.49M","6.74%" +"09/26/2022","24.48","24.66","25.87","24.12","3.44M","-2.24%" +"09/23/2022","25.04","24.15","25.15","24.06","3.62M","1.38%" +"09/22/2022","24.70","27.17","27.27","24.38","4.35M","-8.04%" +"09/21/2022","26.86","27.45","28.99","26.77","3.86M","-2.47%" +"09/20/2022","27.54","29.28","29.33","27.17","3.15M","-4.90%" +"09/19/2022","28.96","28.33","29.65","28.15","3.40M","1.12%" +"09/16/2022","28.64","28.33","28.80","27.78","4.66M","0.10%" +"09/15/2022","28.61","27.86","29.07","27.86","3.33M","1.71%" +"09/14/2022","28.13","27.56","28.45","26.65","3.61M","1.01%" +"09/13/2022","27.85","27.40","28.61","27.32","3.66M","-4.75%" +"09/12/2022","29.24","29.03","30.34","28.00","6.18M","1.11%" +"09/09/2022","28.92","26.30","29.08","26.10","7.92M","11.96%" +"09/08/2022","25.83","25.00","26.74","24.07","14.14M","7.45%" +"09/07/2022","24.04","24.73","25.19","23.42","12.50M","-4.38%" +"09/06/2022","25.14","25.75","26.72","24.67","7.01M","-8.11%" +"09/02/2022","27.36","28.26","28.74","26.93","4.68M","-0.98%" +"09/01/2022","27.63","28.00","28.91","26.95","5.29M","-3.53%" +"08/31/2022","28.64","29.25","29.96","28.26","5.16M","-4.02%" +"08/30/2022","29.84","31.62","31.87","29.42","5.06M","-5.42%" +"08/29/2022","31.55","30.48","32.75","30.38","4.29M","1.97%" +"08/26/2022","30.94","31.50","32.38","30.63","4.30M","-3.19%" +"08/25/2022","31.96","32.84","32.89","31.50","4.73M","-1.66%" +"08/24/2022","32.50","34.00","34.94","32.44","5.62M","-3.07%" +"08/23/2022","33.53","34.70","34.99","33.45","4.84M","-2.81%" +"08/22/2022","34.50","34.31","36.20","34.20","5.80M","-5.45%" +"08/19/2022","36.49","35.18","37.19","34.67","9.55M","-3.80%" +"08/18/2022","37.93","39.27","40.07","37.34","8.15M","-6.39%" +"08/17/2022","40.52","42.17","44.36","40.41","9.77M","-3.96%" +"08/16/2022","42.19","39.17","45.53","38.60","23.60M","6.33%" +"08/15/2022","39.68","39.75","40.39","38.81","5.24M","-2.60%" +"08/12/2022","40.74","40.00","41.43","39.15","5.12M","3.27%" +"08/11/2022","39.45","40.91","41.97","39.35","5.14M","-2.66%" +"08/10/2022","40.53","42.00","42.00","38.63","5.43M","0.40%" +"08/09/2022","40.37","42.14","43.19","39.00","6.95M","-7.09%" +"08/08/2022","43.45","41.29","47.99","40.75","18.05M","8.57%" +"08/05/2022","40.02","37.37","40.43","36.56","8.12M","4.33%" +"08/04/2022","38.36","38.34","39.89","37.89","5.42M","1.13%" +"08/03/2022","37.93","36.22","38.01","36.00","5.19M","5.83%" +"08/02/2022","35.84","35.90","36.80","35.12","4.70M","3.05%" +"08/01/2022","34.78","33.80","35.71","33.77","4.20M","2.26%" +"07/29/2022","34.01","33.68","34.79","33.06","3.99M","0.50%" +"07/28/2022","33.84","33.39","34.43","32.66","3.21M","0.18%" +"07/27/2022","33.78","32.96","34.12","32.16","4.25M","4.16%" +"07/26/2022","32.43","32.87","33.31","32.10","4.87M","-4.56%" +"07/25/2022","33.98","35.00","35.51","33.25","5.69M","-5.03%" +"07/22/2022","35.78","36.88","38.70","34.93","10.06M","-6.74%" +"07/21/2022","38.37","39.93","40.00","37.29","9.28M","-3.33%" +"07/20/2022","39.69","38.50","40.41","38.35","11.40M","4.65%" +"07/19/2022","37.92","37.44","39.21","36.59","12.83M","3.45%" +"07/18/2022","36.66","36.25","37.40","35.77","11.16M","3.53%" +"07/15/2022","35.41","34.86","35.59","33.51","9.83M","3.99%" +"07/14/2022","34.05","34.80","37.99","34.05","20.97M","-3.60%" +"07/13/2022","35.32","33.75","36.34","33.75","13.70M","3.03%" +"07/12/2022","34.28","32.70","35.65","31.82","16.90M","5.40%" +"07/11/2022","32.52","32.14","32.94","31.16","7.56M","1.21%" +"07/08/2022","32.13","31.67","33.17","30.63","13.20M","-4.87%" +"07/07/2022","33.78","31.12","33.88","30.45","30.31M","15.06%" +"07/06/2022","29.36","30.17","30.57","28.34","9.99M","-2.33%" +"07/05/2022","30.06","30.38","30.62","29.75","6.05M","-2.58%" +"07/01/2022","30.85","30.28","31.29","29.82","6.62M","0.92%" +"06/30/2022","30.58","29.84","31.65","29.44","6.72M","-0.46%" +"06/29/2022","30.72","30.39","31.62","29.90","6.83M","-1.22%" +"06/28/2022","31.09","32.75","32.83","30.57","6.62M","-4.09%" +"06/27/2022","32.42","34.12","34.26","31.83","9.75M","-4.08%" +"06/24/2022","33.80","35.75","37.09","32.88","17.00M","-4.80%" +"06/23/2022","35.51","35.41","36.00","34.18","6.68M","2.57%" +"06/22/2022","34.62","34.67","36.18","34.11","7.85M","-1.30%" +"06/21/2022","35.07","34.56","36.35","33.88","12.51M","3.80%" +"06/17/2022","33.78","31.72","33.96","31.58","12.34M","7.48%" +"06/16/2022","31.43","31.24","32.32","30.15","10.00M","-2.75%" +"06/15/2022","32.32","31.24","32.99","30.91","10.76M","2.47%" +"06/14/2022","31.54","29.39","32.00","29.02","12.74M","6.70%" +"06/13/2022","29.56","30.13","31.14","28.58","13.79M","-8.40%" +"06/10/2022","32.27","31.50","32.98","30.78","11.83M","0.09%" +"06/09/2022","32.24","34.70","34.97","31.83","13.14M","-7.03%" +"06/08/2022","34.68","35.35","38.25","33.96","24.47M","-5.30%" +"06/07/2022","36.63","32.50","37.47","31.58","24.97M","14.36%" +"06/06/2022","32.03","33.83","34.03","31.76","9.53M","-4.19%" +"06/03/2022","33.42","32.50","34.53","31.06","18.23M","-0.22%" +"06/02/2022","33.50","29.75","34.13","28.89","27.92M","10.38%" +"06/01/2022","30.35","30.70","32.40","29.25","14.99M","-2.68%" +"05/31/2022","31.18","34.30","34.98","30.13","19.08M","-9.09%" +"05/27/2022","34.30","35.25","35.92","31.75","30.05M","6.81%" +"05/26/2022","32.12","29.00","37.12","28.67","57.89M","11.54%" +"05/25/2022","28.79","22.53","28.87","22.53","40.06M","29.19%" +"05/24/2022","22.29","23.51","23.55","21.67","8.88M","-7.26%" +"05/23/2022","24.03","24.14","24.32","22.88","6.99M","0.49%" +"05/20/2022","23.92","24.95","25.60","22.44","9.97M","-3.56%" +"05/19/2022","24.80","22.81","25.49","22.54","12.72M","8.43%" +"05/18/2022","22.87","24.09","24.96","22.54","11.56M","-8.87%" +"05/17/2022","25.09","23.48","25.09","22.80","10.44M","9.35%" +"05/16/2022","22.95","24.70","24.79","22.69","11.58M","-6.70%" +"05/13/2022","24.60","24.75","26.69","23.76","23.93M","9.85%" +"05/12/2022","22.39","20.76","27.01","19.44","40.14M","10.13%" +"05/11/2022","20.33","23.37","23.82","20.00","16.68M","-13.02%" +"05/10/2022","23.38","25.75","26.51","22.00","16.60M","-5.35%" +"05/09/2022","24.70","27.69","27.69","24.52","13.26M","-13.87%" +"05/06/2022","28.67","29.32","30.14","27.56","7.16M","-3.72%" +"05/05/2022","29.78","30.99","31.17","28.78","7.02M","-6.26%" +"05/04/2022","31.77","29.80","31.94","28.93","6.65M","5.52%" +"05/03/2022","30.11","29.62","31.11","28.60","7.31M","0.72%" +"05/02/2022","29.89","30.91","31.35","28.17","10.17M","-4.40%" +"04/29/2022","31.27","31.83","32.72","30.75","5.14M","-3.28%" +"04/28/2022","32.33","32.57","33.15","30.13","7.08M","-0.41%" +"04/27/2022","32.46","31.82","33.17","31.15","5.22M","1.76%" +"04/26/2022","31.90","33.91","34.20","31.54","6.18M","-6.14%" +"04/25/2022","33.99","33.85","34.93","33.32","6.14M","-1.64%" +"04/22/2022","34.56","35.64","36.58","33.89","6.28M","-2.36%" +"04/21/2022","35.39","37.50","38.28","34.98","6.74M","-4.90%" +"04/20/2022","37.21","38.00","38.08","36.66","4.65M","-2.37%" +"04/19/2022","38.12","35.71","38.24","34.96","9.42M","7.78%" +"04/18/2022","35.37","37.50","37.81","34.31","9.87M","-6.17%" +"04/14/2022","37.69","37.32","39.13","36.81","10.00M","0.05%" +"04/13/2022","37.67","36.03","38.03","35.51","8.03M","4.02%" +"04/12/2022","36.22","36.63","38.06","35.42","8.00M","-1.40%" +"04/11/2022","36.73","35.76","37.06","35.15","9.81M","0.51%" +"04/08/2022","36.55","37.27","37.68","35.51","10.37M","-2.54%" +"04/07/2022","37.50","38.53","39.17","35.39","15.31M","-4.24%" +"04/06/2022","39.16","37.75","39.82","37.42","16.27M","1.99%" +"04/05/2022","38.40","42.00","42.11","38.00","15.83M","-10.04%" +"04/04/2022","42.68","41.74","43.31","39.13","18.56M","3.47%" +"04/01/2022","41.25","47.22","47.44","38.81","52.76M","-0.95%" +"03/31/2022","41.65","40.78","43.94","39.63","44.97M","-0.16%" +"03/30/2022","41.71","43.75","45.83","41.25","36.68M","-7.25%" +"03/29/2022","44.97","47.06","49.85","40.75","72.05M","-5.11%" +"03/28/2022","47.40","37.99","47.71","37.89","65.27M","24.77%" +"03/25/2022","37.99","35.01","39.54","34.55","53.54M","6.71%" +"03/24/2022","35.60","33.50","35.87","31.69","36.40M","0.99%" +"03/23/2022","35.25","32.50","37.73","31.64","98.40M","14.50%" +"03/22/2022","30.78","23.85","31.45","23.61","60.07M","30.72%" +"03/21/2022","23.55","22.50","24.85","22.44","15.81M","3.76%" +"03/18/2022","22.70","19.93","24.36","19.73","35.69M","3.52%" +"03/17/2022","21.92","21.27","22.40","20.86","13.80M","0.97%" +"03/16/2022","21.72","21.28","22.50","20.50","10.62M","5.11%" +"03/15/2022","20.66","20.52","21.89","19.67","14.12M","5.80%" +"03/14/2022","19.53","23.36","23.58","19.40","18.13M","-15.73%" +"03/11/2022","23.17","25.67","25.73","23.17","8.82M","-7.83%" +"03/10/2022","25.14","25.98","26.01","24.56","5.58M","-4.42%" +"03/09/2022","26.30","26.75","27.22","25.88","5.60M","2.14%" +"03/08/2022","25.75","25.26","27.25","24.27","8.54M","3.68%" +"03/07/2022","24.84","28.75","28.75","24.03","12.59M","-11.02%" +"03/04/2022","27.92","29.50","30.13","27.65","5.92M","-5.70%" +"03/03/2022","29.60","30.74","30.93","29.31","4.38M","-2.92%" +"03/02/2022","30.49","29.88","30.67","29.09","5.24M","2.48%" +"03/01/2022","29.75","30.55","31.47","29.59","4.38M","-3.50%" +"02/28/2022","30.83","30.25","31.57","29.22","6.46M","4.01%" +"02/25/2022","29.65","30.89","31.24","29.12","6.84M","-4.82%" +"02/24/2022","31.15","26.38","31.43","26.03","9.02M","8.45%" +"02/23/2022","28.72","30.31","30.84","28.57","5.39M","-2.70%" +"02/22/2022","29.51","29.55","30.83","28.55","6.16M","-2.86%" +"02/18/2022","30.38","31.05","31.41","29.53","6.21M","-1.52%" +"02/17/2022","30.85","31.69","32.71","30.56","6.26M","-3.83%" +"02/16/2022","32.08","31.11","33.21","30.98","8.01M","1.72%" +"02/15/2022","31.54","30.24","31.81","29.82","7.92M","7.75%" +"02/14/2022","29.27","30.73","31.38","29.04","9.10M","-5.76%" +"02/11/2022","31.06","30.62","32.47","30.19","11.30M","1.45%" +"02/10/2022","30.62","29.49","32.94","29.00","14.83M","-1.46%" +"02/09/2022","31.07","28.52","31.18","28.25","15.47M","7.52%" +"02/08/2022","28.90","25.44","29.42","25.14","19.84M","12.96%" +"02/07/2022","25.58","25.75","26.35","24.69","7.04M","0.00%" +"02/04/2022","25.58","24.75","26.00","23.77","7.63M","3.13%" +"02/03/2022","24.81","25.38","26.74","24.43","10.71M","-0.81%" +"02/02/2022","25.01","27.59","27.96","24.51","13.12M","-11.15%" +"02/01/2022","28.15","28.25","29.16","27.07","13.85M","3.37%" +"01/31/2022","27.23","24.47","27.45","24.47","14.00M","11.26%" +"01/28/2022","24.48","23.85","24.50","21.90","16.43M","4.69%" +"01/27/2022","23.38","26.03","26.75","23.22","14.68M","-9.43%" +"01/26/2022","25.82","25.27","29.75","25.08","33.33M","3.48%" +"01/25/2022","24.95","24.23","26.24","23.75","14.30M","-0.36%" +"01/24/2022","25.04","24.75","25.72","21.57","25.07M","-5.84%" +"01/21/2022","26.59","25.25","27.55","23.18","22.12M","3.59%" +"01/20/2022","25.67","26.98","28.80","25.40","11.68M","-3.66%" +"01/19/2022","26.64","27.50","28.26","26.10","9.61M","-2.15%" +"01/18/2022","27.23","28.28","28.44","26.10","15.04M","-6.64%" +"01/14/2022","29.16","30.04","30.58","28.00","15.40M","-4.76%" +"01/13/2022","30.62","32.13","32.63","30.42","8.90M","-4.36%" +"01/12/2022","32.01","32.50","32.83","31.61","6.30M","-1.72%" +"01/11/2022","32.58","32.53","34.20","31.85","10.33M","-0.65%" +"01/10/2022","32.79","33.75","33.92","30.00","22.05M","-6.73%" +"01/07/2022","35.15","39.94","40.08","33.13","48.55M","7.32%" +"01/06/2022","32.76","33.21","34.42","30.28","24.21M","1.28%" +"01/05/2022","32.34","37.10","37.21","32.29","13.59M","-13.12%" +"01/04/2022","37.23","38.04","38.25","35.76","7.34M","-2.57%" +"01/03/2022","38.21","37.31","39.85","37.30","5.67M","3.00%" \ No newline at end of file diff --git a/SAMPLE_DATA/GOOG Historical Data.csv b/SAMPLE_DATA/GOOG Historical Data.csv new file mode 100644 index 0000000..731b1b2 --- /dev/null +++ b/SAMPLE_DATA/GOOG Historical Data.csv @@ -0,0 +1,640 @@ +"Date","Price","Open","High","Low","Vol.","Change %" +"07/19/2024","179.39","180.37","181.97","178.86","14.49M","0.09%" +"07/18/2024","179.22","183.54","184.05","178.21","17.88M","-1.86%" +"07/17/2024","182.62","184.68","185.23","181.62","17.38M","-1.55%" +"07/16/2024","185.50","188.96","190.34","185.12","12.76M","-1.43%" +"07/15/2024","188.19","186.49","189.90","186.49","12.19M","0.75%" +"07/12/2024","186.78","186.92","188.69","186.14","14.45M","-0.28%" +"07/11/2024","187.30","191.34","192.41","186.82","16.45M","-2.78%" +"07/10/2024","192.66","190.75","193.31","190.62","12.05M","1.17%" +"07/09/2024","190.44","191.75","192.86","190.23","10.22M","-0.02%" +"07/08/2024","190.48","191.37","191.68","189.32","12.10M","-0.77%" +"07/05/2024","191.96","187.32","192.26","187.32","14.30M","2.44%" +"07/03/2024","187.39","186.30","187.62","185.38","7.41M","0.42%" +"07/02/2024","186.61","183.47","186.95","183.06","12.56M","1.15%" +"07/01/2024","184.49","184.48","185.34","182.73","11.82M","0.58%" +"06/28/2024","183.42","185.72","186.58","183.32","23.03M","-1.84%" +"06/27/2024","186.86","185.65","187.50","185.45","13.03M","0.80%" +"06/26/2024","185.37","184.20","185.93","183.99","13.38M","-0.11%" +"06/25/2024","185.58","181.15","185.75","181.10","18.92M","2.65%" +"06/24/2024","180.79","181.28","182.08","180.23","18.20M","0.29%" +"06/21/2024","180.26","178.49","182.51","178.06","59.73M","1.43%" +"06/20/2024","177.71","176.71","178.74","176.46","16.75M","0.71%" +"06/18/2024","176.45","178.79","178.91","175.62","15.64M","-1.30%" +"06/17/2024","178.78","176.98","179.92","176.49","15.27M","0.23%" +"06/14/2024","178.37","175.85","178.73","175.85","12.36M","0.92%" +"06/13/2024","176.74","177.84","178.51","176.66","15.96M","-1.57%" +"06/12/2024","179.56","179.75","182.08","177.78","18.60M","0.77%" +"06/11/2024","178.19","177.72","178.39","175.44","14.40M","0.88%" +"06/10/2024","176.63","176.45","178.47","174.38","17.12M","0.39%" +"06/07/2024","175.95","178.46","179.42","175.79","14.72M","-1.35%" +"06/06/2024","178.35","177.43","178.71","177.21","14.26M","0.72%" +"06/05/2024","177.07","176.54","177.97","175.29","15.23M","1.11%" +"06/04/2024","175.13","174.45","175.19","173.22","14.07M","0.41%" +"06/03/2024","174.42","173.88","175.86","172.45","20.74M","0.26%" +"05/31/2024","173.96","173.40","174.42","170.97","28.09M","0.23%" +"05/30/2024","173.56","176.69","176.69","173.23","18.84M","-2.16%" +"05/29/2024","177.40","176.81","178.23","176.26","15.02M","-0.35%" +"05/28/2024","178.02","175.74","178.51","175.68","15.66M","0.96%" +"05/24/2024","176.33","176.52","177.30","175.20","11.40M","0.73%" +"05/23/2024","175.06","178.78","179.91","174.54","14.93M","-1.65%" +"05/22/2024","178.00","178.40","178.85","176.78","16.19M","-0.86%" +"05/21/2024","179.54","178.40","179.82","177.31","14.71M","0.61%" +"05/20/2024","178.46","177.31","179.95","177.23","17.50M","0.66%" +"05/17/2024","177.29","175.55","177.49","174.98","16.55M","1.06%" +"05/16/2024","175.43","174.60","176.34","174.05","17.25M","0.89%" +"05/15/2024","173.88","172.30","174.05","172.03","20.96M","1.13%" +"05/14/2024","171.93","171.59","172.78","170.42","18.73M","0.60%" +"05/13/2024","170.90","165.85","170.95","165.76","19.65M","0.36%" +"05/10/2024","170.29","169.69","171.34","167.91","18.74M","-0.75%" +"05/09/2024","171.58","171.15","172.44","169.93","11.94M","0.25%" +"05/08/2024","171.16","170.75","171.91","170.52","14.57M","-1.05%" +"05/07/2024","172.98","170.12","173.47","170.00","21.10M","1.85%" +"05/06/2024","169.83","169.22","169.90","167.89","15.15M","0.50%" +"05/03/2024","168.99","169.54","169.85","164.98","22.77M","0.31%" +"05/02/2024","168.46","166.67","168.53","165.69","17.04M","1.75%" +"05/01/2024","165.57","166.18","168.81","164.90","25.22M","0.56%" +"04/30/2024","164.64","167.38","169.87","164.50","29.42M","-1.94%" +"04/29/2024","167.90","170.77","171.38","167.06","35.91M","-3.33%" +"04/26/2024","173.69","175.99","176.42","171.40","56.50M","9.97%" +"04/25/2024","157.95","153.36","158.28","152.77","36.20M","-1.96%" +"04/24/2024","161.10","159.09","161.39","158.82","19.49M","0.74%" +"04/23/2024","159.92","158.59","160.48","157.96","16.12M","1.25%" +"04/22/2024","157.95","156.01","159.18","155.66","17.24M","1.43%" +"04/19/2024","155.72","157.75","157.99","153.91","21.48M","-1.11%" +"04/18/2024","157.46","156.93","158.49","156.21","14.02M","0.37%" +"04/17/2024","156.88","157.19","158.68","156.13","16.24M","0.56%" +"04/16/2024","156.00","155.64","157.23","155.05","15.41M","-0.21%" +"04/15/2024","156.33","160.28","160.83","156.15","21.14M","-1.80%" +"04/12/2024","159.19","159.40","161.70","158.60","16.99M","-1.00%" +"04/11/2024","160.79","158.34","161.12","157.93","17.84M","1.99%" +"04/10/2024","157.66","157.88","158.16","156.20","16.34M","-0.30%" +"04/09/2024","158.14","157.35","159.89","156.64","21.54M","1.28%" +"04/08/2024","156.14","154.01","156.65","153.99","16.64M","1.43%" +"04/05/2024","153.94","151.68","154.84","151.08","16.30M","1.32%" +"04/04/2024","151.94","155.08","156.18","151.88","24.18M","-2.83%" +"04/03/2024","156.37","154.92","156.55","154.13","17.27M","0.32%" +"04/02/2024","155.87","154.75","155.99","153.46","17.60M","-0.40%" +"04/01/2024","156.50","151.83","157.00","151.65","24.47M","2.78%" +"03/28/2024","152.26","152.00","152.67","151.33","21.11M","0.21%" +"03/27/2024","151.94","152.15","152.69","150.13","16.62M","0.16%" +"03/26/2024","151.70","151.24","153.20","151.03","19.31M","0.36%" +"03/25/2024","151.15","150.95","151.46","148.80","15.11M","-0.41%" +"03/22/2024","151.77","150.24","152.56","150.09","19.25M","2.04%" +"03/21/2024","148.74","150.32","151.30","148.01","19.84M","-0.63%" +"03/20/2024","149.68","148.79","149.76","147.66","17.73M","1.19%" +"03/19/2024","147.92","148.98","149.62","147.01","17.75M","-0.38%" +"03/18/2024","148.48","149.37","152.93","148.14","47.68M","4.44%" +"03/15/2024","142.17","143.41","144.34","141.13","41.04M","-1.50%" +"03/14/2024","144.34","142.30","144.73","141.49","36.12M","2.54%" +"03/13/2024","140.77","140.06","142.19","140.01","19.64M","0.82%" +"03/12/2024","139.62","138.25","140.28","138.21","19.02M","0.49%" +"03/11/2024","138.94","137.07","139.98","137.07","22.54M","1.94%" +"03/08/2024","136.29","135.04","138.99","134.80","26.50M","0.78%" +"03/07/2024","135.24","133.89","135.82","132.66","24.11M","2.02%" +"03/06/2024","132.56","134.24","134.74","131.95","23.18M","-0.91%" +"03/05/2024","133.78","132.74","134.02","131.55","28.45M","-0.31%" +"03/04/2024","134.20","136.54","136.63","132.86","43.57M","-2.81%" +"03/01/2024","138.08","139.61","140.00","137.98","28.55M","-1.22%" +"02/29/2024","139.78","138.35","139.95","137.57","35.49M","1.71%" +"02/28/2024","137.43","139.10","139.28","136.64","30.63M","-1.91%" +"02/27/2024","140.10","139.41","140.49","138.50","22.36M","0.97%" +"02/26/2024","138.75","143.45","143.84","138.74","33.51M","-4.50%" +"02/23/2024","145.29","144.97","145.96","144.79","14.52M","-0.02%" +"02/22/2024","145.32","146.12","146.20","144.01","23.02M","1.03%" +"02/21/2024","143.84","142.64","143.98","141.91","16.50M","1.15%" +"02/20/2024","142.20","140.94","143.33","140.80","18.63M","0.31%" +"02/16/2024","141.76","144.21","144.48","141.52","21.87M","-1.51%" +"02/15/2024","143.94","144.46","144.76","141.88","26.72M","-2.17%" +"02/14/2024","147.14","147.37","147.83","145.55","16.65M","0.53%" +"02/13/2024","146.37","146.07","148.04","145.11","18.14M","-1.59%" +"02/12/2024","148.73","149.54","150.59","148.56","17.24M","-0.99%" +"02/09/2024","150.22","147.95","150.70","147.43","21.88M","2.04%" +"02/08/2024","147.22","146.97","147.61","146.42","18.24M","0.37%" +"02/07/2024","146.68","146.12","147.00","145.21","21.44M","0.87%" +"02/06/2024","145.41","145.96","146.74","144.52","21.52M","0.33%" +"02/05/2024","144.93","144.04","146.67","143.91","29.25M","0.97%" +"02/02/2024","143.54","140.89","143.88","138.17","42.14M","0.58%" +"02/01/2024","142.71","143.69","144.62","142.26","25.53M","0.64%" +"01/31/2024","141.80","145.39","145.59","141.55","43.91M","-7.35%" +"01/30/2024","153.05","154.01","155.04","152.77","26.58M","-1.16%" +"01/29/2024","154.84","153.64","155.20","152.92","20.91M","0.68%" +"01/26/2024","153.79","152.87","154.11","152.80","19.49M","0.10%" +"01/25/2024","153.64","151.74","154.76","151.22","21.50M","2.19%" +"01/24/2024","150.35","150.29","151.57","149.84","19.25M","1.12%" +"01/23/2024","148.68","147.72","148.86","147.19","14.11M","0.66%" +"01/22/2024","147.71","148.71","150.01","147.58","21.83M","-0.18%" +"01/19/2024","147.97","146.30","148.04","145.80","27.18M","2.06%" +"01/18/2024","144.99","143.44","145.59","143.35","18.88M","1.47%" +"01/17/2024","142.89","142.91","143.41","140.51","17.88M","-0.83%" +"01/16/2024","144.08","143.43","145.84","143.06","19.20M","-0.11%" +"01/12/2024","144.24","144.34","144.74","143.36","14.00M","0.40%" +"01/11/2024","143.67","144.90","146.66","142.21","17.47M","-0.09%" +"01/10/2024","143.80","142.52","144.52","142.46","16.64M","0.87%" +"01/09/2024","142.56","140.06","142.80","139.79","19.58M","1.44%" +"01/08/2024","140.53","138.00","140.64","137.88","17.65M","2.29%" +"01/05/2024","137.39","138.35","138.81","136.85","15.44M","-0.47%" +"01/04/2024","138.04","139.85","140.63","138.01","18.25M","-1.65%" +"01/03/2024","140.36","138.60","141.09","138.43","18.97M","0.57%" +"01/02/2024","139.56","139.60","140.61","137.74","20.07M","-0.97%" +"12/29/2023","140.93","140.68","141.43","139.90","14.88M","-0.25%" +"12/28/2023","141.28","141.85","142.27","140.83","12.19M","-0.11%" +"12/27/2023","141.44","142.83","143.32","141.05","17.29M","-0.97%" +"12/26/2023","142.82","142.98","143.95","142.50","11.17M","0.07%" +"12/22/2023","142.72","142.13","143.25","142.05","18.51M","0.65%" +"12/21/2023","141.80","140.77","142.03","140.47","18.10M","1.53%" +"12/20/2023","139.66","140.33","143.08","139.41","33.51M","1.13%" +"12/19/2023","138.10","138.00","138.77","137.45","20.66M","0.66%" +"12/18/2023","137.19","133.86","138.38","133.77","25.70M","2.50%" +"12/15/2023","133.84","132.92","134.83","132.63","58.59M","0.48%" +"12/14/2023","133.20","134.77","135.04","131.06","29.62M","-0.57%" +"12/13/2023","133.97","134.54","134.78","132.95","25.41M","0.25%" +"12/12/2023","133.64","133.27","134.54","132.83","26.58M","-0.79%" +"12/11/2023","134.70","133.82","134.79","132.89","24.50M","-1.42%" +"12/08/2023","136.64","135.66","137.99","135.57","23.02M","-1.31%" +"12/07/2023","138.45","136.60","140.00","136.23","38.42M","5.34%" +"12/06/2023","131.43","132.90","133.31","131.31","16.36M","-0.73%" +"12/05/2023","132.39","130.37","133.54","129.73","19.24M","1.35%" +"12/04/2023","130.63","131.29","131.45","129.40","24.12M","-2.02%" +"12/01/2023","133.32","133.32","133.50","132.15","24.27M","-0.45%" +"11/30/2023","133.92","136.40","136.96","132.79","29.91M","-1.82%" +"11/29/2023","136.40","138.99","139.67","136.29","21.01M","-1.60%" +"11/28/2023","138.62","137.63","138.66","137.04","17.05M","0.41%" +"11/27/2023","138.05","137.57","139.63","137.54","17.89M","-0.12%" +"11/24/2023","138.22","139.54","139.68","137.47","8.83M","-1.29%" +"11/22/2023","140.02","139.10","141.10","139.00","17.31M","1.01%" +"11/21/2023","138.62","137.94","138.96","137.71","17.65M","0.51%" +"11/20/2023","137.92","135.50","138.43","135.49","19.59M","0.72%" +"11/17/2023","136.94","137.82","138.00","135.48","25.59M","-1.27%" +"11/16/2023","138.70","136.96","138.88","136.08","17.62M","1.70%" +"11/15/2023","136.38","136.64","136.84","135.33","15.84M","0.70%" +"11/14/2023","135.43","135.65","137.24","135.10","22.32M","1.34%" +"11/13/2023","133.64","133.36","134.11","132.77","16.41M","-0.31%" +"11/10/2023","134.06","131.53","134.27","130.87","20.88M","1.80%" +"11/09/2023","131.69","133.36","133.96","131.51","17.98M","-1.18%" +"11/08/2023","133.26","132.36","133.54","132.16","15.09M","0.65%" +"11/07/2023","132.40","131.98","133.28","131.14","19.22M","0.72%" +"11/06/2023","131.45","130.22","131.56","129.93","15.36M","0.83%" +"11/03/2023","130.37","129.09","130.73","129.01","19.53M","1.39%" +"11/02/2023","128.58","129.56","130.09","128.11","24.09M","0.79%" +"11/01/2023","127.57","125.34","127.74","124.93","26.54M","1.81%" +"10/31/2023","125.30","126.27","126.56","123.93","21.12M","-0.36%" +"10/30/2023","125.75","124.46","126.55","123.88","24.17M","1.90%" +"10/27/2023","123.40","124.03","124.44","121.46","37.37M","-0.03%" +"10/26/2023","123.44","124.47","125.46","122.32","33.91M","-2.55%" +"10/25/2023","126.67","129.77","130.10","126.09","58.80M","-9.60%" +"10/24/2023","140.12","139.16","140.71","138.75","26.54M","1.61%" +"10/23/2023","137.90","136.23","139.02","135.11","20.78M","0.85%" +"10/20/2023","136.74","138.59","139.04","136.24","24.97M","-1.61%" +"10/19/2023","138.98","139.80","141.01","138.60","21.83M","-0.22%" +"10/18/2023","139.28","140.75","141.99","138.71","18.30M","-1.21%" +"10/17/2023","140.99","140.03","141.25","138.53","17.42M","0.36%" +"10/16/2023","140.49","139.73","140.90","139.32","17.35M","1.38%" +"10/13/2023","138.58","140.65","141.34","137.97","19.45M","-1.22%" +"10/12/2023","140.29","142.16","142.38","139.45","18.17M","-1.00%" +"10/11/2023","141.70","139.85","142.22","139.84","20.15M","1.80%" +"10/10/2023","139.20","139.51","140.74","138.43","19.55M","-0.22%" +"10/09/2023","139.50","137.99","139.97","136.70","16.60M","0.56%" +"10/06/2023","138.73","134.94","139.19","134.94","20.83M","2.01%" +"10/05/2023","135.99","136.13","136.50","134.46","15.92M","-0.21%" +"10/04/2023","136.27","133.66","136.57","133.43","22.85M","2.23%" +"10/03/2023","133.30","134.93","135.24","132.82","19.63M","-1.38%" +"10/02/2023","135.17","132.15","135.36","132.07","19.21M","2.52%" +"09/29/2023","131.85","134.08","134.89","131.32","23.24M","-0.96%" +"09/28/2023","133.13","130.69","134.18","130.69","18.20M","1.27%" +"09/27/2023","131.46","129.44","131.72","129.38","18.76M","1.55%" +"09/26/2023","129.45","130.91","131.40","128.19","20.38M","-2.06%" +"09/25/2023","132.17","130.77","132.22","130.03","14.65M","0.70%" +"09/22/2023","131.25","131.68","133.01","130.51","17.36M","-0.08%" +"09/21/2023","131.36","132.39","133.19","131.09","22.06M","-2.40%" +"09/20/2023","134.59","138.83","138.84","134.52","21.47M","-3.05%" +"09/19/2023","138.83","138.25","139.18","137.50","15.48M","-0.09%" +"09/18/2023","138.96","137.63","139.93","137.63","16.23M","0.48%" +"09/15/2023","138.30","138.80","139.36","137.18","48.96M","-0.50%" +"09/14/2023","138.99","138.39","139.55","137.06","19.06M","1.08%" +"09/13/2023","137.50","135.90","137.70","134.93","16.39M","1.05%" +"09/12/2023","136.07","137.13","137.64","135.93","15.21M","-1.21%" +"09/11/2023","137.74","137.38","138.26","136.55","17.18M","0.39%" +"09/08/2023","137.20","135.87","137.51","135.87","17.82M","0.73%" +"09/07/2023","136.20","134.60","136.58","133.96","16.98M","0.61%" +"09/06/2023","135.37","137.01","137.48","134.69","15.81M","-0.98%" +"09/05/2023","136.71","136.44","137.37","135.56","17.73M","-0.07%" +"09/01/2023","136.80","138.43","138.58","135.94","16.67M","-0.40%" +"08/31/2023","137.35","137.05","138.40","136.82","28.15M","0.31%" +"08/30/2023","136.93","135.57","137.25","135.02","21.77M","1.06%" +"08/29/2023","135.49","133.00","137.29","132.98","30.80M","2.81%" +"08/28/2023","131.79","132.08","133.24","130.85","16.72M","0.84%" +"08/25/2023","130.69","130.14","131.40","128.04","20.68M","0.21%" +"08/24/2023","130.42","134.73","134.97","130.30","18.68M","-2.09%" +"08/23/2023","133.21","130.85","134.07","130.51","26.50M","2.71%" +"08/22/2023","129.69","129.13","130.95","128.93","15.57M","0.59%" +"08/21/2023","128.93","127.85","129.26","127.16","21.85M","0.64%" +"08/18/2023","128.11","129.06","129.83","127.00","23.63M","-1.80%" +"08/17/2023","130.46","130.45","132.49","129.85","23.67M","1.05%" +"08/16/2023","129.11","129.28","130.90","128.46","17.55M","-0.89%" +"08/15/2023","130.27","131.59","131.99","129.82","14.77M","-1.18%" +"08/14/2023","131.83","129.85","131.91","129.59","17.53M","1.28%" +"08/11/2023","130.17","129.20","130.44","128.75","15.21M","-0.03%" +"08/10/2023","130.21","131.97","132.65","130.04","17.86M","0.05%" +"08/09/2023","130.15","132.19","132.47","129.51","17.75M","-1.28%" +"08/08/2023","131.84","130.98","131.94","130.13","16.84M","-0.08%" +"08/07/2023","131.94","129.51","132.06","129.43","17.62M","2.65%" +"08/04/2023","128.54","129.60","131.93","128.32","20.52M","-0.18%" +"08/03/2023","128.77","128.37","129.77","127.78","15.09M","0.10%" +"08/02/2023","128.64","129.84","130.42","127.85","22.71M","-2.46%" +"08/01/2023","131.89","130.85","132.92","130.75","22.22M","-0.92%" +"07/31/2023","133.11","133.01","133.83","132.13","18.38M","0.08%" +"07/28/2023","133.01","130.97","134.07","130.92","26.97M","2.42%" +"07/27/2023","129.87","131.80","133.60","129.18","35.93M","0.16%" +"07/26/2023","129.66","130.36","131.37","128.71","46.22M","5.59%" +"07/25/2023","122.79","121.88","123.69","121.53","31.82M","0.75%" +"07/24/2023","121.88","121.93","123.35","121.38","22.31M","1.30%" +"07/21/2023","120.31","120.87","121.30","119.07","56.51M","0.65%" +"07/20/2023","119.53","122.12","124.70","118.68","27.54M","-2.65%" +"07/19/2023","122.78","124.79","125.47","122.47","22.31M","-1.05%" +"07/18/2023","124.08","124.90","124.99","123.30","21.07M","-0.78%" +"07/17/2023","125.06","126.06","127.28","124.50","20.68M","-0.51%" +"07/14/2023","125.70","125.13","127.09","124.90","20.50M","0.70%" +"07/13/2023","124.83","121.54","125.33","121.06","31.54M","4.36%" +"07/12/2023","119.62","119.30","120.96","119.00","22.06M","1.62%" +"07/11/2023","117.71","116.76","118.22","115.83","18.29M","0.72%" +"07/10/2023","116.87","119.07","119.07","116.64","32.96M","-2.72%" +"07/07/2023","120.14","120.89","121.75","120.09","21.00M","-0.65%" +"07/06/2023","120.93","120.64","121.15","119.25","17.75M","-1.39%" +"07/05/2023","122.63","120.06","123.37","120.06","17.83M","1.72%" +"07/03/2023","120.56","120.32","121.02","119.71","13.89M","-0.34%" +"06/30/2023","120.97","121.10","122.03","120.88","23.87M","0.80%" +"06/29/2023","120.01","120.09","120.91","119.21","18.52M","-0.88%" +"06/28/2023","121.08","117.96","121.27","117.60","19.75M","1.74%" +"06/27/2023","119.01","117.84","119.89","116.91","27.22M","-0.07%" +"06/26/2023","119.09","121.47","122.72","118.99","23.18M","-3.19%" +"06/23/2023","123.02","122.04","123.44","121.86","29.57M","-0.69%" +"06/22/2023","123.87","120.66","123.93","119.60","20.78M","2.15%" +"06/21/2023","121.26","123.24","123.41","120.86","22.61M","-2.09%" +"06/20/2023","123.85","123.54","125.18","122.83","22.70M","-0.17%" +"06/16/2023","124.06","126.70","126.70","123.79","56.70M","-1.38%" +"06/15/2023","125.79","123.88","126.16","123.14","24.52M","1.13%" +"06/14/2023","124.38","123.80","124.79","122.16","24.66M","-0.04%" +"06/13/2023","124.43","125.65","125.86","123.85","19.29M","0.06%" +"06/12/2023","124.35","123.39","124.75","122.35","22.29M","1.20%" +"06/09/2023","122.87","122.56","124.29","122.42","20.31M","0.16%" +"06/08/2023","122.67","122.58","123.73","122.01","24.81M","-0.22%" +"06/07/2023","122.94","127.57","129.55","122.63","34.18M","-3.89%" +"06/06/2023","127.91","126.60","128.88","125.97","19.45M","1.01%" +"06/05/2023","126.63","124.61","127.99","124.38","22.67M","1.12%" +"06/02/2023","125.23","124.49","126.75","124.35","19.37M","0.69%" +"06/01/2023","124.37","123.50","125.04","123.30","25.02M","0.81%" +"05/31/2023","123.37","123.70","124.90","123.10","41.55M","-1.02%" +"05/30/2023","124.64","126.29","126.38","122.89","27.23M","-0.63%" +"05/26/2023","125.43","124.07","126.00","123.29","25.17M","0.87%" +"05/25/2023","124.35","125.21","125.98","122.90","33.81M","2.23%" +"05/24/2023","121.64","121.88","122.75","120.75","23.09M","-1.34%" +"05/23/2023","123.29","124.93","125.42","123.05","24.48M","-2.05%" +"05/22/2023","125.87","123.51","127.05","123.45","29.76M","2.13%" +"05/19/2023","123.25","124.20","126.48","122.72","30.27M","-0.22%" +"05/18/2023","123.52","121.56","123.90","121.49","27.01M","1.68%" +"05/17/2023","121.48","120.18","122.28","119.46","26.66M","1.16%" +"05/16/2023","120.09","116.83","121.20","116.83","32.37M","2.68%" +"05/15/2023","116.96","116.49","118.79","116.48","22.11M","-0.81%" +"05/12/2023","117.92","117.00","118.26","116.55","31.29M","0.87%" +"05/11/2023","116.90","115.86","118.44","114.93","57.12M","4.11%" +"05/10/2023","112.28","108.55","113.51","108.48","47.53M","4.02%" +"05/09/2023","107.94","108.78","110.60","107.72","24.78M","-0.28%" +"05/08/2023","108.24","105.79","108.42","105.79","17.27M","1.91%" +"05/05/2023","106.21","105.32","106.44","104.74","20.71M","0.96%" +"05/04/2023","105.21","106.16","106.30","104.70","19.78M","-0.86%" +"05/03/2023","106.12","106.22","108.13","105.62","17.12M","0.13%" +"05/02/2023","105.98","107.66","107.73","104.50","20.34M","-1.61%" +"05/01/2023","107.71","107.72","108.68","107.50","20.93M","-0.47%" +"04/28/2023","108.22","107.80","108.29","106.04","23.96M","-0.14%" +"04/27/2023","108.37","105.23","109.15","104.42","38.24M","3.75%" +"04/26/2023","104.45","105.56","107.02","103.27","37.07M","-0.15%" +"04/25/2023","104.61","106.61","107.44","104.56","31.41M","-2.03%" +"04/24/2023","106.78","106.05","107.32","105.36","21.41M","0.82%" +"04/21/2023","105.91","106.09","106.64","105.49","22.38M","0.01%" +"04/20/2023","105.90","104.65","106.89","104.64","22.52M","0.84%" +"04/19/2023","105.02","104.21","105.72","103.80","16.73M","-0.10%" +"04/18/2023","105.12","107.00","107.05","104.78","17.64M","-1.22%" +"04/17/2023","106.42","105.43","106.71","105.32","29.04M","-2.78%" +"04/14/2023","109.46","107.69","109.58","107.59","20.76M","1.17%" +"04/13/2023","108.19","106.47","108.26","106.44","21.65M","2.82%" +"04/12/2023","105.22","107.39","107.59","104.97","22.76M","-0.85%" +"04/11/2023","106.12","106.92","107.22","105.28","18.72M","-0.78%" +"04/10/2023","106.95","107.39","107.97","105.60","19.74M","-1.79%" +"04/06/2023","108.90","105.77","109.63","104.82","34.68M","3.76%" +"04/05/2023","104.95","106.12","106.54","104.10","21.86M","-0.16%" +"04/04/2023","105.12","104.84","106.10","104.60","20.38M","0.20%" +"04/03/2023","104.91","102.67","104.95","102.38","20.72M","0.88%" +"03/31/2023","104.00","101.71","104.19","101.44","28.11M","2.65%" +"03/30/2023","101.32","101.44","101.61","100.29","25.01M","-0.57%" +"03/29/2023","101.90","102.72","102.82","101.03","26.15M","0.53%" +"03/28/2023","101.36","103.00","103.00","100.28","24.91M","-1.65%" +"03/27/2023","103.06","105.32","105.40","102.63","25.39M","-2.83%" +"03/24/2023","106.06","105.74","106.16","104.74","25.25M","-0.19%" +"03/23/2023","106.26","105.89","107.10","105.41","31.39M","1.96%" +"03/22/2023","104.22","105.14","107.51","104.21","32.34M","-1.53%" +"03/21/2023","105.84","101.98","105.96","101.86","33.12M","3.84%" +"03/20/2023","101.93","101.06","102.58","100.79","26.03M","-0.52%" +"03/17/2023","102.46","100.84","103.49","100.75","76.14M","1.38%" +"03/16/2023","101.07","96.57","101.97","95.87","54.59M","4.68%" +"03/15/2023","96.55","93.54","97.25","93.04","38.37M","2.44%" +"03/14/2023","94.25","93.07","94.83","92.78","32.30M","2.83%" +"03/13/2023","91.66","90.57","93.08","89.94","31.51M","0.71%" +"03/10/2023","91.01","92.50","93.18","90.80","32.85M","-1.78%" +"03/09/2023","92.66","94.49","95.92","92.36","24.44M","-2.10%" +"03/08/2023","94.65","94.40","96.24","94.40","25.40M","0.51%" +"03/07/2023","94.17","95.42","96.09","93.84","24.10M","-1.48%" +"03/06/2023","95.58","94.36","96.30","94.30","28.29M","1.66%" +"03/03/2023","94.02","92.74","94.11","92.66","30.24M","1.85%" +"03/02/2023","92.31","89.86","92.48","89.77","23.34M","1.99%" +"03/01/2023","90.51","90.16","91.20","89.85","26.32M","0.23%" +"02/28/2023","90.30","89.54","91.45","89.52","30.55M","0.22%" +"02/27/2023","90.10","90.09","90.45","89.61","22.72M","0.84%" +"02/24/2023","89.35","89.63","90.13","88.86","31.30M","-1.89%" +"02/23/2023","91.07","92.13","92.13","90.01","32.42M","-0.80%" +"02/22/2023","91.80","91.93","92.36","90.87","29.89M","-0.27%" +"02/21/2023","92.05","93.24","93.41","92.00","28.37M","-2.69%" +"02/17/2023","94.59","95.07","95.75","93.45","31.10M","-1.24%" +"02/16/2023","95.78","95.54","97.88","94.97","35.64M","-1.36%" +"02/15/2023","97.10","94.74","97.34","94.36","37.03M","2.26%" +"02/14/2023","94.95","94.66","95.18","92.65","42.51M","-0.05%" +"02/13/2023","95.00","95.01","95.35","94.05","43.12M","0.15%" +"02/10/2023","94.86","95.74","97.02","94.53","49.33M","-0.63%" +"02/09/2023","95.46","100.54","100.61","93.86","97.80M","-4.54%" +"02/08/2023","100.00","102.69","103.58","98.46","73.55M","-7.44%" +"02/07/2023","108.04","103.63","108.67","103.55","33.74M","4.42%" +"02/06/2023","103.47","102.68","104.70","102.21","25.57M","-1.66%" +"02/03/2023","105.22","103.51","108.02","103.30","36.82M","-3.29%" +"02/02/2023","108.80","106.79","108.82","106.54","46.62M","7.27%" +"02/01/2023","101.43","99.74","102.19","98.42","26.39M","1.56%" +"01/31/2023","99.87","97.86","99.91","97.79","22.31M","1.96%" +"01/30/2023","97.95","98.75","99.41","97.52","24.37M","-2.74%" +"01/27/2023","100.71","99.05","101.58","98.97","29.02M","1.56%" +"01/26/2023","99.16","98.28","99.21","96.82","24.54M","2.51%" +"01/25/2023","96.73","97.20","97.72","95.26","31.00M","-2.50%" +"01/24/2023","99.21","99.55","101.09","98.70","27.39M","-1.98%" +"01/23/2023","101.21","99.13","101.40","98.75","31.79M","1.94%" +"01/20/2023","99.28","95.95","99.42","95.91","53.70M","5.72%" +"01/19/2023","93.91","91.39","94.40","91.38","28.71M","2.32%" +"01/18/2023","91.78","92.94","93.59","91.40","19.64M","-0.41%" +"01/17/2023","92.16","92.78","92.97","90.84","22.94M","-0.69%" +"01/13/2023","92.80","91.53","92.98","90.93","18.63M","0.97%" +"01/12/2023","91.91","92.40","92.62","90.57","22.75M","-0.38%" +"01/11/2023","92.26","90.06","92.45","89.74","26.00M","3.38%" +"01/10/2023","89.24","86.72","89.47","86.70","22.86M","0.50%" +"01/09/2023","88.80","89.19","90.83","88.58","23.00M","0.73%" +"01/06/2023","88.16","87.36","88.47","85.57","26.61M","1.60%" +"01/05/2023","86.77","88.07","88.21","86.56","23.14M","-2.19%" +"01/04/2023","88.71","91.01","91.24","87.80","27.05M","-1.10%" +"01/03/2023","89.70","89.83","91.55","89.02","20.74M","1.09%" +"12/30/2022","88.73","87.36","88.83","87.03","19.19M","-0.25%" +"12/29/2022","88.95","87.03","89.36","86.99","18.28M","2.88%" +"12/28/2022","86.46","87.50","88.52","86.37","17.88M","-1.67%" +"12/27/2022","87.93","89.31","89.50","87.54","15.47M","-2.09%" +"12/23/2022","89.81","87.62","90.10","87.62","17.82M","1.76%" +"12/22/2022","88.26","88.93","89.18","86.94","23.66M","-2.20%" +"12/21/2022","90.25","89.73","90.92","88.91","20.34M","0.69%" +"12/20/2022","89.63","88.73","89.78","88.04","21.98M","0.54%" +"12/19/2022","89.15","90.88","91.20","88.93","23.02M","-1.88%" +"12/16/2022","90.86","91.20","91.75","90.01","48.49M","-0.37%" +"12/15/2022","91.20","93.54","94.03","90.43","28.30M","-4.31%" +"12/14/2022","95.31","95.54","97.22","93.94","26.45M","-0.56%" +"12/13/2022","95.85","98.07","99.80","95.38","34.79M","2.45%" +"12/12/2022","93.56","93.09","93.87","91.90","27.38M","0.53%" +"12/09/2022","93.07","93.90","94.49","93.02","21.89M","-0.94%" +"12/08/2022","93.95","95.69","95.87","93.80","25.59M","-1.26%" +"12/07/2022","95.15","96.77","97.31","95.03","26.65M","-2.22%" +"12/06/2022","97.31","99.67","100.21","96.76","20.88M","-2.56%" +"12/05/2022","99.87","99.82","101.75","99.36","19.96M","-0.95%" +"12/02/2022","100.83","99.37","101.15","99.17","18.82M","-0.44%" +"12/01/2022","101.28","101.40","102.59","100.67","21.77M","-0.17%" +"11/30/2022","101.45","95.12","101.45","94.67","39.89M","6.30%" +"11/29/2022","95.44","96.00","96.39","94.39","20.22M","-0.84%" +"11/28/2022","96.25","97.20","97.83","95.89","19.98M","-1.38%" +"11/25/2022","97.60","98.46","98.94","97.53","8.57M","-1.23%" +"11/23/2022","98.82","97.34","99.07","97.34","17.57M","1.53%" +"11/22/2022","97.33","96.16","97.55","94.41","18.87M","1.57%" +"11/21/2022","95.83","97.56","98.72","95.67","18.70M","-2.01%" +"11/18/2022","97.80","99.01","99.16","96.74","24.97M","-0.71%" +"11/17/2022","98.50","97.18","99.48","97.10","21.82M","-0.49%" +"11/16/2022","98.99","98.02","99.85","97.90","24.66M","0.27%" +"11/15/2022","98.72","98.67","100.42","97.02","31.83M","2.80%" +"11/14/2022","96.03","95.50","97.18","95.11","24.17M","-0.72%" +"11/11/2022","96.73","94.71","97.36","94.16","30.57M","2.72%" +"11/10/2022","94.17","92.34","94.55","91.65","42.37M","7.75%" +"11/09/2022","87.40","88.54","89.49","87.36","26.74M","-1.70%" +"11/08/2022","88.91","89.16","90.40","87.65","30.17M","0.29%" +"11/07/2022","88.65","87.34","88.94","86.96","26.90M","2.25%" +"11/04/2022","86.70","85.51","86.73","83.88","40.17M","3.84%" +"11/03/2022","83.49","86.35","86.55","83.45","48.51M","-4.11%" +"11/02/2022","87.07","90.91","91.30","87.01","43.55M","-3.79%" +"11/01/2022","90.50","95.59","96.17","90.43","43.22M","-4.39%" +"10/31/2022","94.66","95.78","96.35","94.38","29.87M","-1.99%" +"10/28/2022","96.58","92.53","96.86","92.32","35.70M","4.30%" +"10/27/2022","92.60","94.31","95.17","91.90","54.04M","-2.34%" +"10/26/2022","94.82","96.76","98.54","94.57","71.67M","-9.63%" +"10/25/2022","104.93","103.30","105.10","103.02","29.91M","1.90%" +"10/24/2022","102.97","102.09","103.10","100.30","24.68M","1.47%" +"10/21/2022","101.48","98.46","101.62","98.23","28.99M","0.94%" +"10/20/2022","100.53","100.82","103.00","99.97","25.13M","0.24%" +"10/19/2022","100.29","100.70","101.66","99.64","21.57M","-1.08%" +"10/18/2022","101.39","103.94","104.22","100.65","21.61M","0.61%" +"10/17/2022","100.78","99.52","101.77","99.51","23.31M","3.70%" +"10/14/2022","97.18","100.63","101.29","97.03","22.62M","-2.54%" +"10/13/2022","99.71","95.93","100.53","95.27","32.81M","1.43%" +"10/12/2022","98.30","98.27","99.65","97.67","17.34M","0.25%" +"10/11/2022","98.05","98.25","100.12","97.25","21.62M","-0.67%" +"10/10/2022","98.71","99.85","99.99","97.87","16.53M","-0.86%" +"10/07/2022","99.57","100.65","101.42","99.21","24.25M","-2.61%" +"10/06/2022","102.24","101.50","103.73","101.50","17.16M","0.02%" +"10/05/2022","102.22","100.69","102.74","99.74","18.48M","-0.19%" +"10/04/2022","102.41","101.04","102.72","101.04","22.58M","3.13%" +"10/03/2022","99.30","97.22","99.97","97.02","24.84M","3.28%" +"09/30/2022","96.15","97.73","99.49","96.03","26.28M","-1.98%" +"09/29/2022","98.09","99.30","99.30","96.52","21.92M","-2.63%" +"09/28/2022","100.74","98.02","101.40","97.80","24.62M","2.70%" +"09/27/2022","98.09","99.91","100.46","97.34","24.22M","-0.73%" +"09/26/2022","98.81","98.61","100.44","98.38","22.44M","-0.36%" +"09/23/2022","99.17","100.06","100.11","98.01","25.66M","-1.39%" +"09/22/2022","100.57","99.45","101.68","99.41","21.27M","0.56%" +"09/21/2022","100.01","102.24","103.49","99.99","26.60M","-1.79%" +"09/20/2022","101.83","102.88","103.17","101.12","24.00M","-1.95%" +"09/19/2022","103.85","102.54","104.02","102.37","19.74M","0.21%" +"09/16/2022","103.63","102.97","104.03","101.86","64.54M","-0.26%" +"09/15/2022","103.90","105.01","106.21","103.31","26.49M","-1.86%" +"09/14/2022","105.87","105.44","106.10","104.50","22.12M","0.53%" +"09/13/2022","105.31","108.89","109.37","105.00","33.01M","-5.86%" +"09/12/2022","111.87","111.99","112.64","110.93","19.73M","0.08%" +"09/09/2022","111.78","110.05","112.00","110.00","21.75M","2.16%" +"09/08/2022","109.42","109.18","110.58","108.06","21.66M","-0.96%" +"09/07/2022","110.48","107.76","110.99","107.61","22.99M","2.79%" +"09/06/2022","107.48","108.14","108.88","106.51","20.57M","-1.10%" +"09/02/2022","108.68","111.34","111.68","108.13","20.62M","-1.69%" +"09/01/2022","110.55","109.20","111.22","108.19","22.78M","1.28%" +"08/31/2022","109.15","111.63","111.77","109.05","25.90M","-0.69%" +"08/30/2022","109.91","111.03","111.37","108.80","20.55M","-0.39%" +"08/29/2022","110.34","110.78","111.96","109.81","20.39M","-0.86%" +"08/26/2022","111.30","115.81","116.60","111.22","31.70M","-5.44%" +"08/25/2022","117.70","115.15","117.78","115.05","14.87M","2.62%" +"08/24/2022","114.70","114.45","115.72","113.78","16.05M","-0.06%" +"08/23/2022","114.77","114.32","115.93","114.30","14.39M","-0.26%" +"08/22/2022","115.07","116.10","116.50","114.67","19.32M","-2.58%" +"08/19/2022","118.12","119.87","120.00","117.67","20.19M","-2.27%" +"08/18/2022","120.86","120.23","121.69","119.55","15.65M","0.45%" +"08/17/2022","120.32","120.93","122.15","120.20","17.59M","-1.79%" +"08/16/2022","122.51","122.32","123.23","121.54","15.63M","-0.30%" +"08/15/2022","122.88","122.21","123.26","121.57","15.52M","0.19%" +"08/12/2022","122.65","121.16","122.65","120.40","16.12M","2.36%" +"08/11/2022","119.82","122.08","122.34","119.55","16.67M","-0.69%" +"08/10/2022","120.65","119.59","121.78","119.36","20.50M","2.68%" +"08/09/2022","117.50","117.99","118.20","116.56","15.42M","-0.54%" +"08/08/2022","118.14","119.12","120.86","117.83","17.06M","-0.07%" +"08/05/2022","118.22","116.93","118.86","116.71","15.62M","-0.55%" +"08/04/2022","118.87","118.30","119.50","117.71","15.76M","0.08%" +"08/03/2022","118.78","116.34","119.42","116.15","25.30M","2.48%" +"08/02/2022","115.90","114.43","117.08","114.26","17.91M","0.36%" +"08/01/2022","115.48","115.53","117.12","114.69","22.86M","-0.99%" +"07/29/2022","116.64","113.40","116.90","113.23","31.34M","1.79%" +"07/28/2022","114.59","112.80","114.70","111.85","23.30M","0.87%" +"07/27/2022","113.60","109.60","114.40","108.42","41.47M","7.74%" +"07/26/2022","105.44","107.43","107.74","104.76","36.63M","-2.56%" +"07/25/2022","108.21","108.88","110.58","107.01","28.29M","-0.14%" +"07/22/2022","108.36","111.81","113.18","107.60","44.46M","-5.81%" +"07/21/2022","115.04","115.09","115.21","111.91","27.27M","0.30%" +"07/20/2022","114.70","114.06","116.33","113.26","26.78M","0.07%" +"07/19/2022","114.62","111.73","114.81","110.50","30.99M","4.29%" +"07/18/2022","109.91","113.44","114.80","109.30","33.35M","-2.53%" +"07/15/2022","112.77","112.96","114.00","111.82","34.33M","1.19%" +"07/14/2022","111.44","110.83","111.99","109.33","32.37M","-0.67%" +"07/13/2022","112.19","112.64","115.16","111.82","38.96M","-2.32%" +"07/12/2022","114.85","116.84","117.85","114.62","24.97M","-1.44%" +"07/11/2022","116.52","118.65","118.79","116.23","26.83M","-3.03%" +"07/08/2022","120.17","117.55","120.43","117.51","29.08M","0.72%" +"07/07/2022","119.31","116.01","119.86","115.53","32.18M","3.55%" +"07/06/2022","115.21","114.09","116.35","112.25","28.85M","1.16%" +"07/05/2022","113.89","107.51","114.05","106.25","36.43M","4.41%" +"07/01/2022","109.08","108.34","109.81","107.11","31.03M","-0.27%" +"06/30/2022","109.37","110.50","111.33","107.31","38.05M","-2.57%" +"06/29/2022","112.26","112.15","113.66","111.55","18.63M","-0.28%" +"06/28/2022","112.57","116.35","117.86","112.44","28.32M","-3.47%" +"06/27/2022","116.62","118.93","119.25","116.00","32.84M","-1.62%" +"06/24/2022","118.54","113.60","118.64","113.60","39.12M","5.19%" +"06/23/2022","112.68","112.95","113.20","111.03","24.71M","0.58%" +"06/22/2022","112.03","111.16","113.77","110.72","23.92M","0.02%" +"06/21/2022","112.01","109.70","112.67","109.29","39.01M","3.85%" +"06/17/2022","107.87","106.54","109.25","105.63","43.52M","1.15%" +"06/16/2022","106.64","108.15","109.29","105.79","35.31M","-3.40%" +"06/15/2022","110.39","108.90","112.06","108.12","33.19M","2.98%" +"06/14/2022","107.19","106.89","108.46","106.35","25.48M","0.30%" +"06/13/2022","106.88","107.45","109.22","106.59","36.76M","-4.08%" +"06/10/2022","111.43","112.78","113.50","110.86","31.35M","-3.04%" +"06/09/2022","114.92","116.34","118.35","114.87","23.14M","-1.98%" +"06/08/2022","117.24","116.88","118.65","116.70","22.54M","0.01%" +"06/07/2022","117.23","115.65","117.75","115.13","26.41M","0.19%" +"06/06/2022","117.01","116.74","119.40","116.53","23.79M","2.14%" +"06/03/2022","114.56","115.99","116.36","113.67","24.95M","-2.70%" +"06/02/2022","117.75","114.19","117.90","113.31","27.50M","3.16%" +"06/01/2022","114.14","114.93","117.40","113.55","28.63M","0.09%" +"05/31/2022","114.04","113.08","116.43","112.57","51.30M","1.10%" +"05/27/2022","112.80","109.79","112.87","109.55","29.92M","4.16%" +"05/26/2022","108.30","106.05","108.96","105.49","30.29M","2.32%" +"05/25/2022","105.84","105.14","106.54","104.21","37.90M","-0.08%" +"05/24/2022","105.93","106.38","106.39","102.21","60.39M","-5.14%" +"05/23/2022","111.67","110.10","112.01","109.15","31.56M","2.15%" +"05/20/2022","109.31","112.09","112.55","106.37","37.59M","-1.29%" +"05/19/2022","110.75","111.84","113.59","110.47","29.19M","-1.47%" +"05/18/2022","112.40","115.24","115.70","112.14","27.98M","-3.69%" +"05/17/2022","116.70","117.23","117.23","115.34","21.58M","1.66%" +"05/16/2022","114.79","115.38","116.61","114.33","23.28M","-1.48%" +"05/13/2022","116.52","114.85","118.08","114.00","29.74M","2.96%" +"05/12/2022","113.16","111.94","114.86","110.11","41.46M","-0.70%" +"05/11/2022","113.96","113.71","116.67","113.65","36.50M","-0.54%" +"05/10/2022","114.58","116.04","116.69","113.38","31.16M","1.33%" +"05/09/2022","113.08","113.30","115.56","112.55","34.52M","-2.23%" +"05/06/2022","115.66","115.52","117.50","114.14","35.31M","-0.93%" +"05/05/2022","116.75","120.22","121.23","115.18","43.09M","-4.76%" +"05/04/2022","122.57","118.00","123.14","115.74","33.23M","3.76%" +"05/03/2022","118.13","116.76","119.30","116.63","21.22M","0.83%" +"05/02/2022","117.16","113.91","117.34","113.40","30.28M","1.91%" +"04/29/2022","114.97","117.58","118.96","114.69","33.69M","-3.72%" +"04/28/2022","119.41","117.11","120.44","115.14","36.79M","3.82%" +"04/27/2022","115.02","114.37","117.50","113.12","62.24M","-3.75%" +"04/26/2022","119.51","122.75","122.75","119.16","49.39M","-3.04%" +"04/25/2022","123.25","119.43","123.28","118.77","34.52M","3.04%" +"04/22/2022","119.61","125.00","125.45","119.14","46.41M","-4.26%" +"04/21/2022","124.94","129.35","130.31","124.65","30.16M","-2.58%" +"04/20/2022","128.25","131.28","131.92","127.89","22.61M","-1.75%" +"04/19/2022","130.53","128.08","130.90","127.45","22.72M","2.01%" +"04/18/2022","127.96","127.41","128.71","126.58","14.92M","0.56%" +"04/14/2022","127.25","130.65","130.71","127.11","23.48M","-2.33%" +"04/13/2022","130.29","128.63","130.66","128.44","19.54M","1.49%" +"04/12/2022","128.37","132.42","132.42","127.58","23.00M","-1.10%" +"04/11/2022","129.80","132.90","132.94","129.62","24.19M","-3.14%" +"04/08/2022","134.01","136.25","136.25","133.75","16.43M","-1.80%" +"04/07/2022","136.46","136.62","137.70","134.86","19.45M","-0.52%" +"04/06/2022","137.18","139.16","139.85","136.42","23.57M","-2.76%" +"04/05/2022","141.06","143.40","143.59","140.94","19.26M","-1.80%" +"04/04/2022","143.64","140.82","144.04","140.82","19.08M","2.09%" +"04/01/2022","140.70","140.01","140.95","138.80","23.48M","0.75%" +"03/31/2022","139.65","142.45","142.64","139.62","29.52M","-2.10%" +"03/30/2022","142.64","142.87","143.48","142.17","21.05M","-0.42%" +"03/29/2022","143.25","143.16","144.16","142.48","28.68M","0.92%" +"03/28/2022","141.95","140.68","141.98","139.83","23.77M","0.30%" +"03/25/2022","141.52","141.75","141.96","139.70","19.29M","0.15%" +"03/24/2022","141.31","139.27","141.40","138.04","20.54M","2.03%" +"03/23/2022","138.50","139.14","140.02","138.17","25.30M","-1.26%" +"03/22/2022","140.28","136.50","141.50","136.50","29.78M","2.78%" +"03/21/2022","136.48","136.85","137.58","134.61","26.63M","-0.24%" +"03/18/2022","136.80","133.88","136.91","132.93","45.90M","1.64%" +"03/17/2022","134.60","133.32","134.74","132.72","23.99M","0.68%" +"03/16/2022","133.69","131.00","133.77","129.20","32.06M","3.11%" +"03/15/2022","129.66","127.74","130.52","126.57","30.29M","2.30%" +"03/14/2022","126.74","130.57","131.03","126.41","30.25M","-2.86%" +"03/11/2022","130.48","134.00","134.20","130.30","26.60M","-1.66%" +"03/10/2022","132.68","131.46","133.54","131.40","24.27M","-0.88%" +"03/09/2022","133.87","131.40","134.20","130.09","32.26M","5.18%" +"03/08/2022","127.28","126.25","131.25","125.86","35.25M","0.64%" +"03/07/2022","126.46","131.90","131.90","126.41","39.18M","-4.28%" +"03/04/2022","132.12","133.38","134.20","130.41","24.47M","-1.63%" +"03/03/2022","134.31","135.98","136.71","133.43","19.78M","-0.33%" +"03/02/2022","134.75","134.61","135.62","133.43","23.97M","0.43%" +"03/01/2022","134.17","134.48","136.11","133.38","24.64M","-0.54%" +"02/28/2022","134.89","133.28","135.64","132.83","29.68M","0.28%" +"02/25/2022","134.52","133.53","135.39","131.76","26.24M","1.39%" +"02/24/2022","132.67","125.00","133.04","124.76","43.17M","3.99%" +"02/23/2022","127.58","131.08","131.75","127.50","26.43M","-1.41%" +"02/22/2022","129.40","129.99","131.90","127.74","38.91M","-0.82%" +"02/18/2022","130.47","133.04","133.82","130.31","31.86M","-1.39%" +"02/17/2022","132.31","136.15","136.84","132.20","30.97M","-3.77%" +"02/16/2022","137.49","136.43","137.95","134.82","25.61M","0.78%" +"02/15/2022","136.43","137.47","137.90","135.54","26.58M","0.84%" +"02/14/2022","135.30","133.37","136.17","133.30","26.79M","0.87%" +"02/11/2022","134.13","138.75","139.28","133.29","38.81M","-3.23%" +"02/10/2022","138.60","139.50","141.43","138.05","33.02M","-2.01%" +"02/09/2022","141.45","140.85","142.18","140.38","28.63M","1.61%" +"02/08/2022","139.21","138.99","139.84","136.87","34.26M","0.19%" +"02/07/2022","138.94","143.71","143.85","138.70","44.61M","-2.85%" +"02/04/2022","143.02","143.02","144.54","139.82","49.22M","0.26%" +"02/03/2022","142.65","145.29","149.12","142.21","56.93M","-3.64%" +"02/02/2022","148.04","151.86","152.10","145.56","89.75M","7.37%" +"02/01/2022","137.88","137.84","138.20","134.57","51.20M","1.61%" +"01/31/2022","135.70","134.20","135.84","132.27","34.06M","1.81%" +"01/28/2022","133.29","130.00","133.37","128.69","30.52M","3.23%" +"01/27/2022","129.12","131.36","132.61","128.94","30.29M","-0.09%" +"01/26/2022","129.24","130.59","132.81","127.15","39.63M","1.97%" +"01/25/2022","126.74","128.44","129.34","126.38","36.01M","-2.78%" +"01/24/2022","130.37","126.03","130.78","124.64","55.29M","0.22%" +"01/21/2022","130.09","133.01","134.76","130.00","41.92M","-2.56%" +"01/20/2022","133.51","136.51","137.91","133.14","21.93M","-1.58%" +"01/19/2022","135.65","136.94","138.40","135.50","20.80M","-0.47%" +"01/18/2022","136.29","136.60","137.39","135.62","27.40M","-2.50%" +"01/14/2022","139.79","137.50","141.20","137.50","23.83M","0.47%" +"01/13/2022","139.13","141.84","143.19","138.91","26.57M","-1.78%" +"01/12/2022","141.65","141.55","142.81","141.11","23.64M","1.16%" +"01/11/2022","140.02","138.18","140.33","136.81","23.50M","1.05%" +"01/10/2022","138.57","135.10","138.64","133.14","34.10M","1.15%" +"01/07/2022","137.00","137.91","138.25","135.79","19.41M","-0.40%" +"01/06/2022","137.55","137.50","139.69","136.76","29.05M","-0.07%" +"01/05/2022","137.65","144.18","144.30","137.52","49.64M","-4.69%" +"01/04/2022","144.42","145.55","146.61","143.82","22.93M","-0.45%" +"01/03/2022","145.07","144.48","145.55","143.50","25.22M","0.27%" \ No newline at end of file diff --git a/SAMPLE_DATA/NASDAQ Composite Historical Data.csv b/SAMPLE_DATA/NASDAQ Composite Historical Data.csv new file mode 100644 index 0000000..8e52401 --- /dev/null +++ b/SAMPLE_DATA/NASDAQ Composite Historical Data.csv @@ -0,0 +1,640 @@ +"Date","Price","Open","High","Low","Vol.","Change %" +"07/19/2024","17,726.94","17,835.59","17,935.14","17,691.43","1.12B","-0.81%" +"07/18/2024","17,871.22","18,119.15","18,130.87","17,759.54","1.13B","-0.70%" +"07/17/2024","17,996.93","18,188.19","18,223.24","17,972.87","1.26B","-2.77%" +"07/16/2024","18,509.34","18,534.27","18,576.83","18,386.07","1.12B","0.20%" +"07/15/2024","18,472.57","18,485.91","18,641.53","18,397.83","1.08B","0.40%" +"07/12/2024","18,398.45","18,303.64","18,556.73","18,293.60","1.10B","0.63%" +"07/11/2024","18,283.41","18,659.25","18,671.07","18,238.78","1.23B","-1.95%" +"07/10/2024","18,647.45","18,512.09","18,655.19","18,467.58","971.36M","1.18%" +"07/09/2024","18,429.29","18,465.02","18,511.89","18,381.60","914.80M","0.14%" +"07/08/2024","18,403.74","18,371.86","18,416.94","18,342.60","984.76M","0.28%" +"07/05/2024","18,352.76","18,200.60","18,366.31","18,197.13","963.80M","0.90%" +"07/03/2024","18,188.30","18,016.12","18,188.30","18,016.12","692.06M","0.88%" +"07/02/2024","18,028.76","17,808.04","18,031.29","17,802.24","932.12M","0.84%" +"07/01/2024","17,879.30","17,773.90","17,894.28","17,657.64","1.03B","0.83%" +"06/28/2024","17,732.60","17,891.10","18,035.00","17,723.83","3.78B","-0.71%" +"06/27/2024","17,858.68","17,793.95","17,892.78","17,765.42","1.05B","0.30%" +"06/26/2024","17,805.16","17,697.27","17,813.55","17,687.07","1.04B","0.49%" +"06/25/2024","17,717.65","17,572.16","17,734.35","17,546.63","1.08B","1.26%" +"06/24/2024","17,496.82","17,640.26","17,730.12","17,494.02","1.14B","-1.09%" +"06/21/2024","17,689.36","17,681.01","17,787.34","17,620.57","3.54B","-0.18%" +"06/20/2024","17,721.59","17,913.94","17,936.79","17,650.70","1.26B","-0.79%" +"06/18/2024","17,862.23","17,856.76","17,890.52","17,796.88","1.11B","0.03%" +"06/17/2024","17,857.02","17,697.30","17,935.98","17,636.36","1.04B","0.95%" +"06/14/2024","17,688.88","17,621.18","17,693.43","17,590.80","965.43M","0.12%" +"06/13/2024","17,667.56","17,715.27","17,741.80","17,566.32","981.98M","0.34%" +"06/12/2024","17,608.44","17,502.15","17,725.39","17,490.64","1.13B","1.53%" +"06/11/2024","17,343.55","17,160.42","17,345.05","17,107.99","941.87M","0.88%" +"06/10/2024","17,192.53","17,083.45","17,213.45","17,057.34","1.01B","0.35%" +"06/07/2024","17,133.13","17,124.13","17,229.31","17,090.04","897.39M","-0.23%" +"06/06/2024","17,173.12","17,204.87","17,235.73","17,123.59","940.92M","-0.09%" +"06/05/2024","17,187.90","16,974.48","17,187.92","16,955.56","1.01B","1.96%" +"06/04/2024","16,857.05","16,823.88","16,891.87","16,750.39","975.74M","0.17%" +"06/03/2024","16,828.67","16,865.70","16,909.89","16,646.43","1.06B","0.56%" +"05/31/2024","16,735.02","16,771.90","16,789.27","16,445.54","1.81B","-0.01%" +"05/30/2024","16,737.08","16,878.63","16,900.46","16,690.36","1.11B","-1.08%" +"05/29/2024","16,920.58","16,879.35","16,989.60","16,873.97","1.15B","-0.58%" +"05/28/2024","17,019.88","16,988.31","17,032.65","16,917.51","1.10B","0.59%" +"05/24/2024","16,920.79","16,786.79","16,947.79","16,771.58","953.61M","1.10%" +"05/23/2024","16,736.03","16,996.38","16,996.38","16,678.37","1.21B","-0.39%" +"05/22/2024","16,801.54","16,839.02","16,855.27","16,712.09","1.15B","-0.18%" +"05/21/2024","16,832.62","16,736.10","16,839.02","16,719.97","1.02B","0.22%" +"05/20/2024","16,794.87","16,702.02","16,823.83","16,695.69","1.12B","0.65%" +"05/17/2024","16,685.97","16,708.49","16,726.41","16,613.84","1.43B","-0.07%" +"05/16/2024","16,698.32","16,738.11","16,797.83","16,693.45","1.47B","-0.26%" +"05/15/2024","16,742.39","16,601.14","16,749.74","16,544.09","1.32B","1.40%" +"05/14/2024","16,511.18","16,391.16","16,526.27","16,386.44","1.24B","0.75%" +"05/13/2024","16,388.24","16,400.31","16,407.05","16,334.86","953.22M","0.29%" +"05/10/2024","16,340.87","16,389.02","16,437.39","16,293.52","940.76M","-0.03%" +"05/09/2024","16,346.26","16,323.74","16,362.79","16,241.98","945.46M","0.27%" +"05/08/2024","16,302.76","16,226.07","16,341.65","16,226.07","976.92M","-0.18%" +"05/07/2024","16,332.55","16,358.34","16,397.39","16,303.84","1.02B","-0.10%" +"05/06/2024","16,349.25","16,208.54","16,350.08","16,197.86","919.31M","1.19%" +"05/03/2024","16,156.33","16,147.48","16,204.71","16,068.34","1.03B","1.99%" +"05/02/2024","15,840.96","15,758.11","15,862.79","15,604.73","1.05B","1.51%" +"05/01/2024","15,605.48","15,646.09","15,926.22","15,557.64","1.12B","-0.33%" +"04/30/2024","15,657.82","15,920.89","15,979.36","15,655.67","1.15B","-2.04%" +"04/29/2024","15,983.08","16,007.00","16,021.50","15,885.89","953.16M","0.35%" +"04/26/2024","15,927.90","15,821.33","15,981.00","15,770.72","939.96M","2.03%" +"04/25/2024","15,611.76","15,375.26","15,644.51","15,343.91","990.23M","-0.64%" +"04/24/2024","15,712.75","15,805.60","15,839.00","15,634.44","955.27M","0.10%" +"04/23/2024","15,696.64","15,525.55","15,730.35","15,510.58","981.75M","1.59%" +"04/22/2024","15,451.30","15,396.13","15,539.00","15,265.66","930.20M","1.11%" +"04/19/2024","15,282.01","15,547.10","15,576.70","15,222.78","1.11B","-2.05%" +"04/18/2024","15,601.50","15,705.70","15,786.12","15,587.50","936.42M","-0.52%" +"04/17/2024","15,683.37","15,942.29","15,957.03","15,654.51","896.71M","-1.15%" +"04/16/2024","15,865.25","15,856.38","15,965.79","15,822.02","912.04M","-0.12%" +"04/15/2024","15,885.02","16,276.47","16,295.27","15,863.88","980.76M","-1.79%" +"04/12/2024","16,175.09","16,293.03","16,341.46","16,125.33","906.05M","-1.62%" +"04/11/2024","16,442.20","16,236.20","16,464.60","16,154.65","888.86M","1.68%" +"04/10/2024","16,170.36","16,104.01","16,200.10","16,092.02","992.41M","-0.84%" +"04/09/2024","16,306.64","16,328.76","16,348.18","16,141.15","888.26M","0.32%" +"04/08/2024","16,253.96","16,285.18","16,323.60","16,220.72","852.61M","0.03%" +"04/05/2024","16,248.52","16,095.40","16,326.50","16,080.49","903.32M","1.24%" +"04/04/2024","16,049.08","16,418.57","16,468.04","16,046.56","1.07B","-1.40%" +"04/03/2024","16,277.46","16,178.79","16,340.74","16,169.31","1.01B","0.23%" +"04/02/2024","16,240.45","16,199.24","16,251.41","16,137.24","1.03B","-0.95%" +"04/01/2024","16,396.83","16,397.05","16,490.65","16,327.89","930.02M","0.11%" +"03/28/2024","16,379.46","16,377.23","16,420.92","16,347.38","1.22B","-0.12%" +"03/27/2024","16,399.52","16,424.76","16,431.82","16,279.17","986.80M","0.51%" +"03/26/2024","16,315.70","16,446.85","16,476.38","16,312.95","1.00B","-0.42%" +"03/25/2024","16,384.47","16,335.30","16,441.17","16,315.72","896.53M","-0.27%" +"03/22/2024","16,428.82","16,387.83","16,467.62","16,361.00","880.01M","0.16%" +"03/21/2024","16,401.84","16,517.24","16,538.86","16,393.90","1.06B","0.20%" +"03/20/2024","16,369.41","16,185.76","16,377.44","16,127.48","1.03B","1.25%" +"03/19/2024","16,166.79","16,031.93","16,175.59","15,951.86","1.04B","0.39%" +"03/18/2024","16,103.45","16,154.92","16,247.59","16,094.17","1.04B","0.82%" +"03/15/2024","15,973.17","16,043.58","16,055.33","15,925.91","3.07B","-0.96%" +"03/14/2024","16,128.53","16,209.19","16,245.32","16,039.68","1.18B","-0.30%" +"03/13/2024","16,177.77","16,220.11","16,233.29","16,143.34","1.09B","-0.54%" +"03/12/2024","16,265.64","16,116.98","16,275.45","15,992.98","1.02B","1.54%" +"03/11/2024","16,019.27","16,052.63","16,085.95","15,978.04","970.77M","-0.41%" +"03/08/2024","16,085.11","16,322.10","16,449.70","16,059.50","1.09B","-1.16%" +"03/07/2024","16,273.38","16,147.32","16,309.02","16,096.01","1.03B","1.51%" +"03/06/2024","16,031.54","16,092.00","16,128.56","15,956.66","1.11B","0.58%" +"03/05/2024","15,939.59","16,077.74","16,087.57","15,862.63","1.16B","-1.65%" +"03/04/2024","16,207.51","16,264.21","16,289.06","16,199.06","1.17B","-0.41%" +"03/01/2024","16,274.94","16,109.83","16,302.24","16,096.60","1.10B","1.14%" +"02/29/2024","16,091.92","16,059.34","16,115.96","15,931.70","1.65B","0.90%" +"02/28/2024","15,947.74","15,969.14","16,003.56","15,924.72","1.10B","-0.55%" +"02/27/2024","16,035.30","16,013.98","16,046.10","15,940.51","1.10B","0.37%" +"02/26/2024","15,976.25","16,014.45","16,054.90","15,973.90","1.06B","-0.13%" +"02/23/2024","15,996.82","16,094.80","16,134.22","15,954.50","1.00B","-0.28%" +"02/22/2024","16,041.62","15,904.48","16,061.82","15,869.24","1.14B","2.96%" +"02/21/2024","15,580.87","15,532.12","15,583.68","15,451.65","984.02M","-0.32%" +"02/20/2024","15,630.78","15,679.84","15,730.47","15,508.50","1.10B","-0.92%" +"02/16/2024","15,775.65","15,910.43","15,917.41","15,752.02","1.12B","-0.82%" +"02/15/2024","15,906.17","15,865.30","15,911.22","15,779.71","1.22B","0.30%" +"02/14/2024","15,859.15","15,781.71","15,865.51","15,683.94","1.08B","1.30%" +"02/13/2024","15,655.60","15,598.88","15,770.42","15,551.44","1.21B","-1.80%" +"02/12/2024","15,942.54","15,980.62","16,080.07","15,917.87","1.09B","-0.30%" +"02/09/2024","15,990.66","15,842.38","16,007.29","15,831.76","1.08B","1.25%" +"02/08/2024","15,793.71","15,762.23","15,813.27","15,739.18","1.02B","0.24%" +"02/07/2024","15,756.64","15,690.35","15,770.67","15,645.80","943.13M","0.95%" +"02/06/2024","15,609.00","15,638.19","15,652.75","15,515.25","931.55M","0.07%" +"02/05/2024","15,597.68","15,613.99","15,637.88","15,471.68","923.28M","-0.20%" +"02/02/2024","15,628.95","15,403.16","15,664.21","15,366.78","956.87M","1.74%" +"02/01/2024","15,361.64","15,254.02","15,372.13","15,208.88","1.01B","1.30%" +"01/31/2024","15,164.01","15,324.19","15,405.55","15,158.49","1.29B","-2.23%" +"01/30/2024","15,509.90","15,604.08","15,619.23","15,484.67","915.72M","-0.76%" +"01/29/2024","15,628.04","15,470.66","15,630.58","15,449.87","959.39M","1.12%" +"01/26/2024","15,455.36","15,474.85","15,538.84","15,433.04","857.50M","-0.36%" +"01/25/2024","15,510.50","15,555.62","15,597.25","15,430.68","998.98M","0.18%" +"01/24/2024","15,481.92","15,560.61","15,629.07","15,468.91","932.89M","0.36%" +"01/23/2024","15,425.94","15,391.41","15,432.35","15,337.23","959.54M","0.43%" +"01/22/2024","15,360.29","15,393.05","15,438.85","15,333.63","1.04B","0.32%" +"01/19/2024","15,310.97","15,122.38","15,310.97","15,087.20","1.14B","1.70%" +"01/18/2024","15,055.65","14,994.52","15,066.81","14,911.11","1.04B","1.35%" +"01/17/2024","14,855.62","14,814.77","14,865.76","14,706.23","944.50M","-0.59%" +"01/16/2024","14,944.35","14,908.26","15,004.35","14,863.81","1.10B","-0.19%" +"01/12/2024","14,972.76","15,001.01","15,047.25","14,931.88","865.51M","0.02%" +"01/11/2024","14,970.18","15,020.95","15,063.61","14,800.38","1.00B","0.00%" +"01/10/2024","14,969.65","14,877.70","14,998.20","14,842.70","904.43M","0.75%" +"01/09/2024","14,857.71","14,744.13","14,894.32","14,716.71","959.65M","0.09%" +"01/08/2024","14,843.77","14,564.47","14,846.90","14,560.20","1.14B","2.20%" +"01/05/2024","14,524.07","14,500.11","14,625.19","14,477.57","1.01B","0.09%" +"01/04/2024","14,510.30","14,532.23","14,632.77","14,504.78","1.04B","-0.56%" +"01/03/2024","14,592.21","14,641.47","14,694.58","14,577.44","1.06B","-1.18%" +"01/02/2024","14,765.94","14,873.70","14,887.80","14,682.38","1.08B","-1.63%" +"12/29/2023","15,011.35","15,099.20","15,111.41","14,955.37","1.04B","-0.56%" +"12/28/2023","15,095.14","15,142.09","15,150.07","15,087.22","907.14M","-0.03%" +"12/27/2023","15,099.18","15,089.66","15,114.08","15,051.67","1.07B","0.16%" +"12/26/2023","15,074.57","15,028.69","15,101.18","15,024.06","871.34M","0.54%" +"12/22/2023","14,992.97","15,006.18","15,047.19","14,927.12","880.44M","0.19%" +"12/21/2023","14,963.87","14,923.14","14,970.81","14,837.47","945.08M","1.26%" +"12/20/2023","14,777.94","14,973.36","15,069.29","14,776.29","1.20B","-1.50%" +"12/19/2023","15,003.22","14,923.02","15,003.80","14,921.60","1.13B","0.66%" +"12/18/2023","14,905.19","14,814.02","14,938.04","14,811.82","1.15B","0.62%" +"12/15/2023","14,813.92","14,797.46","14,848.41","14,753.16","3.35B","0.35%" +"12/14/2023","14,761.56","14,798.72","14,855.62","14,642.23","1.58B","0.19%" +"12/13/2023","14,733.96","14,555.68","14,743.55","14,517.53","1.13B","1.38%" +"12/12/2023","14,533.40","14,423.01","14,533.40","14,385.39","939.56M","0.70%" +"12/11/2023","14,432.49","14,340.13","14,436.08","14,324.57","1.05B","0.20%" +"12/08/2023","14,403.97","14,279.46","14,416.92","14,264.96","997.65M","0.45%" +"12/07/2023","14,339.99","14,230.43","14,353.11","14,220.87","1.05B","1.37%" +"12/06/2023","14,146.71","14,325.62","14,327.63","14,138.51","1.02B","-0.58%" +"12/05/2023","14,229.91","14,126.40","14,285.66","14,121.76","1.11B","0.31%" +"12/04/2023","14,185.49","14,168.66","14,197.52","14,058.52","1.18B","-0.84%" +"12/01/2023","14,305.03","14,181.35","14,311.95","14,135.00","1.09B","0.55%" +"11/30/2023","14,226.22","14,265.05","14,289.20","14,127.05","1.53B","-0.23%" +"11/29/2023","14,258.49","14,367.11","14,423.22","14,247.89","979.43M","-0.16%" +"11/28/2023","14,281.76","14,224.63","14,303.66","14,195.72","870.61M","0.29%" +"11/27/2023","14,241.02","14,239.31","14,305.71","14,205.24","839.28M","-0.07%" +"11/24/2023","14,250.86","14,238.04","14,270.28","14,214.13","441.68M","-0.11%" +"11/22/2023","14,265.86","14,283.82","14,359.61","14,226.63","717.39M","0.46%" +"11/21/2023","14,199.98","14,217.23","14,237.50","14,146.30","815.36M","-0.59%" +"11/20/2023","14,284.53","14,134.75","14,309.80","14,134.20","902.05M","1.13%" +"11/17/2023","14,125.48","14,101.43","14,154.32","14,063.93","946.65M","0.08%" +"11/16/2023","14,113.67","14,066.88","14,130.45","14,033.79","925.11M","0.07%" +"11/15/2023","14,103.84","14,147.27","14,194.36","14,060.70","1.06B","0.07%" +"11/14/2023","14,094.38","14,015.37","14,124.06","14,003.14","1.11B","2.37%" +"11/13/2023","13,767.74","13,745.96","13,805.11","13,687.78","837.61M","-0.22%" +"11/10/2023","13,798.11","13,571.19","13,802.53","13,556.35","998.71M","2.05%" +"11/09/2023","13,521.45","13,693.70","13,697.82","13,506.02","1.04B","-0.94%" +"11/08/2023","13,650.41","13,660.22","13,684.87","13,573.58","956.59M","0.08%" +"11/07/2023","13,639.86","13,555.79","13,675.46","13,516.56","896.95M","0.90%" +"11/06/2023","13,518.78","13,514.08","13,551.62","13,435.99","912.89M","0.30%" +"11/03/2023","13,478.28","13,362.85","13,520.28","13,344.73","1.02B","1.38%" +"11/02/2023","13,294.19","13,230.49","13,302.18","13,177.64","1.03B","1.78%" +"11/01/2023","13,061.47","12,887.06","13,072.42","12,875.20","937.65M","1.64%" +"10/31/2023","12,851.24","12,786.62","12,859.40","12,697.04","914.04M","0.48%" +"10/30/2023","12,789.48","12,750.46","12,842.96","12,691.56","801.65M","1.16%" +"10/27/2023","12,643.01","12,718.69","12,772.43","12,600.57","856.38M","0.38%" +"10/26/2023","12,595.61","12,768.97","12,818.14","12,543.86","941.24M","-1.76%" +"10/25/2023","12,821.22","13,039.86","13,042.52","12,804.30","950.80M","-2.43%" +"10/24/2023","13,139.88","13,084.99","13,170.39","13,022.85","878.12M","0.93%" +"10/23/2023","13,018.33","12,930.85","13,143.22","12,848.83","859.07M","0.27%" +"10/20/2023","12,983.81","13,157.77","13,177.35","12,977.43","1.03B","-1.53%" +"10/19/2023","13,186.17","13,354.80","13,404.73","13,157.33","920.00M","-0.96%" +"10/18/2023","13,314.30","13,439.68","13,499.74","13,275.30","843.06M","-1.62%" +"10/17/2023","13,533.75","13,419.87","13,602.25","13,364.74","906.42M","-0.25%" +"10/16/2023","13,567.98","13,453.81","13,598.05","13,447.17","832.45M","1.20%" +"10/13/2023","13,407.23","13,613.59","13,619.54","13,361.85","843.48M","-1.23%" +"10/12/2023","13,574.22","13,672.47","13,714.14","13,491.56","921.27M","-0.63%" +"10/11/2023","13,659.68","13,619.21","13,671.11","13,549.29","797.05M","0.71%" +"10/10/2023","13,562.84","13,505.81","13,659.63","13,491.81","823.87M","0.58%" +"10/09/2023","13,484.24","13,326.22","13,509.30","13,277.48","723.95M","0.39%" +"10/06/2023","13,431.34","13,127.68","13,472.27","13,099.03","860.52M","1.60%" +"10/05/2023","13,219.83","13,228.12","13,251.18","13,087.57","870.00M","-0.12%" +"10/04/2023","13,236.01","13,092.92","13,258.76","13,072.51","854.22M","1.35%" +"10/03/2023","13,059.47","13,229.68","13,280.04","13,008.60","889.31M","-1.87%" +"10/02/2023","13,307.77","13,217.99","13,364.03","13,204.08","877.57M","0.67%" +"09/29/2023","13,219.32","13,337.71","13,382.98","13,177.09","1.02B","0.14%" +"09/28/2023","13,201.28","13,043.37","13,270.97","13,025.11","884.75M","0.83%" +"09/27/2023","13,092.85","13,115.36","13,156.37","12,963.16","894.11M","0.22%" +"09/26/2023","13,063.61","13,180.96","13,199.13","13,033.40","891.04M","-1.57%" +"09/25/2023","13,271.32","13,172.54","13,277.83","13,132.00","769.22M","0.45%" +"09/22/2023","13,211.81","13,287.17","13,353.22","13,200.64","831.54M","-0.09%" +"09/21/2023","13,223.99","13,328.06","13,362.23","13,222.56","928.74M","-1.82%" +"09/20/2023","13,469.13","13,710.26","13,727.81","13,467.28","835.28M","-1.53%" +"09/19/2023","13,678.19","13,649.44","13,705.15","13,578.87","881.73M","-0.23%" +"09/18/2023","13,710.24","13,669.96","13,751.28","13,663.46","962.57M","0.01%" +"09/15/2023","13,708.33","13,889.20","13,895.75","13,684.24","3.05B","-1.56%" +"09/14/2023","13,926.05","13,889.76","13,957.57","13,810.66","930.53M","0.81%" +"09/13/2023","13,813.58","13,773.67","13,868.57","13,733.82","929.03M","0.29%" +"09/12/2023","13,773.62","13,858.94","13,913.60","13,763.69","853.61M","-1.04%" +"09/11/2023","13,917.89","13,884.03","13,937.46","13,805.13","853.34M","1.14%" +"09/08/2023","13,761.53","13,754.71","13,843.37","13,733.18","781.91M","0.09%" +"09/07/2023","13,748.83","13,675.11","13,774.63","13,642.47","920.58M","-0.89%" +"09/06/2023","13,872.47","13,988.81","14,001.95","13,802.42","826.45M","-1.06%" +"09/05/2023","14,020.95","13,994.54","14,060.85","13,945.65","882.28M","-0.08%" +"09/01/2023","14,031.82","14,129.96","14,149.62","13,982.42","820.13M","-0.02%" +"08/31/2023","14,034.97","14,041.54","14,114.67","14,010.48","1.13B","0.11%" +"08/30/2023","14,019.31","13,961.77","14,050.82","13,924.20","829.23M","0.54%" +"08/29/2023","13,943.76","13,687.23","13,959.81","13,677.06","865.54M","1.74%" +"08/28/2023","13,705.13","13,695.36","13,735.98","13,626.64","674.53M","0.84%" +"08/25/2023","13,590.65","13,514.37","13,633.42","13,376.34","782.12M","0.94%" +"08/24/2023","13,463.97","13,834.31","13,834.68","13,462.84","891.76M","-1.87%" +"08/23/2023","13,721.03","13,532.43","13,757.00","13,532.43","811.82M","1.59%" +"08/22/2023","13,505.87","13,593.95","13,598.76","13,484.38","780.24M","0.06%" +"08/21/2023","13,497.59","13,347.26","13,516.86","13,325.59","828.82M","1.56%" +"08/18/2023","13,290.78","13,190.02","13,335.87","13,161.76","980.92M","-0.20%" +"08/17/2023","13,316.93","13,527.30","13,535.09","13,303.45","956.29M","-1.17%" +"08/16/2023","13,474.63","13,593.17","13,644.32","13,473.03","993.03M","-1.15%" +"08/15/2023","13,631.05","13,760.48","13,774.98","13,611.93","816.65M","-1.14%" +"08/14/2023","13,788.33","13,599.00","13,789.16","13,582.49","836.91M","1.05%" +"08/11/2023","13,644.85","13,633.65","13,720.33","13,609.98","842.28M","-0.56%" +"08/10/2023","13,721.03","13,818.25","13,947.16","13,686.51","979.72M","0.12%" +"08/09/2023","13,705.08","13,897.61","13,898.54","13,698.39","1.06B","-1.17%" +"08/08/2023","13,867.19","13,875.45","13,899.74","13,769.34","1.04B","-0.79%" +"08/07/2023","13,977.13","13,972.45","13,997.15","13,864.92","957.81M","0.61%" +"08/04/2023","13,892.07","14,025.96","14,119.22","13,897.93","1.00B","-0.48%" +"08/03/2023","13,959.71","13,899.76","14,032.28","13,881.35","1.03B","-0.10%" +"08/02/2023","13,973.45","14,132.73","14,133.85","13,914.81","1.06B","-2.17%" +"08/01/2023","14,283.91","14,274.93","14,309.21","14,215.64","909.92M","-0.43%" +"07/31/2023","14,346.02","14,337.90","14,370.91","14,292.75","1.08B","0.21%" +"07/28/2023","14,316.66","14,199.83","14,344.35","14,188.10","937.55M","1.90%" +"07/27/2023","14,050.11","14,319.16","14,360.20","14,006.92","1.00B","-0.55%" +"07/26/2023","14,127.28","14,123.52","14,187.35","14,041.95","883.42M","-0.12%" +"07/25/2023","14,144.55","14,093.24","14,201.91","14,092.52","864.05M","0.61%" +"07/24/2023","14,058.87","14,081.63","14,110.15","13,997.13","812.22M","0.19%" +"07/21/2023","14,032.80","14,148.17","14,179.01","14,020.45","1.45B","-0.22%" +"07/20/2023","14,063.31","14,273.29","14,309.92","14,030.63","996.24M","-2.05%" +"07/19/2023","14,358.02","14,398.53","14,446.55","14,317.09","978.63M","0.03%" +"07/18/2023","14,353.64","14,212.25","14,396.69","14,176.11","930.20M","0.76%" +"07/17/2023","14,244.95","14,149.92","14,274.41","14,138.00","914.53M","0.93%" +"07/14/2023","14,113.70","14,166.66","14,232.11","14,081.96","996.35M","-0.18%" +"07/13/2023","14,138.57","14,021.15","14,163.80","14,012.24","962.46M","1.58%" +"07/12/2023","13,918.96","13,915.64","13,963.45","13,842.13","1.01B","1.15%" +"07/11/2023","13,760.70","13,709.82","13,774.83","13,643.32","913.10M","0.55%" +"07/10/2023","13,685.48","13,645.37","13,692.41","13,584.87","1.00B","0.18%" +"07/07/2023","13,660.72","13,668.07","13,804.51","13,656.74","949.89M","-0.13%" +"07/06/2023","13,679.04","13,653.17","13,689.52","13,567.25","1.04B","-0.82%" +"07/05/2023","13,791.65","13,772.10","13,844.50","13,764.25","937.60M","-0.18%" +"07/03/2023","13,816.77","13,798.70","13,839.09","13,773.41","583.70M","0.21%" +"06/30/2023","13,787.92","13,719.98","13,816.67","13,716.16","1.07B","1.45%" +"06/29/2023","13,591.33","13,592.36","13,618.53","13,540.26","871.64M","0.00%" +"06/28/2023","13,591.75","13,506.02","13,654.14","13,495.73","890.52M","0.27%" +"06/27/2023","13,555.67","13,389.25","13,578.80","13,366.97","966.18M","1.65%" +"06/26/2023","13,335.78","13,468.75","13,573.57","13,334.42","936.28M","-1.16%" +"06/23/2023","13,492.52","13,484.10","13,572.18","13,442.65","3.36B","-1.01%" +"06/22/2023","13,630.61","13,443.41","13,631.85","13,441.56","898.27M","0.95%" +"06/21/2023","13,502.20","13,620.87","13,638.57","13,460.94","1.06B","-1.21%" +"06/20/2023","13,667.29","13,642.29","13,711.18","13,561.84","1.13B","-0.16%" +"06/16/2023","13,689.57","13,859.07","13,864.06","13,680.96","2.92B","-0.68%" +"06/15/2023","13,782.82","13,572.88","13,828.17","13,561.37","1.13B","1.15%" +"06/14/2023","13,626.48","13,570.56","13,661.74","13,455.99","1.16B","0.39%" +"06/13/2023","13,573.32","13,566.53","13,594.40","13,473.19","1.04B","0.83%" +"06/12/2023","13,461.92","13,326.37","13,465.91","13,302.58","974.53M","1.53%" +"06/09/2023","13,259.14","13,312.39","13,385.95","13,229.33","899.24M","0.16%" +"06/08/2023","13,238.52","13,113.27","13,248.60","13,101.18","873.24M","1.02%" +"06/07/2023","13,104.89","13,295.26","13,361.90","13,089.48","1.11B","-1.29%" +"06/06/2023","13,276.42","13,199.59","13,306.21","13,165.65","978.70M","0.36%" +"06/05/2023","13,229.43","13,238.48","13,330.65","13,194.95","887.68M","-0.09%" +"06/02/2023","13,240.77","13,190.48","13,256.21","13,125.86","941.89M","1.07%" +"06/01/2023","13,100.98","12,944.46","13,141.83","12,903.63","957.13M","1.28%" +"05/31/2023","12,935.29","12,968.38","13,029.08","12,889.37","1.94B","-0.63%" +"05/30/2023","13,017.43","13,109.10","13,154.29","12,968.12","969.21M","0.32%" +"05/26/2023","12,975.69","12,736.42","13,001.91","12,729.74","914.77M","2.19%" +"05/25/2023","12,698.09","12,706.44","12,736.92","12,604.89","970.49M","1.71%" +"05/24/2023","12,484.16","12,481.89","12,529.63","12,415.85","842.72M","-0.61%" +"05/23/2023","12,560.25","12,652.88","12,709.74","12,554.43","899.73M","-1.26%" +"05/22/2023","12,720.78","12,664.44","12,756.22","12,655.26","886.96M","0.50%" +"05/19/2023","12,657.90","12,709.46","12,731.73","12,624.06","899.33M","-0.24%" +"05/18/2023","12,688.84","12,513.87","12,698.50","12,512.26","932.20M","1.51%" +"05/17/2023","12,500.57","12,388.58","12,514.07","12,335.02","936.60M","1.28%" +"05/16/2023","12,343.05","12,327.05","12,403.81","12,324.52","857.54M","-0.18%" +"05/15/2023","12,365.21","12,301.17","12,376.40","12,263.35","857.25M","0.66%" +"05/12/2023","12,284.74","12,350.52","12,364.65","12,209.58","865.59M","-0.35%" +"05/11/2023","12,328.51","12,321.26","12,347.38","12,255.44","934.31M","0.18%" +"05/10/2023","12,306.44","12,286.66","12,337.69","12,180.86","1.04B","1.04%" +"05/09/2023","12,179.55","12,195.78","12,216.13","12,174.06","899.76M","-0.63%" +"05/08/2023","12,256.92","12,231.68","12,264.99","12,178.26","882.60M","0.18%" +"05/05/2023","12,235.41","12,073.03","12,264.83","12,065.72","1.01B","2.25%" +"05/04/2023","11,966.40","11,997.34","12,033.15","11,925.37","1.01B","-0.49%" +"05/03/2023","12,025.33","12,097.04","12,212.55","12,022.46","1.09B","-0.46%" +"05/02/2023","12,080.51","12,198.02","12,206.58","12,015.22","1.05B","-1.08%" +"05/01/2023","12,212.60","12,210.05","12,261.32","12,181.08","926.58M","-0.11%" +"04/28/2023","12,226.58","12,117.54","12,227.72","12,082.57","1.07B","0.69%" +"04/27/2023","12,142.24","11,972.15","12,154.01","11,950.92","986.43M","2.43%" +"04/26/2023","11,854.35","11,913.23","11,967.99","11,833.07","973.40M","0.47%" +"04/25/2023","11,799.16","11,968.81","11,990.46","11,798.77","921.37M","-1.98%" +"04/24/2023","12,037.20","12,053.47","12,103.58","11,960.30","853.57M","-0.29%" +"04/21/2023","12,072.46","12,046.03","12,097.15","11,986.82","944.77M","0.11%" +"04/20/2023","12,059.56","12,039.08","12,155.96","12,011.95","899.17M","-0.80%" +"04/19/2023","12,157.23","12,063.68","12,191.10","12,060.17","879.49M","0.03%" +"04/18/2023","12,153.41","12,234.56","12,245.43","12,110.23","883.01M","-0.04%" +"04/17/2023","12,157.72","12,108.23","12,159.02","12,064.10","904.58M","0.28%" +"04/14/2023","12,123.46","12,117.91","12,205.72","12,026.55","874.14M","-0.35%" +"04/13/2023","12,166.27","11,997.42","12,178.80","11,995.94","921.41M","1.99%" +"04/12/2023","11,929.34","12,110.87","12,134.50","11,916.54","916.01M","-0.85%" +"04/11/2023","12,031.88","12,080.24","12,091.27","12,011.40","883.24M","-0.43%" +"04/10/2023","12,084.36","11,975.13","12,084.95","11,924.20","862.62M","-0.03%" +"04/06/2023","12,087.96","11,939.08","12,098.50","11,898.36","785.43M","0.76%" +"04/05/2023","11,996.86","12,081.76","12,086.75","11,931.84","894.37M","-1.07%" +"04/04/2023","12,126.33","12,208.49","12,224.68","12,081.81","877.51M","-0.52%" +"04/03/2023","12,189.45","12,146.09","12,196.34","12,086.52","950.52M","-0.27%" +"03/31/2023","12,221.91","12,031.54","12,227.93","12,030.44","1.16B","1.74%" +"03/30/2023","12,013.47","12,010.45","12,044.79","11,953.37","923.96M","0.73%" +"03/29/2023","11,926.24","11,855.59","11,941.59","11,823.35","915.05M","1.79%" +"03/28/2023","11,716.08","11,752.76","11,752.76","11,635.03","773.10M","-0.45%" +"03/27/2023","11,768.84","11,868.54","11,903.21","11,739.05","844.71M","-0.47%" +"03/24/2023","11,823.96","11,747.62","11,826.23","11,670.67","897.32M","0.31%" +"03/23/2023","11,787.40","11,811.32","11,962.69","11,684.52","1.00B","1.01%" +"03/22/2023","11,669.96","11,857.50","12,013.99","11,666.85","963.97M","-1.60%" +"03/21/2023","11,860.11","11,764.79","11,879.16","11,724.91","1.04B","1.58%" +"03/20/2023","11,675.54","11,614.39","11,695.55","11,550.69","1.08B","0.39%" +"03/17/2023","11,630.51","11,696.34","11,773.11","11,562.63","2.94B","-0.74%" +"03/16/2023","11,717.28","11,384.87","11,733.80","11,365.49","1.13B","2.48%" +"03/15/2023","11,434.05","11,291.17","11,447.90","11,238.44","1.22B","0.05%" +"03/14/2023","11,428.15","11,357.74","11,467.01","11,284.93","1.18B","2.14%" +"03/13/2023","11,188.84","11,041.46","11,326.73","10,982.80","1.31B","0.45%" +"03/10/2023","11,138.89","11,325.36","11,373.81","11,093.86","1.23B","-1.76%" +"03/09/2023","11,338.36","11,578.31","11,667.12","11,319.98","994.86M","-2.05%" +"03/08/2023","11,576.00","11,553.09","11,601.23","11,487.75","923.10M","0.40%" +"03/07/2023","11,530.33","11,670.98","11,705.96","11,512.03","973.96M","-1.25%" +"03/06/2023","11,675.74","11,736.87","11,827.92","11,667.48","977.57M","-0.11%" +"03/03/2023","11,689.01","11,524.65","11,699.63","11,514.74","965.05M","1.97%" +"03/02/2023","11,462.98","11,273.77","11,487.59","11,273.61","950.09M","0.73%" +"03/01/2023","11,379.48","11,447.58","11,479.00","11,349.87","964.54M","-0.66%" +"02/28/2023","11,455.54","11,451.05","11,548.22","11,435.39","1.26B","-0.10%" +"02/27/2023","11,466.98","11,517.19","11,565.23","11,444.60","874.29M","0.63%" +"02/24/2023","11,394.94","11,404.18","11,434.36","11,334.46","900.84M","-1.69%" +"02/23/2023","11,590.40","11,636.93","11,638.97","11,432.58","903.17M","0.72%" +"02/22/2023","11,507.07","11,517.20","11,582.52","11,445.17","942.98M","0.13%" +"02/21/2023","11,492.30","11,640.37","11,684.14","11,491.18","1.02B","-2.50%" +"02/17/2023","11,787.27","11,777.50","11,803.22","11,673.21","966.30M","-0.58%" +"02/16/2023","11,855.83","11,896.31","12,040.34","11,853.36","986.41M","-1.78%" +"02/15/2023","12,070.59","11,905.12","12,071.29","11,876.82","951.90M","0.92%" +"02/14/2023","11,960.14","11,808.20","11,999.85","11,760.57","929.01M","0.57%" +"02/13/2023","11,891.79","11,759.09","11,910.92","11,719.73","937.01M","1.48%" +"02/10/2023","11,718.12","11,714.60","11,775.80","11,630.54","934.05M","-0.61%" +"02/09/2023","11,789.58","12,069.10","12,070.96","11,745.11","1.03B","-1.02%" +"02/08/2023","11,910.52","12,069.12","12,096.39","11,890.09","953.41M","-1.68%" +"02/07/2023","12,113.79","11,891.25","12,150.22","11,836.78","1.07B","1.90%" +"02/06/2023","11,887.45","11,904.41","11,973.41","11,843.49","1.01B","-1.00%" +"02/03/2023","12,006.96","11,946.86","12,231.31","11,946.86","1.11B","-1.59%" +"02/02/2023","12,200.82","12,065.15","12,269.55","12,024.14","1.33B","3.25%" +"02/01/2023","11,816.32","11,573.14","11,904.02","11,500.33","1.21B","2.00%" +"01/31/2023","11,584.55","11,398.58","11,586.01","11,398.37","1.15B","1.67%" +"01/30/2023","11,393.81","11,512.34","11,553.31","11,388.54","954.43M","-1.96%" +"01/27/2023","11,621.71","11,470.47","11,691.89","11,470.27","1.05B","0.95%" +"01/26/2023","11,512.41","11,458.41","11,516.05","11,341.19","992.60M","1.76%" +"01/25/2023","11,313.36","11,146.53","11,334.22","11,069.17","924.72M","-0.18%" +"01/24/2023","11,334.27","11,302.93","11,378.15","11,282.65","914.95M","-0.27%" +"01/23/2023","11,364.41","11,171.94","11,405.50","11,144.03","1.05B","2.01%" +"01/20/2023","11,140.43","10,924.66","11,143.17","10,885.64","1.16B","2.66%" +"01/19/2023","10,852.27","10,890.40","10,932.52","10,804.57","905.21M","-0.96%" +"01/18/2023","10,957.01","11,170.95","11,223.41","10,952.05","986.97M","-1.24%" +"01/17/2023","11,095.11","11,070.00","11,145.44","11,024.72","990.06M","0.14%" +"01/13/2023","11,079.16","10,906.37","11,084.01","10,900.16","919.66M","0.71%" +"01/12/2023","11,001.11","10,969.26","11,027.75","10,797.12","1.03B","0.64%" +"01/11/2023","10,931.67","10,794.99","10,932.44","10,762.73","1.01B","1.76%" +"01/10/2023","10,742.63","10,607.72","10,743.67","10,589.59","888.70M","1.01%" +"01/09/2023","10,635.65","10,662.11","10,807.26","10,619.12","1.04B","0.63%" +"01/06/2023","10,569.29","10,363.96","10,604.14","10,265.04","970.67M","2.56%" +"01/05/2023","10,305.24","10,390.31","10,393.22","10,295.25","957.48M","-1.47%" +"01/04/2023","10,458.76","10,467.82","10,515.22","10,337.64","1.04B","0.69%" +"01/03/2023","10,386.99","10,562.06","10,613.06","10,309.16","983.36M","-0.76%" +"12/30/2022","10,466.48","10,368.37","10,468.31","10,324.70","850.56M","-0.11%" +"12/29/2022","10,478.09","10,321.46","10,502.08","10,301.06","894.54M","2.59%" +"12/28/2022","10,213.29","10,339.20","10,414.82","10,207.47","751.52M","-1.35%" +"12/27/2022","10,353.23","10,462.19","10,472.32","10,340.73","753.05M","-1.38%" +"12/23/2022","10,497.86","10,437.75","10,514.76","10,361.82","678.03M","0.21%" +"12/22/2022","10,476.12","10,586.46","10,599.34","10,313.32","974.20M","-2.18%" +"12/21/2022","10,709.37","10,592.00","10,753.57","10,569.20","937.40M","1.54%" +"12/20/2022","10,547.11","10,490.89","10,609.46","10,446.82","972.31M","0.01%" +"12/19/2022","10,546.03","10,707.44","10,713.97","10,497.55","1.04B","-1.49%" +"12/16/2022","10,705.41","10,767.63","10,833.24","10,642.10","3.28B","-0.97%" +"12/15/2022","10,810.53","11,012.62","11,029.57","10,775.61","1.16B","-3.23%" +"12/14/2022","11,170.89","11,248.09","11,352.09","11,065.24","1.12B","-0.76%" +"12/13/2022","11,256.81","11,542.84","11,571.64","11,160.54","1.24B","1.01%" +"12/12/2022","11,143.74","11,015.48","11,144.67","10,984.82","955.14M","1.26%" +"12/09/2022","11,004.62","11,038.17","11,138.70","10,999.26","867.24M","-0.70%" +"12/08/2022","11,082.00","11,011.33","11,119.16","10,939.47","832.95M","1.13%" +"12/07/2022","10,958.55","10,963.95","11,039.81","10,910.62","828.48M","-0.51%" +"12/06/2022","11,014.89","11,228.42","11,241.42","10,956.20","888.70M","-2.00%" +"12/05/2022","11,239.94","11,380.99","11,425.51","11,193.03","885.18M","-1.93%" +"12/02/2022","11,461.50","11,308.38","11,492.32","11,296.72","859.61M","-0.18%" +"12/01/2022","11,482.45","11,475.17","11,546.77","11,378.75","912.53M","0.13%" +"11/30/2022","11,468.00","10,995.20","11,468.47","10,966.53","1.62B","4.41%" +"11/29/2022","10,983.78","11,060.02","11,086.02","10,944.37","783.46M","-0.59%" +"11/28/2022","11,049.50","11,147.57","11,217.75","11,020.69","811.96M","-1.58%" +"11/25/2022","11,226.36","11,231.00","11,261.57","11,206.38","377.17M","-0.52%" +"11/23/2022","11,285.32","11,174.61","11,310.82","11,174.61","695.12M","0.99%" +"11/22/2022","11,174.41","11,058.56","11,179.87","10,975.66","758.80M","1.36%" +"11/21/2022","11,024.51","11,091.01","11,128.78","10,999.75","765.20M","-1.09%" +"11/18/2022","11,146.06","11,257.01","11,259.44","11,059.16","846.40M","0.01%" +"11/17/2022","11,144.96","11,008.67","11,198.84","11,006.21","837.39M","-0.35%" +"11/16/2022","11,183.66","11,260.09","11,286.10","11,162.92","887.82M","-1.54%" +"11/15/2022","11,358.41","11,474.82","11,492.62","11,241.15","1.04B","1.45%" +"11/14/2022","11,196.22","11,233.90","11,350.13","11,167.17","983.40M","-1.12%" +"11/11/2022","11,323.33","11,124.75","11,352.43","11,069.83","1.21B","1.88%" +"11/10/2022","11,114.15","10,869.17","11,119.12","10,779.95","1.40B","7.35%" +"11/09/2022","10,353.17","10,528.45","10,564.97","10,344.01","1.04B","-2.48%" +"11/08/2022","10,616.20","10,611.53","10,745.64","10,472.73","994.35M","0.49%" +"11/07/2022","10,564.52","10,516.94","10,587.96","10,428.91","930.25M","0.85%" +"11/04/2022","10,475.25","10,548.14","10,553.63","10,262.93","1.09B","1.28%" +"11/03/2022","10,342.94","10,399.45","10,486.01","10,319.54","1.01B","-1.73%" +"11/02/2022","10,524.80","10,885.01","10,993.24","10,522.90","1.10B","-3.36%" +"11/01/2022","10,890.84","11,154.74","11,156.35","10,881.19","903.26M","-0.89%" +"10/31/2022","10,988.15","11,028.43","11,047.94","10,914.00","1.08B","-1.03%" +"10/28/2022","11,102.45","10,766.20","11,117.04","10,766.20","977.64M","2.87%" +"10/27/2022","10,792.67","10,971.95","10,998.73","10,780.50","973.52M","-1.63%" +"10/26/2022","10,970.99","10,969.02","11,205.84","10,948.38","1.00B","-2.04%" +"10/25/2022","11,199.12","10,996.97","11,210.38","10,996.97","991.08M","2.25%" +"10/24/2022","10,952.61","10,867.07","10,983.52","10,713.33","921.20M","0.86%" +"10/21/2022","10,859.72","10,576.04","10,875.72","10,542.43","1.02B","2.31%" +"10/20/2022","10,614.84","10,657.41","10,837.30","10,574.55","866.25M","-0.61%" +"10/19/2022","10,680.51","10,689.31","10,808.04","10,592.88","921.13M","-0.85%" +"10/18/2022","10,772.40","10,963.99","10,972.97","10,670.12","929.62M","0.90%" +"10/17/2022","10,675.80","10,575.65","10,696.59","10,569.69","944.31M","3.43%" +"10/14/2022","10,321.39","10,742.81","10,766.68","10,308.81","918.04M","-3.08%" +"10/13/2022","10,649.15","10,131.82","10,697.71","10,088.83","1.05B","2.23%" +"10/12/2022","10,417.10","10,437.00","10,494.53","10,372.21","823.61M","-0.09%" +"10/11/2022","10,426.19","10,484.37","10,608.84","10,351.98","990.74M","-1.10%" +"10/10/2022","10,542.10","10,659.95","10,669.93","10,449.04","812.52M","-1.04%" +"10/07/2022","10,652.41","10,877.28","10,891.93","10,608.52","1.03B","-3.80%" +"10/06/2022","11,073.31","11,129.04","11,230.44","11,051.27","873.35M","-0.68%" +"10/05/2022","11,148.64","11,022.67","11,210.32","10,910.76","830.23M","-0.25%" +"10/04/2022","11,176.41","11,054.72","11,189.96","11,044.04","1.02B","3.34%" +"10/03/2022","10,815.43","10,659.01","10,875.46","10,577.89","943.34M","2.27%" +"09/30/2022","10,575.62","10,697.71","10,883.04","10,572.33","1.10B","-1.51%" +"09/29/2022","10,737.51","10,894.44","10,899.47","10,623.22","971.92M","-2.84%" +"09/28/2022","11,051.64","10,817.53","11,101.50","10,776.34","953.34M","2.05%" +"09/27/2022","10,829.50","10,955.29","11,040.99","10,741.02","903.37M","0.25%" +"09/26/2022","10,802.92","10,833.38","11,024.00","10,789.05","949.64M","-0.60%" +"09/23/2022","10,867.93","10,952.69","10,958.29","10,732.72","1.00B","-1.80%" +"09/22/2022","11,066.80","11,167.38","11,203.77","11,024.64","934.35M","-1.37%" +"09/21/2022","11,220.19","11,466.21","11,613.57","11,219.00","909.35M","-1.79%" +"09/20/2022","11,425.05","11,440.14","11,520.99","11,343.72","861.66M","-0.95%" +"09/19/2022","11,535.02","11,338.57","11,538.13","11,337.83","932.68M","0.76%" +"09/16/2022","11,448.40","11,401.21","11,460.43","11,316.92","3.05B","-0.90%" +"09/15/2022","11,552.36","11,633.24","11,760.73","11,497.11","1.03B","-1.43%" +"09/14/2022","11,719.68","11,680.41","11,746.83","11,602.76","1.05B","0.74%" +"09/13/2022","11,633.57","11,908.81","11,957.97","11,604.43","1.10B","-5.16%" +"09/12/2022","12,266.41","12,174.94","12,270.19","12,169.28","845.28M","1.27%" +"09/09/2022","12,112.31","11,958.61","12,132.67","11,958.61","881.47M","2.11%" +"09/08/2022","11,862.13","11,679.86","11,896.73","11,660.53","875.83M","0.60%" +"09/07/2022","11,791.90","11,559.38","11,819.07","11,555.08","897.12M","2.14%" +"09/06/2022","11,544.91","11,643.03","11,679.43","11,471.50","945.53M","-0.74%" +"09/02/2022","11,630.86","11,899.14","11,945.91","11,573.51","868.07M","-1.31%" +"09/01/2022","11,785.13","11,707.44","11,798.37","11,546.52","974.17M","-0.26%" +"08/31/2022","11,816.20","11,972.56","12,027.43","11,814.17","1.16B","-0.56%" +"08/30/2022","11,883.14","12,093.06","12,101.85","11,790.03","896.27M","-1.12%" +"08/29/2022","12,017.67","12,021.05","12,124.87","11,981.42","798.39M","-1.02%" +"08/26/2022","12,141.71","12,630.58","12,655.84","12,141.52","960.49M","-3.94%" +"08/25/2022","12,639.26","12,506.37","12,641.26","12,471.98","797.23M","1.67%" +"08/24/2022","12,431.53","12,375.15","12,504.33","12,350.16","770.64M","0.41%" +"08/23/2022","12,381.30","12,380.37","12,490.86","12,352.03","763.64M","0.00%" +"08/22/2022","12,381.57","12,523.16","12,538.55","12,353.73","857.72M","-2.55%" +"08/19/2022","12,705.21","12,832.27","12,859.01","12,674.87","998.67M","-2.01%" +"08/18/2022","12,965.34","12,937.79","13,002.66","12,873.49","865.17M","0.21%" +"08/17/2022","12,938.12","12,968.63","13,053.51","12,863.01","977.81M","-1.25%" +"08/16/2022","13,102.55","13,082.64","13,181.09","12,979.24","952.79M","-0.19%" +"08/15/2022","13,128.05","12,996.63","13,146.06","12,993.78","862.20M","0.62%" +"08/12/2022","13,047.19","12,866.31","13,047.19","12,821.22","936.39M","2.09%" +"08/11/2022","12,779.91","12,944.82","13,026.24","12,760.09","1.08B","-0.58%" +"08/10/2022","12,854.80","12,793.44","12,861.44","12,698.61","1.05B","2.89%" +"08/09/2022","12,493.93","12,557.49","12,582.91","12,438.86","1.02B","-1.19%" +"08/08/2022","12,644.46","12,703.72","12,855.16","12,597.75","1.00B","-0.10%" +"08/05/2022","12,657.55","12,538.80","12,720.44","12,525.77","991.77M","-0.50%" +"08/04/2022","12,720.58","12,675.04","12,736.19","12,600.78","1.05B","0.41%" +"08/03/2022","12,668.16","12,433.87","12,699.64","12,425.21","1.10B","2.59%" +"08/02/2022","12,348.76","12,287.67","12,503.34","12,260.48","902.82M","-0.16%" +"08/01/2022","12,368.98","12,317.96","12,499.72","12,271.98","891.53M","-0.18%" +"07/29/2022","12,390.69","12,239.69","12,426.26","12,181.13","1.10B","1.88%" +"07/28/2022","12,162.59","12,036.48","12,179.09","11,886.67","958.80M","1.08%" +"07/27/2022","12,032.42","11,756.19","12,081.73","11,718.38","939.31M","4.06%" +"07/26/2022","11,562.58","11,701.53","11,711.31","11,533.37","834.49M","-1.87%" +"07/25/2022","11,782.67","11,837.96","11,855.11","11,707.53","783.12M","-0.43%" +"07/22/2022","11,834.11","12,025.37","12,093.02","11,767.19","884.72M","-1.87%" +"07/21/2022","12,059.61","11,914.15","12,060.59","11,812.72","840.81M","1.36%" +"07/20/2022","11,897.65","11,726.09","11,939.96","11,703.36","1.01B","1.58%" +"07/19/2022","11,713.15","11,515.00","11,721.22","11,448.97","974.15M","3.11%" +"07/18/2022","11,360.05","11,561.64","11,629.03","11,322.84","922.80M","-0.81%" +"07/15/2022","11,452.42","11,379.36","11,454.69","11,295.33","947.43M","1.79%" +"07/14/2022","11,251.18","11,151.21","11,279.97","11,005.93","817.49M","0.03%" +"07/13/2022","11,247.58","11,056.55","11,325.67","11,031.27","812.60M","-0.15%" +"07/12/2022","11,264.73","11,420.89","11,483.17","11,207.08","836.73M","-0.95%" +"07/11/2022","11,372.60","11,524.49","11,541.10","11,348.06","844.13M","-2.26%" +"07/08/2022","11,635.31","11,503.61","11,689.70","11,479.77","820.69M","0.12%" +"07/07/2022","11,621.35","11,422.60","11,644.47","11,412.88","916.26M","2.28%" +"07/06/2022","11,361.85","11,337.90","11,443.14","11,250.32","933.39M","0.35%" +"07/05/2022","11,322.24","10,964.18","11,323.89","10,911.45","1.07B","1.75%" +"07/01/2022","11,127.84","11,006.83","11,132.55","10,922.71","930.71M","0.90%" +"06/30/2022","11,028.74","11,048.25","11,160.92","10,850.01","1.16B","-1.33%" +"06/29/2022","11,177.89","11,160.22","11,226.33","11,072.19","1.02B","-0.03%" +"06/28/2022","11,181.54","11,542.24","11,635.86","11,177.68","1.02B","-2.98%" +"06/27/2022","11,524.55","11,661.02","11,677.49","11,487.07","991.61M","-0.72%" +"06/24/2022","11,607.62","11,351.31","11,613.23","11,337.78","4.31B","3.34%" +"06/23/2022","11,232.19","11,137.68","11,260.27","11,046.29","1.03B","1.62%" +"06/22/2022","11,053.08","10,941.95","11,216.77","10,938.06","1.11B","-0.15%" +"06/21/2022","11,069.30","10,974.05","11,164.99","10,974.05","1.19B","2.51%" +"06/17/2022","10,798.35","10,697.55","10,884.71","10,638.72","2.80B","1.43%" +"06/16/2022","10,646.10","10,806.02","10,831.07","10,565.13","1.25B","-4.08%" +"06/15/2022","11,099.16","10,968.40","11,244.26","10,866.39","1.22B","2.50%" +"06/14/2022","10,828.34","10,897.43","10,926.81","10,733.04","953.68M","0.18%" +"06/13/2022","10,809.22","10,986.84","11,071.48","10,775.14","1.21B","-4.68%" +"06/10/2022","11,340.02","11,543.88","11,569.15","11,328.27","1.06B","-3.52%" +"06/09/2022","11,754.23","12,016.47","12,115.07","11,751.98","998.87M","-2.75%" +"06/08/2022","12,086.27","12,147.28","12,235.78","12,052.70","911.77M","-0.73%" +"06/07/2022","12,175.23","11,925.81","12,194.86","11,888.62","900.55M","0.94%" +"06/06/2022","12,061.37","12,200.33","12,245.40","12,004.20","911.01M","0.40%" +"06/03/2022","12,012.73","12,097.12","12,167.44","11,966.62","837.59M","-2.47%" +"06/02/2022","12,316.90","11,945.57","12,320.12","11,901.45","916.66M","2.69%" +"06/01/2022","11,994.46","12,176.89","12,237.93","11,901.43","940.60M","-0.72%" +"05/31/2022","12,081.39","12,137.54","12,190.08","11,942.50","1.77B","-0.41%" +"05/27/2022","12,131.13","11,869.69","12,131.66","11,856.82","942.22M","3.33%" +"05/26/2022","11,740.65","11,409.84","11,796.97","11,406.16","930.42M","2.68%" +"05/25/2022","11,434.74","11,225.03","11,511.90","11,211.85","907.18M","1.51%" +"05/24/2022","11,264.45","11,326.44","11,351.61","11,092.48","924.23M","-2.35%" +"05/23/2022","11,535.28","11,396.28","11,552.07","11,304.56","889.21M","1.59%" +"05/20/2022","11,354.62","11,542.67","11,552.21","11,035.69","1.20B","-0.30%" +"05/19/2022","11,388.50","11,364.40","11,562.82","11,313.31","1.05B","-0.26%" +"05/18/2022","11,418.15","11,790.68","11,826.22","11,381.69","1.03B","-4.73%" +"05/17/2022","11,984.52","11,905.57","11,988.43","11,754.28","1.02B","2.76%" +"05/16/2022","11,662.79","11,727.14","11,804.59","11,627.53","978.06M","-1.20%" +"05/13/2022","11,805.00","11,555.97","11,856.71","11,510.25","1.23B","3.82%" +"05/12/2022","11,370.96","11,199.25","11,547.33","11,108.76","1.40B","0.06%" +"05/11/2022","11,364.24","11,645.57","11,844.50","11,339.18","1.27B","-3.18%" +"05/10/2022","11,737.67","11,900.34","11,944.94","11,566.28","1.28B","0.98%" +"05/09/2022","11,623.25","11,923.03","11,990.61","11,574.94","1.24B","-4.29%" +"05/06/2022","12,144.66","12,246.83","12,358.42","11,990.15","1.09B","-1.40%" +"05/05/2022","12,317.69","12,787.52","12,787.52","12,183.56","1.10B","-4.99%" +"05/04/2022","12,964.86","12,574.73","12,985.01","12,367.02","1.11B","3.19%" +"05/03/2022","12,563.76","12,511.46","12,645.83","12,460.99","897.84M","0.22%" +"05/02/2022","12,536.02","12,331.69","12,542.54","12,202.41","1.04B","1.63%" +"04/29/2022","12,334.64","12,710.42","12,861.83","12,315.74","1.09B","-4.17%" +"04/28/2022","12,871.53","12,712.86","12,948.52","12,487.86","1.01B","3.06%" +"04/27/2022","12,488.93","12,500.88","12,703.79","12,430.90","942.84M","-0.01%" +"04/26/2022","12,490.74","12,918.04","12,918.04","12,490.74","1.02B","-3.95%" +"04/25/2022","13,004.85","12,749.17","13,011.45","12,722.59","988.04M","1.29%" +"04/22/2022","12,839.29","13,168.80","13,212.61","12,828.02","950.70M","-2.55%" +"04/21/2022","13,174.65","13,623.70","13,710.70","13,140.83","993.83M","-2.07%" +"04/20/2022","13,453.07","13,665.38","13,678.55","13,426.13","871.26M","-1.22%" +"04/19/2022","13,619.66","13,312.44","13,643.97","13,281.22","855.29M","2.15%" +"04/18/2022","13,332.36","13,319.39","13,414.27","13,222.03","832.41M","-0.14%" +"04/14/2022","13,351.08","13,647.42","13,662.93","13,345.22","927.38M","-2.14%" +"04/13/2022","13,643.59","13,373.12","13,679.43","13,353.66","910.79M","2.03%" +"04/12/2022","13,371.57","13,584.69","13,685.95","13,317.74","902.42M","-0.30%" +"04/11/2022","13,411.96","13,547.29","13,585.08","13,401.39","991.30M","-2.18%" +"04/08/2022","13,711.00","13,830.47","13,866.06","13,693.69","858.45M","-1.34%" +"04/07/2022","13,897.30","13,861.49","13,978.25","13,689.23","931.35M","0.06%" +"04/06/2022","13,888.82","14,002.58","14,032.84","13,788.90","1.09B","-2.22%" +"04/05/2022","14,204.17","14,490.26","14,500.29","14,169.12","930.40M","-2.26%" +"04/04/2022","14,532.55","14,304.35","14,534.38","14,286.45","915.41M","1.90%" +"04/01/2022","14,261.50","14,269.53","14,306.94","14,131.81","1.02B","0.29%" +"03/31/2022","14,220.52","14,444.78","14,456.74","14,217.72","1.10B","-1.54%" +"03/30/2022","14,442.28","14,558.59","14,609.25","14,383.45","1.01B","-1.21%" +"03/29/2022","14,619.64","14,500.39","14,646.90","14,419.40","1.09B","1.84%" +"03/28/2022","14,354.90","14,177.21","14,356.00","14,101.34","892.94M","1.31%" +"03/25/2022","14,169.30","14,194.72","14,218.76","14,010.79","941.78M","-0.16%" +"03/24/2022","14,191.84","14,001.32","14,193.55","13,897.20","916.74M","1.93%" +"03/23/2022","13,922.60","13,990.35","14,152.14","13,921.65","961.73M","-1.32%" +"03/22/2022","14,108.82","13,866.43","14,141.07","13,857.29","1.10B","1.95%" +"03/21/2022","13,838.46","13,860.39","13,945.80","13,682.55","1.14B","-0.40%" +"03/18/2022","13,893.84","13,564.63","13,899.28","13,528.06","2.85B","2.05%" +"03/17/2022","13,614.78","13,360.72","13,620.80","13,317.14","1.14B","1.33%" +"03/16/2022","13,436.55","13,119.37","13,440.12","12,992.20","1.41B","3.77%" +"03/15/2022","12,948.62","12,685.23","12,973.88","12,616.59","1.13B","2.92%" +"03/14/2022","12,581.22","12,795.12","12,918.01","12,555.35","1.21B","-2.04%" +"03/11/2022","12,843.81","13,229.77","13,239.35","12,830.37","1.02B","-2.18%" +"03/10/2022","13,129.96","13,098.35","13,163.50","12,946.28","961.59M","-0.95%" +"03/09/2022","13,255.55","13,113.70","13,301.16","13,039.79","1.12B","3.59%" +"03/08/2022","12,795.55","12,800.04","13,159.44","12,670.08","1.34B","-0.28%" +"03/07/2022","12,830.96","13,328.36","13,353.28","12,828.02","1.29B","-3.62%" +"03/04/2022","13,313.44","13,455.23","13,486.71","13,224.98","1.04B","-1.66%" +"03/03/2022","13,537.94","13,837.59","13,837.59","13,472.64","1.03B","-1.56%" +"03/02/2022","13,752.02","13,597.53","13,796.55","13,493.91","1.03B","1.62%" +"03/01/2022","13,532.46","13,716.70","13,777.04","13,441.32","1.24B","-1.59%" +"02/28/2022","13,751.40","13,570.83","13,810.64","13,549.90","1.39B","0.41%" +"02/25/2022","13,694.62","13,485.26","13,696.86","13,358.29","978.45M","1.64%" +"02/24/2022","13,473.58","12,587.88","13,486.11","12,587.88","1.38B","3.34%" +"02/23/2022","13,037.49","13,511.75","13,533.78","13,032.17","944.40M","-2.57%" +"02/22/2022","13,381.52","13,424.36","13,618.71","13,249.65","1.02B","-1.23%" +"02/18/2022","13,548.07","13,735.40","13,762.40","13,465.56","1.02B","-1.23%" +"02/17/2022","13,716.72","14,004.19","14,020.82","13,704.70","922.82M","-2.88%" +"02/16/2022","14,124.09","14,038.92","14,163.73","13,931.99","838.99M","-0.11%" +"02/15/2022","14,139.76","13,997.18","14,142.49","13,976.29","903.09M","2.53%" +"02/14/2022","13,790.92","13,768.97","13,921.71","13,664.76","936.80M","0.00%" +"02/11/2022","13,791.15","14,213.62","14,246.70","13,733.16","1.08B","-2.78%" +"02/10/2022","14,185.64","14,228.68","14,509.56","14,118.20","1.06B","-2.10%" +"02/09/2022","14,490.37","14,368.16","14,490.72","14,330.87","935.01M","2.08%" +"02/08/2022","14,194.46","13,984.43","14,226.48","13,934.78","865.49M","1.28%" +"02/07/2022","14,015.67","14,118.79","14,236.31","13,974.10","858.02M","-0.58%" +"02/04/2022","14,098.01","13,958.48","14,222.76","13,850.39","862.97M","1.58%" +"02/03/2022","13,878.82","14,045.83","14,207.89","13,851.75","945.51M","-3.74%" +"02/02/2022","14,417.55","14,494.47","14,504.82","14,264.65","1.00B","0.50%" +"02/01/2022","14,346.00","14,277.43","14,358.69","14,070.77","962.00M","0.75%" +"01/31/2022","14,239.88","13,812.19","14,242.90","13,767.71","1.24B","3.41%" +"01/28/2022","13,770.57","13,436.71","13,771.91","13,236.56","1.06B","3.13%" +"01/27/2022","13,352.78","13,710.99","13,765.91","13,322.66","1.07B","-1.40%" +"01/26/2022","13,542.12","13,871.77","14,002.65","13,392.19","1.18B","0.02%" +"01/25/2022","13,539.30","13,610.87","13,781.62","13,414.14","1.04B","-2.28%" +"01/24/2022","13,855.13","13,481.50","13,876.61","13,094.65","1.55B","0.63%" +"01/21/2022","13,768.92","14,046.22","14,171.72","13,764.24","1.32B","-2.72%" +"01/20/2022","14,154.02","14,462.85","14,642.03","14,140.78","1.02B","-1.30%" +"01/19/2022","14,340.25","14,582.22","14,658.89","14,331.65","935.06M","-1.15%" +"01/18/2022","14,506.90","14,681.83","14,740.54","14,482.94","1.06B","-2.60%" +"01/14/2022","14,893.75","14,708.02","14,897.67","14,689.43","872.56M","0.59%" +"01/13/2022","14,806.81","15,245.04","15,259.71","14,782.24","852.15M","-2.51%" +"01/12/2022","15,188.39","15,263.10","15,319.03","15,117.29","840.02M","0.23%" +"01/11/2022","15,153.45","14,919.26","15,158.71","14,837.64","863.02M","1.41%" +"01/10/2022","14,942.83","14,751.78","14,953.85","14,530.23","1.09B","0.05%" +"01/07/2022","14,935.90","15,095.72","15,171.02","14,877.63","852.53M","-0.96%" +"01/06/2022","15,080.86","15,024.15","15,198.45","14,914.87","951.12M","-0.13%" +"01/05/2022","15,100.17","15,547.16","15,586.30","15,095.18","1.01B","-3.34%" +"01/04/2022","15,622.72","15,852.14","15,852.14","15,512.41","970.70M","-1.33%" +"01/03/2022","15,832.80","15,732.50","15,832.80","15,644.09","871.65M","1.20%" \ No newline at end of file diff --git a/SAMPLE_DATA/NVDA Historical Data.csv b/SAMPLE_DATA/NVDA Historical Data.csv new file mode 100644 index 0000000..a4a7156 --- /dev/null +++ b/SAMPLE_DATA/NVDA Historical Data.csv @@ -0,0 +1,640 @@ +"Date","Price","Open","High","Low","Vol.","Change %" +"07/19/2024","117.93","120.35","121.60","117.37","217.22M","-2.61%" +"07/18/2024","121.09","121.85","122.40","116.56","320.98M","2.63%" +"07/17/2024","117.99","121.35","121.85","116.72","390.09M","-6.62%" +"07/16/2024","126.36","128.44","129.04","124.58","214.77M","-1.62%" +"07/15/2024","128.44","130.56","131.39","127.18","208.33M","-0.62%" +"07/12/2024","129.24","128.26","131.92","127.22","252.68M","1.44%" +"07/11/2024","127.40","135.75","136.15","127.05","374.78M","-5.57%" +"07/10/2024","134.91","134.03","135.10","132.42","248.98M","2.69%" +"07/09/2024","131.38","130.35","133.82","128.65","287.02M","2.48%" +"07/08/2024","128.20","127.49","130.77","127.04","237.68M","1.88%" +"07/05/2024","125.83","127.38","128.85","125.68","214.18M","-1.91%" +"07/03/2024","128.28","121.66","128.28","121.36","215.75M","4.57%" +"07/02/2024","122.67","121.13","123.41","121.03","218.37M","-1.31%" +"07/01/2024","124.30","123.47","124.84","118.83","284.89M","0.62%" +"06/28/2024","123.54","124.58","127.71","122.75","315.52M","-0.36%" +"06/27/2024","123.99","124.10","126.41","122.92","252.57M","-1.91%" +"06/26/2024","126.40","126.13","128.12","122.60","362.98M","0.25%" +"06/25/2024","126.09","121.20","126.50","119.32","425.79M","6.76%" +"06/24/2024","118.11","123.24","124.46","118.04","476.06M","-6.68%" +"06/21/2024","126.57","127.12","130.63","124.30","655.48M","-3.22%" +"06/20/2024","130.78","139.80","140.76","129.52","517.77M","-3.54%" +"06/18/2024","135.58","131.14","136.33","130.69","294.34M","3.51%" +"06/17/2024","130.98","132.99","133.73","129.58","288.50M","-0.68%" +"06/14/2024","131.88","129.96","132.84","128.32","309.32M","1.75%" +"06/13/2024","129.61","129.39","129.80","127.16","260.70M","3.52%" +"06/12/2024","125.20","123.06","126.88","122.57","299.60M","3.55%" +"06/11/2024","120.91","121.77","122.87","118.74","222.55M","-0.72%" +"06/10/2024","121.79","120.37","123.10","117.01","314.16M","0.74%" +"06/07/2024","120.89","119.77","121.69","118.02","412.39M","-0.09%" +"06/06/2024","121.00","124.05","125.59","118.32","664.70M","-1.18%" +"06/05/2024","122.44","118.37","122.45","117.47","528.40M","5.15%" +"06/04/2024","116.44","115.72","116.60","114.05","403.32M","1.25%" +"06/03/2024","115.00","113.62","115.00","112.00","438.39M","4.90%" +"05/31/2024","109.63","112.52","112.72","106.94","613.26M","-0.79%" +"05/30/2024","110.50","114.65","115.82","109.66","487.35M","-3.77%" +"05/29/2024","114.83","113.05","115.49","110.90","557.44M","0.82%" +"05/28/2024","113.90","110.24","114.94","109.88","652.73M","6.98%" +"05/24/2024","106.47","104.45","106.47","103.00","429.49M","2.57%" +"05/23/2024","103.80","102.03","106.32","101.52","835.07M","9.32%" +"05/22/2024","94.95","95.46","96.02","93.25","548.65M","-0.46%" +"05/21/2024","95.39","93.60","95.40","93.18","328.95M","0.64%" +"05/20/2024","94.78","93.75","95.20","93.44","318.76M","2.49%" +"05/17/2024","92.48","94.37","94.74","91.81","359.69M","-1.99%" +"05/16/2024","94.36","94.91","95.82","94.10","323.95M","-0.29%" +"05/15/2024","94.63","92.47","94.86","91.60","417.74M","3.58%" +"05/14/2024","91.36","89.60","91.65","88.93","296.51M","1.06%" +"05/13/2024","90.40","90.48","91.00","88.53","289.68M","0.58%" +"05/10/2024","89.88","90.30","91.40","89.23","335.33M","1.27%" +"05/09/2024","88.75","90.53","91.07","88.23","378.01M","-1.84%" +"05/08/2024","90.41","89.48","91.19","89.42","325.72M","-0.15%" +"05/07/2024","90.55","91.10","91.78","89.01","437.34M","-1.73%" +"05/06/2024","92.14","89.39","92.22","89.06","376.20M","3.77%" +"05/03/2024","88.79","87.79","89.28","87.04","398.34M","3.46%" +"05/02/2024","85.82","84.45","86.24","83.20","377.90M","3.35%" +"05/01/2024","83.04","85.08","86.00","81.25","559.86M","-3.89%" +"04/30/2024","86.40","87.24","88.82","86.30","363.71M","-1.55%" +"04/29/2024","87.76","87.59","87.99","85.27","388.97M","0.03%" +"04/26/2024","87.73","83.82","88.33","83.39","551.01M","6.17%" +"04/25/2024","82.63","78.87","83.32","78.22","424.64M","3.70%" +"04/24/2024","79.68","83.95","84.08","79.18","512.21M","-3.32%" +"04/23/2024","82.42","80.77","82.77","80.26","438.56M","3.65%" +"04/22/2024","79.52","78.10","80.07","76.40","596.34M","4.36%" +"04/19/2024","76.20","83.15","84.32","75.61","875.20M","-10.00%" +"04/18/2024","84.67","84.97","86.19","82.40","447.26M","0.76%" +"04/17/2024","84.03","88.34","88.78","83.95","495.40M","-3.88%" +"04/16/2024","87.42","86.43","88.12","86.06","370.45M","1.65%" +"04/15/2024","86.00","89.10","90.61","85.93","443.08M","-2.48%" +"04/12/2024","88.19","89.70","90.17","87.53","426.80M","-2.68%" +"04/11/2024","90.62","87.42","90.74","86.93","431.64M","4.11%" +"04/10/2024","87.04","83.93","87.40","83.71","431.93M","1.98%" +"04/09/2024","85.35","87.44","87.64","83.02","503.55M","-2.04%" +"04/08/2024","87.13","88.70","88.83","86.73","283.22M","-1.00%" +"04/05/2024","88.01","86.87","88.48","85.93","399.68M","2.44%" +"04/04/2024","85.91","90.41","90.63","85.88","434.96M","-3.43%" +"04/03/2024","88.96","88.48","90.37","88.40","370.07M","-0.55%" +"04/02/2024","89.45","88.45","90.09","87.62","433.06M","-1.01%" +"04/01/2024","90.36","90.30","92.22","89.20","452.44M","0.00%" +"03/28/2024","90.36","90.00","91.30","89.19","435.21M","0.12%" +"03/27/2024","90.25","93.11","93.24","89.12","586.07M","-2.50%" +"03/26/2024","92.56","95.85","96.38","92.50","513.65M","-2.57%" +"03/25/2024","95.00","93.94","96.77","93.51","552.14M","0.75%" +"03/22/2024","94.29","91.14","94.78","90.83","586.72M","3.12%" +"03/21/2024","91.44","92.30","92.65","90.41","480.37M","1.18%" +"03/20/2024","90.37","89.80","90.41","88.22","479.06M","1.09%" +"03/19/2024","89.40","86.70","90.54","85.01","672.17M","1.07%" +"03/18/2024","88.45","90.39","92.41","87.08","668.98M","0.69%" +"03/15/2024","87.84","86.93","89.55","86.26","642.09M","-0.11%" +"03/14/2024","87.94","89.58","90.65","86.60","602.32M","-3.25%" +"03/13/2024","90.89","91.06","91.50","88.44","635.71M","-1.11%" +"03/12/2024","91.91","88.05","91.96","86.15","668.08M","7.16%" +"03/11/2024","85.77","86.43","88.80","84.17","678.36M","-2.01%" +"03/08/2024","87.53","95.14","97.40","86.51","1.14B","-5.55%" +"03/07/2024","92.67","90.16","92.77","89.60","608.12M","4.48%" +"03/06/2024","88.70","88.02","89.72","87.03","582.52M","3.19%" +"03/05/2024","85.96","85.27","86.10","83.42","520.64M","0.84%" +"03/04/2024","85.24","84.13","87.69","83.72","615.62M","3.60%" +"03/01/2024","82.28","80.00","82.30","79.44","479.14M","4.01%" +"02/29/2024","79.11","79.09","79.99","78.35","507.29M","1.87%" +"02/28/2024","77.66","77.62","78.93","77.12","393.11M","-1.32%" +"02/27/2024","78.70","79.38","79.48","77.16","391.71M","-0.49%" +"02/26/2024","79.09","79.70","80.65","78.50","503.97M","0.34%" +"02/23/2024","78.82","80.79","82.39","77.57","829.39M","0.36%" +"02/22/2024","78.54","75.03","78.58","74.22","865.10M","16.41%" +"02/21/2024","67.47","68.01","68.89","66.25","690.30M","-2.85%" +"02/20/2024","69.45","71.95","71.96","67.73","704.83M","-4.35%" +"02/16/2024","72.61","74.10","74.40","72.50","495.33M","-0.07%" +"02/15/2024","72.66","73.87","73.97","72.40","420.12M","-1.68%" +"02/14/2024","73.90","73.20","74.24","71.94","504.92M","2.45%" +"02/13/2024","72.13","70.40","73.45","69.62","602.58M","-0.17%" +"02/12/2024","72.25","72.60","74.61","71.25","613.71M","0.17%" +"02/09/2024","72.13","70.53","72.19","70.21","436.64M","3.58%" +"02/08/2024","69.64","70.07","70.79","69.45","414.42M","-0.66%" +"02/07/2024","70.10","68.32","70.22","67.60","495.57M","2.76%" +"02/06/2024","68.22","69.63","69.75","66.30","683.11M","-1.60%" +"02/05/2024","69.33","68.22","69.50","67.20","680.08M","4.79%" +"02/02/2024","66.16","63.97","66.60","63.69","476.58M","4.97%" +"02/01/2024","63.03","62.10","63.19","61.65","369.15M","2.44%" +"01/31/2024","61.53","61.44","62.27","60.70","453.79M","-1.98%" +"01/30/2024","62.77","62.90","63.49","62.26","410.74M","0.48%" +"01/29/2024","62.47","61.23","62.49","60.91","348.73M","2.36%" +"01/26/2024","61.03","60.96","61.78","60.57","390.31M","-0.96%" +"01/25/2024","61.62","62.35","62.72","60.85","482.78M","0.42%" +"01/24/2024","61.36","60.30","62.85","59.94","560.27M","2.49%" +"01/23/2024","59.87","59.57","59.91","58.59","294.65M","0.37%" +"01/22/2024","59.65","60.05","60.33","59.07","452.95M","0.27%" +"01/19/2024","59.49","57.99","59.50","57.23","543.50M","4.17%" +"01/18/2024","57.11","57.26","57.60","56.11","491.65M","1.89%" +"01/17/2024","56.05","56.35","56.47","54.74","474.39M","-0.59%" +"01/16/2024","56.38","55.02","56.83","54.90","449.58M","3.05%" +"01/12/2024","54.71","54.62","54.97","54.33","352.99M","-0.20%" +"01/11/2024","54.82","55.00","55.35","53.56","596.76M","0.86%" +"01/10/2024","54.35","53.62","54.60","53.49","533.80M","2.28%" +"01/09/2024","53.14","52.40","54.33","51.69","773.10M","1.70%" +"01/08/2024","52.25","49.51","52.27","49.48","642.51M","6.42%" +"01/05/2024","49.10","48.46","49.55","48.31","415.04M","2.29%" +"01/04/2024","48.00","47.77","48.50","47.51","306.53M","0.90%" +"01/03/2024","47.57","47.48","48.18","47.32","320.90M","-1.25%" +"01/02/2024","48.17","49.24","49.30","47.59","411.25M","-2.73%" +"12/29/2023","49.52","49.81","50.00","48.75","389.29M","0.00%" +"12/28/2023","49.52","49.64","49.88","49.41","246.59M","0.20%" +"12/27/2023","49.42","49.51","49.68","49.09","233.65M","0.28%" +"12/26/2023","49.28","48.97","49.60","48.96","244.20M","0.92%" +"12/22/2023","48.83","49.20","49.38","48.47","252.51M","-0.33%" +"12/21/2023","48.99","48.81","49.09","48.42","300.43M","1.83%" +"12/20/2023","48.11","49.66","50.00","48.10","397.89M","-3.00%" +"12/19/2023","49.60","49.42","49.70","48.90","464.44M","-0.96%" +"12/18/2023","50.08","49.40","50.43","49.15","412.59M","2.43%" +"12/15/2023","48.89","48.19","49.40","48.12","479.95M","1.12%" +"12/14/2023","48.35","48.39","48.67","47.42","391.23M","0.54%" +"12/13/2023","48.09","47.63","48.59","47.61","447.79M","0.90%" +"12/12/2023","47.66","46.05","47.67","46.05","372.39M","2.21%" +"12/11/2023","46.63","47.49","47.53","45.83","509.73M","-1.85%" +"12/08/2023","47.51","46.59","47.74","46.55","359.22M","1.95%" +"12/07/2023","46.60","45.70","46.63","45.60","350.82M","2.42%" +"12/06/2023","45.50","47.21","47.39","45.41","380.59M","-2.30%" +"12/05/2023","46.57","45.47","46.60","45.27","371.72M","2.33%" +"12/04/2023","45.51","46.08","46.08","45.01","437.54M","-2.69%" +"12/01/2023","46.77","46.52","47.20","46.19","369.32M","0.00%" +"11/30/2023","46.77","48.02","48.11","46.42","526.25M","-2.85%" +"11/29/2023","48.14","48.38","48.76","47.86","382.00M","0.67%" +"11/28/2023","47.82","48.24","48.32","47.47","401.49M","-0.87%" +"11/27/2023","48.24","47.80","48.53","47.65","395.66M","0.96%" +"11/24/2023","47.78","48.47","48.92","47.74","294.64M","-1.93%" +"11/22/2023","48.72","49.85","50.33","47.69","900.64M","-2.44%" +"11/21/2023","49.94","50.13","50.52","49.22","565.75M","-0.93%" +"11/20/2023","50.41","49.31","50.55","49.18","416.14M","2.25%" +"11/17/2023","49.30","49.52","49.72","49.01","325.90M","-0.36%" +"11/16/2023","49.48","48.68","49.52","48.33","339.76M","1.21%" +"11/15/2023","48.89","49.94","49.96","48.20","475.50M","-1.55%" +"11/14/2023","49.66","49.68","49.83","49.04","416.95M","2.14%" +"11/13/2023","48.62","48.32","49.12","48.10","384.14M","0.58%" +"11/10/2023","48.34","47.50","48.47","47.28","422.44M","2.96%" +"11/09/2023","46.95","47.47","48.23","46.75","540.50M","0.82%" +"11/08/2023","46.57","46.10","46.87","45.97","346.72M","1.35%" +"11/07/2023","45.95","45.72","46.22","45.16","343.17M","0.44%" +"11/06/2023","45.75","45.28","45.94","44.90","400.73M","1.64%" +"11/03/2023","45.01","44.02","45.31","43.72","424.61M","3.45%" +"11/02/2023","43.51","43.33","43.88","42.89","409.17M","2.79%" +"11/01/2023","42.33","40.88","42.38","40.87","437.59M","3.80%" +"10/31/2023","40.78","40.45","40.88","39.23","517.97M","-0.92%" +"10/30/2023","41.16","41.09","41.77","40.48","388.03M","1.63%" +"10/27/2023","40.50","41.13","41.21","40.02","416.78M","0.42%" +"10/26/2023","40.33","41.85","42.26","39.88","541.00M","-3.47%" +"10/25/2023","41.78","43.40","43.65","41.55","398.38M","-4.31%" +"10/24/2023","43.66","43.08","43.70","42.69","401.46M","1.58%" +"10/23/2023","42.98","41.23","43.25","40.95","478.53M","3.84%" +"10/20/2023","41.39","41.89","42.47","41.08","477.27M","-1.69%" +"10/19/2023","42.10","42.81","43.30","41.88","501.23M","-0.24%" +"10/18/2023","42.20","42.59","43.22","41.83","627.29M","-3.96%" +"10/17/2023","43.94","44.00","44.75","42.48","812.33M","-4.66%" +"10/16/2023","46.09","45.06","46.23","44.91","375.10M","1.39%" +"10/13/2023","45.46","46.96","47.12","45.28","475.43M","-3.17%" +"10/12/2023","46.95","46.78","47.61","46.33","481.32M","0.30%" +"10/11/2023","46.81","46.20","46.86","46.05","378.14M","2.21%" +"10/10/2023","45.80","45.31","46.26","45.09","368.58M","1.17%" +"10/09/2023","45.27","44.84","45.60","44.37","409.67M","-1.07%" +"10/06/2023","45.76","44.19","45.79","44.03","434.44M","2.39%" +"10/05/2023","44.69","44.05","44.90","43.89","393.48M","1.48%" +"10/04/2023","44.04","43.74","44.14","43.29","361.82M","1.19%" +"10/03/2023","43.52","44.81","45.13","43.25","470.85M","-2.81%" +"10/02/2023","44.78","44.03","45.17","43.86","433.30M","2.94%" +"09/29/2023","43.50","43.83","44.14","43.31","397.83M","0.95%" +"09/28/2023","43.09","42.46","43.45","42.12","424.66M","1.46%" +"09/27/2023","42.47","42.33","42.87","41.63","444.94M","1.34%" +"09/26/2023","41.91","42.00","42.82","41.66","402.28M","-0.73%" +"09/25/2023","42.22","41.59","42.54","41.18","419.09M","1.47%" +"09/22/2023","41.61","41.57","42.12","41.23","479.24M","1.44%" +"09/21/2023","41.02","41.58","42.10","40.98","450.74M","-2.89%" +"09/20/2023","42.24","43.60","43.90","42.22","367.11M","-2.94%" +"09/19/2023","43.52","43.83","43.97","43.00","373.06M","-1.02%" +"09/18/2023","43.97","42.75","44.24","42.00","500.27M","0.16%" +"09/15/2023","43.90","45.34","45.60","43.81","506.83M","-3.69%" +"09/14/2023","45.58","45.95","45.99","45.13","370.10M","0.22%" +"09/13/2023","45.48","44.60","45.93","44.50","398.36M","1.36%" +"09/12/2023","44.87","44.74","45.67","44.53","349.26M","-0.69%" +"09/11/2023","45.18","46.15","46.16","44.31","473.97M","-0.86%" +"09/08/2023","45.57","45.94","46.61","45.27","473.90M","-1.45%" +"09/07/2023","46.24","45.52","46.34","45.15","433.33M","-1.74%" +"09/06/2023","47.06","48.44","48.55","46.58","468.67M","-3.07%" +"09/05/2023","48.55","48.22","48.85","47.86","382.65M","0.08%" +"09/01/2023","48.51","49.76","49.80","48.14","463.83M","-1.70%" +"08/31/2023","49.35","49.38","49.74","48.96","528.57M","0.18%" +"08/30/2023","49.26","49.04","49.93","48.42","735.21M","0.98%" +"08/29/2023","48.78","46.67","49.08","46.39","701.40M","4.14%" +"08/28/2023","46.84","46.48","46.98","44.89","685.19M","1.78%" +"08/25/2023","46.02","47.01","47.80","45.02","925.34M","-2.42%" +"08/24/2023","47.16","50.22","50.27","47.16","1.16B","0.08%" +"08/23/2023","47.12","45.87","47.20","45.21","779.05M","3.17%" +"08/22/2023","45.67","48.13","48.19","45.33","757.21M","-2.77%" +"08/21/2023","46.97","44.49","47.06","44.22","692.57M","8.48%" +"08/18/2023","43.30","42.63","43.58","41.66","583.77M","-0.09%" +"08/17/2023","43.34","43.97","44.06","43.00","452.39M","-0.34%" +"08/16/2023","43.49","44.52","44.67","43.41","527.45M","-1.02%" +"08/15/2023","43.94","44.56","45.27","43.71","676.51M","0.43%" +"08/14/2023","43.75","40.49","43.80","40.31","690.29M","7.10%" +"08/11/2023","40.85","41.75","42.02","40.64","533.09M","-3.63%" +"08/10/2023","42.39","42.16","43.57","41.84","492.71M","-0.38%" +"08/09/2023","42.55","44.27","44.31","42.13","586.45M","-4.72%" +"08/08/2023","44.66","44.85","45.24","44.06","353.84M","-1.67%" +"08/07/2023","45.42","45.11","45.54","44.56","322.15M","1.66%" +"08/04/2023","44.68","44.98","45.64","44.39","362.67M","0.36%" +"08/03/2023","44.52","43.80","45.12","43.80","325.08M","0.56%" +"08/02/2023","44.27","45.83","45.84","43.39","530.14M","-4.82%" +"08/01/2023","46.51","46.46","46.90","46.03","239.28M","-0.47%" +"07/31/2023","46.73","46.75","47.13","46.51","251.06M","-0.04%" +"07/28/2023","46.75","46.67","47.03","46.38","331.19M","1.85%" +"07/27/2023","45.90","46.52","47.40","45.75","455.98M","0.99%" +"07/26/2023","45.45","46.02","46.05","44.63","364.24M","-0.50%" +"07/25/2023","45.68","44.94","46.18","44.92","348.08M","2.40%" +"07/24/2023","44.61","44.73","45.11","44.04","383.10M","0.68%" +"07/21/2023","44.31","45.79","45.87","44.10","963.77M","-2.66%" +"07/20/2023","45.52","46.51","47.09","45.06","537.86M","-3.31%" +"07/19/2023","47.08","47.46","47.82","46.74","427.50M","-0.86%" +"07/18/2023","47.49","46.70","47.90","45.73","570.19M","2.22%" +"07/17/2023","46.46","46.29","46.50","45.26","510.49M","2.18%" +"07/14/2023","45.47","46.58","48.09","45.06","772.08M","-1.11%" +"07/13/2023","45.98","44.52","46.16","44.49","478.20M","4.74%" +"07/12/2023","43.90","43.03","43.94","42.78","481.28M","3.51%" +"07/11/2023","42.41","42.48","42.76","42.07","298.24M","0.55%" +"07/10/2023","42.18","42.66","42.81","41.65","353.91M","-0.75%" +"07/07/2023","42.50","42.32","43.21","42.18","355.88M","0.95%" +"07/06/2023","42.10","41.84","42.18","41.35","304.14M","-0.52%" +"07/05/2023","42.32","42.13","43.18","42.09","323.62M","-0.21%" +"07/03/2023","42.41","42.52","42.90","42.20","198.21M","0.26%" +"06/30/2023","42.30","41.68","42.55","41.50","501.15M","3.63%" +"06/29/2023","40.82","41.56","41.60","40.60","380.51M","-0.73%" +"06/28/2023","41.12","40.66","41.84","40.52","582.64M","-1.81%" +"06/27/2023","41.88","40.80","41.94","40.45","462.17M","3.08%" +"06/26/2023","40.63","42.46","42.76","40.10","594.32M","-3.74%" +"06/23/2023","42.21","42.46","42.81","42.02","358.14M","-1.88%" +"06/22/2023","43.02","42.25","43.43","42.23","417.74M","-0.07%" +"06/21/2023","43.05","43.50","43.62","42.08","551.60M","-1.73%" +"06/20/2023","43.81","43.00","43.99","42.67","451.15M","2.62%" +"06/16/2023","42.69","43.45","43.72","42.66","655.71M","0.09%" +"06/15/2023","42.65","42.60","43.29","42.15","568.62M","-0.81%" +"06/14/2023","43.00","40.82","43.00","40.55","740.47M","4.83%" +"06/13/2023","41.02","40.19","41.10","39.74","613.21M","3.90%" +"06/12/2023","39.48","39.20","39.53","38.62","389.67M","1.83%" +"06/09/2023","38.77","39.04","39.71","38.57","427.72M","0.68%" +"06/08/2023","38.51","37.72","38.86","37.51","417.77M","2.75%" +"06/07/2023","37.48","38.91","39.50","37.36","512.00M","-3.03%" +"06/06/2023","38.65","38.83","39.16","38.15","388.73M","-1.33%" +"06/05/2023","39.17","38.91","39.57","38.71","396.09M","-0.41%" +"06/02/2023","39.33","40.10","40.50","39.06","482.73M","-1.11%" +"06/01/2023","39.77","38.49","40.05","38.34","635.87M","5.13%" +"05/31/2023","37.83","39.49","40.30","37.82","1.00B","-5.68%" +"05/30/2023","40.11","40.59","41.94","39.95","923.40M","2.98%" +"05/26/2023","38.95","37.89","39.17","37.55","714.40M","2.55%" +"05/25/2023","37.98","38.52","39.48","36.63","1.54B","24.36%" +"05/24/2023","30.54","30.21","30.61","29.81","721.42M","-0.49%" +"05/23/2023","30.69","31.00","31.29","30.63","356.25M","-1.57%" +"05/22/2023","31.18","30.90","31.52","30.68","372.00M","-0.26%" +"05/19/2023","31.26","31.54","31.58","30.92","473.91M","-1.33%" +"05/18/2023","31.68","30.41","31.83","30.32","748.72M","4.97%" +"05/17/2023","30.18","29.58","30.20","29.43","432.54M","3.32%" +"05/16/2023","29.21","28.84","29.87","28.83","449.40M","0.90%" +"05/15/2023","28.95","28.51","28.97","28.15","293.93M","2.15%" +"05/12/2023","28.34","28.53","28.78","28.05","274.22M","-0.84%" +"05/11/2023","28.58","28.90","28.95","28.25","322.15M","-1.07%" +"05/10/2023","28.89","29.00","29.11","28.46","369.35M","1.12%" +"05/09/2023","28.57","28.90","28.97","28.45","314.87M","-1.99%" +"05/08/2023","29.15","28.52","29.22","28.35","344.98M","1.64%" +"05/05/2023","28.68","27.83","28.75","27.73","361.49M","4.06%" +"05/04/2023","27.56","27.65","27.86","27.24","321.85M","-0.86%" +"05/03/2023","27.80","27.84","28.37","27.47","383.39M","-1.45%" +"05/02/2023","28.21","28.68","28.84","28.08","402.73M","-2.42%" +"05/01/2023","28.91","27.84","29.06","27.78","570.33M","4.18%" +"04/28/2023","27.75","27.23","27.76","27.07","292.22M","1.91%" +"04/27/2023","27.23","27.36","27.50","26.63","377.16M","1.00%" +"04/26/2023","26.96","27.00","27.33","26.71","406.34M","2.74%" +"04/25/2023","26.24","27.08","27.25","26.23","378.53M","-2.96%" +"04/24/2023","27.04","27.01","27.37","26.67","339.28M","-0.29%" +"04/21/2023","27.12","26.95","27.18","26.72","345.10M","0.07%" +"04/20/2023","27.10","27.67","28.03","27.00","427.71M","-2.97%" +"04/19/2023","27.93","27.36","28.00","27.23","358.66M","0.94%" +"04/18/2023","27.67","27.53","28.11","27.36","604.81M","2.48%" +"04/17/2023","27.00","26.57","27.01","26.43","321.47M","0.90%" +"04/14/2023","26.76","26.50","26.88","26.22","395.66M","1.13%" +"04/13/2023","26.46","26.73","26.89","26.33","353.62M","-0.15%" +"04/12/2023","26.50","27.37","27.47","26.45","446.26M","-2.47%" +"04/11/2023","27.17","27.72","27.79","27.13","314.38M","-1.49%" +"04/10/2023","27.58","26.82","27.62","26.67","395.28M","2.00%" +"04/06/2023","27.04","26.58","27.08","26.43","397.65M","0.60%" +"04/05/2023","26.88","26.83","27.00","26.39","515.01M","-2.08%" +"04/04/2023","27.45","27.97","28.00","27.31","368.59M","-1.82%" +"04/03/2023","27.96","27.51","28.00","27.34","398.72M","0.65%" +"03/31/2023","27.78","27.14","27.83","27.11","433.93M","1.46%" +"03/30/2023","27.38","27.23","27.50","27.10","364.52M","1.48%" +"03/29/2023","26.98","26.82","27.08","26.60","393.69M","2.16%" +"03/28/2023","26.41","26.45","26.51","25.85","356.10M","-0.45%" +"03/27/2023","26.53","26.84","27.00","26.36","361.03M","-0.93%" +"03/24/2023","26.78","27.03","27.17","26.36","455.41M","-1.51%" +"03/23/2023","27.19","27.12","27.50","26.69","564.89M","2.72%" +"03/22/2023","26.47","26.43","27.59","26.24","797.30M","1.03%" +"03/21/2023","26.20","26.18","26.39","25.38","547.41M","1.16%" +"03/20/2023","25.90","25.61","26.02","25.13","432.75M","0.66%" +"03/17/2023","25.73","25.98","26.40","25.67","848.55M","0.74%" +"03/16/2023","25.54","24.03","25.59","23.89","584.95M","5.41%" +"03/15/2023","24.23","23.76","24.29","23.36","524.49M","0.71%" +"03/14/2023","24.06","23.50","24.22","23.46","474.91M","4.75%" +"03/13/2023","22.97","22.75","23.30","22.30","421.89M","0.04%" +"03/10/2023","22.96","23.41","23.63","22.73","474.87M","-2.05%" +"03/09/2023","23.44","24.18","24.45","23.38","501.26M","-3.06%" +"03/08/2023","24.18","23.49","24.20","23.42","513.57M","3.82%" +"03/07/2023","23.29","23.60","24.12","23.24","515.15M","-1.10%" +"03/06/2023","23.55","23.89","24.25","23.49","437.43M","-1.42%" +"03/03/2023","23.89","23.32","23.90","23.13","412.39M","2.49%" +"03/02/2023","23.31","22.49","23.38","22.43","390.07M","2.69%" +"03/01/2023","22.70","23.19","23.26","22.51","460.03M","-2.24%" +"02/28/2023","23.22","23.37","23.82","23.21","455.96M","-1.19%" +"02/27/2023","23.50","23.67","23.88","23.45","452.99M","0.90%" +"02/24/2023","23.29","23.23","23.47","22.95","589.72M","-1.56%" +"02/23/2023","23.66","23.44","23.89","23.02","1.12B","14.02%" +"02/22/2023","20.75","20.71","21.10","20.42","513.18M","0.44%" +"02/21/2023","20.66","21.00","21.49","20.62","410.01M","-3.41%" +"02/17/2023","21.39","21.63","21.74","20.98","465.89M","-2.77%" +"02/16/2023","22.00","22.13","22.55","21.93","412.03M","-3.34%" +"02/15/2023","22.76","22.55","22.86","22.11","421.19M","-0.91%" +"02/14/2023","22.97","21.58","23.05","21.37","675.47M","5.42%" +"02/13/2023","21.79","21.54","22.05","20.96","474.92M","2.44%" +"02/10/2023","21.27","21.69","22.08","20.81","550.74M","-4.79%" +"02/09/2023","22.34","22.61","23.02","22.12","523.88M","0.63%" +"02/08/2023","22.20","22.39","22.88","22.01","559.65M","0.14%" +"02/07/2023","22.17","21.38","22.26","21.15","664.15M","5.12%" +"02/06/2023","21.09","20.81","21.57","20.79","452.20M","-0.05%" +"02/03/2023","21.10","21.00","21.74","20.79","429.37M","-2.81%" +"02/02/2023","21.71","21.00","21.95","20.70","564.28M","3.68%" +"02/01/2023","20.94","19.69","21.19","19.61","660.48M","7.16%" +"01/31/2023","19.54","19.17","19.69","18.95","498.02M","1.98%" +"01/30/2023","19.16","19.95","20.14","19.15","488.61M","-5.89%" +"01/27/2023","20.36","19.46","20.63","19.41","542.14M","2.83%" +"01/26/2023","19.80","19.70","20.17","19.28","489.54M","2.48%" +"01/25/2023","19.32","18.91","19.37","18.58","449.54M","0.26%" +"01/24/2023","19.27","18.83","19.50","18.82","496.20M","0.42%" +"01/23/2023","19.19","18.06","19.25","17.82","655.16M","7.57%" +"01/20/2023","17.84","17.01","17.86","16.82","564.97M","6.38%" +"01/19/2023","16.77","17.04","17.20","16.73","452.93M","-3.51%" +"01/18/2023","17.38","17.67","17.87","17.28","439.62M","-1.81%" +"01/17/2023","17.70","16.90","17.73","16.90","511.10M","4.73%" +"01/13/2023","16.90","16.28","16.92","16.16","447.29M","2.36%" +"01/12/2023","16.51","16.10","16.64","15.49","551.41M","3.19%" +"01/11/2023","16.00","15.84","16.03","15.56","353.28M","0.57%" +"01/10/2023","15.91","15.51","15.96","15.47","384.10M","1.79%" +"01/09/2023","15.63","15.28","16.06","15.14","504.23M","5.18%" +"01/06/2023","14.86","14.47","15.01","14.03","405.04M","4.13%" +"01/05/2023","14.27","14.49","14.56","14.15","389.17M","-3.25%" +"01/04/2023","14.75","14.57","14.85","14.24","431.32M","3.07%" +"01/03/2023","14.31","14.85","15.00","14.10","401.28M","-2.05%" +"12/30/2022","14.61","14.33","14.63","14.23","310.49M","0.07%" +"12/29/2022","14.60","14.40","14.68","14.23","354.92M","3.99%" +"12/28/2022","14.04","13.93","14.26","13.88","351.07M","-0.57%" +"12/27/2022","14.12","15.07","15.10","14.06","464.90M","-7.17%" +"12/23/2022","15.21","15.20","15.34","14.88","349.33M","-0.85%" +"12/22/2022","15.34","16.09","16.14","14.88","565.05M","-7.03%" +"12/21/2022","16.50","16.11","16.63","16.10","325.03M","2.55%" +"12/20/2022","16.09","16.06","16.31","15.85","403.26M","-0.98%" +"12/19/2022","16.25","16.57","16.61","16.14","354.04M","-1.93%" +"12/16/2022","16.57","16.86","17.04","16.41","478.23M","-2.24%" +"12/15/2022","16.95","17.15","17.32","16.70","478.54M","-4.07%" +"12/14/2022","17.67","17.99","18.25","17.42","496.89M","-2.21%" +"12/13/2022","18.07","18.53","18.79","17.71","656.59M","3.02%" +"12/12/2022","17.54","17.04","17.54","16.80","457.33M","3.18%" +"12/09/2022","17.00","17.16","17.58","16.98","465.34M","-0.99%" +"12/08/2022","17.17","16.27","17.18","15.96","515.46M","6.51%" +"12/07/2022","16.12","15.77","16.19","15.67","372.39M","0.81%" +"12/06/2022","15.99","16.53","16.57","15.82","352.69M","-3.73%" +"12/05/2022","16.61","16.68","17.00","16.47","352.26M","-1.60%" +"12/02/2022","16.88","16.66","16.93","16.45","371.39M","-1.52%" +"12/01/2022","17.14","17.00","17.27","16.64","470.98M","1.30%" +"11/30/2022","16.92","15.70","16.93","15.60","565.30M","8.18%" +"11/29/2022","15.64","15.83","15.93","15.52","298.38M","-1.20%" +"11/28/2022","15.83","16.03","16.36","15.72","304.15M","-2.70%" +"11/25/2022","16.27","16.32","16.49","16.17","167.93M","-1.51%" +"11/23/2022","16.52","16.10","16.53","16.05","427.24M","2.99%" +"11/22/2022","16.04","15.33","16.06","15.12","472.87M","4.70%" +"11/21/2022","15.32","15.15","15.48","15.08","404.74M","-0.58%" +"11/18/2022","15.41","15.97","16.00","15.12","492.07M","-1.72%" +"11/17/2022","15.68","15.71","16.27","15.54","710.89M","-1.45%" +"11/16/2022","15.91","16.16","16.36","15.87","649.55M","-4.56%" +"11/15/2022","16.67","16.72","17.00","16.38","545.88M","2.27%" +"11/14/2022","16.30","16.22","16.54","15.92","527.85M","-0.18%" +"11/11/2022","16.33","15.81","16.39","15.48","655.49M","3.68%" +"11/10/2022","15.75","14.80","15.77","14.55","700.82M","14.30%" +"11/09/2022","13.78","14.16","14.21","13.76","454.41M","-5.62%" +"11/08/2022","14.60","14.80","14.89","14.22","595.29M","2.10%" +"11/07/2022","14.30","14.23","14.41","13.95","410.06M","0.99%" +"11/04/2022","14.16","13.99","14.23","13.70","612.58M","5.51%" +"11/03/2022","13.42","13.04","13.78","12.96","500.06M","1.51%" +"11/02/2022","13.22","13.85","14.21","13.21","672.63M","-2.36%" +"11/01/2022","13.54","13.81","13.93","13.52","432.82M","0.30%" +"10/31/2022","13.50","13.78","13.84","13.30","486.34M","-2.39%" +"10/28/2022","13.83","13.10","13.85","13.06","521.04M","4.93%" +"10/27/2022","13.18","13.63","13.84","13.12","583.11M","2.17%" +"10/26/2022","12.90","12.87","13.39","12.71","535.53M","-2.71%" +"10/25/2022","13.26","12.69","13.30","12.66","505.48M","5.24%" +"10/24/2022","12.60","12.51","12.71","12.06","517.46M","1.04%" +"10/21/2022","12.47","12.10","12.50","11.89","609.49M","2.30%" +"10/20/2022","12.19","12.11","12.77","12.11","652.40M","1.16%" +"10/19/2022","12.05","11.88","12.35","11.83","523.13M","0.67%" +"10/18/2022","11.97","12.34","12.49","11.62","659.36M","0.67%" +"10/17/2022","11.89","11.52","11.95","11.52","580.77M","5.88%" +"10/14/2022","11.23","12.06","12.11","11.20","713.43M","-6.10%" +"10/13/2022","11.96","10.97","12.08","10.81","850.10M","4.00%" +"10/12/2022","11.50","11.58","11.73","11.35","492.59M","-0.78%" +"10/11/2022","11.59","11.56","11.85","11.28","667.48M","-0.69%" +"10/10/2022","11.67","12.04","12.12","11.41","698.70M","-3.39%" +"10/07/2022","12.08","12.51","12.67","12.02","672.48M","-8.00%" +"10/06/2022","13.13","13.22","13.66","13.10","644.16M","-0.61%" +"10/05/2022","13.21","12.91","13.32","12.62","507.13M","0.30%" +"10/04/2022","13.17","12.88","13.22","12.88","584.18M","5.28%" +"10/03/2022","12.51","12.35","12.68","12.11","547.48M","3.05%" +"09/30/2022","12.14","12.09","12.63","12.07","565.64M","-0.65%" +"09/29/2022","12.22","12.45","12.50","11.95","532.76M","-4.08%" +"09/28/2022","12.74","12.41","12.82","12.35","542.41M","2.66%" +"09/27/2022","12.41","12.51","12.74","12.26","553.85M","1.47%" +"09/26/2022","12.23","12.49","12.66","12.21","547.34M","-2.32%" +"09/23/2022","12.52","12.42","12.61","12.26","663.31M","-0.32%" +"09/22/2022","12.56","13.07","13.15","12.43","759.16M","-5.28%" +"09/21/2022","13.26","13.21","14.03","13.11","807.68M","0.61%" +"09/20/2022","13.18","13.21","13.48","13.06","524.82M","-1.49%" +"09/19/2022","13.38","13.01","13.46","13.01","569.69M","1.36%" +"09/16/2022","13.20","12.74","13.21","12.62","670.75M","2.09%" +"09/15/2022","12.93","13.02","13.23","12.79","523.63M","-1.52%" +"09/14/2022","13.13","13.25","13.29","12.91","588.51M","0.00%" +"09/13/2022","13.13","13.80","13.92","13.10","714.96M","-9.51%" +"09/12/2022","14.51","14.37","14.55","14.20","484.16M","0.83%" +"09/09/2022","14.39","14.16","14.47","14.13","487.13M","2.86%" +"09/08/2022","13.99","13.46","14.01","13.37","624.87M","2.04%" +"09/07/2022","13.71","13.56","13.84","13.35","512.66M","1.86%" +"09/06/2022","13.46","13.73","13.78","13.35","535.75M","-1.39%" +"09/02/2022","13.65","14.10","14.17","13.59","743.16M","-2.08%" +"09/01/2022","13.94","14.21","14.38","13.27","1.18B","-7.62%" +"08/31/2022","15.09","15.38","15.54","14.96","573.71M","-2.46%" +"08/30/2022","15.47","15.96","16.04","15.18","530.18M","-2.09%" +"08/29/2022","15.80","16.02","16.34","15.77","496.13M","-2.83%" +"08/26/2022","16.26","17.86","17.92","16.24","769.13M","-9.21%" +"08/25/2022","17.91","16.84","17.95","16.83","770.69M","4.01%" +"08/24/2022","17.22","17.01","17.41","16.89","522.66M","0.23%" +"08/23/2022","17.18","16.99","17.46","16.97","369.99M","0.88%" +"08/22/2022","17.03","17.49","17.56","16.97","409.59M","-4.59%" +"08/19/2022","17.85","18.41","18.52","17.77","441.59M","-4.90%" +"08/18/2022","18.77","18.30","18.86","18.18","415.45M","2.34%" +"08/17/2022","18.34","18.52","18.69","18.14","446.80M","-2.86%" +"08/16/2022","18.88","18.92","19.14","18.50","451.24M","-0.79%" +"08/15/2022","19.03","18.70","19.16","18.61","457.67M","1.71%" +"08/12/2022","18.71","18.16","18.72","17.95","478.09M","4.29%" +"08/11/2022","17.94","18.13","18.71","17.88","509.33M","-0.88%" +"08/10/2022","18.10","17.70","18.12","17.32","597.42M","5.91%" +"08/09/2022","17.09","17.25","17.45","16.72","668.26M","-3.93%" +"08/08/2022","17.79","17.50","18.24","17.24","983.78M","-6.32%" +"08/05/2022","18.99","18.81","19.23","18.67","386.07M","-1.15%" +"08/04/2022","19.21","18.85","19.27","18.76","409.65M","1.69%" +"08/03/2022","18.89","18.18","18.97","18.14","418.15M","1.94%" +"08/02/2022","18.53","18.12","18.94","18.09","489.53M","0.49%" +"08/01/2022","18.44","18.18","18.85","17.99","476.47M","1.54%" +"07/29/2022","18.16","17.81","18.24","17.69","435.46M","1.00%" +"07/28/2022","17.98","17.98","18.14","17.44","474.65M","1.07%" +"07/27/2022","17.79","17.03","17.94","16.91","569.78M","7.62%" +"07/26/2022","16.53","16.89","16.92","16.48","397.86M","-2.88%" +"07/25/2022","17.02","17.02","17.12","16.65","480.75M","-1.73%" +"07/22/2022","17.32","17.89","17.97","17.14","536.67M","-4.04%" +"07/21/2022","18.05","17.89","18.14","17.54","557.05M","1.35%" +"07/20/2022","17.81","16.95","17.93","16.80","760.54M","4.83%" +"07/19/2022","16.99","16.49","17.11","16.17","702.37M","5.53%" +"07/18/2022","16.10","16.30","16.90","16.00","670.52M","2.16%" +"07/15/2022","15.76","15.66","15.78","15.45","385.94M","2.54%" +"07/14/2022","15.37","15.11","15.47","14.73","456.23M","1.39%" +"07/13/2022","15.16","14.59","15.38","14.46","521.92M","0.53%" +"07/12/2022","15.08","15.27","15.43","14.88","458.48M","-0.46%" +"07/11/2022","15.15","15.53","15.53","15.04","438.39M","-4.36%" +"07/08/2022","15.84","15.43","16.04","15.39","467.97M","-0.13%" +"07/07/2022","15.86","15.46","15.95","15.39","492.90M","4.82%" +"07/06/2022","15.13","15.01","15.32","14.79","529.07M","1.14%" +"07/05/2022","14.96","14.18","14.97","14.05","652.21M","3.03%" +"07/01/2022","14.52","14.90","15.06","14.39","577.61M","-4.22%" +"06/30/2022","15.16","15.36","15.57","14.86","686.07M","-2.45%" +"06/29/2022","15.54","15.81","15.82","15.17","482.35M","-2.75%" +"06/28/2022","15.98","16.90","17.20","15.95","461.86M","-5.28%" +"06/27/2022","16.87","17.31","17.33","16.63","427.97M","-1.52%" +"06/24/2022","17.13","16.50","17.14","16.31","472.15M","5.55%" +"06/23/2022","16.23","16.52","16.59","15.85","463.68M","-0.79%" +"06/22/2022","16.36","16.23","16.66","16.18","438.00M","-1.27%" +"06/21/2022","16.57","16.47","17.01","16.41","483.09M","4.35%" +"06/17/2022","15.88","15.65","15.99","15.33","630.33M","1.79%" +"06/16/2022","15.60","15.86","15.94","15.40","545.75M","-5.63%" +"06/15/2022","16.53","16.09","16.87","15.93","563.94M","4.36%" +"06/14/2022","15.84","15.73","16.07","15.41","469.68M","1.21%" +"06/13/2022","15.65","16.00","16.31","15.61","604.15M","-7.78%" +"06/10/2022","16.97","17.60","17.70","16.87","465.65M","-5.98%" +"06/09/2022","18.05","18.48","18.93","18.04","395.57M","-3.22%" +"06/08/2022","18.65","18.80","19.18","18.54","363.25M","-1.48%" +"06/07/2022","18.93","18.47","19.00","18.19","388.91M","0.75%" +"06/06/2022","18.79","19.14","19.34","18.56","422.41M","0.37%" +"06/03/2022","18.72","19.08","19.33","18.52","598.78M","-4.44%" +"06/02/2022","19.59","18.29","19.62","18.20","648.66M","6.93%" +"06/01/2022","18.32","18.72","19.05","18.12","544.51M","-1.87%" +"05/31/2022","18.67","18.98","19.20","18.35","664.10M","-0.74%" +"05/27/2022","18.81","18.19","18.88","18.10","738.38M","5.38%" +"05/26/2022","17.85","16.04","18.09","16.02","996.57M","5.12%" +"05/25/2022","16.98","16.02","17.11","16.00","781.13M","5.14%" +"05/24/2022","16.15","16.51","16.60","15.78","588.55M","-4.44%" +"05/23/2022","16.90","16.27","16.91","16.18","639.89M","1.26%" +"05/20/2022","16.69","17.33","17.41","15.76","739.11M","-2.51%" +"05/19/2022","17.12","16.94","17.69","16.73","621.31M","1.06%" +"05/18/2022","16.94","17.70","18.12","16.86","545.16M","-6.82%" +"05/17/2022","18.18","18.07","18.37","17.63","585.83M","5.33%" +"05/16/2022","17.26","17.51","17.79","17.11","521.45M","-2.54%" +"05/13/2022","17.71","16.79","17.93","16.59","670.44M","9.46%" +"05/12/2022","16.18","16.22","16.79","15.57","708.73M","-2.71%" +"05/11/2022","16.63","17.35","17.75","16.57","670.17M","-5.46%" +"05/10/2022","17.59","17.69","18.20","17.02","761.47M","3.78%" +"05/09/2022","16.95","18.03","18.25","16.83","644.45M","-9.26%" +"05/06/2022","18.68","18.74","19.51","17.99","633.30M","-0.85%" +"05/05/2022","18.84","19.87","19.93","18.50","626.33M","-7.33%" +"05/04/2022","20.33","19.92","20.40","18.75","648.85M","3.72%" +"05/03/2022","19.60","19.40","19.82","19.13","475.75M","0.36%" +"05/02/2022","19.53","18.54","19.57","18.39","572.05M","5.28%" +"04/29/2022","18.55","19.40","20.13","18.52","500.43M","-6.22%" +"04/28/2022","19.78","18.97","20.04","18.49","570.33M","7.44%" +"04/27/2022","18.41","18.60","19.17","18.29","499.46M","-2.02%" +"04/26/2022","18.79","19.72","19.79","18.67","653.14M","-5.58%" +"04/25/2022","19.90","19.20","19.95","19.10","641.57M","1.95%" +"04/22/2022","19.52","20.30","20.49","19.50","624.71M","-3.27%" +"04/21/2022","20.18","21.71","22.39","20.00","656.21M","-6.05%" +"04/20/2022","21.48","22.52","22.67","21.20","468.97M","-3.24%" +"04/19/2022","22.20","21.72","22.37","21.31","512.78M","1.93%" +"04/18/2022","21.78","21.20","22.09","21.08","525.70M","2.45%" +"04/14/2022","21.26","22.50","22.78","21.16","569.10M","-4.23%" +"04/13/2022","22.20","21.73","22.50","21.45","516.94M","3.26%" +"04/12/2022","21.50","22.54","22.73","21.28","662.26M","-1.92%" +"04/11/2022","21.92","22.21","22.32","21.66","575.21M","-5.19%" +"04/08/2022","23.12","23.92","23.92","23.06","524.78M","-4.50%" +"04/07/2022","24.21","24.44","24.72","23.48","557.99M","-0.82%" +"04/06/2022","24.41","24.93","25.30","24.00","703.83M","-5.86%" +"04/05/2022","25.93","27.25","27.32","25.82","436.61M","-5.23%" +"04/04/2022","27.36","26.73","27.56","26.61","397.71M","2.43%" +"04/01/2022","26.71","27.38","27.50","26.27","517.24M","-2.13%" +"03/31/2022","27.29","27.78","28.25","27.27","523.44M","-1.44%" +"03/30/2022","27.69","28.30","28.50","27.50","463.49M","-3.38%" +"03/29/2022","28.66","28.69","28.95","27.98","488.98M","1.56%" +"03/28/2022","28.22","27.76","28.25","27.21","425.49M","1.91%" +"03/25/2022","27.69","27.89","28.36","27.27","579.02M","-1.63%" +"03/24/2022","28.15","26.17","28.32","25.91","877.38M","9.83%" +"03/23/2022","25.63","26.13","26.61","25.58","502.12M","-3.36%" +"03/22/2022","26.52","26.73","27.24","26.07","547.01M","-0.79%" +"03/21/2022","26.73","26.51","27.15","25.97","591.73M","1.06%" +"03/18/2022","26.45","24.80","26.57","24.62","730.72M","6.78%" +"03/17/2022","24.77","24.12","24.84","23.91","471.94M","1.10%" +"03/16/2022","24.50","23.50","24.60","23.17","671.42M","6.66%" +"03/15/2022","22.97","21.52","23.04","21.32","492.00M","7.69%" +"03/14/2022","21.33","21.87","22.26","21.16","385.35M","-3.48%" +"03/11/2022","22.10","23.02","23.14","22.05","367.21M","-2.47%" +"03/10/2022","22.66","22.53","22.79","21.88","428.07M","-1.52%" +"03/09/2022","23.01","22.39","23.22","22.25","492.74M","6.97%" +"03/08/2022","21.51","21.31","22.37","20.65","557.47M","0.75%" +"03/07/2022","21.35","22.82","23.03","21.33","450.82M","-6.93%" +"03/04/2022","22.94","23.38","23.68","22.48","432.01M","-3.25%" +"03/03/2022","23.71","24.26","24.33","23.47","365.10M","-2.11%" +"03/02/2022","24.22","23.76","24.41","23.41","389.64M","3.15%" +"03/01/2022","23.48","24.29","24.38","23.13","412.06M","-3.73%" +"02/28/2022","24.39","23.99","24.66","23.71","477.32M","0.95%" +"02/25/2022","24.16","23.72","24.22","23.38","528.87M","1.73%" +"02/24/2022","23.75","21.02","23.80","20.89","735.80M","6.07%" +"02/23/2022","22.39","23.80","24.15","22.30","566.51M","-4.28%" +"02/22/2022","23.39","23.04","24.06","23.00","633.42M","-1.06%" +"02/18/2022","23.64","24.67","24.99","23.10","761.25M","-3.55%" +"02/17/2022","24.51","25.63","25.79","24.16","810.60M","-7.54%" +"02/16/2022","26.51","26.26","26.58","25.55","732.68M","0.04%" +"02/15/2022","26.50","24.95","26.55","24.78","701.75M","9.19%" +"02/14/2022","24.27","23.93","24.88","23.75","440.42M","1.34%" +"02/11/2022","23.95","25.92","26.15","23.77","605.47M","-7.24%" +"02/10/2022","25.82","26.00","26.92","25.60","513.20M","-3.30%" +"02/09/2022","26.70","25.62","26.73","25.35","524.28M","6.33%" +"02/08/2022","25.11","24.36","25.23","23.98","410.36M","1.54%" +"02/07/2022","24.73","24.37","25.18","24.20","376.87M","1.69%" +"02/04/2022","24.32","23.97","24.64","23.63","354.83M","1.54%" +"02/03/2022","23.95","24.46","25.08","23.78","410.18M","-5.11%" +"02/02/2022","25.24","25.79","25.82","24.55","543.42M","2.44%" +"02/01/2022","24.64","25.10","25.14","23.89","518.93M","0.61%" +"01/31/2022","24.49","23.18","24.51","23.05","564.68M","7.22%" +"01/28/2022","22.84","22.01","22.86","21.30","543.77M","4.10%" +"01/27/2022","21.94","23.57","24.00","21.68","573.35M","-3.65%" +"01/26/2022","22.77","23.24","24.06","22.30","755.96M","2.02%" +"01/25/2022","22.32","22.55","22.94","22.00","664.62M","-4.49%" +"01/24/2022","23.37","22.33","23.38","20.89","915.81M","0.00%" +"01/21/2022","23.37","23.51","24.82","23.26","718.96M","-3.23%" +"01/20/2022","24.15","25.30","25.58","24.08","435.18M","-3.67%" +"01/19/2022","25.07","26.08","26.54","25.05","488.31M","-3.20%" +"01/18/2022","25.90","26.26","26.64","25.77","425.31M","-3.86%" +"01/14/2022","26.94","26.30","27.20","26.21","395.83M","1.39%" +"01/13/2022","26.57","28.38","28.48","26.50","538.87M","-5.11%" +"01/12/2022","28.00","28.07","28.59","27.61","383.41M","0.65%" +"01/11/2022","27.82","27.32","28.07","26.84","404.09M","1.53%" +"01/10/2022","27.40","26.58","27.47","25.64","594.68M","0.55%" +"01/07/2022","27.25","28.14","28.42","27.06","409.94M","-3.30%" +"01/06/2022","28.18","27.64","28.44","27.07","454.19M","2.10%" +"01/05/2022","27.60","28.95","29.42","27.53","498.06M","-5.77%" +"01/04/2022","29.29","30.28","30.47","28.35","527.15M","-2.76%" +"01/03/2022","30.12","29.82","30.71","29.79","392.40M","2.41%" \ No newline at end of file diff --git a/SAMPLE_DATA/README.md b/SAMPLE_DATA/README.md new file mode 100644 index 0000000..dca9195 --- /dev/null +++ b/SAMPLE_DATA/README.md @@ -0,0 +1,22 @@ + +Sources for data in this directory: +* titanic.csv: https://www.kaggle.com/c/titanic/ +* iris.csv: +* pulse_calories_modified.csv: modified from https://www.kaggle.com/datasets/vivekbaaganps/maxpulse-calories +* AAPL, GME, GOOG, NVDA Historycal data - yahoo finance. + +Notes on where USGS stores data: +Aquarious TS - time series +* moored data +* fixed stations on interval over time +* nwis.gov sacramento river nwis, grizzley bay nwis +* requires a station number + +Aquarious Samples / AQS +* Launched in March +* water data for the nation, wdfn +* discrete data + +ScienceBase +* Mapping data +* Stuff that doesn't fit in the above two. diff --git a/SAMPLE_DATA/iris.csv b/SAMPLE_DATA/iris.csv new file mode 100644 index 0000000..21ae196 --- /dev/null +++ b/SAMPLE_DATA/iris.csv @@ -0,0 +1,151 @@ +sepal_length,sepal_width,petal_length,petal_width,species +5.1,3.5,1.4,0.2,Iris-setosa +4.9,3,1.4,0.2,Iris-setosa +4.7,3.2,1.3,0.2,Iris-setosa +4.6,3.1,1.5,0.2,Iris-setosa +5,3.6,1.4,0.2,Iris-setosa +5.4,3.9,1.7,0.4,Iris-setosa +4.6,3.4,1.4,0.3,Iris-setosa +5,3.4,1.5,0.2,Iris-setosa +4.4,2.9,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5.4,3.7,1.5,0.2,Iris-setosa +4.8,3.4,1.6,0.2,Iris-setosa +4.8,3,1.4,0.1,Iris-setosa +4.3,3,1.1,0.1,Iris-setosa +5.8,4,1.2,0.2,Iris-setosa +5.7,4.4,1.5,0.4,Iris-setosa +5.4,3.9,1.3,0.4,Iris-setosa +5.1,3.5,1.4,0.3,Iris-setosa +5.7,3.8,1.7,0.3,Iris-setosa +5.1,3.8,1.5,0.3,Iris-setosa +5.4,3.4,1.7,0.2,Iris-setosa +5.1,3.7,1.5,0.4,Iris-setosa +4.6,3.6,1,0.2,Iris-setosa +5.1,3.3,1.7,0.5,Iris-setosa +4.8,3.4,1.9,0.2,Iris-setosa +5,3,1.6,0.2,Iris-setosa +5,3.4,1.6,0.4,Iris-setosa +5.2,3.5,1.5,0.2,Iris-setosa +5.2,3.4,1.4,0.2,Iris-setosa +4.7,3.2,1.6,0.2,Iris-setosa +4.8,3.1,1.6,0.2,Iris-setosa +5.4,3.4,1.5,0.4,Iris-setosa +5.2,4.1,1.5,0.1,Iris-setosa +5.5,4.2,1.4,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +5,3.2,1.2,0.2,Iris-setosa +5.5,3.5,1.3,0.2,Iris-setosa +4.9,3.1,1.5,0.1,Iris-setosa +4.4,3,1.3,0.2,Iris-setosa +5.1,3.4,1.5,0.2,Iris-setosa +5,3.5,1.3,0.3,Iris-setosa +4.5,2.3,1.3,0.3,Iris-setosa +4.4,3.2,1.3,0.2,Iris-setosa +5,3.5,1.6,0.6,Iris-setosa +5.1,3.8,1.9,0.4,Iris-setosa +4.8,3,1.4,0.3,Iris-setosa +5.1,3.8,1.6,0.2,Iris-setosa +4.6,3.2,1.4,0.2,Iris-setosa +5.3,3.7,1.5,0.2,Iris-setosa +5,3.3,1.4,0.2,Iris-setosa +7,3.2,4.7,1.4,Iris-versicolor +6.4,3.2,4.5,1.5,Iris-versicolor +6.9,3.1,4.9,1.5,Iris-versicolor +5.5,2.3,4,1.3,Iris-versicolor +6.5,2.8,4.6,1.5,Iris-versicolor +5.7,2.8,4.5,1.3,Iris-versicolor +6.3,3.3,4.7,1.6,Iris-versicolor +4.9,2.4,3.3,1,Iris-versicolor +6.6,2.9,4.6,1.3,Iris-versicolor +5.2,2.7,3.9,1.4,Iris-versicolor +5,2,3.5,1,Iris-versicolor +5.9,3,4.2,1.5,Iris-versicolor +6,2.2,4,1,Iris-versicolor +6.1,2.9,4.7,1.4,Iris-versicolor +5.6,2.9,3.6,1.3,Iris-versicolor +6.7,3.1,4.4,1.4,Iris-versicolor +5.6,3,4.5,1.5,Iris-versicolor +5.8,2.7,4.1,1,Iris-versicolor +6.2,2.2,4.5,1.5,Iris-versicolor +5.6,2.5,3.9,1.1,Iris-versicolor +5.9,3.2,4.8,1.8,Iris-versicolor +6.1,2.8,4,1.3,Iris-versicolor +6.3,2.5,4.9,1.5,Iris-versicolor +6.1,2.8,4.7,1.2,Iris-versicolor +6.4,2.9,4.3,1.3,Iris-versicolor +6.6,3,4.4,1.4,Iris-versicolor +6.8,2.8,4.8,1.4,Iris-versicolor +6.7,3,5,1.7,Iris-versicolor +6,2.9,4.5,1.5,Iris-versicolor +5.7,2.6,3.5,1,Iris-versicolor +5.5,2.4,3.8,1.1,Iris-versicolor +5.5,2.4,3.7,1,Iris-versicolor +5.8,2.7,3.9,1.2,Iris-versicolor +6,2.7,5.1,1.6,Iris-versicolor +5.4,3,4.5,1.5,Iris-versicolor +6,3.4,4.5,1.6,Iris-versicolor +6.7,3.1,4.7,1.5,Iris-versicolor +6.3,2.3,4.4,1.3,Iris-versicolor +5.6,3,4.1,1.3,Iris-versicolor +5.5,2.5,4,1.3,Iris-versicolor +5.5,2.6,4.4,1.2,Iris-versicolor +6.1,3,4.6,1.4,Iris-versicolor +5.8,2.6,4,1.2,Iris-versicolor +5,2.3,3.3,1,Iris-versicolor +5.6,2.7,4.2,1.3,Iris-versicolor +5.7,3,4.2,1.2,Iris-versicolor +5.7,2.9,4.2,1.3,Iris-versicolor +6.2,2.9,4.3,1.3,Iris-versicolor +5.1,2.5,3,1.1,Iris-versicolor +5.7,2.8,4.1,1.3,Iris-versicolor +6.3,3.3,6,2.5,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +7.1,3,5.9,2.1,Iris-virginica +6.3,2.9,5.6,1.8,Iris-virginica +6.5,3,5.8,2.2,Iris-virginica +7.6,3,6.6,2.1,Iris-virginica +4.9,2.5,4.5,1.7,Iris-virginica +7.3,2.9,6.3,1.8,Iris-virginica +6.7,2.5,5.8,1.8,Iris-virginica +7.2,3.6,6.1,2.5,Iris-virginica +6.5,3.2,5.1,2,Iris-virginica +6.4,2.7,5.3,1.9,Iris-virginica +6.8,3,5.5,2.1,Iris-virginica +5.7,2.5,5,2,Iris-virginica +5.8,2.8,5.1,2.4,Iris-virginica +6.4,3.2,5.3,2.3,Iris-virginica +6.5,3,5.5,1.8,Iris-virginica +7.7,3.8,6.7,2.2,Iris-virginica +7.7,2.6,6.9,2.3,Iris-virginica +6,2.2,5,1.5,Iris-virginica +6.9,3.2,5.7,2.3,Iris-virginica +5.6,2.8,4.9,2,Iris-virginica +7.7,2.8,6.7,2,Iris-virginica +6.3,2.7,4.9,1.8,Iris-virginica +6.7,3.3,5.7,2.1,Iris-virginica +7.2,3.2,6,1.8,Iris-virginica +6.2,2.8,4.8,1.8,Iris-virginica +6.1,3,4.9,1.8,Iris-virginica +6.4,2.8,5.6,2.1,Iris-virginica +7.2,3,5.8,1.6,Iris-virginica +7.4,2.8,6.1,1.9,Iris-virginica +7.9,3.8,6.4,2,Iris-virginica +6.4,2.8,5.6,2.2,Iris-virginica +6.3,2.8,5.1,1.5,Iris-virginica +6.1,2.6,5.6,1.4,Iris-virginica +7.7,3,6.1,2.3,Iris-virginica +6.3,3.4,5.6,2.4,Iris-virginica +6.4,3.1,5.5,1.8,Iris-virginica +6,3,4.8,1.8,Iris-virginica +6.9,3.1,5.4,2.1,Iris-virginica +6.7,3.1,5.6,2.4,Iris-virginica +6.9,3.1,5.1,2.3,Iris-virginica +5.8,2.7,5.1,1.9,Iris-virginica +6.8,3.2,5.9,2.3,Iris-virginica +6.7,3.3,5.7,2.5,Iris-virginica +6.7,3,5.2,2.3,Iris-virginica +6.3,2.5,5,1.9,Iris-virginica +6.5,3,5.2,2,Iris-virginica +6.2,3.4,5.4,2.3,Iris-virginica +5.9,3,5.1,1.8,Iris-virginica diff --git a/SAMPLE_DATA/pulse_calories_modified.csv b/SAMPLE_DATA/pulse_calories_modified.csv new file mode 100644 index 0000000..2e18f27 --- /dev/null +++ b/SAMPLE_DATA/pulse_calories_modified.csv @@ -0,0 +1,172 @@ +Duration,Pulse,Maxpulse,Calories +60,110,130,409.1 +60,117,145,479.0 +60,103,135,340.0 +45,109,275,282.4 +45,117,148,406.0 +60,102,127,300.0 +60,110,136,374.0 +45,104,134,253.3 +,109,133,195.1 +60,98,124,269.0 +60,103,147,329.3 +60,100,120,250.7 +60,106,128,345.3 +60,104,132,379.3 +6000,98,123,275.0 +60,98,120,215.2 +60,100,120,300.0 +45,90,112, +60,103,123,323.0 +45,97,125,243.0 +60,108,131,364.2 +45,100,119,282.0 +60,130,101,300.0 +45,105,132,246.0 +60,102,126,334.5 +60,100,320,250.0 +60,92,118,241.0 +60,103,132, +60,100,132,280.0 +60,102,129,380.3 +60,92,115,243.0 +45,90,112,180.1 +60,101,124,299.0 +60,93,113,223.0 +60,107,136,361.0 +60,114,140,415.0 +60,102,127,300.0 +60,100,120,300.0 +60,100,120,300.0 +45,104,129,266.0 +45,90,112,180.1 +60,98,126,286.0 +60,100,122,329.4 +60,111,138,400.0 +60,111,131,397.0 +60,99,119,273.0 +60,109,153,387.6 +45,111,136,300.0 +45,108,129,298.0 +60,111,139,397.6 +60,107,136,380.2 +80,123,146,643.1 +60,106,130,263.0 +60,118,151,486.0 +30,136,175,238.0 +60,121,146,450.7 +60,118,121,413.0 +45,115,144,305.0 +20,153,172,226.4 +45,123,152,321.0 +210,108,160,1376.0 +160,110,137,1034.4 +160,109,135,853.0 +45,118,141,341.0 +20,110,130,131.4 +180,90,130,800.4 +150,105,135,873.4 +150,107,130,816.0 +20,106,136,110.4 +300,108,143,1500.2 +150,97,129,1115.0 +60,109,153,387.6 +90,100,127,700.0 +150,97,127,953.2 +45,114,146,304.0 +90,98,125,563.2 +45,105,134,251.0 +45,110,141,300.0 +120,100,130,500.4 +270,100,131,1729.0 +30,159,182,319.2 +45,149,169,344.0 +30,103,139,151.1 +120,100,130,500.0 +45,100,120,225.3 +30,151,170,300.0 +45,102,136,234.0 +120,100,157,1000.1 +45,129,103,242.0 +20,83,107,50.3 +180,101,127,600.1 +45,107,137, +30,90,107,105.3 +15,80,100,50.5 +20,150,171,127.4 +20,151,168,229.4 +30,95,128,128.2 +25,152,168,244.2 +30,109,131,188.2 +90,93,124,604.1 +20,95,112,77.7 +90,90,110,500.0 +90,90,100,500.0 +90,90,100,500.4 +30,92,408,92.7 +30,93,128,124.0 +180,90,120,800.3 +30,90,120,86.2 +90,90,120,500.3 +210,137,184,1860.4 +60,102,124,325.2 +45,107,124,275.0 +15,124,139,124.2 +45,100,120,225.3 +60,108,131,367.6 +60,108,151,351.7 +60,116,141,443.0 +60,97,122,277.4 +60,105,125, +60,103,124,332.7 +30,112,137,193.9 +45,100,120,100.7 +60,119,169,336.7 +60,107,127,344.9 +60,111,151,368.5 +60,98,122,271.0 +60,97,124,275.3 +60,109,127,382.0 +90,99,125,466.4 +60,114,151,384.0 +60,104,134,342.5 +60,107,138,357.5 +60,103,133,335.0 +60,106,132,327.5 +60,103,136,339.0 +20,,156,189.0 +45,117,143,317.7 +45,115,137,318.0 +45,113,138,308.0 +20,141,162,222.4 +60,108,135,390.0 +60,97,127, +45,100,120,250.4 +45,122,149,335.4 +60,136,170,470.2 +45,106,126,270.8 +60,107,,400.0 +60,112,146,361.9 +30,103,127,185.0 +60,110,150,409.4 +60,185,134,343.0 +60,109,129,353.2 +60,109,138,374.0 +'foo','bar','bla','asd' +30,150,167,275.8 +60,105,128,328.0 +60,111,151,368.5 +60,97,131,270.4 +60,100,120,270.4 +60,114,150,382.8 +30,180,120,240.9 +30,85,120,250.4 +45,90,130,260.4 +45,95,130,270.0 +45,100,140,280.9 +60,105,140,290.8 +60,110,145,300.0 +60,-115,145,310.2 +75,120,150,320.4 +75,125,150,330.4 +a,b,c,d \ No newline at end of file diff --git a/SAMPLE_DATA/simple.csv b/SAMPLE_DATA/simple.csv new file mode 100644 index 0000000..074605b --- /dev/null +++ b/SAMPLE_DATA/simple.csv @@ -0,0 +1,4 @@ +Age,Name,Fav_Color +40,Dan,Blue +9,James,Green +25,Frank,Black diff --git a/SAMPLE_DATA/titaninc.csv b/SAMPLE_DATA/titaninc.csv new file mode 100644 index 0000000..63b68ab --- /dev/null +++ b/SAMPLE_DATA/titaninc.csv @@ -0,0 +1,892 @@ +PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked +1,0,3,"Braund, Mr. Owen Harris",male,22,1,0,A/5 21171,7.25,,S +2,1,1,"Cumings, Mrs. John Bradley (Florence Briggs Thayer)",female,38,1,0,PC 17599,71.2833,C85,C +3,1,3,"Heikkinen, Miss. Laina",female,26,0,0,STON/O2. 3101282,7.925,,S +4,1,1,"Futrelle, Mrs. Jacques Heath (Lily May Peel)",female,35,1,0,113803,53.1,C123,S +5,0,3,"Allen, Mr. William Henry",male,35,0,0,373450,8.05,,S +6,0,3,"Moran, Mr. James",male,,0,0,330877,8.4583,,Q +7,0,1,"McCarthy, Mr. Timothy J",male,54,0,0,17463,51.8625,E46,S +8,0,3,"Palsson, Master. Gosta Leonard",male,2,3,1,349909,21.075,,S +9,1,3,"Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg)",female,27,0,2,347742,11.1333,,S +10,1,2,"Nasser, Mrs. Nicholas (Adele Achem)",female,14,1,0,237736,30.0708,,C +11,1,3,"Sandstrom, Miss. Marguerite Rut",female,4,1,1,PP 9549,16.7,G6,S +12,1,1,"Bonnell, Miss. Elizabeth",female,58,0,0,113783,26.55,C103,S +13,0,3,"Saundercock, Mr. William Henry",male,20,0,0,A/5. 2151,8.05,,S +14,0,3,"Andersson, Mr. Anders Johan",male,39,1,5,347082,31.275,,S +15,0,3,"Vestrom, Miss. Hulda Amanda Adolfina",female,14,0,0,350406,7.8542,,S +16,1,2,"Hewlett, Mrs. (Mary D Kingcome) ",female,55,0,0,248706,16,,S +17,0,3,"Rice, Master. Eugene",male,2,4,1,382652,29.125,,Q +18,1,2,"Williams, Mr. Charles Eugene",male,,0,0,244373,13,,S +19,0,3,"Vander Planke, Mrs. Julius (Emelia Maria Vandemoortele)",female,31,1,0,345763,18,,S +20,1,3,"Masselmani, Mrs. Fatima",female,,0,0,2649,7.225,,C +21,0,2,"Fynney, Mr. Joseph J",male,35,0,0,239865,26,,S +22,1,2,"Beesley, Mr. Lawrence",male,34,0,0,248698,13,D56,S +23,1,3,"McGowan, Miss. Anna ""Annie""",female,15,0,0,330923,8.0292,,Q +24,1,1,"Sloper, Mr. William Thompson",male,28,0,0,113788,35.5,A6,S +25,0,3,"Palsson, Miss. Torborg Danira",female,8,3,1,349909,21.075,,S +26,1,3,"Asplund, Mrs. Carl Oscar (Selma Augusta Emilia Johansson)",female,38,1,5,347077,31.3875,,S +27,0,3,"Emir, Mr. Farred Chehab",male,,0,0,2631,7.225,,C +28,0,1,"Fortune, Mr. Charles Alexander",male,19,3,2,19950,263,C23 C25 C27,S +29,1,3,"O'Dwyer, Miss. Ellen ""Nellie""",female,,0,0,330959,7.8792,,Q +30,0,3,"Todoroff, Mr. Lalio",male,,0,0,349216,7.8958,,S +31,0,1,"Uruchurtu, Don. Manuel E",male,40,0,0,PC 17601,27.7208,,C +32,1,1,"Spencer, Mrs. William Augustus (Marie Eugenie)",female,,1,0,PC 17569,146.5208,B78,C +33,1,3,"Glynn, Miss. Mary Agatha",female,,0,0,335677,7.75,,Q +34,0,2,"Wheadon, Mr. Edward H",male,66,0,0,C.A. 24579,10.5,,S +35,0,1,"Meyer, Mr. Edgar Joseph",male,28,1,0,PC 17604,82.1708,,C +36,0,1,"Holverson, Mr. Alexander Oskar",male,42,1,0,113789,52,,S +37,1,3,"Mamee, Mr. Hanna",male,,0,0,2677,7.2292,,C +38,0,3,"Cann, Mr. Ernest Charles",male,21,0,0,A./5. 2152,8.05,,S +39,0,3,"Vander Planke, Miss. Augusta Maria",female,18,2,0,345764,18,,S +40,1,3,"Nicola-Yarred, Miss. Jamila",female,14,1,0,2651,11.2417,,C +41,0,3,"Ahlin, Mrs. Johan (Johanna Persdotter Larsson)",female,40,1,0,7546,9.475,,S +42,0,2,"Turpin, Mrs. William John Robert (Dorothy Ann Wonnacott)",female,27,1,0,11668,21,,S +43,0,3,"Kraeff, Mr. Theodor",male,,0,0,349253,7.8958,,C +44,1,2,"Laroche, Miss. Simonne Marie Anne Andree",female,3,1,2,SC/Paris 2123,41.5792,,C +45,1,3,"Devaney, Miss. Margaret Delia",female,19,0,0,330958,7.8792,,Q +46,0,3,"Rogers, Mr. William John",male,,0,0,S.C./A.4. 23567,8.05,,S +47,0,3,"Lennon, Mr. Denis",male,,1,0,370371,15.5,,Q +48,1,3,"O'Driscoll, Miss. Bridget",female,,0,0,14311,7.75,,Q +49,0,3,"Samaan, Mr. Youssef",male,,2,0,2662,21.6792,,C +50,0,3,"Arnold-Franchi, Mrs. Josef (Josefine Franchi)",female,18,1,0,349237,17.8,,S +51,0,3,"Panula, Master. Juha Niilo",male,7,4,1,3101295,39.6875,,S +52,0,3,"Nosworthy, Mr. Richard Cater",male,21,0,0,A/4. 39886,7.8,,S +53,1,1,"Harper, Mrs. Henry Sleeper (Myna Haxtun)",female,49,1,0,PC 17572,76.7292,D33,C +54,1,2,"Faunthorpe, Mrs. Lizzie (Elizabeth Anne Wilkinson)",female,29,1,0,2926,26,,S +55,0,1,"Ostby, Mr. Engelhart Cornelius",male,65,0,1,113509,61.9792,B30,C +56,1,1,"Woolner, Mr. Hugh",male,,0,0,19947,35.5,C52,S +57,1,2,"Rugg, Miss. Emily",female,21,0,0,C.A. 31026,10.5,,S +58,0,3,"Novel, Mr. Mansouer",male,28.5,0,0,2697,7.2292,,C +59,1,2,"West, Miss. Constance Mirium",female,5,1,2,C.A. 34651,27.75,,S +60,0,3,"Goodwin, Master. William Frederick",male,11,5,2,CA 2144,46.9,,S +61,0,3,"Sirayanian, Mr. Orsen",male,22,0,0,2669,7.2292,,C +62,1,1,"Icard, Miss. Amelie",female,38,0,0,113572,80,B28, +63,0,1,"Harris, Mr. Henry Birkhardt",male,45,1,0,36973,83.475,C83,S +64,0,3,"Skoog, Master. Harald",male,4,3,2,347088,27.9,,S +65,0,1,"Stewart, Mr. Albert A",male,,0,0,PC 17605,27.7208,,C +66,1,3,"Moubarek, Master. Gerios",male,,1,1,2661,15.2458,,C +67,1,2,"Nye, Mrs. (Elizabeth Ramell)",female,29,0,0,C.A. 29395,10.5,F33,S +68,0,3,"Crease, Mr. Ernest James",male,19,0,0,S.P. 3464,8.1583,,S +69,1,3,"Andersson, Miss. Erna Alexandra",female,17,4,2,3101281,7.925,,S +70,0,3,"Kink, Mr. Vincenz",male,26,2,0,315151,8.6625,,S +71,0,2,"Jenkin, Mr. Stephen Curnow",male,32,0,0,C.A. 33111,10.5,,S +72,0,3,"Goodwin, Miss. Lillian Amy",female,16,5,2,CA 2144,46.9,,S +73,0,2,"Hood, Mr. Ambrose Jr",male,21,0,0,S.O.C. 14879,73.5,,S +74,0,3,"Chronopoulos, Mr. Apostolos",male,26,1,0,2680,14.4542,,C +75,1,3,"Bing, Mr. Lee",male,32,0,0,1601,56.4958,,S +76,0,3,"Moen, Mr. Sigurd Hansen",male,25,0,0,348123,7.65,F G73,S +77,0,3,"Staneff, Mr. Ivan",male,,0,0,349208,7.8958,,S +78,0,3,"Moutal, Mr. Rahamin Haim",male,,0,0,374746,8.05,,S +79,1,2,"Caldwell, Master. Alden Gates",male,0.83,0,2,248738,29,,S +80,1,3,"Dowdell, Miss. Elizabeth",female,30,0,0,364516,12.475,,S +81,0,3,"Waelens, Mr. Achille",male,22,0,0,345767,9,,S +82,1,3,"Sheerlinck, Mr. Jan Baptist",male,29,0,0,345779,9.5,,S +83,1,3,"McDermott, Miss. Brigdet Delia",female,,0,0,330932,7.7875,,Q +84,0,1,"Carrau, Mr. Francisco M",male,28,0,0,113059,47.1,,S +85,1,2,"Ilett, Miss. Bertha",female,17,0,0,SO/C 14885,10.5,,S +86,1,3,"Backstrom, Mrs. Karl Alfred (Maria Mathilda Gustafsson)",female,33,3,0,3101278,15.85,,S +87,0,3,"Ford, Mr. William Neal",male,16,1,3,W./C. 6608,34.375,,S +88,0,3,"Slocovski, Mr. Selman Francis",male,,0,0,SOTON/OQ 392086,8.05,,S +89,1,1,"Fortune, Miss. Mabel Helen",female,23,3,2,19950,263,C23 C25 C27,S +90,0,3,"Celotti, Mr. Francesco",male,24,0,0,343275,8.05,,S +91,0,3,"Christmann, Mr. Emil",male,29,0,0,343276,8.05,,S +92,0,3,"Andreasson, Mr. Paul Edvin",male,20,0,0,347466,7.8542,,S +93,0,1,"Chaffee, Mr. Herbert Fuller",male,46,1,0,W.E.P. 5734,61.175,E31,S +94,0,3,"Dean, Mr. Bertram Frank",male,26,1,2,C.A. 2315,20.575,,S +95,0,3,"Coxon, Mr. Daniel",male,59,0,0,364500,7.25,,S +96,0,3,"Shorney, Mr. Charles Joseph",male,,0,0,374910,8.05,,S +97,0,1,"Goldschmidt, Mr. George B",male,71,0,0,PC 17754,34.6542,A5,C +98,1,1,"Greenfield, Mr. William Bertram",male,23,0,1,PC 17759,63.3583,D10 D12,C +99,1,2,"Doling, Mrs. John T (Ada Julia Bone)",female,34,0,1,231919,23,,S +100,0,2,"Kantor, Mr. Sinai",male,34,1,0,244367,26,,S +101,0,3,"Petranec, Miss. Matilda",female,28,0,0,349245,7.8958,,S +102,0,3,"Petroff, Mr. Pastcho (""Pentcho"")",male,,0,0,349215,7.8958,,S +103,0,1,"White, Mr. Richard Frasar",male,21,0,1,35281,77.2875,D26,S +104,0,3,"Johansson, Mr. Gustaf Joel",male,33,0,0,7540,8.6542,,S +105,0,3,"Gustafsson, Mr. Anders Vilhelm",male,37,2,0,3101276,7.925,,S +106,0,3,"Mionoff, Mr. Stoytcho",male,28,0,0,349207,7.8958,,S +107,1,3,"Salkjelsvik, Miss. Anna Kristine",female,21,0,0,343120,7.65,,S +108,1,3,"Moss, Mr. Albert Johan",male,,0,0,312991,7.775,,S +109,0,3,"Rekic, Mr. Tido",male,38,0,0,349249,7.8958,,S +110,1,3,"Moran, Miss. Bertha",female,,1,0,371110,24.15,,Q +111,0,1,"Porter, Mr. Walter Chamberlain",male,47,0,0,110465,52,C110,S +112,0,3,"Zabour, Miss. Hileni",female,14.5,1,0,2665,14.4542,,C +113,0,3,"Barton, Mr. David John",male,22,0,0,324669,8.05,,S +114,0,3,"Jussila, Miss. Katriina",female,20,1,0,4136,9.825,,S +115,0,3,"Attalah, Miss. Malake",female,17,0,0,2627,14.4583,,C +116,0,3,"Pekoniemi, Mr. Edvard",male,21,0,0,STON/O 2. 3101294,7.925,,S +117,0,3,"Connors, Mr. Patrick",male,70.5,0,0,370369,7.75,,Q +118,0,2,"Turpin, Mr. William John Robert",male,29,1,0,11668,21,,S +119,0,1,"Baxter, Mr. Quigg Edmond",male,24,0,1,PC 17558,247.5208,B58 B60,C +120,0,3,"Andersson, Miss. Ellis Anna Maria",female,2,4,2,347082,31.275,,S +121,0,2,"Hickman, Mr. Stanley George",male,21,2,0,S.O.C. 14879,73.5,,S +122,0,3,"Moore, Mr. Leonard Charles",male,,0,0,A4. 54510,8.05,,S +123,0,2,"Nasser, Mr. Nicholas",male,32.5,1,0,237736,30.0708,,C +124,1,2,"Webber, Miss. Susan",female,32.5,0,0,27267,13,E101,S +125,0,1,"White, Mr. Percival Wayland",male,54,0,1,35281,77.2875,D26,S +126,1,3,"Nicola-Yarred, Master. Elias",male,12,1,0,2651,11.2417,,C +127,0,3,"McMahon, Mr. Martin",male,,0,0,370372,7.75,,Q +128,1,3,"Madsen, Mr. Fridtjof Arne",male,24,0,0,C 17369,7.1417,,S +129,1,3,"Peter, Miss. Anna",female,,1,1,2668,22.3583,F E69,C +130,0,3,"Ekstrom, Mr. Johan",male,45,0,0,347061,6.975,,S +131,0,3,"Drazenoic, Mr. Jozef",male,33,0,0,349241,7.8958,,C +132,0,3,"Coelho, Mr. Domingos Fernandeo",male,20,0,0,SOTON/O.Q. 3101307,7.05,,S +133,0,3,"Robins, Mrs. Alexander A (Grace Charity Laury)",female,47,1,0,A/5. 3337,14.5,,S +134,1,2,"Weisz, Mrs. Leopold (Mathilde Francoise Pede)",female,29,1,0,228414,26,,S +135,0,2,"Sobey, Mr. Samuel James Hayden",male,25,0,0,C.A. 29178,13,,S +136,0,2,"Richard, Mr. Emile",male,23,0,0,SC/PARIS 2133,15.0458,,C +137,1,1,"Newsom, Miss. Helen Monypeny",female,19,0,2,11752,26.2833,D47,S +138,0,1,"Futrelle, Mr. Jacques Heath",male,37,1,0,113803,53.1,C123,S +139,0,3,"Osen, Mr. Olaf Elon",male,16,0,0,7534,9.2167,,S +140,0,1,"Giglio, Mr. Victor",male,24,0,0,PC 17593,79.2,B86,C +141,0,3,"Boulos, Mrs. Joseph (Sultana)",female,,0,2,2678,15.2458,,C +142,1,3,"Nysten, Miss. Anna Sofia",female,22,0,0,347081,7.75,,S +143,1,3,"Hakkarainen, Mrs. Pekka Pietari (Elin Matilda Dolck)",female,24,1,0,STON/O2. 3101279,15.85,,S +144,0,3,"Burke, Mr. Jeremiah",male,19,0,0,365222,6.75,,Q +145,0,2,"Andrew, Mr. Edgardo Samuel",male,18,0,0,231945,11.5,,S +146,0,2,"Nicholls, Mr. Joseph Charles",male,19,1,1,C.A. 33112,36.75,,S +147,1,3,"Andersson, Mr. August Edvard (""Wennerstrom"")",male,27,0,0,350043,7.7958,,S +148,0,3,"Ford, Miss. Robina Maggie ""Ruby""",female,9,2,2,W./C. 6608,34.375,,S +149,0,2,"Navratil, Mr. Michel (""Louis M Hoffman"")",male,36.5,0,2,230080,26,F2,S +150,0,2,"Byles, Rev. Thomas Roussel Davids",male,42,0,0,244310,13,,S +151,0,2,"Bateman, Rev. Robert James",male,51,0,0,S.O.P. 1166,12.525,,S +152,1,1,"Pears, Mrs. Thomas (Edith Wearne)",female,22,1,0,113776,66.6,C2,S +153,0,3,"Meo, Mr. Alfonzo",male,55.5,0,0,A.5. 11206,8.05,,S +154,0,3,"van Billiard, Mr. Austin Blyler",male,40.5,0,2,A/5. 851,14.5,,S +155,0,3,"Olsen, Mr. Ole Martin",male,,0,0,Fa 265302,7.3125,,S +156,0,1,"Williams, Mr. Charles Duane",male,51,0,1,PC 17597,61.3792,,C +157,1,3,"Gilnagh, Miss. Katherine ""Katie""",female,16,0,0,35851,7.7333,,Q +158,0,3,"Corn, Mr. Harry",male,30,0,0,SOTON/OQ 392090,8.05,,S +159,0,3,"Smiljanic, Mr. Mile",male,,0,0,315037,8.6625,,S +160,0,3,"Sage, Master. Thomas Henry",male,,8,2,CA. 2343,69.55,,S +161,0,3,"Cribb, Mr. John Hatfield",male,44,0,1,371362,16.1,,S +162,1,2,"Watt, Mrs. James (Elizabeth ""Bessie"" Inglis Milne)",female,40,0,0,C.A. 33595,15.75,,S +163,0,3,"Bengtsson, Mr. John Viktor",male,26,0,0,347068,7.775,,S +164,0,3,"Calic, Mr. Jovo",male,17,0,0,315093,8.6625,,S +165,0,3,"Panula, Master. Eino Viljami",male,1,4,1,3101295,39.6875,,S +166,1,3,"Goldsmith, Master. Frank John William ""Frankie""",male,9,0,2,363291,20.525,,S +167,1,1,"Chibnall, Mrs. (Edith Martha Bowerman)",female,,0,1,113505,55,E33,S +168,0,3,"Skoog, Mrs. William (Anna Bernhardina Karlsson)",female,45,1,4,347088,27.9,,S +169,0,1,"Baumann, Mr. John D",male,,0,0,PC 17318,25.925,,S +170,0,3,"Ling, Mr. Lee",male,28,0,0,1601,56.4958,,S +171,0,1,"Van der hoef, Mr. Wyckoff",male,61,0,0,111240,33.5,B19,S +172,0,3,"Rice, Master. Arthur",male,4,4,1,382652,29.125,,Q +173,1,3,"Johnson, Miss. Eleanor Ileen",female,1,1,1,347742,11.1333,,S +174,0,3,"Sivola, Mr. Antti Wilhelm",male,21,0,0,STON/O 2. 3101280,7.925,,S +175,0,1,"Smith, Mr. James Clinch",male,56,0,0,17764,30.6958,A7,C +176,0,3,"Klasen, Mr. Klas Albin",male,18,1,1,350404,7.8542,,S +177,0,3,"Lefebre, Master. Henry Forbes",male,,3,1,4133,25.4667,,S +178,0,1,"Isham, Miss. Ann Elizabeth",female,50,0,0,PC 17595,28.7125,C49,C +179,0,2,"Hale, Mr. Reginald",male,30,0,0,250653,13,,S +180,0,3,"Leonard, Mr. Lionel",male,36,0,0,LINE,0,,S +181,0,3,"Sage, Miss. Constance Gladys",female,,8,2,CA. 2343,69.55,,S +182,0,2,"Pernot, Mr. Rene",male,,0,0,SC/PARIS 2131,15.05,,C +183,0,3,"Asplund, Master. Clarence Gustaf Hugo",male,9,4,2,347077,31.3875,,S +184,1,2,"Becker, Master. Richard F",male,1,2,1,230136,39,F4,S +185,1,3,"Kink-Heilmann, Miss. Luise Gretchen",female,4,0,2,315153,22.025,,S +186,0,1,"Rood, Mr. Hugh Roscoe",male,,0,0,113767,50,A32,S +187,1,3,"O'Brien, Mrs. Thomas (Johanna ""Hannah"" Godfrey)",female,,1,0,370365,15.5,,Q +188,1,1,"Romaine, Mr. Charles Hallace (""Mr C Rolmane"")",male,45,0,0,111428,26.55,,S +189,0,3,"Bourke, Mr. John",male,40,1,1,364849,15.5,,Q +190,0,3,"Turcin, Mr. Stjepan",male,36,0,0,349247,7.8958,,S +191,1,2,"Pinsky, Mrs. (Rosa)",female,32,0,0,234604,13,,S +192,0,2,"Carbines, Mr. William",male,19,0,0,28424,13,,S +193,1,3,"Andersen-Jensen, Miss. Carla Christine Nielsine",female,19,1,0,350046,7.8542,,S +194,1,2,"Navratil, Master. Michel M",male,3,1,1,230080,26,F2,S +195,1,1,"Brown, Mrs. James Joseph (Margaret Tobin)",female,44,0,0,PC 17610,27.7208,B4,C +196,1,1,"Lurette, Miss. Elise",female,58,0,0,PC 17569,146.5208,B80,C +197,0,3,"Mernagh, Mr. Robert",male,,0,0,368703,7.75,,Q +198,0,3,"Olsen, Mr. Karl Siegwart Andreas",male,42,0,1,4579,8.4042,,S +199,1,3,"Madigan, Miss. Margaret ""Maggie""",female,,0,0,370370,7.75,,Q +200,0,2,"Yrois, Miss. Henriette (""Mrs Harbeck"")",female,24,0,0,248747,13,,S +201,0,3,"Vande Walle, Mr. Nestor Cyriel",male,28,0,0,345770,9.5,,S +202,0,3,"Sage, Mr. Frederick",male,,8,2,CA. 2343,69.55,,S +203,0,3,"Johanson, Mr. Jakob Alfred",male,34,0,0,3101264,6.4958,,S +204,0,3,"Youseff, Mr. Gerious",male,45.5,0,0,2628,7.225,,C +205,1,3,"Cohen, Mr. Gurshon ""Gus""",male,18,0,0,A/5 3540,8.05,,S +206,0,3,"Strom, Miss. Telma Matilda",female,2,0,1,347054,10.4625,G6,S +207,0,3,"Backstrom, Mr. Karl Alfred",male,32,1,0,3101278,15.85,,S +208,1,3,"Albimona, Mr. Nassef Cassem",male,26,0,0,2699,18.7875,,C +209,1,3,"Carr, Miss. Helen ""Ellen""",female,16,0,0,367231,7.75,,Q +210,1,1,"Blank, Mr. Henry",male,40,0,0,112277,31,A31,C +211,0,3,"Ali, Mr. Ahmed",male,24,0,0,SOTON/O.Q. 3101311,7.05,,S +212,1,2,"Cameron, Miss. Clear Annie",female,35,0,0,F.C.C. 13528,21,,S +213,0,3,"Perkin, Mr. John Henry",male,22,0,0,A/5 21174,7.25,,S +214,0,2,"Givard, Mr. Hans Kristensen",male,30,0,0,250646,13,,S +215,0,3,"Kiernan, Mr. Philip",male,,1,0,367229,7.75,,Q +216,1,1,"Newell, Miss. Madeleine",female,31,1,0,35273,113.275,D36,C +217,1,3,"Honkanen, Miss. Eliina",female,27,0,0,STON/O2. 3101283,7.925,,S +218,0,2,"Jacobsohn, Mr. Sidney Samuel",male,42,1,0,243847,27,,S +219,1,1,"Bazzani, Miss. Albina",female,32,0,0,11813,76.2917,D15,C +220,0,2,"Harris, Mr. Walter",male,30,0,0,W/C 14208,10.5,,S +221,1,3,"Sunderland, Mr. Victor Francis",male,16,0,0,SOTON/OQ 392089,8.05,,S +222,0,2,"Bracken, Mr. James H",male,27,0,0,220367,13,,S +223,0,3,"Green, Mr. George Henry",male,51,0,0,21440,8.05,,S +224,0,3,"Nenkoff, Mr. Christo",male,,0,0,349234,7.8958,,S +225,1,1,"Hoyt, Mr. Frederick Maxfield",male,38,1,0,19943,90,C93,S +226,0,3,"Berglund, Mr. Karl Ivar Sven",male,22,0,0,PP 4348,9.35,,S +227,1,2,"Mellors, Mr. William John",male,19,0,0,SW/PP 751,10.5,,S +228,0,3,"Lovell, Mr. John Hall (""Henry"")",male,20.5,0,0,A/5 21173,7.25,,S +229,0,2,"Fahlstrom, Mr. Arne Jonas",male,18,0,0,236171,13,,S +230,0,3,"Lefebre, Miss. Mathilde",female,,3,1,4133,25.4667,,S +231,1,1,"Harris, Mrs. Henry Birkhardt (Irene Wallach)",female,35,1,0,36973,83.475,C83,S +232,0,3,"Larsson, Mr. Bengt Edvin",male,29,0,0,347067,7.775,,S +233,0,2,"Sjostedt, Mr. Ernst Adolf",male,59,0,0,237442,13.5,,S +234,1,3,"Asplund, Miss. Lillian Gertrud",female,5,4,2,347077,31.3875,,S +235,0,2,"Leyson, Mr. Robert William Norman",male,24,0,0,C.A. 29566,10.5,,S +236,0,3,"Harknett, Miss. Alice Phoebe",female,,0,0,W./C. 6609,7.55,,S +237,0,2,"Hold, Mr. Stephen",male,44,1,0,26707,26,,S +238,1,2,"Collyer, Miss. Marjorie ""Lottie""",female,8,0,2,C.A. 31921,26.25,,S +239,0,2,"Pengelly, Mr. Frederick William",male,19,0,0,28665,10.5,,S +240,0,2,"Hunt, Mr. George Henry",male,33,0,0,SCO/W 1585,12.275,,S +241,0,3,"Zabour, Miss. Thamine",female,,1,0,2665,14.4542,,C +242,1,3,"Murphy, Miss. Katherine ""Kate""",female,,1,0,367230,15.5,,Q +243,0,2,"Coleridge, Mr. Reginald Charles",male,29,0,0,W./C. 14263,10.5,,S +244,0,3,"Maenpaa, Mr. Matti Alexanteri",male,22,0,0,STON/O 2. 3101275,7.125,,S +245,0,3,"Attalah, Mr. Sleiman",male,30,0,0,2694,7.225,,C +246,0,1,"Minahan, Dr. William Edward",male,44,2,0,19928,90,C78,Q +247,0,3,"Lindahl, Miss. Agda Thorilda Viktoria",female,25,0,0,347071,7.775,,S +248,1,2,"Hamalainen, Mrs. William (Anna)",female,24,0,2,250649,14.5,,S +249,1,1,"Beckwith, Mr. Richard Leonard",male,37,1,1,11751,52.5542,D35,S +250,0,2,"Carter, Rev. Ernest Courtenay",male,54,1,0,244252,26,,S +251,0,3,"Reed, Mr. James George",male,,0,0,362316,7.25,,S +252,0,3,"Strom, Mrs. Wilhelm (Elna Matilda Persson)",female,29,1,1,347054,10.4625,G6,S +253,0,1,"Stead, Mr. William Thomas",male,62,0,0,113514,26.55,C87,S +254,0,3,"Lobb, Mr. William Arthur",male,30,1,0,A/5. 3336,16.1,,S +255,0,3,"Rosblom, Mrs. Viktor (Helena Wilhelmina)",female,41,0,2,370129,20.2125,,S +256,1,3,"Touma, Mrs. Darwis (Hanne Youssef Razi)",female,29,0,2,2650,15.2458,,C +257,1,1,"Thorne, Mrs. Gertrude Maybelle",female,,0,0,PC 17585,79.2,,C +258,1,1,"Cherry, Miss. Gladys",female,30,0,0,110152,86.5,B77,S +259,1,1,"Ward, Miss. Anna",female,35,0,0,PC 17755,512.3292,,C +260,1,2,"Parrish, Mrs. (Lutie Davis)",female,50,0,1,230433,26,,S +261,0,3,"Smith, Mr. Thomas",male,,0,0,384461,7.75,,Q +262,1,3,"Asplund, Master. Edvin Rojj Felix",male,3,4,2,347077,31.3875,,S +263,0,1,"Taussig, Mr. Emil",male,52,1,1,110413,79.65,E67,S +264,0,1,"Harrison, Mr. William",male,40,0,0,112059,0,B94,S +265,0,3,"Henry, Miss. Delia",female,,0,0,382649,7.75,,Q +266,0,2,"Reeves, Mr. David",male,36,0,0,C.A. 17248,10.5,,S +267,0,3,"Panula, Mr. Ernesti Arvid",male,16,4,1,3101295,39.6875,,S +268,1,3,"Persson, Mr. Ernst Ulrik",male,25,1,0,347083,7.775,,S +269,1,1,"Graham, Mrs. William Thompson (Edith Junkins)",female,58,0,1,PC 17582,153.4625,C125,S +270,1,1,"Bissette, Miss. Amelia",female,35,0,0,PC 17760,135.6333,C99,S +271,0,1,"Cairns, Mr. Alexander",male,,0,0,113798,31,,S +272,1,3,"Tornquist, Mr. William Henry",male,25,0,0,LINE,0,,S +273,1,2,"Mellinger, Mrs. (Elizabeth Anne Maidment)",female,41,0,1,250644,19.5,,S +274,0,1,"Natsch, Mr. Charles H",male,37,0,1,PC 17596,29.7,C118,C +275,1,3,"Healy, Miss. Hanora ""Nora""",female,,0,0,370375,7.75,,Q +276,1,1,"Andrews, Miss. Kornelia Theodosia",female,63,1,0,13502,77.9583,D7,S +277,0,3,"Lindblom, Miss. Augusta Charlotta",female,45,0,0,347073,7.75,,S +278,0,2,"Parkes, Mr. Francis ""Frank""",male,,0,0,239853,0,,S +279,0,3,"Rice, Master. Eric",male,7,4,1,382652,29.125,,Q +280,1,3,"Abbott, Mrs. Stanton (Rosa Hunt)",female,35,1,1,C.A. 2673,20.25,,S +281,0,3,"Duane, Mr. Frank",male,65,0,0,336439,7.75,,Q +282,0,3,"Olsson, Mr. Nils Johan Goransson",male,28,0,0,347464,7.8542,,S +283,0,3,"de Pelsmaeker, Mr. Alfons",male,16,0,0,345778,9.5,,S +284,1,3,"Dorking, Mr. Edward Arthur",male,19,0,0,A/5. 10482,8.05,,S +285,0,1,"Smith, Mr. Richard William",male,,0,0,113056,26,A19,S +286,0,3,"Stankovic, Mr. Ivan",male,33,0,0,349239,8.6625,,C +287,1,3,"de Mulder, Mr. Theodore",male,30,0,0,345774,9.5,,S +288,0,3,"Naidenoff, Mr. Penko",male,22,0,0,349206,7.8958,,S +289,1,2,"Hosono, Mr. Masabumi",male,42,0,0,237798,13,,S +290,1,3,"Connolly, Miss. Kate",female,22,0,0,370373,7.75,,Q +291,1,1,"Barber, Miss. Ellen ""Nellie""",female,26,0,0,19877,78.85,,S +292,1,1,"Bishop, Mrs. Dickinson H (Helen Walton)",female,19,1,0,11967,91.0792,B49,C +293,0,2,"Levy, Mr. Rene Jacques",male,36,0,0,SC/Paris 2163,12.875,D,C +294,0,3,"Haas, Miss. Aloisia",female,24,0,0,349236,8.85,,S +295,0,3,"Mineff, Mr. Ivan",male,24,0,0,349233,7.8958,,S +296,0,1,"Lewy, Mr. Ervin G",male,,0,0,PC 17612,27.7208,,C +297,0,3,"Hanna, Mr. Mansour",male,23.5,0,0,2693,7.2292,,C +298,0,1,"Allison, Miss. Helen Loraine",female,2,1,2,113781,151.55,C22 C26,S +299,1,1,"Saalfeld, Mr. Adolphe",male,,0,0,19988,30.5,C106,S +300,1,1,"Baxter, Mrs. James (Helene DeLaudeniere Chaput)",female,50,0,1,PC 17558,247.5208,B58 B60,C +301,1,3,"Kelly, Miss. Anna Katherine ""Annie Kate""",female,,0,0,9234,7.75,,Q +302,1,3,"McCoy, Mr. Bernard",male,,2,0,367226,23.25,,Q +303,0,3,"Johnson, Mr. William Cahoone Jr",male,19,0,0,LINE,0,,S +304,1,2,"Keane, Miss. Nora A",female,,0,0,226593,12.35,E101,Q +305,0,3,"Williams, Mr. Howard Hugh ""Harry""",male,,0,0,A/5 2466,8.05,,S +306,1,1,"Allison, Master. Hudson Trevor",male,0.92,1,2,113781,151.55,C22 C26,S +307,1,1,"Fleming, Miss. Margaret",female,,0,0,17421,110.8833,,C +308,1,1,"Penasco y Castellana, Mrs. Victor de Satode (Maria Josefa Perez de Soto y Vallejo)",female,17,1,0,PC 17758,108.9,C65,C +309,0,2,"Abelson, Mr. Samuel",male,30,1,0,P/PP 3381,24,,C +310,1,1,"Francatelli, Miss. Laura Mabel",female,30,0,0,PC 17485,56.9292,E36,C +311,1,1,"Hays, Miss. Margaret Bechstein",female,24,0,0,11767,83.1583,C54,C +312,1,1,"Ryerson, Miss. Emily Borie",female,18,2,2,PC 17608,262.375,B57 B59 B63 B66,C +313,0,2,"Lahtinen, Mrs. William (Anna Sylfven)",female,26,1,1,250651,26,,S +314,0,3,"Hendekovic, Mr. Ignjac",male,28,0,0,349243,7.8958,,S +315,0,2,"Hart, Mr. Benjamin",male,43,1,1,F.C.C. 13529,26.25,,S +316,1,3,"Nilsson, Miss. Helmina Josefina",female,26,0,0,347470,7.8542,,S +317,1,2,"Kantor, Mrs. Sinai (Miriam Sternin)",female,24,1,0,244367,26,,S +318,0,2,"Moraweck, Dr. Ernest",male,54,0,0,29011,14,,S +319,1,1,"Wick, Miss. Mary Natalie",female,31,0,2,36928,164.8667,C7,S +320,1,1,"Spedden, Mrs. Frederic Oakley (Margaretta Corning Stone)",female,40,1,1,16966,134.5,E34,C +321,0,3,"Dennis, Mr. Samuel",male,22,0,0,A/5 21172,7.25,,S +322,0,3,"Danoff, Mr. Yoto",male,27,0,0,349219,7.8958,,S +323,1,2,"Slayter, Miss. Hilda Mary",female,30,0,0,234818,12.35,,Q +324,1,2,"Caldwell, Mrs. Albert Francis (Sylvia Mae Harbaugh)",female,22,1,1,248738,29,,S +325,0,3,"Sage, Mr. George John Jr",male,,8,2,CA. 2343,69.55,,S +326,1,1,"Young, Miss. Marie Grice",female,36,0,0,PC 17760,135.6333,C32,C +327,0,3,"Nysveen, Mr. Johan Hansen",male,61,0,0,345364,6.2375,,S +328,1,2,"Ball, Mrs. (Ada E Hall)",female,36,0,0,28551,13,D,S +329,1,3,"Goldsmith, Mrs. Frank John (Emily Alice Brown)",female,31,1,1,363291,20.525,,S +330,1,1,"Hippach, Miss. Jean Gertrude",female,16,0,1,111361,57.9792,B18,C +331,1,3,"McCoy, Miss. Agnes",female,,2,0,367226,23.25,,Q +332,0,1,"Partner, Mr. Austen",male,45.5,0,0,113043,28.5,C124,S +333,0,1,"Graham, Mr. George Edward",male,38,0,1,PC 17582,153.4625,C91,S +334,0,3,"Vander Planke, Mr. Leo Edmondus",male,16,2,0,345764,18,,S +335,1,1,"Frauenthal, Mrs. Henry William (Clara Heinsheimer)",female,,1,0,PC 17611,133.65,,S +336,0,3,"Denkoff, Mr. Mitto",male,,0,0,349225,7.8958,,S +337,0,1,"Pears, Mr. Thomas Clinton",male,29,1,0,113776,66.6,C2,S +338,1,1,"Burns, Miss. Elizabeth Margaret",female,41,0,0,16966,134.5,E40,C +339,1,3,"Dahl, Mr. Karl Edwart",male,45,0,0,7598,8.05,,S +340,0,1,"Blackwell, Mr. Stephen Weart",male,45,0,0,113784,35.5,T,S +341,1,2,"Navratil, Master. Edmond Roger",male,2,1,1,230080,26,F2,S +342,1,1,"Fortune, Miss. Alice Elizabeth",female,24,3,2,19950,263,C23 C25 C27,S +343,0,2,"Collander, Mr. Erik Gustaf",male,28,0,0,248740,13,,S +344,0,2,"Sedgwick, Mr. Charles Frederick Waddington",male,25,0,0,244361,13,,S +345,0,2,"Fox, Mr. Stanley Hubert",male,36,0,0,229236,13,,S +346,1,2,"Brown, Miss. Amelia ""Mildred""",female,24,0,0,248733,13,F33,S +347,1,2,"Smith, Miss. Marion Elsie",female,40,0,0,31418,13,,S +348,1,3,"Davison, Mrs. Thomas Henry (Mary E Finck)",female,,1,0,386525,16.1,,S +349,1,3,"Coutts, Master. William Loch ""William""",male,3,1,1,C.A. 37671,15.9,,S +350,0,3,"Dimic, Mr. Jovan",male,42,0,0,315088,8.6625,,S +351,0,3,"Odahl, Mr. Nils Martin",male,23,0,0,7267,9.225,,S +352,0,1,"Williams-Lambert, Mr. Fletcher Fellows",male,,0,0,113510,35,C128,S +353,0,3,"Elias, Mr. Tannous",male,15,1,1,2695,7.2292,,C +354,0,3,"Arnold-Franchi, Mr. Josef",male,25,1,0,349237,17.8,,S +355,0,3,"Yousif, Mr. Wazli",male,,0,0,2647,7.225,,C +356,0,3,"Vanden Steen, Mr. Leo Peter",male,28,0,0,345783,9.5,,S +357,1,1,"Bowerman, Miss. Elsie Edith",female,22,0,1,113505,55,E33,S +358,0,2,"Funk, Miss. Annie Clemmer",female,38,0,0,237671,13,,S +359,1,3,"McGovern, Miss. Mary",female,,0,0,330931,7.8792,,Q +360,1,3,"Mockler, Miss. Helen Mary ""Ellie""",female,,0,0,330980,7.8792,,Q +361,0,3,"Skoog, Mr. Wilhelm",male,40,1,4,347088,27.9,,S +362,0,2,"del Carlo, Mr. Sebastiano",male,29,1,0,SC/PARIS 2167,27.7208,,C +363,0,3,"Barbara, Mrs. (Catherine David)",female,45,0,1,2691,14.4542,,C +364,0,3,"Asim, Mr. Adola",male,35,0,0,SOTON/O.Q. 3101310,7.05,,S +365,0,3,"O'Brien, Mr. Thomas",male,,1,0,370365,15.5,,Q +366,0,3,"Adahl, Mr. Mauritz Nils Martin",male,30,0,0,C 7076,7.25,,S +367,1,1,"Warren, Mrs. Frank Manley (Anna Sophia Atkinson)",female,60,1,0,110813,75.25,D37,C +368,1,3,"Moussa, Mrs. (Mantoura Boulos)",female,,0,0,2626,7.2292,,C +369,1,3,"Jermyn, Miss. Annie",female,,0,0,14313,7.75,,Q +370,1,1,"Aubart, Mme. Leontine Pauline",female,24,0,0,PC 17477,69.3,B35,C +371,1,1,"Harder, Mr. George Achilles",male,25,1,0,11765,55.4417,E50,C +372,0,3,"Wiklund, Mr. Jakob Alfred",male,18,1,0,3101267,6.4958,,S +373,0,3,"Beavan, Mr. William Thomas",male,19,0,0,323951,8.05,,S +374,0,1,"Ringhini, Mr. Sante",male,22,0,0,PC 17760,135.6333,,C +375,0,3,"Palsson, Miss. Stina Viola",female,3,3,1,349909,21.075,,S +376,1,1,"Meyer, Mrs. Edgar Joseph (Leila Saks)",female,,1,0,PC 17604,82.1708,,C +377,1,3,"Landergren, Miss. Aurora Adelia",female,22,0,0,C 7077,7.25,,S +378,0,1,"Widener, Mr. Harry Elkins",male,27,0,2,113503,211.5,C82,C +379,0,3,"Betros, Mr. Tannous",male,20,0,0,2648,4.0125,,C +380,0,3,"Gustafsson, Mr. Karl Gideon",male,19,0,0,347069,7.775,,S +381,1,1,"Bidois, Miss. Rosalie",female,42,0,0,PC 17757,227.525,,C +382,1,3,"Nakid, Miss. Maria (""Mary"")",female,1,0,2,2653,15.7417,,C +383,0,3,"Tikkanen, Mr. Juho",male,32,0,0,STON/O 2. 3101293,7.925,,S +384,1,1,"Holverson, Mrs. Alexander Oskar (Mary Aline Towner)",female,35,1,0,113789,52,,S +385,0,3,"Plotcharsky, Mr. Vasil",male,,0,0,349227,7.8958,,S +386,0,2,"Davies, Mr. Charles Henry",male,18,0,0,S.O.C. 14879,73.5,,S +387,0,3,"Goodwin, Master. Sidney Leonard",male,1,5,2,CA 2144,46.9,,S +388,1,2,"Buss, Miss. Kate",female,36,0,0,27849,13,,S +389,0,3,"Sadlier, Mr. Matthew",male,,0,0,367655,7.7292,,Q +390,1,2,"Lehmann, Miss. Bertha",female,17,0,0,SC 1748,12,,C +391,1,1,"Carter, Mr. William Ernest",male,36,1,2,113760,120,B96 B98,S +392,1,3,"Jansson, Mr. Carl Olof",male,21,0,0,350034,7.7958,,S +393,0,3,"Gustafsson, Mr. Johan Birger",male,28,2,0,3101277,7.925,,S +394,1,1,"Newell, Miss. Marjorie",female,23,1,0,35273,113.275,D36,C +395,1,3,"Sandstrom, Mrs. Hjalmar (Agnes Charlotta Bengtsson)",female,24,0,2,PP 9549,16.7,G6,S +396,0,3,"Johansson, Mr. Erik",male,22,0,0,350052,7.7958,,S +397,0,3,"Olsson, Miss. Elina",female,31,0,0,350407,7.8542,,S +398,0,2,"McKane, Mr. Peter David",male,46,0,0,28403,26,,S +399,0,2,"Pain, Dr. Alfred",male,23,0,0,244278,10.5,,S +400,1,2,"Trout, Mrs. William H (Jessie L)",female,28,0,0,240929,12.65,,S +401,1,3,"Niskanen, Mr. Juha",male,39,0,0,STON/O 2. 3101289,7.925,,S +402,0,3,"Adams, Mr. John",male,26,0,0,341826,8.05,,S +403,0,3,"Jussila, Miss. Mari Aina",female,21,1,0,4137,9.825,,S +404,0,3,"Hakkarainen, Mr. Pekka Pietari",male,28,1,0,STON/O2. 3101279,15.85,,S +405,0,3,"Oreskovic, Miss. Marija",female,20,0,0,315096,8.6625,,S +406,0,2,"Gale, Mr. Shadrach",male,34,1,0,28664,21,,S +407,0,3,"Widegren, Mr. Carl/Charles Peter",male,51,0,0,347064,7.75,,S +408,1,2,"Richards, Master. William Rowe",male,3,1,1,29106,18.75,,S +409,0,3,"Birkeland, Mr. Hans Martin Monsen",male,21,0,0,312992,7.775,,S +410,0,3,"Lefebre, Miss. Ida",female,,3,1,4133,25.4667,,S +411,0,3,"Sdycoff, Mr. Todor",male,,0,0,349222,7.8958,,S +412,0,3,"Hart, Mr. Henry",male,,0,0,394140,6.8583,,Q +413,1,1,"Minahan, Miss. Daisy E",female,33,1,0,19928,90,C78,Q +414,0,2,"Cunningham, Mr. Alfred Fleming",male,,0,0,239853,0,,S +415,1,3,"Sundman, Mr. Johan Julian",male,44,0,0,STON/O 2. 3101269,7.925,,S +416,0,3,"Meek, Mrs. Thomas (Annie Louise Rowley)",female,,0,0,343095,8.05,,S +417,1,2,"Drew, Mrs. James Vivian (Lulu Thorne Christian)",female,34,1,1,28220,32.5,,S +418,1,2,"Silven, Miss. Lyyli Karoliina",female,18,0,2,250652,13,,S +419,0,2,"Matthews, Mr. William John",male,30,0,0,28228,13,,S +420,0,3,"Van Impe, Miss. Catharina",female,10,0,2,345773,24.15,,S +421,0,3,"Gheorgheff, Mr. Stanio",male,,0,0,349254,7.8958,,C +422,0,3,"Charters, Mr. David",male,21,0,0,A/5. 13032,7.7333,,Q +423,0,3,"Zimmerman, Mr. Leo",male,29,0,0,315082,7.875,,S +424,0,3,"Danbom, Mrs. Ernst Gilbert (Anna Sigrid Maria Brogren)",female,28,1,1,347080,14.4,,S +425,0,3,"Rosblom, Mr. Viktor Richard",male,18,1,1,370129,20.2125,,S +426,0,3,"Wiseman, Mr. Phillippe",male,,0,0,A/4. 34244,7.25,,S +427,1,2,"Clarke, Mrs. Charles V (Ada Maria Winfield)",female,28,1,0,2003,26,,S +428,1,2,"Phillips, Miss. Kate Florence (""Mrs Kate Louise Phillips Marshall"")",female,19,0,0,250655,26,,S +429,0,3,"Flynn, Mr. James",male,,0,0,364851,7.75,,Q +430,1,3,"Pickard, Mr. Berk (Berk Trembisky)",male,32,0,0,SOTON/O.Q. 392078,8.05,E10,S +431,1,1,"Bjornstrom-Steffansson, Mr. Mauritz Hakan",male,28,0,0,110564,26.55,C52,S +432,1,3,"Thorneycroft, Mrs. Percival (Florence Kate White)",female,,1,0,376564,16.1,,S +433,1,2,"Louch, Mrs. Charles Alexander (Alice Adelaide Slow)",female,42,1,0,SC/AH 3085,26,,S +434,0,3,"Kallio, Mr. Nikolai Erland",male,17,0,0,STON/O 2. 3101274,7.125,,S +435,0,1,"Silvey, Mr. William Baird",male,50,1,0,13507,55.9,E44,S +436,1,1,"Carter, Miss. Lucile Polk",female,14,1,2,113760,120,B96 B98,S +437,0,3,"Ford, Miss. Doolina Margaret ""Daisy""",female,21,2,2,W./C. 6608,34.375,,S +438,1,2,"Richards, Mrs. Sidney (Emily Hocking)",female,24,2,3,29106,18.75,,S +439,0,1,"Fortune, Mr. Mark",male,64,1,4,19950,263,C23 C25 C27,S +440,0,2,"Kvillner, Mr. Johan Henrik Johannesson",male,31,0,0,C.A. 18723,10.5,,S +441,1,2,"Hart, Mrs. Benjamin (Esther Ada Bloomfield)",female,45,1,1,F.C.C. 13529,26.25,,S +442,0,3,"Hampe, Mr. Leon",male,20,0,0,345769,9.5,,S +443,0,3,"Petterson, Mr. Johan Emil",male,25,1,0,347076,7.775,,S +444,1,2,"Reynaldo, Ms. Encarnacion",female,28,0,0,230434,13,,S +445,1,3,"Johannesen-Bratthammer, Mr. Bernt",male,,0,0,65306,8.1125,,S +446,1,1,"Dodge, Master. Washington",male,4,0,2,33638,81.8583,A34,S +447,1,2,"Mellinger, Miss. Madeleine Violet",female,13,0,1,250644,19.5,,S +448,1,1,"Seward, Mr. Frederic Kimber",male,34,0,0,113794,26.55,,S +449,1,3,"Baclini, Miss. Marie Catherine",female,5,2,1,2666,19.2583,,C +450,1,1,"Peuchen, Major. Arthur Godfrey",male,52,0,0,113786,30.5,C104,S +451,0,2,"West, Mr. Edwy Arthur",male,36,1,2,C.A. 34651,27.75,,S +452,0,3,"Hagland, Mr. Ingvald Olai Olsen",male,,1,0,65303,19.9667,,S +453,0,1,"Foreman, Mr. Benjamin Laventall",male,30,0,0,113051,27.75,C111,C +454,1,1,"Goldenberg, Mr. Samuel L",male,49,1,0,17453,89.1042,C92,C +455,0,3,"Peduzzi, Mr. Joseph",male,,0,0,A/5 2817,8.05,,S +456,1,3,"Jalsevac, Mr. Ivan",male,29,0,0,349240,7.8958,,C +457,0,1,"Millet, Mr. Francis Davis",male,65,0,0,13509,26.55,E38,S +458,1,1,"Kenyon, Mrs. Frederick R (Marion)",female,,1,0,17464,51.8625,D21,S +459,1,2,"Toomey, Miss. Ellen",female,50,0,0,F.C.C. 13531,10.5,,S +460,0,3,"O'Connor, Mr. Maurice",male,,0,0,371060,7.75,,Q +461,1,1,"Anderson, Mr. Harry",male,48,0,0,19952,26.55,E12,S +462,0,3,"Morley, Mr. William",male,34,0,0,364506,8.05,,S +463,0,1,"Gee, Mr. Arthur H",male,47,0,0,111320,38.5,E63,S +464,0,2,"Milling, Mr. Jacob Christian",male,48,0,0,234360,13,,S +465,0,3,"Maisner, Mr. Simon",male,,0,0,A/S 2816,8.05,,S +466,0,3,"Goncalves, Mr. Manuel Estanslas",male,38,0,0,SOTON/O.Q. 3101306,7.05,,S +467,0,2,"Campbell, Mr. William",male,,0,0,239853,0,,S +468,0,1,"Smart, Mr. John Montgomery",male,56,0,0,113792,26.55,,S +469,0,3,"Scanlan, Mr. James",male,,0,0,36209,7.725,,Q +470,1,3,"Baclini, Miss. Helene Barbara",female,0.75,2,1,2666,19.2583,,C +471,0,3,"Keefe, Mr. Arthur",male,,0,0,323592,7.25,,S +472,0,3,"Cacic, Mr. Luka",male,38,0,0,315089,8.6625,,S +473,1,2,"West, Mrs. Edwy Arthur (Ada Mary Worth)",female,33,1,2,C.A. 34651,27.75,,S +474,1,2,"Jerwan, Mrs. Amin S (Marie Marthe Thuillard)",female,23,0,0,SC/AH Basle 541,13.7917,D,C +475,0,3,"Strandberg, Miss. Ida Sofia",female,22,0,0,7553,9.8375,,S +476,0,1,"Clifford, Mr. George Quincy",male,,0,0,110465,52,A14,S +477,0,2,"Renouf, Mr. Peter Henry",male,34,1,0,31027,21,,S +478,0,3,"Braund, Mr. Lewis Richard",male,29,1,0,3460,7.0458,,S +479,0,3,"Karlsson, Mr. Nils August",male,22,0,0,350060,7.5208,,S +480,1,3,"Hirvonen, Miss. Hildur E",female,2,0,1,3101298,12.2875,,S +481,0,3,"Goodwin, Master. Harold Victor",male,9,5,2,CA 2144,46.9,,S +482,0,2,"Frost, Mr. Anthony Wood ""Archie""",male,,0,0,239854,0,,S +483,0,3,"Rouse, Mr. Richard Henry",male,50,0,0,A/5 3594,8.05,,S +484,1,3,"Turkula, Mrs. (Hedwig)",female,63,0,0,4134,9.5875,,S +485,1,1,"Bishop, Mr. Dickinson H",male,25,1,0,11967,91.0792,B49,C +486,0,3,"Lefebre, Miss. Jeannie",female,,3,1,4133,25.4667,,S +487,1,1,"Hoyt, Mrs. Frederick Maxfield (Jane Anne Forby)",female,35,1,0,19943,90,C93,S +488,0,1,"Kent, Mr. Edward Austin",male,58,0,0,11771,29.7,B37,C +489,0,3,"Somerton, Mr. Francis William",male,30,0,0,A.5. 18509,8.05,,S +490,1,3,"Coutts, Master. Eden Leslie ""Neville""",male,9,1,1,C.A. 37671,15.9,,S +491,0,3,"Hagland, Mr. Konrad Mathias Reiersen",male,,1,0,65304,19.9667,,S +492,0,3,"Windelov, Mr. Einar",male,21,0,0,SOTON/OQ 3101317,7.25,,S +493,0,1,"Molson, Mr. Harry Markland",male,55,0,0,113787,30.5,C30,S +494,0,1,"Artagaveytia, Mr. Ramon",male,71,0,0,PC 17609,49.5042,,C +495,0,3,"Stanley, Mr. Edward Roland",male,21,0,0,A/4 45380,8.05,,S +496,0,3,"Yousseff, Mr. Gerious",male,,0,0,2627,14.4583,,C +497,1,1,"Eustis, Miss. Elizabeth Mussey",female,54,1,0,36947,78.2667,D20,C +498,0,3,"Shellard, Mr. Frederick William",male,,0,0,C.A. 6212,15.1,,S +499,0,1,"Allison, Mrs. Hudson J C (Bessie Waldo Daniels)",female,25,1,2,113781,151.55,C22 C26,S +500,0,3,"Svensson, Mr. Olof",male,24,0,0,350035,7.7958,,S +501,0,3,"Calic, Mr. Petar",male,17,0,0,315086,8.6625,,S +502,0,3,"Canavan, Miss. Mary",female,21,0,0,364846,7.75,,Q +503,0,3,"O'Sullivan, Miss. Bridget Mary",female,,0,0,330909,7.6292,,Q +504,0,3,"Laitinen, Miss. Kristina Sofia",female,37,0,0,4135,9.5875,,S +505,1,1,"Maioni, Miss. Roberta",female,16,0,0,110152,86.5,B79,S +506,0,1,"Penasco y Castellana, Mr. Victor de Satode",male,18,1,0,PC 17758,108.9,C65,C +507,1,2,"Quick, Mrs. Frederick Charles (Jane Richards)",female,33,0,2,26360,26,,S +508,1,1,"Bradley, Mr. George (""George Arthur Brayton"")",male,,0,0,111427,26.55,,S +509,0,3,"Olsen, Mr. Henry Margido",male,28,0,0,C 4001,22.525,,S +510,1,3,"Lang, Mr. Fang",male,26,0,0,1601,56.4958,,S +511,1,3,"Daly, Mr. Eugene Patrick",male,29,0,0,382651,7.75,,Q +512,0,3,"Webber, Mr. James",male,,0,0,SOTON/OQ 3101316,8.05,,S +513,1,1,"McGough, Mr. James Robert",male,36,0,0,PC 17473,26.2875,E25,S +514,1,1,"Rothschild, Mrs. Martin (Elizabeth L. Barrett)",female,54,1,0,PC 17603,59.4,,C +515,0,3,"Coleff, Mr. Satio",male,24,0,0,349209,7.4958,,S +516,0,1,"Walker, Mr. William Anderson",male,47,0,0,36967,34.0208,D46,S +517,1,2,"Lemore, Mrs. (Amelia Milley)",female,34,0,0,C.A. 34260,10.5,F33,S +518,0,3,"Ryan, Mr. Patrick",male,,0,0,371110,24.15,,Q +519,1,2,"Angle, Mrs. William A (Florence ""Mary"" Agnes Hughes)",female,36,1,0,226875,26,,S +520,0,3,"Pavlovic, Mr. Stefo",male,32,0,0,349242,7.8958,,S +521,1,1,"Perreault, Miss. Anne",female,30,0,0,12749,93.5,B73,S +522,0,3,"Vovk, Mr. Janko",male,22,0,0,349252,7.8958,,S +523,0,3,"Lahoud, Mr. Sarkis",male,,0,0,2624,7.225,,C +524,1,1,"Hippach, Mrs. Louis Albert (Ida Sophia Fischer)",female,44,0,1,111361,57.9792,B18,C +525,0,3,"Kassem, Mr. Fared",male,,0,0,2700,7.2292,,C +526,0,3,"Farrell, Mr. James",male,40.5,0,0,367232,7.75,,Q +527,1,2,"Ridsdale, Miss. Lucy",female,50,0,0,W./C. 14258,10.5,,S +528,0,1,"Farthing, Mr. John",male,,0,0,PC 17483,221.7792,C95,S +529,0,3,"Salonen, Mr. Johan Werner",male,39,0,0,3101296,7.925,,S +530,0,2,"Hocking, Mr. Richard George",male,23,2,1,29104,11.5,,S +531,1,2,"Quick, Miss. Phyllis May",female,2,1,1,26360,26,,S +532,0,3,"Toufik, Mr. Nakli",male,,0,0,2641,7.2292,,C +533,0,3,"Elias, Mr. Joseph Jr",male,17,1,1,2690,7.2292,,C +534,1,3,"Peter, Mrs. Catherine (Catherine Rizk)",female,,0,2,2668,22.3583,,C +535,0,3,"Cacic, Miss. Marija",female,30,0,0,315084,8.6625,,S +536,1,2,"Hart, Miss. Eva Miriam",female,7,0,2,F.C.C. 13529,26.25,,S +537,0,1,"Butt, Major. Archibald Willingham",male,45,0,0,113050,26.55,B38,S +538,1,1,"LeRoy, Miss. Bertha",female,30,0,0,PC 17761,106.425,,C +539,0,3,"Risien, Mr. Samuel Beard",male,,0,0,364498,14.5,,S +540,1,1,"Frolicher, Miss. Hedwig Margaritha",female,22,0,2,13568,49.5,B39,C +541,1,1,"Crosby, Miss. Harriet R",female,36,0,2,WE/P 5735,71,B22,S +542,0,3,"Andersson, Miss. Ingeborg Constanzia",female,9,4,2,347082,31.275,,S +543,0,3,"Andersson, Miss. Sigrid Elisabeth",female,11,4,2,347082,31.275,,S +544,1,2,"Beane, Mr. Edward",male,32,1,0,2908,26,,S +545,0,1,"Douglas, Mr. Walter Donald",male,50,1,0,PC 17761,106.425,C86,C +546,0,1,"Nicholson, Mr. Arthur Ernest",male,64,0,0,693,26,,S +547,1,2,"Beane, Mrs. Edward (Ethel Clarke)",female,19,1,0,2908,26,,S +548,1,2,"Padro y Manent, Mr. Julian",male,,0,0,SC/PARIS 2146,13.8625,,C +549,0,3,"Goldsmith, Mr. Frank John",male,33,1,1,363291,20.525,,S +550,1,2,"Davies, Master. John Morgan Jr",male,8,1,1,C.A. 33112,36.75,,S +551,1,1,"Thayer, Mr. John Borland Jr",male,17,0,2,17421,110.8833,C70,C +552,0,2,"Sharp, Mr. Percival James R",male,27,0,0,244358,26,,S +553,0,3,"O'Brien, Mr. Timothy",male,,0,0,330979,7.8292,,Q +554,1,3,"Leeni, Mr. Fahim (""Philip Zenni"")",male,22,0,0,2620,7.225,,C +555,1,3,"Ohman, Miss. Velin",female,22,0,0,347085,7.775,,S +556,0,1,"Wright, Mr. George",male,62,0,0,113807,26.55,,S +557,1,1,"Duff Gordon, Lady. (Lucille Christiana Sutherland) (""Mrs Morgan"")",female,48,1,0,11755,39.6,A16,C +558,0,1,"Robbins, Mr. Victor",male,,0,0,PC 17757,227.525,,C +559,1,1,"Taussig, Mrs. Emil (Tillie Mandelbaum)",female,39,1,1,110413,79.65,E67,S +560,1,3,"de Messemaeker, Mrs. Guillaume Joseph (Emma)",female,36,1,0,345572,17.4,,S +561,0,3,"Morrow, Mr. Thomas Rowan",male,,0,0,372622,7.75,,Q +562,0,3,"Sivic, Mr. Husein",male,40,0,0,349251,7.8958,,S +563,0,2,"Norman, Mr. Robert Douglas",male,28,0,0,218629,13.5,,S +564,0,3,"Simmons, Mr. John",male,,0,0,SOTON/OQ 392082,8.05,,S +565,0,3,"Meanwell, Miss. (Marion Ogden)",female,,0,0,SOTON/O.Q. 392087,8.05,,S +566,0,3,"Davies, Mr. Alfred J",male,24,2,0,A/4 48871,24.15,,S +567,0,3,"Stoytcheff, Mr. Ilia",male,19,0,0,349205,7.8958,,S +568,0,3,"Palsson, Mrs. Nils (Alma Cornelia Berglund)",female,29,0,4,349909,21.075,,S +569,0,3,"Doharr, Mr. Tannous",male,,0,0,2686,7.2292,,C +570,1,3,"Jonsson, Mr. Carl",male,32,0,0,350417,7.8542,,S +571,1,2,"Harris, Mr. George",male,62,0,0,S.W./PP 752,10.5,,S +572,1,1,"Appleton, Mrs. Edward Dale (Charlotte Lamson)",female,53,2,0,11769,51.4792,C101,S +573,1,1,"Flynn, Mr. John Irwin (""Irving"")",male,36,0,0,PC 17474,26.3875,E25,S +574,1,3,"Kelly, Miss. Mary",female,,0,0,14312,7.75,,Q +575,0,3,"Rush, Mr. Alfred George John",male,16,0,0,A/4. 20589,8.05,,S +576,0,3,"Patchett, Mr. George",male,19,0,0,358585,14.5,,S +577,1,2,"Garside, Miss. Ethel",female,34,0,0,243880,13,,S +578,1,1,"Silvey, Mrs. William Baird (Alice Munger)",female,39,1,0,13507,55.9,E44,S +579,0,3,"Caram, Mrs. Joseph (Maria Elias)",female,,1,0,2689,14.4583,,C +580,1,3,"Jussila, Mr. Eiriik",male,32,0,0,STON/O 2. 3101286,7.925,,S +581,1,2,"Christy, Miss. Julie Rachel",female,25,1,1,237789,30,,S +582,1,1,"Thayer, Mrs. John Borland (Marian Longstreth Morris)",female,39,1,1,17421,110.8833,C68,C +583,0,2,"Downton, Mr. William James",male,54,0,0,28403,26,,S +584,0,1,"Ross, Mr. John Hugo",male,36,0,0,13049,40.125,A10,C +585,0,3,"Paulner, Mr. Uscher",male,,0,0,3411,8.7125,,C +586,1,1,"Taussig, Miss. Ruth",female,18,0,2,110413,79.65,E68,S +587,0,2,"Jarvis, Mr. John Denzil",male,47,0,0,237565,15,,S +588,1,1,"Frolicher-Stehli, Mr. Maxmillian",male,60,1,1,13567,79.2,B41,C +589,0,3,"Gilinski, Mr. Eliezer",male,22,0,0,14973,8.05,,S +590,0,3,"Murdlin, Mr. Joseph",male,,0,0,A./5. 3235,8.05,,S +591,0,3,"Rintamaki, Mr. Matti",male,35,0,0,STON/O 2. 3101273,7.125,,S +592,1,1,"Stephenson, Mrs. Walter Bertram (Martha Eustis)",female,52,1,0,36947,78.2667,D20,C +593,0,3,"Elsbury, Mr. William James",male,47,0,0,A/5 3902,7.25,,S +594,0,3,"Bourke, Miss. Mary",female,,0,2,364848,7.75,,Q +595,0,2,"Chapman, Mr. John Henry",male,37,1,0,SC/AH 29037,26,,S +596,0,3,"Van Impe, Mr. Jean Baptiste",male,36,1,1,345773,24.15,,S +597,1,2,"Leitch, Miss. Jessie Wills",female,,0,0,248727,33,,S +598,0,3,"Johnson, Mr. Alfred",male,49,0,0,LINE,0,,S +599,0,3,"Boulos, Mr. Hanna",male,,0,0,2664,7.225,,C +600,1,1,"Duff Gordon, Sir. Cosmo Edmund (""Mr Morgan"")",male,49,1,0,PC 17485,56.9292,A20,C +601,1,2,"Jacobsohn, Mrs. Sidney Samuel (Amy Frances Christy)",female,24,2,1,243847,27,,S +602,0,3,"Slabenoff, Mr. Petco",male,,0,0,349214,7.8958,,S +603,0,1,"Harrington, Mr. Charles H",male,,0,0,113796,42.4,,S +604,0,3,"Torber, Mr. Ernst William",male,44,0,0,364511,8.05,,S +605,1,1,"Homer, Mr. Harry (""Mr E Haven"")",male,35,0,0,111426,26.55,,C +606,0,3,"Lindell, Mr. Edvard Bengtsson",male,36,1,0,349910,15.55,,S +607,0,3,"Karaic, Mr. Milan",male,30,0,0,349246,7.8958,,S +608,1,1,"Daniel, Mr. Robert Williams",male,27,0,0,113804,30.5,,S +609,1,2,"Laroche, Mrs. Joseph (Juliette Marie Louise Lafargue)",female,22,1,2,SC/Paris 2123,41.5792,,C +610,1,1,"Shutes, Miss. Elizabeth W",female,40,0,0,PC 17582,153.4625,C125,S +611,0,3,"Andersson, Mrs. Anders Johan (Alfrida Konstantia Brogren)",female,39,1,5,347082,31.275,,S +612,0,3,"Jardin, Mr. Jose Neto",male,,0,0,SOTON/O.Q. 3101305,7.05,,S +613,1,3,"Murphy, Miss. Margaret Jane",female,,1,0,367230,15.5,,Q +614,0,3,"Horgan, Mr. John",male,,0,0,370377,7.75,,Q +615,0,3,"Brocklebank, Mr. William Alfred",male,35,0,0,364512,8.05,,S +616,1,2,"Herman, Miss. Alice",female,24,1,2,220845,65,,S +617,0,3,"Danbom, Mr. Ernst Gilbert",male,34,1,1,347080,14.4,,S +618,0,3,"Lobb, Mrs. William Arthur (Cordelia K Stanlick)",female,26,1,0,A/5. 3336,16.1,,S +619,1,2,"Becker, Miss. Marion Louise",female,4,2,1,230136,39,F4,S +620,0,2,"Gavey, Mr. Lawrence",male,26,0,0,31028,10.5,,S +621,0,3,"Yasbeck, Mr. Antoni",male,27,1,0,2659,14.4542,,C +622,1,1,"Kimball, Mr. Edwin Nelson Jr",male,42,1,0,11753,52.5542,D19,S +623,1,3,"Nakid, Mr. Sahid",male,20,1,1,2653,15.7417,,C +624,0,3,"Hansen, Mr. Henry Damsgaard",male,21,0,0,350029,7.8542,,S +625,0,3,"Bowen, Mr. David John ""Dai""",male,21,0,0,54636,16.1,,S +626,0,1,"Sutton, Mr. Frederick",male,61,0,0,36963,32.3208,D50,S +627,0,2,"Kirkland, Rev. Charles Leonard",male,57,0,0,219533,12.35,,Q +628,1,1,"Longley, Miss. Gretchen Fiske",female,21,0,0,13502,77.9583,D9,S +629,0,3,"Bostandyeff, Mr. Guentcho",male,26,0,0,349224,7.8958,,S +630,0,3,"O'Connell, Mr. Patrick D",male,,0,0,334912,7.7333,,Q +631,1,1,"Barkworth, Mr. Algernon Henry Wilson",male,80,0,0,27042,30,A23,S +632,0,3,"Lundahl, Mr. Johan Svensson",male,51,0,0,347743,7.0542,,S +633,1,1,"Stahelin-Maeglin, Dr. Max",male,32,0,0,13214,30.5,B50,C +634,0,1,"Parr, Mr. William Henry Marsh",male,,0,0,112052,0,,S +635,0,3,"Skoog, Miss. Mabel",female,9,3,2,347088,27.9,,S +636,1,2,"Davis, Miss. Mary",female,28,0,0,237668,13,,S +637,0,3,"Leinonen, Mr. Antti Gustaf",male,32,0,0,STON/O 2. 3101292,7.925,,S +638,0,2,"Collyer, Mr. Harvey",male,31,1,1,C.A. 31921,26.25,,S +639,0,3,"Panula, Mrs. Juha (Maria Emilia Ojala)",female,41,0,5,3101295,39.6875,,S +640,0,3,"Thorneycroft, Mr. Percival",male,,1,0,376564,16.1,,S +641,0,3,"Jensen, Mr. Hans Peder",male,20,0,0,350050,7.8542,,S +642,1,1,"Sagesser, Mlle. Emma",female,24,0,0,PC 17477,69.3,B35,C +643,0,3,"Skoog, Miss. Margit Elizabeth",female,2,3,2,347088,27.9,,S +644,1,3,"Foo, Mr. Choong",male,,0,0,1601,56.4958,,S +645,1,3,"Baclini, Miss. Eugenie",female,0.75,2,1,2666,19.2583,,C +646,1,1,"Harper, Mr. Henry Sleeper",male,48,1,0,PC 17572,76.7292,D33,C +647,0,3,"Cor, Mr. Liudevit",male,19,0,0,349231,7.8958,,S +648,1,1,"Simonius-Blumer, Col. Oberst Alfons",male,56,0,0,13213,35.5,A26,C +649,0,3,"Willey, Mr. Edward",male,,0,0,S.O./P.P. 751,7.55,,S +650,1,3,"Stanley, Miss. Amy Zillah Elsie",female,23,0,0,CA. 2314,7.55,,S +651,0,3,"Mitkoff, Mr. Mito",male,,0,0,349221,7.8958,,S +652,1,2,"Doling, Miss. Elsie",female,18,0,1,231919,23,,S +653,0,3,"Kalvik, Mr. Johannes Halvorsen",male,21,0,0,8475,8.4333,,S +654,1,3,"O'Leary, Miss. Hanora ""Norah""",female,,0,0,330919,7.8292,,Q +655,0,3,"Hegarty, Miss. Hanora ""Nora""",female,18,0,0,365226,6.75,,Q +656,0,2,"Hickman, Mr. Leonard Mark",male,24,2,0,S.O.C. 14879,73.5,,S +657,0,3,"Radeff, Mr. Alexander",male,,0,0,349223,7.8958,,S +658,0,3,"Bourke, Mrs. John (Catherine)",female,32,1,1,364849,15.5,,Q +659,0,2,"Eitemiller, Mr. George Floyd",male,23,0,0,29751,13,,S +660,0,1,"Newell, Mr. Arthur Webster",male,58,0,2,35273,113.275,D48,C +661,1,1,"Frauenthal, Dr. Henry William",male,50,2,0,PC 17611,133.65,,S +662,0,3,"Badt, Mr. Mohamed",male,40,0,0,2623,7.225,,C +663,0,1,"Colley, Mr. Edward Pomeroy",male,47,0,0,5727,25.5875,E58,S +664,0,3,"Coleff, Mr. Peju",male,36,0,0,349210,7.4958,,S +665,1,3,"Lindqvist, Mr. Eino William",male,20,1,0,STON/O 2. 3101285,7.925,,S +666,0,2,"Hickman, Mr. Lewis",male,32,2,0,S.O.C. 14879,73.5,,S +667,0,2,"Butler, Mr. Reginald Fenton",male,25,0,0,234686,13,,S +668,0,3,"Rommetvedt, Mr. Knud Paust",male,,0,0,312993,7.775,,S +669,0,3,"Cook, Mr. Jacob",male,43,0,0,A/5 3536,8.05,,S +670,1,1,"Taylor, Mrs. Elmer Zebley (Juliet Cummins Wright)",female,,1,0,19996,52,C126,S +671,1,2,"Brown, Mrs. Thomas William Solomon (Elizabeth Catherine Ford)",female,40,1,1,29750,39,,S +672,0,1,"Davidson, Mr. Thornton",male,31,1,0,F.C. 12750,52,B71,S +673,0,2,"Mitchell, Mr. Henry Michael",male,70,0,0,C.A. 24580,10.5,,S +674,1,2,"Wilhelms, Mr. Charles",male,31,0,0,244270,13,,S +675,0,2,"Watson, Mr. Ennis Hastings",male,,0,0,239856,0,,S +676,0,3,"Edvardsson, Mr. Gustaf Hjalmar",male,18,0,0,349912,7.775,,S +677,0,3,"Sawyer, Mr. Frederick Charles",male,24.5,0,0,342826,8.05,,S +678,1,3,"Turja, Miss. Anna Sofia",female,18,0,0,4138,9.8417,,S +679,0,3,"Goodwin, Mrs. Frederick (Augusta Tyler)",female,43,1,6,CA 2144,46.9,,S +680,1,1,"Cardeza, Mr. Thomas Drake Martinez",male,36,0,1,PC 17755,512.3292,B51 B53 B55,C +681,0,3,"Peters, Miss. Katie",female,,0,0,330935,8.1375,,Q +682,1,1,"Hassab, Mr. Hammad",male,27,0,0,PC 17572,76.7292,D49,C +683,0,3,"Olsvigen, Mr. Thor Anderson",male,20,0,0,6563,9.225,,S +684,0,3,"Goodwin, Mr. Charles Edward",male,14,5,2,CA 2144,46.9,,S +685,0,2,"Brown, Mr. Thomas William Solomon",male,60,1,1,29750,39,,S +686,0,2,"Laroche, Mr. Joseph Philippe Lemercier",male,25,1,2,SC/Paris 2123,41.5792,,C +687,0,3,"Panula, Mr. Jaako Arnold",male,14,4,1,3101295,39.6875,,S +688,0,3,"Dakic, Mr. Branko",male,19,0,0,349228,10.1708,,S +689,0,3,"Fischer, Mr. Eberhard Thelander",male,18,0,0,350036,7.7958,,S +690,1,1,"Madill, Miss. Georgette Alexandra",female,15,0,1,24160,211.3375,B5,S +691,1,1,"Dick, Mr. Albert Adrian",male,31,1,0,17474,57,B20,S +692,1,3,"Karun, Miss. Manca",female,4,0,1,349256,13.4167,,C +693,1,3,"Lam, Mr. Ali",male,,0,0,1601,56.4958,,S +694,0,3,"Saad, Mr. Khalil",male,25,0,0,2672,7.225,,C +695,0,1,"Weir, Col. John",male,60,0,0,113800,26.55,,S +696,0,2,"Chapman, Mr. Charles Henry",male,52,0,0,248731,13.5,,S +697,0,3,"Kelly, Mr. James",male,44,0,0,363592,8.05,,S +698,1,3,"Mullens, Miss. Katherine ""Katie""",female,,0,0,35852,7.7333,,Q +699,0,1,"Thayer, Mr. John Borland",male,49,1,1,17421,110.8833,C68,C +700,0,3,"Humblen, Mr. Adolf Mathias Nicolai Olsen",male,42,0,0,348121,7.65,F G63,S +701,1,1,"Astor, Mrs. John Jacob (Madeleine Talmadge Force)",female,18,1,0,PC 17757,227.525,C62 C64,C +702,1,1,"Silverthorne, Mr. Spencer Victor",male,35,0,0,PC 17475,26.2875,E24,S +703,0,3,"Barbara, Miss. Saiide",female,18,0,1,2691,14.4542,,C +704,0,3,"Gallagher, Mr. Martin",male,25,0,0,36864,7.7417,,Q +705,0,3,"Hansen, Mr. Henrik Juul",male,26,1,0,350025,7.8542,,S +706,0,2,"Morley, Mr. Henry Samuel (""Mr Henry Marshall"")",male,39,0,0,250655,26,,S +707,1,2,"Kelly, Mrs. Florence ""Fannie""",female,45,0,0,223596,13.5,,S +708,1,1,"Calderhead, Mr. Edward Pennington",male,42,0,0,PC 17476,26.2875,E24,S +709,1,1,"Cleaver, Miss. Alice",female,22,0,0,113781,151.55,,S +710,1,3,"Moubarek, Master. Halim Gonios (""William George"")",male,,1,1,2661,15.2458,,C +711,1,1,"Mayne, Mlle. Berthe Antonine (""Mrs de Villiers"")",female,24,0,0,PC 17482,49.5042,C90,C +712,0,1,"Klaber, Mr. Herman",male,,0,0,113028,26.55,C124,S +713,1,1,"Taylor, Mr. Elmer Zebley",male,48,1,0,19996,52,C126,S +714,0,3,"Larsson, Mr. August Viktor",male,29,0,0,7545,9.4833,,S +715,0,2,"Greenberg, Mr. Samuel",male,52,0,0,250647,13,,S +716,0,3,"Soholt, Mr. Peter Andreas Lauritz Andersen",male,19,0,0,348124,7.65,F G73,S +717,1,1,"Endres, Miss. Caroline Louise",female,38,0,0,PC 17757,227.525,C45,C +718,1,2,"Troutt, Miss. Edwina Celia ""Winnie""",female,27,0,0,34218,10.5,E101,S +719,0,3,"McEvoy, Mr. Michael",male,,0,0,36568,15.5,,Q +720,0,3,"Johnson, Mr. Malkolm Joackim",male,33,0,0,347062,7.775,,S +721,1,2,"Harper, Miss. Annie Jessie ""Nina""",female,6,0,1,248727,33,,S +722,0,3,"Jensen, Mr. Svend Lauritz",male,17,1,0,350048,7.0542,,S +723,0,2,"Gillespie, Mr. William Henry",male,34,0,0,12233,13,,S +724,0,2,"Hodges, Mr. Henry Price",male,50,0,0,250643,13,,S +725,1,1,"Chambers, Mr. Norman Campbell",male,27,1,0,113806,53.1,E8,S +726,0,3,"Oreskovic, Mr. Luka",male,20,0,0,315094,8.6625,,S +727,1,2,"Renouf, Mrs. Peter Henry (Lillian Jefferys)",female,30,3,0,31027,21,,S +728,1,3,"Mannion, Miss. Margareth",female,,0,0,36866,7.7375,,Q +729,0,2,"Bryhl, Mr. Kurt Arnold Gottfrid",male,25,1,0,236853,26,,S +730,0,3,"Ilmakangas, Miss. Pieta Sofia",female,25,1,0,STON/O2. 3101271,7.925,,S +731,1,1,"Allen, Miss. Elisabeth Walton",female,29,0,0,24160,211.3375,B5,S +732,0,3,"Hassan, Mr. Houssein G N",male,11,0,0,2699,18.7875,,C +733,0,2,"Knight, Mr. Robert J",male,,0,0,239855,0,,S +734,0,2,"Berriman, Mr. William John",male,23,0,0,28425,13,,S +735,0,2,"Troupiansky, Mr. Moses Aaron",male,23,0,0,233639,13,,S +736,0,3,"Williams, Mr. Leslie",male,28.5,0,0,54636,16.1,,S +737,0,3,"Ford, Mrs. Edward (Margaret Ann Watson)",female,48,1,3,W./C. 6608,34.375,,S +738,1,1,"Lesurer, Mr. Gustave J",male,35,0,0,PC 17755,512.3292,B101,C +739,0,3,"Ivanoff, Mr. Kanio",male,,0,0,349201,7.8958,,S +740,0,3,"Nankoff, Mr. Minko",male,,0,0,349218,7.8958,,S +741,1,1,"Hawksford, Mr. Walter James",male,,0,0,16988,30,D45,S +742,0,1,"Cavendish, Mr. Tyrell William",male,36,1,0,19877,78.85,C46,S +743,1,1,"Ryerson, Miss. Susan Parker ""Suzette""",female,21,2,2,PC 17608,262.375,B57 B59 B63 B66,C +744,0,3,"McNamee, Mr. Neal",male,24,1,0,376566,16.1,,S +745,1,3,"Stranden, Mr. Juho",male,31,0,0,STON/O 2. 3101288,7.925,,S +746,0,1,"Crosby, Capt. Edward Gifford",male,70,1,1,WE/P 5735,71,B22,S +747,0,3,"Abbott, Mr. Rossmore Edward",male,16,1,1,C.A. 2673,20.25,,S +748,1,2,"Sinkkonen, Miss. Anna",female,30,0,0,250648,13,,S +749,0,1,"Marvin, Mr. Daniel Warner",male,19,1,0,113773,53.1,D30,S +750,0,3,"Connaghton, Mr. Michael",male,31,0,0,335097,7.75,,Q +751,1,2,"Wells, Miss. Joan",female,4,1,1,29103,23,,S +752,1,3,"Moor, Master. Meier",male,6,0,1,392096,12.475,E121,S +753,0,3,"Vande Velde, Mr. Johannes Joseph",male,33,0,0,345780,9.5,,S +754,0,3,"Jonkoff, Mr. Lalio",male,23,0,0,349204,7.8958,,S +755,1,2,"Herman, Mrs. Samuel (Jane Laver)",female,48,1,2,220845,65,,S +756,1,2,"Hamalainen, Master. Viljo",male,0.67,1,1,250649,14.5,,S +757,0,3,"Carlsson, Mr. August Sigfrid",male,28,0,0,350042,7.7958,,S +758,0,2,"Bailey, Mr. Percy Andrew",male,18,0,0,29108,11.5,,S +759,0,3,"Theobald, Mr. Thomas Leonard",male,34,0,0,363294,8.05,,S +760,1,1,"Rothes, the Countess. of (Lucy Noel Martha Dyer-Edwards)",female,33,0,0,110152,86.5,B77,S +761,0,3,"Garfirth, Mr. John",male,,0,0,358585,14.5,,S +762,0,3,"Nirva, Mr. Iisakki Antino Aijo",male,41,0,0,SOTON/O2 3101272,7.125,,S +763,1,3,"Barah, Mr. Hanna Assi",male,20,0,0,2663,7.2292,,C +764,1,1,"Carter, Mrs. William Ernest (Lucile Polk)",female,36,1,2,113760,120,B96 B98,S +765,0,3,"Eklund, Mr. Hans Linus",male,16,0,0,347074,7.775,,S +766,1,1,"Hogeboom, Mrs. John C (Anna Andrews)",female,51,1,0,13502,77.9583,D11,S +767,0,1,"Brewe, Dr. Arthur Jackson",male,,0,0,112379,39.6,,C +768,0,3,"Mangan, Miss. Mary",female,30.5,0,0,364850,7.75,,Q +769,0,3,"Moran, Mr. Daniel J",male,,1,0,371110,24.15,,Q +770,0,3,"Gronnestad, Mr. Daniel Danielsen",male,32,0,0,8471,8.3625,,S +771,0,3,"Lievens, Mr. Rene Aime",male,24,0,0,345781,9.5,,S +772,0,3,"Jensen, Mr. Niels Peder",male,48,0,0,350047,7.8542,,S +773,0,2,"Mack, Mrs. (Mary)",female,57,0,0,S.O./P.P. 3,10.5,E77,S +774,0,3,"Elias, Mr. Dibo",male,,0,0,2674,7.225,,C +775,1,2,"Hocking, Mrs. Elizabeth (Eliza Needs)",female,54,1,3,29105,23,,S +776,0,3,"Myhrman, Mr. Pehr Fabian Oliver Malkolm",male,18,0,0,347078,7.75,,S +777,0,3,"Tobin, Mr. Roger",male,,0,0,383121,7.75,F38,Q +778,1,3,"Emanuel, Miss. Virginia Ethel",female,5,0,0,364516,12.475,,S +779,0,3,"Kilgannon, Mr. Thomas J",male,,0,0,36865,7.7375,,Q +780,1,1,"Robert, Mrs. Edward Scott (Elisabeth Walton McMillan)",female,43,0,1,24160,211.3375,B3,S +781,1,3,"Ayoub, Miss. Banoura",female,13,0,0,2687,7.2292,,C +782,1,1,"Dick, Mrs. Albert Adrian (Vera Gillespie)",female,17,1,0,17474,57,B20,S +783,0,1,"Long, Mr. Milton Clyde",male,29,0,0,113501,30,D6,S +784,0,3,"Johnston, Mr. Andrew G",male,,1,2,W./C. 6607,23.45,,S +785,0,3,"Ali, Mr. William",male,25,0,0,SOTON/O.Q. 3101312,7.05,,S +786,0,3,"Harmer, Mr. Abraham (David Lishin)",male,25,0,0,374887,7.25,,S +787,1,3,"Sjoblom, Miss. Anna Sofia",female,18,0,0,3101265,7.4958,,S +788,0,3,"Rice, Master. George Hugh",male,8,4,1,382652,29.125,,Q +789,1,3,"Dean, Master. Bertram Vere",male,1,1,2,C.A. 2315,20.575,,S +790,0,1,"Guggenheim, Mr. Benjamin",male,46,0,0,PC 17593,79.2,B82 B84,C +791,0,3,"Keane, Mr. Andrew ""Andy""",male,,0,0,12460,7.75,,Q +792,0,2,"Gaskell, Mr. Alfred",male,16,0,0,239865,26,,S +793,0,3,"Sage, Miss. Stella Anna",female,,8,2,CA. 2343,69.55,,S +794,0,1,"Hoyt, Mr. William Fisher",male,,0,0,PC 17600,30.6958,,C +795,0,3,"Dantcheff, Mr. Ristiu",male,25,0,0,349203,7.8958,,S +796,0,2,"Otter, Mr. Richard",male,39,0,0,28213,13,,S +797,1,1,"Leader, Dr. Alice (Farnham)",female,49,0,0,17465,25.9292,D17,S +798,1,3,"Osman, Mrs. Mara",female,31,0,0,349244,8.6833,,S +799,0,3,"Ibrahim Shawah, Mr. Yousseff",male,30,0,0,2685,7.2292,,C +800,0,3,"Van Impe, Mrs. Jean Baptiste (Rosalie Paula Govaert)",female,30,1,1,345773,24.15,,S +801,0,2,"Ponesell, Mr. Martin",male,34,0,0,250647,13,,S +802,1,2,"Collyer, Mrs. Harvey (Charlotte Annie Tate)",female,31,1,1,C.A. 31921,26.25,,S +803,1,1,"Carter, Master. William Thornton II",male,11,1,2,113760,120,B96 B98,S +804,1,3,"Thomas, Master. Assad Alexander",male,0.42,0,1,2625,8.5167,,C +805,1,3,"Hedman, Mr. Oskar Arvid",male,27,0,0,347089,6.975,,S +806,0,3,"Johansson, Mr. Karl Johan",male,31,0,0,347063,7.775,,S +807,0,1,"Andrews, Mr. Thomas Jr",male,39,0,0,112050,0,A36,S +808,0,3,"Pettersson, Miss. Ellen Natalia",female,18,0,0,347087,7.775,,S +809,0,2,"Meyer, Mr. August",male,39,0,0,248723,13,,S +810,1,1,"Chambers, Mrs. Norman Campbell (Bertha Griggs)",female,33,1,0,113806,53.1,E8,S +811,0,3,"Alexander, Mr. William",male,26,0,0,3474,7.8875,,S +812,0,3,"Lester, Mr. James",male,39,0,0,A/4 48871,24.15,,S +813,0,2,"Slemen, Mr. Richard James",male,35,0,0,28206,10.5,,S +814,0,3,"Andersson, Miss. Ebba Iris Alfrida",female,6,4,2,347082,31.275,,S +815,0,3,"Tomlin, Mr. Ernest Portage",male,30.5,0,0,364499,8.05,,S +816,0,1,"Fry, Mr. Richard",male,,0,0,112058,0,B102,S +817,0,3,"Heininen, Miss. Wendla Maria",female,23,0,0,STON/O2. 3101290,7.925,,S +818,0,2,"Mallet, Mr. Albert",male,31,1,1,S.C./PARIS 2079,37.0042,,C +819,0,3,"Holm, Mr. John Fredrik Alexander",male,43,0,0,C 7075,6.45,,S +820,0,3,"Skoog, Master. Karl Thorsten",male,10,3,2,347088,27.9,,S +821,1,1,"Hays, Mrs. Charles Melville (Clara Jennings Gregg)",female,52,1,1,12749,93.5,B69,S +822,1,3,"Lulic, Mr. Nikola",male,27,0,0,315098,8.6625,,S +823,0,1,"Reuchlin, Jonkheer. John George",male,38,0,0,19972,0,,S +824,1,3,"Moor, Mrs. (Beila)",female,27,0,1,392096,12.475,E121,S +825,0,3,"Panula, Master. Urho Abraham",male,2,4,1,3101295,39.6875,,S +826,0,3,"Flynn, Mr. John",male,,0,0,368323,6.95,,Q +827,0,3,"Lam, Mr. Len",male,,0,0,1601,56.4958,,S +828,1,2,"Mallet, Master. Andre",male,1,0,2,S.C./PARIS 2079,37.0042,,C +829,1,3,"McCormack, Mr. Thomas Joseph",male,,0,0,367228,7.75,,Q +830,1,1,"Stone, Mrs. George Nelson (Martha Evelyn)",female,62,0,0,113572,80,B28, +831,1,3,"Yasbeck, Mrs. Antoni (Selini Alexander)",female,15,1,0,2659,14.4542,,C +832,1,2,"Richards, Master. George Sibley",male,0.83,1,1,29106,18.75,,S +833,0,3,"Saad, Mr. Amin",male,,0,0,2671,7.2292,,C +834,0,3,"Augustsson, Mr. Albert",male,23,0,0,347468,7.8542,,S +835,0,3,"Allum, Mr. Owen George",male,18,0,0,2223,8.3,,S +836,1,1,"Compton, Miss. Sara Rebecca",female,39,1,1,PC 17756,83.1583,E49,C +837,0,3,"Pasic, Mr. Jakob",male,21,0,0,315097,8.6625,,S +838,0,3,"Sirota, Mr. Maurice",male,,0,0,392092,8.05,,S +839,1,3,"Chip, Mr. Chang",male,32,0,0,1601,56.4958,,S +840,1,1,"Marechal, Mr. Pierre",male,,0,0,11774,29.7,C47,C +841,0,3,"Alhomaki, Mr. Ilmari Rudolf",male,20,0,0,SOTON/O2 3101287,7.925,,S +842,0,2,"Mudd, Mr. Thomas Charles",male,16,0,0,S.O./P.P. 3,10.5,,S +843,1,1,"Serepeca, Miss. Augusta",female,30,0,0,113798,31,,C +844,0,3,"Lemberopolous, Mr. Peter L",male,34.5,0,0,2683,6.4375,,C +845,0,3,"Culumovic, Mr. Jeso",male,17,0,0,315090,8.6625,,S +846,0,3,"Abbing, Mr. Anthony",male,42,0,0,C.A. 5547,7.55,,S +847,0,3,"Sage, Mr. Douglas Bullen",male,,8,2,CA. 2343,69.55,,S +848,0,3,"Markoff, Mr. Marin",male,35,0,0,349213,7.8958,,C +849,0,2,"Harper, Rev. John",male,28,0,1,248727,33,,S +850,1,1,"Goldenberg, Mrs. Samuel L (Edwiga Grabowska)",female,,1,0,17453,89.1042,C92,C +851,0,3,"Andersson, Master. Sigvard Harald Elias",male,4,4,2,347082,31.275,,S +852,0,3,"Svensson, Mr. Johan",male,74,0,0,347060,7.775,,S +853,0,3,"Boulos, Miss. Nourelain",female,9,1,1,2678,15.2458,,C +854,1,1,"Lines, Miss. Mary Conover",female,16,0,1,PC 17592,39.4,D28,S +855,0,2,"Carter, Mrs. Ernest Courtenay (Lilian Hughes)",female,44,1,0,244252,26,,S +856,1,3,"Aks, Mrs. Sam (Leah Rosen)",female,18,0,1,392091,9.35,,S +857,1,1,"Wick, Mrs. George Dennick (Mary Hitchcock)",female,45,1,1,36928,164.8667,,S +858,1,1,"Daly, Mr. Peter Denis ",male,51,0,0,113055,26.55,E17,S +859,1,3,"Baclini, Mrs. Solomon (Latifa Qurban)",female,24,0,3,2666,19.2583,,C +860,0,3,"Razi, Mr. Raihed",male,,0,0,2629,7.2292,,C +861,0,3,"Hansen, Mr. Claus Peter",male,41,2,0,350026,14.1083,,S +862,0,2,"Giles, Mr. Frederick Edward",male,21,1,0,28134,11.5,,S +863,1,1,"Swift, Mrs. Frederick Joel (Margaret Welles Barron)",female,48,0,0,17466,25.9292,D17,S +864,0,3,"Sage, Miss. Dorothy Edith ""Dolly""",female,,8,2,CA. 2343,69.55,,S +865,0,2,"Gill, Mr. John William",male,24,0,0,233866,13,,S +866,1,2,"Bystrom, Mrs. (Karolina)",female,42,0,0,236852,13,,S +867,1,2,"Duran y More, Miss. Asuncion",female,27,1,0,SC/PARIS 2149,13.8583,,C +868,0,1,"Roebling, Mr. Washington Augustus II",male,31,0,0,PC 17590,50.4958,A24,S +869,0,3,"van Melkebeke, Mr. Philemon",male,,0,0,345777,9.5,,S +870,1,3,"Johnson, Master. Harold Theodor",male,4,1,1,347742,11.1333,,S +871,0,3,"Balkic, Mr. Cerin",male,26,0,0,349248,7.8958,,S +872,1,1,"Beckwith, Mrs. Richard Leonard (Sallie Monypeny)",female,47,1,1,11751,52.5542,D35,S +873,0,1,"Carlsson, Mr. Frans Olof",male,33,0,0,695,5,B51 B53 B55,S +874,0,3,"Vander Cruyssen, Mr. Victor",male,47,0,0,345765,9,,S +875,1,2,"Abelson, Mrs. Samuel (Hannah Wizosky)",female,28,1,0,P/PP 3381,24,,C +876,1,3,"Najib, Miss. Adele Kiamie ""Jane""",female,15,0,0,2667,7.225,,C +877,0,3,"Gustafsson, Mr. Alfred Ossian",male,20,0,0,7534,9.8458,,S +878,0,3,"Petroff, Mr. Nedelio",male,19,0,0,349212,7.8958,,S +879,0,3,"Laleff, Mr. Kristo",male,,0,0,349217,7.8958,,S +880,1,1,"Potter, Mrs. Thomas Jr (Lily Alexenia Wilson)",female,56,0,1,11767,83.1583,C50,C +881,1,2,"Shelley, Mrs. William (Imanita Parrish Hall)",female,25,0,1,230433,26,,S +882,0,3,"Markun, Mr. Johann",male,33,0,0,349257,7.8958,,S +883,0,3,"Dahlberg, Miss. Gerda Ulrika",female,22,0,0,7552,10.5167,,S +884,0,2,"Banfield, Mr. Frederick James",male,28,0,0,C.A./SOTON 34068,10.5,,S +885,0,3,"Sutehall, Mr. Henry Jr",male,25,0,0,SOTON/OQ 392076,7.05,,S +886,0,3,"Rice, Mrs. William (Margaret Norton)",female,39,0,5,382652,29.125,,Q +887,0,2,"Montvila, Rev. Juozas",male,27,0,0,211536,13,,S +888,1,1,"Graham, Miss. Margaret Edith",female,19,0,0,112053,30,B42,S +889,0,3,"Johnston, Miss. Catherine Helen ""Carrie""",female,,1,2,W./C. 6607,23.45,,S +890,1,1,"Behr, Mr. Karl Howell",male,26,0,0,111369,30,C148,C +891,0,3,"Dooley, Mr. Patrick",male,32,0,0,370376,7.75,,Q diff --git a/SAMPLE_DATA/y77d-th95.json b/SAMPLE_DATA/y77d-th95.json new file mode 100644 index 0000000..1638f49 --- /dev/null +++ b/SAMPLE_DATA/y77d-th95.json @@ -0,0 +1,1000 @@ +[{"name":"Aachen","id":"1","nametype":"Valid","recclass":"L5","mass":"21","fall":"Fell","year":"1880-01-01T00:00:00.000","reclat":"50.775000","reclong":"6.083330","geolocation":{"type":"Point","coordinates":[6.08333,50.775]}} +,{"name":"Aarhus","id":"2","nametype":"Valid","recclass":"H6","mass":"720","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"56.183330","reclong":"10.233330","geolocation":{"type":"Point","coordinates":[10.23333,56.18333]}} +,{"name":"Abee","id":"6","nametype":"Valid","recclass":"EH4","mass":"107000","fall":"Fell","year":"1952-01-01T00:00:00.000","reclat":"54.216670","reclong":"-113.000000","geolocation":{"type":"Point","coordinates":[-113,54.21667]}} +,{"name":"Acapulco","id":"10","nametype":"Valid","recclass":"Acapulcoite","mass":"1914","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"16.883330","reclong":"-99.900000","geolocation":{"type":"Point","coordinates":[-99.9,16.88333]}} +,{"name":"Achiras","id":"370","nametype":"Valid","recclass":"L6","mass":"780","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"-33.166670","reclong":"-64.950000","geolocation":{"type":"Point","coordinates":[-64.95,-33.16667]}} +,{"name":"Adhi Kot","id":"379","nametype":"Valid","recclass":"EH4","mass":"4239","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"32.100000","reclong":"71.800000","geolocation":{"type":"Point","coordinates":[71.8,32.1]}} +,{"name":"Adzhi-Bogdo (stone)","id":"390","nametype":"Valid","recclass":"LL3-6","mass":"910","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"44.833330","reclong":"95.166670","geolocation":{"type":"Point","coordinates":[95.16667,44.83333]}} +,{"name":"Agen","id":"392","nametype":"Valid","recclass":"H5","mass":"30000","fall":"Fell","year":"1814-01-01T00:00:00.000","reclat":"44.216670","reclong":"0.616670","geolocation":{"type":"Point","coordinates":[0.61667,44.21667]}} +,{"name":"Aguada","id":"398","nametype":"Valid","recclass":"L6","mass":"1620","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"-31.600000","reclong":"-65.233330","geolocation":{"type":"Point","coordinates":[-65.23333,-31.6]}} +,{"name":"Aguila Blanca","id":"417","nametype":"Valid","recclass":"L","mass":"1440","fall":"Fell","year":"1920-01-01T00:00:00.000","reclat":"-30.866670","reclong":"-64.550000","geolocation":{"type":"Point","coordinates":[-64.55,-30.86667]}} +,{"name":"Aioun el Atrouss","id":"423","nametype":"Valid","recclass":"Diogenite-pm","mass":"1000","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"16.398060","reclong":"-9.570280","geolocation":{"type":"Point","coordinates":[-9.57028,16.39806]}} +,{"name":"Aïr","id":"424","nametype":"Valid","recclass":"L6","mass":"24000","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"19.083330","reclong":"8.383330","geolocation":{"type":"Point","coordinates":[8.38333,19.08333]}} +,{"name":"Aire-sur-la-Lys","id":"425","nametype":"Valid","recclass":"Unknown","fall":"Fell","year":"1769-01-01T00:00:00.000","reclat":"50.666670","reclong":"2.333330","geolocation":{"type":"Point","coordinates":[2.33333,50.66667]}} +,{"name":"Akaba","id":"426","nametype":"Valid","recclass":"L6","mass":"779","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"29.516670","reclong":"35.050000","geolocation":{"type":"Point","coordinates":[35.05,29.51667]}} +,{"name":"Akbarpur","id":"427","nametype":"Valid","recclass":"H4","mass":"1800","fall":"Fell","year":"1838-01-01T00:00:00.000","reclat":"29.716670","reclong":"77.950000","geolocation":{"type":"Point","coordinates":[77.95,29.71667]}} +,{"name":"Akwanga","id":"432","nametype":"Valid","recclass":"H","mass":"3000","fall":"Fell","year":"1959-01-01T00:00:00.000","reclat":"8.916670","reclong":"8.433330","geolocation":{"type":"Point","coordinates":[8.43333,8.91667]}} +,{"name":"Akyumak","id":"433","nametype":"Valid","recclass":"Iron, IVA","mass":"50000","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"39.916670","reclong":"42.816670","geolocation":{"type":"Point","coordinates":[42.81667,39.91667]}} +,{"name":"Al Rais","id":"446","nametype":"Valid","recclass":"CR2-an","mass":"160","fall":"Fell","year":"1957-01-01T00:00:00.000","reclat":"24.416670","reclong":"39.516670","geolocation":{"type":"Point","coordinates":[39.51667,24.41667]}} +,{"name":"Al Zarnkh","id":"447","nametype":"Valid","recclass":"LL5","mass":"700","fall":"Fell","year":"2001-01-01T00:00:00.000","reclat":"13.660330","reclong":"28.960000","geolocation":{"type":"Point","coordinates":[28.96,13.66033]}} +,{"name":"Alais","id":"448","nametype":"Valid","recclass":"CI1","mass":"6000","fall":"Fell","year":"1806-01-01T00:00:00.000","reclat":"44.116670","reclong":"4.083330","geolocation":{"type":"Point","coordinates":[4.08333,44.11667]}} +,{"name":"Albareto","id":"453","nametype":"Valid","recclass":"L/LL4","mass":"2000","fall":"Fell","year":"1766-01-01T00:00:00.000","reclat":"44.650000","reclong":"11.016670","geolocation":{"type":"Point","coordinates":[11.01667,44.65]}} +,{"name":"Alberta","id":"454","nametype":"Valid","recclass":"L","mass":"625","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"2.000000","reclong":"22.666670","geolocation":{"type":"Point","coordinates":[22.66667,2]}} +,{"name":"Alby sur Chéran","id":"458","nametype":"Valid","recclass":"Eucrite-mmict","mass":"252","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"45.821330","reclong":"6.015330","geolocation":{"type":"Point","coordinates":[6.01533,45.82133]}} +,{"name":"Aldsworth","id":"461","nametype":"Valid","recclass":"LL5","mass":"700","fall":"Fell","year":"1835-01-01T00:00:00.000","reclat":"51.783330","reclong":"-1.783330","geolocation":{"type":"Point","coordinates":[-1.78333,51.78333]}} +,{"name":"Aleppo","id":"462","nametype":"Valid","recclass":"L6","mass":"3200","fall":"Fell","year":"1873-01-01T00:00:00.000","reclat":"36.233330","reclong":"37.133330","geolocation":{"type":"Point","coordinates":[37.13333,36.23333]}} +,{"name":"Alessandria","id":"463","nametype":"Valid","recclass":"H5","mass":"908","fall":"Fell","year":"1860-01-01T00:00:00.000","reclat":"44.883330","reclong":"8.750000","geolocation":{"type":"Point","coordinates":[8.75,44.88333]}} +,{"name":"Alexandrovsky","id":"465","nametype":"Valid","recclass":"H4","mass":"9251","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"50.950000","reclong":"31.816670","geolocation":{"type":"Point","coordinates":[31.81667,50.95]}} +,{"name":"Alfianello","id":"466","nametype":"Valid","recclass":"L6","mass":"228000","fall":"Fell","year":"1883-01-01T00:00:00.000","reclat":"45.266670","reclong":"10.150000","geolocation":{"type":"Point","coordinates":[10.15,45.26667]}} +,{"name":"Allegan","id":"2276","nametype":"Valid","recclass":"H5","mass":"32000","fall":"Fell","year":"1899-01-01T00:00:00.000","reclat":"42.533330","reclong":"-85.883330","geolocation":{"type":"Point","coordinates":[-85.88333,42.53333]},":@computed_region_cbhk_fwbd":"50",":@computed_region_nnqa_25f4":"429"} +,{"name":"Allende","id":"2278","nametype":"Valid","recclass":"CV3","mass":"2000000","fall":"Fell","year":"1969-01-01T00:00:00.000","reclat":"26.966670","reclong":"-105.316670","geolocation":{"type":"Point","coordinates":[-105.31667,26.96667]}} +,{"name":"Almahata Sitta","id":"48915","nametype":"Valid","recclass":"Ureilite-an","mass":"3950","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"20.745750","reclong":"32.412750","geolocation":{"type":"Point","coordinates":[32.41275,20.74575]}} +,{"name":"Alta'ameem","id":"2284","nametype":"Valid","recclass":"LL5","mass":"6000","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"35.273330","reclong":"44.215560","geolocation":{"type":"Point","coordinates":[44.21556,35.27333]}} +,{"name":"Ambapur Nagla","id":"2290","nametype":"Valid","recclass":"H5","mass":"6400","fall":"Fell","year":"1895-01-01T00:00:00.000","reclat":"27.666670","reclong":"78.250000","geolocation":{"type":"Point","coordinates":[78.25,27.66667]}} +,{"name":"Andhara","id":"2294","nametype":"Valid","recclass":"Stone-uncl","mass":"2700","fall":"Fell","year":"1880-01-01T00:00:00.000","reclat":"26.583330","reclong":"85.566670","geolocation":{"type":"Point","coordinates":[85.56667,26.58333]}} +,{"name":"Andover","id":"2295","nametype":"Valid","recclass":"L6","mass":"3200","fall":"Fell","year":"1898-01-01T00:00:00.000","reclat":"44.616670","reclong":"-70.750000","geolocation":{"type":"Point","coordinates":[-70.75,44.61667]},":@computed_region_cbhk_fwbd":"49",":@computed_region_nnqa_25f4":"1723"} +,{"name":"Andreevka","id":"2296","nametype":"Valid","recclass":"L3","mass":"600","fall":"Fell","year":"1969-01-01T00:00:00.000","reclat":"48.700000","reclong":"37.500000","geolocation":{"type":"Point","coordinates":[37.5,48.7]}} +,{"name":"Andura","id":"2298","nametype":"Valid","recclass":"H6","mass":"17900","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"20.883330","reclong":"76.866670","geolocation":{"type":"Point","coordinates":[76.86667,20.88333]}} +,{"name":"Northwest Africa 5815","id":"50693","nametype":"Valid","recclass":"L5","mass":"256.8","fall":"Found","reclat":"0.000000","reclong":"0.000000","geolocation":{"type":"Point","coordinates":[0,0]}} +,{"name":"Angers","id":"2301","nametype":"Valid","recclass":"L6","fall":"Fell","year":"1822-01-01T00:00:00.000","reclat":"47.466670","reclong":"-0.550000","geolocation":{"type":"Point","coordinates":[-0.55,47.46667]}} +,{"name":"Angra dos Reis (stone)","id":"2302","nametype":"Valid","recclass":"Angrite","mass":"1500","fall":"Fell","year":"1869-01-01T00:00:00.000","reclat":"-22.966670","reclong":"-44.316670","geolocation":{"type":"Point","coordinates":[-44.31667,-22.96667]}} +,{"name":"Ankober","id":"2304","nametype":"Valid","recclass":"H4","mass":"6500","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"9.533330","reclong":"39.716670","geolocation":{"type":"Point","coordinates":[39.71667,9.53333]}} +,{"name":"Anlong","id":"2305","nametype":"Valid","recclass":"H5","mass":"2500","fall":"Fell","year":"1971-01-01T00:00:00.000","reclat":"25.150000","reclong":"105.183330","geolocation":{"type":"Point","coordinates":[105.18333,25.15]}} +,{"name":"Aomori","id":"2313","nametype":"Valid","recclass":"L6","mass":"320","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"40.810560","reclong":"140.785560","geolocation":{"type":"Point","coordinates":[140.78556,40.81056]}} +,{"name":"Appley Bridge","id":"2318","nametype":"Valid","recclass":"LL6","mass":"15000","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"53.583330","reclong":"-2.716670","geolocation":{"type":"Point","coordinates":[-2.71667,53.58333]}} +,{"name":"Apt","id":"2320","nametype":"Valid","recclass":"L6","mass":"3200","fall":"Fell","year":"1803-01-01T00:00:00.000","reclat":"43.866670","reclong":"5.383330","geolocation":{"type":"Point","coordinates":[5.38333,43.86667]}} +,{"name":"Arbol Solo","id":"2325","nametype":"Valid","recclass":"H5","mass":"810","fall":"Fell","year":"1954-01-01T00:00:00.000","reclat":"-33.000000","reclong":"-66.000000","geolocation":{"type":"Point","coordinates":[-66,-33]}} +,{"name":"Archie","id":"2329","nametype":"Valid","recclass":"H6","mass":"5070","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"38.500000","reclong":"-94.300000","geolocation":{"type":"Point","coordinates":[-94.3,38.5]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"2697"} +,{"name":"Arroyo Aguiar","id":"2340","nametype":"Valid","recclass":"H5","mass":"7450","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"-31.416670","reclong":"-60.666670","geolocation":{"type":"Point","coordinates":[-60.66667,-31.41667]}} +,{"name":"Asco","id":"2345","nametype":"Valid","recclass":"H6","mass":"41","fall":"Fell","year":"1805-01-01T00:00:00.000","reclat":"42.450000","reclong":"9.033330","geolocation":{"type":"Point","coordinates":[9.03333,42.45]}} +,{"name":"Ash Creek","id":"48954","nametype":"Valid","recclass":"L6","mass":"9500","fall":"Fell","year":"2009-01-01T00:00:00.000","reclat":"31.805000","reclong":"-97.010000","geolocation":{"type":"Point","coordinates":[-97.01,31.805]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"774"} +,{"name":"Ashdon","id":"2346","nametype":"Valid","recclass":"L6","mass":"1300","fall":"Fell","year":"1923-01-01T00:00:00.000","reclat":"52.050000","reclong":"0.300000","geolocation":{"type":"Point","coordinates":[0.3,52.05]}} +,{"name":"Assisi","id":"2353","nametype":"Valid","recclass":"H5","mass":"2000","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"43.033330","reclong":"12.550000","geolocation":{"type":"Point","coordinates":[12.55,43.03333]}} +,{"name":"Atarra","id":"4883","nametype":"Valid","recclass":"L4","mass":"1280","fall":"Fell","year":"1920-01-01T00:00:00.000","reclat":"25.254170","reclong":"80.625000","geolocation":{"type":"Point","coordinates":[80.625,25.25417]}} +,{"name":"Atemajac","id":"4884","nametype":"Valid","recclass":"L6","mass":"94.2","fall":"Fell","year":"1896-01-01T00:00:00.000","reclat":"20.066670","reclong":"-103.666670","geolocation":{"type":"Point","coordinates":[-103.66667,20.06667]}} +,{"name":"Athens","id":"4885","nametype":"Valid","recclass":"LL6","mass":"265","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"34.750000","reclong":"-87.000000","geolocation":{"type":"Point","coordinates":[-87,34.75]},":@computed_region_cbhk_fwbd":"29",":@computed_region_nnqa_25f4":"3134"} +,{"name":"Atoka","id":"4888","nametype":"Valid","recclass":"L6","mass":"1384.2","fall":"Fell","year":"1945-01-01T00:00:00.000","reclat":"34.316670","reclong":"-96.150000","geolocation":{"type":"Point","coordinates":[-96.15,34.31667]},":@computed_region_cbhk_fwbd":"20",":@computed_region_nnqa_25f4":"602"} +,{"name":"Aubres","id":"4893","nametype":"Valid","recclass":"Aubrite","mass":"800","fall":"Fell","year":"1836-01-01T00:00:00.000","reclat":"44.383330","reclong":"5.166670","geolocation":{"type":"Point","coordinates":[5.16667,44.38333]}} +,{"name":"Aumale","id":"4899","nametype":"Valid","recclass":"L6","mass":"50000","fall":"Fell","year":"1865-01-01T00:00:00.000","reclat":"36.166670","reclong":"3.666670","geolocation":{"type":"Point","coordinates":[3.66667,36.16667]}} +,{"name":"Aumieres","id":"4900","nametype":"Valid","recclass":"L6","mass":"2000","fall":"Fell","year":"1842-01-01T00:00:00.000","reclat":"44.333330","reclong":"3.233330","geolocation":{"type":"Point","coordinates":[3.23333,44.33333]}} +,{"name":"Ausson","id":"4903","nametype":"Valid","recclass":"L5","mass":"50000","fall":"Fell","year":"1858-01-01T00:00:00.000","reclat":"43.083330","reclong":"0.583330","geolocation":{"type":"Point","coordinates":[0.58333,43.08333]}} +,{"name":"Avanhandava","id":"4905","nametype":"Valid","recclass":"H4","mass":"9330","fall":"Fell","year":"1952-01-01T00:00:00.000","reclat":"-21.460280","reclong":"-49.950830","geolocation":{"type":"Point","coordinates":[-49.95083,-21.46028]}} +,{"name":"Avce","id":"4906","nametype":"Valid","recclass":"Iron, IIAB","mass":"1230","fall":"Fell","year":"1908-01-01T00:00:00.000","reclat":"46.000000","reclong":"13.500000","geolocation":{"type":"Point","coordinates":[13.5,46]}} +,{"name":"Avilez","id":"4907","nametype":"Valid","recclass":"H","mass":"146","fall":"Fell","year":"1855-01-01T00:00:00.000","reclat":"25.000000","reclong":"-103.500000","geolocation":{"type":"Point","coordinates":[-103.5,25]}} +,{"name":"Awere","id":"4910","nametype":"Valid","recclass":"L4","mass":"134","fall":"Fell","year":"1968-01-01T00:00:00.000","reclat":"2.716670","reclong":"32.833330","geolocation":{"type":"Point","coordinates":[32.83333,2.71667]}} +,{"name":"Aztec","id":"4913","nametype":"Valid","recclass":"L6","mass":"2830","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"36.800000","reclong":"-108.000000","geolocation":{"type":"Point","coordinates":[-108,36.8]},":@computed_region_cbhk_fwbd":"11",":@computed_region_nnqa_25f4":"1989"} +,{"name":"Bachmut","id":"4917","nametype":"Valid","recclass":"L6","mass":"18000","fall":"Fell","year":"1814-01-01T00:00:00.000","reclat":"48.600000","reclong":"38.000000","geolocation":{"type":"Point","coordinates":[38,48.6]}} +,{"name":"Bahjoi","id":"4922","nametype":"Valid","recclass":"Iron, IAB-sLL","mass":"10322","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"28.483330","reclong":"78.500000","geolocation":{"type":"Point","coordinates":[78.5,28.48333]}} +,{"name":"Bald Mountain","id":"4925","nametype":"Valid","recclass":"L4","mass":"3700","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"35.966670","reclong":"-82.483330","geolocation":{"type":"Point","coordinates":[-82.48333,35.96667]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"2373"} +,{"name":"Baldwyn","id":"4926","nametype":"Valid","recclass":"L6","mass":"345","fall":"Fell","year":"1922-01-01T00:00:00.000","reclat":"34.500000","reclong":"-88.666670","geolocation":{"type":"Point","coordinates":[-88.66667,34.5]},":@computed_region_cbhk_fwbd":"32",":@computed_region_nnqa_25f4":"495"} +,{"name":"Bali","id":"4928","nametype":"Valid","recclass":"CV3","mass":"1000","fall":"Fell","year":"1907-01-01T00:00:00.000","reclat":"5.383330","reclong":"16.383330","geolocation":{"type":"Point","coordinates":[16.38333,5.38333]}} +,{"name":"Ban Rong Du","id":"4934","nametype":"Valid","recclass":"Iron, ungrouped","mass":"16700","fall":"Fell","year":"1993-01-01T00:00:00.000","reclat":"16.666670","reclong":"101.183330","geolocation":{"type":"Point","coordinates":[101.18333,16.66667]}} +,{"name":"Bandong","id":"4935","nametype":"Valid","recclass":"LL6","mass":"11500","fall":"Fell","year":"1871-01-01T00:00:00.000","reclat":"-6.916670","reclong":"107.600000","geolocation":{"type":"Point","coordinates":[107.6,-6.91667]}} +,{"name":"Bansur","id":"4936","nametype":"Valid","recclass":"L6","mass":"15000","fall":"Fell","year":"1892-01-01T00:00:00.000","reclat":"27.700000","reclong":"76.333330","geolocation":{"type":"Point","coordinates":[76.33333,27.7]}} +,{"name":"Banswal","id":"4937","nametype":"Valid","recclass":"L5","mass":"14","fall":"Fell","year":"1913-01-01T00:00:00.000","reclat":"30.400000","reclong":"78.200000","geolocation":{"type":"Point","coordinates":[78.2,30.4]}} +,{"name":"Banten","id":"4938","nametype":"Valid","recclass":"CM2","mass":"629","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"-6.333330","reclong":"106.000000","geolocation":{"type":"Point","coordinates":[106,-6.33333]}} +,{"name":"Barbotan","id":"4942","nametype":"Valid","recclass":"H5","mass":"6400","fall":"Fell","year":"1790-01-01T00:00:00.000","reclat":"43.950000","reclong":"-0.050000","geolocation":{"type":"Point","coordinates":[-0.05,43.95]}} +,{"name":"Barcelona (stone)","id":"4944","nametype":"Valid","recclass":"OC","fall":"Fell","year":"1704-01-01T00:00:00.000","reclat":"41.366670","reclong":"2.166670","geolocation":{"type":"Point","coordinates":[2.16667,41.36667]}} +,{"name":"Barea","id":"4946","nametype":"Valid","recclass":"Mesosiderite-A1","mass":"3200","fall":"Fell","year":"1842-01-01T00:00:00.000","reclat":"42.383330","reclong":"-2.500000","geolocation":{"type":"Point","coordinates":[-2.5,42.38333]}} +,{"name":"Barnaul","id":"4947","nametype":"Valid","recclass":"H5","mass":"23.2","fall":"Fell","year":"1904-01-01T00:00:00.000","reclat":"52.733330","reclong":"84.083330","geolocation":{"type":"Point","coordinates":[84.08333,52.73333]}} +,{"name":"Barntrup","id":"4948","nametype":"Valid","recclass":"LL4","mass":"17","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"52.000000","reclong":"9.100000","geolocation":{"type":"Point","coordinates":[9.1,52]}} +,{"name":"Baroti","id":"4949","nametype":"Valid","recclass":"L6","mass":"4500","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"31.616670","reclong":"76.800000","geolocation":{"type":"Point","coordinates":[76.8,31.61667]}} +,{"name":"Barwell","id":"4954","nametype":"Valid","recclass":"L5","mass":"44000","fall":"Fell","year":"1965-01-01T00:00:00.000","reclat":"52.565280","reclong":"-1.339720","geolocation":{"type":"Point","coordinates":[-1.33972,52.56528]}} +,{"name":"Bassikounou","id":"44876","nametype":"Valid","recclass":"H5","mass":"29560","fall":"Fell","year":"2006-01-01T00:00:00.000","reclat":"15.783330","reclong":"-5.900000","geolocation":{"type":"Point","coordinates":[-5.9,15.78333]}} +,{"name":"Baszkówka","id":"4957","nametype":"Valid","recclass":"L5","mass":"15500","fall":"Fell","year":"1994-01-01T00:00:00.000","reclat":"52.033330","reclong":"20.935830","geolocation":{"type":"Point","coordinates":[20.93583,52.03333]}} +,{"name":"Bath","id":"4974","nametype":"Valid","recclass":"H4","mass":"21000","fall":"Fell","year":"1892-01-01T00:00:00.000","reclat":"45.416670","reclong":"-98.316670","geolocation":{"type":"Point","coordinates":[-98.31667,45.41667]},":@computed_region_cbhk_fwbd":"21",":@computed_region_nnqa_25f4":"662"} +,{"name":"Bath Furnace","id":"4975","nametype":"Valid","recclass":"L6","mass":"86000","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"38.250000","reclong":"-83.750000","geolocation":{"type":"Point","coordinates":[-83.75,38.25]},":@computed_region_cbhk_fwbd":"36",":@computed_region_nnqa_25f4":"1921"} +,{"name":"Battle Mountain","id":"56133","nametype":"Valid","recclass":"L6","mass":"2900","fall":"Fell","year":"2012-01-01T00:00:00.000","reclat":"40.668130","reclong":"-117.189130","geolocation":{"type":"Point","coordinates":[-117.18913,40.66813]},":@computed_region_cbhk_fwbd":"10",":@computed_region_nnqa_25f4":"2397"} +,{"name":"Bawku","id":"4976","nametype":"Valid","recclass":"LL5","mass":"1557","fall":"Fell","year":"1989-01-01T00:00:00.000","reclat":"11.083330","reclong":"-0.183330","geolocation":{"type":"Point","coordinates":[-0.18333,11.08333]}} +,{"name":"Baxter","id":"4977","nametype":"Valid","recclass":"L6","mass":"611","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"36.750000","reclong":"-93.500000","geolocation":{"type":"Point","coordinates":[-93.5,36.75]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"2216"} +,{"name":"Beardsley","id":"4984","nametype":"Valid","recclass":"H5","mass":"16000","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"39.800000","reclong":"-101.200000","geolocation":{"type":"Point","coordinates":[-101.2,39.8]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1285"} +,{"name":"Beaver Creek","id":"4986","nametype":"Valid","recclass":"H5","mass":"14000","fall":"Fell","year":"1893-01-01T00:00:00.000","reclat":"51.166670","reclong":"-117.333330","geolocation":{"type":"Point","coordinates":[-117.33333,51.16667]}} +,{"name":"Beddgelert","id":"4993","nametype":"Valid","recclass":"H5","mass":"794","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"53.016670","reclong":"-4.100000","geolocation":{"type":"Point","coordinates":[-4.1,53.01667]}} +,{"name":"Bells","id":"5005","nametype":"Valid","recclass":"C2-ung","mass":"375","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"33.600000","reclong":"-96.466670","geolocation":{"type":"Point","coordinates":[-96.46667,33.6]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"1978"} +,{"name":"Belville","id":"5009","nametype":"Valid","recclass":"OC","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"-32.333330","reclong":"-64.866670","geolocation":{"type":"Point","coordinates":[-64.86667,-32.33333]}} +,{"name":"Benares (a)","id":"5011","nametype":"Valid","recclass":"LL4","mass":"3700","fall":"Fell","year":"1798-01-01T00:00:00.000","reclat":"25.366670","reclong":"82.916670","geolocation":{"type":"Point","coordinates":[82.91667,25.36667]}} +,{"name":"Benguerir","id":"30443","nametype":"Valid","recclass":"LL6","mass":"25000","fall":"Fell","year":"2004-01-01T00:00:00.000","reclat":"32.250000","reclong":"-8.150000","geolocation":{"type":"Point","coordinates":[-8.15,32.25]}} +,{"name":"Beni M'hira","id":"5018","nametype":"Valid","recclass":"L6","mass":"19000","fall":"Fell","year":"2001-01-01T00:00:00.000","reclat":"32.866670","reclong":"10.800000","geolocation":{"type":"Point","coordinates":[10.8,32.86667]}} +,{"name":"Benld","id":"5021","nametype":"Valid","recclass":"H6","mass":"1770.5","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"39.083330","reclong":"-89.150000","geolocation":{"type":"Point","coordinates":[-89.15,39.08333]},":@computed_region_cbhk_fwbd":"34",":@computed_region_nnqa_25f4":"1869"} +,{"name":"Benoni","id":"5023","nametype":"Valid","recclass":"H6","mass":"3880","fall":"Fell","year":"1943-01-01T00:00:00.000","reclat":"-26.166670","reclong":"28.416670","geolocation":{"type":"Point","coordinates":[28.41667,-26.16667]}} +,{"name":"Bensour","id":"5024","nametype":"Valid","recclass":"LL6","mass":"45000","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"30.000000","reclong":"-7.000000","geolocation":{"type":"Point","coordinates":[-7,30]}} +,{"name":"Benton","id":"5026","nametype":"Valid","recclass":"LL6","mass":"2840","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"45.950000","reclong":"-67.550000","geolocation":{"type":"Point","coordinates":[-67.55,45.95]}} +,{"name":"Berduc","id":"48975","nametype":"Valid","recclass":"L6","mass":"270","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"-31.910000","reclong":"-58.328330","geolocation":{"type":"Point","coordinates":[-58.32833,-31.91]}} +,{"name":"Béréba","id":"5028","nametype":"Valid","recclass":"Eucrite-mmict","mass":"18000","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"11.650000","reclong":"-3.650000","geolocation":{"type":"Point","coordinates":[-3.65,11.65]}} +,{"name":"Berlanguillas","id":"5029","nametype":"Valid","recclass":"L6","mass":"1440","fall":"Fell","year":"1811-01-01T00:00:00.000","reclat":"41.683330","reclong":"-3.800000","geolocation":{"type":"Point","coordinates":[-3.8,41.68333]}} +,{"name":"Berthoud","id":"47355","nametype":"Valid","recclass":"Eucrite-mmict","mass":"960","fall":"Fell","year":"2004-01-01T00:00:00.000","reclat":"40.305830","reclong":"-105.023250","geolocation":{"type":"Point","coordinates":[-105.02325,40.30583]},":@computed_region_cbhk_fwbd":"9",":@computed_region_nnqa_25f4":"1072"} +,{"name":"Bethlehem","id":"5032","nametype":"Valid","recclass":"H","mass":"13.9","fall":"Fell","year":"1859-01-01T00:00:00.000","reclat":"42.533330","reclong":"-73.833330","geolocation":{"type":"Point","coordinates":[-73.83333,42.53333]},":@computed_region_cbhk_fwbd":"47",":@computed_region_nnqa_25f4":"2030"} +,{"name":"Beuste","id":"5034","nametype":"Valid","recclass":"L5","mass":"2000","fall":"Fell","year":"1859-01-01T00:00:00.000","reclat":"43.216670","reclong":"-0.233330","geolocation":{"type":"Point","coordinates":[-0.23333,43.21667]}} +,{"name":"Beyrout","id":"5035","nametype":"Valid","recclass":"LL3.8","mass":"1100","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"33.883330","reclong":"35.500000","geolocation":{"type":"Point","coordinates":[35.5,33.88333]}} +,{"name":"Bhagur","id":"5037","nametype":"Valid","recclass":"L6","mass":"18","fall":"Fell","year":"1877-01-01T00:00:00.000","reclat":"20.883330","reclong":"74.833330","geolocation":{"type":"Point","coordinates":[74.83333,20.88333]}} +,{"name":"Bhawad","id":"36591","nametype":"Valid","recclass":"LL6","mass":"678","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"26.508330","reclong":"73.115280","geolocation":{"type":"Point","coordinates":[73.11528,26.50833]}} +,{"name":"Bherai","id":"5039","nametype":"Valid","recclass":"L6","mass":"100","fall":"Fell","year":"1893-01-01T00:00:00.000","reclat":"20.833330","reclong":"71.466670","geolocation":{"type":"Point","coordinates":[71.46667,20.83333]}} +,{"name":"Bhola","id":"5040","nametype":"Valid","recclass":"LL3-6","mass":"1047","fall":"Fell","year":"1940-01-01T00:00:00.000","reclat":"22.683330","reclong":"90.650000","geolocation":{"type":"Point","coordinates":[90.65,22.68333]}} +,{"name":"Bholghati","id":"5041","nametype":"Valid","recclass":"Howardite","mass":"2500","fall":"Fell","year":"1905-01-01T00:00:00.000","reclat":"22.083330","reclong":"86.900000","geolocation":{"type":"Point","coordinates":[86.9,22.08333]}} +,{"name":"Bialystok","id":"5042","nametype":"Valid","recclass":"Eucrite-pmict","mass":"4000","fall":"Fell","year":"1827-01-01T00:00:00.000","reclat":"53.100000","reclong":"23.200000","geolocation":{"type":"Point","coordinates":[23.2,53.1]}} +,{"name":"Bielokrynitschie","id":"5043","nametype":"Valid","recclass":"H4","mass":"1900","fall":"Fell","year":"1887-01-01T00:00:00.000","reclat":"50.133330","reclong":"27.166670","geolocation":{"type":"Point","coordinates":[27.16667,50.13333]}} +,{"name":"Bilanga","id":"5045","nametype":"Valid","recclass":"Diogenite","mass":"25000","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"12.450000","reclong":"-0.083330","geolocation":{"type":"Point","coordinates":[-0.08333,12.45]}} +,{"name":"Binningup","id":"5051","nametype":"Valid","recclass":"H5","mass":"488.1","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"-33.156390","reclong":"115.676390","geolocation":{"type":"Point","coordinates":[115.67639,-33.15639]}} +,{"name":"Birni N'konni","id":"5056","nametype":"Valid","recclass":"H4","mass":"560","fall":"Fell","year":"1923-01-01T00:00:00.000","reclat":"13.766670","reclong":"5.300000","geolocation":{"type":"Point","coordinates":[5.3,13.76667]}} +,{"name":"Bishopville","id":"5059","nametype":"Valid","recclass":"Aubrite","mass":"6000","fall":"Fell","year":"1843-01-01T00:00:00.000","reclat":"34.166670","reclong":"-80.283330","geolocation":{"type":"Point","coordinates":[-80.28333,34.16667]},":@computed_region_cbhk_fwbd":"33",":@computed_region_nnqa_25f4":"657"} +,{"name":"Bishunpur","id":"5060","nametype":"Valid","recclass":"LL3.15","mass":"1039","fall":"Fell","year":"1895-01-01T00:00:00.000","reclat":"25.383330","reclong":"82.600000","geolocation":{"type":"Point","coordinates":[82.6,25.38333]}} +,{"name":"Bjelaja Zerkov","id":"5063","nametype":"Valid","recclass":"H6","mass":"1850","fall":"Fell","year":"1796-01-01T00:00:00.000","reclat":"49.783330","reclong":"30.166670","geolocation":{"type":"Point","coordinates":[30.16667,49.78333]}} +,{"name":"Bjurböle","id":"5064","nametype":"Valid","recclass":"L/LL4","mass":"330000","fall":"Fell","year":"1899-01-01T00:00:00.000","reclat":"60.400000","reclong":"25.800000","geolocation":{"type":"Point","coordinates":[25.8,60.4]}} +,{"name":"Black Moshannan Park","id":"5065","nametype":"Valid","recclass":"L5","mass":"705","fall":"Fell","year":"1941-01-01T00:00:00.000","reclat":"40.916670","reclong":"-78.083330","geolocation":{"type":"Point","coordinates":[-78.08333,40.91667]},":@computed_region_cbhk_fwbd":"48",":@computed_region_nnqa_25f4":"2495"} +,{"name":"Blackwell","id":"5068","nametype":"Valid","recclass":"L5","mass":"2381","fall":"Fell","year":"1906-01-01T00:00:00.000","reclat":"36.833330","reclong":"-97.333330","geolocation":{"type":"Point","coordinates":[-97.33333,36.83333]},":@computed_region_cbhk_fwbd":"20",":@computed_region_nnqa_25f4":"2164"} +,{"name":"Blanket","id":"5071","nametype":"Valid","recclass":"L6","mass":"5100","fall":"Fell","year":"1909-01-01T00:00:00.000","reclat":"31.833330","reclong":"-98.833330","geolocation":{"type":"Point","coordinates":[-98.83333,31.83333]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"3063"} +,{"name":"Blansko","id":"5072","nametype":"Valid","recclass":"H6","mass":"470","fall":"Fell","year":"1833-01-01T00:00:00.000","reclat":"49.366670","reclong":"16.633330","geolocation":{"type":"Point","coordinates":[16.63333,49.36667]}} +,{"name":"Bloomington","id":"5076","nametype":"Valid","recclass":"LL6","mass":"67.8","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"40.480000","reclong":"-89.004170","geolocation":{"type":"Point","coordinates":[-89.00417,40.48]},":@computed_region_cbhk_fwbd":"34",":@computed_region_nnqa_25f4":"1795"} +,{"name":"Bo Xian","id":"5090","nametype":"Valid","recclass":"LL3.9","mass":"7500","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"33.833330","reclong":"115.833330","geolocation":{"type":"Point","coordinates":[115.83333,33.83333]}} +,{"name":"Bocas","id":"5093","nametype":"Valid","recclass":"L6","mass":"56","fall":"Fell","year":"1804-01-01T00:00:00.000","reclat":"23.000000","reclong":"-102.000000","geolocation":{"type":"Point","coordinates":[-102,23]}} +,{"name":"Bogou","id":"5097","nametype":"Valid","recclass":"Iron, IAB-MG","mass":"8800","fall":"Fell","year":"1962-01-01T00:00:00.000","reclat":"12.500000","reclong":"0.700000","geolocation":{"type":"Point","coordinates":[0.7,12.5]}} +,{"name":"Boguslavka","id":"5098","nametype":"Valid","recclass":"Iron, IIAB","mass":"256000","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"44.550000","reclong":"131.633330","geolocation":{"type":"Point","coordinates":[131.63333,44.55]}} +,{"name":"Borgo San Donino","id":"5110","nametype":"Valid","recclass":"LL6","mass":"1676","fall":"Fell","year":"1808-01-01T00:00:00.000","reclat":"44.866670","reclong":"10.050000","geolocation":{"type":"Point","coordinates":[10.05,44.86667]}} +,{"name":"Bori","id":"5111","nametype":"Valid","recclass":"L6","mass":"8600","fall":"Fell","year":"1894-01-01T00:00:00.000","reclat":"21.950000","reclong":"78.033330","geolocation":{"type":"Point","coordinates":[78.03333,21.95]}} +,{"name":"Boriskino","id":"5112","nametype":"Valid","recclass":"CM2","mass":"1342","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"54.233330","reclong":"52.483330","geolocation":{"type":"Point","coordinates":[52.48333,54.23333]}} +,{"name":"Borkut","id":"5113","nametype":"Valid","recclass":"L5","mass":"7000","fall":"Fell","year":"1852-01-01T00:00:00.000","reclat":"48.150000","reclong":"24.283330","geolocation":{"type":"Point","coordinates":[24.28333,48.15]}} +,{"name":"Borodino","id":"5114","nametype":"Valid","recclass":"H5","mass":"500","fall":"Fell","year":"1812-01-01T00:00:00.000","reclat":"55.466670","reclong":"35.866670","geolocation":{"type":"Point","coordinates":[35.86667,55.46667]}} +,{"name":"Botschetschki","id":"5117","nametype":"Valid","recclass":"L4","mass":"614","fall":"Fell","year":"1823-01-01T00:00:00.000","reclat":"51.333330","reclong":"33.883330","geolocation":{"type":"Point","coordinates":[33.88333,51.33333]}} +,{"name":"Boumdeid (2003)","id":"57168","nametype":"Valid","recclass":"L6","mass":"190","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"17.710670","reclong":"-11.371500","geolocation":{"type":"Point","coordinates":[-11.3715,17.71067]}} +,{"name":"Boumdeid (2011)","id":"57167","nametype":"Valid","recclass":"L6","mass":"3599","fall":"Fell","year":"2011-01-01T00:00:00.000","reclat":"17.174930","reclong":"-11.341330","geolocation":{"type":"Point","coordinates":[-11.34133,17.17493]}} +,{"name":"Bovedy","id":"5121","nametype":"Valid","recclass":"L3","mass":"5460","fall":"Fell","year":"1969-01-01T00:00:00.000","reclat":"54.566670","reclong":"-6.333330","geolocation":{"type":"Point","coordinates":[-6.33333,54.56667]}} +,{"name":"Bradford Woods","id":"5128","nametype":"Valid","recclass":"L","mass":"762","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"40.500000","reclong":"-80.083330","geolocation":{"type":"Point","coordinates":[-80.08333,40.5]},":@computed_region_cbhk_fwbd":"48",":@computed_region_nnqa_25f4":"2455"} +,{"name":"Braunau","id":"5133","nametype":"Valid","recclass":"Iron, IIAB","mass":"39000","fall":"Fell","year":"1847-01-01T00:00:00.000","reclat":"50.600000","reclong":"16.300000","geolocation":{"type":"Point","coordinates":[16.3,50.6]}} +,{"name":"Breitscheid","id":"5134","nametype":"Valid","recclass":"H5","mass":"1500","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"50.666940","reclong":"8.183610","geolocation":{"type":"Point","coordinates":[8.18361,50.66694]}} +,{"name":"Bremervörde","id":"5135","nametype":"Valid","recclass":"H/L3.9","mass":"7250","fall":"Fell","year":"1855-01-01T00:00:00.000","reclat":"53.400000","reclong":"9.100000","geolocation":{"type":"Point","coordinates":[9.1,53.4]}} +,{"name":"Brient","id":"5140","nametype":"Valid","recclass":"Eucrite-pmict","mass":"219","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"52.133330","reclong":"59.316670","geolocation":{"type":"Point","coordinates":[59.31667,52.13333]}} +,{"name":"Bruderheim","id":"5156","nametype":"Valid","recclass":"L6","mass":"303000","fall":"Fell","year":"1960-01-01T00:00:00.000","reclat":"53.900000","reclong":"-112.883330","geolocation":{"type":"Point","coordinates":[-112.88333,53.9]}} +,{"name":"Bukhara","id":"30448","nametype":"Valid","recclass":"CV3","mass":"5300","fall":"Fell","year":"2001-01-01T00:00:00.000","reclat":"39.779780","reclong":"64.600350","geolocation":{"type":"Point","coordinates":[64.60035,39.77978]}} +,{"name":"Bulls Run","id":"5163","nametype":"Valid","recclass":"Iron?","mass":"2250","fall":"Fell","year":"1964-01-01T00:00:00.000"} +,{"name":"Bunburra Rockhole","id":"48653","nametype":"Valid","recclass":"Eucrite","mass":"324","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"-31.350000","reclong":"129.190000","geolocation":{"type":"Point","coordinates":[129.19,-31.35]}} +,{"name":"Bununu","id":"5165","nametype":"Valid","recclass":"Howardite","mass":"357","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"10.016670","reclong":"9.583330","geolocation":{"type":"Point","coordinates":[9.58333,10.01667]}} +,{"name":"Bur-Gheluai","id":"5169","nametype":"Valid","recclass":"H5","mass":"120000","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"5.000000","reclong":"48.000000","geolocation":{"type":"Point","coordinates":[48,5]}} +,{"name":"Burnwell","id":"5175","nametype":"Valid","recclass":"H4-an","mass":"1504","fall":"Fell","year":"1990-01-01T00:00:00.000","reclat":"37.621940","reclong":"-82.237220","geolocation":{"type":"Point","coordinates":[-82.23722,37.62194]},":@computed_region_cbhk_fwbd":"36",":@computed_region_nnqa_25f4":"256"} +,{"name":"Bursa","id":"5177","nametype":"Valid","recclass":"L6","mass":"25000","fall":"Fell","year":"1946-01-01T00:00:00.000","reclat":"40.200000","reclong":"29.233330","geolocation":{"type":"Point","coordinates":[29.23333,40.2]}} +,{"name":"Buschhof","id":"5178","nametype":"Valid","recclass":"L6","mass":"5000","fall":"Fell","year":"1863-01-01T00:00:00.000","reclat":"46.450000","reclong":"25.783330","geolocation":{"type":"Point","coordinates":[25.78333,46.45]}} +,{"name":"Bustee","id":"5181","nametype":"Valid","recclass":"Aubrite","mass":"1500","fall":"Fell","year":"1852-01-01T00:00:00.000","reclat":"26.783330","reclong":"82.833330","geolocation":{"type":"Point","coordinates":[82.83333,26.78333]}} +,{"name":"Butsura","id":"5183","nametype":"Valid","recclass":"H6","mass":"29000","fall":"Fell","year":"1861-01-01T00:00:00.000","reclat":"27.083330","reclong":"84.083330","geolocation":{"type":"Point","coordinates":[84.08333,27.08333]}} +,{"name":"Buzzard Coulee","id":"48654","nametype":"Valid","recclass":"H4","mass":"41000","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"52.996000","reclong":"-109.848170","geolocation":{"type":"Point","coordinates":[-109.84817,52.996]}} +,{"name":"Cabezo de Mayo","id":"5185","nametype":"Valid","recclass":"L/LL6","mass":"25000","fall":"Fell","year":"1870-01-01T00:00:00.000","reclat":"37.983330","reclong":"-1.166670","geolocation":{"type":"Point","coordinates":[-1.16667,37.98333]}} +,{"name":"Cabin Creek","id":"5186","nametype":"Valid","recclass":"Iron, IIIAB","mass":"48500","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"35.500000","reclong":"-93.500000","geolocation":{"type":"Point","coordinates":[-93.5,35.5]},":@computed_region_cbhk_fwbd":"15",":@computed_region_nnqa_25f4":"1029"} +,{"name":"Cacak","id":"5187","nametype":"Valid","recclass":"OC","mass":"212","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"43.838890","reclong":"20.333330","geolocation":{"type":"Point","coordinates":[20.33333,43.83889]}} +,{"name":"Cali","id":"45976","nametype":"Valid","recclass":"H/L4","mass":"478","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"3.405000","reclong":"-76.510000","geolocation":{"type":"Point","coordinates":[-76.51,3.405]}} +,{"name":"Calivo","id":"5200","nametype":"Valid","recclass":"Stone-uncl","mass":"2400","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"11.750000","reclong":"122.333330","geolocation":{"type":"Point","coordinates":[122.33333,11.75]}} +,{"name":"Campos Sales","id":"5249","nametype":"Valid","recclass":"L5","mass":"23680","fall":"Fell","year":"1991-01-01T00:00:00.000","reclat":"-7.033330","reclong":"-40.166670","geolocation":{"type":"Point","coordinates":[-40.16667,-7.03333]}} +,{"name":"Çanakkale","id":"5250","nametype":"Valid","recclass":"L6","mass":"4000","fall":"Fell","year":"1964-01-01T00:00:00.000","reclat":"39.800000","reclong":"26.600000","geolocation":{"type":"Point","coordinates":[26.6,39.8]}} +,{"name":"Cañellas","id":"5251","nametype":"Valid","recclass":"H4","mass":"945","fall":"Fell","year":"1861-01-01T00:00:00.000","reclat":"41.250000","reclong":"1.666670","geolocation":{"type":"Point","coordinates":[1.66667,41.25]}} +,{"name":"Cangas de Onis","id":"5252","nametype":"Valid","recclass":"H5","mass":"34000","fall":"Fell","year":"1866-01-01T00:00:00.000","reclat":"43.383330","reclong":"-5.150000","geolocation":{"type":"Point","coordinates":[-5.15,43.38333]}} +,{"name":"Canon City","id":"5253","nametype":"Valid","recclass":"H6","mass":"1400","fall":"Fell","year":"1973-01-01T00:00:00.000","reclat":"38.470280","reclong":"-105.241390","geolocation":{"type":"Point","coordinates":[-105.24139,38.47028]},":@computed_region_cbhk_fwbd":"9",":@computed_region_nnqa_25f4":"1448"} +,{"name":"Cape Girardeau","id":"5260","nametype":"Valid","recclass":"H6","mass":"2300","fall":"Fell","year":"1846-01-01T00:00:00.000","reclat":"37.266670","reclong":"-89.583330","geolocation":{"type":"Point","coordinates":[-89.58333,37.26667]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"2695"} +,{"name":"Capilla del Monte","id":"5264","nametype":"Valid","recclass":"H6","mass":"750","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"-30.883330","reclong":"-64.550000","geolocation":{"type":"Point","coordinates":[-64.55,-30.88333]}} +,{"name":"Carancas","id":"45817","nametype":"Valid","recclass":"H4-5","mass":"342","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"-16.664440","reclong":"-69.043890","geolocation":{"type":"Point","coordinates":[-69.04389,-16.66444]}} +,{"name":"Caratash","id":"5265","nametype":"Valid","recclass":"LL6","mass":"8","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"38.500000","reclong":"27.000000","geolocation":{"type":"Point","coordinates":[27,38.5]}} +,{"name":"Castalia","id":"5291","nametype":"Valid","recclass":"H5","mass":"7300","fall":"Fell","year":"1874-01-01T00:00:00.000","reclat":"36.083330","reclong":"-78.066670","geolocation":{"type":"Point","coordinates":[-78.06667,36.08333]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"648"} +,{"name":"Castel Berardenga","id":"5292","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1791-01-01T00:00:00.000","reclat":"43.350000","reclong":"11.500000","geolocation":{"type":"Point","coordinates":[11.5,43.35]}} +,{"name":"Castine","id":"5293","nametype":"Valid","recclass":"L6","mass":"94","fall":"Fell","year":"1848-01-01T00:00:00.000","reclat":"44.383330","reclong":"-68.750000","geolocation":{"type":"Point","coordinates":[-68.75,44.38333]},":@computed_region_cbhk_fwbd":"49",":@computed_region_nnqa_25f4":"414"} +,{"name":"Castrovillari","id":"5295","nametype":"Valid","recclass":"Stone-uncl","mass":"15000","fall":"Fell","year":"1583-01-01T00:00:00.000","reclat":"39.800000","reclong":"16.200000","geolocation":{"type":"Point","coordinates":[16.2,39.8]}} +,{"name":"Caswell County","id":"5296","nametype":"Valid","recclass":"OC","mass":"1360","fall":"Fell","year":"1810-01-01T00:00:00.000","reclat":"36.500000","reclong":"-79.250000","geolocation":{"type":"Point","coordinates":[-79.25,36.5]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"637"} +,{"name":"Ceniceros","id":"5306","nametype":"Valid","recclass":"L3.7","mass":"1025","fall":"Fell","year":"1988-01-01T00:00:00.000","reclat":"26.466670","reclong":"-105.233330","geolocation":{"type":"Point","coordinates":[-105.23333,26.46667]}} +,{"name":"Centerville","id":"5307","nametype":"Valid","recclass":"H5","mass":"45.6","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"43.200000","reclong":"-96.916670","geolocation":{"type":"Point","coordinates":[-96.91667,43.2]},":@computed_region_cbhk_fwbd":"21",":@computed_region_nnqa_25f4":"2684"} +,{"name":"Cereseto","id":"5308","nametype":"Valid","recclass":"H5","mass":"6460","fall":"Fell","year":"1840-01-01T00:00:00.000","reclat":"45.083330","reclong":"8.300000","geolocation":{"type":"Point","coordinates":[8.3,45.08333]}} +,{"name":"Chadong","id":"5313","nametype":"Valid","recclass":"L6","mass":"3700","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"28.533330","reclong":"109.316670","geolocation":{"type":"Point","coordinates":[109.31667,28.53333]}} +,{"name":"Chail","id":"5314","nametype":"Valid","recclass":"H6","mass":"0.5","fall":"Fell","year":"1814-01-01T00:00:00.000","reclat":"25.366670","reclong":"81.666670","geolocation":{"type":"Point","coordinates":[81.66667,25.36667]}} +,{"name":"Chainpur","id":"5315","nametype":"Valid","recclass":"LL3.4","mass":"8200","fall":"Fell","year":"1907-01-01T00:00:00.000","reclat":"25.850000","reclong":"83.483330","geolocation":{"type":"Point","coordinates":[83.48333,25.85]}} +,{"name":"Chajari","id":"5316","nametype":"Valid","recclass":"L5","mass":"18300","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"-30.783330","reclong":"-58.050000","geolocation":{"type":"Point","coordinates":[-58.05,-30.78333]}} +,{"name":"Chandakapur","id":"5320","nametype":"Valid","recclass":"L5","mass":"8800","fall":"Fell","year":"1838-01-01T00:00:00.000","reclat":"20.266670","reclong":"76.016670","geolocation":{"type":"Point","coordinates":[76.01667,20.26667]}} +,{"name":"Chandpur","id":"5321","nametype":"Valid","recclass":"L6","mass":"1100","fall":"Fell","year":"1885-01-01T00:00:00.000","reclat":"27.283330","reclong":"79.050000","geolocation":{"type":"Point","coordinates":[79.05,27.28333]}} +,{"name":"Changde","id":"5322","nametype":"Valid","recclass":"H5","mass":"1810","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"29.083330","reclong":"111.750000","geolocation":{"type":"Point","coordinates":[111.75,29.08333]}} +,{"name":"Chantonnay","id":"5325","nametype":"Valid","recclass":"L6","mass":"31500","fall":"Fell","year":"1812-01-01T00:00:00.000","reclat":"46.683330","reclong":"1.050000","geolocation":{"type":"Point","coordinates":[1.05,46.68333]}} +,{"name":"Charlotte","id":"5328","nametype":"Valid","recclass":"Iron, IVA","mass":"4300","fall":"Fell","year":"1835-01-01T00:00:00.000","reclat":"36.166670","reclong":"-87.333330","geolocation":{"type":"Point","coordinates":[-87.33333,36.16667]},":@computed_region_cbhk_fwbd":"39",":@computed_region_nnqa_25f4":"2007"} +,{"name":"Charsonville","id":"5329","nametype":"Valid","recclass":"H6","mass":"27000","fall":"Fell","year":"1810-01-01T00:00:00.000","reclat":"47.933330","reclong":"1.566670","geolocation":{"type":"Point","coordinates":[1.56667,47.93333]}} +,{"name":"Charwallas","id":"5330","nametype":"Valid","recclass":"H6","mass":"12000","fall":"Fell","year":"1834-01-01T00:00:00.000","reclat":"29.483330","reclong":"75.500000","geolocation":{"type":"Point","coordinates":[75.5,29.48333]}} +,{"name":"Chassigny","id":"5331","nametype":"Valid","recclass":"Martian (chassignite)","mass":"4000","fall":"Fell","year":"1815-01-01T00:00:00.000","reclat":"47.716670","reclong":"5.366670","geolocation":{"type":"Point","coordinates":[5.36667,47.71667]}} +,{"name":"Château-Renard","id":"5332","nametype":"Valid","recclass":"L6","mass":"30000","fall":"Fell","year":"1841-01-01T00:00:00.000","reclat":"47.933330","reclong":"2.916670","geolocation":{"type":"Point","coordinates":[2.91667,47.93333]}} +,{"name":"Chaves","id":"5334","nametype":"Valid","recclass":"Howardite","mass":"2945","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"41.933330","reclong":"-7.466670","geolocation":{"type":"Point","coordinates":[-7.46667,41.93333]}} +,{"name":"Chela","id":"5338","nametype":"Valid","recclass":"H4","mass":"2936","fall":"Fell","year":"1988-01-01T00:00:00.000","reclat":"-3.666670","reclong":"32.500000","geolocation":{"type":"Point","coordinates":[32.5,-3.66667]}} +,{"name":"Chelyabinsk","id":"57165","nametype":"Valid","recclass":"LL5","mass":"100000","fall":"Fell","year":"2013-01-01T00:00:00.000","reclat":"54.816670","reclong":"61.116670","geolocation":{"type":"Point","coordinates":[61.11667,54.81667]}} +,{"name":"Chergach ","id":"47347","nametype":"Valid","recclass":"H5","mass":"100000","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"23.696390","reclong":"-5.014720","geolocation":{"type":"Point","coordinates":[-5.01472,23.69639]}} +,{"name":"Chernyi Bor","id":"5339","nametype":"Valid","recclass":"H4","mass":"6000","fall":"Fell","year":"1964-01-01T00:00:00.000","reclat":"53.700000","reclong":"30.100000","geolocation":{"type":"Point","coordinates":[30.1,53.7]}} +,{"name":"Cherokee Springs","id":"5340","nametype":"Valid","recclass":"LL6","mass":"8400","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"35.033330","reclong":"-81.883330","geolocation":{"type":"Point","coordinates":[-81.88333,35.03333]},":@computed_region_cbhk_fwbd":"33",":@computed_region_nnqa_25f4":"2582"} +,{"name":"Chervettaz","id":"5341","nametype":"Valid","recclass":"L5","mass":"705","fall":"Fell","year":"1901-01-01T00:00:00.000","reclat":"46.550000","reclong":"6.816670","geolocation":{"type":"Point","coordinates":[6.81667,46.55]}} +,{"name":"Chervony Kut","id":"5342","nametype":"Valid","recclass":"Eucrite-mmict","mass":"1700","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"50.833330","reclong":"34.000000","geolocation":{"type":"Point","coordinates":[34,50.83333]}} +,{"name":"Chetrinahatti","id":"5344","nametype":"Valid","recclass":"Stone-uncl","mass":"72","fall":"Fell","year":"1880-01-01T00:00:00.000","reclat":"14.500000","reclong":"76.500000","geolocation":{"type":"Point","coordinates":[76.5,14.5]}} +,{"name":"Chiang Khan","id":"5345","nametype":"Valid","recclass":"H6","mass":"367","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"17.900000","reclong":"101.633330","geolocation":{"type":"Point","coordinates":[101.63333,17.9]}} +,{"name":"Chicora","id":"5349","nametype":"Valid","recclass":"LL6","mass":"303","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"40.933330","reclong":"-79.733330","geolocation":{"type":"Point","coordinates":[-79.73333,40.93333]},":@computed_region_cbhk_fwbd":"48",":@computed_region_nnqa_25f4":"2459"} +,{"name":"Chisenga","id":"5355","nametype":"Valid","recclass":"Iron, IIIAB","mass":"3920","fall":"Fell","year":"1988-01-01T00:00:00.000","reclat":"-10.059440","reclong":"33.395000","geolocation":{"type":"Point","coordinates":[33.395,-10.05944]}} +,{"name":"Chitado","id":"5356","nametype":"Valid","recclass":"L6","fall":"Fell","year":"1966-01-01T00:00:00.000","reclat":"-17.350000","reclong":"13.966670","geolocation":{"type":"Point","coordinates":[13.96667,-17.35]}} +,{"name":"Chitenay","id":"5357","nametype":"Valid","recclass":"L6","mass":"4000","fall":"Fell","year":"1978-01-01T00:00:00.000","reclat":"47.470830","reclong":"0.976670","geolocation":{"type":"Point","coordinates":[0.97667,47.47083]}} +,{"name":"Cilimus","id":"5364","nametype":"Valid","recclass":"L5","mass":"1600","fall":"Fell","year":"1979-01-01T00:00:00.000","reclat":"-6.950000","reclong":"108.100000","geolocation":{"type":"Point","coordinates":[108.1,-6.95]}} +,{"name":"Claxton","id":"5374","nametype":"Valid","recclass":"L6","mass":"1455","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"32.102500","reclong":"-81.872780","geolocation":{"type":"Point","coordinates":[-81.87278,32.1025]},":@computed_region_cbhk_fwbd":"31",":@computed_region_nnqa_25f4":"67"} +,{"name":"Clohars","id":"5383","nametype":"Valid","recclass":"L4","mass":"48.6","fall":"Fell","year":"1822-01-01T00:00:00.000"} +,{"name":"Colby (Wisconsin)","id":"5395","nametype":"Valid","recclass":"L6","mass":"104000","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"44.900000","reclong":"-90.283330","geolocation":{"type":"Point","coordinates":[-90.28333,44.9]},":@computed_region_cbhk_fwbd":"41",":@computed_region_nnqa_25f4":"877"} +,{"name":"Cold Bokkeveld","id":"5397","nametype":"Valid","recclass":"CM2","mass":"5200","fall":"Fell","year":"1838-01-01T00:00:00.000","reclat":"-33.133330","reclong":"19.383330","geolocation":{"type":"Point","coordinates":[19.38333,-33.13333]}} +,{"name":"Coleman","id":"5401","nametype":"Valid","recclass":"L6","mass":"469","fall":"Fell","year":"1994-01-01T00:00:00.000","reclat":"43.761110","reclong":"-84.507780","geolocation":{"type":"Point","coordinates":[-84.50778,43.76111]},":@computed_region_cbhk_fwbd":"50",":@computed_region_nnqa_25f4":"356"} +,{"name":"Collescipoli","id":"5403","nametype":"Valid","recclass":"H5","mass":"5000","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"42.533330","reclong":"12.616670","geolocation":{"type":"Point","coordinates":[12.61667,42.53333]}} +,{"name":"Conquista","id":"5418","nametype":"Valid","recclass":"H4","mass":"20350","fall":"Fell","year":"1965-01-01T00:00:00.000","reclat":"-19.850000","reclong":"-47.550000","geolocation":{"type":"Point","coordinates":[-47.55,-19.85]}} +,{"name":"Cosina","id":"5451","nametype":"Valid","recclass":"H5","mass":"1200","fall":"Fell","year":"1844-01-01T00:00:00.000","reclat":"21.166670","reclong":"-100.866670","geolocation":{"type":"Point","coordinates":[-100.86667,21.16667]}} +,{"name":"Cranganore","id":"5465","nametype":"Valid","recclass":"L6","mass":"1460","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"10.200000","reclong":"76.266670","geolocation":{"type":"Point","coordinates":[76.26667,10.2]}} +,{"name":"Crescent","id":"5470","nametype":"Valid","recclass":"CM2","mass":"78.400000000000006","fall":"Fell","year":"1936-01-01T00:00:00.000","reclat":"35.950000","reclong":"-97.583330","geolocation":{"type":"Point","coordinates":[-97.58333,35.95]},":@computed_region_cbhk_fwbd":"20",":@computed_region_nnqa_25f4":"2201"} +,{"name":"Cronstad","id":"5474","nametype":"Valid","recclass":"H5","mass":"3650","fall":"Fell","year":"1877-01-01T00:00:00.000","reclat":"-27.700000","reclong":"27.300000","geolocation":{"type":"Point","coordinates":[27.3,-27.7]}} +,{"name":"Cross Roads","id":"5476","nametype":"Valid","recclass":"H5","mass":"167","fall":"Fell","year":"1892-01-01T00:00:00.000","reclat":"35.633330","reclong":"-78.133330","geolocation":{"type":"Point","coordinates":[-78.13333,35.63333]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"2332"} +,{"name":"Crumlin","id":"5477","nametype":"Valid","recclass":"L5","mass":"4255","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"54.616670","reclong":"-6.216670","geolocation":{"type":"Point","coordinates":[-6.21667,54.61667]}} +,{"name":"Cumberland Falls","id":"5496","nametype":"Valid","recclass":"Aubrite","mass":"17000","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"36.833330","reclong":"-84.350000","geolocation":{"type":"Point","coordinates":[-84.35,36.83333]},":@computed_region_cbhk_fwbd":"36",":@computed_region_nnqa_25f4":"1426"} +,{"name":"Cynthiana","id":"5500","nametype":"Valid","recclass":"L/LL4","mass":"6000","fall":"Fell","year":"1877-01-01T00:00:00.000","reclat":"38.400000","reclong":"-84.250000","geolocation":{"type":"Point","coordinates":[-84.25,38.4]},":@computed_region_cbhk_fwbd":"36",":@computed_region_nnqa_25f4":"244"} +,{"name":"Dahmani","id":"5504","nametype":"Valid","recclass":"LL6","mass":"18000","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"35.616670","reclong":"8.833330","geolocation":{"type":"Point","coordinates":[8.83333,35.61667]}} +,{"name":"Dandapur","id":"5511","nametype":"Valid","recclass":"L6","mass":"5650","fall":"Fell","year":"1878-01-01T00:00:00.000","reclat":"26.916670","reclong":"83.966670","geolocation":{"type":"Point","coordinates":[83.96667,26.91667]}} +,{"name":"Daniel's Kuil","id":"5513","nametype":"Valid","recclass":"EL6","mass":"1064","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"-28.200000","reclong":"24.566670","geolocation":{"type":"Point","coordinates":[24.56667,-28.2]}} +,{"name":"Danville","id":"5514","nametype":"Valid","recclass":"L6","mass":"2000","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"34.400000","reclong":"-87.066670","geolocation":{"type":"Point","coordinates":[-87.06667,34.4]},":@computed_region_cbhk_fwbd":"29",":@computed_region_nnqa_25f4":"103"} +,{"name":"Darmstadt","id":"6603","nametype":"Valid","recclass":"H5","mass":"100","fall":"Fell","year":"1804-01-01T00:00:00.000","reclat":"49.866670","reclong":"8.650000","geolocation":{"type":"Point","coordinates":[8.65,49.86667]}} +,{"name":"Dashoguz","id":"6604","nametype":"Valid","recclass":"H5","mass":"7000","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"41.984440","reclong":"59.685000","geolocation":{"type":"Point","coordinates":[59.685,41.98444]}} +,{"name":"Daule","id":"51559","nametype":"Valid","recclass":"L5","mass":"6580","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"-1.870890","reclong":"-79.957560","geolocation":{"type":"Point","coordinates":[-79.95756,-1.87089]}} +,{"name":"De Cewsville","id":"6621","nametype":"Valid","recclass":"H6","mass":"340","fall":"Fell","year":"1887-01-01T00:00:00.000","reclat":"43.000000","reclong":"-80.000000","geolocation":{"type":"Point","coordinates":[-80,43]}} +,{"name":"Deal","id":"6634","nametype":"Valid","recclass":"L6","mass":"28","fall":"Fell","year":"1829-01-01T00:00:00.000","reclat":"40.250000","reclong":"-74.000000","geolocation":{"type":"Point","coordinates":[-74,40.25]},":@computed_region_nnqa_25f4":"2491"} +,{"name":"Delhi","id":"6642","nametype":"Valid","recclass":"L5","mass":"0.8","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"28.566670","reclong":"77.250000","geolocation":{"type":"Point","coordinates":[77.25,28.56667]}} +,{"name":"Demina","id":"6649","nametype":"Valid","recclass":"L6","mass":"16400","fall":"Fell","year":"1911-01-01T00:00:00.000","reclat":"51.466670","reclong":"84.766670","geolocation":{"type":"Point","coordinates":[84.76667,51.46667]}} +,{"name":"Denver","id":"6660","nametype":"Valid","recclass":"L6","mass":"230","fall":"Fell","year":"1967-01-01T00:00:00.000","reclat":"39.782500","reclong":"-104.930560","geolocation":{"type":"Point","coordinates":[-104.93056,39.7825]},":@computed_region_cbhk_fwbd":"9",":@computed_region_nnqa_25f4":"1444"} +,{"name":"Dergaon","id":"6664","nametype":"Valid","recclass":"H5","mass":"12500","fall":"Fell","year":"2001-01-01T00:00:00.000","reclat":"26.683330","reclong":"93.866670","geolocation":{"type":"Point","coordinates":[93.86667,26.68333]}} +,{"name":"Desuri","id":"6693","nametype":"Valid","recclass":"H6","mass":"25400","fall":"Fell","year":"1962-01-01T00:00:00.000","reclat":"25.733330","reclong":"73.616670","geolocation":{"type":"Point","coordinates":[73.61667,25.73333]}} +,{"name":"Devgaon","id":"6694","nametype":"Valid","recclass":"H3.8","mass":"12000","fall":"Fell","year":"2001-01-01T00:00:00.000","reclat":"19.000000","reclong":"81.000000","geolocation":{"type":"Point","coordinates":[81,19]}} +,{"name":"Devri-Khera","id":"6696","nametype":"Valid","recclass":"L6","mass":"1140","fall":"Fell","year":"1994-01-01T00:00:00.000","reclat":"24.225000","reclong":"76.525000","geolocation":{"type":"Point","coordinates":[76.525,24.225]}} +,{"name":"Dhajala","id":"6698","nametype":"Valid","recclass":"H3.8","mass":"45000","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"22.377780","reclong":"71.427220","geolocation":{"type":"Point","coordinates":[71.42722,22.37778]}} +,{"name":"Dharwar","id":"6699","nametype":"Valid","recclass":"OC","mass":"1800","fall":"Fell","year":"1848-01-01T00:00:00.000","reclat":"14.883330","reclong":"75.600000","geolocation":{"type":"Point","coordinates":[75.6,14.88333]}} +,{"name":"Dhurmsala","id":"7640","nametype":"Valid","recclass":"LL6","mass":"32000","fall":"Fell","year":"1860-01-01T00:00:00.000","reclat":"32.233330","reclong":"76.466670","geolocation":{"type":"Point","coordinates":[76.46667,32.23333]}} +,{"name":"Didim","id":"47350","nametype":"Valid","recclass":"H3-5","mass":"3396","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"37.351720","reclong":"27.329970","geolocation":{"type":"Point","coordinates":[27.32997,37.35172]}} +,{"name":"Diep River","id":"7642","nametype":"Valid","recclass":"L6","mass":"1000","fall":"Fell","year":"1906-01-01T00:00:00.000","reclat":"-33.750000","reclong":"18.566670","geolocation":{"type":"Point","coordinates":[18.56667,-33.75]}} +,{"name":"Distrito Quebracho","id":"7649","nametype":"Valid","recclass":"H4","mass":"400","fall":"Fell","year":"1957-01-01T00:00:00.000","reclat":"-31.883330","reclong":"-60.466670","geolocation":{"type":"Point","coordinates":[-60.46667,-31.88333]}} +,{"name":"Djati-Pengilon","id":"7652","nametype":"Valid","recclass":"H6","mass":"166000","fall":"Fell","year":"1884-01-01T00:00:00.000","reclat":"-7.500000","reclong":"111.500000","geolocation":{"type":"Point","coordinates":[111.5,-7.5]}} +,{"name":"Djermaia","id":"7656","nametype":"Valid","recclass":"H","mass":"3950","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"12.733330","reclong":"15.050000","geolocation":{"type":"Point","coordinates":[15.05,12.73333]}} +,{"name":"Djoumine","id":"7657","nametype":"Valid","recclass":"H5-6","mass":"10000","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"36.950000","reclong":"9.550000","geolocation":{"type":"Point","coordinates":[9.55,36.95]}} +,{"name":"Dokachi","id":"7658","nametype":"Valid","recclass":"H5","mass":"3840","fall":"Fell","year":"1903-01-01T00:00:00.000","reclat":"23.500000","reclong":"90.333330","geolocation":{"type":"Point","coordinates":[90.33333,23.5]}} +,{"name":"Dolgovoli","id":"7659","nametype":"Valid","recclass":"L6","mass":"1600","fall":"Fell","year":"1864-01-01T00:00:00.000","reclat":"50.750000","reclong":"25.300000","geolocation":{"type":"Point","coordinates":[25.3,50.75]}} +,{"name":"Domanitch","id":"7661","nametype":"Valid","recclass":"L5","mass":"438","fall":"Fell","year":"1907-01-01T00:00:00.000","reclat":"40.000000","reclong":"29.000000","geolocation":{"type":"Point","coordinates":[29,40]}} +,{"name":"Dong Ujimqin Qi","id":"7706","nametype":"Valid","recclass":"Mesosiderite","mass":"128800","fall":"Fell","year":"1995-01-01T00:00:00.000","reclat":"45.500000","reclong":"119.033330","geolocation":{"type":"Point","coordinates":[119.03333,45.5]}} +,{"name":"Donga Kohrod","id":"7707","nametype":"Valid","recclass":"H6","mass":"230","fall":"Fell","year":"1899-01-01T00:00:00.000","reclat":"21.866670","reclong":"82.450000","geolocation":{"type":"Point","coordinates":[82.45,21.86667]}} +,{"name":"Dongtai","id":"7708","nametype":"Valid","recclass":"LL6","mass":"5500","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"32.916670","reclong":"120.783330","geolocation":{"type":"Point","coordinates":[120.78333,32.91667]}} +,{"name":"Doroninsk","id":"7718","nametype":"Valid","recclass":"H5-7","mass":"3891","fall":"Fell","year":"1805-01-01T00:00:00.000","reclat":"51.200000","reclong":"112.300000","geolocation":{"type":"Point","coordinates":[112.3,51.2]}} +,{"name":"Dosso","id":"7722","nametype":"Valid","recclass":"L6","mass":"1250","fall":"Fell","year":"1962-01-01T00:00:00.000","reclat":"13.050000","reclong":"3.166670","geolocation":{"type":"Point","coordinates":[3.16667,13.05]}} +,{"name":"Douar Mghila","id":"7723","nametype":"Valid","recclass":"LL6","mass":"1161","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"32.333330","reclong":"-6.300000","geolocation":{"type":"Point","coordinates":[-6.3,32.33333]}} +,{"name":"Dowa","id":"7725","nametype":"Valid","recclass":"Stone-uncl","mass":"642","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"-13.666670","reclong":"33.916670","geolocation":{"type":"Point","coordinates":[33.91667,-13.66667]}} +,{"name":"Drake Creek","id":"7728","nametype":"Valid","recclass":"L6","mass":"5000","fall":"Fell","year":"1827-01-01T00:00:00.000","reclat":"36.400000","reclong":"-86.500000","geolocation":{"type":"Point","coordinates":[-86.5,36.4]},":@computed_region_cbhk_fwbd":"39",":@computed_region_nnqa_25f4":"2115"} +,{"name":"Dresden (Ontario)","id":"7731","nametype":"Valid","recclass":"H6","mass":"47700","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"42.520000","reclong":"-82.260000","geolocation":{"type":"Point","coordinates":[-82.26,42.52]}} +,{"name":"Dubrovnik","id":"7736","nametype":"Valid","recclass":"L3-6","mass":"1900","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"42.458330","reclong":"18.441670","geolocation":{"type":"Point","coordinates":[18.44167,42.45833]}} +,{"name":"Dunbogan","id":"7743","nametype":"Valid","recclass":"L6","mass":"30","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"-31.666670","reclong":"152.833330","geolocation":{"type":"Point","coordinates":[152.83333,-31.66667]}} +,{"name":"Dundrum","id":"7745","nametype":"Valid","recclass":"H5","mass":"2270","fall":"Fell","year":"1865-01-01T00:00:00.000","reclat":"52.550000","reclong":"-8.033330","geolocation":{"type":"Point","coordinates":[-8.03333,52.55]}} +,{"name":"Dunhua","id":"7749","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"43.333330","reclong":"128.250000","geolocation":{"type":"Point","coordinates":[128.25,43.33333]}} +,{"name":"Durala","id":"7750","nametype":"Valid","recclass":"L6","mass":"13200","fall":"Fell","year":"1815-01-01T00:00:00.000","reclat":"30.300000","reclong":"76.633330","geolocation":{"type":"Point","coordinates":[76.63333,30.3]}} +,{"name":"Duruma","id":"7752","nametype":"Valid","recclass":"L6","mass":"577","fall":"Fell","year":"1853-01-01T00:00:00.000","reclat":"-4.000000","reclong":"39.500000","geolocation":{"type":"Point","coordinates":[39.5,-4]}} +,{"name":"Duwun","id":"7754","nametype":"Valid","recclass":"L6","mass":"2117","fall":"Fell","year":"1943-01-01T00:00:00.000","reclat":"33.433330","reclong":"127.266670","geolocation":{"type":"Point","coordinates":[127.26667,33.43333]}} +,{"name":"Dwaleni","id":"7755","nametype":"Valid","recclass":"H4-6","mass":"3230","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"-27.200000","reclong":"31.316670","geolocation":{"type":"Point","coordinates":[31.31667,-27.2]}} +,{"name":"Dyalpur","id":"7757","nametype":"Valid","recclass":"Ureilite","mass":"300","fall":"Fell","year":"1872-01-01T00:00:00.000","reclat":"26.250000","reclong":"82.000000","geolocation":{"type":"Point","coordinates":[82,26.25]}} +,{"name":"Dyarrl Island","id":"7758","nametype":"Valid","recclass":"Mesosiderite-A1","mass":"188","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"-3.000000","reclong":"151.000000","geolocation":{"type":"Point","coordinates":[151,-3]}} +,{"name":"Eagle","id":"7760","nametype":"Valid","recclass":"EL6","mass":"10000","fall":"Fell","year":"1947-01-01T00:00:00.000","reclat":"40.781670","reclong":"-96.471670","geolocation":{"type":"Point","coordinates":[-96.47167,40.78167]},":@computed_region_cbhk_fwbd":"19",":@computed_region_nnqa_25f4":"462"} +,{"name":"Ehole","id":"7774","nametype":"Valid","recclass":"H5","mass":"2400","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"-17.300000","reclong":"15.833330","geolocation":{"type":"Point","coordinates":[15.83333,-17.3]}} +,{"name":"Eichstädt","id":"7775","nametype":"Valid","recclass":"H5","mass":"3000","fall":"Fell","year":"1785-01-01T00:00:00.000","reclat":"48.900000","reclong":"11.216670","geolocation":{"type":"Point","coordinates":[11.21667,48.9]}} +,{"name":"Ekeby","id":"7776","nametype":"Valid","recclass":"H4","mass":"3336","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"56.033330","reclong":"13.000000","geolocation":{"type":"Point","coordinates":[13,56.03333]}} +,{"name":"Ekh Khera","id":"7777","nametype":"Valid","recclass":"H6","mass":"840","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"28.266670","reclong":"78.783330","geolocation":{"type":"Point","coordinates":[78.78333,28.26667]}} +,{"name":"El Idrissia","id":"7807","nametype":"Valid","recclass":"L6","mass":"10000","fall":"Fell","year":"1989-01-01T00:00:00.000","reclat":"34.416670","reclong":"3.250000","geolocation":{"type":"Point","coordinates":[3.25,34.41667]}} +,{"name":"El Paso de Aguila","id":"45977","nametype":"Valid","recclass":"H5","mass":"17226","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"25.370000","reclong":"-97.370000","geolocation":{"type":"Point","coordinates":[-97.37,25.37]}} +,{"name":"El Tigre","id":"7819","nametype":"Valid","recclass":"L6","mass":"5000","fall":"Fell","year":"1993-01-01T00:00:00.000","reclat":"19.967220","reclong":"-103.051670","geolocation":{"type":"Point","coordinates":[-103.05167,19.96722]}} +,{"name":"Elbert","id":"7822","nametype":"Valid","recclass":"LL6","mass":"680.5","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"39.246670","reclong":"-104.588170","geolocation":{"type":"Point","coordinates":[-104.58817,39.24667]},":@computed_region_cbhk_fwbd":"9",":@computed_region_nnqa_25f4":"88"} +,{"name":"Elbogen","id":"7823","nametype":"Valid","recclass":"Iron, IID","mass":"107000","fall":"Fell","year":"1400-01-01T00:00:00.000","reclat":"50.183330","reclong":"12.733330","geolocation":{"type":"Point","coordinates":[12.73333,50.18333]}} +,{"name":"Elenovka","id":"7824","nametype":"Valid","recclass":"L5","mass":"54640","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"47.833330","reclong":"37.666670","geolocation":{"type":"Point","coordinates":[37.66667,47.83333]}} +,{"name":"Ellemeet","id":"10019","nametype":"Valid","recclass":"Diogenite","mass":"1470","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"51.750000","reclong":"4.000000","geolocation":{"type":"Point","coordinates":[4,51.75]}} +,{"name":"Emmaville","id":"10033","nametype":"Valid","recclass":"Eucrite-mmict","mass":"127","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"-29.466670","reclong":"151.616670","geolocation":{"type":"Point","coordinates":[151.61667,-29.46667]}} +,{"name":"Enshi","id":"10038","nametype":"Valid","recclass":"H5","mass":"8000","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"30.300000","reclong":"109.500000","geolocation":{"type":"Point","coordinates":[109.5,30.3]}} +,{"name":"Ensisheim","id":"10039","nametype":"Valid","recclass":"LL6","mass":"127000","fall":"Fell","year":"1492-01-01T00:00:00.000","reclat":"47.866670","reclong":"7.350000","geolocation":{"type":"Point","coordinates":[7.35,47.86667]}} +,{"name":"Épinal","id":"10041","nametype":"Valid","recclass":"H5","mass":"277","fall":"Fell","year":"1822-01-01T00:00:00.000","reclat":"48.183330","reclong":"6.466670","geolocation":{"type":"Point","coordinates":[6.46667,48.18333]}} +,{"name":"Erakot","id":"10042","nametype":"Valid","recclass":"CM2","mass":"113","fall":"Fell","year":"1940-01-01T00:00:00.000","reclat":"19.033330","reclong":"81.891670","geolocation":{"type":"Point","coordinates":[81.89167,19.03333]}} +,{"name":"Erevan","id":"10043","nametype":"Valid","recclass":"Howardite","mass":"107.2","fall":"Fell","year":"1911-01-01T00:00:00.000","reclat":"40.300000","reclong":"44.500000","geolocation":{"type":"Point","coordinates":[44.5,40.3]}} +,{"name":"Ergheo","id":"10044","nametype":"Valid","recclass":"L5","mass":"20000","fall":"Fell","year":"1889-01-01T00:00:00.000","reclat":"1.166670","reclong":"44.166670","geolocation":{"type":"Point","coordinates":[44.16667,1.16667]}} +,{"name":"Erxleben","id":"10049","nametype":"Valid","recclass":"H6","mass":"2250","fall":"Fell","year":"1812-01-01T00:00:00.000","reclat":"52.216670","reclong":"11.250000","geolocation":{"type":"Point","coordinates":[11.25,52.21667]}} +,{"name":"Esnandes","id":"10051","nametype":"Valid","recclass":"L6","mass":"1500","fall":"Fell","year":"1837-01-01T00:00:00.000","reclat":"46.250000","reclong":"-1.100000","geolocation":{"type":"Point","coordinates":[-1.1,46.25]}} +,{"name":"Essebi","id":"10055","nametype":"Valid","recclass":"C2-ung","mass":"500","fall":"Fell","year":"1957-01-01T00:00:00.000","reclat":"2.883330","reclong":"30.833330","geolocation":{"type":"Point","coordinates":[30.83333,2.88333]}} +,{"name":"Estherville","id":"10059","nametype":"Valid","recclass":"Mesosiderite-A3/4","mass":"320000","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"43.416670","reclong":"-94.833330","geolocation":{"type":"Point","coordinates":[-94.83333,43.41667]},":@computed_region_cbhk_fwbd":"16",":@computed_region_nnqa_25f4":"277"} +,{"name":"Farmington","id":"10074","nametype":"Valid","recclass":"L5","mass":"89400","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"39.750000","reclong":"-97.033330","geolocation":{"type":"Point","coordinates":[-97.03333,39.75]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1300"} +,{"name":"Farmville","id":"10075","nametype":"Valid","recclass":"H4","mass":"56000","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"35.550000","reclong":"-77.533330","geolocation":{"type":"Point","coordinates":[-77.53333,35.55]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"2439"} +,{"name":"Favars","id":"10078","nametype":"Valid","recclass":"H5","mass":"1500","fall":"Fell","year":"1844-01-01T00:00:00.000","reclat":"44.383330","reclong":"2.816670","geolocation":{"type":"Point","coordinates":[2.81667,44.38333]}} +,{"name":"Fayetteville","id":"10079","nametype":"Valid","recclass":"H4","mass":"2360","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"36.050000","reclong":"-94.166670","geolocation":{"type":"Point","coordinates":[-94.16667,36.05]},":@computed_region_cbhk_fwbd":"15",":@computed_region_nnqa_25f4":"70"} +,{"name":"Feid Chair","id":"10080","nametype":"Valid","recclass":"H4","mass":"380","fall":"Fell","year":"1875-01-01T00:00:00.000","reclat":"36.883330","reclong":"8.450000","geolocation":{"type":"Point","coordinates":[8.45,36.88333]}} +,{"name":"Felix","id":"10081","nametype":"Valid","recclass":"CO3.3","mass":"3200","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"32.533330","reclong":"-87.166670","geolocation":{"type":"Point","coordinates":[-87.16667,32.53333]},":@computed_region_cbhk_fwbd":"29",":@computed_region_nnqa_25f4":"1631"} +,{"name":"Fenghsien-Ku","id":"10086","nametype":"Valid","recclass":"H5","mass":"82","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"34.600000","reclong":"116.750000","geolocation":{"type":"Point","coordinates":[116.75,34.6]}} +,{"name":"Ferguson","id":"10088","nametype":"Valid","recclass":"OC","mass":"220","fall":"Fell","year":"1889-01-01T00:00:00.000","reclat":"36.100000","reclong":"-81.416670","geolocation":{"type":"Point","coordinates":[-81.41667,36.1]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"2331"} +,{"name":"Fermo","id":"10091","nametype":"Valid","recclass":"H3-5","mass":"10200","fall":"Fell","year":"1996-01-01T00:00:00.000","reclat":"43.181110","reclong":"13.753330","geolocation":{"type":"Point","coordinates":[13.75333,43.18111]}} +,{"name":"Fisher","id":"10107","nametype":"Valid","recclass":"L6","mass":"17600","fall":"Fell","year":"1894-01-01T00:00:00.000","reclat":"47.816670","reclong":"-96.850000","geolocation":{"type":"Point","coordinates":[-96.85,47.81667]},":@computed_region_cbhk_fwbd":"1",":@computed_region_nnqa_25f4":"385"} +,{"name":"Florence","id":"10111","nametype":"Valid","recclass":"H3","mass":"3640","fall":"Fell","year":"1922-01-01T00:00:00.000","reclat":"30.833330","reclong":"-97.766670","geolocation":{"type":"Point","coordinates":[-97.76667,30.83333]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"807"} +,{"name":"Forest City","id":"10119","nametype":"Valid","recclass":"H5","mass":"152000","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"43.250000","reclong":"-93.666670","geolocation":{"type":"Point","coordinates":[-93.66667,43.25]},":@computed_region_cbhk_fwbd":"16",":@computed_region_nnqa_25f4":"1785"} +,{"name":"Forest Vale","id":"10120","nametype":"Valid","recclass":"H4","mass":"26000","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"-33.350000","reclong":"146.858330","geolocation":{"type":"Point","coordinates":[146.85833,-33.35]}} +,{"name":"Forksville","id":"10123","nametype":"Valid","recclass":"L6","mass":"6067","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"36.783330","reclong":"-78.083330","geolocation":{"type":"Point","coordinates":[-78.08333,36.78333]},":@computed_region_cbhk_fwbd":"40",":@computed_region_nnqa_25f4":"2839"} +,{"name":"Forsbach","id":"10163","nametype":"Valid","recclass":"H6","mass":"240","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"50.950000","reclong":"7.316670","geolocation":{"type":"Point","coordinates":[7.31667,50.95]}} +,{"name":"Forsyth","id":"10164","nametype":"Valid","recclass":"L6","mass":"16300","fall":"Fell","year":"1829-01-01T00:00:00.000","reclat":"33.016670","reclong":"-83.966670","geolocation":{"type":"Point","coordinates":[-83.96667,33.01667]},":@computed_region_cbhk_fwbd":"31",":@computed_region_nnqa_25f4":"1470"} +,{"name":"Fort Flatters","id":"10166","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1944-01-01T00:00:00.000","reclat":"28.250000","reclong":"7.000000","geolocation":{"type":"Point","coordinates":[7,28.25]}} +,{"name":"Frankfort (stone)","id":"10177","nametype":"Valid","recclass":"Howardite","mass":"650","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"34.483330","reclong":"-87.833330","geolocation":{"type":"Point","coordinates":[-87.83333,34.48333]},":@computed_region_cbhk_fwbd":"29",":@computed_region_nnqa_25f4":"99"} +,{"name":"Fuhe","id":"52412","nametype":"Valid","recclass":"L5","mass":"23000","fall":"Fell","year":"1945-01-01T00:00:00.000","reclat":"31.475560","reclong":"113.566940","geolocation":{"type":"Point","coordinates":[113.56694,31.47556]}} +,{"name":"Fukutomi","id":"10836","nametype":"Valid","recclass":"L5","mass":"11620","fall":"Fell","year":"1882-01-01T00:00:00.000","reclat":"33.183330","reclong":"130.200000","geolocation":{"type":"Point","coordinates":[130.2,33.18333]}} +,{"name":"Fünen","id":"10838","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1654-01-01T00:00:00.000","reclat":"55.333330","reclong":"10.333330","geolocation":{"type":"Point","coordinates":[10.33333,55.33333]}} +,{"name":"Futtehpur","id":"10839","nametype":"Valid","recclass":"L6","mass":"4000","fall":"Fell","year":"1822-01-01T00:00:00.000","reclat":"25.950000","reclong":"80.816670","geolocation":{"type":"Point","coordinates":[80.81667,25.95]}} +,{"name":"Fuyang","id":"10840","nametype":"Valid","recclass":"Stone-uncl","mass":"2500","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"32.900000","reclong":"115.900000","geolocation":{"type":"Point","coordinates":[115.9,32.9]}} +,{"name":"Galapian","id":"10846","nametype":"Valid","recclass":"H6","mass":"132.69999999999999","fall":"Fell","year":"1826-01-01T00:00:00.000","reclat":"44.300000","reclong":"0.400000","geolocation":{"type":"Point","coordinates":[0.4,44.3]}} +,{"name":"Galim (a)","id":"10848","nametype":"Valid","recclass":"LL6","mass":"36.1","fall":"Fell","year":"1952-01-01T00:00:00.000","reclat":"7.050000","reclong":"12.433330","geolocation":{"type":"Point","coordinates":[12.43333,7.05]}} +,{"name":"Galim (b)","id":"10849","nametype":"Valid","recclass":"EH3/4-an","mass":"28","fall":"Fell","year":"1952-01-01T00:00:00.000","reclat":"7.050000","reclong":"12.433330","geolocation":{"type":"Point","coordinates":[12.43333,7.05]}} +,{"name":"Galkiv","id":"10850","nametype":"Valid","recclass":"H4","mass":"5000","fall":"Fell","year":"1995-01-01T00:00:00.000","reclat":"51.683330","reclong":"30.783330","geolocation":{"type":"Point","coordinates":[30.78333,51.68333]}} +,{"name":"Gambat","id":"10851","nametype":"Valid","recclass":"L6","mass":"6400","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"27.350000","reclong":"68.533330","geolocation":{"type":"Point","coordinates":[68.53333,27.35]}} +,{"name":"Gao-Guenie","id":"10854","nametype":"Valid","recclass":"H5","fall":"Fell","year":"1960-01-01T00:00:00.000","reclat":"11.650000","reclong":"-2.183330","geolocation":{"type":"Point","coordinates":[-2.18333,11.65]}} +,{"name":"Garhi Yasin","id":"10860","nametype":"Valid","recclass":"Iron, IIE","mass":"380","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"27.883330","reclong":"68.533330","geolocation":{"type":"Point","coordinates":[68.53333,27.88333]}} +,{"name":"Garland","id":"10861","nametype":"Valid","recclass":"Diogenite-pm","mass":"102","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"41.683330","reclong":"-112.133330","geolocation":{"type":"Point","coordinates":[-112.13333,41.68333]},":@computed_region_cbhk_fwbd":"13",":@computed_region_nnqa_25f4":"2985"} +,{"name":"Gashua","id":"44882","nametype":"Valid","recclass":"L6","mass":"4162","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"12.850000","reclong":"11.033330","geolocation":{"type":"Point","coordinates":[11.03333,12.85]}} +,{"name":"Gasseltepaoua","id":"10866","nametype":"Valid","recclass":"H5","fall":"Fell","year":"2000-01-01T00:00:00.000","reclat":"14.150830","reclong":"-2.041670","geolocation":{"type":"Point","coordinates":[-2.04167,14.15083]}} +,{"name":"Geidam","id":"10870","nametype":"Valid","recclass":"H5","mass":"725","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"12.916670","reclong":"11.916670","geolocation":{"type":"Point","coordinates":[11.91667,12.91667]}} +,{"name":"Gifu","id":"10914","nametype":"Valid","recclass":"L6","mass":"14290","fall":"Fell","year":"1909-01-01T00:00:00.000","reclat":"35.533330","reclong":"136.883330","geolocation":{"type":"Point","coordinates":[136.88333,35.53333]}} +,{"name":"Girgenti","id":"10917","nametype":"Valid","recclass":"L6","mass":"18000","fall":"Fell","year":"1853-01-01T00:00:00.000","reclat":"37.316670","reclong":"13.566670","geolocation":{"type":"Point","coordinates":[13.56667,37.31667]}} +,{"name":"Git-Git","id":"10919","nametype":"Valid","recclass":"L6","mass":"480","fall":"Fell","year":"1947-01-01T00:00:00.000","reclat":"9.600000","reclong":"9.916670","geolocation":{"type":"Point","coordinates":[9.91667,9.6]}} +,{"name":"Glanerbrug","id":"10923","nametype":"Valid","recclass":"L/LL5","mass":"670","fall":"Fell","year":"1990-01-01T00:00:00.000","reclat":"52.200000","reclong":"6.866670","geolocation":{"type":"Point","coordinates":[6.86667,52.2]}} +,{"name":"Glanggang","id":"10924","nametype":"Valid","recclass":"H5-6","mass":"1303","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"-7.250000","reclong":"107.700000","geolocation":{"type":"Point","coordinates":[107.7,-7.25]}} +,{"name":"Glasatovo","id":"10926","nametype":"Valid","recclass":"H4","mass":"152000","fall":"Fell","year":"1918-01-01T00:00:00.000","reclat":"57.350000","reclong":"37.616670","geolocation":{"type":"Point","coordinates":[37.61667,57.35]}} +,{"name":"Glatton","id":"10930","nametype":"Valid","recclass":"L6","mass":"767","fall":"Fell","year":"1991-01-01T00:00:00.000","reclat":"52.459720","reclong":"-0.300000","geolocation":{"type":"Point","coordinates":[-0.3,52.45972]}} +,{"name":"Gnadenfrei","id":"10936","nametype":"Valid","recclass":"H5","mass":"1750","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"50.666670","reclong":"16.766670","geolocation":{"type":"Point","coordinates":[16.76667,50.66667]}} +,{"name":"Gopalpur","id":"10948","nametype":"Valid","recclass":"H6","mass":"1600","fall":"Fell","year":"1865-01-01T00:00:00.000","reclat":"24.233330","reclong":"89.050000","geolocation":{"type":"Point","coordinates":[89.05,24.23333]}} +,{"name":"Gorlovka","id":"10949","nametype":"Valid","recclass":"H3.7","mass":"3618","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"48.283330","reclong":"38.083330","geolocation":{"type":"Point","coordinates":[38.08333,48.28333]}} +,{"name":"Granes","id":"10956","nametype":"Valid","recclass":"L6","mass":"9000","fall":"Fell","year":"1964-01-01T00:00:00.000","reclat":"42.900000","reclong":"2.250000","geolocation":{"type":"Point","coordinates":[2.25,42.9]}} +,{"name":"Grefsheim","id":"11196","nametype":"Valid","recclass":"L5","mass":"45.5","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"60.666670","reclong":"11.000000","geolocation":{"type":"Point","coordinates":[11,60.66667]}} +,{"name":"Grimsby","id":"50911","nametype":"Valid","recclass":"H5","mass":"215","fall":"Fell","year":"2009-01-01T00:00:00.000","reclat":"43.200000","reclong":"-79.616670","geolocation":{"type":"Point","coordinates":[-79.61667,43.2]}} +,{"name":"Grosnaja","id":"11206","nametype":"Valid","recclass":"CV3","mass":"3500","fall":"Fell","year":"1861-01-01T00:00:00.000","reclat":"43.666670","reclong":"45.383330","geolocation":{"type":"Point","coordinates":[45.38333,43.66667]}} +,{"name":"Gross-Divina","id":"11207","nametype":"Valid","recclass":"H5","mass":"10500","fall":"Fell","year":"1837-01-01T00:00:00.000","reclat":"49.266670","reclong":"18.716670","geolocation":{"type":"Point","coordinates":[18.71667,49.26667]}} +,{"name":"Grossliebenthal","id":"11208","nametype":"Valid","recclass":"L6","mass":"8000","fall":"Fell","year":"1881-01-01T00:00:00.000","reclat":"46.350000","reclong":"30.583330","geolocation":{"type":"Point","coordinates":[30.58333,46.35]}} +,{"name":"Grüneberg","id":"11426","nametype":"Valid","recclass":"H4","mass":"1000","fall":"Fell","year":"1841-01-01T00:00:00.000","reclat":"51.933330","reclong":"15.500000","geolocation":{"type":"Point","coordinates":[15.5,51.93333]}} +,{"name":"Grzempach","id":"11429","nametype":"Valid","recclass":"H5","mass":"690","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"52.866670","reclong":"16.633330","geolocation":{"type":"Point","coordinates":[16.63333,52.86667]}} +,{"name":"Gualeguaychú","id":"11432","nametype":"Valid","recclass":"H6","mass":"22000","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"-33.000000","reclong":"-58.616670","geolocation":{"type":"Point","coordinates":[-58.61667,-33]}} +,{"name":"Guangmingshan","id":"11435","nametype":"Valid","recclass":"H5","mass":"2910","fall":"Fell","year":"1996-01-01T00:00:00.000","reclat":"39.804170","reclong":"122.763890","geolocation":{"type":"Point","coordinates":[122.76389,39.80417]}} +,{"name":"Guangnan","id":"11436","nametype":"Valid","recclass":"L6","fall":"Fell","year":"1983-01-01T00:00:00.000","reclat":"24.100000","reclong":"105.000000","geolocation":{"type":"Point","coordinates":[105,24.1]}} +,{"name":"Guangrao","id":"11437","nametype":"Valid","recclass":"L6","mass":"1900","fall":"Fell","year":"1980-01-01T00:00:00.000","reclat":"37.100000","reclong":"118.400000","geolocation":{"type":"Point","coordinates":[118.4,37.1]}} +,{"name":"Guareña","id":"11439","nametype":"Valid","recclass":"H6","mass":"39000","fall":"Fell","year":"1892-01-01T00:00:00.000","reclat":"38.733330","reclong":"-6.016670","geolocation":{"type":"Point","coordinates":[-6.01667,38.73333]}} +,{"name":"Guêa","id":"11440","nametype":"Valid","recclass":"Stone-uncl","mass":"1915","fall":"Fell","year":"1891-01-01T00:00:00.000","reclat":"43.766670","reclong":"20.233330","geolocation":{"type":"Point","coordinates":[20.23333,43.76667]}} +,{"name":"Guibga","id":"11442","nametype":"Valid","recclass":"L5","mass":"288","fall":"Fell","year":"1972-01-01T00:00:00.000","reclat":"13.500000","reclong":"-0.683330","geolocation":{"type":"Point","coordinates":[-0.68333,13.5]}} +,{"name":"Guidder","id":"11443","nametype":"Valid","recclass":"LL5","mass":"968","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"9.916670","reclong":"13.983330","geolocation":{"type":"Point","coordinates":[13.98333,9.91667]}} +,{"name":"Gujargaon","id":"11448","nametype":"Valid","recclass":"H5","mass":"2449","fall":"Fell","year":"1982-01-01T00:00:00.000","reclat":"22.983330","reclong":"76.050000","geolocation":{"type":"Point","coordinates":[76.05,22.98333]}} +,{"name":"Gujba","id":"11449","nametype":"Valid","recclass":"CBa","mass":"100000","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"11.491670","reclong":"11.658330","geolocation":{"type":"Point","coordinates":[11.65833,11.49167]}} +,{"name":"Gumoschnik","id":"11450","nametype":"Valid","recclass":"H5","mass":"5700","fall":"Fell","year":"1904-01-01T00:00:00.000","reclat":"42.900000","reclong":"24.700000","geolocation":{"type":"Point","coordinates":[24.7,42.9]}} +,{"name":"Gurram Konda","id":"11464","nametype":"Valid","recclass":"L6","mass":"28","fall":"Fell","year":"1814-01-01T00:00:00.000","reclat":"13.783330","reclong":"78.566670","geolocation":{"type":"Point","coordinates":[78.56667,13.78333]}} +,{"name":"Gursum","id":"11465","nametype":"Valid","recclass":"H4/5","mass":"34650","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"9.366670","reclong":"42.416670","geolocation":{"type":"Point","coordinates":[42.41667,9.36667]}} +,{"name":"Gütersloh","id":"11466","nametype":"Valid","recclass":"H3/4","mass":"1000","fall":"Fell","year":"1851-01-01T00:00:00.000","reclat":"51.916670","reclong":"8.383330","geolocation":{"type":"Point","coordinates":[8.38333,51.91667]}} +,{"name":"Gyokukei","id":"11467","nametype":"Valid","recclass":"OC","mass":"1320","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"35.000000","reclong":"127.500000","geolocation":{"type":"Point","coordinates":[127.5,35]}} +,{"name":"Hachi-oji","id":"11468","nametype":"Valid","recclass":"H?","mass":"0.2","fall":"Fell","year":"1817-01-01T00:00:00.000","reclat":"35.650000","reclong":"139.333330","geolocation":{"type":"Point","coordinates":[139.33333,35.65]}} +,{"name":"Hainaut","id":"11472","nametype":"Valid","recclass":"H3-6","mass":"9000","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"50.316670","reclong":"3.733330","geolocation":{"type":"Point","coordinates":[3.73333,50.31667]}} +,{"name":"Hallingeberg","id":"11479","nametype":"Valid","recclass":"L3.4","mass":"1456","fall":"Fell","year":"1944-01-01T00:00:00.000","reclat":"57.816670","reclong":"16.233330","geolocation":{"type":"Point","coordinates":[16.23333,57.81667]}} +,{"name":"Hamlet","id":"11485","nametype":"Valid","recclass":"LL4","mass":"3710","fall":"Fell","year":"1959-01-01T00:00:00.000","reclat":"41.383330","reclong":"-86.600000","geolocation":{"type":"Point","coordinates":[-86.6,41.38333]},":@computed_region_cbhk_fwbd":"35",":@computed_region_nnqa_25f4":"1205"} +,{"name":"Haraiya","id":"11824","nametype":"Valid","recclass":"Eucrite-mmict","mass":"1000","fall":"Fell","year":"1878-01-01T00:00:00.000","reclat":"26.800000","reclong":"82.533330","geolocation":{"type":"Point","coordinates":[82.53333,26.8]}} +,{"name":"Haripura","id":"11829","nametype":"Valid","recclass":"CM2","mass":"315","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"28.383330","reclong":"75.783330","geolocation":{"type":"Point","coordinates":[75.78333,28.38333]}} +,{"name":"Harleton","id":"11830","nametype":"Valid","recclass":"L6","mass":"8360","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"32.675000","reclong":"-94.511670","geolocation":{"type":"Point","coordinates":[-94.51167,32.675]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"2025"} +,{"name":"Harrison County","id":"11842","nametype":"Valid","recclass":"L6","mass":"680","fall":"Fell","year":"1859-01-01T00:00:00.000","reclat":"38.250000","reclong":"-86.166670","geolocation":{"type":"Point","coordinates":[-86.16667,38.25]},":@computed_region_cbhk_fwbd":"35",":@computed_region_nnqa_25f4":"1855"} +,{"name":"Hashima","id":"11848","nametype":"Valid","recclass":"H4","mass":"1110.5999999999999","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"35.294500","reclong":"136.700330","geolocation":{"type":"Point","coordinates":[136.70033,35.2945]}} +,{"name":"Hassi-Jekna","id":"11852","nametype":"Valid","recclass":"Iron, IAB-sHL","mass":"1250","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"28.950000","reclong":"0.816670","geolocation":{"type":"Point","coordinates":[0.81667,28.95]}} +,{"name":"Hatford","id":"11855","nametype":"Valid","recclass":"Stone-uncl","mass":"29000","fall":"Fell","year":"1628-01-01T00:00:00.000","reclat":"51.650000","reclong":"-1.516670","geolocation":{"type":"Point","coordinates":[-1.51667,51.65]}} +,{"name":"Haverö","id":"11859","nametype":"Valid","recclass":"Ureilite","mass":"1544","fall":"Fell","year":"1971-01-01T00:00:00.000","reclat":"60.245560","reclong":"22.061940","geolocation":{"type":"Point","coordinates":[22.06194,60.24556]}} +,{"name":"Hedeskoga","id":"11869","nametype":"Valid","recclass":"H5","mass":"3500","fall":"Fell","year":"1922-01-01T00:00:00.000","reclat":"55.466670","reclong":"13.783330","geolocation":{"type":"Point","coordinates":[13.78333,55.46667]}} +,{"name":"Hedjaz","id":"11870","nametype":"Valid","recclass":"L3.7-6","mass":"6100","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"27.333330","reclong":"35.666670","geolocation":{"type":"Point","coordinates":[35.66667,27.33333]}} +,{"name":"Heredia","id":"11875","nametype":"Valid","recclass":"H5","mass":"1000","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"10.000000","reclong":"-84.100000","geolocation":{"type":"Point","coordinates":[-84.1,10]}} +,{"name":"Hessle","id":"11878","nametype":"Valid","recclass":"H5","mass":"20000","fall":"Fell","year":"1869-01-01T00:00:00.000","reclat":"59.850000","reclong":"17.666670","geolocation":{"type":"Point","coordinates":[17.66667,59.85]}} +,{"name":"Higashi-koen","id":"11883","nametype":"Valid","recclass":"H5","mass":"750","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"33.600000","reclong":"130.433330","geolocation":{"type":"Point","coordinates":[130.43333,33.6]}} +,{"name":"High Possil","id":"11884","nametype":"Valid","recclass":"L6","mass":"4500","fall":"Fell","year":"1804-01-01T00:00:00.000","reclat":"55.900000","reclong":"-4.233330","geolocation":{"type":"Point","coordinates":[-4.23333,55.9]}} +,{"name":"Hiroshima","id":"11889","nametype":"Valid","recclass":"H5","mass":"414","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"34.450000","reclong":"132.383330","geolocation":{"type":"Point","coordinates":[132.38333,34.45]}} +,{"name":"Hoima","id":"44714","nametype":"Valid","recclass":"H6","mass":"167.7","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"1.345000","reclong":"31.472780","geolocation":{"type":"Point","coordinates":[31.47278,1.345]}} +,{"name":"Hökmark","id":"11893","nametype":"Valid","recclass":"L4","mass":"305.5","fall":"Fell","year":"1954-01-01T00:00:00.000","reclat":"64.433330","reclong":"21.200000","geolocation":{"type":"Point","coordinates":[21.2,64.43333]}} +,{"name":"Holbrook","id":"11894","nametype":"Valid","recclass":"L/LL6","mass":"220000","fall":"Fell","year":"1912-01-01T00:00:00.000","reclat":"34.900000","reclong":"-110.183330","geolocation":{"type":"Point","coordinates":[-110.18333,34.9]},":@computed_region_cbhk_fwbd":"7",":@computed_region_nnqa_25f4":"990"} +,{"name":"Holetta","id":"11895","nametype":"Valid","recclass":"Stone-uncl","mass":"1415","fall":"Fell","year":"1923-01-01T00:00:00.000","reclat":"9.066670","reclong":"38.416670","geolocation":{"type":"Point","coordinates":[38.41667,9.06667]}} +,{"name":"Homestead","id":"11901","nametype":"Valid","recclass":"L5","mass":"230000","fall":"Fell","year":"1875-01-01T00:00:00.000","reclat":"41.800000","reclong":"-91.866670","geolocation":{"type":"Point","coordinates":[-91.86667,41.8]},":@computed_region_cbhk_fwbd":"16",":@computed_region_nnqa_25f4":"284"} +,{"name":"Honolulu","id":"11904","nametype":"Valid","recclass":"L5","mass":"2420","fall":"Fell","year":"1825-01-01T00:00:00.000","reclat":"21.300000","reclong":"-157.866670","geolocation":{"type":"Point","coordinates":[-157.86667,21.3]},":@computed_region_cbhk_fwbd":"4",":@computed_region_nnqa_25f4":"1657"} +,{"name":"Hotse","id":"11913","nametype":"Valid","recclass":"L6","mass":"180","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"35.666670","reclong":"115.500000","geolocation":{"type":"Point","coordinates":[115.5,35.66667]}} +,{"name":"Hoxie","id":"11915","nametype":"Valid","recclass":"OC","mass":"266.10000000000002","fall":"Fell","year":"1963-01-01T00:00:00.000","reclat":"39.350000","reclong":"-100.450000","geolocation":{"type":"Point","coordinates":[-100.45,39.35]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1293"} +,{"name":"Hraschina","id":"11916","nametype":"Valid","recclass":"Iron, IID","mass":"49000","fall":"Fell","year":"1751-01-01T00:00:00.000","reclat":"46.100000","reclong":"16.333330","geolocation":{"type":"Point","coordinates":[16.33333,46.1]}} +,{"name":"Huaxi","id":"54719","nametype":"Valid","recclass":"H5","mass":"1600","fall":"Fell","year":"2010-01-01T00:00:00.000","reclat":"26.464690","reclong":"106.632410","geolocation":{"type":"Point","coordinates":[106.63241,26.46469]}} +,{"name":"Hungen","id":"11986","nametype":"Valid","recclass":"H6","mass":"112","fall":"Fell","year":"1877-01-01T00:00:00.000","reclat":"50.300000","reclong":"8.916670","geolocation":{"type":"Point","coordinates":[8.91667,50.3]}} +,{"name":"Hvittis","id":"11989","nametype":"Valid","recclass":"EL6","mass":"14000","fall":"Fell","year":"1901-01-01T00:00:00.000","reclat":"61.183330","reclong":"22.683330","geolocation":{"type":"Point","coordinates":[22.68333,61.18333]}} +,{"name":"Ibbenbüren","id":"11992","nametype":"Valid","recclass":"Diogenite","mass":"2000","fall":"Fell","year":"1870-01-01T00:00:00.000","reclat":"52.283330","reclong":"7.700000","geolocation":{"type":"Point","coordinates":[7.7,52.28333]}} +,{"name":"Ibitira","id":"11993","nametype":"Valid","recclass":"Eucrite-mmict","mass":"2500","fall":"Fell","year":"1957-01-01T00:00:00.000","reclat":"-20.000000","reclong":"-45.000000","geolocation":{"type":"Point","coordinates":[-45,-20]}} +,{"name":"Ibrisim","id":"11994","nametype":"Valid","recclass":"OC","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"38.000000","reclong":"35.000000","geolocation":{"type":"Point","coordinates":[35,38]}} +,{"name":"Ichkala","id":"11995","nametype":"Valid","recclass":"H6","mass":"3973","fall":"Fell","year":"1936-01-01T00:00:00.000","reclat":"58.200000","reclong":"82.933330","geolocation":{"type":"Point","coordinates":[82.93333,58.2]}} +,{"name":"Idutywa","id":"12000","nametype":"Valid","recclass":"H5","mass":"3457","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"-32.100000","reclong":"28.333330","geolocation":{"type":"Point","coordinates":[28.33333,-32.1]}} +,{"name":"Iguaracu","id":"12003","nametype":"Valid","recclass":"H5","mass":"1200","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"-23.200000","reclong":"-51.833330","geolocation":{"type":"Point","coordinates":[-51.83333,-23.2]}} +,{"name":"Ijopega","id":"12004","nametype":"Valid","recclass":"H6","mass":"7330","fall":"Fell","year":"1975-01-01T00:00:00.000","reclat":"-6.033330","reclong":"145.366670","geolocation":{"type":"Point","coordinates":[145.36667,-6.03333]}} +,{"name":"Indarch","id":"12027","nametype":"Valid","recclass":"EH4","mass":"27000","fall":"Fell","year":"1891-01-01T00:00:00.000","reclat":"39.750000","reclong":"46.666670","geolocation":{"type":"Point","coordinates":[46.66667,39.75]}} +,{"name":"Independence","id":"12028","nametype":"Valid","recclass":"L6","mass":"880","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"39.083330","reclong":"-94.400000","geolocation":{"type":"Point","coordinates":[-94.4,39.08333]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"525"} +,{"name":"Inner Mongolia","id":"12037","nametype":"Valid","recclass":"L6","mass":"3000","fall":"Fell","year":"1963-01-01T00:00:00.000","reclat":"41.000000","reclong":"112.000000","geolocation":{"type":"Point","coordinates":[112,41]}} +,{"name":"Innisfree","id":"12039","nametype":"Valid","recclass":"L5","mass":"4576","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"53.415000","reclong":"-111.337500","geolocation":{"type":"Point","coordinates":[-111.3375,53.415]}} +,{"name":"Ipiranga","id":"12043","nametype":"Valid","recclass":"H6","mass":"7000","fall":"Fell","year":"1972-01-01T00:00:00.000","reclat":"-25.500000","reclong":"-54.500000","geolocation":{"type":"Point","coordinates":[-54.5,-25.5]}} +,{"name":"Ishinga","id":"12049","nametype":"Valid","recclass":"H","mass":"1300","fall":"Fell","year":"1954-01-01T00:00:00.000","reclat":"-8.933330","reclong":"33.800000","geolocation":{"type":"Point","coordinates":[33.8,-8.93333]}} +,{"name":"Isthilart","id":"12053","nametype":"Valid","recclass":"H5","mass":"3050","fall":"Fell","year":"1928-01-01T00:00:00.000","reclat":"-31.183330","reclong":"-57.950000","geolocation":{"type":"Point","coordinates":[-57.95,-31.18333]}} +,{"name":"Itapicuru-Mirim","id":"12056","nametype":"Valid","recclass":"H5","mass":"2024","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"-3.400000","reclong":"-44.333330","geolocation":{"type":"Point","coordinates":[-44.33333,-3.4]}} +,{"name":"Itqiy","id":"12058","nametype":"Valid","recclass":"EH7-an","mass":"4720","fall":"Fell","year":"1990-01-01T00:00:00.000","reclat":"26.590830","reclong":"-12.952170","geolocation":{"type":"Point","coordinates":[-12.95217,26.59083]}} +,{"name":"Ivuna","id":"12063","nametype":"Valid","recclass":"CI1","mass":"704.5","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"-8.416670","reclong":"32.433330","geolocation":{"type":"Point","coordinates":[32.43333,-8.41667]}} +,{"name":"Jackalsfontein","id":"12065","nametype":"Valid","recclass":"L6","mass":"48000","fall":"Fell","year":"1903-01-01T00:00:00.000","reclat":"-32.500000","reclong":"21.900000","geolocation":{"type":"Point","coordinates":[21.9,-32.5]}} +,{"name":"Jajh deh Kot Lalu","id":"12067","nametype":"Valid","recclass":"EL6","mass":"973","fall":"Fell","year":"1926-01-01T00:00:00.000","reclat":"26.750000","reclong":"68.416670","geolocation":{"type":"Point","coordinates":[68.41667,26.75]}} +,{"name":"Jalanash","id":"12068","nametype":"Valid","recclass":"Ureilite","mass":"700","fall":"Fell","year":"1990-01-01T00:00:00.000"} +,{"name":"Jalandhar","id":"12069","nametype":"Valid","recclass":"Iron","mass":"1967","fall":"Fell","year":"1621-01-01T00:00:00.000","reclat":"31.000000","reclong":"75.000000","geolocation":{"type":"Point","coordinates":[75,31]}} +,{"name":"Jamkheir","id":"12072","nametype":"Valid","recclass":"H6","mass":"22","fall":"Fell","year":"1866-01-01T00:00:00.000","reclat":"18.750000","reclong":"75.333330","geolocation":{"type":"Point","coordinates":[75.33333,18.75]}} +,{"name":"Jartai","id":"12074","nametype":"Valid","recclass":"L6","mass":"20500","fall":"Fell","year":"1979-01-01T00:00:00.000","reclat":"39.700000","reclong":"105.800000","geolocation":{"type":"Point","coordinates":[105.8,39.7]}} +,{"name":"Jelica","id":"12078","nametype":"Valid","recclass":"LL6","mass":"34000","fall":"Fell","year":"1889-01-01T00:00:00.000","reclat":"43.833330","reclong":"20.441670","geolocation":{"type":"Point","coordinates":[20.44167,43.83333]}} +,{"name":"Jemlapur","id":"12079","nametype":"Valid","recclass":"L6","mass":"450","fall":"Fell","year":"1901-01-01T00:00:00.000"} +,{"name":"Jesenice","id":"51589","nametype":"Valid","recclass":"L6","mass":"3667","fall":"Fell","year":"2009-01-01T00:00:00.000","reclat":"46.421370","reclong":"14.052170","geolocation":{"type":"Point","coordinates":[14.05217,46.42137]}} +,{"name":"Jhung","id":"12085","nametype":"Valid","recclass":"L5","mass":"5900","fall":"Fell","year":"1873-01-01T00:00:00.000","reclat":"31.300000","reclong":"72.383330","geolocation":{"type":"Point","coordinates":[72.38333,31.3]}} +,{"name":"Jiange","id":"12086","nametype":"Valid","recclass":"H5","mass":"222","fall":"Fell","year":"1964-01-01T00:00:00.000","reclat":"31.916670","reclong":"104.916670","geolocation":{"type":"Point","coordinates":[104.91667,31.91667]}} +,{"name":"Jianshi","id":"12087","nametype":"Valid","recclass":"Iron, IIIAB","mass":"600000","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"30.808330","reclong":"109.500000","geolocation":{"type":"Point","coordinates":[109.5,30.80833]}} +,{"name":"Jilin","id":"12171","nametype":"Valid","recclass":"H5","mass":"4000000","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"44.050000","reclong":"126.166670","geolocation":{"type":"Point","coordinates":[126.16667,44.05]}} +,{"name":"Jodiya","id":"47362","nametype":"Valid","recclass":"L5","mass":"100","fall":"Fell","year":"2006-01-01T00:00:00.000","reclat":"22.680000","reclong":"70.313330","geolocation":{"type":"Point","coordinates":[70.31333,22.68]}} +,{"name":"Jodzie","id":"12173","nametype":"Valid","recclass":"Howardite","mass":"30","fall":"Fell","year":"1877-01-01T00:00:00.000","reclat":"55.700000","reclong":"24.400000","geolocation":{"type":"Point","coordinates":[24.4,55.7]}} +,{"name":"Johnstown","id":"12198","nametype":"Valid","recclass":"Diogenite","mass":"40300","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"40.350000","reclong":"-104.900000","geolocation":{"type":"Point","coordinates":[-104.9,40.35]},":@computed_region_cbhk_fwbd":"9",":@computed_region_nnqa_25f4":"1072"} +,{"name":"Jolomba","id":"12199","nametype":"Valid","recclass":"LL6","mass":"483","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"-11.850000","reclong":"15.833330","geolocation":{"type":"Point","coordinates":[15.83333,-11.85]}} +,{"name":"Jonzac","id":"12202","nametype":"Valid","recclass":"Eucrite-mmict","mass":"5000","fall":"Fell","year":"1819-01-01T00:00:00.000","reclat":"45.433330","reclong":"-0.450000","geolocation":{"type":"Point","coordinates":[-0.45,45.43333]}} +,{"name":"Juancheng","id":"12203","nametype":"Valid","recclass":"H5","mass":"100000","fall":"Fell","year":"1997-01-01T00:00:00.000","reclat":"35.500000","reclong":"115.416670","geolocation":{"type":"Point","coordinates":[115.41667,35.5]}} +,{"name":"Judesegeri","id":"12207","nametype":"Valid","recclass":"H6","mass":"680","fall":"Fell","year":"1876-01-01T00:00:00.000","reclat":"12.850000","reclong":"76.800000","geolocation":{"type":"Point","coordinates":[76.8,12.85]}} +,{"name":"Jumapalo","id":"12209","nametype":"Valid","recclass":"L6","mass":"32490","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"-7.716670","reclong":"111.200000","geolocation":{"type":"Point","coordinates":[111.2,-7.71667]}} +,{"name":"Junan","id":"12210","nametype":"Valid","recclass":"L6","mass":"950","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"35.200000","reclong":"118.800000","geolocation":{"type":"Point","coordinates":[118.8,35.2]}} +,{"name":"Juromenha","id":"12213","nametype":"Valid","recclass":"Iron, IIIAB","mass":"25250","fall":"Fell","year":"1968-01-01T00:00:00.000","reclat":"38.740280","reclong":"-7.270000","geolocation":{"type":"Point","coordinates":[-7.27,38.74028]}} +,{"name":"Juvinas","id":"12214","nametype":"Valid","recclass":"Eucrite-mmict","mass":"91000","fall":"Fell","year":"1821-01-01T00:00:00.000","reclat":"44.716670","reclong":"4.300000","geolocation":{"type":"Point","coordinates":[4.3,44.71667]}} +,{"name":"Kaba","id":"12218","nametype":"Valid","recclass":"CV3","mass":"3000","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"47.350000","reclong":"21.300000","geolocation":{"type":"Point","coordinates":[21.3,47.35]}} +,{"name":"Kabo","id":"12220","nametype":"Valid","recclass":"H4","mass":"13400","fall":"Fell","year":"1971-01-01T00:00:00.000","reclat":"11.850000","reclong":"8.216670","geolocation":{"type":"Point","coordinates":[8.21667,11.85]}} +,{"name":"Kadonah","id":"12221","nametype":"Valid","recclass":"H6","mass":"89","fall":"Fell","year":"1822-01-01T00:00:00.000","reclat":"27.083330","reclong":"78.333330","geolocation":{"type":"Point","coordinates":[78.33333,27.08333]}} +,{"name":"Kaee","id":"12222","nametype":"Valid","recclass":"H5","mass":"230","fall":"Fell","year":"1838-01-01T00:00:00.000","reclat":"27.250000","reclong":"79.966670","geolocation":{"type":"Point","coordinates":[79.96667,27.25]}} +,{"name":"Kagarlyk","id":"12227","nametype":"Valid","recclass":"L6","mass":"1900","fall":"Fell","year":"1908-01-01T00:00:00.000","reclat":"49.866670","reclong":"30.833330","geolocation":{"type":"Point","coordinates":[30.83333,49.86667]}} +,{"name":"Kaidun","id":"12228","nametype":"Valid","recclass":"CR2","mass":"2000","fall":"Fell","year":"1980-01-01T00:00:00.000","reclat":"15.000000","reclong":"48.300000","geolocation":{"type":"Point","coordinates":[48.3,15]}} +,{"name":"Kainsaz","id":"12229","nametype":"Valid","recclass":"CO3.2","mass":"200000","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"55.433330","reclong":"53.250000","geolocation":{"type":"Point","coordinates":[53.25,55.43333]}} +,{"name":"Kakangari","id":"12230","nametype":"Valid","recclass":"K3","mass":"350","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"12.383330","reclong":"78.516670","geolocation":{"type":"Point","coordinates":[78.51667,12.38333]}} +,{"name":"Kakowa","id":"12231","nametype":"Valid","recclass":"L6","mass":"577","fall":"Fell","year":"1858-01-01T00:00:00.000","reclat":"45.133330","reclong":"21.666670","geolocation":{"type":"Point","coordinates":[21.66667,45.13333]}} +,{"name":"Kalaba","id":"12232","nametype":"Valid","recclass":"H4","mass":"950","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"-6.833330","reclong":"29.500000","geolocation":{"type":"Point","coordinates":[29.5,-6.83333]}} +,{"name":"Kalumbi","id":"12236","nametype":"Valid","recclass":"L6","mass":"4500","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"17.833330","reclong":"73.983330","geolocation":{"type":"Point","coordinates":[73.98333,17.83333]}} +,{"name":"Kamalpur","id":"12238","nametype":"Valid","recclass":"L6","mass":"2770","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"26.033330","reclong":"81.466670","geolocation":{"type":"Point","coordinates":[81.46667,26.03333]}} +,{"name":"Kamiomi","id":"12240","nametype":"Valid","recclass":"H5","mass":"448","fall":"Fell","year":"1913-01-01T00:00:00.000","reclat":"36.041670","reclong":"139.956670","geolocation":{"type":"Point","coordinates":[139.95667,36.04167]}} +,{"name":"Kamsagar","id":"12241","nametype":"Valid","recclass":"L6","mass":"1293","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"14.183330","reclong":"75.800000","geolocation":{"type":"Point","coordinates":[75.8,14.18333]}} +,{"name":"Kandahar (Afghanistan)","id":"12243","nametype":"Valid","recclass":"L6","mass":"299","fall":"Fell","year":"1959-01-01T00:00:00.000","reclat":"31.600000","reclong":"65.783330","geolocation":{"type":"Point","coordinates":[65.78333,31.6]}} +,{"name":"Kangean","id":"12245","nametype":"Valid","recclass":"H5","mass":"1630","fall":"Fell","year":"1908-01-01T00:00:00.000","reclat":"-7.000000","reclong":"115.500000","geolocation":{"type":"Point","coordinates":[115.5,-7]}} +,{"name":"Kangra Valley","id":"12246","nametype":"Valid","recclass":"H5","mass":"400","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"32.083330","reclong":"76.300000","geolocation":{"type":"Point","coordinates":[76.3,32.08333]}} +,{"name":"Kapoeta","id":"12251","nametype":"Valid","recclass":"Howardite","mass":"11355","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"4.700000","reclong":"33.633330","geolocation":{"type":"Point","coordinates":[33.63333,4.7]}} +,{"name":"Kaprada","id":"47357","nametype":"Valid","recclass":"L5/6","mass":"1600","fall":"Fell","year":"2004-01-01T00:00:00.000","reclat":"20.339160","reclong":"73.223290","geolocation":{"type":"Point","coordinates":[73.22329,20.33916]}} +,{"name":"Kaptal-Aryk","id":"12253","nametype":"Valid","recclass":"L6","mass":"3500","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"42.450000","reclong":"73.366670","geolocation":{"type":"Point","coordinates":[73.36667,42.45]}} +,{"name":"Karakol","id":"12256","nametype":"Valid","recclass":"LL6","mass":"3000","fall":"Fell","year":"1840-01-01T00:00:00.000","reclat":"47.216670","reclong":"81.016670","geolocation":{"type":"Point","coordinates":[81.01667,47.21667]}} +,{"name":"Karatu","id":"12258","nametype":"Valid","recclass":"LL6","mass":"2220","fall":"Fell","year":"1963-01-01T00:00:00.000","reclat":"-3.500000","reclong":"35.583330","geolocation":{"type":"Point","coordinates":[35.58333,-3.5]}} +,{"name":"Karewar","id":"12260","nametype":"Valid","recclass":"L6","mass":"180","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"12.900000","reclong":"7.150000","geolocation":{"type":"Point","coordinates":[7.15,12.9]}} +,{"name":"Karkh","id":"12262","nametype":"Valid","recclass":"L6","mass":"22000","fall":"Fell","year":"1905-01-01T00:00:00.000","reclat":"27.800000","reclong":"67.166670","geolocation":{"type":"Point","coordinates":[67.16667,27.8]}} +,{"name":"Karloowala","id":"12263","nametype":"Valid","recclass":"L6","mass":"2950","fall":"Fell","year":"1955-01-01T00:00:00.000","reclat":"31.583330","reclong":"71.600000","geolocation":{"type":"Point","coordinates":[71.6,31.58333]}} +,{"name":"Karoonda","id":"12264","nametype":"Valid","recclass":"CK4","mass":"41730","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"-35.083330","reclong":"139.916670","geolocation":{"type":"Point","coordinates":[139.91667,-35.08333]}} +,{"name":"Kasamatsu","id":"12266","nametype":"Valid","recclass":"H","mass":"710","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"35.366670","reclong":"136.766670","geolocation":{"type":"Point","coordinates":[136.76667,35.36667]}} +,{"name":"Kasauli","id":"30740","nametype":"Valid","recclass":"H4","mass":"16820","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"29.583330","reclong":"77.583330","geolocation":{"type":"Point","coordinates":[77.58333,29.58333]}} +,{"name":"Katagum","id":"35465","nametype":"Valid","recclass":"L6","mass":"1500","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"11.333330","reclong":"10.083330","geolocation":{"type":"Point","coordinates":[10.08333,11.33333]}} +,{"name":"Kavarpura","id":"47351","nametype":"Valid","recclass":"Iron, IIE-an","mass":"6800","fall":"Fell","year":"2006-01-01T00:00:00.000","reclat":"25.143330","reclong":"75.813330","geolocation":{"type":"Point","coordinates":[75.81333,25.14333]}} +,{"name":"Kayakent","id":"12268","nametype":"Valid","recclass":"Iron, IIIAB","mass":"85000","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"39.263330","reclong":"31.780000","geolocation":{"type":"Point","coordinates":[31.78,39.26333]}} +,{"name":"Kediri","id":"12270","nametype":"Valid","recclass":"L4","mass":"3300","fall":"Fell","year":"1940-01-01T00:00:00.000","reclat":"-7.750000","reclong":"112.016670","geolocation":{"type":"Point","coordinates":[112.01667,-7.75]}} +,{"name":"Kemer","id":"53654","nametype":"Valid","recclass":"L4","mass":"5760","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"36.541940","reclong":"29.418220","geolocation":{"type":"Point","coordinates":[29.41822,36.54194]}} +,{"name":"Kendleton","id":"12275","nametype":"Valid","recclass":"L4","mass":"6937","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"29.450000","reclong":"-96.000000","geolocation":{"type":"Point","coordinates":[-96,29.45]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"3190"} +,{"name":"Kendrapara","id":"12276","nametype":"Valid","recclass":"H4-5","mass":"6669.2","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"20.462500","reclong":"86.702780","geolocation":{"type":"Point","coordinates":[86.70278,20.4625]}} +,{"name":"Kerilis","id":"12282","nametype":"Valid","recclass":"H5","mass":"5000","fall":"Fell","year":"1874-01-01T00:00:00.000","reclat":"48.400000","reclong":"-3.300000","geolocation":{"type":"Point","coordinates":[-3.3,48.4]}} +,{"name":"Kernouve","id":"12284","nametype":"Valid","recclass":"H6","mass":"80000","fall":"Fell","year":"1869-01-01T00:00:00.000","reclat":"48.116670","reclong":"-3.083330","geolocation":{"type":"Point","coordinates":[-3.08333,48.11667]}} +,{"name":"Kesen","id":"12286","nametype":"Valid","recclass":"H4","mass":"135000","fall":"Fell","year":"1850-01-01T00:00:00.000","reclat":"38.983330","reclong":"141.616670","geolocation":{"type":"Point","coordinates":[141.61667,38.98333]}} +,{"name":"Khairpur","id":"12288","nametype":"Valid","recclass":"EL6","mass":"13600","fall":"Fell","year":"1873-01-01T00:00:00.000","reclat":"29.533330","reclong":"72.300000","geolocation":{"type":"Point","coordinates":[72.3,29.53333]}} +,{"name":"Khanpur","id":"12289","nametype":"Valid","recclass":"LL5","mass":"3698","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"25.550000","reclong":"83.116670","geolocation":{"type":"Point","coordinates":[83.11667,25.55]}} +,{"name":"Kharkov","id":"12291","nametype":"Valid","recclass":"L6","mass":"1500","fall":"Fell","year":"1787-01-01T00:00:00.000","reclat":"50.625000","reclong":"35.075000","geolocation":{"type":"Point","coordinates":[35.075,50.625]}} +,{"name":"Kheragur","id":"12294","nametype":"Valid","recclass":"L6","mass":"450","fall":"Fell","year":"1860-01-01T00:00:00.000","reclat":"26.950000","reclong":"77.883330","geolocation":{"type":"Point","coordinates":[77.88333,26.95]}} +,{"name":"Khetri","id":"12296","nametype":"Valid","recclass":"H6","mass":"100","fall":"Fell","year":"1867-01-01T00:00:00.000","reclat":"28.016670","reclong":"75.816670","geolocation":{"type":"Point","coordinates":[75.81667,28.01667]}} +,{"name":"Khmelevka","id":"12297","nametype":"Valid","recclass":"L5","mass":"6109","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"56.750000","reclong":"75.333330","geolocation":{"type":"Point","coordinates":[75.33333,56.75]}} +,{"name":"Khohar","id":"12298","nametype":"Valid","recclass":"L3.6","mass":"9700","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"25.100000","reclong":"81.533330","geolocation":{"type":"Point","coordinates":[81.53333,25.1]}} +,{"name":"Khor Temiki","id":"12299","nametype":"Valid","recclass":"Aubrite","mass":"3200","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"16.000000","reclong":"36.000000","geolocation":{"type":"Point","coordinates":[36,16]}} +,{"name":"Kidairat","id":"12300","nametype":"Valid","recclass":"H6","mass":"100000","fall":"Fell","year":"1983-01-01T00:00:00.000","reclat":"14.000000","reclong":"28.000000","geolocation":{"type":"Point","coordinates":[28,14]}} +,{"name":"Kiel","id":"12301","nametype":"Valid","recclass":"L6","mass":"737.6","fall":"Fell","year":"1962-01-01T00:00:00.000","reclat":"54.400000","reclong":"10.150000","geolocation":{"type":"Point","coordinates":[10.15,54.4]}} +,{"name":"Kiffa","id":"12303","nametype":"Valid","recclass":"H5","mass":"1500","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"16.583330","reclong":"-11.333330","geolocation":{"type":"Point","coordinates":[-11.33333,16.58333]}} +,{"name":"Kijima (1906)","id":"12305","nametype":"Valid","recclass":"Stone-uncl","mass":"331","fall":"Fell","year":"1906-01-01T00:00:00.000","reclat":"36.850000","reclong":"138.383330","geolocation":{"type":"Point","coordinates":[138.38333,36.85]}} +,{"name":"Kikino","id":"12306","nametype":"Valid","recclass":"H6","mass":"195","fall":"Fell","year":"1809-01-01T00:00:00.000","reclat":"55.000000","reclong":"34.000000","geolocation":{"type":"Point","coordinates":[34,55]}} +,{"name":"Kilabo","id":"12307","nametype":"Valid","recclass":"LL6","mass":"19000","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"12.766670","reclong":"9.800000","geolocation":{"type":"Point","coordinates":[9.8,12.76667]}} +,{"name":"Kilbourn","id":"12308","nametype":"Valid","recclass":"H5","mass":"772","fall":"Fell","year":"1911-01-01T00:00:00.000","reclat":"43.583330","reclong":"-89.600000","geolocation":{"type":"Point","coordinates":[-89.6,43.58333]},":@computed_region_cbhk_fwbd":"41",":@computed_region_nnqa_25f4":"2971"} +,{"name":"Killeter","id":"12309","nametype":"Valid","recclass":"H6","mass":"140","fall":"Fell","year":"1844-01-01T00:00:00.000","reclat":"54.666670","reclong":"-7.666670","geolocation":{"type":"Point","coordinates":[-7.66667,54.66667]}} +,{"name":"Kingai","id":"12316","nametype":"Valid","recclass":"H6","mass":"67.400000000000006","fall":"Fell","year":"1967-01-01T00:00:00.000","reclat":"11.633330","reclong":"24.683330","geolocation":{"type":"Point","coordinates":[24.68333,11.63333]}} +,{"name":"Kirbyville","id":"12321","nametype":"Valid","recclass":"Eucrite-mmict","mass":"97.7","fall":"Fell","year":"1906-01-01T00:00:00.000","reclat":"30.750000","reclong":"-95.950000","geolocation":{"type":"Point","coordinates":[-95.95,30.75]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"2018"} +,{"name":"Kisvarsány","id":"12325","nametype":"Valid","recclass":"L6","mass":"1550","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"48.166670","reclong":"22.308330","geolocation":{"type":"Point","coordinates":[22.30833,48.16667]}} +,{"name":"Kitchener","id":"12326","nametype":"Valid","recclass":"L6","mass":"202.6","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"43.383330","reclong":"-80.383330","geolocation":{"type":"Point","coordinates":[-80.38333,43.38333]}} +,{"name":"Klein-Wenden","id":"12332","nametype":"Valid","recclass":"H6","mass":"3250","fall":"Fell","year":"1843-01-01T00:00:00.000","reclat":"51.600000","reclong":"10.800000","geolocation":{"type":"Point","coordinates":[10.8,51.6]}} +,{"name":"Knyahinya","id":"12335","nametype":"Valid","recclass":"L/LL5","mass":"500000","fall":"Fell","year":"1866-01-01T00:00:00.000","reclat":"48.900000","reclong":"22.400000","geolocation":{"type":"Point","coordinates":[22.4,48.9]}} +,{"name":"Kobe","id":"12336","nametype":"Valid","recclass":"CK4","mass":"136","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"34.733330","reclong":"135.166670","geolocation":{"type":"Point","coordinates":[135.16667,34.73333]}} +,{"name":"Kokubunji","id":"12342","nametype":"Valid","recclass":"L6","mass":"11510","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"34.300000","reclong":"133.950000","geolocation":{"type":"Point","coordinates":[133.95,34.3]}} +,{"name":"Komagome","id":"12343","nametype":"Valid","recclass":"Iron","mass":"238","fall":"Fell","year":"1926-01-01T00:00:00.000","reclat":"35.733330","reclong":"139.750000","geolocation":{"type":"Point","coordinates":[139.75,35.73333]}} +,{"name":"Konovo","id":"12344","nametype":"Valid","recclass":"LL5","mass":"90","fall":"Fell","year":"1931-01-01T00:00:00.000","reclat":"42.516670","reclong":"26.166670","geolocation":{"type":"Point","coordinates":[26.16667,42.51667]}} +,{"name":"Košice","id":"53810","nametype":"Valid","recclass":"H5","mass":"4300","fall":"Fell","year":"2010-01-01T00:00:00.000","reclat":"48.763670","reclong":"21.176330","geolocation":{"type":"Point","coordinates":[21.17633,48.76367]}} +,{"name":"Krähenberg","id":"12353","nametype":"Valid","recclass":"LL5","mass":"16500","fall":"Fell","year":"1869-01-01T00:00:00.000","reclat":"49.326940","reclong":"7.464720","geolocation":{"type":"Point","coordinates":[7.46472,49.32694]}} +,{"name":"Krasnoi-Ugol","id":"12355","nametype":"Valid","recclass":"L6","mass":"2440","fall":"Fell","year":"1829-01-01T00:00:00.000","reclat":"54.033330","reclong":"40.900000","geolocation":{"type":"Point","coordinates":[40.9,54.03333]}} +,{"name":"Krasnyi Klyuch","id":"12357","nametype":"Valid","recclass":"H5","mass":"4000","fall":"Fell","year":"1946-01-01T00:00:00.000","reclat":"54.333330","reclong":"56.083330","geolocation":{"type":"Point","coordinates":[56.08333,54.33333]}} +,{"name":"Krutikha","id":"12363","nametype":"Valid","recclass":"OC","mass":"845.2","fall":"Fell","year":"1906-01-01T00:00:00.000","reclat":"56.800000","reclong":"77.000000","geolocation":{"type":"Point","coordinates":[77,56.8]}} +,{"name":"Krymka","id":"12364","nametype":"Valid","recclass":"LL3.2","mass":"50000","fall":"Fell","year":"1946-01-01T00:00:00.000","reclat":"47.833330","reclong":"30.766670","geolocation":{"type":"Point","coordinates":[30.76667,47.83333]}} +,{"name":"Kukschin","id":"12368","nametype":"Valid","recclass":"L6","mass":"2250","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"51.150000","reclong":"31.700000","geolocation":{"type":"Point","coordinates":[31.7,51.15]}} +,{"name":"Kulak","id":"12369","nametype":"Valid","recclass":"L5","mass":"453.6","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"30.731110","reclong":"66.802220","geolocation":{"type":"Point","coordinates":[66.80222,30.73111]}} +,{"name":"Kuleschovka","id":"12370","nametype":"Valid","recclass":"L6","mass":"6000","fall":"Fell","year":"1811-01-01T00:00:00.000","reclat":"50.750000","reclong":"33.500000","geolocation":{"type":"Point","coordinates":[33.5,50.75]}} +,{"name":"Kulp","id":"12373","nametype":"Valid","recclass":"H6","mass":"3719","fall":"Fell","year":"1906-01-01T00:00:00.000","reclat":"41.116670","reclong":"45.000000","geolocation":{"type":"Point","coordinates":[45,41.11667]}} +,{"name":"Kunashak","id":"12377","nametype":"Valid","recclass":"L6","mass":"200000","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"55.783330","reclong":"61.366670","geolocation":{"type":"Point","coordinates":[61.36667,55.78333]}} +,{"name":"Kunya-Urgench","id":"12379","nametype":"Valid","recclass":"H5","mass":"1100000","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"42.250000","reclong":"59.200000","geolocation":{"type":"Point","coordinates":[59.2,42.25]}} +,{"name":"Kushiike","id":"12381","nametype":"Valid","recclass":"OC","mass":"4460","fall":"Fell","year":"1920-01-01T00:00:00.000","reclat":"37.050000","reclong":"138.383330","geolocation":{"type":"Point","coordinates":[138.38333,37.05]}} +,{"name":"Kusiali","id":"12382","nametype":"Valid","recclass":"L6","mass":"5","fall":"Fell","year":"1860-01-01T00:00:00.000","reclat":"29.683330","reclong":"78.383330","geolocation":{"type":"Point","coordinates":[78.38333,29.68333]}} +,{"name":"Kutais","id":"12383","nametype":"Valid","recclass":"H5","mass":"23","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"44.516670","reclong":"39.300000","geolocation":{"type":"Point","coordinates":[39.3,44.51667]}} +,{"name":"Kuttippuram","id":"12384","nametype":"Valid","recclass":"L6","mass":"45000","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"10.833330","reclong":"76.033330","geolocation":{"type":"Point","coordinates":[76.03333,10.83333]}} +,{"name":"Kuznetzovo","id":"12385","nametype":"Valid","recclass":"L6","mass":"4047","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"55.200000","reclong":"75.333330","geolocation":{"type":"Point","coordinates":[75.33333,55.2]}} +,{"name":"Kyushu","id":"12390","nametype":"Valid","recclass":"L6","mass":"45000","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"32.033330","reclong":"130.633330","geolocation":{"type":"Point","coordinates":[130.63333,32.03333]}} +,{"name":"La Bécasse","id":"12392","nametype":"Valid","recclass":"L6","mass":"2800","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"47.083330","reclong":"1.750000","geolocation":{"type":"Point","coordinates":[1.75,47.08333]}} +,{"name":"La Charca","id":"12394","nametype":"Valid","recclass":"OC","mass":"399","fall":"Fell","year":"1878-01-01T00:00:00.000","reclat":"20.666670","reclong":"-101.283330","geolocation":{"type":"Point","coordinates":[-101.28333,20.66667]}} +,{"name":"La Colina","id":"12395","nametype":"Valid","recclass":"H5","mass":"2000","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"-37.333330","reclong":"-61.533330","geolocation":{"type":"Point","coordinates":[-61.53333,-37.33333]}} +,{"name":"La Criolla","id":"12396","nametype":"Valid","recclass":"L6","mass":"45000","fall":"Fell","year":"1985-01-01T00:00:00.000","reclat":"-31.233330","reclong":"-58.166670","geolocation":{"type":"Point","coordinates":[-58.16667,-31.23333]}} +,{"name":"Laborel","id":"12408","nametype":"Valid","recclass":"H5","mass":"3833","fall":"Fell","year":"1871-01-01T00:00:00.000","reclat":"44.283330","reclong":"5.583330","geolocation":{"type":"Point","coordinates":[5.58333,44.28333]}} +,{"name":"Lahrauli","id":"12433","nametype":"Valid","recclass":"Ureilite","mass":"900","fall":"Fell","year":"1955-01-01T00:00:00.000","reclat":"26.783330","reclong":"82.716670","geolocation":{"type":"Point","coordinates":[82.71667,26.78333]}} +,{"name":"L'Aigle","id":"12434","nametype":"Valid","recclass":"L6","mass":"37000","fall":"Fell","year":"1803-01-01T00:00:00.000","reclat":"48.766670","reclong":"0.633330","geolocation":{"type":"Point","coordinates":[0.63333,48.76667]}} +,{"name":"Cumulus Hills 04075","id":"32531","nametype":"Valid","recclass":"Pallasite","mass":"9.6","fall":"Found","year":"2003-01-01T00:00:00.000"} +,{"name":"Lakangaon","id":"12435","nametype":"Valid","recclass":"Eucrite-mmict","mass":"212.5","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"21.866670","reclong":"76.033330","geolocation":{"type":"Point","coordinates":[76.03333,21.86667]}} +,{"name":"Lalitpur","id":"12451","nametype":"Valid","recclass":"L6","mass":"372","fall":"Fell","year":"1887-01-01T00:00:00.000","reclat":"24.450000","reclong":"78.566670","geolocation":{"type":"Point","coordinates":[78.56667,24.45]}} +,{"name":"Lancé","id":"12455","nametype":"Valid","recclass":"CO3.5","mass":"51700","fall":"Fell","year":"1872-01-01T00:00:00.000","reclat":"47.700000","reclong":"1.066670","geolocation":{"type":"Point","coordinates":[1.06667,47.7]}} +,{"name":"Lancon","id":"12456","nametype":"Valid","recclass":"H6","mass":"7000","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"43.750000","reclong":"5.116670","geolocation":{"type":"Point","coordinates":[5.11667,43.75]}} +,{"name":"Långhalsen","id":"12461","nametype":"Valid","recclass":"L6","mass":"2300","fall":"Fell","year":"1947-01-01T00:00:00.000","reclat":"58.850000","reclong":"16.733330","geolocation":{"type":"Point","coordinates":[16.73333,58.85]}} +,{"name":"Lanxi","id":"12464","nametype":"Valid","recclass":"L6","mass":"1282","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"46.241670","reclong":"126.196110","geolocation":{"type":"Point","coordinates":[126.19611,46.24167]}} +,{"name":"Lanzenkirchen","id":"12465","nametype":"Valid","recclass":"L4","mass":"7000","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"47.750000","reclong":"16.233330","geolocation":{"type":"Point","coordinates":[16.23333,47.75]}} +,{"name":"Laochenzhen","id":"12466","nametype":"Valid","recclass":"H5","mass":"14250","fall":"Fell","year":"1987-01-01T00:00:00.000","reclat":"33.133330","reclong":"115.166670","geolocation":{"type":"Point","coordinates":[115.16667,33.13333]}} +,{"name":"Launton","id":"12740","nametype":"Valid","recclass":"L6","mass":"1060","fall":"Fell","year":"1830-01-01T00:00:00.000","reclat":"51.900000","reclong":"-1.116670","geolocation":{"type":"Point","coordinates":[-1.11667,51.9]}} +,{"name":"Lavrentievka","id":"12743","nametype":"Valid","recclass":"L6","mass":"800","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"52.450000","reclong":"51.566670","geolocation":{"type":"Point","coordinates":[51.56667,52.45]}} +,{"name":"Le Pressoir","id":"12748","nametype":"Valid","recclass":"H5","mass":"3000","fall":"Fell","year":"1845-01-01T00:00:00.000","reclat":"47.166670","reclong":"0.433330","geolocation":{"type":"Point","coordinates":[0.43333,47.16667]}} +,{"name":"Le Teilleul","id":"12749","nametype":"Valid","recclass":"Howardite","mass":"780","fall":"Fell","year":"1845-01-01T00:00:00.000","reclat":"48.533330","reclong":"-0.866670","geolocation":{"type":"Point","coordinates":[-0.86667,48.53333]}} +,{"name":"Leedey","id":"12755","nametype":"Valid","recclass":"L6","mass":"51500","fall":"Fell","year":"1943-01-01T00:00:00.000","reclat":"35.883330","reclong":"-99.333330","geolocation":{"type":"Point","coordinates":[-99.33333,35.88333]},":@computed_region_cbhk_fwbd":"20",":@computed_region_nnqa_25f4":"608"} +,{"name":"Leeuwfontein","id":"12756","nametype":"Valid","recclass":"L6","mass":"460","fall":"Fell","year":"1912-01-01T00:00:00.000","reclat":"-25.666670","reclong":"28.366670","geolocation":{"type":"Point","coordinates":[28.36667,-25.66667]}} +,{"name":"Leighlinbridge","id":"12759","nametype":"Valid","recclass":"L6","mass":"271.39999999999998","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"52.666670","reclong":"-6.966670","geolocation":{"type":"Point","coordinates":[-6.96667,52.66667]}} +,{"name":"Leighton","id":"12760","nametype":"Valid","recclass":"H5","mass":"877","fall":"Fell","year":"1907-01-01T00:00:00.000","reclat":"34.583330","reclong":"-87.500000","geolocation":{"type":"Point","coordinates":[-87.5,34.58333]},":@computed_region_cbhk_fwbd":"29",":@computed_region_nnqa_25f4":"1585"} +,{"name":"Leonovka","id":"12765","nametype":"Valid","recclass":"L6","mass":"700","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"52.266670","reclong":"32.850000","geolocation":{"type":"Point","coordinates":[32.85,52.26667]}} +,{"name":"Les Ormes","id":"12769","nametype":"Valid","recclass":"L6","mass":"125","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"48.350000","reclong":"3.250000","geolocation":{"type":"Point","coordinates":[3.25,48.35]}} +,{"name":"Lesves","id":"12772","nametype":"Valid","recclass":"L6","mass":"2000","fall":"Fell","year":"1896-01-01T00:00:00.000","reclat":"50.366670","reclong":"4.733330","geolocation":{"type":"Point","coordinates":[4.73333,50.36667]}} +,{"name":"Lichtenberg","id":"14646","nametype":"Valid","recclass":"H6","mass":"4000","fall":"Fell","year":"1973-01-01T00:00:00.000","reclat":"-26.150000","reclong":"26.183330","geolocation":{"type":"Point","coordinates":[26.18333,-26.15]}} +,{"name":"Lillaverke","id":"14650","nametype":"Valid","recclass":"H5","mass":"6862","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"56.650000","reclong":"15.866670","geolocation":{"type":"Point","coordinates":[15.86667,56.65]}} +,{"name":"Limerick","id":"14652","nametype":"Valid","recclass":"H5","mass":"50000","fall":"Fell","year":"1813-01-01T00:00:00.000","reclat":"52.566670","reclong":"-8.783330","geolocation":{"type":"Point","coordinates":[-8.78333,52.56667]}} +,{"name":"Linum","id":"14655","nametype":"Valid","recclass":"L6","mass":"1862","fall":"Fell","year":"1854-01-01T00:00:00.000","reclat":"52.750000","reclong":"12.900000","geolocation":{"type":"Point","coordinates":[12.9,52.75]}} +,{"name":"Lishui","id":"14659","nametype":"Valid","recclass":"L5","mass":"498","fall":"Fell","year":"1978-01-01T00:00:00.000","reclat":"31.633330","reclong":"118.983330","geolocation":{"type":"Point","coordinates":[118.98333,31.63333]}} +,{"name":"Lissa","id":"14661","nametype":"Valid","recclass":"L6","mass":"12800","fall":"Fell","year":"1808-01-01T00:00:00.000","reclat":"50.200000","reclong":"14.850000","geolocation":{"type":"Point","coordinates":[14.85,50.2]}} +,{"name":"Little Piney","id":"14664","nametype":"Valid","recclass":"L5","mass":"491","fall":"Fell","year":"1839-01-01T00:00:00.000","reclat":"37.916670","reclong":"-92.083330","geolocation":{"type":"Point","coordinates":[-92.08333,37.91667]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"2171"} +,{"name":"Lixna","id":"14670","nametype":"Valid","recclass":"H4","mass":"5213","fall":"Fell","year":"1820-01-01T00:00:00.000","reclat":"56.000000","reclong":"26.433330","geolocation":{"type":"Point","coordinates":[26.43333,56]}} +,{"name":"Lodran","id":"14675","nametype":"Valid","recclass":"Lodranite","mass":"1000","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"29.533330","reclong":"71.800000","geolocation":{"type":"Point","coordinates":[71.8,29.53333]}} +,{"name":"Lohawat","id":"14678","nametype":"Valid","recclass":"Howardite","mass":"40000","fall":"Fell","year":"1994-01-01T00:00:00.000","reclat":"26.965560","reclong":"72.626670","geolocation":{"type":"Point","coordinates":[72.62667,26.96556]}} +,{"name":"Lorton","id":"52843","nametype":"Valid","recclass":"L6","mass":"329.7","fall":"Fell","year":"2010-01-01T00:00:00.000","reclat":"38.700660","reclong":"-77.211630","geolocation":{"type":"Point","coordinates":[-77.21163,38.70066]},":@computed_region_cbhk_fwbd":"40",":@computed_region_nnqa_25f4":"2770"} +,{"name":"Los Martinez","id":"14708","nametype":"Valid","recclass":"L6","mass":"25","fall":"Fell","year":"1894-01-01T00:00:00.000","reclat":"38.000000","reclong":"-0.833330","geolocation":{"type":"Point","coordinates":[-0.83333,38]}} +,{"name":"Lost City","id":"14711","nametype":"Valid","recclass":"H5","mass":"17000","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"36.008330","reclong":"-95.150000","geolocation":{"type":"Point","coordinates":[-95.15,36.00833]},":@computed_region_cbhk_fwbd":"20",":@computed_region_nnqa_25f4":"2711"} +,{"name":"Louisville","id":"14716","nametype":"Valid","recclass":"L6","mass":"1300","fall":"Fell","year":"1977-01-01T00:00:00.000","reclat":"38.250000","reclong":"-85.750000","geolocation":{"type":"Point","coordinates":[-85.75,38.25]},":@computed_region_cbhk_fwbd":"36",":@computed_region_nnqa_25f4":"1327"} +,{"name":"Łowicz","id":"14718","nametype":"Valid","recclass":"Mesosiderite-A3","mass":"59000","fall":"Fell","year":"1935-01-01T00:00:00.000","reclat":"52.000000","reclong":"19.916670","geolocation":{"type":"Point","coordinates":[19.91667,52]}} +,{"name":"Lua","id":"14721","nametype":"Valid","recclass":"L5","mass":"9241","fall":"Fell","year":"1926-01-01T00:00:00.000","reclat":"24.950000","reclong":"75.150000","geolocation":{"type":"Point","coordinates":[75.15,24.95]}} +,{"name":"Lucé","id":"14724","nametype":"Valid","recclass":"L6","mass":"3500","fall":"Fell","year":"1768-01-01T00:00:00.000","reclat":"47.850000","reclong":"0.483330","geolocation":{"type":"Point","coordinates":[0.48333,47.85]}} +,{"name":"Lumpkin","id":"14753","nametype":"Valid","recclass":"L6","mass":"340","fall":"Fell","year":"1869-01-01T00:00:00.000","reclat":"32.033330","reclong":"-84.766670","geolocation":{"type":"Point","coordinates":[-84.76667,32.03333]},":@computed_region_cbhk_fwbd":"31",":@computed_region_nnqa_25f4":"1567"} +,{"name":"Lunan","id":"14754","nametype":"Valid","recclass":"H6","mass":"2520","fall":"Fell","year":"1980-01-01T00:00:00.000","reclat":"24.800000","reclong":"103.300000","geolocation":{"type":"Point","coordinates":[103.3,24.8]}} +,{"name":"Lundsgård","id":"14755","nametype":"Valid","recclass":"L6","mass":"11000","fall":"Fell","year":"1889-01-01T00:00:00.000","reclat":"56.216670","reclong":"13.033330","geolocation":{"type":"Point","coordinates":[13.03333,56.21667]}} +,{"name":"Luotolax","id":"14756","nametype":"Valid","recclass":"Howardite","mass":"885","fall":"Fell","year":"1813-01-01T00:00:00.000","reclat":"61.200000","reclong":"27.700000","geolocation":{"type":"Point","coordinates":[27.7,61.2]}} +,{"name":"Luponnas","id":"14757","nametype":"Valid","recclass":"H3-5","mass":"14000","fall":"Fell","year":"1753-01-01T00:00:00.000","reclat":"46.216670","reclong":"5.000000","geolocation":{"type":"Point","coordinates":[5,46.21667]}} +,{"name":"Lusaka","id":"14759","nametype":"Valid","recclass":"Unknown","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"-7.216670","reclong":"29.433330","geolocation":{"type":"Point","coordinates":[29.43333,-7.21667]}} +,{"name":"Mabwe-Khoywa","id":"14764","nametype":"Valid","recclass":"L5","mass":"540","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"19.000000","reclong":"97.000000","geolocation":{"type":"Point","coordinates":[97,19]}} +,{"name":"Macau","id":"15370","nametype":"Valid","recclass":"H5","mass":"1500","fall":"Fell","year":"1836-01-01T00:00:00.000","reclat":"-5.200000","reclong":"-36.666670","geolocation":{"type":"Point","coordinates":[-36.66667,-5.2]}} +,{"name":"Machinga","id":"15371","nametype":"Valid","recclass":"L6","mass":"93200","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"-15.212220","reclong":"35.242220","geolocation":{"type":"Point","coordinates":[35.24222,-15.21222]}} +,{"name":"Macibini","id":"15372","nametype":"Valid","recclass":"Eucrite-pmict","mass":"1995","fall":"Fell","year":"1936-01-01T00:00:00.000","reclat":"-28.833330","reclong":"31.950000","geolocation":{"type":"Point","coordinates":[31.95,-28.83333]}} +,{"name":"Madhipura","id":"15379","nametype":"Valid","recclass":"L","mass":"1000","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"25.916670","reclong":"86.366670","geolocation":{"type":"Point","coordinates":[86.36667,25.91667]}} +,{"name":"Madiun","id":"15380","nametype":"Valid","recclass":"L6","mass":"400","fall":"Fell","year":"1935-01-01T00:00:00.000","reclat":"-7.750000","reclong":"111.533330","geolocation":{"type":"Point","coordinates":[111.53333,-7.75]}} +,{"name":"Madrid","id":"15382","nametype":"Valid","recclass":"L6","mass":"400","fall":"Fell","year":"1896-01-01T00:00:00.000","reclat":"40.416670","reclong":"-3.716670","geolocation":{"type":"Point","coordinates":[-3.71667,40.41667]}} +,{"name":"Mafra","id":"15383","nametype":"Valid","recclass":"L3-4","mass":"600","fall":"Fell","year":"1941-01-01T00:00:00.000","reclat":"-26.166670","reclong":"-49.933330","geolocation":{"type":"Point","coordinates":[-49.93333,-26.16667]}} +,{"name":"Magnesia","id":"15386","nametype":"Valid","recclass":"Iron, IAB-sHL","mass":"5000","fall":"Fell","year":"1899-01-01T00:00:00.000","reclat":"37.866670","reclong":"27.516670","geolocation":{"type":"Point","coordinates":[27.51667,37.86667]}} +,{"name":"Magombedze","id":"15387","nametype":"Valid","recclass":"H3-5","mass":"666.6","fall":"Fell","year":"1990-01-01T00:00:00.000","reclat":"-19.483330","reclong":"31.650000","geolocation":{"type":"Point","coordinates":[31.65,-19.48333]}} +,{"name":"Mahadevpur","id":"47361","nametype":"Valid","recclass":"H4/5","mass":"70500","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"27.666670","reclong":"95.783330","geolocation":{"type":"Point","coordinates":[95.78333,27.66667]}} +,{"name":"Maigatari-Danduma","id":"30751","nametype":"Valid","recclass":"H5/6","mass":"4629","fall":"Fell","year":"2004-01-01T00:00:00.000","reclat":"12.833330","reclong":"9.383330","geolocation":{"type":"Point","coordinates":[9.38333,12.83333]}} +,{"name":"Malaga","id":"15393","nametype":"Valid","recclass":"OC","mass":"150","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"32.216670","reclong":"-104.000000","geolocation":{"type":"Point","coordinates":[-104,32.21667]},":@computed_region_cbhk_fwbd":"11",":@computed_region_nnqa_25f4":"611"} +,{"name":"Malakal","id":"15394","nametype":"Valid","recclass":"L5","mass":"2000","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"9.500000","reclong":"31.750000","geolocation":{"type":"Point","coordinates":[31.75,9.5]}} +,{"name":"Malampaka","id":"15395","nametype":"Valid","recclass":"H","mass":"470","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"-3.133330","reclong":"33.516670","geolocation":{"type":"Point","coordinates":[33.51667,-3.13333]}} +,{"name":"Malotas","id":"15397","nametype":"Valid","recclass":"H5","fall":"Fell","year":"1931-01-01T00:00:00.000","reclat":"-28.933330","reclong":"-63.233330","geolocation":{"type":"Point","coordinates":[-63.23333,-28.93333]}} +,{"name":"Malvern","id":"15400","nametype":"Valid","recclass":"Eucrite-pmict","mass":"807","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"-29.450000","reclong":"26.766670","geolocation":{"type":"Point","coordinates":[26.76667,-29.45]}} +,{"name":"Mamra Springs","id":"15401","nametype":"Valid","recclass":"L6","mass":"1000","fall":"Fell","year":"1927-01-01T00:00:00.000","reclat":"45.216670","reclong":"62.083330","geolocation":{"type":"Point","coordinates":[62.08333,45.21667]}} +,{"name":"Manbhoom","id":"15402","nametype":"Valid","recclass":"LL6","mass":"1700","fall":"Fell","year":"1863-01-01T00:00:00.000","reclat":"23.050000","reclong":"86.700000","geolocation":{"type":"Point","coordinates":[86.7,23.05]}} +,{"name":"Manegaon","id":"15403","nametype":"Valid","recclass":"Diogenite","mass":"50","fall":"Fell","year":"1843-01-01T00:00:00.000","reclat":"20.966670","reclong":"76.100000","geolocation":{"type":"Point","coordinates":[76.1,20.96667]}} +,{"name":"Mangwendi","id":"15405","nametype":"Valid","recclass":"LL6","mass":"22300","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"-17.650000","reclong":"31.600000","geolocation":{"type":"Point","coordinates":[31.6,-17.65]}} +,{"name":"Manych","id":"15409","nametype":"Valid","recclass":"LL3.4","mass":"3555","fall":"Fell","year":"1951-01-01T00:00:00.000","reclat":"45.816670","reclong":"44.633330","geolocation":{"type":"Point","coordinates":[44.63333,45.81667]}} +,{"name":"Mardan","id":"15414","nametype":"Valid","recclass":"H5","mass":"4500","fall":"Fell","year":"1948-01-01T00:00:00.000","reclat":"34.233330","reclong":"72.083330","geolocation":{"type":"Point","coordinates":[72.08333,34.23333]}} +,{"name":"Maria Linden","id":"15418","nametype":"Valid","recclass":"L4","mass":"114","fall":"Fell","year":"1925-01-01T00:00:00.000"} +,{"name":"Mariaville","id":"15419","nametype":"Valid","recclass":"Iron","mass":"340","fall":"Fell","year":"1898-01-01T00:00:00.000","reclat":"42.716670","reclong":"-99.383330","geolocation":{"type":"Point","coordinates":[-99.38333,42.71667]},":@computed_region_cbhk_fwbd":"19",":@computed_region_nnqa_25f4":"471"} +,{"name":"Maribo","id":"48973","nametype":"Valid","recclass":"CM2","mass":"25.81","fall":"Fell","year":"2009-01-01T00:00:00.000","reclat":"54.761830","reclong":"11.467450","geolocation":{"type":"Point","coordinates":[11.46745,54.76183]}} +,{"name":"Maridi","id":"15421","nametype":"Valid","recclass":"H6","mass":"3200","fall":"Fell","year":"1941-01-01T00:00:00.000","reclat":"4.666670","reclong":"29.250000","geolocation":{"type":"Point","coordinates":[29.25,4.66667]}} +,{"name":"Marilia","id":"15422","nametype":"Valid","recclass":"H4","mass":"2500","fall":"Fell","year":"1971-01-01T00:00:00.000","reclat":"-22.250000","reclong":"-49.933330","geolocation":{"type":"Point","coordinates":[-49.93333,-22.25]}} +,{"name":"Marion (Iowa)","id":"15424","nametype":"Valid","recclass":"L6","mass":"28400","fall":"Fell","year":"1847-01-01T00:00:00.000","reclat":"41.900000","reclong":"-91.600000","geolocation":{"type":"Point","coordinates":[-91.6,41.9]},":@computed_region_cbhk_fwbd":"16",":@computed_region_nnqa_25f4":"287"} +,{"name":"Marjalahti","id":"15426","nametype":"Valid","recclass":"Pallasite, PMG","mass":"45000","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"61.500000","reclong":"30.500000","geolocation":{"type":"Point","coordinates":[30.5,61.5]}} +,{"name":"Marmande","id":"15429","nametype":"Valid","recclass":"L5","mass":"3000","fall":"Fell","year":"1848-01-01T00:00:00.000","reclat":"44.500000","reclong":"0.150000","geolocation":{"type":"Point","coordinates":[0.15,44.5]}} +,{"name":"Maromandia","id":"15430","nametype":"Valid","recclass":"L6","mass":"6000","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"-14.200000","reclong":"48.100000","geolocation":{"type":"Point","coordinates":[48.1,-14.2]}} +,{"name":"Maryville","id":"15436","nametype":"Valid","recclass":"L6","mass":"1443","fall":"Fell","year":"1983-01-01T00:00:00.000","reclat":"35.800000","reclong":"-84.100000","geolocation":{"type":"Point","coordinates":[-84.1,35.8]},":@computed_region_cbhk_fwbd":"39",":@computed_region_nnqa_25f4":"2740"} +,{"name":"Mascombes","id":"15438","nametype":"Valid","recclass":"L6","mass":"1000","fall":"Fell","year":"1836-01-01T00:00:00.000","reclat":"45.366670","reclong":"1.866670","geolocation":{"type":"Point","coordinates":[1.86667,45.36667]}} +,{"name":"Mason Gully","id":"53653","nametype":"Valid","recclass":"H5","mass":"24.54","fall":"Fell","year":"2010-01-01T00:00:00.000","reclat":"0.000000","reclong":"0.000000","geolocation":{"type":"Point","coordinates":[0,0]}} +,{"name":"Mässing","id":"15443","nametype":"Valid","recclass":"Howardite","mass":"1600","fall":"Fell","year":"1803-01-01T00:00:00.000","reclat":"48.133330","reclong":"12.616670","geolocation":{"type":"Point","coordinates":[12.61667,48.13333]}} +,{"name":"Mauerkirchen","id":"15446","nametype":"Valid","recclass":"L6","mass":"19000","fall":"Fell","year":"1768-01-01T00:00:00.000","reclat":"48.183330","reclong":"13.133330","geolocation":{"type":"Point","coordinates":[13.13333,48.18333]}} +,{"name":"Mauritius","id":"15447","nametype":"Valid","recclass":"L6","mass":"220","fall":"Fell","year":"1801-01-01T00:00:00.000","reclat":"-20.000000","reclong":"57.000000","geolocation":{"type":"Point","coordinates":[57,-20]}} +,{"name":"Mayo Belwa","id":"15451","nametype":"Valid","recclass":"Aubrite","mass":"4850","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"8.966670","reclong":"12.083330","geolocation":{"type":"Point","coordinates":[12.08333,8.96667]}} +,{"name":"Mazapil","id":"15453","nametype":"Valid","recclass":"Iron, IAB-sLL","mass":"4000","fall":"Fell","year":"1885-01-01T00:00:00.000","reclat":"24.683330","reclong":"-101.683330","geolocation":{"type":"Point","coordinates":[-101.68333,24.68333]}} +,{"name":"Maziba","id":"15454","nametype":"Valid","recclass":"L6","mass":"4975","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"-1.216670","reclong":"30.000000","geolocation":{"type":"Point","coordinates":[30,-1.21667]}} +,{"name":"Mbale","id":"15455","nametype":"Valid","recclass":"L5/6","mass":"150000","fall":"Fell","year":"1992-01-01T00:00:00.000","reclat":"1.066670","reclong":"34.166670","geolocation":{"type":"Point","coordinates":[34.16667,1.06667]}} +,{"name":"Medanitos","id":"15467","nametype":"Valid","recclass":"Eucrite-cm","mass":"31","fall":"Fell","year":"1953-01-01T00:00:00.000","reclat":"-27.250000","reclong":"-67.500000","geolocation":{"type":"Point","coordinates":[-67.5,-27.25]}} +,{"name":"Meerut","id":"15469","nametype":"Valid","recclass":"H5","mass":"22","fall":"Fell","year":"1861-01-01T00:00:00.000","reclat":"29.016670","reclong":"77.800000","geolocation":{"type":"Point","coordinates":[77.8,29.01667]}} +,{"name":"Meester-Cornelis","id":"15470","nametype":"Valid","recclass":"H5","mass":"24750","fall":"Fell","year":"1915-01-01T00:00:00.000","reclat":"-6.233330","reclong":"106.883330","geolocation":{"type":"Point","coordinates":[106.88333,-6.23333]}} +,{"name":"Menow","id":"15485","nametype":"Valid","recclass":"H4","mass":"10500","fall":"Fell","year":"1862-01-01T00:00:00.000","reclat":"53.183330","reclong":"13.150000","geolocation":{"type":"Point","coordinates":[13.15,53.18333]}} +,{"name":"Menziswyl","id":"15486","nametype":"Valid","recclass":"L5","mass":"28.9","fall":"Fell","year":"1903-01-01T00:00:00.000","reclat":"46.818670","reclong":"7.218170","geolocation":{"type":"Point","coordinates":[7.21817,46.81867]}} +,{"name":"Mern","id":"15489","nametype":"Valid","recclass":"L6","mass":"4000","fall":"Fell","year":"1878-01-01T00:00:00.000","reclat":"55.050000","reclong":"12.066670","geolocation":{"type":"Point","coordinates":[12.06667,55.05]}} +,{"name":"Meru","id":"15491","nametype":"Valid","recclass":"LL6","mass":"6000","fall":"Fell","year":"1945-01-01T00:00:00.000","reclat":"0.000000","reclong":"37.666670","geolocation":{"type":"Point","coordinates":[37.66667,0]}} +,{"name":"Merua","id":"15492","nametype":"Valid","recclass":"H5","mass":"71400","fall":"Fell","year":"1920-01-01T00:00:00.000","reclat":"25.483330","reclong":"81.983330","geolocation":{"type":"Point","coordinates":[81.98333,25.48333]}} +,{"name":"Messina","id":"15495","nametype":"Valid","recclass":"L5","mass":"2405","fall":"Fell","year":"1955-01-01T00:00:00.000","reclat":"38.183330","reclong":"15.566670","geolocation":{"type":"Point","coordinates":[15.56667,38.18333]}} +,{"name":"Meuselbach","id":"16626","nametype":"Valid","recclass":"L6","mass":"870","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"50.583330","reclong":"11.100000","geolocation":{"type":"Point","coordinates":[11.1,50.58333]}} +,{"name":"Mezel","id":"16627","nametype":"Valid","recclass":"L6","mass":"1300","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"45.766670","reclong":"3.250000","geolocation":{"type":"Point","coordinates":[3.25,45.76667]}} +,{"name":"Mezö-Madaras","id":"16628","nametype":"Valid","recclass":"L3.7","mass":"22700","fall":"Fell","year":"1852-01-01T00:00:00.000","reclat":"46.500000","reclong":"25.733330","geolocation":{"type":"Point","coordinates":[25.73333,46.5]}} +,{"name":"Mhow","id":"16629","nametype":"Valid","recclass":"L6","mass":"350","fall":"Fell","year":"1827-01-01T00:00:00.000","reclat":"25.900000","reclong":"83.616670","geolocation":{"type":"Point","coordinates":[83.61667,25.9]}} +,{"name":"Mianchi","id":"16631","nametype":"Valid","recclass":"H5","mass":"1100","fall":"Fell","year":"1980-01-01T00:00:00.000","reclat":"34.800000","reclong":"111.700000","geolocation":{"type":"Point","coordinates":[111.7,34.8]}} +,{"name":"Middlesbrough","id":"16632","nametype":"Valid","recclass":"L6","mass":"1600","fall":"Fell","year":"1881-01-01T00:00:00.000","reclat":"54.566670","reclong":"-1.166670","geolocation":{"type":"Point","coordinates":[-1.16667,54.56667]}} +,{"name":"Mifflin","id":"52090","nametype":"Valid","recclass":"L5","mass":"3584","fall":"Fell","year":"2010-01-01T00:00:00.000","reclat":"42.907500","reclong":"-90.365560","geolocation":{"type":"Point","coordinates":[-90.36556,42.9075]},":@computed_region_cbhk_fwbd":"41",":@computed_region_nnqa_25f4":"2996"} +,{"name":"Mighei","id":"16634","nametype":"Valid","recclass":"CM2","mass":"8000","fall":"Fell","year":"1889-01-01T00:00:00.000","reclat":"48.066670","reclong":"30.966670","geolocation":{"type":"Point","coordinates":[30.96667,48.06667]}} +,{"name":"Mihonoseki","id":"16635","nametype":"Valid","recclass":"L6","mass":"6380","fall":"Fell","year":"1992-01-01T00:00:00.000","reclat":"35.568330","reclong":"133.220000","geolocation":{"type":"Point","coordinates":[133.22,35.56833]}} +,{"name":"Mike","id":"16636","nametype":"Valid","recclass":"L6","mass":"224.2","fall":"Fell","year":"1944-01-01T00:00:00.000","reclat":"46.233330","reclong":"17.533330","geolocation":{"type":"Point","coordinates":[17.53333,46.23333]}} +,{"name":"Milena","id":"16640","nametype":"Valid","recclass":"L6","mass":"10000","fall":"Fell","year":"1842-01-01T00:00:00.000","reclat":"46.183330","reclong":"16.100000","geolocation":{"type":"Point","coordinates":[16.1,46.18333]}} +,{"name":"Millbillillie","id":"16643","nametype":"Valid","recclass":"Eucrite-mmict","mass":"330000","fall":"Fell","year":"1960-01-01T00:00:00.000","reclat":"-26.450000","reclong":"120.366670","geolocation":{"type":"Point","coordinates":[120.36667,-26.45]}} +,{"name":"Miller (Arkansas)","id":"16645","nametype":"Valid","recclass":"H5","mass":"16700","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"35.400000","reclong":"-92.050000","geolocation":{"type":"Point","coordinates":[-92.05,35.4]},":@computed_region_cbhk_fwbd":"15",":@computed_region_nnqa_25f4":"11"} +,{"name":"Minamino","id":"16692","nametype":"Valid","recclass":"L","mass":"1040","fall":"Fell","year":"1632-01-01T00:00:00.000","reclat":"35.078330","reclong":"136.933330","geolocation":{"type":"Point","coordinates":[136.93333,35.07833]}} +,{"name":"Mineo","id":"16696","nametype":"Valid","recclass":"Pallasite","mass":"42","fall":"Fell","year":"1826-01-01T00:00:00.000","reclat":"37.283330","reclong":"14.700000","geolocation":{"type":"Point","coordinates":[14.7,37.28333]}} +,{"name":"Min-Fan-Zhun","id":"16697","nametype":"Valid","recclass":"LL6","mass":"5500","fall":"Fell","year":"1952-01-01T00:00:00.000","reclat":"32.333330","reclong":"120.666670","geolocation":{"type":"Point","coordinates":[120.66667,32.33333]}} +,{"name":"Minnichhof","id":"16700","nametype":"Valid","recclass":"OC","mass":"550","fall":"Fell","year":"1905-01-01T00:00:00.000","reclat":"47.700000","reclong":"16.600000","geolocation":{"type":"Point","coordinates":[16.6,47.7]}} +,{"name":"Mirzapur","id":"16701","nametype":"Valid","recclass":"L5","mass":"8510","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"25.683330","reclong":"83.250000","geolocation":{"type":"Point","coordinates":[83.25,25.68333]}} +,{"name":"Misshof","id":"16703","nametype":"Valid","recclass":"H5","mass":"5800","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"56.666670","reclong":"23.000000","geolocation":{"type":"Point","coordinates":[23,56.66667]}} +,{"name":"Mjelleim","id":"16707","nametype":"Valid","recclass":"H","mass":"100.7","fall":"Fell","year":"1898-01-01T00:00:00.000","reclat":"61.733330","reclong":"5.933330","geolocation":{"type":"Point","coordinates":[5.93333,61.73333]}} +,{"name":"Mocs","id":"16709","nametype":"Valid","recclass":"L5-6","mass":"300000","fall":"Fell","year":"1882-01-01T00:00:00.000","reclat":"46.800000","reclong":"24.033330","geolocation":{"type":"Point","coordinates":[24.03333,46.8]}} +,{"name":"Modoc (1905)","id":"16711","nametype":"Valid","recclass":"L6","mass":"35000","fall":"Fell","year":"1905-01-01T00:00:00.000","reclat":"38.500000","reclong":"-101.100000","geolocation":{"type":"Point","coordinates":[-101.1,38.5]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1290"} +,{"name":"Mokoia","id":"16713","nametype":"Valid","recclass":"CV3","mass":"4500","fall":"Fell","year":"1908-01-01T00:00:00.000","reclat":"-39.633330","reclong":"174.400000","geolocation":{"type":"Point","coordinates":[174.4,-39.63333]}} +,{"name":"Molina","id":"16715","nametype":"Valid","recclass":"H5","mass":"144000","fall":"Fell","year":"1858-01-01T00:00:00.000","reclat":"38.116670","reclong":"-1.166670","geolocation":{"type":"Point","coordinates":[-1.16667,38.11667]}} +,{"name":"Molteno","id":"16717","nametype":"Valid","recclass":"Howardite","mass":"150","fall":"Fell","year":"1953-01-01T00:00:00.000","reclat":"-31.250000","reclong":"26.466670","geolocation":{"type":"Point","coordinates":[26.46667,-31.25]}} +,{"name":"Monahans (1998)","id":"16719","nametype":"Valid","recclass":"H5","mass":"2587","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"31.608330","reclong":"-102.858330","geolocation":{"type":"Point","coordinates":[-102.85833,31.60833]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"2957"} +,{"name":"Monroe","id":"16720","nametype":"Valid","recclass":"H4","mass":"8600","fall":"Fell","year":"1849-01-01T00:00:00.000","reclat":"35.250000","reclong":"-80.500000","geolocation":{"type":"Point","coordinates":[-80.5,35.25]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"636"} +,{"name":"Monte das Fortes","id":"16725","nametype":"Valid","recclass":"L5","mass":"4885","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"38.016670","reclong":"-8.250000","geolocation":{"type":"Point","coordinates":[-8.25,38.01667]}} +,{"name":"Monte Milone","id":"16726","nametype":"Valid","recclass":"L5","mass":"3130","fall":"Fell","year":"1846-01-01T00:00:00.000","reclat":"43.266670","reclong":"13.350000","geolocation":{"type":"Point","coordinates":[13.35,43.26667]}} +,{"name":"Montferré","id":"16727","nametype":"Valid","recclass":"H5","mass":"149000","fall":"Fell","year":"1923-01-01T00:00:00.000","reclat":"43.390560","reclong":"1.962500","geolocation":{"type":"Point","coordinates":[1.9625,43.39056]}} +,{"name":"Montlivault","id":"16729","nametype":"Valid","recclass":"L6","mass":"500","fall":"Fell","year":"1838-01-01T00:00:00.000","reclat":"47.633330","reclong":"1.583330","geolocation":{"type":"Point","coordinates":[1.58333,47.63333]}} +,{"name":"Monze","id":"16733","nametype":"Valid","recclass":"L6","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"-15.966670","reclong":"27.350000","geolocation":{"type":"Point","coordinates":[27.35,-15.96667]}} +,{"name":"Moore County","id":"16736","nametype":"Valid","recclass":"Eucrite-cm","mass":"1880","fall":"Fell","year":"1913-01-01T00:00:00.000","reclat":"35.416670","reclong":"-79.383330","geolocation":{"type":"Point","coordinates":[-79.38333,35.41667]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"2431"} +,{"name":"Mooresfort","id":"16737","nametype":"Valid","recclass":"H5","mass":"3520","fall":"Fell","year":"1810-01-01T00:00:00.000","reclat":"52.450000","reclong":"-8.333330","geolocation":{"type":"Point","coordinates":[-8.33333,52.45]}} +,{"name":"Moorleah","id":"16738","nametype":"Valid","recclass":"L6","mass":"8887.5","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"-40.975000","reclong":"145.600000","geolocation":{"type":"Point","coordinates":[145.6,-40.975]}} +,{"name":"Moradabad","id":"16740","nametype":"Valid","recclass":"L6","mass":"70","fall":"Fell","year":"1808-01-01T00:00:00.000","reclat":"28.783330","reclong":"78.833330","geolocation":{"type":"Point","coordinates":[78.83333,28.78333]}} +,{"name":"Morávka","id":"16742","nametype":"Valid","recclass":"H5","mass":"633","fall":"Fell","year":"2000-01-01T00:00:00.000","reclat":"49.600000","reclong":"18.533330","geolocation":{"type":"Point","coordinates":[18.53333,49.6]}} +,{"name":"Mornans","id":"16747","nametype":"Valid","recclass":"H5","mass":"1300","fall":"Fell","year":"1875-01-01T00:00:00.000","reclat":"44.600000","reclong":"5.133330","geolocation":{"type":"Point","coordinates":[5.13333,44.6]}} +,{"name":"Moss","id":"36592","nametype":"Valid","recclass":"CO3.6","mass":"3763","fall":"Fell","year":"2006-01-01T00:00:00.000","reclat":"59.433330","reclong":"10.700000","geolocation":{"type":"Point","coordinates":[10.7,59.43333]}} +,{"name":"Moti-ka-nagla","id":"16759","nametype":"Valid","recclass":"H6","mass":"1500","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"26.833330","reclong":"77.333330","geolocation":{"type":"Point","coordinates":[77.33333,26.83333]}} +,{"name":"Motta di Conti","id":"16762","nametype":"Valid","recclass":"H4","mass":"9150","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"45.200000","reclong":"8.500000","geolocation":{"type":"Point","coordinates":[8.5,45.2]}} +,{"name":"Mount Browne","id":"16766","nametype":"Valid","recclass":"H6","mass":"11300","fall":"Fell","year":"1902-01-01T00:00:00.000","reclat":"-29.800000","reclong":"141.700000","geolocation":{"type":"Point","coordinates":[141.7,-29.8]}} +,{"name":"Mount Tazerzait","id":"16804","nametype":"Valid","recclass":"L5","mass":"110000","fall":"Fell","year":"1991-01-01T00:00:00.000","reclat":"18.700000","reclong":"4.800000","geolocation":{"type":"Point","coordinates":[4.8,18.7]}} +,{"name":"Mount Vaisi","id":"16805","nametype":"Valid","recclass":"Stone-uncl","mass":"17000","fall":"Fell","year":"1637-01-01T00:00:00.000","reclat":"44.083330","reclong":"6.866670","geolocation":{"type":"Point","coordinates":[6.86667,44.08333]}} +,{"name":"Mtola","id":"16820","nametype":"Valid","recclass":"Stone-uncl","mass":"1100","fall":"Fell","year":"1944-01-01T00:00:00.000","reclat":"-11.500000","reclong":"33.500000","geolocation":{"type":"Point","coordinates":[33.5,-11.5]}} +,{"name":"Muddoor","id":"16841","nametype":"Valid","recclass":"L5","mass":"4400","fall":"Fell","year":"1865-01-01T00:00:00.000","reclat":"12.633330","reclong":"77.016670","geolocation":{"type":"Point","coordinates":[77.01667,12.63333]}} +,{"name":"Mulletiwu","id":"16851","nametype":"Valid","recclass":"L","mass":"25.5","fall":"Fell","year":"1795-01-01T00:00:00.000","reclat":"9.333330","reclong":"80.833330","geolocation":{"type":"Point","coordinates":[80.83333,9.33333]}} +,{"name":"Muraid","id":"16874","nametype":"Valid","recclass":"L6","mass":"4703","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"24.500000","reclong":"90.216670","geolocation":{"type":"Point","coordinates":[90.21667,24.5]}} +,{"name":"Murchison","id":"16875","nametype":"Valid","recclass":"CM2","mass":"100000","fall":"Fell","year":"1969-01-01T00:00:00.000","reclat":"-36.616670","reclong":"145.200000","geolocation":{"type":"Point","coordinates":[145.2,-36.61667]}} +,{"name":"Murray","id":"16882","nametype":"Valid","recclass":"CM2","mass":"12600","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"36.600000","reclong":"-88.100000","geolocation":{"type":"Point","coordinates":[-88.1,36.6]},":@computed_region_cbhk_fwbd":"36",":@computed_region_nnqa_25f4":"237"} +,{"name":"Muzaffarpur","id":"16885","nametype":"Valid","recclass":"Iron, IAB-sHL","mass":"1245","fall":"Fell","year":"1964-01-01T00:00:00.000","reclat":"26.133330","reclong":"85.533330","geolocation":{"type":"Point","coordinates":[85.53333,26.13333]}} +,{"name":"Myhee Caunta","id":"16887","nametype":"Valid","recclass":"OC","fall":"Fell","year":"1842-01-01T00:00:00.000","reclat":"23.050000","reclong":"72.633330","geolocation":{"type":"Point","coordinates":[72.63333,23.05]}} +,{"name":"Nadiabondi","id":"16889","nametype":"Valid","recclass":"H5","mass":"8165","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"12.000000","reclong":"1.000000","geolocation":{"type":"Point","coordinates":[1,12]}} +,{"name":"Nagai","id":"16890","nametype":"Valid","recclass":"L6","mass":"1810","fall":"Fell","year":"1922-01-01T00:00:00.000","reclat":"38.121670","reclong":"140.061670","geolocation":{"type":"Point","coordinates":[140.06167,38.12167]}} +,{"name":"Nagaria","id":"16892","nametype":"Valid","recclass":"Eucrite-cm","mass":"20","fall":"Fell","year":"1875-01-01T00:00:00.000","reclat":"26.983330","reclong":"78.216670","geolocation":{"type":"Point","coordinates":[78.21667,26.98333]}} +,{"name":"Nagy-Borové","id":"16893","nametype":"Valid","recclass":"L5","mass":"6100","fall":"Fell","year":"1895-01-01T00:00:00.000","reclat":"49.166670","reclong":"19.500000","geolocation":{"type":"Point","coordinates":[19.5,49.16667]}} +,{"name":"Nakhla","id":"16898","nametype":"Valid","recclass":"Martian (nakhlite)","mass":"10000","fall":"Fell","year":"1911-01-01T00:00:00.000","reclat":"31.316670","reclong":"30.350000","geolocation":{"type":"Point","coordinates":[30.35,31.31667]}} +,{"name":"Nakhon Pathom","id":"16899","nametype":"Valid","recclass":"L6","mass":"23200","fall":"Fell","year":"1923-01-01T00:00:00.000","reclat":"13.733330","reclong":"100.083330","geolocation":{"type":"Point","coordinates":[100.08333,13.73333]}} +,{"name":"Nammianthal","id":"16902","nametype":"Valid","recclass":"H5","mass":"4500","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"12.283330","reclong":"79.200000","geolocation":{"type":"Point","coordinates":[79.2,12.28333]}} +,{"name":"Nan Yang Pao","id":"16903","nametype":"Valid","recclass":"L6","mass":"52900","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"35.666670","reclong":"103.500000","geolocation":{"type":"Point","coordinates":[103.5,35.66667]}} +,{"name":"Nanjemoy","id":"16904","nametype":"Valid","recclass":"H6","mass":"7500","fall":"Fell","year":"1825-01-01T00:00:00.000","reclat":"38.416670","reclong":"-77.166670","geolocation":{"type":"Point","coordinates":[-77.16667,38.41667]},":@computed_region_cbhk_fwbd":"45",":@computed_region_nnqa_25f4":"419"} +,{"name":"Nantong","id":"16907","nametype":"Valid","recclass":"H6","mass":"529","fall":"Fell","year":"1984-01-01T00:00:00.000","reclat":"32.116670","reclong":"121.800000","geolocation":{"type":"Point","coordinates":[121.8,32.11667]}} +,{"name":"Naoki","id":"16908","nametype":"Valid","recclass":"H6","mass":"17000","fall":"Fell","year":"1928-01-01T00:00:00.000","reclat":"19.250000","reclong":"77.000000","geolocation":{"type":"Point","coordinates":[77,19.25]}} +,{"name":"Naragh","id":"16909","nametype":"Valid","recclass":"H6","mass":"2700","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"33.750000","reclong":"51.500000","geolocation":{"type":"Point","coordinates":[51.5,33.75]}} +,{"name":"Narellan","id":"16912","nametype":"Valid","recclass":"L6","mass":"367.5","fall":"Fell","year":"1928-01-01T00:00:00.000","reclat":"-34.050000","reclong":"150.688890","geolocation":{"type":"Point","coordinates":[150.68889,-34.05]}} +,{"name":"Narni","id":"16914","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"0921-01-01T00:00:00.000","reclat":"42.516670","reclong":"12.516670","geolocation":{"type":"Point","coordinates":[12.51667,42.51667]}} +,{"name":"Nassirah","id":"16922","nametype":"Valid","recclass":"H4","mass":"347","fall":"Fell","year":"1936-01-01T00:00:00.000","reclat":"-21.733330","reclong":"165.900000","geolocation":{"type":"Point","coordinates":[165.9,-21.73333]}} +,{"name":"Natal","id":"16923","nametype":"Valid","recclass":"Stone-uncl","mass":"1.4","fall":"Fell","year":"1973-01-01T00:00:00.000"} +,{"name":"Nawapali","id":"16927","nametype":"Valid","recclass":"CM2","mass":"105","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"21.250000","reclong":"83.666670","geolocation":{"type":"Point","coordinates":[83.66667,21.25]}} +,{"name":"Neagari","id":"16934","nametype":"Valid","recclass":"L6","mass":"420","fall":"Fell","year":"1995-01-01T00:00:00.000","reclat":"36.449170","reclong":"136.465280","geolocation":{"type":"Point","coordinates":[136.46528,36.44917]}} +,{"name":"Nedagolla","id":"16935","nametype":"Valid","recclass":"Iron, ungrouped","mass":"4500","fall":"Fell","year":"1870-01-01T00:00:00.000","reclat":"18.683330","reclong":"83.483330","geolocation":{"type":"Point","coordinates":[83.48333,18.68333]}} +,{"name":"Nejo","id":"16941","nametype":"Valid","recclass":"L6","mass":"2450","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"9.500000","reclong":"35.333330","geolocation":{"type":"Point","coordinates":[35.33333,9.5]}} +,{"name":"Nerft","id":"16945","nametype":"Valid","recclass":"L6","mass":"10250","fall":"Fell","year":"1864-01-01T00:00:00.000","reclat":"56.500000","reclong":"21.500000","geolocation":{"type":"Point","coordinates":[21.5,56.5]}} +,{"name":"Neuschwanstein","id":"16950","nametype":"Valid","recclass":"EL6","mass":"6189","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"47.525000","reclong":"10.808330","geolocation":{"type":"Point","coordinates":[10.80833,47.525]}} +,{"name":"New Concord","id":"16953","nametype":"Valid","recclass":"L6","mass":"230000","fall":"Fell","year":"1860-01-01T00:00:00.000","reclat":"40.000000","reclong":"-81.766670","geolocation":{"type":"Point","coordinates":[-81.76667,40]},":@computed_region_cbhk_fwbd":"38",":@computed_region_nnqa_25f4":"2615"} +,{"name":"New Halfa","id":"16954","nametype":"Valid","recclass":"L4","mass":"12000","fall":"Fell","year":"1994-01-01T00:00:00.000","reclat":"15.366670","reclong":"35.683330","geolocation":{"type":"Point","coordinates":[35.68333,15.36667]}} +,{"name":"New Orleans","id":"16960","nametype":"Valid","recclass":"H5","mass":"19256","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"29.947180","reclong":"-90.109760","geolocation":{"type":"Point","coordinates":[-90.10976,29.94718]},":@computed_region_cbhk_fwbd":"22",":@computed_region_nnqa_25f4":"1667"} +,{"name":"Ngawi","id":"16966","nametype":"Valid","recclass":"LL3.6","mass":"1393","fall":"Fell","year":"1883-01-01T00:00:00.000","reclat":"-7.450000","reclong":"111.416670","geolocation":{"type":"Point","coordinates":[111.41667,-7.45]}} +,{"name":"N'Goureyma","id":"16968","nametype":"Valid","recclass":"Iron, ungrouped","mass":"37500","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"13.850000","reclong":"-4.383330","geolocation":{"type":"Point","coordinates":[-4.38333,13.85]}} +,{"name":"Nicorps","id":"16970","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1750-01-01T00:00:00.000","reclat":"49.033330","reclong":"-1.433330","geolocation":{"type":"Point","coordinates":[-1.43333,49.03333]}} +,{"name":"Niger (L6)","id":"16974","nametype":"Valid","recclass":"L6","mass":"3.3","fall":"Fell","year":"1967-01-01T00:00:00.000"} +,{"name":"Niger (LL6)","id":"16975","nametype":"Valid","recclass":"LL6","mass":"3.3","fall":"Fell","year":"1967-01-01T00:00:00.000"} +,{"name":"Nikolaevka","id":"16976","nametype":"Valid","recclass":"H4","mass":"3996","fall":"Fell","year":"1935-01-01T00:00:00.000","reclat":"52.450000","reclong":"78.633330","geolocation":{"type":"Point","coordinates":[78.63333,52.45]}} +,{"name":"Nikolskoe","id":"16977","nametype":"Valid","recclass":"L4","mass":"6000","fall":"Fell","year":"1954-01-01T00:00:00.000","reclat":"56.116670","reclong":"37.333330","geolocation":{"type":"Point","coordinates":[37.33333,56.11667]}} +,{"name":"Ningbo","id":"16980","nametype":"Valid","recclass":"Iron, IVA","mass":"14250","fall":"Fell","year":"1975-01-01T00:00:00.000","reclat":"29.866670","reclong":"121.483330","geolocation":{"type":"Point","coordinates":[121.48333,29.86667]}} +,{"name":"Ningqiang","id":"16981","nametype":"Valid","recclass":"C3-ung","mass":"4610","fall":"Fell","year":"1983-01-01T00:00:00.000","reclat":"32.925000","reclong":"105.906670","geolocation":{"type":"Point","coordinates":[105.90667,32.925]}} +,{"name":"Nio","id":"16982","nametype":"Valid","recclass":"H3-4","mass":"467","fall":"Fell","year":"1897-01-01T00:00:00.000","reclat":"34.200000","reclong":"131.566670","geolocation":{"type":"Point","coordinates":[131.56667,34.2]}} +,{"name":"N'Kandhla","id":"16983","nametype":"Valid","recclass":"Iron, IID","mass":"17200","fall":"Fell","year":"1912-01-01T00:00:00.000","reclat":"-28.566670","reclong":"30.700000","geolocation":{"type":"Point","coordinates":[30.7,-28.56667]}} +,{"name":"Nobleborough","id":"16984","nametype":"Valid","recclass":"Eucrite-pmict","mass":"2300","fall":"Fell","year":"1823-01-01T00:00:00.000","reclat":"44.083330","reclong":"-69.483330","geolocation":{"type":"Point","coordinates":[-69.48333,44.08333]},":@computed_region_cbhk_fwbd":"49",":@computed_region_nnqa_25f4":"1683"} +,{"name":"Noblesville","id":"16985","nametype":"Valid","recclass":"H4-6","mass":"483.7","fall":"Fell","year":"1991-01-01T00:00:00.000","reclat":"40.085280","reclong":"-86.055000","geolocation":{"type":"Point","coordinates":[-86.055,40.08528]},":@computed_region_cbhk_fwbd":"35",":@computed_region_nnqa_25f4":"2238"} +,{"name":"Nogata","id":"16988","nametype":"Valid","recclass":"L6","mass":"472","fall":"Fell","year":"0861-01-01T00:00:00.000","reclat":"33.725000","reclong":"130.750000","geolocation":{"type":"Point","coordinates":[130.75,33.725]}} +,{"name":"Nogoya","id":"16989","nametype":"Valid","recclass":"CM2","mass":"4000","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"-32.366670","reclong":"-59.833330","geolocation":{"type":"Point","coordinates":[-59.83333,-32.36667]}} +,{"name":"Norfork","id":"16994","nametype":"Valid","recclass":"Iron, IIIAB","mass":"1050","fall":"Fell","year":"1918-01-01T00:00:00.000","reclat":"36.216670","reclong":"-92.266670","geolocation":{"type":"Point","coordinates":[-92.26667,36.21667]},":@computed_region_cbhk_fwbd":"15",":@computed_region_nnqa_25f4":"10"} +,{"name":"Norton County","id":"17922","nametype":"Valid","recclass":"Aubrite","mass":"1100000","fall":"Fell","year":"1948-01-01T00:00:00.000","reclat":"39.683330","reclong":"-99.866670","geolocation":{"type":"Point","coordinates":[-99.86667,39.68333]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1252"} +,{"name":"Noventa Vicentina","id":"17930","nametype":"Valid","recclass":"H4","mass":"177","fall":"Fell","year":"1971-01-01T00:00:00.000","reclat":"45.291670","reclong":"11.527220","geolocation":{"type":"Point","coordinates":[11.52722,45.29167]}} +,{"name":"Novo-Urei","id":"17933","nametype":"Valid","recclass":"Ureilite","mass":"1900","fall":"Fell","year":"1886-01-01T00:00:00.000","reclat":"54.816670","reclong":"46.000000","geolocation":{"type":"Point","coordinates":[46,54.81667]}} +,{"name":"Novy-Ergi","id":"17934","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1662-01-01T00:00:00.000","reclat":"58.550000","reclong":"31.333330","geolocation":{"type":"Point","coordinates":[31.33333,58.55]}} +,{"name":"Novy-Projekt","id":"17935","nametype":"Valid","recclass":"OC","mass":"1001","fall":"Fell","year":"1908-01-01T00:00:00.000","reclat":"56.000000","reclong":"22.000000","geolocation":{"type":"Point","coordinates":[22,56]}} +,{"name":"Noyan-Bogdo","id":"17936","nametype":"Valid","recclass":"L6","mass":"250","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"42.916670","reclong":"102.466670","geolocation":{"type":"Point","coordinates":[102.46667,42.91667]}} +,{"name":"Nuevo Mercurio","id":"17938","nametype":"Valid","recclass":"H5","mass":"50000","fall":"Fell","year":"1978-01-01T00:00:00.000","reclat":"24.300000","reclong":"-102.133330","geolocation":{"type":"Point","coordinates":[-102.13333,24.3]}} +,{"name":"Nulles","id":"17959","nametype":"Valid","recclass":"H6","mass":"5000","fall":"Fell","year":"1851-01-01T00:00:00.000","reclat":"41.633330","reclong":"0.750000","geolocation":{"type":"Point","coordinates":[0.75,41.63333]}} +,{"name":"Numakai","id":"17960","nametype":"Valid","recclass":"H4","mass":"363","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"43.333330","reclong":"141.866670","geolocation":{"type":"Point","coordinates":[141.86667,43.33333]}} +,{"name":"Nyaung","id":"17969","nametype":"Valid","recclass":"Iron, IIIAB","mass":"737.6","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"21.208330","reclong":"94.916670","geolocation":{"type":"Point","coordinates":[94.91667,21.20833]}} +,{"name":"Nyirábrany","id":"17970","nametype":"Valid","recclass":"LL5","mass":"1100","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"47.550000","reclong":"22.025000","geolocation":{"type":"Point","coordinates":[22.025,47.55]}} +,{"name":"Ochansk","id":"17979","nametype":"Valid","recclass":"H4","mass":"500000","fall":"Fell","year":"1887-01-01T00:00:00.000","reclat":"57.783330","reclong":"55.266670","geolocation":{"type":"Point","coordinates":[55.26667,57.78333]}} +,{"name":"Oesede","id":"17988","nametype":"Valid","recclass":"H5","mass":"1400","fall":"Fell","year":"1927-01-01T00:00:00.000","reclat":"52.283330","reclong":"8.050000","geolocation":{"type":"Point","coordinates":[8.05,52.28333]}} +,{"name":"Oesel","id":"17989","nametype":"Valid","recclass":"L6","mass":"6000","fall":"Fell","year":"1855-01-01T00:00:00.000","reclat":"58.500000","reclong":"23.000000","geolocation":{"type":"Point","coordinates":[23,58.5]}} +,{"name":"Ofehértó","id":"17990","nametype":"Valid","recclass":"L6","mass":"3750","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"47.883330","reclong":"22.033330","geolocation":{"type":"Point","coordinates":[22.03333,47.88333]}} +,{"name":"Ogi","id":"17994","nametype":"Valid","recclass":"H6","mass":"14360","fall":"Fell","year":"1741-01-01T00:00:00.000","reclat":"33.283330","reclong":"130.200000","geolocation":{"type":"Point","coordinates":[130.2,33.28333]}} +,{"name":"Ohaba","id":"17995","nametype":"Valid","recclass":"H5","mass":"16250","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"46.066670","reclong":"23.583330","geolocation":{"type":"Point","coordinates":[23.58333,46.06667]}} +,{"name":"Ohuma","id":"17996","nametype":"Valid","recclass":"L5","mass":"7700","fall":"Fell","year":"1963-01-01T00:00:00.000","reclat":"6.750000","reclong":"8.500000","geolocation":{"type":"Point","coordinates":[8.5,6.75]}} +,{"name":"Ojuelos Altos","id":"17997","nametype":"Valid","recclass":"L6","mass":"5850","fall":"Fell","year":"1926-01-01T00:00:00.000","reclat":"38.183330","reclong":"-5.400000","geolocation":{"type":"Point","coordinates":[-5.4,38.18333]}} +,{"name":"Okabe","id":"17998","nametype":"Valid","recclass":"H5","mass":"194","fall":"Fell","year":"1958-01-01T00:00:00.000","reclat":"36.183330","reclong":"139.216670","geolocation":{"type":"Point","coordinates":[139.21667,36.18333]}} +,{"name":"Okano","id":"18000","nametype":"Valid","recclass":"Iron, IIAB","mass":"4742","fall":"Fell","year":"1904-01-01T00:00:00.000","reclat":"35.083330","reclong":"135.200000","geolocation":{"type":"Point","coordinates":[135.2,35.08333]}} +,{"name":"Okniny","id":"18002","nametype":"Valid","recclass":"LL6","mass":"12000","fall":"Fell","year":"1834-01-01T00:00:00.000","reclat":"50.833330","reclong":"25.500000","geolocation":{"type":"Point","coordinates":[25.5,50.83333]}} +,{"name":"Oldenburg (1930)","id":"18009","nametype":"Valid","recclass":"L6","mass":"16570","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"52.950000","reclong":"8.166670","geolocation":{"type":"Point","coordinates":[8.16667,52.95]}} +,{"name":"Oliva-Gandia","id":"18012","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1520-01-01T00:00:00.000","reclat":"39.000000","reclong":"-0.033330","geolocation":{"type":"Point","coordinates":[-0.03333,39]}} +,{"name":"Olivenza","id":"18013","nametype":"Valid","recclass":"LL5","mass":"150000","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"38.716670","reclong":"-7.066670","geolocation":{"type":"Point","coordinates":[-7.06667,38.71667]}} +,{"name":"Olmedilla de Alarcón","id":"18015","nametype":"Valid","recclass":"H5","mass":"40000","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"39.566670","reclong":"-2.100000","geolocation":{"type":"Point","coordinates":[-2.1,39.56667]}} +,{"name":"Omolon","id":"18019","nametype":"Valid","recclass":"Pallasite, PMG","mass":"250000","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"64.020000","reclong":"161.808330","geolocation":{"type":"Point","coordinates":[161.80833,64.02]}} +,{"name":"Orgueil","id":"18026","nametype":"Valid","recclass":"CI1","mass":"14000","fall":"Fell","year":"1864-01-01T00:00:00.000","reclat":"43.883330","reclong":"1.383330","geolocation":{"type":"Point","coordinates":[1.38333,43.88333]}} +,{"name":"Orlando","id":"34489","nametype":"Valid","recclass":"Eucrite","mass":"180","fall":"Fell","year":"2004-01-01T00:00:00.000","reclat":"28.547500","reclong":"-81.362220","geolocation":{"type":"Point","coordinates":[-81.36222,28.5475]},":@computed_region_cbhk_fwbd":"30",":@computed_region_nnqa_25f4":"1078"} +,{"name":"Ornans","id":"18030","nametype":"Valid","recclass":"CO3.4","mass":"6000","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"47.116670","reclong":"6.150000","geolocation":{"type":"Point","coordinates":[6.15,47.11667]}} +,{"name":"Ortenau","id":"18033","nametype":"Valid","recclass":"Stone-uncl","mass":"4500","fall":"Fell","year":"1671-01-01T00:00:00.000","reclat":"48.500000","reclong":"8.000000","geolocation":{"type":"Point","coordinates":[8,48.5]}} +,{"name":"Orvinio","id":"18034","nametype":"Valid","recclass":"H6","mass":"3400","fall":"Fell","year":"1872-01-01T00:00:00.000","reclat":"42.133330","reclong":"12.933330","geolocation":{"type":"Point","coordinates":[12.93333,42.13333]}} +,{"name":"Oterøy","id":"18042","nametype":"Valid","recclass":"L6","mass":"246","fall":"Fell","year":"1928-01-01T00:00:00.000","reclat":"58.883330","reclong":"9.400000","geolocation":{"type":"Point","coordinates":[9.4,58.88333]}} +,{"name":"Otomi","id":"18045","nametype":"Valid","recclass":"H","mass":"6510","fall":"Fell","year":"1867-01-01T00:00:00.000","reclat":"38.400000","reclong":"140.350000","geolocation":{"type":"Point","coordinates":[140.35,38.4]}} +,{"name":"Ottawa","id":"18046","nametype":"Valid","recclass":"LL6","mass":"840","fall":"Fell","year":"1896-01-01T00:00:00.000","reclat":"38.600000","reclong":"-95.216670","geolocation":{"type":"Point","coordinates":[-95.21667,38.6]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1947"} +,{"name":"Ouadangou","id":"56729","nametype":"Valid","recclass":"L5","mass":"4440","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"12.900000","reclong":"0.080000","geolocation":{"type":"Point","coordinates":[0.08,12.9]}} +,{"name":"Oued el Hadjar","id":"18050","nametype":"Valid","recclass":"LL6","mass":"1215.5","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"30.180000","reclong":"-6.577170","geolocation":{"type":"Point","coordinates":[-6.57717,30.18]}} +,{"name":"Oum Dreyga","id":"31282","nametype":"Valid","recclass":"H3-5","mass":"17000","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"24.300000","reclong":"-13.100000","geolocation":{"type":"Point","coordinates":[-13.1,24.3]}} +,{"name":"Ourique","id":"18052","nametype":"Valid","recclass":"H4","mass":"20000","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"37.608330","reclong":"-8.280000","geolocation":{"type":"Point","coordinates":[-8.28,37.60833]}} +,{"name":"Ovambo","id":"18055","nametype":"Valid","recclass":"L6","mass":"121.5","fall":"Fell","year":"1900-01-01T00:00:00.000","reclat":"-18.000000","reclong":"16.000000","geolocation":{"type":"Point","coordinates":[16,-18]}} +,{"name":"Oviedo","id":"18058","nametype":"Valid","recclass":"H5","mass":"205","fall":"Fell","year":"1856-01-01T00:00:00.000","reclat":"43.400000","reclong":"-5.866670","geolocation":{"type":"Point","coordinates":[-5.86667,43.4]}} +,{"name":"Owrucz","id":"18062","nametype":"Valid","recclass":"OC","fall":"Fell","year":"1775-01-01T00:00:00.000","reclat":"51.333330","reclong":"28.833330","geolocation":{"type":"Point","coordinates":[28.83333,51.33333]}} +,{"name":"Pacula","id":"18068","nametype":"Valid","recclass":"L6","mass":"3400","fall":"Fell","year":"1881-01-01T00:00:00.000","reclat":"21.050000","reclong":"-99.300000","geolocation":{"type":"Point","coordinates":[-99.3,21.05]}} +,{"name":"Padvarninkai","id":"18069","nametype":"Valid","recclass":"Eucrite-mmict","mass":"3858","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"55.666670","reclong":"25.000000","geolocation":{"type":"Point","coordinates":[25,55.66667]}} +,{"name":"Paitan","id":"18072","nametype":"Valid","recclass":"H6","mass":"515","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"17.743330","reclong":"120.455830","geolocation":{"type":"Point","coordinates":[120.45583,17.74333]}} +,{"name":"Palahatchie","id":"18073","nametype":"Valid","recclass":"OC","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"32.316670","reclong":"-89.716670","geolocation":{"type":"Point","coordinates":[-89.71667,32.31667]},":@computed_region_cbhk_fwbd":"32",":@computed_region_nnqa_25f4":"503"} +,{"name":"Palca de Aparzo","id":"18074","nametype":"Valid","recclass":"L5","mass":"1430","fall":"Fell","year":"1988-01-01T00:00:00.000","reclat":"-23.116670","reclong":"-65.100000","geolocation":{"type":"Point","coordinates":[-65.1,-23.11667]}} +,{"name":"Palinshih","id":"18077","nametype":"Valid","recclass":"Iron","mass":"18000","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"43.483330","reclong":"118.616670","geolocation":{"type":"Point","coordinates":[118.61667,43.48333]}} +,{"name":"Palmyra","id":"18079","nametype":"Valid","recclass":"L3","mass":"135","fall":"Fell","year":"1926-01-01T00:00:00.000","reclat":"39.800000","reclong":"-91.500000","geolocation":{"type":"Point","coordinates":[-91.5,39.8]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"2122"} +,{"name":"Palolo Valley","id":"18082","nametype":"Valid","recclass":"H5","mass":"682","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"21.300000","reclong":"-157.783330","geolocation":{"type":"Point","coordinates":[-157.78333,21.3]},":@computed_region_cbhk_fwbd":"4",":@computed_region_nnqa_25f4":"1657"} +,{"name":"Dominion Range 03239","id":"32591","nametype":"Valid","recclass":"L6","mass":"69.5","fall":"Found","year":"2002-01-01T00:00:00.000"} +,{"name":"Pampanga","id":"18093","nametype":"Valid","recclass":"L5","mass":"10500","fall":"Fell","year":"1859-01-01T00:00:00.000","reclat":"15.083330","reclong":"120.700000","geolocation":{"type":"Point","coordinates":[120.7,15.08333]}} +,{"name":"Pantar","id":"18098","nametype":"Valid","recclass":"H5","mass":"2130","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"8.066670","reclong":"124.283330","geolocation":{"type":"Point","coordinates":[124.28333,8.06667]}} +,{"name":"Paragould","id":"18101","nametype":"Valid","recclass":"LL5","mass":"408000","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"36.066670","reclong":"-90.500000","geolocation":{"type":"Point","coordinates":[-90.5,36.06667]},":@computed_region_cbhk_fwbd":"15",":@computed_region_nnqa_25f4":"1023"} +,{"name":"Parambu","id":"18102","nametype":"Valid","recclass":"LL5","mass":"2000","fall":"Fell","year":"1967-01-01T00:00:00.000","reclat":"-6.233330","reclong":"-40.700000","geolocation":{"type":"Point","coordinates":[-40.7,-6.23333]}} +,{"name":"Paranaiba","id":"18103","nametype":"Valid","recclass":"L6","mass":"100000","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"-19.133330","reclong":"-51.666670","geolocation":{"type":"Point","coordinates":[-51.66667,-19.13333]}} +,{"name":"Park Forest","id":"18106","nametype":"Valid","recclass":"L5","mass":"18000","fall":"Fell","year":"2003-01-01T00:00:00.000","reclat":"41.484720","reclong":"-87.679170","geolocation":{"type":"Point","coordinates":[-87.67917,41.48472]},":@computed_region_cbhk_fwbd":"34",":@computed_region_nnqa_25f4":"1863"} +,{"name":"Parnallee","id":"18108","nametype":"Valid","recclass":"LL3.6","mass":"77600","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"9.233330","reclong":"78.350000","geolocation":{"type":"Point","coordinates":[78.35,9.23333]}} +,{"name":"Parsa","id":"18109","nametype":"Valid","recclass":"EH3","mass":"800","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"26.200000","reclong":"85.400000","geolocation":{"type":"Point","coordinates":[85.4,26.2]}} +,{"name":"Pasamonte","id":"18110","nametype":"Valid","recclass":"Eucrite-pmict","mass":"5100","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"36.216670","reclong":"-103.400000","geolocation":{"type":"Point","coordinates":[-103.4,36.21667]},":@computed_region_cbhk_fwbd":"11",":@computed_region_nnqa_25f4":"1994"} +,{"name":"Patora","id":"18112","nametype":"Valid","recclass":"H6","mass":"4375","fall":"Fell","year":"1969-01-01T00:00:00.000","reclat":"20.936940","reclong":"82.050000","geolocation":{"type":"Point","coordinates":[82.05,20.93694]}} +,{"name":"Patrimonio","id":"18116","nametype":"Valid","recclass":"L6","mass":"2121","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"-19.533330","reclong":"-48.566670","geolocation":{"type":"Point","coordinates":[-48.56667,-19.53333]}} +,{"name":"Patti","id":"18118","nametype":"Valid","recclass":"Iron","mass":"12","fall":"Fell","year":"1922-01-01T00:00:00.000","reclat":"38.133330","reclong":"14.966670","geolocation":{"type":"Point","coordinates":[14.96667,38.13333]}} +,{"name":"Patwar","id":"18171","nametype":"Valid","recclass":"Mesosiderite-A1","mass":"37350","fall":"Fell","year":"1935-01-01T00:00:00.000","reclat":"23.150000","reclong":"91.183330","geolocation":{"type":"Point","coordinates":[91.18333,23.15]}} +,{"name":"Pavel","id":"18173","nametype":"Valid","recclass":"H5","mass":"2968","fall":"Fell","year":"1966-01-01T00:00:00.000","reclat":"43.466670","reclong":"25.516670","geolocation":{"type":"Point","coordinates":[25.51667,43.46667]}} +,{"name":"Pavlodar (stone)","id":"18175","nametype":"Valid","recclass":"H5","mass":"142.5","fall":"Fell","year":"1938-01-01T00:00:00.000","reclat":"52.300000","reclong":"77.033330","geolocation":{"type":"Point","coordinates":[77.03333,52.3]}} +,{"name":"Pavlograd","id":"18176","nametype":"Valid","recclass":"L6","mass":"40000","fall":"Fell","year":"1826-01-01T00:00:00.000","reclat":"48.533330","reclong":"35.983330","geolocation":{"type":"Point","coordinates":[35.98333,48.53333]}} +,{"name":"Pavlovka","id":"18177","nametype":"Valid","recclass":"Howardite","mass":"2000","fall":"Fell","year":"1882-01-01T00:00:00.000","reclat":"52.033330","reclong":"43.000000","geolocation":{"type":"Point","coordinates":[43,52.03333]}} +,{"name":"Pê","id":"18179","nametype":"Valid","recclass":"L6","fall":"Fell","year":"1989-01-01T00:00:00.000","reclat":"11.333670","reclong":"-3.542170","geolocation":{"type":"Point","coordinates":[-3.54217,11.33367]}} +,{"name":"Peace River","id":"18180","nametype":"Valid","recclass":"L6","mass":"45760","fall":"Fell","year":"1963-01-01T00:00:00.000","reclat":"56.133330","reclong":"-117.933330","geolocation":{"type":"Point","coordinates":[-117.93333,56.13333]}} +,{"name":"Peckelsheim","id":"18181","nametype":"Valid","recclass":"Diogenite-pm","mass":"117.8","fall":"Fell","year":"1953-01-01T00:00:00.000","reclat":"51.666670","reclong":"9.250000","geolocation":{"type":"Point","coordinates":[9.25,51.66667]}} +,{"name":"Peekskill","id":"18782","nametype":"Valid","recclass":"H6","mass":"12570","fall":"Fell","year":"1992-01-01T00:00:00.000","reclat":"41.283330","reclong":"-73.916670","geolocation":{"type":"Point","coordinates":[-73.91667,41.28333]},":@computed_region_cbhk_fwbd":"47",":@computed_region_nnqa_25f4":"2185"} +,{"name":"Peña Blanca Spring","id":"18786","nametype":"Valid","recclass":"Aubrite","mass":"70000","fall":"Fell","year":"1946-01-01T00:00:00.000","reclat":"30.125000","reclong":"-103.116670","geolocation":{"type":"Point","coordinates":[-103.11667,30.125]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"3062"} +,{"name":"Peramiho","id":"18792","nametype":"Valid","recclass":"Eucrite-mmict","mass":"165","fall":"Fell","year":"1899-01-01T00:00:00.000","reclat":"-10.666670","reclong":"35.500000","geolocation":{"type":"Point","coordinates":[35.5,-10.66667]}} +,{"name":"Perpeti","id":"18793","nametype":"Valid","recclass":"L6","mass":"23474","fall":"Fell","year":"1935-01-01T00:00:00.000","reclat":"23.325000","reclong":"91.000000","geolocation":{"type":"Point","coordinates":[91,23.325]}} +,{"name":"Perth","id":"18797","nametype":"Valid","recclass":"LL5","mass":"2","fall":"Fell","year":"1830-01-01T00:00:00.000","reclat":"56.400000","reclong":"-3.433330","geolocation":{"type":"Point","coordinates":[-3.43333,56.4]}} +,{"name":"Pervomaisky","id":"18798","nametype":"Valid","recclass":"L6","mass":"66000","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"56.633330","reclong":"39.433330","geolocation":{"type":"Point","coordinates":[39.43333,56.63333]}} +,{"name":"Pesyanoe","id":"18799","nametype":"Valid","recclass":"Aubrite","mass":"3393","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"55.500000","reclong":"66.083330","geolocation":{"type":"Point","coordinates":[66.08333,55.5]}} +,{"name":"Pétèlkolé","id":"18800","nametype":"Valid","recclass":"H5","mass":"189","fall":"Fell","year":"1995-01-01T00:00:00.000","reclat":"14.052000","reclong":"0.420000","geolocation":{"type":"Point","coordinates":[0.42,14.052]}} +,{"name":"Petersburg","id":"18801","nametype":"Valid","recclass":"Eucrite-pmict","mass":"1800","fall":"Fell","year":"1855-01-01T00:00:00.000","reclat":"35.300000","reclong":"-86.633330","geolocation":{"type":"Point","coordinates":[-86.63333,35.3]},":@computed_region_cbhk_fwbd":"39",":@computed_region_nnqa_25f4":"2017"} +,{"name":"Pettiswood","id":"18804","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1779-01-01T00:00:00.000","reclat":"53.533330","reclong":"-7.333330","geolocation":{"type":"Point","coordinates":[-7.33333,53.53333]}} +,{"name":"Phillips County (stone)","id":"18808","nametype":"Valid","recclass":"L6","mass":"57900","fall":"Fell","year":"1901-01-01T00:00:00.000","reclat":"40.000000","reclong":"-99.250000","geolocation":{"type":"Point","coordinates":[-99.25,40]},":@computed_region_cbhk_fwbd":"17",":@computed_region_nnqa_25f4":"1255"} +,{"name":"Phu Hong","id":"18809","nametype":"Valid","recclass":"H4","mass":"500","fall":"Fell","year":"1887-01-01T00:00:00.000","reclat":"11.250000","reclong":"108.583330","geolocation":{"type":"Point","coordinates":[108.58333,11.25]}} +,{"name":"Phum Sambo","id":"18811","nametype":"Valid","recclass":"H4","mass":"7800","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"12.000000","reclong":"105.483330","geolocation":{"type":"Point","coordinates":[105.48333,12]}} +,{"name":"Phuoc-Binh","id":"18812","nametype":"Valid","recclass":"L5","mass":"11000","fall":"Fell","year":"1941-01-01T00:00:00.000","reclat":"15.716670","reclong":"108.100000","geolocation":{"type":"Point","coordinates":[108.1,15.71667]}} +,{"name":"Piancaldoli","id":"18813","nametype":"Valid","recclass":"LL3.4","mass":"13.1","fall":"Fell","year":"1968-01-01T00:00:00.000","reclat":"44.244170","reclong":"11.502220","geolocation":{"type":"Point","coordinates":[11.50222,44.24417]}} +,{"name":"Picote","id":"18816","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1843-01-01T00:00:00.000","reclat":"41.366670","reclong":"-6.233330","geolocation":{"type":"Point","coordinates":[-6.23333,41.36667]}} +,{"name":"Pillistfer","id":"18822","nametype":"Valid","recclass":"EL6","mass":"23250","fall":"Fell","year":"1863-01-01T00:00:00.000","reclat":"58.666670","reclong":"25.733330","geolocation":{"type":"Point","coordinates":[25.73333,58.66667]}} +,{"name":"Piplia Kalan","id":"18831","nametype":"Valid","recclass":"Eucrite-mmict","mass":"42000","fall":"Fell","year":"1996-01-01T00:00:00.000","reclat":"26.034720","reclong":"73.941670","geolocation":{"type":"Point","coordinates":[73.94167,26.03472]}} +,{"name":"Piquetberg","id":"18832","nametype":"Valid","recclass":"H","mass":"37","fall":"Fell","year":"1881-01-01T00:00:00.000","reclat":"-32.866670","reclong":"18.716670","geolocation":{"type":"Point","coordinates":[18.71667,-32.86667]}} +,{"name":"Pirgunje","id":"18834","nametype":"Valid","recclass":"L6","mass":"842","fall":"Fell","year":"1882-01-01T00:00:00.000","reclat":"25.800000","reclong":"88.450000","geolocation":{"type":"Point","coordinates":[88.45,25.8]}} +,{"name":"Pirthalla","id":"18835","nametype":"Valid","recclass":"H6","mass":"1161","fall":"Fell","year":"1884-01-01T00:00:00.000","reclat":"29.583330","reclong":"76.000000","geolocation":{"type":"Point","coordinates":[76,29.58333]}} +,{"name":"Pitts","id":"18837","nametype":"Valid","recclass":"Iron, IAB-ung","mass":"3760","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"31.950000","reclong":"-83.516670","geolocation":{"type":"Point","coordinates":[-83.51667,31.95]},":@computed_region_cbhk_fwbd":"31",":@computed_region_nnqa_25f4":"207"} +,{"name":"Plantersville","id":"18846","nametype":"Valid","recclass":"H6","mass":"2085","fall":"Fell","year":"1930-01-01T00:00:00.000","reclat":"30.700000","reclong":"-96.116670","geolocation":{"type":"Point","coordinates":[-96.11667,30.7]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"2018"} +,{"name":"Pleşcoi","id":"51706","nametype":"Valid","recclass":"L5-6","mass":"6913","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"45.275000","reclong":"26.709720","geolocation":{"type":"Point","coordinates":[26.70972,45.275]}} +,{"name":"Ploschkovitz","id":"18849","nametype":"Valid","recclass":"L5","mass":"39","fall":"Fell","year":"1723-01-01T00:00:00.000","reclat":"50.533330","reclong":"14.116670","geolocation":{"type":"Point","coordinates":[14.11667,50.53333]}} +,{"name":"Pnompehn","id":"18851","nametype":"Valid","recclass":"L6","mass":"96","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"11.583330","reclong":"104.916670","geolocation":{"type":"Point","coordinates":[104.91667,11.58333]}} +,{"name":"Dominion Range 03240","id":"32592","nametype":"Valid","recclass":"LL5","mass":"290.89999999999998","fall":"Found","year":"2002-01-01T00:00:00.000"} +,{"name":"Pohlitz","id":"18853","nametype":"Valid","recclass":"L5","mass":"3000","fall":"Fell","year":"1819-01-01T00:00:00.000","reclat":"50.933330","reclong":"12.133330","geolocation":{"type":"Point","coordinates":[12.13333,50.93333]}} +,{"name":"Pokhra","id":"18858","nametype":"Valid","recclass":"H5","mass":"350","fall":"Fell","year":"1866-01-01T00:00:00.000","reclat":"26.716670","reclong":"82.666670","geolocation":{"type":"Point","coordinates":[82.66667,26.71667]}} +,{"name":"Pollen","id":"18860","nametype":"Valid","recclass":"CM2","mass":"253.6","fall":"Fell","year":"1942-01-01T00:00:00.000","reclat":"66.348330","reclong":"14.015000","geolocation":{"type":"Point","coordinates":[14.015,66.34833]}} +,{"name":"Pontlyfni","id":"18865","nametype":"Valid","recclass":"Winonaite","mass":"157","fall":"Fell","year":"1931-01-01T00:00:00.000","reclat":"53.036390","reclong":"-4.319440","geolocation":{"type":"Point","coordinates":[-4.31944,53.03639]}} +,{"name":"Portales Valley","id":"18874","nametype":"Valid","recclass":"H6","mass":"71400","fall":"Fell","year":"1998-01-01T00:00:00.000","reclat":"34.175000","reclong":"-103.295000","geolocation":{"type":"Point","coordinates":[-103.295,34.175]},":@computed_region_cbhk_fwbd":"11",":@computed_region_nnqa_25f4":"1987"} +,{"name":"Portugal","id":"18876","nametype":"Valid","recclass":"Stone-uncl","mass":"4500","fall":"Fell","year":"1796-01-01T00:00:00.000","reclat":"38.500000","reclong":"-8.000000","geolocation":{"type":"Point","coordinates":[-8,38.5]}} +,{"name":"Po-wang Chen","id":"18879","nametype":"Valid","recclass":"LL","mass":"665","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"31.416670","reclong":"118.500000","geolocation":{"type":"Point","coordinates":[118.5,31.41667]}} +,{"name":"Prambachkirchen","id":"18883","nametype":"Valid","recclass":"L6","mass":"2125","fall":"Fell","year":"1932-01-01T00:00:00.000","reclat":"48.302500","reclong":"13.940830","geolocation":{"type":"Point","coordinates":[13.94083,48.3025]}} +,{"name":"Pribram","id":"18887","nametype":"Valid","recclass":"H5","mass":"5555","fall":"Fell","year":"1959-01-01T00:00:00.000","reclat":"49.666670","reclong":"14.033330","geolocation":{"type":"Point","coordinates":[14.03333,49.66667]}} +,{"name":"Pricetown","id":"18888","nametype":"Valid","recclass":"L6","mass":"900","fall":"Fell","year":"1893-01-01T00:00:00.000","reclat":"39.116670","reclong":"-83.850000","geolocation":{"type":"Point","coordinates":[-83.85,39.11667]},":@computed_region_cbhk_fwbd":"38",":@computed_region_nnqa_25f4":"2566"} +,{"name":"Puerto Lápice","id":"45984","nametype":"Valid","recclass":"Eucrite-br","mass":"500","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"39.350000","reclong":"-3.516670","geolocation":{"type":"Point","coordinates":[-3.51667,39.35]}} +,{"name":"Pulsora","id":"18899","nametype":"Valid","recclass":"H5","mass":"560","fall":"Fell","year":"1863-01-01T00:00:00.000","reclat":"23.366670","reclong":"75.183330","geolocation":{"type":"Point","coordinates":[75.18333,23.36667]}} +,{"name":"Pultusk","id":"18901","nametype":"Valid","recclass":"H5","mass":"250000","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"52.766670","reclong":"21.266670","geolocation":{"type":"Point","coordinates":[21.26667,52.76667]}} +,{"name":"Punganaru","id":"18902","nametype":"Valid","recclass":"Stone-uncl","mass":"100","fall":"Fell","year":"1811-01-01T00:00:00.000","reclat":"13.333330","reclong":"78.950000","geolocation":{"type":"Point","coordinates":[78.95,13.33333]}} +,{"name":"Putinga","id":"18905","nametype":"Valid","recclass":"L6","mass":"300000","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"-29.033330","reclong":"-53.050000","geolocation":{"type":"Point","coordinates":[-53.05,-29.03333]}} +,{"name":"Qidong","id":"18907","nametype":"Valid","recclass":"L/LL5","mass":"1275","fall":"Fell","year":"1982-01-01T00:00:00.000","reclat":"32.083330","reclong":"121.500000","geolocation":{"type":"Point","coordinates":[121.5,32.08333]}} +,{"name":"Qingzhen","id":"18908","nametype":"Valid","recclass":"EH3","mass":"2600","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"26.533330","reclong":"106.466670","geolocation":{"type":"Point","coordinates":[106.46667,26.53333]}} +,{"name":"Queen's Mercy","id":"22357","nametype":"Valid","recclass":"H6","mass":"7000","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"-30.116670","reclong":"28.700000","geolocation":{"type":"Point","coordinates":[28.7,-30.11667]}} +,{"name":"Quenggouk","id":"22358","nametype":"Valid","recclass":"H4","mass":"6045","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"17.766670","reclong":"95.183330","geolocation":{"type":"Point","coordinates":[95.18333,17.76667]}} +,{"name":"Quesa","id":"22360","nametype":"Valid","recclass":"Iron, IAB-ung","mass":"10750","fall":"Fell","year":"1898-01-01T00:00:00.000","reclat":"39.000000","reclong":"-0.666670","geolocation":{"type":"Point","coordinates":[-0.66667,39]}} +,{"name":"Quija","id":"22361","nametype":"Valid","recclass":"H","mass":"17450","fall":"Fell","year":"1990-01-01T00:00:00.000","reclat":"44.616670","reclong":"126.133330","geolocation":{"type":"Point","coordinates":[126.13333,44.61667]}} +,{"name":"Quincay","id":"22363","nametype":"Valid","recclass":"L6","mass":"65","fall":"Fell","year":"1851-01-01T00:00:00.000","reclat":"46.600000","reclong":"0.250000","geolocation":{"type":"Point","coordinates":[0.25,46.6]}} +,{"name":"Raco","id":"22368","nametype":"Valid","recclass":"H5","mass":"5000","fall":"Fell","year":"1957-01-01T00:00:00.000","reclat":"-26.666670","reclong":"-65.450000","geolocation":{"type":"Point","coordinates":[-65.45,-26.66667]}} +,{"name":"Raghunathpura","id":"22371","nametype":"Valid","recclass":"Iron, IIAB","mass":"10200","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"27.725280","reclong":"76.465000","geolocation":{"type":"Point","coordinates":[76.465,27.72528]}} +,{"name":"Rahimyar Khan","id":"31302","nametype":"Valid","recclass":"L5","mass":"67225","fall":"Fell","year":"1983-01-01T00:00:00.000","reclat":"28.225000","reclong":"70.200000","geolocation":{"type":"Point","coordinates":[70.2,28.225]}} +,{"name":"Rakovka","id":"22376","nametype":"Valid","recclass":"L6","mass":"9000","fall":"Fell","year":"1878-01-01T00:00:00.000","reclat":"52.983330","reclong":"37.033330","geolocation":{"type":"Point","coordinates":[37.03333,52.98333]}} +,{"name":"Ramnagar","id":"22384","nametype":"Valid","recclass":"L6","mass":"3766","fall":"Fell","year":"1940-01-01T00:00:00.000","reclat":"26.450000","reclong":"82.900000","geolocation":{"type":"Point","coordinates":[82.9,26.45]}} +,{"name":"Rampurhat","id":"22385","nametype":"Valid","recclass":"LL","mass":"100","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"24.166670","reclong":"87.766670","geolocation":{"type":"Point","coordinates":[87.76667,24.16667]}} +,{"name":"Ramsdorf","id":"22386","nametype":"Valid","recclass":"L6","mass":"4682","fall":"Fell","year":"1958-01-01T00:00:00.000","reclat":"51.883330","reclong":"6.933330","geolocation":{"type":"Point","coordinates":[6.93333,51.88333]}} +,{"name":"Ranchapur","id":"22387","nametype":"Valid","recclass":"H4","mass":"290.39999999999998","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"23.983330","reclong":"87.083330","geolocation":{"type":"Point","coordinates":[87.08333,23.98333]}} +,{"name":"Rancho de la Presa","id":"22390","nametype":"Valid","recclass":"H5","mass":"300","fall":"Fell","year":"1899-01-01T00:00:00.000","reclat":"19.866670","reclong":"-100.816670","geolocation":{"type":"Point","coordinates":[-100.81667,19.86667]}} +,{"name":"Rangala","id":"22392","nametype":"Valid","recclass":"L6","mass":"3224.5","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"25.383330","reclong":"72.016670","geolocation":{"type":"Point","coordinates":[72.01667,25.38333]}} +,{"name":"Raoyang","id":"22394","nametype":"Valid","recclass":"L6","mass":"4910","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"38.200000","reclong":"115.700000","geolocation":{"type":"Point","coordinates":[115.7,38.2]}} +,{"name":"Ras Tanura","id":"22395","nametype":"Valid","recclass":"H6","mass":"6.1","fall":"Fell","year":"1961-01-01T00:00:00.000","reclat":"26.666670","reclong":"50.150000","geolocation":{"type":"Point","coordinates":[50.15,26.66667]}} +,{"name":"Rasgrad","id":"22396","nametype":"Valid","recclass":"Stone-uncl","mass":"24700","fall":"Fell","year":"1740-01-01T00:00:00.000","reclat":"43.500000","reclong":"26.533330","geolocation":{"type":"Point","coordinates":[26.53333,43.5]}} +,{"name":"Ratyn","id":"22398","nametype":"Valid","recclass":"Stone-uncl","mass":"910","fall":"Fell","year":"1880-01-01T00:00:00.000","reclat":"52.200000","reclong":"17.983330","geolocation":{"type":"Point","coordinates":[17.98333,52.2]}} +,{"name":"Red Canyon Lake","id":"53502","nametype":"Valid","recclass":"H5","mass":"18.41","fall":"Fell","year":"2007-01-01T00:00:00.000","reclat":"38.137420","reclong":"-119.758120","geolocation":{"type":"Point","coordinates":[-119.75812,38.13742]},":@computed_region_cbhk_fwbd":"8",":@computed_region_nnqa_25f4":"1391"} +,{"name":"Reliegos","id":"22584","nametype":"Valid","recclass":"L5","mass":"17300","fall":"Fell","year":"1947-01-01T00:00:00.000","reclat":"42.475000","reclong":"-5.333330","geolocation":{"type":"Point","coordinates":[-5.33333,42.475]}} +,{"name":"Rembang","id":"22585","nametype":"Valid","recclass":"Iron, IVA","mass":"10000","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"-6.733330","reclong":"111.366670","geolocation":{"type":"Point","coordinates":[111.36667,-6.73333]}} +,{"name":"Renazzo","id":"22586","nametype":"Valid","recclass":"CR2","mass":"1000","fall":"Fell","year":"1824-01-01T00:00:00.000","reclat":"44.766670","reclong":"11.283330","geolocation":{"type":"Point","coordinates":[11.28333,44.76667]}} +,{"name":"Renca","id":"22587","nametype":"Valid","recclass":"L5","mass":"300","fall":"Fell","year":"1925-01-01T00:00:00.000","reclat":"-32.750000","reclong":"-65.283330","geolocation":{"type":"Point","coordinates":[-65.28333,-32.75]}} +,{"name":"Renqiu","id":"22589","nametype":"Valid","recclass":"L6","mass":"355","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"38.666670","reclong":"116.133330","geolocation":{"type":"Point","coordinates":[116.13333,38.66667]}} +,{"name":"Repeev Khutor","id":"22590","nametype":"Valid","recclass":"Iron, IIF","mass":"7000","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"48.600000","reclong":"45.666670","geolocation":{"type":"Point","coordinates":[45.66667,48.6]}} +,{"name":"Revelstoke","id":"22592","nametype":"Valid","recclass":"CI1","mass":"1","fall":"Fell","year":"1965-01-01T00:00:00.000","reclat":"51.333330","reclong":"-118.950000","geolocation":{"type":"Point","coordinates":[-118.95,51.33333]}} +,{"name":"Rewari","id":"22593","nametype":"Valid","recclass":"L6","mass":"3332","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"28.200000","reclong":"76.666670","geolocation":{"type":"Point","coordinates":[76.66667,28.2]}} +,{"name":"Rich Mountain","id":"22597","nametype":"Valid","recclass":"L6","mass":"668","fall":"Fell","year":"1903-01-01T00:00:00.000","reclat":"35.033330","reclong":"-83.033330","geolocation":{"type":"Point","coordinates":[-83.03333,35.03333]},":@computed_region_cbhk_fwbd":"37",":@computed_region_nnqa_25f4":"2388"} +,{"name":"Uzcudun","id":"24140","nametype":"Valid","recclass":"L","mass":"20000","fall":"Fell","year":"1948-01-01T00:00:00.000","reclat":"-44.116670","reclong":"-66.150000","geolocation":{"type":"Point","coordinates":[-66.15,-44.11667]}} +,{"name":"Richardton","id":"22599","nametype":"Valid","recclass":"H5","mass":"90000","fall":"Fell","year":"1918-01-01T00:00:00.000","reclat":"46.883330","reclong":"-102.316670","geolocation":{"type":"Point","coordinates":[-102.31667,46.88333]},":@computed_region_cbhk_fwbd":"3",":@computed_region_nnqa_25f4":"569"} +,{"name":"Richland Springs","id":"22602","nametype":"Valid","recclass":"OC","mass":"1900","fall":"Fell","year":"1980-01-01T00:00:00.000","reclat":"31.250000","reclong":"-99.033330","geolocation":{"type":"Point","coordinates":[-99.03333,31.25]},":@computed_region_cbhk_fwbd":"23",":@computed_region_nnqa_25f4":"2885"} +,{"name":"Richmond","id":"22603","nametype":"Valid","recclass":"LL5","mass":"1800","fall":"Fell","year":"1828-01-01T00:00:00.000","reclat":"37.466670","reclong":"-77.500000","geolocation":{"type":"Point","coordinates":[-77.5,37.46667]},":@computed_region_cbhk_fwbd":"40",":@computed_region_nnqa_25f4":"2764"} +,{"name":"Rio Negro","id":"22611","nametype":"Valid","recclass":"L4","mass":"1310","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"-26.100000","reclong":"-49.800000","geolocation":{"type":"Point","coordinates":[-49.8,-26.1]}} +,{"name":"Rivolta de Bassi","id":"22614","nametype":"Valid","recclass":"Stone-uncl","mass":"103.3","fall":"Fell","year":"1491-01-01T00:00:00.000","reclat":"45.483330","reclong":"9.516670","geolocation":{"type":"Point","coordinates":[9.51667,45.48333]}} +,{"name":"Rochester","id":"22637","nametype":"Valid","recclass":"H6","mass":"340","fall":"Fell","year":"1876-01-01T00:00:00.000","reclat":"41.083330","reclong":"-86.283330","geolocation":{"type":"Point","coordinates":[-86.28333,41.08333]},":@computed_region_cbhk_fwbd":"35",":@computed_region_nnqa_25f4":"150"} +,{"name":"Rockhampton","id":"22640","nametype":"Valid","recclass":"Stone-uncl","mass":"1641","fall":"Fell","year":"1895-01-01T00:00:00.000","reclat":"-23.383330","reclong":"150.516670","geolocation":{"type":"Point","coordinates":[150.51667,-23.38333]}} +,{"name":"Roda","id":"22641","nametype":"Valid","recclass":"Diogenite","mass":"400","fall":"Fell","year":"1871-01-01T00:00:00.000","reclat":"42.300000","reclong":"0.550000","geolocation":{"type":"Point","coordinates":[0.55,42.3]}} +,{"name":"Rodach","id":"22642","nametype":"Valid","recclass":"Stone-uncl","mass":"2900","fall":"Fell","year":"1775-01-01T00:00:00.000","reclat":"50.350000","reclong":"10.800000","geolocation":{"type":"Point","coordinates":[10.8,50.35]}} +,{"name":"Rose City","id":"22766","nametype":"Valid","recclass":"H5","mass":"10600","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"44.516670","reclong":"-83.950000","geolocation":{"type":"Point","coordinates":[-83.95,44.51667]},":@computed_region_cbhk_fwbd":"50",":@computed_region_nnqa_25f4":"361"} +,{"name":"Rowton","id":"22773","nametype":"Valid","recclass":"Iron, IIIAB","mass":"3500","fall":"Fell","year":"1876-01-01T00:00:00.000","reclat":"52.766670","reclong":"-2.516670","geolocation":{"type":"Point","coordinates":[-2.51667,52.76667]}} +,{"name":"Ruhobobo","id":"22780","nametype":"Valid","recclass":"L6","mass":"465.5","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"-1.450000","reclong":"29.833330","geolocation":{"type":"Point","coordinates":[29.83333,-1.45]}} +,{"name":"Rumuruti","id":"22782","nametype":"Valid","recclass":"R3.8-6","mass":"67","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"0.266670","reclong":"36.533330","geolocation":{"type":"Point","coordinates":[36.53333,0.26667]}} +,{"name":"Rupota","id":"22783","nametype":"Valid","recclass":"L4-6","mass":"6000","fall":"Fell","year":"1949-01-01T00:00:00.000","reclat":"-10.266670","reclong":"38.766670","geolocation":{"type":"Point","coordinates":[38.76667,-10.26667]}} +,{"name":"Ryechki","id":"22791","nametype":"Valid","recclass":"L5","mass":"13000","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"51.133330","reclong":"34.500000","geolocation":{"type":"Point","coordinates":[34.5,51.13333]}} +,{"name":"Sabetmahet","id":"22792","nametype":"Valid","recclass":"H5","mass":"1250","fall":"Fell","year":"1855-01-01T00:00:00.000","reclat":"27.433330","reclong":"82.083330","geolocation":{"type":"Point","coordinates":[82.08333,27.43333]}} +,{"name":"Sabrum","id":"22793","nametype":"Valid","recclass":"LL6","mass":"478","fall":"Fell","year":"1999-01-01T00:00:00.000","reclat":"23.083330","reclong":"91.666670","geolocation":{"type":"Point","coordinates":[91.66667,23.08333]}} +,{"name":"Sagan","id":"22796","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1636-01-01T00:00:00.000","reclat":"51.533330","reclong":"14.883330","geolocation":{"type":"Point","coordinates":[14.88333,51.53333]}} +,{"name":"Saint-Sauveur","id":"23101","nametype":"Valid","recclass":"EH5","mass":"14000","fall":"Fell","year":"1914-01-01T00:00:00.000","reclat":"43.733330","reclong":"1.383330","geolocation":{"type":"Point","coordinates":[1.38333,43.73333]}} +,{"name":"Saint-Séverin","id":"23102","nametype":"Valid","recclass":"LL6","mass":"271000","fall":"Fell","year":"1966-01-01T00:00:00.000","reclat":"45.300000","reclong":"0.233330","geolocation":{"type":"Point","coordinates":[0.23333,45.3]}} +,{"name":"Sakauchi","id":"23103","nametype":"Valid","recclass":"Iron","mass":"4180","fall":"Fell","year":"1913-01-01T00:00:00.000","reclat":"35.666670","reclong":"136.300000","geolocation":{"type":"Point","coordinates":[136.3,35.66667]}} +,{"name":"Salem","id":"23107","nametype":"Valid","recclass":"L6","mass":"61.4","fall":"Fell","year":"1981-01-01T00:00:00.000","reclat":"44.979170","reclong":"-122.969440","geolocation":{"type":"Point","coordinates":[-122.96944,44.97917]},":@computed_region_cbhk_fwbd":"12",":@computed_region_nnqa_25f4":"2409"} +,{"name":"Salles","id":"23111","nametype":"Valid","recclass":"L5","mass":"9000","fall":"Fell","year":"1798-01-01T00:00:00.000","reclat":"46.050000","reclong":"4.633330","geolocation":{"type":"Point","coordinates":[4.63333,46.05]}} +,{"name":"Salzwedel","id":"23114","nametype":"Valid","recclass":"LL5","mass":"43","fall":"Fell","year":"1985-01-01T00:00:00.000","reclat":"52.750000","reclong":"11.050000","geolocation":{"type":"Point","coordinates":[11.05,52.75]}} +,{"name":"Samelia","id":"23115","nametype":"Valid","recclass":"Iron, IIIAB","mass":"2462","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"25.666670","reclong":"74.866670","geolocation":{"type":"Point","coordinates":[74.86667,25.66667]}} +,{"name":"San Juan Capistrano","id":"23128","nametype":"Valid","recclass":"H6","mass":"56","fall":"Fell","year":"1973-01-01T00:00:00.000","reclat":"33.484720","reclong":"-117.662500","geolocation":{"type":"Point","coordinates":[-117.6625,33.48472]},":@computed_region_cbhk_fwbd":"8",":@computed_region_nnqa_25f4":"1174"} +,{"name":"San Michele","id":"31315","nametype":"Valid","recclass":"L6","mass":"237","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"43.666670","reclong":"13.000000","geolocation":{"type":"Point","coordinates":[13,43.66667]}} +,{"name":"San Pedro de Quiles","id":"23130","nametype":"Valid","recclass":"L6","mass":"282","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"-31.016670","reclong":"-71.400000","geolocation":{"type":"Point","coordinates":[-71.4,-31.01667]}} +,{"name":"San Pedro Jacuaro","id":"34063","nametype":"Valid","recclass":"LL6","mass":"460","fall":"Fell","year":"1968-01-01T00:00:00.000","reclat":"19.766670","reclong":"-100.650000","geolocation":{"type":"Point","coordinates":[-100.65,19.76667]}} +,{"name":"Santa Barbara","id":"23161","nametype":"Valid","recclass":"L4","mass":"400","fall":"Fell","year":"1873-01-01T00:00:00.000","reclat":"-29.200000","reclong":"-51.866670","geolocation":{"type":"Point","coordinates":[-51.86667,-29.2]}} +,{"name":"Santa Cruz","id":"23164","nametype":"Valid","recclass":"CM2","mass":"60","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"24.166670","reclong":"-99.333330","geolocation":{"type":"Point","coordinates":[-99.33333,24.16667]}} +,{"name":"Santa Isabel","id":"23165","nametype":"Valid","recclass":"L6","mass":"5500","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"-33.900000","reclong":"-61.700000","geolocation":{"type":"Point","coordinates":[-61.7,-33.9]}} +,{"name":"Santa Lucia (2008)","id":"50909","nametype":"Valid","recclass":"L6","mass":"4000","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"-31.535556","reclong":"-68.489444","geolocation":{"type":"Point","coordinates":[-68.489444,-31.535556]}} +,{"name":"São Jose do Rio Preto","id":"23171","nametype":"Valid","recclass":"H4","mass":"927","fall":"Fell","year":"1962-01-01T00:00:00.000","reclat":"-20.810000","reclong":"-49.380560","geolocation":{"type":"Point","coordinates":[-49.38056,-20.81]}} +,{"name":"Saratov","id":"23176","nametype":"Valid","recclass":"L4","mass":"200000","fall":"Fell","year":"1918-01-01T00:00:00.000","reclat":"52.550000","reclong":"46.550000","geolocation":{"type":"Point","coordinates":[46.55,52.55]}} +,{"name":"Sasagase","id":"23187","nametype":"Valid","recclass":"H","mass":"695","fall":"Fell","year":"1688-01-01T00:00:00.000","reclat":"34.716670","reclong":"137.783330","geolocation":{"type":"Point","coordinates":[137.78333,34.71667]}} +,{"name":"Sauguis","id":"23188","nametype":"Valid","recclass":"L6","mass":"4000","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"43.150000","reclong":"-0.850000","geolocation":{"type":"Point","coordinates":[-0.85,43.15]}} +,{"name":"Savtschenskoje","id":"23190","nametype":"Valid","recclass":"LL4","mass":"2500","fall":"Fell","year":"1894-01-01T00:00:00.000","reclat":"47.216670","reclong":"29.866670","geolocation":{"type":"Point","coordinates":[29.86667,47.21667]}} +,{"name":"Sayama","id":"23192","nametype":"Valid","recclass":"CM2","mass":"430","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"35.866670","reclong":"139.400000","geolocation":{"type":"Point","coordinates":[139.4,35.86667]}} +,{"name":"Sazovice","id":"23455","nametype":"Valid","recclass":"L5","mass":"412","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"49.233330","reclong":"17.566670","geolocation":{"type":"Point","coordinates":[17.56667,49.23333]}} +,{"name":"Schellin","id":"23457","nametype":"Valid","recclass":"L","mass":"7000","fall":"Fell","year":"1715-01-01T00:00:00.000","reclat":"53.350000","reclong":"15.050000","geolocation":{"type":"Point","coordinates":[15.05,53.35]}} +,{"name":"Schenectady","id":"23458","nametype":"Valid","recclass":"H5","mass":"283.3","fall":"Fell","year":"1968-01-01T00:00:00.000","reclat":"42.860830","reclong":"-73.950280","geolocation":{"type":"Point","coordinates":[-73.95028,42.86083]},":@computed_region_cbhk_fwbd":"47",":@computed_region_nnqa_25f4":"2142"} +,{"name":"Schönenberg","id":"23460","nametype":"Valid","recclass":"L6","mass":"8000","fall":"Fell","year":"1846-01-01T00:00:00.000","reclat":"48.116670","reclong":"10.466670","geolocation":{"type":"Point","coordinates":[10.46667,48.11667]}} +,{"name":"Searsmont","id":"23472","nametype":"Valid","recclass":"H5","mass":"5400","fall":"Fell","year":"1871-01-01T00:00:00.000","reclat":"44.366670","reclong":"-69.200000","geolocation":{"type":"Point","coordinates":[-69.2,44.36667]},":@computed_region_cbhk_fwbd":"49",":@computed_region_nnqa_25f4":"1727"} +,{"name":"Sediköy","id":"23473","nametype":"Valid","recclass":"L6","mass":"240","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"38.300000","reclong":"27.133330","geolocation":{"type":"Point","coordinates":[27.13333,38.3]}} +,{"name":"Segowlie","id":"23476","nametype":"Valid","recclass":"LL6","mass":"6930","fall":"Fell","year":"1853-01-01T00:00:00.000","reclat":"26.750000","reclong":"84.783330","geolocation":{"type":"Point","coordinates":[84.78333,26.75]}} +,{"name":"Selakopi","id":"23481","nametype":"Valid","recclass":"H5","mass":"1590","fall":"Fell","year":"1939-01-01T00:00:00.000","reclat":"-7.233330","reclong":"107.333330","geolocation":{"type":"Point","coordinates":[107.33333,-7.23333]}} +,{"name":"Seldebourak","id":"23483","nametype":"Valid","recclass":"H5","mass":"150","fall":"Fell","year":"1947-01-01T00:00:00.000","reclat":"22.833330","reclong":"4.983330","geolocation":{"type":"Point","coordinates":[4.98333,22.83333]}} +,{"name":"Semarkona","id":"23487","nametype":"Valid","recclass":"LL3.00","mass":"691","fall":"Fell","year":"1940-01-01T00:00:00.000","reclat":"22.250000","reclong":"79.000000","geolocation":{"type":"Point","coordinates":[79,22.25]}} +,{"name":"Sena","id":"23495","nametype":"Valid","recclass":"H4","mass":"4000","fall":"Fell","year":"1773-01-01T00:00:00.000","reclat":"41.716670","reclong":"-0.050000","geolocation":{"type":"Point","coordinates":[-0.05,41.71667]}} +,{"name":"Senboku","id":"23496","nametype":"Valid","recclass":"H6","mass":"866","fall":"Fell","year":"1993-01-01T00:00:00.000","reclat":"39.438330","reclong":"140.511670","geolocation":{"type":"Point","coordinates":[140.51167,39.43833]}} +,{"name":"Seoni","id":"23500","nametype":"Valid","recclass":"H6","mass":"20000","fall":"Fell","year":"1966-01-01T00:00:00.000","reclat":"21.683890","reclong":"79.500830","geolocation":{"type":"Point","coordinates":[79.50083,21.68389]}} +,{"name":"Seres","id":"23501","nametype":"Valid","recclass":"H4","mass":"8500","fall":"Fell","year":"1818-01-01T00:00:00.000","reclat":"41.050000","reclong":"23.566670","geolocation":{"type":"Point","coordinates":[23.56667,41.05]}} +,{"name":"Serra de Magé","id":"23502","nametype":"Valid","recclass":"Eucrite-cm","mass":"1800","fall":"Fell","year":"1923-01-01T00:00:00.000","reclat":"-8.383330","reclong":"-36.766670","geolocation":{"type":"Point","coordinates":[-36.76667,-8.38333]}} +,{"name":"Sete Lagoas","id":"23504","nametype":"Valid","recclass":"H4","mass":"350","fall":"Fell","year":"1908-01-01T00:00:00.000","reclat":"-19.466670","reclong":"-44.216670","geolocation":{"type":"Point","coordinates":[-44.21667,-19.46667]}} +,{"name":"Sevilla","id":"23508","nametype":"Valid","recclass":"LL4","mass":"180","fall":"Fell","year":"1862-01-01T00:00:00.000","reclat":"37.416670","reclong":"-6.000000","geolocation":{"type":"Point","coordinates":[-6,37.41667]}} +,{"name":"Sevrukovo","id":"23509","nametype":"Valid","recclass":"L5","mass":"101000","fall":"Fell","year":"1874-01-01T00:00:00.000","reclat":"50.616670","reclong":"36.600000","geolocation":{"type":"Point","coordinates":[36.6,50.61667]}} +,{"name":"Sfax","id":"23512","nametype":"Valid","recclass":"L6","mass":"7000","fall":"Fell","year":"1989-01-01T00:00:00.000","reclat":"34.750000","reclong":"10.716670","geolocation":{"type":"Point","coordinates":[10.71667,34.75]}} +,{"name":"Shalka","id":"23521","nametype":"Valid","recclass":"Diogenite","mass":"4000","fall":"Fell","year":"1850-01-01T00:00:00.000","reclat":"23.100000","reclong":"87.300000","geolocation":{"type":"Point","coordinates":[87.3,23.1]}} +,{"name":"Sharps","id":"23525","nametype":"Valid","recclass":"H3.4","mass":"1265","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"37.833330","reclong":"-76.700000","geolocation":{"type":"Point","coordinates":[-76.7,37.83333]},":@computed_region_cbhk_fwbd":"40",":@computed_region_nnqa_25f4":"921"} +,{"name":"Shelburne","id":"23529","nametype":"Valid","recclass":"L5","mass":"18600","fall":"Fell","year":"1904-01-01T00:00:00.000","reclat":"44.050000","reclong":"-80.166670","geolocation":{"type":"Point","coordinates":[-80.16667,44.05]}} +,{"name":"Shergotty","id":"23530","nametype":"Valid","recclass":"Martian (shergottite)","mass":"5000","fall":"Fell","year":"1865-01-01T00:00:00.000","reclat":"24.550000","reclong":"84.833330","geolocation":{"type":"Point","coordinates":[84.83333,24.55]}} +,{"name":"Sheyang","id":"23531","nametype":"Valid","recclass":"L6","mass":"605","fall":"Fell","year":"1976-01-01T00:00:00.000","reclat":"33.650000","reclong":"120.066670","geolocation":{"type":"Point","coordinates":[120.06667,33.65]}} +,{"name":"Shikarpur","id":"23534","nametype":"Valid","recclass":"L6","mass":"3679.7","fall":"Fell","year":"1921-01-01T00:00:00.000","reclat":"25.850000","reclong":"87.577500","geolocation":{"type":"Point","coordinates":[87.5775,25.85]}} +,{"name":"Shuangyang","id":"23582","nametype":"Valid","recclass":"H5","mass":"3900","fall":"Fell","year":"1971-01-01T00:00:00.000","reclat":"43.500000","reclong":"125.666670","geolocation":{"type":"Point","coordinates":[125.66667,43.5]}} +,{"name":"Shupiyan","id":"23583","nametype":"Valid","recclass":"H6","mass":"5000","fall":"Fell","year":"1912-01-01T00:00:00.000","reclat":"33.716670","reclong":"74.833330","geolocation":{"type":"Point","coordinates":[74.83333,33.71667]}} +,{"name":"Shytal","id":"23584","nametype":"Valid","recclass":"L6","mass":"3200","fall":"Fell","year":"1863-01-01T00:00:00.000","reclat":"24.333330","reclong":"90.166670","geolocation":{"type":"Point","coordinates":[90.16667,24.33333]}} +,{"name":"Siena","id":"23586","nametype":"Valid","recclass":"LL5","mass":"3700","fall":"Fell","year":"1794-01-01T00:00:00.000","reclat":"43.116670","reclong":"11.600000","geolocation":{"type":"Point","coordinates":[11.6,43.11667]}} +,{"name":"Sikhote-Alin","id":"23593","nametype":"Valid","recclass":"Iron, IIAB","mass":"23000000","fall":"Fell","year":"1947-01-01T00:00:00.000","reclat":"46.160000","reclong":"134.653330","geolocation":{"type":"Point","coordinates":[134.65333,46.16]}} +,{"name":"Silao","id":"23594","nametype":"Valid","recclass":"H5","mass":"1710","fall":"Fell","year":"1995-01-01T00:00:00.000","reclat":"20.933330","reclong":"-101.383330","geolocation":{"type":"Point","coordinates":[-101.38333,20.93333]}} +,{"name":"Silistra","id":"55584","nametype":"Valid","recclass":"Achondrite-ung","mass":"0.15","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"44.116670","reclong":"27.266670","geolocation":{"type":"Point","coordinates":[27.26667,44.11667]}} +,{"name":"Simmern","id":"23603","nametype":"Valid","recclass":"H5","mass":"1222","fall":"Fell","year":"1920-01-01T00:00:00.000","reclat":"49.983330","reclong":"7.533330","geolocation":{"type":"Point","coordinates":[7.53333,49.98333]}} +,{"name":"Sinai","id":"23606","nametype":"Valid","recclass":"L6","mass":"1455","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"30.900000","reclong":"32.483330","geolocation":{"type":"Point","coordinates":[32.48333,30.9]}} +,{"name":"Sindhri","id":"23611","nametype":"Valid","recclass":"H5","mass":"8400","fall":"Fell","year":"1901-01-01T00:00:00.000","reclat":"26.216670","reclong":"69.550000","geolocation":{"type":"Point","coordinates":[69.55,26.21667]}} +,{"name":"Sinnai","id":"23613","nametype":"Valid","recclass":"H6","mass":"2000","fall":"Fell","year":"1956-01-01T00:00:00.000","reclat":"39.300000","reclong":"9.200000","geolocation":{"type":"Point","coordinates":[9.2,39.3]}} +,{"name":"Sioux County","id":"23614","nametype":"Valid","recclass":"Eucrite-mmict","mass":"4100","fall":"Fell","year":"1933-01-01T00:00:00.000","reclat":"42.583330","reclong":"-103.666670","geolocation":{"type":"Point","coordinates":[-103.66667,42.58333]},":@computed_region_cbhk_fwbd":"19",":@computed_region_nnqa_25f4":"2351"} +,{"name":"Sitathali","id":"23616","nametype":"Valid","recclass":"H5","mass":"1600","fall":"Fell","year":"1875-01-01T00:00:00.000","reclat":"20.916670","reclong":"82.583330","geolocation":{"type":"Point","coordinates":[82.58333,20.91667]}} +,{"name":"Sivas","id":"23617","nametype":"Valid","recclass":"H6","mass":"40000","fall":"Fell","year":"1989-01-01T00:00:00.000","reclat":"39.824670","reclong":"36.135830","geolocation":{"type":"Point","coordinates":[36.13583,39.82467]}} +,{"name":"Sixiangkou","id":"23619","nametype":"Valid","recclass":"L5","mass":"630","fall":"Fell","year":"1989-01-01T00:00:00.000","reclat":"32.433330","reclong":"119.866670","geolocation":{"type":"Point","coordinates":[119.86667,32.43333]}} +,{"name":"Ski","id":"23621","nametype":"Valid","recclass":"L6","mass":"850","fall":"Fell","year":"1848-01-01T00:00:00.000","reclat":"59.733330","reclong":"10.866670","geolocation":{"type":"Point","coordinates":[10.86667,59.73333]}} +,{"name":"Slavetic","id":"23626","nametype":"Valid","recclass":"H5","mass":"1708","fall":"Fell","year":"1868-01-01T00:00:00.000","reclat":"45.683330","reclong":"15.600000","geolocation":{"type":"Point","coordinates":[15.6,45.68333]}} +,{"name":"Slobodka","id":"23645","nametype":"Valid","recclass":"L4","mass":"2750","fall":"Fell","year":"1818-01-01T00:00:00.000","reclat":"55.000000","reclong":"35.000000","geolocation":{"type":"Point","coordinates":[35,55]}} +,{"name":"Soheria","id":"23660","nametype":"Valid","recclass":"OC","mass":"72.900000000000006","fall":"Fell","year":"1960-01-01T00:00:00.000","reclat":"27.133330","reclong":"84.066670","geolocation":{"type":"Point","coordinates":[84.06667,27.13333]}} +,{"name":"Soko-Banja","id":"23661","nametype":"Valid","recclass":"LL4","mass":"80000","fall":"Fell","year":"1877-01-01T00:00:00.000","reclat":"43.666670","reclong":"21.866670","geolocation":{"type":"Point","coordinates":[21.86667,43.66667]}} +,{"name":"Sologne","id":"23663","nametype":"Valid","recclass":"H5","mass":"54","fall":"Fell","year":"1860-01-01T00:00:00.000","reclat":"47.366670","reclong":"1.733330","geolocation":{"type":"Point","coordinates":[1.73333,47.36667]}} +,{"name":"Sołtmany","id":"53829","nametype":"Valid","recclass":"L6","mass":"1066","fall":"Fell","year":"2011-01-01T00:00:00.000","reclat":"54.008830","reclong":"22.005000","geolocation":{"type":"Point","coordinates":[22.005,54.00883]}} +,{"name":"Sone","id":"23667","nametype":"Valid","recclass":"H5","mass":"17100","fall":"Fell","year":"1866-01-01T00:00:00.000","reclat":"35.166670","reclong":"135.333330","geolocation":{"type":"Point","coordinates":[135.33333,35.16667]}} +,{"name":"Songyuan","id":"23668","nametype":"Valid","recclass":"L6","mass":"36900","fall":"Fell","year":"1993-01-01T00:00:00.000","reclat":"45.250000","reclong":"125.000000","geolocation":{"type":"Point","coordinates":[125,45.25]}} +,{"name":"Sopot","id":"23670","nametype":"Valid","recclass":"OC","mass":"958","fall":"Fell","year":"1927-01-01T00:00:00.000","reclat":"44.416670","reclong":"23.500000","geolocation":{"type":"Point","coordinates":[23.5,44.41667]}} +,{"name":"Soroti","id":"23671","nametype":"Valid","recclass":"Iron, ungrouped","mass":"2050","fall":"Fell","year":"1945-01-01T00:00:00.000","reclat":"1.700000","reclong":"33.633330","geolocation":{"type":"Point","coordinates":[33.63333,1.7]}} +,{"name":"St. Caprais-de-Quinsac","id":"23081","nametype":"Valid","recclass":"L6","mass":"360","fall":"Fell","year":"1883-01-01T00:00:00.000","reclat":"44.750000","reclong":"0.050000","geolocation":{"type":"Point","coordinates":[0.05,44.75]}} +,{"name":"St. Christophe-la-Chartreuse","id":"23082","nametype":"Valid","recclass":"L6","mass":"5500","fall":"Fell","year":"1841-01-01T00:00:00.000","reclat":"46.950000","reclong":"-1.500000","geolocation":{"type":"Point","coordinates":[-1.5,46.95]}} +,{"name":"St. Denis Westrem","id":"23083","nametype":"Valid","recclass":"L6","mass":"700","fall":"Fell","year":"1855-01-01T00:00:00.000","reclat":"51.050000","reclong":"3.750000","geolocation":{"type":"Point","coordinates":[3.75,51.05]}} +,{"name":"St. Germain-du-Pinel","id":"23087","nametype":"Valid","recclass":"H6","mass":"4000","fall":"Fell","year":"1890-01-01T00:00:00.000","reclat":"48.016670","reclong":"-1.150000","geolocation":{"type":"Point","coordinates":[-1.15,48.01667]}} +,{"name":"St. Louis","id":"23089","nametype":"Valid","recclass":"H4","mass":"1000","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"38.700000","reclong":"-90.233330","geolocation":{"type":"Point","coordinates":[-90.23333,38.7]},":@computed_region_cbhk_fwbd":"18",":@computed_region_nnqa_25f4":"2223"} +,{"name":"St. Mark's","id":"23090","nametype":"Valid","recclass":"EH5","mass":"13780","fall":"Fell","year":"1903-01-01T00:00:00.000","reclat":"-32.016670","reclong":"27.416670","geolocation":{"type":"Point","coordinates":[27.41667,-32.01667]}} +,{"name":"St. Mary's County","id":"23091","nametype":"Valid","recclass":"LL3.3","mass":"24.3","fall":"Fell","year":"1919-01-01T00:00:00.000","reclat":"38.166670","reclong":"-76.383330","geolocation":{"type":"Point","coordinates":[-76.38333,38.16667]},":@computed_region_cbhk_fwbd":"45",":@computed_region_nnqa_25f4":"424"} +,{"name":"St. Mesmin","id":"23092","nametype":"Valid","recclass":"LL6","mass":"8300","fall":"Fell","year":"1866-01-01T00:00:00.000","reclat":"48.450000","reclong":"3.933330","geolocation":{"type":"Point","coordinates":[3.93333,48.45]}} +,{"name":"St. Michel","id":"23093","nametype":"Valid","recclass":"L6","mass":"17000","fall":"Fell","year":"1910-01-01T00:00:00.000","reclat":"61.650000","reclong":"27.200000","geolocation":{"type":"Point","coordinates":[27.2,61.65]}} +,{"name":"St.-Chinian","id":"23097","nametype":"Valid","recclass":"L6","mass":"134.30000000000001","fall":"Fell","year":"1959-01-01T00:00:00.000","reclat":"43.433330","reclong":"2.950000","geolocation":{"type":"Point","coordinates":[2.95,43.43333]}} +,{"name":"Ställdalen","id":"23712","nametype":"Valid","recclass":"H5","mass":"34000","fall":"Fell","year":"1876-01-01T00:00:00.000","reclat":"59.933330","reclong":"14.950000","geolocation":{"type":"Point","coordinates":[14.95,59.93333]}} +,{"name":"Stannern","id":"23713","nametype":"Valid","recclass":"Eucrite-mmict","mass":"52000","fall":"Fell","year":"1808-01-01T00:00:00.000","reclat":"49.283330","reclong":"15.566670","geolocation":{"type":"Point","coordinates":[15.56667,49.28333]}} +,{"name":"Stavropol","id":"23717","nametype":"Valid","recclass":"L6","mass":"1500","fall":"Fell","year":"1857-01-01T00:00:00.000","reclat":"45.050000","reclong":"41.983330","geolocation":{"type":"Point","coordinates":[41.98333,45.05]}} +,{"name":"Ste. Marguerite","id":"23099","nametype":"Valid","recclass":"H4","mass":"4960","fall":"Fell","year":"1962-01-01T00:00:00.000","reclat":"50.766670","reclong":"3.000000","geolocation":{"type":"Point","coordinates":[3,50.76667]}} +,{"name":"Sterlitamak","id":"23724","nametype":"Valid","recclass":"Iron, IIIAB","mass":"325000","fall":"Fell","year":"1990-01-01T00:00:00.000","reclat":"53.666670","reclong":"55.983330","geolocation":{"type":"Point","coordinates":[55.98333,53.66667]}} +,{"name":"Stolzenau","id":"23726","nametype":"Valid","recclass":"Stone-uncl","fall":"Fell","year":"1647-01-01T00:00:00.000","reclat":"52.533330","reclong":"9.050000","geolocation":{"type":"Point","coordinates":[9.05,52.53333]}} +,{"name":"Stratford","id":"23728","nametype":"Valid","recclass":"L6","mass":"50","fall":"Fell","year":"1974-01-01T00:00:00.000","reclat":"41.200000","reclong":"-73.133330","geolocation":{"type":"Point","coordinates":[-73.13333,41.2]},":@computed_region_cbhk_fwbd":"24",":@computed_region_nnqa_25f4":"1040"} +,{"name":"Strathmore","id":"23729","nametype":"Valid","recclass":"L6","mass":"13400","fall":"Fell","year":"1917-01-01T00:00:00.000","reclat":"56.583330","reclong":"-3.250000","geolocation":{"type":"Point","coordinates":[-3.25,56.58333]}} +,{"name":"Stretchleigh","id":"23732","nametype":"Valid","recclass":"Stone-uncl","mass":"10400","fall":"Fell","year":"1623-01-01T00:00:00.000","reclat":"50.383330","reclong":"-3.950000","geolocation":{"type":"Point","coordinates":[-3.95,50.38333]}} +,{"name":"St-Robert","id":"23733","nametype":"Valid","recclass":"H5","mass":"25400","fall":"Fell","year":"1994-01-01T00:00:00.000","reclat":"45.968610","reclong":"-72.978060","geolocation":{"type":"Point","coordinates":[-72.97806,45.96861]}} +,{"name":"Success","id":"23736","nametype":"Valid","recclass":"L6","mass":"3500","fall":"Fell","year":"1924-01-01T00:00:00.000","reclat":"36.483330","reclong":"-90.666670","geolocation":{"type":"Point","coordinates":[-90.66667,36.48333]},":@computed_region_cbhk_fwbd":"15",":@computed_region_nnqa_25f4":"955"} +,{"name":"Suchy Dul","id":"23737","nametype":"Valid","recclass":"L6","mass":"815.3","fall":"Fell","year":"1969-01-01T00:00:00.000","reclat":"50.538060","reclong":"16.263330","geolocation":{"type":"Point","coordinates":[16.26333,50.53806]}} +,{"name":"Suizhou","id":"23738","nametype":"Valid","recclass":"L6","mass":"260000","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"31.616670","reclong":"113.466670","geolocation":{"type":"Point","coordinates":[113.46667,31.61667]}} +,{"name":"Sulagiri","id":"48951","nametype":"Valid","recclass":"LL6","mass":"110000","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"12.666670","reclong":"78.033330","geolocation":{"type":"Point","coordinates":[78.03333,12.66667]}} +,{"name":"Sultanpur","id":"23741","nametype":"Valid","recclass":"L/LL6","mass":"1710.5","fall":"Fell","year":"1916-01-01T00:00:00.000","reclat":"25.933330","reclong":"84.283330","geolocation":{"type":"Point","coordinates":[84.28333,25.93333]}} +,{"name":"Sungach","id":"23745","nametype":"Valid","recclass":"H5","mass":"637","fall":"Fell","year":"1935-01-01T00:00:00.000","reclat":"44.866670","reclong":"133.166670","geolocation":{"type":"Point","coordinates":[133.16667,44.86667]}} +,{"name":"Supuhee","id":"23760","nametype":"Valid","recclass":"H6","mass":"7235","fall":"Fell","year":"1865-01-01T00:00:00.000","reclat":"26.716670","reclong":"84.216670","geolocation":{"type":"Point","coordinates":[84.21667,26.71667]}} +,{"name":"Sutter's Mill","id":"55529","nametype":"Valid","recclass":"C","mass":"992.5","fall":"Fell","year":"2012-01-01T00:00:00.000","reclat":"38.803890","reclong":"-120.908060","geolocation":{"type":"Point","coordinates":[-120.90806,38.80389]},":@computed_region_cbhk_fwbd":"8",":@computed_region_nnqa_25f4":"1187"} +,{"name":"Sylacauga","id":"23773","nametype":"Valid","recclass":"H4","mass":"5560","fall":"Fell","year":"1954-01-01T00:00:00.000","reclat":"33.188360","reclong":"-86.294500","geolocation":{"type":"Point","coordinates":[-86.2945,33.18836]},":@computed_region_cbhk_fwbd":"29",":@computed_region_nnqa_25f4":"1637"} +,{"name":"Tabor","id":"23776","nametype":"Valid","recclass":"H5","mass":"7540","fall":"Fell","year":"1753-01-01T00:00:00.000","reclat":"49.400000","reclong":"14.650000","geolocation":{"type":"Point","coordinates":[14.65,49.4]}} +,{"name":"Tadjera","id":"23778","nametype":"Valid","recclass":"L5","mass":"9000","fall":"Fell","year":"1867-01-01T00:00:00.000","reclat":"36.183330","reclong":"5.416670","geolocation":{"type":"Point","coordinates":[5.41667,36.18333]}} +,{"name":"Tagish Lake","id":"23782","nametype":"Valid","recclass":"C2-ung","mass":"10000","fall":"Fell","year":"2000-01-01T00:00:00.000","reclat":"59.704440","reclong":"-134.201390","geolocation":{"type":"Point","coordinates":[-134.20139,59.70444]}} +,{"name":"Tahara","id":"23784","nametype":"Valid","recclass":"H4/5","mass":"1000","fall":"Fell","year":"1991-01-01T00:00:00.000","reclat":"34.720000","reclong":"137.305000","geolocation":{"type":"Point","coordinates":[137.305,34.72]}} +,{"name":"Takenouchi","id":"23789","nametype":"Valid","recclass":"H5","mass":"720","fall":"Fell","year":"1880-01-01T00:00:00.000","reclat":"35.383330","reclong":"134.900000","geolocation":{"type":"Point","coordinates":[134.9,35.38333]}} +,{"name":"Talampaya","id":"23791","nametype":"Valid","recclass":"Eucrite-cm","mass":"1421","fall":"Fell","year":"1995-01-01T00:00:00.000"} +,{"name":"Tambakwatu","id":"23795","nametype":"Valid","recclass":"L6","mass":"10500","fall":"Fell","year":"1975-01-01T00:00:00.000","reclat":"-7.750000","reclong":"112.766670","geolocation":{"type":"Point","coordinates":[112.76667,-7.75]}} +,{"name":"Tamdakht","id":"48691","nametype":"Valid","recclass":"H5","mass":"100000","fall":"Fell","year":"2008-01-01T00:00:00.000","reclat":"31.163330","reclong":"-7.015000","geolocation":{"type":"Point","coordinates":[-7.015,31.16333]}} +,{"name":"Tané","id":"23801","nametype":"Valid","recclass":"L5","mass":"905","fall":"Fell","year":"1918-01-01T00:00:00.000","reclat":"35.433330","reclong":"136.233330","geolocation":{"type":"Point","coordinates":[136.23333,35.43333]}} +,{"name":"Taonan","id":"23873","nametype":"Valid","recclass":"L5","mass":"3850","fall":"Fell","year":"1965-01-01T00:00:00.000","reclat":"45.400000","reclong":"122.900000","geolocation":{"type":"Point","coordinates":[122.9,45.4]}} +,{"name":"Tatahouine","id":"23884","nametype":"Valid","recclass":"Diogenite","mass":"12000","fall":"Fell","year":"1931-01-01T00:00:00.000","reclat":"32.950000","reclong":"10.416670","geolocation":{"type":"Point","coordinates":[10.41667,32.95]}} +,{"name":"Tathlith","id":"23885","nametype":"Valid","recclass":"L6","mass":"2500","fall":"Fell","year":"1967-01-01T00:00:00.000","reclat":"19.383330","reclong":"43.733330","geolocation":{"type":"Point","coordinates":[43.73333,19.38333]}} +,{"name":"Tauk","id":"23887","nametype":"Valid","recclass":"L6","mass":"6000","fall":"Fell","year":"1929-01-01T00:00:00.000","reclat":"35.133330","reclong":"44.450000","geolocation":{"type":"Point","coordinates":[44.45,35.13333]}} +,{"name":"Tauti","id":"23888","nametype":"Valid","recclass":"L6","mass":"21000","fall":"Fell","year":"1937-01-01T00:00:00.000","reclat":"46.716670","reclong":"23.500000","geolocation":{"type":"Point","coordinates":[23.5,46.71667]}} +,{"name":"Tenham","id":"23897","nametype":"Valid","recclass":"L6","mass":"160000","fall":"Fell","year":"1879-01-01T00:00:00.000","reclat":"-25.733330","reclong":"142.950000","geolocation":{"type":"Point","coordinates":[142.95,-25.73333]}} +,{"name":"Tennasilm","id":"23898","nametype":"Valid","recclass":"L4","mass":"28500","fall":"Fell","year":"1872-01-01T00:00:00.000","reclat":"58.033330","reclong":"26.950000","geolocation":{"type":"Point","coordinates":[26.95,58.03333]}} +,{"name":"Thal","id":"23908","nametype":"Valid","recclass":"H6","mass":"342","fall":"Fell","year":"1950-01-01T00:00:00.000","reclat":"33.400000","reclong":"70.600000","geolocation":{"type":"Point","coordinates":[70.6,33.4]}} +,{"name":"Thika","id":"54493","nametype":"Valid","recclass":"L6","mass":"14200","fall":"Fell","year":"2011-01-01T00:00:00.000","reclat":"-1.002780","reclong":"37.150280","geolocation":{"type":"Point","coordinates":[37.15028,-1.00278]}} +,{"name":"Thuathe","id":"23976","nametype":"Valid","recclass":"H4/5","mass":"45300","fall":"Fell","year":"2002-01-01T00:00:00.000","reclat":"-29.333330","reclong":"27.583330","geolocation":{"type":"Point","coordinates":[27.58333,-29.33333]}} +,{"name":"Tianzhang","id":"23984","nametype":"Valid","recclass":"H5","mass":"2232","fall":"Fell","year":"1986-01-01T00:00:00.000","reclat":"32.946670","reclong":"118.990000","geolocation":{"type":"Point","coordinates":[118.99,32.94667]}} +,{"name":"Tieschitz","id":"23989","nametype":"Valid","recclass":"H/L3.6","mass":"28000","fall":"Fell","year":"1878-01-01T00:00:00.000","reclat":"49.600000","reclong":"17.116670","geolocation":{"type":"Point","coordinates":[17.11667,49.6]}} +,{"name":"Tilden","id":"23998","nametype":"Valid","recclass":"L6","mass":"74800","fall":"Fell","year":"1927-01-01T00:00:00.000","reclat":"38.200000","reclong":"-89.683330","geolocation":{"type":"Point","coordinates":[-89.68333,38.2]},":@computed_region_cbhk_fwbd":"34",":@computed_region_nnqa_25f4":"1762"} +,{"name":"Tillaberi","id":"23999","nametype":"Valid","recclass":"L6","mass":"3000","fall":"Fell","year":"1970-01-01T00:00:00.000","reclat":"14.250000","reclong":"1.533330","geolocation":{"type":"Point","coordinates":[1.53333,14.25]}} +,{"name":"Timochin","id":"24004","nametype":"Valid","recclass":"H5","mass":"65500","fall":"Fell","year":"1807-01-01T00:00:00.000","reclat":"54.500000","reclong":"35.200000","geolocation":{"type":"Point","coordinates":[35.2,54.5]}} +,{"name":"Tirupati","id":"24009","nametype":"Valid","recclass":"H6","mass":"230","fall":"Fell","year":"1934-01-01T00:00:00.000","reclat":"13.633330","reclong":"79.416670","geolocation":{"type":"Point","coordinates":[79.41667,13.63333]}} +,{"name":"Tissint","id":"54823","nametype":"Valid","recclass":"Martian (shergottite)","mass":"7000","fall":"Fell","year":"2011-01-01T00:00:00.000","reclat":"29.481950","reclong":"-7.611230","geolocation":{"type":"Point","coordinates":[-7.61123,29.48195]}} +,{"name":"Tjabe","id":"24011","nametype":"Valid","recclass":"H6","mass":"20000","fall":"Fell","year":"1869-01-01T00:00:00.000","reclat":"-7.083330","reclong":"111.533330","geolocation":{"type":"Point","coordinates":[111.53333,-7.08333]}} +,{"name":"Tjerebon","id":"24012","nametype":"Valid","recclass":"L5","mass":"16500","fall":"Fell","year":"1922-01-01T00:00:00.000","reclat":"-6.666670","reclong":"106.583330","geolocation":{"type":"Point","coordinates":[106.58333,-6.66667]}} +,{"name":"Tomakovka","id":"24019","nametype":"Valid","recclass":"LL6","mass":"600","fall":"Fell","year":"1905-01-01T00:00:00.000","reclat":"47.850000","reclong":"34.766670","geolocation":{"type":"Point","coordinates":[34.76667,47.85]}}] diff --git a/T-Datetime.ipynb b/T-Datetime.ipynb new file mode 100644 index 0000000..d9edcb7 --- /dev/null +++ b/T-Datetime.ipynb @@ -0,0 +1,115 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section T - Datetime Module\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "**Topics**:\n", + "* The Datetime Module\n", + "* Conversion To String\n", + "* Conversion From String\n", + "* Time Deltas\n", + "* Timezone Conversions\n", + "* Pandas Stuff\n", + "* Epoch Time\n", + "* Whate else?\n", + "\n", + "## The Datetime Module (Package?)\n", + "There are a few useful objects bundled within the datetime module:\n", + "\n", + " >>> import datetime as dtm\n", + " >>> dtm.\n", + " dtm.MAXYEAR dtm.date( dtm.time( dtm.tzinfo(\n", + " dtm.MINYEAR dtm.datetime( dtm.timedelta( \n", + " dtm.UTC dtm.datetime_CAPI dtm.timezone( \n", + "\n", + "**datetime.datetime** is used to create datetime objects. These objects encapsulate date and time to the microsecond?\n", + "**datetime.timedelta** is an object used ti describe an increment of time." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "UTC+08:00\n" + ] + } + ], + "source": [ + "from datetime import datetime, timedelta, timezone\n", + "\n", + "# Today's date:\n", + "now = datetime.now()\n", + "\n", + "# 24 hours from now:\n", + "print(now + timedelta(hours=24))\n", + "\n", + "# 1 month time delta:\n", + "\n", + "# Demo of timezone:\n", + "# Create a timezone for UTC+8:00\n", + "tz_utc8 = timezone(timedelta(hours=8))\n", + "print(tz_utc8)\n", + "#\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Time Deltas\n", + "A time delta is a difference in time by some intervale. We can create a timedelta object using datetime.timedelta, and add or subtract it from a datetime object. This is particularly useful for incrementing dates or timestamps.\n", + "\n", + " from datetime import timedelta\n", + " one_hour = timedelta(hours=1)\n", + "\n", + "These are the increments allowed for a time delta:\n", + "\n", + " timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "one_year = timedelta(days=365)\n", + "one_hour = timedelta(hours=1)\n", + "one_week = timedelta(weeks=1)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/V-Virtual_Environments.ipynb b/V-Virtual_Environments.ipynb new file mode 100644 index 0000000..a8bd1ff --- /dev/null +++ b/V-Virtual_Environments.ipynb @@ -0,0 +1,29 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section V - Virtual Environments\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "What, how,and why!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/W-Web_Scraping.ipynb b/W-Web_Scraping.ipynb new file mode 100644 index 0000000..aec77f2 --- /dev/null +++ b/W-Web_Scraping.ipynb @@ -0,0 +1,406 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Section G - Web Scraping\n", + "\n", + "Feedback: https://forms.gle/Le3RAsMEcYqEyswEA\n", + "\n", + "\n", + "Scraping modules\n", + "Javascript or no javascript\n", + "Navigating a page\n", + "Interaction - clicking elements or entering text data\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['ASCII_SPACES', 'DEFAULT_BUILDER_FEATURES', 'DEFAULT_INTERESTING_STRING_TYPES', 'EMPTY_ELEMENT_EVENT', 'END_ELEMENT_EVENT', 'NO_PARSER_SPECIFIED_WARNING', 'ROOT_TAG_NAME', 'START_ELEMENT_EVENT', 'STRING_ELEMENT_EVENT', '__bool__', '__call__', '__class__', '__contains__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', '_all_strings', '_clone', '_decode_markup', '_event_stream', '_feed', '_find_all', '_find_one', '_format_tag', '_indent_string', '_is_xml', '_lastRecursiveChild', '_last_descendant', '_linkage_fixer', '_markup_is_url', '_markup_resembles_filename', '_most_recent_element', '_namespaces', '_popToTag', '_should_pretty_print', 'append', 'attrs', 'builder', 'can_be_empty_element', 'cdata_list_attributes', 'childGenerator', 'children', 'clear', 'contains_replacement_characters', 'contents', 'css', 'currentTag', 'current_data', 'declared_html_encoding', 'decode', 'decode_contents', 'decompose', 'decomposed', 'default', 'descendants', 'element_classes', 'encode', 'encode_contents', 'endData', 'extend', 'extract', 'fetchNextSiblings', 'fetchParents', 'fetchPrevious', 'fetchPreviousSiblings', 'find', 'findAll', 'findAllNext', 'findAllPrevious', 'findChild', 'findChildren', 'findNext', 'findNextSibling', 'findNextSiblings', 'findParent', 'findParents', 'findPrevious', 'findPreviousSibling', 'findPreviousSiblings', 'find_all', 'find_all_next', 'find_all_previous', 'find_next', 'find_next_sibling', 'find_next_siblings', 'find_parent', 'find_parents', 'find_previous', 'find_previous_sibling', 'find_previous_siblings', 'format_string', 'formatter_for_name', 'get', 'getText', 'get_attribute_list', 'get_text', 'handle_data', 'handle_endtag', 'handle_starttag', 'has_attr', 'has_key', 'hidden', 'index', 'insert', 'insert_after', 'insert_before', 'interesting_string_types', 'isSelfClosing', 'is_empty_element', 'is_xml', 'known_xml', 'markup', 'name', 'namespace', 'new_string', 'new_tag', 'next', 'nextGenerator', 'nextSibling', 'nextSiblingGenerator', 'next_element', 'next_elements', 'next_sibling', 'next_siblings', 'object_was_parsed', 'open_tag_counter', 'original_encoding', 'parent', 'parentGenerator', 'parents', 'parse_only', 'parserClass', 'parser_class', 'popTag', 'prefix', 'preserve_whitespace_tag_stack', 'preserve_whitespace_tags', 'prettify', 'previous', 'previousGenerator', 'previousSibling', 'previousSiblingGenerator', 'previous_element', 'previous_elements', 'previous_sibling', 'previous_siblings', 'pushTag', 'recursiveChildGenerator', 'renderContents', 'replaceWith', 'replaceWithChildren', 'replace_with', 'replace_with_children', 'reset', 'select', 'select_one', 'self_and_descendants', 'setup', 'smooth', 'string', 'string_container', 'string_container_stack', 'strings', 'stripped_strings', 'tagStack', 'text', 'unwrap', 'wrap']\n", + "Python (programming language) - Wikipedia\n" + ] + } + ], + "source": [ + "from bs4 import BeautifulSoup\n", + "from urllib.request import urlopen\n", + "\n", + "# url = \"http://wikipedia.org\"\n", + "url = \"https://en.wikipedia.org/wiki/Python_(programming_language)\"\n", + "page = urlopen(url)\n", + "html = page.read().decode('utf-8')\n", + "soup = BeautifulSoup(html, 'html.parser')\n", + "# print(soup.get_text())\n", + "print(dir(soup))\n", + "print(soup.title)\n", + "# print(soup.body.get_text())\n", + "# xpath = '//*[@id=\"mw-content-text\"]/div[1]/p[2]'\n", + "# xpath = '/html/body/div[2]/div/div[3]/main/div[3]/div[3]/div[1]/p[2]'\n", + "# print(soup.select_one(xpath).get_text())" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install lxml\n", + "\n", + "try:\n", + " # Python 2\n", + " from urllib2 import urlopen\n", + "except ImportError:\n", + " from urllib.request import urlopen\n", + "from lxml import etree\n", + "\n", + "response = urlopen(url)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "htmlparser = etree.HTMLParser()\n", + "tree = etree.parse(response, htmlparser)\n", + "section = tree.xpath(xpath)\n", + "for item in section:\n", + " print(item.text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "Following along with:\n", + "https://zperzan.github.io/projects/scrape-weather-underground/\n", + "Requires chromedriver from https://googlechromelabs.github.io/chrome-for-testing/\n", + "* set it in the chromedriver_path variable once installed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\"\"\"Module to scrape 5-min personal weather station data from Weather Underground.\n", + "\n", + "Usage is:\n", + ">>> python scrape_wunderground.py STATION DATE\n", + "\n", + "where station is a personal weather station (e.g., KCAJAMES3) and date is in the \n", + "format YYYY-MM-DD. \n", + "\n", + "Alternatively, each function below can be imported and used in a separate python\n", + "script. Note that a working version of chromedriver must be installed and the absolute \n", + "path to executable has to be updated below (\"chromedriver_path\").\n", + "\n", + "Zach Perzan, 2021-07-28\"\"\"\n", + "\n", + "import time\n", + "import sys\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "from bs4 import BeautifulSoup as BS\n", + "from selenium import webdriver\n", + "\n", + "\n", + "# Set the absolute path to chromedriver\n", + "# chromedriver_path = '/home/_snap/bin/chromium.chromedriver'\n", + "# chromedriver_path = '/home/dan/opt/chrome-linux64'\n", + "chromedriver_path = '/home/dan/opt/geckodriver-v0.36.0-linux64/geckodriver'\n", + "\n", + "\n", + "def render_page(url):\n", + " \n", + " # driver = webdriver.Chrome(chromedriver_path)\n", + " driver = webdriver.Firefox(chromedriver_path)\n", + " driver.get(url)\n", + " time.sleep(3) # Could potentially decrease the sleep time\n", + " r = driver.page_source\n", + " driver.quit()\n", + "\n", + " return r\n", + "\n", + "\n", + "def scrape_wunderground(station, date):\n", + " \n", + " # Render the url and open the page source as BS object\n", + " # url = 'https://www.wunderground.com/dashboard/pws/%s/table/%s/%s/daily' % (station, date, date)\n", + " url = f'https://www.wunderground.com/history/weekly/us/ca/sacramento/KSMF/date/2025-3-1'\n", + " \n", + " print(\"Working on url:\", url)\n", + " r = render_page(url)\n", + " soup = BS(r, \"html.parser\",)\n", + "\n", + " # container = soup.find('lib-history-table')\n", + " container = soup.find('lib-city-history-observation')\n", + " \n", + " # Check that lib-history-table is found\n", + " if container is None:\n", + " print('error finding the container...')\n", + " raise ValueError(\"could not find lib-history-table in html source for %s\" % url)\n", + " \n", + " print(container.contents)\n", + " # Get the timestamps and data from two separate 'tbody' tags\n", + " all_checks = container.find_all('tbody')\n", + " time_check = all_checks[0]\n", + " data_check = all_checks[1]\n", + " print(time_check)\n", + " print(data_check)\n", + "\n", + " # Iterate through 'tr' tags and get the timestamps\n", + " hours = []\n", + " for i in time_check.find_all('tr'):\n", + " trial = i.get_text()\n", + " hours.append(trial)\n", + "\n", + " # For data, locate both value and no-value (\"--\") classes\n", + " # classes = ['wu-value wu-value-to', 'wu-unit-no-value ng-star-inserted']\n", + " classes = ['observation-table', 'ng-star-inserted']\n", + "\n", + " # Iterate through span tags and get data\n", + " data = []\n", + " for i in data_check.find_all('span', class_=classes):\n", + " trial = i.get_text()\n", + " data.append(trial)\n", + "\n", + " columns = ['Time', 'Temperature', 'Dew Point', 'Humidity', 'Wind Speed', \n", + " 'Wind Gust', 'Pressure', 'Precip.', 'Condition']\n", + "\n", + " # Convert NaN values (stings of '--') to np.nan\n", + " data_nan = [np.nan if x == '--' else x for x in data]\n", + "\n", + " # Convert list of data to an array\n", + " data_array = np.array(data_nan, dtype=float)\n", + " data_array = data_array.reshape(-1, len(columns))\n", + "\n", + " # Prepend date to HH:MM strings\n", + " timestamps = ['%s %s' % (date, t) for t in hours]\n", + "\n", + " # Convert to dataframe\n", + " df = pd.DataFrame(index=timestamps, data=data_array, columns=columns)\n", + " df.index = pd.to_datetime(df.index)\n", + " \n", + " return df\n", + "\n", + "\n", + "def scrape_multiattempt(station, date, attempts=4, wait_time=5.0):\n", + " \"\"\"Try to scrape data from Weather Underground. If there is an error on the \n", + " first attempt, try again.\n", + " \n", + " Parameters\n", + " ----------\n", + " station : str\n", + " The personal weather station ID\n", + " date : str\n", + " The date for which to acquire data, formatted as 'YYYY-MM-DD'\n", + " attempts : int, default 4\n", + " Maximum number of times to try accessing before failuer\n", + " wait_time : float, default 5.0\n", + " Amount of time to wait in between attempts\n", + " \n", + " Returns\n", + " -------\n", + " df : dataframe or None\n", + " A dataframe of weather observations, with index as pd.DateTimeIndex \n", + " and columns as the observed data\n", + " \"\"\"\n", + " \n", + " # Try to download data limited number of attempts\n", + " for n in range(attempts):\n", + " try:\n", + " df = scrape_wunderground(station, date)\n", + " print('success')\n", + " except:\n", + " print('exception')\n", + " # if unsuccessful, pause and retry\n", + " if attempts > 1:\n", + " time.sleep(wait_time)\n", + " else: \n", + " # if successful, then break\n", + " break\n", + " # If all attempts failed, return empty df\n", + " else:\n", + " df = pd.DataFrame()\n", + " \n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Working on url: https://www.wunderground.com/history/weekly/us/ca/sacramento/KSMF/date/2025-3-1\n" + ] + }, + { + "ename": "AttributeError", + "evalue": "'str' object has no attribute 'capabilities'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[59], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# data = scrape_multiattempt('KSMF', '2025-03-01', 1)\u001b[39;00m\n\u001b[1;32m 2\u001b[0m \u001b[38;5;66;03m# data = scrape_multiattempt('KCAJAMES3', '2025-03-01')\u001b[39;00m\n\u001b[0;32m----> 3\u001b[0m data \u001b[38;5;241m=\u001b[39m \u001b[43mscrape_wunderground\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mKSMF\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m2025-03-01\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[58], line 77\u001b[0m, in \u001b[0;36mscrape_wunderground\u001b[0;34m(station, date)\u001b[0m\n\u001b[1;32m 74\u001b[0m url \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mhttps://www.wunderground.com/history/weekly/us/ca/sacramento/KSMF/date/2025-3-1\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m 76\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mWorking on url:\u001b[39m\u001b[38;5;124m\"\u001b[39m, url)\n\u001b[0;32m---> 77\u001b[0m r \u001b[38;5;241m=\u001b[39m \u001b[43mrender_page\u001b[49m\u001b[43m(\u001b[49m\u001b[43murl\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 78\u001b[0m soup \u001b[38;5;241m=\u001b[39m BS(r, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhtml.parser\u001b[39m\u001b[38;5;124m\"\u001b[39m,)\n\u001b[1;32m 80\u001b[0m \u001b[38;5;66;03m# container = soup.find('lib-history-table')\u001b[39;00m\n", + "Cell \u001b[0;32mIn[58], line 45\u001b[0m, in \u001b[0;36mrender_page\u001b[0;34m(url)\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Given a url, render it with chromedriver and return the html source\u001b[39;00m\n\u001b[1;32m 32\u001b[0m \u001b[38;5;124;03m\u001b[39;00m\n\u001b[1;32m 33\u001b[0m \u001b[38;5;124;03mParameters\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;124;03m rendered page source\u001b[39;00m\n\u001b[1;32m 42\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 44\u001b[0m \u001b[38;5;66;03m# driver = webdriver.Chrome(chromedriver_path)\u001b[39;00m\n\u001b[0;32m---> 45\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[43mwebdriver\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mFirefox\u001b[49m\u001b[43m(\u001b[49m\u001b[43mchromedriver_path\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 46\u001b[0m driver\u001b[38;5;241m.\u001b[39mget(url)\n\u001b[1;32m 47\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(\u001b[38;5;241m3\u001b[39m) \u001b[38;5;66;03m# Could potentially decrease the sleep time\u001b[39;00m\n", + "File \u001b[0;32m~/venv/lib/python3.12/site-packages/selenium/webdriver/firefox/webdriver.py:57\u001b[0m, in \u001b[0;36mWebDriver.__init__\u001b[0;34m(self, options, service, keep_alive)\u001b[0m\n\u001b[1;32m 54\u001b[0m options \u001b[38;5;241m=\u001b[39m options \u001b[38;5;28;01mif\u001b[39;00m options \u001b[38;5;28;01melse\u001b[39;00m Options()\n\u001b[1;32m 56\u001b[0m finder \u001b[38;5;241m=\u001b[39m DriverFinder(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mservice, options)\n\u001b[0;32m---> 57\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[43mfinder\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_browser_path\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m:\n\u001b[1;32m 58\u001b[0m options\u001b[38;5;241m.\u001b[39mbinary_location \u001b[38;5;241m=\u001b[39m finder\u001b[38;5;241m.\u001b[39mget_browser_path()\n\u001b[1;32m 59\u001b[0m options\u001b[38;5;241m.\u001b[39mbrowser_version \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "File \u001b[0;32m~/venv/lib/python3.12/site-packages/selenium/webdriver/common/driver_finder.py:47\u001b[0m, in \u001b[0;36mDriverFinder.get_browser_path\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mget_browser_path\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mstr\u001b[39m:\n\u001b[0;32m---> 47\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_binary_paths\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbrowser_path\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "File \u001b[0;32m~/venv/lib/python3.12/site-packages/selenium/webdriver/common/driver_finder.py:56\u001b[0m, in \u001b[0;36mDriverFinder._binary_paths\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 53\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_paths[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdriver_path\u001b[39m\u001b[38;5;124m\"\u001b[39m]:\n\u001b[1;32m 54\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_paths\n\u001b[0;32m---> 56\u001b[0m browser \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_options\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcapabilities\u001b[49m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbrowserName\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m 57\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 58\u001b[0m path \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_service\u001b[38;5;241m.\u001b[39mpath\n", + "\u001b[0;31mAttributeError\u001b[0m: 'str' object has no attribute 'capabilities'" + ] + } + ], + "source": [ + "# data = scrape_multiattempt('KSMF', '2025-03-01', 1)\n", + "# data = scrape_multiattempt('KCAJAMES3', '2025-03-01')\n", + "data = scrape_wunderground('KSMF', '2025-03-01')" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Empty DataFrame\n", + "Columns: []\n", + "Index: []\n" + ] + } + ], + "source": [ + "print(data)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import sys\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "from bs4 import BeautifulSoup as BS\n", + "from selenium import webdriver\n", + "from selenium.webdriver.chrome.service import Service\n", + "\n", + "\n", + "# Set the absolute path to chromedriver\n", + "chromedriver_path = '/home/dan/opt/chromedriver-linux64/chromedriver'\n", + "\n", + "url = f'https://www.wunderground.com/history/weekly/us/ca/sacramento/KSMF/date/2025-3-1'\n", + "\n", + "service = Service(chromedriver_path)\n", + "driver = webdriver.Chrome(service=service)\n", + "\n", + "driver.get(url)\n", + "time.sleep(3) # Could potentially decrease the sleep time\n", + "r = driver.page_source\n", + "driver.quit()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[
Daily Observations
TimeTemperature (°F)Dew Point (°F)Humidity (%)Wind Speed (mph)Pressure (in)Precipitation (in)
Feb
23
24
25
26
27
28
1
Max Avg Min
68 59.9 54
67 56.2 49
67 52.9 41
71 54.2 40
73 57.5 44
71 58.5 46
71 56.0 43
Max Avg Min
52 47.5 43
54 50.7 46
51 43.8 38
46 41.5 36
53 46.5 41
49 45.7 41
52 46.8 40
Max Avg Min
81 64.6 47
93 83.2 59
100 74.4 37
86 65.3 32
89 69.5 35
83 64.6 41
89 72.0 49
Max Avg Min
14 7.6 3
14 8.0 0
15 7.1 0
8 2.8 0
9 4.8 0
8 4.0 0
20 9.4 0
Max Avg Min
30.3 30.2 30.1
30.2 30.1 30.1
30.2 30.1 30.0
30.1 30.0 30.0
30.1 30.0 29.9
29.9 29.9 29.8
29.9 29.9 29.8
Total
0.00
0.00
0.00
0.00
0.00
0.00
0.00
]\n", + " Feb 23 24 25 26 27 28 1 Max Avg Min 68 59.9 54 67 56.2 49 67 52.9 41 71 54.2 40 73 57.5 44 71 58.5 46 71 56.0 43 Max Avg Min 52 47.5 43 54 50.7 46 51 43.8 38 46 41.5 36 53 46.5 41 49 45.7 41 52 46.8 40 Max Avg Min 81 64.6 47 93 83.2 59 100 74.4 37 86 65.3 32 89 69.5 35 83 64.6 41 89 72.0 49 Max Avg Min 14 7.6 3 14 8.0 0 15 7.1 0 8 2.8 0 9 4.8 0 8 4.0 0 20 9.4 0 Max Avg Min 30.3 30.2 30.1 30.2 30.1 30.1 30.2 30.1 30.0 30.1 30.0 30.0 30.1 30.0 29.9 29.9 29.9 29.8 29.9 29.9 29.8 Total 0.00 0.00 0.00 0.00 0.00 0.00 0.00 \n" + ] + } + ], + "source": [ + "soup = BS(r, \"html.parser\",)\n", + "\n", + "# container = soup.find('lib-history-table')\n", + "container = soup.find('lib-city-history-observation')\n", + "print(container.contents)\n", + "\n", + "# column names are in thead\n", + "columns = ['Time', 'Temperature', 'Dew Point', 'Humidity', 'Wind Speed', \n", + " 'Wind Gust', 'Pressure', 'Precip.', 'Condition']\n", + "# confirm that our columns are correct:\n", + "tbody = container.find_all('tbody')\n", + "# break it up by column:\n", + "for foo in tbody:\n", + " print(foo.get_text())\n", + "\n", + "# data rows are in tbody\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/check_progress.py b/check_progress.py deleted file mode 100644 index f8436ed..0000000 --- a/check_progress.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python - -import unittest -import boot_config as bc - -def writeFile(content, path, perms=None): - with open(path, 'w') as f: - f.write(content) - if perms != None: - # TODO: add permissions setting code here. - pass - -class CheckProgress(unittest.TestCase): - def setUp(self): - pass - - def test_platformInfo_readWrite(self): - content = ('VMX_LOADED=1.2.345\n' - + 'FOO=bar\n') - writeFile(content, '/.platform_info') - self.assertEqual(bc.platformInfo('FOO'), 'bar') - self.assertEqual(bc.platformInfo('VMX_LOADED'), '1.2.345') - bc.platformInfo('ANOTHER', 'new_content') - self.assertEqual(bc.platformInfo('FOO'), 'bar') - self.assertEqual(bc.platformInfo('VMX_LOADED'), '1.2.345') - self.assertEqual(bc.platformInfo('ANOTHER'), 'new_content') - - def testgetPoolOverrides(self): - pass - -if __name__ == '__main__': - unittest.main() - diff --git a/circuitpy/font5x8.bin b/circuitpy/font5x8.bin new file mode 100644 index 0000000..9a0563b Binary files /dev/null and b/circuitpy/font5x8.bin differ diff --git a/cobra/.gitignore b/cobra/.gitignore deleted file mode 100644 index 2c2218b..0000000 --- a/cobra/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -__pycache__ -*.pyc -*yml_* -users -session.yml -clientdata -*.bak -OLD diff --git a/cobra/README.md b/cobra/README.md deleted file mode 100644 index 4f3e076..0000000 --- a/cobra/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# to run the server -``` -pip install gunicorn -gunicorn instructor_server:app -``` -or -``` -pip install waitress -waitress-serve --port=8000 instructor_server:app -``` - -# required modules: -``` -conda install prompt_toolkit -pip install ptpython -conda install flake8 -``` - diff --git a/cobra/archive/format_example.yml b/cobra/archive/format_example.yml deleted file mode 100644 index 226ffb2..0000000 --- a/cobra/archive/format_example.yml +++ /dev/null @@ -1,60 +0,0 @@ -# A label identifies the question unique to the .yml lesson -addition_example: - # This is an example question - # It shows off the format used - text: | - Write a function that takes 2 integers as parameter - It should return the sum of the 2 ints - signature: "add(number1: int, number2: int ) -> int" - # I'm putting this in base64, I think it might help readability. This codes to: - # def add(num_1, num_2): - # return num_1 + num_2 - solution: !!binary "ZGVmIGFkZChudW1fMSwgbnVtXzIpOgogICAgcmV0dXJuIG51bV8xICsgbnVtXzI=" - # order to serve questions. Same tier served randomly - tier: 1 - unittests: - test1: - - "int(3)" - - "int(5)" - test2: - - "int(-3)" - - "int(0)" - test3: - - "randint(-100,100)" - - "randint(-100,100)" - # The x4 will mean repeat this test 4 times - test4_x4: - - "randint(-1000,1000)" - - "randint(-1,1)" - - # Used for any outside module dependancies - imports: "from random import randint, seed" - # Setup scripts to prep an environment. Run before unittests - setup: "seed({seed})" - # Teardown scripts to clean up the environment. Run after unittests - teardown: "" - # Scripts to be run before individual tests take place - pretest: "" - # Scripts to be run after infividual tests take place - posttest: "" - # Tags can be used to sort and filter questions - tags: - - sample - - arithmatic - # This is how many times the challenge has been solved - successes: 1 - # These are derived from user ratings, the data can be used as question feedback - # think of them like upvotes/downvotes, but more category specific - ratings: - challenging: 0 - useful: 0 - interesting: 0 - # The solution history, every success can be stored here. - history: - ab7511ee456ce56e64d69141b7e2241b: - code: !!binary "ZGVmIGFkZChhYWEsYmJiKToKICAgIHg9IGFhYStiYmIKICAgIHJldHVybiB4" - pep8: 0 - size: 0 - line: 0 - characters: 0 - likes: 0 \ No newline at end of file diff --git a/cobra/archive/python_basics.yml b/cobra/archive/python_basics.yml deleted file mode 100644 index ba70853..0000000 --- a/cobra/archive/python_basics.yml +++ /dev/null @@ -1,678 +0,0 @@ -basic_math_1: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: addThem(int, int) -> int - solution: "def addThem(num_a, num_b):\n return num_a + num_b\n" - tags: '' - teardown: '' - text: "Write a function that takes 2 integers as parameter\nIt should return the\ - \ sum of the 2 integers.\n\nE.g. \ndef addThem(num_a, num_b):\n #your code\ - \ here\n return the_sum\n" - unittests: - test1: - - int(3) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -basic_math_2: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: remainder(int, int) -> int - solution: "def remainder(a, b):\n the_remainder = a%b\n return the_remainder\n" - tags: '' - teardown: '' - text: "Write a function that takes 2 integers as parameters and returns the remainder\n\ - from dividing the first number, \"a\", into the second number, \"b\". \n\nE.g:\n\ - def remainder(a, b):\n #your code here\n return the_remainder\n" - unittests: - test1: - - int(3) - - int(5) - test2: - - int(10) - - int(1) - test3: - - randint(100,500) - - randint(100,200) - test4_x4: - - randint(1000,2000) - - randint(1,10) -basic_math_3: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: toInt(float) -> int - solution: "def toInt(a_float):\n an_int = int(a_float)\n return an_int\n" - tags: '' - teardown: '' - text: "Write a function that takes a floating point number and returns it\nas an\ - \ integer.\n\nE.g:\ndef toInt(a_float):\n #your code here\n return an_int\n" - unittests: - test1: - - int(7) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -basic_math_4: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: divideThemInt(int, int) -> (int, int) - solution: "def divideThemInt(num_a, num_b):\n return (num_a / num_b, num_a %\ - \ num_b)\n" - tags: '' - teardown: '' - text: "Write a function that divides two integers and returns a tuple with the first\ - \ value equal to the integer diviion result, and teh second value equal to the\ - \ remainder. \n\nE.g:\ndef divideThemInt(num_a, num_b):\n #your code here\n\ - \ return (sum_of_them, remainder)\n" - unittests: - test1: - - int(7) - - int(5) - test2: - - int(-3) - - int(1) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -basic_math_5: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: divideThem(int, int) -> float - solution: "def divideThem(num_a, num_b):\n return float(num_a) / float(num_b)\n" - tags: '' - teardown: '' - text: "Write a function that divides two integers and returns a floating point result.\n\ - Note: the result should be a float even if the division has no remainder...\n\n\ - E.g:\ndef divideThem(num_a, num_b):\n #your code here\n return the_result\n" - unittests: - test1: - - int(7) - - int(5) - test2: - - int(-3) - - int(0) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -basic_math_6: - imports: from random import randint, seed - posttest: '' - pretest: '' - setup: seed({seed}) - signature: convertCToF(int) -> float - solution: "def convertCToF(temp_in_c):\n return temp_in_c/5.0 + 32.0/9.0\n" - tags: '' - teardown: '' - text: "Write a function that accepts a temperature in Centigrade and returns an\n\ - equivelant temperature in Farenheight. \n\nThe equation for this is (f = c/5 +\ - \ 32/9)\n\nE.g:\ndef convertCToF(temp_in_c):\n #your code here\n return\ - \ temp_in_f\n" - unittests: - test1: - - int(7) - - int(5) - test2: - - int(-3) - - int(5) - test3: - - randint(-100,100) - - randint(-100,100) - test4_x4: - - randint(-1000,1000) - - randint(-1,1) -branching_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: getTruthiness(obj) -> string - solution: "def getTruthiness(obj):\n if obj:\n resulting_word = \"tequilla\"\ - \n else:\n resulting_word = \"margarita\"\n return resulting_word\n" - tags: '' - teardown: '' - text: "Create a function called getTruthiness that is given an objct and, if\nthat\ - \ object evaluates True, returns \"tequilla\", otherwise it returns,\n\"margarita\"\ - . \n\nE.g:\ndef getTruthiness(obj):\n #your code here\n return resulting_word\n" - unittests: - test1: - - true - test2: - - '""' - test3: - - '"a"' - test4: - - '"()"' -branching_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: twosTruthiness(bool, bool, bool, bool) -> string - solution: "def twosTruthiness(obj0, obj1, obj2, obj3):\n items = (obj0, obj1,\ - \ obj2, obj3)\n count = len([o for o in items if o == True])\n if count\ - \ == 2:\n resulting_word = \"twos\"\n elif count == 3:\n resulting_word\ - \ = \"threes\"\n else:\n resulting_word = \"foobar\"\n return resulting_word\n" - tags: '' - teardown: '' - text: "Create a function called twosTruthiness that is given four boolean values.\n\ - if any two of the four are True, then return \"twos\". If any three of them are\n\ - True, then return \"threes\", if less than two or four of them are True, then\n\ - return \"foobar\"\n\nE.g:\ndef twosTruthiness(obj, obj, obj, obj):\n #your\ - \ code here\n return resulting_word\n" - unittests: - test1: - - (True, True, False, False) - test2: - - (False, True, False, True) - test3: - - (True, True, False, True) - test4: - - (True, True, True, True) -branching_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: carmenFound(dict) -> string - solution: "def carmenFound(cities):\n for city in cities:\n if cities[city]\ - \ == True:\n return city\n" - tags: '' - teardown: '' - text: "Create a function called carmenFound that is given a dictionary with a list\ - \ of\ncity names as keys, each associated with a boolean value indicating whether\n\ - or not Carmen is in the city. Return the name of the city Carmen is found in!\n\ - \nE.g:\ndef carmenFound(cities):\n #your code here\n return city_name\n" - unittests: - test1: - - atlanta: true - menphis: false - redding: false - test2: - - atlanta: false - menphis: true - redding: false -dictionaries_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: pocketContents() -> dict - solution: "def pocketContents():\n inventory = {\n 'gold' : 500,\n \ - \ 'pouch' : ['flint', 'twine', 'gemstone'],\n 'backpack' : ['xylophone','dagger',\ - \ 'bedroll','bread loaf']\n }\n inventory['pocket'] = ['seashell']\n \ - \ return inventory\n" - tags: '' - teardown: '' - text: "Given the following dictionary called \"inventory\", modify the pocketContents\n\ - function to add a 'pocket' into the dictionary with contents 'seashell'\n(a single\ - \ string in a list).\n\nE.g:\ndef pocketContents():\n inventory = {\n \ - \ 'gold' : 500,\n 'pouch' : ['flint', 'twine', 'gemstone'],\n \ - \ 'backpack' : ['xylophone','dagger', 'bedroll','bread loaf']\n }\n\n return\ - \ inventory\n" - unittests: - test1: - - '" rofl this is cool "' - test2: - - '" ABCDS"' - test3: - - '"zABCDS "' -dictionaries_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: myPricesDict() -> dict - solution: "def myPricesDict():\n my_prices = {\"bananna\": 4, \"apple\": 2, \"\ - orange\": 1.5, \"pear\": 3}\n return my_prices\n" - tags: '' - teardown: '' - text: "Put the following items into a prices dictionary and return it:\n \"bananna\"\ - : 4,\n \"apple\": 2,\n \"orange\": 1.5,\n \"pear\": 3\n\nE.g:\ndef myPricesDict():\n\ - \ #your code here\n return my_prices\n" - unittests: - test1: null -dictionaries_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: mergeToDict(list, list) -> dict - solution: "def mergeToDict(keys, values):\n resulting_dict = dict(zip(keys, values))\n\ - \ return resulting_dict\n" - tags: '' - teardown: '' - text: "Given a list of keys and a list of corresponding values, create a dictionary\n\ - containing them and return it as output. You may assume that both lists will\n\ - always be the same length.\n\nFor example, if the keys were ('color', 'flavor',\ - \ 'texture') and the values\nwere ('red', 'sour', and 'rough'), the dictionary\ - \ would look like:\n{'color': 'red', 'flavor': 'sour', 'texture': 'rough'}\n\n\ - E.g:\ndef mergeToDict(keys, values):\n #your code here\n return resulting_dict\n" - unittests: - test1: - - (1, 2, 3, 4) - - (5, 6, 7, 8) - test2: - - ('1', '2', '3', '4') - - ('a', 'b', 'c', 'd') - test3: - - ('1', '2', '3', '4') - - ([1,], [2,], [3,], [4,]) -dictionaries_4: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: getDictKeys(dict) -> list - solution: "def getDictKeys(a_dictionary):\n return a_dictionary.keys()\n" - tags: '' - teardown: '' - text: "Write a function called getDictKeys that is given a dictionary and returns\ - \ a \nlist of keys in the given dictionary. \n\nE.g:\ndef getDictKeys(a_dictionary):\n\ - \ # do stuff here\n return all_the_keys\n" - unittests: - test1: - - a: 1 - b: 2 - c: 3 - test2: - - 1: 1 - c: None - ('a': null - ): 2 - b: {} - a: [] -dictionaries_5: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: checkKeyExists(dict, key) -> bool - solution: "def getDictKeys(a_dictionary):\n return a_dictionary.keys()\n" - tags: '' - teardown: '' - text: "Write a function called checkKeyExists that is given a dictionary and a key\ - \ and\nreturns True if the key exists in the dictionary or False if it does not.\ - \ \n\nE.g:\ndef checkKeyExists(a_dictionary, the_key):\n # do stuff here\n\ - \ return exists_bool\n" - unittests: - test1: - - a: 1 - b: 2 - - a - test2: - - a: 1 - b: 2 - - 1 - test3: - - a: 1 - b: 2 - - b - test4: - - a: 1 - b: 2 - - c - test5: - - a: 1 - b: 2 - - '2' -dictionaries_6: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: checkKeysExist(dict, keys) -> dict - solution: "def checkKeysExists(the_dict, keys):\n out = {}\n for key in keys:\n\ - \ out[key] = key in the_dict\n return out\n" - tags: '' - teardown: '' - text: "Write a function called checkKeysExists that is given a dictionary and a\ - \ list\nof keys to look for in teh dictionary. The function returns a new dictionary\n\ - containing each key in the provided list with an associated boolean value\nindicating\ - \ whether or not the key from the list was found in the given\ndictionary.\n\n\ - As an example, if given {'a': 0, 'b': 1} and ['a', 'c'] for keys, the output\n\ - would be {'a': True, 'c': False}. \n\nE.g:\ndef checkKeysExists(a_dictionary,\ - \ some_keys):\n # do stuff here\n return exists_dict\n" - unittests: - test1: - - a: 12 - b: 2 - - - a - - c - - d - test2: - - a: 1 - b: 2 - - () -dictionaries_7: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: printGivenKeys(dict, list) - solution: "def checkKeysExists(the_dict, keys):\n out = {}\n for key in keys:\n\ - \ out[key] = key in the_dict\n return out\n" - tags: '' - teardown: '' - text: "Write a function called printGivenKeys that is given a dictionary and a list\n\ - of keys to look for in teh dictionary. For each item in the list, the function\n\ - prints the item and the value associated with it in the provided dictionary.\n\ - If the item is not in the dictionary, None is used for the value. \n\nAs an example,\ - \ if given {'a': 0, 'b': 1} and ['a', 'c'] for keys, it would \nprint:\na, 0\n\ - c, None\n\nE.g:\ndef printGivenKeys(a_dictionary, some_keys):\n # do stuff\ - \ here\n # return nothing\n" - unittests: - test1: - - a: 12 - b: 2 - - - a - - c - - d - test2: - - a: 1 - b: 2 - - () -lists_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: sumAllItems(list of num) -> number - solution: "def sumAllItmes(some_nums):\n the_sum = 0.\n for num in some_nums:\n\ - \ the_sum += num\n return the_sum\n" - tags: '' - teardown: '' - text: "write a function called sumAllItems that accepts a list or tuple of numbers,\ - \ \nsumms them, and returns the sum. \n\nE.g:\ndef sumAllItmes(some_nums):\n \ - \ # do stuff here\n return the_sum\n" - unittests: - test1: [1, 2, 3, 4, 5] - test2: [-5, 2.2, 999, -1000.0] - test3: [1, -2, 4, -6, 123.1] -lists_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: smallestOfList(list of numbers) -> number - solution: "def smallestOfList(some_nums):\n smallest = some_nums[0]\n for\ - \ num in some_nums:\n if num tuple - solution: "def convTupleUnique(some_items):\n return tuple(set(some_items))\n" - tags: '' - teardown: '' - text: "Write a function called convTupleUnique(list) that accepts a list of objects\n\ - and returns a tuple (not a list) with only the unique items from the list. \n\ - Order of the returned list is not important.\n\nE.g:\ndef convTupleUnique(some_items):\n\ - \ # do stuff here\n return unique_items\n" - unittests: - test1: ['asfd', 'b', 'b', 'c', 'b', '1', '2', 'b', 'a'] -sets_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: convTupleUniqueOrder(list) -> tuple - solution: "def convTupleUniqueOrder(some_items):\n out = []\n for item in\ - \ some_items:\n if item in out:\n continue\n out.append(item)\n\ - \ return tuple(out)\n" - tags: '' - teardown: '' - text: "Write a function called convTupleUniqueOrder(list) that accepts a list of\n\ - objects and returns a tuple (not a list) with only the unique items from the\n\ - list. Order of the returned tuple IS important. Order from the original list\n\ - should be preserved; the first time an object is observed in the given list, \n\ - it is in the returned tuple, and subsequent occurences are ignored. \n\nE.g:\n\ - def convTupleUniqueOrder(some_items):\n # do stuff here\n return unique_items\n" - unittests: - test1: ['asfd', 'b', 'b', 'c', 'b', '1', '2', 'b', 'a'] -sets_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: createSet(obj, obj, obj, obj, obj) -> set - solution: "def createSet(obj1=None, obj2=None, obj3=None, obj4=None, obj5=None):\n\ - \ new_set = set()\n for obj in (obj1, obj2, obj3, obj4, obj5):\n \ - \ if obj != None:\n new_set.add(obj)\n return new_set\n" - tags: '' - teardown: '' - text: "Write a function called createSet that accepts up to five objects, adds them\n\ - into a set, and returns a set of those objects. Hint: \"set\" is a data type.\ - \ \nDo not add any of the objects fo the set if the object is equal to the None\n\ - object.\n\nE.g:\ndef createSet(obj1=None, obj2=None, obj3=None, obj4=None, obj5=None):\n\ - \ # do stuff here\n return new_set\n" - unittests: - test1: ['asfd', 'b', 'b', 'c', 'b', '1', '2', 'b', 'a'] -sets_4: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: removeFromSet(set, obj) -> tuple - solution: "def removeFromSet(a_set, an_obj):\n if an_obj in a_set:\n a_set.remove(an_obj)\n\ - \ return tuple(a_set)\n" - tags: '' - teardown: '' - text: "Write a function called removeFromSet that accepts a set and an object. \ - \ If\nthe object exists in the set, then it is removed. The resulting set is\n\ - converted to a tuple and returned. \n\nE.g:\ndef removeFromSet(a_set, an_obj):\n\ - \ # do stuff here\n return new_tuple\n" - unittests: - test1: ['asfd', 'b', 'b', 'c', 'b', '1', '2', 'b', 'a'] -strings_1: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: returnWithQuotes() -> string - solution: "def returnWithQuotes():\n my_string = \"\"\"'It's modulus, \"%\",\ - \ not division, \"/\", or escaping \"\\\"!'\"\"\"\n return my_string\n \n" - tags: '' - teardown: '' - text: "Write a function called returnWithQuotes that takes no arguments and, when\n\ - called, returns the following text (no whitespace on the ends), but with all quotes\ - \ shown included in the string:\n\n 'It's modulus, \"%\", not division, \"\ - /\", or escaping \"\\\"!'\n\nE.g:\ndef returnWithQuotes():\n # do stuff here\n\ - \ return my_silly_string\n" - unittests: -strings_2: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: strUpper(string) -> string - solution: "def strUpper(foo):\n return foo.strip().upper()\n" - tags: '' - teardown: '' - text: "Write a function called \"strUpper\" that takes a string as an argument and\n\ - returns the string without any whitespace on the ends and all upper case.\n\n\ - E.g:\ndef strUpper(foo):\n # do stuff here\n return foo\n" - unittests: - test1: - - str(' rofl this is cool ') - test2: - - str' ABCDS') - test3: - - str('zABCDS ') -strings_3: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: firstHalfLower(string) -> string - solution: "def firstHalfLower(foo):\n length = int(len(foo) / 2)\n result\ - \ = foo[:length].lower()\n assert(len(result) * 2 <= len(foo))\n return\ - \ result\n" - tags: '' - teardown: '' - text: "Write a function called \"firstHalfLower\" that takes a string as an argument\ - \ and\nreturns the first half of the string, all lower case. When calculating\ - \ how many\ncharacters of the string to return, round down - an 11 character string\ - \ would\nresult in 5 characters being returned.\n\nE.g:\ndef firstHalfLower(foo):\n\ - \ # do stuff here\n return foo\n" - unittests: - test1: - - str(' ro3! T2is is cool ') - test2: - - str(' ABCDS') - test3: - - str('zABCDS ') - test4: - - str('123456789') -strings_4: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: justEvenChars(string) -> (string) - solution: "def justEvenChars(foo):\n return foo[::2]\n" - tags: '' - teardown: '' - text: "Write a function called \"justEvenChars\" that takes a string as an argument\ - \ and\nreturns only even numbered characters from the string. If the string is\ - \ \"coolio\", the result would be \"coi\", treating the zeroth characte as even\ - \ (0%2==0). \n\nE.g:\ndef justEvenChars(foo):\n # do stuff here\n return\ - \ foo\n" - unittests: - test1: - - str(' ro3! T2is is cool ') - test2: - - str(' ABCDS') - test3: - - str('zABCDS ') - test4: - - str('123456789') -strings_5: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: reverseOrder(string) -> string - solution: "def reverseOrder(foo):\n foo = foo.strip()\n foo.split()\n foo\ - \ = foo[::-1]\n foo = \" \".join(foo)\n return foo\n" - tags: '' - teardown: '' - text: "Write a function called \"reverseOrder\" that takes a string as an argument\ - \ and\nreturns another string with all of the whitespace delimetered words in\ - \ the\nreverse order, not taking any special consideration for number/symbols.\ - \ KISS.\nIf the string, \" one1 tw_o thREE four!\" is passed in, \"four! thREE\ - \ tw_0 one1\"\nwould be returned. Strip any whitespace from the ends of hte given\ - \ string.\n\nE.g:\ndef reverseOrder(foo):\n # do stuff here\n return foo\n" - unittests: - test1: - - str('ro3! T2is is cool') - test2: - - str(' ABCDS') - test3: - - str('zABCDS one two three!') - test4: - - str('123456789 asdf ASDF 4 _ 123 nine? \"\"') -strings_6: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: listToCSV(list) -> string - solution: "def listToCSV(words_list):\n csv_string = ','.join(words_list)\n \ - \ return csv_string\n" - tags: '' - teardown: '' - text: "Write a function called \"listToCSV\" that takes a list of strings and combines\n\ - them into a single string with all words separated by a comma: \",\". For\nexample,\ - \ [\"one\", 'two', 'three'] becomes \"one,two,three\".\n\nE.g:\ndef listToCSV(words_list):\n\ - \ # do stuff here\n return csv_string\n" - unittests: - test1: - - ['one', 'two', 'three'] - test2: - - ['1', ',', ':', "fiftyfive"] -strings_7: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: undToShortCSV(string) -> string - solution: "def listToCSV(words_list):\n csv_string = ','.join(words_list)\n \ - \ return csv_string\n" - tags: '' - teardown: '' - text: "Write a function called \"undToShortCSV\" that takes a string with words\n\ - separated by underscores, \"_\", changes the underscores to commas, \",\", and\n\ - returns only the first three words. You can assume that there will always\nbe\ - \ more than three words separated by underscore given. \n\nFor exmaple, \"one_two_three_four_five\"\ - \ becomes \"one,two,three\".\n\nE.g:\ndef undToShortCSV(und_sep_words):\n #\ - \ do stuff here\n return csv_sep_words\n" - unittests: - test1: - - str('one_two_three_four_five') - test2: - - '_______' - test3: - - str('1_2_3__five_six!\'\'_seven') -strings_8: - imports: '' - posttest: '' - pretest: '' - setup: '' - signature: getIndexOf(string, string) -> int - solution: "def getIndexOf(word, search_string):\n if word in search_string:\n\ - \ return search_string.index(word)\n else:\n return -1\n" - tags: '' - teardown: '' - text: "Wirte a functuion called \"getIndexOf\" that returns the index of a given\ - \ word\ninside of a given string. If the word is not present, it returns a -1.\ - \ \n\nFor exmaple, if the word is \"pizza\", and the search_string is \"there\ - \ is pizza on the plate\", then the index is 9.\n\nE.g:\ndef getIndexOf(word,\ - \ search_string):\n # do stuff here\n return index \n" - unittests: - test1: - - str('one_two_three_four_five') - test2: - - str('_______') - test3: - - str('1_2_3__five_six!\'\'_seven') diff --git a/cobra/clientdata/.gitkeep b/cobra/clientdata/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/cobra/cobra_client.py b/cobra/cobra_client.py deleted file mode 100644 index 3be8e07..0000000 --- a/cobra/cobra_client.py +++ /dev/null @@ -1,229 +0,0 @@ -import requests -import json -from util.solution_checker import Solution -from prompt_toolkit.shortcuts import create_eventloop -from ptpython.python_input import PythonInput, PythonCommandLineInterface -from ptpython.repl import run_config -from util.utility import cls, hash_results, encode_message, decode_message, load_yml, save_yml -from getpass import getpass -import colorama as cr - - -class CobraClient(): - def __init__(self, server_socket): - cr.init() - self.headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} - self.username = None - self.sessionid = None - self.server_socket = server_socket - self.run() - - def get_lessons(self): - req = requests.get('http://{0}:{1}/getlessons'.format(*self.server_socket)) - return json.loads(req.text) - - def get_questions(self, lesson): - req = requests.post('http://{0}:{1}/getquestions'.format(*self.server_socket), - json={'lesson':lesson}, - headers=self.headers) - return son.loads(req.text) - - def get_question(self, lesson, question_label): - req = requests.post('http://{0}:{1}/getquestion'.format(*self.server_socket), - json={'lesson': lesson, 'question_label': question_label, 'username': self.username}, - headers=self.headers) - return json.loads(req.text) - - def get_next_question(self): - req = requests.post('http://{0}:{1}/getnextquestion'.format(*self.server_socket), - json={'username': self.username}, - headers=self.headers) - return json.loads(req.text) - - def create_new_user(self): - username = input('Enter a username: ') - password = getpass('Enter a password: ') - req = requests.post('http://{0}:{1}/newuser'.format(*self.server_socket), - json={'username':username, 'password':encode_message(password)}, - headers=self.headers) - self.username = username - self.sessionid = decode_message(req.text) - - def login(self, continue_session=False): - if continue_session: - username, sessionid = list(load_yml('clientdata/session.yml').items())[0] - password = '0' - else: - username = input('Enter a username: ') - password = getpass('Enter password: ') - sessionid = '0' - req = requests.post('http://{0}:{1}/login'.format(*self.server_socket), - json={'username':username, 'password':encode_message(password), 'sessionid': encode_message(sessionid)}, - headers=self.headers) - self.username = username - save_yml('clientdata/session.yml', {self.username: req.text}) - self.session_id = decode_message(req.text) - - def solve_question(self, lesson, question_label): - question_data = self.get_question(lesson, question_label) - run_question_loop = True - while run_question_loop: - print('======================================================================') - print('{lesson}\n{title}\n{text}\n{signature}\n'.format(lesson=lesson, title=question_label, **question_data)) - - eventloop = create_eventloop() - ptpython_input = PythonInput() - run_config(ptpython_input, config_file='util/ptpython_config.py') - try: - cli = PythonCommandLineInterface(python_input=ptpython_input, eventloop=eventloop) - solution = cli.run() - finally: - eventloop.close() - try: - results = Solution(question_data, solution.text) - results.run_solution() - except Exception as e: - print('An exception occred while running your code: {}'.format(e)) - continue - - print('{:f}'.format(results.time_to_execute)) - print('Unit Test results: {}'.format(results.test_results)) - print('Line count: {}'.format(results.linecount)) - print('Character count: {}'.format(results.charcount)) - print('Format style violations: {}'.format(results.violationcount)) - print('Violation details:\n{}'.format(results.violations)) - - stats = { 'runtime': results.time_to_execute, - 'linecount': results.linecount, - 'charcount': results.charcount, - 'violations': results.violationcount} - - req = requests.post('http://{0}:{1}/submitsolution'.format(*self.server_socket), - json={'username': self.username, 'lesson': lesson, 'question_label': question_label, - 'solution': results.solution, 'results': hash_results(results.test_results), 'stats': stats}, - headers=self.headers) - if req.text == '"fail"': - input('Your solution did not match the server results. Please try again') - continue - else: - run_question_loop = False - - def history_menu(self): - req = requests.post('http://{0}:{1}/getcompleted'.format(*self.server_socket), - json={'username': self.username}, - headers=self.headers) - completed = json.loads(req.text) - - while True: - for index, item in enumerate(completed, 1): - print('{}) {}: {}'.format(index, item[0], item[1])) - print('0) Back') - try: - selection = int(input('Select a question to view it\'s submissions: ')) - if selection == 0: - break - item = dict(enumerate(completed, 1))[selection] - self.print_history(item[0], item[1]) - except KeyError: - pass - except ValueError: - pass - - def print_history(self, lesson, question_label): - req = requests.post('http://{0}:{1}/gethistory'.format(*self.server_socket), - json={'username': self.username, 'lesson': lesson, 'question_label': question_label}, - headers=self.headers) - history = json.loads(req.text) - for name, info in history.items(): - print('{}:'.format(name)) - print('SOLUTION:') - print(info['solution']) - print('RUNTIME:') - print(info['stats']['runtime']) - print('LINES:') - print(info['stats']['linecount']) - print('CHARACTERS:') - print(info['stats']['charcount']) - print('VIOLATIONS:') - print(info['stats']['violations']) - - - def run(self): - cls() - selection = input('1) login\n2) create account\n3) continue last session\n> ') - if selection == '1': - self.login() - elif selection == '2': - self.create_new_user() - elif selection == '3': - self.login(continue_session=True) - else: - pass - - run_main_loop = True - while run_main_loop: - while True: - print('1) Get next question') - print('2) Review qestion solutions') - try: - selection = int(input('Select an option: ')) - if selection == 2: - self.history_menu() - if selection == 1: - break - except KeyError: - pass - except ValueError: - pass - - lesson, question_label = self.get_next_question() - if lesson == None and question_label == None: - run_main_loop = False - else: - self.solve_question(lesson, question_label) - - #self.solve_question('python_basics', 'basic_math_1') - #self.solve_question('python_basics', 'basic_math_2') - #self.solve_question('python_basics', 'basic_math_3') - #self.solve_question('python_basics', 'basic_math_4') - #self.solve_question('python_basics', 'basic_math_5') - #self.solve_question('python_basics', 'basic_math_6') - #self.solve_question('python_basics', 'strings_1') - #self.solve_question('python_basics', 'strings_2') - #self.solve_question('python_basics', 'strings_3') - #self.solve_question('python_basics', 'strings_4') - #self.solve_question('python_basics', 'strings_5') - #self.solve_question('python_basics', 'strings_6') - #self.solve_question('python_basics', 'strings_7') - #self.solve_question('python_basics', 'strings_8') - #self.solve_question('python_basics', 'branching_1') - #self.solve_question('python_basics', 'branching_2') - #self.solve_question('python_basics', 'branching_3') - #self.solve_question('python_basics', 'lists_1') - #self.solve_question('python_basics', 'lists_2') - #self.solve_question('python_basics', 'sets_1') - #self.solve_question('python_basics', 'sets_2') - #self.solve_question('python_basics', 'sets_3') - #self.solve_question('python_basics', 'sets_4') - #self.solve_question('python_basics', 'dictionaries_1') - #self.solve_question('python_basics', 'dictionaries_2') - #self.solve_question('python_basics', 'dictionaries_3') - #self.solve_question('python_basics', 'dictionaries_4') - #self.solve_question('python_basics', 'dictionaries_5') - #self.solve_question('python_basics', 'dictionaries_6') - #self.solve_question('python_basics', 'dictionaries_7') - -if __name__ == '__main__': - CobraClient(('127.0.0.1', '8000')) - - - - - - - - - - - - diff --git a/cobra/cobra_server.py b/cobra/cobra_server.py deleted file mode 100644 index 480d7c1..0000000 --- a/cobra/cobra_server.py +++ /dev/null @@ -1,139 +0,0 @@ -import falcon -import yaml -#from random import * -#import uuid -import json -from util.utility import decode_message, encode_message, hash_results, load_yml -from util.server_utility import Questions, User, get_users, update_history, get_history -from util.solution_checker import Solution - - -class GetLessons(): - def on_get(self, req, resp): - resp.body = json.dumps(questions.get_lessons()) - -class GetQuestions(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - lesson = post_info['lesson'] - resp.body = json.dumps(questions.get_questions(lesson)) - -class GetQuestion(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - username = post_info['username'] - lesson = post_info['lesson'] - question_label = post_info['question_label'] - seed = users[username].new_seed() - question = questions.get_question(lesson, question_label) - question.pop('solution') - #question.pop('history') - question.update({'seed':seed}) - resp.body = json.dumps(question) - -class AddUser(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - ip = req.remote_addr - username = post_info['username'] - password = decode_message(post_info['password']) - users.update({username: User(username)}) - if users[username].create_user(password, ip): - sessionid = users[username].create_new_session() - else: - raise - resp.body = encode_message(sessionid) - -class LoginUser(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - ip = req.remote_addr - username = post_info['username'] - password = decode_message(post_info['password']) - sessionid = decode_message(post_info['sessionid']) - login_pass = False - - if users[username].check_session_id(sessionid, ip): - login_pass = True - elif users[username].login_user(password, ip): - login_pass = True - else: - sessionid = '-1' - if login_pass: - sessionid = users[username].create_new_session() - resp.body = encode_message(sessionid) - -class SubmitSolution(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - ip = req.remote_addr - username = post_info['username'] - lesson = post_info['lesson'] - question_label = post_info['question_label'] - solution = post_info['solution'] - submitted_results = post_info['results'] - stats = post_info['stats'] - question = questions.get_question(lesson, question_label) - question.update({'seed': users[username].get_seed()}) - master_results = Solution(question) - master_results.run_solution() - print(master_results.test_results) - print(submitted_results) - if hash_results(master_results.test_results) == submitted_results: - correct = [lesson, question_label] - users[username].update_completed(correct) - update_history(correct, username, solution, stats) - else: - correct = 'fail' - resp.body = json.dumps(correct) - -class GetNextQuestion(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - response = [None, None] - question_list = load_yml('question_list.yml') - username = post_info['username'] - for lesson, question_label in question_list: - if [lesson, question_label] in users[username].get_completed(): - continue - else: - response = [lesson, question_label] - break - resp.body = json.dumps(response) - -class GetHistory(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - lesson = post_info['lesson'] - question_label = post_info['question_label'] - username = post_info['username'] - question_item = [lesson, question_label] - if question_item in users[username].get_completed(): - history = get_history(question_item) - if history: - pass - else: - history = {} - else: - history = {} - resp.body = json.dumps(history) - -class GetCompleted(): - def on_post(self, req, resp): - post_info = json.loads(req.stream.read().decode('utf-8')) - username = post_info['username'] - completed = users[username].get_completed() - resp.body = json.dumps(completed) - -questions = Questions() -users = get_users() -app = falcon.API() -app.add_route('/getlessons', GetLessons()) -app.add_route('/getquestions', GetQuestions()) -app.add_route('/getquestion', GetQuestion()) -app.add_route('/newuser', AddUser()) -app.add_route('/login', LoginUser()) -app.add_route('/submitsolution', SubmitSolution()) -app.add_route('/getnextquestion', GetNextQuestion()) -app.add_route('/gethistory', GetHistory()) -app.add_route('/getcompleted', GetCompleted()) diff --git a/cobra/enabled/2_problems.yml b/cobra/enabled/2_problems.yml deleted file mode 100644 index d0ee07d..0000000 --- a/cobra/enabled/2_problems.yml +++ /dev/null @@ -1,858 +0,0 @@ -addThem: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(2 == self._function(1, 1)) - - self.test_results.append(1 == self._function(-5.1, 6.1))' - pretest: '' - setup: '' - signature: 'def addThem(a, b): -> return the_sum' - solution: "def addThem(a, b):\n the_sum = a + b\n return the_sum" - tags: '' - teardown: '' - text: 'Write a function called addThem that accepts two numbers and returns - - their sum.' - title: basic_math_1 - unittests: {} -carmenFound: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(''atlanta'' == self._function({{''atlanta'': - True, ''memphis'': False}})) - - self.test_results.append(''memphis'' == self._function({{''atlanta'': False, ''memphis'': - True}}))' - pretest: '' - setup: '' - signature: 'def carmenFound(cities): -> return city' - solution: "def carmenFound(cities):\n for city in cities:\n if cities[city]\ - \ == True:\n return city" - tags: '' - teardown: '' - text: 'Create a function called carmenFound that is given a dictionary with a - - list of city names as keys, each associated with a boolean value - - indicating whether or not Carmen is in the city. Return the name of the - - city Carmen is found in! - - The cities dictionary will look like: {{''city_a'': False, ''city_b''...}}' - title: branching_3 - unittests: {} -checkKeyExists: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(self._function({{''a'': 0, ''b'': 1}}, ''a'')) - - self.test_results.append(not self._function({{''a'': 0, ''b'': 1}}, ''z'')) - - self.test_results.append(not self._function({{''a'': 0, ''b'': 1}}, 1)) - - self.test_results.append(not self._function({{''a'': 0, ''b'': 1}}, 0))' - pretest: '' - setup: '' - signature: 'def checkKeyExists(a_dictionary, the_key): -> return exists_bool' - solution: "def checkKeyExists(a_dictionary, the_key):\n exists_bool = the_key\ - \ in a_dictionary\n return exists_bool" - tags: '' - teardown: '' - text: 'Write a function called checkKeyExists that is given a dictionary and a - - key and returns True if the key exists in the dictionary or False if it - - does not.' - title: dictionaries_5 - unittests: {} -checkKeysExist: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'ans = {{''z'': True, ''c'': False}} - - self.test_results.append(ans.items() == self._function(((''z'',0), (''b'', 1)), - (''z'', ''c'')).items()) - - self.test_results.append((len(self._function({{''z'': 0, ''b'': 1}}, [''f'',]).keys()) - == 1))' - pretest: '' - setup: '' - signature: 'def checkKeysExist(a_dictionary, some_keys): -> return out' - solution: "def checkKeysExist(a_dictionary, some_keys):\n if isinstance(a_dictionary,\ - \ tuple):\n a_dictionary = dict(a_dictionary)\n out = {{}}\n for\ - \ key in some_keys:\n out[key] = key in a_dictionary\n return out" - tags: '' - teardown: '' - text: 'Write a function called checkKeysExist that is given a dictionary and a - - list of keys to look for in teh dictionary. The function returns a new - - dictionary containing each key in the provided list with an associated - - boolean value indicating whether or not the key from the list was found - - in the given dictionary. - - As an example, if given {{''a'': 0, ''b'': 1}} and [''a'', ''c''] for keys, the - - output would be {{''a'': True, ''c'': False}}.' - title: dictionaries_6 - unittests: {} -convTupleUnique: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'items = (9, 1, 1, 9, 2, 3, 4, 4, 5) - - res = self._function(items) - - self.test_results.append(sorted(res) == sorted(set(items)))' - pretest: '' - setup: '' - signature: 'def convTupleUnique(some_items): -> return unique_tuple' - solution: "def convTupleUnique(some_items):\n unique_tuple = tuple(set(some_items))\n\ - \ return unique_tuple" - tags: '' - teardown: '' - text: 'Write a function called convTupleUnique(list) that accepts a list of - - objects and returns a tuple (not a list) with only the unique items from - - the list. Order of the returned list is not important.' - title: sets_1 - unittests: {} -convTupleUniqueOrder: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: "items = (1, 1, 2, 3, 4, 4, 5) \nres = self._function(items)\nself.test_results.append((1,\ - \ 2, 3, 4, 5) == res)" - pretest: '' - setup: '' - signature: 'def convTupleUniqueOrder(some_items): -> return tuple(out)' - solution: "def convTupleUniqueOrder(some_items):\n out = []\n for item in\ - \ some_items:\n if item in out:\n continue\n out.append(item)\n\ - \ return tuple(out)" - tags: '' - teardown: '' - text: 'Write a function called convTupleUniqueOrder(list) that accepts a list of - - objects and returns a tuple (not a list) with only the unique items from - - the list. Order of the returned tuple IS important. Order from the - - original list should be preserved; the first time an object is observed - - in the given list, it is in the returned tuple, and subsequent occurences - - are ignored.' - title: sets_2 - unittests: {} -convertCToF: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(20/5.0 + 32.0/9.0 == self._function(20)) - - self.test_results.append(-10/5.0 + 32.0/9.0 == self._function(-10))' - pretest: '' - setup: '' - signature: 'def convertCToF(temp_in_c): -> return temp_in_f' - solution: "def convertCToF(temp_in_c):\n temp_in_f = temp_in_c/5.0 + 32.0/9.0\n\ - \ return temp_in_f" - tags: '' - teardown: '' - text: 'Write a function called convertCToF that accepts a temperature in - - centigrade and returns the equivelant temperature in Farenheight. - - The equation for this is: (f = c/5 + 32/9)' - title: basic_math_5 - unittests: {} -createSet: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(set((1, 2, 3)) == self._function(obj2=1, obj3=2, - obj4=3, obj5=3)) - - self.test_results.append(set((1, 2, 3)) == self._function(obj2=1, obj3=2, obj5=3)) - - self.test_results.append(set() == self._function(None, None, None)) - - self.test_results.append(set() == self._function())' - pretest: '' - setup: '' - signature: 'def createSet(obj1=None, obj2=None, obj3=None, obj4=None, obj5=None): - -> return new_set' - solution: "def createSet(obj1=None, obj2=None, obj3=None, obj4=None, obj5=None):\n\ - \ new_set = set()\n for obj in (obj1, obj2, obj3, obj4, obj5):\n \ - \ if obj != None:\n new_set.add(obj)\n return new_set" - tags: '' - teardown: '' - text: 'Write a function called createSet that accepts up to five objects, adds - - them into a set, and returns a set of those objects. Hint: "set" is a - - data type. Do not add any of the objects fo the set if the object is - - equal to the None object.' - title: sets_3 - unittests: {} -divideThemInt: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(2 == self._function(4.4, 2)) - - self.test_results.append(2 == self._function(5, 2))' - pretest: '' - setup: '' - signature: 'def divideThemInt(a, b): -> return integer_result' - solution: "def divideThemInt(a, b):\n integer_result = int(a//b)\n return\ - \ integer_result" - tags: '' - teardown: '' - text: 'Write a function called divideThemIOnt that performs integer division - - on two given integers, a divided by b, and return the output as an integer.' - title: basic_math_4 - unittests: {} -firstHalfLower: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'foo = "asdF12345" - - out = self._function(foo) - - self.test_results.append(foo[:len(foo)//2].lower() == out) - - self.test_results.append("" == self._function("A")) - - foo = "aS1dF2" - - out = self._function(foo) - - self.test_results.append(foo[:len(foo)//2].lower() == out)' - pretest: '' - setup: '' - signature: 'def firstHalfLower(a_string): -> return result' - solution: "def firstHalfLower(a_string):\n length = int(len(a_string) / 2)\n\ - \ result = a_string[:length].lower()\n return result" - tags: '' - teardown: '' - text: 'Write a function called "firstHalfLower" that takes a string as an - - argument and returns the first half of the string, all lower case. When - - calculating how many characters of the string to return, round down: - - An 11 character string would result in 5 characters being returned.' - title: strings_3 - unittests: {} -getDictKeys: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append([1, 2, 3, 4] == self._function({{1: 5, 2: 6, - 3: 7, 4: 8}}))' - pretest: '' - setup: '' - signature: 'def getDictKeys(a_dictionary): -> return keys' - solution: "def getDictKeys(a_dictionary):\n keys = list(a_dictionary.keys())\n\ - \ return keys" - tags: '' - teardown: '' - text: 'Write a function called getDictKeys that is given a dictionary and returns - - the keys in the dictionary as a list.' - title: dictionaries_4 - unittests: {} -getIndexOf: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(9 == self._function(''pizza'', ''there is pizza - on the plate'')) - - self.test_results.append(-1 == self._function(''PIZZA'', ''there is pizza on the - plate''))' - pretest: '' - setup: '' - signature: 'def getIndexOf(word, search_string): -> return -1' - solution: "def getIndexOf(word, search_string):\n if word in search_string:\n\ - \ return search_string.index(word)\n else:\n return -1" - tags: '' - teardown: '' - text: 'Wirte a functuion called "getIndexOf" that returns the index of a given - - word inside of a given string. If the word is not present, it returns - - a -1. - - For exmaple, if the word is "pizza", and the search_string is: - - "there is pizza on the plate" - - then the index is 9.' - title: strings_8 - unittests: {} -getTruthiness: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append("margarita" == self._function([])) - - self.test_results.append("tequilla" == self._function((1,))) - - self.test_results.append("margarita" == self._function(0))' - pretest: '' - setup: '' - signature: 'def getTruthiness(obj): -> return resulting_word' - solution: "def getTruthiness(obj):\n if obj:\n resulting_word = \"tequilla\"\ - \n else:\n resulting_word = \"margarita\"\n return resulting_word" - tags: '' - teardown: '' - text: 'Write a function called getTruthiness that is given an object and, if - - that object evaluates to True, returns the string "tequilla", or otherwise - - returns the string "margarita".' - title: branching_1 - unittests: {} -justEvenChars: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(''zBD '' == self._function(''zABCDS '')) - - self.test_results.append(''13579'' == self._function(''123456789'')) - - self.test_results.append('' o!Ti sco '' == self._function('' ro3! T2is is cool - ''))' - pretest: '' - setup: '' - signature: 'def justEvenChars(a_string): -> return even_num_chars' - solution: "def justEvenChars(a_string):\n even_num_chars = a_string[::2]\n \ - \ return even_num_chars" - tags: '' - teardown: '' - text: 'Write a function called "justEvenChars" that takes a string as an - - argument and returns only even numbered characters from the string. If - - the string is "coolio", the result would be "coi", treating the zeroth - - characte as even (0%2==0).' - title: strings_4 - unittests: {} -listToCSV: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'out = self._function([''one'', '' '', ''two'', '''', ''three'', '''']) - - self.test_results.append(out == "one, ,two,,three,") - - out = self._function([''1'', '','', '':'', ''fiftyfive'']) - - self.test_results.append(out == ''1,,,:,fiftyfive'')' - pretest: '' - setup: '' - signature: 'def listToCSV(words_list): -> return csv_string' - solution: "def listToCSV(words_list):\n csv_string = ','.join(words_list)\n \ - \ return csv_string" - tags: '' - teardown: '' - text: 'Write a function called "listToCSV" that takes a list of strings and - - combines them into a single string with all words separated by a - - comma: ",". For example, ["one", ''two'', ''three''] becomes "one,two,three".' - title: strings_6 - unittests: {} -mergeToDict: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'keys = [1, 2, 3, 4] - - vals = [5, 6, 7, 8] - - self.test_results.append({{1: 5, 2: 6, 3: 7, 4: 8}} == self._function(keys, vals))' - pretest: '' - setup: '' - signature: 'def mergeToDict(keys, values): -> return merged_dict' - solution: "def mergeToDict(keys, values):\n merged_dict = dict(zip(keys, values))\n\ - \ return merged_dict" - tags: '' - teardown: '' - text: 'Write a function called mergeToDict that accepts a list of keys and a - - corresponding list ov values and returns a dictionary that has each - - key and value associated. - - For example, if the keys were (''color'', ''flavor'', ''texture'') and the values - - were (''red'', ''sour'', and ''rough''), the dictionary would look like: - - {{''color'': ''red'', ''flavor'': ''sour'', ''texture'': ''rough''}}' - title: dictoinaries_3 - unittests: {} -myPricesDict: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'answer = {{''bananna'': 4, ''apple'': 2, ''orange'': 1.5, ''pear'': 3}} - - self.test_results.append(answer == self._function())' - pretest: '' - setup: '' - signature: 'def myPricesDict(): -> return prices_dict' - solution: "def myPricesDict():\n prices_dict = {{'bananna': 4, 'apple': 2, 'orange':\ - \ 1.5, 'pear': 3}}\n return prices_dict" - tags: '' - teardown: '' - text: 'Write a function called myPricesDict that puts the following items and - - prices into a dictionary and returns it: - - "bananna": 4, - - "apple": 2, - - "orange": 1.5, - - "pear": 3' - title: dictoinaries_2 - unittests: {} -pocketContent: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'i = {{''gold'': 90, ''po'': [''fl'', ''te'', ''gon'']}} - - r = {{''gold'': 90, ''po'': [''fl'', ''te'', ''gon''], ''pocket'': [''seashell'']}} - - self.test_results.append(r == self._function(i))' - pretest: '' - setup: '' - signature: 'def pocketContent(inventory): -> return inventory' - solution: "def pocketContent(inventory):\n inventory['pocket'] = ['seashell']\n\ - \ return inventory" - tags: '' - teardown: '' - text: 'Write a function called pocketContents that accepts an inventory - - dictiionary and adds a "pocket" to the inventory that contains a - - [''seashell'',]. - - For example the inventory might look like this: - - {{''gold'': 400, ''pouch'': [''flint'', ''twine'', ''gemston'']}} - - And the returned inventory would look like: - - {{''gold'': 400, ''pouch'': [''flint'', ''twine''], ''pocket'': [''seashell'']}}' - title: dictionaries_1 - unittests: {} -printGivenKeys: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'p0 = ''./{{}}''.format(_randStr()) - - _stdRdr(self._function, ({{''a'': 0, ''b'': 1}}, ()), p0) - - self.test_results.append('''' == open(p0, ''r'').read()) - - _stdRdr(self._function, ({{''a'': 0, ''b'': 1}}, (''z'', ''y'',''a'')), p0) - - self.test_results.append(''z, None\\ny, None\\na, 0\\n'' == open(p0, ''r'').read()) - - os.remove(p0)' - pretest: '' - setup: '' - signature: 'def printGivenKeys(a_dictionary, some_keys): -> #return nothing' - solution: "def printGivenKeys(a_dictionary, some_keys):\n for key in some_keys:\n\ - \ if key in a_dictionary:\n print(\"{{}}, {{}}\".format(key,\ - \ a_dictionary[key]))\n else:\n print(\"{{}}, {{}}\".format(key,\ - \ None))\n #return nothing" - tags: '' - teardown: '' - text: 'Write a function called printGivenKeys that is given a dictionary and a - - list of keys to look for in teh dictionary. For each item in the list, - - the function prints the item and the value associated with it in the - - provided dictionary. If the item is not in the dictionary, None is used - - for the value. The sequence of the list should be preserve when printing. - - As an example, if given {{''a'': 0, ''b'': 1}} and [''c'', ''a''] for keys, it - would - - print: - - c, None - - a, 0' - title: dictionaries_7 - unittests: {} -remainder: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: self.test_results.append(4 == self._function(9, 5)) - pretest: '' - setup: '' - signature: 'def remainder(a, b): -> return the_remainder' - solution: "def remainder(a, b):\n the_remainder = a % b\n return the_remainder" - tags: '' - teardown: '' - text: 'Write a function called remainder that accepts two numbers, a and b, - - and returns the remainder of a / b.' - title: basic_math_2 - unittests: {} -removeFromSet: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'foo = (1, 2, 3, 4, 5, 6) - - new = self._function(set(foo), 6) - - self.test_results.append(sorted((1, 2, 3, 4, 5)) == sorted(new)) - - new = self._function(set(foo), 7) - - self.test_results.append(sorted(new) == sorted(foo))' - pretest: '' - setup: '' - signature: 'def removeFromSet(a_set, an_item): -> return tuple(a_set)' - solution: "def removeFromSet(a_set, an_item):\n if an_item in a_set:\n \ - \ a_set.remove(an_item)\n return tuple(a_set)" - tags: '' - teardown: '' - text: 'Write a function called removeFromSet that accepts a set and an item. - - If the item exists in the set, then it is removed. The resulting set - - is converted to a tuple and returned.' - title: sets_4 - unittests: {} -returnWithQuotes: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'foo = """''It''s modulus, "%", not division, "/", or escaping "\"!''""" - - out = self._function() - - self.test_results.append(foo == out)' - pretest: '' - setup: '' - signature: 'def returnWithQuotes(): -> return quotes' - solution: "def returnWithQuotes():\n quotes = \"\"\"'It's modulus, \"%\", not\ - \ division, \"/\", or escaping \"\\\"!'\"\"\"\n return quotes" - tags: '' - teardown: '' - text: 'Write a function called returnWithQuotes that takes no arguments and, - - when called, returns the following text (no whitespace on the ends), - - but with all quotes shown included in the string: - - ''It''s modulus, "%", not division, "/", or escaping "\"!''' - title: strings_1 - unittests: {} -reverseOrder: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'out = self._function(''ro3! T2is is cool'') - - self.test_results.append(''cool is T2is ro3!'' == out) - - out = self._function('' ABCDS'') - - self.test_results.append(''ABCDS'' == out) - - out = self._function(''123456789 asdf ASDF 4 _ 123 nine? \"\"'') - - self.test_results.append(''\"\" nine? 123 _ 4 ASDF asdf 123456789'' == out)' - pretest: '' - setup: '' - signature: 'def reverseOrder(a_string): -> return switched' - solution: "def reverseOrder(a_string):\n switched = a_string.strip()\n switched\ - \ = switched.split()\n switched = switched[::-1]\n switched = \" \".join(switched)\n\ - \ return switched" - tags: '' - teardown: '' - text: 'Write a function called "reverseOrder" that takes a string as an - - argument and returns another string with all of the whitespace - - delimetered words in the reverse order, not taking any special - - consideration for number/symbols. KISS. If the string, " one1 tw_o - - thREE four!" is passed in, "four! thREE tw_0 one1" would be returned. - - Strip any whitespace from the ends of the given string.' - title: strings_5 - unittests: {} -smallestOfList: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(-5 == self._function((1, 2, 3, 4, -5))) - - self.test_results.append(1 == self._function((1, 2, 3, 4, -5), True)) - - self.test_results.append(1 == self._function((2, 1, -1, 3, 4, -5), True)) - - self.test_results.append(1 == self._function((-2, 1, -1, 3, 4, -5), True))' - pretest: '' - setup: '' - signature: 'def smallestOfList(some_nums, absolute_val=False): -> return smallest' - solution: "def smallestOfList(some_nums, absolute_val=False):\n smallest = None\n\ - \ small_loc = None\n for n, num in enumerate(some_nums):\n num =\ - \ abs(num) if absolute_val else num\n if smallest == None or num < smallest:\n\ - \ smallest = num\n small_loc = n\n smallest = some_nums[small_loc]\n\ - \ return smallest" - tags: '' - teardown: '' - text: 'Write a function called smallestOfList that accepts a list or tuple of - - numbers and returns the smallest number found in the list. - - However, if absolute value is set to True, it should return the number that - - has the smallest absolute value. - - If two numbers in the list both have an absolute value that is the - - smallest and the same, the first one encounterd should be returned.' - title: lists_2 - unittests: {} -strUpper: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'foo = " asfd" - - self.test_results.append(foo.upper().strip() == self._function(foo)) - - foo = "123%asf d " - - self.test_results.append(foo.upper().strip() == self._function(foo)) - - foo = "ASDF" - - self.test_results.append(foo == self._function(foo)) - - foo = "" - - self.test_results.append(foo == self._function(foo)) - - foo = " \\n" - - self.test_results.append(foo.strip() == self._function(foo))' - pretest: '' - setup: '' - signature: 'def strUpper(a_string): -> return upper_stripped' - solution: "def strUpper(a_string):\n upper_stripped = a_string.upper().strip()\n\ - \ return upper_stripped" - tags: '' - teardown: '' - text: 'Write a function called "strUpper" that takes a string as an argument - - and returns the string without any whitespace on the ends and all upper - - case.' - title: strings_2 - unittests: {} -sumAllItems: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self.test_results.append(0.0000001 > 10.1 - self._function([2, 4, 20, - 4.1, -20])) - - self.test_results.append(0 == self._function((-1, 1))) - - self.test_results.append(None == self._function(())) - - self.test_results.append(None == self._function([]))' - pretest: '' - setup: '' - signature: 'def sumAllItems(some_nums): -> return the_sum' - solution: "def sumAllItems(some_nums):\n if len(some_nums) == 0:\n the_sum\ - \ = None\n else:\n the_sum = sum(some_nums)\n return the_sum" - tags: '' - teardown: '' - text: 'Write a function called sumAllItems that accepts a list or tuple of - - numbers, summs them, and returns the sum. If the list is empty, return - - None, rather than zero.' - title: lists_1 - unittests: {} -toInt: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: self.test_results.append(3 == self._function(3.9)) - pretest: '' - setup: '' - signature: 'def toInt(a_float): -> return an_integer' - solution: "def toInt(a_float):\n an_integer = int(a_float)\n return an_integer" - tags: '' - teardown: '' - text: 'Write a function called toInt that accepts an interger or floating point - - number and returns it as an integer. E.g. 3.3 becomes 3.' - title: basic_math_3 - unittests: {} -twosTruthiness: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'self._function([], [], [], []) - - ''foobar'' - - self._function([], [], [1,], []) - - ''foobar'' - - self._function([], [], [1,], [1,]) - - ''twos'' - - self._function([1,], [], [1,], [1,]) - - ''threes'' - - self._function([1,], [1,], [1,], [1,]) - - ''foobar''' - pretest: '' - setup: '' - signature: 'def twosTruthiness(obj0, obj1, obj2, obj3): -> return resulting_word' - solution: "def twosTruthiness(obj0, obj1, obj2, obj3):\n items = (obj0, obj1,\ - \ obj2, obj3)\n count = len([o for o in items if o])\n if count == 2:\n\ - \ resulting_word = \"twos\"\n elif count == 3:\n resulting_word\ - \ = \"threes\"\n else:\n resulting_word = \"foobar\"\n return resulting_word" - tags: '' - teardown: '' - text: 'Write a function called twosTruthiness that is given four boolean values. - - if any two of the four are True, then return "twos". If any three of them - - are True, then return "threes", if less than two or four of them are True, - - then return "foobar"' - title: branching_2 - unittests: {} -undToShortCSV: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\nglobal sys\n\ - import sys\n\ndef _randStr(str_len=10):\n return ''.join(random.choices(string.ascii_uppercase,\ - \ k=str_len))\n\ndef _stdRdr(func, args, path):\n orig = sys.stdout\n with\ - \ open(path, 'w') as sys.stdout:\n func(*args)\n sys.stdout = orig\n" - posttest: 'out = self._function(''one_two_three_four_five'') - - self.test_results.append(out == ''one,two,three'') - - out = self._function(''one_two_ '') - - self.test_results.append(out == ''one,two, '') - - out = self._function('' _ __ _ '') - - self.test_results.append(out == '' , ,'')' - pretest: '' - setup: '' - signature: 'def undToShortCSV(und_sep_words): -> return comma_sep' - solution: "def undToShortCSV(und_sep_words):\n comma_sep = ','.join(und_sep_words.split('_')[:3])\n\ - \ return comma_sep" - tags: '' - teardown: '' - text: 'Write a function called "undToShortCSV" that takes a string with words, - - each separated by an underscore, ''_'', changes the underscores to - - commas, ",", and returns only the first three words. You can assume - - that there will always be more than three words separated by underscore - - given.' - title: strings_7 - unittests: {} diff --git a/cobra/enabled/3_problems.yml b/cobra/enabled/3_problems.yml deleted file mode 100644 index 0d61e39..0000000 --- a/cobra/enabled/3_problems.yml +++ /dev/null @@ -1,309 +0,0 @@ -appendLineToFile: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - c0 = "{{}}\\n{{}}\\n".format(_randStr(), _randStr()) - - c1 = _randStr() - - self.test_results.append(len(c0) == open(f0, ''w'').write(c0)) - - self._function(f0, c1) - - self.test_results.append(c0 + c1 == open(f0, ''r'').read()) - - os.remove(f0)' - pretest: '' - setup: '' - signature: 'def appendLineToFile(file_path, content): -> #return nothing' - solution: "def appendLineToFile(file_path, content):\n with open(file_path, 'a')\ - \ as f:\n f.write(content)\n #return nothing" - tags: '' - teardown: '' - text: 'Write a function called appendLineToFile that accepts a path and a string, - - and writes the string to the end of the file (without modifying the - - existing contents in the file).' - title: readwrite_3 - unittests: {} -cdAndWrite: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - d0 = ''./{{}}''.format(_randStr()) - - os.mkdir(d0) - - cwd = os.path.realpath(''.'') - - content = ''asdf'' - - self.test_results.append(len(content) == self._function(d0, f0, content)) - - self.test_results.append(''./'' + os.path.realpath(''.'').split(''/'')[-1] == - d0) - - self.test_results.append(content == (os.path.isfile(f0) and open(f0, ''r'').read())) - - os.path.isfile(f0) and os.remove(f0) - - os.chdir(cwd) - - os.path.isdir(d0) and os.rmdir(d0)' - pretest: '' - setup: '' - signature: 'def cdAndWrite(dir_path, file_name, content): -> return os.stat(file_name).st_size' - solution: "def cdAndWrite(dir_path, file_name, content):\n os.chdir(dir_path)\n\ - \ open(file_name, 'w').write(content)\n return os.stat(file_name).st_size" - tags: '' - teardown: '' - text: 'Write a function called cdAndWrite that changes directory to the given - - path, then edits a file and writes the given content to it. Return the - - size of the file in bytes!' - title: os_basics_2 - unittests: {} -createTmpDir: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'd0 = ''''.join(random.choices(string.ascii_uppercase, k=4)) - - p0 = ''/tmp/{{}}''.format(d0) - - out = self._function(d0) - - self.test_results.append(out == p0) - - os.path.isdir(p0) and os.rmdir(p0)' - pretest: '' - setup: '' - signature: 'def createTmpDir(dir_name): -> return dir_path' - solution: "def createTmpDir(dir_name):\n #os.umask(0077)\n dir_path = '/tmp/{{}}'.format(dir_name)\n\ - \ os.mkdir(dir_path)\n return dir_path" - tags: '' - teardown: '' - text: 'Write a function called createTmpDir that accepts a directory name and - - creates it in /tmp. Set the permissions so that only the directory owner - - can read/write/execute it. Return the complete path to the directory. - - Bonus: Can you do this in a way that avoids a race condition security - - vulnerability?' - title: os_basics_4 - unittests: {} -listDirFilter: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: "e0 = _randStr()\ne1 = _randStr()\nfiles = {{e0: set(), e1: set()}}\n\ - for e in (e0, e1):\n for n in range(5):\n f = \"{{}}.{{}}\".format(n,\ - \ e)\n files[e].add(f)\n open(f, 'w').close()\nreg_filter = '(./){{0,1}}[0-9].'\ - \ + e0\nself.test_results.append(files[e0] == set(self._function('./', reg_filter)))\n\ - for f in list(files[e0]) + list(files[e1]):\n os.remove(f)" - pretest: '' - setup: '' - signature: 'def listDirFilter(dir_path, regex_filter): -> return files_list' - solution: "def listDirFilter(dir_path, regex_filter):\n files_list = []\n \ - \ for name in os.listdir(dir_path):\n if re.match(regex_filter, name):\n\ - \ files_list.append(name) \n return files_list" - tags: '' - teardown: '' - text: 'Write a function called listDirFilter that accepts a directory path and a - - regex filter. It retuns a list of files at the directory path whos names - - match the given regex. Return only the file names, not their complete - - path.' - title: os_basics_3 - unittests: {} -moveAFile: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - f1 = ''./{{}}''.format(_randStr()) - - content = ''asdf'' - - self.test_results.append(len(content) == open(f0, ''w'').write(content)) - - self._function(f0, f1) - - self.test_results.append(content == (os.path.isfile(f1) and open(f1, ''r'').read())) - - self.test_results.append(os.path.isfile(f1) and os.remove(f1) or True) - - self.test_results.append(not (os.path.isfile(f0) and os.remove(f0)))' - pretest: '' - setup: '' - signature: 'def moveAFile(src_path, dst_path): -> # return nothing' - solution: "def moveAFile(src_path, dst_path):\n shutil.move(src_path, dst_path)\n\ - \ # return nothing" - tags: '' - teardown: '' - text: 'Write a function called moveAFile that accepts a source file path and a - - dest file path and moves the file to the destination.' - title: os_basics_1 - unittests: {} -readFileToString: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - c0 = ''{{}}\\n{{}}\\n''.format(_randStr(), _randStr()) - - self.test_results.append(len(c0) == open(f0, ''w'').write(c0)) - - self.test_results.append(c0 == self._function(f0)) - - os.remove(f0)' - pretest: '' - setup: '' - signature: 'def readFileToString(file_path): -> return contents' - solution: "def readFileToString(file_path):\n with open(file_path, 'r') as f:\n\ - \ contents = f.read()\n return contents" - tags: '' - teardown: '' - text: 'Write a function called readFileToString that accepts a path, opens the - - path, and returns the contents of the file as a string value. You can - - assume that you''ll have access to the file, it won''t be binary data, you - - don''t need to do anything to the given path to open it.' - title: readwrite_1 - unittests: {} -readLinesFromFile: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - c0 = "{{}}\\n{{}}\\n".format(_randStr(), _randStr()) - - self.test_results.append(len(c0) == open(f0, ''w'').write(c0)) - - self.test_results.append(c0.split(''\\n'') == self._function(f0)) - - os.remove(f0)' - pretest: '' - setup: '' - signature: 'def readLinesFromFile(file_path): -> return contents' - solution: "def readLinesFromFile(file_path):\n contents = []\n with open(file_path,\ - \ 'r') as f:\n for line in f.read().split('\\n'):\n contents.append(line)\n\ - \ return contents" - tags: '' - teardown: '' - text: 'Write a function called readLinesFromFiles that accepts a path, reads the - - contents, and returns a list of stings for each line in the file. Do not - - include newline characters in the returned strings.' - title: readwrite_2 - unittests: {} -realPath: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'cwd = os.path.realpath(''.'') - - self.test_results.append(cwd == self._function(''.''))' - pretest: '' - setup: '' - signature: 'def realPath(dir_name): -> # return files_paths' - solution: "def realPath(dir_name):\n real_path = os.path.realpath(dir_name)\n\ - \ return real_path\n#def filePaths(dir_path, files_list):\n# '''os_basics_6\n\ - # Write a function called filePaths that accepts a directory path and a\n#\ - \ list of files. It returns a list of full paths to those files. \n# For\ - \ example, if dir_path is '/tmp/' and files list is ['./foobar.txt',\n# 'diddun.txt'],\ - \ the output would be ['/tmp/foobar.txt', '/tmp/diddun.txt'].\n# '''\n# \ - \ return files_paths" - tags: '' - teardown: '' - text: 'Write a function called realPath that accepts a path, checks if it has - - any symlinks in it, and returns the actual path (wihout symlinks) to the - - file or directory the original path pointed to.' - title: os_basics_5 - unittests: {} -rewriteInLower: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - f1 = ''./{{}}''.format(_randStr()) - - c0 = "!{{}}\\n{{}}13\\n! #@\\n".format(_randStr(), _randStr()).upper() - - self.test_results.append(len(c0) == open(f0, ''w'').write(c0)) - - self._function(f0, f1) - - self.test_results.append(os.path.isfile(f0) and os.path.isfile(f1)) - - self.test_results.append(c0.lower() == open(f1, ''r'').read()) - - os.remove(f0) - - os.remove(f1)' - pretest: '' - setup: '' - signature: 'def rewriteInLower(source_path, dest_path): -> #return nothing' - solution: "def rewriteInLower(source_path, dest_path):\n with open(source_path,\ - \ 'r') as f:\n contents = f.read().lower()\n with open(dest_path, 'w')\ - \ as f:\n f.write(contents)\n #return nothing" - tags: '' - teardown: '' - text: 'Write a function called rewriteInLower that accepts a source and - - destination path. It reads in the source path, converts the contents to - - all lower case, and writes them to the destination path.' - title: readwrite_5 - unittests: {} -truncateWriteFile: - imports: "\nglobal os\nimport os\nglobal random\nimport random\nglobal re\nimport\ - \ re\nglobal shutil\nimport shutil\nglobal string\nimport string\n\ndef _randStr(str_len=10):\n\ - \ return ''.join(random.choices(string.ascii_uppercase, k=str_len))\n" - posttest: 'f0 = ''./{{}}''.format(_randStr()) - - c0 = "{{}}\\n{{}}\\n".format(_randStr(), _randStr()) - - c1 = _randStr() - - self.test_results.append(len(c0) == open(f0, ''w'').write(c0)) - - self._function(f0, c1) - - self.test_results.append(c1 == open(f0, ''r'').read()) - - os.remove(f0)' - pretest: '' - setup: '' - signature: 'def truncateWriteFile(file_path, content): -> #return nothing' - solution: "def truncateWriteFile(file_path, content):\n with open(file_path,\ - \ 'w') as f:\n f.write(content)\n #return nothing" - tags: '' - teardown: '' - text: 'Write a function called truncateWriteFile that accepts a path and a - - string, and writes the string to the file, truncating (overwriting) any - - existing content in the file.' - title: readwrite_4 - unittests: {} diff --git a/cobra/enabled/test.yml b/cobra/enabled/test.yml deleted file mode 100644 index 3ab4884..0000000 --- a/cobra/enabled/test.yml +++ /dev/null @@ -1,17 +0,0 @@ -test: - imports: "from time import time\nimport random\nimport string\n_randStr = '''''.join(random.choices(string.ascii_uppercase, k=10))'''" - posttest: "print('DIR:', dir())\nprint('locals:', locals())\nprint(exec(_randStr))" - pretest: 'pretest = "pretest: " + str(time()); print(time())' - setup: 'setup = "setup: " + str(time()); print(time())' - signature: test(a,b,c) - solution: 'def test(a, b, c): return 0' - tags: '' - teardown: 'print("{{setup}} teardown: {{time}}".format(setup=setup, time=time())); print(time())' - text: "Write a function that takes 2 integers as parameter\nIt should return the\ - \ sum of the 2 integers.\n\nE.g. \ndef addThem(num_a, num_b):\n #your code\ - \ here\n return the_sum\n" - unittests: - test1: - - str(time()) - - str(time()) - - str(time()) diff --git a/cobra/history/.gitkeep b/cobra/history/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/cobra/prob_edit.py b/cobra/prob_edit.py deleted file mode 100755 index 34dcd9b..0000000 --- a/cobra/prob_edit.py +++ /dev/null @@ -1,453 +0,0 @@ -#!/usr/bin/env python -# Python2 compatibility: -#from __future__ import print_function -#from future.builtins import input - -# Other imports: -import copy -import filecmp -from glob import glob -#import operator -from operator import itemgetter -import os -import shutil -import subprocess as sp -#import tempfile -from tempfile import mkstemp -import time -import traceback -import yaml -import cobra_client as cc - - -EDITOR='/usr/bin/vi' -EXCLUDE_FILES = ['session.yml',] -ESSENTIAL_KEYS = ('imports', 'posttest', 'pretest', 'setup', 'signature', - 'solution', 'tags', 'teardown', 'text', 'unittests') - -def cls(): - os.system('cls' if os.name=='nt' else 'clear') - - -def editTempFile(content, ref_header=None): - '''put "content" into a temp file and open it with the system editor. - if ref_header is defined, put that at the top of the file for reference. - a marker line follows, and the content is placed below that for editing. - Return the updated content.''' - - marker = "\n### do not edit anything above this line ###\n" - _, fname = mkstemp() - with open(fname, 'w') as f: - if ref_header != None: - f.write(ref_header) - f.write(marker) - if not content.startswith('\n'): - f.write('\n') - f.write(content) - - vi_cmd = (EDITOR, fname) - sp.call(vi_cmd, shell=False) - - with open(fname, 'r') as f: - new_content = f.read() - - if ref_header != None: - marker_loc = new_content.find(marker) - if marker_loc < 0: - print('Marker line not found... Aborting!') - print('Will re-open the editor, please copy your stuff externally.') - input("enter to continue...") - time.sleep(2) - with open(fname, 'a') as f: - f.write('\n### SAVE THIS CONTENT EXTERNALLY, FATAL ERROR ###\n') - f.write('\n### SAVE THIS CONTENT EXTERNALLY, FATAL ERROR ###\n') - f.write('\n### SAVE THIS CONTENT EXTERNALLY, FATAL ERROR ###\n') - f.write('\n### SAVE THIS CONTENT EXTERNALLY, FATAL ERROR ###\n') - sp.call(vi_cmd, shell=False) - return content - #offset to end of marker line - marker_loc += len(marker) - new_content = new_content[marker_loc:] - - #for guess in (1, 2, 3): - # answer = input("Save changes? [y]/n: ") - # if answer in ("", "y", "n"): - # if answer == "n": - # new_content = content - # break - # print("Responses accepted: 'y', 'n', or implicit y ''") - #else: - # print("Aborting!") - # time.sleep(2) - # new_content = content - return new_content - - -def mergeEditYml(problem, keys_to_edit, ref_header=None): - '''The idea here is to generate a string with yaml data for all - of the "keys_to_edit" from the problem data. Then pas it to the - editTempFile function for user edit with VI, and then return - the modified data. - ''' - content = {} - for key in keys_to_edit: - content[key] = problem[key] - new_content = yaml.dump(content, default_flow_style=False) - new_content = editTempFile(new_content, ref_header) - try: - print("Success loading yaml content...") - new_content = yaml.load(new_content) - except: - new_content = content - for key in keys_to_edit: - if key not in new_content: - print("Keys missing in returned text:", key, "from", keys_to_edit) - print("Aborting...") - time.sleep(2) - break - else: - print("All good...") - return new_content - return content - - -def getProbsFiles(): - all_files = glob('*.yml') - out_files = [] - for f in all_files: - for x in EXCLUDE_FILES: - if x in f: - break - else: - out_files.append(f) - return out_files - - -def testUpdateYmlFormat(probs_dict): - '''This checks if the yml is the old format (with uuid, etc). if it - is, then it is convrted to the new format and returned.''' - out = {} - for key, val in probs_dict.items(): - if 'title' in val: - key = val.pop('title') - if 'uuid' in val: - val.pop('uuid') - for k in ('pretest', 'posttest', 'tags', - 'imports', 'setup', 'teardown'): - if k not in val: - val[k] = '' - for k in ('history', 'ratings', 'successes'): - if k in val: - val.pop(k) - out[key] = val - return out - - - -def readProbsFile(problem_file): - '''This is called for each file containing course problems. Returns - a list of problems (dicts)''' - probs_dict = yaml.load(open(problem_file, 'r')) - if not isinstance(probs_dict, dict): - probs_dict = None - else: - probs_dict = testUpdateYmlFormat(probs_dict) - return probs_dict - - -def writeProbsFile(problem_file, probs_dict): - '''Takes a list of problem dicts and converts them to a dict of dicts - using the title as the primary key and writes them as yaml to the - problem_file''' - # translate back into dict for storage - #probs_dict = {} - #for prob in probs_list: - # probs_dict[prob['title']] = prob - with open(problem_file, 'w') as f: - f.write(yaml.dump(probs_dict, default_flow_style=False)) - - -def promptMenu(title, options, defaults=None): - '''This is mianly what the user interacts with. It puts up a list of - optoins and queries for a response from the user. - "options" is a list of options that will be assigned numbers to chose - from. "defaults" is a list of (key, description) items - that the user can choose from.''' - if not defaults: - defaults = (('n', 'next'), - ('p', 'previous'), - ('q', 'quit/return')) - valid_choices = [str(n) for n in range(len(options))] - valid_choices += [n for n, o in defaults] - - print("\n --- {} ---".format(title)) - for n, option in enumerate(options): - print(" {} {}".format(n, option)) - print("") - for n, option in defaults: - print(" {} {}".format(n, option)) - print("") - - for guess in (1, 2, 3): - answer = input("Select: ") - if answer not in valid_choices: - print("Invalid. Optoins are:", valid_choices) - continue - break - else: - return None - return answer - - -def backupProbsFile(probs_file_name): - # Make a backup copy of the problems file - if not os.path.isdir('./backups'): - os.mkdir('./backups') - epoch_seconds = int(time.time()) - shutil.copy( probs_file_name, - "./backups/{}_{}".format(probs_file_name, - epoch_seconds) ) - assert( filecmp.cmp( - probs_file_name, - "./backups/{}_{}".format(probs_file_name, - epoch_seconds) ) ) - - -def dPos(a_dict, key=None, index=None): - '''If key is set, return the index of the key; if index is set, return - the key at the given index.''' - d_list = list(a_dict.keys()) - if key != None: - index = d_list.index(key) - return index - elif index != None: - key = d_list[index] - return key - - -def dMove(a_dict, key, offset): - '''Return re-ordered dictionary with key move by given offset. - Do nothing if key not in dictionary. Limit offset to ends of dict.''' - if key in a_dict: - index = dPos(a_dict, key) - foo = list(a_dict.items()) - new_index = min(max(0, index + offset), len(foo)-1) - tmp = foo.pop(index) - foo.insert(new_index, tmp) - foo = dict(foo) - else: - foo = a_dict - return foo - - -def interactiveMenu(probs_dicts): - '''This is the meat of the tool. All of the code that make things - happen at each screen is included here. Trying to keep cross-contamination - between variables in here to a minimum w/o having to break out seperate - functions for each screen.''' - probs_file_name = None - probs_dict = None - prob_title = None - while True: - cls() - print("probs_file_name:", probs_file_name) - print("prob_title:", prob_title) - - # Each time menu is updated, write changes to disk - if not probs_file_name == None: - writeProbsFile(probs_file_name, probs_dict) - - ###################### - # Chose a problem file - ###################### - if probs_file_name == None: - defaults = (('q', 'quit/return'), ) - title = "Choose a problem file:" - choice = promptMenu(title, probs_dicts.keys(), defaults) - print("Choice was:", (choice,)) - #time.sleep(2) - - if choice == None: - break - elif choice.isdigit(): - #probs_file_name = probs_dicts.keys()[int(choice)] - probs_file_name = dPos(probs_dicts, index=int(choice)) - probs_dict = probs_dicts[probs_file_name] - backupProbsFile(probs_file_name) - elif choice == 'q': - print("Quitting this fine program!") - break - - ###################### - # Chose a problem - ###################### - elif prob_title == None: - defaults = ( ('q', 'quit/return'), ) - title = "Choose a problem to work on from '{}':".format( - probs_file_name) - probs_titles = [(k, v['signature']) for k, v in probs_dict.items()] - choice = promptMenu(title, probs_titles, defaults) - print("Choice was:", (choice,)) - #time.sleep(2) - - if choice == None: - break - elif choice.isdigit(): - prob_title = dPos(probs_dict, index=int(choice)) - #prob_title = probs_dict.keys()[int(choice)] - elif choice == 'q': - probs_file_name = None - continue - - ###################### - # Problem edit menu - ###################### - else: - prob_dict = probs_dict[prob_title] - prob_index = dPos(probs_dict, prob_title) - - defaults = (('e', 'edit all relevant fields'), - ('c', 'copy the problem'), - ('r', 'run the problem'), - ('-', ''), - ('t', 'edit title'), - ('x', 'edit text description'), - ('g', 'edit signature'), - ('s', 'edit solution'), - ('u', 'edit unit test'), - ('d', 'edit teardown'), - ('+', 'move up in order'), - ('-', 'move down in order'), - ('[', 'previous problem'), - (']', 'next problem'), - ('q', 'quit/return')) - title = ( "Prob Selected: index: {}\n" - " title: {}\n" - " signature: {}\n" - " text: \n" - "{}".format( prob_index, prob_title, - prob_dict['signature'], - prob_dict['text'] ) ) - choice = promptMenu(title, [], defaults) - print("Choice was:", (choice,)) - #time.sleep(2) - if choice.isdigit(): - pass - - # Edit problem title - elif choice == 't': - old_title = prob_title - while True: - prob_title = input("New Title: ") - if prob_title in probs_dict: - print("duplicate title!, try again.") - continue - break - probs_dict[prob_title] = probs_dict.pop(old_title) - - # Edit problem signature - elif choice == 'g': - prob_dict['signature'] = input("New Signature: ") - - # Edit text description - elif choice == 'x': - prob_dict['text'] = editTempFile(prob_dict['text']) - - elif choice == 's': - prob_dict['solution'] = editTempFile( prob_dict['solution'], - prob_dict['text'] ) - - # Edit unit tests - elif choice == 'u': - edit_keys = ('unittests', 'imports', 'setup', 'teardown') - content = mergeEditYml(prob_dict, edit_keys, prob_dict['text']) - for key in edit_keys: - prob_dict[key] = content[key] - - # Edit unit test teardown - elif choice == 'd': - prob_dict['teardown'] = editTempFile( prob_dict['teardown'], - prob_dict['text'] ) - - # Edit all relevant fields - elif choice == 'e': - edit_keys = ('text', 'signature', 'solution', 'tags', - 'unittests', 'imports', 'setup', 'teardown') - content = mergeEditYml(prob_dict, edit_keys) - for key in edit_keys: - prob_dict[key] = content[key] - - # Copy the current problem - elif choice == 'c': - old_title = prob_title - old_dict = prob_dict - - digit = 0 - while True: - prob_title = '{} copy {}'.format(old_title, digit) - if prob_title in probs_dict: - digit += 1 - continue - break - prob_dict = {} - for key in ESSENTIAL_KEYS: - prob_dict[key] = copy.deepcopy(old_dict[key]) - probs_dict[prob_title] = prob_dict - - # Run the problem: - elif choice == 'r': - from ptpython.repl import run_config - question_data = prob_dict - question_data['seed'] = 0 - eventloop = cc.create_eventloop() - ptpython_input = cc.PythonInput() - run_config(ptpython_input, - config_file='util/ptpython_config.py') - print("answer.text: ", question_data['solution']) - print("------------- running ------------") - answer = cc.Solution(question_data, question_data['solution']) - try: - answer.run_solution(True) - print("------------- RESULS: ------------") - print("solution: ", answer.test_results) - print("a.violations:", answer.violations) - print("a.violcount:", answer.violationcount) - #print("teardown:", answer._teardown) - #import code - #code.InteractiveConsole(locals=locals()).interact() - except Exception as e: - print("Exception in run: {}".format(e)) - traceback.print_stack() - - input("Enter to continue...") - - # Change ordering, etc... - elif choice == '+': - probs_dict = dMove(probs_dict, prob_title, 1) - elif choice == '-': - probs_dict = dMove(probs_dict, prob_title, -1) - elif choice == '[': - prob_index = max(0, prob_index-1) - prob_title = dPos(probs_dict, index=prob_index) - elif choice == ']': - prob_index = min(len(probs_dict)-1, prob_index+1) - prob_title = dPos(probs_dict, index=prob_index) - - elif choice == 'q': - prob_title = None - prob_dit = None - -def mainFunc(): - probs_files = sorted(getProbsFiles()) - print(probs_files) - probs_dicts = {} - for p_file in sorted(probs_files): - tmp = readProbsFile(p_file) - if tmp != None: - probs_dicts[p_file] = tmp - - interactiveMenu(probs_dicts) - - -if __name__ == "__main__": - mainFunc() diff --git a/cobra/question_list.yml b/cobra/question_list.yml deleted file mode 100644 index c99da75..0000000 --- a/cobra/question_list.yml +++ /dev/null @@ -1,6 +0,0 @@ -- [2_problems, addThem] -- [2_problems, carmenFound] -- [2_problems, checkKeyExists] -- [2_problems, checkKeysExist] -- [2_problems, convTupleUnique] -- [2_problems, convTupleUniqueOrder] diff --git a/cobra/run_gunicorn_server.sh b/cobra/run_gunicorn_server.sh deleted file mode 100755 index 0a7ca96..0000000 --- a/cobra/run_gunicorn_server.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -if which gunicorn3; then - gunicorn3 cobra_server:app -else - gunicorn cobra_server:app -fi diff --git a/cobra/run_waitress_server.bat b/cobra/run_waitress_server.bat deleted file mode 100644 index 3e7a042..0000000 --- a/cobra/run_waitress_server.bat +++ /dev/null @@ -1 +0,0 @@ -waitress-serve --port=8000 cobra_server:app \ No newline at end of file diff --git a/cobra/translate_doctest.py b/cobra/translate_doctest.py deleted file mode 100755 index 08edf2a..0000000 --- a/cobra/translate_doctest.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python - -import sys -import yaml -import time -from base64 import b64encode - -#def getFolders(base_path): -# for item in os.path.list(base_path): -# ipath = "{}/{}".format(base_path, item) -# if os.path.isdir(): -# pass - - -def pull_probs(fpath): - lines = open(fpath).read().split('\n') - - probs = {'PRE': []} - - loc = 'PRE' - for line in lines[1:]: - if line.startswith('if __name__ =='): - break - elif loc != 'PRE' and not line.strip(): - continue - elif line.startswith('def ') and not line.startswith('def _'): - loc = line.split()[1].split('(')[0] - probs[loc] = [] - #print(loc, line) - probs[loc].append(line) - - pre = probs.pop('PRE') - return pre, probs - - -def grokProb(pre, prob_lines): - '''takes the text from the entire function definition of a problem - and solution and converts it into a dictoinary with all of the - parts needed to make a yml representation of it for the tool''' - assert(prob_lines[1].startswith(" '''")) - assert(len(prob_lines) > 8) - - # everything in pre gets executed in the library code block - func_name = prob_lines[0].split('def ')[1].split('(')[0] - prob = {'imports': '\n'.join(pre) } - prob['signature'] = '{} -> {}'.format(prob_lines[0], prob_lines[-1]) - #prob['name'] = definition.split()[1].split('(')[0] - prob['title'] = prob_lines[1].split("'")[3].strip() - - loc = 'text' - for line in prob_lines[2:]: - if line.strip().startswith('>>>'): - loc = 'posttest' - elif line.strip() in ("'''", '"""'): - loc = 'solution' - prob[loc] = [prob['signature'].split(' -> ')[0], ] - continue - - # initialize any missing keys - if loc not in prob: - prob[loc] = [] - - # cleanup specific data - if loc in ('text', ): - line = line.strip() - elif loc == 'posttest': - if line.startswith(' >>> ') or line.startswith(' ... '): - line = line[8:] - else: - line = line[4:] - - #print(prob['title'], loc, line) - prob[loc].append(line) - - # adapt test code around self.test_results - #test = [ n.strip()[4:] if n.startswith(' >>> ') else n.strip() - # for n in prob['posttest'] ] + [None,] - test = prob['posttest'] + [None,] - - # generate post test starting with function definition line - prob['posttest'] = [] - skipone = False - for n, line in enumerate(test[:-1]): - if skipone: - skipone = False - continue - nline = test[n+1] - if nline == 'True': - line = 'self.test_results.append({})'.format(line) - skipone = True - prob['posttest'].append(line) - - for loc in ('text', 'solution', 'posttest'): - prob[loc] = '\n'.join(prob[loc]) - #prob[loc] = prob[loc].replace('{}', '{{}}') - prob[loc] = prob[loc].replace('{', '{{') - prob[loc] = prob[loc].replace('}', '}}') - - print("FUNC_NAME:", func_name) - #time.sleep(10) - prob['posttest'] = prob['posttest'].replace(func_name, 'self._function') - # add any missing fields needed for the yml format... - prob['unittests'] = {} - prob['tags'] = '' - prob['setup'] = '' - prob['pretest'] = '' - prob['teardown'] = '' - - #for loc in ('solution', 'posttest'): - # prob[loc] = b64encode(prob[loc].encode('ascii')) - - return prob - - -def translate(pre, probs): - out = {} - for key, prob in probs.items(): - out[key] = grokProb(pre, prob) - return yaml.dump(out, default_flow_style=False) - -if __name__ == '__main__': - doctest_file = sys.argv[1] - yml_file = sys.argv[2] - print("DOCTEST FILE:", doctest_file) - print("YML FILE:", yml_file) - - PRE, probs = pull_probs(doctest_file) - print("PRE:") - print(PRE) - print("PROBS keys:", probs.keys()) - - yml_data = translate(PRE, probs) - - open(yml_file, 'w').write(yml_data) diff --git a/cobra/users/.gitkeep b/cobra/users/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/cobra/util/editor_utility.py b/cobra/util/editor_utility.py deleted file mode 100644 index 133f2bf..0000000 --- a/cobra/util/editor_utility.py +++ /dev/null @@ -1,67 +0,0 @@ -from util.utility import load_yml -from util.solution_checker import Solution -import colorama as cr - -cr.init() - -def get_question_labels(yml_file): - data = load_yml(yml_file) - return list(data.keys()) - -def print_question_data(yml_file, question_label): - question = load_yml(yml_file)[question_label] - - for key, value in question.items(): - try: - question[key] = value.decode('utf-8') - except AttributeError: - pass - - print('''\ -{h1}----==========={question_label}===========---- -{h2}imports (modules loaded before all tests)------------------------------------: -{p}{imports} -{h2}setup (script ran before all unit tests)-------------------------------------: -{p}{setup} -{h2}teardown (script ran after all unit tests)-----------------------------------: -{p}{teardown} -{h2}pretest (script ran before each unit test)-----------------------------------: -{p}{pretest} -{h2}posttest (script ran after each unit test)-----------------------------------: -{p}{posttest} -{h2}soulition (server accepted solution to question)-----------------------------: -{p}{solution} -{h2}text (text description of question)------------------------------------------: -{p}{text} -{h2}tags (tags to categorize question)-------------------------------------------: -{p}{tags} -{h2}unittests (parameters passed to soultion)------------------------------------:'''.format( - h1=cr.Fore.CYAN + cr.Back.MAGENTA, - h2=cr.Fore.WHITE + cr.Back.BLUE, - p=cr.Style.RESET_ALL, - question_label=question_label, - **question)) - print_unti_tests(yml_file, question_label) - print('''\ -{h5}RESULTS~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~: -{results}'''.format(h5=cr.Fore.RED + cr.Back.WHITE, results=check_solution(yml_file, question_label))) - -def print_unti_tests(yml_file, question_label): - try: - unittests = load_yml(yml_file)[question_label]['unittests'] - except KeyError: - unittests = {} - for label, parameters in sorted(unittests.items()): - print('{h3}{label}:{reset}'.format( - h3=cr.Style.BRIGHT + cr.Fore.YELLOW + cr.Back.BLUE, - label=label, reset=cr.Style.RESET_ALL)) - for index, parameter in enumerate(parameters, 1): - print('{h4}parameter{index}{reset}'.format( - h4=cr.Fore.YELLOW, index=index, reset=cr.Style.RESET_ALL)) - print(parameter) - -def check_solution(yml_file, question_label): - question = load_yml(yml_file)[question_label] - master_results = Solution(question) - master_results.run_solution() - return master_results.test_results \ No newline at end of file diff --git a/cobra/util/ptpython_config.py b/cobra/util/ptpython_config.py deleted file mode 100644 index 269c2e0..0000000 --- a/cobra/util/ptpython_config.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import unicode_literals -from prompt_toolkit.filters import ViInsertMode -from prompt_toolkit.key_binding.input_processor import KeyPress -from prompt_toolkit.keys import Keys -from pygments.token import Token - -from ptpython.layout import CompletionVisualisation - -__all__ = ( - 'configure', -) - - -def configure(repl): - # Show function signature (bool). - repl.show_signature = False - - # Show docstring (bool). - repl.show_docstring = True - - # Ask for confirmation on exit. - repl.confirm_exit = False - - # Enable input validation. (Don't try to execute when the input contains - # syntax errors.) - repl.enable_input_validation = True - - # Use this colorscheme for the code. - repl.use_code_colorscheme('monokai') - - # Show completions. (NONE, POP_UP, MULTI_COLUMN or TOOLBAR) - repl.completion_visualisation = CompletionVisualisation.POP_UP - - # When CompletionVisualisation.POP_UP has been chosen, use this - # scroll_offset in the completion menu. - repl.completion_menu_scroll_offset = 0 - - # Show line numbers (when the input contains multiple lines.) - repl.show_line_numbers = True - - # Show status bar. - repl.show_status_bar = False - - # When the sidebar is visible, also show the help text. - repl.show_sidebar_help = False - - # Highlight matching parethesis. - repl.highlight_matching_parenthesis = False - - # Vi mode. - repl.vi_mode = True - - # Don't insert a blank line after the output. - repl.insert_blank_line_after_output = False - - # Complete while typing. (Don't require tab before the - # completion menu is shown.) - repl.complete_while_typing = True \ No newline at end of file diff --git a/cobra/util/server_utility.py b/cobra/util/server_utility.py deleted file mode 100644 index 33d90bd..0000000 --- a/cobra/util/server_utility.py +++ /dev/null @@ -1,124 +0,0 @@ -from hashlib import sha256 -from random import randint -from uuid import uuid4 -from time import time -from util.utility import encode_message, load_yml, save_yml -from os.path import isfile -from os import listdir - -class User(): - def __init__(self, name): - self.name = name - self.filepath = 'users/{file}.yml'.format(file=self.name) - self.exists = False - if self.user_exists(): - self.userinfo = load_yml(self.filepath) - self.exists = True - else: - self.userinfo = {'name': self.name, 'hash': None, 'salt': None, 'sessionid': None, 'ip': None, 'timestamp': None, 'completed': [], 'seed': 0} - - def user_exists(self): - return isfile(self.filepath) - - def create_user(self, password, ip): - if self.user_exists(): - return False - salt = make_salt() - pwhash = hash_creds(password, salt) - self.update_user({'hash': pwhash, 'salt': salt, 'ip': ip, 'seed': self.new_seed()}) - self.exists = True - return True - - def update_user(self, data): - self.userinfo.update(data) - save_yml(self.filepath, self.userinfo) - - def get_completed(self): - return self.userinfo['completed'] - - def update_completed(self, item): - if item in self.userinfo['completed']: - pass - else: - self.update_user({'completed': self.get_completed() + [item]}) - - def check_completed(self, item): - if item in self.userinfo['completed']: - return True - else: - return False - - def create_new_session(self): - sessionid = uuid4().hex - salt = self.userinfo['ip'] - sessionhash = hash_creds(sessionid, salt) - self.update_user({'sessionid':sessionhash, 'timestamp': time()}) - return encode_message(sessionid) - - def check_session_id(self, id, ip): - # timeout session if not active for over an hour - if self.userinfo['timestamp'] + 3600 < time(): - return False - # check to see if id is valid for ip - elif self.userinfo['sessionid'] == hash_creds(id, ip): - return True - else: - return False - - def login_user(self, password, ip): - if self.userinfo['hash'] == hash_creds(password, self.userinfo['salt']): - self.update_user({'ip': ip}) - return self.create_new_session() - else: - return False - - def new_seed(self): - self.update_user({'seed': int(make_salt())}) - return self.get_seed() - - def get_seed(self): - return self.userinfo['seed'] - - -class Questions(): - def __init__(self): - self.questions = {filename.rstrip('.yml'): load_yml('enabled/{}'.format(filename)) for filename in listdir('enabled')} - - def get_lessons(self): - return list(self.questions.keys()) - - def get_questions(self, lesson): - return list(self.questions[lesson].keys()) - - def get_question(self, lesson, question_label): - return dict(self.questions[lesson][question_label]) - - -def get_users(): - return {filename.rsplit('.yml', maxsplit=1)[0]: User(filename.rsplit('.yml', maxsplit=1)[0]) - for filename in listdir('users')} - -def make_salt(): - return str(randint(0, 99999999)).zfill(8) - -def hash_creds(password, salt): - return sha256(password.encode('ascii') + salt.encode('ascii')).hexdigest() - -def update_history(item, user, solution, stats): - print(item) - yml_file = 'history/{0}__{1}.yml'.format(*item) - if isfile(yml_file): - history_data = load_yml(yml_file) - else: - history_data = {} - print(history_data) - history_data[user] = {'solution': solution, 'stats': stats} - save_yml(yml_file, history_data) - -def get_history(item): - yml_file = 'history/{0}__{1}.yml'.format(*item) - if isfile(yml_file): - history_data = load_yml(yml_file) - return history_data - else: - return False \ No newline at end of file diff --git a/cobra/util/solution_checker.py b/cobra/util/solution_checker.py deleted file mode 100644 index bd60c19..0000000 --- a/cobra/util/solution_checker.py +++ /dev/null @@ -1,150 +0,0 @@ -from re import findall -from timeit import default_timer -from sys import executable -from subprocess import Popen, PIPE -from tempfile import NamedTemporaryFile -from os import remove - -class Solution(): - def __init__(self, data, solution=None): - if 'seed' in data.keys(): - pass - else: - data.update({'seed':0}) - - for key, value in data.items(): - try: - data[key] = value.decode('utf-8') - except AttributeError: - pass - try: - data[key] = value.format(**data) - except KeyError: - pass - except AttributeError: - pass - - if solution: - self.solution = solution - else: - self.solution = data['solution'] - self._imports = data['imports'] - self._setup = data['setup'] - self._teardown = data['teardown'] - self._pretest = data['pretest'] - self._posttest = data['posttest'] - try: - self._unittests = data['unittests'] - except KeyError: - self._unittests = {} - - self._function = None - self.exception_raised = False - self.test_results = [] - self.time_to_execute = 0 - self.linecount, self.charcount = self.get_counts() - self.violations = self.check_codestyle() - if self.violations == '': - self.violationcount = 0 - else: - self.violationcount = len(self.violations.split('\n')) - - def check_codestyle(self): - '''Checks the solution for pep8 standards''' - solution_file = NamedTemporaryFile(delete=False, encoding='utf-8', mode='w', suffix='.py') - solution_file.write(self.solution) - solution_file.close() - flake = Popen([executable, '-m', 'flake8', - '--format=row %(row)d, col %(col)d: %(text)s', - '--disable-noqa', '--max-line-length=150', '--ignore=W292,E731', solution_file.name], - stdout=PIPE, stderr=PIPE) - out, error = flake.communicate() - if error: - print(error.decode('utf8')) - remove(solution_file.name) - return out.decode('utf-8').strip() - - def get_counts(self): - linecount = len(self.solution.split('\n')) - charcount = len(self.solution) - return linecount, charcount - - def run_solution(self): - '''Takes a text solution and yml data, and combines the two for execution''' - # we need to make imports global so they can be used inside of unit tests - # we will also run our setup scripts here since we want those imports in the setup namespace - scope = {} - try: - exec(self.solution, scope) - except Exception as e: - print('{}: {}'.format(type(e).__name__, e)) - exception_raised = True - return None - #scope.pop('__builtins__') - #self._function = [value for value in scope.values() if value != '__builtins__'][0] - for value in scope.values(): - if isinstance(value, dict): - continue - else: - self._function = value - # now that we have the function in our namespace we can run it against our unittests - self._run_tests() - # and finally we will run our teardown scripts - - def _run_tests(self): - '''Runs the solution against all unit tests''' - test_list = [] - - exec(self._imports) - exec(self._setup) - - # first implement any text case multipliers, extends the total number of tests - try: - for testname, values in sorted(self._unittests.items()): - for _ in range(self._loopcount(testname)): - test_list.append(values) - except AttributeError: - pass - - # run through all the unit tests if they exist - if test_list: - for test in test_list: - exec(self._pretest) # pretest script - arguments = [] - for argument in test: - #print(type(argument)) - arguments += [eval(str(argument))] - #arguments.append(argument) - #arguments = map(lambda argument: eval(argument, locals), test) # converts the yml test case string into the solution arguments - self._run_test(arguments) - exec(self._posttest) # posttest script - # if there are no unit tests we just run the function once - else: - exec(self._pretest) # pretest script - self._run_test([]) - exec(self._posttest) # posttest script - exec(self._teardown) - - def _loopcount(self, testname): - '''Checks for _x in test names and returns the number following''' - try: - loop = int(findall(r'_x(\d*)', testname)[0]) - except IndexError: - loop = 1 - return loop - - def _run_test(self, arguments): - ''' run test and save results, and time taken ''' - start_time = default_timer() - try: - #print(arguments) - #print(self._function) - result = self._function(*arguments) # the actual test is run here - except Exception as e: - print('{}: {}'.format(type(e).__name__, e)) - result = None - exception_raised = True - finally: - time_to_execute = default_timer() - start_time - self.test_results.append(result) - self.time_to_execute += time_to_execute diff --git a/cobra/util/utility.py b/cobra/util/utility.py deleted file mode 100644 index c8ddfbd..0000000 --- a/cobra/util/utility.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -from base64 import b64encode, b64decode -from hashlib import sha1, sha256 -from Crypto.Cipher import AES -from Crypto import Random -from random import randint -import yaml - -def cls(): - os.system('cls' if os.name=='nt' else 'clear') - -def encode_solution(soultion): - return b64encode(soultion.encode('ascii')).decode('utf-8') - -def encode_message(message, key=b'Sixteen byte key'): - key = key.zfill(16)[:16] - message = message.encode('ascii') - iv = Random.new().read(AES.block_size) - cipher = AES.new(key, AES.MODE_CFB, iv) - return b64encode(iv + cipher.encrypt(message)).decode('utf-8') - -def decode_message(b64coded_message, key=b'Sixteen byte key'): - key = key.zfill(16)[:16] - coded_message = b64decode(b64coded_message.encode('ascii')) - iv = coded_message[:16] - message = coded_message[16:] - cipher = AES.new(key, AES.MODE_CFB, iv) - return cipher.decrypt(message).decode('utf-8') - -def hash_results(results, token='0'): - hash = sha1(token.encode('ascii')) - for result in results: - hash.update(str(result).encode('ascii')) - return hash.hexdigest() - -def save_yml(filepath, data): - with open(filepath, 'w') as f: - yaml.dump(data, f, default_flow_style=False) - -def load_yml(filepath): - with open(filepath, 'r') as f: - data = yaml.load(f.read()) - return data \ No newline at end of file diff --git a/cobra/validate_yml.py b/cobra/validate_yml.py deleted file mode 100755 index 7f8b110..0000000 --- a/cobra/validate_yml.py +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env python - -import sys -from util import editor_utility as eu - -def validate(yml): - for label in eu.get_question_labels(yml): - eu.print_question_data(yml, label) - -if __name__ == '__main__': - if len(sys.argv) == 1: - #files = ['enabled/2_basic_python.yml', 'enabled/3_files_paths.yml'] - #files = ['enabled/test.yml'] - files = ['enabled/2_problems.yml'] - #files = ['enabled/3_problems.yml'] - #files = ['enabled/test.yml'] - else: - files = [sys.argv[1]] - - for file in files: - validate(file) diff --git a/images/circuitpython_logo.png b/images/circuitpython_logo.png new file mode 100644 index 0000000..6ce2879 Binary files /dev/null and b/images/circuitpython_logo.png differ diff --git a/images/multithreading-comparison.png b/images/multithreading-comparison.png new file mode 100644 index 0000000..354b6c7 Binary files /dev/null and b/images/multithreading-comparison.png differ diff --git a/images/multithreading-example1.png b/images/multithreading-example1.png new file mode 100644 index 0000000..114fef5 Binary files /dev/null and b/images/multithreading-example1.png differ diff --git a/images/multithreading-example2.png b/images/multithreading-example2.png new file mode 100644 index 0000000..1a71a74 Binary files /dev/null and b/images/multithreading-example2.png differ diff --git a/images/multithreading-gil.png b/images/multithreading-gil.png new file mode 100644 index 0000000..283a042 Binary files /dev/null and b/images/multithreading-gil.png differ diff --git a/images/pico_pin_reference.jpg b/images/pico_pin_reference.jpg new file mode 100644 index 0000000..29817ee Binary files /dev/null and b/images/pico_pin_reference.jpg differ diff --git a/images/pico_proto_bracket_rev0.stl b/images/pico_proto_bracket_rev0.stl new file mode 100644 index 0000000..68a54fe Binary files /dev/null and b/images/pico_proto_bracket_rev0.stl differ diff --git a/images/picow_ssd1306_adxl345.jpg b/images/picow_ssd1306_adxl345.jpg new file mode 100644 index 0000000..c283741 Binary files /dev/null and b/images/picow_ssd1306_adxl345.jpg differ diff --git a/images/threading_vs_processes.png b/images/threading_vs_processes.png new file mode 100644 index 0000000..b309596 Binary files /dev/null and b/images/threading_vs_processes.png differ diff --git a/legacy/0-coursework/README.md b/legacy/0-coursework/README.md new file mode 100644 index 0000000..bc56c4d --- /dev/null +++ b/legacy/0-coursework/README.md @@ -0,0 +1 @@ +Foo diff --git a/legacy/0-coursework/fireballs.ipynb b/legacy/0-coursework/fireballs.ipynb new file mode 100644 index 0000000..fc74538 --- /dev/null +++ b/legacy/0-coursework/fireballs.ipynb @@ -0,0 +1,396 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
date/time for peak brightnesslatitudelongitudealtitude(km)velocity(km/s)velocity in x directionvelocity in y directionvelocity in z directionradiated energytotal impact energy
02022-04-21 22:15:2855.5S68.9W28.41.270000e+01-4.20011.63.23.900000e+100.130
12022-04-12 21:59:128.2S57.8E23.82.060000e+01-19.300-6.33.65.200000e+100.170
22022-04-04 00:30:393.2S64.3W31.51.970000e+01-17.6005.3-7.22.700000e+100.095
32022-03-30 18:19:1845.9S171.4W74.02.000000e+100.073NaNNaNNaNNaN
42022-03-28 10:20:247.7S74.3E29.01.960000e+01-16.600-10.40.13.780000e+110.980
\n", + "
" + ], + "text/plain": [ + " date/time for peak brightness latitude longitude altitude(km) \\\n", + "0 2022-04-21 22:15:28 55.5S 68.9W 28.4 \n", + "1 2022-04-12 21:59:12 8.2S 57.8E 23.8 \n", + "2 2022-04-04 00:30:39 3.2S 64.3W 31.5 \n", + "3 2022-03-30 18:19:18 45.9S 171.4W 74.0 \n", + "4 2022-03-28 10:20:24 7.7S 74.3E 29.0 \n", + "\n", + " velocity(km/s) velocity in x direction velocity in y direction \\\n", + "0 1.270000e+01 -4.200 11.6 \n", + "1 2.060000e+01 -19.300 -6.3 \n", + "2 1.970000e+01 -17.600 5.3 \n", + "3 2.000000e+10 0.073 NaN \n", + "4 1.960000e+01 -16.600 -10.4 \n", + "\n", + " velocity in z direction radiated energy total impact energy \n", + "0 3.2 3.900000e+10 0.130 \n", + "1 3.6 5.200000e+10 0.170 \n", + "2 -7.2 2.700000e+10 0.095 \n", + "3 NaN NaN NaN \n", + "4 0.1 3.780000e+11 0.980 " + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "csv_file_name = 'nasas fireballs.csv'\n", + "nfb = pd.read_csv(csv_file_name)\n", + "nfb.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
latitudelongitude
055.5S68.9W
18.2S57.8E
23.2S64.3W
345.9S171.4W
47.7S74.3E
\n", + "
" + ], + "text/plain": [ + " latitude longitude\n", + "0 55.5S 68.9W\n", + "1 8.2S 57.8E\n", + "2 3.2S 64.3W\n", + "3 45.9S 171.4W\n", + "4 7.7S 74.3E" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nfb['date'] = pd.to_datetime(nfb['date/time for peak brightness'])\n", + "nfb[['latitude', 'longitude']].head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "'''ArithmeticErrorlatitude\tlongitude\n", + "0\t55.5S\t68.9W\n", + "1\t8.2S\t57.8E\n", + "2\t3.2S\t64.3W\n", + "3\t45.9S\t171.4W'''\n", + "def convert_latlon(s):\n", + " direction = s[-1]\n", + " num = float(s[:-1])\n", + " if direction in ['S', 'W']:\n", + " num *= -1\n", + " return num\n", + "nfb['lat_deg'] = nfb['latitude'].apply(lambda s: convert_latlon(s))\n", + "nfb['lon_deg'] = nfb['longitude'].apply(lambda s: convert_latlon(s))" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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d3eHk5MTHnnkEZ1tWsrLy1FUVKT2R0RERE2XWRriVlRUICMjA5GRkX+v2MYGkZGROHToEADA398fBw8exJ07d1BdXY309HR06dJF6zITExPh5uam+vP392/07SAiIiLLMUvQUlBQgOrqanh5ealN9/LyQm5uLgDggQcewMiRI9G7d2/07NkTHTp0wJgxY7Quc86cOZDL5aq/7OzsRt0GIiIisiyr6j30zjvv4J133jFoXgcHBzg4ODRyioiIiMhamKWkxcPDA7a2tsjLy1ObnpeXB29vb3MkgYiIiCTOLEGLvb09QkJCkJaWppqmUCiQlpaGfv36mSMJREREJHEmqx4qLi7G+fPnVZ8zMzNx/PhxuLu7IyAgAPHx8YiNjUVoaCjCwsKQlJSEkpISTJs2zVRJICIioibMZEHL0aNHERERofocHx8PAIiNjUVKSgpiYmKQn5+PuXPnIjc3F7169cKuXbvqNM4lIiIi0kQmmshbCYuKiuDm5ga5XA5XV1dLJ4eIiIgMYMz922pemEhERESkC4MWIiIikgQGLURERCQJDFqIiIhIEhi0EBERkSQwaCEiIiJJYNBCREREksCghYiIiCSBQQsRERFJAoMWIiIikgQGLURERCQJDFqIiIhIEhi0EBERkSQwaCEiIiJJYNBCREREksCghYiIiCSBQQsRERFJAoMWIiIikgQGLURERCQJDFqIiIhIEhi0EBERkSQwaCEiIiJJYNBCREREksCghYiIiCTBqoKWzMxMREREICgoCD169EBJSYmlk0RERERWws7SCahp6tSpWLBgAQYNGoSbN2/CwcHB0kkiIiIiK2E1Qctvv/2GZs2aYdCgQQAAd3d3C6eIiIiIrInJqof27duH0aNHw9fXFzKZDFu2bKkzT3JyMgIDA+Ho6Ijw8HAcPnxY9d25c+fQvHlzjB49Gn369MG7775rqqQRERFRE2CyoKWkpATBwcFITk7W+H1qairi4+Mxb948HDt2DMHBwYiKisL169cBAFVVVfjpp5/w0Ucf4dChQ9izZw/27NljquQRERGRxJksaBkxYgQWLFiA6Ohojd8vXboUcXFxmDZtGoKCgrB8+XI4Oztj9erVAAA/Pz+EhobC398fDg4OGDlyJI4fP651feXl5SgqKlL7IyIioqbLLL2HKioqkJGRgcjIyL9XbGODyMhIHDp0CADQ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nfb.plot(x='date', y='radiated energy', style='.', logy=True, title='Radiated energy vs date')" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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T+d99qKj5uIVRG2S+uYQHx+PJUuWID09HQDw9ddfo2vXrlizZo1Wj5/Zs2drfT4kJAS5ubmorKzUqsU4ceJEo/tev349amtr8e2332rVTOirOjc0km63bt1QWVmJhIQEo/tqTjnN2Y+punbtCuBGomtTtxkSEgLgRq1NfHy8uPz69esoLCxE//79tdbv27cvBgwYgFWrVqFLly44c+YM3nvvPZP2NWzYMPj7+yMnJwdDhgzB1q1bxaRoTe7u7khOTkZycjLq6uowYcIEvPHGG8jIyICLi4vebZt6reljzgjLxtb19PTU6UlWV1eH4uJirWUhISFiLYqmhtdRt27dAAA+Pj4Wu2aINDGnhdqsESNGICYmBosXLxYHmFPXFKhrBgBg79692LNnj9Znx4wZg+vXr2t1U66vrzfpZqhvH0qlEp988onOuu7u7nq7Jz/wwAPYs2cPvv/+e533Ll++jOvXrze7nObsx1Q+Pj4YMWIEPvjgA50bIwBcuHCh0W1ER0ejU6dOWL58udb+V61aJTZDNTRp0iT88MMPWLx4MTp16oTRo0ebVF4HBwfcd999WL9+PT777DNcv35dq2kIAC5evKj12tnZGeHh4RAEQavJpyFTrzV91GPVmNJ13di63bp108lL+vDDD3VqWsaMGYOff/4Z+/btE5dduHBBK1cIABITE+Hh4YF58+bpPXZTvl8iY1jTQm3aCy+8gPvvvx/Z2dl44oknMHbsWKxZswZJSUm46667UFBQgGXLliE8PByVlZXi58aNG4fBgwcjPT0dhYWFCA8Px5o1a0xKor3jjjvg7OyMcePG4R//+AcqKyuxfPly+Pj46NzIo6KisHTpUsydOxfdu3eHj48PRo4ciRdeeAHffvstxo4diylTpiAqKgpVVVU4cuQIvv76axQWFsLb27tZ5VSfH1P2Y46srCwMGTIE/fr1Q2pqKrp27YrS0lLs2bMHf/31F3799Vejn3d2dsacOXPwzDPPYOTIkXjggQdQWFiI7OxsdOvWTW/NwkMPPYQXX3wRa9euxZNPPil2vzZFcnIy3nvvPcyePRv9+vXT6S58xx13wM/PD4MHD4avry9+++03LFmyBHfddRc6dOhgcLumXmv6REVFAQBefvllPPjgg2jXrh3GjRund+C9yMhIODo6YsGCBVAqlZDL5eIYQY8//jieeOIJ3Hvv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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nfb.plot(x='altitude(km)', y='radiated energy', style='.', logy=True, title='Radiated energy vs altitude')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi0AAAHLCAYAAAAEHKhwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABZmklEQVR4nO3deVxU5eIG8GcAWZURRFkUxCXXFBTE3EUpLiYmWlmaIpbXW2kLPyu5t6vV1cgW45qUZiktWuRuuVRShmsqpKmlqWGSsroMsgjCvL8/uHNimIUZGJg58Hw/Hz45Z3nPOwNxHt7tKIQQAkREREQ2zs7aFSAiIiIyBUMLERERyQJDCxEREckCQwsRERHJAkMLERERyQJDCxEREckCQwsRERHJAkMLERERyQJDCxEREckCQwuRBV28eBEKhQIpKSnStpdeegkKhcJ6ldJDXz1J/hQKBV566aVGKZs/M2QLGFqo2UtJSYFCoZC+HBwc0LFjR8ycOROXL1+2dvWMevfdd3mTIJu1c+fORgtJRPowtFCL8corr+CTTz7BypUrERUVhU8//RSjRo3CrVu3GvW6L774IsrKyup1LkML2YrOnTujrKwM06dPl7bt3LkTL7/8shVrRS2Ng7UrQNRUoqKiEBoaCgB47LHH4OXlhaVLl2L79u148MEHG+26Dg4OcHDg/2qWUFJSAjc3N2tXo0VSKBRwdna2djWohWNLC7VYI0aMAABcuHBB2lZRUYGFCxciJCQESqUSbm5uGDFiBL7//nud82/cuIGZM2dCqVSibdu2iI2NxY0bN3SO0zemZe3atRgzZgw6dOgAJycn9OnTB++9957WMYGBgTh9+jR++OEHqWtr9OjRWtd/5pln4O/vDycnJ3Tv3h1Lly6FWq2uVz0NMeU6mvEOb775Jt5//31069YNTk5OGDRoEI4ePapT5pkzZ3D//ffD09MTzs7OCA0Nxfbt27WO0XTr/fDDD3jiiSfQoUMHdOrUSdqfnJyMrl27wsXFBWFhYdi3bx9Gjx4tfUbFxcVwc3PD008/rXP9P//8E/b29khMTNT7nm/fvg1PT0/ExcXp7CsqKoKzszPmz58vbXvnnXfQt29fuLq6wsPDA6GhoVi/fr3BzzQvLw8ODg56WynOnj0LhUKBFStWSNtM/V7r89NPPyEqKgru7u5o3bo1xo4di8OHD+scd+PGDTz77LMIDAyEk5MTOnXqhBkzZqCwsBCA7piWmTNnIjk5GQC0ul+FEAgMDMR9992nc41bt25BqVRizpw5ddabSB/++Uct1sWLFwEAHh4e0raioiJ88MEHePjhhzF79mzcvHkTH374ISIjI3HkyBEEBwcDAIQQuO+++7B//3784x//QO/evbFlyxbExsaadO333nsPffv2xYQJE+Dg4IAvv/wSTzzxBNRqNZ588kkAQFJSEubNm4fWrVvjX//6FwDA29sbAFBaWopRo0bh8uXLmDNnDgICAnDw4EEkJCQgJycHSUlJFqmnqdfRWL9+PW7evIk5c+ZAoVDg9ddfx6RJk/D777+jVatWAIDTp09j2LBh6NixIxYsWAA3Nzd88cUXmDhxIjZt2oSYmBitMp944gm0b98eCxcuRElJifT5zZ07FyNGjMCzzz6LixcvYuLEifDw8JCCTevWrRETE4PU1FQsW7YM9vb2UpmfffYZhBCYNm2a3vfdqlUrxMTEYPPmzVi1ahUcHR2lfVu3bkV5eTkeeughAMDq1avx1FNP4f7778fTTz+NW7du4eeff8aPP/6IqVOn6i3f29sbo0aNwhdffIFFixZp7UtNTYW9vT0eeOCBen0Pajp9+jRGjBgBd3d3PP/882jVqhVWrVqF0aNH44cffsDgwYMBVAe8ESNG4Ndff8WsWbMwcOBAFBYWYvv27fjzzz/h5eWlU/acOXNw5coVfPvtt/jkk0+k7QqFAo888ghef/11XLt2DZ6entK+L7/8EkVFRXjkkUcM1pnIKEHUzK1du1YAEHv27BEFBQUiOztbbNy4UbRv3144OTmJ7Oxs6djKykpRXl6udf7169eFt7e3mDVrlrRt69atAoB4/fXXtc4dMWKEACDWrl0rbV+0aJGo/b9aaWmpTj0jIyNF165dtbb17dtXjBo1SufY//znP8LNzU389ttvWtsXLFgg7O3txaVLl8yupz6mXicrK0sAEO3atRPXrl2Tjtu2bZsAIL788ktp29ixY0W/fv3ErVu3pG1qtVoMHTpU3HHHHdI2zfdt+PDhorKyUtpeXl4u2rVrJwYNGiRu374tbU9JSREAtD6vr7/+WgAQu3bt0qp///799X6uNWnOrVl3IYQYN26c1vfpvvvuE3379jValj6rVq0SAMTJkye1tvfp00eMGTNGem3q90AIIQCIRYsWSa8nTpwoHB0dxYULF6RtV65cEW3atBEjR46Uti1cuFAAEJs3b9app1qtFkL89T2u+TPz5JNP6vxsCyHE2bNnBQDx3nvvaW2fMGGCCAwMlMokMhe7h6jFiIiIQPv27eHv74/7778fbm5u2L59u1aXg729vfRXtVqtxrVr11BZWYnQ0FBkZmZKx+3cuRMODg54/PHHtc6dN2+eSXVxcXGR/q1SqVBYWIhRo0bh999/h0qlqvP8DRs2YMSIEfDw8EBhYaH0FRERgaqqKqSnp1uknqZeR2PKlClaLVeaLrjff/8dAHDt2jV89913ePDBB3Hz5k2pvKtXryIyMhLnzp3TmdE1e/ZsrVaSY8eO4erVq5g9e7bWWKFp06ZpXRuo/p77+flh3bp10rZTp07h559/rvOv/TFjxsDLywupqanStuvXr+Pbb7/FlClTpG1t27bFn3/+qbcbzJhJkybBwcFBq/xTp07hl19+0Srf3O+BRlVVFb755htMnDgRXbt2lbb7+vpi6tSp2L9/P4qKigAAmzZtQlBQkE4rF4B6Tdfv0aMHBg8erPW5X7t2Dbt27cK0adNsbgkAkg92D1GLkZycjB49ekClUmHNmjVIT0+Hk5OTznEfffQR3nrrLZw5cwa3b9+Wtnfp0kX69x9//AFfX1+0bt1a69yePXuaVJcDBw5g0aJFOHToEEpLS7X2qVQqKJVKo+efO3cOP//8M9q3b693f35+vkXqaep1NAICArRea0LE9evXAQDnz5+HEAL//ve/8e9//9tgmR07dpRe1/zcger3BADdu3fX2u7g4IDAwECtbXZ2dpg2bRree+89lJaWwtXVFevWrYOzs7PU/WKIg4MDJk+ejPXr16O8vBxOTk7YvHkzbt++rRUqXnjhBezZswdhYWHo3r077rnnHkydOhXDhg0zWr6XlxfGjh2LL774Av/5z38AVHcNOTg4YNKkSdJx5n4PNAoKClBaWqr3e927d2+o1WpkZ2ejb9++uHDhAiZPnmy0vuaaMWMG5s6diz/++AOdO3fGhg0bcPv2ba3ZR0TmYmihFiMsLEyaPTRx4kQMHz4cU6dOxdmzZ6Wb+qeffoqZM2di4sSJeO6559ChQwdpwGbNAbsNceHCBYwdOxa9evXCsmXL4O/vD0dHR+zcuRNvv/22SYMr1Wo17r77bjz//PN69/fo0cMidTX3OjVbRGoSQkjlAcD8+fMRGRmp99jaYaRmq1R9zJgxA2+88Qa2bt2Khx9+GOvXr8f48ePrDIYA8NBDD2HVqlXYtWsXJk6ciC+++AK9evVCUFCQdEzv3r1x9uxZfPXVV9i9ezc2bdqEd999FwsXLqxzOvBDDz2EuLg4HD9+HMHBwfjiiy8wduxYrTEkTfW9trSHHnoIzz77LNatW4d//vOf+PTTTxEaGmpyYCbSh6GFWiRNEAkPD8eKFSuwYMECAMDGjRvRtWtXbN68WasJu/Zgyc6dOyMtLQ3FxcVarRhnz56t89pffvklysvLsX37dq2WCX0zlAw1o3fr1g3FxcWIiIgweq2G1NOc65hK003RqlWrepfZuXNnANWtNuHh4dL2yspKXLx4Ef3799c6/s4778SAAQOwbt06dOrUCZcuXcI777xj0rVGjhwJX19fpKamYvjw4fjuu++kQdE1ubm5YcqUKZgyZQoqKiowadIkLFmyBAkJCUanCU+cOBFz5syRuoh+++03JCQkaB1T3+9B+/bt4erqqvd7febMGdjZ2cHf31+6xqlTp8wqHzDedeTp6Yl7770X69atw7Rp03DgwAGjg4aJTMExLdRijR49GmFhYUhKSpIWmNO0FGhaBgDgxx9/xKFDh7TOHTduHCorK7WmKVdVVZl0M9R3DZVKhbVr1+oc6+bmpnd68oMPPohDhw7h66+/1tl348YNVFZWNrie5lzHVB06dMDo0aOxatUq5OTk6OwvKCios4zQ0FC0a9cOq1ev1rr+unXrpG6o2qZPn45vvvkGSUlJaNeuHaKiokyqr52dHe6//358+eWX+OSTT1BZWanVNQQAV69e1Xrt6OiIPn36QAih1b2oT9u2bREZGYkvvvgCn3/+ORwdHTFx4kStY+r7PbC3t8c999yDbdu2STPlgOrp1uvXr8fw4cPh7u4OAJg8eTJOnDiBLVu26JRT8+e0Ns2aOYam0E+fPh2//PILnnvuOdjb20szrojqiy0t1KI999xzeOCBB5CSkoJ//OMfGD9+PDZv3oyYmBjce++9yMrKwsqVK9GnTx8UFxdL50VHR2PYsGFYsGABLl68iD59+mDz5s0mDaK955574OjoiOjoaMyZMwfFxcVYvXo1OnTooHMjDwkJwXvvvYfFixeje/fu6NChA8aMGYPnnnsO27dvx/jx4zFz5kyEhISgpKQEJ0+exMaNG3Hx4kV4eXk1qJ6az8eU65gjOTkZw4cPR79+/TB79mx07doVeXl5OHToEP7880+cOHHC6PmOjo546aWXMG/ePIwZMwYPPvggLl68iJSUFHTr1k3vX/9Tp07F888/jy1btuDxxx+Xpl+bYsqUKXjnnXewaNEi9OvXD71799baf88998DHxwfDhg2Dt7c3fv31V6xYsQL33nsv2rRpY1L5jzzyCN59911ERkaibdu2Wvsb8j1YvHgxvv32WwwfPhxPPPEEHBwcsGrVKpSXl+P111/XusbGjRvxwAMPYNasWQgJCcG1a9ewfft2rFy5Uqs7rKaQkBAAwFNPPYXIyEidYHLvvfeiXbt22LBhA6KiotChQ4c6Pw8io6w5dYmoKWimzh49elRnX1VVlejWrZvo1q2bqKysFGq1Wrz66quic+fOwsnJSQwYMEB89dVXIjY2VnTu3Fnr3KtXr4rp06cLd3d3oVQqxfTp08VPP/1k0pTn7du3i/79+wtnZ2cRGBgoli5dKtasWSMAiKysLOm43Nxcce+994o2bdroTOe9efOmSEhIEN27dxeOjo7Cy8tLDB06VLz55puioqLC7HoaYsp1NNNh33jjDZ3zUWsarhBCXLhwQcyYMUP4+PiIVq1aiY4dO4rx48eLjRs3SscY+74JIcTy5cul71NYWJg4cOCACAkJEX/729/0Hj9u3DgBQBw8eLDO91yTWq0W/v7+AoBYvHixzv5Vq1aJkSNHinbt2gknJyfRrVs38dxzzwmVSmVS+UVFRcLFxUUAEJ9++qneY0z9Xuv7rDMzM0VkZKRo3bq1cHV1FeHh4Xo/g6tXr4q5c+eKjh07CkdHR9GpUycRGxsrCgsLhRD6pzxXVlaKefPmifbt2wuFQqF3+vMTTzwhAIj169eb9HkQGaMQwkjbHxGRTKjVarRv3x6TJk3C6tWrdfbHxMTg5MmTOH/+vBVq13I9++yz+PDDD5GbmwtXV1drV4dkjmNaiEh2bt26pTPW4uOPP8a1a9e0HnWgkZOTgx07dnC6bRO7desWPv30U0yePJmBhSyCY1qISHYOHz6MZ599Fg888ADatWuHzMxMfPjhh7jzzju11l/JysrCgQMH8MEHH6BVq1Z85k0Tyc/Px549e7Bx40ZcvXpV7/OfiOqDoYWIZCcwMBD+/v5Yvny59HybGTNm4LXXXtN6TtAPP/yAuLg4BAQE4KOPPoKPj48Va91y/PLLL5g2bRo6dOiA5cuXS8/sImoojmkhIiIiWeCYFiIiIpIFhhYiIiKShWYzpkWtVuPKlSto06YNnyBKREQkE0II3Lx5E35+frCzM96W0mxCy5UrV6TnaBAREZG8ZGdno1OnTkaPaTahRbNcdnZ2tvQ8DSIiIrJtRUVF8Pf3N+mxF80mtGi6hNzd3RlaiIiIZMaUoR0ciEtERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCRERmyVGV4eCFQuSoyqxdFWphms2zh4iIqPGlHr2EhM0noRaAnQJInNQPUwYFWLta1EKwpYWIiEySoyqTAgsAqAXwz82n2OJCTYahhYiITJJVWCIFFo0qIXCxsNQ6FaIWh6GFiIhM0sXLDXYK7W32CgUCvVytUyFqcRhaiIjIJL5KFyRO6gd7RXVysVco8OqkO+GrdLFyzail4EBcIiIy2ZRBARjZoz0uFpYi0MuVgYWaFEMLERGZxVfpwrBCVsHuISIiIpIFhhYiIiKSBauElpiYGHh4eOD+++/X2VdaWorOnTtj/vz5VqgZERER2SqrhJann34aH3/8sd59S5YswV133dXENSIiIiJbZ5XQMnr0aLRp00Zn+7lz53DmzBlERUVZoVZERERky8wOLenp6YiOjoafnx8UCgW2bt2qc0xycjICAwPh7OyMwYMH48iRIyaVPX/+fCQmJppbJSIiImoBzA4tJSUlCAoKQnJyst79qampiI+Px6JFi5CZmYmgoCBERkYiPz/faLnbtm1Djx490KNHD3OrRERERC2A2eu0REVFGe2+WbZsGWbPno24uDgAwMqVK7Fjxw6sWbMGCxYsMHje4cOH8fnnn2PDhg0oLi7G7du34e7ujoULF+o9vry8HOXl5dLroqIic98KERERyYhFx7RUVFQgIyMDERERf13Azg4RERE4dOiQ0XMTExORnZ2Nixcv4s0338Ts2bMNBhbN8UqlUvry9/e32PsgIiIi22PR0FJYWIiqqip4e3trbff29kZubq70OiIiAg888AB27tyJTp061Rlo9ElISIBKpZK+srOzG1x/IiIisl1WWcZ/z549RvfPnDmz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6NAhAIC/vz8OHjyIW7duoaqqCnv37kXPnj0NlpmQkACVSiV9ZWdnN/r7ICIiIutpkoG4hYWFqKqqgre3t9Z2b29vnDlzBgBw1113Ydy4cRgwYADs7OwwduxYTJgwwWCZTk5OcHJyatR6ExERke2wqdlDS5YswZIlS6xdDSIiIrJBTdI95OXlBXt7e+Tl5Wltz8vLg4+PT1NUgYiIiGSuSUKLo6MjQkJCkJaWJm1Tq9VIS0vDkCFDmqIKREREJHMW6x4qLi7G+fPnpddZWVk4fvw4PD09ERAQgPj4eMTGxiI0NBRhYWFISkpCSUkJ4uLiLFUFIiIiasYsFlqOHTuG8PBw6XV8fDwAIDY2FikpKZgyZQoKCgqwcOFC5ObmIjg4GLt379YZnEtERESkj0I0k6cSFhUVQalUQqVSwd3d3drVISIiIhOYc/+2mQcmEhERERnD0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESywNBCREREssDQQkRERLLA0EJERESyYFOhJSsrC+Hh4ejTpw/69euHkpISa1eJiIiIbISDtStQ08yZM7F48WKMGDEC165dg5OTk7WrRERERDbCZkLL6dOn0apVK4wYMQIA4OnpaeUaERERkS2xWPdQeno6oqOj4efnB4VCga1bt+ock5ycjMDAQDg7O2Pw4ME4cuSItO/cuXNo3bo1oqOjMXDgQLz66quWqhoRERE1AxYLLSUlJQgKCkJycrLe/ampqYiPj8eiRYuQmZmJoKAgREZGIj8/HwBQWVmJffv24d1338WhQ4fw7bff4ttvvzV4vfLychQVFWl9ERERUfNlsdASFRWFxYsXIyYmRu/+ZcuWYfbs2YiLi0OfPn2wcuVKuLq6Ys2aNQCAjh07IjQ0FP7+/nBycsK4ceNw/Phxg9dLTEyEUqmUvvz9/S31VoiIiMgGNcnsoYqKCmRkZCAiIuKvC9vZISIiAocOHQIADBo0CPn5+bh+/TrUajXS09PRu3dv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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "nfb.plot(x='velocity(km/s)', y='radiated energy', style='.', logy=True, logx=True, title='Radiated energy vs velocity')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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REREpFaYvBAREZFaYfJCREREaoXJCxEREakVJi9ERESkVpi8EBERkVph8kJERERqhckLERERqRUmL0RERKRWmLwQERGRWmHyQkRERGqFyQsRERGpFSYvREREpFaYvBAREZFaYfJCREREaoXJCxEREakVJi9ERESkVpi8EBERkVph8kJERERqhckLERERqRUmL0RERKRWmLwQERGRWimS5GXJkiWwtraGtrY2GjVqhHPnzimtu2rVKjRt2hTGxsYwNjaGu7t7vvWJiIioZFF58rJ582YEBgZiypQpuHjxIpycnODh4YFnz54prB8dHY3evXvj2LFjOH36NCpVqoTvv/8ejx8/VnWoREREpAZUnrzMmzcPAQEB6N+/P2rUqIHly5dDV1cXa9asUVh/w4YN+Omnn+Ds7Izq1atj9erVyM3NRVRUlKpDJSIiIjWg0uQlKysLFy5cgLu7+7831NCAu7s7Tp8+/UXXSE9Px/v372FiYqLweGZmJlJTU2VeRERE9O1SafLy4sUL5OTkoHz58jLl5cuXR3Jy8hddY9y4cbC0tJRJgD4WHBwMQ0ND6atSpUr/OW4iIiIqvor1bKNff/0VmzZtwo4dO6Ctra2wzoQJE5CSkiJ9PXz4sIijJCIioqJUWpUXNzU1RalSpfD06VOZ8qdPn6JChQr5njt37lz8+uuvOHLkCOrUqaO0npaWFrS0tAolXiIiIir+VNrzoqmpiXr16skMts0bfOvq6qr0vDlz5mD69OmIjIxE/fr1VRkiERERqRmV9rwAQGBgIHx8fFC/fn00bNgQoaGhePv2Lfr37w8A6NevH6ysrBAcHAwAmD17NiZPnoyIiAhYW1tLx8bo6elBT09P1eESERFRMafy5KVnz554/vw5Jk+ejOTkZDg7OyMyMlI6iPfBgwfQ0Pi3A2jZsmXIyspCt27dZK4zZcoUTJ06VdXhEhERUTGn8uQFAIYMGYIhQ4YoPBYdHS3z/t69e6oPiIiIiNRWsZ5tRERERPQpJi9ERESkVpi8EBERkVph8kJERERqhckLERERqRUmL0RERKRWmLwQERGRWmHyQkRERGqFyQsRERGpFSYvREREpFaYvBAREZFaYfJCREREaoXJCxEREamVItlVmkqu2mtry5Vd9bkqQiQim2ooX2ZTuejjICL6BrDnhYiIiNQKkxciIiJSK0xeiIiI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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "correlations = nfb.corr(numeric_only=True)\n", + "correlations.plot(kind='bar', title='Correlations')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/legacy/0-coursework/grades.csv b/legacy/0-coursework/grades.csv new file mode 100644 index 0000000..6ef211c --- /dev/null +++ b/legacy/0-coursework/grades.csv @@ -0,0 +1,2 @@ +name,math,science,history +Stanley,85,90,92Casey,75,80,85Taylor,95,100,100 \ No newline at end of file diff --git a/legacy/0-coursework/nasas fireballs.csv b/legacy/0-coursework/nasas fireballs.csv new file mode 100644 index 0000000..9814ea4 --- /dev/null +++ b/legacy/0-coursework/nasas fireballs.csv @@ -0,0 +1,916 @@ +date/time for peak brightness,latitude,longitude,altitude(km),velocity(km/s),velocity in x direction,velocity in y direction,velocity in z direction,radiated energy,total impact energy +2022-04-21 22:15:28,55.5S,68.9W,28.4,12.7,-4.2,11.6,3.2,3.9e10,0.13 +2022-04-12 21:59:12,8.2S,57.8E,23.8,20.6,-19.3,-6.3,3.6,5.2e10,0.17 +2022-04-04 00:30:39,3.2S,64.3W,31.5,19.7,-17.6,5.3,-7.2,2.7e10,0.095 +2022-03-30 18:19:18,45.9S,171.4W,74.0,2.0e10,0.073,,,, +2022-03-28 10:20:24,7.7S,74.3E,29.0,19.6,-16.6,-10.4,0.1,37.8e10,0.98 +2022-03-24 03:43:42,1.9N,20.6W,56.7,18.2,-12.4,11.4,6.9,7.6e10,0.24 +2022-03-11 21:22:46,70.0N,9.1W,33.3,17.2,-11.5,-5.3,-11.7,185.1e10,4 +2022-03-06 15:06:15,4.1S,99.5W,2.0e10,0.073,,,,, +2022-03-03 00:03:03,50.4S,45.9E,72.0,2.1e10,0.076,,,, +2022-02-17 12:08:06,33.5N,38.9W,41.0,2.7e10,0.095,,,, +2022-02-17 03:53:24,5.4N,56.4E,32.4,21.5,-4.4,-19.6,-7.7,6.5e10,0.21 +2022-02-07 20:06:26,28.7S,11.4E,26.5,13.1,-8.9,-7.3,-6.3,348.0e10,7 +2022-02-03 19:50:40,13.3S,142.2E,36.0,22.8,17.6,9.7,-10.8,15.2e10,0.44 +2022-01-30 02:06:18,50.0N,38.0W,36.6,20.0,-10.8,16.8,1.0,5.4e10,0.18 +2022-01-28 05:04:45,4.5S,73.9W,37.0,34.1e10,0.9,,,, +2022-01-11 03:33:13,58.4S,160.2W,40.8,22.8,-2.5,5.3,22.0,126.4e10,2.9 +2022-01-01 20:23:04,66.1N,152.6W,35.5,14.5e10,0.42,,,, +2021-12-29 03:15:35,69.7S,115.0E,44,22.0,7.4,-8.6,18.8,2.0e10,0.073 +2021-12-23 21:27:58,4.9S,29.6W,37,2.1e10,0.076,,,, +2021-12-20 23:15:55,62.7N,60.3E,56,18.2,10.3,-7.1,-13.2,3.2e10,0.11 +2021-12-10 01:19:06,47.5S,172.6E,27.5,5.0e10,0.16,,,, +2021-11-28 18:06:50,32.6N,113.5E,38.4,19.7,0.2,-2.2,-19.6,4.0e10,0.13 +2021-11-17 15:53:21,6.8S,119.1E,35.0,23.0,7.0,-18.3,-12.0,2.4e10,0.086 +2021-11-08 05:28:28,33.8S,7.7W,36,3.3e10,0.11,,,, +2021-10-28 09:10:30,4.1S,138.7W,35.2,3.0e10,0.1,,,, +2021-10-21 10:32:02,51.5N,51.4E,30,15.9,-14.1,-7.0,-1.9,3.7e10,0.13 +2021-10-20 08:41:50,13.8N,140.4W,28,6.0e10,0.19,,,, +2021-10-20 00:43:57,59.0N,154.3E,31.4,27.5,12.9,4.2,-23.9,2.0e10,0.073 +2021-09-29 10:50:59,53.9N,148.0W,28.0,21.2,-3.5,-9.0,-18.9,13.7e10,0.4 +2021-09-06 17:55:42,2.1S,111.8W,26.0,13.6,-4.4,6.9,10.9,3.1e10,0.11 +2021-07-30 08:06:34,7.8S,90.1E,63.0,14.6e10,0.42,,,, +2021-07-29 13:19:57,42.4N,98.4E,26.4,14.7,-1.6,-11.9,-8.4,3.7e10,0.13 +2021-07-07 13:41:14,3.3e10,0.11,,,,,,, +2021-07-05 03:46:24,44.3N,164.2W,43.4,15.7,0.7,15.7,-0.5,74e10,1.8 +2021-06-09 05:43:59,17.9S,55.3W,2.3e10,0.082,,,,, +2021-05-16 15:51:08,52.1S,171.2W,37.0,3.8e10,0.13,,,, +2021-05-06 05:54:27,34.7S,141.0E,31.0,26.6,9.6,-24.4,-4.6,2.1e10,0.076 +2021-05-02 14:12:49,12.3N,43.4W,2.5e10,0.089,,,,, +2021-04-13 02:16:47,26.8N,79.1W,44.4,14.1,-2.8,12.6,5.6,2.1e10,0.076 +2021-04-02 15:52:58,71.2N,106.7E,40.0,-8.9,6.3,-9.0,13.7e10,0.4,14.1 +2021-03-06 08:43:06,48.6S,90.4E,31.1,12.7,-4.7,12.0,14.1e10,0.41,18.1 +2021-03-05 13:50:01,81.1S,141.1E,32.5,10.1,-8.4,19.2,3.9e10,0.13,23.3 +2021-02-28 03:47:37,9.2N,64.1W,2.8e10,0.098,,,,, +2021-02-09 23:27:29,75.8N,92.8W,31.0,-5.2,6.3,-10.3,3.0e10,0.1,13.1 +2021-02-02 10:03:21,48.7N,80.1E,20,4.0,-6.7,-10.1,3.1e10,0.11,12.8 +2021-01-31 02:59:39,5.3N,115.2E,39.4,14.0,-5.8,1.7,26.7e10,0.72,15.2 +2021-01-29 16:12:47,38.8N,51.3W,30.0,-14.2,1.9,-.6,7.7e10,0.24,14.3 +2021-01-25 03:01:37,38.5N,47.6W,19.1,7.5e10,0.23,,,, +2021-01-24 07:33:43,45.0S,95.5E,37.5,13.3,-3.7,13.3,6.1e10,0.2,19.2 +2020-12-29 20:32:22,14.9N,158.2W,33.0,-3.0,10.2,-9.7,4.9e10,0.16,14.4 +2020-12-28 17:27:53,36.8N,54.7W,28.3,1.5,3.5,-14.7,5.7e10,0.18,15.2 +2020-12-22 23:23:33,31.9N,96.2E,35.5,13.6,-2.6,5.9,-12.1,489.8e10,9.5 +2020-11-28 16:34:11,33.3N,135.1E,28.1,19.6,1.8,-16.5,-10.4,2.6e10,0.092 +2020-11-25 12:20:50,30.5S,81.0W,2.1e10,0.076,,,,, +2020-11-07 21:27:04,59.8N,16.8E,22.3,16.7,-10.8,1.2,-12.7,11.1e10,0.33 +2020-10-26 15:09:10,5.9S,160.4E,28.5,17.6,10.9,-13.8,-0.1,11.4e10,0.34 +2020-10-23 20:51:39,30.0N,71.9W,48.0,8.0e10,0.25,,,, +2020-10-22 17:39:33,22.0N,133.5W,40.0,17.6,-9.4,14.1,-4.9,4.4e10,0.15 +2020-10-21 18:57:33,12.9N,150.2W,2.2e10,0.079,,,,, +2020-10-21 06:38:49,29.7S,93.9W,39,2.7e10,0.095,,,, +2020-10-19 07:05:47,48.6N,93.9E,40.7,2.1e10,0.076,,,, +2020-10-18 10:52:43,11.4S,135.8W,36.0,16.4,15.6,1.5,4.9,3.6e10,0.12 +2020-09-18 08:05:27,2.4N,169.7W,46.0,11.7,10.2,2.9,-4.9,4.1e10,0.14 +2020-08-30 16:08:22,26.0N,133.5E,27.8,23.4,7.8,-21.7,3.7,6.4e10,0.2 +2020-08-02 16:36:25,35.1S,34.2W,38.0,11.1,0.5,6.0,9.3,7.4e10,0.23 +2020-07-22 02:55:40,20.0S,103.8W,36.0,2.2e10,0.079,,,, +2020-07-20 21:25:09,51.8S,11.2W,31.6,14.1,-2.9,-1.0,-13.8,5.0e10,0.16 +2020-07-12 07:50:32,48.7S,74.0E,29.4,18.3,-5.0,-13.0,-11.9,7.5e10,0.23 +2020-05-27 17:30:18,40.8N,41.7E,29.3,14.9,-6.0,-7.3,-11.5,5.7e10,0.18 +2020-05-18 01:11:09,38.7S,77.2E,25,16.2e10,0.46,,,, +2020-05-12 23:22:56,15.9N,174.2E,8.3e10,0.26,,,,, +2020-05-09 09:37:15,7.2N,44.2W,52.5,4.1e10,0.14,,,, +2020-05-09 02:56:11,44.8N,131.0W,31.2,14.5,-13.0,-4.0,-5.0,4.1e10,0.14 +2020-04-28 05:43:17,20.1N,109.4W,2.1e10,0.076,,,,, +2020-04-18 13:08:38,12.5N,49.8W,2.7e10,0.095,,,,, +2020-04-14 11:11:16,65.6S,45.6W,2.0e10,0.073,,,,, +2020-03-26 23:27:56,38.3S,23.5E,26.5,20.7,-10,3.2,17.8,12.4e10,0.37 +2020-03-23 16:51:51,24.4S,67.9W,25,13.3e10,0.39,,,, +2020-03-22 06:44:29,2.5e10,0.089,,,,,,, +2020-03-04 20:25:59,53.3S,90.8E,24.3,19.8,-5.2,2.2,19.0,39.4e10,1 +2020-02-28 09:30:34,45.7N,15.1E,34.5,21.5,-18.2,-11.3,-2.1,11.5e10,0.34 +2020-02-24 22:21:28,3.6N,96.0W,2.0e10,0.073,,,,, +2020-02-10 23:48:17,28.2N,76.7E,41.7,31.7,-27.8,-14.3,-5.2,2.7e10,0.095 +2020-01-27 05:39:15,30.4N,1.5E,32.5,19.8,-2.0,-16.6,-10.6,4.4e10,0.15 +2020-01-24 11:13:31,28.0N,35.8W,32.0,21.2,-18.6,-9.0,-4.7,2.6e10,0.092 +2020-01-21 20:07:44,33.1N,34.3E,43.3,27.4,-7.5,-23.5,-11.9,2.8e10,0.098 +2020-01-17 21:29:49,19.4N,66.0W,14.5,15.5,-13.2,8.1,1.2,9.7e10,0.29 +2020-01-16 09:31:42,71.7S,116.4W,27.8,12.9,9.8,-4.5,7.0,5.9e10,0.19 +2020-01-15 06:31:39,23.7S,125.2W,31.5,19.6e10,0.55,,,, +2020-01-06 11:03:50,70.4S,17.5W,4.5e10,0.15,,,,, +2019-12-21 14:30:52,56.5N,147.6W,35.5,22.2,14.9,-8.1,-14.3,6.5e10,0.21 +2019-12-11 01:19:11,47.7N,161.7E,37,17.8,13.7,-10.9,-3.3,3.9e10,0.13 +2019-12-06 10:19:57,3.3S,37.7W,19.5,4.6e10,0.15,,,, +2019-12-03 06:46:27,5.6N,52.2W,61.5,4.2e10,0.14,,,, +2019-11-28 20:30:54,35.7N,31.7W,35,13.0,-11.6,-2.5,-5.4,2.7e10,0.095 +2019-11-28 13:22:10,2.6e10,0.092,,,,,,, +2019-11-28 11:55:02,22.1S,25.7E,22.5,24.7,-22.8,-5.5,7.6,2.5e10,0.089 +2019-11-05 11:24:51,10.4S,143.3W,38.0,27.4,5.2,12.3,23.9,11.0e10,0.33 +2019-10-22 22:21:15,12.0N,76.0W,40.7,2.7e10,0.095,,,, +2019-10-10 16:16:36,44.3N,122.9E,47.3,14.1,1.5,-12.9,-5.4,20.6e10,0.57 +2019-09-28 10:40:20,12.5S,107.2W,52,20.4,-10.1,11.2,13.7,2.3e10,0.082 +2019-09-27 13:35:46,25.7N,28.4W,3.4e10,0.12,,,,, +2019-09-14 12:39:34,38.6S,33.5W,38,15.9,-12.9,8.1,4.6,10.9e10,0.33 +2019-09-13 02:02:04,18.6S,126.9E,27.4,13.5,5.2,-8.1,9.5,4.2e10,0.14 +2019-09-12 12:49:48,54.5N,9.2E,42,18.5,-18.1,-0.4,3.7,16.9e10,0.48 +2019-09-12 02:34:58,24.9N,47.8W,30.6,17.2,-11.7,11.7,4.6,5.9e10,0.19 +2019-08-24 12:02:59,21.9N,130.4W,39.8,13.4,11.1,-5.2,5.4,4.0e10,0.13 +2019-08-22 21:47:29,24.4S,92.9W,30.2,2.0e10,0.073,,,, +2019-08-16 20:36:05,38.9N,7.0E,36.0,14.9,-3.9,4.0,-13.8,2.5e10,0.089 +2019-07-23 20:42:58,44.6N,147.6W,30.6,16.1,1.5,15.1,-5.5,25.5e10,0.69 +2019-06-30 16:52:58,21.2N,129.5W,59.0,42.3,25.2,31.2,-13.3,3.2e10,0.11 +2019-06-30 08:11:29,2.5S,168.7E,2.1e10,0.076,,,,, +2019-06-22 21:25:48,14.9N,66.2W,25.0,14.9,-13.4,6.0,2.5,294.7e10,6 +2019-06-20 06:07:32,7.3N,67.6W,37.0,2.8e10,0.098,,,, +2019-05-26 10:07:55,56.6N,25.3W,24.4,17.5,3.8,-5.8,16.1,4.2e10,0.14 +2019-05-25 06:44:04,19.2S,89.4E,29.2,15.8,0.2,-15.7,2.1,4.9e10,0.16 +2019-05-22 15:16:49,10.8N,37.3W,32.6,9.5e10,0.29,,,, +2019-05-21 13:21:35,38.8S,137.5E,31.5,11.5,4.4,-8.5,6.4,65.6e10,1.6 +2019-05-19 14:47:03,23.6S,132.8E,33.3,15.2,7.3,-12.2,5.3,3.3e10,0.11 +2019-05-12 22:41:48,6.2N,57.1W,2.1e10,0.076,,,,, +2019-05-04 15:35:46,28.4N,88.3W,26.5,2.2e10,0.079,,,, +2019-04-22 21:42:11,48.8S,67.8E,33.3,11.4,3.4,-4.2,10.0,12.4e10,0.37 +2019-04-14 17:54:33,18.3N,74.6W,30.6,15.9,-2.5,5.9,-14.6,2.9e10,0.1 +2019-04-06 11:59:09,56.5N,94.9E,41.5,18.1,6.2,11.1,-12.9,7.0e10,0.22 +2019-04-04 22:19:01,35.3N,93.9W,2.8e10,0.098,,,,, +2019-03-27 12:50:34,41.8S,7.4W,2.2e10,0.079,,,,, +2019-03-19 02:06:39,24.0S,140.3E,28.7,16.2,10.2,0.4,12.6,2.0e10,0.073 +2019-03-15 12:26:56,63.7N,95.7E,31.5,14.4,5.4,-13.2,1.7,4.6e10,0.15 +2019-02-18 10:00:43,15.5S,25.3E,26,20.8,-16.6,-12.6,0.6,195.8e10,4.2 +2019-02-01 18:17:10,22.5N,83.8W,23.7,16.3,-2.4,13.6,8.7,57.9e10,1.4 +2019-01-29 20:47:20,2.5e10,0.089,,,,,,, +2019-01-22 09:18:01,18.0N,6.5E,42.5,11.6,-8.6,-5.9,5.0,3.6e10,0.12 +2018-12-23 23:38:03,47.5S,174.4W,31.8,16.5,9.9,7.6,10.8,8.9e10,0.27 +2018-12-18 23:48:20,56.9N,172.4E,26.0,13.6,6.3,-3.0,-31.2,3.13e13,49 +2018-11-20 17:30:28,25.3N,6.7W,27.4,17.4,-10.1,13.9,3.0,42.2e10,1.1 +2018-11-17 21:48:24,47.3N,172.9W,32.5,19.1,7.6,17.3,-2.7,22.0e10,0.61 +2018-11-15 08:02:44,42N,57W,2.0e10,0.073,,,,, +2018-11-14 04:03:47,37.6S,83.5E,37,3.8e10,0.13,,,, +2018-10-24 21:19:07,6.7S,148.6W,33.3,4.7e10,0.16,,,, +2018-10-22 07:11:03,2.6e10,0.092,,,,,,, +2018-10-05 00:27:04,39.8S,31.7W,31.5,14.7,-13.2,-6.5,-0.4,3.8e10,0.13 +2018-09-25 14:10:33,23.5S,56.8E,33.0,16.5,-16.2,2.8,0.6,80.6e10,1.9 +2018-09-25 00:16:59,34.3S,44.9E,40.7,12.5,-11.0,2.5,-5.5,5.3e10,0.17 +2018-09-20 18:29:03,67.3S,75.1E,11.1,-5.6,-7.9,5.5,8.3e10,0.26, +2018-09-17 01:08:02,6.8S,27.8W,15.0e10,0.43,,,,, +2018-09-13 00:51:21,42.5N,50.1W,4.2e10,0.14,,,,, +2018-08-27 04:36:45,1.7S,141.4E,33.0,16.1,9.8,-9.6,-8.4,2.4e10,0.086 +2018-08-21 12:26:14,39.2S,162.9W,37.0,2.2e10,0.079,,,, +2018-07-27 09:35:14,58.8S,105.8E,32.0,10.5e10,0.32,,,, +2018-07-25 21:55:26,76.9N,69.0W,43.3,24.4,20.4,12.9,-3.8,87.7e10,2.1 +2018-07-17 15:17:37,82.5N,136.7W,21.1e10,0.59,,,,, +2018-06-26 17:51:53,32.0N,12.1E,63.0,14.1,-10.0,-1.0,-9.9,2.9e10,0.1 +2018-06-21 01:16:20,52.8N,38.1E,27.2,14.4,-8.9,-4.3,-10.5,122.4e10,2.8 +2018-06-02 16:44:12,21.2S,23.3E,28.7,16.9,0.9,-16.4,3.9,37.5e10,0.98 +2018-05-12 03:26:46,6.5S,173.7E,34,19.3e10,0.54,,,, +2018-05-08 02:27:13,32N,60.7W,7.3e10,0.23,,,,, +2018-05-03 07:23:59,46.9N,7.5W,39,11.5,1.3,-2.1,-11.2,3.8e10,0.13 +2018-04-30 13:17:57,45.5S,1.4W,34,13.1,8.7,-9.5,2.5,3.0e10,0.1 +2018-04-21 12:06:04,59.0S,45.8E,28.2,14.6,7.1,-4.6,11.9,3.6e10,0.12 +2018-04-19 14:02:27,7.5N,3.6E,30,20.9,-9.1,-2.5,18.6,7.2e10,0.23 +2018-04-19 13:39:38,22.2S,72.6E,31.5,10.9,-5.9,-9.1,1.4,51.2e10,1.3 +2018-04-07 03:05:09,72.4N,78.7W,31.5,8.6e10,0.27,,,, +2018-02-21 01:28:03,13.5S,37.1W,31.5,13.1,-0.9,13.1,-0.4,7.1e10,0.22 +2018-02-15 13:38:22,43.8S,1.1W,50.7,2.7e10,0.095,,,, +2018-02-12 02:15:19,15.9S,58.9W,3.9e10,0.13,,,,, +2018-02-08 22:21:41,42.9N,179.7E,43.5,25.9e10,0.7,,,, +2018-02-01 12:21:36,19.4S,104.3E,37.0,16.5,8.1,-8.4,-11.7,19.0e10,0.53 +2018-01-22 22:06:30,14.0N,17.4W,3.2e10,0.11,,,,, +2018-01-15 02:18:38,52.0S,57.2E,43.6,23.7,18.6,-12.1,8.4,19.9e10,0.56 +2018-01-06 21:24:22,55.8N,52.5E,26.0,21.0,0.8,2.2,-20.9,2.8e10,0.098 +2018-01-06 18:24:28,39.5S,12.8E,26.0,3.6e10,0.12,,,, +2017-12-31 09:36:10,63.5S,101.3W,64.5,4.4e10,0.15,,,, +2017-12-29 12:47:31,14.6N,49.5W,38.0,11.0e10,0.33,,,, +2017-12-28 17:45:44,11.4e10,0.34,,,,,,, +2017-12-15 13:14:37,60.2N,170.0E,20.0,31.4,27.8,-4.7,-13.9,311.4e10,6.4 +2017-11-19 04:17:32,24.2S,135.0E,33.3,11.4,6.7,-3.4,8.6,2.8e10,0.098 +2017-10-26 22:05:35,21.3S,177.6E,42.5,55.8e10,1.4,,,, +2017-10-23 15:31:23,28.8N,44.6E,35.4,16.7,-5.7,-10.7,-11.5,2.4e10,0.086 +2017-10-15 04:33:16,65.2S,128.2E,24.1,15.9,9.5,-8.3,9.7,3.3e10,0.11 +2017-10-09 12:51:48,18.3S,64.1W,3.0e10,0.1,,,,, +2017-10-04 12:07:05,28.1N,99.4E,37.0,14.6,-8.5,-9.0,7.8,19.2e10,0.54 +2017-09-05 05:11:27,49.3N,116.9W,36.0,14.7,12.7,-6.1,-4.2,3.8e10,0.13 +2017-07-31 22:01:35,24.7N,118.5W,5.8e10,0.19,,,,, +2017-07-23 06:12:38,6.6S,69.7W,38.0,17.2,-0.4,8.7,-14.8,3.5e10,0.12 +2017-07-13 09:30:36,23.1N,60.7E,35.0,13.7,-10.0,-6.5,-6.8,7.3e10,0.23 +2017-06-30 14:26:45,34.3S,134.5E,20.0,15.2,10.9,-9.7,4.2,9.4e10,0.29 +2017-06-23 20:21:55,57.0N,143.7E,35.1,24.3,17.7,13.1,-10.3,18.4e10,0.52 +2017-06-20 13:41:32,54.2S,133.0E,33.3,13.6,8.7,-5.7,8.8,63.6e10,1.6 +2017-05-24 07:03:03,9.1S,101.8E,46.0,18.4,-6.5,-16.5,-5.0,9.0e10,0.28 +2017-05-22 17:44:39,49.6S,157.6W,33.0,3.5e10,0.12,,,, +2017-05-14 09:30:35,26.0S,32.4E,33.0,3.5e10,0.12,,,, +2017-04-30 21:28:28,25.7S,56.2E,32.4,21.5,-13.4,-14.2,8.9,15.0e10,0.43 +2017-03-11 04:51:21,28.3N,60.2W,28.0,126.3e10,2.9,,,, +2017-03-09 04:16:37,40.5N,18.0W,23.0,36.5,-15.3,25.8,-20.8,40.0e10,1 +2017-03-08 22:21:59,26.1S,174.9E,37.0,7.2e10,0.23,,,, +2017-02-25 01:22:59,29.5N,13.5E,25.4,12.2,-7.6,-9.3,2.2,6.5e10,0.21 +2017-02-22 18:47:30,50.7S,66.0W,3.8e10,0.13,,,,, +2017-02-18 19:48:29,6.2N,60.4E,38.0,24.2,-6.6,-22.7,-5.3,29.5e10,0.79 +2017-02-07 17:37:31,27.4S,14.8W,54.0,2.0e10,0.073,,,, +2017-02-06 06:09:59,10.4N,131.6E,33.5,6.6e10,0.21,,,, +2016-12-23 03:29:09,21.3N,49.3E,42.0,29.7,-22.4,16.4,-10.5,3.8e10,0.13 +2016-12-07 04:51:39,34.5S,126.6W,11.7e10,0.35,,,,, +2016-11-29 08:05:38,30.6S,93.1W,3.1e10,0.11,,,,, +2016-11-24 14:10:34,15.2S,80.3E,30.6,17.4,9.1,-11.2,9.7,13.8e10,0.4 +2016-11-03 17:14:29,39.6S,16.3W,37,7.6e10,0.24,,,, +2016-10-01 20:23:45,36.2N,6.7E,27.8,14.2,-10.0,3.9,-9.3,3.1e10,0.11 +2016-09-22 04:57:49,51.8S,178.5E,40.0,17.5,-2.5,-3.3,17.0,7.1e10,0.22 +2016-09-14 15:01:51,3.5S,44.6E,54.0,18.3,3.5,-16.2,7.7,7.6e10,0.24 +2016-08-27 21:45:13,56.9S,162.2E,42.0,14.2e10,0.41,,,, +2016-08-11 05:59:58,43.7S,53.8E,34.3,14.9,-0.7,-11.4,9.6,18.4e10,0.52 +2016-08-05 18:02:44,46.4N,171.6E,32.4,12.1e10,0.36,,,, +2016-07-21 00:48:53,7.8N,1.6W,37.0,4.5e10,0.15,,,, +2016-07-05 01:24:26,1.0N,48.6E,38.2,25.1,-10.3,-2.0,-22.8,15.3e10,0.44 +2016-06-27 10:02:42,15.8N,11.9W,33.3,29.1,-29.1,1.5,0.7,45.8e10,1.2 +2016-06-05 06:12:55,17.4S,138.3E,28.7,14.5,6.0,-11.9,5.7,33.1e10,0.87 +2016-06-02 10:56:32,33.8N,110.9W,17.2e10,0.49,,,,, +2016-05-29 12:14:55,10.2N,48.8W,32.0,6.9e10,0.22,,,, +2016-05-20 11:59:46,32.8S,15.1E,30.6,20.8,5.4,-9.9,17.5,2.0e10,0.073 +2016-05-16 10:09:41,3.2N,6.6E,41.7,12.2,-6.7,-3.3,-9.6,51.9e10,1.3 +2016-05-13 00:34:01,26.2N,122.3W,33.0,10.1e10,0.31,,,, +2016-04-24 05:39:24,9.8N,42.8W,50.0,14.6e10,0.42,,,, +2016-04-18 11:59:10,20.7N,14.5W,31.5,17.1,-3.5,2.2,-16.6,22.4e10,0.62 +2016-04-12 09:51:40,38.3N,162.2E,2.0e10,0.073,,,,, +2016-04-10 14:57:53,22.0N,149.0E,35.2,15.1,4.7,-12.9,-6.4,65.5e10,1.6 +2016-03-16 23:54:20,49.2S,6.3W,42.0,13.3,-7.6,9.1,6.0,3.2e10,0.11 +2016-03-03 01:32:43,48.0S,51.0E,31.8,11.7,4.8,-7.1,7.9,5.8e10,0.19 +2016-02-23 03:59:13,32.3N,67.2E,44.0,17.9,-8.5,-1.6,-15.7,3.5e10,0.12 +2016-02-21 05:58:53,36.5N,37.2W,32.0,36.9e10,0.96,,,, +2016-02-19 08:15:02,0.7N,11.6W,39.4,15.5,-14.9,-0.5,4.1,20.2e10,0.56 +2016-02-13 00:10:13,3.1N,117.9E,5.1e10,0.17,,,,, +2016-02-06 13:55:09,30.4S,25.5W,31.0,15.6,2.7,14.5,5.0,685.3e10,13 +2016-01-27 09:59:16,45.8S,53.6E,37,11.5,-10.0,-4.4,3.6,5.0e10,0.16 +2016-01-21 16:44:54,10.8S,0.7E,42.5,18.1,-3.8,-17.7,-1.2,4.6e10,0.15 +2015-12-30 13:07:50,33.8N,160.7W,39.0,2.2e10,0.079,,,, +2015-12-21 02:32:48,5.9N,143.0E,42.2,12.1,6.4,-10.0,2.5,8.3e10,0.26 +2015-12-08 00:34:23,69.9S,150.5E,38.0,19.7e10,0.55,,,, +2015-11-13 14:59:27,16.0N,124.3E,28.0,10.2e10,0.31,,,, +2015-11-02 21:34:20,41.4S,33.0E,37.0,7.8e10,0.24,,,, +2015-10-31 11:34:30,9.0N,138.0W,71.0,9.7e10,0.29,,,, +2015-10-30 07:07:12,85.0S,161.7W,18.0e10,0.51,,,,, +2015-10-13 12:23:08,8.0S,52.5W,38.9,12.9,-6.6,3.8,10.4,2.3e10,0.082 +2015-10-11 00:07:46,55.4S,18.8W,3.0e10,0.1,,,,, +2015-10-10 09:57:51,51.0S,21.1W,51.8,11.8,-1.3,-5.1,10.6,3.6e10,0.12 +2015-10-04 21:02:17,22.0N,171.6W,36.1,4.4e10,0.15,,,, +2015-09-17 21:03:14,43.1S,94.9E,9.8e10,0.3,,,,, +2015-09-14 23:50:50,5.8N,15.2W,7.0e10,0.22,,,,, +2015-09-08 13:46:42,6.3N,29.9E,44.4,16.1,-11.5,-11.3,-0.9,2.0e10,0.073 +2015-09-07 01:41:19,14.5N,98.9E,29.3,21.0,16.8,-12.0,-3.8,179.8e10,3.9 +2015-09-02 20:10:30,39.1N,40.2E,39.8,24.1,10.3,-12.2,-18.0,3.7e10,0.13 +2015-08-04 10:24:59,9.6S,125.9E,2.9e10,0.1,,,,, +2015-07-19 07:06:26,20.6N,87.6W,22.0,17.8,9.4,13.0,7.8,2.3e10,0.082 +2015-07-12 22:23:14,31.0N,159.6E,41.0,2.2e10,0.079,,,, +2015-07-04 01:40:11,38.6N,103.1E,46.3,49.0,0.9,-40.4,-27.7,5.6e10,0.18 +2015-06-14 03:03:06,6.3N,124.1E,32.4,31.9,-4.7,-17.8,-26.0,7.1e10,0.22 +2015-06-12 17:03:35,1.3S,32.1W,43.5,17.6e10,0.5,,,, +2015-06-10 17:43:03,11.5S,161.9W,61.1,38.4e10,1,,,, +2015-06-02 08:44:50,6.4S,142.7W,38.0e10,0.99,,,,, +2015-05-20 10:20:41,1.0N,172.6E,32.4,3.6e10,0.12,,,, +2015-05-18 17:13:51,32.4N,139.1E,29.0,4.3e10,0.14,,,, +2015-05-10 07:45:01,46.3S,179.3W,29.6,12.2,11.2,0.9,4.7,14.3e10,0.42 +2015-05-07 20:34:34,21.5S,29.3W,37.0,17.3,-16.2,-5.8,1.4,5.2e10,0.17 +2015-04-30 10:21:01,48.7S,139.1E,26.7,12.9,12.2,-4.2,0.9,10.5e10,0.32 +2015-04-21 01:42:51,37.7N,39.6W,37.4,21.3,-15.3,12.8,7.4,8.8e10,0.27 +2015-04-10 01:14:27,42.8S,8.2E,6.5e10,0.21,,,,, +2015-04-08 04:06:31,25.5S,51.5E,36.3,19.2,8.0,-15.6,-7.9,17.3e10,0.49 +2015-04-03 01:39:38,8.4N,157.9W,4.2e10,0.14,,,,, +2015-03-30 21:33:52,36.1S,5.5W,33.1,13.8,-13.7,-1.7,0.8,6.4e10,0.2 +2015-03-18 00:04:50,5.4S,159.3E,50.0,12.1e10,0.36,,,, +2015-03-11 06:18:59,8.0N,119.1E,35.2,19.9,5.5,-10.5,-16.0,7.2e10,0.23 +2015-03-08 04:26:28,39.1S,118.6W,2.0e10,0.073,,,,, +2015-03-04 04:30:05,15.9S,88.1E,39.8,18.0,7.8,-16.0,-2.5,5.5e10,0.18 +2015-02-26 22:06:24,68.0N,149.0W,33.7,21.1,5.6,-2.3,-20.2,18.8e10,0.53 +2015-02-25 10:53:24,12.4N,122.4W,42,5.8e10,0.19,,,, +2015-02-17 13:19:50,8.0S,11.2W,39,28.8,-28.2,3.4,4.6,3.3e10,0.11 +2015-01-09 17:31:47,23.3S,49.2W,2.2e10,0.079,,,,, +2015-01-09 10:41:11,2.0N,28.8E,36.0,17.5,-10.7,-7.6,11.6,13.9e10,0.41 +2015-01-07 01:05:59,45.7N,26.9E,45.5,35.7,-35.4,1.8,-4.4,13.6e10,0.4 +2015-01-02 13:39:19,31.1S,140.0E,38.1,18.1,4.5,-14.4,-10.0,2.0e10,0.073 +2014-12-13 02:53:52,86.7N,162.1W,30.7,21.7,15.3,-13.3,-7.8,4.4e10,0.15 +2014-12-12 06:48:11,33.5N,144.9E,26.3,12.0,11.5,-2.8,-2.2,3.3e10,0.11 +2014-12-09 21:19:18,76.6N,96.3E,26.3,7.8e10,0.24,,,, +2014-11-28 11:47:18,45.8S,172.7W,26.1,13.4,0.4,-1.4,13.3,70.0e10,1.7 +2014-11-27 12:12:52,18.8S,73.4W,38.0,5.5e10,0.18,,,, +2014-11-26 23:16:51,69.5S,179.7W,23.3,25.3,21.3,2.2,13.4,11.8e10,0.35 +2014-11-26 17:40:16,68.2S,24.0W,37.0,19.9,-7.0,16.1,9.4,10.5e10,0.32 +2014-11-04 20:13:30,43.1N,115.8E,22.2,16.0,-7.2,-12.1,-7.7,15.6e10,0.45 +2014-10-21 18:55:37,22.2N,132.9W,3.4e10,0.12,,,,, +2014-10-17 14:07:36,4.6S,66.3W,39.0,7.2e10,0.23,,,, +2014-10-14 10:25:03,2.0S,119.2E,27.2,16.9,15.0,-6.9,-3.5,2.9e10,0.1 +2014-10-06 20:02:15,43.7S,85.7E,3.9e10,0.13,,,,, +2014-09-09 18:55:46,3.2N,137.2E,32.5,2.8e10,0.098,,,, +2014-09-05 21:37:26,22.7N,150.0W,3.5e10,0.12,,,,, +2014-08-29 23:15:39,6.2S,49.9W,2.6e10,0.092,,,,, +2014-08-28 03:07:45,3.2N,45.4W,3.4e10,0.12,,,,, +2014-08-23 06:29:41,61.7S,132.6E,22.2,16.2,-2.3,5.7,16.5,381.9e10,7.6 +2014-07-29 07:38:07,49.2S,172.2W,7.3e10,0.23,,,,, +2014-07-29 03:07:43,33.9S,115.9W,5.3e10,0.17,,,,, +2014-06-28 02:40:07,18.9N,141.2E,26.3,12.4,12.0,3.5,-10.5,24.5e10,0.67 +2014-06-26 05:54:41,71.5S,93.4E,28.5,11.2,7.0,2.9,8.3,6.1e10,0.2 +2014-05-29 01:12:36,21.9N,131.1W,28.7,5.8e10,0.19,,,, +2014-05-16 20:06:28,39.4S,95.9W,30.8,18.0,2.9,13.4,-12.5,13.6e10,0.4 +2014-05-16 12:42:48,44.2S,176.2W,44.0,16.5,14.4,4.6,6.5,30.9e10,0.82 +2014-05-08 19:42:37,36.9S,87.3E,35.4,19.0,-2.0,-16.1,9.9,105e10,2.4 +2014-03-29 13:45:41,28.7S,121.5E,30.7,16.3,10.0,-12.7,2.2,3.9e10,0.13 +2014-03-18 11:02:37,0.0N,111.8W,30.5,54e10,1.3,,,, +2014-03-03 15:00:21,29.0S,94.9W,9.4e10,0.29,,,,, +2014-02-18 12:50:44,32.8S,61.5W,2.6e10,0.092,,,,, +2014-02-13 06:47:42,13.3N,110.7W,25.0,63e10,1.5,,,, +2014-01-15 02:46:19,18.5S,141.8E,29.6,14.0e10,0.41,,,, +2014-01-12 16:00:48,2.9N,64.4E,37.0,16.2,-5.2,-15.1,2.6,7.8e10,0.24 +2014-01-08 17:05:34,1.3S,147.6E,18.7,44.8,-3.4,-43.5,-10.3,3.1e10,0.11 +2013-12-23 08:30:57,39.5N,2.0E,34.3,15.1,-1.1,11.4,-9.9,14.7e10,0.43 +2013-12-08 03:10:09,32.8N,165.1W,23.5,11.8,2.3,2.5,-11.3,6.4e10,0.2 +2013-11-21 01:50:35,44.7N,35.3E,59.3,12.4,-5.0,-11.0,-2.7,7.5e10,0.23 +2013-10-12 16:06:45,19.1S,25.0W,22.2,12.8,-8.0,8.4,-5.5,161.0e10,3.5 +2013-10-09 17:27:36,6.0e10,0.19,,,,,,, +2013-09-24 15:31:16,10.3S,164.7W,40.7,16.0e10,0.46,,,, +2013-08-12 18:08:02,34.4S,118.2E,66.6,4.4e10,0.15,,,, +2013-07-31 07:00:38,3.9e10,0.13,,,,,,, +2013-07-31 03:50:14,31.8S,137.1E,29.1,17.8,17.7,-2.3,-0.1,6.9e10,0.22 +2013-07-30 02:36:58,50.2S,90.2E,25.6,18.8,15.9,-8.6,5.1,39.0e10,1 +2013-07-27 08:30:36,0.3N,156.2E,26.5,22.1,16.0,14.9,-3.3,12.0e10,0.36 +2013-07-26 11:32:26,21.0N,178.5W,37.0,2.0e10,0.073,,,, +2013-07-18 00:46:37,2.2e10,0.079,,,,,,, +2013-06-13 02:51:14,2.2e10,0.079,,,,,,, +2013-06-01 22:49:48,65.6S,138.4E,28.9,3.4e10,0.12,,,, +2013-05-14 23:20:21,3.0S,76.4E,2.0e10,0.073,,,,, +2013-04-30 08:40:38,35.5N,30.7W,21.2,12.1,1,9,-8,511e10,10 +2013-04-21 06:23:12,28.1S,64.6W,40.7,14.9,5,14,1,106.6e10,2.5 +2013-03-12 10:32:59,32.7S,17.1E,26.0,2.9e10,0.1,,,, +2013-02-20 13:13:07,23.0S,38.8W,13.6,-11,-8,-1,3.2e10,0.1, +2013-02-15 03:20:33,54.8N,61.1E,23.3,18.6,+12.8,-13.3,-2.4,3.75e14,440 +2013-02-07 13:12:24,18.8S,158.6W,6.5e10,0.21,,,,, +2013-01-25 07:40:18,60.3N,64.6W,340e10,6.9,,,,, +2013-01-12 03:04:21,15.1S,155.6W,36.1,4.8e10,0.16,,,, +2012-12-30 07:25:35,17.3N,83.6W,19.8e10,0.55,,,,, +2012-12-18 11:19:17,2.7e10,0.095,,,,,,, +2012-11-20 20:37:31,2.5N,29.6E,33.3,14.3,-12.2,-5.3,5.3,2.5e10,0.089 +2012-11-20 06:25:11,8.0S,86.0W,12.0e10,0.36,,,,, +2012-10-25 15:57:19,3.0e10,0.1,,,,,,, +2012-10-19 16:26:22,75.4S,49.6E,29.3,13.2,-2.3,-3.9,12.4,2.3e10,0.082 +2012-10-09 00:54:55,51.2N,84.6W,27.8,13.5,3.4,12.0,5.1,21.0e10,0.58 +2012-10-03 22:50:12,41.5S,21.9W,17.0,-2.4,5.5,15.9,28.0e10,0.75, +2012-10-02 16:38:38,8.1S,111.9W,35.0,15.4,1.4,15.3,1.0,47.0e10,1.2 +2012-09-28 05:44:12,6.9S,73.7E,3.8e10,0.13,,,,, +2012-09-18 19:34:39,1.2N,52.2W,28.1,18.3,-1.9,14.1,-11.5,24.4e10,0.67 +2012-09-11 22:07:30,18.9S,105.2E,5.2e10,0.17,,,,, +2012-09-10 01:03:32,69.8S,111.7W,23.8,16.9,-10.2,-5.2,12.4,2.3e10,0.082 +2012-08-27 06:57:43,18.3S,64.2E,38.7,28.9,-8.0,-23.7,-14.5,6.8e10,0.22 +2012-08-26 14:55:47,11.8N,117.0E,36.0,12.7,5.0,-11.6,-0.7,24.9e10,0.68 +2012-08-13 05:31:53,3.3e10,0.11,,,,,,, +2012-07-27 04:19:50,63.1N,172.3E,27.2,3.4e10,0.12,,,, +2012-07-25 07:48:20,36.4N,41.5E,26.8,18.5,0.8,2.0,-18.4,13.3e10,0.39 +2012-06-05 07:44:54,2.4e10,0.086,,,,,,, +2012-05-25 11:31:24,41.8S,36.2W,6.0e10,0.19,,,,, +2012-05-22 08:31:42,21.1e10,0.59,,,,,,, +2012-05-15 11:04:17,61.8S,135.5W,33.3,17.1,-0.8,1.1,17.0,13.2e10,0.39 +2012-05-04 21:54:49,76.7N,10.6W,22.9e10,0.63,,,,, +2012-04-23 22:01:10,36.2N,107.4E,25.2,4.4e10,0.15,,,, +2012-04-21 16:08:23,15.8S,174.8W,14.3e10,0.42,,,,, +2012-04-19 22:12:10,5.5N,16.8E,3.0e10,0.1,,,,, +2012-04-02 16:50:33,28.1N,95.2W,3.2e10,0.11,,,,, +2012-03-12 06:40:44,2.5N,139.8E,25.0,11.8,0.1,-11.8,0.3,9.9e10,0.3 +2012-03-03 21:28:24,7.8N,2.7E,20.4,10.1e10,0.31,,,, +2012-03-01 03:12:40,46.9N,29.8W,2.2e10,0.079,,,,, +2012-02-24 19:11:41,22.7S,30.8E,3.7e10,0.13,,,,, +2012-02-17 10:47:16,3.2S,39.9W,45.6,15.4e10,0.44,,,, +2012-02-16 04:50:52,9.8N,151.8E,9.8e10,0.3,,,,, +2012-02-12 05:25:52,31.7S,54.9E,61.0,14.0e10,0.41,,,, +2012-02-04 14:42:51,32.4N,0.1E,34.2,12.2,-3.9,10.9,4.0,15.0e10,0.43 +2012-01-15 12:26:20,64.1S,109.9E,26.3,12.3,-1.9,5.1,11.0,2.1e10,0.076 +2012-01-11 02:23:15,32.2N,88.5E,8.5e10,0.26,,,,, +2011-12-19 11:35:39,30.2S,52.6E,36.1,13.5e10,0.4,,,, +2011-12-14 05:01:38,62.9S,89.6E,32.4,5.0e10,0.16,,,, +2011-12-11 17:29:33,2.9e10,0.1,,,,,,, +2011-11-20 05:25:05,27.9S,116.3E,2.3e10,0.082,,,,, +2011-10-12 07:13:20,26.4S,78.4W,3.6e10,0.12,,,,, +2011-09-13 23:36:47,19.9S,13.8W,21.3,16.7,-3.7,1.8,16.2,6.7e10,0.21 +2011-08-31 09:44:13,18.6N,5.1W,2.7e10,0.095,,,,, +2011-08-20 20:01:37,27.2S,2.8W,2.3e10,0.082,,,,, +2011-08-18 14:55:45,2.3e10,0.082,,,,,,, +2011-08-11 02:56:08,3.5e10,0.12,,,,,,, +2011-08-04 07:25:57,40.7S,86.7W,63.0,2.8e10,0.098,,,, +2011-07-27 23:00:36,45.3S,63.5E,29.6,4.4e10,0.15,,,, +2011-07-07 23:25:54,3.3e10,0.11,,,,,,, +2011-07-05 15:42:41,29.1N,139.7E,40.7,6.5e10,0.21,,,, +2011-07-04 09:18:04,51.7S,175.0E,2.9e10,0.1,,,,, +2011-06-16 11:51:50,67.3N,21.4W,40.5,2.4e10,0.086,,,, +2011-05-25 05:40:02,4.1N,14.0E,59.0,11.6,-3.4,-10.8,2.4,228.0e10,4.8 +2011-05-16 13:39:06,1.2S,92.8E,2.0e10,0.073,,,,, +2011-04-27 20:38:09,1.4N,126.6W,28.7,22.0e10,0.61,,,, +2011-04-27 11:21:44,2.4e10,0.086,,,,,,, +2011-04-17 11:21:44,2.4e10,0.086,,,,,,, +2011-04-11 21:43:40,3.8e10,0.13,,,,,,, +2011-04-06 08:30:55,71.1N,43.5W,22.2,12.7,3.3,11.8,-3.5,14.8e10,0.43 +2011-03-24 20:23:58,0.6N,127.5W,59.0,5.8e10,0.19,,,, +2011-03-23 04:24:46,3.1e10,0.11,,,,,,, +2011-03-23 04:16:32,16.8S,85.6W,2.2e10,0.079,,,,, +2011-03-01 10:37:54,53.5N,103.9E,30.6,11.9,-6.7,-1.1,-9.8,3.7e10,0.13 +2011-02-21 05:07:03,26.3N,43.7E,44.4,18.0,10.3,-14.8,0.1,3.9e10,0.13 +2011-02-12 11:00:12,7.8N,95.3W,2.0e10,0.073,,,,, +2011-01-21 15:11:43,18.9N,44.6W,61.0,7.2e10,0.23,,,, +2011-01-08 19:38:44,33.3N,125.8W,48.0,2.9e10,0.1,,,, +2010-12-25 23:24:00,38.0N,158.0E,26.0,18.1,18,-2,-4,2.00e13,33 +2010-12-14 00:27:53,4.9S,175.5E,24.0,3.9e10,0.13,,,, +2010-12-09 02:54:07,54.5S,169.7W,66.0,6.3e10,0.2,,,, +2010-12-01 06:31:46,72.5S,144.9E,33.3,13.3e10,0.39,,,, +2010-11-21 14:45:27,1.9N,143.3E,50.0,8.1e10,0.25,,,, +2010-11-19 07:25:56,10.3S,148.8E,30.0,3.3e10,0.11,,,, +2010-11-10 08:26:35,74.5N,77.7W,6.8e10,0.22,,,,, +2010-11-09 13:05:46,56.3S,16.7W,37.0,8.6e10,0.27,,,, +2010-11-09 06:56:52,14.0S,160.0W,26.0,2.0e10,0.073,,,, +2010-10-27 11:27:39,14.1S,67.7E,35.2,14.5e10,0.42,,,, +2010-10-08 09:58:01,2.0e10,0.073,,,,,,, +2010-09-24 12:02:07,67.4S,50.6W,5.0e10,0.16,,,,, +2010-09-18 05:04:41,7.4N,36.7E,6.7e10,0.21,,,,, +2010-09-08 19:51:36,13.9S,65.5W,46.3,6.5e10,0.21,,,, +2010-09-05 23:37:33,25.9S,49.0E,35.2,68.3e10,1.7,,,, +2010-09-03 12:04:58,61.0S,146.7E,33.3,12.3,9.8,-3.5,6.5,175.0e10,3.8 +2010-08-17 04:19:37,20.7N,114.3W,33.3,2.1e10,0.076,,,, +2010-08-12 02:59:36,2.8e10,0.098,,,,,,, +2010-08-05 19:31:48,21.5S,46.6E,3.6e10,0.12,,,,, +2010-07-15 01:49:56,60.9N,178.1W,2.4e10,0.086,,,,, +2010-07-06 23:54:43,34.1S,174.5W,26.0,15.7,12.1,10.0,0.2,756.0e10,14 +2010-06-26 06:04:38,0.5S,133.2E,50.0,11.3e10,0.34,,,, +2010-06-21 06:42:00,22.5S,120.9W,16.3e10,0.47,,,,, +2010-06-17 04:24:45,26.1S,100.0E,42.0,11.9e10,0.35,,,, +2010-04-17 02:21:58,13.1N,173.0W,5.6e10,0.18,,,,, +2010-04-16 04:38:52,1.8N,176.9W,22.2,18.8,12.4,-13.2,-5.2,84.4e10,2 +2010-04-06 18:33:12,52.8N,146.5W,8.0e10,0.25,,,,, +2010-03-18 16:11:16,32.4S,51.8W,17.5e10,0.5,,,,, +2010-03-15 15:55:43,8.0e10,0.25,,,,,,, +2010-03-14 18:44:42,33.8N,90.2W,35.6,4.2e10,0.14,,,, +2010-03-08 22:44:41,18.2N,110.1E,53.0,3.0e10,0.1,,,, +2010-03-08 22:02:07,32.0N,92.9W,52.0,24.5,19.1,11.0,10.7,32.3e10,0.85 +2010-02-28 22:24:50,48.7N,21.0E,37.0,15.1,-11.7,2.7,-9.1,15.3e10,0.44 +2010-02-26 22:46:13,37.3S,166.0W,23.7e10,0.65,,,,, +2010-02-24 19:55:58,2.6S,102.2W,9.3e10,0.28,,,,, +2010-01-15 19:17:54,8.3S,27.0E,25.0,14.0,-9.1,6.0,8.8,49.2e10,1.2 +2009-12-31 16:24:23,8.3e10,0.26,,,,,,, +2009-12-31 12:50:25,37.9N,178.3W,20.7,10.2e10,0.31,,,, +2009-11-25 01:36:20,52.8S,136.5E,6.4e10,0.2,,,,, +2009-11-21 20:53:00,22.0S,29.2E,38.0,32.1,3,-17,27,1.00e13,18 +2009-11-18 17:36:07,8.5e10,0.26,,,,,,, +2009-11-18 07:07:19,40.4N,113.2W,31.5,73.6e10,1.8,,,, +2009-11-14 19:58:55,2.3e10,0.082,,,,,,, +2009-11-07 11:31:59,45.5N,157.7W,2.2e10,0.079,,,,, +2009-11-07 10:41:38,24.0N,64.1E,37.0,4.2e10,0.14,,,, +2009-10-11 12:49:51,78.3S,70.2E,27.8,7.1e10,0.22,,,, +2009-10-08 02:57:00,4.2S,120.6E,19.1,19.2,14,-16,-6,2.00e13,33 +2009-09-27 22:22:48,36.0S,67.6W,37.0,8.9e10,0.27,,,, +2009-09-18 20:13:56,7.7N,29.5W,14.4e10,0.42,,,,, +2009-09-04 02:23:18,42.5N,110.0E,28.3,24.0,19.2,-11.6,-8.5,96.5e10,2.3 +2009-08-23 21:17:19,67.7S,18.3E,34.0,12.2,-6.9,5.3,8.5,28.0e10,0.75 +2009-07-31 02:13:19,8.9N,121.9W,2.5e10,0.089,,,,, +2009-07-16 06:39:05,24.4S,59.8W,32.2,72.7e10,1.8,,,, +2009-07-03 04:02:00,2.7e10,0.095,,,,,,, +2009-06-27 13:08:05,26.6S,12.6W,26.1,15.2,-11.6,1.6,9.7,3.2e10,0.11 +2009-06-20 11:04:41,2.7e10,0.095,,,,,,, +2009-06-18 04:39:00,23.7S,16.0W,57.4,3.3e10,0.11,,,, +2009-06-09 22:42:28,54.9N,152.7W,34.2,28.1e10,0.76,,,, +2009-05-31 06:05:47,19.7N,121.0W,14.3e10,0.42,,,,, +2009-05-13 20:20:16,7.3e10,0.23,,,,,,, +2009-05-04 11:39:03,36.4N,160.4W,40.7,14.0e10,0.41,,,, +2009-04-20 04:01:39,6.0N,84.3E,2.2e10,0.079,,,,, +2009-04-10 18:42:45,44.7S,25.7E,32.4,19.1,-18.9,2.6,0.3,27.0e10,0.73 +2009-03-15 05:44:33,21.7S,98.6W,3.2e10,0.11,,,,, +2009-03-04 00:38:05,17.0e10,0.48,,,,,,, +2009-03-01 09:00:59,2.0e10,0.073,,,,,,, +2009-02-20 12:15:57,64.9S,70.0W,5.0e10,0.16,,,,, +2009-02-07 19:51:32,56.6N,69.8E,40.0,15.4,-2.4,-1.9,-15.1,160.0e10,3.5 +2009-01-12 22:24:56,47.8N,44.3W,4.8e10,0.16,,,,, +2009-01-10 07:42:39,64.0S,122.8E,26.5,2.3e10,0.082,,,, +2008-12-24 15:51:58,68.9S,102.0W,21.1,24.1,-13.4,18.0,8.8,3.5e10,0.12 +2008-12-12 11:36:36,7.0S,9.7W,50.0,21.6e10,0.6,,,, +2008-12-09 06:08:16,3.4e10,0.12,,,,,,, +2008-11-24 22:01:19,57.9S,146.1E,34.8,23.7,21.5,10.0,0.4,14.6e10,0.42 +2008-11-21 00:26:44,53.1N,109.9W,28.2,12.9,3.9,-4.1,-11.6,14.2e10,0.41 +2008-11-18 09:41:51,29.4S,75.9E,35.2,22.4,-4.0,-15.2,-16.0,2.5e10,0.089 +2008-11-09 02:38:34,14.5N,112.7E,29.6,22.2e10,0.61,,,, +2008-10-21 02:20:25,32.8N,165.6W,29.6,11.3,9.6,5.8,1.5,4.6e10,0.15 +2008-10-10 09:34:18,57.3S,17.0E,21.4,18.0e10,0.51,,,, +2008-10-07 02:45:45,20.9N,31.4E,38.9,13.3,-9.0,9.0,3.8,39.5e10,1 +2008-09-09 09:49:41,5.9e10,0.19,,,,,,, +2008-08-16 14:40:24,11.3N,97.2E,13.1e10,0.38,,,,, +2008-08-12 11:44:10,11.6S,175.0W,2.0e10,0.073,,,,, +2008-08-07 06:07:10,18.5N,180.0E,45.4,13.8,6.5,-12.1,1.7,4.1e10,0.14 +2008-07-23 14:45:25,38.6N,68.0E,31.5,14.5,-7.7,-8.2,-9.1,12.1e10,0.36 +2008-07-22 19:34:00,17.8S,89.2W,54.4,6.1e10,0.2,,,, +2008-07-11 14:35:28,5.2e10,0.17,,,,,,, +2008-07-08 15:55:30,72.8N,147.3E,52.2,21.7,-12.9,1.9,-17.4,6.6e10,0.21 +2008-07-01 17:40:19,37.1N,115.7W,36.1,9.8,2.8,1.7,-9.2,3.6e10,0.12 +2008-06-27 02:01:23,26.9S,17.7W,33.7,23.1,-17.9,13.0,6.6,17.2e10,0.49 +2008-06-18 13:45:36,6.1N,103.1E,2.1e10,0.076,,,,, +2008-05-29 21:23:56,15.7N,83.5W,2.1e10,0.076,,,,, +2008-05-24 10:18:10,0.8N,162.0E,37.0,14.2,7.9,3.1,11.4,15.0e10,0.43 +2008-05-22 20:50:28,46.9N,134.5E,2.1e10,0.076,,,,, +2008-05-15 11:29:55,28.0N,41.5W,8.0e10,0.25,,,,, +2008-05-06 01:08:56,5.7e10,0.18,,,,,,, +2008-04-30 01:18:38,33.6S,35.1W,2.0e10,0.073,,,,, +2008-04-07 01:22:28,31.8S,58.5W,2.1e10,0.076,,,,, +2008-04-06 16:03:34,7.7e10,0.24,,,,,,, +2008-03-15 11:29:55,28.0N,41.5W,26.7,12.9,-4.1,4.8,-11.2,5.0e10,0.16 +2008-02-24 19:33:14,7.4e10,0.23,,,,,,, +2008-02-19 13:30:30,48.9N,119.8W,2.0e10,0.073,,,,, +2008-02-18 08:51:12,5.0e10,0.16,,,,,,, +2008-02-17 12:19:16,74.9N,73.4W,40.4,13.9,-5.8,-10.7,-6.7,11.0e10,0.33 +2008-02-16 08:38:39,7.1e10,0.22,,,,,,, +2008-01-18 01:17:39,4.4e10,0.15,,,,,,, +2008-01-09 03:53:15,66.8S,67.3W,31.5,11.6,4.3,5.7,9.1,4.1e10,0.14 +2007-12-26 06:46:20,61.6S,158.9W,13.6e10,0.4,,,,, +2007-12-20 17:00:48,51.3N,115.4E,12.2e10,0.36,,,,, +2007-10-25 19:35:38,40.9S,91.3E,46.3,5.8e10,0.19,,,, +2007-10-12 09:14:03,88.5N,116.6E,37.0,18.4,-4.5,-14.1,-10.9,3.3e10,0.11 +2007-10-07 13:31:01,35.2S,125.6E,5.8e10,0.19,,,,, +2007-09-22 17:57:12,49.2S,85.5W,30.2,16.9,-9.2,13.6,3.8,23.7e10,0.65 +2007-06-11 09:47:05,23.4S,170.9W,35.2,17.0,16.7,-2.1,-2.2,4.9e10,0.16 +2007-06-08 13:32:00,52.0S,175.3E,38.9,23.5e10,0.65,,,, +2007-06-07 21:28:12,21.9N,53.1E,29.6,3.1e10,0.11,,,, +2007-05-16 16:20:58,4.5S,111.7E,3.8e10,0.13,,,,, +2007-05-16 04:45:52,42.4S,164.0E,31.5,40.0e10,1,,,, +2007-05-04 17:52:39,22.9N,109.4E,48.0,17.5e10,0.5,,,, +2007-04-18 12:44:23,83.7S,171.2W,38.0,24.4,-5.3,-2.5,23.7,11.2e10,0.33 +2007-04-16 14:56:51,2.4e10,0.086,,,,,,, +2007-03-17 06:48:35,7.1N,4.1E,32.5,14.5,-7.3,-1.9,-12.4,4.0e10,0.13 +2007-03-15 02:20:15,44.1S,148.4W,2.5e10,0.089,,,,, +2007-03-07 15:16:49,2.7e10,0.095,,,,,,, +2007-02-02 12:48:41,24.0N,37.2W,35.5,34.0e10,0.89,,,, +2007-01-26 22:22:21,3.7N,99.7E,14.7e10,0.43,,,,, +2007-01-22 07:24:56,45.4N,53.5E,32.0,13.4,-3.3,-12.8,-1.9,7.6e10,0.24 +2007-01-18 13:51:10,5.3N,164.3W,34.1,3.2e10,0.11,,,, +2007-01-17 09:50:46,8.7S,50.8E,33.3,54.8e10,1.4,,,, +2007-01-01 11:43:29,44.4N,116.5E,53.0,3.6e10,0.12,,,, +2006-12-09 06:31:12,26.2N,26.0E,26.5,15.9,4.9,-15.0,1.6,741.0e10,14 +2006-12-07 11:42:00,14.0N,140.0W,2.1e10,0.076,,,,, +2006-12-01 06:09:25,13.0S,30.7E,6.3e10,0.2,,,,, +2006-11-13 15:16:34,44.0S,43.3E,2.3e10,0.082,,,,, +2006-10-24 08:42:52,1.9S,2.7W,43.0,22.5e10,0.62,,,, +2006-10-14 18:10:49,49.4N,175.0W,44.4,23.9,4.9,23.4,-1.0,25.8e10,0.7 +2006-10-09 04:45:30,47.0S,78.9E,22.2,4.1e10,0.14,,,, +2006-10-07 12:18:53,23.0S,61.8W,40.7,4.1e10,0.14,,,, +2006-10-02 19:10:27,14.0N,53.1E,42.0,9.0e10,0.28,,,, +2006-09-27 08:33:43,32.0S,60.2E,48.1,10.7e10,0.32,,,, +2006-09-23 18:52:58,29.0S,108.0W,12.1e10,0.36,,,,, +2006-09-02 17:57:58,2.2e10,0.079,,,,,,, +2006-09-02 04:26:15,14.0S,109.1E,44.1,14.2,10.0,-9.9,1.5,123.0e10,2.8 +2006-08-29 01:38:36,44.0S,162.0W,40.7,9.2e10,0.28,,,, +2006-08-18 00:03:18,43.0S,33.4E,47.2,3.2e10,0.11,,,, +2006-08-17 10:43:34,11.0S,165.7E,48.2,25.6e10,0.7,,,, +2006-08-15 10:52:24,4.9N,49.6E,32.7,4.7e10,0.16,,,, +2006-08-09 04:30:44,23.1S,53.7E,37.0,102.0e10,2.4,,,, +2006-07-15 23:55:45,78.3S,5.0W,29.6,12.4,0.1,2.0,12.2,8.5e10,0.26 +2006-07-15 15:22:49,31.1N,45.6E,38.9,30.2,9.2,-1.2,-28.7,16.3e10,0.47 +2006-06-07 00:06:28,69.2N,22.5E,40.7,19.6,6.1,4.6,-18.0,5.9e10,0.19 +2006-05-28 01:32:24,2.6e10,0.092,,,,,,, +2006-05-21 07:51:11,11.6S,25.5W,26.3e10,0.71,,,,, +2006-05-07 17:45:14,3.0e10,0.1,,,,,,, +2006-05-06 15:39:06,60.2S,152.3W,35.2,12.8e10,0.38,,,, +2006-04-25 18:46:53,2.0e10,0.073,,,,,,, +2006-04-08 13:16:23,17.3N,113.2W,33.3,12.7e10,0.37,,,, +2006-04-04 11:30:08,26.6N,26.6W,25.0,240.0e10,5,,,, +2006-03-14 03:21:06,7.0N,64.6W,35.2,14.4e10,0.42,,,, +2006-02-26 07:30:06,7.0e10,0.22,,,,,,, +2006-02-06 01:57:37,54.5S,18.1E,35.2,119.0e10,2.7,,,, +2006-02-04 08:38:05,36.9N,143.6W,38.9,19.8,-8.8,3.4,-17.4,10.0e10,0.3 +2006-01-28 03:33:48,51.7S,56.4E,37.0,18.7,8.4,-16.4,3.2,74.0e10,1.8 +2006-01-27 01:27:42,58.7N,74.7E,20.0,4.5e10,0.15,,,, +2006-01-26 00:00:53,79.8S,111.0W,37.0,5.3e10,0.17,,,, +2006-01-10 23:25:28,29.8N,12.7W,32.4,16.9,-9.9,-6.3,-12.2,2.8e10,0.098 +2006-01-08 05:20:19,7.6N,28.2W,9.4e10,0.29,,,,, +2005-12-29 10:05:35,3.0S,154.9W,42.2,20.7,18.6,8.5,3.2,19.0e10,0.53 +2005-12-24 15:30:26,54.0S,17.3E,66.0,18.1e10,0.51,,,, +2005-12-03 12:45:49,33.8S,117.4E,32.2,17.0,-12.1,-9.6,7.2,8.8e10,0.27 +2005-12-01 10:40:20,6.4S,155.8W,3.2e10,0.11,,,,, +2005-11-29 07:33:16,7.6N,58.2W,59.3,3.2e10,0.11,,,, +2005-11-15 05:19:07,26.3N,113.4W,32.4,2.5e10,0.089,,,, +2005-11-11 20:34:23,21.4N,134.1W,29.6,4.2e10,0.14,,,, +2005-11-09 07:33:08,31.0S,145.9E,30.7,13.8,13.5,-2.7,-0.7,7.3e10,0.23 +2005-11-02 07:04:32,33.9N,154.9W,68.5,3.2e10,0.11,,,, +2005-11-02 05:16:47,22.9N,123.8W,74.0,6.7e10,0.21,,,, +2005-10-26 21:30:47,36.3S,80.5W,16.7,13.8e10,0.4,,,, +2005-09-30 19:04:06,2.8S,84.1W,53.0,2.2e10,0.079,,,, +2005-09-14 01:08:52,11.6N,27.3E,33.3,2.5e10,0.089,,,, +2005-09-02 07:59:47,13.5N,73.1E,8.2e10,0.25,,,,, +2005-08-20 12:10:24,2.7e10,0.095,,,,,,, +2005-08-09 14:35:45,21.5S,56.2E,37.0,16.9,-16.3,4.3,1.4,2.5e10,0.089 +2005-07-01 22:36:15,49.8S,33.1E,50.0,3.1e10,0.11,,,, +2005-06-18 19:40:41,47.9N,85.6E,2.3e10,0.082,,,,, +2005-06-05 01:56:09,34.8N,90.9E,4.1e10,0.14,,,,, +2005-06-03 08:15:41,31.0S,90.3W,29.6,26.2,-1.5,25.3,6.7,8.2e10,0.25 +2005-05-27 14:12:13,48.9S,145.1E,50.5,2.0e10,0.073,,,, +2005-05-14 13:02:53,12.9e10,0.38,,,,,,, +2005-05-07 09:31:44,75.8S,163.7E,15.2,16.6,9.6,-9.7,9.4,2.6e10,0.092 +2005-05-02 20:10:36,17.7N,36.0E,4.6e10,0.15,,,,, +2005-04-22 11:18:05,20.9N,36.7W,37.0,2.2e10,0.079,,,, +2005-04-19 07:37:47,50.2S,146.4W,38.5,16.8,9.3,13.8,2.5,23.2e10,0.64 +2005-04-16 10:40:38,2.0e10,0.073,,,,,,, +2005-04-15 06:54:59,43.8S,73.9W,39.0,2.1e10,0.076,,,, +2005-04-14 14:05:22,4.9N,176.0W,26.5,7.1e10,0.22,,,, +2005-04-11 05:20:29,34.2S,95.7W,37.0,10.6e10,0.32,,,, +2005-04-06 01:30:24,42.7S,154.6E,70.0,2.9e10,0.1,,,, +2005-04-05 17:48:07,3.5e10,0.12,,,,,,, +2005-04-03 01:45:29,1.0S,112.4E,59.2,21.9e10,0.61,,,, +2005-04-02 22:52:25,14.1N,169.7E,27.2,20.4e10,0.57,,,, +2005-03-31 22:15:55,42.8N,36.2W,3.8e10,0.13,,,,, +2005-03-18 16:48:32,9.7S,34.7W,33.0,2.7e10,0.095,,,, +2005-03-12 22:16:31,2.2e10,0.079,,,,,,, +2005-03-09 15:47:36,21.4S,157.9W,44.4,5.3e10,0.17,,,, +2005-03-09 12:49:08,14.3N,142.7E,30.7,4.0e10,0.13,,,, +2005-03-06 17:32:51,5.5e10,0.18,,,,,,, +2005-02-22 22:51:06,4.1e10,0.14,,,,,,, +2005-02-17 22:52:36,48.0N,161.5W,42.5,10.0e10,0.3,,,, +2005-01-19 01:43:14,27.5S,164.9W,40.7,14.1e10,0.41,,,, +2005-01-02 23:09:51,21.3S,154.7E,35.2,21.5,20.2,-3.3,6.6,11.9e10,0.35 +2005-01-01 03:44:09,32.7N,12.4E,31.8,45.4e10,1.2,,,, +2004-12-29 07:11:45,8.5S,171.8E,9.0e10,0.28,,,,, +2004-12-13 11:35:55,9.7S,155.3E,3.9e10,0.13,,,,, +2004-12-11 15:36:51,36.0N,104.1E,3.0e10,0.1,,,,, +2004-11-30 08:32:53,61.0N,171.0W,18.1e10,0.51,,,,, +2004-11-17 03:13:04,18.6e10,0.52,,,,,,, +2004-10-14 11:41:01,9.3e10,0.28,,,,,,, +2004-10-10 11:05:28,3.0e10,0.1,,,,,,, +2004-10-07 13:14:43,27.3S,71.5E,35.0,19.2,-15.3,1.0,11.6,1.04e13,18 +2004-10-04 04:39:52,3.7N,150.9W,7.1e10,0.22,,,,, +2004-09-28 08:57:28,0.2N,101.1W,6.2e10,0.2,,,,, +2004-09-03 12:07:22,67.7S,18.2E,31.5,726.0e10,13,,,, +2004-08-22 10:01:33,51.9S,22.7E,37.0,144.0e10,3.2,,,, +2004-07-29 12:41:45,2.5e10,0.089,,,,,,, +2004-07-25 05:29:13,19.7e10,0.55,,,,,,, +2004-07-22 03:34:31,3.5e10,0.12,,,,,,, +2004-07-16 00:11:01,2.9e10,0.1,,,,,,, +2004-07-04 16:58:04,7.9e10,0.25,,,,,,, +2004-07-03 20:47:22,6.5e10,0.21,,,,,,, +2004-06-12 07:13:56,21.7N,175.3E,10.4e10,0.31,,,,, +2004-06-11 15:41:40,10.4e10,0.31,,,,,,, +2004-06-05 20:34:10,1.3N,174.4W,43.0,19.5,9.4,17.0,-1.5,181.0e10,3.9 +2004-06-04 13:41:38,33.9e10,0.89,,,,,,, +2004-06-03 21:59:15,4.7e10,0.16,,,,,,, +2004-06-03 09:40:12,48.9N,120.4W,5.4e10,0.18,,,,, +2004-05-18 11:12:12,28.1S,47.4W,39.4e10,1,,,,, +2004-05-17 02:08:27,18.9S,28.3E,44.0,5.5e10,0.18,,,, +2004-05-06 02:22:49,4.9e10,0.16,,,,,,, +2004-04-23 00:33:41,5.6e10,0.18,,,,,,, +2004-04-22 21:19:55,15.2S,55.1E,13.9e10,0.41,,,,, +2004-04-22 04:21:49,44.3S,83.3E,29.6,16.3,8.5,-12.1,-6.8,62.4e10,1.5 +2004-04-06 03:24:49,12.0S,162.8E,35.0,25.6,10.5,-23.2,-2.9,43.3e10,1.1 +2004-03-26 16:35:45,7.6S,155.1E,46.0,2.4e10,0.086,,,, +2004-03-25 09:39:26,4.8S,21.0E,2.1e10,0.076,,,,, +2004-02-27 01:18:54,6.0e10,0.19,,,,,,, +2004-02-02 18:52:20,18.3S,52.3E,3.0e10,0.1,,,,, +2004-01-22 01:06:43,50.6S,157.8E,37.0,23.2e10,0.64,,,, +2004-01-17 20:11:02,2.8e10,0.098,,,,,,, +2004-01-16 11:17:06,9.8e10,0.3,,,,,,, +2004-01-02 04:27:59,28.2S,3.2E,63.0,13.4e10,0.39,,,, +2003-12-09 22:36:23,67.1S,90.8W,64.3e10,1.6,,,,, +2003-11-26 02:00:04,22.9S,22.7E,32.0,3.5e10,0.12,,,, +2003-11-10 13:54:06,64.5S,136.2E,23.0,20.1,14.8,-8.7,10.4,51.8e10,1.3 +2003-11-01 14:09:30,51.4S,151.7E,7.3e10,0.23,,,,, +2003-10-16 00:47:28,28.5e10,0.77,,,,,,, +2003-10-13 14:06:59,3.0e10,0.1,,,,,,, +2003-10-07 00:23:56,3.7e10,0.13,,,,,,, +2003-09-27 12:59:02,21.0N,86.6E,26.0,18.2,-1.0,-5.4,-17.3,215.0e10,4.6 +2003-09-22 03:45:43,3.3e10,0.11,,,,,,, +2003-09-21 07:40:00,2.0e10,0.073,,,,,,, +2003-09-20 19:04:01,3.0e10,0.1,,,,,,, +2003-09-02 20:00:46,51.3N,161.0W,38.5e10,1,,,,, +2003-08-26 22:08:45,7.2e10,0.23,,,,,,, +2003-08-26 08:44:07,24.9e10,0.68,,,,,,, +2003-08-17 13:16:07,39.0S,34.0E,64.7e10,1.6,,,,, +2003-08-01 04:09:32,2.1e10,0.076,,,,,,, +2003-07-21 05:11:28,5.8e10,0.19,,,,,,, +2003-06-22 22:53:28,2.1e10,0.076,,,,,,, +2003-06-21 14:49:57,3.8e10,0.13,,,,,,, +2003-06-16 17:17:19,6.5e10,0.21,,,,,,, +2003-06-10 14:11:07,41.8S,122.9E,3.2e10,0.11,,,,, +2003-05-27 23:32:32,5.2N,166.2E,6.8e10,0.22,,,,, +2003-05-19 03:38:12,52.1e10,1.3,,,,,,, +2003-05-18 07:51:40,2.1e10,0.076,,,,,,, +2003-05-15 06:28:32,54.0N,80.4W,4.3e10,0.14,,,,, +2003-04-28 13:06:46,2.3e10,0.082,,,,,,, +2003-04-13 17:58:41,14.8N,64.5E,17.0,17.5e10,0.5,,,, +2003-04-07 09:25:28,18.4S,162.6E,2.2e10,0.079,,,,, +2003-04-01 04:40:55,3.1e10,0.11,,,,,,, +2003-03-27 05:50:26,41.4N,87.7W,45.0,14.2e10,0.41,,,, +2003-02-25 23:13:28,40.0N,116.0E,3.3e10,0.11,,,,, +2003-02-12 23:45:57,7.9e10,0.25,,,,,,, +2003-02-12 02:37:54,31.5S,107.5E,12.0e10,0.36,,,,, +2003-02-06 17:00:19,62.9S,113.9W,19.7e10,0.55,,,,, +2003-02-05 06:16:27,10.3e10,0.31,,,,,,, +2003-02-04 14:07:08,59.9S,41.0E,13.5e10,0.4,,,,, +2003-01-30 06:02:59,10.7e10,0.32,,,,,,, +2002-11-28 15:41:53,4.6e10,0.15,,,,,,, +2002-11-21 00:11:17,1.4S,154.0W,24.0e10,0.66,,,,, +2002-11-12 21:49:56,21.1S,6.8W,4.3e10,0.14,,,,, +2002-11-10 22:13:54,16.0N,166.0W,46.0e10,1.2,,,,, +2002-10-09 12:00:35,4.3S,175.9W,4.9e10,0.16,,,,, +2002-10-04 10:08:01,11.7e10,0.35,,,,,,, +2002-09-24 16:48:57,57.9N,112.9E,86.0e10,2,,,,, +2002-08-14 07:48:32,6.9S,126.2W,9.0e10,0.28,,,,, +2002-08-11 20:42:53,18.2S,159.4E,151.0e10,3.3,,,,, +2002-08-10 18:01:51,2.5e10,0.089,,,,,,, +2002-07-25 15:57:32,28.7S,47.0E,23.0e10,0.63,,,,, +2002-07-22 11:16:02,34.0N,106.1E,5.3e10,0.17,,,,, +2002-06-29 16:31:55,15.9e10,0.46,,,,,,, +2002-06-15 11:51:18,2.9e10,0.1,,,,,,, +2002-06-13 15:29:38,24.9S,111.4E,19.1e10,0.54,,,,, +2002-06-02 04:28:20,34.0N,21.0E,450.0e10,8.8,,,,, +2002-04-03 19:10:21,5.3S,27.1E,18.2e10,0.51,,,,, +2002-04-02 02:36:28,3.2e10,0.11,,,,,,, +2002-03-28 21:29:56,2.7e10,0.095,,,,,,, +2002-03-19 05:56:10,8.3e10,0.26,,,,,,, +2002-03-19 02:56:52,5.3e10,0.17,,,,,,, +2002-03-18 14:44:57,60.4S,120.5W,2.0e10,0.073,,,,, +2002-03-09 01:20:24,6.9N,147.3W,24.9e10,0.68,,,,, +2002-03-03 21:10:55,37.5N,154.0E,8.2e10,0.25,,,,, +2002-03-01 03:53:59,29.2N,66.8W,3.8e10,0.13,,,,, +2002-02-09 19:50:26,17.7S,138.7E,7.0e10,0.22,,,,, +2002-02-01 19:07:54,60.7N,116.6E,7.0e10,0.22,,,,, +2002-01-20 16:42:04,48.4N,165.0W,10.4e10,0.31,,,,, +2002-01-03 12:19:37,12.3e10,0.36,,,,,,, +2001-12-14 17:58:04,15.1e10,0.44,,,,,,, +2001-12-12 16:56:13,9.8e10,0.3,,,,,,, +2001-11-26 06:51:52,19.2e10,0.54,,,,,,, +2001-11-13 10:58:48,31.2e10,0.83,,,,,,, +2001-11-11 12:14:02,13.0e10,0.38,,,,,,, +2001-10-27 19:20:12,52.7N,3.8E,3.6e10,0.12,,,,, +2001-10-14 12:03:11,8.9e10,0.27,,,,,,, +2001-10-12 03:11:53,6.2e10,0.2,,,,,,, +2001-10-06 06:29:38,15.8e10,0.45,,,,,,, +2001-09-25 11:54:06,4.2e10,0.14,,,,,,, +2001-08-26 16:08:52,3.8e10,0.13,,,,,,, +2001-08-18 13:57:43,4.0e10,0.13,,,,,,, +2001-07-26 21:20:19,0.4N,84.8E,32.6e10,0.86,,,,, +2001-07-23 22:19:11,41.0N,77.0W,124.0e10,2.8,,,,, +2001-05-06 04:30:29,5.0e10,0.16,,,,,,, +2001-04-27 09:46:18,13.0e10,0.38,,,,,,, +2001-04-23 06:12:35,28.0N,133.6W,29,460.0e10,9,,,, +2001-04-14 06:40:36,2.4e10,0.086,,,,,,, +2001-04-13 00:29:57,15.3S,162.4E,25.1e10,0.68,,,,, +2001-02-09 21:27:55,10.8e10,0.32,,,,,,, +2001-02-04 05:53:38,64.0S,97.3E,15.1e10,0.44,,,,, +2001-01-28 16:19:18,66.0N,31.3E,10.8e10,0.32,,,,, +2000-12-15 13:22:59,41.3N,95.2E,26.2e10,0.71,,,,, +2000-12-15 03:46:27,50.4N,58.9E,2.7e10,0.095,,,,, +2000-11-28 12:20:13,11.9e10,0.35,,,,,,, +2000-11-13 00:28:01,13.6S,5.8W,6.6e10,0.21,,,,, +2000-11-06 07:18:57,52.0S,22.2W,6.9e10,0.22,,,,, +2000-10-11 23:29:55,31.7S,5.5W,8.1e10,0.25,,,,, +2000-09-24 06:57:19,2.7e10,0.095,,,,,,, +2000-09-23 04:00:45,58.5S,142.6E,2.2e10,0.079,,,,, +2000-09-19 22:12:38,3.2S,133.8W,8.9e10,0.27,,,,, +2000-08-25 01:12:25,14.5N,106.1W,138.5e10,3.1,,,,, +2000-08-13 03:00:32,36.7N,127.8W,6.5e10,0.21,,,,, +2000-08-01 16:48:27,50.2S,101.9W,18.2e10,0.51,,,,, +2000-07-31 07:06:34,15.7N,138.5W,3.8e10,0.13,,,,, +2000-07-19 17:40:25,17.7S,94.1E,10.7e10,0.32,,,,, +2000-07-15 16:13:29,46.6S,163.3E,2.1e10,0.076,,,,, +2000-07-09 01:08:45,12.1e10,0.36,,,,,,, +2000-07-07 01:34:20,15.0N,140.7E,6.5e10,0.21,,,,, +2000-06-27 10:06:51,34.9N,36.8E,2.7e10,0.095,,,,, +2000-06-23 09:03:42,69.2N,44.0W,2.0e10,0.073,,,,, +2000-06-22 20:02:11,32.9N,159.0E,3.0e10,0.1,,,,, +2000-06-18 13:40:02,13.3e10,0.39,,,,,,, +2000-06-14 16:39:18,28.1N,107.3E,48,14.5e10,0.42,,,, +2000-06-04 03:17:39,19.0e10,0.53,,,,,,, +2000-06-03 03:24:49,36.8N,74.8W,3.0e10,0.1,,,,, +2000-06-02 18:44:16,27.5S,18.9W,3.0e10,0.1,,,,, +2000-05-29 16:46:28,6.0e10,0.19,,,,,,, +2000-05-06 11:51:52,49.9N,18.4E,2.8e10,0.098,,,,, +2000-05-03 10:40:09,5.0S,73.0E,5.9e10,0.19,,,,, +2000-04-21 13:42:20,8.6e10,0.27,,,,,,, +2000-04-04 13:38:15,2.3e10,0.082,,,,,,, +2000-03-28 15:27:17,1.0N,98.3E,6.3e10,0.2,,,,, +2000-03-19 05:11:50,4.9e10,0.16,,,,,,, +2000-03-06 08:29:18,58.0N,175.0E,96.0e10,2.2,,,,, +2000-02-18 09:25:59,0.9S,109.2E,362.0e10,7.3,,,,, +2000-02-17 14:22:07,14.2N,115.9E,2.2e10,0.079,,,,, +2000-01-18 16:43:42,60.3N,134.6W,105.0e10,2.4,,,,, +2000-01-18 08:33:58,24.3N,94.9W,3.5e10,0.12,,,,, +1999-12-16 00:07:22,26.5S,11.3W,6.7e10,0.21,,,,, +1999-12-11 17:31:52,27.3e10,0.74,,,,,,, +1999-12-10 18:56:50,2.8e10,0.098,,,,,,, +1999-12-03 17:24:45,4.2e10,0.14,,,,,,, +1999-12-01 19:38:15,2.3e10,0.082,,,,,,, +1999-11-30 02:18:53,4.5e10,0.15,,,,,,, +1999-11-15 20:01:28,8.1S,75.4E,7.4e10,0.23,,,,, +1999-11-07 17:53:06,2.3S,77.4W,8.9e10,0.27,,,,, +1999-10-26 17:19:42,13.7N,70.8W,8.6e10,0.27,,,,, +1999-09-08 23:55:35,22.4N,0.2E,2.8e10,0.098,,,,, +1999-09-08 14:41:53,32.5N,104.6E,32,9.0e10,0.28,,,, +1999-08-16 05:18:20,35.0N,107.2W,3.6e10,0.12,,,,, +1999-08-06 03:22:37,6.8e10,0.22,,,,,,, +1999-08-03 18:25:49,64.7S,18.8W,35.6e10,0.93,,,,, +1999-07-10 08:11:42,37.8S,39.6E,52,32.6e10,0.86,,,, +1999-07-07 04:14:41,39.5S,174.4E,14.0e10,0.41,,,,, +1999-06-25 06:27:41,50.0N,121.0E,69.0,12.4e10,0.37,,,, +1999-05-23 07:02:10,16.4S,116.3W,2.6e10,0.092,,,,, +1999-04-26 11:33:06,22.5S,6.5E,9.2e10,0.28,,,,, +1999-04-26 09:49:26,32.8S,159.1E,3.3e10,0.11,,,,, +1999-03-31 23:54:35,17.9S,22.6E,23.4e10,0.64,,,,, +1999-03-28 15:37:01,0.8N,97.6E,30.4e10,0.81,,,,, +1999-03-02 22:23:25,18.9N,50.5E,5.9e10,0.19,,,,, +1999-02-18 23:15:25,54.9S,64.6W,15.4e10,0.44,,,,, +1999-02-01 14:24:09,80.0N,154.2E,2.8e10,0.098,,,,, +1999-01-19 02:32:21,7.9N,85.8E,2.4e10,0.086,,,,, +1999-01-14 08:06:05,44.0S,129.7W,32.0,506.0e10,9.8,,,, +1999-01-12 19:24:52,4.3e10,0.14,,,,,,, +1999-01-11 05:18:17,2.4e10,0.086,,,,,,, +1999-01-02 18:25:51,47.0N,103.0E,65.0,3.5e10,0.12,,,, +1998-12-22 09:24:00,2.7e10,0.095,,,,,,, +1998-11-23 20:20:14,82.3N,160.1E,2.5e10,0.089,,,,, +1998-11-11 16:46:18,6.5N,156.4E,65.6e10,1.6,,,,, +1998-10-03 12:58:50,3.2e10,0.11,,,,,,, +1998-09-04 09:16:11,12.8e10,0.38,,,,,,, +1998-09-01 11:15:04,34.6N,23.6E,2.4e10,0.086,,,,, +1998-08-30 00:20:12,4.1e10,0.14,,,,,,, +1998-08-08 12:55:22,2.3e10,0.082,,,,,,, +1998-07-28 14:16:53,6.3e10,0.2,,,,,,, +1998-03-24 09:08:14,2.7e10,0.095,,,,,,, +1998-03-22 22:25:37,1.4N,26.6E,14.0e10,0.41,,,,, +1998-01-08 16:10:21,6.2e10,0.2,,,,,,, +1998-01-04 23:00:27,35.1S,33.4E,30.0,17.1,6.0,-10.6,12.0,7.4e10,0.23 +1997-12-28 03:58:18,23.1S,152.4E,3.1e10,0.11,,,,, +1997-12-09 08:15:55,62.7N,49.9W,27.0e10,0.73,,,,, +1997-11-07 07:46:55,57.3S,167.2E,80.0e10,1.9,,,,, +1997-10-09 18:47:15,31.8N,106.0W,37.0,19.0e10,0.53,,,, +1997-10-01 14:26:43,46.7N,108.9E,6.2e10,0.2,,,,, +1997-09-30 12:31:18,38.1S,63.9E,2.3e10,0.082,,,,, +1997-09-05 11:41:54,31.1S,56.4E,19.0e10,0.53,,,,, +1997-08-20 17:16:43,2.6e10,0.092,,,,,,, +1997-08-15 01:05:22,2.2e10,0.079,,,,,,, +1997-07-30 03:01:51,5.0e10,0.16,,,,,,, +1997-07-04 12:22:33,15.8S,175.8W,2.7e10,0.095,,,,, +1997-05-22 08:30:15,4.5e10,0.15,,,,,,, +1997-04-27 22:34:21,16.7N,87.5E,32.5e10,0.86,,,,, +1997-02-19 04:31:35,16.3S,87.7W,14.0e10,0.41,,,,, +1997-02-15 15:23:35,35.5N,115.6E,15.0e10,0.43,,,,, +1997-02-06 18:28:34,2.6e10,0.092,,,,,,, +1997-01-28 17:49:49,2.4e10,0.086,,,,,,, +1997-01-23 10:03:27,15.0S,94.2E,27.0e10,0.73,,,,, +1997-01-22 21:13:16,32.2N,29.0E,48.0e10,1.2,,,,, +1997-01-04 06:46:39,25.7N,5.3W,4.3e10,0.14,,,,, +1997-01-03 15:08:07,35.0e10,0.92,,,,,,, +1996-12-17 04:16:18,34.1N,37.2W,4.1e10,0.14,,,,, +1996-12-10 06:09:32,25.0e10,0.68,,,,,,, +1996-12-04 17:00:34,4.9e10,0.16,,,,,,, +1996-12-01 13:19:35,6.2e10,0.2,,,,,,, +1996-11-22 10:06:17,6.8e10,0.22,,,,,,, +1996-11-08 16:02:13,6.1e10,0.2,,,,,,, +1996-10-30 12:48:19,2.1S,123.1W,2.1e10,0.076,,,,, +1996-10-28 04:46:21,27.4N,79.4W,4.3e10,0.14,,,,, +1996-10-23 08:28:06,47.3S,20.6E,4.4e10,0.15,,,,, +1996-10-19 19:01:08,29.7N,34.7W,13.0e10,0.38,,,,, +1996-10-07 17:43:44,4.5e10,0.15,,,,,,, +1996-10-05 19:21:02,49.6S,145.9E,25.0e10,0.68,,,,, +1996-08-17 15:46:08,3.4e10,0.12,,,,,,, +1996-08-15 16:07:51,8.4e10,0.26,,,,,,, +1996-08-09 18:14:56,3.0e10,0.1,,,,,,, +1996-08-07 03:16:03,15.0e10,0.43,,,,,,, +1996-08-06 04:50:32,13.0e10,0.38,,,,,,, +1996-08-05 19:27:52,22.0e10,0.61,,,,,,, +1996-08-05 15:19:30,8.0e10,0.25,,,,,,, +1996-07-17 03:16:07,31.8N,111.4E,5.0e10,0.16,,,,, +1996-07-12 14:04:45,20.7N,93.6W,3.2e10,0.11,,,,, +1996-06-25 11:22:40,2.1e10,0.076,,,,,,, +1996-05-08 01:02:05,2.8e10,0.098,,,,,,, +1996-05-01 13:19:25,3.5e10,0.12,,,,,,, +1996-03-31 00:53:57,2.7e10,0.095,,,,,,, +1996-03-30 04:03:32,31.1S,84.3W,12.0e10,0.36,,,,, +1996-03-29 20:30:54,21.5N,158.1W,12.8e10,0.38,,,,, +1996-03-25 17:00:41,4.4e10,0.15,,,,,,, +1996-03-13 08:31:01,23.0e10,0.63,,,,,,, +1996-02-16 07:03:14,5.5e10,0.18,,,,,,, +1996-02-15 02:38:05,76.0N,127.0W,5.0e10,0.16,,,,, +1996-01-18 17:10:49,12.0e10,0.36,,,,,,, +1996-01-15 13:44:23,59.8S,175.8E,26.0e10,0.71,,,,, +1995-12-27 12:55:01,2.2e10,0.079,,,,,,, +1995-12-22 13:26:29,70.2S,73.3W,45.0e10,1.1,,,,, +1995-12-09 19:54:26,2.9S,79.0W,12.0e10,0.36,,,,, +1995-11-25 05:29:31,2.9e10,0.1,,,,,,, +1995-11-13 03:10:47,2.1e10,0.076,,,,,,, +1995-10-01 02:42:01,3.5e10,0.12,,,,,,, +1995-09-09 07:38:38,50.0e10,1.3,,,,,,, +1995-08-24 21:54:35,12.0e10,0.36,,,,,,, +1995-08-17 16:39:02,16.0e10,0.46,,,,,,, +1995-08-06 04:38:09,5.5e10,0.18,,,,,,, +1995-08-05 17:14:10,11.6N,104.3W,20.0e10,0.56,,,,, +1995-07-11 18:38:41,28.5S,93.3E,13.0e10,0.38,,,,, +1995-07-09 18:20:09,0.9S,66.3E,2.5e10,0.089,,,,, +1995-07-07 17:33:37,40.2N,76.1W,14.0e10,0.41,,,,, +1995-06-09 09:28:38,2.5e10,0.089,,,,,,, +1995-04-02 12:32:38,2.5e10,0.089,,,,,,, +1995-02-16 13:05:47,16.7N,141.7W,6.0e10,0.19,,,,, +1995-01-18 10:17:26,51.5N,115.4E,7.0e10,0.22,,,,, +1995-01-10 21:08:41,2.5e10,0.089,,,,,,, +1995-01-04 04:16:17,46.4N,12.1E,4.1e10,0.14,,,,, +1995-01-02 20:41:38,3.0e10,0.1,,,,,,, +1994-12-18 12:45:40,5.0e10,0.16,,,,,,, +1994-12-16 09:41:03,42.2S,27.6E,5.0e10,0.16,,,,, +1994-11-03 20:01:36,6.5N,89.0E,235.0e10,5,,,,, +1994-11-01 06:50:46,1.5S,84.5W,100.0e10,2.3,,,,, +1994-10-27 04:21:29,32.0e10,0.85,,,,,,, +1994-10-20 00:11:21,45.2S,1.9W,8.7e10,0.27,,,,, +1994-10-08 03:24:22,6.6e10,0.21,,,,,,, +1994-09-22 04:22:17,6.7e10,0.21,,,,,,, +1994-08-15 23:16:48,16.4e10,0.47,,,,,,, +1994-06-15 00:02:26,45.0N,73.5W,4.1e10,0.14,,,,, +1994-06-03 20:48:42,50.9e10,1.3,,,,,,, +1994-05-29 09:30:58,52.8N,2.3E,38.4e10,1,,,,, +1994-02-01 22:38:09,2.7N,164.1E,1.82e13,30,,,,, +1993-11-29 17:48:41,26.5N,78.3E,2.6e10,0.092,,,,, +1993-10-31 03:39:27,51.3N,100.9W,4.0e10,0.13,,,,, +1991-10-04 09:22:47,78.7N,6.3E,55.0e10,1.4,,,,, +1990-10-01 03:51:47,7.5N,142.8E,250.0e10,5.2,,,,, +1988-04-15 03:03:10,4.1S,124.3E,758e10,14,,,,, \ No newline at end of file diff --git a/legacy/0-coursework/simple_text.txt b/legacy/0-coursework/simple_text.txt new file mode 100644 index 0000000..5be377b --- /dev/null +++ b/legacy/0-coursework/simple_text.txt @@ -0,0 +1 @@ +The quick brown fox jumps over the lazy dog! diff --git a/legacy/0-coursework/stundent_grades.json b/legacy/0-coursework/stundent_grades.json new file mode 100644 index 0000000..1cc1413 --- /dev/null +++ b/legacy/0-coursework/stundent_grades.json @@ -0,0 +1 @@ +[{"name": "Stanley", "math": "85", "science": "90", "history": "92"}, {"name": "Casey", "math": "75", "science": "80", "history": "85"}, {"name": "Taylor", "math": "95", "science": "100", "history": "100"}] \ No newline at end of file diff --git a/1-git_and_github/.ignore/git-model.png b/legacy/1-git_and_github/.ignore/git-model.png similarity index 100% rename from 1-git_and_github/.ignore/git-model.png rename to legacy/1-git_and_github/.ignore/git-model.png diff --git a/1-git_and_github/.ignore/graph_reference.png b/legacy/1-git_and_github/.ignore/graph_reference.png similarity index 100% rename from 1-git_and_github/.ignore/graph_reference.png rename to legacy/1-git_and_github/.ignore/graph_reference.png diff --git a/1-git_and_github/README.md b/legacy/1-git_and_github/README.md similarity index 100% rename from 1-git_and_github/README.md rename to legacy/1-git_and_github/README.md diff --git a/2-python_basics/README.md b/legacy/2-python_basics/README.md similarity index 99% rename from 2-python_basics/README.md rename to legacy/2-python_basics/README.md index 9e7f278..d5d95a8 100644 --- a/2-python_basics/README.md +++ b/legacy/2-python_basics/README.md @@ -54,18 +54,13 @@ Python 3 converts to float during division unless `//` is used instead of `/`. In [1]: x = 1 In [2]: x / 2 +Out[2]: 0.5 + +In [2]: x // 2 Out[2]: 0 In [3]: x % 2 Out[3]: 1 - -In [4]: x = 1.0 - -In [5]: x / 2 -Out[5]: 0.5 - -In [6]: x % 2 -Out[6]: 1.0 ``` Python has built in support for complex numbers. ```python diff --git a/2-python_basics/problems.py b/legacy/2-python_basics/problems.py similarity index 100% rename from 2-python_basics/problems.py rename to legacy/2-python_basics/problems.py diff --git a/3-files_and_paths/README.md b/legacy/3-files_and_paths/README.md similarity index 100% rename from 3-files_and_paths/README.md rename to legacy/3-files_and_paths/README.md diff --git a/3-files_and_paths/problems.py b/legacy/3-files_and_paths/problems.py similarity index 100% rename from 3-files_and_paths/problems.py rename to legacy/3-files_and_paths/problems.py diff --git a/4-system_and_env/README.md b/legacy/4-system_and_env/README.md similarity index 100% rename from 4-system_and_env/README.md rename to legacy/4-system_and_env/README.md diff --git a/4-system_and_env/problems.py b/legacy/4-system_and_env/problems.py similarity index 100% rename from 4-system_and_env/problems.py rename to legacy/4-system_and_env/problems.py diff --git a/5-data_manipulation/README.md b/legacy/5-data_manipulation/README.md similarity index 100% rename from 5-data_manipulation/README.md rename to legacy/5-data_manipulation/README.md diff --git a/5-data_manipulation/problems.py b/legacy/5-data_manipulation/problems.py similarity index 61% rename from 5-data_manipulation/problems.py rename to legacy/5-data_manipulation/problems.py index 6941c65..e4045fb 100755 --- a/5-data_manipulation/problems.py +++ b/legacy/5-data_manipulation/problems.py @@ -1,13 +1,12 @@ #!/usr/bin/env python -import argparse +import json import os import random import re import shutil import string -import subprocess as sp -import sys +import yaml DATA_C = '''name,age,favorite_color dan,90,green @@ -130,9 +129,73 @@ def dictToCSVFile(csv_path, data): #return nothing - - - +def readingFormat(file_path, file_format): + '''data_4 + Write a function caled readingFormat that accepts a file path to a json + or yaml formatted file and a string, either "json" or "yaml", and + reads in the file as the corresponding type and resturns the resulting + python data structure. + >>> f0 = _randStr() + >>> json.dump(open(f0, 'w'), DATA_LDL) + >>> DATA_LDL == readingFormat(f0, 'json') + True + >>> os.remove(f0) + >>> f1 = _randStr() + >>> open(f1, 'w').write(yaml.dump(DATA_LDL)) + >>> DATA_LDL == readingFormat(f1, 'yaml') + True + >>> os.remove(f1) + ''' + with open(file_path, 'r') as f: + result_data = yaml.load(f.read()) + return result_data + +def writingFormat(file_path, data_object, file_format='json'): + '''data_5 + Write a function called writingFormat that accepts a file path, a + python object and a string, either 'json' or 'yaml', and writes + the data object to the given file path in the corresponding format. + >>> f0 = _randStr() + >>> writingFormat(f0, DATA_LDL, 'json') + >>> DATA_LDL == json.load(open(f0, 'r')) + True + >>> os.path.exists(f0) and os.remove(f0) + >>> writingFormat(f0, DATA_LDL, 'yaml') + >>> DATA_LDL == yaml.load(open(f0, 'r').read()) + True + >>> os.remove(f0) + ''' + if file_format == 'json': + json.dump(open(file_path, 'w'), data_object) + elif file_format == 'yaml': + open(file_path, 'w').write(yaml.dump(data_object)) + #return nothing + +def somethingWithRegex(content, regex_str): + '''data_6 + foo + ''' + pass + #return bool + +class dbHandler(extends Object): + '''Create a class called dbHndler that abstracts interaction with a + sqlite database into a couple of methods. On __init__, the path to + the qslite db is given with the table name to interact with, and, + optoinally, the headers to create the table with. If the table does + not already exist, headers are required or an exceptoin should be raised. + ''' + def __init__(self, db_path, table_name, headers=None): + # initialize db cursor + #self.cursor = foobar + self.table = table_name + def writeLine(content): + '''append a row onto the db table''' + pass + def readLines(): + '''return a list of dictoinaries continaing all rows in the table. + ''' + pass if __name__ == '__main__': import doctest diff --git a/6-exception_hadling/README.md b/legacy/6-exception_handling/README.md similarity index 100% rename from 6-exception_hadling/README.md rename to legacy/6-exception_handling/README.md diff --git a/7-Unit_Testing/README.md b/legacy/7-unit_testing/README.md similarity index 100% rename from 7-Unit_Testing/README.md rename to legacy/7-unit_testing/README.md diff --git a/legacy/8-pandas/README.md b/legacy/8-pandas/README.md new file mode 100644 index 0000000..4fda40e --- /dev/null +++ b/legacy/8-pandas/README.md @@ -0,0 +1,9 @@ +Foo +# Index: +* [Importing Pandas](#importing-pandas) +* [Loading Data](#loading-data) + * csv, xlsx, json +* + +# Reference: +* https://medium.com/dunder-data/minimally-sufficient-pandas-a8e67f2a2428 diff --git a/EXAMPLES/args.py b/legacy/EXAMPLES/args.py similarity index 100% rename from EXAMPLES/args.py rename to legacy/EXAMPLES/args.py diff --git a/EXAMPLES/hangman.py b/legacy/EXAMPLES/hangman.py similarity index 100% rename from EXAMPLES/hangman.py rename to legacy/EXAMPLES/hangman.py diff --git a/EXAMPLES/loop_else.py b/legacy/EXAMPLES/loop_else.py similarity index 100% rename from EXAMPLES/loop_else.py rename to legacy/EXAMPLES/loop_else.py diff --git a/EXAMPLES/readfiles.py b/legacy/EXAMPLES/readfiles.py similarity index 100% rename from EXAMPLES/readfiles.py rename to legacy/EXAMPLES/readfiles.py diff --git a/EXAMPLES/universal_nogui_widget.py b/legacy/EXAMPLES/universal_nogui_widget.py similarity index 100% rename from EXAMPLES/universal_nogui_widget.py rename to legacy/EXAMPLES/universal_nogui_widget.py diff --git a/EXAMPLES/variable_scope.py b/legacy/EXAMPLES/variable_scope.py similarity index 100% rename from EXAMPLES/variable_scope.py rename to legacy/EXAMPLES/variable_scope.py diff --git a/EXAMPLES/wordlist b/legacy/EXAMPLES/wordlist similarity index 100% rename from EXAMPLES/wordlist rename to legacy/EXAMPLES/wordlist diff --git a/EXAMPLES/writefile.py b/legacy/EXAMPLES/writefile.py similarity index 100% rename from EXAMPLES/writefile.py rename to legacy/EXAMPLES/writefile.py