diff --git a/02_linux_ex1/README b/02_linux_ex1/README index 2fab31e8..65522175 100644 --- a/02_linux_ex1/README +++ b/02_linux_ex1/README @@ -9,4 +9,4 @@ Kernel System Calls Binary Numbers -------------- -< Your Answer > \ No newline at end of file +< Your Answer > \ No newline at end of file diff --git a/06_linux_ex2/README b/06_linux_ex2/README index 8489ffb1..62f42731 100644 --- a/06_linux_ex2/README +++ b/06_linux_ex2/README @@ -1,2 +1,58 @@ -name@example.com +doron.dollev@gmail.com +### Processes handling + +**(Q1)** A user started a process and logged out from the terminal. Which command he used if the process still running in the background: + +* nohup + + +**(Q2)** The `kill` command always terminates a process. + +* False + + +**(Q3)** Which command could be used to know how many processes are running in the background terminal session? + +* jobs + + +**(Q4)** Given a terminal session with long process running in it, how will you ask this process to terminate? + +* CTRL+c + + +**(Q5)** Given a terminal session with long process running in it, how will you ask this process the stop? + +* CTRL+z + + +**(Q6)** How would you run the `sleep 10` command as a foreground process? + +* sleep 10 + + +**(Q7)** Which of the following command would deliver a SIGTERM to the `xscreensaver` process? + +* None of the above + + +**(Q8)** Which of the following would deliver a SIGKILL to the `xscreensaver` command? + +* kill -9 4846 + + +**(Q9)** Which of the following would send a SIGCHLD (signal number 17) to the `ssh-agent` process? + +* kill -CHLD 4828 + + +**(Q10)** Which key pressed within the `top` command allows the user to send a signal to a process? + +* k + + +**(Q11 - easy 5 points bonus)** Open a new terminal session and type the command `python`. Then send a SIGINT signal using your keyboard. What best describes + how the python process responds to the SIGINT signal? + +* The program has implemented a custom signal handler for the SIGINT signal. diff --git a/06_linux_ex2/tlsHandshake.sh b/06_linux_ex2/tlsHandshake.sh index e69de29b..49180fe5 100644 --- a/06_linux_ex2/tlsHandshake.sh +++ b/06_linux_ex2/tlsHandshake.sh @@ -0,0 +1,46 @@ +#!/bin/bash +echo "Initializing random number generator..." +openssl rand -out masterKey.txt -base64 32 +if [ $? -gt 0 ] +then + echo "couldn't generate key 32 based" + exit 1 +fi +curl -X POST -H "Content-Type: application/json" -d '{"clientVersion":"3.2","message":"Client Hello"}' http://devops-jan22-1273001359.eu-north-1.elb.amazonaws.com:8080/clienthello | jq -r '.serverCert,.sessionID' >tmp.txt +STATUS=$? +if [ $STATUS -gt 0 ] +then + echo "run \"man curl|jq\" end check for details for error status number $STATUS" + # for example: "error 20 at 0 depth lookup: unable to get local issuer certificate" + # This is Eve that is the reason error 20 is unlisted in curl + exit 1 +fi +# Instead could be used /clienthello -o (>) tmp.txt and use twice jq -r on cert.pem and sessionID +head --lines=-1 tmp.txt>cert.pem +export SESSION_ID=$( tail -1 tmp.txt ) +rm -f tmp.txt +export VERIFICATION_RESULT=$( openssl verify -CAfile cert-ca-aws.pem cert.pem ) + +if [ "$VERIFICATION_RESULT" != "cert.pem: OK" ] +then + echo "Server Certificate is invalid." + exit 1 +fi + +MASTER_KEY=$( openssl smime -encrypt -aes-256-cbc -in masterKey.txt -outform DER cert.pem | base64 -w 0 ) +curl -X POST -H 'Content-Type: application/json' -d '{"sessionID": "'$SESSION_ID'","masterKey": "'$MASTER_KEY'","sampleMessage": "Hi server, please encrypt me and send to client!"}' http://devops-jan22-1273001359.eu-north-1.elb.amazonaws.com:8080/keyexchange | jq -r '.encryptedSampleMessage' > encSampleMsg.txt +STATUS=$? +if [ $STATUS -gt 0 ] +then + echo "run \"man curl|jq\" end check for details for error status number $STATUS" + exit 1 +fi +cat encSampleMsg.txt | base64 -d > encSampleMsgReady.txt +openssl enc -d -aes-256-cbc -pbkdf2 -kfile masterKey.txt -in encSampleMsgReady.txt -out decrypted_secret.txt +export DECRYPTED_SAMPLE_MESSAGE=`cat decrypted_secret.txt` +if [ "$DECRYPTED_SAMPLE_MESSAGE" != "Hi server, please encrypt me and send to client!" ]; then + echo "Server symmetric encryption using the exchanged master-key has failed." + exit 1 +else + echo "Client-Server TLS handshake has been completed successfully" +fi \ No newline at end of file diff --git a/python_katas/kata_1/questions.py b/python_katas/kata_1/questions.py index 9ad97b58..00942287 100644 --- a/python_katas/kata_1/questions.py +++ b/python_katas/kata_1/questions.py @@ -1,3 +1,4 @@ + def sum_of_element(elements): """ 1 Kata @@ -5,11 +6,7 @@ def sum_of_element(elements): :param elements: list of integers :return: Return int - the sum of all elements. """ - s = 0 - for num in elements: - s = s + num - - return s + return sum(elements) def verbing(word): @@ -28,7 +25,15 @@ def verbing(word): :param word: str :return: Return the resulting string. """ - return None + my_str = word + if len(my_str) < 3: + return my_str + elif my_str[-3:] == 'ing': + my_str = my_str[:-3] + my_str += 'ly' + else: + my_str += 'ing' + return my_str def words_concatenation(words): @@ -43,14 +48,15 @@ def words_concatenation(words): :param words: list of str :return: Return the resulting string. """ - return None + my_lst = ' '.join(words) + return my_lst def reverse_words_concatenation(words): """ 1 Kata - Given a list of words, write a program that concatenates the words in a reverse way + Given a list of words, write a program that concatenates the words in a reverse way (both words and each word itself) For example: reverse_words_concatenation(['take', 'me', 'home']) returns 'home me take' @@ -58,14 +64,17 @@ def reverse_words_concatenation(words): :param words: list of str :return: Return the resulting string. """ - return None + strings = words + strings.reverse() + my_lst = words_concatenation(strings) + return my_lst def is_unique_string(some_str): """ 2 Kata - Given a string, the function returns True if all characters in the string are unique, False otherwise + Given a string, the function returns True is all characters in the string are unique, False otherwise e.g 'abcd' -> True @@ -75,10 +84,14 @@ def is_unique_string(some_str): :param some_str: :return: bool """ - return None + if len(set(some_str)) == len(some_str): + return True + else: + return False def list_diff(elements): + """ 1 Kata @@ -86,27 +99,38 @@ def list_diff(elements): reduces by its previous one. The first element should be None e.g. - [1, 2, 3, 4, 7, 11] -> [None, 1, 1, 1, 3, 4] + [1, 2, 3, 4, 7, 11] -> [None, 1, 1, 3, 4] [] -> [] [1, 5, 0, 4, 1, 1, 1] -> [None, 4, -5, 4, -3, 0, 0] :param elements: list of integers :return: the diff list """ - return None + if len(elements) > 1: + diff_list = [elements[i] - elements[i - 1] for i in range(1, len(elements))] + diff_list.insert(0, None) + return diff_list + elif len(elements) > 0: + return [None] + else: + return [] def prime_number(num): """ - 1 Kata + 1 Kata - Check if the given number is prime or not. + Check if the given number is prime or not. - hint: use the built-in function "range" - :param num: the number to check - :return: bool. True if prime, else False - """ - return None + hint: use the built-in function "range" + :param num: the number to check + :return: bool. True if prime, else False + """ + if num > 1: + for i in range(2, num): + if (num % i) == 0: + return False + return True def palindrome_num(num): @@ -122,7 +146,12 @@ def palindrome_num(num): :param num: int :return: bool. True is palindrome, else False """ - return None + my_num = str(num) + my_rnum = my_num[::-1] + if my_num == my_rnum: + return True + else: + return False def pair_match(men, women): @@ -153,19 +182,27 @@ def pair_match(men, women): :param women: dict mapping name -> age :return: tuple (men_name, women_name) such their age absolute difference is the minimal """ - return None + minimum = 1000 + # dict_diff = {} # empty dictionary + for m in men.keys(): # run over all men + for w in women.keys(): # run over all women + diff_age = abs(men[m] - women[w]) + if diff_age < minimum: + minimum = diff_age + couple = (m, w) + return couple def bad_average(a, b, c): """ - 1 Kata + 1 Kata: fixed This function gets 3 numbers and calculates the average. There is a mistake in the following implementation, you are required to fix it :return: """ - return a + b + c / 3 + return (a + b + c) / 3 def best_student(grades): @@ -188,7 +225,10 @@ def best_student(grades): :param grades: dict of name -> grade mapping :return: str. some key from the dict """ - return None + sorted_values = sorted(grades.values()) + for key, value in grades.items(): + if sorted_values[-1] == value: + return key def print_dict_as_table(some_dict): @@ -217,7 +257,10 @@ def print_dict_as_table(some_dict): :param some_dict: :return: """ - return None + print("{:<7} {}".format('Key', 'Value')) + print("{}".format('-' * 13)) + for key, value in some_dict.items(): + print("{:<7} {}".format(key, value)) def merge_dicts(dict1, dict2): @@ -237,7 +280,9 @@ def merge_dicts(dict1, dict2): :param dict2: :return: """ - return dict1 + dict3 = dict1.copy() + dict3.update(dict2) + return dict3 def seven_boom(n): @@ -252,7 +297,9 @@ def seven_boom(n): :param n: int. The last number for count for a 7-boom play :return: list of integers """ - return None + boom = [] + [boom.append(x) if '7' in str(x) or x % 7 == 0 else x for x in range(0, n - 1)] + return boom def caesar_cipher(str_to_encrypt): @@ -267,7 +314,27 @@ def caesar_cipher(str_to_encrypt): :return: """ - return None + key = 3 + encryption = "" + + for c in str_to_encrypt: + if c.isspace(): + encryption += c + elif c.isupper(): + c_unicode = ord(c) + c_index = c_unicode - ord("A") + new_index = (c_index + key) % 26 + new_unicode = new_index + ord("A") + new_c = chr(new_unicode) + encryption += new_c + elif c.islower: + c_unicode = ord(c) + c_index = c_unicode - ord("a") + new_index = (c_index + key) % 26 + new_unicode = new_index + ord("a") + new_c = chr(new_unicode) + encryption += new_c + return encryption def sum_of_digits(digits_str): @@ -285,7 +352,9 @@ def sum_of_digits(digits_str): :param digits_str: str of numerical digits only :return: int representing the sum of digits """ - return None + chars_array = [char for char in digits_str] + int_array = [int(c) for c in chars_array] + return sum(int_array) if __name__ == '__main__': diff --git a/python_katas/kata_2/mnist-predictor.yaml b/python_katas/kata_2/mnist-predictor.yaml index 989de028..2cc31bc3 100644 --- a/python_katas/kata_2/mnist-predictor.yaml +++ b/python_katas/kata_2/mnist-predictor.yaml @@ -18,7 +18,7 @@ spec: terminationGracePeriodSeconds: 30 containers: - name: mnist-predictor - image: {{REGISTRY_URL}}/{{IMG_NAME}} + image: {{REGISTRY_URL}}/mnist-pred:0.0.1 --- apiVersion: v1 kind: Service diff --git a/python_katas/kata_2/questions.py b/python_katas/kata_2/questions.py index a7f0908a..3e24bb9a 100644 --- a/python_katas/kata_2/questions.py +++ b/python_katas/kata_2/questions.py @@ -1,3 +1,8 @@ +import os +import json +import re + + def valid_parentheses(s): """ 3 Kata @@ -13,7 +18,18 @@ def valid_parentheses(s): s = '[[{()}](){}]' -> True s = '[{]}' -> False """ - return None + stack = [] + parentheses_pairs = {")": "(", "]": "[", "}": "{"} + + for i in s: + if i in parentheses_pairs: + if stack and stack[-1] == parentheses_pairs[i]: + stack.pop() + else: + return False + else: + stack.append(i) + return True if not stack else False def fibonacci_fixme(n): @@ -36,12 +52,12 @@ def fibonacci_fixme(n): """ a = 0 b = 1 - for i in range(1, n): + tmp = a + for i in range(0, n): a = b - tmp = a + b b = tmp - - return a + tmp = a + b + return tmp def most_frequent_name(file_path): @@ -56,7 +72,18 @@ def most_frequent_name(file_path): :param file_path: str - absolute or relative file to read names from :return: str - the mose frequent name. If there are many, return one of them """ - return None + my_file = open(file_path, "r") + content = my_file.read() + content_list = content.split(" ") + my_file.close() + element = content_list[0] + counter = 0 + for i in content_list: + cur = content_list.count(i) + if cur > counter: + counter = cur + element = i + return element def files_backup(dir_path): @@ -76,7 +103,11 @@ def files_backup(dir_path): :param dir_path: string - path to a directory :return: str - the backup file name """ - return None + path_to_dir = dir_path.split("/") + source_dir = (path_to_dir[-1]) + command = "/usr/bin/tar zcvf backup_{0}_`date +%Y-%m-%d`.tar.gz {1}".format(source_dir, dir_path) + status = os.system(command) + return source_dir def replace_in_file(file_path, text, replace_text): @@ -93,33 +124,40 @@ def replace_in_file(file_path, text, replace_text): :param replace_text: text to replace with :return: None """ + if os.path.exists(file_path): + file = open(file_path, "r") + data = file.read() + data = data.replace(text, replace_text) + file.close() + file = open(file_path, "w") + file.write(data) return None def json_configs_merge(*json_paths): """ 2 Kata - This function gets an unknown number of paths to json files (represented as tuple in json_paths argument) it reads the files content as a dictionary, and merges all of them into a single dictionary, in the same order the files have been sent to the function! - :param json_paths: :return: dict - the merges json files """ - return None + for file in json_paths: + with open(file) as data: + my_dict = json.load(data) + return my_dict def monotonic_array(lst): """ 1 Kata - This function returns True/False if the given list is monotonically increased or decreased - :param lst: list of numbers (int, floats) :return: bool: indicating for monotonicity """ - return None + return (all(lst[i] <= lst[i + 1] for i in range(len(lst) - 1)) or all( + lst[i] >= lst[i + 1] for i in range(len(lst) - 1))) def matrix_avg(mat, rows=None): @@ -133,7 +171,17 @@ def matrix_avg(mat, rows=None): :param rows: list of unique integers in the range [0, 2] and length of maximum 3 :return: int - the average values """ - return None + mylist = 0 + rng = 0 + if rows is not None: + for i in rows: + mylist += sum(mat[i]) + rng += len(mat[i]) + else: + for j in range(len(mat)): + mylist += sum(mat[j]) + rng += len(mat[j]) + return mylist / rng def merge_sorted_lists(l1, l2): @@ -149,7 +197,22 @@ def merge_sorted_lists(l1, l2): :param l2: list of integers :return: list: sorted list combining l1 and l2 """ - return None + sizeof_l1 = len(l1) + sizeof_l2 = len(l2) + + res = [] + i = 0 + j = 0 + + while i < sizeof_l1 and j < sizeof_l2: + if l1[i] < l2[j]: + res.append(l1[i]) + i += 1 + else: + res.append(l2[j]) + j += 1 + res = res + l1[i:] + l2[j:] + return res def longest_common_substring(str1, str2): @@ -169,7 +232,24 @@ def longest_common_substring(str1, str2): :param str2: str :return: str - the longest common substring """ - return None + m = len(str1) + n = len(str2) + counter = [[0] * (n + 1) for x in range(m + 1)] + longest = 0 + lcs = set() + for i in range(m): + for j in range(n): + if str1[i] == str2[j]: + c = counter[i][j] + 1 + counter[i + 1][j + 1] = c + if c > longest: + lcs = set() + longest = c + lcs.add(str1[i - c + 1:i + 1]) + elif c == longest: + lcs.add(str1[i - c + 1:i + 1]) + + return lcs def longest_common_prefix(str1, str2): @@ -188,7 +268,13 @@ def longest_common_prefix(str1, str2): :param str2: str :return: str - the longest common prefix """ - return None + i = j = 0 + while i < len(str1) and j < len(str2): + if str1[i] != str2[j]: + break + i = i + 1 + j = j + 1 + return str1[:i] def rotate_matrix(mat): @@ -214,7 +300,15 @@ def rotate_matrix(mat): :param mat: :return: list of lists - rotate matrix """ - return None + rows = len(mat) + cols = len(mat[0]) + + mat2 = [[""] * rows for _ in range(cols)] + + for i in range(rows): + for j in range(cols): + mat2[j][rows - i - 1] = box[i][j] + return mat2 def is_valid_email(mail_str): @@ -269,7 +363,19 @@ def pascal_triangle(lines): :param lines: int :return: None """ - return None + lst = [] # an empty list + for n in range(lines): + lst.append([]) + lst[n].append(1) + for m in range(1, n): + lst[n].append(lst[n - 1][m - 1] + lst[n - 1][m]) + if lines != 0: + lst[n].append(1) + for n in range(lines): + print(" " * (lines - n), end=" ", sep=" ") + for m in range(0, n + 1): + print('{0:5}'.format(lst[n][m]), end=" ", sep=" ") + print() def list_flatten(lst): @@ -278,7 +384,7 @@ def list_flatten(lst): This function gets a list of combination of integers or nested lists e.g. - [1, [], [1, 2, [4, 0, [5], 6], [5, 4], 34, 0], [3]] + [1, [], [1, 2, [4, 0, [5], 6], [5, 4], 34, 0, [3]] The functions should return a flatten list (including all nested lists): [1, 1, 2, 4, 0, 5, 6, 5, 4, 34, 0, 3] @@ -286,7 +392,10 @@ def list_flatten(lst): :param lst: list of integers of another list :return: flatten list """ - return None + for i, x in enumerate(lst): + while i < len(lst) and isinstance(lst[i], list): + lst[i:i + 1] = lst[i] + return lst def str_compression(text): @@ -306,7 +415,20 @@ def str_compression(text): :param text: str :return: list representing the compressed form of the string """ - return None + lst = [] + cnt = 1 + for i in range(1, len(text)): + if text[i] == text[i-1]: + cnt += 1 + else: + lst.append(text[i-1]) + if cnt > 1: + lst.append(str(cnt)) + cnt = 1 + lst.append(text[-1]) + if cnt > 1: + lst.append(str(cnt)) + return lst def strong_pass(password): @@ -322,7 +444,17 @@ def strong_pass(password): This function returns True if the given password is strong enough """ - return None + if len(password) < 6: + return False + if not re.search("[0-9]", password): + return False + if not re.search("[a-z]", password): + return False + if not re.search("[A-Z]", password): + return False + if not re.search("[!@#$%^&*()-+]", password): + return False + return True if __name__ == '__main__': @@ -336,7 +468,7 @@ def strong_pass(password): print(most_frequent_name('names.txt')) print('\nfiles_backup:\n--------------------') - print(files_backup('files_to_backup')) + print(files_backup('/home/doron')) print('\nreplace_in_file:\n--------------------') print(replace_in_file('mnist-predictor.yaml', '{{IMG_NAME}}', 'mnist-pred:0.0.1'))