ynkap-payment
Version:
Module de paiement Y-Nkap pour Angular - Intégration simple des paiements mobiles (Orange Money, MTN Mobile Money)
192 lines • 28.6 kB
JavaScript
import { Injectable } from '@angular/core';
import { HttpHeaders } from '@angular/common/http';
import { BehaviorSubject, catchError, map, of, tap, throwError, switchMap } from 'rxjs';
import { YnkapError } from '../error-handling/models/error.model';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common/http";
import * as i2 from "../configuration/configuration.service";
import * as i3 from "../error-handling/error-handling.service";
import * as i4 from "../auth/auth.service";
import * as i5 from "./retry/retry.service";
import * as i6 from "../shared/logo.service";
export class PaymentService {
/**
* Observable of available payment methods
*/
get availablePaymentMethods$() {
return this.availablePaymentMethodsSubject.asObservable();
}
/**
* Observable of the current transaction
*/
get currentTransaction$() {
return this.currentTransactionSubject.asObservable();
}
/**
* Observable of transaction history
*/
get transactionHistory$() {
return this.transactionHistorySubject.asObservable();
}
getMockPaymentMethods() {
return [
{
id: 'mtn-momo',
name: 'MTN Mobile Money',
provider: 'MTN',
iconUrl: this.logoService.getOperatorLogoUrl('mtn-momo'),
status: 'enabled'
},
{
id: 'orange-money',
name: 'Orange Money',
provider: 'Orange',
iconUrl: this.logoService.getOperatorLogoUrl('orange-money'),
status: 'enabled'
}
];
}
constructor(http, configService, errorHandlingService, authService, retryService, logoService) {
this.http = http;
this.configService = configService;
this.errorHandlingService = errorHandlingService;
this.authService = authService;
this.retryService = retryService;
this.logoService = logoService;
this.availablePaymentMethodsSubject = new BehaviorSubject([]);
this.currentTransactionSubject = new BehaviorSubject(null);
this.transactionHistorySubject = new BehaviorSubject([]);
this.loadPaymentMethods();
}
/**
* Load available payment methods
*/
loadPaymentMethods() {
this.authService.getApiKey().subscribe(apiKey => {
if (!apiKey) {
// Mode démo : on affiche les méthodes mockées sans erreur
this.availablePaymentMethodsSubject.next(this.getMockPaymentMethods());
return;
}
const headers = new HttpHeaders().set('Authorization', `Bearer ${apiKey}`);
this.http.get(`${this.configService.apiUrl}/payment-methods`, { headers })
.pipe(catchError(error => {
this.errorHandlingService.handleError(error);
return of(this.getMockPaymentMethods());
}))
.subscribe(methods => {
this.availablePaymentMethodsSubject.next(methods);
});
});
}
/**
* Initiate a payment transaction
* @param paymentRequest The payment request details
* @returns Observable of the payment response
*/
initiatePayment(request) {
// Generate a unique transaction ID for retry tracking
const transactionId = this.generateTransactionId();
return this.authService.getApiKey().pipe(map(apiKey => {
if (!apiKey) {
throw new YnkapError('AUTH_ERROR', 'Clé API non configurée', 'Veuillez configurer votre clé API Y-Nkap');
}
return apiKey;
}), switchMap(apiKey => {
// Initialize retry state for this transaction
this.retryService.initializeRetryState(transactionId);
const headers = new HttpHeaders().set('Authorization', `Bearer ${apiKey}`);
const paymentRequest = { ...request, transactionId };
return this.http.post(`${this.configService.apiUrl}/payments`, paymentRequest, { headers }).pipe(catchError(error => {
// Convert error to YnkapError
let ynkapError;
if (error instanceof YnkapError) {
ynkapError = error;
}
else {
ynkapError = new YnkapError(error.code || 'PAYMENT_ERROR', error.message || 'Erreur lors du paiement', { originalError: error, retryable: true });
}
// Update retry state
this.retryService.updateRetryState(transactionId, ynkapError);
// Check if we should auto-retry
if (this.retryService.shouldAutoRetry(ynkapError)) {
const retryState = this.retryService.getRetryState(transactionId);
if (retryState?.canRetry) {
// Auto-retry with delay
return this.retryService.executeRetry(transactionId, () => this.http.post(`${this.configService.apiUrl}/payments`, paymentRequest, { headers }));
}
}
this.errorHandlingService.handleError(ynkapError);
return throwError(() => ynkapError);
}), tap(response => {
if (response.status === 'success' && response.transaction) {
this.currentTransactionSubject.next(response.transaction);
const history = this.transactionHistorySubject.value;
this.transactionHistorySubject.next([...history, response.transaction]);
// Clear retry state on success
this.retryService.clearRetryState(transactionId);
}
}));
}));
}
/**
* Retry a payment after an error or failure
* @param transactionId ID of the failed transaction
* @returns Observable of the payment response
*/
retryPayment(transactionId) {
return this.authService.getApiKey().pipe(map(apiKey => {
if (!apiKey) {
throw new YnkapError('AUTH_ERROR', 'Clé API non configurée', 'Veuillez configurer votre clé API Y-Nkap');
}
return apiKey;
}), switchMap(apiKey => {
const headers = new HttpHeaders().set('Authorization', `Bearer ${apiKey}`);
return this.http.post(`${this.configService.apiUrl}/payments/${transactionId}/retry`, {}, { headers }).pipe(catchError(error => {
this.errorHandlingService.handleError(error);
return throwError(() => error);
}), tap(response => {
if (response.status === 'success' && response.transaction) {
this.currentTransactionSubject.next(response.transaction);
const history = this.transactionHistorySubject.value;
this.transactionHistorySubject.next([...history, response.transaction]);
}
}));
}));
}
/**
* Generate a unique transaction ID for retry tracking
*/
generateTransactionId() {
return `txn_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
}
/**
* Create authentication headers for API requests
* @param apiKey The API key from configuration
* @param apiSecret The API secret from configuration
* @returns Object with authorization headers
*/
getAuthHeaders(apiKey, apiSecret) {
// In a real implementation, you might want to use a more secure
// authentication method like OAuth or JWT
const timestamp = Date.now().toString();
// This is a simple example of creating an authorization header
// In a production environment, you would use a more secure approach
const authToken = btoa(`${apiKey}:${apiSecret}:${timestamp}`);
return {
'Authorization': `Bearer ${authToken}`,
'X-Api-Key': apiKey,
'X-Timestamp': timestamp,
'Content-Type': 'application/json'
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PaymentService, deps: [{ token: i1.HttpClient }, { token: i2.ConfigurationService }, { token: i3.ErrorHandlingService }, { token: i4.AuthService }, { token: i5.RetryService }, { token: i6.LogoService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PaymentService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PaymentService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.ConfigurationService }, { type: i3.ErrorHandlingService }, { type: i4.AuthService }, { type: i5.RetryService }, { type: i6.LogoService }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5bWVudC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMveW5rYXAvc3JjL2xpYi9wYXltZW50L3BheW1lbnQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFBYyxXQUFXLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUMvRCxPQUFPLEVBQUUsZUFBZSxFQUFjLFVBQVUsRUFBRSxHQUFHLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBV3BHLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQzs7Ozs7Ozs7QUFNbEUsTUFBTSxPQUFPLGNBQWM7SUFNekI7O09BRUc7SUFDSCxJQUFJLHdCQUF3QjtRQUMxQixPQUFPLElBQUksQ0FBQyw4QkFBOEIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUM1RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLG1CQUFtQjtRQUNyQixPQUFPLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN2RCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxJQUFJLG1CQUFtQjtRQUNyQixPQUFPLElBQUksQ0FBQyx5QkFBeUIsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN2RCxDQUFDO0lBRU8scUJBQXFCO1FBQzNCLE9BQU87WUFDTDtnQkFDRSxFQUFFLEVBQUUsVUFBVTtnQkFDZCxJQUFJLEVBQUUsa0JBQWtCO2dCQUN4QixRQUFRLEVBQUUsS0FBSztnQkFDZixPQUFPLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUM7Z0JBQ3hELE1BQU0sRUFBRSxTQUFTO2FBQ2xCO1lBQ0Q7Z0JBQ0UsRUFBRSxFQUFFLGNBQWM7Z0JBQ2xCLElBQUksRUFBRSxj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QztRQUMxQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFeEMsK0RBQStEO1FBQy9ELG9FQUFvRTtRQUNwRSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxNQUFNLElBQUksU0FBUyxJQUFJLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFFOUQsT0FBTztZQUNMLGVBQWUsRUFBRSxVQUFVLFNBQVMsRUFBRTtZQUN0QyxXQUFXLEVBQUUsTUFBTTtZQUNuQixhQUFhLEVBQUUsU0FBUztZQUN4QixjQUFjLEVBQUUsa0JBQWtCO1NBQ25DLENBQUM7SUFDSixDQUFDOytHQXZPVSxjQUFjO21IQUFkLGNBQWMsY0FGYixNQUFNOzs0RkFFUCxjQUFjO2tCQUgxQixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEh0dHBDbGllbnQsIEh0dHBIZWFkZXJzIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uL2h0dHAnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlLCBjYXRjaEVycm9yLCBtYXAsIG9mLCB0YXAsIHRocm93RXJyb3IsIHN3aXRjaE1hcCB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ29uZmlndXJhdGlvblNlcnZpY2UgfSBmcm9tICcuLi9jb25maWd1cmF0aW9uL2NvbmZpZ3VyYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBFcnJvckhhbmRsaW5nU2VydmljZSB9IGZyb20gJy4uL2Vycm9yLWhhbmRsaW5nL2Vycm9yLWhhbmRsaW5nLnNlcnZpY2UnO1xuaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuLi9hdXRoL2F1dGguc2VydmljZSc7XG5pbXBvcnQgeyBSZXRyeVNlcnZpY2UgfSBmcm9tICcuL3JldHJ5L3JldHJ5LnNlcnZpY2UnO1xuaW1wb3J0IHtcbiAgUGF5bWVudE1ldGhvZCxcbiAgUGF5bWVudFJlcXVlc3QsXG4gIFBheW1lbnRSZXNwb25zZSxcbiAgUGF5bWVudFRyYW5zYWN0aW9uXG59IGZyb20gJy4vbW9kZWxzL3BheW1lbnQubW9kZWwnO1xuaW1wb3J0IHsgWW5rYXBFcnJvciB9IGZyb20gJy4uL2Vycm9yLWhhbmRsaW5nL21vZGVscy9lcnJvci5tb2RlbCc7XG5pbXBvcnQgeyBMb2dvU2VydmljZSB9IGZyb20gJy4uL3NoYXJlZC9sb2dvLnNlcnZpY2UnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBQYXltZW50U2VydmljZSB7XG4gIHByaXZhdGUgYXZhaWxhYmxlUGF5bWVudE1ldGhvZHNTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxQYXltZW50TWV0aG9kW10+KFtdKTtcbiAgcHJpdmF0ZSBjdXJyZW50VHJhbnNhY3Rpb25TdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxQYXltZW50VHJhbnNhY3Rpb24gfCBudWxsPihudWxsKTtcbiAgcHJpdmF0ZSB0cmFuc2FjdGlvbkhpc3RvcnlTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxQYXltZW50VHJhbnNhY3Rpb25bXT4oW10pO1xuXG5cbiAgLyoqXG4gICAqIE9ic2VydmFibGUgb2YgYXZhaWxhYmxlIHBheW1lbnQgbWV0aG9kc1xuICAgKi9cbiAgZ2V0IGF2YWlsYWJsZVBheW1lbnRNZXRob2RzJCgpOiBPYnNlcnZhYmxlPFBheW1lbnRNZXRob2RbXT4ge1xuICAgIHJldHVybiB0aGlzLmF2YWlsYWJsZVBheW1lbnRNZXRob2RzU3ViamVjdC5hc09ic2VydmFibGUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZhYmxlIG9mIHRoZSBjdXJyZW50IHRyYW5zYWN0aW9uXG4gICAqL1xuICBnZXQgY3VycmVudFRyYW5zYWN0aW9uJCgpOiBPYnNlcnZhYmxlPFBheW1lbnRUcmFuc2FjdGlvbiB8IG51bGw+IHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50VHJhbnNhY3Rpb25TdWJqZWN0LmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9ic2VydmFibGUgb2YgdHJhbnNhY3Rpb24gaGlzdG9yeVxuICAgKi9cbiAgZ2V0IHRyYW5zYWN0aW9uSGlzdG9yeSQoKTogT2JzZXJ2YWJsZTxQYXltZW50VHJhbnNhY3Rpb25bXT4ge1xuICAgIHJldHVybiB0aGlzLnRyYW5zYWN0aW9uSGlzdG9yeVN1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICBwcml2YXRlIGdldE1vY2tQYXltZW50TWV0aG9kcygpOiBQYXltZW50TWV0aG9kW10ge1xuICAgIHJldHVybiBbXG4gICAgICB7XG4gICAgICAgIGlkOiAnbXRuLW1vbW8nLFxuICAgICAgICBuYW1lOiAnTVROIE1vYmlsZSBNb25leScsXG4gICAgICAgIHByb3ZpZGVyOiAnTVROJyxcbiAgICAgICAgaWNvblVybDogdGhpcy5sb2dvU2VydmljZS5nZXRPcGVyYXRvckxvZ29VcmwoJ210bi1tb21vJyksXG4gICAgICAgIHN0YXR1czogJ2VuYWJsZWQnXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBpZDogJ29yYW5nZS1tb25leScsXG4gICAgICAgIG5hbWU6ICdPcmFuZ2UgTW9uZXknLFxuICAgICAgICBwcm92aWRlcjogJ09yYW5nZScsXG4gICAgICAgIGljb25Vcmw6IHRoaXMubG9nb1NlcnZpY2UuZ2V0T3BlcmF0b3JMb2dvVXJsKCdvcmFuZ2UtbW9uZXknKSxcbiAgICAgICAgc3RhdHVzOiAnZW5hYmxlZCdcbiAgICAgIH1cbiAgICBdO1xuICB9XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50LFxuICAgIHByaXZhdGUgY29uZmlnU2VydmljZTogQ29uZmlndXJhdGlvblNlcnZpY2UsXG4gICAgcHJpdmF0ZSBlcnJvckhhbmRsaW5nU2VydmljZTogRXJyb3JIYW5kbGluZ1NlcnZpY2UsXG4gICAgcHJpdmF0ZSBhdXRoU2VydmljZTogQXV0aFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByZXRyeVNlcnZpY2U6IFJldHJ5U2VydmljZSxcbiAgICBwcml2YXRlIGxvZ29TZXJ2aWNlOiBMb2dvU2VydmljZVxuICApIHtcbiAgICB0aGlzLmxvYWRQYXltZW50TWV0aG9kcygpO1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgYXZhaWxhYmxlIHBheW1lbnQgbWV0aG9kc1xuICAgKi9cbiAgcHJpdmF0ZSBsb2FkUGF5bWVudE1ldGhvZHMoKTogdm9pZCB7XG4gICAgdGhpcy5hdXRoU2VydmljZS5nZXRBcGlLZXkoKS5zdWJzY3JpYmUoYXBpS2V5ID0+IHtcbiAgICAgIGlmICghYXBpS2V5KSB7XG4gICAgICAgIC8vIE1vZGUgZMOpbW8gOiBvbiBhZmZpY2hlIGxlcyBtw6l0aG9kZXMgbW9ja8OpZXMgc2FucyBlcnJldXJcbiAgICAgICAgdGhpcy5hdmFpbGFibGVQYXltZW50TWV0aG9kc1N1YmplY3QubmV4dCh0aGlzLmdldE1vY2tQYXltZW50TWV0aG9kcygpKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoZWFkZXJzID0gbmV3IEh0dHBIZWFkZXJzKCkuc2V0KCdBdXRob3JpemF0aW9uJywgYEJlYXJlciAke2FwaUtleX1gKTtcbiAgICAgIHRoaXMuaHR0cC5nZXQ8UGF5bWVudE1ldGhvZFtdPihgJHt0aGlzLmNvbmZpZ1NlcnZpY2UuYXBpVXJsfS9wYXltZW50LW1ldGhvZHNgLCB7IGhlYWRlcnMgfSlcbiAgICAgICAgLnBpcGUoXG4gICAgICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB7XG4gICAgICAgICAgICB0aGlzLmVycm9ySGFuZGxpbmdTZXJ2aWNlLmhhbmRsZUVycm9yKGVycm9yKTtcbiAgICAgIHJldHVybiBvZih0aGlzLmdldE1vY2tQYXltZW50TWV0aG9kcygpKTtcbiAgICAgICAgICB9KVxuICAgICAgICApXG4gICAgICAgIC5zdWJzY3JpYmUobWV0aG9kcyA9PiB7XG4gICAgICAgICAgdGhpcy5hdmFpbGFibGVQYXltZW50TWV0aG9kc1N1YmplY3QubmV4dChtZXRob2RzKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogSW5pdGlhdGUgYSBwYXltZW50IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXltZW50UmVxdWVzdCBUaGUgcGF5bWVudCByZXF1ZXN0IGRldGFpbHNcbiAgICogQHJldHVybnMgT2JzZXJ2YWJsZSBvZiB0aGUgcGF5bWVudCByZXNwb25zZVxuICAgKi9cbiAgaW5pdGlhdGVQYXltZW50KHJlcXVlc3Q6IFBheW1lbnRSZXF1ZXN0KTogT2JzZXJ2YWJsZTxQYXltZW50UmVzcG9uc2U+IHtcbiAgICAvLyBHZW5lcmF0ZSBhIHVuaXF1ZSB0cmFuc2FjdGlvbiBJRCBmb3IgcmV0cnkgdHJhY2tpbmdcbiAgICBjb25zdCB0cmFuc2FjdGlvbklkID0gdGhpcy5nZW5lcmF0ZVRyYW5zYWN0aW9uSWQoKTtcblxuICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLmdldEFwaUtleSgpLnBpcGUoXG4gICAgICBtYXAoYXBpS2V5ID0+IHtcbiAgICAgICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgWW5rYXBFcnJvcihcbiAgICAgICAgICAgICdBVVRIX0VSUk9SJyxcbiAgICAgICAgICAgICdDbMOpIEFQSSBub24gY29uZmlndXLDqWUnLFxuICAgICAgICAgICAgJ1ZldWlsbGV6IGNvbmZpZ3VyZXIgdm90cmUgY2zDqSBBUEkgWS1Oa2FwJ1xuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFwaUtleTtcbiAgICAgIH0pLFxuICAgICAgc3dpdGNoTWFwKGFwaUtleSA9PiB7XG4gICAgICAgIC8vIEluaXRpYWxpemUgcmV0cnkgc3RhdGUgZm9yIHRoaXMgdHJhbnNhY3Rpb25cbiAgICAgICAgdGhpcy5yZXRyeVNlcnZpY2UuaW5pdGlhbGl6ZVJldHJ5U3RhdGUodHJhbnNhY3Rpb25JZCk7XG5cbiAgICAgICAgY29uc3QgaGVhZGVycyA9IG5ldyBIdHRwSGVhZGVycygpLnNldCgnQXV0aG9yaXphdGlvbicsIGBCZWFyZXIgJHthcGlLZXl9YCk7XG4gICAgICAgIGNvbnN0IHBheW1lbnRSZXF1ZXN0ID0geyAuLi5yZXF1ZXN0LCB0cmFuc2FjdGlvbklkIH07XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuaHR0cC5wb3N0PFBheW1lbnRSZXNwb25zZT4oXG4gICAgICAgICAgYCR7dGhpcy5jb25maWdTZXJ2aWNlLmFwaVVybH0vcGF5bWVudHNgLFxuICAgICAgICAgIHBheW1lbnRSZXF1ZXN0LFxuICAgICAgICAgIHsgaGVhZGVycyB9XG4gICAgICAgICkucGlwZShcbiAgICAgICAgICBjYXRjaEVycm9yKGVycm9yID0+IHtcbiAgICAgICAgICAgIC8vIENvbnZlcnQgZXJyb3IgdG8gWW5rYXBFcnJvclxuICAgICAgICAgICAgbGV0IHlua2FwRXJyb3I6IFlua2FwRXJyb3I7XG4gICAgICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBZbmthcEVycm9yKSB7XG4gICAgICAgICAgICAgIHlua2FwRXJyb3IgPSBlcnJvcjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHlua2FwRXJyb3IgPSBuZXcgWW5rYXBFcnJvcihcbiAgICAgICAgICAgICAgICBlcnJvci5jb2RlIHx8ICdQQVlNRU5UX0VSUk9SJyxcbiAgICAgICAgICAgICAgICBlcnJvci5tZXNzYWdlIHx8ICdFcnJldXIgbG9ycyBkdSBwYWllbWVudCcsXG4gICAgICAgICAgICAgICAgeyBvcmlnaW5hbEVycm9yOiBlcnJvciwgcmV0cnlhYmxlOiB0cnVlIH1cbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gVXBkYXRlIHJldHJ5IHN0YXRlXG4gICAgICAgICAgICB0aGlzLnJldHJ5U2VydmljZS51cGRhdGVSZXRyeVN0YXRlKHRyYW5zYWN0aW9uSWQsIHlua2FwRXJyb3IpO1xuXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB3ZSBzaG91bGQgYXV0by1yZXRyeVxuICAgICAgICAgICAgaWYgKHRoaXMucmV0cnlTZXJ2aWNlLnNob3VsZEF1dG9SZXRyeSh5bmthcEVycm9yKSkge1xuICAgICAgICAgICAgICBjb25zdCByZXRyeVN0YXRlID0gdGhpcy5yZXRyeVNlcnZpY2UuZ2V0UmV0cnlTdGF0ZSh0cmFuc2FjdGlvbklkKTtcbiAgICAgICAgICAgICAgaWYgKHJldHJ5U3RhdGU/LmNhblJldHJ5KSB7XG4gICAgICAgICAgICAgICAgLy8gQXV0by1yZXRyeSB3aXRoIGRlbGF5XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmV0cnlTZXJ2aWNlLmV4ZWN1dGVSZXRyeShcbiAgICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9uSWQsXG4gICAgICAgICAgICAgICAgICAoKSA9PiB0aGlzLmh0dHAucG9zdDxQYXltZW50UmVzcG9uc2U+KFxuICAgICAgICAgICAgICAgICAgICBgJHt0aGlzLmNvbmZpZ1NlcnZpY2UuYXBpVXJsfS9wYXltZW50c2AsXG4gICAgICAgICAgICAgICAgICAgIHBheW1lbnRSZXF1ZXN0LFxuICAgICAgICAgICAgICAgICAgICB7IGhlYWRlcnMgfVxuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5lcnJvckhhbmRsaW5nU2VydmljZS5oYW5kbGVFcnJvcih5bmthcEVycm9yKTtcbiAgICAgICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IHlua2FwRXJyb3IpO1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIHRhcChyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSAnc3VjY2VzcycgJiYgcmVzcG9uc2UudHJhbnNhY3Rpb24pIHtcbiAgICAgICAgICAgICAgdGhpcy5jdXJyZW50VHJhbnNhY3Rpb25TdWJqZWN0Lm5leHQocmVzcG9uc2UudHJhbnNhY3Rpb24pO1xuICAgICAgICAgICAgICBjb25zdCBoaXN0b3J5ID0gdGhpcy50cmFuc2FjdGlvbkhpc3RvcnlTdWJqZWN0LnZhbHVlO1xuICAgICAgICAgICAgICB0aGlzLnRyYW5zYWN0aW9uSGlzdG9yeVN1YmplY3QubmV4dChbLi4uaGlzdG9yeSwgcmVzcG9uc2UudHJhbnNhY3Rpb25dKTtcbiAgICAgICAgICAgICAgLy8gQ2xlYXIgcmV0cnkgc3RhdGUgb24gc3VjY2Vzc1xuICAgICAgICAgICAgICB0aGlzLnJldHJ5U2VydmljZS5jbGVhclJldHJ5U3RhdGUodHJhbnNhY3Rpb25JZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyeSBhIHBheW1lbnQgYWZ0ZXIgYW4gZXJyb3Igb3IgZmFpbHVyZVxuICAgKiBAcGFyYW0gdHJhbnNhY3Rpb25JZCBJRCBvZiB0aGUgZmFpbGVkIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm5zIE9ic2VydmFibGUgb2YgdGhlIHBheW1lbnQgcmVzcG9uc2VcbiAgICovXG4gIHJldHJ5UGF5bWVudCh0cmFuc2FjdGlvbklkOiBzdHJpbmcpOiBPYnNlcnZhYmxlPFBheW1lbnRSZXNwb25zZT4ge1xuICAgIHJldHVybiB0aGlzLmF1dGhTZXJ2aWNlLmdldEFwaUtleSgpLnBpcGUoXG4gICAgICBtYXAoYXBpS2V5ID0+IHtcbiAgICAgICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgWW5rYXBFcnJvcihcbiAgICAgICAgICAgICdBVVRIX0VSUk9SJyxcbiAgICAgICAgICAgICdDbMOpIEFQSSBub24gY29uZmlndXLDqWUnLFxuICAgICAgICAgICAgJ1ZldWlsbGV6IGNvbmZpZ3VyZXIgdm90cmUgY2zDqSBBUEkgWS1Oa2FwJ1xuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFwaUtleTtcbiAgICAgIH0pLFxuICAgICAgc3dpdGNoTWFwKGFwaUtleSA9PiB7XG4gICAgICAgIGNvbnN0IGhlYWRlcnMgPSBuZXcgSHR0cEhlYWRlcnMoKS5zZXQoJ0F1dGhvcml6YXRpb24nLCBgQmVhcmVyICR7YXBpS2V5fWApO1xuICAgICAgICByZXR1cm4gdGhpcy5odHRwLnBvc3Q8UGF5bWVudFJlc3BvbnNlPihcbiAgICAgICAgICBgJHt0aGlzLmNvbmZpZ1NlcnZpY2UuYXBpVXJsfS9wYXltZW50cy8ke3RyYW5zYWN0aW9uSWR9L3JldHJ5YCxcbiAgICAgICAgICB7fSxcbiAgICAgICAgICB7IGhlYWRlcnMgfVxuICAgICAgICApLnBpcGUoXG4gICAgICBjYXRjaEVycm9yKGVycm9yID0+IHtcbiAgICAgICAgICAgIHRoaXMuZXJyb3JIYW5kbGluZ1NlcnZpY2UuaGFuZGxlRXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gZXJyb3IpO1xuICAgICAgICAgIH0pLFxuICAgICAgICAgIHRhcChyZXNwb25zZSA9PiB7XG4gICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSAnc3VjY2VzcycgJiYgcmVzcG9uc2UudHJhbnNhY3Rpb24pIHtcbiAgICAgICAgICAgICAgdGhpcy5jdXJyZW50VHJhbnNhY3Rpb25TdWJqZWN0Lm5leHQocmVzcG9uc2UudHJhbnNhY3Rpb24pO1xuICAgICAgICAgICAgICBjb25zdCBoaXN0b3J5ID0gdGhpcy50cmFuc2FjdGlvbkhpc3RvcnlTdWJqZWN0LnZhbHVlO1xuICAgICAgICAgICAgICB0aGlzLnRyYW5zYWN0aW9uSGlzdG9yeVN1YmplY3QubmV4dChbLi4uaGlzdG9yeSwgcmVzcG9uc2UudHJhbnNhY3Rpb25dKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgdW5pcXVlIHRyYW5zYWN0aW9uIElEIGZvciByZXRyeSB0cmFja2luZ1xuICAgKi9cbiAgcHJpdmF0ZSBnZW5lcmF0ZVRyYW5zYWN0aW9uSWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYHR4bl8ke0RhdGUubm93KCl9XyR7TWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyaW5nKDIsIDExKX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhdXRoZW50aWNhdGlvbiBoZWFkZXJzIGZvciBBUEkgcmVxdWVzdHNcbiAgICogQHBhcmFtIGFwaUtleSBUaGUgQVBJIGtleSBmcm9tIGNvbmZpZ3VyYXRpb25cbiAgICogQHBhcmFtIGFwaVNlY3JldCBUaGUgQVBJIHNlY3JldCBmcm9tIGNvbmZpZ3VyYXRpb25cbiAgICogQHJldHVybnMgT2JqZWN0IHdpdGggYXV0aG9yaXphdGlvbiBoZWFkZXJzXG4gICAqL1xuICBwcml2YXRlIGdldEF1dGhIZWFkZXJzKGFwaUtleTogc3RyaW5nLCBhcGlTZWNyZXQ6IHN0cmluZyk6IHsgW2hlYWRlcjogc3RyaW5nXTogc3RyaW5nIH0ge1xuICAgIC8vIEluIGEgcmVhbCBpbXBsZW1lbnRhdGlvbiwgeW91IG1pZ2h0IHdhbnQgdG8gdXNlIGEgbW9yZSBzZWN1cmVcbiAgICAvLyBhdXRoZW50aWNhdGlvbiBtZXRob2QgbGlrZSBPQXV0aCBvciBKV1RcbiAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpLnRvU3RyaW5nKCk7XG4gICAgXG4gICAgLy8gVGhpcyBpcyBhIHNpbXBsZSBleGFtcGxlIG9mIGNyZWF0aW5nIGFuIGF1dGhvcml6YXRpb24gaGVhZGVyXG4gICAgLy8gSW4gYSBwcm9kdWN0aW9uIGVudmlyb25tZW50LCB5b3Ugd291bGQgdXNlIGEgbW9yZSBzZWN1cmUgYXBwcm9hY2hcbiAgICBjb25zdCBhdXRoVG9rZW4gPSBidG9hKGAke2FwaUtleX06JHthcGlTZWNyZXR9OiR7dGltZXN0YW1wfWApO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICAnQXV0aG9yaXphdGlvbic6IGBCZWFyZXIgJHthdXRoVG9rZW59YCxcbiAgICAgICdYLUFwaS1LZXknOiBhcGlLZXksXG4gICAgICAnWC1UaW1lc3RhbXAnOiB0aW1lc3RhbXAsXG4gICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nXG4gICAgfTtcbiAgfVxufVxuIl19