@zero-library/common 2.0.8 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -137,19 +137,6 @@ interface Props {
137
137
  }
138
138
  declare const _default$1: ({ size, avatarSrc, userName }: Props) => react_jsx_runtime.JSX.Element;
139
139
 
140
- /**
141
- * 通用的 Valtio Context 工厂
142
- * 支持:
143
- * - useStore() 获取 store 实例
144
- */
145
- declare function createValtioContext<T extends object>(): {
146
- ValtioProvider: ({ store, children }: {
147
- store: T;
148
- children?: ReactNode;
149
- }) => react_jsx_runtime.JSX.Element;
150
- useValtioStore: () => T;
151
- };
152
-
153
140
  type Params = Record<string, any>;
154
141
  /**
155
142
  * 通知当前页面的父页面或者顶级窗口
@@ -166,6 +153,19 @@ declare function useIframeRelayBridge(allowedOrigins?: string[]): {
166
153
  off: (type: string, handler: Handler<Params>) => void;
167
154
  };
168
155
 
156
+ /**
157
+ * 通用的 Valtio Context 工厂
158
+ * 支持:
159
+ * - useStore() 获取 store 实例
160
+ */
161
+ declare function useCreateValtioContext<T extends object>(): {
162
+ ValtioProvider: ({ store, children }: {
163
+ store: T;
164
+ children?: ReactNode;
165
+ }) => react_jsx_runtime.JSX.Element;
166
+ useValtioStore: () => T;
167
+ };
168
+
169
169
  /**
170
170
  * 防抖hook
171
171
  * @param func 需要执行的函数
@@ -242,6 +242,7 @@ declare const copyText: (text: string) => Promise<void>;
242
242
  declare function formatNumberWithCommas(number: number | string): string | number;
243
243
  declare const generateRandomNumbers: (min: number, max: number, count: number) => number[];
244
244
  declare const getFileName: (filePath: string) => string;
245
+ declare const getFileSuffixName: (fileName: string) => string;
245
246
  declare const textAreaView: (con?: string) => string;
246
247
  /**
247
248
  * 将对象转换为 URL 查询参数字符串
@@ -311,7 +312,21 @@ declare const isClient: boolean;
311
312
  */
312
313
  declare const isExternal: (path: string) => boolean;
313
314
  declare const isBlob: (val: unknown) => boolean;
315
+ declare const isLocalhost: (host?: string) => boolean;
314
316
 
317
+ interface UserInfo {
318
+ id: number;
319
+ orgName: string;
320
+ name: string;
321
+ username: string;
322
+ mobile: string;
323
+ avatar: string;
324
+ myInviteCode: string;
325
+ email?: string;
326
+ remark?: string;
327
+ roles: number[];
328
+ permissions: string[];
329
+ }
315
330
  declare function setCurrentUser(userInfo: any): void;
316
331
  declare function getCurrentUser(): any;
317
332
  declare function clearCurrentUser(): void;
@@ -367,4 +382,4 @@ declare function getSignPath(): string;
367
382
  declare const LgPrimaryColor: string;
368
383
  declare const themeConfig: ThemeConfig;
369
384
 
370
- export { _default$c as AudioPlayer, DateFormatType, DateFormatType2, ERROR, FORBIDDEN, FacePastCode, _default$b as FileIcon, _default$a as FilePreview, _default$9 as FilePreviewDrawer, ILLEGAL_PARAMETER, _default$5 as Iframe, _default$4 as LazyComponent, LgPrimaryColor, LoginPastCode, MISSING_PARAMETER, _default$3 as MarkdownEditor, _default$8 as MarkdownPreview, NOT_FOUND, type NsSetIntervalReturnType, OK, OK2, PERMISSION_DENIED, type Params, _default$7 as PdfPreview, type RenderControl, type RenderControlObj, _default$2 as RenderMarkdown, RenderWrapper, TOKEN_KEY, UNAUTHORIZED, _default$1 as UserAvatar, _default$6 as VideoPlayer, absVal, addUrlLastSlash, arrToObj, buildUrlParams, calculate, clearCurrentUser, clearToken, compareNum, copyText, createValtioContext, decimalPlaces, deepCopy, deepEqual, deepMerge, dividedBy, downloadFile, emit, emitToChild, formType, formatDate, formatNumberWithCommas, genNonDuplicateID, generateRandomNumbers, getCurrentUser, getDeviceId, getEndOfTimestamp, getFileName, getSignPath, getStartOfTimestamp, getTimestamp, getToken, getUrlMainSource, getUrlToken, getWebSocketUrl, is, isArray, isBlob, isBoolean, isClient, isDate, isDef, isElement, isEmpty, isEmptyObj, isExpire, isExternal, isFunction, isInteger, isMap, isNegative, isNull, isNullOrUnDef, isNumber, isNumberNoNaN, isObject, isPromise, isRegExp, isServer, isString, isUnDef, isWindow, jsonType, minus, nsSetInterval, objToOptions, plus, precision, propsMerge, _default as request, setCurrentUser, setToken, shouldRender, textAreaView, themeConfig, times, toFixed, useDebounce, useDeepEffect, useIframeRelayBridge, useRefState, useSyncInput, useThrottle, useWebSocket };
385
+ export { _default$c as AudioPlayer, DateFormatType, DateFormatType2, ERROR, FORBIDDEN, FacePastCode, _default$b as FileIcon, _default$a as FilePreview, _default$9 as FilePreviewDrawer, ILLEGAL_PARAMETER, _default$5 as Iframe, _default$4 as LazyComponent, LgPrimaryColor, LoginPastCode, MISSING_PARAMETER, _default$3 as MarkdownEditor, _default$8 as MarkdownPreview, NOT_FOUND, type NsSetIntervalReturnType, OK, OK2, PERMISSION_DENIED, type Params, _default$7 as PdfPreview, type RenderControl, type RenderControlObj, _default$2 as RenderMarkdown, RenderWrapper, TOKEN_KEY, UNAUTHORIZED, _default$1 as UserAvatar, type UserInfo, _default$6 as VideoPlayer, absVal, addUrlLastSlash, arrToObj, buildUrlParams, calculate, clearCurrentUser, clearToken, compareNum, copyText, decimalPlaces, deepCopy, deepEqual, deepMerge, dividedBy, downloadFile, emit, emitToChild, formType, formatDate, formatNumberWithCommas, genNonDuplicateID, generateRandomNumbers, getCurrentUser, getDeviceId, getEndOfTimestamp, getFileName, getFileSuffixName, getSignPath, getStartOfTimestamp, getTimestamp, getToken, getUrlMainSource, getUrlToken, getWebSocketUrl, is, isArray, isBlob, isBoolean, isClient, isDate, isDef, isElement, isEmpty, isEmptyObj, isExpire, isExternal, isFunction, isInteger, isLocalhost, isMap, isNegative, isNull, isNullOrUnDef, isNumber, isNumberNoNaN, isObject, isPromise, isRegExp, isServer, isString, isUnDef, isWindow, jsonType, minus, nsSetInterval, objToOptions, plus, precision, propsMerge, _default as request, setCurrentUser, setToken, shouldRender, textAreaView, themeConfig, times, toFixed, useCreateValtioContext, useDebounce, useDeepEffect, useIframeRelayBridge, useRefState, useSyncInput, useThrottle, useWebSocket };
package/dist/index.d.ts CHANGED
@@ -137,19 +137,6 @@ interface Props {
137
137
  }
138
138
  declare const _default$1: ({ size, avatarSrc, userName }: Props) => react_jsx_runtime.JSX.Element;
139
139
 
140
- /**
141
- * 通用的 Valtio Context 工厂
142
- * 支持:
143
- * - useStore() 获取 store 实例
144
- */
145
- declare function createValtioContext<T extends object>(): {
146
- ValtioProvider: ({ store, children }: {
147
- store: T;
148
- children?: ReactNode;
149
- }) => react_jsx_runtime.JSX.Element;
150
- useValtioStore: () => T;
151
- };
152
-
153
140
  type Params = Record<string, any>;
154
141
  /**
155
142
  * 通知当前页面的父页面或者顶级窗口
@@ -166,6 +153,19 @@ declare function useIframeRelayBridge(allowedOrigins?: string[]): {
166
153
  off: (type: string, handler: Handler<Params>) => void;
167
154
  };
168
155
 
156
+ /**
157
+ * 通用的 Valtio Context 工厂
158
+ * 支持:
159
+ * - useStore() 获取 store 实例
160
+ */
161
+ declare function useCreateValtioContext<T extends object>(): {
162
+ ValtioProvider: ({ store, children }: {
163
+ store: T;
164
+ children?: ReactNode;
165
+ }) => react_jsx_runtime.JSX.Element;
166
+ useValtioStore: () => T;
167
+ };
168
+
169
169
  /**
170
170
  * 防抖hook
171
171
  * @param func 需要执行的函数
@@ -242,6 +242,7 @@ declare const copyText: (text: string) => Promise<void>;
242
242
  declare function formatNumberWithCommas(number: number | string): string | number;
243
243
  declare const generateRandomNumbers: (min: number, max: number, count: number) => number[];
244
244
  declare const getFileName: (filePath: string) => string;
245
+ declare const getFileSuffixName: (fileName: string) => string;
245
246
  declare const textAreaView: (con?: string) => string;
246
247
  /**
247
248
  * 将对象转换为 URL 查询参数字符串
@@ -311,7 +312,21 @@ declare const isClient: boolean;
311
312
  */
312
313
  declare const isExternal: (path: string) => boolean;
313
314
  declare const isBlob: (val: unknown) => boolean;
315
+ declare const isLocalhost: (host?: string) => boolean;
314
316
 
317
+ interface UserInfo {
318
+ id: number;
319
+ orgName: string;
320
+ name: string;
321
+ username: string;
322
+ mobile: string;
323
+ avatar: string;
324
+ myInviteCode: string;
325
+ email?: string;
326
+ remark?: string;
327
+ roles: number[];
328
+ permissions: string[];
329
+ }
315
330
  declare function setCurrentUser(userInfo: any): void;
316
331
  declare function getCurrentUser(): any;
317
332
  declare function clearCurrentUser(): void;
@@ -367,4 +382,4 @@ declare function getSignPath(): string;
367
382
  declare const LgPrimaryColor: string;
368
383
  declare const themeConfig: ThemeConfig;
369
384
 
370
- export { _default$c as AudioPlayer, DateFormatType, DateFormatType2, ERROR, FORBIDDEN, FacePastCode, _default$b as FileIcon, _default$a as FilePreview, _default$9 as FilePreviewDrawer, ILLEGAL_PARAMETER, _default$5 as Iframe, _default$4 as LazyComponent, LgPrimaryColor, LoginPastCode, MISSING_PARAMETER, _default$3 as MarkdownEditor, _default$8 as MarkdownPreview, NOT_FOUND, type NsSetIntervalReturnType, OK, OK2, PERMISSION_DENIED, type Params, _default$7 as PdfPreview, type RenderControl, type RenderControlObj, _default$2 as RenderMarkdown, RenderWrapper, TOKEN_KEY, UNAUTHORIZED, _default$1 as UserAvatar, _default$6 as VideoPlayer, absVal, addUrlLastSlash, arrToObj, buildUrlParams, calculate, clearCurrentUser, clearToken, compareNum, copyText, createValtioContext, decimalPlaces, deepCopy, deepEqual, deepMerge, dividedBy, downloadFile, emit, emitToChild, formType, formatDate, formatNumberWithCommas, genNonDuplicateID, generateRandomNumbers, getCurrentUser, getDeviceId, getEndOfTimestamp, getFileName, getSignPath, getStartOfTimestamp, getTimestamp, getToken, getUrlMainSource, getUrlToken, getWebSocketUrl, is, isArray, isBlob, isBoolean, isClient, isDate, isDef, isElement, isEmpty, isEmptyObj, isExpire, isExternal, isFunction, isInteger, isMap, isNegative, isNull, isNullOrUnDef, isNumber, isNumberNoNaN, isObject, isPromise, isRegExp, isServer, isString, isUnDef, isWindow, jsonType, minus, nsSetInterval, objToOptions, plus, precision, propsMerge, _default as request, setCurrentUser, setToken, shouldRender, textAreaView, themeConfig, times, toFixed, useDebounce, useDeepEffect, useIframeRelayBridge, useRefState, useSyncInput, useThrottle, useWebSocket };
385
+ export { _default$c as AudioPlayer, DateFormatType, DateFormatType2, ERROR, FORBIDDEN, FacePastCode, _default$b as FileIcon, _default$a as FilePreview, _default$9 as FilePreviewDrawer, ILLEGAL_PARAMETER, _default$5 as Iframe, _default$4 as LazyComponent, LgPrimaryColor, LoginPastCode, MISSING_PARAMETER, _default$3 as MarkdownEditor, _default$8 as MarkdownPreview, NOT_FOUND, type NsSetIntervalReturnType, OK, OK2, PERMISSION_DENIED, type Params, _default$7 as PdfPreview, type RenderControl, type RenderControlObj, _default$2 as RenderMarkdown, RenderWrapper, TOKEN_KEY, UNAUTHORIZED, _default$1 as UserAvatar, type UserInfo, _default$6 as VideoPlayer, absVal, addUrlLastSlash, arrToObj, buildUrlParams, calculate, clearCurrentUser, clearToken, compareNum, copyText, decimalPlaces, deepCopy, deepEqual, deepMerge, dividedBy, downloadFile, emit, emitToChild, formType, formatDate, formatNumberWithCommas, genNonDuplicateID, generateRandomNumbers, getCurrentUser, getDeviceId, getEndOfTimestamp, getFileName, getFileSuffixName, getSignPath, getStartOfTimestamp, getTimestamp, getToken, getUrlMainSource, getUrlToken, getWebSocketUrl, is, isArray, isBlob, isBoolean, isClient, isDate, isDef, isElement, isEmpty, isEmptyObj, isExpire, isExternal, isFunction, isInteger, isLocalhost, isMap, isNegative, isNull, isNullOrUnDef, isNumber, isNumberNoNaN, isObject, isPromise, isRegExp, isServer, isString, isUnDef, isWindow, jsonType, minus, nsSetInterval, objToOptions, plus, precision, propsMerge, _default as request, setCurrentUser, setToken, shouldRender, textAreaView, themeConfig, times, toFixed, useCreateValtioContext, useDebounce, useDeepEffect, useIframeRelayBridge, useRefState, useSyncInput, useThrottle, useWebSocket };
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import { FileUnknownOutlined, FileZipOutlined, FileMarkdownOutlined, FileGifOutlined, FileImageOutlined, FileJpgOutlined, NotificationOutlined, VideoCameraOutlined, FilePptOutlined, FileExcelOutlined, FileWordOutlined, FilePdfOutlined, FileTextOutlined } from '@ant-design/icons';
3
3
  import * as React16 from 'react';
4
- import { forwardRef, useState, useMemo, useEffect, lazy, Suspense, createContext, useRef, useCallback, useContext } from 'react';
4
+ import { forwardRef, useState, useMemo, useEffect, lazy, Suspense, useRef, createContext, useCallback, useContext } from 'react';
5
5
  import { Spin, notification, Modal, Result, Splitter, Empty, Image, Flex, Drawer, Tag, Avatar, Alert, Form, Input, Button } from 'antd';
6
6
  import parse from 'html-react-parser';
7
7
  import { jsonrepair } from 'jsonrepair';
@@ -43,7 +43,6 @@ import TiptapLink from '@tiptap/extension-link';
43
43
  import { Plugin, TextSelection, PluginKey } from '@tiptap/pm/state';
44
44
  import { DecorationSet, Decoration } from '@tiptap/pm/view';
45
45
  import { useMergeRefs, FloatingPortal, FloatingFocusManager, useListItem, FloatingDelayGroup, useFloating, offset, flip, shift, autoUpdate, useHover, useFocus, useDismiss, useRole, useInteractions, FloatingList, useClick, useListNavigation, useTypeahead, limitShift } from '@floating-ui/react';
46
- import TurndownService from 'turndown';
47
46
  import { Node, mergeAttributes, Extension as Extension$1 } from '@tiptap/core';
48
47
 
49
48
  // src/components/File/styles.module.less
@@ -315,20 +314,6 @@ var MarkdownPreview_default = ({ fileUrl, searchValue }) => {
315
314
  }, [fileUrl]);
316
315
  return error ? /* @__PURE__ */ jsx(Result, { status: "error", title: error }) : /* @__PURE__ */ jsx("div", { className: "height-full", children: /* @__PURE__ */ jsx(RenderMarkdown_default, { content, searchValue }) });
317
316
  };
318
- function createValtioContext() {
319
- const Context = createContext(null);
320
- const ValtioProvider = ({ store, children }) => /* @__PURE__ */ jsx(Context.Provider, { value: store, children });
321
- const useValtioStore = () => {
322
- const store = useContext(Context);
323
- if (!store) throw new Error("useStore must be used within Provider");
324
- return store;
325
- };
326
- return {
327
- ValtioProvider,
328
- useValtioStore
329
- // Context
330
- };
331
- }
332
317
 
333
318
  // src/hooks/iframe/iframeRelay.ts
334
319
  function emit(type, data, to = "top") {
@@ -434,6 +419,9 @@ var isExternal = (path) => {
434
419
  var isBlob = (val) => {
435
420
  return is(val, "Blob");
436
421
  };
422
+ var isLocalhost = (host) => {
423
+ return /^(localhost:)/.test(host || location.host);
424
+ };
437
425
 
438
426
  // src/hooks/iframe/useIframeRelayBridge.ts
439
427
  function useIframeRelayBridge(allowedOrigins = ["*"]) {
@@ -464,6 +452,20 @@ function useIframeRelayBridge(allowedOrigins = ["*"]) {
464
452
  }
465
453
  return { on, off };
466
454
  }
455
+ function useCreateValtioContext() {
456
+ const Context = createContext(null);
457
+ const ValtioProvider = ({ store, children }) => /* @__PURE__ */ jsx(Context.Provider, { value: store, children });
458
+ const useValtioStore = () => {
459
+ const store = useContext(Context);
460
+ if (!store) throw new Error("useStore must be used within Provider");
461
+ return store;
462
+ };
463
+ return {
464
+ ValtioProvider,
465
+ useValtioStore
466
+ // Context
467
+ };
468
+ }
467
469
  function useDebounce(func, wait = 400) {
468
470
  const { current } = useRef({ func, timeOut: null });
469
471
  useEffect(() => {
@@ -641,6 +643,9 @@ var generateRandomNumbers = (min, max, count) => {
641
643
  var getFileName = (filePath) => {
642
644
  return filePath.split("?")[0].split("/").pop() || "";
643
645
  };
646
+ var getFileSuffixName = (fileName) => {
647
+ return fileName.split(".").pop() || "";
648
+ };
644
649
  var textAreaView = (con) => {
645
650
  return con ? con.replace(/\r\n/g, "\n").replace(/\n/g, "<br/>") : "";
646
651
  };
@@ -4914,7 +4919,6 @@ var SearchAndReplace = Extension$1.create({
4914
4919
  }
4915
4920
  });
4916
4921
  var searchAndReplace_default = SearchAndReplace;
4917
- var turndown = new TurndownService();
4918
4922
  var MainToolbarContent = ({
4919
4923
  onHighlighterClick,
4920
4924
  onLinkClick,
@@ -5044,7 +5048,7 @@ var MarkdownEditor_default = ({ value = "", onChange, onScrollPage, searchValue,
5044
5048
  });
5045
5049
  const getMarkdown = () => {
5046
5050
  if (!editor) return "";
5047
- return turndown.turndown(editor.getHTML());
5051
+ return editor.storage.markdown.getMarkdown();
5048
5052
  };
5049
5053
  const bodyRect = useCursorVisibility({
5050
5054
  editor,
@@ -5217,6 +5221,6 @@ var UserAvatar_default = ({ size, avatarSrc, userName }) => {
5217
5221
  return avatarSrc ? /* @__PURE__ */ jsx(Avatar, { size, src: avatarSrc }) : /* @__PURE__ */ jsx(Avatar, { size, className: "cursor-pointer", style: { backgroundColor: LgPrimaryColor }, children: userName?.slice(0, 1)?.toLocaleUpperCase() });
5218
5222
  };
5219
5223
 
5220
- export { AudioPlayer_default as AudioPlayer, DateFormatType, DateFormatType2, ERROR, FORBIDDEN, FacePastCode, FileIcon_default as FileIcon, FilePreview_default as FilePreview, FilePreviewDrawer_default as FilePreviewDrawer, ILLEGAL_PARAMETER, Iframe_default as Iframe, LazyComponent_default as LazyComponent, LgPrimaryColor, LoginPastCode, MISSING_PARAMETER, MarkdownEditor_default as MarkdownEditor, MarkdownPreview_default as MarkdownPreview, NOT_FOUND, OK, OK2, PERMISSION_DENIED, PdfPreview_default as PdfPreview, RenderMarkdown_default as RenderMarkdown, RenderWrapper, TOKEN_KEY, UNAUTHORIZED, UserAvatar_default as UserAvatar, VideoPlayer_default as VideoPlayer, absVal, addUrlLastSlash, arrToObj, buildUrlParams, calculate, clearCurrentUser, clearToken, compareNum, copyText, createValtioContext, decimalPlaces, deepCopy, deepEqual, deepMerge, dividedBy, downloadFile, emit, emitToChild, formType, formatDate, formatNumberWithCommas, genNonDuplicateID, generateRandomNumbers, getCurrentUser, getDeviceId, getEndOfTimestamp, getFileName, getSignPath, getStartOfTimestamp, getTimestamp, getToken, getUrlMainSource, getUrlToken, getWebSocketUrl, is, isArray, isBlob, isBoolean, isClient, isDate, isDef, isElement, isEmpty, isEmptyObj, isExpire, isExternal, isFunction, isInteger, isMap, isNegative, isNull, isNullOrUnDef, isNumber, isNumberNoNaN, isObject, isPromise, isRegExp, isServer, isString, isUnDef, isWindow, jsonType, minus, nsSetInterval, objToOptions, plus, precision, propsMerge, request_default as request, setCurrentUser, setToken, shouldRender, textAreaView, themeConfig, times, toFixed, useDebounce, useDeepEffect, useIframeRelayBridge, useRefState, useSyncInput, useThrottle, useWebSocket_default as useWebSocket };
5224
+ export { AudioPlayer_default as AudioPlayer, DateFormatType, DateFormatType2, ERROR, FORBIDDEN, FacePastCode, FileIcon_default as FileIcon, FilePreview_default as FilePreview, FilePreviewDrawer_default as FilePreviewDrawer, ILLEGAL_PARAMETER, Iframe_default as Iframe, LazyComponent_default as LazyComponent, LgPrimaryColor, LoginPastCode, MISSING_PARAMETER, MarkdownEditor_default as MarkdownEditor, MarkdownPreview_default as MarkdownPreview, NOT_FOUND, OK, OK2, PERMISSION_DENIED, PdfPreview_default as PdfPreview, RenderMarkdown_default as RenderMarkdown, RenderWrapper, TOKEN_KEY, UNAUTHORIZED, UserAvatar_default as UserAvatar, VideoPlayer_default as VideoPlayer, absVal, addUrlLastSlash, arrToObj, buildUrlParams, calculate, clearCurrentUser, clearToken, compareNum, copyText, decimalPlaces, deepCopy, deepEqual, deepMerge, dividedBy, downloadFile, emit, emitToChild, formType, formatDate, formatNumberWithCommas, genNonDuplicateID, generateRandomNumbers, getCurrentUser, getDeviceId, getEndOfTimestamp, getFileName, getFileSuffixName, getSignPath, getStartOfTimestamp, getTimestamp, getToken, getUrlMainSource, getUrlToken, getWebSocketUrl, is, isArray, isBlob, isBoolean, isClient, isDate, isDef, isElement, isEmpty, isEmptyObj, isExpire, isExternal, isFunction, isInteger, isLocalhost, isMap, isNegative, isNull, isNullOrUnDef, isNumber, isNumberNoNaN, isObject, isPromise, isRegExp, isServer, isString, isUnDef, isWindow, jsonType, minus, nsSetInterval, objToOptions, plus, precision, propsMerge, request_default as request, setCurrentUser, setToken, shouldRender, textAreaView, themeConfig, times, toFixed, useCreateValtioContext, useDebounce, useDeepEffect, useIframeRelayBridge, useRefState, useSyncInput, useThrottle, useWebSocket_default as useWebSocket };
5221
5225
  //# sourceMappingURL=index.esm.js.map
5222
5226
  //# sourceMappingURL=index.esm.js.map