From 1a30c1080690a4810324c67a7f1e4989eede2510 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Wed, 10 May 2023 15:48:24 +0700 Subject: [PATCH] convert const function to function --- .prettierrc | 11 +++++++- .../components/messages/hideButton.tsx | 2 +- .../components/messages/muteButton.tsx | 2 +- .../components/messages/replyButton.tsx | 2 +- src/app/daily/components/header.tsx | 4 +-- .../daily/components/views/createModal.tsx | 10 ++----- src/app/note/components/base.tsx | 4 +-- src/app/note/components/kind1.tsx | 4 +-- src/app/note/components/kind1063.tsx | 4 +-- src/app/note/components/mentions/user.tsx | 4 +-- src/app/note/components/quoteRepost.tsx | 4 +-- src/app/note/components/skeleton.tsx | 4 +-- src/app/note/components/user/default.tsx | 4 +-- src/app/note/components/user/repost.tsx | 4 +-- src/app/note/components/wrapper.tsx | 6 ++-- src/renderer/shell.tsx | 2 +- src/shared/avatarUploader.tsx | 4 +-- src/shared/form/imagePicker.tsx | 4 +-- src/shared/image.tsx | 4 +-- src/shared/networkStatusIndicator.tsx | 4 +-- src/shared/relayProvider.tsx | 2 +- src/shared/tooltip.tsx | 2 +- src/utils/getDate.tsx | 12 ++++---- src/utils/hooks/useActiveAccount.tsx | 4 +-- src/utils/hooks/useChannelProfile.tsx | 4 +-- src/utils/hooks/useDecryptMessage.tsx | 4 +-- src/utils/hooks/useNetworkStatus.tsx | 4 +-- src/utils/hooks/useProfile.tsx | 4 +-- src/utils/parser.tsx | 4 +-- src/utils/shortenKey.tsx | 4 +-- src/utils/transform.tsx | 28 +++++++++---------- tsconfig.json | 7 ++++- 32 files changed, 87 insertions(+), 79 deletions(-) diff --git a/.prettierrc b/.prettierrc index 1139bff5..ae3f2e49 100644 --- a/.prettierrc +++ b/.prettierrc @@ -8,7 +8,16 @@ "endOfLine": "lf", "bracketSpacing": true, "bracketSameLine": false, - "importOrder": ["^@lume/(.*)$", "", "^[./]"], + "importOrder": [ + "^@lume/(.*)$", + "^@app/(.*)$", + "^@shared/(.*)$", + "^@icons/(.*)$", + "^@stores/(.*)$", + "^@utils/(.*)$", + "", + "^[./]" + ], "importOrderSeparation": true, "importOrderSortSpecifiers": true, "plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-tailwindcss"], diff --git a/src/app/channel/components/messages/hideButton.tsx b/src/app/channel/components/messages/hideButton.tsx index 77da9707..eb6c1e56 100644 --- a/src/app/channel/components/messages/hideButton.tsx +++ b/src/app/channel/components/messages/hideButton.tsx @@ -1,7 +1,7 @@ import CancelIcon from '@lume/shared/icons/cancel'; import HideIcon from '@lume/shared/icons/hide'; import { RelayContext } from '@lume/shared/relayProvider'; -import Tooltip from '@lume/shared/tooltip'; +import { Tooltip } from '@lume/shared/tooltip'; import { channelMessagesAtom } from '@lume/stores/channel'; import { WRITEONLY_RELAYS } from '@lume/stores/constants'; import { dateToUnix } from '@lume/utils/getDate'; diff --git a/src/app/channel/components/messages/muteButton.tsx b/src/app/channel/components/messages/muteButton.tsx index b8f28637..f698df87 100644 --- a/src/app/channel/components/messages/muteButton.tsx +++ b/src/app/channel/components/messages/muteButton.tsx @@ -1,7 +1,7 @@ import CancelIcon from '@lume/shared/icons/cancel'; import MuteIcon from '@lume/shared/icons/mute'; import { RelayContext } from '@lume/shared/relayProvider'; -import Tooltip from '@lume/shared/tooltip'; +import { Tooltip } from '@lume/shared/tooltip'; import { channelMessagesAtom } from '@lume/stores/channel'; import { WRITEONLY_RELAYS } from '@lume/stores/constants'; import { dateToUnix } from '@lume/utils/getDate'; diff --git a/src/app/channel/components/messages/replyButton.tsx b/src/app/channel/components/messages/replyButton.tsx index 436c867d..502c2625 100644 --- a/src/app/channel/components/messages/replyButton.tsx +++ b/src/app/channel/components/messages/replyButton.tsx @@ -1,5 +1,5 @@ import ReplyMessageIcon from '@lume/shared/icons/replyMessage'; -import Tooltip from '@lume/shared/tooltip'; +import { Tooltip } from '@lume/shared/tooltip'; import { channelReplyAtom } from '@lume/stores/channel'; import { useSetAtom } from 'jotai'; diff --git a/src/app/daily/components/header.tsx b/src/app/daily/components/header.tsx index 1172284b..84faf03e 100644 --- a/src/app/daily/components/header.tsx +++ b/src/app/daily/components/header.tsx @@ -1,6 +1,6 @@ import { CreateViewModal } from '@lume/app/daily/components/views/createModal'; -export const Header = () => { +export function Header() { return (
); -}; +} diff --git a/src/app/daily/components/views/createModal.tsx b/src/app/daily/components/views/createModal.tsx index a3204d63..95900128 100644 --- a/src/app/daily/components/views/createModal.tsx +++ b/src/app/daily/components/views/createModal.tsx @@ -1,16 +1,10 @@ import CancelIcon from '@lume/shared/icons/cancel'; import PlusIcon from '@lume/shared/icons/plus'; -//import { getNoteAuthors } from '@lume/utils/storage'; import { Dialog, Transition } from '@headlessui/react'; import { Fragment, useState } from 'react'; -//import useSWR from 'swr'; - -//const fetcher = () => getNoteAuthors(); - -export const CreateViewModal = () => { - //const { data, error }: any = useSWR('authors', fetcher); +export function CreateViewModal() { const [isOpen, setIsOpen] = useState(false); const closeModal = () => { @@ -89,4 +83,4 @@ export const CreateViewModal = () => { ); -}; +} diff --git a/src/app/note/components/base.tsx b/src/app/note/components/base.tsx index 7a61f63d..580014df 100644 --- a/src/app/note/components/base.tsx +++ b/src/app/note/components/base.tsx @@ -9,7 +9,7 @@ import { isTagsIncludeID } from '@lume/utils/transform'; import { useMemo } from 'react'; -export const NoteBase = ({ event }: { event: any }) => { +export function NoteBase({ event }: { event: any }) { const content = useMemo(() => noteParser(event), [event]); const checkParentID = isTagsIncludeID(event.parent_id, event.tags); @@ -34,4 +34,4 @@ export const NoteBase = ({ event }: { event: any }) => { ); -}; +} diff --git a/src/app/note/components/kind1.tsx b/src/app/note/components/kind1.tsx index d6e7659d..45758803 100644 --- a/src/app/note/components/kind1.tsx +++ b/src/app/note/components/kind1.tsx @@ -6,7 +6,7 @@ import VideoPreview from '@lume/app/note/components/preview/video'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; -export const Kind1 = ({ content }: { content: any }) => { +export function Kind1({ content }: { content: any }) { return ( <> { )} ); -}; +} diff --git a/src/app/note/components/kind1063.tsx b/src/app/note/components/kind1063.tsx index 93e16cd2..d69f03a9 100644 --- a/src/app/note/components/kind1063.tsx +++ b/src/app/note/components/kind1063.tsx @@ -4,7 +4,7 @@ function isImage(url: string) { return /\.(jpg|jpeg|gif|png|webp|avif)$/.test(url); } -export const Kind1063 = ({ metadata }: { metadata: string[] }) => { +export function Kind1063({ metadata }: { metadata: string[] }) { const url = metadata[0][1]; return ( @@ -12,4 +12,4 @@ export const Kind1063 = ({ metadata }: { metadata: string[] }) => { {isImage(url) && image} ); -}; +} diff --git a/src/app/note/components/mentions/user.tsx b/src/app/note/components/mentions/user.tsx index 7a671958..3b50ea9f 100644 --- a/src/app/note/components/mentions/user.tsx +++ b/src/app/note/components/mentions/user.tsx @@ -1,11 +1,11 @@ import { useProfile } from '@lume/utils/hooks/useProfile'; import { shortenKey } from '@lume/utils/shortenKey'; -export const MentionUser = (props: { children: any[] }) => { +export function MentionUser(props: { children: any[] }) { const pubkey = props.children[0]; const { user } = useProfile(pubkey); return ( @{user?.name || user?.display_name || shortenKey(pubkey)} ); -}; +} diff --git a/src/app/note/components/quoteRepost.tsx b/src/app/note/components/quoteRepost.tsx index 725b6e85..ca7bd9a3 100644 --- a/src/app/note/components/quoteRepost.tsx +++ b/src/app/note/components/quoteRepost.tsx @@ -3,7 +3,7 @@ import { NoteRepostUser } from '@lume/app/note/components/user/repost'; import { NoteWrapper } from '@lume/app/note/components/wrapper'; import { getQuoteID } from '@lume/utils/transform'; -export const NoteQuoteRepost = ({ event }: { event: any }) => { +export function NoteQuoteRepost({ event }: { event: any }) { const rootID = getQuoteID(event.tags); return ( @@ -17,4 +17,4 @@ export const NoteQuoteRepost = ({ event }: { event: any }) => { ); -}; +} diff --git a/src/app/note/components/skeleton.tsx b/src/app/note/components/skeleton.tsx index 9540364a..127cbd1d 100644 --- a/src/app/note/components/skeleton.tsx +++ b/src/app/note/components/skeleton.tsx @@ -1,4 +1,4 @@ -export const NoteSkeleton = () => { +export function NoteSkeleton() { return (
@@ -17,4 +17,4 @@ export const NoteSkeleton = () => {
); -}; +} diff --git a/src/app/note/components/user/default.tsx b/src/app/note/components/user/default.tsx index c7102cd7..ce70ecb0 100644 --- a/src/app/note/components/user/default.tsx +++ b/src/app/note/components/user/default.tsx @@ -8,7 +8,7 @@ import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(relativeTime); -export const NoteDefaultUser = ({ pubkey, time }: { pubkey: string; time: number }) => { +export function NoteDefaultUser({ pubkey, time }: { pubkey: string; time: number }) { const { user } = useProfile(pubkey); return ( @@ -34,4 +34,4 @@ export const NoteDefaultUser = ({ pubkey, time }: { pubkey: string; time: number ); -}; +} diff --git a/src/app/note/components/user/repost.tsx b/src/app/note/components/user/repost.tsx index e738d8cf..f28b6d89 100644 --- a/src/app/note/components/user/repost.tsx +++ b/src/app/note/components/user/repost.tsx @@ -7,7 +7,7 @@ import relativeTime from 'dayjs/plugin/relativeTime'; dayjs.extend(relativeTime); -export const NoteRepostUser = ({ pubkey, time }: { pubkey: string; time: number }) => { +export function NoteRepostUser({ pubkey, time }: { pubkey: string; time: number }) { const { user } = useProfile(pubkey); return ( @@ -32,4 +32,4 @@ export const NoteRepostUser = ({ pubkey, time }: { pubkey: string; time: number ); -}; +} diff --git a/src/app/note/components/wrapper.tsx b/src/app/note/components/wrapper.tsx index bdd0cb19..dc78e91a 100644 --- a/src/app/note/components/wrapper.tsx +++ b/src/app/note/components/wrapper.tsx @@ -1,6 +1,6 @@ import { navigate } from 'vite-plugin-ssr/client/router'; -export const NoteWrapper = ({ +export function NoteWrapper({ children, href, className, @@ -8,7 +8,7 @@ export const NoteWrapper = ({ children: React.ReactNode; href: string; className: string; -}) => { +}) { const openThread = (event: any, href: string) => { const selection = window.getSelection(); if (selection.toString().length === 0) { @@ -23,4 +23,4 @@ export const NoteWrapper = ({ {children} ); -}; +} diff --git a/src/renderer/shell.tsx b/src/renderer/shell.tsx index 38f072f7..42b13916 100644 --- a/src/renderer/shell.tsx +++ b/src/renderer/shell.tsx @@ -1,5 +1,5 @@ import { PageContext } from '@lume/renderer/types'; -import RelayProvider from '@lume/shared/relayProvider'; +import { RelayProvider } from '@lume/shared/relayProvider'; import { PageContextProvider } from '@lume/utils/hooks/usePageContext'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; diff --git a/src/shared/avatarUploader.tsx b/src/shared/avatarUploader.tsx index 21fcea09..efc2c735 100644 --- a/src/shared/avatarUploader.tsx +++ b/src/shared/avatarUploader.tsx @@ -4,7 +4,7 @@ import { open } from '@tauri-apps/api/dialog'; import { Body, fetch } from '@tauri-apps/api/http'; import { useState } from 'react'; -export const AvatarUploader = ({ valueState }: { valueState: any }) => { +export function AvatarUploader({ valueState }: { valueState: any }) { const [loading, setLoading] = useState(false); const openFileDialog = async () => { @@ -72,4 +72,4 @@ export const AvatarUploader = ({ valueState }: { valueState: any }) => { )} ); -}; +} diff --git a/src/shared/form/imagePicker.tsx b/src/shared/form/imagePicker.tsx index dfaed859..aed574ca 100644 --- a/src/shared/form/imagePicker.tsx +++ b/src/shared/form/imagePicker.tsx @@ -9,7 +9,7 @@ import { Body, fetch } from '@tauri-apps/api/http'; import { useSetAtom } from 'jotai'; import { useState } from 'react'; -export const ImagePicker = ({ type }: { type: string }) => { +export function ImagePicker({ type }: { type: string }) { let atom; switch (type) { @@ -93,4 +93,4 @@ export const ImagePicker = ({ type }: { type: string }) => { )} ); -}; +} diff --git a/src/shared/image.tsx b/src/shared/image.tsx index 8da699f5..21ed05f9 100644 --- a/src/shared/image.tsx +++ b/src/shared/image.tsx @@ -1,6 +1,6 @@ import { DEFAULT_AVATAR } from '@lume/stores/constants'; -export const Image = (props) => { +export function Image(props) { const addImageFallback = (event) => { event.currentTarget.src = DEFAULT_AVATAR; }; @@ -8,4 +8,4 @@ export const Image = (props) => { return ( ); -}; +} diff --git a/src/shared/networkStatusIndicator.tsx b/src/shared/networkStatusIndicator.tsx index 9803a4ff..a08c2c4b 100644 --- a/src/shared/networkStatusIndicator.tsx +++ b/src/shared/networkStatusIndicator.tsx @@ -1,6 +1,6 @@ import { useNetworkStatus } from '@lume/utils/hooks/useNetworkStatus'; -export const NetworkStatusIndicator = () => { +export function NetworkStatusIndicator() { const isOnline = useNetworkStatus(); return ( @@ -18,4 +18,4 @@ export const NetworkStatusIndicator = () => {

{isOnline ? 'Online' : 'Offline'}

); -}; +} diff --git a/src/shared/relayProvider.tsx b/src/shared/relayProvider.tsx index 023cc69d..43348588 100644 --- a/src/shared/relayProvider.tsx +++ b/src/shared/relayProvider.tsx @@ -12,6 +12,6 @@ const pool = new RelayPool(FULL_RELAYS, { logSubscriptions: false, }); -export default function RelayProvider({ children }: { children: React.ReactNode }) { +export function RelayProvider({ children }: { children: React.ReactNode }) { return {children}; } diff --git a/src/shared/tooltip.tsx b/src/shared/tooltip.tsx index 0ff90d0d..dff0f6c8 100644 --- a/src/shared/tooltip.tsx +++ b/src/shared/tooltip.tsx @@ -1,7 +1,7 @@ import { autoUpdate, offset, shift, useFloating, useFocus, useHover, useInteractions } from '@floating-ui/react'; import { useState } from 'react'; -export default function Tooltip({ children, message }: { children: React.ReactNode; message: string }) { +export function Tooltip({ children, message }: { children: React.ReactNode; message: string }) { const [isOpen, setIsOpen] = useState(false); const { x, y, strategy, refs, context } = useFloating({ diff --git a/src/utils/getDate.tsx b/src/utils/getDate.tsx index 2915fbcc..3e0f30c6 100644 --- a/src/utils/getDate.tsx +++ b/src/utils/getDate.tsx @@ -1,22 +1,22 @@ // get X days ago with user provided date -export const daysAgo = (numOfDays, date = new Date()) => { +export function daysAgo(numOfDays, date = new Date()) { const daysAgo = new Date(date.getTime()); daysAgo.setDate(date.getDate() - numOfDays); return daysAgo; -}; +} // get X hours ago with user provided date -export const hoursAgo = (numOfHours, date = new Date()) => { +export function hoursAgo(numOfHours, date = new Date()) { const hoursAgo = new Date(date.getTime()); hoursAgo.setHours(date.getHours() - numOfHours); return hoursAgo; -}; +} // convert date to unix timestamp -export const dateToUnix = (_date?: Date) => { +export function dateToUnix(_date?: Date) { const date = _date || new Date(); return Math.floor(date.getTime() / 1000); -}; +} diff --git a/src/utils/hooks/useActiveAccount.tsx b/src/utils/hooks/useActiveAccount.tsx index 2a7baee3..99997e38 100644 --- a/src/utils/hooks/useActiveAccount.tsx +++ b/src/utils/hooks/useActiveAccount.tsx @@ -4,7 +4,7 @@ import useSWR from 'swr'; const fetcher = () => getActiveAccount(); -export const useActiveAccount = () => { +export function useActiveAccount() { const { data, error, isLoading } = useSWR('activeAcount', fetcher); return { @@ -12,4 +12,4 @@ export const useActiveAccount = () => { isLoading, isError: error, }; -}; +} diff --git a/src/utils/hooks/useChannelProfile.tsx b/src/utils/hooks/useChannelProfile.tsx index b357402c..58dad366 100644 --- a/src/utils/hooks/useChannelProfile.tsx +++ b/src/utils/hooks/useChannelProfile.tsx @@ -15,7 +15,7 @@ const fetcher = async ([, id]) => { } }; -export const useChannelProfile = (id: string, channelPubkey: string) => { +export function useChannelProfile(id: string, channelPubkey: string) { const pool: any = useContext(RelayContext); const { data: cache, isLoading } = useSWR(['channel-cache-profile', id], fetcher); @@ -53,4 +53,4 @@ export const useChannelProfile = (id: string, channelPubkey: string) => { } else { return data; } -}; +} diff --git a/src/utils/hooks/useDecryptMessage.tsx b/src/utils/hooks/useDecryptMessage.tsx index b6fee199..2bf390f4 100644 --- a/src/utils/hooks/useDecryptMessage.tsx +++ b/src/utils/hooks/useDecryptMessage.tsx @@ -1,7 +1,7 @@ import { nip04 } from 'nostr-tools'; import { useCallback, useEffect, useState } from 'react'; -export const useDecryptMessage = (userKey: string, userPriv: string, data: any) => { +export function useDecryptMessage(userKey: string, userPriv: string, data: any) { const [content, setContent] = useState(null); const extractSenderKey = useCallback(() => { @@ -25,4 +25,4 @@ export const useDecryptMessage = (userKey: string, userPriv: string, data: any) }, [decrypt]); return content ? content : null; -}; +} diff --git a/src/utils/hooks/useNetworkStatus.tsx b/src/utils/hooks/useNetworkStatus.tsx index f61f0edc..76bb2265 100644 --- a/src/utils/hooks/useNetworkStatus.tsx +++ b/src/utils/hooks/useNetworkStatus.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'; const getOnLineStatus = () => typeof navigator !== 'undefined' && typeof navigator.onLine === 'boolean' ? navigator.onLine : true; -export const useNetworkStatus = () => { +export function useNetworkStatus() { const [status, setStatus] = useState(getOnLineStatus()); const setOnline = () => setStatus(true); @@ -20,4 +20,4 @@ export const useNetworkStatus = () => { }, []); return status; -}; +} diff --git a/src/utils/hooks/useProfile.tsx b/src/utils/hooks/useProfile.tsx index e41feb2e..f10161d6 100644 --- a/src/utils/hooks/useProfile.tsx +++ b/src/utils/hooks/useProfile.tsx @@ -22,7 +22,7 @@ const fetcher = async (pubkey: string) => { } }; -export const useProfile = (pubkey: string) => { +export function useProfile(pubkey: string) { const { data, error, isLoading } = useSWR(pubkey, fetcher); return { @@ -30,4 +30,4 @@ export const useProfile = (pubkey: string) => { isLoading, isError: error, }; -}; +} diff --git a/src/utils/parser.tsx b/src/utils/parser.tsx index dd7fa449..4ba57811 100644 --- a/src/utils/parser.tsx +++ b/src/utils/parser.tsx @@ -5,7 +5,7 @@ const getURLs = new RegExp( 'gmi' ); -export const noteParser = (event: Event) => { +export function noteParser(event: Event) { const references = parseReferences(event); const content: { original: string; parsed: any; notes: string[]; images: string[]; videos: string[] } = { original: event.content, @@ -54,4 +54,4 @@ export const noteParser = (event: Event) => { }); return content; -}; +} diff --git a/src/utils/shortenKey.tsx b/src/utils/shortenKey.tsx index 7a79e1e4..4e90b4f5 100644 --- a/src/utils/shortenKey.tsx +++ b/src/utils/shortenKey.tsx @@ -1,6 +1,6 @@ import { nip19 } from 'nostr-tools'; -export const shortenKey = (pubkey: string) => { +export function shortenKey(pubkey: string) { const npub = nip19.npubEncode(pubkey); return npub.substring(0, 16).concat('...'); -}; +} diff --git a/src/utils/transform.tsx b/src/utils/transform.tsx index 69b2dfc1..e214d1a2 100644 --- a/src/utils/transform.tsx +++ b/src/utils/transform.tsx @@ -1,37 +1,37 @@ import destr from 'destr'; // convert NIP-02 to array of pubkey -export const nip02ToArray = (tags: any) => { +export function nip02ToArray(tags: any) { const arr = []; tags.forEach((item) => { arr.push(item[1]); }); return arr; -}; +} // convert array to NIP-02 tag list -export const arrayToNIP02 = (arr: string[]) => { +export function arrayToNIP02(arr: string[]) { const nip02_arr = []; arr.forEach((item) => { nip02_arr.push(['p', item]); }); return nip02_arr; -}; +} // convert array object to pure array -export const arrayObjToPureArr = (arr: any) => { +export function arrayObjToPureArr(arr: any) { const pure_arr = []; arr.forEach((item) => { pure_arr.push(item.content); }); return pure_arr; -}; +} // get parent id from event tags -export const getParentID = (arr: string[], fallback: string) => { +export function getParentID(arr: string[], fallback: string) { const tags = destr(arr); let parentID = fallback; @@ -48,10 +48,10 @@ export const getParentID = (arr: string[], fallback: string) => { } return parentID; -}; +} // check id present in event tags -export const isTagsIncludeID = (id: string, arr: string[]) => { +export function isTagsIncludeID(id: string, arr: string[]) { const tags = destr(arr); if (tags.length > 0) { @@ -61,10 +61,10 @@ export const isTagsIncludeID = (id: string, arr: string[]) => { } else { return false; } -}; +} // get parent id from event tags -export const getQuoteID = (arr: string[]) => { +export function getQuoteID(arr: string[]) { const tags = destr(arr); let quoteID = null; @@ -81,13 +81,13 @@ export const getQuoteID = (arr: string[]) => { } return quoteID; -}; +} // sort events by timestamp -export const sortEvents = (arr: any) => { +export function sortEvents(arr: any) { arr.sort((a, b) => { return a.created_at - b.created_at; }); return arr; -}; +} diff --git a/tsconfig.json b/tsconfig.json index d7059203..77879d30 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,12 @@ "compilerOptions": { "baseUrl": "./", "paths": { - "@lume/*": ["src/*"] + "@lume/*": ["src/*"], + "@app/*": ["src/app/*"], + "@shared/*": ["src/shared/*"], + "@icons/*": ["src/shared/icons/*"], + "@stores/*": ["src/stores/*"], + "@utils/*": ["src/utils/*"] }, "types": ["vidstack/globals"], "target": "es2017",