docs: @Nonnull
    public EChange unassignUserFromAllUserGroups (@Nullable final String sUserID)
    {
      if (StringHelper.hasNoText (sUserID))
        return EChange.UNCHANGED;
  
      final ICommonsList <IUserGroup> aAffectedUserGroups = new CommonsArrayList <> ();
      m_aRWLock.writeLock ().lock ();
      try
      {
        EChange eChange = EChange.UNCHANGED;
        for (final UserGroup aUserGroup : internalDirectGetAll ())
          if (aUserGroup.unassignUser (sUserID).isChanged ())
          {
            aAffectedUserGroups.add (aUserGroup);
            BusinessObjectHelper.setLastModificationNow (aUserGroup);
            internalUpdateItem (aUserGroup);
            eChange = EChange.CHANGED;
          }
        if (eChange.isUnchanged ())
          return EChange.UNCHANGED;
  
      }
      finally
      {
        m_aRWLock.writeLock ().unlock ();
      }
      AuditHelper.onAuditModifySuccess (UserGroup.OT, "unassign-user-from-all-usergroups", sUserID);
  
      // Execute callback as the very last action
      for (final IUserGroup aUserGroup : aAffectedUserGroups)
        m_aCallbacks.forEach (aCB -> aCB.onUserGroupUserAssignment (aUserGroup, sUserID, false));
  
      return EChange.CHANGED;
    }
  
    /**
     * Check if the passed user is assigned to the specified user group
     *
     * @param sUserGroupID
     *        ID of the user group to check
     * @param sUserID
     *        ID of the user to be checked.
     * @return <code>true</code> if the specified user is assigned to the
     *         specified user group.
     */
    public boolean isUserAssignedToUserGroup (@Nullable final String sUserGroupID, @Nullable final String sUserID)
    {
      if (StringHelper.hasNoText (sUserID))
        return false;
  
      final IUserGroup aUserGroup = getOfID (sUserGroupID);
      return aUserGroup == null ? false : aUserGroup.containsUserID (sUserID);
    }