def dot_notation(dict_like, dot_spec):
    """Return the value corresponding to the dot_spec from a dict_like object
    :param dict_like: dictionary, JSON, etc.
    :param dot_spec: a dot notation (e.g. a1.b1.c1.d1 => a1["b1"]["c1"]["d1"])
    :return: the value referenced by the dot_spec
    """
    attrs = dot_spec.split(".")  # we split the path
    parent = dict_like.get(attrs[0])
    children = ".".join(attrs[1:])
    if not (parent and children):  # if no children or no parent, bail out
        return parent
    if isinstance(parent, list):  # here, we apply remaining path spec to all children
        return [dot_notation(j, children) for j in parent]
    elif isinstance(parent, dict):
        return dot_notation(parent, children)
    else:
        return None