Page MenuHomePhabricator

D10142.diff
No OneTemporary

D10142.diff

diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js
--- a/keyserver/src/push/send.js
+++ b/keyserver/src/push/send.js
@@ -39,10 +39,7 @@
ResolvedNotifTexts,
} from 'lib/types/notif-types.js';
import { resolvedNotifTextsValidator } from 'lib/types/notif-types.js';
-import type {
- ServerThreadInfo,
- LegacyThreadInfo,
-} from 'lib/types/thread-types.js';
+import type { ServerThreadInfo, ThreadInfo } from 'lib/types/thread-types.js';
import { updateTypes } from 'lib/types/update-types-enum.js';
import { type GlobalUserInfo } from 'lib/types/user-types.js';
import { isDev } from 'lib/utils/dev-utils.js';
@@ -196,7 +193,7 @@
userID: string,
pushUserInfo: PushUserInfo,
unreadCount: number,
- threadInfos: { +[threadID: string]: LegacyThreadInfo },
+ threadInfos: { +[threadID: string]: ThreadInfo },
userInfos: { +[userID: string]: GlobalUserInfo },
dbIDs: string[], // mutable
rowsToSave: Map<string, NotificationRow>, // mutable
diff --git a/lib/selectors/chat-selectors.js b/lib/selectors/chat-selectors.js
--- a/lib/selectors/chat-selectors.js
+++ b/lib/selectors/chat-selectors.js
@@ -38,7 +38,6 @@
import type { BaseAppState } from '../types/redux-types.js';
import { threadTypes } from '../types/thread-types-enum.js';
import {
- type LegacyThreadInfo,
type RawThreadInfo,
type SidebarInfo,
type ThreadInfo,
@@ -68,7 +67,7 @@
export type ChatThreadItem = {
+type: 'chatThreadItem',
- +threadInfo: LegacyThreadInfo,
+ +threadInfo: ThreadInfo,
+mostRecentMessageInfo: ?MessageInfo,
+mostRecentNonLocalMessage: ?string,
+lastUpdatedTime: number,
@@ -124,7 +123,7 @@
}
function createChatThreadItem(
- threadInfo: LegacyThreadInfo,
+ threadInfo: ThreadInfo,
messageStore: MessageStore,
messages: { +[id: string]: ?MessageInfo },
sidebarInfos: ?$ReadOnlyArray<SidebarInfo>,
@@ -209,7 +208,7 @@
messageInfoSelector,
sidebarInfoSelector,
(
- threadInfos: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
messageStore: MessageStore,
messageInfos: { +[id: string]: ?MessageInfo },
sidebarInfos: { +[id: string]: $ReadOnlyArray<SidebarInfo> },
@@ -249,7 +248,7 @@
}
function getChatThreadItems(
- threadInfos: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
messageStore: MessageStore,
messageInfos: { +[id: string]: ?MessageInfo },
sidebarInfos: { +[id: string]: $ReadOnlyArray<SidebarInfo> },
@@ -257,7 +256,7 @@
): $ReadOnlyArray<ChatThreadItem> {
return _flow(
_filter(filterFunction),
- _map((threadInfo: LegacyThreadInfo): ChatThreadItem =>
+ _map((threadInfo: ThreadInfo): ChatThreadItem =>
createChatThreadItem(
threadInfo,
messageStore,
@@ -309,8 +308,8 @@
threadID: string,
messageStore: MessageStore,
messageInfos: { +[id: string]: ?MessageInfo },
- threadInfos: { +[id: string]: LegacyThreadInfo },
- threadInfoFromSourceMessageID: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
+ threadInfoFromSourceMessageID: { +[id: string]: ThreadInfo },
additionalMessages: $ReadOnlyArray<MessageInfo>,
viewerID: string,
): ChatMessageItem[] {
@@ -581,8 +580,8 @@
(
messageStore: MessageStore,
messageInfos: { +[id: string]: ?MessageInfo },
- threadInfos: { +[id: string]: LegacyThreadInfo },
- threadInfoFromSourceMessageID: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
+ threadInfoFromSourceMessageID: { +[id: string]: ThreadInfo },
viewerID: ?string,
): ?(ChatMessageItem[]) => {
if (!threadID || !viewerID) {
diff --git a/lib/selectors/thread-selectors.js b/lib/selectors/thread-selectors.js
--- a/lib/selectors/thread-selectors.js
+++ b/lib/selectors/thread-selectors.js
@@ -47,7 +47,6 @@
type ThreadType,
} from '../types/thread-types-enum.js';
import {
- type LegacyThreadInfo,
type LegacyRawThreadInfo,
type SidebarInfo,
type LegacyRawThreadInfos,
@@ -60,7 +59,7 @@
const _mapValuesWithKeys = _mapValues.convert({ cap: false });
type ThreadInfoSelectorType = (state: BaseAppState<>) => {
- +[id: string]: LegacyThreadInfo,
+ +[id: string]: ThreadInfo,
};
const threadInfoSelector: ThreadInfoSelectorType = createObjectSelector(
(state: BaseAppState<>) => state.threadStore.threadInfos,
@@ -88,9 +87,9 @@
const canBeOnScreenThreadInfos: (
state: BaseAppState<>,
-) => $ReadOnlyArray<LegacyThreadInfo> = createSelector(
+) => $ReadOnlyArray<ThreadInfo> = createSelector(
threadInfoSelector,
- (threadInfos: { +[id: string]: LegacyThreadInfo }) => {
+ (threadInfos: { +[id: string]: ThreadInfo }) => {
const result = [];
for (const threadID in threadInfos) {
const threadInfo = threadInfos[threadID];
@@ -105,13 +104,13 @@
const onScreenThreadInfos: (
state: BaseAppState<>,
-) => $ReadOnlyArray<LegacyThreadInfo> = createSelector(
+) => $ReadOnlyArray<ThreadInfo> = createSelector(
filteredThreadIDsSelector,
canBeOnScreenThreadInfos,
(
inputThreadIDs: ?$ReadOnlySet<string>,
- threadInfos: $ReadOnlyArray<LegacyThreadInfo>,
- ): $ReadOnlyArray<LegacyThreadInfo> => {
+ threadInfos: $ReadOnlyArray<ThreadInfo>,
+ ): $ReadOnlyArray<ThreadInfo> => {
const threadIDs = inputThreadIDs;
if (!threadIDs) {
return threadInfos;
@@ -122,11 +121,9 @@
const onScreenEntryEditableThreadInfos: (
state: BaseAppState<>,
-) => $ReadOnlyArray<LegacyThreadInfo> = createSelector(
+) => $ReadOnlyArray<ThreadInfo> = createSelector(
onScreenThreadInfos,
- (
- threadInfos: $ReadOnlyArray<LegacyThreadInfo>,
- ): $ReadOnlyArray<LegacyThreadInfo> =>
+ (threadInfos: $ReadOnlyArray<ThreadInfo>): $ReadOnlyArray<ThreadInfo> =>
threadInfos.filter(threadInfo =>
threadHasPermission(threadInfo, threadPermissions.EDIT_ENTRIES),
),
@@ -186,11 +183,11 @@
);
const childThreadInfos: (state: BaseAppState<>) => {
- +[id: string]: $ReadOnlyArray<LegacyThreadInfo>,
+ +[id: string]: $ReadOnlyArray<ThreadInfo>,
} = createSelector(
threadInfoSelector,
- (threadInfos: { +[id: string]: LegacyThreadInfo }) => {
- const result: { [string]: LegacyThreadInfo[] } = {};
+ (threadInfos: { +[id: string]: ThreadInfo }) => {
+ const result: { [string]: ThreadInfo[] } = {};
for (const id in threadInfos) {
const threadInfo = threadInfos[id];
const parentThreadID = threadInfo.parentThreadID;
@@ -198,7 +195,7 @@
continue;
}
if (result[parentThreadID] === undefined) {
- result[parentThreadID] = ([]: LegacyThreadInfo[]);
+ result[parentThreadID] = ([]: ThreadInfo[]);
}
result[parentThreadID].push(threadInfo);
}
@@ -314,7 +311,7 @@
const ancestorThreadInfos: (
threadID: string,
-) => (state: BaseAppState<>) => $ReadOnlyArray<LegacyThreadInfo> = _memoize(
+) => (state: BaseAppState<>) => $ReadOnlyArray<ThreadInfo> = _memoize(
baseAncestorThreadInfos,
);
@@ -396,17 +393,17 @@
);
const threadInfoFromSourceMessageIDSelector: (state: BaseAppState<>) => {
- +[id: string]: LegacyThreadInfo,
+ +[id: string]: ThreadInfo,
} = createSelector(
(state: BaseAppState<>) => state.threadStore.threadInfos,
threadInfoSelector,
(
rawThreadInfos: LegacyRawThreadInfos,
- threadInfos: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
) => {
const pendingToRealizedThreadIDs =
pendingToRealizedThreadIDsSelector(rawThreadInfos);
- const result: { [string]: LegacyThreadInfo } = {};
+ const result: { [string]: ThreadInfo } = {};
for (const realizedID of pendingToRealizedThreadIDs.values()) {
const threadInfo = threadInfos[realizedID];
if (threadInfo && threadInfo.sourceMessageID) {
@@ -505,7 +502,7 @@
const threadInfosSelectorForThreadType: (
threadType: ThreadType,
-) => (state: BaseAppState<>) => $ReadOnlyArray<LegacyThreadInfo> = _memoize(
+) => (state: BaseAppState<>) => $ReadOnlyArray<ThreadInfo> = _memoize(
baseThreadInfosSelectorForThreadType,
);
diff --git a/lib/shared/ancestor-threads.js b/lib/shared/ancestor-threads.js
--- a/lib/shared/ancestor-threads.js
+++ b/lib/shared/ancestor-threads.js
@@ -6,15 +6,12 @@
ancestorThreadInfos,
} from '../selectors/thread-selectors.js';
import { threadIsPending } from '../shared/thread-utils.js';
-import {
- type LegacyThreadInfo,
- type ThreadInfo,
-} from '../types/thread-types.js';
+import { type ThreadInfo } from '../types/thread-types.js';
import { useSelector } from '../utils/redux-utils.js';
function useAncestorThreads(
threadInfo: ThreadInfo,
-): $ReadOnlyArray<LegacyThreadInfo> {
+): $ReadOnlyArray<ThreadInfo> {
return useSelector(state => {
if (!threadIsPending(threadInfo.id)) {
const ancestorThreads = ancestorThreadInfos(threadInfo.id)(state);
diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js
--- a/lib/shared/message-utils.js
+++ b/lib/shared/message-utils.js
@@ -41,11 +41,7 @@
RawReactionMessageInfo,
ReactionMessageInfo,
} from '../types/messages/reaction.js';
-import type {
- RawThreadInfo,
- LegacyThreadInfo,
- ThreadInfo,
-} from '../types/thread-types.js';
+import type { RawThreadInfo, ThreadInfo } from '../types/thread-types.js';
import type { UserInfos } from '../types/user-types.js';
import { extractKeyserverIDFromID } from '../utils/action-utils.js';
import {
@@ -94,7 +90,7 @@
rawMessageInfo: RawMessageInfo,
viewerID: ?string,
userInfos: UserInfos,
- threadInfos: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
): ?MessageInfo {
const creatorInfo = userInfos[rawMessageInfo.creatorID];
const creator = {
diff --git a/lib/shared/notif-utils.js b/lib/shared/notif-utils.js
--- a/lib/shared/notif-utils.js
+++ b/lib/shared/notif-utils.js
@@ -19,7 +19,7 @@
import type { TextMessageInfo } from '../types/messages/text.js';
import type { NotifTexts, ResolvedNotifTexts } from '../types/notif-types.js';
import { type ThreadType, threadTypes } from '../types/thread-types-enum.js';
-import type { LegacyThreadInfo, ThreadInfo } from '../types/thread-types.js';
+import type { ThreadInfo } from '../types/thread-types.js';
import type { RelativeUserInfo, UserInfo } from '../types/user-types.js';
import { prettyDate } from '../utils/date-utils.js';
import type { GetENSNames } from '../utils/ens-helpers.js';
@@ -34,8 +34,8 @@
async function notifTextsForMessageInfo(
messageInfos: MessageInfo[],
- threadInfo: LegacyThreadInfo,
- parentThreadInfo: ?LegacyThreadInfo,
+ threadInfo: ThreadInfo,
+ parentThreadInfo: ?ThreadInfo,
notifTargetUserInfo: UserInfo,
getENSNames: ?GetENSNames,
): Promise<?ResolvedNotifTexts> {
@@ -214,8 +214,8 @@
async function fullNotifTextsForMessageInfo(
messageInfos: $ReadOnlyArray<MessageInfo>,
- threadInfo: LegacyThreadInfo,
- parentThreadInfo: ?LegacyThreadInfo,
+ threadInfo: ThreadInfo,
+ parentThreadInfo: ?ThreadInfo,
notifTargetUserInfo: UserInfo,
getENSNames: ?GetENSNames,
): Promise<?ResolvedNotifTexts> {
diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -404,7 +404,7 @@
}
type PendingPersonalThread = {
- +threadInfo: LegacyThreadInfo,
+ +threadInfo: ThreadInfo,
+pendingPersonalThreadUserInfo: UserInfo,
};
@@ -1755,13 +1755,13 @@
}
if (isViewerProfile) {
- const privateThreadInfo: ?LegacyThreadInfo = privateThreadInfos[0];
+ const privateThreadInfo: ?ThreadInfo = privateThreadInfos[0];
return privateThreadInfo ? { threadInfo: privateThreadInfo } : null;
}
if (usersWithPersonalThread.has(userID)) {
- const personalThreadInfo: ?LegacyThreadInfo = personalThreadInfos.find(
+ const personalThreadInfo: ?ThreadInfo = personalThreadInfos.find(
threadInfo =>
userID === getSingleOtherUser(threadInfo, loggedInUserInfo.id),
);
diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js
--- a/lib/types/thread-types.js
+++ b/lib/types/thread-types.js
@@ -412,7 +412,7 @@
};
export type SidebarInfo = {
- +threadInfo: LegacyThreadInfo,
+ +threadInfo: ThreadInfo,
+lastUpdatedTime: number,
+mostRecentNonLocalMessage: ?string,
};
@@ -495,6 +495,6 @@
};
export type UserProfileThreadInfo = {
- +threadInfo: LegacyThreadInfo,
+ +threadInfo: ThreadInfo,
+pendingPersonalThreadUserInfo?: UserInfo,
};
diff --git a/lib/utils/entity-helpers.js b/lib/utils/entity-helpers.js
--- a/lib/utils/entity-helpers.js
+++ b/lib/utils/entity-helpers.js
@@ -9,12 +9,7 @@
entityTextToRawString,
} from './entity-text.js';
import type { UseENSNamesOptions } from '../hooks/ens-cache.js';
-import type {
- LegacyThreadInfo,
- LegacyResolvedThreadInfo,
- ThreadInfo,
- ResolvedThreadInfo,
-} from '../types/thread-types.js';
+import type { ThreadInfo, ResolvedThreadInfo } from '../types/thread-types.js';
import { values } from '../utils/objects.js';
function useResolvedThreadInfos(
@@ -57,8 +52,8 @@
}
function useResolvedOptionalThreadInfos(
- threadInfos: ?$ReadOnlyArray<LegacyThreadInfo>,
-): ?$ReadOnlyArray<LegacyResolvedThreadInfo> {
+ threadInfos: ?$ReadOnlyArray<ThreadInfo>,
+): ?$ReadOnlyArray<ResolvedThreadInfo> {
const entityText = React.useMemo(() => {
if (!threadInfos) {
return null;
diff --git a/native/chat/settings/thread-settings.react.js b/native/chat/settings/thread-settings.react.js
--- a/native/chat/settings/thread-settings.react.js
+++ b/native/chat/settings/thread-settings.react.js
@@ -37,7 +37,6 @@
import { threadPermissions } from 'lib/types/thread-permission-types.js';
import { threadTypes } from 'lib/types/thread-types-enum.js';
import type {
- LegacyResolvedThreadInfo,
RelativeMemberInfo,
ThreadInfo,
ResolvedThreadInfo,
@@ -268,7 +267,7 @@
+viewerID: ?string,
+threadInfo: ResolvedThreadInfo,
+parentThreadInfo: ?ResolvedThreadInfo,
- +childThreadInfos: ?$ReadOnlyArray<LegacyResolvedThreadInfo>,
+ +childThreadInfos: ?$ReadOnlyArray<ResolvedThreadInfo>,
+somethingIsSaving: boolean,
+styles: $ReadOnly<typeof unboundStyles>,
+indicatorStyle: IndicatorStyle,
diff --git a/native/push/push-handler.react.js b/native/push/push-handler.react.js
--- a/native/push/push-handler.react.js
+++ b/native/push/push-handler.react.js
@@ -31,7 +31,7 @@
import type { Dispatch } from 'lib/types/redux-types.js';
import { type ConnectionInfo } from 'lib/types/socket-types.js';
import type { GlobalTheme } from 'lib/types/theme-types.js';
-import type { LegacyThreadInfo, ThreadInfo } from 'lib/types/thread-types.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
import {
useDispatchActionPromise,
type DispatchActionPromise,
@@ -104,7 +104,7 @@
+deviceTokens: {
+[keyserverID: string]: ?string,
},
- +threadInfos: { +[id: string]: LegacyThreadInfo },
+ +threadInfos: { +[id: string]: ThreadInfo },
+notifPermissionAlertInfo: NotifPermissionAlertInfo,
+connection: ConnectionInfo,
+updatesCurrentAsOf: number,
diff --git a/native/selectors/calendar-selectors.js b/native/selectors/calendar-selectors.js
--- a/native/selectors/calendar-selectors.js
+++ b/native/selectors/calendar-selectors.js
@@ -8,7 +8,7 @@
} from 'lib/selectors/thread-selectors.js';
import { isLoggedIn } from 'lib/selectors/user-selectors.js';
import type { EntryInfo } from 'lib/types/entry-types.js';
-import type { LegacyThreadInfo } from 'lib/types/thread-types.js';
+import type { ThreadInfo } from 'lib/types/thread-types.js';
import { dateString } from 'lib/utils/date-utils.js';
import type { AppState } from '../redux/state-types.js';
@@ -32,7 +32,7 @@
| {
itemType: 'entryInfo',
entryInfo: EntryInfo,
- threadInfo: LegacyThreadInfo,
+ threadInfo: ThreadInfo,
};
const calendarListData: (state: AppState) => ?(CalendarItem[]) = createSelector(
@@ -42,7 +42,7 @@
(
loggedIn: boolean,
daysToEntries: { +[dayString: string]: EntryInfo[] },
- threadInfos: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
) => {
if (!loggedIn || daysToEntries[dateString(new Date())] === undefined) {
return null;
diff --git a/web/chat/thread-list-provider.js b/web/chat/thread-list-provider.js
--- a/web/chat/thread-list-provider.js
+++ b/web/chat/thread-list-provider.js
@@ -147,6 +147,7 @@
if (indexToInsert === -1) {
indexToInsert = parentItem.sidebars.length;
}
+
const activeSidebar = {
type: 'sidebar',
lastUpdatedTime: activeChatThreadItem.lastUpdatedTime,
diff --git a/web/modals/threads/settings/thread-settings-modal.react.js b/web/modals/threads/settings/thread-settings-modal.react.js
--- a/web/modals/threads/settings/thread-settings-modal.react.js
+++ b/web/modals/threads/settings/thread-settings-modal.react.js
@@ -19,11 +19,7 @@
import type { RelationshipButton } from 'lib/types/relationship-types.js';
import { threadPermissions } from 'lib/types/thread-permission-types.js';
import { threadTypes } from 'lib/types/thread-types-enum.js';
-import {
- type LegacyThreadInfo,
- type ThreadChanges,
- type ThreadInfo,
-} from 'lib/types/thread-types.js';
+import { type ThreadChanges, type ThreadInfo } from 'lib/types/thread-types.js';
import { useResolvedThreadInfo } from 'lib/utils/entity-helpers.js';
import ThreadSettingsDeleteTab from './thread-settings-delete-tab.react.js';
@@ -54,7 +50,7 @@
deleteThreadLoadingStatusSelector(state) === 'loading' ||
changeThreadSettingsLoadingStatusSelector(state) === 'loading',
);
- const threadInfo: ?LegacyThreadInfo = useSelector(
+ const threadInfo: ?ThreadInfo = useSelector(
state => threadInfoSelector(state)[props.threadID],
);
const modalContext = useModalContext();
@@ -70,7 +66,10 @@
if (threadInfo.name === null || threadInfo.name === undefined) {
return threadInfo;
}
- const withNoName = { ...threadInfo, name: undefined };
+ // Branching on `minimallyEncoded` to appease `flow`.
+ const withNoName = threadInfo.minimallyEncoded
+ ? { ...threadInfo, name: undefined }
+ : { ...threadInfo, name: undefined };
return {
...withNoName,
uiName: threadUIName(withNoName),
diff --git a/web/selectors/chat-selectors.js b/web/selectors/chat-selectors.js
--- a/web/selectors/chat-selectors.js
+++ b/web/selectors/chat-selectors.js
@@ -14,7 +14,7 @@
} from 'lib/selectors/thread-selectors.js';
import { threadIsPending } from 'lib/shared/thread-utils.js';
import type { MessageStore, MessageInfo } from 'lib/types/message-types.js';
-import type { LegacyThreadInfo, SidebarInfo } from 'lib/types/thread-types.js';
+import type { SidebarInfo, ThreadInfo } from 'lib/types/thread-types.js';
import type { AppState } from '../redux/redux-setup.js';
import { useSelector } from '../redux/redux-utils.js';
@@ -28,11 +28,11 @@
(state: AppState) => state.navInfo.pendingThread,
sidebarInfoSelector,
(
- threadInfos: { +[id: string]: LegacyThreadInfo },
+ threadInfos: { +[id: string]: ThreadInfo },
messageStore: MessageStore,
messageInfos: { +[id: string]: ?MessageInfo },
activeChatThreadID: ?string,
- pendingThreadInfo: ?LegacyThreadInfo,
+ pendingThreadInfo: ?ThreadInfo,
sidebarInfos: { +[id: string]: $ReadOnlyArray<SidebarInfo> },
): ?ChatThreadItem => {
if (!activeChatThreadID) {
@@ -55,7 +55,7 @@
},
);
-function useChatThreadItem(threadInfo: ?LegacyThreadInfo): ?ChatThreadItem {
+function useChatThreadItem(threadInfo: ?ThreadInfo): ?ChatThreadItem {
const messageInfos = useSelector(messageInfoSelector);
const sidebarInfos = useSelector(sidebarInfoSelector);
const messageStore = useSelector(state => state.messageStore);
diff --git a/web/types/nav-types.js b/web/types/nav-types.js
--- a/web/types/nav-types.js
+++ b/web/types/nav-types.js
@@ -4,8 +4,8 @@
import { type BaseNavInfo } from 'lib/types/nav-types.js';
import {
- type LegacyThreadInfo,
legacyThreadInfoValidator,
+ type ThreadInfo,
} from 'lib/types/thread-types.js';
import {
type AccountUserInfo,
@@ -35,7 +35,7 @@
...$Exact<BaseNavInfo>,
+tab: NavigationTab,
+activeChatThreadID: ?string,
- +pendingThread?: LegacyThreadInfo,
+ +pendingThread?: ThreadInfo,
+settingsSection?: NavigationSettingsSection,
+selectedUserList?: $ReadOnlyArray<AccountUserInfo>,
+chatMode?: NavigationChatMode,

File Metadata

Mime Type
text/plain
Expires
Mon, Dec 2, 7:20 AM (16 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2606982
Default Alt Text
D10142.diff (20 KB)

Event Timeline