{"id":14449392,"url":"https://github.com/The-Commit-Company/frappe-react-sdk","last_synced_at":"2025-08-28T03:31:44.640Z","repository":{"id":58935193,"uuid":"530507362","full_name":"The-Commit-Company/frappe-react-sdk","owner":"The-Commit-Company","description":"React hooks for Frappe","archived":false,"fork":false,"pushed_at":"2025-07-11T04:38:16.000Z","size":1089,"stargazers_count":139,"open_issues_count":6,"forks_count":44,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-08-15T00:17:41.073Z","etag":null,"topics":["frappe","react"],"latest_commit_sha":null,"homepage":"https://frappe-react.vercel.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/The-Commit-Company.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-08-30T05:16:17.000Z","updated_at":"2025-08-02T14:28:42.000Z","dependencies_parsed_at":"2023-12-11T14:34:12.604Z","dependency_job_id":"f8b3a546-41a1-4111-be81-e396d6d0be10","html_url":"https://github.com/The-Commit-Company/frappe-react-sdk","commit_stats":null,"previous_names":["nikkothari22/frappe-react-sdk"],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/The-Commit-Company/frappe-react-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-Commit-Company%2Ffrappe-react-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-Commit-Company%2Ffrappe-react-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-Commit-Company%2Ffrappe-react-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-Commit-Company%2Ffrappe-react-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/The-Commit-Company","download_url":"https://codeload.github.com/The-Commit-Company/frappe-react-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/The-Commit-Company%2Ffrappe-react-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272430601,"owners_count":24933891,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-28T02:00:10.768Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["frappe","react"],"created_at":"2024-09-01T08:01:15.761Z","updated_at":"2025-08-28T03:31:44.319Z","avatar_url":"https://github.com/The-Commit-Company.png","language":"TypeScript","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# frappe-react-sdk\n\nReact hooks library for a [Frappe Framework](https://frappeframework.com) backend.\n\n\u003cbr /\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/nikkothari22/frappe-react-sdk\"\u003e\u003cimg src=\"https://img.shields.io/maintenance/yes/2024?style=flat-square\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/nikkothari22/frappe-react-sdk\"\u003e\u003cimg src=\"https://img.shields.io/github/license/nikkothari22/frappe-react-sdk?style=flat-square\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/frappe-react-sdk\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/frappe-react-sdk?style=flat-square\" /\u003e\u003c/a\u003e\n    \u003ca href=\"https://www.npmjs.com/package/frappe-react-sdk\"\u003e\u003cimg src=\"https://img.shields.io/npm/dw/frappe-react-sdk?style=flat-square\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Features\n\nThe library currently supports the following features:\n\n- 🔐 Authentication - login with username and password (cookie based) + token based authentication, logout and maintain user state\n- 🗄 Database - Hooks to get document, get list of documents, get count, create, update and delete documents\n- 📄 File upload - Hook to upload a file to the Frappe filesystem. Maintains loading, progress and error states.\n- 🤙🏻 API calls - Hooks to make API calls to your whitelisted backend functions and maintain state\n- 🔍 Search - Hook to search documents in your database (with debouncing ✨)\n\nWe plan to add the following features in the future:\n\n- Support for other common functions like `exists` in the database.\n\nThe library uses [frappe-js-sdk](https://github.com/The-Commit-Company/frappe-js-sdk) and [SWR](https://swr.vercel.app) under the hood to make API calls to your Frappe backend.\n\n\u003cbr/\u003e\n\n## SWR\n\nSWR uses a cache invalidation strategy and also updates the data constantly and automatically (in the background). This allows the UI to always be fast and reactive.\nThe hooks in the library use the default configuration for useSWR but you will be able to overwrite the configuration of useSWR. Please refer to the [useSWR API Options](https://swr.vercel.app/docs/options)\n\n\u003cbr/\u003e\n\n## Looking for a Frappe frontend library for other Javascript frameworks?\n\nYou can use [frappe-js-sdk](https://github.com/nikkothari22/frappe-js-sdk) to interface your frontend web app with Frappe.\n\n\u003cbr/\u003e\n\n## Maintainers\n\n| Maintainer     | GitHub                                          | Social                                                       |\n| -------------- | ----------------------------------------------- | ------------------------------------------------------------ |\n| Nikhil Kothari | [nikkothari22](https://github.com/nikkothari22) | [@nik_kothari22](https://twitter.com/nik_kothari22)          |\n| Janhvi Patil   | [janhvipatil](https://github.com/janhvipatil)   | [@janhvipatil\\_](https://twitter.com/janhvipatil_)           |\n| Sumit Jain     | [sumitjain236](https://github.com/sumitjain236) | [LinkedIn](https://www.linkedin.com/in/sumit-jain-66bb5719a) |\n\n\u003cbr/\u003e\n\n## Installation\n\n```bash\nnpm install frappe-react-sdk\n```\n\nor\n\n```bash\nyarn add frappe-react-sdk\n```\n\n**Note** - All examples below are in Typescript. If you want to use it with Javascript, just ignore the type generics like `\u003cT\u003e` in the examples below.\n\n\u003cbr/\u003e\n\n## Initialising the library\n\nTo get started, initialise the library by wrapping your App with the `FrappeProvider`.\nYou can optionally provide the URL of your Frappe server if the web app is not hosted on the same URL.\n\nIn `App.tsx` or `App.jsx`:\n\n```jsx\nimport { FrappeProvider } from \"frappe-react-sdk\";\n\nfunction App() {\n    /** The URL is an optional parameter. Only use it if the Frappe server is hosted on a separate URL **/\n  return (\n    \u003cFrappeProvider url='https://my-frappe-server.frappe.cloud'\u003e\n    {/** Your other app components **/}\n    \u003c/FrappeProvider\u003e\n  )\n\n```\n\nIn case you want to use the library with token based authentication (OAuth bearer tokens or API key/secret pairs), you can initialise the library like this:\n\n```jsx\nimport { FrappeProvider } from 'frappe-react-sdk';\n\nfunction App() {\n\n  /** The URL is an optional parameter. Only use it if the Frappe server is hosted on a separate URL **/\n  return (\n    \u003cFrappeProvider url='https://my-frappe-server.frappe.cloud' tokenParams={\n        useToken: true,\n        // Pass a custom function that returns the token as a string - this could be fetched from LocalStorage or auth providers like Firebase, Auth0 etc.\n        token: getTokenFromLocalStorage(),\n        // This can be \"Bearer\" or \"token\"\n        type: \"Bearer\"\n    } \u003e\n      {/** Your other app components **/}\n    \u003c/FrappeProvider\u003e\n  );\n}\n```\n\n\u003cbr/\u003e\n\n## Authentication\n\nThe `useFrappeAuth` hook allows you to maintain the state of the current user, as well as login and logout the current user.\n\nThe hook uses `useSWR` under the hood to make the `get_current_user` API call - you can also pass in parameters to configure the behaviour of the useSWR hook.\n\n```jsx\nexport const MyAuthComponent = () =\u003e {\n  const {\n    currentUser,\n    isValidating,\n    isLoading,\n    login,\n    logout,\n    error,\n    updateCurrentUser,\n    getUserCookie,\n  } = useFrappeAuth();\n\n  if (isLoading) return \u003cdiv\u003eloading...\u003c/div\u003e;\n\n  // render user\n  return (\n    \u003cdiv\u003e\n      {currentUser}\n      \u003cbutton onClick={() =\u003e login('administrator', 'admin')}\u003eLogin\u003c/button\u003e\n      \u003cbutton onClick={logout}\u003eLogout\u003c/button\u003e\n      \u003cbutton onClick={updateCurrentUser}\u003eFetch current user\u003c/button\u003e\n    \u003c/div\u003e\n  );\n};\n```\n\nThe hook will not make an API call if no cookie is found. If there is a cookie, it will call the `frappe.auth.get_logged_user` method.\nThe hook will throw an error if the API call to `frappe.auth.get_logged_user` fails (network issue etc) or if the user is logged out (403 Forbidden). Handle errors accordingly and route the user to your login page if the error is because the user is not logged in.\n\nThe `getUserCookie` method can be used to reset the auth state if you encounter an authorization error in any other API call. This will then reset the `currentUser` to null.\n\n\u003cbr/\u003e\n\n## Database\n\n\u003cbr/\u003e\n\n### Fetch a document\n\nThe `useFrappeGetDoc` hook can be used to fetch a document from the database. The hook uses `useSWR` under the hood and it's configuration can be passed to it.\n\nParameters:\n\n| No. | Variable  | type               | Required | Description               |\n| --- | --------- | ------------------ | -------- | ------------------------- |\n| 1.  | `doctype` | `string`           | ✅       | Name of the doctype       |\n| 2.  | `docname` | `string`           | ✅       | Name of the document      |\n| 3.  | `options` | `SWRConfiguration` | -        | SWR Configuration Options |\n\n```tsx\nexport const MyDocumentData = () =\u003e {\n  const { data, error, isValidating, mutate } = useFrappeGetDoc\u003cT\u003e(\n    'User',\n    'Administrator',\n    {\n      /** SWR Configuration Options - Optional **/\n    }\n  );\n\n  if (isValidating) {\n    return \u003c\u003eLoading\u003c/\u003e;\n  }\n  if (error) {\n    return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e;\n  }\n  if (data) {\n    return (\n      \u003cp\u003e\n        {JSON.stringify(data)}\n        \u003cbutton onClick={() =\u003e mutate()}\u003eReload\u003c/button\u003e\n      \u003c/p\u003e\n    );\n  }\n  return null;\n};\n```\n\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### Fetch list of documents\n\nThe `useFrappeGetDocList` hook can be used to fetch a list of documents from the database.\n\nParameters:\n\n| No. | Variable  | type               | Required | Description                                                                                         |\n| --- | --------- | ------------------ | -------- | --------------------------------------------------------------------------------------------------- |\n| 1.  | `doctype` | `string`           | ✅       | Name of the doctype                                                                                 |\n| 2.  | `args`    | `GetDocListArgs`   | -        | optional parameter (object) to sort, filter, paginate and select the fields that you want to fetch. |\n| 3.  | `options` | `SWRConfiguration` | -        | SWR Configuration Options                                                                           |\n\n```tsx\nexport const MyDocumentList = () =\u003e {\n  const { data, error, isValidating, mutate } = useFrappeGetDocList\u003cT\u003e(\n    'DocType',\n    {\n      /** Fields to be fetched - Optional */\n      fields: ['name', 'creation'],\n      /** Filters to be applied - SQL AND operation */\n      filters: [['creation', '\u003e', '2021-10-09']],\n      /** Filters to be applied - SQL OR operation */\n      orFilters: [],\n      /** Fetch from nth document in filtered and sorted list. Used for pagination  */\n      limit_start: 5,\n      /** Number of documents to be fetched. Default is 20  */\n      limit: 10,\n      /** Sort results by field and order  */\n      orderBy: {\n        field: 'creation',\n        order: 'desc',\n      },\n      /** Fetch documents as a dictionary */\n      asDict: false,\n    },\n    {\n      /** SWR Configuration Options - Optional **/\n    }\n  );\n\n  if (isValidating) {\n    return \u003c\u003eLoading\u003c/\u003e;\n  }\n  if (error) {\n    return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e;\n  }\n  if (data) {\n    return (\n      \u003cp\u003e\n        {JSON.stringify(data)}\n        \u003cbutton onClick={() =\u003e mutate()}\u003eReload\u003c/button\u003e\n      \u003c/p\u003e\n    );\n  }\n  return null;\n};\n```\n\nType declarations are available for the second argument and will be shown to you in your code editor.\n\u003cbr/\u003e\n\u003cbr/\u003e\n\n#### Some other simpler examples (click to expand):\n\n\u003cbr/\u003e\n\n\u003cdetails\u003e\u003csummary\u003eFetch 20 items without optional parameters\u003c/summary\u003e\u003cp\u003e\n\nIn this case, only the `name` attribute will be fetched.\n\n```tsx\nexport const MyDocumentList = () =\u003e {\n  const { data, error, isValidating } = useFrappeGetDocList\u003cstring\u003e('User');\n\n  if (isValidating) {\n    return \u003c\u003eLoading\u003c/\u003e;\n  }\n  if (error) {\n    return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e;\n  }\n  if (data) {\n    return (\n      \u003cul\u003e\n        {data.map((username) =\u003e (\n          \u003cli\u003e{username}\u003c/li\u003e\n        ))}\n      \u003c/ul\u003e\n    );\n  }\n  return null;\n};\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eFetch usernames and emails with pagination\u003c/summary\u003e\u003cp\u003e\n\n```tsx\ntype UserItem = {\n    name: string,\n    email: string\n}\nexport const MyDocumentList = () =\u003e {\n    const [pageIndex, setPageIndex] = useState(0)\n    const { data, error, isValidating } = useFrappeGetDocList\u003cUserItem\u003e(\"User\" , {\n        fields: [\"name\", \"email\"],\n        limit_start: pageIndex,\n        /** Number of documents to be fetched. Default is 20  */\n        limit: 10,\n        /** Sort results by field and order  */\n        orderBy: {\n            field: \"creation\",\n            order: 'desc'\n        }\n    });\n\n    if (isValidating) {\n        return \u003c\u003eLoading\u003c/\u003e\n    }\n    if (error) {\n        return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e\n    }\n    if (data) {\n        return \u003cdiv\u003e\n            \u003cul\u003e\n            {\n                data.map({name, email} =\u003e \u003cli\u003e{name} - {email}\u003c/li\u003e)\n            }\n            \u003c/ul\u003e\n            \u003cbutton onClick={() =\u003e setPageIndex(pageIndex + 10)}\u003eNext page\u003c/button\u003e\n        \u003c/div\u003e\n    }\n    return null\n}\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### Fetch number of documents with filters\n\n\u003cbr/\u003e\n\nParameters:\n\n| No. | Variable  | type               | Required | Description                                                    |\n| --- | --------- | ------------------ | -------- | -------------------------------------------------------------- |\n| 1.  | `doctype` | `string`           | ✅       | Name of the doctype                                            |\n| 2.  | `filters` | `Filter[]`         | -        | optional parameter to filter the result                        |\n| 3.  | `cache`   | `boolean`          | -        | Whether to cache the value on the server - default: `false`    |\n| 3.  | `debug`   | `boolean`          | -        | Whether to log debug messages on the server - default: `false` |\n| 3.  | `config`  | `SWRConfiguration` | -        | SWR Configuration Options                                      |\n\n```tsx\nexport const DocumentCount = () =\u003e {\n  const { data, error, isValidating, mutate } = useFrappeGetDocCount(\n    'User',\n    /** Filters **/\n    [['enabled', '=', true]],\n    /** Cache the result on server **/\n    false,\n    /** Print debug logs on server **/\n    false,\n    {\n      /** SWR Configuration Options - Optional **/\n    }\n  );\n\n  if (isValidating) {\n    return \u003c\u003eLoading\u003c/\u003e;\n  }\n  if (error) {\n    return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e;\n  }\n  if (data) {\n    return (\n      \u003cp\u003e\n        {data} enabled users\n        \u003cButton onClick={() =\u003e mutate()}\u003eReload\u003c/Button\u003e\n      \u003c/p\u003e\n    );\n  }\n  return null;\n};\n```\n\n#### Some other simpler examples (click to expand):\n\n\u003cbr/\u003e\n\u003cdetails\u003e\u003csummary\u003eFetch total number of documents\u003c/summary\u003e\u003cp\u003e\n\n```tsx\nexport const DocumentCount = () =\u003e {\n  const { data, error, isValidating } = useFrappeGetDocCount('User');\n\n  if (isValidating) {\n    return \u003c\u003eLoading\u003c/\u003e;\n  }\n  if (error) {\n    return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e;\n  }\n  if (data) {\n    return \u003cp\u003e{data} total users\u003c/p\u003e;\n  }\n  return null;\n};\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eFetch number of documents with filters\u003c/summary\u003e\u003cp\u003e\n\n```tsx\nexport const DocumentCount = () =\u003e {\n  const { data, error, isValidating } = useFrappeGetDocCount('User', [\n    ['enabled', '=', true],\n  ]);\n\n  if (isValidating) {\n    return \u003c\u003eLoading\u003c/\u003e;\n  }\n  if (error) {\n    return \u003c\u003e{JSON.stringify(error)}\u003c/\u003e;\n  }\n  if (data) {\n    return \u003cp\u003e{data} enabled users\u003c/p\u003e;\n  }\n  return null;\n};\n```\n\n\u003c/p\u003e\u003c/details\u003e\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### Create a document\n\nTo create a new document, pass the name of the DocType and the fields to `createDoc`.\n\n```js\ndb.createDoc('My Custom DocType', {\n  name: 'Test',\n  test_field: 'This is a test field',\n})\n  .then((doc) =\u003e console.log(doc))\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### Update a document\n\nTo update an existing document, pass the name of the DocType, name of the document and the fields to be updated to `updateDoc`.\n\n```js\ndb.updateDoc('My Custom DocType', 'Test', {\n  test_field: 'This is an updated test field.',\n})\n  .then((doc) =\u003e console.log(doc))\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### Delete a document\n\nTo create a new document, pass the name of the DocType and the name of the document to be deleted to `deleteDoc`.\n\n```js\ndb.deleteDoc('My Custom DocType', 'Test')\n  .then((response) =\u003e console.log(response.message)) // Message will be \"ok\"\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\n## API Calls\n\n\u003cbr/\u003e\n\n### GET request\n\nMake a GET request to your endpoint with parameters.\n\n```js\nconst searchParams = {\n  doctype: 'Currency',\n  txt: 'IN',\n};\ncall\n  .get('frappe.desk.search_link', searchParams)\n  .then((result) =\u003e console.log(result))\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### POST request\n\nMake a POST request to your endpoint with parameters.\n\n```js\nconst updatedFields = {\n  doctype: 'User',\n  name: 'Administrator',\n  fieldname: 'interest',\n  value: 'Frappe Framework, ERPNext',\n};\ncall\n  .post('frappe.client.set_value', updatedFields)\n  .then((result) =\u003e console.log(result))\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### PUT request\n\nMake a PUT request to your endpoint with parameters.\n\n```js\nconst updatedFields = {\n  doctype: 'User',\n  name: 'Administrator',\n  fieldname: 'interest',\n  value: 'Frappe Framework, ERPNext',\n};\ncall\n  .put('frappe.client.set_value', updatedFields)\n  .then((result) =\u003e console.log(result))\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\u003chr/\u003e\n\u003cbr/\u003e\n\n### DELETE request\n\nMake a DELETE request to your endpoint with parameters.\n\n```js\nconst documentToBeDeleted = {\n  doctype: 'Tag',\n  name: 'Random Tag',\n};\ncall\n  .put('frappe.client.delete', documentToBeDeleted)\n  .then((result) =\u003e console.log(result))\n  .catch((error) =\u003e console.error(error));\n```\n\n\u003cbr/\u003e\n\n## File Uploads\n\n```js\nconst myFile; //Your File object\n\nconst fileArgs = {\n  /** If the file access is private then set to TRUE (optional) */\n  \"isPrivate\": true,\n  /** Folder the file exists in (optional) */\n  \"folder\": \"Home\",\n  /** File URL (optional) */\n  \"file_url\": \"\",\n  /** Doctype associated with the file (optional) */\n  \"doctype\": \"User\",\n  /** Docname associated with the file (mandatory if doctype is present) */\n  \"docname\": \"Administrator\",\n  /** Field to be linked in the Document **/\n  \"fieldname\" : \"image\"\n}\n\nfile.uploadFile(\n            myFile,\n            fileArgs,\n            /** Progress Indicator callback function **/\n            (completedBytes, totalBytes) =\u003e console.log(Math.round((c / t) * 100), \" completed\")\n        )\n        .then(() =\u003e console.log(\"File Upload complete\"))\n        .catch(e =\u003e console.error(e))\n```\n\n\u003cbr/\u003e\n\n## License\n\nSee [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThe-Commit-Company%2Ffrappe-react-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FThe-Commit-Company%2Ffrappe-react-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThe-Commit-Company%2Ffrappe-react-sdk/lists"}