A fully open source & end-to-end encrypted note taking alternative to Evernote.
This report summarizes scanner evidence for streetwriters/notesnook, a TypeScript project with 14,864 GitHub stars. SynthScan examined 455,548 lines of code across 2022 source files, recording 200 pattern matches distributed across 9 syntactic categories. The legacy adjusted pattern signal is 0.5 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 159 finding(s).
Are imports declared and package/API names verified? 30 finding(s).
Are wrappers, guards, and repeated structures necessary? 86 finding(s).
Which changes need focused human review? 200 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 200 distinct pattern matches across 9 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | extensions/web-clipper/webpack.config.js | 161 | force: true | COMMENT |
| LOW | extensions/web-clipper/webpack.config.js | 181 | cache: false | COMMENT |
| LOW | packages/core/__e2e__/user-manager.test.js | 121 | // const usermanager = new UserManager(db); | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 321 | ); | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 341 | // if (type === "upload" && current === half) { | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 361 | // }); | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 381 | // async () => { | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 401 | // const noteId = await deviceA.notes.add({ | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 421 | // await expect(deviceA.sync(true)).rejects.toThrow(); | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 721 | // initializeDevice("deviceA"), | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 741 | // await deviceB.sync({ type: "full" }); | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 761 | // console.timeEnd("adding devices"); | COMMENT |
| LOW | packages/core/__e2e__/sync.test.js | 781 | // await Promise.all( | COMMENT |
| LOW | packages/core/__tests__/vault.test.js | 321 | // const vault = await db.vaults.default(); | COMMENT |
| LOW | packages/core/__benches__/relations.bench.ts | 21 | import { databaseTest } from "../__tests__/utils/index.js"; | COMMENT |
| LOW | packages/core/__benches__/relations.bench.ts | 41 | // } | COMMENT |
| LOW | packages/core/src/database/sql-cached-collection.ts | 181 | COMMENT | |
| LOW | packages/core/src/database/sql-cached-collection.ts | 201 | // items(map?: (item: T) => T | undefined) { | COMMENT |
| LOW | packages/core/src/database/sql-cached-collection.ts | 221 | // } | COMMENT |
| LOW | packages/core/src/database/migrations.ts | 361 | } | COMMENT |
| LOW | packages/core/src/api/index.ts | 181 | // return; | COMMENT |
| LOW | packages/core/src/collections/note-history.ts | 41 | } | COMMENT |
| LOW | packages/core/src/collections/note-history.ts | 241 | // const items = await this.collection.getItems(sessionIds); | COMMENT |
| LOW | packages/core/src/collections/shortcuts.ts | 161 | // (shortcut) => | COMMENT |
| LOW | packages/clipper/playwright.config.ts | 81 | // ...devices["Desktop Firefox"] | COMMENT |
| LOW | packages/clipper/playwright.config.ts | 101 | // use: { | COMMENT |
| LOW | packages/editor-mobile/src/setupTests.js | 21 | // allows you to do things like: | COMMENT |
| LOW | packages/editor/src/extensions/table/component.tsx | 61 | }, [node, cellMinWidth]); | COMMENT |
| LOW | …r/src/extensions/table/prosemirror-tables/copypaste.ts | 1 | // Utilities used for copy/paste handling. | COMMENT |
| LOW | …ckages/editor/src/extensions/react/react-node-view.tsx | 361 | // return false; | COMMENT |
| LOW | …ckages/editor/src/extensions/react/react-node-view.tsx | 381 | COMMENT | |
| LOW | apps/web/playwright.config.ts | 81 | // } | COMMENT |
| LOW | apps/web/__e2e__/user.test.ts | 101 | expect(await app.navigation.findItem("Notes")).toBeDefined(); | COMMENT |
| LOW | apps/web/__e2e__/user.test.ts | 121 | // password: currentPassword | COMMENT |
| LOW | apps/web/__e2e__/user.test.ts | 141 | COMMENT | |
| LOW | apps/web/__e2e__/user.test.ts | 161 | // await page.click(getTestId("step-recovery-key")); | COMMENT |
| LOW | apps/web/__e2e__/user.test.ts | 181 | // let newPassword = USER.NEW.password; | COMMENT |
| LOW | apps/web/__e2e__/user.test.ts | 201 | // await page.click(getTestId("submitButton")); | COMMENT |
| LOW | apps/web/__e2e__/user.test.ts | 221 | COMMENT | |
| LOW | apps/web/__e2e__/user.test.ts | 241 | COMMENT | |
| LOW | apps/web/__e2e__/user.test.ts | 281 | COMMENT | |
| LOW | apps/web/__e2e__/user.test.ts | 301 | // const cKey = currentKey; | COMMENT |
| LOW | apps/web/__e2e__/importer.test.js | 21 | // const { getTestId, isTestAll, loginUser } = require("./utils"); | COMMENT |
| LOW | apps/web/__e2e__/importer.test.js | 41 | // await page.click(getTestId("navitem-settings")); | COMMENT |
| LOW | apps/web/__e2e__/importer.test.js | 61 | // } | COMMENT |
| LOW | apps/web/__e2e__/notebooks.test.ts | 181 | // const notebook = await notebooks.createNotebook(NOTEBOOK); | COMMENT |
| LOW | apps/web/src/components/virtualized-table/index.tsx | 101 | ); | COMMENT |
| LOW | apps/web/src/components/virtualized-table/index.tsx | 121 | // height: virtualizer.getTotalSize() + headerSize | COMMENT |
| LOW | apps/web/src/components/virtualized-table/index.tsx | 141 | // }} | COMMENT |
| LOW | apps/web/src/components/split-pane/index.tsx | 241 | // TODO: responsiveness | COMMENT |
| LOW | apps/web/src/common/db.ts | 101 | const limit = await getFeatureLimit(getFeature("maxNoteVersions")); | COMMENT |
| LOW | apps/web/src/dialogs/settings/index.tsx | 201 | COMMENT | |
| LOW | apps/web/src/dialogs/buy-dialog/types.ts | 101 | COMMENT | |
| LOW | apps/web/src/dialogs/buy-dialog/types.ts | 181 | // payments: Payments; | COMMENT |
| LOW | apps/web/src/views/email-confirmed.tsx | 221 | </Button> */} | COMMENT |
| LOW | apps/web/src/views/email-confirmed.tsx | 241 | // "Privacy is our basic right" | COMMENT |
| LOW | apps/web/src/views/email-confirmed.tsx | 261 | // | COMMENT |
| LOW | apps/web/src/views/email-confirmed.tsx | 281 | // </Button> | COMMENT |
| LOW | apps/desktop/__tests__/electron-test/base-test.ts | 61 | // builtins: Builtins; | COMMENT |
| LOW | apps/monograph/app/components/footer.tsx | 161 | borderRadius: "default" | COMMENT |
| 17 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | packages/core/__e2e__/user-keys.test.ts | 75 | async function storeKeysNewerThanMasterKey(db: any) { | CODE |
| LOW | packages/core/__tests__/sql-migrations.test.ts | 52 | async function createMigrationProviderBefore(migrationName: string) { | CODE |
| LOW | packages/core/__tests__/notes.test.ts | 36 | async function createAndAddNoteToNotebook( | CODE |
| LOW | packages/core/src/migrations.ts | 616 | function replaceDateEditedWithDateModified(removeDateEditedProperty = false) { | CODE |
| LOW | packages/core/src/migrations.ts | 642 | function removeToxClassFromChecklist(html: string): string { | CODE |
| LOW | packages/core/src/common.ts | 60 | export function sendMigrationProgressEvent( | CODE |
| LOW | packages/core/src/utils/date.ts | 40 | export function getWeekGroupFromTimestamp(timestamp: number, locale?: string) { | CODE |
| LOW | …/core/src/utils/__tests__/virtualized-grouping.test.ts | 36 | function createVirtualizedGrouping( | CODE |
| LOW | packages/core/src/collections/reminders.ts | 287 | export function createUpcomingReminderTimeQuery(unix = "now") { | CODE |
| LOW | packages/core/src/collections/reminders.ts | 334 | export function createIsReminderActiveQuery(now = "now") { | CODE |
| LOW | packages/clipper/src/index.ts | 269 | function injectNodeSelectionControls( | CODE |
| LOW | packages/common/src/utils/date-time.ts | 48 | export function getFormattedHistorySessionDate(session: HistorySession) { | CODE |
| LOW | …s/editor/src/toolbar/floating-menus/search-replace.tsx | 26 | export function SearchReplaceFloatingMenu(props: FloatingMenuProps) { | CODE |
| LOW | packages/editor/src/utils/prosemirror.ts | 152 | export function findParentNodeClosestToPos( | CODE |
| LOW | packages/editor/src/extensions/embed/component.tsx | 194 | function getIframeAllowPermissions(src: string) { | CODE |
| LOW | packages/editor/src/extensions/heading/heading.ts | 384 | function findEndOfCollapsedSection( | CODE |
| LOW | …src/extensions/math/plugin/plugins/math-paste-rules.ts | 67 | function texFromMediaWikiFallbackImage(root: Element): false | string { | CODE |
| LOW | …c/extensions/table/prosemirror-tables/cellselection.ts | 408 | function isTextSelectionAcrossCells({ $from, $to }: TextSelection) { | CODE |
| LOW | …/extensions/table/prosemirror-tables/columnresizing.ts | 370 | export function createColumnResizeHandles( | CODE |
| LOW | …c/extensions/table/prosemirror-tables/utils/convert.ts | 29 | export function convertTableNodeToArrayOfRows( | CODE |
| LOW | …c/extensions/table/prosemirror-tables/utils/convert.ts | 70 | export function convertArrayOfRowsToTableNode( | CODE |
| LOW | …ions/table/prosemirror-tables/utils/selection-range.ts | 23 | export function getSelectionRangeInColumn( | CODE |
| LOW | …ditor/src/extensions/clipboard/clipboard-dom-parser.ts | 106 | export function convertBrToSingleSpacedParagraphs(dom: HTMLElement | Document) { | CODE |
| LOW | …ditor/src/extensions/clipboard/clipboard-dom-parser.ts | 156 | export function convertGoogleDocsChecklist(dom: HTMLElement | Document) { | CODE |
| LOW | apps/web/__e2e__/models/utils.ts | 127 | export async function fillConfirmPasswordDialog(page: Page, password: string) { | CODE |
| LOW | apps/web/src/index.html | 42 | (async function validateServiceWorkerTrack() { | CODE |
| LOW | apps/web/src/app-effects.tsx | 102 | function handleDownloadUploadProgress( | CODE |
| LOW | apps/web/src/app-effects.tsx | 219 | function getProcessingStatusFromType(type: ProcessingType) { | CODE |
| LOW | apps/web/src/utils/feature-check.ts | 29 | export function isTransferableStreamsSupported() { | CODE |
| LOW | apps/web/src/utils/stream-saver/index.ts | 54 | function checkSupportsTransferable() { | CODE |
| LOW | apps/web/src/components/list-container/index.tsx | 54 | >(function CustomScrollbarsVirtualList(props, ref) { | CODE |
| LOW | …ps/web/src/components/list-container/list-profiles.tsx | 126 | export function getListItemPlaceholderData( | CODE |
| LOW | apps/web/src/components/navigation-menu/index.tsx | 1109 | async function getSidebarItemsAsMenuItems(): Promise<MenuItem[]> { | CODE |
| LOW | apps/web/src/components/pdf-preview/links-plugin.tsx | 28 | function findAndReplaceLinkAnnotations(e: PluginOnAnnotationLayerRender) { | CODE |
| LOW | apps/web/src/components/theme-provider/index.tsx | 98 | export function FixedColorSchemeThemeProvider( | CODE |
| LOW | apps/web/src/components/editor/index.tsx | 428 | function DownloadAttachmentProgress(props: DownloadAttachmentProgressProps) { | CODE |
| LOW | apps/web/src/common/toasts.ts | 25 | export function showFeatureNotAllowedToast( | CODE |
| LOW | apps/web/src/common/notices.ts | 89 | export async function shouldAddAutoBackupsDisabledNotice() { | CODE |
| LOW | apps/web/src/common/notices.ts | 112 | export async function shouldAddRecoveryKeyBackupNotice() { | CODE |
| LOW | apps/web/src/common/notices.ts | 125 | export async function shouldAddConfirmEmailNotice() { | CODE |
| LOW | apps/web/src/common/index.ts | 435 | export function totalSubscriptionConsumed(user: User) { | CODE |
| LOW | apps/web/src/common/index.ts | 494 | export function createSetDefaultHomepageMenuItem( | CODE |
| LOW | apps/web/src/common/index.ts | 602 | export async function scheduleExpiredNotesDeletion() { | CODE |
| LOW | apps/web/src/hooks/use-keyboard-list-navigation.ts | 40 | export function useKeyboardListNavigation( | CODE |
| LOW | apps/web/src/dialogs/confirm.tsx | 178 | export function showMultiDeleteConfirmation(length: number) { | CODE |
| LOW | apps/web/src/dialogs/confirm.tsx | 189 | export function showMultiPermanentDeleteConfirmation(length: number) { | CODE |
| LOW | apps/web/src/dialogs/confirm.tsx | 216 | export function showClearSessionsConfirmation() { | CODE |
| LOW | apps/web/src/dialogs/confirm.tsx | 225 | export async function showUpdateAvailableNotice({ | CODE |
| LOW | apps/web/src/dialogs/edit-note-creation-date-dialog.tsx | 48 | function EditNoteCreationDateDialog({ | CODE |
| LOW | apps/web/src/dialogs/command-palette/commands.ts | 351 | async function getActiveNotebookCommands() { | CODE |
| LOW | apps/web/src/dialogs/buy-dialog/plan-list.tsx | 653 | export function formatRecurringPeriodShort(period: Period) { | CODE |
| LOW | apps/mobile/worker.js | 244 | function isEntityInAttributeInvalidEnd(code) { | CODE |
| LOW | apps/mobile/worker.js | 6507 | function hasDependsOnCurrentElement(selector) { | CODE |
| LOW | apps/mobile/worker.js | 10463 | function requireCSSValueExpression() { | CODE |
| LOW | apps/mobile/worker.js | 11422 | function requireCSSStyleDeclaration() { | CODE |
| LOW | apps/mobile/app/screens/settings/theme-selector.tsx | 609 | export default function ThemeSelectorWithQueryClient() { | CODE |
| LOW | apps/mobile/app/screens/manage-tags/index.tsx | 50 | async function updateInitialSelectionState(items: string[]) { | CODE |
| LOW | apps/mobile/app/screens/link-notebooks/index.tsx | 60 | async function updateInitialSelectionState(items: string[]) { | CODE |
| LOW | apps/mobile/app/common/database/encryption.ts | 82 | export async function encryptDatabaseKeyWithPassword(appLockPassword: string) { | CODE |
| LOW | apps/mobile/app/common/database/encryption.ts | 95 | export async function restoreDatabaseKeyToKeyChain(appLockPassword: string) { | CODE |
| 15 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | packages/crypto/__tests__/crypto.test.ts | 30 | // ─── Key Derivation ──────────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/crypto/__tests__/crypto.test.ts | 87 | // ─── Symmetric Encryption Round-Trip ─────────────────────────────── | COMMENT |
| MEDIUM | packages/crypto/__tests__/crypto.test.ts | 166 | // ─── Multi-Encryption ────────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/crypto/__tests__/crypto.test.ts | 190 | // ─── Password Hashing ────────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/crypto/__tests__/crypto.test.ts | 224 | // ─── Streaming Encryption ────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/core/__tests__/encryption-verification.test.ts | 25 | // ─── verifyPassword ──────────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/core/__tests__/encryption-verification.test.ts | 68 | // ─── verifyEncryptionKey ─────────────────────────────────────────── | COMMENT |
| MEDIUM | packages/core/__tests__/password-change.test.ts | 87 | // ─── _updatePassword (change) ────────────────────────────────────── | COMMENT |
| MEDIUM | packages/core/__tests__/password-change.test.ts | 240 | // ─── _updatePassword (reset) ─────────────────────────────────────── | COMMENT |
| MEDIUM | packages/core/__tests__/password-change.test.ts | 287 | // ─── Key migration scenarios ─────────────────────────────────────── | COMMENT |
| MEDIUM | packages/core/__tests__/password-change.test.ts | 388 | // ─── getDataEncryptionKeys ───────────────────────────────────────── | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | packages/core/__tests__/encryption-verification.test.ts | 221 | access_token: "fake-token", | CODE |
| LOW | packages/core/__tests__/encryption-verification.test.ts | 254 | access_token: "fake-token", | CODE |
| LOW | packages/core/__tests__/encryption-verification.test.ts | 274 | "fake-token" | CODE |
| LOW | packages/core/__tests__/encryption-verification.test.ts | 293 | access_token: "fake-token", | CODE |
| LOW | packages/core/__tests__/password-change.test.ts | 60 | access_token: "fake-token", | CODE |
| LOW | packages/core/__tests__/password-change.test.ts | 298 | access_token: "fake-token", t: Date.now(), expires_in: 3600, | CODE |
| LOW | packages/core/__tests__/password-change.test.ts | 341 | access_token: "fake-token", t: Date.now(), expires_in: 3600, | CODE |
| LOW | packages/core/__tests__/user-keys.test.ts | 136 | access_token: "fake-token", | CODE |
| LOW | packages/core/__tests__/user-keys.test.ts | 351 | access_token: "fake-token", | CODE |
| LOW | packages/core/__tests__/user-keys.test.ts | 359 | access_token: "fake-token", | CODE |
| LOW⚡ | packages/core/__tests__/notes.test.ts | 219 | "<p><strong>head</strong><em>line</em>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam rutrum ex ac e | CODE |
| LOW⚡ | packages/core/__tests__/notes.test.ts | 219 | "<p><strong>head</strong><em>line</em>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam rutrum ex ac e | CODE |
| LOW⚡ | packages/core/__tests__/notes.test.ts | 220 | "headlineLorem ipsum dolor sit amet, consectetur adipiscing e" | CODE |
| LOW⚡ | packages/core/__tests__/notes.test.ts | 220 | "headlineLorem ipsum dolor sit amet, consectetur adipiscing e" | CODE |
| LOW | packages/core/__tests__/utils/index.ts | 96 | "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standa | CODE |
| LOW | packages/theme/v1.schema.json | 244 | "placeholder": { | CODE |
| LOW | packages/theme/v1.schema.json | 281 | "placeholder", | CODE |
| LOW | packages/theme/v1.schema.json | 354 | "placeholder": { | CODE |
| LOW | packages/theme/src/theme-engine/types.ts | 312 | "placeholder", | CODE |
| LOW | packages/theme/src/theme-engine/types.ts | 322 | "placeholder", | CODE |
| LOW | packages/theme/src/theme/variants/input.ts | 44 | color: "placeholder" | CODE |
| LOW | packages/theme/src/theme/variants/input.ts | 64 | color: "placeholder" | CODE |
| LOW | apps/web/src/components/editor/title-box.tsx | 130 | color: "placeholder" | CODE |
| LOW | apps/mobile/worker.js | 11876 | return this.getAttribute("placeholder"); | CODE |
| LOW | apps/mobile/worker.js | 11879 | this.setAttribute("placeholder", value); | CODE |
| LOW | apps/mobile/worker.js | 12285 | return this.getAttribute("placeholder"); | CODE |
| LOW | apps/mobile/worker.js | 12288 | this.setAttribute("placeholder", value); | CODE |
| LOW | …bile/app/components/side-menu/side-menu-list-empty.tsx | 66 | key={"placeholder" + i} | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | packages/editor/src/extensions/code-block/code-block.ts | 709 | document.body.firstElementChild.style.fontFamily.includes("monospace") && | CODE |
| CRITICAL | packages/editor/src/extensions/code-block/code-block.ts | 710 | document.body.firstElementChild.style.whiteSpace.includes("pre")); | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | packages/core/__tests__/__fixtures__/backup.v5.2.json | 267 | "data": "<header class=\"header-container header-chrome\"><form class=\"minerva-header\" action=\"https://en.m.wik | CODE |
| MEDIUM | packages/core/__tests__/__fixtures__/backup.v5.2.json | 267 | "data": "<header class=\"header-container header-chrome\"><form class=\"minerva-header\" action=\"https://en.m.wik | CODE |
| MEDIUM | packages/core/src/content-types/tiptap.ts | 452 | // so the dumb length comparison is the most robust way to get the correct value. | COMMENT |
| MEDIUM | …ditor/src/extensions/table/prosemirror-tables/input.ts | 228 | // is robust regardless of what domAtPos returns (text node, <p>, etc.). | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | …ckages/core/src/content-types/__tests__/tiptap.test.js | 72 | codeblocks: `<p>Typescript is one of those languages that appear to be very simple. It's often described as "Javascrip | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | apps/monograph/app/entry.server.tsx | 30 | export default function handleRequest( | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …a/com/streetwriters/notesnook/BootRecieverService.java | 36 | We need to check if app is in foreground otherwise the app will crash. | CODE |