### Background
In classical cryptography, the Hill cipher is a polygraphic substitution cipher based on linear algebra. It was invented by Lester S. Hill in 1929.



### Task


This cipher involves a text key which has to be turned into a matrix and text which needs to be encoded. The text key can be of any perfect square length but for the sake of this kata we will focus on keys of length 4 forming a 2x2 matrix.

To encrypt a message using the hill cipher, first of all you need to convert the text key into a key matrix. To do that you will convert the key row wise into a 2x2 matrix. Then you will substitute the letters with their respective positions on the alphabet: A=0, B=1,C=2 and so on till Z=25. So for example if we get the key text as ```cats```, the key matrix will be:
    
    [[ 2  0]
     [19 18]]
     
Now the next step is to break the text into pairs of two and convert those pairs into 2x1 matrices. If your text has an odd number of letters then just add a Z next to your last letter. Now again convert those letters into their respective position in the alphabet as above. So for example the text ```Hi``` would be converted into:

    [[7]
     [8]]
     
Now we need to [multiply](https://www.mathsisfun.com/algebra/matrix-multiplying.html) the key matrix by the text matrix to get our encrypted matrix and then find out the encrypted matrix [modulo](https://en.wikipedia.org/wiki/Modulo_operation) 26:

    [[ 2  0]  *  [[7]  =  [[14]   =  [[14]  mod 26
     [19 18]]     [8]]     [277]]     [17]]
     
For the final step we just find out the letters at the alphabet position of 14 and 17 which are ```O``` and ```R```. So ```OR``` is our encrypted message for the message ```Hi```


In this kata you will be given a function named ```encrypt``` with the parameters ```text``` and ```key``` and you have to return the encrypted message in all uppercase letters

``` python
encrypt('','azyb') → ''
encrypt('Hi','cats') → 'OR'
encrypt('This is a good day','bbaa') → 'AAAAAAGACAGAYA'
```

Note:
- The text to encrypt will contain characters other than the alphabets, its your job to clean them before converting text to matrices. Spaces also need to be removed
- The text may contain both uppercase and lowercase alphabets. Its your job to standardize them, the encrypted text however should be returned in uppercase letters.
- The key will always contain 4 lowercase alphabet.

```python

USER_FILENAME = "<user_code>"
import sys, json, builtins
import math, heapq, bisect, itertools, functools, collections, statistics, fractions, decimal, operator, array, random, re, string, os, pathlib
try:
    import resource as _res
except Exception:
    _res = None
from collections import Counter, defaultdict, deque, OrderedDict
from functools import lru_cache, reduce
from itertools import accumulate, permutations, combinations, product
from math import gcd, ceil, floor, sqrt
from decimal import Decimal
try:
    from typing import *
except Exception:
    pass
try:
    sys.setrecursionlimit(1_000_000)
except Exception:
    pass
try:
    import site as _site
    try:
        _sys_sites = _site.getsitepackages() if hasattr(_site, "getsitepackages") else []
        for _p in _sys_sites:
            if _p and _p not in sys.path:
                sys.path.append(_p)
    except Exception:
        pass
    try:
        _usp = _site.getusersitepackages()
        if isinstance(_usp, str):
            _usp = [_usp]
        for _p in _usp:
            if _p and _p not in sys.path:
                sys.path.append(_p)
    except Exception:
        pass
except Exception:
    pass

def _disabled_input(*args, **kwargs):
    raise RuntimeError("input() is disabled in callable mode")
builtins.input = _disabled_input

ns = {"__name__": "__judge__"}  # prevent if __name__ == "__main__" blocks
for _k, _v in list(globals().items()):
    if not _k.startswith("_"):
        ns[_k] = _v
_CODE = "import numpy as np\nfrom itertools import zip_longest\nfrom string import ascii_lowercase as lower, ascii_uppercase as upper\n\nD = {c:i%26 for i,c in enumerate(lower+upper)}\n\ndef encrypt(text, key):\n    result = []\n    text = ''.join(filter(str.isalpha, text))\n    key = np.array(([D[key[0]], D[key[1]]], [D[key[2]], D[key[3]]]))\n    for c1,c2 in zip_longest(text[::2], text[1::2], fillvalue='Z'):\n        x,y = key @ ([D[c1]], [D[c2]])\n        result.append(upper[x[0]%26] + upper[y[0]%26])\n    return ''.join(result)"
_co = compile(_CODE, USER_FILENAME, "exec")
exec(_co, ns, ns)

_target = None
_fn_name = 'encrypt'
if _fn_name:
    if "Solution" in ns:
        try:
            _obj = ns["Solution"]()
            if hasattr(_obj, _fn_name):
                _target = getattr(_obj, _fn_name)
        except Exception:
            _target = None
    if _target is None and _fn_name in ns and callable(ns[_fn_name]):
        _target = ns[_fn_name]
# Fallback: if there's exactly one user-defined function, use it
if _target is None:
    _cands = [v for k, v in ns.items() if callable(v) and getattr(v, "__module__", "") in ("__judge__", "__main__")]
    _user_funcs = [c for c in _cands if getattr(c, "__name__", "").startswith("_") is False]
    if len(_user_funcs) == 1:
        _target = _user_funcs[0]
if _target is None:
    raise RuntimeError(f"Could not resolve callable '{_fn_name}'")

_raw = sys.stdin.read().strip()
if _raw:
    _parsed = json.loads(_raw)
    if isinstance(_parsed, dict):
        _kwargs = _parsed.get("kwargs", {})
        _args = _parsed.get("args", [])
    else:
        _args, _kwargs = _parsed, {}
else:
    _args, _kwargs = [], {}
if not isinstance(_args, (list, tuple)):
    _args = [_args]
_res = _target(*_args, **_kwargs)
try:
    sys.stdout.write(repr(_res) + "\n")
except Exception:
    pass

```

Measured memory_bytes: 6362