contract Clone {
        /// @notice Reads an immutable arg with type address
        /// @param argOffset The offset of the arg in the packed data
        /// @return arg The arg value
        function _getArgAddress(uint256 argOffset)
            internal
            pure
            returns (address arg)
        {
            uint256 offset = _getImmutableArgsOffset();
            assembly {
                arg := shr(0x60, calldataload(add(offset, argOffset)))
            }
        }

        /// @notice Reads an immutable arg with type uint256
        /// @param argOffset The offset of the arg in the packed data
        /// @return arg The arg value
        function _getArgUint256(uint256 argOffset)
            internal
            pure
            returns (uint256 arg)
        {
            uint256 offset = _getImmutableArgsOffset();
            // solhint-disable-next-line no-inline-assembly
            assembly {
                arg := calldataload(add(offset, argOffset))
            }
        }

        /// @notice Reads an immutable arg with type uint64
        /// @param argOffset The offset of the arg in the packed data
        /// @return arg The arg value
        function _getArgUint64(uint256 argOffset)
            internal
            pure
            returns (uint64 arg)
        {
            uint256 offset = _getImmutableArgsOffset();
            // solhint-disable-next-line no-inline-assembly
            assembly {
                arg := shr(0xc0, calldataload(add(offset, argOffset)))
            }
        }

        /// @notice Reads an immutable arg with type uint8
        /// @param argOffset The offset of the arg in the packed data
        /// @return arg The arg value
        function _getArgUint8(uint256 argOffset) internal pure returns (uint8 arg) {
            uint256 offset = _getImmutableArgsOffset();
            // solhint-disable-next-line no-inline-assembly
            assembly {
                arg := shr(0xf8, calldataload(add(offset, argOffset)))
            }
        }

        /// @return offset The offset of the packed immutable args in calldata
        function _getImmutableArgsOffset() internal pure returns (uint256 offset) {
            // solhint-disable-next-line no-inline-assembly
            assembly {
                offset := sub(
                    calldatasize(),
                    add(shr(240, calldataload(sub(calldatasize(), 2))), 2)
                )
            }
        }
    }
/// @title Clone
/// @author zefram.eth
/// @notice Provides helper functions for reading immutable args from calldata
function _getArgAddress(uint256 argOffset)
    internal
    pure
    returns (address arg)
{
    uint256 offset = _getImmutableArgsOffset();
    assembly {
        arg := shr(0x60, calldataload(add(offset, argOffset)))
    }
}

/// @notice Reads an immutable arg with type address
/// @param argOffset The offset of the arg in the packed data
/// @return arg The arg value