{"id":18897316,"url":"https://github.com/iagocalazans/twilio-functions-utils","last_synced_at":"2025-08-26T00:05:33.189Z","repository":{"id":37544207,"uuid":"501890462","full_name":"iagocalazans/twilio-functions-utils","owner":"iagocalazans","description":"This lib was created with the aim of simplifying the use of serverless Twilio.","archived":false,"fork":false,"pushed_at":"2025-07-06T04:02:04.000Z","size":1335,"stargazers_count":11,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-08-11T00:39:16.083Z","etag":null,"topics":["functions","nodejs","serverless","twilio","utils"],"latest_commit_sha":null,"homepage":"https://iagocalazans.github.io/twilio-functions-utils","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/iagocalazans.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2022-06-10T03:45:13.000Z","updated_at":"2025-07-06T04:02:07.000Z","dependencies_parsed_at":"2023-02-08T14:00:29.880Z","dependency_job_id":"663abcaf-1459-4e36-b98d-191c64b8b4b8","html_url":"https://github.com/iagocalazans/twilio-functions-utils","commit_stats":{"total_commits":134,"total_committers":2,"mean_commits":67.0,"dds":"0.014925373134328401","last_synced_commit":"8a9972fb788e435d5ae55c1e82e3e882f92e7a9d"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/iagocalazans/twilio-functions-utils","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iagocalazans%2Ftwilio-functions-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iagocalazans%2Ftwilio-functions-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iagocalazans%2Ftwilio-functions-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iagocalazans%2Ftwilio-functions-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iagocalazans","download_url":"https://codeload.github.com/iagocalazans/twilio-functions-utils/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iagocalazans%2Ftwilio-functions-utils/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272149876,"owners_count":24882043,"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-25T02:00:12.092Z","response_time":1107,"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":["functions","nodejs","serverless","twilio","utils"],"created_at":"2024-11-08T08:36:56.482Z","updated_at":"2025-08-26T00:05:33.165Z","avatar_url":"https://github.com/iagocalazans.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Twilio Functions Utils ⚡\n\n\u003cimg src=\"https://avatars.githubusercontent.com/u/109142?s=200\u0026v=4\" width=\"80\" /\u003e\n\n![npm](https://img.shields.io/npm/v/twilio-functions-utils?color=white\u0026label=version\u0026logo=npm\u0026style=for-the-badge) ![npm](https://img.shields.io/npm/dw/twilio-functions-utils?color=white\u0026logo=npm\u0026style=for-the-badge) ![npms.io (final)](https://img.shields.io/npms-io/final-score/twilio-functions-utils?color=white\u0026label=score\u0026logo=npm\u0026logoColor=white\u0026style=for-the-badge) ![Coveralls](https://img.shields.io/coveralls/github/iagocalazans/twilio-functions-utils?color=white\u0026logo=coveralls\u0026style=for-the-badge)\n\n## 🚀 **Next-Generation Twilio Functions Development**\n\nA powerful, **RxJS-powered** utility library that revolutionizes Twilio serverless function development with reactive streams, functional composition, and zero-boilerplate dependency injection.\n\n**✨ What's New in v2.4+:**\n- 🔄 **Reactive Streams**: Built on RxJS for composable, testable functions\n- 🎯 **Zero Breaking Changes**: 100% backward compatible with existing code\n- 🧪 **Enhanced Testing**: Marble testing and advanced mocking capabilities\n- 🛠 **Two API Levels**: Simple injection API + powerful Effects API\n- ⚡ **Better Performance**: Optimized stream processing\n- 🔒 **Type Safe**: Full TypeScript support with proper inference\n\n```bash\nnpm install twilio-functions-utils\n```\n\n## 📋 **Requirements \u0026 Compatibility**\n\n- **Node.js**: \u003e= 14.0.0\n- **Twilio Runtime**: Compatible with Twilio Functions runtime\n- **TypeScript**: \u003e= 5.0.0 (for TypeScript projects)\n- **Dependencies**: RxJS 7.8.2+, Twilio SDK 3.77.2+\n\n### **Peer Dependencies**\n- `twilio` - Twilio JavaScript SDK\n- `@twilio/runtime-handler` - For local development\n\n---\n\n## 🛠 **Development Setup**\n\n### **Building the Project**\n```bash\nnpm run build        # Compile TypeScript to JavaScript\nnpm run prebuild     # Clean build directory before building\n```\n\n### **Testing**\n```bash\nnpm run test         # Run Jest test suite with coverage\nNODE_ENV=test npm test  # Ensure test environment\n```\n\n### **Documentation**\n```bash\nnpm run docs         # Generate JSDoc documentation\n```\n\n### **Project Structure**\nThe library supports flexible directory structures:\n- `./functions/` or `./src/functions/` for your Twilio Functions\n- `./assets/` or `./src/assets/` for static assets\n- Automatically detected during testing\n\n---\n\n## 🎯 **Quick Start**\n\n### **Option 1: Simple API (Familiar \u0026 Easy)**\n\n```javascript\nconst { useInjection, Response, BadRequestError, Result } = require('twilio-functions-utils');\n\n// Provider: Your business logic\nconst sendSmsProvider = async function (to, message) {\n  const { client } = this;\n  \n  try {\n    const result = await client.messages.create({\n      to,\n      from: '+1234567890',\n      body: message\n    });\n    return Result.ok({ sid: result.sid, status: 'sent' });\n  } catch (error) {\n    return Result.failed(error.message);\n  }\n};\n\n// Handler: Your Twilio Function\nasync function sendSmsHandler(event) {\n  const { env, providers } = this;\n  const { to, message } = event;\n  \n  if (!to || !message) {\n    return new BadRequestError('Missing \"to\" or \"message\" parameters');\n  }\n  \n  const result = await providers.sendSms(to, message);\n  \n  if (result.isError) {\n    return new BadRequestError(result.error);\n  }\n  \n  return new Response(result.data, 201);\n}\n\n// Export for Twilio\nexports.handler = useInjection(sendSmsHandler, {\n  providers: { sendSms: sendSmsProvider }\n});\n```\n\n### **Option 2: RxJS Effects API (Advanced \u0026 Powerful)**\n\n```javascript\nconst { \n  twilioEffect, \n  injectEvent, \n  injectClient, \n  requireFields, \n  ok, \n  handleError \n} = require('twilio-functions-utils');\n\nconst { switchMap, map } = require('rxjs/operators');\n\nconst sendSmsEffect = context$ =\u003e \n  context$.pipe(\n    requireFields('to', 'message'),\n    injectEvent(),\n    injectClient(),\n    switchMap(([event, client]) =\u003e\n      client.messages.create({\n        to: event.to,\n        from: '+1234567890',\n        body: event.message\n      })\n    ),\n    map(result =\u003e ({ sid: result.sid, status: 'sent' })),\n    ok(),\n    handleError()\n  );\n\nexports.handler = twilioEffect(sendSmsEffect);\n```\n\n### **TypeScript Examples**\n\n```typescript\nimport { \n  useInjection, \n  Response, \n  BadRequestError, \n  Result,\n  InjectorFunction,\n  ProviderFunction \n} from 'twilio-functions-utils';\n\n// Type your environment variables\ninterface MyEnv {\n  ACCOUNT_SID: string;\n  AUTH_TOKEN: string;\n  FROM_NUMBER: string;\n}\n\n// Type your event data\ninterface SmsEvent {\n  to: string;\n  message: string;\n}\n\n// Type your providers\ninterface MyProviders {\n  sendSms: (to: string, message: string) =\u003e Promise\u003cResult\u003c{ sid: string }, string\u003e\u003e;\n}\n\n// Provider with full typing\nconst sendSmsProvider: ProviderFunction\u003cSmsEvent, MyEnv\u003e = async function (\n  to: string, \n  message: string\n) {\n  const { client, env } = this;\n  \n  try {\n    const result = await client.messages.create({\n      to,\n      from: env.FROM_NUMBER,\n      body: message\n    });\n    return Result.ok({ sid: result.sid });\n  } catch (error: any) {\n    return Result.failed(error.message);\n  }\n};\n\n// Handler with full typing\nconst sendSmsHandler: InjectorFunction\u003cSmsEvent, MyEnv, MyProviders\u003e = async function (event) {\n  const { env, providers } = this;\n  const { to, message } = event;\n  \n  if (!to || !message) {\n    return new BadRequestError('Missing required parameters');\n  }\n  \n  const result = await providers.sendSms(to, message);\n  \n  if (result.isError) {\n    return new BadRequestError(result.error);\n  }\n  \n  return new Response(result.data, 201);\n};\n\n// Export with types\nexport const handler = useInjection\u003cSmsEvent, MyEnv, MyProviders\u003e(sendSmsHandler, {\n  providers: { sendSms: sendSmsProvider }\n});\n```\n\n### **RxJS Effects with TypeScript**\n\n```typescript\nimport { \n  twilioEffect, \n  EffectWithContext,\n  EffectContext,\n  injectEvent, \n  injectClient,\n  requireFields,\n  ok \n} from 'twilio-functions-utils';\nimport { switchMap, map } from 'rxjs/operators';\n\ninterface SmsEnv {\n  FROM_NUMBER: string;\n}\n\ninterface SmsEvent {\n  to: string;\n  message: string;\n}\n\nconst sendSmsEffect: EffectWithContext\u003cSmsEnv, {}, Response\u003e = (context$) =\u003e\n  context$.pipe(\n    requireFields\u003cSmsEvent\u003e('to', 'message'),\n    injectEvent\u003cSmsEvent\u003e(),\n    injectClient(),\n    switchMap(([event, client]) =\u003e\n      client.messages.create({\n        to: event.to,\n        from: process.env.FROM_NUMBER,\n        body: event.message\n      })\n    ),\n    map(result =\u003e ({ sid: result.sid, status: 'sent' })),\n    ok()\n  );\n\nexport const handler = twilioEffect\u003cSmsEnv, {}\u003e(sendSmsEffect);\n```\n\n---\n\n## 🔥 **Core Features**\n\n### **🎭 Dependency Injection Made Simple**\n\nAccess everything you need through clean `this` context:\n\n```javascript\nasync function myHandler(event) {\n  const { \n    env,        // Environment variables\n    providers,  // Your business logic\n    request,    // HTTP headers \u0026 data\n    cookies     // Request cookies\n  } = this;\n  \n  // Your logic here...\n}\n```\n\n### **📦 Result Pattern (No More Try-Catch Hell)**\n\n```javascript\n// In your providers\nconst fetchUser = async function (userId) {\n  const { client, env } = this;\n  \n  try {\n    const user = await client.api.accounts(env.ACCOUNT_SID)\n      .calls\n      .list({ limit: 1 });\n    \n    return Result.ok(user[0]);\n  } catch (error) {\n    return Result.failed('User not found');\n  }\n};\n\n// In your handlers\nconst userResult = await this.providers.fetchUser(event.userId);\n\nif (userResult.isError) {\n  return new NotFoundError(userResult.error);\n}\n\nreturn new Response(userResult.data);\n```\n\n### **🎯 Smart Response Handling**\n\n```javascript\n// JSON Responses\nreturn new Response({ success: true, data: results }, 201);\n\n// TwiML Responses\nconst twiml = new Twilio.twiml.VoiceResponse();\ntwiml.say('Hello from RxJS-powered Twilio!');\nreturn new TwiMLResponse(twiml.toString());\n\n// Error Responses\nreturn new BadRequestError('Invalid input');\nreturn new NotFoundError('Resource not found');\nreturn new UnauthorizedError('Access denied');\nreturn new InternalServerError('Something went wrong');\n```\n\n---\n\n## 🔄 **RxJS Effects API**\n\nFor advanced use cases, leverage the full power of reactive programming:\n\n### **Composition with Operators**\n\n```javascript\nconst complexWorkflow = context$ =\u003e\n  context$.pipe(\n    // Validation\n    requireFields('customerId', 'action'),\n    authenticated(ctx =\u003e ctx.event.token),\n    \n    // Data fetching\n    switchMap(ctx =\u003e \n      ctx.providers.customerService.getProfile(ctx.event.customerId)\n    ),\n    \n    // Business logic\n    map(customer =\u003e ({\n      id: customer.id,\n      name: customer.name,\n      tier: customer.subscriptions.length \u003e 0 ? 'premium' : 'basic'\n    })),\n    \n    // Response formatting\n    apiResponse({ message: 'Profile retrieved successfully' }),\n    \n    // Error handling\n    handleError(error =\u003e {\n      if (error.code === 'CUSTOMER_NOT_FOUND') {\n        return new NotFoundError('Customer not found');\n      }\n      return null; // Use default error handling\n    })\n  );\n```\n\n### **Built-in Operators**\n\n```javascript\n// Validation\nrequireFields('email', 'phone')\nvalidateEvent(event =\u003e event.email.includes('@'))\nauthenticated(ctx =\u003e checkApiKey(ctx.event.apiKey))\n\n// Data injection\ninjectEvent()           // Get event data\ninjectEnv()            // Get environment vars\ninjectClient()         // Get Twilio client\ninjectProviders()      // Get all providers\ninjectProvider('userService')  // Get specific provider\n\n// Response formatting\nok()                   // 200 response\ncreated()              // 201 response  \napiResponse({ meta: { version: '1.0' } })\ntoTwiMLResponse()      // Convert TwiML to response\n\n// Error handling\nhandleError()          // Comprehensive error handling\nretryWithBackoff(3)    // Retry failed operations\ntimeoutWithError(5000) // Timeout after 5 seconds\nfallback(defaultValue) // Provide fallback value\n```\n\n---\n\n## 🧪 **Testing Made Easy**\n\n### **Simple Testing (Original API)**\n\n```javascript\nrequire('twilio-functions-utils/dist/lib/twilio.mock.js');\n\nconst { useMock, Response } = require('twilio-functions-utils');\nconst { myHandler } = require('../functions/myHandler');\n\nconst mockFn = useMock(myHandler, {\n  providers: {\n    sendSms: async (to, message) =\u003e ({ sid: 'SM123', status: 'sent' })\n  },\n  env: { ACCOUNT_SID: 'AC123' },\n  client: { /* mock Twilio client */ }\n});\n\ntest('should send SMS successfully', async () =\u003e {\n  const result = await mockFn({ to: '+1234567890', message: 'Hello!' });\n  \n  expect(result).toBeInstanceOf(Response);\n  expect(result.statusCode).toBe(201);\n});\n```\n\n### **Advanced Testing (RxJS Effects)**\n\n```javascript\nconst { testEffect, marbleTest, expectEmissions } = require('twilio-functions-utils');\n\ntest('should handle SMS sending with marble testing', () =\u003e {\n  marbleTest(({ cold, expectObservable }) =\u003e {\n    const context$ = cold('a|', {\n      a: { event: { to: '+1234567890', message: 'Test' } }\n    });\n\n    const result$ = sendSmsEffect(context$);\n\n    expectObservable(result$).toBe('a|', {\n      a: expect.objectContaining({ statusCode: 200 })\n    });\n  });\n});\n```\n\n---\n\n## 🔒 **Flex Integration**\n\nBuilt-in support for Twilio Flex token validation:\n\n```javascript\n// Simple API\nexports.handler = useInjection(myHandler, {\n  providers: { taskService },\n  validateToken: true  // Automatically validates Flex tokens\n});\n\n// RxJS API  \nconst flexEffect = context$ =\u003e\n  context$.pipe(\n    validateFlexToken(),  // Validates token from event.Token\n    // ... rest of your logic\n  );\n\n// Custom token validation\nconst customFlexEffect = context$ =\u003e\n  context$.pipe(\n    validateFlexTokenWithOptions({\n      tokenField: 'customToken',\n      onValidation: (result) =\u003e console.log('Token validated:', result)\n    }),\n    // ... rest of your logic\n  );\n```\n\n---\n\n## 📚 **Migration Guide**\n\n### **From v2.4.x to v2.5.0: Zero Breaking Changes! 🎉**\n\nYour existing code works without any modifications:\n\n```javascript\n// This code works exactly the same in v2.5.0\nconst { useInjection, Response, Result } = require('twilio-functions-utils');\n\nasync function existingHandler(event) {\n  const result = await this.providers.existingProvider(event);\n  return new Response(result.data);\n}\n\nexports.handler = useInjection(existingHandler, {\n  providers: { existingProvider }\n});\n```\n\n### **What's New in v2.5.0:**\n- ✅ **RxJS-Powered Architecture** - Enhanced reactive stream processing under the hood\n- ✅ **Advanced Effects API** - Optional RxJS Effects for complex workflows\n- ✅ **Enhanced Testing** - Marble testing and improved mocking capabilities\n- ✅ **Better Performance** - Optimized stream processing and error handling\n- ✅ **Full TypeScript Support** - Complete type safety with proper inference\n\n---\n\n## 🛠 **API Reference**\n\n### **Core Functions**\n\n| Function | Description |\n|----------|-------------|\n| `useInjection(fn, options)` | Main dependency injection wrapper |\n| `twilioEffect(effect, options)` | RxJS Effects wrapper |\n| `useMock(fn, options)` | Testing utility (test environment only) |\n\n### **Response Classes**\n\n| Class | Status Code | Usage |\n|-------|-------------|-------|\n| `Response(body, statusCode)` | Custom | General responses |\n| `TwiMLResponse(twiml)` | 200 | TwiML responses |\n| `BadRequestError(message)` | 400 | Invalid input |\n| `UnauthorizedError(message)` | 401 | Authentication required |\n| `NotFoundError(message)` | 404 | Resource not found |\n| `InternalServerError(message)` | 500 | Server errors |\n\n### **Utility Classes**\n\n| Class | Description |\n|-------|-------------|\n| `Result.ok(data)` | Success result wrapper |\n| `Result.failed(error)` | Error result wrapper |\n| `typeOf(value)` | Enhanced type checking |\n\n---\n\n## 🔧 **Troubleshooting**\n\n### **Common Issues**\n\n#### **\"Module not found\" Error**\n```bash\n# Ensure you've installed the package\nnpm install twilio-functions-utils\n\n# For TypeScript projects, ensure proper types\nnpm install --save-dev typescript @types/node\n```\n\n#### **Testing Issues**\n```javascript\n// ❌ Wrong - Missing mock import\nconst { useMock } = require('twilio-functions-utils');\n\n// ✅ Correct - Import mock first\nrequire('twilio-functions-utils/dist/lib/twilio.mock.js');\nconst { useMock } = require('twilio-functions-utils');\n\n// Ensure NODE_ENV=test\nprocess.env.NODE_ENV = 'test';\n```\n\n#### **RxJS Operator Issues**\n```bash\n# Ensure RxJS is installed\nnpm install rxjs@^7.8.2\n\n# Import operators correctly\nconst { switchMap, map } = require('rxjs/operators');\n```\n\n#### **TypeScript Compilation Errors**\n```json\n// tsconfig.json - Ensure proper configuration\n{\n  \"compilerOptions\": {\n    \"target\": \"ES2018\",\n    \"module\": \"commonjs\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n```\n\n#### **Runtime Context Issues**\n```javascript\n// ❌ Wrong - Arrow functions lose 'this' context\nconst handler = (event) =\u003e {\n  // 'this' is undefined here\n};\n\n// ✅ Correct - Use regular functions\nasync function handler(event) {\n  // 'this' context available here\n  const { env, providers } = this;\n}\n```\n\n### **Performance Tips**\n\n- Use `injectMany()` instead of multiple `inject()` calls\n- Leverage RxJS operators for complex data transformations\n- Use `Result` pattern to avoid try-catch overhead\n- Enable TypeScript strict mode for better optimization\n\n### **Getting Help**\n\n- 📖 Check [documentation](https://iagocalazans.github.io/twilio-functions-utils)\n- 🐛 Report bugs on [GitHub Issues](https://github.com/iagocalazans/twilio-functions-utils/issues)\n- 💬 Ask questions in [Twilio Community](https://www.twilio.com/community)\n\n---\n\n## 🤝 **Contributing**\n\nWe welcome contributions! Here's how you can help:\n\n1. **🐛 Report bugs** - Open an issue with reproduction steps\n2. **💡 Suggest features** - Describe your use case and proposed solution  \n3. **📝 Improve docs** - Help make our documentation clearer\n4. **🧪 Write tests** - Add test cases for new features\n5. **🔧 Submit PRs** - Follow our coding standards and include tests\n\n---\n\n## 🌟 **Community \u0026 Support**\n\n### **📚 Resources**\n- 🏠 **[Project Homepage](https://iagocalazans.github.io/twilio-functions-utils)** - Documentation and guides\n- 📦 **[NPM Package](https://www.npmjs.com/package/twilio-functions-utils)** - Package details and versions\n- 🐙 **[GitHub Repository](https://github.com/iagocalazans/twilio-functions-utils)** - Source code and issues\n\n### **🆘 Getting Help**\n- 🐛 **[Report Issues](https://github.com/iagocalazans/twilio-functions-utils/issues)** - Bug reports and feature requests\n- 💬 **[Twilio Community](https://www.twilio.com/community)** - General Twilio development discussions\n- 📧 **[Contact Author](mailto:iago.calazans@gmail.com)** - Direct support for complex issues\n\n### **🤝 Contributing**\n- 🔀 **[Pull Requests](https://github.com/iagocalazans/twilio-functions-utils/pulls)** - Code contributions welcome\n- 📖 **[Contributing Guide](https://github.com/iagocalazans/twilio-functions-utils/blob/master/CONTRIBUTING.md)** - How to contribute\n- 🧪 **[Running Tests](https://github.com/iagocalazans/twilio-functions-utils#testing)** - Test your changes\n\n---\n\n## 📄 **License**\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n---\n\n## 👨‍💻 **Author**\n\n**[Iago Calazans](https://github.com/iagocalazans)** - Senior Node.js Engineer\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n**⭐ If this library helps you build amazing Twilio Functions, give it a star! ⭐**\n\nMade with ❤️ and ☕ for the Twilio community\n\n\u003c/div\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiagocalazans%2Ftwilio-functions-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiagocalazans%2Ftwilio-functions-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiagocalazans%2Ftwilio-functions-utils/lists"}