/**
 * Recursively navigates into nested collections inside `collection` by
 * following a sequence of properties `pathArray`, executing any methods
 * along the way, and returning the first `undefined` encountered.
 * @param {any} collection - The collection to traverse.
 * @param {Array<string|number|function()>} pathArray - A sequence of
 * property names, indexes, or functions to traverse into the `collection`.
 * @returns {any|undefined} The final value found,
 * otherwise the first `undefined` encountered.
 * @example
 * const largeViewModelObject = {
 *   knockoutObservable: {
 *     GetSomeValue() { return [1, 2, 3] }
 *   }
 * }
 * getByPath(largeViewModelObject, ["knockoutObservable", "GetSomeValue", 2]);
 * // returns 3
 */
const getByPath = (collection, pathArray) => {
	const [prop, ...leftoverProps] = pathArray;
	const value = collection[prop];
	return leftoverProps.length == 0
	  ? value
		: getByPath(
			  value instanceof Function ? collection[prop]() : value,
				leftoverProps
		  );
};