diff --git a/fern/assistants/call-recording.mdx b/fern/assistants/call-recording.mdx index 797943654..7e1038b50 100644 --- a/fern/assistants/call-recording.mdx +++ b/fern/assistants/call-recording.mdx @@ -1,567 +1 @@ ---- -title: Call recording, logging and transcribing -subtitle: Record, log, and transcribe calls using artifact plans -slug: assistants/call-recording -description: Learn how to configure artifact plans to record calls, generate transcripts, and store logs for analysis ---- - - - **Deprecated**: The old `recordingEnabled`, `recordingPath`, and `recordingCredentials` properties are deprecated. Use the new `artifactPlan` configuration instead for recording, logging, and transcript generation. - - -## Overview - -Vapi's artifact plan system provides comprehensive call recording, logging, and transcription capabilities that allow you to capture, store, and analyze voice conversations for quality assurance, training, and compliance purposes. - -**Artifact plans enable you to:** -- Record audio conversations for quality monitoring -- Generate detailed call logs for debugging and analysis -- Create transcripts for conversation analysis -- Store artifacts in custom storage or Vapi's secure cloud -- Monitor conversation quality and assistant performance -- Ensure compliance with regulatory requirements - -## Use Cases - -### Payment Processing Flows - -Protect sensitive payment information by using a middle assistant with all artifacts disabled: - -```json -{ - "squad": { - "members": [ - { - "assistant": { - "name": "Service Assistant", - "artifactPlan": { - "recordingEnabled": true, - "loggingEnabled": true, - "transcriptPlan": { "enabled": true } - } - } - }, - { - "assistant": { - "name": "Payment Assistant", - "artifactPlan": { - "recordingEnabled": false, - "loggingEnabled": false, - "transcriptPlan": { "enabled": false } - } - } - }, - { - "assistant": { - "name": "Confirmation Assistant", - "artifactPlan": { - "recordingEnabled": true, - "loggingEnabled": true, - "transcriptPlan": { "enabled": true } - } - } - } - ] - } -} -``` - -This flow ensures that: -- Service conversations are recorded for quality assurance -- Payment details (credit card numbers, CVV codes) are never recorded or logged -- Confirmation conversations are recorded for compliance - -### Consent Gathering - -For Enterprise customers, Vapi provides built-in [recording consent plans](/security-and-privacy/recording-consent-plan) that automatically create a consent assistant to request recording permission before transferring to your main assistant. - -The Enterprise consent feature supports both: -- **Verbal consent**: Requires explicit "yes" confirmation from users -- **Implicit consent**: Assumes consent if users stay on the line after hearing the consent message - -The system automatically tracks consent decisions and provides compliance data in the end-of-call report, including whether consent was granted and when it was obtained. - -Alternatively, you can implement custom consent flows using squads: - -```json -{ - "squad": { - "members": [ - { - "assistant": { - "name": "Consent Assistant", - "artifactPlan": { - "recordingEnabled": false, - "loggingEnabled": false, - "transcriptPlan": { "enabled": false } - } - } - }, - { - "assistant": { - "name": "Main Assistant", - "artifactPlan": { - "recordingEnabled": true, - "loggingEnabled": true, - "transcriptPlan": { "enabled": true } - } - } - } - ] - } -} -``` - -The consent assistant runs without generating artifacts, while the main assistant records the actual conversation after consent is obtained. - -## Artifact Plan Configuration - -### Configure via Dashboard - - - - Open the [Dashboard](https://dashboard.vapi.ai/assistants). Select **Assistants**, then select the assistant you want to configure. - - - - Select the **Advanced** tab, then locate **Recording & Artifacts**. - - - - Select **Audio Recording**, **Logging**, and **Transcript** to enable or disable each artifact. Choose an **Audio Recording Format** for call recordings. - - - - Select **Video Recording** to enable or disable recording for web calls. - - - - Select **publish** in the unsaved-changes message to apply the update. - - - - - - - -### Basic Configuration - -Configure recording, logging, and transcript generation using the `artifactPlan`: - - -```json title="Assistant Configuration" -{ - "name": "Customer Support Assistant", - "artifactPlan": { - "recordingEnabled": true, - "recordingFormat": "wav;l16", - "loggingEnabled": true, - "pcapEnabled": true, - "transcriptPlan": { - "enabled": true, - "assistantName": "Assistant", - "userName": "Customer" - } - }, - "model": { - "provider": "openai", - "model": "gpt-4" - }, - "voice": { - "provider": "11labs", - "voiceId": "harry" - } -} -``` - -```json title="Per-Call Configuration" -{ - "assistant": { - "name": "Support Agent", - "artifactPlan": { - "recordingEnabled": true, - "recordingFormat": "wav;l16", - "loggingEnabled": true, - "pcapEnabled": true, - "transcriptPlan": { - "enabled": true, - "assistantName": "Support Agent", - "userName": "Customer" - } - } - }, - "phoneNumberId": "your-phone-number-id" -} -``` - - -### Artifact Plan Options - -Configure different types of artifacts with these options: - -- **`recordingEnabled`**: Enable call recording (stored in `call.artifact.recording`) Default: `true` -- **`recordingFormat`**: Audio format for recordings (e.g., "wav;l16", "mp3") Default: "wav;l16" -- **`loggingEnabled`**: Enable detailed call logs (stored in `call.artifact.logUrl`) Default: `true` -- **`pcapEnabled`**: Enable SIP packet capture for phone calls (stored in `call.artifact.pcapUrl`) Default: `true` -- **`transcriptPlan`**: Configure transcript generation with speaker names - -## Storage Configuration - -### Default Storage - -By default, Vapi stores artifacts securely in the cloud: - -- Recordings, logs, and transcripts are encrypted at rest and in transit -- Access is controlled through your API credentials -- Artifacts are automatically cleaned up based on your retention policy - -### Custom Storage - -Configure custom storage for different artifact types: - - -```json title="S3 Storage Configuration" -{ - "artifactPlan": { - "recordingEnabled": true, - "recordingFormat": "wav;l16", - "loggingEnabled": true, - "pcapEnabled": true, - "recordingUseCustomStorageEnabled": true, - "loggingUseCustomStorageEnabled": true, - "pcapUseCustomStorageEnabled": true, - "recordingPath": "https://your-bucket.s3.amazonaws.com/recordings/", - "loggingPath": "https://your-bucket.s3.amazonaws.com/logs/", - "pcapS3PathPrefix": "/pcaps", - "transcriptPlan": { - "enabled": true, - "assistantName": "Assistant", - "userName": "Customer" - } - }, - "credentials": [ - { - "provider": "aws", - "region": "us-east-1", - "accessKeyId": "your-access-key", - "secretAccessKey": "your-secret-key" - } - ] -} -``` - -```json title="Google Cloud Storage" -{ - "artifactPlan": { - "recordingEnabled": true, - "recordingFormat": "wav;l16", - "loggingEnabled": true, - "pcapEnabled": true, - "recordingUseCustomStorageEnabled": true, - "loggingUseCustomStorageEnabled": true, - "pcapUseCustomStorageEnabled": true, - "recordingPath": "gs://your-bucket/recordings/", - "loggingPath": "gs://your-bucket/logs/", - "transcriptPlan": { - "enabled": true, - "assistantName": "Assistant", - "userName": "Customer" - } - }, - "credentials": [ - { - "provider": "gcp", - "serviceAccountKey": "your-service-account-json" - } - ] -} -``` - - -### Storage Control Options - -Control where each artifact type is stored: - -- **`recordingUseCustomStorageEnabled`**: Use custom storage for recordings (default: true) -- **`loggingUseCustomStorageEnabled`**: Use custom storage for logs (default: true) -- **`pcapUseCustomStorageEnabled`**: Use custom storage for SIP packet capture (default: true) -- **`recordingPath`**: Custom path for recording storage -- **`loggingPath`**: Custom path for log storage -- **`pcapS3PathPrefix`**: S3 path prefix for PCAP files - -## Squad and Transfer Behavior - -### Dynamic Artifact Control - -When handing off between assistants in a Squad, you may choose to change the local context for each assistant via the `contextEngineeringPlan`. By default, only the final context will be used in the artifact and analysis (Structured outputs and success evaluation). To include the full message history across all assistants in the call, set [`artifactPlan.fullMessageHistoryEnabled`](/api-reference/squads/create#request.body.membersOverrides.artifactPlan.fullMessageHistoryEnabled) to true. - -In squads with multiple assistants, artifact generation (recording, logging, transcripts) can be controlled per assistant. When assistants are swapped or transferred during a call: - -- **Recording**: Pauses when `recordingEnabled: false` assistant is active, resumes when `recordingEnabled: true` assistant takes over -- **Logging**: Pauses when `loggingEnabled: false` assistant is active, resumes when `loggingEnabled: true` assistant takes over -- **Transcripts**: Pauses when `transcriptPlan.enabled: false` assistant is active, resumes when `transcriptPlan.enabled: true` assistant takes over - -## Transcript Configuration - -### Automatic Transcription - -Configure transcript generation using the `transcriptPlan`: - -```json -{ - "artifactPlan": { - "transcriptPlan": { - "enabled": true, - "assistantName": "Assistant", - "userName": "Customer" - } - } -} -``` - -### Transcript Plan Options - -- **`enabled`**: Enable or disable transcript generation -- **`assistantName`**: Name to use for assistant messages in transcripts -- **`userName`**: Name to use for user messages in transcripts - -### Transcript Features - -- **Real-time transcription**: Transcripts are generated during the call -- **Speaker identification**: Distinguishes between assistant and user messages -- **Timestamps**: Each message includes timing information -- **OpenAI formatting**: Available in `call.artifact.messagesOpenAIFormatted` - -### Transcript Structure - -```json -{ - "callId": "call-123", - "artifact": { - "transcript": [ - { - "role": "assistant", - "message": "Hello! How can I help you today?", - "time": 0.5 - }, - { - "role": "user", - "message": "I need help with my account", - "time": 3.2 - } - ], - "messagesOpenAIFormatted": [ - { - "role": "assistant", - "content": "Hello! How can I help you today?" - }, - { - "role": "user", - "content": "I need help with my account" - } - ] - } -} -``` - -## Logging Configuration - -### Detailed Call Logs - -Enable comprehensive logging for debugging and analysis: - -```json -{ - "artifactPlan": { - "loggingEnabled": true, - "loggingUseCustomStorageEnabled": true, - "loggingPath": "https://your-bucket.s3.amazonaws.com/logs/" - } -} -``` - -### Log Features - -- **Debug information**: Detailed logs for troubleshooting -- **Performance metrics**: Call timing and performance data -- **Error tracking**: Comprehensive error logs and stack traces - -### Accessing Logs - -Logs are available through: -- **Dashboard**: View logs in the call details page -- **API**: Access via `call.artifact.logUrl` -- **Custom storage**: Store logs in your S3/GCP bucket - -## Accessing Artifacts - -### Via Dashboard - -1. Open the [Dashboard](https://dashboard.vapi.ai/). -2. Select **Logs**, then select **Calls**. -3. Select a call from the list. -4. Review the available call artifacts: - - Use the recording controls to play or download the audio recording when recording is enabled. - - Select **Transcripts** to view the conversation transcript. - - Select **Logs** to review detailed call logs for debugging. - - Download the PCAP file to inspect the packet capture when the call uses SIP and PCAP is enabled. - -### Via API - -Retrieve artifact URLs programmatically: - -```typescript -import { VapiClient } from "@vapi-ai/server-sdk"; - -const client = new VapiClient({ token: "your-api-key" }); - -// Get call details including all artifacts -const call = await client.calls.get("call-id"); - -console.log("Recording URL:", call.artifact.recording); -console.log("Transcript:", call.artifact.transcript); -console.log("Log URL:", call.artifact.logUrl); -console.log("PCAP URL:", call.artifact.pcapUrl); -console.log("Messages:", call.artifact.messages); -console.log("Nodes:", call.artifact.nodes); -``` - - - The `recording` and `logUrl` values are private, authenticated URLs — they can't be downloaded directly. See [Retrieve call artifacts](/assistants/retrieve-call-artifacts) for how to fetch the actual files. - - -## Privacy and Compliance - -### Legal Considerations - -**Important**: Call recording laws vary by jurisdiction. Ensure compliance with: - -- **Consent requirements** - Inform participants about recording -- **Data protection** regulations (GDPR, CCPA, etc.) -- **Industry standards** (PCI DSS, HIPAA, etc.) - -### Built-in Consent Management - -For Enterprise customers, Vapi provides automated consent management through [recording consent plans](/security-and-privacy/recording-consent-plan). This feature automatically: - -- Creates a consent assistant that requests recording permission -- Handles both verbal and stay-on-line consent types -- Only begins recording after consent is granted -- Maintains audit trails of consent decisions - -### Best Practices - -- **Inform callers** about recording at the start of conversations -- **Secure storage** with encryption and access controls -- **Retention policies** to automatically delete old recordings -- **Access logs** to track who accesses recordings - - - Always comply with local laws regarding call recording. Some jurisdictions require explicit consent from all parties before recording. - - -## Recording Analysis - -### Call Artifacts - -Use the comprehensive artifact data for analysis: - -```json -{ - "callId": "call-123", - "artifact": { - "transcript": [ - { - "role": "assistant", - "message": "Hello! How can I help you today?", - "time": 0.5 - }, - { - "role": "user", - "message": "I need help with my account", - "time": 3.2 - } - ], - "messages": [ - { - "role": "assistant", - "message": "Hello! How can I help you today?" - }, - { - "role": "user", - "message": "I need help with my account" - } - ], - "nodes": [ - { - "name": "greeting", - "messages": ["Hello! How can I help you today?"], - "variables": {} - } - ], - "variableValues": { - "customerName": "John Doe", - "issueType": "account_access" - } - } -} -``` - -### Analysis Use Cases - -Use artifact data for comprehensive insights: - -- **Conversation flow** analysis using `artifact.nodes` -- **Response quality** evaluation using `artifact.messages` -- **Customer satisfaction** metrics from transcript analysis -- **Assistant performance** tracking using logs and recordings -- **Variable tracking** using `artifact.variableValues` - -## FAQ - - - - Use the `artifactPlan` configuration in your assistant or call settings. Set `recordingEnabled`, `loggingEnabled`, and configure `transcriptPlan.enabled` to `true` to enable all three features. - - - - By default, artifacts are stored securely in Vapi's cloud storage. You can configure custom storage using S3 or Google Cloud Storage with the `recordingPath`, `loggingPath`, and storage control options. - - - - Artifacts are available through the API via `call.artifact.recording`, `call.artifact.transcript`, `call.artifact.logUrl`, and other properties. You can also view them in the Vapi dashboard. - - - - The `transcript` includes timing information and is optimized for conversation analysis. The `messages` property contains the same content but in a simpler format, while `messagesOpenAIFormatted` is structured for OpenAI API compatibility. - - - - Use the `transcriptPlan` configuration with `assistantName` and `userName` properties to customize how speakers are identified in the transcript output. - - - - Yes, you can configure artifact plans at both the assistant level and per individual call. This gives you granular control over what artifacts are generated for each conversation. - - - - PCAP (Packet Capture) is available for phone calls and contains SIP packet data for debugging telephony issues. It's stored in `call.artifact.pcapUrl` when `pcapEnabled` is set to `true`. - - - - Retention periods vary by plan: - - **Pay-As-You-Go:** Up to 30 days for chats and 14 days for calls - - **Enterprise:** Configurable retention policies - - - - In squads, each assistant can have different artifact settings. Recording, logging, and transcripts pause when an assistant with disabled artifacts is active, and resume when an assistant with enabled artifacts takes over. This allows for privacy-conscious flows like consent collection. - - - -## Next Steps - -- **[Call Analysis](/assistants/call-analysis)** - Analyze recorded conversations for insights -- **[Recording Consent Plans](/security-and-privacy/recording-consent-plan)** - Automated consent management for Enterprise customers -- **[Privacy Compliance](/security-and-privacy/GDPR)** - Ensure GDPR and privacy compliance -- **[API Reference](/api-reference/calls/create)** - Explore recording configuration options +LS0tCnRpdGxlOiBDYWxsIFJlY29yZGluZywgTG9nZ2luZyAmIFRyYW5zY3JpYmluZwpzdWJ0aXRsZTogQ29uZmlndXJlIGhvdyBWYXBpIGNhcHR1cmVzIGFuZCBzdG9yZXMgY2FsbCBhcnRpZmFjdHMKLS0tCgojIyBPdmVydmlldwoKVmFwaSB1c2VzIGFuICoqYGFydGlmYWN0UGxhbmAqKiBjb25maWd1cmF0aW9uICh0aGUgb2xkZXIgYHJlY29yZGluZ0VuYWJsZWRgL2ByZWNvcmRpbmdQYXRoYCBwcm9wZXJ0aWVzIGFyZSBkZXByZWNhdGVkKSB0byBjb250cm9sIGNhbGwgcmVjb3JkaW5nLCBsb2dnaW5nLCBhbmQgdHJhbnNjcmlwdGlvbi4gS2V5IGNhcGFiaWxpdGllczoKCi0g8J+Yme+4jyBSZWNvcmQgYXVkaW8gY2FsbHMKLSDwn5OLIEdlbmVyYXRlIGRldGFpbGVkIGNhbGwgbG9ncwotIPCfk50gQ3JlYXRlIHRpbWVzdGFtcGVkIHRyYW5zY3JpcHRzIHdpdGggc3BlYWtlciBsYWJlbHMKLSDimIHvuI8gU3RvcmUgYXJ0aWZhY3RzIGluIFZhcGkncyBjbG91ZCBvciBjdXN0b20gc3RvcmFnZSAoUzMgLyBHQ1ApCgotLS0KCiMjIEFydGlmYWN0IFBsYW4gT3B0aW9ucwoKfCBPcHRpb24gfCBEZXNjcmlwdGlvbiB8IERlZmF1bHQgfAp8LS0tfC0tLXwtLS18CnwgYHJlY29yZGluZ0VuYWJsZWRgIHwgRW5hYmxlIGNhbGwgcmVjb3JkaW5nIHwgYHRydWVgIHwKfCBgcmVjb3JkaW5nRm9ybWF0YCB8IEF1ZGlvIGZvcm1hdCAoYCJ3YXY7bDE2ImAsIGAibXAzImAsIGV0Yy4pIHwgYCJ3YXY7bDE2ImAgfAp8IGBsb2dnaW5nRW5hYmxlZGAgfCBFbmFibGUgZGV0YWlsZWQgY2FsbCBsb2dzIHwgYHRydWVgIHwKfCBgcGNhcEVuYWJsZWRgIHwgRW5hYmxlIFNJUCBwYWNrZXQgY2FwdHVyZSAocGhvbmUgY2FsbHMgb25seSkgfCBgdHJ1ZWAgfAp8IGB0cmFuc2NyaXB0UGxhbi5lbmFibGVkYCB8IEVuYWJsZSB0cmFuc2NyaXB0IGdlbmVyYXRpb24gfCDigJQgfAp8IGB0cmFuc2NyaXB0UGxhbi5hc3Npc3RhbnROYW1lYCB8IFNwZWFrZXIgbGFiZWwgZm9yIGFzc2lzdGFudCB8IOKAlCB8CnwgYHRyYW5zY3JpcHRQbGFuLnVzZXJOYW1lYCB8IFNwZWFrZXIgbGFiZWwgZm9yIHVzZXIgfCDigJQgfAoKLS0tCgojIyBJbmxpbmUgdnMuIFNhdmVkIEFzc2lzdGFudHMKCkhvdyB5b3Ugc3RhcnQgYSBjYWxsIGRldGVybWluZXMgd2hlcmUgVmFwaSBsb29rcyBmb3IgeW91ciBgYXJ0aWZhY3RQbGFuYC4KCjxXYXJuaW5nPgpEYXNoYm9hcmQgYGFydGlmYWN0UGxhbmAgc2V0dGluZ3Mgb25seSBhcHBseSB3aGVuIHlvdSBzdGFydCBhIGNhbGwgd2l0aCBhbiBgYXNzaXN0YW50SWRgLiBJZiB5b3UgZW1iZWQgdGhlIGFzc2lzdGFudCBvYmplY3QgZGlyZWN0bHkgaW4gdGhlIGBQT1NUIC9jYWxsYCByZXF1ZXN0IGJvZHkgKGFuIGlubGluZSBvciB0cmFuc2llbnQgYXNzaXN0YW50KSwgVmFwaSBpZ25vcmVzIGRhc2hib2FyZCBkZWZhdWx0cyDigJQgeW91IG11c3QgaW5jbHVkZSBgYXJ0aWZhY3RQbGFuYCBleHBsaWNpdGx5IGluIHRoZSBwYXlsb2FkIG9yIG5vIHJlY29yZGluZyBvciBsb2dzIHdpbGwgYmUgZ2VuZXJhdGVkLgo8L1dhcm5pbmc+CgojIyMgU2F2ZWQgYXNzaXN0YW50IOKAlCB1c2VzIGRhc2hib2FyZCBvciBBUEktY29uZmlndXJlZCBgYXJ0aWZhY3RQbGFuYAoKYGBganNvbiB0aXRsZT0iUE9TVCAvY2FsbCDigJQgc2F2ZWQgYXNzaXN0YW50Igp7CiAgImFzc2lzdGFudElkIjogInlvdXItYXNzaXN0YW50LWlkIiwKICAicGhvbmVOdW1iZXJJZCI6ICJ5b3VyLXBob25lLW51bWJlci1pZCIKfQpgYGAKCkFydGlmYWN0IHNldHRpbmdzIGNvbWUgZnJvbSB0aGUgc2F2ZWQgYXNzaXN0YW50IHJlY29yZC4gVXBkYXRlIHRoZW0gdmlhIHRoZSBkYXNoYm9hcmQgb3IgYFBBVENIIC9hc3Npc3RhbnQve2lkfWAuCgojIyMgSW5saW5lIGFzc2lzdGFudCDigJQgbXVzdCBpbmNsdWRlIGBhcnRpZmFjdFBsYW5gIGV4cGxpY2l0bHkKCmBgYGpzb24gdGl0bGU9IlBPU1QgL2NhbGwg4oCUIGlubGluZSBhc3Npc3RhbnQgd2l0aCByZWNvcmRpbmciCnsKICAiYXNzaXN0YW50IjogewogICAgIm1vZGVsIjogewogICAgICAicHJvdmlkZXIiOiAib3BlbmFpIiwKICAgICAgIm1vZGVsIjogImdwdC00by1taW5pIiwKICAgICAgIm1lc3NhZ2VzIjogW3sgInJvbGUiOiAic3lzdGVtIiwgImNvbnRlbnQiOiAiWW91IGFyZSBhIGhlbHBmdWwgYXNzaXN0YW50LiIgfV0KICAgIH0sCiAgICAidm9pY2UiOiB7ICJwcm92aWRlciI6ICIxMWxhYnMiLCAidm9pY2VJZCI6ICJ5b3VyLXZvaWNlLWlkIiB9LAogICAgImFydGlmYWN0UGxhbiI6IHsKICAgICAgInJlY29yZGluZ0VuYWJsZWQiOiB0cnVlLAogICAgICAicmVjb3JkaW5nRm9ybWF0IjogIndhdjtsMTYiLAogICAgICAibG9nZ2luZ0VuYWJsZWQiOiB0cnVlCiAgICB9CiAgfSwKICAicGhvbmVOdW1iZXJJZCI6ICJ5b3VyLXBob25lLW51bWJlci1pZCIKfQpgYGAKCllvdSBjYW4gYWxzbyBwYXNzIGBhcnRpZmFjdFBsYW5gIHZpYSBgYXNzaXN0YW50T3ZlcnJpZGVzYCB3aGVuIHVzaW5nIGEgc2F2ZWQgYXNzaXN0YW50IGFuZCB3YW50IHRvIG92ZXJyaWRlIHNldHRpbmdzIHBlciBjYWxsOgoKYGBganNvbiB0aXRsZT0iUE9TVCAvY2FsbCDigJQgcGVyLWNhbGwgb3ZlcnJpZGUiCnsKICAiYXNzaXN0YW50SWQiOiAieW91ci1hc3Npc3RhbnQtaWQiLAogICJhc3Npc3RhbnRPdmVycmlkZXMiOiB7CiAgICAiYXJ0aWZhY3RQbGFuIjogewogICAgICAicmVjb3JkaW5nRW5hYmxlZCI6IHRydWUsCiAgICAgICJyZWNvcmRpbmdGb3JtYXQiOiAibXAzIgogICAgfQogIH0sCiAgInBob25lTnVtYmVySWQiOiAieW91ci1waG9uZS1udW1iZXItaWQiCn0KYGBgCgotLS0KCiMjIFN0b3JhZ2UKCi0gKipEZWZhdWx0OioqIFZhcGkncyBzZWN1cmUgY2xvdWQgKGVuY3J5cHRlZCBhdCByZXN0ICYgaW4gdHJhbnNpdCwgYXV0by1jbGVhbnVwIHBlciByZXRlbnRpb24gcG9saWN5KS4KLSAqKkN1c3RvbToqKiBTMyBvciBHb29nbGUgQ2xvdWQgU3RvcmFnZSB2aWEgYHJlY29yZGluZ1BhdGhgLCBgbG9nZ2luZ1BhdGhgLCBgcGNhcFMzUGF0aFByZWZpeGAsIGFuZCBjb3JyZXNwb25kaW5nIGBjcmVkZW50aWFsc2AuCgpDb250cm9sIGZsYWdzIHBlciBhcnRpZmFjdCB0eXBlOgotIGByZWNvcmRpbmdVc2VDdXN0b21TdG9yYWdlRW5hYmxlZGAKLSBgbG9nZ2luZ1VzZUN1c3RvbVN0b3JhZ2VFbmFibGVkYAotIGBwY2FwVXNlQ3VzdG9tU3RvcmFnZUVuYWJsZWRgCgotLS0KCiMjIFNxdWFkIC8gTXVsdGktQXNzaXN0YW50IEJlaGF2aW9yCgpFYWNoIGFzc2lzdGFudCBpbiBhIFNxdWFkIGNhbiBoYXZlIGl0cyBvd24gYGFydGlmYWN0UGxhbmAuIFJlY29yZGluZywgbG9nZ2luZywgYW5kIHRyYW5zY3JpcHRzICoqcGF1c2UqKiB3aGVuIGFuIGFzc2lzdGFudCB3aXRoIHRob3NlIGZlYXR1cmVzIGRpc2FibGVkIGlzIGFjdGl2ZSwgdGhlbiAqKnJlc3VtZSoqIHdoZW4gdGhlIG5leHQgYXNzaXN0YW50IGhhcyB0aGVtIGVuYWJsZWQuCgoqKkNvbW1vbiBwYXR0ZXJuczoqKgotICoqUGF5bWVudCBmbG93czoqKiBEaXNhYmxlIGFsbCBhcnRpZmFjdHMgb24gdGhlIHBheW1lbnQgYXNzaXN0YW50LCBlbmFibGUgb24gc2VydmljZS9jb25maXJtYXRpb24gYXNzaXN0YW50cy4KLSAqKkNvbnNlbnQgZmxvd3M6KiogRGlzYWJsZSBhcnRpZmFjdHMgb24gdGhlIGNvbnNlbnQgYXNzaXN0YW50LCBlbmFibGUgb24gdGhlIG1haW4gYXNzaXN0YW50IGFmdGVyIGNvbnNlbnQgaXMgZ3JhbnRlZC4KLSAqKkZ1bGwgbWVzc2FnZSBoaXN0b3J5OioqIFNldCBgYXJ0aWZhY3RQbGFuLmZ1bGxNZXNzYWdlSGlzdG9yeUVuYWJsZWQ6IHRydWVgIHRvIGluY2x1ZGUgbWVzc2FnZXMgYWNyb3NzIGFsbCBhc3Npc3RhbnRzIGluIHRoZSBmaW5hbCBhcnRpZmFjdC4KCi0tLQoKIyMgQWNjZXNzaW5nIEFydGlmYWN0cwoKKipWaWEgRGFzaGJvYXJkOioqIENhbGxzIOKGkiBTZWxlY3QgY2FsbCDihpIgQXJ0aWZhY3RzIHNlY3Rpb24gKHJlY29yZGluZywgdHJhbnNjcmlwdCwgbG9ncywgUENBUCkuCgoqKlZpYSBBUEk6KioKYGBgdHlwZXNjcmlwdApjb25zdCBjYWxsID0gYXdhaXQgY2xpZW50LmNhbGxzLmdldCgiY2FsbC1pZCIpOwpjYWxsLmFydGlmYWN0LnJlY29yZGluZyAgIC8vIEF1ZGlvIFVSTApjYWxsLmFydGlmYWN0LnRyYW5zY3JpcHQgIC8vIFRpbWVzdGFtcGVkIG1lc3NhZ2VzCmNhbGwuYXJ0aWZhY3QubG9nVXJsICAgICAgLy8gTG9nIGZpbGUgVVJMCmNhbGwuYXJ0aWZhY3QucGNhcFVybCAgICAgLy8gU0lQIHBhY2tldCBjYXB0dXJlIFVSTApgYGAKCi0tLQoKIyMgUHJpdmFjeSAmIENvbXBsaWFuY2UKCi0g4pqg77iPIFJlY29yZGluZyBsYXdzIHZhcnkgYnkganVyaXNkaWN0aW9uIOKAlCBhbHdheXMgaW5mb3JtIHBhcnRpY2lwYW50cy4KLSBBcHBsaWNhYmxlIHJlZ3VsYXRpb25zOiBHRFBSLCBDQ1BBLCBQQ0kgRFNTLCBISVBBQS4KLSAqKkVudGVycHJpc2U6KiogQnVpbHQtaW4gUmVjb3JkaW5nIENvbnNlbnQgUGxhbnMgc3VwcG9ydCB2ZXJiYWwgYW5kIGltcGxpY2l0IGNvbnNlbnQsIHdpdGggYXVkaXQgdHJhaWxzIGluIGVuZC1vZi1jYWxsIHJlcG9ydHMuCgotLS0KCiMjIFJldGVudGlvbgoKfCBQbGFuIHwgQ2FsbCByZWNvcmRpbmdzICYgbG9ncyB8IENoYXQgdHJhbnNjcmlwdHMgfAp8LS0tfC0tLXwtLS18CnwgUGF5LUFzLVlvdS1HbyB8IDE0IGRheXMgfCAzMCBkYXlzIHwKfCBFbnRlcnByaXNlIHwgQ29uZmlndXJhYmxlIHwgQ29uZmlndXJhYmxlIHwKCiMjIyBXaGF0IGhhcHBlbnMgd2hlbiBhIHJlY29yZGluZyBleHBpcmVzCgpPbmNlIGEgcmVjb3JkaW5nIGV4Y2VlZHMgeW91ciBwbGFuJ3MgcmV0ZW50aW9uIHdpbmRvdywgdGhlIEFQSSByZXR1cm5zIGEgYDQwMCBCYWQgUmVxdWVzdGA6CgpgYGAKWW91ciBzdWJzY3JpcHRpb24gcGxhbiBvbmx5IGNvdmVycyB0aGUgbGFzdCAxNCBkYXlzIG9mIGNhbGwgaGlzdG9yeS4KVGhpcyBjYWxsIGV4Y2VlZHMgeW91ciByZXRlbnRpb24gd2luZG93LgpgYGAKClRoZSBgY2FsbC5hcnRpZmFjdC5yZWNvcmRpbmdgIFVSTCBiZWNvbWVzIGluYWNjZXNzaWJsZS4gQ2FsbCBtZXRhZGF0YSAoSUQsIHRpbWVzdGFtcHMsIGR1cmF0aW9uLCB0cmFuc2NyaXB0IHN1bW1hcnkpIHJlbWFpbnMgYXZhaWxhYmxlIGluZGVmaW5pdGVseS4KCiMjIyBPcHRpb25zIHRvIGV4dGVuZCBvciBieXBhc3MgdGhlIHJldGVudGlvbiBsaW1pdAoKKioxLiBVc2UgY3VzdG9tIGNsb3VkIHN0b3JhZ2UgKHJlY29tbWVuZGVkIGZvciBwcm9kdWN0aW9uKSoqCgpDb25uZWN0IHlvdXIgb3duIFMzIG9yIEdDUyBidWNrZXQuIFJlY29yZGluZ3MgYXJlIHdyaXR0ZW4gZGlyZWN0bHkgdG8geW91ciBidWNrZXQgYXQgY2FsbCB0aW1lIGFuZCBhcmUgc3ViamVjdCB0byB5b3VyIG93biByZXRlbnRpb24gcnVsZXMg4oCUIG5vdCBWYXBpJ3MuIENvbmZpZ3VyZSB0aGlzIHZpYSBgYXJ0aWZhY3RQbGFuLnJlY29yZGluZ1BhdGhgIGFuZCB5b3VyIHN0b3JhZ2UgY3JlZGVudGlhbHM6CgpgYGBqc29uCnsKICAiYXJ0aWZhY3RQbGFuIjogewogICAgInJlY29yZGluZ0VuYWJsZWQiOiB0cnVlLAogICAgInJlY29yZGluZ1BhdGgiOiAiczM6Ly95b3VyLWJ1Y2tldC9yZWNvcmRpbmdzLyIsCiAgICAicmVjb3JkaW5nVXNlQ3VzdG9tU3RvcmFnZUVuYWJsZWQiOiB0cnVlCiAgfQp9CmBgYAoKU2VlIFtDbG91ZCBTdG9yYWdlIFByb3ZpZGVyc10oL3Jlc291cmNlcy9jbG91ZC1wcm92aWRlcnMpIGZvciBTMywgR0NTLCBDbG91ZGZsYXJlIFIyLCBhbmQgU3VwYWJhc2Ugc2V0dXAuCgoqKjIuIFVwZ3JhZGUgdG8gRW50ZXJwcmlzZSoqCgpFbnRlcnByaXNlIHBsYW5zIGluY2x1ZGUgY29uZmlndXJhYmxlIHJldGVudGlvbiBhbmQgb3B0aW9uYWwgemVyby1kYXRhLXJldGVudGlvbiBtb2RlLiBbQ29udGFjdCBTYWxlc10oaHR0cHM6Ly92YXBpLmFpKSB0byBkaXNjdXNzIHJlcXVpcmVtZW50cy4KCjxDYWxsb3V0PgpOZWVkIGhlbHA/IENoYXQgd2l0aCB0aGUgdGVhbSBvbiBvdXIgW0Rpc2NvcmRdKGh0dHBzOi8vZGlzY29yZC5jb20vaW52aXRlL3BVRk5jZjJXbUgpIG9yIG1lbnRpb24gdXMgb24gW1gvVHdpdHRlcl0oaHR0cHM6Ly94LmNvbS9WYXBpX0FJKS4KPC9DYWxsb3V0Pgo= \ No newline at end of file