genassist-chat-react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -0
- package/assets/chat-logo.png +0 -0
- package/dist/components/ChatMessage.d.ts +20 -0
- package/dist/components/ChatMessage.js +188 -0
- package/dist/components/GenAgentChat.d.ts +3 -0
- package/dist/components/GenAgentChat.js +520 -0
- package/dist/components/VoiceInput.d.ts +14 -0
- package/dist/components/VoiceInput.js +51 -0
- package/dist/hooks/useChat.d.ts +21 -0
- package/dist/hooks/useChat.js +256 -0
- package/dist/hooks/useVoiceInput.d.ts +16 -0
- package/dist/hooks/useVoiceInput.js +210 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/services/audioService.d.ts +17 -0
- package/dist/services/audioService.js +118 -0
- package/dist/services/chatService.d.ts +48 -0
- package/dist/services/chatService.js +376 -0
- package/dist/types/index.d.ts +42 -0
- package/dist/types/index.js +2 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# GenAssist Chat React
|
|
2
|
+
|
|
3
|
+
A reusable React chat component for integrating with GenAssist API.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install genassist-chat-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Basic Usage
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
import React from 'react';
|
|
17
|
+
import { GenAgentChat } from 'genassist-chat-react';
|
|
18
|
+
|
|
19
|
+
function App() {
|
|
20
|
+
return (
|
|
21
|
+
<div style={{ height: '600px', width: '400px' }}>
|
|
22
|
+
<GenAgentChat
|
|
23
|
+
baseUrl="https://your-api-base-url.com"
|
|
24
|
+
apiKey="your-api-key"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default App;
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### With Custom Theme and User Data
|
|
34
|
+
|
|
35
|
+
```jsx
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import { GenAgentChat } from 'genassist-chat-react';
|
|
38
|
+
|
|
39
|
+
function App() {
|
|
40
|
+
const userData = {
|
|
41
|
+
userId: '12345',
|
|
42
|
+
username: 'johndoe',
|
|
43
|
+
email: 'john@example.com',
|
|
44
|
+
// Any additional metadata
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const theme = {
|
|
48
|
+
primaryColor: '#4a90e2',
|
|
49
|
+
secondaryColor: '#f5f5f5',
|
|
50
|
+
backgroundColor: '#ffffff',
|
|
51
|
+
textColor: '#333333',
|
|
52
|
+
fontFamily: 'Roboto, sans-serif',
|
|
53
|
+
fontSize: '15px',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div style={{ height: '600px', width: '400px' }}>
|
|
58
|
+
<GenAgentChat
|
|
59
|
+
baseUrl="https://your-api-base-url.com"
|
|
60
|
+
apiKey="your-api-key"
|
|
61
|
+
userData={userData}
|
|
62
|
+
theme={theme}
|
|
63
|
+
headerTitle="Customer Support"
|
|
64
|
+
placeholder="Ask a question..."
|
|
65
|
+
onError={(error) => console.error('Chat error:', error)}
|
|
66
|
+
onTakeover={handleTakeover}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export default App;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Props
|
|
76
|
+
|
|
77
|
+
| Prop | Type | Required | Default | Description |
|
|
78
|
+
|------|------|----------|---------|-------------|
|
|
79
|
+
| baseUrl | string | Yes | - | Base URL for the API endpoints |
|
|
80
|
+
| apiKey | string | Yes | - | API key for authentication |
|
|
81
|
+
| userData | object | No | - | Any user metadata to include |
|
|
82
|
+
| onError | function | No | - | Error handler callback |
|
|
83
|
+
| onTakeover | function | No | - | Callback triggered when a takeover event occurs |
|
|
84
|
+
| theme | object | No | - | Custom theme options |
|
|
85
|
+
| headerTitle | string | No | 'Chat' | Title displayed in the chat header |
|
|
86
|
+
| placeholder | string | No | 'Type a message...' | Placeholder text for the input |
|
|
87
|
+
|
|
88
|
+
## Theme Options
|
|
89
|
+
|
|
90
|
+
| Option | Type | Description |
|
|
91
|
+
|--------|------|-------------|
|
|
92
|
+
| primaryColor | string | Primary color for buttons and user messages |
|
|
93
|
+
| secondaryColor | string | Background color for agent messages |
|
|
94
|
+
| backgroundColor | string | Background color for the chat container |
|
|
95
|
+
| textColor | string | Text color for agent messages |
|
|
96
|
+
| fontFamily | string | Font family for all text |
|
|
97
|
+
| fontSize | string | Font size for messages |
|
|
98
|
+
|
|
99
|
+
## API Endpoints
|
|
100
|
+
|
|
101
|
+
The component interacts with the following endpoints:
|
|
102
|
+
|
|
103
|
+
1. Start Conversation: `POST /api/conversations/in-progress/start`
|
|
104
|
+
2. Update Conversation: `POST /api/conversations/in-progress/update/{conversation_id}`
|
|
105
|
+
3. WebSocket: `/api/conversations/ws/{conversation_id}?access_token={token}&lang=en&topics=message&topics=takeover`
|
|
106
|
+
|
|
107
|
+
## Run
|
|
108
|
+
./
|
|
109
|
+
yarn run build
|
|
110
|
+
|
|
111
|
+
cd example-app
|
|
112
|
+
|
|
113
|
+
yarn run dev
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ChatMessage } from '../types';
|
|
3
|
+
interface ChatMessageProps {
|
|
4
|
+
message: ChatMessage;
|
|
5
|
+
theme?: {
|
|
6
|
+
primaryColor?: string;
|
|
7
|
+
secondaryColor?: string;
|
|
8
|
+
fontFamily?: string;
|
|
9
|
+
fontSize?: string;
|
|
10
|
+
backgroundColor?: string;
|
|
11
|
+
textColor?: string;
|
|
12
|
+
};
|
|
13
|
+
onPlayAudio?: (text: string) => Promise<void>;
|
|
14
|
+
isPlayingAudio?: boolean;
|
|
15
|
+
isFirstMessage?: boolean;
|
|
16
|
+
isNextSameSpeaker?: boolean;
|
|
17
|
+
isPrevSameSpeaker?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const ChatMessageComponent: React.FC<ChatMessageProps>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { User, UserX, AlertCircle } from 'lucide-react';
|
|
15
|
+
export var ChatMessageComponent = function (_a) {
|
|
16
|
+
var message = _a.message, theme = _a.theme, onPlayAudio = _a.onPlayAudio, isPlayingAudio = _a.isPlayingAudio, _b = _a.isFirstMessage, isFirstMessage = _b === void 0 ? false : _b, _c = _a.isNextSameSpeaker, isNextSameSpeaker = _c === void 0 ? false : _c, _d = _a.isPrevSameSpeaker, isPrevSameSpeaker = _d === void 0 ? false : _d;
|
|
17
|
+
var isUser = message.speaker === 'customer';
|
|
18
|
+
var isSpecial = message.speaker === 'special';
|
|
19
|
+
var isWelcomeMessage = !isUser && !isSpecial && isFirstMessage;
|
|
20
|
+
var formatTimestamp = function (timestamp) {
|
|
21
|
+
try {
|
|
22
|
+
if (!timestamp || isNaN(timestamp)) {
|
|
23
|
+
return 'Just now';
|
|
24
|
+
}
|
|
25
|
+
var timestampMs = timestamp < 1000000000000 ? timestamp * 1000 : timestamp;
|
|
26
|
+
var date = new Date(timestampMs);
|
|
27
|
+
// Quick check if date is valid
|
|
28
|
+
if (isNaN(date.getTime())) {
|
|
29
|
+
return 'Just now';
|
|
30
|
+
}
|
|
31
|
+
var today = new Date();
|
|
32
|
+
var yesterday = new Date(today);
|
|
33
|
+
yesterday.setDate(yesterday.getDate() - 1);
|
|
34
|
+
// Format time as HH:MM AM/PM
|
|
35
|
+
var timeOptions = { hour: 'numeric', minute: '2-digit', hour12: true };
|
|
36
|
+
var timeStr = date.toLocaleTimeString(undefined, timeOptions);
|
|
37
|
+
// Check if date is today, yesterday, or another day
|
|
38
|
+
if (date.toDateString() === today.toDateString()) {
|
|
39
|
+
return "Today, ".concat(timeStr);
|
|
40
|
+
}
|
|
41
|
+
else if (date.toDateString() === yesterday.toDateString()) {
|
|
42
|
+
return "Yesterday, ".concat(timeStr);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// Format date as Month DD, YYYY
|
|
46
|
+
var dateOptions = { month: 'short', day: 'numeric', year: 'numeric' };
|
|
47
|
+
var dateStr = date.toLocaleDateString(undefined, dateOptions);
|
|
48
|
+
return "".concat(dateStr, ", ").concat(timeStr);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error('Error formatting timestamp:', error);
|
|
53
|
+
return 'Just now';
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var timestamp = formatTimestamp(message.create_time);
|
|
57
|
+
var userBubbleBgColor = (theme === null || theme === void 0 ? void 0 : theme.primaryColor) || '#2563EB';
|
|
58
|
+
var userTextColor = '#ffffff';
|
|
59
|
+
var agentBubbleBgColor = (theme === null || theme === void 0 ? void 0 : theme.secondaryColor) || '#eeeeee';
|
|
60
|
+
var agentTextColor = '#000000';
|
|
61
|
+
var fontFamily = (theme === null || theme === void 0 ? void 0 : theme.fontFamily) || 'Roboto, Arial, sans-serif';
|
|
62
|
+
var fontSize = (theme === null || theme === void 0 ? void 0 : theme.fontSize) || '15px';
|
|
63
|
+
var messageContainerStyle = {
|
|
64
|
+
display: 'flex',
|
|
65
|
+
flexDirection: 'column',
|
|
66
|
+
width: '100%',
|
|
67
|
+
marginBottom: isPrevSameSpeaker ? '8px' : '8px',
|
|
68
|
+
marginTop: isPrevSameSpeaker ? '0px' : '16px',
|
|
69
|
+
position: 'relative',
|
|
70
|
+
alignItems: isUser ? 'flex-end' : 'flex-start',
|
|
71
|
+
};
|
|
72
|
+
var messageRowStyle = {
|
|
73
|
+
display: 'flex',
|
|
74
|
+
width: '100%',
|
|
75
|
+
justifyContent: isUser ? 'flex-end' : 'flex-start',
|
|
76
|
+
};
|
|
77
|
+
var labelContainerStyle = {
|
|
78
|
+
display: isPrevSameSpeaker ? 'none' : 'flex',
|
|
79
|
+
width: '80%',
|
|
80
|
+
justifyContent: isUser ? 'flex-end' : 'flex-start',
|
|
81
|
+
marginBottom: '4px',
|
|
82
|
+
};
|
|
83
|
+
var messageLabelStyle = {
|
|
84
|
+
fontSize: '12px',
|
|
85
|
+
color: '#757575',
|
|
86
|
+
lineHeight: 1,
|
|
87
|
+
};
|
|
88
|
+
var messageBubbleContainerStyle = {
|
|
89
|
+
display: 'flex',
|
|
90
|
+
flexDirection: 'column',
|
|
91
|
+
maxWidth: '80%',
|
|
92
|
+
};
|
|
93
|
+
var bubbleStyle = {
|
|
94
|
+
backgroundColor: isUser
|
|
95
|
+
? userBubbleBgColor
|
|
96
|
+
: agentBubbleBgColor,
|
|
97
|
+
color: isUser ? userTextColor : agentTextColor,
|
|
98
|
+
padding: '12px 16px',
|
|
99
|
+
borderRadius: '8px',
|
|
100
|
+
fontSize: fontSize,
|
|
101
|
+
fontFamily: fontFamily,
|
|
102
|
+
wordBreak: 'break-word',
|
|
103
|
+
lineHeight: 1.4,
|
|
104
|
+
maxWidth: '100%',
|
|
105
|
+
};
|
|
106
|
+
var timestampStyle = {
|
|
107
|
+
fontSize: '11px',
|
|
108
|
+
color: '#757575',
|
|
109
|
+
marginTop: '4px',
|
|
110
|
+
width: '80%',
|
|
111
|
+
textAlign: isUser ? 'right' : 'left',
|
|
112
|
+
display: isNextSameSpeaker ? 'none' : 'block', // Hide timestamp if next message is from same speaker
|
|
113
|
+
};
|
|
114
|
+
var welcomeTitleStyle = {
|
|
115
|
+
fontSize: '18px',
|
|
116
|
+
fontWeight: 'bold',
|
|
117
|
+
marginBottom: '4px',
|
|
118
|
+
color: '#000000',
|
|
119
|
+
};
|
|
120
|
+
var welcomeContentStyle = {
|
|
121
|
+
fontSize: '16px',
|
|
122
|
+
fontWeight: 'normal',
|
|
123
|
+
color: '#000000',
|
|
124
|
+
};
|
|
125
|
+
var speakerLabel = isUser ? 'You' : isSpecial ? 'System' : 'Agent';
|
|
126
|
+
var welcomeTitle = '';
|
|
127
|
+
var welcomeContent = '';
|
|
128
|
+
if (isWelcomeMessage) {
|
|
129
|
+
var messageText = message.text;
|
|
130
|
+
if (messageText.toLowerCase().startsWith('')) {
|
|
131
|
+
var parts = messageText.split(/[,.!?]/);
|
|
132
|
+
if (parts.length > 0) {
|
|
133
|
+
welcomeTitle = parts[0].trim();
|
|
134
|
+
welcomeContent = messageText.substring(welcomeTitle.length).trim();
|
|
135
|
+
// Remove any punctuation at the start
|
|
136
|
+
welcomeContent = welcomeContent.replace(/^[,.!?\s]+/, '');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
welcomeTitle = '';
|
|
141
|
+
welcomeContent = messageText;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
var messageLines = !isWelcomeMessage ? message.text.split('\n').map(function (line, i) { return (_jsxs(React.Fragment, { children: [line, i < message.text.split('\n').length - 1 && _jsx("br", {})] }, i)); }) : null;
|
|
145
|
+
// Handle special messages (like takeover indicators)
|
|
146
|
+
if (isSpecial) {
|
|
147
|
+
var specialMessageStyle = {
|
|
148
|
+
display: 'flex',
|
|
149
|
+
justifyContent: 'center',
|
|
150
|
+
alignItems: 'center',
|
|
151
|
+
margin: '16px 0',
|
|
152
|
+
width: '100%',
|
|
153
|
+
};
|
|
154
|
+
// Determine icon and style based on message content
|
|
155
|
+
var icon = void 0;
|
|
156
|
+
var backgroundColor = '#E3F2FD';
|
|
157
|
+
var textColor = '#1976D2';
|
|
158
|
+
if (message.text.toLowerCase().includes('offline') || message.text.toLowerCase().includes('inactive')) {
|
|
159
|
+
icon = _jsx(AlertCircle, { size: 18 });
|
|
160
|
+
backgroundColor = '#FFF3E0';
|
|
161
|
+
textColor = '#F57C00';
|
|
162
|
+
}
|
|
163
|
+
else if (message.text.toLowerCase().includes('took over') || message.text.toLowerCase().includes('takeover')) {
|
|
164
|
+
icon = _jsx(UserX, { size: 18 });
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
icon = _jsx(User, { size: 18 });
|
|
168
|
+
}
|
|
169
|
+
var specialBubbleStyle = {
|
|
170
|
+
backgroundColor: backgroundColor,
|
|
171
|
+
color: textColor,
|
|
172
|
+
padding: '8px 16px',
|
|
173
|
+
borderRadius: '16px',
|
|
174
|
+
fontSize: '14px',
|
|
175
|
+
fontFamily: fontFamily,
|
|
176
|
+
fontWeight: '500',
|
|
177
|
+
display: 'flex',
|
|
178
|
+
alignItems: 'center',
|
|
179
|
+
gap: '8px',
|
|
180
|
+
};
|
|
181
|
+
return (_jsx("div", { style: specialMessageStyle, children: _jsxs("div", { style: specialBubbleStyle, children: [icon, message.text] }) }));
|
|
182
|
+
}
|
|
183
|
+
if (isWelcomeMessage) {
|
|
184
|
+
return (_jsx("div", { style: messageContainerStyle, children: _jsxs("div", { style: messageBubbleContainerStyle, children: [_jsx("div", { style: labelContainerStyle, children: _jsx("div", { style: messageLabelStyle, children: "Agent" }) }), _jsx("div", { style: messageRowStyle, children: _jsx("div", { style: __assign(__assign({}, bubbleStyle), { backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.primaryColor) || '#2563EB', color: '#ffffff' }), children: message.text }) }), _jsx("div", { style: timestampStyle, children: timestamp })] }) }));
|
|
185
|
+
}
|
|
186
|
+
return (_jsxs("div", { style: messageContainerStyle, children: [_jsx("div", { style: labelContainerStyle, children: _jsx("div", { style: messageLabelStyle, children: speakerLabel }) }), _jsx("div", { style: bubbleStyle, children: messageLines }), _jsx("div", { style: timestampStyle, children: timestamp })] }));
|
|
187
|
+
};
|
|
188
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ2hhdE1lc3NhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tcG9uZW50cy9DaGF0TWVzc2FnZS50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBRTFCLE9BQU8sRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQW1CeEQsTUFBTSxDQUFDLElBQU0sb0JBQW9CLEdBQStCLFVBQUMsRUFRaEU7UUFQQyxPQUFPLGFBQUEsRUFDUCxLQUFLLFdBQUEsRUFDTCxXQUFXLGlCQUFBLEVBQ1gsY0FBYyxvQkFBQSxFQUNkLHNCQUFzQixFQUF0QixjQUFjLG1CQUFHLEtBQUssS0FBQSxFQUN0Qix5QkFBeUIsRUFBekIsaUJBQWlCLG1CQUFHLEtBQUssS0FBQSxFQUN6Qix5QkFBeUIsRUFBekIsaUJBQWlCLG1CQUFHLEtBQUssS0FBQTtJQUV6QixJQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsT0FBTyxLQUFLLFVBQVUsQ0FBQztJQUM5QyxJQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxLQUFLLFNBQVMsQ0FBQztJQUNoRCxJQUFNLGdCQUFnQixHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsU0FBUyxJQUFJLGNBQWMsQ0FBQztJQUVqRSxJQUFNLGVBQWUsR0FBRyxVQUFDLFNBQWlCO1FBQ3hDLElBQUksQ0FBQztZQUNILElBQUksQ0FBQyxTQUFTLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7Z0JBQ25DLE9BQU8sVUFBVSxDQUFDO1lBQ3BCLENBQUM7WUFFRCxJQUFNLFdBQVcsR0FBRyxTQUFTLEdBQUcsYUFBYSxDQUFDLENBQUMsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7WUFFN0UsSUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLENBQUMsV0FBVyxDQUFDLENB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RUFBRSxpQkFBaUIsc0JBQWEsR0FDdEMsRUFDTixjQUFLLEtBQUssRUFBRSxlQUFlLFlBQ3pCLGNBQUssS0FBSyx3QkFBTSxXQUFXLEtBQUUsZUFBZSxFQUFFLENBQUEsS0FBSyxhQUFMLEtBQUssdUJBQUwsS0FBSyxDQUFFLFlBQVksS0FBSSxTQUFTLEVBQUUsS0FBSyxFQUFFLFNBQVMsZUFDN0YsT0FBTyxDQUFDLElBQUksR0FDVCxHQUNGLEVBQ04sY0FBSyxLQUFLLEVBQUUsY0FBYyxZQUFHLFNBQVMsR0FBTyxJQUN6QyxHQUNGLENBQ1AsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPLENBQ0wsZUFBSyxLQUFLLEVBQUUscUJBQXFCLGFBQy9CLGNBQUssS0FBSyxFQUFFLG1CQUFtQixZQUM3QixjQUFLLEtBQUssRUFBRSxpQkFBaUIsWUFBRyxZQUFZLEdBQU8sR0FDL0MsRUFDTixjQUFLLEtBQUssRUFBRSxXQUFXLFlBQ3BCLFlBQVksR0FDVCxFQUNOLGNBQUssS0FBSyxFQUFFLGNBQWMsWUFBRyxTQUFTLEdBQU8sSUFDekMsQ0FDUCxDQUFDO0FBQ0osQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7IENoYXRNZXNzYWdlIH0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IHsgVXNlciwgVXNlclgsIEFsZXJ0Q2lyY2xlIH0gZnJvbSAnbHVjaWRlLXJlYWN0JztcblxuaW50ZXJmYWNlIENoYXRNZXNzYWdlUHJvcHMge1xuICBtZXNzYWdlOiBDaGF0TWVzc2FnZTtcbiAgdGhlbWU/OiB7XG4gICAgcHJpbWFyeUNvbG9yPzogc3RyaW5nO1xuICAgIHNlY29uZGFyeUNvbG9yPzogc3RyaW5nO1xuICAgIGZvbnRGYW1pbHk/OiBzdHJpbmc7XG4gICAgZm9udFNpemU/OiBzdHJpbmc7XG4gICAgYmFja2dyb3VuZENvbG9yPzogc3RyaW5nO1xuICAgIHRleHRDb2xvcj86IHN0cmluZztcbiAgfTtcbiAgb25QbGF5QXVkaW8/OiAodGV4dDogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBpc1BsYXlpbmdBdWRpbz86IGJvb2xlYW47XG4gIGlzRmlyc3RNZXNzYWdlPzogYm9vbGVhbjtcbiAgaXNOZXh0U2FtZVNwZWFrZXI/OiBib29sZWFuO1xuICBpc1ByZXZTYW1lU3BlYWtlcj86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjb25zdCBDaGF0TWVzc2FnZUNvbXBvbmVudDogUmVhY3QuRkM8Q2hhdE1lc3NhZ2VQcm9wcz4gPSAoe1xuICBtZXNzYWdlLFxuICB0aGVtZSxcbiAgb25QbGF5QXVkaW8sXG4gIGlzUGxheWluZ0F1ZGlvLFxuICBpc0ZpcnN0TWVzc2FnZSA9IGZhbHNlLFxuICBpc05leHRTYW1lU3BlYWtlciA9IGZhbHNlLFxuICBpc1ByZXZTYW1lU3BlYWtlciA9IGZhbHNlXG59KSA9PiB7XG4gIGNvbnN0IGlzVXNlciA9IG1lc3NhZ2Uuc3BlYWtlciA9PT0gJ2N1c3RvbWVyJztcbiAgY29uc3QgaXNTcGVjaWFsID0gbWVzc2FnZS5zcGVha2VyID09PSAnc3BlY2lhbCc7XG4gIGNvbnN0IGlzV2VsY29tZU1lc3NhZ2UgPSAhaXNVc2VyICYmICFpc1NwZWNpYWwgJiYgaXNGaXJzdE1lc3NhZ2U7XG5cbiAgY29uc3QgZm9ybWF0VGltZXN0YW1wID0gKHRpbWVzdGFtcDogbnVtYmVyKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGlmICghdGltZXN0YW1wIHx8IGlzTmFOKHRpbWVzdGFtcCkpIHtcbiAgICAgICAgcmV0dXJuICdKdXN0IG5vdyc7XG4gICAgICB9XG4gICAgICBcbiAgICAgIGNvbnN0IHRpbWVzdGFtcE1zID0gdGltZXN0YW1wIDwgMTAwMDAwMDAwMDAwMCA/IHRpbWVzdGFtcCAqIDEwMDAgOiB0aW1lc3RhbXA7XG4gICAgICBcbiAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSh0aW1lc3RhbXBNcyk7XG4gICAgICAvLyBRdWljayBjaGVjayBpZiBkYXRlIGlzIHZhbGlkXG4gICAgICBpZiAoaXNOYU4oZGF0ZS5nZXRUaW1lKCkpKSB7XG4gICAgICAgIHJldHVybiAnSnVzdCBub3cnO1xuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCB0b2RheSA9IG5ldyBEYXRlKCk7XG4gICAgICBjb25zdCB5ZXN0ZXJkYXkgPSBuZXcgRGF0ZSh0b2RheSk7XG4gICAgICB5ZXN0ZXJkYXkuc2V0RGF0ZSh5ZXN0ZXJkYXkuZ2V0RGF0ZSgpIC0gMSk7XG4gICAgICBcbiAgICAgIC8vIEZvcm1hdCB0aW1lIGFzIEhIOk1NIEFNL1BNXG4gICAgICBjb25zdCB0aW1lT3B0aW9uczogSW50bC5EYXRlVGltZUZvcm1hdE9wdGlvbnMgPSB7IGhvdXI6ICdudW1lcmljJywgbWludXRlOiAnMi1kaWdpdCcsIGhvdXIxMjogdHJ1ZSB9O1xuICAgICAgY29uc3QgdGltZVN0ciA9IGRhdGUudG9Mb2NhbGVUaW1lU3RyaW5nKHVuZGVmaW5lZCwgdGltZU9wdGlvbnMpO1xuICAgICAgXG4gICAgICAvLyBDaGVjayBpZiBkYXRlIGlzIHRvZGF5LCB5ZXN0ZXJkYXksIG9yIGFub3RoZXIgZGF5XG4gICAgICBpZiAoZGF0ZS50b0RhdGVTdHJpbmcoKSA9PT0gdG9kYXkudG9EYXRlU3RyaW5nKCkpIHtcbiAgICAgICAgcmV0dXJuIGBUb2RheSwgJHt0aW1lU3RyfWA7XG4gICAgICB9IGVsc2UgaWYgKGRhdGUudG9EYXRlU3RyaW5nKCkgPT09IHllc3RlcmRheS50b0RhdGVTdHJpbmcoKSkge1xuICAgICAgICByZXR1cm4gYFllc3RlcmRheSwgJHt0aW1lU3RyfWA7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBGb3JtYXQgZGF0ZSBhcyBNb250aCBERCwgWVlZWVxuICAgICAgICBjb25zdCBkYXRlT3B0aW9uczogSW50bC5EYXRlVGltZUZvcm1hdE9wdGlvbnMgPSB7IG1vbnRoOiAnc2hvcnQnLCBkYXk6ICdudW1lcmljJywgeWVhcjogJ251bWVyaWMnIH07XG4gICAgICAgIGNvbnN0IGRhdGVTdHIgPSBkYXRlLnRvTG9jYWxlRGF0ZVN0cmluZyh1bmRlZmluZWQsIGRhdGVPcHRpb25zKTtcbiAgICAgICAgcmV0dXJuIGAke2RhdGVTdHJ9LCAke3RpbWVTdHJ9YDtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgZm9ybWF0dGluZyB0aW1lc3RhbXA6JywgZXJyb3IpO1xuICAgICAgcmV0dXJuICdKdXN0IG5vdyc7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IHRpbWVzdGFtcCA9IGZvcm1hdFRpbWVzdGFtcChtZXNzYWdlLmNyZWF0ZV90aW1lKTtcblxuICBjb25zdCB1c2VyQnViYmxlQmdDb2xvciA9IHRoZW1lPy5wcmltYXJ5Q29sb3IgfHwgJyMyNTYzRUInO1xuICBjb25zdCB1c2VyVGV4dENvbG9yID0gJyNmZmZmZmYnO1xuICBjb25zdCBhZ2VudEJ1YmJsZUJnQ29sb3IgPSB0aGVtZT8uc2Vjb25kYXJ5Q29sb3IgfHwgJyNlZWVlZWUnO1xuICBjb25zdCBhZ2VudFRleHRDb2xvciA9ICcjMDAwMDAwJztcbiAgY29uc3QgZm9udEZhbWlseSA9IHRoZW1lPy5mb250RmFtaWx5IHx8ICdSb2JvdG8sIEFyaWFsLCBzYW5zLXNlcmlmJztcbiAgY29uc3QgZm9udFNpemUgPSB0aGVtZT8uZm9udFNpemUgfHwgJzE1cHgnO1xuXG4gIGNvbnN0IG1lc3NhZ2VDb250YWluZXJTdHlsZTogUmVhY3QuQ1NTUHJvcGVydGllcyA9IHtcbiAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgZmxleERpcmVjdGlvbjogJ2NvbHVtbicsXG4gICAgd2lkdGg6ICcxMDAlJyxcbiAgICBtYXJnaW5Cb3R0b206IGlzUHJldlNhbWVTcGVha2VyID8gJzhweCcgOiAnOHB4JyxcbiAgICBtYXJnaW5Ub3A6IGlzUHJldlNhbWVTcGVha2VyID8gJzBweCcgOiAnMTZweCcsXG4gICAgcG9zaXRpb246ICdyZWxhdGl2ZScsXG4gICAgYWxpZ25JdGVtczogaXNVc2VyID8gJ2ZsZXgtZW5kJyA6ICdmbGV4LXN0YXJ0JyxcbiAgfTtcblxuICBjb25zdCBtZXNzYWdlUm93U3R5bGU6IFJlYWN0LkNTU1Byb3BlcnRpZXMgPSB7XG4gICAgZGlzcGxheTogJ2ZsZXgnLFxuICAgIHdpZHRoOiAnMTAwJScsXG4gICAganVzdGlmeUNvbnRlbnQ6IGlzVXNlciA/ICdmbGV4LWVuZCcgOiAnZmxleC1zdGFydCcsXG4gIH07XG5cbiAgY29uc3QgbGFiZWxDb250YWluZXJTdHlsZTogUmVhY3QuQ1NTUHJvcGVydGllcyA9IHtcbiAgICBkaXNwbGF5OiBpc1ByZXZTYW1lU3BlYWtlciA/ICdub25lJyA6ICdmbGV4JyxcbiAgICB3aWR0aDogJzgwJScsXG4gICAganVzdGlmeUNvbnRlbnQ6IGlzVXNlciA/ICdmbGV4LWVuZCcgOiAnZmxleC1zdGFydCcsXG4gICAgbWFyZ2luQm90dG9tOiAnNHB4JyxcbiAgfTtcblxuICBjb25zdCBtZXNzYWdlTGFiZWxTdHlsZTogUmVhY3QuQ1NTUHJvcGVydGllcyA9IHtcbiAgICBmb250U2l6ZTogJzEycHgnLFxuICAgIGNvbG9yOiAnIzc1NzU3NScsXG4gICAgbGluZUhlaWdodDogMSxcbiAgfTtcblxuICBjb25zdCBtZXNzYWdlQnViYmxlQ29udGFpbmVyU3R5bGU6IFJlYWN0LkNTU1Byb3BlcnRpZXMgPSB7XG4gICAgZGlzcGxheTogJ2ZsZXgnLFxuICAgIGZsZXhEaXJlY3Rpb246ICdjb2x1bW4nLFxuICAgIG1heFdpZHRoOiAnODAlJyxcbiAgfTtcblxuICBjb25zdCBidWJibGVTdHlsZTogUmVhY3QuQ1NTUHJvcGVydGllcyA9IHtcbiAgICBiYWNrZ3JvdW5kQ29sb3I6IGlzVXNlciBcbiAgICAgID8gdXNlckJ1YmJsZUJnQ29sb3JcbiAgICAgIDogYWdlbnRCdWJibGVCZ0NvbG9yLFxuICAgIGNvbG9yOiBpc1VzZXIgPyB1c2VyVGV4dENvbG9yIDogYWdlbnRUZXh0Q29sb3IsXG4gICAgcGFkZGluZzogJzEycHggMTZweCcsXG4gICAgYm9yZGVyUmFkaXVzOiAnOHB4JyxcbiAgICBmb250U2l6ZSxcbiAgICBmb250RmFtaWx5LFxuICAgIHdvcmRCcmVhazogJ2JyZWFrLXdvcmQnLFxuICAgIGxpbmVIZWlnaHQ6IDEuNCxcbiAgICBtYXhXaWR0aDogJzEwMCUnLFxuICB9O1xuXG4gIGNvbnN0IHRpbWVzdGFtcFN0eWxlOiBSZWFjdC5DU1NQcm9wZXJ0aWVzID0ge1xuICAgIGZvbnRTaXplOiAnMTFweCcsXG4gICAgY29sb3I6ICcjNzU3NTc1JyxcbiAgICBtYXJnaW5Ub3A6ICc0cHgnLFxuICAgIHdpZHRoOiAnODAlJyxcbiAgICB0ZXh0QWxpZ246IGlzVXNlciA/ICdyaWdodCcgOiAnbGVmdCcsXG4gICAgZGlzcGxheTogaXNOZXh0U2FtZVNwZWFrZXIgPyAnbm9uZScgOiAnYmxvY2snLCAvLyBIaWRlIHRpbWVzdGFtcCBpZiBuZXh0IG1lc3NhZ2UgaXMgZnJvbSBzYW1lIHNwZWFrZXJcbiAgfTtcblxuICBjb25zdCB3ZWxjb21lVGl0bGVTdHlsZTogUmVhY3QuQ1NTUHJvcGVydGllcyA9IHtcbiAgICBmb250U2l6ZTogJzE4cHgnLFxuICAgIGZvbnRXZWlnaHQ6ICdib2xkJyxcbiAgICBtYXJnaW5Cb3R0b206ICc0cHgnLFxuICAgIGNvbG9yOiAnIzAwMDAwMCcsXG4gIH07XG5cbiAgY29uc3Qgd2VsY29tZUNvbnRlbnRTdHlsZTogUmVhY3QuQ1NTUHJvcGVydGllcyA9IHtcbiAgICBmb250U2l6ZTogJzE2cHgnLFxuICAgIGZvbnRXZWlnaHQ6ICdub3JtYWwnLFxuICAgIGNvbG9yOiAnIzAwMDAwMCcsXG4gIH07XG5cbiAgY29uc3Qgc3BlYWtlckxhYmVsID0gaXNVc2VyID8gJ1lvdScgOiBpc1NwZWNpYWwgPyAnU3lzdGVtJyA6ICdBZ2VudCc7XG5cbiAgbGV0IHdlbGNvbWVUaXRsZSA9ICcnO1xuICBsZXQgd2VsY29tZUNvbnRlbnQgPSAnJztcbiAgXG4gIGlmIChpc1dlbGNvbWVNZXNzYWdlKSB7XG4gICAgY29uc3QgbWVzc2FnZVRleHQgPSBtZXNzYWdlLnRleHQ7XG4gICAgaWYgKG1lc3NhZ2VUZXh0LnRvTG93ZXJDYXNlKCkuc3RhcnRzV2l0aCgnJykpIHtcbiAgICAgIGNvbnN0IHBhcnRzID0gbWVzc2FnZVRleHQuc3BsaXQoL1ssLiE/XS8pO1xuICAgICAgaWYgKHBhcnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgd2VsY29tZVRpdGxlID0gcGFydHNbMF0udHJpbSgpO1xuICAgICAgICB3ZWxjb21lQ29udGVudCA9IG1lc3NhZ2VUZXh0LnN1YnN0cmluZyh3ZWxjb21lVGl0bGUubGVuZ3RoKS50cmltKCk7XG4gICAgICAgIC8vIFJlbW92ZSBhbnkgcHVuY3R1YXRpb24gYXQgdGhlIHN0YXJ0XG4gICAgICAgIHdlbGNvbWVDb250ZW50ID0gd2VsY29tZUNvbnRlbnQucmVwbGFjZSgvXlssLiE/XFxzXSsvLCAnJyk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHdlbGNvbWVUaXRsZSA9ICcnO1xuICAgICAgd2VsY29tZUNvbnRlbnQgPSBtZXNzYWdlVGV4dDtcbiAgICB9XG4gIH1cblxuICBjb25zdCBtZXNzYWdlTGluZXMgPSAhaXNXZWxjb21lTWVzc2FnZSA/IG1lc3NhZ2UudGV4dC5zcGxpdCgnXFxuJykubWFwKChsaW5lLCBpKSA9PiAoXG4gICAgPFJlYWN0LkZyYWdtZW50IGtleT17aX0+XG4gICAgICB7bGluZX1cbiAgICAgIHtpIDwgbWVzc2FnZS50ZXh0LnNwbGl0KCdcXG4nKS5sZW5ndGggLSAxICYmIDxiciAvPn1cbiAgICA8L1JlYWN0LkZyYWdtZW50PlxuICApKSA6IG51bGw7XG5cbiAgLy8gSGFuZGxlIHNwZWNpYWwgbWVzc2FnZXMgKGxpa2UgdGFrZW92ZXIgaW5kaWNhdG9ycylcbiAgaWYgKGlzU3BlY2lhbCkge1xuICAgIGNvbnN0IHNwZWNpYWxNZXNzYWdlU3R5bGU6IFJlYWN0LkNTU1Byb3BlcnRpZXMgPSB7XG4gICAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgICBqdXN0aWZ5Q29udGVudDogJ2NlbnRlcicsXG4gICAgICBhbGlnbkl0ZW1zOiAnY2VudGVyJyxcbiAgICAgIG1hcmdpbjogJzE2cHggMCcsXG4gICAgICB3aWR0aDogJzEwMCUnLFxuICAgIH07XG5cbiAgICAvLyBEZXRlcm1pbmUgaWNvbiBhbmQgc3R5bGUgYmFzZWQgb24gbWVzc2FnZSBjb250ZW50XG4gICAgbGV0IGljb247XG4gICAgbGV0IGJhY2tncm91bmRDb2xvciA9ICcjRTNGMkZEJztcbiAgICBsZXQgdGV4dENvbG9yID0gJyMxOTc2RDInO1xuICAgIFxuICAgIGlmIChtZXNzYWdlLnRleHQudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnb2ZmbGluZScpIHx8IG1lc3NhZ2UudGV4dC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKCdpbmFjdGl2ZScpKSB7XG4gICAgICBpY29uID0gPEFsZXJ0Q2lyY2xlIHNpemU9ezE4fSAvPjtcbiAgICAgIGJhY2tncm91bmRDb2xvciA9ICcjRkZGM0UwJztcbiAgICAgIHRleHRDb2xvciA9ICcjRjU3QzAwJztcbiAgICB9IGVsc2UgaWYgKG1lc3NhZ2UudGV4dC50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKCd0b29rIG92ZXInKSB8fCBtZXNzYWdlLnRleHQudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygndGFrZW92ZXInKSkge1xuICAgICAgaWNvbiA9IDxVc2VyWCBzaXplPXsxOH0gLz47XG4gICAgfSBlbHNlIHtcbiAgICAgIGljb24gPSA8VXNlciBzaXplPXsxOH0gLz47XG4gICAgfVxuXG4gICAgY29uc3Qgc3BlY2lhbEJ1YmJsZVN0eWxlOiBSZWFjdC5DU1NQcm9wZXJ0aWVzID0ge1xuICAgICAgYmFja2dyb3VuZENvbG9yLFxuICAgICAgY29sb3I6IHRleHRDb2xvcixcbiAgICAgIHBhZGRpbmc6ICc4cHggMTZweCcsXG4gICAgICBib3JkZXJSYWRpdXM6ICcxNnB4JyxcbiAgICAgIGZvbnRTaXplOiAnMTRweCcsXG4gICAgICBmb250RmFtaWx5LFxuICAgICAgZm9udFdlaWdodDogJzUwMCcsXG4gICAgICBkaXNwbGF5OiAnZmxleCcsXG4gICAgICBhbGlnbkl0ZW1zOiAnY2VudGVyJyxcbiAgICAgIGdhcDogJzhweCcsXG4gICAgfTtcblxuICAgIHJldHVybiAoXG4gICAgICA8ZGl2IHN0eWxlPXtzcGVjaWFsTWVzc2FnZVN0eWxlfT5cbiAgICAgICAgPGRpdiBzdHlsZT17c3BlY2lhbEJ1YmJsZVN0eWxlfT5cbiAgICAgICAgICB7aWNvbn1cbiAgICAgICAgICB7bWVzc2FnZS50ZXh0fVxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICk7XG4gIH1cblxuICBpZiAoaXNXZWxjb21lTWVzc2FnZSkge1xuICAgIHJldHVybiAoXG4gICAgICA8ZGl2IHN0eWxlPXttZXNzYWdlQ29udGFpbmVyU3R5bGV9PlxuICAgICAgICA8ZGl2IHN0eWxlPXttZXNzYWdlQnViYmxlQ29udGFpbmVyU3R5bGV9PlxuICAgICAgICAgIDxkaXYgc3R5bGU9e2xhYmVsQ29udGFpbmVyU3R5bGV9PlxuICAgICAgICAgICAgPGRpdiBzdHlsZT17bWVzc2FnZUxhYmVsU3R5bGV9PkFnZW50PC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBzdHlsZT17bWVzc2FnZVJvd1N0eWxlfT5cbiAgICAgICAgICAgIDxkaXYgc3R5bGU9e3suLi5idWJibGVTdHlsZSwgYmFja2dyb3VuZENvbG9yOiB0aGVtZT8ucHJpbWFyeUNvbG9yIHx8ICcjMjU2M0VCJywgY29sb3I6ICcjZmZmZmZmJ319PlxuICAgICAgICAgICAgICB7bWVzc2FnZS50ZXh0fVxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBzdHlsZT17dGltZXN0YW1wU3R5bGV9Pnt0aW1lc3RhbXB9PC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiAoXG4gICAgPGRpdiBzdHlsZT17bWVzc2FnZUNvbnRhaW5lclN0eWxlfT5cbiAgICAgIDxkaXYgc3R5bGU9e2xhYmVsQ29udGFpbmVyU3R5bGV9PlxuICAgICAgICA8ZGl2IHN0eWxlPXttZXNzYWdlTGFiZWxTdHlsZX0+e3NwZWFrZXJMYWJlbH08L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBzdHlsZT17YnViYmxlU3R5bGV9PlxuICAgICAgICB7bWVzc2FnZUxpbmVzfVxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IHN0eWxlPXt0aW1lc3RhbXBTdHlsZX0+e3RpbWVzdGFtcH08L2Rpdj5cbiAgICA8L2Rpdj5cbiAgKTtcbn07ICJdfQ==
|