Write a function that accepts two square (`NxN`) matrices (two dimensional arrays), and returns the product of the two. Only square matrices will be given.

How to multiply two square matrices: 

We are given two matrices, A and B, of size 2x2 (note: tests are not limited to 2x2). Matrix C, the solution, will be equal to the product of A and B. To fill in cell `[0][0]` of matrix C, you need to compute: `A[0][0] * B[0][0] + A[0][1] * B[1][0]`.

More general: To fill in cell `[n][m]` of matrix C, you need to first multiply the elements in the nth row of matrix A by the elements in the mth column of matrix B, then take the sum of all those products. This will give you the value for cell `[m][n]` in matrix C. 

## Example
```
  A         B          C
|1 2|  x  |3 2|  =  | 5 4|
|3 2|     |1 1|     |11 8|
```

Detailed calculation:
```
C[0][0] = A[0][0] * B[0][0] + A[0][1] * B[1][0] = 1*3 + 2*1 =  5
C[0][1] = A[0][0] * B[0][1] + A[0][1] * B[1][1] = 1*2 + 2*1 =  4
C[1][0] = A[1][0] * B[0][0] + A[1][1] * B[1][0] = 3*3 + 2*1 = 11
C[1][1] = A[1][0] * B[0][1] + A[1][1] * B[1][1] = 3*2 + 2*1 =  8
```
Link to Wikipedia explaining matrix multiplication (look at the square matrix example): 
http://en.wikipedia.org/wiki/Matrix_multiplication

A more visual explanation of matrix multiplication: http://matrixmultiplication.xyz

~~~if:c
**Note:** In **C**, the dimensions of both square matrices `n` will be passed into your function.  However, since the dimensions of your returned "matrix" is expected to be the same as that of the inputs, you will not need to keep track of the dimensions of your matrix in another variable.
~~~

```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 = 'class Matrix:\n    def __init__(self, data):\n        self._data = data\n        self._rows = len(data)\n        self._columns = len(data[0])\n\n\n    @classmethod\n    def empty(cls, rows, columns):\n        data = [[None for _ in range(columns)] for _ in range(rows)]\n\n        return cls(data)\n\n\n    def __getitem__(self, key):\n        return self._data[key]\n        \n      \n    @property\n    def data(self):\n        return self._data\n\n\n    @property\n    def rows(self):\n        return self._rows\n\n\n    @property\n    def columns(self):\n        return self._columns\n\n\n    def row(self, row_index):\n        for elem in self._data[row_index]:\n            yield elem\n\n\n    def column(self, column_index):\n        for row in self._data:\n            yield row[column_index]\n\n\n    def __str__(self):\n        str_rows = []\n        for row in self._data:\n            str_rows.append(\'  \'.join(map(str, row)))\n\n        return "\\n".join(str_rows)\n\n\n    def __mul__(self, matrix):\n        result = Matrix.empty(self.rows, self.columns)\n\n        for result_row in range(result.rows):\n            for result_column in range(result.columns):\n                current_row = self.row(result_row)\n                current_column = matrix.column(result_column)\n\n                result_element = 0\n                while True:\n                    try:\n                        row_element = next(current_row)\n                        column_element = next(current_column)\n                    except StopIteration:\n                        break\n                    result_element += row_element * column_element\n\n                result[result_row][result_column] = result_element\n\n        return result\n\n\ndef matrix_mult(a, b):\n  product = Matrix(a) * Matrix(b)\n  return product.data\n  \n  \n  \n'
_co = compile(_CODE, USER_FILENAME, "exec")
exec(_co, ns, ns)

_target = None
_fn_name = 'matrix_mult'
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: 8172